summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2011-01-18 18:10:19 +0100
committerWaldemar Brodkorb <wbx@openadk.org>2011-01-18 18:10:19 +0100
commit46b2bb3001ce838ba2483a08418587d8a027f3a9 (patch)
treeb2b618839b5afcc859fcb90556e6f199d9a9a10c
parent88d3e6d6c572143bd95a589a44e30bfefd616b88 (diff)
parent902ee7e7b23751ca7a8264d36a837aa4aae12032 (diff)
Merge branch 'master' of git+ssh://openadk.org/git/openadk
-rw-r--r--.gitignore2
-rw-r--r--Config.in26
-rw-r--r--Makefile27
-rw-r--r--README7
-rw-r--r--TODO18
-rw-r--r--mk/build.mk48
-rw-r--r--mk/buildhlp.mk5
-rw-r--r--mk/image.mk42
-rw-r--r--mk/kernel-build.mk8
-rw-r--r--mk/kernel-vars.mk10
-rw-r--r--mk/kernel-ver.mk4
-rw-r--r--mk/kernel.mk2
-rw-r--r--mk/modules.mk10
-rw-r--r--mk/package.mk16
-rw-r--r--mk/pkg-bottom.mk4
-rw-r--r--mk/python.mk4
-rw-r--r--mk/vars.mk33
-rw-r--r--package/.template/Makefile4
-rw-r--r--package/DirectFB/Makefile11
-rw-r--r--package/DirectFB/patches/patch-configure11
-rw-r--r--package/DirectFB/patches/patch-ltmain_sh11
-rw-r--r--package/ImageMagick/Makefile12
-rw-r--r--package/ImageMagick/patches/patch-config_ltmain_sh39
-rw-r--r--package/Makefile3
-rw-r--r--package/alsa-lib/Makefile6
-rw-r--r--package/alsa-lib/patches/patch-ltmain_sh11
-rw-r--r--package/alsa-utils/Makefile8
-rw-r--r--package/apr/Makefile3
-rw-r--r--package/apr/patches/patch-build_ltmain_sh11
-rw-r--r--package/arpd/Makefile2
-rw-r--r--package/asterisk/Makefile15
-rw-r--r--package/aufs2-util/Makefile26
-rw-r--r--package/aufs2-util/patches/patch-Makefile68
-rw-r--r--package/aufs2-util/src/COPYING340
-rw-r--r--package/aufs2-util/src/Makefile93
-rw-r--r--package/aufs2-util/src/README46
-rw-r--r--package/aufs2-util/src/au_util.h67
-rwxr-xr-xpackage/aufs2-util/src/aubrsync304
-rwxr-xr-xpackage/aufs2-util/src/auchk130
-rw-r--r--package/aufs2-util/src/aufs.in.51684
-rw-r--r--package/aufs2-util/src/aufs.shlib83
-rw-r--r--package/aufs2-util/src/auplink.c64
-rw-r--r--package/aufs2-util/src/br.c172
-rw-r--r--package/aufs2-util/src/c2sh.c42
-rw-r--r--package/aufs2-util/src/c2tmac.c44
-rw-r--r--package/aufs2-util/src/compat.h34
-rw-r--r--package/aufs2-util/src/mount.aufs.c255
-rw-r--r--package/aufs2-util/src/mtab.c216
-rw-r--r--package/aufs2-util/src/plink.c356
-rw-r--r--package/aufs2-util/src/proc_mnt.c85
-rw-r--r--package/aufs2-util/src/rdu.c749
-rwxr-xr-xpackage/aufs2-util/src/umount.aufs31
-rw-r--r--package/autossh/patches/patch-Makefile_in11
-rw-r--r--package/avahi/patches/patch-ltmain_sh11
-rw-r--r--package/axtls/Makefile4
-rw-r--r--package/axtls/files/config4
-rw-r--r--package/base-files/Makefile3
-rwxr-xr-xpackage/base-files/src/etc/network/if-pre-up.d/03-bridge1
-rwxr-xr-xpackage/base-files/src/etc/network/if-pre-up.d/04-wireless2
-rw-r--r--package/bash/Makefile2
-rw-r--r--package/bind/Makefile4
-rw-r--r--package/bind/patches/patch-ltmain_sh11
-rw-r--r--package/binutils/patches/patch-ld_Makefile_in20
-rw-r--r--package/binutils/patches/patch-ltmain_sh11
-rw-r--r--package/bitlbee/Makefile4
-rw-r--r--package/bluez/patches/patch-Makefile_in10
-rw-r--r--package/bluez/patches/patch-ltmain_sh11
-rw-r--r--package/bogofilter/Makefile8
-rw-r--r--package/busybox/Makefile8
-rw-r--r--package/busybox/config/miscutils/Config.in11
-rw-r--r--package/busybox/patches/007-missing-headers.patch10
-rw-r--r--package/bzr/Makefile14
-rw-r--r--package/ca-certificates/Makefile2
-rw-r--r--package/cairo/patches/patch-build_ltmain_sh11
-rw-r--r--package/cairo/patches/patch-src_cairo-features_h15
-rw-r--r--package/ccid/patches/patch-ltmain_sh11
-rw-r--r--package/cgilib/patches/patch-ltmain_sh11
-rw-r--r--package/collectd/Makefile18
-rw-r--r--package/collectd/patches/patch-ltmain_sh11
-rw-r--r--package/coreutils/Makefile2
-rw-r--r--package/cryptsetup/Makefile3
-rw-r--r--package/cryptsetup/patches/patch-ltmain_sh11
-rw-r--r--package/cups/Makefile4
-rw-r--r--package/curl/Makefile15
-rw-r--r--package/curl/patches/patch-configure6
-rw-r--r--package/curl/patches/patch-ltmain_sh11
-rw-r--r--package/dansguardian/Makefile9
-rw-r--r--package/dbus/patches/patch-configure6
-rw-r--r--package/dbus/patches/patch-ltmain_sh39
-rw-r--r--package/digitemp/patches/patch-Makefile33
-rw-r--r--package/dillo/Makefile2
-rw-r--r--package/dillo/patches/patch-Makefile_in11
-rw-r--r--package/dillo/patches/patch-configure14
-rw-r--r--package/dillo/patches/patch-src_IO_Makefile_in11
-rw-r--r--package/dnsmasq/Makefile9
-rw-r--r--package/dnsmasq/patches/patch-Makefile20
-rw-r--r--package/dnsmasq/patches/patch-src_config_h8
-rw-r--r--package/dosfstools/Makefile6
-rw-r--r--package/dosfstools/patches/patch-Makefile11
-rw-r--r--package/dovecot/Makefile2
-rw-r--r--package/dovecot/patches/patch-ltmain_sh11
-rw-r--r--package/drbd/patches/patch-drbd_drbd_buildtag_c9
-rw-r--r--package/drbd/patches/patch-user_Makefile_in24
-rw-r--r--package/e2fsprogs/Makefile20
-rw-r--r--package/e2fsprogs/patches/patch-debugfs_dump_c.orig10
-rw-r--r--package/e2fsprogs/patches/patch-e2fsck_Makefile_in20
-rw-r--r--package/e2fsprogs/patches/patch-e2fsprogs_spec11
-rw-r--r--package/e2fsprogs/patches/patch-misc_e2undo_c11
-rw-r--r--package/ebtables/patches/patch-Makefile24
-rw-r--r--package/eglibc/Makefile38
-rw-r--r--package/elinks/Makefile3
-rw-r--r--package/esound/patches/patch-esd_c6
-rw-r--r--package/esound/patches/patch-ltmain_sh11
-rw-r--r--package/exmap/Makefile1
-rw-r--r--package/exmap/patches/autotool.patch11256
-rw-r--r--package/exmap/patches/patch-Makefile_in12
-rw-r--r--package/expat/Makefile6
-rw-r--r--package/expat/patches/patch-conftools_ltmain_sh11
-rw-r--r--package/faad2/patches/patch-ltmain_sh11
-rw-r--r--package/fetchmail/Makefile10
-rw-r--r--package/ffmpeg/Makefile6
-rw-r--r--package/file/patches/patch-ltmain_sh11
-rw-r--r--package/findutils/Makefile12
-rw-r--r--package/firefox/Makefile2
-rw-r--r--package/flac/patches/patch-ltmain_sh11
-rw-r--r--package/fltk/Makefile14
-rw-r--r--package/fltk/patches/patch-Makefile11
-rw-r--r--package/fltk/patches/patch-fltk2-config_in27
-rw-r--r--package/fluxbox/Makefile2
-rw-r--r--package/font-bh-100dpi/Makefile1
-rw-r--r--package/font-bh-75dpi/Makefile1
-rw-r--r--package/font-bh-lucidatypewriter-100dpi/Makefile1
-rw-r--r--package/font-bh-lucidatypewriter-75dpi/Makefile1
-rw-r--r--package/font-bh-ttf/Makefile1
-rw-r--r--package/font-bh-type1/Makefile1
-rw-r--r--package/font-bitstream-100dpi/Makefile1
-rw-r--r--package/font-bitstream-75dpi/Makefile1
-rw-r--r--package/font-bitstream-type1/Makefile1
-rw-r--r--package/font-xfree86-type1/Makefile1
-rw-r--r--package/fontconfig/Makefile5
-rw-r--r--package/fontconfig/patches/patch-ltmain_sh11
-rw-r--r--package/freeglut/Makefile2
-rw-r--r--package/freeglut/patches/patch-ltmain_sh11
-rw-r--r--package/freeradius-client/patches/patch-ltmain_sh11
-rw-r--r--package/freeradius-server/patches/patch-ltmain_sh11
-rw-r--r--package/freetype/patches/patch-builds_unix_ltmain_sh11
-rw-r--r--package/gatling/patches/patch-GNUmakefile17
-rw-r--r--package/gcc/Makefile3
-rw-r--r--package/gcc/patches/cross-gcc-fix.patch10
-rw-r--r--package/gcc/patches/ltmain.patch12
-rw-r--r--package/gdb/patches/patch-ltmain_sh11
-rw-r--r--package/gdk-pixbuf/Makefile1
-rw-r--r--package/gdk-pixbuf/patches/patch-ltmain_sh11
-rw-r--r--package/gettext/Makefile3
-rw-r--r--package/gettext/patches/patch-build-aux_ltmain_sh39
-rw-r--r--package/gkrellm/Makefile (renamed from package/gkrellmd/Makefile)7
-rw-r--r--package/gkrellm/files/gkrellmd.init (renamed from package/gkrellmd/files/gkrellmd.init)0
-rw-r--r--package/gkrellm/files/gkrellmd.postinst (renamed from package/gkrellmd/files/gkrellmd.postinst)0
-rw-r--r--package/gkrellm/patches/patch-server_Makefile22
-rw-r--r--package/glib/Makefile18
-rw-r--r--package/glib/patches/patch-glib_gconvert_c16
-rw-r--r--package/glib/patches/patch-ltmain_sh11
-rw-r--r--package/glibc/Makefile28
-rw-r--r--package/gmp/patches/patch-ltmain_sh11
-rw-r--r--package/gnupg/Makefile1
-rw-r--r--package/gnutls/Makefile1
-rw-r--r--package/gnutls/patches/patch-build-aux_ltmain_sh11
-rw-r--r--package/gnutls/patches/patch-lib_build-aux_ltmain_sh11
-rw-r--r--package/gnutls/patches/patch-libextra_build-aux_ltmain_sh11
-rw-r--r--package/gpm/patches/patch-src_Makefile_in51
-rw-r--r--package/gpsd/Makefile10
-rw-r--r--package/gpsd/patches/patch-Makefile_in11
-rw-r--r--package/gpsd/patches/patch-ltmain_sh20
-rw-r--r--package/grep/Makefile2
-rw-r--r--package/gtk+/Makefile9
-rw-r--r--package/gtk+/patches/patch-Makefile_in13
-rw-r--r--package/gtk+/patches/patch-gtk_Makefile_in265
-rw-r--r--package/gtk+/patches/patch-gtk_gtktypefuncs_c78
-rw-r--r--package/gtk+/patches/patch-ltmain_sh11
-rw-r--r--package/hdparm/patches/patch-Makefile30
-rw-r--r--package/heimdal/Makefile61
-rw-r--r--package/heimdal/patches/patch-Makefile_in24
-rw-r--r--package/heimdal/patches/patch-configure19
-rw-r--r--package/heimdal/patches/patch-kdc_config_c18
-rw-r--r--package/heimdal/patches/patch-kdc_kdc-replay_c18
-rw-r--r--package/heimdal/patches/patch-lib_hcrypto_Makefile_in12
-rw-r--r--package/heimdal/patches/patch-lib_roken_Makefile_in.orig27
-rw-r--r--package/heimdal/patches/patch-lib_roken_roken_h_in11
-rw-r--r--package/heimdal/patches/patch-ltmain_sh11
-rw-r--r--package/heimdal/src/lib/hcrypto/libtommath/tommath.h592
-rw-r--r--package/heimdal/src/lib/hcrypto/libtommath/tommath_class.h1000
-rw-r--r--package/heimdal/src/lib/hcrypto/libtommath/tommath_superclass.h76
-rw-r--r--package/hostapd/Makefile2
-rw-r--r--package/hostapd/files/hostapd.config1
-rw-r--r--package/id3lib/Makefile8
-rw-r--r--package/id3lib/patches/patch-ltmain_sh22
-rw-r--r--package/imlib2/patches/patch-ltmain_sh11
-rw-r--r--package/ipcad/patches/patch-Makefile_in17
-rw-r--r--package/iperf/Makefile5
-rw-r--r--package/iproute2/Makefile48
-rw-r--r--package/iproute2/files/Config2
-rw-r--r--package/ipsec-tools/Makefile4
-rw-r--r--package/ipsec-tools/patches/patch-ltmain_sh11
-rw-r--r--package/ipset/Makefile12
-rw-r--r--package/iptables-snmp/patches/patch-Makefile_in11
-rw-r--r--package/iptables-snmp/patches/patch-iptables-snmp_c12
-rw-r--r--package/iptables/Makefile13
-rw-r--r--package/iptables/patches/patch-ltmain_sh11
-rw-r--r--package/iptraf/Makefile2
-rw-r--r--package/irssi/Makefile2
-rw-r--r--package/irssi/patches/patch-build-aux_ltmain_sh30
-rw-r--r--package/iw/Makefile4
-rw-r--r--package/iw/patches/patch-Makefile15
-rw-r--r--package/iw/patches/patch-version_sh4
-rw-r--r--package/jamvm/patches/patch-ltmain_sh11
-rw-r--r--package/jpeg/Makefile6
-rw-r--r--package/jpeg/patches/patch-ltmain_sh11
-rw-r--r--package/krb5/Makefile6
-rw-r--r--package/krb5/patches/patch-src_krb5-config_in22
-rw-r--r--package/lame/patches/patch-ltmain_sh11
-rw-r--r--package/libICE/patches/patch-ltmain_sh11
-rw-r--r--package/libSM/patches/patch-ltmain_sh11
-rw-r--r--package/libX11/Makefile6
-rw-r--r--package/libX11/patches/patch-ltmain_sh11
-rw-r--r--package/libXau/Makefile7
-rw-r--r--package/libXau/patches/patch-ltmain_sh11
-rw-r--r--package/libXaw/patches/patch-ltmain_sh11
-rw-r--r--package/libXcomposite/Makefile6
-rw-r--r--package/libXcursor/patches/patch-ltmain_sh11
-rw-r--r--package/libXdmcp/Makefile7
-rw-r--r--package/libXdmcp/patches/patch-ltmain_sh11
-rw-r--r--package/libXext/Makefile6
-rw-r--r--package/libXext/patches/patch-ltmain_sh11
-rw-r--r--package/libXfont/patches/patch-ltmain_sh11
-rw-r--r--package/libXft/patches/patch-ltmain_sh11
-rw-r--r--package/libXi/patches/patch-ltmain_sh11
-rw-r--r--package/libXmu/patches/patch-ltmain_sh11
-rw-r--r--package/libXpm/patches/patch-ltmain_sh11
-rw-r--r--package/libXt/patches/patch-ltmain_sh11
-rw-r--r--package/libXv/patches/patch-ltmain_sh11
-rw-r--r--package/libao/patches/patch-ltmain_sh11
-rw-r--r--package/libart/patches/100-cross_compile_fix.patch6
-rw-r--r--package/libart/patches/patch-ltmain_sh11
-rw-r--r--package/libaudiofile/Makefile12
-rw-r--r--package/libaudiofile/patches/001-audiofile-config-libdirs.patch6
-rw-r--r--package/libaudiofile/patches/patch-ltmain_sh27
-rw-r--r--package/libdaemon/patches/patch-ltmain_sh11
-rw-r--r--package/libdb/patches/patch-dist_ltmain_sh11
-rw-r--r--package/libdnet/patches/libdnet-1.10-dnet_config.patch6
-rw-r--r--package/libdnet/patches/patch-config_ltmain_sh11
-rw-r--r--package/libdrm/patches/patch-ltmain_sh11
-rw-r--r--package/libelf/Makefile11
-rw-r--r--package/libelf/patches/patch-lib_Makefile_in11
-rw-r--r--package/libevent/Makefile6
-rw-r--r--package/libevent/patches/patch-ltmain_sh11
-rw-r--r--package/libffi/patches/patch-ltmain_sh11
-rw-r--r--package/libfontenc/patches/patch-ltmain_sh11
-rw-r--r--package/libgcrypt/patches/patch-ltmain_sh11
-rw-r--r--package/libgssglue/patches/patch-ltmain_sh11
-rw-r--r--package/libiconv/patches/patch-build-aux_ltmain_sh11
-rw-r--r--package/libiconv/patches/patch-libcharset_build-aux_ltmain_sh11
-rw-r--r--package/liblzo/patches/patch-autoconf_ltmain_sh11
-rw-r--r--package/libmad/Makefile6
-rw-r--r--package/libmad/patches/patch-ltmain_sh11
-rw-r--r--package/libmms/patches/patch-ltmain_sh11
-rw-r--r--package/libmpdclient/patches/patch-build_ltmain_sh11
-rw-r--r--package/libnet/patches/patch-ltmain_sh11
-rw-r--r--package/libnetfilter_conntrack/patches/patch-ltmain_sh11
-rw-r--r--package/libnetfilter_log/patches/patch-ltmain_sh11
-rw-r--r--package/libnetfilter_queue/patches/patch-ltmain_sh11
-rw-r--r--package/libnfnetlink/patches/patch-ltmain_sh11
-rw-r--r--package/libnfsidmap/patches/patch-ltmain_sh11
-rw-r--r--package/libnl/Makefile23
-rw-r--r--package/libnl/patches/patch-include_netlink-local_h20
-rw-r--r--package/libnl/patches/patch-include_netlink-types_h19
-rw-r--r--package/libnl/patches/patch-include_netlink_genl_mngt_h19
-rw-r--r--package/libnl/patches/patch-lib_object_c12
-rw-r--r--package/libnl/patches/patch-ltmain_sh11
-rw-r--r--package/libnl/patches/patch-src_nl-list-caches_c11
-rw-r--r--package/libnl/patches/patch-src_utils_c11
-rw-r--r--package/libnl/patches/patch-src_utils_h11
-rw-r--r--package/libogg/Makefile6
-rw-r--r--package/libol/patches/patch-ltmain_sh11
-rw-r--r--package/libosip2/patches/patch-scripts_ltmain_sh11
-rw-r--r--package/libowfat/Makefile3
-rw-r--r--package/libowfat/patches/patch-GNUmakefile22
-rw-r--r--package/libowfat/patches/patch-Makefile11
-rw-r--r--package/libp11/Makefile6
-rw-r--r--package/libp11/patches/patch-ltmain_sh11
-rw-r--r--package/libpcap/Makefile4
-rw-r--r--package/libpcap/patches/patch-pcap-config_in27
-rw-r--r--package/libpciaccess/patches/patch-ltmain_sh11
-rw-r--r--package/libpng/Makefile6
-rw-r--r--package/libpng/patches/patch-ltmain_sh11
-rw-r--r--package/librpcsecgss/patches/patch-ltmain_sh11
-rw-r--r--package/libshout/patches/patch-ltmain_sh11
-rw-r--r--package/libstdcxx/Makefile6
-rw-r--r--package/libtasn1/patches/patch-build-aux_ltmain_sh11
-rw-r--r--package/libtiff/Makefile10
-rw-r--r--package/libtiff/patches/patch-Makefile_in11
-rw-r--r--package/libtiff/patches/patch-config_ltmain_sh11
-rw-r--r--package/libtirpc/patches/patch-ltmain_sh11
-rw-r--r--package/libtool/Makefile7
-rw-r--r--package/libtool/patches/patch-libltdl_config_ltmain_sh31
-rw-r--r--package/libupnp/patches/autotool.patch2
-rw-r--r--package/libusb-compat/Makefile6
-rw-r--r--package/libusb/Makefile6
-rw-r--r--package/libusb/patches/patch-ltmain_sh11
-rw-r--r--package/libvirt/Makefile5
-rw-r--r--package/libvirt/patches/patch-build-aux_ltmain_sh11
-rw-r--r--package/libvirt/patches/patch-configure38
-rw-r--r--package/libvirt/patches/patch-libvirt_pc9
-rw-r--r--package/libvirt/patches/patch-src_storage_storage_backend_c8
-rw-r--r--package/libvorbis/Makefile8
-rw-r--r--package/libvorbis/patches/patch-ltmain_sh11
-rw-r--r--package/libvorbisidec/patches/autotool.patch2
-rw-r--r--package/libxkbfile/patches/patch-ltmain_sh11
-rw-r--r--package/libxml2/patches/patch-ltmain_sh11
-rw-r--r--package/libxslt/patches/patch-libexslt_Makefile_in11
-rw-r--r--package/libxslt/patches/patch-ltmain_sh11
-rw-r--r--package/libxslt/patches/patch-xsltproc_Makefile_in11
-rw-r--r--package/lighttpd/patches/patch-ltmain_sh11
-rw-r--r--package/links/Makefile2
-rw-r--r--package/linux-atm/patches/patch-ltmain_sh11
-rw-r--r--package/logrotate/Makefile1
-rw-r--r--package/logrotate/patches/patch-Makefile32
-rw-r--r--package/lsof/Makefile9
-rw-r--r--package/lsof/patches/patch-Configure30
-rw-r--r--package/lsof/patches/patch-lsof_4_84_src_Configure17
-rw-r--r--package/lsof/patches/patch-lsof_4_84_src_dialects_linux_dlsof_h (renamed from package/lsof/patches/patch-dialects_linux_dlsof_h)4
-rw-r--r--package/lsof/patches/patch-lsof_4_84_src_dialects_linux_machine_h (renamed from package/lsof/patches/patch-dialects_linux_machine_h)4
-rw-r--r--package/lsof/patches/patch-lsof_4_84_src_lib_Makefile_skel11
-rw-r--r--package/lvm/Makefile13
-rw-r--r--package/lvm/patches/patch-Makefile_in20
-rw-r--r--package/lvm/patches/patch-make_tmpl_in13
-rw-r--r--package/microperl/patches/patch-Makefile_micro11
-rw-r--r--package/miredo/patches/patch-admin_ltmain_sh11
-rw-r--r--package/mksh/Makefile2
-rw-r--r--package/moc/patches/patch-ltmain_sh11
-rw-r--r--package/mpd/Makefile6
-rw-r--r--package/mpfr/patches/patch-ltmain_sh11
-rw-r--r--package/mpg123/patches/patch-build_ltmain_sh11
-rw-r--r--package/mplayer/Makefile6
-rw-r--r--package/mplayer/patches/patch-configure11
-rw-r--r--package/mrd6/Makefile10
-rw-r--r--package/mysql/patches/patch-configure24
-rw-r--r--package/mysql/patches/patch-include_config_h_in4
-rw-r--r--package/mysql/patches/patch-ltmain_sh11
-rw-r--r--package/nano/Makefile2
-rw-r--r--package/ncurses/Makefile15
-rw-r--r--package/neon/patches/patch-ltmain_sh11
-rw-r--r--package/net-snmp/Makefile22
-rw-r--r--package/net-snmp/patches/patch-agent_mibgroup_mibII_tcpTable_c48
-rw-r--r--package/nfs-utils/Makefile2
-rw-r--r--package/nmap/Makefile8
-rw-r--r--package/nut/Makefile35
-rw-r--r--package/nut/patches/patch-ltmain_sh11
-rw-r--r--package/obexftp/patches/patch-ltmain_sh11
-rw-r--r--package/opencdk/patches/patch-build-aux_ltmain_sh11
-rw-r--r--package/opencdk/patches/patch-configure6
-rw-r--r--package/opencdk/patches/patch-ltmain_sh11
-rw-r--r--package/openct/Makefile6
-rw-r--r--package/openct/patches/patch-ltmain_sh11
-rw-r--r--package/openldap/Makefile6
-rw-r--r--package/openldap/patches/patch-build_ltmain_sh11
-rw-r--r--package/openobex/patches/patch-ltmain_sh11
-rw-r--r--package/opensc/Makefile6
-rw-r--r--package/opensc/patches/patch-ltmain_sh39
-rw-r--r--package/opensc/patches/patch-src_Makefile_in6
-rw-r--r--package/openssh/Makefile17
-rw-r--r--package/openssl-pkcs11/patches/patch-ltmain_sh11
-rw-r--r--package/openssl/Makefile15
-rw-r--r--package/openvpn/Makefile8
-rw-r--r--package/oprofile/patches/patch-doc_oprofile_126
-rw-r--r--package/oprofile/patches/patch-ltmain_sh11
-rw-r--r--package/osiris/patches/patch-configure89
-rw-r--r--package/osiris/patches/patch-src_db-4_2_52_dist_configure12
-rw-r--r--package/osiris/patches/patch-src_db-4_2_52_dist_ltmain_sh11
-rw-r--r--package/owfs/patches/autotool.patch2
-rw-r--r--package/pango/patches/patch-ltmain_sh11
-rw-r--r--package/pango/patches/patch-tests_runtests_sh8
-rw-r--r--package/parted/patches/patch-build-aux_ltmain_sh11
-rw-r--r--package/pciutils/Makefile7
-rw-r--r--package/pcre/patches/patch-ltmain_sh11
-rw-r--r--package/pcsc-lite/Makefile8
-rw-r--r--package/pcsc-lite/patches/patch-ltmain_sh11
-rw-r--r--package/pcsc-lite/patches/patch-src_Makefile_in20
-rw-r--r--package/pdnsd/Makefile2
-rw-r--r--package/pipacs/Makefile4
-rw-r--r--package/pipacs/src/Makefile8
-rw-r--r--package/pixman/patches/patch-ltmain_sh11
-rw-r--r--package/ppp/Makefile34
-rw-r--r--package/ppp/patches/patch-chat_Makefile_linux26
-rw-r--r--package/ppp/patches/patch-include_linux_ppp-comp_h63
-rw-r--r--package/ppp/patches/patch-include_net_ppp-comp_h36
-rw-r--r--package/ppp/patches/patch-pppd_Makefile_linux70
-rw-r--r--package/ppp/patches/patch-pppd_chap_ms_c6
-rw-r--r--package/ppp/patches/patch-pppd_main_c14
-rw-r--r--package/ppp/patches/patch-pppd_plugins_Makefile_linux29
-rw-r--r--package/ppp/patches/patch-pppd_plugins_pppoatm_Makefile_linux36
-rw-r--r--package/ppp/patches/patch-pppd_plugins_pppol2tp_Makefile_linux41
-rw-r--r--package/ppp/patches/patch-pppd_plugins_radius_Makefile_linux40
-rw-r--r--package/ppp/patches/patch-pppd_plugins_rp-pppoe_Makefile_linux80
-rw-r--r--package/ppp/patches/patch-pppd_pppd_810
-rw-r--r--package/ppp/patches/patch-pppdump_Makefile_linux32
-rw-r--r--package/ppp/patches/patch-pppstats_Makefile_linux45
-rw-r--r--package/ppp/src/makedefs.linux14
-rw-r--r--package/pptp/Makefile3
-rw-r--r--package/pptp/patches/patch-Makefile22
-rw-r--r--package/procmail/src/Makefile.new4
-rw-r--r--package/proftpd/Makefile6
-rw-r--r--package/proftpd/files/ftpusers37
-rw-r--r--package/proftpd/files/proftpd.conffiles1
-rw-r--r--package/python2/Makefile16
-rw-r--r--package/python2/files/python-config.in4
-rw-r--r--package/python2/patches/patch-Misc_python_pc11
-rw-r--r--package/python2/patches/patch-pyconfig_h521
-rw-r--r--package/qemu/Makefile9
-rw-r--r--package/qemu/patches/patch-configure11
-rw-r--r--package/qemu/patches/patch-hw_vhost_c10
-rw-r--r--package/qemu/patches/patch-hw_vhost_net_c10
-rw-r--r--package/qingy/patches/patch-ltmain_sh11
-rw-r--r--package/quagga/Makefile2
-rw-r--r--package/quagga/patches/patch-ltmain_sh11
-rw-r--r--package/quagga/patches/patch-redhat_quagga_spec11
-rw-r--r--package/quagga/patches/patch-vtysh_extract_pl8
-rw-r--r--package/rp-pppoe/patches/patch-src_Makefile_in32
-rw-r--r--package/rpcbind/Makefile2
-rw-r--r--package/rpcbind/files/rpcbind.init4
-rw-r--r--package/rpcbind/patches/patch-ltmain_sh30
-rw-r--r--package/rrdtool/patches/patch-ltmain_sh11
-rw-r--r--package/rtorrent/patches/patch-ltmain_sh30
-rw-r--r--package/rtorrent/patches/patch-src_command_download_cc6
-rw-r--r--package/rtorrent/patches/patch-src_command_events_cc6
-rw-r--r--package/rtorrent/patches/patch-src_command_network_cc6
-rw-r--r--package/rtorrent/patches/patch-src_rpc_parse_cc8
-rw-r--r--package/rtorrent/patches/patch-src_rpc_scgi_task_cc6
-rw-r--r--package/rtorrent/patches/patch-src_utils_lockfile_cc6
-rw-r--r--package/rtsp/Makefile12
-rw-r--r--package/ruby/Makefile3
-rw-r--r--package/ruby/patches/patch-Makefile_in11
-rw-r--r--package/sane-backends/patches/patch-ltmain_sh11
-rw-r--r--package/sangam-atm/Makefile2
-rw-r--r--package/scanlogd/Makefile5
-rw-r--r--package/scanlogd/patches/patch-Makefile14
-rw-r--r--package/scanlogd/patches/patch-params_h20
-rw-r--r--package/sdl-image/Makefile6
-rw-r--r--package/sdl-image/patches/patch-ltmain_sh11
-rw-r--r--package/sdl/Makefile19
-rw-r--r--package/sdl/patches/patch-build-scripts_ltmain_sh11
-rw-r--r--package/sdl/patches/patch-include_SDL_config_h311
-rw-r--r--package/sdl/patches/patch-sdl-config_in16
-rw-r--r--package/sdl/patches/patch-sdl_pc_in10
-rw-r--r--package/siproxd/patches/patch-libltdl_ltmain_sh11
-rw-r--r--package/siproxd/patches/patch-scripts_ltmain_sh11
-rw-r--r--package/snort/patches/patch-ltmain_sh11
-rw-r--r--package/speex/patches/patch-ltmain_sh11
-rw-r--r--package/sqlite/patches/patch-ltmain_sh11
-rw-r--r--package/ssmtp/patches/901-strftime_space_padding.patch12
-rw-r--r--package/ssmtp/patches/patch-Makefile_in11
-rw-r--r--package/ssmtp/patches/patch-arpadate_c11
-rw-r--r--package/ssmtp/patches/patch-configure_in13
-rw-r--r--package/ssmtp/patches/patch-ssmtp_c (renamed from package/ssmtp/patches/500-debian-subset-2.61-2.patch)62
-rw-r--r--package/ssmtp/patches/patch-ssmtp_conf11
-rw-r--r--package/strongswan/Makefile2
-rw-r--r--package/strongswan/patches/patch-ltmain_sh11
-rw-r--r--package/subversion/patches/patch-build_ltmain_sh39
-rw-r--r--package/sysfsutils/patches/patch-ltmain_sh11
-rw-r--r--package/syslinux/Makefile2
-rw-r--r--package/tcl/Makefile8
-rw-r--r--package/tcl/patches/patch-unix_configure33
-rw-r--r--package/tcl/patches/patch-unix_tclUnixTime_c39
-rw-r--r--package/tcp_wrappers/patches/patch-Makefile16
-rw-r--r--package/tcp_wrappers/patches/patch-cflags4
-rw-r--r--package/tcpdump/Makefile9
-rw-r--r--package/traceroute/Makefile2
-rw-r--r--package/traceroute/patches/patch-default_rules11
-rw-r--r--package/tslib/Makefile1
-rw-r--r--package/tslib/patches/patch-ltmain_sh8416
-rw-r--r--package/uclibc++/Config.in.manual4
-rw-r--r--package/uclibc++/Makefile1
-rw-r--r--package/uclibc/Makefile9
-rw-r--r--package/ulogd/Makefile9
-rw-r--r--package/ulogd/patches/patch-ltmain_sh11
-rw-r--r--package/updatedd/patches/patch-ltmain_sh11
-rw-r--r--package/util-linux-ng/patches/patch-config_ltmain_sh11
-rw-r--r--package/valgrind/patches/patch-auxprogs_valgrind-listener_c29
-rw-r--r--package/valgrind/patches/patch-coregrind_launcher-linux_c29
-rw-r--r--package/vrrpd/patches/patch-Makefile17
-rw-r--r--package/watchdog/Makefile2
-rw-r--r--package/weechat/patches/patch-ltmain_sh11
-rw-r--r--package/wget/Makefile3
-rw-r--r--package/wget/files/wget.conffiles1
-rw-r--r--package/wifidog/patches/patch-config_ltmain_sh11
-rw-r--r--package/wireless-tools/patches/patch-Makefile11
-rw-r--r--package/wpa_supplicant/Makefile21
-rw-r--r--package/wpa_supplicant/files/config1
-rw-r--r--package/wput/patches/patch-Makefile21
-rw-r--r--package/wput/patches/patch-config_status160
-rw-r--r--package/wput/patches/patch-po_Makefile50
-rw-r--r--package/wput/patches/patch-po_Makefile_in50
-rw-r--r--package/wput/patches/patch-src_Makefile19
-rw-r--r--package/wput/patches/patch-src_Makefile_in19
-rw-r--r--package/wput/patches/patch-src_config_h27
-rw-r--r--package/xf86-input-evtouch/patches/patch-ltmain_sh11
-rw-r--r--package/xf86-input-keyboard/patches/patch-ltmain_sh11
-rw-r--r--package/xf86-input-mouse/patches/patch-ltmain_sh11
-rw-r--r--package/xf86-video-cirrus/patches/patch-ltmain_sh11
-rw-r--r--package/xf86-video-geode/patches/patch-ltmain_sh11
-rw-r--r--package/xf86-video-intel/patches/patch-ltmain_sh11
-rw-r--r--package/xf86-video-siliconmotion/patches/patch-ltmain_sh11
-rw-r--r--package/xorg-server/Makefile8
-rw-r--r--package/xorg-server/patches/patch-ltmain_sh11
-rw-r--r--package/xz/patches/patch-build-aux_ltmain_sh11
-rw-r--r--package/zlib/Makefile6
-rw-r--r--rules.mk6
-rwxr-xr-xscripts/reloc.sh16
-rw-r--r--scripts/scan-pkgs.sh12
-rw-r--r--target/Makefile9
-rw-r--r--target/arm/Makefile5
-rw-r--r--target/config/Config.in11
-rw-r--r--target/config/Config.in.runtime76
-rw-r--r--target/cris/Makefile7
-rw-r--r--target/linux/config/Config.in.block4
-rw-r--r--target/linux/config/Config.in.fs3
-rw-r--r--target/linux/config/Config.in.input7
-rw-r--r--target/linux/config/Config.in.leds28
-rw-r--r--target/linux/config/Config.in.netdevice9
-rw-r--r--target/linux/config/Config.in.network8
-rw-r--r--target/linux/patches/2.6.36/aufs2.patch33532
-rw-r--r--target/linux/patches/2.6.36/brcm.patch87
-rw-r--r--target/linux/patches/2.6.36/yaffs2.patch103
-rw-r--r--target/linux/patches/2.6.37/ar7.patch90
-rw-r--r--target/linux/patches/2.6.37/ar71xx.patch18667
-rw-r--r--target/linux/patches/2.6.37/aufs2.patch28523
-rw-r--r--target/linux/patches/2.6.37/brcm.patch169
-rw-r--r--target/linux/patches/2.6.37/bsd-compatibility.patch2512
-rw-r--r--target/linux/patches/2.6.37/cc-abstract.patch14
-rw-r--r--target/linux/patches/2.6.37/cris.patch5736
-rw-r--r--target/linux/patches/2.6.37/cygwin-compat.patch14
-rw-r--r--target/linux/patches/2.6.37/drm-kconfig.patch36
-rw-r--r--target/linux/patches/2.6.37/exmap.patch11
-rw-r--r--target/linux/patches/2.6.37/foxg20.patch522
-rw-r--r--target/linux/patches/2.6.37/freebsd-compat.patch11
-rw-r--r--target/linux/patches/2.6.37/gemalto.patch11
-rw-r--r--target/linux/patches/2.6.37/lemote.patch4271
-rw-r--r--target/linux/patches/2.6.37/mtd-root.patch64
-rw-r--r--target/linux/patches/2.6.37/ocf-20100325.patch87545
-rw-r--r--target/linux/patches/2.6.37/rb532.patch18
-rw-r--r--target/linux/patches/2.6.37/startup.patch20
-rw-r--r--target/linux/patches/2.6.37/uuid.patch261
-rw-r--r--target/linux/patches/2.6.37/yaffs2.patch16912
-rw-r--r--target/mips/kernel.config18
-rw-r--r--target/mips/patches/io_map_base.patch52
-rw-r--r--target/mips64/Makefile9
-rw-r--r--target/mips64/kernel.config548
-rw-r--r--target/mips64/patches/io_map_base.patch52
-rw-r--r--target/mips64/sys-available/qemu-mips6414
-rw-r--r--target/mips64/sys-available/toolchain-mips641
-rw-r--r--target/mips64el/Makefile2
-rw-r--r--target/mips64el/kernel.config611
-rw-r--r--target/mips64el/sys-available/lemote-yeelong1
-rw-r--r--target/mips64el/sys-available/qemu-mips64el14
-rw-r--r--target/mips64el/sys-available/toolchain-mips64el1
-rw-r--r--target/mipsel/Makefile29
-rw-r--r--target/mipsel/kernel.config5
-rw-r--r--target/mipsel/sys-available/linksys-wrt54g1
-rw-r--r--target/tools/squashfs/Makefile4
-rw-r--r--target/tools/squashfs/patches/honour-cflags.patch11
-rw-r--r--target/tools/squashfs/patches/squashfs-bsd.patch173
-rw-r--r--toolchain/Config.in45
-rw-r--r--toolchain/Makefile13
-rw-r--r--toolchain/binutils/Makefile10
-rw-r--r--toolchain/eglibc/Makefile21
-rw-r--r--toolchain/eglibc/Makefile.inc2
-rw-r--r--toolchain/eglibc/patches/eglibc-cross.patch2
-rw-r--r--toolchain/gcc/Makefile49
-rw-r--r--toolchain/gcc/patches/cflags.patch253
-rw-r--r--toolchain/gdb/Makefile1
-rw-r--r--toolchain/glibc/Makefile13
-rw-r--r--toolchain/glibc/Makefile.inc3
-rw-r--r--toolchain/glibc/patches/i686_define_bug.patch38
-rw-r--r--toolchain/glibc/patches/tz.patch135
-rw-r--r--toolchain/kernel-headers/Makefile5
-rw-r--r--toolchain/kernel-headers/patches/2.6.36/aufs2.patch240
-rw-r--r--toolchain/kernel-headers/patches/2.6.37/aufs2.patch240
-rw-r--r--toolchain/kernel-headers/patches/2.6.37/cleankernel.patch11
-rw-r--r--toolchain/kernel-headers/patches/2.6.37/etrax-header.patch75
-rw-r--r--toolchain/kernel-headers/patches/2.6.37/linux-gcc-check.patch18
-rw-r--r--toolchain/kernel-headers/patches/2.6.37/microperl.patch24
-rw-r--r--toolchain/libelf/Makefile31
-rw-r--r--toolchain/libelf/Makefile.inc8
-rw-r--r--toolchain/uClibc/Makefile19
-rw-r--r--tools/adk/Makefile18
-rw-r--r--tools/adk/pkgmaker.c111
-rw-r--r--tools/cpio/Makefile6
-rw-r--r--tools/mkcrypt/Makefile6
597 files changed, 227881 insertions, 8120 deletions
diff --git a/.gitignore b/.gitignore
index da11d7d98..4f602504a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,7 +33,7 @@
/config/*.o
/config/lxdialog/*.o
/make.log
-/dl/
+/dl
/package/Config.in.auto*
/package/pkgconfigs.d/
/package/*/Config.in
diff --git a/Config.in b/Config.in
index 9a779028b..3fdb5ee96 100644
--- a/Config.in
+++ b/Config.in
@@ -46,13 +46,37 @@ endmenu
menu "Package selection"
depends on !ADK_CHOOSE_TARGET_ARCH && !ADK_CHOOSE_TARGET_SYSTEM
+
+config ADK_INSTALL_PACKAGE_INIT_SCRIPTS
+ boolean "ship custom init-scripts along with packages"
+ default y
+ help
+ Turning this option to false will prevent the ADK from
+ installing init-scripts (i.e. files in /etc/init.d) for
+ certain daemons and daemon-like applications.
+
+ Note that without further customisation, turning this option
+ off will almost certainly render the resulting system unusable.
+
+config ADK_INSTALL_PACKAGE_NETWORK_SCRIPTS
+ boolean "ship custom network-scripts along with packages"
+ default y
+ help
+ Turning this option to false will prevent the ADK from
+ installing network-scripts (i.e. files in /etc/network/) for
+ packages providing any.
+
+ Note that without further customisation, turning this option
+ off will almost certainly render the resulting system unusable.
+
source "package/Config.in.auto.global"
source "package/Config.in.auto"
endmenu
menu "Kernel configuration"
-depends on !ADK_TOOLCHAIN_ONLY && !ADK_CHOOSE_TARGET_ARCH && !ADK_CHOOSE_TARGET_SYSTEM
+depends on !ADK_TOOLCHAIN_ONLY && !ADK_CHOOSE_TARGET_ARCH && !ADK_CHOOSE_TARGET_SYSTEM && ADK_TARGET_KERNEL_CUSTOMISING
source "target/linux/Config.in"
endmenu
source "target/config/Config.in.adk"
+source "toolchain/Config.in"
diff --git a/Makefile b/Makefile
index 9c08dc134..04f8d5651 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
_UNLIMIT= __limit=$$(ulimit -dH 2>/dev/null); \
test -n "$$__limit" && ulimit -dS $$__limit;
-all: .prereq_done
+all: checkreloc .prereq_done
@${_UNLIMIT} ${GMAKE_INV} all
v: .prereq_done
@@ -191,20 +191,9 @@ NO_ERROR=0
echo "GMAKE:=$$(which gmake)" >>prereq.mk ;\
fi
@echo "GNU_HOST_NAME:=$$(${CC} -dumpmachine)" >>prereq.mk
- @echo "HOST_ARCH:=$$(${CC} -dumpmachine | sed -e s'/-.*//' \
- -e 's/sparc.*/sparc/' \
- -e 's/arm.*/arm/g' \
- -e 's/m68k.*/m68k/' \
- -e 's/ppc/powerpc/g' \
- -e 's/v850.*/v850/g' \
- -e 's/sh[234]/sh/' \
- -e 's/mips-.*/mips/' \
- -e 's/mipsel-.*/mipsel/' \
- -e 's/cris.*/cris/' \
- -e 's/i[3-9]86/i386/' \
- )" >>prereq.mk
@echo "HOSTARCH:=$$(${CC} -dumpmachine | sed -e s'/-.*//' \
-e 's/sparc.*/sparc/' \
+ -e 's/armeb.*/armeb/g' \
-e 's/arm.*/arm/g' \
-e 's/m68k.*/m68k/' \
-e 's/v850.*/v850/g' \
@@ -215,11 +204,7 @@ NO_ERROR=0
-e 's/i[3-9]86/x86/' \
)" >>prereq.mk
@echo 'HOSTCC:=${CC}' >>prereq.mk
- @echo 'HOSTCFLAGS:=-O2' >>prereq.mk
@echo 'HOSTCXX:=${CXX}' >>prereq.mk
- @echo 'HOSTCXXFLAGS:=-O2' >>prereq.mk
- @echo "HOST_LIBIDL_CONFIG:=$$(which libIDL-config-2 2>/dev/null)" >>prereq.mk
- @echo "PKG_HOSTLIB_DIR:=$$(pkg-config --variable pc_path pkg-config 2>/dev/null)" >>prereq.mk
@echo 'LANGUAGE:=C' >>prereq.mk
@echo 'LC_ALL:=C' >>prereq.mk
@echo 'MAKE:=$${GMAKE}' >>prereq.mk
@@ -228,6 +213,9 @@ NO_ERROR=0
@echo "_PATH:=$$PATH" >>prereq.mk
@echo "PATH:=\$${TOPDIR}/scripts:/usr/sbin:$$PATH" >>prereq.mk
@echo "SHELL:=$$(which bash)" >>prereq.mk
+ @echo "HOST_LIBIDL_CONFIG:=$$(which libIDL-config-2 2>/dev/null)" >>prereq.mk
+ @echo "PKG_HOSTLIB_DIR=$$(eval pkg-config --variable pc_path pkg-config 2>/dev/null)" >/dev/null
+ @echo "PKG_HOSTLIB_DIR:=$${PKG_HOSTLIB_DIR:-/usr/lib/pkgconfig}" >>prereq.mk
@env NO_ERROR=${NO_ERROR} BASH="$$(which bash)" \
CC='${CC}' CPPFLAGS='${CPPFLAGS}' \
bash scripts/scan-tools.sh
@@ -237,4 +225,7 @@ NO_ERROR=0
@touch .adkinit
@touch $@
-.PHONY: prereq prereq-noerror
+checkreloc:
+ @bash scripts/reloc.sh
+
+.PHONY: prereq prereq-noerror checkreloc
diff --git a/README b/README
index aff899665..ec27db1ab 100644
--- a/README
+++ b/README
@@ -26,11 +26,14 @@ Before you can start you need to install some tools:
There is a check for the required versions of these tools in advance, though.
(to re-issue the checks, use "make prereq").
-Please use "make menuconfig" to choose your embedded system and configure
-like you want to.
+Please use "make menuconfig" to choose your target architecture and
+embedded system and configure like you want to.
Simply running 'make' will build the firmware for your embedded system. The
buildsystem will download all sources, build the toolchain, the kernel and all
applications.
+To switch to another target configuration, simply run "make switch". This will
+backup your existing configuration and will start with an empty one.
+
Sunshine!
diff --git a/TODO b/TODO
index 6e95a3ff7..2b0525cfb 100644
--- a/TODO
+++ b/TODO
@@ -1,13 +1,25 @@
+- man pages in ipkg/tgz packages (automatic)
+- automate /etc handling via conffiles
+- ccache support for speedup
+- distcc evaluation
+- GCC SSP evaluation
+- LTO GCC evaluation
+- finish qemu package
+- fix autoreconf usage in opensc
- openssl ocf support check
+- locales support
- new package minidlna
- wget/curl/ftp download support
- fix heimdal package
-- check all patches for CFLAGS compliance
+- fix or remove bazaar package
+- check all patches for CFLAGS compliance, fhonour patch from FreeWRT
+- rpath cleanup
- busybox update and SuSv3 removal
- check rtc support on foxg20
-- relocatable gcc (adk)
- adkinstall with NTP and hwclock support
- PKG_CONFLICTS for python/python2, is this possible with Kconfig?
- mirror only option, for no internet access
-- add support for brcm 2.6 (lzma/flash/wireless support)
+- add and test brcm 2.6 wireless support
- help text for config/ needs adoption
+- diet libc / klibc / newlib support
+- pcc support? clang+llvm
diff --git a/mk/build.mk b/mk/build.mk
index f8143311c..156555af3 100644
--- a/mk/build.mk
+++ b/mk/build.mk
@@ -14,17 +14,11 @@ DEFCONFIG= ADK_DEBUG=n \
ADK_STATIC=n \
ADK_MAKE_PARALLEL=y \
ADK_MAKE_JOBS=4 \
- ADK_PACKAGE_BZR=n \
ADK_PACKAGE_GRUB=n \
- ADK_PACKAGE_AUFS2_UTIL=n \
ADK_PACKAGE_BASE_FILES=y \
- ADK_PACKAGE_MGETTY=n \
- ADK_COMPILE_HEIMDAL=n \
- ADK_PACKAGE_HEIMDAL_PKINIT=n \
- ADK_PACKAGE_HEIMDAL_SERVER=n \
- ADK_PACKAGE_LIBHEIMDAL=n \
- ADK_PACKAGE_LIBHEIMDAL_CLIENT=n \
ADK_PACKAGE_PYTHON=n \
+ ADK_TOOLCHAIN_GCC_USE_SSP=n \
+ ADK_TOOLCHAIN_GCC_USE_LTO=n \
BUSYBOX_BBCONFIG=n \
BUSYBOX_SELINUX=n \
BUSYBOX_INSTALL_NO_USR=n \
@@ -113,7 +107,9 @@ ${TOPDIR}/package/Depends.mk: ${TOPDIR}/.config $(wildcard ${TOPDIR}/package/*/M
.NOTPARALLEL:
.PHONY: all world clean cleantarget cleandir distclean image_clean
-world: $(DISTDIR) $(BUILD_DIR) $(TARGET_DIR) $(PACKAGE_DIR)
+world:
+ mkdir -p $(DISTDIR) $(BUILD_DIR) $(TARGET_DIR) $(PACKAGE_DIR)/.stamps \
+ $(TOOLS_DIR) $(TOOLS_BUILD_DIR) $(TOOLCHAIN_BUILD_DIR)
${BASH} ${TOPDIR}/scripts/scan-pkgs.sh
${BASH} ${TOPDIR}/scripts/update-sys
${BASH} ${TOPDIR}/scripts/update-pkg
@@ -133,21 +129,9 @@ ifeq ($(ADK_TARGET_PACKAGE_IPKG),y)
${BASH} ${TOPDIR}/scripts/ipkg-make-index.sh . >Packages
endif
-$(DISTDIR):
- mkdir -p $(DISTDIR)
-
-$(BUILD_DIR):
- mkdir -p $(BUILD_DIR)
-
-$(TARGET_DIR):
- mkdir -p $(TARGET_DIR)
-
-$(PACKAGE_DIR):
- mkdir -p ${PACKAGE_DIR}/.stamps
-
${STAGING_TARGET_DIR} ${STAGING_TARGET_DIR}/etc ${STAGING_HOST_DIR}:
- mkdir -p ${STAGING_TARGET_DIR}/{bin,etc,lib,usr/include} \
- ${STAGING_HOST_DIR}/{bin,lib}
+ mkdir -p ${STAGING_TARGET_DIR}/{bin,etc,lib,usr/include,usr/lib} \
+ ${STAGING_HOST_DIR}/{bin,lib,usr/bin,usr/lib}
${STAGING_TARGET_DIR}/etc/ipkg.conf: ${STAGING_TARGET_DIR}/etc
ifeq ($(ADK_TARGET_PACKAGE_IPKG),y)
@@ -191,9 +175,9 @@ switch:
fi
kernelconfig:
- cp $(TOPDIR)/target/$(ARCH)/kernel.config $(BUILD_DIR)/linux/.config
- $(MAKE) -C $(BUILD_DIR)/linux/ ARCH=$(ARCH) menuconfig
- cp $(BUILD_DIR)/linux/.config $(TOPDIR)/target/$(ARCH)/kernel.config
+ cp $(TOPDIR)/target/$(ADK_TARGET_ARCH)/kernel.config $(BUILD_DIR)/linux/.config
+ ${KERNEL_MAKE_ENV} ${MAKE} ${KERNEL_MAKE_OPTS} -C $(BUILD_DIR)/linux menuconfig
+ cp $(BUILD_DIR)/linux/.config $(TOPDIR)/target/$(ADK_TARGET_ARCH)/kernel.config
# create a new package from package/.template
newpackage:
@@ -211,7 +195,7 @@ root_clean:
mkdir -p $(TARGET_DIR)
# Do a per-package clean here, too. This way stale headers and
-# libraries from cross_*/target/ get wiped away, which keeps
+# libraries from target_*/ get wiped away, which keeps
# future package build's configure scripts from returning false
# dependencies information.
@@ -221,7 +205,7 @@ clean:
for d in ${STAGING_PKG_DIR}; do \
for f in $$(ls $$d/[a-z]* 2>/dev/null); do \
while read file ; do \
- rm $$d/target/$$file 2>/dev/null; \
+ rm ${STAGING_TARGET_DIR}/$$file 2>/dev/null;\
done < $$f ; \
rm $$f ; \
done \
@@ -563,12 +547,11 @@ bulkallmod:
done <${TOPDIR}/target/arch.lst ;\
done
-${TOPDIR}/bin/tools/pkgmaker:
+${TOPDIR}/bin/tools/pkgmaker: tools/adk/pkgmaker.c tools/adk/sortfile.c tools/adk/strmap.c
@mkdir -p $(TOPDIR)/bin/tools
@$(HOSTCC) -Wall -g -o $@ tools/adk/pkgmaker.c tools/adk/sortfile.c tools/adk/strmap.c
${TOPDIR}/bin/tools/pkgrebuild:
- @mkdir -p $(TOPDIR)/bin/tools
@$(HOSTCC) -Wall -g -o $@ tools/adk/pkgrebuild.c tools/adk/strmap.c
package/Config.in.auto menu .menu: $(wildcard ${TOPDIR}/package/*/Makefile) ${TOPDIR}/bin/tools/pkgmaker ${TOPDIR}/bin/tools/pkgrebuild
@@ -576,10 +559,7 @@ package/Config.in.auto menu .menu: $(wildcard ${TOPDIR}/package/*/Makefile) ${TO
@$(TOPDIR)/bin/tools/pkgmaker
@:>.menu
-$(TOPDIR)/bin/tools:
- @mkdir -p $(TOPDIR)/bin/tools
-
-${TOPDIR}/bin/tools/depmaker: $(TOPDIR)/bin/tools
+${TOPDIR}/bin/tools/depmaker:
$(HOSTCC) -g -o $(TOPDIR)/bin/tools/depmaker $(TOPDIR)/tools/adk/depmaker.c
dep: $(TOPDIR)/bin/tools/depmaker
diff --git a/mk/buildhlp.mk b/mk/buildhlp.mk
index 35d4eebd0..2cb4f1714 100644
--- a/mk/buildhlp.mk
+++ b/mk/buildhlp.mk
@@ -24,7 +24,10 @@ else
_CHECKSUM_COOKIE=
endif
-post-extract:
+${PACKAGE_DIR}/.stamps:
+ @mkdir -p ${PACKAGE_DIR}/.stamps
+
+post-extract: ${PACKAGE_DIR}/.stamps
ifeq ($(strip ${NO_DISTFILES}),1)
${WRKDIST}/.extract_done:
diff --git a/mk/image.mk b/mk/image.mk
index 1b7178eef..5c3d27c41 100644
--- a/mk/image.mk
+++ b/mk/image.mk
@@ -1,6 +1,34 @@
# This file is part of the OpenADK project. OpenADK is copyrighted
# material, please see the LICENCE file in the top-level directory.
+# relative paths, like 'mksh' or '../usr/bin/foosh'
+ifeq (${ADK_BINSH_ASH},y)
+BINSH:=ash
+else ifeq (${ADK_BINSH_BASH},y)
+BINSH:=bash
+else ifeq (${ADK_BINSH_MKSH},y)
+BINSH:=mksh
+else ifeq (${ADK_BINSH_ZSH},y)
+BINSH:=zsh
+else
+$(error No /bin/sh configured!)
+endif
+
+# absolute paths
+ifeq (${ADK_ROOTSH_ASH},y)
+ROOTSH:=/bin/ash
+else ifeq (${ADK_ROOTSH_BASH},y)
+ROOTSH:=/bin/bash
+else ifeq (${ADK_ROOTSH_MKSH},y)
+ROOTSH:=/bin/mksh
+else ifeq (${ADK_ROOTSH_TCSH},y)
+ROOTSH:=/usr/bin/tcsh
+else ifeq (${ADK_ROOTSH_ZSH},y)
+ROOTSH:=/bin/zsh
+else
+$(error No login shell configured!)
+endif
+
imageprepare: image-prepare-post extra-install
# if an extra directory exist in TOPDIR, copy all content over the
@@ -14,12 +42,14 @@ image-prepare-post:
dd if=$$rng bs=512 count=1 >>${TARGET_DIR}/etc/.rnd 2>/dev/null; \
chmod 600 ${TARGET_DIR}/etc/.rnd
chmod 4511 ${TARGET_DIR}/bin/busybox
- chmod 1777 ${TARGET_DIR}/tmp
@if [ -d ${TARGET_DIR}/usr/share/fonts/X11 ];then \
for i in $$(ls ${TARGET_DIR}/usr/share/fonts/X11/);do \
mkfontdir ${TARGET_DIR}/usr/share/fonts/X11/$${i}; \
done; \
fi
+ sed -i '/^root:/s!:/bin/sh$$!:${ROOTSH}!' ${TARGET_DIR}/etc/passwd
+ -rm -f ${TARGET_DIR}/bin/sh
+ ln -sf ${BINSH} ${TARGET_DIR}/bin/sh
KERNEL_PKGDIR:=$(LINUX_BUILD_DIR)/kernel-pkg
KERNEL_PKG:=$(PACKAGE_DIR)/kernel_$(KERNEL_VERSION)_$(CPU_ARCH).$(PKG_SUFFIX)
@@ -65,12 +95,16 @@ ${BUILD_DIR}/${INITRAMFS_PIGGYBACK}: ${TARGET_DIR}
sed "s#\(.*\)#:0:0::::::\1#" | sort | \
${TOOLS_DIR}/cpio -o -C512 -Hnewc -P >$@ 2>/dev/null
-${BIN_DIR}/${ROOTFSSQUASHFS}: ${TARGET_DIR}
+${BUILD_DIR}/root.squashfs: ${TARGET_DIR}
${STAGING_HOST_DIR}/bin/mksquashfs ${TARGET_DIR} \
${BUILD_DIR}/root.squashfs \
-nopad -noappend -root-owned $(MAKE_TRACE)
- cat ${BUILD_DIR}/${TARGET_KERNEL} ${BUILD_DIR}/root.squashfs > \
- ${BUILD_DIR}/${ROOTFSSQUASHFS}
+
+ifeq (,${CUSTOM_ROOTFSSQUASHFS_BUILD})
+${BUILD_DIR}/${ROOTFSSQUASHFS}: ${BUILD_DIR}/root.squashfs
+ cat ${BUILD_DIR}/${TARGET_KERNEL} ${BUILD_DIR}/root.squashfs \
+ >${BUILD_DIR}/${ROOTFSSQUASHFS}
+endif
createinitramfs:
@-rm $(LINUX_DIR)/usr/initramfs_data.cpio* $(MAKE_TRACE)
diff --git a/mk/kernel-build.mk b/mk/kernel-build.mk
index ba3259b16..986eb9c29 100644
--- a/mk/kernel-build.mk
+++ b/mk/kernel-build.mk
@@ -21,16 +21,16 @@ $(LINUX_DIR)/.config: $(LINUX_DIR)/.prepared $(BUILD_DIR)/.kernelconfig $(TOPDIR
$(TRACE) target/$(ADK_TARGET_ARCH)-kernel-configure
for f in $(TARGETS);do if [ -f $$f ];then rm $$f;fi;done $(MAKE_TRACE)
$(CP) $(BUILD_DIR)/.kernelconfig $(LINUX_DIR)/.config
- echo N | $(MAKE) ${KERNEL_MAKE_OPTS} oldconfig $(MAKE_TRACE)
- $(MAKE) ${KERNEL_MAKE_OPTS} prepare scripts $(MAKE_TRACE)
+ echo N | ${KERNEL_MAKE_ENV} $(MAKE) ${KERNEL_MAKE_OPTS} oldconfig $(MAKE_TRACE)
+ ${KERNEL_MAKE_ENV} $(MAKE) ${KERNEL_MAKE_OPTS} prepare scripts $(MAKE_TRACE)
touch -c $(LINUX_DIR)/.config
$(LINUX_DIR)/vmlinux: $(LINUX_DIR)/.config
$(TRACE) target/$(ADK_TARGET_ARCH)-kernel-compile
- $(MAKE) ${KERNEL_MAKE_OPTS} -j${ADK_MAKE_JOBS} LOCALVERSION="" $(MAKE_TRACE)
+ ${KERNEL_MAKE_ENV} $(MAKE) ${KERNEL_MAKE_OPTS} -j${ADK_MAKE_JOBS} LOCALVERSION="" $(MAKE_TRACE)
$(TRACE) target/$(ADK_TARGET_ARCH)-kernel-modules-install
rm -rf $(LINUX_BUILD_DIR)/modules
- $(MAKE) ${KERNEL_MAKE_OPTS} DEPMOD=true \
+ ${KERNEL_MAKE_ENV} $(MAKE) ${KERNEL_MAKE_OPTS} DEPMOD=true \
INSTALL_MOD_PATH=$(LINUX_BUILD_DIR)/modules \
LOCALVERSION="" \
modules_install $(MAKE_TRACE)
diff --git a/mk/kernel-vars.mk b/mk/kernel-vars.mk
index 48b7023b5..f66b238e0 100644
--- a/mk/kernel-vars.mk
+++ b/mk/kernel-vars.mk
@@ -3,5 +3,13 @@
KERNEL_MAKE_OPTS:= -C "${LINUX_DIR}" V=1
ifneq ($(ADK_NATIVE),y)
-KERNEL_MAKE_OPTS+= CROSS_COMPILE="$(TARGET_CROSS)" ARCH=$(ARCH) CC="$(TARGET_CC)" HOSTCC="${HOSTCC}"
+KERNEL_MAKE_OPTS+= CROSS_COMPILE="$(TARGET_CROSS)" ARCH=$(ARCH) \
+ CC="$(TARGET_CC)" HOSTCC="${HOSTCC}" \
+ HOSTCFLAGS='${HOSTCFLAGS}'
endif
+
+ifeq (${ADK_TARGET_SYSTEM_LINKSYS_WRT54G},y)
+ADK_KCPPFLAGS+= -DBCM47XX_OVERRIDE_FLASHSIZE=0x400000
+endif
+
+KERNEL_MAKE_ENV+= KCPPFLAGS='${ADK_KCPPFLAGS}'
diff --git a/mk/kernel-ver.mk b/mk/kernel-ver.mk
index 50b8c4056..1741c62d0 100644
--- a/mk/kernel-ver.mk
+++ b/mk/kernel-ver.mk
@@ -1,3 +1,3 @@
-KERNEL_VERSION:= 2.6.36
+KERNEL_VERSION:= 2.6.37
KERNEL_RELEASE:= 1
-KERNEL_MD5SUM:= 61f3739a73afb6914cb007f37fb09b62
+KERNEL_MD5SUM:= c8ee37b4fdccdb651e0603d35350b434
diff --git a/mk/kernel.mk b/mk/kernel.mk
index 2ce156694..d5288cd7e 100644
--- a/mk/kernel.mk
+++ b/mk/kernel.mk
@@ -33,6 +33,7 @@ IDEPENDK_$(1):=kernel ($(KERNEL_VERSION)) $(foreach pkg,$(5),", $(pkg)")
PKG_$(1) := $(PACKAGE_DIR)/kmod-$(2)_$(KERNEL_VERSION)-$(KERNEL_RELEASE)_$(CPU_ARCH).$(PKG_SUFFIX)
I_$(1) := $(KMOD_BUILD_DIR)/ipkg/$(2)
+ifeq ($${ADK_TARGET_KERNEL_CUSTOMISING},y)
ifeq ($$(ADK_KPACKAGE_KMOD_$(1)),m)
TARGETS+=$$(PKG_$(1))
endif
@@ -40,6 +41,7 @@ ifeq ($$(ADK_KPACKAGE_KMOD_$(1)),y)
TARGETS+=$$(PKG_$(1))
INSTALL_TARGETS+=$$(PKG_$(1))
endif
+endif
$$(PKG_$(1)):
rm -rf $$(I_$(1))
diff --git a/mk/modules.mk b/mk/modules.mk
index 94a1d235a..27b02bbf7 100644
--- a/mk/modules.mk
+++ b/mk/modules.mk
@@ -926,11 +926,13 @@ $(eval $(call KMOD_template,CRYPTO_FCRYPT,crypto-fcrypt,\
,11))
ZLIB:=lib/zlib_deflate/zlib_deflate
-ifeq ($(ADK_LINUX_CRIS_FOXBOARD),)
-ifeq ($(ADK_LINUX_MIPS_AG241),)
+ifeq ($(ADK_TARGET_SYSTEM_FOXBOARD_LX832),y)
+ifeq ($(ADK_TARGET_SYSTEM_FOXBOARD_LX416),y)
+ifeq ($(ADK_TARGET_SYSTEM_LINKSYS_AG241),y)
ZLIB+=lib/zlib_inflate/zlib_inflate
endif
endif
+endif
$(eval $(call KMOD_template,CRYPTO_DEFLATE,crypto-deflate,\
$(foreach mod, $(ZLIB),$(MODULES_DIR)/kernel/$(mod)) \
@@ -1177,11 +1179,13 @@ $(eval $(call KMOD_template,INPUT_EVDEV,input-evdev,\
# USB
#
-ifeq ($(ADK_LINUX_CRIS_FOXBOARD),)
+ifeq ($(ADK_TARGET_SYSTEM_FOXBOARD_LX832),)
+ifeq ($(ADK_TARGET_SYSTEM_FOXBOARD_LX416),)
$(eval $(call KMOD_template,USB,usb,\
$(MODULES_DIR)/kernel/drivers/usb/core/usbcore \
,50))
endif
+endif
$(eval $(call KMOD_template,USB_EHCI_HCD,usb-ehci-hcd,\
$(MODULES_DIR)/kernel/drivers/usb/host/ehci-hcd \
diff --git a/mk/package.mk b/mk/package.mk
index edbf3c6d5..bacee71f4 100644
--- a/mk/package.mk
+++ b/mk/package.mk
@@ -3,6 +3,10 @@
all: build-all-pkgs
+ifeq ($(ADK_HOST_CYGWIN),y)
+EXEEXT:= .exe
+endif
+
TCFLAGS:= ${TARGET_CFLAGS}
TCXXFLAGS:= ${TARGET_CFLAGS}
TCPPFLAGS:= ${TARGET_CPPFLAGS}
@@ -36,7 +40,8 @@ CONFIGURE_ARGS+= --enable-debug
endif
endif
-CONFIGURE_ENV+= CONFIG_SHELL='$(strip ${SHELL})' \
+CONFIGURE_ENV+= GCC_HONOUR_COPTS=s \
+ CONFIG_SHELL='$(strip ${SHELL})' \
CFLAGS='$(strip ${TCFLAGS})' \
CXXFLAGS='$(strip ${TCXXFLAGS})' \
CPPFLAGS='$(strip ${TCPPFLAGS})' \
@@ -74,9 +79,12 @@ MAKE_ENV+= PATH='${TARGET_PATH}' \
${HOST_CONFIGURE_OPTS} \
CC='${TARGET_CC}' \
CXX='${TARGET_CXX}' \
+ LD='${TARGET_LD}' \
AR='${TARGET_CROSS}ar' \
RANLIB='${TARGET_CROSS}ranlib' \
NM='${TARGET_CROSS}nm' \
+ OBJCOPY='${TARGET_CROSS}objcopy' \
+ RANLIB='${TARGET_CROSS}ranlib' \
STRIP='${TARGET_CROSS}strip' \
CROSS="$(TARGET_CROSS)"
endif
@@ -142,6 +150,8 @@ IDIR_$(1)= $(WRKDIR)/fake-${CPU_ARCH}/pkg-$(2)
ifneq (${ADK_PACKAGE_$(1)}${DEVELOPER},)
ALL_IPKGS+= $$(IPKG_$(1))
ALL_IDIRS+= $${IDIR_$(1)}
+ALL_POSTINST+= $(2)-install
+$(2)-install:
endif
INFO_$(1)= $(PKG_STATE_DIR)/info/$(2).list
@@ -181,6 +191,7 @@ $$(IPKG_$(1)): $$(IDIR_$(1))/CONTROL/control $${_FAKE_COOKIE}
ifeq ($(ADK_DEBUG),)
$${RSTRIP} $${IDIR_$(1)} $(MAKE_TRACE)
endif
+ifeq (${ADK_INSTALL_PACKAGE_INIT_SCRIPTS},y)
@for file in $$$$(ls ./files/*.init 2>/dev/null); do \
fname=$$$$(echo $$$$file| sed -e "s#.*/##" -e "s#.init##"); \
check=$$$$(grep PKG $$$$file|cut -d ' ' -f 2); \
@@ -192,6 +203,7 @@ endif
[[ -e $$$$script ]] || continue; \
chmod 0755 "$$$$script"; \
done
+endif
@mkdir -p $${PACKAGE_DIR} '$${STAGING_PKG_DIR}' \
'$${STAGING_TARGET_DIR}/scripts'
ifeq (,$(filter noremove,$(7)))
@@ -216,7 +228,7 @@ endif
find usr ! -type d 2>/dev/null | \
grep -v -e '^usr/share' -e '^usr/man' -e '^usr/info' -e '^usr/lib/libc.so' | \
tee '$${STAGING_PKG_DIR}/$(1)' | \
- $(TOPDIR)/bin/tools/cpio -padlmu '$${STAGING_TARGET_DIR}'
+ $(TOOLS_DIR)/cpio -padlmu '$${STAGING_TARGET_DIR}'
@cd '$${STAGING_TARGET_DIR}'; grep 'usr/lib/.*\.la$$$$' \
'$${STAGING_PKG_DIR}/$(1)' | while read fn; do \
chmod u+w $$$$fn; \
diff --git a/mk/pkg-bottom.mk b/mk/pkg-bottom.mk
index 122198e45..f91e1bb45 100644
--- a/mk/pkg-bottom.mk
+++ b/mk/pkg-bottom.mk
@@ -127,6 +127,7 @@ endif
pre-install:
do-install:
post-install:
+spkg-install: ${ALL_POSTINST}
${_FAKE_COOKIE}: ${_BUILD_COOKIE}
-rm -f ${_ALL_CONTROLS}
@mkdir -p '${STAGING_PKG_DIR}' ${WRKINST} '${STAGING_TARGET_DIR}/scripts'
@@ -145,6 +146,7 @@ else
@echo "Invalid INSTALL_STYLE '${INSTALL_STYLE}'" >&2
@exit 1
endif
+ env ${MAKE_ENV} ${MAKE} spkg-install $(MAKE_TRACE)
ifeq ($(ADK_NATIVE),)
@for a in ${WRKINST}/usr/{bin/*-config,lib/pkgconfig/*.pc}; do \
[[ -e $$a ]] || continue; \
@@ -168,7 +170,7 @@ endif
find usr ! -type d 2>/dev/null | \
grep -v -e '^usr/share' -e '^usr/man' -e '^usr/info' -e '^usr/lib/libc.so' | \
tee '${STAGING_PKG_DIR}/${PKG_NAME}' | \
- $(TOPDIR)/bin/tools/cpio -padlmu '${STAGING_TARGET_DIR}'
+ $(TOOLS_DIR)/cpio -padlmu '${STAGING_TARGET_DIR}'
@cd '${STAGING_TARGET_DIR}'; grep 'usr/lib/.*\.la$$' \
'${STAGING_PKG_DIR}/${PKG_NAME}' | while read fn; do \
chmod u+w $$fn; \
diff --git a/mk/python.mk b/mk/python.mk
index e0fce5f0e..5767b12f7 100644
--- a/mk/python.mk
+++ b/mk/python.mk
@@ -1,3 +1,3 @@
PYTHON_VERSION=2.7
-PYTHON_LIBDIR:=$(STAGING_HOST_DIR)/lib
-PYTHON:=${STAGING_HOST_DIR}/bin/hostpython
+PYTHON_LIBDIR:=$(STAGING_HOST_DIR)/usr/lib
+PYTHON:=${STAGING_HOST_DIR}/usr/bin/hostpython
diff --git a/mk/vars.mk b/mk/vars.mk
index 25b285518..ab247901f 100644
--- a/mk/vars.mk
+++ b/mk/vars.mk
@@ -9,12 +9,25 @@ INSTALL_SCRIPT= install -m0755
MAKEFLAGS= $(EXTRA_MAKEFLAGS)
BUILD_USER= $(shell id -un)
BUILD_GROUP= $(shell id -gn)
+
+# target compiler settings
+TARGET_CPPFLAGS+= -I${STAGING_TARGET_DIR}/usr/include
+TARGET_LDFLAGS+= -Wl,-O2
ifneq ($(ADK_DEBUG),)
TARGET_DEBUGGING:= -g3 -fno-omit-frame-pointer
else
-TARGET_DEBUGGING:= -fomit-frame-pointer $(TARGET_OPTIMIZATION)
+TARGET_DEBUGGING:= $(TARGET_OPTIMIZATION) -fomit-frame-pointer
endif
TARGET_CFLAGS:= $(TARGET_CFLAGS_ARCH) $(TARGET_DEBUGGING) -fwrapv
+ifneq ($(ADK_TOOLCHAIN_GCC_USE_SSP),)
+TARGET_CFLAGS+= -fstack-protector
+TARGET_CXXFLAGS+= -fstack-protector
+TARGET_LDFLAGS+= -fstack-protector
+endif
+ifneq ($(ADK_TOOLCHAIN_GCC_USE_LTO),)
+TARGET_CFLAGS+= -flto
+TARGET_LDFLAGS+= -flto
+endif
BASE_DIR:= $(TOPDIR)
DISTDIR?= ${BASE_DIR}/dl
@@ -26,6 +39,9 @@ STAGING_HOST_DIR:= ${BASE_DIR}/host_${CPU_ARCH}_${ADK_TARGET_LIBC}
STAGING_HOST_DIR_PFX:= ${BASE_DIR}/host_*
STAGING_TARGET_DIR:= ${BASE_DIR}/target_${CPU_ARCH}_${ADK_TARGET_LIBC}
STAGING_TARGET_DIR_PFX:=${BASE_DIR}/target_*
+# relation from STAGING_HOST_DIR to STAGING_TARGET_DIR (for gcc to find
+# its sysroot while staying relocatable)
+STAGING_HOST2TARGET:= ../target_${CPU_ARCH}_${ADK_TARGET_LIBC}
TOOLCHAIN_BUILD_DIR= $(BASE_DIR)/toolchain_build_${CPU_ARCH}_${ADK_TARGET_LIBC}
TOOLCHAIN_BUILD_DIR_PFX=$(BASE_DIR)/toolchain_build_*
TOOLS_BUILD_DIR= $(BASE_DIR)/tools_build
@@ -36,10 +52,9 @@ BIN_DIR_PFX:= $(BASE_DIR)/bin
PACKAGE_DIR:= $(BIN_DIR)/packages
TARGET_DIR:= $(BASE_DIR)/root_${ADK_TARGET_SYSTEM}_${CPU_ARCH}_${ADK_TARGET_LIBC}
TARGET_DIR_PFX:= $(BASE_DIR)/root_*
-TARGET_PATH= ${SCRIPT_DIR}:${TOOLS_DIR}:${STAGING_HOST_DIR}/bin:${STAGING_TARGET_DIR}/scripts:${_PATH}
+TARGET_PATH= ${SCRIPT_DIR}:${TOOLS_DIR}:${STAGING_HOST_DIR}/bin:${STAGING_HOST_DIR}/usr/bin:${STAGING_TARGET_DIR}/scripts:${_PATH}
REAL_GNU_TARGET_NAME= $(CPU_ARCH)-$(ADK_VENDOR)-linux-$(ADK_TARGET_SUFFIX)
GNU_TARGET_NAME= $(CPU_ARCH)-$(ADK_VENDOR)-linux
-TOOLCHAIN_SYSROOT:= $(TOOLCHAIN_BUILD_DIR)/libc_dev
ifeq ($(ADK_NATIVE),y)
TARGET_CROSS:=
TARGET_COMPILER_PREFIX?=
@@ -50,8 +65,6 @@ endif
TARGET_CC:= ${TARGET_COMPILER_PREFIX}gcc
TARGET_CXX:= ${TARGET_COMPILER_PREFIX}g++
TARGET_LD:= ${TARGET_COMPILER_PREFIX}ld
-TARGET_CPPFLAGS+= -I${STAGING_TARGET_DIR}/usr/include
-TARGET_LDFLAGS+= -Wl,-O2
PATCH= ${BASH} $(SCRIPT_DIR)/patch.sh
SED:= sed -i -e
LINUX_DIR:= $(BUILD_DIR)/linux
@@ -102,19 +115,19 @@ EXTRACT_CMD= mkdir -p ${WRKDIR}; \
cd ${WRKDIR} && \
for file in ${FULLDISTFILES}; do case $$file in \
*.cpio) \
- cat $$file | $(TOPDIR)/bin/tools/cpio -i -d ;; \
+ cat $$file | $(TOOLS_DIR)/cpio -i -d ;; \
*.tar) \
tar -xf $$file ;; \
*.cpio.Z | *.cpio.gz | *.cgz | *.mcz) \
- gzip -dc $$file | $(TOPDIR)/bin/tools/cpio -i -d ;; \
+ gzip -dc $$file | $(TOOLS_DIR)/cpio -i -d ;; \
*.tar.Z | *.tar.gz | *.taz | *.tgz) \
gzip -dc $$file | tar -xf - ;; \
*.cpio.bz2 | *.cbz) \
- bzip2 -dc $$file | $(TOPDIR)/bin/tools/cpio -i -d ;; \
+ bzip2 -dc $$file | $(TOOLS_DIR)/cpio -i -d ;; \
*.tar.bz2 | *.tbz | *.tbz2) \
bzip2 -dc $$file | tar -xf - ;; \
*.zip) \
- cat $$file | $(TOPDIR)/bin/tools/cpio -ivd -H zip ;; \
+ cat $$file | $(TOOLS_DIR)/cpio -ivd -H zip ;; \
*.arm) \
cp $$file ${WRKDIR} ;; \
*) \
@@ -127,6 +140,6 @@ QUIET:=
else
QUIET:= --quiet
endif
-FETCH_CMD?= wget --tries=1 --timeout=30 $(QUIET)
+FETCH_CMD?= wget --timeout=30 $(QUIET)
include $(TOPDIR)/mk/mirrors.mk
diff --git a/package/.template/Makefile b/package/.template/Makefile
index e5593b3fb..b9b1c125e 100644
--- a/package/.template/Makefile
+++ b/package/.template/Makefile
@@ -14,6 +14,8 @@ PKG_DEPENDS:= add dependendant package names
PKG_BUILDDEP:= add packages which need to be compiled
PKG_URL:= add project url
PKG_SITES:= add download url without package name
+# alternatively use a pre-defined set of mirrors, see mk/mirrors.mk:
+#PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=sub/path/}
# if more than one binary package is created, add symbol names of all here
# leave variable empty, when no binary package is created. You can set it
@@ -30,7 +32,7 @@ PKG_SITES:= add download url without package name
#PKGSD_SUBPKG1:=
# define your flavours for your package here, WITH_SSL f.e.
-#PKG_FLAVOURS:= WITH_SSL
+#PKG_FLAVOURS_PKGNAME:= WITH_SSL
# flavour description
#PKGFD_WITH_SSL:= enable SSL support
# flavour runtime dependency, package name
diff --git a/package/DirectFB/Makefile b/package/DirectFB/Makefile
index 45dc3e13f..3f2b8297b 100644
--- a/package/DirectFB/Makefile
+++ b/package/DirectFB/Makefile
@@ -5,13 +5,13 @@ include $(TOPDIR)/rules.mk
PKG_NAME:= DirectFB
PKG_VERSION:= 1.4.11
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_EXTRAVER:= 1.4-5
PKG_MD5SUM:= 94735ccec21120794adcce93a61445d2
PKG_DESCR:= Thin graphic library for the Linux framebuffer devices
PKG_SECTION:= libs
PKG_DEPENDS:= libpng libjpeg
-PKG_BUILDDEP:= libpng jpeg
+PKG_BUILDDEP:= libpng jpeg freetype
PKG_URL:= http://www.directfb.org/
PKG_SITES:= http://directfb.org/downloads/Core/DirectFB-1.4/
@@ -26,6 +26,7 @@ $(eval $(call PKG_template,DIRECTFB_DEV,directfb-dev,$(PKG_VERSION)-${PKG_RELEAS
CONFIGURE_ARGS+= --with-inputdrivers=linuxinput,keyboard,ps2mouse \
--with-gfxdrivers=none \
+ --without-tools \
--enable-fbdev \
--disable-sdl \
--disable-osx \
@@ -43,11 +44,7 @@ ifeq (${ADK_TARGET_SYSTEM_LEMOTE_YEELONG},y)
XAKE_FLAGS+= LDEMULATION=elf64ltsmip
endif
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_DIRECTFB_DEV}+= directfb-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_DIRECTFB}/etc
${INSTALL_DATA} ./files/directfbrc ${IDIR_DIRECTFB}/etc/
$(INSTALL_DIR) $(IDIR_DIRECTFB)/usr/lib/directfb-${PKG_EXTRAVER}/{inputdrivers,systems,wm}
diff --git a/package/DirectFB/patches/patch-configure b/package/DirectFB/patches/patch-configure
new file mode 100644
index 000000000..86831102d
--- /dev/null
+++ b/package/DirectFB/patches/patch-configure
@@ -0,0 +1,11 @@
+--- DirectFB-1.4.11.orig/configure 2010-11-15 22:35:38.000000000 +0100
++++ DirectFB-1.4.11/configure 2011-01-08 11:46:41.000000000 +0100
+@@ -16257,7 +16257,7 @@ if test x"$CFLAGS" = x"-g -O2"; then
+ CFLAGS=
+ fi
+
+-CFLAGS="-O3 -ffast-math -pipe $CFLAGS"
++CFLAGS="-ffast-math -pipe $CFLAGS"
+
+ DFB_INTERNAL_CFLAGS="-D_GNU_SOURCE $DFB_INTERNAL_CFLAGS"
+
diff --git a/package/DirectFB/patches/patch-ltmain_sh b/package/DirectFB/patches/patch-ltmain_sh
new file mode 100644
index 000000000..cd25bbd95
--- /dev/null
+++ b/package/DirectFB/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- DirectFB-1.4.11.orig/ltmain.sh 2010-11-03 11:14:45.000000000 +0100
++++ DirectFB-1.4.11/ltmain.sh 2011-01-14 00:24:52.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/ImageMagick/Makefile b/package/ImageMagick/Makefile
index 648befeeb..9f16e819e 100644
--- a/package/ImageMagick/Makefile
+++ b/package/ImageMagick/Makefile
@@ -10,7 +10,7 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= a07a97cfb28b588cbcf83ffa9ec92e3f
PKG_DESCR:= image processing and converting utility
PKG_SECTION:= multimedia
-PKG_BUILDDEP:= jpeg libtiff
+PKG_BUILDDEP:= jpeg libtiff fontconfig libiconv
PKG_DEPENDS:= libjpeg libtiff
PKG_URL:= http://www.imagemagick.org/
PKG_SITES:= http://image_magick.veidrodis.com/image_magick/
@@ -35,14 +35,10 @@ $(eval $(call PKG_template,LIBIMAGEMAGICK,libimagemagick,$(PKG_VERSION)-${PKG_RE
$(eval $(call PKG_template,CONVERT,convert,$(PKG_VERSION)-${PKG_RELEASE},${PKGSS_CONVERT},${PKGSD_CONVERT},${PKGSC_CONVERT}))
$(eval $(call PKG_template,DISPLAY,display,$(PKG_VERSION)-${PKG_RELEASE},${PKGSS_DISPLAY},${PKGSD_DISPLAY},${PKGSC_DISPLAY}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_CONVERT}+= convert-install
-SUB_INSTALLS-${ADK_PACKAGE_DISPLAY}+= display-install
+CONFIGURE_ARGS+= --with-magick-plus-plus=no \
+ --enable-fast-install
-CONFIGURE_ARGS+= --with-magick-plus-plus=no
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
$(INSTALL_DIR) $(IDIR_LIBIMAGEMAGICK)/usr/lib
$(INSTALL_DIR) $(IDIR_LIBIMAGEMAGICK)/usr/lib/${PKG_NAME}-${PKG_VERSION}/config
$(INSTALL_DATA) $(WRKINST)/usr/lib/${PKG_NAME}-${PKG_VERSION}/config/* \
diff --git a/package/ImageMagick/patches/patch-config_ltmain_sh b/package/ImageMagick/patches/patch-config_ltmain_sh
new file mode 100644
index 000000000..9ca2a4a6c
--- /dev/null
+++ b/package/ImageMagick/patches/patch-config_ltmain_sh
@@ -0,0 +1,39 @@
+--- ImageMagick-6.6.5-10.orig/config/ltmain.sh 2010-11-21 22:35:22.000000000 +0100
++++ ImageMagick-6.6.5-10/config/ltmain.sh 2011-01-14 00:59:45.000000000 +0100
+@@ -5091,7 +5091,7 @@ func_mode_link ()
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
+@@ -5843,27 +5843,6 @@ func_mode_link ()
+ esac
+ fi
+
+- # Hardcode the library path.
+- # Skip directories that are in the system default run-time
+- # search path.
+- case " $sys_lib_dlsearch_path " in
+- *" $absdir "*) ;;
+- *)
+- case "$compile_rpath " in
+- *" $absdir "*) ;;
+- *) compile_rpath="$compile_rpath $absdir"
+- esac
+- ;;
+- esac
+- case " $sys_lib_dlsearch_path " in
+- *" $libdir "*) ;;
+- *)
+- case "$finalize_rpath " in
+- *" $libdir "*) ;;
+- *) finalize_rpath="$finalize_rpath $libdir"
+- esac
+- ;;
+- esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
diff --git a/package/Makefile b/package/Makefile
index 6b49e5d8f..9cf448ff8 100644
--- a/package/Makefile
+++ b/package/Makefile
@@ -48,9 +48,6 @@ compile: $(REBUILD_PACKAGES) base-files-compile $(COMPILE_PACKAGES)
install: base-files-install $(INSTALL_PACKAGES)
endif
-$(TARGET_DIR):
- mkdir -p $(TARGET_DIR)
-
%-download:
$(START_TRACE) "package/$(patsubst %-download,%,$@)-download: "
$(MAKE) -C $(patsubst %-download,%,$@) fetch
diff --git a/package/alsa-lib/Makefile b/package/alsa-lib/Makefile
index 679efb111..fdc0a08cd 100644
--- a/package/alsa-lib/Makefile
+++ b/package/alsa-lib/Makefile
@@ -25,11 +25,7 @@ $(eval $(call PKG_template,ALSA_LIB_DEV,alsa-lib-dev,${PKG_VERSION}-${PKG_RELEAS
CONFIGURE_ARGS+= --disable-python
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_ALSA_LIB_DEV}+= alsa-lib-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_ALSA_LIB}/usr/lib ${IDIR_ALSA_LIB}/usr/share/alsa
${CP} ${WRKINST}/usr/lib/libasound.so* ${IDIR_ALSA_LIB}/usr/lib/
${CP} ${WRKINST}/usr/share/alsa/* ${IDIR_ALSA_LIB}/usr/share/alsa/
diff --git a/package/alsa-lib/patches/patch-ltmain_sh b/package/alsa-lib/patches/patch-ltmain_sh
new file mode 100644
index 000000000..7c980c176
--- /dev/null
+++ b/package/alsa-lib/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- alsa-lib-1.0.22.orig/ltmain.sh 2006-11-25 12:04:27.000000000 +0100
++++ alsa-lib-1.0.22/ltmain.sh 2011-01-14 11:34:46.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/alsa-utils/Makefile b/package/alsa-utils/Makefile
index 288faafdf..c134b85be 100644
--- a/package/alsa-utils/Makefile
+++ b/package/alsa-utils/Makefile
@@ -14,10 +14,10 @@ PKG_BUILDDEP:= alsa-lib
PKG_URL:= http://www.alsa-project.org/
PKG_SITES:= ftp://ftp.alsa-project.org/pub/utils/
-PKG_FLAVOURS:= WITH_ALSAMIXER
-PKGFS_WITH_ALSAMIXER:= libncurses
-PKGFD_WITH_ALSAMIXER:= include alsamixer ncurses applet
-PKGFB_WITH_ALSAMIXER:= ncurses
+PKG_FLAVOURS_ALSA_UTILS:= WITH_ALSAMIXER
+PKGFS_WITH_ALSAMIXER:= libncurses
+PKGFD_WITH_ALSAMIXER:= include alsamixer ncurses applet
+PKGFB_WITH_ALSAMIXER:= ncurses
DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tar.bz2
diff --git a/package/apr/Makefile b/package/apr/Makefile
index 096981833..2b6c05305 100644
--- a/package/apr/Makefile
+++ b/package/apr/Makefile
@@ -13,7 +13,7 @@ PKG_DEPENDS:= libpthread
PKG_URL:= http://apr.apache.org/
PKG_SITES:= http://gd.tuwien.ac.at/infosys/servers/http/apache/dist/${PKG_NAME}/
-PKG_FLAVOURS:= WITH_IPV6
+PKG_FLAVOURS_APR:= WITH_IPV6
PKGFD_WITH_IPV6:= enable IPv6 support
include ${TOPDIR}/mk/package.mk
@@ -28,7 +28,6 @@ CONFIGURE_ENV+= ac_cv_file__dev_zero=yes
CONFIGURE_ENV+= apr_cv_process_shared_works=no
CONFIGURE_ENV+= ac_cv_lib_nsl_gethostbyname=no
CONFIGURE_ENV+= apr_cv_tcp_nodelay_with_cork=no
-
CONFIGURE_ARGS+= --with-devrandom=/dev/urandom \
--enable-threads
diff --git a/package/apr/patches/patch-build_ltmain_sh b/package/apr/patches/patch-build_ltmain_sh
new file mode 100644
index 000000000..0ce8441f6
--- /dev/null
+++ b/package/apr/patches/patch-build_ltmain_sh
@@ -0,0 +1,11 @@
+--- apr-1.4.2.orig/build/ltmain.sh 2010-01-21 08:59:41.000000000 +0100
++++ apr-1.4.2/build/ltmain.sh 2011-01-14 11:41:48.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/arpd/Makefile b/package/arpd/Makefile
index 3494c2115..722faae9d 100644
--- a/package/arpd/Makefile
+++ b/package/arpd/Makefile
@@ -23,7 +23,7 @@ $(eval $(call PKG_template,ARPD,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_
CONFIGURE_ARGS+= --with-libdnet=${STAGING_TARGET_DIR}/usr \
--with-libevent=${STAGING_TARGET_DIR}/usr \
--with-libpcap=${STAGING_TARGET_DIR}/usr
-MAKE_FLAGS+= CCOPT="${TARGET_CFLAGS}" \
+MAKE_FLAGS+= CFLAGS="${TCFLAGS}" \
INCLS="-I. -I${STAGING_TARGET_DIR}/usr/include" \
LIBS="-L${STAGING_TARGET_DIR}/usr/lib -lpcap -ldnet -levent"
diff --git a/package/asterisk/Makefile b/package/asterisk/Makefile
index bdf44fb96..2b1fc70a5 100644
--- a/package/asterisk/Makefile
+++ b/package/asterisk/Makefile
@@ -44,19 +44,6 @@ $(eval $(call PKG_template,ASTERISK_CODEC_GSM,asterisk-codec-gsm,$(PKG_VERSION)-
$(eval $(call PKG_template,ASTERISK_PBX_DUNDI,asterisk-pbx-dundi,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,ASTERISK_RES_AGI,asterisk-res-agi,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_ASTERISK_PGSQL}+= asterisk-pgsql-install
-SUB_INSTALLS-${ADK_PACKAGE_ASTERISK_VOICEMAIL}+= asterisk-voicemail-install
-SUB_INSTALLS-${ADK_PACKAGE_ASTERISK_SOUNDS}+= asterisk-sounds-install
-SUB_INSTALLS-${ADK_PACKAGE_ASTERISK_CHAN_MGCP}+= asterisk-chan-mgcp-install
-SUB_INSTALLS-${ADK_PACKAGE_ASTERISK_CHAN_SKINNY}+= asterisk-chan-skinny-install
-SUB_INSTALLS-${ADK_PACKAGE_ASTERISK_CHAN_IAX2}+= asterisk-chan-iax2-install
-SUB_INSTALLS-${ADK_PACKAGE_ASTERISK_CODEC_SPEEX}+= asterisk-codec-speex-install
-SUB_INSTALLS-${ADK_PACKAGE_ASTERISK_CODEC_GSM}+= asterisk-codec-gsm-install
-SUB_INSTALLS-${ADK_PACKAGE_ASTERISK_PBX_DUNDI}+= asterisk-pbx-dundi-install
-SUB_INSTALLS-${ADK_PACKAGE_ASTERISK_RES_AGI}+= asterisk-res-agi-install
-
CONFIGURE_ARGS= --with-z=${STAGING_TARGET_DIR}/usr \
--with-ncurses=${STAGING_TARGET_DIR}/usr \
--with-ssl=${STAGING_TARGET_DIR}/usr \
@@ -132,7 +119,7 @@ post-build:
tar xzf asterisk-core-sounds-en-gsm-1.4.19.tar.gz ; \
rm asterisk-core-sounds-en-gsm-1.4.19.tar.gz
-do-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+do-install:
$(CP) $(WRKINST)/* $(IDIR_ASTERISK)
rm -rf $(IDIR_ASTERISK)/usr/sbin/astgenkey
rm -rf $(IDIR_ASTERISK)/usr/bin
diff --git a/package/aufs2-util/Makefile b/package/aufs2-util/Makefile
index 4078fa8e1..f42767dbe 100644
--- a/package/aufs2-util/Makefile
+++ b/package/aufs2-util/Makefile
@@ -4,26 +4,44 @@
include $(TOPDIR)/rules.mk
PKG_NAME:= aufs2-util
-PKG_VERSION:= 130809
+PKG_VERSION:= 2-100111
PKG_RELEASE:= 1
+PKG_MD5SUM:= 1854f5ab560dd375b22f6e2b747cb412
PKG_DESCR:= aufs2 utilities
PKG_SECTION:= fs
PKG_URL:= http://aufs.sf.net/
+# created from git via:
+# $ git archive --format tar aufs2.1 | \
+# gzip -9 -c >../aufs2-util-2-$(date +%d%m%g).tar.gz
+
+PKG_SITES:= http://nwl.cc/~n0-1/
+WRKDIST= ${WRKDIR}
+
PKG_HOST_DEPENDS:= !cygwin !freebsd !openbsd !netbsd
-NO_DISTFILES:= 1
+PKG_SUBPKGS:= AUFS2_UTIL LIBAU
+PKGSD_LIBAU:= aufs2 userspace library
include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,AUFS2_UTIL,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+$(eval $(call PKG_template,LIBAU,libau,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBAU},${PKG_SECTION}))
CONFIG_STYLE:= manual
-MAKE_FLAGS+= KDIR=${LINUX_DIR}
+XAKE_FLAGS+= Install=install HOSTCPPFLAGS="-I${LINUX_HEADER_DIR}/include"
post-install:
$(INSTALL_DIR) $(IDIR_AUFS2_UTIL)/sbin
- $(INSTALL_BIN) ${WRKINST}/sbin/{u,}mount.aufs \
+ $(INSTALL_BIN) ${WRKINST}/sbin/{{u,}mount.aufs,auplink} \
$(IDIR_AUFS2_UTIL)/sbin
+ $(INSTALL_DIR) $(IDIR_AUFS2_UTIL)/usr/bin
+ $(INSTALL_BIN) ${WRKINST}/usr/bin/au{brsync,chk} \
+ $(IDIR_AUFS2_UTIL)/usr/bin
+ $(INSTALL_DIR) $(IDIR_AUFS2_UTIL)/etc/default
+ $(INSTALL_DATA) ${WRKINST}/etc/default/aufs \
+ $(IDIR_AUFS2_UTIL)/etc/default
+ $(INSTALL_DIR) $(IDIR_LIBAU)/usr/lib
+ ${CP} ${WRKINST}/usr/lib/libau* ${IDIR_LIBAU}/usr/lib
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/aufs2-util/patches/patch-Makefile b/package/aufs2-util/patches/patch-Makefile
index 5cfb193c3..d77ea81ec 100644
--- a/package/aufs2-util/patches/patch-Makefile
+++ b/package/aufs2-util/patches/patch-Makefile
@@ -1,33 +1,47 @@
- - explicitly use the host cc to compile c2sh and c2tmac
- (using per-target local variable assignments is an elegant
- way for not having to define explicit rules for the targets)
- - dont try setting owner and group of installed files
---- aufs2-util-130809.orig/Makefile 2009-08-13 14:59:49.000000000 +0200
-+++ aufs2-util-130809/Makefile 2009-08-23 18:05:03.909726416 +0200
-@@ -54,6 +54,11 @@ ${Dummy}: ${LibSoObj}
- ${LibSo}: ${Dummy}
- ln -f $< $@
+--- w-aufs2-util-2-100111-1.orig/Makefile 2011-01-07 05:00:54.000000000 +0100
++++ w-aufs2-util-2-100111-1/Makefile 2011-01-10 23:43:23.000000000 +0100
+@@ -15,6 +15,11 @@
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+c2sh c2tmac: CC = ${HOSTCC}
-+c2sh c2tmac: CFLAGS="-I${KDIR}/include"
-+c2sh c2tmac: LDFLAGS=
-+c2sh c2tmac: CPPFLAGS=
++c2sh c2tmac: CFLAGS= ${HOSTCFLAGS}
++c2sh c2tmac: LDFLAGS= ${HOSTLDFLAGS}
++c2sh c2tmac: CPPFLAGS= ${HOSTCPPFLAGS} -I./libau -I${LINUX_HEADER_DIR}/include
+
- etc_default_aufs: c2sh aufs.shlib
- ${RM} $@
- echo '# aufs variables for shell scripts' > $@
-@@ -86,12 +91,12 @@ install_ulib: File = ${LibSo}
- install_ulib: Tgt = ${DESTDIR}/ulib
- install_sbin install_ubin install_man install_ulib: ${File}
- install -d ${Tgt}
-- install -m 755 -o root -g root -p ${Opt} ${File} ${Tgt}
-+ install -m 755 -p ${Opt} ${File} ${Tgt}
- install_etc: File = etc_default_aufs
+ CFLAGS += -I./libau
+ CFLAGS += -O -Wall
+
+@@ -28,13 +33,10 @@ LibUtilObj = proc_mnt.o br.o plink.o mta
+ LibUtilHdr = au_util.h
+ export
+
+-all: ver_test ${Man} ${Bin} ${Etc}
++all: ${Man} ${Bin} ${Etc}
+ ${MAKE} -C libau $@
+ ln -sf ./libau/libau*.so .
+
+-ver_test: ver
+- ./ver
+-
+ ${Bin}: LDFLAGS += -static -s
+ ${Bin}: LDLIBS = -L. -lautil
+ ${BinObj}: %.o: %.c ${LibUtilHdr} ${LibUtil}
+@@ -63,7 +65,7 @@ aufs.5: aufs.in.5 c2tmac
+ }' aufs.in.5 >> $@
+ chmod a-w $@
+
+-.INTERMEDIATE: c2sh c2tmac ver
++.INTERMEDIATE: c2sh c2tmac
+
+ Install = install -o root -g root -p
+ install_sbin: File = mount.aufs umount.aufs auplink
+@@ -77,7 +79,7 @@ install_etc: File = etc_default_aufs
install_etc: Tgt = ${DESTDIR}/etc/default/aufs
install_etc: ${File}
install -d $(dir ${Tgt})
-- install -m 644 -o root -g root -p -T ${File} ${Tgt}
-+ install -m 644 -p -T ${File} ${Tgt}
-
- # do not inlcude install_ulib here
- install: install_man install_sbin install_ubin install_etc
+- ${Install} -m 644 -T ${File} ${Tgt}
++ ${Install} -m 644 ${File} ${Tgt}
+ install_man: File = aufs.5
+ install_man: Tgt = ${DESTDIR}/usr/share/man/man5
+ install_man: ${File}
diff --git a/package/aufs2-util/src/COPYING b/package/aufs2-util/src/COPYING
deleted file mode 100644
index f90922eea..000000000
--- a/package/aufs2-util/src/COPYING
+++ /dev/null
@@ -1,340 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 51 Franklin Street, 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 Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/package/aufs2-util/src/Makefile b/package/aufs2-util/src/Makefile
deleted file mode 100644
index 544dfc538..000000000
--- a/package/aufs2-util/src/Makefile
+++ /dev/null
@@ -1,93 +0,0 @@
-
-# Copyright (C) 2005-2010 Junjiro R. Okajima
-#
-# This program, aufs 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
-
-CFLAGS += -I./libau
-CFLAGS += -O -Wall
-
-Cmd = umount.aufs auchk aubrsync
-Man = aufs.5
-Etc = etc_default_aufs
-Bin = auplink mount.aufs #auctl
-BinObj = $(addsuffix .o, ${Bin})
-LibUtil = libautil.a
-LibUtilObj = proc_mnt.o br.o plink.o mtab.o
-LibUtilHdr = au_util.h
-export
-
-all: ${Man} ${Bin} ${Etc}
- ${MAKE} -C libau $@
- ln -sf ./libau/libau*.so .
-
-${Bin}: LDFLAGS += -static -s
-${Bin}: LDLIBS = -L. -lautil
-${BinObj}: %.o: %.c ${LibUtilHdr} ${LibUtil}
-
-${LibUtilObj}: %.o: %.c ${LibUtilHdr}
-#${LibUtil}: ${LibUtil}(${LibUtilObj})
-${LibUtil}: $(foreach o, ${LibUtilObj}, ${LibUtil}(${o}))
-.NOTPARALLEL: ${LibUtil}
-
-etc_default_aufs: c2sh aufs.shlib
- ${RM} $@
- echo '# aufs variables for shell scripts' > $@
- ./c2sh >> $@
- echo >> $@
- sed -e '0,/^$$/d' aufs.shlib >> $@
-
-aufs.5: aufs.in.5 c2tmac
- ${RM} $@
- ./c2tmac > $@
- awk '{ \
- gsub(/\140[^\047]*\047/, "\\[oq]&\\[cq]"); \
- gsub(/\\\[oq\]\140/, "\\[oq]"); \
- gsub(/\047\\\[cq\]/, "\\[cq]"); \
- gsub(/\047/, "\\[aq]"); \
- print; \
- }' aufs.in.5 >> $@
- chmod a-w $@
-
-.INTERMEDIATE: c2sh c2tmac
-
-Install = install -o root -g root -p
-install_sbin: File = mount.aufs umount.aufs auplink
-install_sbin: Tgt = ${DESTDIR}/sbin
-install_ubin: File = auchk aubrsync #auctl
-install_ubin: Tgt = ${DESTDIR}/usr/bin
-install_sbin install_ubin: ${File}
- install -d ${Tgt}
- ${Install} -m 755 ${File} ${Tgt}
-install_etc: File = etc_default_aufs
-install_etc: Tgt = ${DESTDIR}/etc/default/aufs
-install_etc: ${File}
- install -d $(dir ${Tgt})
- ${Install} -m 644 -T ${File} ${Tgt}
-install_man: File = aufs.5
-install_man: Tgt = ${DESTDIR}/usr/share/man/man5
-install_man: ${File}
- install -d ${Tgt}
- ${Install} -m 644 ${File} ${Tgt}
-install_ulib:
- ${MAKE} -C libau $@
-
-install: install_man install_sbin install_ubin install_etc install_ulib
-
-clean:
- ${RM} ${Man} ${Bin} ${Etc} ${LibUtil} libau.so* *~
- ${RM} ${BinObj} ${LibUtilObj}
- ${MAKE} -C libau $@
-
--include priv.mk
diff --git a/package/aufs2-util/src/README b/package/aufs2-util/src/README
deleted file mode 100644
index 1e1f45422..000000000
--- a/package/aufs2-util/src/README
+++ /dev/null
@@ -1,46 +0,0 @@
-
-Utilities for aufs2
-http://aufs.sf.net
-J. R. Okajima
-
-These utilities are always necessary for aufs2.
-If you forget to install them, your aufs may not work correctly.
-And these are not for aufs1 essentially, except aubrsync. See below in
-detail.
-
-Makefile in this tree has some customizable make-variables.
-- KDIR
- specify your kernel source path if necessary
-- DESTDIR
- specify your install path if necessary.
- some commands have to be installed under /sbin.
-
-o /sbin/mount.aufs, /sbin/umount.aufs
- Helpers for util-linux-ng package. You should NOT invoke them
- manually. Just install them by "make install".
-
-o /sbin/auplink
- Handles aufs pseudo-link at remount/unmount time. You can invoke it
- manually at anytime.
-
-o /usr/bin/auchk
- Similar to generic fsck. Checks whether a branch is healthy or not
- from aufs's point of view.
-
-o /usr/bin/aubrsync
- Move files from the upper writable branch to the lower branch.
- If you use this script with aufs1, then you need to install aufs.shlib
- to /usr/lib/aufs.shlib. Currently only the 20080211 version is tested
- for aufs1.
- The development of this script is sponcered by ASUSTek Computer Inc.
- (http://www.asus.com/).
- Kindly they agreed that I keep my aufs work as free software as it has
- been.
-
-o /etc/default/aufs
- A library for shell scripts.
-
-
-# Local variables: ;
-# mode: text;
-# End: ;
diff --git a/package/aufs2-util/src/au_util.h b/package/aufs2-util/src/au_util.h
deleted file mode 100644
index 21b965510..000000000
--- a/package/aufs2-util/src/au_util.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2005-2009 Junjiro Okajima
- *
- * This program, aufs 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
- */
-
-#ifndef __AUFS_UTIL_H__
-#define __AUFS_UTIL_H__
-
-#include <errno.h>
-#include <error.h>
-
-/*
- * error_at_line() is decleared with (__printf__, 5, 6) attribute,
- * and our compiler produces a warning unless args is not given.
- * __VA_ARGS__ does not help the attribute.
- */
-#define AuFin(fmt, args...) \
- error_at_line(errno, errno, __FILE__, __LINE__, fmt, ##args)
-
-#ifdef DEBUG
-#define MTab "/tmp/mtab"
-#else
-#define MTab "/etc/mtab"
-#endif
-
-/* proc_mounts.c */
-struct mntent;
-int au_proc_getmntent(char *mntpnt, struct mntent *rent);
-
-/* br.c */
-int au_br(char ***br, int *nbr, struct mntent *ent);
-
-/* plink.c */
-enum {
- AuPlink_FLUSH,
- AuPlink_CPUP,
- AuPlink_LIST
-};
-int au_plink(char cwd[], int cmd, int begin_maint, int end_maint);
-void au_plink_maint(char *path);
-
-/* mtab.c */
-void au_print_ent(struct mntent *ent);
-int au_update_mtab(char *mntpnt, int do_remount, int do_verbose);
-
-#define _Dpri(fmt, ...) printf("%s:%d:" fmt, \
- __func__, __LINE__, ##__VA_ARGS__)
-#ifdef DEBUG
-#define Dpri(fmt, ...) _Dpri(fmt, ##__VA_ARGS__)
-#else
-#define Dpri(fmt, ...) do { } while(0)
-#endif
-
-#endif /* __AUFS_UTIL_H__ */
diff --git a/package/aufs2-util/src/aubrsync b/package/aufs2-util/src/aubrsync
deleted file mode 100755
index 54adac9cb..000000000
--- a/package/aufs2-util/src/aubrsync
+++ /dev/null
@@ -1,304 +0,0 @@
-#!/bin/sh
-
-# Copyright (C) 2005-2009 Junjiro Okajima
-#
-# This program, aufs 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
-
-#
-# The development of this script is sponcered by ASUSTek Computer Inc.
-# Kindly they agreed that I keep my aufs work as free software as it has
-# been.
-#
-
-set -eu
-#set -x
-
-me=$(basename $0)
-EEcho() # str
-{
- echo ${me}: $@ 1>&2
-}
-
-f=/sbin/mount.aufs
-test ! -x $f && EEcho $f is not installed && exit 1
-
-# special handling for backward compatibility.
-#
-# aufs in the donated eeepc is aufs1 20080211 without CONFIG_AUFS_COMPAT.
-# /etc/default/aufs was introduced in aufs1 20080922.
-# shwh/noshwh was introduced in aufs1 20080310 with CONFIG_AUFS_SHWH.
-# noshwh became always available regardless CONFIG_AUFS_SHWH in aufs1 20081117.
-
-noshwh=1
-AUFS_VERSION=20080211
-f=/etc/default/aufs
-if [ -s $f ]
-then
- . $f
-else
- echo ${me}: warning, broken $f, assuming aufs is $AUFS_VERSION
- f=/usr/lib/aufs.shlib
- test ! -s $f && EEcho $f is not installed && exit 1
- . $f
-
- case $AUFS_VERSION in
- 200*) # aufs1
- test $AUFS_VERSION -lt 20081117 && noshwh=0
- ;;
- esac
- AUFS_SUPER_MAGIC=1635083891
- AUFS_SUPER_MAGIC_HEX=0x61756673
- AUFS_WH_PFX=.wh.
- AUFS_WH_PFX2=.wh..wh.
- AUFS_WH_DIROPQ=.wh..wh..opq
-fi
-
-########################################
-
-_Rsync="rsync --exclude=lost+found"
-Rsync="$_Rsync -aHSx --devices --specials --delete-before"
-Copy="$Rsync"
-Move="$Copy"
-RsyncWh="$_Rsync -ptgoHx"
-
-FindForRm() # rw
-{
- echo "find \"$1\" -xdev -depth \(
- \( ! -type d
- \( -name $AUFS_WH_DIROPQ
- -o ! -name ${AUFS_WH_PFX2}\* \) \)
- -o \( -type d
- ! -name ${AUFS_WH_PFX2}\*
- ! -wholename \"$1\"
- ! -wholename \"$1/lost+found\" \)
- \) -print0"
-}
-
-MoveWh() # rw ro+wh
-{
- cd "$1"
- find . -xdev -name ${AUFS_WH_PFX}\* ! -name ${AUFS_WH_PFX2}\* \
- -printf '%P\n' |
- while read wh
- do
- f=$(echo "$wh" | sed -e '
- s/^'${AUFS_WH_PFX}'//
- t
- s:/'${AUFS_WH_PFX}':/:
- ')
- test -e "$dst/$f" || echo "$wh"
- done |
- # -v
- $RsyncWh --files-from=- ./ "$2"
- cd "$OLDPWD"
-}
-
-copy()
-{
- $Copy $@ "$mntpnt"/ "$dst"
-}
-
-_move()
-{
- set +x
- test $hinotify -ne 1 && echo ${me}: warning, -i is not specified
- src_is_nfs=0
- test $(stat -f -c %T "$src") = nfs && src_is_nfs=1
- set $quiet
-
- $Move $@ &&
- eval $(FindForRm "$src") |
- {
- if [ $src_is_nfs -eq 1 ]
- then
- mount -o remount "$mntpnt"
- mount -o remount "$src"
- fi
- xargs -r0 rm -fr #-v
- }
-}
-
-move()
-{
- _move $@ "$mntpnt"/ "$dst"
-}
-
-move_with_wh()
-{
- {
- set +x
- MoveWh "$src" "$dst"
- set $quiet
- } &&
- move --exclude=${AUFS_WH_PFX}\*
-}
-
-# backward compatibility
-move_w()
-{
- move_with_wh $@
-}
-
-Usage()
-{
- t=$(FindForRm src_branch | sed -e '
- s/"//g
- $b
- s/$/ \\/')
-
- cat <<- EOF
- $me Options move | move_with_wh | copy \\
- mntpnt src_branch dst_branch [ options for rsync ]
-
- generic form:
- $me [ -w | --wh ] [ -i | --inotify ] Options \\
- mntpnt cmd [ parameters for cmd ]
-
- Options:
- [ -n | --dry_run ]
- [ -q | --quiet ]
-
- The dst_branch must be mounted as writable.
- During the operation, the mntpnt is set readonly.
- If you are opening a file for writing on the writable branch,
- you need to close the file before invoking this script.
- The -w or --wh option requires CONFIG_AUFS_SHWH enabled.
- The -i or --inotify option requires CONFIG_AUFS_HINOTIFY enabled.
-
- 'copy' is a shortcut for
- $me mntpnt \\
- $Copy mntpnt/ dst_branch
- 'move' is a shortcut for
- $me mntpnt \\
- "$Move \\
- mntpnt/ dst_branch && \\
- $t |\\
- xargs -r0 rm -fr"
- Note: in most cases, you will need '-i' option, and
- find(1) is invoked by $me only when rsync(1)
- succeded.
- 'move_with_wh' is a simple variation of 'move' which moves
- whiteouts separately before the actual 'move'.
-
- If you execute this script under linux-2.6.24 or earlier, the
- kernel may produce a harmless warning "inotify.c:NNN
- set_dentry_child_flags()". The message was already removed in
- linux-2.6.25.
-
- examples:
- - Copy and reflect all the modification (modifed files, newly
- created and removed ones) in the upper branch to the lower
- branch. This operation is for aufs which has only 2 branches,
- and mainly for a system shutdown script.
- All files on the upper branch remain.
-
- $ sudo $me copy /your/aufs /your/upper_branch /your/lower_branch
-
- - Like above (2 branches), move and reflect all modifications
- from upper to lower. Almost all files on the upper branch will
- be removed. You can still use this aufs after the
- operation. But the inode number may be changed. If your
- application which depends upon the inode number was running at
- that time, it may not work correctly.
-
- $ sudo $me move /your/aufs /your/upper_branch /your/lower_branch
- EOF
-
-# - Like above (2 branches), generate a new middle layer like a
-# snapshot including whiteouts and make the upper_branch almost
-# empty, but untouch the lower_branch.
-#
-# $ img=/hda1/a.ext2
-# $ dd if=/dev/zero of=\$img bs=4k count=1k
-# $ mkfs -t ext2 -F \$img
-# $ sudo mount -o rw,loop \$img /your/new_branch
-# $ sudo mount -o remount,ins:1:/your/new_branch=ro+wh /your/aufs
-# $ sudo $me _move /your/aufs /your/upper_branch /your/lower_branch \\
-# "--remove-source-files \\
-# --exclude=$AUFS_WH_BASE \\
-# --exclude=$AUFS_WH_PLINKDIR \\
-# --exclude=$AUFS_WH_TMPDIR \\
-# /your/upper_branch/ /your/new_branch; \\
-# mount -o remount,ro /your/new_branch"
-# EOF
-}
-
-########################################
-
-wh=0
-hinotify=0
-quiet=-x
-dry_run=
-cmd=
-cmd_opts=
-for i
-do
- case $i in
- -w|--wh) wh=1;;
- -i|--inotify) hinotify=1;;
- -n|--dry_run) dry_run=echo;;
- -q|--quiet) quiet=+x;;
- -h|--help) Usage; exit 0;;
- --) shift; break;;
- *) break;;
- esac
- shift
-done
-
-test $# -lt 2 && Usage 1>&2 && exit 1
-case "$1" in
-_move|move|copy|move_w|move_with_wh)
- test $# -lt 4 && Usage 1>&2 && exit 1
- cmd=$1
- SetDir mntpnt "$2"
- SetDir src "$3"
- SetDir dst "$4"
- shift 4
- wh=0
- ;;
-*)
- SetDir mntpnt "$1"
- cmd="$2"
- shift 2
- ;;
-esac
-cmd_opts="$@"
-
-case $(stat -f -c %T "$mntpnt") in
-aufs|UNKNOWN*${AUFS_SUPER_MAGIC_HEX}*) ;;
-*)
- EEcho "$mntpnt" is not aufs
- exit 1
- ;;
-esac
-
-cur_opts=$(MntOpts "$mntpnt")
-test ! "$cur_opts" &&
-EEcho bad /proc/mounts or "$mntpnt" is not mounted &&
-exit 1
-cur_opts="udba=reval,noshwh,$cur_opts"
-test $noshwh -eq 0 && cur_opts=$(echo $cur_opts | sed -e 's/,noshwh//')
-
-# force flushing the pusedo-links
-tmp_opts="remount,ro,udba=reval,noshwh"
-test $noshwh -eq 0 && tmp_opts=$(echo $tmp_opts | sed -e 's/,noshwh//')
-test $wh -eq 1 && tmp_opts="$tmp_opts,shwh"
-test $hinotify -eq 1 && tmp_opts="$tmp_opts,udba=inotify"
-
-# here we go
-trap "$dry_run mount -o remount,$cur_opts \"$mntpnt\"" EXIT
-set $quiet
-$dry_run mount -o $tmp_opts "$mntpnt"
-eval "$dry_run $cmd $cmd_opts"
diff --git a/package/aufs2-util/src/auchk b/package/aufs2-util/src/auchk
deleted file mode 100755
index 26a3d8027..000000000
--- a/package/aufs2-util/src/auchk
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/bin/sh -
-
-# Copyright (C) 2005-2009 Junjiro Okajima
-#
-# This program, aufs 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
-
-set -eu
-#set -x
-
-EEcho() # str
-{
- echo $0: $@ 1>&2
-}
-
-f=/etc/default/aufs
-. $f
-
-Usage()
-{
- echo $0 writable_branch '[...]'
-}
-
-Pass() # title
-{
- pass=$(($pass + 1))
- EEcho \[Pass $pass\] $@
-}
-
-Remove() # file
-{
- if [ -d "$1" ]
- then
- rm -ir "$1" || :
- else
- rm -v "$1" || :
- fi
-}
-
-for i
-do
- EEcho Checking "$i" for aufs
-
- cd "$i"
- case $(stat -f -c %T .) in
- aufs|UNKNOWN*${AUFS_SUPER_MAGIC_HEX}*)
- EEcho $i must not be aufs
- cd $OLDPWD
- continue
- ;;
- esac
-
- ########################################
- pass=0
- Pass Illegal whiteout
- find . -name '.wh.*' ! -name '.wh..wh.*' -printf '%h\0%f\0' |
- xargs -r0n2 |
- while read dir wh
- do
- #echo \""$dir"\" \""$wh"\"
- base=$(echo "$wh" | cut -c5-)
- test ! -e "$dir/$base" && continue
-
- ls -ld "$dir/$wh" "$dir/$base"
- read -p 'Which to remove [whiteout/real/skip]? ' ans \
- < /dev/tty > /dev/tty 2>&1
- case "$ans" in
- [wW]*) Remove "$dir/$wh" || :;;
- [rR]*) Remove "$dir/$base" || :;;
- *) echo skipped;;
- esac
- done
-
- ########################################
- Pass Remained pseudo-links
- did=0
- for plink in ${AUFS_WH_PLINKDIR}/*
- do
- test ! -e "$plink" && break
- if [ -d "$plink" ]
- then
- EEcho illegal "$plink"
- continue
- fi
-
- did=1
- #ls -l "$plink" || :
- find . -inum $(basename "$plink" | cut -f2 -d .) -ls || :
- done
- if [ $did -ne 0 ]
- then
- cat <<- EOF
- They will be maintained at remount or umount time,
- if you installed aufs helper scripts (See README
- in detail).
- If "$i" is not a writeble branch of CURRENTLY mounted
- aufs, you need to maintain them by yourself.
- EOF
- fi
-
- ########################################
- Pass Remained temp files
- for tmp in ${AUFS_WH_TMPDIR}/*
- do
- test ! -e "$tmp" && break
- if [ -d "$tmp" ]
- then
- EEcho illegal "$tmp"
- continue
- fi
-
- ls -l "$tmp" || :
- rm -i "$tmp" || :
- done
-
- # nothing to do for xinodir
-
- cd $OLDPWD
-done
diff --git a/package/aufs2-util/src/aufs.in.5 b/package/aufs2-util/src/aufs.in.5
deleted file mode 100644
index 0cbb14487..000000000
--- a/package/aufs2-util/src/aufs.in.5
+++ /dev/null
@@ -1,1684 +0,0 @@
-.\".so aufs.tmac
-.
-.eo
-.de TQ
-.br
-.ns
-.TP \$1
-..
-.de Bu
-.IP \(bu 4
-..
-.ec
-.\" end of macro definitions
-.
-.\" ----------------------------------------------------------------------
-.TH aufs 5 \*[AUFS_VERSION] Linux "Linux Aufs User's Manual"
-.SH NAME
-aufs \- advanced multi layered unification filesystem. version \*[AUFS_VERSION]
-
-.\" ----------------------------------------------------------------------
-.SH DESCRIPTION
-Aufs is a stackable unification filesystem such as Unionfs, which unifies
-several directories and provides a merged single directory.
-In the early days, aufs was entirely re-designed and re-implemented
-Unionfs Version 1.x series. After
-many original ideas, approaches and improvements, it
-becomes totally different from Unionfs while keeping the basic features.
-See Unionfs Version 1.x series for the basic features.
-Recently, Unionfs Version 2.x series begin taking some of same
-approaches to aufs's.
-
-.\" ----------------------------------------------------------------------
-.SH MOUNT OPTIONS
-At mount-time, the order of interpreting options is,
-.RS
-.Bu
-simple flags, except xino/noxino and udba=inotify
-.Bu
-branches
-.Bu
-xino/noxino
-.Bu
-udba=inotify
-.RE
-
-At remount-time,
-the options are interpreted in the given order,
-e.g. left to right.
-.RS
-.Bu
-create or remove
-whiteout-base(\*[AUFS_WH_BASE]) and
-whplink-dir(\*[AUFS_WH_PLINKDIR]) if necessary
-.RE
-.
-.TP
-.B br:BRANCH[:BRANCH ...] (dirs=BRANCH[:BRANCH ...])
-Adds new branches.
-(cf. Branch Syntax).
-
-Aufs rejects the branch which is an ancestor or a descendant of another
-branch. It is called overlapped. When the branch is loopback-mounted
-directory, aufs also checks the source fs-image file of loopback
-device. If the source file is a descendant of another branch, it will
-be rejected too.
-
-After mounting aufs or adding a branch, if you move a branch under
-another branch and make it descendant of another branch, aufs will not
-work correctly.
-.
-.TP
-.B [ add | ins ]:index:BRANCH
-Adds a new branch.
-The index begins with 0.
-Aufs creates
-whiteout-base(\*[AUFS_WH_BASE]) and
-whplink-dir(\*[AUFS_WH_PLINKDIR]) if necessary.
-
-If there is the same named file on the lower branch (larger index),
-aufs will hide the lower file.
-You can only see the highest file.
-You will be confused if the added branch has whiteouts (including
-diropq), they may or may not hide the lower entries.
-.\" It is recommended to make sure that the added branch has no whiteout.
-
-Even if a process have once mapped a file by mmap(2) with MAP_SHARED
-and the same named file exists on the lower branch,
-the process still refers the file on the lower(hidden)
-branch after adding the branch.
-If you want to update the contents of a process address space after
-adding, you need to restart your process or open/mmap the file again.
-.\" Usually, such files are executables or shared libraries.
-(cf. Branch Syntax).
-.
-.TP
-.B del:dir
-Removes a branch.
-Aufs does not remove
-whiteout-base(\*[AUFS_WH_BASE]) and
-whplink-dir(\*[AUFS_WH_PLINKDIR]) automatically.
-For example, when you add a RO branch which was unified as RW, you
-will see whiteout-base or whplink-dir on the added RO branch.
-
-If a process is referencing the file/directory on the deleting branch
-(by open, mmap, current working directory, etc.), aufs will return an
-error EBUSY.
-.
-.TP
-.B mod:BRANCH
-Modifies the permission flags of the branch.
-Aufs creates or removes
-whiteout-base(\*[AUFS_WH_BASE]) and/or
-whplink-dir(\*[AUFS_WH_PLINKDIR]) if necessary.
-
-If the branch permission is been changing `rw' to `ro', and a process
-is mapping a file by mmap(2)
-.\" with MAP_SHARED
-on the branch, the process may or may not
-be able to modify its mapped memory region after modifying branch
-permission flags.
-Additioanlly when you enable CONFIG_IMA (in linux-2.6.30 and later), IMA
-may produce some wrong messages. But this is equivalent when the
-filesystem is changed `ro' in emergency.
-(cf. Branch Syntax).
-.
-.TP
-.B append:BRANCH
-equivalent to `add:(last index + 1):BRANCH'.
-(cf. Branch Syntax).
-.
-.TP
-.B prepend:BRANCH
-equivalent to `add:0:BRANCH.'
-(cf. Branch Syntax).
-.
-.TP
-.B xino=filename
-Use external inode number bitmap and translation table.
-When CONFIG_AUFS_EXPORT is enabled, external inode generation table too.
-It is set to
-<FirstWritableBranch>/\*[AUFS_XINO_FNAME] by default, or
-\*[AUFS_XINO_DEFPATH].
-Comma character in filename is not allowed.
-
-The files are created per an aufs and per a branch filesystem, and
-unlinked. So you
-cannot find this file, but it exists and is read/written frequently by
-aufs.
-(cf. External Inode Number Bitmap, Translation Table and Generation Table).
-
-If you enable CONFIG_SYSFS, the path of xino files are not shown in
-/proc/mounts (and /etc/mtab), instead it is shown in
-<sysfs>/fs/aufs/si_<id>/xi_path.
-Otherwise, it is shown in /proc/mounts unless it is not the default
-path.
-.
-.TP
-.B noxino
-Stop using external inode number bitmap and translation table.
-
-If you use this option,
-Some applications will not work correctly.
-.\" And pseudo link feature will not work after the inode cache is
-.\" shrunk.
-(cf. External Inode Number Bitmap, Translation Table and Generation Table).
-.
-.TP
-.B trunc_xib
-Truncate the external inode number bitmap file. The truncation is done
-automatically when you delete a branch unless you do not specify
-`notrunc_xib' option.
-(cf. External Inode Number Bitmap, Translation Table and Generation Table).
-.
-.TP
-.B notrunc_xib
-Stop truncating the external inode number bitmap file when you delete
-a branch.
-(cf. External Inode Number Bitmap, Translation Table and Generation Table).
-.
-.TP
-.B create_policy | create=CREATE_POLICY
-.TQ
-.B copyup_policy | copyup | cpup=COPYUP_POLICY
-Policies to select one among multiple writable branches. The default
-values are `create=tdp' and `cpup=tdp'.
-link(2) and rename(2) systemcalls have an exception. In aufs, they
-try keeping their operations in the branch where the source exists.
-(cf. Policies to Select One among Multiple Writable Branches).
-.
-.TP
-.B verbose | v
-Print some information.
-Currently, it is only busy file (or inode) at deleting a branch.
-.
-.TP
-.B noverbose | quiet | q | silent
-Disable `verbose' option.
-This is default value.
-.
-.TP
-.B sum
-df(1)/statfs(2) returns the total number of blocks and inodes of
-all branches.
-Note that there are cases that systemcalls may return ENOSPC, even if
-df(1)/statfs(2) shows that aufs has some free space/inode.
-.
-.TP
-.B nosum
-Disable `sum' option.
-This is default value.
-.
-.TP
-.B dirwh=N
-Watermark to remove a dir actually at rmdir(2) and rename(2).
-
-If the target dir which is being removed or renamed (destination dir)
-has a huge number of whiteouts, i.e. the dir is empty logically but
-physically, the cost to remove/rename the single
-dir may be very high.
-It is
-required to unlink all of whiteouts internally before issuing
-rmdir/rename to the branch.
-To reduce the cost of single systemcall,
-aufs renames the target dir to a whiteout-ed temporary name and
-invokes a pre-created
-kernel thread to remove whiteout-ed children and the target dir.
-The rmdir/rename systemcall returns just after kicking the thread.
-
-When the number of whiteout-ed children is less than the value of
-dirwh, aufs remove them in a single systemcall instead of passing
-another thread.
-This value is ignored when the branch is NFS.
-The default value is \*[AUFS_DIRWH_DEF].
-.\" .
-.\" .TP
-.\" .B rdcache=N
-.
-.TP
-.B rdblk=N
-Specifies a size of internal VDIR block which is allocated at a time in
-byte.
-The VDIR block will be allocated several times when necessary. If your
-directory has millions of files, you may want to expand this size.
-The default value is defined as \*[AUFS_RDBLK_DEF].
-The size has to be lager than NAME_MAX (usually 255) and kmalloc\-able
-(the maximum limit depends on your system. at least 128KB is available
-for every system).
-Whenever you can reset the value to default by specifying rdblk=def.
-(cf. Virtual or Vertical Directory Block).
-.
-.TP
-.B rdhash=N
-Specifies a size of internal VDIR hash table which is used to compare
-the file names under the same named directory on multiple branches.
-The VDIR hash table will be allocated in readdir(3)/getdents(2),
-rmdir(2) and rename(2) for the existing target directory. If your
-directory has millions of files, you may want to expand this size.
-The default value is defined as \*[AUFS_RDHASH_DEF].
-The size has to be lager than zero, and it will be multiplied by 4 or 8
-(for 32\-bit and 64\-bit respectively, currently). The result must be
-kmalloc\-able
-(the maximum limit depends on your system. at least 128KB is available
-for every system).
-Whenever you can reset the value to default by specifying rdhash=def.
-(cf. Virtual or Vertical Directory Block).
-.
-.TP
-.B plink
-.TQ
-.B noplink
-Specifies to use `pseudo link' feature or not.
-The default is `plink' which means use this feature.
-(cf. Pseudo Link)
-.
-.TP
-.B clean_plink
-Removes all pseudo-links in memory.
-In order to make pseudo-link permanent, use
-`auplink' utility just before one of these operations,
-unmounting aufs,
-using `ro' or `noplink' mount option,
-deleting a branch from aufs,
-adding a branch into aufs,
-or changing your writable branch as readonly.
-If you installed both of /sbin/mount.aufs and /sbin/umount.aufs, and your
-mount(8) and umount(8) support them,
-`auplink' utility will be executed automatically and flush pseudo-links.
-(cf. Pseudo Link)
-.
-.TP
-.B udba=none | reval | inotify
-Specifies the level of UDBA (User's Direct Branch Access) test.
-(cf. User's Direct Branch Access and Inotify Limitation).
-.
-.TP
-.B diropq=whiteouted | w | always | a
-Specifies whether mkdir(2) and rename(2) dir case make the created directory
-`opaque' or not.
-In other words, to create `\*[AUFS_WH_DIROPQ]' under the created or renamed
-directory, or not to create.
-When you specify diropq=w or diropq=whiteouted, aufs will not create
-it if the
-directory was not whiteouted or opaqued. If the directory was whiteouted
-or opaqued, the created or renamed directory will be opaque.
-When you specify diropq=a or diropq==always, aufs will always create
-it regardless
-the directory was whiteouted/opaqued or not.
-The default value is diropq=w, it means not to create when it is unnecessary.
-If you define CONFIG_AUFS_COMPAT at aufs compiling time, the default will be
-diropq=a.
-You need to consider this option if you are planning to add a branch later
-since `diropq' affects the same named directory on the added branch.
-.
-.TP
-.B warn_perm
-.TQ
-.B nowarn_perm
-Adding a branch, aufs will issue a warning about uid/gid/permission of
-the adding branch directory,
-when they differ from the existing branch's. This difference may or
-may not impose a security risk.
-If you are sure that there is no problem and want to stop the warning,
-use `nowarn_perm' option.
-The default is `warn_perm' (cf. DIAGNOSTICS).
-.
-.TP
-.B shwh
-.TQ
-.B noshwh
-By default (noshwh), aufs doesn't show the whiteouts and
-they just hide the same named entries in the lower branches. The
-whiteout itself also never be appeared.
-If you enable CONFIG_AUFS_SHWH and specify `shwh' option, aufs
-will show you the name of whiteouts
-with keeping its feature to hide the lowers.
-Honestly speaking, I am rather confused with this `visible whiteouts.'
-But a user who originally requested this feature wrote a nice how-to
-document about this feature. See Tips file in the aufs CVS tree.
-
-.\" ----------------------------------------------------------------------
-.SH Module Parameters
-.TP
-.B nwkq=N
-The number of kernel thread named \*[AUFS_WKQ_NAME].
-
-Those threads stay in the system while the aufs module is loaded,
-and handle the special I/O requests from aufs.
-The default value is \*[AUFS_NWKQ_DEF].
-
-The special I/O requests from aufs include a part of copy-up, lookup,
-directory handling, pseudo-link, xino file operations and the
-delegated access to branches.
-For example, Unix filesystems allow you to rmdir(2) which has no write
-permission bit, if its parent directory has write permission bit. In aufs, the
-removing directory may or may not have whiteout or `dir opaque' mark as its
-child. And aufs needs to unlink(2) them before rmdir(2).
-Therefore aufs delegates the actual unlink(2) and rmdir(2) to another kernel
-thread which has been created already and has a superuser privilege.
-
-If you enable CONFIG_SYSFS, you can check this value through
-<sysfs>/module/aufs/parameters/nwkq.
-
-.
-.TP
-.B brs=1 | 0
-Specifies to use the branch path data file under sysfs or not.
-
-If the number of your branches is large or their path is long
-and you meet the limitation of mount(8) ro /etc/mtab, you need to
-enable CONFIG_SYSFS and set aufs module parameter brs=1.
-
-When this parameter is set as 1, aufs does not show `br:' (or dirs=)
-mount option through /proc/mounts (and /etc/mtab). So you can
-keep yourself from the page limitation of
-mount(8) or /etc/mtab.
-Aufs shows branch paths through <sysfs>/fs/aufs/si_XXX/brNNN.
-Actually the file under sysfs has also a size limitation, but I don't
-think it is harmful.
-
-There is one more side effect in setting 1 to this parameter.
-If you rename your branch, the branch path written in /etc/mtab will be
-obsoleted and the future remount will meet some error due to the
-unmatched parameters (Remember that mount(8) may take the options from
-/etc/mtab and pass them to the systemcall).
-If you set 1, /etc/mtab will not hold the branch path and you will not
-meet such trouble. On the other hand, the entries for the
-branch path under sysfs are generated dynamically. So it must not be obsoleted.
-But I don't think users want to rename branches so often.
-
-If CONFIG_SYSFS is disable, this parameter is always set to 0.
-.
-.TP
-.B sysrq=key
-Specifies MagicSysRq key for debugging aufs.
-You need to enable both of CONFIG_MAGIC_SYSRQ and CONFIG_AUFS_DEBUG.
-Currently this is for developers only.
-The default is `a'.
-.
-.TP
-.B debug= 0 | 1
-Specifies disable(0) or enable(1) debug print in aufs.
-This parameter can be changed dynamically.
-You need to enable CONFIG_AUFS_DEBUG.
-Currently this is for developers only.
-The default is `0' (disable).
-
-.\" ----------------------------------------------------------------------
-.SH Entries under Sysfs and Debugfs
-See linux/Documentation/ABI/*/{sys,debug}fs-aufs.
-
-.\" ----------------------------------------------------------------------
-.SH Branch Syntax
-.TP
-.B dir_path[ =permission [ + attribute ] ]
-.TQ
-.B permission := rw | ro | rr
-.TQ
-.B attribute := wh | nolwh
-dir_path is a directory path.
-The keyword after `dir_path=' is a
-permission flags for that branch.
-Comma, colon and the permission flags string (including `=')in the path
-are not allowed.
-
-Any filesystem can be a branch, But some are not accepted such like
-sysfs, procfs and unionfs.
-If you specify such filesystems as an aufs branch, aufs will return an error
-saying it is unsupported.
-
-Cramfs in linux stable release has strange inodes and it makes aufs
-confused. For example,
-.nf
-$ mkdir -p w/d1 w/d2
-$ > w/z1
-$ > w/z2
-$ mkcramfs w cramfs
-$ sudo mount -t cramfs -o ro,loop cramfs /mnt
-$ find /mnt -ls
- 76 1 drwxr-xr-x 1 jro 232 64 Jan 1 1970 /mnt
- 1 1 drwxr-xr-x 1 jro 232 0 Jan 1 1970 /mnt/d1
- 1 1 drwxr-xr-x 1 jro 232 0 Jan 1 1970 /mnt/d2
- 1 1 -rw-r--r-- 1 jro 232 0 Jan 1 1970 /mnt/z1
- 1 1 -rw-r--r-- 1 jro 232 0 Jan 1 1970 /mnt/z2
-.fi
-
-All these two directories and two files have the same inode with one
-as their link count. Aufs cannot handle such inode correctly.
-Currently, aufs involves a tiny workaround for such inodes. But some
-applications may not work correctly since aufs inode number for such
-inode will change silently.
-If you do not have any empty files, empty directories or special files,
-inodes on cramfs will be all fine.
-
-A branch should not be shared as the writable branch between multiple
-aufs. A readonly branch can be shared.
-
-The maximum number of branches is configurable at compile time (127 by
-default).
-
-When an unknown permission or attribute is given, aufs sets ro to that
-branch silently.
-
-.SS Permission
-.
-.TP
-.B rw
-Readable and writable branch. Set as default for the first branch.
-If the branch filesystem is mounted as readonly, you cannot set it `rw.'
-.\" A filesystem which does not support link(2) and i_op\->setattr(), for
-.\" example FAT, will not be used as the writable branch.
-.
-.TP
-.B ro
-Readonly branch and it has no whiteouts on it.
-Set as default for all branches except the first one. Aufs never issue
-both of write operation and lookup operation for whiteout to this branch.
-.
-.TP
-.B rr
-Real readonly branch, special case of `ro', for natively readonly
-branch. Assuming the branch is natively readonly, aufs can optimize
-some internal operation. For example, if you specify `udba=inotify'
-option, aufs does not set inotify for the things on rr branch.
-Set by default for a branch whose fs-type is either `iso9660',
-`cramfs' or `romfs' (and `squashfs' for linux\-2.6.29 and later).
-
-When your branch exists on slower device and you have some
-capacity on your hdd, you may want to try ulobdev tool in ULOOP sample.
-It can cache the contents of the real devices on another faster device,
-so you will be able to get the better access performance.
-The ulobdev tool is for a generic block device, and the ulohttp is for a
-filesystem image on http server.
-If you want to spin down your hdd to save the
-battery life or something, then you may want to use ulobdev to save the
-access to the hdd, too.
-See $AufsCVS/sample/uloop in detail.
-
-.SS Attribute
-.
-.TP
-.B wh
-Readonly branch and it has/might have whiteouts on it.
-Aufs never issue write operation to this branch, but lookup for whiteout.
-Use this as `<branch_dir>=ro+wh'.
-.
-.TP
-.B nolwh
-Usually, aufs creates a whiteout as a hardlink on a writable
-branch. This attributes prohibits aufs to create the hardlinked
-whiteout, including the source file of all hardlinked whiteout
-(\*[AUFS_WH_BASE].)
-If you do not like a hardlink, or your writable branch does not support
-link(2), then use this attribute.
-But I am afraid a filesystem which does not support link(2) natively
-will fail in other place such as copy-up.
-Use this as `<branch_dir>=rw+nolwh'.
-Also you may want to try `noplink' mount option, while it is not recommended.
-
-.\" .SS FUSE as a branch
-.\" A FUSE branch needs special attention.
-.\" The struct fuse_operations has a statfs operation. It is OK, but the
-.\" parameter is struct statvfs* instead of struct statfs*. So almost
-.\" all user\-space implementation will call statvfs(3)/fstatvfs(3) instead of
-.\" statfs(2)/fstatfs(2).
-.\" In glibc, [f]statvfs(3) issues [f]statfs(2), open(2)/read(2) for
-.\" /proc/mounts,
-.\" and stat(2) for the mountpoint. With this situation, a FUSE branch will
-.\" cause a deadlock in creating something in aufs. Here is a sample
-.\" scenario,
-.\" .\" .RS
-.\" .\" .IN -10
-.\" .Bu
-.\" create/modify a file just under the aufs root dir.
-.\" .Bu
-.\" aufs acquires a write\-lock for the parent directory, ie. the root dir.
-.\" .Bu
-.\" A library function or fuse internal may call statfs for a fuse branch.
-.\" The create=mfs mode in aufs will surely call statfs for each writable
-.\" branches.
-.\" .Bu
-.\" FUSE in kernel\-space converts and redirects the statfs request to the
-.\" user\-space.
-.\" .Bu
-.\" the user\-space statfs handler will call [f]statvfs(3).
-.\" .Bu
-.\" the [f]statvfs(3) in glibc will access /proc/mounts and issue
-.\" stat(2) for the mountpoint. But those require a read\-lock for the aufs
-.\" root directory.
-.\" .Bu
-.\" Then a deadlock occurs.
-.\" .\" .RE 1
-.\" .\" .IN
-.\"
-.\" In order to avoid this deadlock, I would suggest not to call
-.\" [f]statvfs(3) from fuse. Here is a sample code to do this.
-.\" .nf
-.\" struct statvfs stvfs;
-.\"
-.\" main()
-.\" {
-.\" statvfs(..., &stvfs)
-.\" or
-.\" fstatvfs(..., &stvfs)
-.\" stvfs.f_fsid = 0
-.\" }
-.\"
-.\" statfs_handler(const char *path, struct statvfs *arg)
-.\" {
-.\" struct statfs stfs
-.\"
-.\" memcpy(arg, &stvfs, sizeof(stvfs))
-.\"
-.\" statfs(..., &stfs)
-.\" or
-.\" fstatfs(..., &stfs)
-.\"
-.\" arg->f_bfree = stfs.f_bfree
-.\" arg->f_bavail = stfs.f_bavail
-.\" arg->f_ffree = stfs.f_ffree
-.\" arg->f_favail = /* any value */
-.\" }
-.\" .fi
-
-.\" ----------------------------------------------------------------------
-.SH External Inode Number Bitmap, Translation Table and Generation Table (xino)
-Aufs uses one external bitmap file and one external inode number
-translation table files per an aufs and per a branch
-filesystem by default.
-Additionally when CONFIG_AUFS_EXPORT is enabled, one external inode
-generation table is added.
-The bitmap (and the generation table) is for recycling aufs inode number
-and the others
-are a table for converting an inode number on a branch to
-an aufs inode number. The default path
-is `first writable branch'/\*[AUFS_XINO_FNAME].
-If there is no writable branch, the
-default path
-will be \*[AUFS_XINO_DEFPATH].
-.\" A user who executes mount(8) needs the privilege to create xino
-.\" file.
-
-If you enable CONFIG_SYSFS, the path of xino files are not shown in
-/proc/mounts (and /etc/mtab), instead it is shown in
-<sysfs>/fs/aufs/si_<id>/xi_path.
-Otherwise, it is shown in /proc/mounts unless it is not the default
-path.
-
-Those files are always opened and read/write by aufs frequently.
-If your writable branch is on flash memory device, it is recommended
-to put xino files on other than flash memory by specifying `xino='
-mount option.
-
-The
-maximum file size of the bitmap is, basically, the amount of the
-number of all the files on all branches divided by 8 (the number of
-bits in a byte).
-For example, on a 4KB page size system, if you have 32,768 (or
-2,599,968) files in aufs world,
-then the maximum file size of the bitmap is 4KB (or 320KB).
-
-The
-maximum file size of the table will
-be `max inode number on the branch x size of an inode number'.
-For example in 32bit environment,
-
-.nf
-$ df -i /branch_fs
-/dev/hda14 2599968 203127 2396841 8% /branch_fs
-.fi
-
-and /branch_fs is an branch of the aufs. When the inode number is
-assigned contiguously (without `hole'), the maximum xino file size for
-/branch_fs will be 2,599,968 x 4 bytes = about 10 MB. But it might not be
-allocated all of disk blocks.
-When the inode number is assigned discontinuously, the maximum size of
-xino file will be the largest inode number on a branch x 4 bytes.
-Additionally, the file size is limited to LLONG_MAX or the s_maxbytes
-in filesystem's superblock (s_maxbytes may be smaller than
-LLONG_MAX). So the
-support-able largest inode number on a branch is less than
-2305843009213693950 (LLONG_MAX/4\-1).
-This is the current limitation of aufs.
-On 64bit environment, this limitation becomes more strict and the
-supported largest inode number is less than LLONG_MAX/8\-1.
-
-The xino files are always hidden, i.e. removed. So you cannot
-do `ls \-l xino_file'.
-If you enable CONFIG_DEBUG_FS, you can check these information through
-<debugfs>/aufs/<si_id>/{xib,xi[0-9]*,xigen}. xib is for the bitmap file,
-xi0 ix for the first branch, and xi1 is for the next. xigen is for the
-generation table.
-xib and xigen are in the format of,
-
-.nf
-<blocks>x<block size> <file size>
-.fi
-
-Note that a filesystem usually has a
-feature called pre-allocation, which means a number of
-blocks are allocated automatically, and then deallocated
-silently when the filesystem thinks they are unnecessary.
-You do not have to be surprised the sudden changes of the number of
-blocks, when your filesystem which xino files are placed supports the
-pre-allocation feature.
-
-The rests are hidden xino file information in the format of,
-
-.nf
-<file count>, <blocks>x<block size> <file size>
-.fi
-
-If the file count is larger than 1, it means some of your branches are
-on the same filesystem and the xino file is shared by them.
-Note that the file size may not be equal to the actual consuming blocks
-since xino file is a sparse file, i.e. a hole in a file which does not
-consume any disk blocks.
-
-Once you unmount aufs, the xino files for that aufs are totally gone.
-It means that the inode number is not permanent across umount or
-shutdown.
-
-The xino files should be created on the filesystem except NFS.
-If your first writable branch is NFS, you will need to specify xino
-file path other than NFS.
-Also if you are going to remove the branch where xino files exist or
-change the branch permission to readonly, you need to use xino option
-before del/mod the branch.
-
-The bitmap file can be truncated.
-For example, if you delete a branch which has huge number of files,
-many inode numbers will be recycled and the bitmap will be truncated
-to smaller size. Aufs does this automatically when a branch is
-deleted.
-You can truncate it anytime you like if you specify `trunc_xib' mount
-option. But when the accessed inode number was not deleted, nothing
-will be truncated.
-If you do not want to truncate it (it may be slow) when you delete a
-branch, specify `notrunc_xib' after `del' mount option.
-
-If you do not want to use xino, use noxino mount option. Use this
-option with care, since the inode number may be changed silently and
-unexpectedly anytime.
-For example,
-rmdir failure, recursive chmod/chown/etc to a large and deep directory
-or anything else.
-And some applications will not work correctly.
-.\" When the inode number has been changed, your system
-.\" can be crazy.
-If you want to change the xino default path, use xino mount option.
-
-After you add branches, the persistence of inode number may not be
-guaranteed.
-At remount time, cached but unused inodes are discarded.
-And the newly appeared inode may have different inode number at the
-next access time. The inodes in use have the persistent inode number.
-
-When aufs assigned an inode number to a file, and if you create the
-same named file on the upper branch directly, then the next time you
-access the file, aufs may assign another inode number to the file even
-if you use xino option.
-Some applications may treat the file whose inode number has been
-changed as totally different file.
-
-.\" ----------------------------------------------------------------------
-.SH Pseudo Link (hardlink over branches)
-Aufs supports `pseudo link' which is a logical hard-link over
-branches (cf. ln(1) and link(2)).
-In other words, a copied-up file by link(2) and a copied-up file which was
-hard-linked on a readonly branch filesystem.
-
-When you have files named fileA and fileB which are
-hardlinked on a readonly branch, if you write something into fileA,
-aufs copies-up fileA to a writable branch, and write(2) the originally
-requested thing to the copied-up fileA. On the writable branch,
-fileA is not hardlinked.
-But aufs remembers it was hardlinked, and handles fileB as if it existed
-on the writable branch, by referencing fileA's inode on the writable
-branch as fileB's inode.
-
-Once you unmount aufs, the plink info for that aufs kept in memory are totally
-gone.
-It means that the pseudo-link is not permanent.
-If you want to make plink permanent, try `auplink' utility just before
-one of these operations,
-unmounting your aufs,
-using `ro' or `noplink' mount option,
-deleting a branch from aufs,
-adding a branch into aufs,
-or changing your writable branch to readonly.
-
-This utility will reproduces all real hardlinks on a writable branch by linking
-them, and removes pseudo-link info in memory and temporary link on the
-writable branch.
-Since this utility access your branches directly, you cannot hide them by
-`mount \-\-bind /tmp /branch' or something.
-
-If you are willing to rebuild your aufs with the same branches later, you
-should use auplink utility before you umount your aufs.
-If you installed both of /sbin/mount.aufs and /sbin/umount.aufs, and your
-mount(8) and umount(8) support them,
-`auplink' utility will be executed automatically and flush pseudo-links.
-
-.nf
-# auplink /your/aufs/root flush
-# umount /your/aufs/root
-or
-# auplink /your/aufs/root flush
-# mount -o remount,mod:/your/writable/branch=ro /your/aufs/root
-or
-# auplink /your/aufs/root flush
-# mount -o remount,noplink /your/aufs/root
-or
-# auplink /your/aufs/root flush
-# mount -o remount,del:/your/aufs/branch /your/aufs/root
-or
-# auplink /your/aufs/root flush
-# mount -o remount,append:/your/aufs/branch /your/aufs/root
-.fi
-
-The plinks are kept both in memory and on disk. When they consumes too much
-resources on your system, you can use the `auplink' utility at anytime and
-throw away the unnecessary pseudo-links in safe.
-
-Additionally, the `auplink' utility is very useful for some security reasons.
-For example, when you have a directory whose permission flags
-are 0700, and a file who is 0644 under the 0700 directory. Usually,
-all files under the 0700 directory are private and no one else can see
-the file. But when the directory is 0711 and someone else knows the 0644
-filename, he can read the file.
-
-Basically, aufs pseudo-link feature creates a temporary link under the
-directory whose owner is root and the permission flags are 0700.
-But when the writable branch is NFS, aufs sets 0711 to the directory.
-When the 0644 file is pseudo-linked, the temporary link, of course the
-contents of the file is totally equivalent, will be created under the
-0711 directory. The filename will be generated by its inode number.
-While it is hard to know the generated filename, someone else may try peeping
-the temporary pseudo-linked file by his software tool which may try the name
-from one to MAX_INT or something.
-In this case, the 0644 file will be read unexpectedly.
-I am afraid that leaving the temporary pseudo-links can be a security hole.
-It makes sense to execute `auplink /your/aufs/root flush'
-periodically, when your writable branch is NFS.
-
-When your writable branch is not NFS, or all users are careful enough to set 0600
-to their private files, you do not have to worry about this issue.
-
-If you do not want this feature, use `noplink' mount option.
-
-.SS The behaviours of plink and noplink
-This sample shows that the `f_src_linked2' with `noplink' option cannot follow
-the link.
-
-.nf
-none on /dev/shm/u type aufs (rw,xino=/dev/shm/rw/.aufs.xino,br:/dev/shm/rw=rw:/dev/shm/ro=ro)
-$ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
-ls: ./copied: No such file or directory
-15 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
-15 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
-22 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ./f_src_linked
-22 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ./f_src_linked2
-$ echo abc >> f_src_linked
-$ cp f_src_linked copied
-$ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
-15 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
-15 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
-36 -rw-r--r-- 2 jro jro 6 Dec 22 11:03 ../rw/f_src_linked
-53 -rw-r--r-- 1 jro jro 6 Dec 22 11:03 ./copied
-22 -rw-r--r-- 2 jro jro 6 Dec 22 11:03 ./f_src_linked
-22 -rw-r--r-- 2 jro jro 6 Dec 22 11:03 ./f_src_linked2
-$ cmp copied f_src_linked2
-$
-
-none on /dev/shm/u type aufs (rw,xino=/dev/shm/rw/.aufs.xino,noplink,br:/dev/shm/rw=rw:/dev/shm/ro=ro)
-$ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
-ls: ./copied: No such file or directory
-17 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
-17 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
-23 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ./f_src_linked
-23 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ./f_src_linked2
-$ echo abc >> f_src_linked
-$ cp f_src_linked copied
-$ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
-17 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
-17 -rw-r--r-- 2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
-36 -rw-r--r-- 1 jro jro 6 Dec 22 11:03 ../rw/f_src_linked
-53 -rw-r--r-- 1 jro jro 6 Dec 22 11:03 ./copied
-23 -rw-r--r-- 2 jro jro 6 Dec 22 11:03 ./f_src_linked
-23 -rw-r--r-- 2 jro jro 6 Dec 22 11:03 ./f_src_linked2
-$ cmp copied f_src_linked2
-cmp: EOF on f_src_linked2
-$
-.fi
-
-.\"
-.\" If you add/del a branch, or link/unlink the pseudo-linked
-.\" file on a branch
-.\" directly, aufs cannot keep the correct link count, but the status of
-.\" `pseudo-linked.'
-.\" Those files may or may not keep the file data after you unlink the
-.\" file on the branch directly, especially the case of your branch is
-.\" NFS.
-
-If you add a branch which has fileA or fileB, aufs does not follow the
-pseudo link. The file on the added branch has no relation to the same
-named file(s) on the lower branch(es).
-If you use noxino mount option, pseudo link will not work after the
-kernel shrinks the inode cache.
-
-This feature will not work for squashfs before version 3.2 since its
-inode is tricky.
-When the inode is hardlinked, squashfs inodes has the same inode
-number and correct link count, but the inode memory object is
-different. Squashfs inodes (before v3.2) are generated for each, even
-they are hardlinked.
-
-.\" ----------------------------------------------------------------------
-.SH User's Direct Branch Access (UDBA)
-UDBA means a modification to a branch filesystem manually or directly,
-e.g. bypassing aufs.
-While aufs is designed and implemented to be safe after UDBA,
-it can make yourself and your aufs confused. And some information like
-aufs inode will be incorrect.
-For example, if you rename a file on a branch directly, the file on
-aufs may
-or may not be accessible through both of old and new name.
-Because aufs caches various information about the files on
-branches. And the cache still remains after UDBA.
-
-Aufs has a mount option named `udba' which specifies the test level at
-access time whether UDBA was happened or not.
-.
-.TP
-.B udba=none
-Aufs trusts the dentry and the inode cache on the system, and never
-test about UDBA. With this option, aufs runs fastest, but it may show
-you incorrect data.
-Additionally, if you often modify a branch
-directly, aufs will not be able to trace the changes of inodes on the
-branch. It can be a cause of wrong behaviour, deadlock or anything else.
-
-It is recommended to use this option only when you are sure that
-nobody access a file on a branch.
-It might be difficult for you to achieve real `no UDBA' world when you
-cannot stop your users doing `find / \-ls' or something.
-If you really want to forbid all of your users to UDBA, here is a trick
-for it.
-With this trick, users cannot see the
-branches directly and aufs runs with no problem, except `auplink' utility.
-But if you are not familiar with aufs, this trick may make
-yourself confused.
-
-.nf
-# d=/tmp/.aufs.hide
-# mkdir $d
-# for i in $branches_you_want_to_hide
-> do
-> mount -n --bind $d $i
-> done
-.fi
-
-When you unmount the aufs, delete/modify the branch by remount, or you
-want to show the hidden branches again, unmount the bound
-/tmp/.aufs.hide.
-
-.nf
-# umount -n $branches_you_want_to_unbound
-.fi
-
-If you use FUSE filesystem as an aufs branch which supports hardlink,
-you should not set this option, since FUSE makes inode objects for
-each hardlinks (at least in linux\-2.6.23). When your FUSE filesystem
-maintains them at link/unlinking, it is equivalent
-to `direct branch access' for aufs.
-
-.
-.TP
-.B udba=reval
-Aufs tests only the existence of the file which existed. If
-the existed file was removed on the branch directly, aufs
-discard the cache about the file and
-re-lookup it. So the data will be updated.
-This test is at minimum level to keep the performance and ensure the
-existence of a file.
-This is default and aufs runs still fast.
-
-This rule leads to some unexpected situation, but I hope it is
-harmless. Those are totally depends upon cache. Here are just a few
-examples.
-.
-.RS
-.Bu
-If the file is cached as negative or
-not-existed, aufs does not test it. And the file is still handled as
-negative after a user created the file on a branch directly. If the
-file is not cached, aufs will lookup normally and find the file.
-.
-.Bu
-When the file is cached as positive or existed, and a user created the
-same named file directly on the upper branch. Aufs detects the cached
-inode of the file is still existing and will show you the old (cached)
-file which is on the lower branch.
-.
-.Bu
-When the file is cached as positive or existed, and a user renamed the
-file by rename(2) directly. Aufs detects the inode of the file is
-still existing. You may or may not see both of the old and new files.
-Todo: If aufs also tests the name, we can detect this case.
-.RE
-
-If your outer modification (UDBA) is rare and you can ignore the
-temporary and minor differences between virtual aufs world and real
-branch filesystem, then try this mount option.
-.
-.TP
-.B udba=inotify
-Aufs sets `inotify' to all the accessed directories on its branches
-and receives the event about the dir and its children. It consumes
-resources, cpu and memory. And I am afraid that the performance will be
-hurt, but it is most strict test level.
-There are some limitations of linux inotify, see also Inotify
-Limitation.
-So it is recommended to leave udba default option usually, and set it
-to inotify by remount when you need it.
-
-When a user accesses the file which was notified UDBA before, the cached data
-about the file will be discarded and aufs re-lookup it. So the data will
-be updated.
-When an error condition occurs between UDBA and aufs operation, aufs
-will return an error, including EIO.
-To use this option, you need to enable CONFIG_INOTIFY and
-CONFIG_AUFS_UDBA_INOTIFY.
-
-To rename/rmdir a directory on a branch directory may reveal the same named
-directory on the lower branch. Aufs tries re-lookuping the renamed
-directory and the revealed directory and assigning different inode
-number to them. But the inode number including their children can be a
-problem. The inode numbers will be changed silently, and
-aufs may produce a warning. If you rename a directory repeatedly and
-reveal/hide the lower directory, then aufs may confuse their inode
-numbers too. It depends upon the system cache.
-
-When you make a directory in aufs and mount other filesystem on it,
-the directory in aufs cannot be removed expectedly because it is a
-mount point. But the same named directory on the writable branch can
-be removed, if someone wants. It is just an empty directory, instead
-of a mount point.
-Aufs cannot stop such direct rmdir, but produces a warning about it.
-
-If the pseudo-linked file is hardlinked or unlinked on the branch
-directly, its inode link count in aufs may be incorrect. It is
-recommended to flush the pseudo-links by auplink script.
-
-.\" ----------------------------------------------------------------------
-.SH Linux Inotify Limitation
-Unfortunately, current inotify (linux\-2.6.18) has some limitations,
-and aufs must derive it.
-
-.SS IN_ATTRIB, updating atime
-When a file/dir on a branch is accessed directly, the inode atime (access
-time, cf. stat(2)) may or may not be updated. In some cases, inotify
-does not fire this event. So the aufs inode atime may remain old.
-
-.SS IN_ATTRIB, updating nlink
-When the link count of a file on a branch is incremented by link(2)
-directly,
-inotify fires IN_CREATE to the parent
-directory, but IN_ATTRIB to the file. So the aufs inode nlink may
-remain old.
-
-.SS IN_DELETE, removing file on NFS
-When a file on a NFS branch is deleted directly, inotify may or may
-not fire
-IN_DELETE event. It depends upon the status of dentry
-(DCACHE_NFSFS_RENAMED flag).
-In this case, the file on aufs seems still exists. Aufs and any user can see
-the file.
-
-.SS IN_IGNORED, deleted rename target
-When a file/dir on a branch is unlinked by rename(2) directly, inotify
-fires IN_IGNORED which means the inode is deleted. Actually, in some
-cases, the inode survives. For example, the rename target is linked or
-opened. In this case, inotify watch set by aufs is removed by VFS and
-inotify.
-And aufs cannot receive the events anymore. So aufs may show you
-incorrect data about the file/dir.
-
-.\" ----------------------------------------------------------------------
-.SH Virtual or Vertical Directory Block (VDIR)
-In order to provide the merged view of file listing, aufs builds
-internal directory block on memory. For readdir, aufs performs readdir()
-internally for each dir on branches, merges their entries with
-eliminating the whiteout\-ed ones, and sets it to the opened file (dir)
-object. So the file object has its entry list until it is closed. The
-entry list will be updated when the file position is zero (by
-rewinddir(3)) and becomes obsoleted.
-
-Some people may call it can be a security hole or invite DoS attack
-since the opened and once readdir\-ed dir (file object) holds its entry
-list and becomes a pressure for system memory. But I would say it is similar
-to files under /proc or /sys. The virtual files in them also holds a
-memory page (generally) while they are opened. When an idea to reduce
-memory for them is introduced, it will be applied to aufs too.
-
-The dynamically allocated memory block for the name of entries has a
-unit of \*[AUFS_RDBLK_DEF] bytes by default.
-During building dir blocks, aufs creates hash list (hashed and divided by
-\*[AUFS_RDHASH_DEF] by default) and judging whether
-the entry is whiteouted by its upper branch or already listed.
-
-These values are suitable for normal environments. But you may have
-millions of files or very long filenames under a single directory. For
-such cases, you may need to customize these values by specifying rdblk=
-and rdhash= aufs mount options.
-
-For instance, there are 97 files under my /bin, and the total name
-length is 597 bytes.
-
-.nf
-$ \\ls -1 /bin | wc
- 97 97 597
-.fi
-
-Strictly speaking, 97 end\-of\-line codes are
-included. But it is OK since aufs VDIR also stores the name length in 1
-byte. In this case, you do not need to customize the default values. 597 bytes
-filenames will be stored in 2 VDIR memory blocks (597 <
-\*[AUFS_RDBLK_DEF] x 2).
-And 97 filenames are distributed among \*[AUFS_RDHASH_DEF] lists, so one
-list will point 4 names in average. To judge the names is whiteouted or
-not, the number of comparison will be 4. 2 memory allocations
-and 4 comparison costs low (even if the directory is opened for a long
-time). So you do not need to customize.
-
-If your directory has millions of files, the you will need to specify
-rdblk= and rdhash=.
-
-.nf
-$ ls -U /mnt/rotating-rust | wc -l
-1382438
-.fi
-
-In this case, assuming the average length of filenames is 6, in order to
-get better time performance I would
-recommend to set $((128*1024)) or $((64*1024)) for rdblk, and
-$((8*1024)) or $((4*1024)) for rdhash.
-You can change these values of the active aufs mount by "mount -o
-remount".
-
-This customization is not for
-reducing the memory space, but for reducing time for the number of memory
-allocation and the name comparison. The larger value is faster, in
-general. Of course, you will need system memory. This is a generic
-"time\-vs\-space" problem.
-
-.\" ----------------------------------------------------------------------
-.SH Copy On Write, or aufs internal copyup and copydown
-Every stackable filesystem which implements copy\-on\-write supports the
-copyup feature. The feature is to copy a file/dir from the lower branch
-to the upper internally. When you have one readonly branch and one
-upper writable branch, and you append a string to a file which exists on
-the readonly branch, then aufs will copy the file from the readonly
-branch to the writable branch with its directory hierarchy. It means one
-write(2) involves several logical/internal mkdir(2), creat(2), read(2),
-write(2) and close(2) systemcalls
-before the actual expected write(2) is performed. Sometimes it may take
-a long time, particularly when the file is very large.
-If CONFIG_AUFS_DEBUG is enabled, aufs produces a message saying `copying
-a large file.'
-
-You may see the message when you change the xino file path or
-truncate the xino/xib files. Sometimes those files can be large and may
-take a long time to handle them.
-
-.\" ----------------------------------------------------------------------
-.SH Policies to Select One among Multiple Writable Branches
-Aufs has some policies to select one among multiple writable branches
-when you are going to write/modify something. There are two kinds of
-policies, one is for newly create something and the other is for
-internal copy-up.
-You can select them by specifying mount option `create=CREATE_POLICY'
-or `cpup=COPYUP_POLICY.'
-These policies have no meaning when you have only one writable
-branch. If there is some meaning, it must hurt the performance.
-
-.SS Exceptions for Policies
-In every cases below, even if the policy says that the branch where a
-new file should be created is /rw2, the file will be created on /rw1.
-.
-.Bu
-If there is a readonly branch with `wh' attribute above the
-policy-selected branch and the parent dir is marked as opaque,
-or the target (creating) file is whiteouted on the ro+wh branch, then
-the policy will be ignored and the target file will be created on the
-nearest upper writable branch than the ro+wh branch.
-.RS
-.nf
-/aufs = /rw1 + /ro+wh/diropq + /rw2
-/aufs = /rw1 + /ro+wh/wh.tgt + /rw2
-.fi
-.RE
-.
-.Bu
-If there is a writable branch above the policy-selected branch and the
-parent dir is marked as opaque or the target file is whiteouted on the
-branch, then the policy will be ignored and the target file will be
-created on the highest one among the upper writable branches who has
-diropq or whiteout. In case of whiteout, aufs removes it as usual.
-.RS
-.nf
-/aufs = /rw1/diropq + /rw2
-/aufs = /rw1/wh.tgt + /rw2
-.fi
-.RE
-.
-.Bu
-link(2) and rename(2) systemcalls are exceptions in every policy.
-They try selecting the branch where the source exists as possible since
-copyup a large file will take long time. If it can't be, ie. the
-branch where the source exists is readonly, then they will follow the
-copyup policy.
-.
-.Bu
-There is an exception for rename(2) when the target exists.
-If the rename target exists, aufs compares the index of the branches
-where the source and the target are existing and selects the higher
-one. If the selected branch is readonly, then aufs follows the copyup
-policy.
-
-.SS Policies for Creating
-.
-.TP
-.B create=tdp | top\-down\-parent
-Selects the highest writable branch where the parent dir exists. If
-the parent dir does not exist on a writable branch, then the internal
-copyup will happen. The policy for this copyup is always `bottom-up.'
-This is the default policy.
-.
-.TP
-.B create=rr | round\-robin
-Selects a writable branch in round robin. When you have two writable
-branches and creates 10 new files, 5 files will be created for each
-branch.
-mkdir(2) systemcall is an exception. When you create 10 new directories,
-all are created on the same branch.
-.
-.TP
-.B create=mfs[:second] | most\-free\-space[:second]
-Selects a writable branch which has most free space. In order to keep
-the performance, you can specify the duration (`second') which makes
-aufs hold the index of last selected writable branch until the
-specified seconds expires. The first time you create something in aufs
-after the specified seconds expired, aufs checks the amount of free
-space of all writable branches by internal statfs call
-and the held branch index will be updated.
-The default value is \*[AUFS_MFS_SECOND_DEF] seconds.
-.
-.TP
-.B create=mfsrr:low[:second]
-Selects a writable branch in most-free-space mode first, and then
-round-robin mode. If the selected branch has less free space than the
-specified value `low' in bytes, then aufs re-tries in round-robin mode.
-.\" `G', `M' and `K' (case insensitive) can be followed after `low.' Or
-Try an arithmetic expansion of shell which is defined by POSIX.
-For example, $((10 * 1024 * 1024)) for 10M.
-You can also specify the duration (`second') which is equivalent to
-the `mfs' mode.
-.
-.TP
-.B create=pmfs[:second]
-Selects a writable branch where the parent dir exists, such as tdp
-mode. When the parent dir exists on multiple writable branches, aufs
-selects the one which has most free space, such as mfs mode.
-
-.SS Policies for Copy-Up
-.
-.TP
-.B cpup=tdp | top\-down\-parent
-Equivalent to the same named policy for create.
-This is the default policy.
-.
-.TP
-.B cpup=bup | bottom\-up\-parent
-Selects the writable branch where the parent dir exists and the branch
-is nearest upper one from the copyup-source.
-.
-.TP
-.B cpup=bu | bottom\-up
-Selects the nearest upper writable branch from the copyup-source,
-regardless the existence of the parent dir.
-
-.\" ----------------------------------------------------------------------
-.SH Exporting Aufs via NFS
-Aufs is supporting NFS-exporting.
-Since aufs has no actual block device, you need to add NFS `fsid' option at
-exporting. Refer to the manual of NFS about the detail of this option.
-
-There are some limitations or requirements.
-.RS
-.Bu
-The branch filesystem must support NFS-exporting.
-.Bu
-NFSv2 is not supported. When you mount the exported aufs from your NFS
-client, you will need to some NFS options like v3 or nfsvers=3,
-especially if it is nfsroot.
-.Bu
-If the size of the NFS file handle on your branch filesystem is large,
-aufs will
-not be able to handle it. The maximum size of NFSv3 file
-handle for a filesystem is 64 bytes. Aufs uses 24 bytes for 32bit
-system, plus 12 bytes for 64bit system. The rest is a room for a file
-handle of a branch filesystem.
-.Bu
-The External Inode Number Bitmap, Translation Table and Generation Table
-(xino) is
-required since NFS file
-handle is based upon inode number. The mount option `xino' is enabled
-by default.
-The external inode generation table and its debugfs entry
-(<debugfs>/aufs/si_*/xigen) is created when CONFIG_AUFS_EXPORT is
-enabled even if you don't export aufs actually.
-The size of the external inode generation table grows only, never be
-truncated. You might need to pay attention to the free space of the
-filesystem where xino files are placed. By default, it is the first
-writable branch.
-.Bu
-The branch filesystems must be accessible, which means `not hidden.'
-It means you need to `mount \-\-move' when you use initramfs and
-switch_root(8), or chroot(8).
-.RE
-
-.\" ----------------------------------------------------------------------
-.SH Dentry and Inode Caches
-If you want to clear caches on your system, there are several tricks
-for that. If your system ram is low,
-try `find /large/dir \-ls > /dev/null'.
-It will read many inodes and dentries and cache them. Then old caches will be
-discarded.
-But when you have large ram or you do not have such large
-directory, it is not effective.
-
-If you want to discard cache within a certain filesystem,
-try `mount \-o remount /your/mntpnt'. Some filesystem may return an error of
-EINVAL or something, but VFS discards the unused dentry/inode caches on the
-specified filesystem.
-
-.\" ----------------------------------------------------------------------
-.SH Compatible/Incompatible with Unionfs Version 1.x Series
-If you compile aufs with \-DCONFIG_AUFS_COMPAT, dirs= option and =nfsro
-branch permission flag are available. They are interpreted as
-br: option and =ro flags respectively.
- `debug', `delete', `imap' options are ignored silently. When you
-compile aufs without \-DCONFIG_AUFS_COMPAT, these three options are
-also ignored, but a warning message is issued.
-
-Ignoring `delete' option, and to keep filesystem consistency, aufs tries
-writing something to only one branch in a single systemcall. It means
-aufs may copyup even if the copyup-src branch is specified as writable.
-For example, you have two writable branches and a large regular file
-on the lower writable branch. When you issue rename(2) to the file on aufs,
-aufs may copyup it to the upper writable branch.
-If this behaviour is not what you want, then you should rename(2) it
-on the lower branch directly.
-
-And there is a simple shell
-script `unionctl' under sample subdirectory, which is compatible with
-unionctl(8) in
-Unionfs Version 1.x series, except \-\-query action.
-This script executes mount(8) with `remount' option and uses
-add/del/mod aufs mount options.
-If you are familiar with Unionfs Version 1.x series and want to use unionctl(8), you can
-try this script instead of using mount \-o remount,... directly.
-Aufs does not support ioctl(2) interface.
-This script is highly depending upon mount(8) in
-util\-linux\-2.12p package, and you need to mount /proc to use this script.
-If your mount(8) version differs, you can try modifying this
-script. It is very easy.
-The unionctl script is just for a sample usage of aufs remount
-interface.
-
-Aufs uses the external inode number bitmap and translation table by
-default.
-
-The default branch permission for the first branch is `rw', and the
-rest is `ro.'
-
-The whiteout is for hiding files on lower branches. Also it is applied
-to stop readdir going lower branches.
-The latter case is called `opaque directory.' Any
-whiteout is an empty file, it means whiteout is just an mark.
-In the case of hiding lower files, the name of whiteout is
-`\*[AUFS_WH_PFX]<filename>.'
-And in the case of stopping readdir, the name is
-`\*[AUFS_WH_PFX]\*[AUFS_WH_PFX].opq' or
-`\*[AUFS_WH_PFX]__dir_opaque.' The name depends upon your compile
-configuration
-CONFIG_AUFS_COMPAT.
-.\" All of newly created or renamed directory will be opaque.
-All whiteouts are hardlinked,
-including `<writable branch top dir>/\*[AUFS_WH_BASE].'
-
-The hardlink on an ordinary (disk based) filesystem does not
-consume inode resource newly. But in linux tmpfs, the number of free
-inodes will be decremented by link(2). It is recommended to specify
-nr_inodes option to your tmpfs if you meet ENOSPC. Use this option
-after checking by `df \-i.'
-
-When you rmdir or rename-to the dir who has a number of whiteouts,
-aufs rename the dir to the temporary whiteouted-name like
-`\*[AUFS_WH_PFX]<dir>.<random hex>.' Then remove it after actual operation.
-cf. mount option `dirwh.'
-
-.\" ----------------------------------------------------------------------
-.SH Incompatible with an Ordinary Filesystem
-stat(2) returns the inode info from the first existence inode among
-the branches, except the directory link count.
-Aufs computes the directory link count larger than the exact value usually, in
-order to keep UNIX filesystem semantics, or in order to shut find(1) mouth up.
-The size of a directory may be wrong too, but it has to do no harm.
-The timestamp of a directory will not be updated when a file is
-created or removed under it, and it was done on a lower branch.
-
-The test for permission bits has two cases. One is for a directory,
-and the other is for a non-directory. In the case of a directory, aufs
-checks the permission bits of all existing directories. It means you
-need the correct privilege for the directories including the lower
-branches.
-The test for a non-directory is more simple. It checks only the
-topmost inode.
-
-statfs(2) returns the information of the first branch info except
-namelen when `nosum' is specified (the default). The namelen is
-decreased by the whiteout prefix length. And the block size may differ
-from st_blksize which is obtained by stat(2).
-
-Remember, seekdir(3) and telldir(3) are not defined in POSIX. They may
-not work as you expect. Try rewinddir(3) or re-open the dir.
-
-The whiteout prefix (\*[AUFS_WH_PFX]) is reserved on all branches. Users should
-not handle the filename begins with this prefix.
-In order to future whiteout, the maximum filename length is limited by
-the longest value \- \*[AUFS_WH_PFX_LEN]. It may be a violation of POSIX.
-
-If you dislike the difference between the aufs entries in /etc/mtab
-and /proc/mounts, and if you are using mount(8) in util\-linux package,
-then try ./mount.aufs utility. Copy the script to /sbin/mount.aufs.
-This simple utility tries updating
-/etc/mtab. If you do not care about /etc/mtab, you can ignore this
-utility.
-Remember this utility is highly depending upon mount(8) in
-util\-linux\-2.12p package, and you need to mount /proc.
-
-Since aufs uses its own inode and dentry, your system may cache huge
-number of inodes and dentries. It can be as twice as all of the files
-in your union.
-It means that unmounting or remounting readonly at shutdown time may
-take a long time, since mount(2) in VFS tries freeing all of the cache
-on the target filesystem.
-
-When you open a directory, aufs will open several directories
-internally.
-It means you may reach the limit of the number of file descriptor.
-And when the lower directory cannot be opened, aufs will close all the
-opened upper directories and return an error.
-
-The sub-mount under the branch
-of local filesystem
-is ignored.
-For example, if you have mount another filesystem on
-/branch/another/mntpnt, the files under `mntpnt' will be ignored by aufs.
-It is recommended to mount the sub-mount under the mounted aufs.
-For example,
-
-.nf
-# sudo mount /dev/sdaXX /ro_branch
-# d=another/mntpnt
-# sudo mount /dev/sdbXX /ro_branch/$d
-# mkdir -p /rw_branch/$d
-# sudo mount -t aufs -o br:/rw_branch:/ro_branch none /aufs
-# sudo mount -t aufs -o br:/rw_branch/${d}:/ro_branch/${d} none /aufs/another/$d
-.fi
-
-There are several characters which are not allowed to use in a branch
-directory path and xino filename. See detail in Branch Syntax and Mount
-Option.
-
-The file-lock which means fcntl(2) with F_SETLK, F_SETLKW or F_GETLK, flock(2)
-and lockf(3), is applied to virtual aufs file only, not to the file on a
-branch. It means you can break the lock by accessing a branch directly.
-TODO: check `security' to hook locks, as inotify does.
-
-The I/O to the named pipe or local socket are not handled by aufs, even
-if it exists in aufs. After the reader and the writer established their
-connection if the pipe/socket are copied-up, they keep using the old one
-instead of the copied-up one.
-
-The fsync(2) and fdatasync(2) systemcalls return 0 which means success, even
-if the given file descriptor is not opened for writing.
-I am afraid this behaviour may violate some standards. Checking the
-behaviour of fsync(2) on ext2, aufs decided to return success.
-
-If you want to use disk-quota, you should set it up to your writable
-branch since aufs does not have its own block device.
-
-When your aufs is the root directory of your system, and your system
-tells you some of the filesystem were not unmounted cleanly, try these
-procedure when you shutdown your system.
-.nf
-# mount -no remount,ro /
-# for i in $writable_branches
-# do mount -no remount,ro $i
-# done
-.fi
-If your xino file is on a hard drive, you also need to specify
-`noxino' option or `xino=/your/tmpfs/xino' at remounting root
-directory.
-
-To rename(2) directory may return EXDEV even if both of src and tgt
-are on the same aufs. When the rename-src dir exists on multiple
-branches and the lower dir has child(ren), aufs has to copyup all his
-children. It can be recursive copyup. Current aufs does not support
-such huge copyup operation at one time in kernel space, instead
-produces a warning and returns EXDEV.
-Generally, mv(1) detects this error and tries mkdir(2) and
-rename(2) or copy/unlink recursively. So the result is harmless.
-If your application which issues rename(2) for a directory does not
-support EXDEV, it will not work on aufs.
-Also this specification is applied to the case when the src directory
-exists on the lower readonly branch and it has child(ren).
-
-If a sudden accident such like a power failure happens during aufs is
-performing, and regular fsck for branch filesystems is completed after
-the disaster, you need to extra fsck for aufs writable branches. It is
-necessary to check whether the whiteout remains incorrectly or not,
-eg. the real filename and the whiteout for it under the same parent
-directory. If such whiteout remains, aufs cannot handle the file
-correctly.
-To check the consistency from the aufs' point of view, you can use a
-simple shell script called /sbin/auchk. Its purpose is a fsck tool for
-aufs, and it checks the illegal whiteout, the remained
-pseudo-links and the remained aufs-temp files. If they are found, the
-utility reports you and asks whether to delete or not.
-It is recommended to execute /sbin/auchk for every writable branch
-filesystem before mounting aufs if the system experienced crash.
-
-
-.\" ----------------------------------------------------------------------
-.SH EXAMPLES
-The mount options are interpreted from left to right at remount-time.
-These examples
-shows how the options are handled. (assuming /sbin/mount.aufs was
-installed)
-
-.nf
-# mount -v -t aufs br:/day0:/base none /u
-none on /u type aufs (rw,xino=/day0/.aufs.xino,br:/day0=rw:/base=ro)
-# mount -v -o remount,\\
- prepend:/day1,\\
- xino=/day1/xino,\\
- mod:/day0=ro,\\
- del:/day0 \\
- /u
-none on /u type aufs (rw,xino=/day1/xino,br:/day1=rw:/base=ro)
-.fi
-
-.nf
-# mount -t aufs br:/rw none /u
-# mount -o remount,append:/ro /u
-different uid/gid/permission, /ro
-# mount -o remount,del:/ro /u
-# mount -o remount,nowarn_perm,append:/ro /u
-#
-(there is no warning)
-.fi
-
-.\" If you want to expand your filesystem size, aufs may help you by
-.\" adding an writable branch. Since aufs supports multiple writable
-.\" branches, the old writable branch can be being writable, if you want.
-.\" In this example, any modifications to the files under /ro branch will
-.\" be copied-up to /new, but modifications to the files under /rw branch
-.\" will not.
-.\" And the next example shows the modifications to the files under /rw branch
-.\" will be copied-up to /new/a.
-.\"
-.\" Todo: test multiple writable branches policy. cpup=nearest, cpup=exist_parent.
-.\"
-.\" .nf
-.\" # mount -v -t aufs br:/rw:/ro none /u
-.\" none on /u type aufs (rw,xino=/rw/.aufs.xino,br:/rw=rw:/ro=ro)
-.\" # mkfs /new
-.\" # mount -v -o remount,add:1:/new=rw /u
-.\" none on /u type aufs (rw,xino=/rw/.aufs.xino,br:/rw=rw:/new=rw:/ro=ro)
-.\" .fi
-.\"
-.\" .nf
-.\" # mount -v -t aufs br:/rw:/ro none /u
-.\" none on /u type aufs (rw,xino=/rw/.aufs.xino,br:/rw=rw:/ro=ro)
-.\" # mkfs /new
-.\" # mkdir /new/a new/b
-.\" # mount -v -o remount,add:1:/new/b=rw,prepend:/new/a,mod:/rw=ro /u
-.\" none on /u type aufs (rw,xino=/rw/.aufs.xino,br:/new/a=rw:/rw=ro:/new/b=rw:/ro=ro)
-.\" .fi
-
-When you use aufs as root filesystem, it is recommended to consider to
-exclude some directories. For example, /tmp and /var/log are not need
-to stack in many cases. They do not usually need to copyup or to whiteout.
-Also the swapfile on aufs (a regular file, not a block device) is not
-supported.
-In order to exclude the specific dir from aufs, try bind mounting.
-
-And there is a good sample which is for network booted diskless machines. See
-sample/ in detail.
-
-.\" ----------------------------------------------------------------------
-.SH DIAGNOSTICS
-When you add a branch to your union, aufs may warn you about the
-privilege or security of the branch, which is the permission bits,
-owner and group of the top directory of the branch.
-For example, when your upper writable branch has a world writable top
-directory,
-a malicious user can create any files on the writable branch directly,
-like copyup and modify manually. I am afraid it can be a security
-issue.
-
-When you mount or remount your union without \-o ro common mount option
-and without writable branch, aufs will warn you that the first branch
-should be writable.
-
-.\" It is discouraged to set both of `udba' and `noxino' mount options. In
-.\" this case the inode number under aufs will always be changed and may
-.\" reach the end of inode number which is a maximum of unsigned long. If
-.\" the inode number reaches the end, aufs will return EIO repeatedly.
-
-When you set udba other than inotify and change something on your
-branch filesystem directly, later aufs may detect some mismatches to
-its cache. If it is a critical mismatch, aufs returns EIO.
-
-When an error occurs in aufs, aufs prints the kernel message with
-`errno.' The priority of the message (log level) is ERR or WARNING which
-depends upon the message itself.
-You can convert the `errno' into the error message by perror(3),
-strerror(3) or something.
-For example, the `errno' in the message `I/O Error, write failed (\-28)'
-is 28 which means ENOSPC or `No space left on device.'
-
-When CONFIG_AUFS_BR_RAMFS is enabled, you can specify ramfs as an aufs
-branch. Since ramfs is simple, it does not set the maximum link count
-originally. In aufs, it is very dangerous, particularly for
-whiteouts. Finally aufs sets the maximum link count for ramfs. The
-value is 32000 which is borrowed from ext2.
-
-
-.\" .SH Current Limitation
-.
-.\" ----------------------------------------------------------------------
-.\" SYNOPSIS
-.\" briefly describes the command or function's interface. For commands, this
-.\" shows the syntax of the command and its arguments (including options); bold-
-.\" face is used for as-is text and italics are used to indicate replaceable
-.\" arguments. Brackets ([]) surround optional arguments, vertical bars (|) sep-
-.\" arate choices, and ellipses (...) can be repeated. For functions, it shows
-.\" any required data declarations or #include directives, followed by the func-
-.\" tion declaration.
-.
-.\" DESCRIPTION
-.\" gives an explanation of what the command, function, or format does. Discuss
-.\" how it interacts with files and standard input, and what it produces on
-.\" standard output or standard error. Omit internals and implementation
-.\" details unless they're critical for understanding the interface. Describe
-.\" the usual case; for information on options use the OPTIONS section. If
-.\" there is some kind of input grammar or complex set of subcommands, consider
-.\" describing them in a separate USAGE section (and just place an overview in
-.\" the DESCRIPTION section).
-.
-.\" RETURN VALUE
-.\" gives a list of the values the library routine will return to the caller and
-.\" the conditions that cause these values to be returned.
-.
-.\" EXIT STATUS
-.\" lists the possible exit status values or a program and the conditions that
-.\" cause these values to be returned.
-.
-.\" USAGE
-.\" describes the grammar of any sublanguage this implements.
-.
-.\" FILES
-.\" lists the files the program or function uses, such as configuration files,
-.\" startup files, and files the program directly operates on. Give the full
-.\" pathname of these files, and use the installation process to modify the
-.\" directory part to match user preferences. For many programs, the default
-.\" installation location is in /usr/local, so your base manual page should use
-.\" /usr/local as the base.
-.
-.\" ENVIRONMENT
-.\" lists all environment variables that affect your program or function and how
-.\" they affect it.
-.
-.\" SECURITY
-.\" discusses security issues and implications. Warn about configurations or
-.\" environments that should be avoided, commands that may have security impli-
-.\" cations, and so on, especially if they aren't obvious. Discussing security
-.\" in a separate section isn't necessary; if it's easier to understand, place
-.\" security information in the other sections (such as the DESCRIPTION or USAGE
-.\" section). However, please include security information somewhere!
-.
-.\" CONFORMING TO
-.\" describes any standards or conventions this implements.
-.
-.\" NOTES
-.\" provides miscellaneous notes.
-.
-.\" BUGS
-.\" lists limitations, known defects or inconveniences, and other questionable
-.\" activities.
-
-.SH COPYRIGHT
-Copyright \(co 2005\-2009 Junjiro R. Okajima
-
-.SH AUTHOR
-Junjiro R. Okajima
-
-.\" SEE ALSO
-.\" lists related man pages in alphabetical order, possibly followed by other
-.\" related pages or documents. Conventionally this is the last section.
diff --git a/package/aufs2-util/src/aufs.shlib b/package/aufs2-util/src/aufs.shlib
deleted file mode 100644
index 7aa07665c..000000000
--- a/package/aufs2-util/src/aufs.shlib
+++ /dev/null
@@ -1,83 +0,0 @@
-#
-# Copyright (C) 2005-2009 Junjiro Okajima
-#
-# This program, aufs 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
-
-# library functions for aufs shell scripts
-
-# path in canonical representation
-SetDir() # var dir
-{
- cd "$2"
- eval "$1=\"$PWD\""
- cd "$OLDPWD"
-}
-
-# escape the unprintable characters, mainly for grep-ping /proc/mounts
-Esc() # [-e]
-{
- sed -r -e '
- s/\\/\\134/g
- s/$/\\012/
- ' |
- tr -d '\n' |
- sed -r -e '
- s/ /\\040/g
- s/\t/\\011/g
- s/\r/\\015/g
- s/\\012$//
- ' |
- { test $# -eq 1 &&
- test "$1" = "-e" &&
- sed -r -e 's/\\/\\\\/g' ||
- cat; }
- echo
-}
-
-# find a mount-entry by its mount-point
-FindMntEnt() # mntpnt
-{
- proc_mounts=/proc/self/mounts
- test ! -e $proc_mounts && proc_mounts=/proc/$$/mounts
- test ! -e $proc_mounts && proc_mounts=/proc/mounts
- fgrep \ $(echo "$1" | Esc)\ aufs\ $proc_mounts |
- tail -n 1
-}
-
-# current mount options
-MntOpts() # mntpnt
-{
- FindMntEnt "$1" |
- cut -f4 -d' '
-}
-
-########################################
-
-AuDebug() # 1 | 0 [sec]
-{
- test $1 -eq 0 && set +x
- aufs_debug=/sys/module/aufs/parameters/debug
- if [ -f $aufs_debug ]
- then
- echo $1 | sudo dd of=$aufs_debug 2> /dev/null
- test $# -eq 2 && sleep $2
- fi
- test $1 -eq 1 && set -x
- true
-}
-
-# Local variables: ;
-# mode: text;
-# End: ;
diff --git a/package/aufs2-util/src/auplink.c b/package/aufs2-util/src/auplink.c
deleted file mode 100644
index 1b48bea51..000000000
--- a/package/aufs2-util/src/auplink.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2005-2009 Junjiro Okajima
- *
- * This program, aufs 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
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "au_util.h"
-
-static void usage(char *me)
-{
- fprintf(stderr,
- "usage: %s aufs_mount_point list|cpup|flush\n"
- "'list' shows the pseudo-linked inode numbers and filenames.\n"
- "'cpup' copies-up all pseudo-link to the writeble branch.\n"
- "'flush' calls 'cpup', and then 'mount -o remount,clean_plink=inum'\n"
- "and remove the whiteouted plink.\n", me);
- exit(EINVAL);
-}
-
-int main(int argc, char *argv[])
-{
- int err, cmd;
- char *cwd;
-
- if (argc != 3)
- usage(argv[0]);
-
- if (!strcmp(argv[2], "flush"))
- cmd = AuPlink_FLUSH;
- else if (!strcmp(argv[2], "list"))
- cmd = AuPlink_LIST;
- else if (!strcmp(argv[2], "cpup"))
- cmd = AuPlink_CPUP;
- else {
- errno = EINVAL;
- AuFin("%s", argv[2]);
- cmd = 0; /* never reach here */
- }
-
- err = chdir(argv[1]);
- if (err)
- AuFin("chdir");
- cwd = getcwd(NULL, 0); /* glibc */
- if (!cwd)
- AuFin("getcwd");
- return au_plink(cwd, cmd, 1, 0);
-}
diff --git a/package/aufs2-util/src/br.c b/package/aufs2-util/src/br.c
deleted file mode 100644
index 6451c120e..000000000
--- a/package/aufs2-util/src/br.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2005-2009 Junjiro Okajima
- *
- * This program, aufs 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
- */
-
-#define _GNU_SOURCE /* strndup */
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <mntent.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <linux/aufs_type.h>
-#include "au_util.h"
-
-static int by_opts(char ***br, int *nbr, char *bropt)
-{
- char *p, **a;
- int l;
-
- /* bropts is placed at the end of mnt_opts */
- errno = EINVAL;
- //puts(bropt);
- if (strchr(bropt, ','))
- AuFin("%s", bropt);
-
- l = strlen(bropt);
- p = malloc(l + 2);
- if (!p)
- AuFin("malloc");
- memcpy(p, bropt, l + 1);
- bropt = p;
- bropt[l + 1] = 0; /* end marker */
-
- *nbr = 1;
- while (1) {
- p = strchr(p + 1, ':');
- if (!p)
- break;
- *p = 0;
- (*nbr)++;
- }
-
- a = malloc(sizeof(a) * (*nbr + 1));
- if (!a)
- AuFin("malloc");
-
- *br = a;
- *a++ = bropt;
- p = bropt;
- while (*p) {
- p += strlen(p) + 1;
- *a++ = p;
- }
- *--a = NULL;
- /* don't free bropt */
-
- return 0;
-}
-
-#ifdef DEBUG
-#define SiPathPrefix "/tmp/aufs/si_"
-#define BufSiz 4
-#else
-#define SiPathPrefix "/sys/fs/aufs/si_"
-#define BufSiz BUFSIZ
-#endif
-
-static int by_sysfs(char ***br, int *nbr, char *siopt)
-{
- int err, i, l, sz;
- char buf[BufSiz], path[] = SiPathPrefix "1234567890123456/br32767";
- char *p, *end, **a, *q;
- FILE *fp;
-
- errno = EINVAL;
- end = strchr(siopt, ',');
- if (end)
- i = end - siopt;
- else
- i = strlen(siopt);
-
- strncpy(path + sizeof(SiPathPrefix) - 1, siopt, i);
- p = path + sizeof(SiPathPrefix) - 1 + i;
- strcpy(p, "/br");
- p += 3; /* "/br" */
- *nbr = 0;
- err = 0;
- while (!err) {
- sprintf(p, "%d", (*nbr)++);
- err = access(path, F_OK);
- }
-
- a = malloc(sizeof(*br) * *nbr);
- if (!a)
- AuFin("malloc");
-
- (*nbr)--;
- *br = a;
- for (i = 0; i < *nbr; i++) {
- sprintf(p, "%d", i);
- fp = fopen(path, "r");
- if (!fp)
- AuFin("%s", path);
- if (fgets(buf, sizeof(buf), fp) != buf)
- AuFin("%s", path);
- l = strlen(buf);
- if (l < 1)
- AuFin("internal error, %d", l);
-
- q = strndup(buf, l - 1);
- if (buf[l - 1] != '\n') {
- /* a branch path with crazy length */
- /* stat(2) for sysfs is meaningless */
- sz = sizeof(buf);
- do {
- free(q);
- sz <<= 1;
- q = malloc(sz);
- if (!q)
- AuFin("malloc");
- rewind(fp);
- if (fgets(q, sz, fp) != q)
- AuFin("%s", path);
- l = strlen(q);
- } while (q[l - 1] != '\n');
- q[l - 1] = 0;
- }
-
- *a++ = q;
- /* don't free q */
- fclose(fp); /* ignore */
- }
- *a = NULL;
-
- return 0;
-}
-
-#define BrOpt ",br:"
-#define SiOpt "si"
-int au_br(char ***br, int *nbr, struct mntent *ent)
-{
- char *p;
-
- *nbr = 0;
- p = strstr(ent->mnt_opts, BrOpt);
- if (p)
- return by_opts(br, nbr, p + sizeof(BrOpt) - 1);
- p = hasmntopt(ent, SiOpt);
- if (p)
- return by_sysfs(br, nbr, p + sizeof(SiOpt));
-
- /* broken opts */
- AuFin("internal error, %s", ent->mnt_opts);
- return -1; /* never reach here */
-}
diff --git a/package/aufs2-util/src/c2sh.c b/package/aufs2-util/src/c2sh.c
deleted file mode 100644
index 80ef044a1..000000000
--- a/package/aufs2-util/src/c2sh.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2005-2009 Junjiro Okajima
- *
- * This program, aufs 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
- */
-
-#include <stdio.h>
-#include <linux/aufs_type.h>
-
-#define AUFS_WH_PFX2 AUFS_WH_PFX AUFS_WH_PFX
-
-int
-main(int argc, char *argv[])
-{
-#define p(m, v, fmt) printf("%s=" fmt "\n", m, v)
-#define pstr(m) p(#m, m, "%s")
-#define pint(m) p(#m, m, "%d")
- pstr(AUFS_VERSION);
- pint(AUFS_SUPER_MAGIC);
- printf("AUFS_SUPER_MAGIC_HEX=0x%x\n", AUFS_SUPER_MAGIC);
- pstr(AUFS_WH_PFX);
- pstr(AUFS_WH_PFX2);
- pstr(AUFS_WKQ_NAME);
- pstr(AUFS_WH_DIROPQ);
- pstr(AUFS_WH_BASE);
- pstr(AUFS_WH_PLINKDIR);
- pstr(AUFS_WH_ORPHDIR);
- //pint(AUFS_BRANCH_MAX);
- return 0;
-}
diff --git a/package/aufs2-util/src/c2tmac.c b/package/aufs2-util/src/c2tmac.c
deleted file mode 100644
index 0018763b4..000000000
--- a/package/aufs2-util/src/c2tmac.c
+++ /dev/null
@@ -1,44 +0,0 @@
-
-/*
- * Copyright (C) 2005-2009 Junjiro Okajima
- *
- * This program, aufs 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
- */
-
-#include <stdio.h>
-#include <linux/aufs_type.h>
-
-int
-main(int argc, char *argv[])
-{
-#define p(m, v, fmt) printf(".ds %s " fmt "\n", m, v)
-#define pstr(m) p(#m, m, "%s")
-#define pint(m) p(#m, m, "%d")
- pstr(AUFS_VERSION);
- pstr(AUFS_XINO_FNAME);
- pstr(AUFS_XINO_DEFPATH);
- pint(AUFS_DIRWH_DEF);
- pstr(AUFS_WH_PFX);
- pint(AUFS_WH_PFX_LEN);
- pstr(AUFS_WKQ_NAME);
- pint(AUFS_NWKQ_DEF);
- pstr(AUFS_WH_DIROPQ);
- pstr(AUFS_WH_BASE);
- pstr(AUFS_WH_PLINKDIR);
- pint(AUFS_MFS_SECOND_DEF);
- pint(AUFS_RDBLK_DEF);
- pint(AUFS_RDHASH_DEF);
- return 0;
-}
diff --git a/package/aufs2-util/src/compat.h b/package/aufs2-util/src/compat.h
deleted file mode 100644
index ddb436e7e..000000000
--- a/package/aufs2-util/src/compat.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2009 Junjiro Okajima
- *
- * This program, aufs 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
- */
-
-#ifndef __compat_h__
-#define __compat_h__
-
-#ifndef AT_SYMLINK_NOFOLLOW
-#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
-
-#define __KERNEL__
-#include <unistd.h>
-#include <asm/unistd.h>
-#define fstatat fstatat64
-int fstatat(int dirfd, const char *path, struct stat *buf, int flags);
-_syscall4(int, fstatat64, int, _dirfd, const char *, path, struct stat *, buf, int, flags);
-#undef __KERNEL__
-#endif
-
-#endif /* __compat_h__ */
diff --git a/package/aufs2-util/src/mount.aufs.c b/package/aufs2-util/src/mount.aufs.c
deleted file mode 100644
index d801cfd3c..000000000
--- a/package/aufs2-util/src/mount.aufs.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2005-2009 Junjiro Okajima
- *
- * This program, aufs 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
- */
-
-/*
- * The main purpose of this script is updating /etc/mtab and calling auplilnk.
- * This behaviour is highly depending on mount(8) in util-linux package.
- */
-
-#define _XOPEN_SOURCE 500 /* getsubopt */
-#define _BSD_SOURCE /* dirfd */
-
-#include <sys/types.h>
-#include <dirent.h>
-#include <mntent.h>
-#include <regex.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <wait.h>
-
-#include <linux/aufs_type.h>
-#include "au_util.h"
-
-enum { Remount, Bind, Fake, Update, Verbose, AuFlush, LastOpt };
-static void test_opts(char opts[], unsigned char flags[])
-{
- int c;
- char *p, *o, *val, *pat[] = {
- [Remount] = "remount",
- [Bind] = "bind",
- NULL
- };
-
- o = strdup(opts);
- if (!o)
- AuFin("stdup");
-
- p = o;
- while (*p) {
- c = getsubopt(&p, pat, &val);
- switch (c) {
- case Remount:
- flags[Remount] = 1;
- break;
- case Bind:
- flags[Bind] = 1;
- break;
- }
- }
- free(o);
-}
-
-static int test_flush(char opts[])
-{
- int err, i;
- regex_t preg;
- char *p, *o;
- const char *pat = "^((add|ins|append|prepend|del)[:=]"
- "|(mod|imod)[:=][^,]*=ro"
- "|(noplink|ro)$)";
-
-
- o = strdup(opts);
- if (!o)
- AuFin("stdup");
-
- p = o;
- i = 1;
- while ((p = strchr(p, ','))) {
- i++;
- *p++ = 0;
- }
-
- /* todo: try getsubopt(3)? */
- err = regcomp(&preg, pat, REG_EXTENDED | REG_NOSUB);
- if (err)
- AuFin("regcomp");
-
- p = o;
- while (i--) {
- if (!regexec(&preg, p, 0, NULL, 0)) {
- err = 1;
- break;
- } else
- p += strlen(p) + 1;
- }
- regfree(&preg);
- free(o);
-
- return err;
-}
-
-static void do_mount(char *dev, char *mntpnt, int argc, char *argv[],
- unsigned char flags[])
-{
- int i;
- const int ac = argc + 6;
- char *av[ac], **a;
-
- /* todo: eliminate the duplicated options */
- a = av;
- *a++ = "mount";
- *a++ = "-i";
- if (flags[Fake])
- *a++ = "-f";
- if (!flags[Bind] || !flags[Update])
- *a++ = "-n";
- if (flags[Bind] && flags[Verbose])
- *a++ = "-v";
- *a++ = "-t";
- *a++ = AUFS_NAME;
-
- for (i = 3; i < argc; i++)
- if (strcmp(argv[i], "-v") && strcmp(argv[i], "-n"))
- *a++ = argv[i];
- *a++ = dev;
- *a++ = mntpnt;
- *a++ = NULL;
-
-#ifdef DEBUG
- for (i = 0; av[i] && i < ac; i++)
- puts(av[i]);
- exit(0);
-#endif
- execvp("mount", av);
- AuFin("mount");
-}
-
-/* ---------------------------------------------------------------------- */
-
-int main(int argc, char *argv[])
-{
- int err, c, status;
- pid_t pid;
- unsigned char flags[LastOpt];
- struct mntent ent;
- char *dev, *mntpnt, *opts, *cwd;
- DIR *cur;
-
- if (argc < 3) {
- errno = EINVAL;
- AuFin(NULL);
- }
-
- memset(flags, 0, sizeof(flags));
- flags[Update] = 1;
- opts = NULL;
-
- /* mount(8) always passes the arguments in this order */
- dev = argv[1];
- mntpnt = argv[2];
- while ((c = getopt(argc - 2, argv + 2, "fnvo:")) != -1) {
- switch (c) {
- case 'f':
- flags[Fake] = 1;
- break;
- case 'n':
- flags[Update] = 0;
- break;
- case 'v':
- flags[Verbose] = 1;
- break;
- case 'o':
- opts = optarg;
- break;
- case '?':
- case ':':
- errno = EINVAL;
- AuFin("internal error");
- }
- }
-
- cur = opendir(".");
- if (!cur)
- AuFin(".");
- err = chdir(mntpnt);
- if (err)
- AuFin("%s", mntpnt);
- cwd = getcwd(NULL, 0); /* glibc */
- if (!cwd)
- AuFin("getcwd");
- err = fchdir(dirfd(cur));
- if (err)
- AuFin("fchdir");
- closedir(cur); /* ignore */
-
- if (opts)
- test_opts(opts, flags);
-
- if (!flags[Bind] && flags[Update]) {
- err = access(MTab, R_OK | W_OK);
- if (err)
- AuFin(MTab);
- }
-
- if (flags[Remount]) {
- errno = EINVAL;
- if (flags[Bind])
- AuFin("both of remount and bind are specified");
- flags[AuFlush] = test_flush(opts);
- if (flags[AuFlush] /* && !flags[Fake] */) {
- err = au_plink(cwd, AuPlink_FLUSH, 1, 1);
- if (err)
- AuFin(NULL);
- }
- }
-
- pid = fork();
- if (!pid) {
- /* actual mount operation */
- do_mount(dev, mntpnt, argc, argv, flags);
- return 0;
- } else if (pid < 0)
- AuFin("fork");
-
- err = waitpid(pid, &status, 0);
- if (err < 0)
- AuFin("child process");
-
- err = !WIFEXITED(status);
- if (!err)
- err = WEXITSTATUS(status);
-
- if (!err && !flags[Bind]) {
- if (flags[Update])
- err = au_update_mtab(cwd, flags[Remount],
- flags[Verbose]);
- else if (flags[Verbose]) {
- /* withoug blocking plink */
- err = au_proc_getmntent(cwd, &ent);
- if (!err)
- au_print_ent(&ent);
- else
- AuFin("internal error");
- }
- }
-
- return err;
-}
diff --git a/package/aufs2-util/src/mtab.c b/package/aufs2-util/src/mtab.c
deleted file mode 100644
index 713e9e267..000000000
--- a/package/aufs2-util/src/mtab.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2005-2009 Junjiro Okajima
- *
- * This program, aufs 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
- */
-
-/* cf. fstab.c or the locking for /etc/mtab in util-linux */
-/*
- * we need to extract a part of util-linux and create a simple and generic
- * library for locking /etc/mtab.
- */
-
-/* #include <linux/proc_fs.h> */
-#define PROC_SUPER_MAGIC 0x9fa0
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-#include <mntent.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "au_util.h"
-
-void au_print_ent(struct mntent *ent)
-{
- printf("%s on %s type %s (%s)\n",
- ent->mnt_fsname, ent->mnt_dir, ent->mnt_type, ent->mnt_opts);
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void lock_mtab(char *pid_file)
-{
- int err, i;
-
- for (i = 0; i < 5; i++) {
- err = link(pid_file, MTab "~");
- if (!err)
- break;
- sleep(1);
- }
- if (err)
- AuFin(MTab "~");
-}
-
-static void unlock_mtab(void)
-{
- int err;
-
- err = rename(MTab "~", MTab);
- if (err)
- AuFin(MTab);
-}
-
-static void append_mtab(FILE *fp, FILE *ofp, struct mntent *ent)
-{
- int err;
- struct mntent *p;
-
- while ((p = getmntent(ofp))) {
- err = addmntent(fp, p);
- if (err)
- AuFin("addmntent");
- }
-
- err = addmntent(fp, ent);
- if (err)
- AuFin("addmntent");
-}
-
-/* todo: there are some cases which options are not changed */
-static void update_mtab(FILE *fp, char *mntpnt, int do_remount, int do_verbose)
-{
- int err;
- long pos;
- FILE *ofp;
- struct mntent ent, *p;
-
- /* prohibit updating mount options for this mntpnt */
- au_plink_maint(mntpnt);
- err = au_proc_getmntent(mntpnt, &ent);
- if (err)
- AuFin("no such mount point");
-
- ofp = setmntent(MTab, "r");
- if (!ofp)
- AuFin(MTab);
-
- if (do_remount) {
- /* find the last one */
- pos = -1;
- while ((p = getmntent(ofp))) {
- if (!strcmp(p->mnt_dir, mntpnt))
- pos = ftell(ofp);
- }
- rewind(ofp);
-
- if (pos > 0) {
- while ((p = getmntent(ofp))) {
- if (ftell(ofp) == pos) {
- /* replace the line */
- p = &ent;
- pos = -1;
- }
- err = addmntent(fp, p);
- if (err)
- AuFin("addmntent");
- }
- if (pos > 0)
- AuFin("internal error");
- } else
- append_mtab(fp, ofp, &ent);
- } else
- append_mtab(fp, ofp, &ent);
-
- endmntent(ofp); /* ignore */
- au_plink_maint(NULL);
- if (do_verbose)
- au_print_ent(&ent);
-}
-
-/* ---------------------------------------------------------------------- */
-
-int au_update_mtab(char *mntpnt, int do_remount, int do_verbose)
-{
- int err, fd, status, e2;
- pid_t pid;
- ino_t ino;
- struct stat st;
- struct statfs stfs;
- struct flock flock = {
- .l_type = F_WRLCK,
- .l_whence = SEEK_SET,
- .l_start = 0,
- .l_len = 0
- };
- char pid_file[sizeof(MTab "~.") + 20];
- FILE *fp;
-
- err = statfs(MTab, &stfs);
- if (stfs.f_type == PROC_SUPER_MAGIC)
- return 0;
-
- snprintf(pid_file, sizeof(pid_file), MTab "~.%d", getpid());
- fd = open(pid_file, O_RDWR | O_CREAT | O_EXCL,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- if (fd < 0)
- AuFin("%s", pid_file);
- err = fcntl(fd, F_SETLK, &flock);
- if (err)
- AuFin("%s", pid_file);
- fp = fdopen(fd, "r+");
- if (!fp)
- AuFin("%s", pid_file);
-
- pid = fork();
- if (!pid) {
- lock_mtab(pid_file);
- update_mtab(fp, mntpnt, do_remount, do_verbose);
- unlock_mtab();
- return 0;
- } else if (pid < 0)
- AuFin("fork");
-
- err = fstat(fd, &st);
- if (err)
- perror(pid_file);
- ino = st.st_ino;
-
- err = waitpid(pid, &status, 0);
- if (err < 0) {
- perror(pid_file);
- goto out;
- }
- err = !WIFEXITED(status);
- if (!err)
- err = WEXITSTATUS(status);
-
- e2 = unlink(pid_file);
- if (e2 && errno != ENOENT)
- perror(pid_file);
- e2 = stat(MTab "~", &st);
- if (!e2) {
- if (st.st_ino == ino) {
- /*
- * The inode number is same,
- * it means it is we who made the file.
- * If someone else removed our file between stat(2) and
- * unlink(2), it is a breakage of the rule.
- */
- e2 = unlink(MTab "~");
- if (e2)
- perror(MTab);
- }
- } else if (errno != ENOENT)
- perror(MTab "~");
- fclose(fp);
-
- out:
- return err;
-}
diff --git a/package/aufs2-util/src/plink.c b/package/aufs2-util/src/plink.c
deleted file mode 100644
index 6ff16c76a..000000000
--- a/package/aufs2-util/src/plink.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (C) 2005-2009 Junjiro Okajima
- *
- * This program, aufs 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
- */
-
-#define _FILE_OFFSET_BITS 64 /* ftw.h */
-#define _XOPEN_SOURCE 500 /* ftw.h */
-#define _GNU_SOURCE /* ftw.h */
-
-#include <sys/ioctl.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <ftw.h>
-#include <mntent.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <linux/aufs_type.h>
-#include "au_util.h"
-
-/* todo: try argz? */
-static struct name_array {
- char *o;
- int bytes;
-
- char *cur;
- int nname;
-} na;
-
-static struct ino_array {
- char *o;
- int bytes;
-
- union {
- char *p;
- ino_t *cur;
- };
- int nino;
-} ia;
-
-static int na_append(char *plink_dir, char *name)
-{
- int l, sz;
- char *p;
- const int cur = na.cur - na.o;
-
- l = strlen(plink_dir) + strlen(name) + 2;
- sz = na.bytes + l;
- p = realloc(na.o, sz);
- if (!p)
- AuFin("realloc");
-
- na.o = p;
- na.bytes = sz;
- na.cur = p + cur;
- na.cur += sprintf(na.cur, "%s/%s", plink_dir, name) + 1;
- na.nname++;
-
- return 0;
-}
-
-static int ia_append(ino_t ino)
-{
- int sz;
- char *p;
- const int cur = ia.p - ia.o;
-
- sz = na.bytes + sizeof(ino_t);
- p = realloc(ia.o, sz);
- if (!p)
- AuFin("realloc");
-
- ia.o = p;
- ia.bytes = sz;
- ia.p = p + cur;
- *ia.cur++ = ino;
- ia.nino++;
-
- return 0;
-}
-
-static int build_array(char *plink_dir)
-{
- int err;
- DIR *dp;
- struct dirent *de;
- char *p;
- ino_t ino;
-
- err = access(plink_dir, F_OK);
- if (err)
- return 0;
-
- err = 0;
- dp = opendir(plink_dir);
- if (!dp)
- AuFin("%s", plink_dir);
- while ((de = readdir(dp))) {
- if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
- continue;
-#if 0
- if (de->d_type == DT_DIR) {
- errno = EISDIR;
- AuFin(de->d_name);
- }
-#endif
-
- err = na_append(plink_dir, de->d_name);
- if (err)
- break;
-
- p = strchr(de->d_name, '.');
- if (!p) {
- errno = EINVAL;
- AuFin("internal error, %s", de->d_name);
- }
- *p = 0;
- errno = 0;
- ino = strtoull(de->d_name, NULL, 0);
- if (ino == /*ULLONG_MAX*/-1 && errno == ERANGE)
- AuFin("internal error, %s", de->d_name);
- err = ia_append(ino);
- if (err)
- break;
- }
- closedir(dp);
-
- return err;
-}
-
-static int ia_test(ino_t ino)
-{
- int i;
- ino_t *p;
-
- /* todo: hash table */
- ia.p = ia.o;
- p = ia.cur;
- for (i = 0; i < ia.nino; i++)
- if (*p++ == ino)
- return 1;
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int ftw_list(const char *fname, const struct stat *st, int flags,
- struct FTW *ftw)
-{
- if (!strcmp(fname + ftw->base, AUFS_WH_PLINKDIR))
- return FTW_SKIP_SUBTREE;
- if (flags == FTW_D || flags == FTW_DNR)
- return FTW_CONTINUE;
-
- if (ia_test(st->st_ino))
- puts(fname);
-
- return FTW_CONTINUE;
-}
-
-static int ftw_cpup(const char *fname, const struct stat *st, int flags,
- struct FTW *ftw)
-{
- int err;
-
- if (!strcmp(fname + ftw->base, AUFS_WH_PLINKDIR))
- return FTW_SKIP_SUBTREE;
- if (flags == FTW_D || flags == FTW_DNR)
- return FTW_CONTINUE;
-
- /*
- * do nothing but update something harmless in order to make it copyup
- */
- if (ia_test(st->st_ino)) {
- Dpri("%s\n", fname);
- if (!S_ISLNK(st->st_mode))
- err = chown(fname, -1, -1);
- else
- err = lchown(fname, -1, -1);
- if (err)
- AuFin("%s", fname);
- }
-
- return FTW_CONTINUE;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static DIR *dp;
-void au_plink_maint(char *path)
-{
- int err;
-
- if (path) {
- if (dp) {
- errno = EINVAL;
- AuFin("dp is not NULL");
- }
- dp = opendir(path);
- if (!dp)
- AuFin("%s", path);
-
- err = ioctl(dirfd(dp), AUFS_CTL_PLINK_MAINT);
-#ifndef DEBUG
- if (err)
- AuFin("AUFS_CTL_PLINK_MAINT");
-#endif
- } else {
- err = closedir(dp);
- if (err)
- AuFin("closedir");
- dp = NULL;
- }
-}
-
-void au_clean_plink(void)
-{
- int err;
-
- err = ioctl(dirfd(dp), AUFS_CTL_PLINK_CLEAN);
-#ifndef DEBUG
- if (err)
- AuFin("AUFS_CTL_PLINK_CLEAN");
-#endif
-}
-
-static int do_plink(char *cwd, int cmd, int nbr, char *br[])
-{
- int err, i, l;
- struct rlimit rlim;
- __nftw_func_t func;
- char *p;
-
- err = 0;
- switch (cmd) {
- case AuPlink_FLUSH:
- /*FALLTHROUGH*/
- case AuPlink_CPUP:
- func = ftw_cpup;
- break;
- case AuPlink_LIST:
- func = ftw_list;
- break;
- default:
- errno = EINVAL;
- AuFin(NULL);
- func = NULL; /* never reach here */
- }
-
- for (i = 0; i < nbr; i++) {
- //puts(br[i]);
- p = strchr(br[i], '=');
- if (strcmp(p + 1, AUFS_BRPERM_RW)
- && strcmp(p + 1, AUFS_BRPERM_RWNLWH))
- continue;
-
- *p = 0;
- l = strlen(br[i]);
- p = malloc(l + sizeof(AUFS_WH_PLINKDIR) + 2);
- if (!p)
- AuFin("malloc");
- sprintf(p, "%s/%s", br[i], AUFS_WH_PLINKDIR);
- //puts(p);
- err = build_array(p);
- if (err)
- AuFin("build_array");
- free(p);
- }
- if (!ia.nino)
- goto out;
-
- if (cmd == AuPlink_LIST) {
- ia.p = ia.o;
- for (i = 0; i < ia.nino; i++)
- printf("%llu ", (unsigned long long)*ia.cur++);
- putchar('\n');
- }
-
- err = getrlimit(RLIMIT_NOFILE, &rlim);
- if (err)
- AuFin("getrlimit");
- nftw(cwd, func, rlim.rlim_cur - 10,
- FTW_PHYS | FTW_MOUNT | FTW_ACTIONRETVAL);
- /* ignore */
-
- if (cmd == AuPlink_FLUSH) {
- au_clean_plink();
-
- na.cur = na.o;
- for (i = 0; i < na.nname; i++) {
- Dpri("%s\n", na.cur);
- err = unlink(na.cur);
- if (err)
- AuFin("%s", na.cur);
- na.cur += strlen(na.cur) + 1;
- }
- }
-
- out:
- free(ia.o);
- free(na.o);
- return err;
-}
-
-int au_plink(char cwd[], int cmd, int begin_maint, int end_maint)
-{
- int err, nbr;
- struct mntent ent;
- char **br;
-
- if (begin_maint)
- au_plink_maint(cwd);
-
- err = au_proc_getmntent(cwd, &ent);
- if (err)
- AuFin("no such mount point");
-
- if (hasmntopt(&ent, "noplink"))
- goto out; /* success */
-
-#ifdef DEBUG
- //char a[] = "a,b,br:/tmp/br0=rw:/br1=ro";
- char a[] = "a,b,si=1,c";
- ent.mnt_opts = a;
-#endif
- err = au_br(&br, &nbr, &ent);
- //printf("nbr %d\n", nbr);
- if (err)
- AuFin(NULL);
-
- err = do_plink(cwd, cmd, nbr, br);
- if (err)
- AuFin(NULL);
-
- out:
- if (end_maint)
- au_plink_maint(NULL);
- return err;
-}
diff --git a/package/aufs2-util/src/proc_mnt.c b/package/aufs2-util/src/proc_mnt.c
deleted file mode 100644
index 5230aa259..000000000
--- a/package/aufs2-util/src/proc_mnt.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2005-2009 Junjiro Okajima
- *
- * This program, aufs 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
- */
-
-#include <sys/types.h>
-#include <errno.h>
-#include <mntent.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "au_util.h"
-
-#define ProcMounts "/proc/self/mounts"
-
-static void copy_ent(struct mntent *dst, struct mntent *src)
-{
- free(dst->mnt_opts);
- free(dst->mnt_type);
- free(dst->mnt_dir);
- free(dst->mnt_fsname);
-
- dst->mnt_dir = NULL;
- dst->mnt_type = NULL;
- dst->mnt_opts = NULL;
-
- dst->mnt_fsname = strdup(src->mnt_fsname);
- if (dst->mnt_fsname)
- dst->mnt_dir = strdup(src->mnt_dir);
- if (dst->mnt_dir)
- dst->mnt_type = strdup(src->mnt_type);
- if (dst->mnt_type)
- dst->mnt_opts = strdup(src->mnt_opts);
- if (dst->mnt_opts) {
- dst->mnt_freq = src->mnt_freq;
- dst->mnt_passno = src->mnt_passno;
- } else
- AuFin("strdup");
-
-}
-
-int au_proc_getmntent(char *mntpnt, struct mntent *rent)
-{
- int found;
- struct mntent *p;
- FILE *fp;
-
- fp = setmntent(ProcMounts, "r");
- if (!fp)
- AuFin(ProcMounts);
-
- /* find the last one */
- memset(rent, 0, sizeof(*rent));
- found = 0;
- while ((p = getmntent(fp)))
- if (!strcmp(p->mnt_dir, mntpnt)) {
- Dpri("%s, %s, %s, %s, %d, %d\n",
- p->mnt_fsname, p->mnt_dir, p->mnt_type,
- p->mnt_opts, p->mnt_freq, p->mnt_passno);
- copy_ent(rent, p);
- found = 1;
- }
- endmntent(fp);
-
- if (!found) {
- errno = EINVAL;
- AuFin("%s", mntpnt);
- }
-
- return 0;
-}
diff --git a/package/aufs2-util/src/rdu.c b/package/aufs2-util/src/rdu.c
deleted file mode 100644
index ac958f084..000000000
--- a/package/aufs2-util/src/rdu.c
+++ /dev/null
@@ -1,749 +0,0 @@
-/*
- * Copyright (C) 2009 Junjiro Okajima
- *
- * This program, aufs 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
- */
-
-#define _ATFILE_SOURCE
-#define _GNU_SOURCE
-#define _REENTRANT
-
-#include <linux/aufs_type.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/vfs.h> /* or <sys/statfs.h> */
-#include <assert.h>
-#include <dirent.h>
-#include <dlfcn.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <search.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "compat.h"
-
-/* ---------------------------------------------------------------------- */
-
-struct rdu {
-#ifdef AuRDU_REENTRANT
- pthread_rwlock_t lock;
-#else
- struct dirent de;
-#endif
-
- int fd;
-
- unsigned long npos, idx;
- struct au_rdu_ent **pos;
-
- unsigned long nent, sz;
- struct au_rdu_ent *ent;
-
- int shwh;
- struct au_rdu_ent *real, *wh;
-};
-
-static struct rdu **rdu;
-#define RDU_STEP 8
-static int rdu_cur, rdu_lim = RDU_STEP;
-
-/* ---------------------------------------------------------------------- */
-
-/* #define RduLocalTest */
-#ifdef RduLocalTest
-static int rdu_test_data(struct rdu *p, int err)
-{
- struct au_rdu_ent *e = p->ent;
- static int i;
-
- if (!i++) {
- err = 3;
- e->ino = e->type = e->nlen = 1;
- strcpy(e->name, ".");
- e += au_rdu_len(e->nlen);
- e->ino = e->type = e->nlen = 2;
- strcpy(e->name, "..");
- e += au_rdu_len(e->nlen);
- e->ino = e->type = e->nlen = 3;
- strcpy(e->name, "foo");
- } else
- err = 0;
-
- return err;
-}
-#else
-static int rdu_test_data(struct rdu *p, int err)
-{
- return err;
-}
-#endif
-
-/* #define RduDebug */
-#ifdef RduDebug
-#define DPri(fmt, args...) fprintf(stderr, "%s:%d: " fmt, \
- __func__, __LINE__, ##args)
-#else
-#define DPri(fmt, args...) do {} while (0)
-#endif
-
-/* ---------------------------------------------------------------------- */
-
-#ifdef AuRDU_REENTRANT
-static void rdu_rwlock_init(struct rdu *p)
-{
- pthread_rwlock_init(&p->lock);
-}
-
-static void rdu_read_lock(struct rdu *p)
-{
- pthread_rwlock_rdlock(&p->lock);
-}
-
-static void rdu_write_lock(struct rdu *p)
-{
- pthread_rwlock_wrlock(&p->lock);
-}
-
-static void rdu_unlock(struct rdu *p)
-{
- pthread_rwlock_unlock(&p->lock);
-}
-
-static pthread_mutex_t rdu_lib_mtx = PTHREAD_MUTEX_INITIALIZER;
-#define rdu_lib_lock() pthread_mutex_lock(&rdu_lib_mtx)
-#define rdu_lib_unlock() pthread_mutex_unlock(&rdu_lib_mtx)
-#define rdu_lib_must_lock() assert(pthread_mutex_trylock(&rdu_lib_mtx))
-#else
-static void rdu_rwlock_init(struct rdu *p)
-{
- /* empty */
-}
-
-static void rdu_read_lock(struct rdu *p)
-{
- /* empty */
-}
-
-static void rdu_write_lock(struct rdu *p)
-{
- /* empty */
-}
-
-static void rdu_unlock(struct rdu *p)
-{
- /* empty */
-}
-
-#define rdu_lib_lock() do {} while(0)
-#define rdu_lib_unlock() do {} while(0)
-#define rdu_lib_must_lock() do {} while(0)
-#endif
-
-/*
- * initialize this library, particularly global variables.
- */
-static int rdu_lib_init(void)
-{
- int err;
-
- err = 0;
- if (rdu)
- goto out;
-
- rdu_lib_lock();
- if (!rdu) {
- rdu = calloc(rdu_lim, sizeof(*rdu));
- err = !rdu;
- }
- rdu_lib_unlock();
-
- out:
- return err;
-}
-
-static int rdu_append(struct rdu *p)
-{
- int err, i;
- void *t;
-
- rdu_lib_must_lock();
-
- err = 0;
- if (rdu_cur < rdu_lim - 1)
- rdu[rdu_cur++] = p;
- else {
- t = realloc(rdu, rdu_lim + RDU_STEP * sizeof(*rdu));
- if (t) {
- rdu = t;
- rdu_lim += RDU_STEP;
- rdu[rdu_cur++] = p;
- for (i = 0; i < RDU_STEP - 1; i++)
- rdu[rdu_cur + i] = NULL;
- } else
- err = -1;
- }
-
- return err;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static struct rdu *rdu_new(int fd)
-{
- struct rdu *p;
- int err;
-
- p = malloc(sizeof(*p));
- if (p) {
- rdu_rwlock_init(p);
- p->fd = fd;
- p->sz = BUFSIZ;
- p->ent = malloc(BUFSIZ);
- if (p->ent) {
- err = rdu_append(p);
- if (!err)
- goto out; /* success */
- }
- }
- free(p);
- p = NULL;
-
- out:
- return p;
-}
-
-static struct rdu *rdu_buf_lock(int fd)
-{
- struct rdu *p;
- int i;
-
- assert(rdu);
- assert(fd >= 0);
-
- p = NULL;
- rdu_lib_lock();
- for (i = 0; i < rdu_cur; i++)
- if (rdu[i] && rdu[i]->fd == fd) {
- p = rdu[i];
- goto out;
- }
-
- for (i = 0; i < rdu_cur; i++)
- if (rdu[i] && rdu[i]->fd == -1) {
- p = rdu[i];
- p->fd = fd;
- goto out;
- }
- if (!p)
- p = rdu_new(fd);
-
- out:
- if (p)
- rdu_write_lock(p);
- rdu_lib_unlock();
-
- return p;
-}
-
-static void rdu_free(int fd)
-{
- struct rdu *p;
-
- p = rdu_buf_lock(fd);
- if (p) {
- free(p->ent);
- free(p->pos);
- p->fd = -1;
- p->ent = NULL;
- p->pos = NULL;
- rdu_unlock(p);
- }
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int rdu_do_store(int dirfd, struct au_rdu_ent *ent,
- struct au_rdu_ent **pos, struct rdu *p)
-{
- int err;
- unsigned char c;
- struct stat st;
-
- c = ent->name[ent->nlen];
- ent->name[ent->nlen] = 0;
- DPri("%s\n", ent->name);
- err = fstatat(dirfd, ent->name, &st, AT_SYMLINK_NOFOLLOW);
- ent->name[ent->nlen] = c;
- if (!err) {
- ent->ino = st.st_ino;
- pos[p->idx++] = ent;
- } else {
- DPri("err %d\n", err);
- if (errno == ENOENT)
- err = 0;
- }
-
- return err;
-}
-
-struct rdu_thread_arg {
- int pipefd;
- struct rdu *p;
-};
-
-static void *rdu_thread(void *_arg)
-{
- int err, pipefd, dirfd;
- ssize_t ssz;
- struct rdu_thread_arg *arg = _arg;
- struct au_rdu_ent *ent, **pos;
- struct rdu *p;
-
- pipefd = arg->pipefd;
- p = arg->p;
- dirfd = p->fd;
- pos = p->pos;
- while (1) {
- DPri("read\n");
- ssz = read(pipefd, &ent, sizeof(ent));
- DPri("ssz %zd\n", ssz);
- if (ssz != sizeof(ent) || !ent) {
- //perror("read");
- break;
- }
-
- //DPri("%p\n", ent);
- err = rdu_do_store(dirfd, ent, pos, p);
- }
-
- DPri("here\n");
- return NULL;
-}
-
-static int rdu_store(struct rdu *p, struct au_rdu_ent *ent, int pipefd)
-{
-#ifdef RduLocalTest
- if (ent)
- return rdu_do_store(p->fd, ent, p->pos, p);
- return 0;
-#else
- ssize_t ssz;
-
- //DPri("%p\n", ent);
- ssz = write(pipefd, &ent, sizeof(ent));
- DPri("ssz %zd\n", ssz);
- //sleep(1);
- return ssz != sizeof(ent);
-#endif
-}
-
-/* ---------------------------------------------------------------------- */
-/* the heart of this library */
-
-static void rdu_tfree(void *node)
-{
- /* empty */
-}
-
-static int rdu_ent_compar(const void *_a, const void *_b)
-{
- int ret;
- const struct au_rdu_ent *a = _a, *b = _b;
-
- ret = (int)a->nlen - b->nlen;
- if (!ret)
- ret = memcmp(a->name, b->name, a->nlen);
- return ret;
-}
-
-static int rdu_ent_compar_wh(const void *_a, const void *_b)
-{
- int ret;
- const struct au_rdu_ent *real = _a, *wh = _b;
-
- if (real->nlen >= AUFS_WH_PFX_LEN
- && !memcmp(real->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
- wh = _a;
- real = _b;
- }
-
- ret = (int)wh->nlen - AUFS_WH_PFX_LEN - real->nlen;
- if (!ret)
- ret = memcmp(wh->name + AUFS_WH_PFX_LEN, real->name,
- real->nlen);
- return ret;
-}
-
-/* tsearch(3) may not be thread-safe */
-static int rdu_ent_append(struct rdu *p, struct au_rdu_ent *ent, int pipefd)
-{
- int err;
- struct au_rdu_ent *e;
-
- err = 0;
- e = tfind(ent, (void *)&p->wh, rdu_ent_compar_wh);
- if (e)
- goto out;
-
- e = tsearch(ent, (void *)&p->real, rdu_ent_compar);
- if (e)
- err = rdu_store(p, ent, pipefd);
- else
- err = -1;
-
- out:
- return err;
-}
-
-static int rdu_ent_append_wh(struct rdu *p, struct au_rdu_ent *ent, int pipefd)
-{
- int err;
- struct au_rdu_ent *e;
-
- err = 0;
- e = tfind(ent, (void *)&p->wh, rdu_ent_compar);
- if (e)
- goto out;
-
- e = tsearch(ent, (void *)&p->wh, rdu_ent_compar);
- if (e) {
- if (p->shwh)
- err = rdu_store(p, ent, pipefd);
- } else
- err = -1;
-
- out:
- return err;
-}
-
-static int rdu_merge(struct rdu *p)
-{
- int err;
- unsigned long ul;
- pthread_t th;
- int fds[2];
- struct rdu_thread_arg arg;
- struct au_rdu_ent *ent;
- void *t;
-
- err = -1;
- p->pos = malloc(sizeof(*p->pos) * p->npos);
- if (!p->pos)
- goto out;
-
- /* pipe(2) may not be scheduled well in linux-2.6.23 and earlier */
- err = pipe(fds);
- if (err)
- goto out_free;
-
- arg.pipefd = fds[0];
- arg.p = p;
-#ifndef RduLocalTest
- err = pthread_create(&th, NULL, rdu_thread, &arg);
-#endif
- if (err)
- goto out_close;
-
- p->real = NULL;
- p->wh = NULL;
- ent = p->ent;
- for (ul = 0; !err && ul < p->npos; ul++) {
- if (ent->nlen <= AUFS_WH_PFX_LEN
- || strncmp(ent->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))
- err = rdu_ent_append(p, ent, fds[1]);
- else
- err = rdu_ent_append_wh(p, ent, fds[1]);
- ent += au_rdu_len(ent->nlen);
- }
- rdu_store(p, /*ent*/NULL, fds[1]); /* terminate the thread */
- tdestroy(p->real, rdu_tfree);
- tdestroy(p->wh, rdu_tfree);
-
-#ifndef RduLocalTest
- pthread_join(th, NULL);
-#endif
- p->npos = p->idx;
- t = realloc(p->pos, sizeof(*p->pos) * p->npos);
- if (t)
- p->pos = t;
- /* t == NULL is not an error */
-
- out_close:
- close(fds[1]);
- close(fds[0]);
- if (!err)
- goto out; /* success */
- out_free:
- free(p->pos);
- p->pos = NULL;
- out:
- return err;
-}
-
-static int rdu_init(struct rdu *p)
-{
- int err;
- struct aufs_rdu param;
- char *t;
-
- memset(&param, 0, sizeof(param));
- param.ent = p->ent;
- param.sz = p->sz;
- t = getenv("AUFS_RDU_BLK");
- if (t)
- param.blk = strtoul(t + sizeof("AUFS_RDU_BLK"), NULL, 0);
-
- do {
- err = ioctl(p->fd, AUFS_CTL_RDU, &param);
- err = rdu_test_data(p, err);
- if (err > 0) {
- p->npos += err;
- if (!param.full)
- continue;
-
- assert(param.blk);
- t = realloc(p->ent, p->sz + param.blk);
- if (t) {
- param.sz = param.blk;
- param.ent = (void *)(t + p->sz);
- p->ent = (void *)t;
- p->sz += param.blk;
- } else
- err = -1;
- }
- } while (err > 0);
- p->shwh = param.shwh;
- if (!err)
- err = rdu_merge(p);
-
- if (err) {
- free(p->ent);
- p->ent = NULL;
- }
-
- return err;
-}
-
-static int rdu_pos(struct dirent *de, struct rdu *p, long pos)
-{
- int err;
- struct au_rdu_ent *ent;
-
- err = -1;
- if (pos <= p->npos) {
- ent = p->pos[pos];
- de->d_ino = ent->ino;
- de->d_off = pos;
- de->d_reclen = sizeof(*ent) + ent->nlen;
- de->d_type = ent->type;
- memcpy(de->d_name, ent->name, ent->nlen);
- de->d_name[ent->nlen] = 0;
- err = 0;
- }
- return err;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static struct dirent *(*real_readdir)(DIR *dir);
-static int (*real_readdir_r)(DIR *dir, struct dirent *de, struct dirent **rde);
-static int (*real_closedir)(DIR *dir);
-
-static int rdu_dl(void **real, char *sym)
-{
- char *p;
-
- if (*real)
- return 0;
-
- dlerror(); /* clear */
- *real = dlsym(RTLD_NEXT, sym);
- p = dlerror();
- if (p)
- fprintf(stderr, "%s\n", p);
- return !!p;
-}
-
-#define RduDlFunc(sym) \
-static int rdu_dl_##sym(void) \
-{ \
- return rdu_dl((void *)&real_##sym, #sym); \
-}
-
-RduDlFunc(readdir);
-RduDlFunc(closedir);
-
-#ifdef AuRDU_REENTRANT
-RduDlFunc(readdir_r);
-#else
-#define rdu_dl_readdir_r() 1
-#endif
-
-/* ---------------------------------------------------------------------- */
-
-static int rdu_readdir(DIR *dir, struct dirent *de, struct dirent **rde)
-{
- int err, fd;
- struct rdu *p;
- long pos;
- struct statfs stfs;
-
- if (rde)
- *rde = NULL;
-
- errno = EBADF;
- fd = dirfd(dir);
- err = fd;
- if (fd < 0)
- goto out;
-
- err = fstatfs(fd, &stfs);
- if (err)
- goto out;
-
- if (
-#ifdef RduLocalTest
- 1 ||
-#endif
- stfs.f_type == AUFS_SUPER_MAGIC) {
- err = rdu_lib_init();
- if (err)
- goto out;
-
- p = rdu_buf_lock(fd);
- if (!p)
- goto out;
-
- pos = telldir(dir);
- if (!pos || !p->npos) {
- err = rdu_init(p);
- rdu_unlock(p);
- }
- if (err)
- goto out;
-
- rdu_read_lock(p);
- if (!de)
- de = &p->de;
- err = rdu_pos(de, p, pos);
- rdu_unlock(p);
- if (!err) {
- *rde = de;
- seekdir(dir, pos + 1);
- }
- } else if (!de) {
- if (!rdu_dl_readdir()) {
- err = 0;
- *rde = real_readdir(dir);
- if (!*rde)
- err = -1;
- }
- } else {
- if (!rdu_dl_readdir_r())
- err = real_readdir_r(dir, de, rde);
- }
- out:
- return err;
-}
-
-struct dirent *readdir(DIR *dir)
-{
- struct dirent *de;
- int err;
-
- err = rdu_readdir(dir, NULL, &de);
- DPri("err %d\n", err);
- return de;
-}
-
-#ifdef AuRDU_REENTRANT
-int readdir_r(DIR *dirp, struct dirent *de, struct dirent **rde)
-{
- return rdu_readdir(dir, de, rde);
-}
-#endif
-
-int closedir(DIR *dir)
-{
- int err, fd;
- struct statfs stfs;
-
- errno = EBADF;
- fd = dirfd(dir);
- if (fd < 0)
- goto out;
- err = fstatfs(fd, &stfs);
- if (err)
- goto out;
-
- if (stfs.f_type == AUFS_SUPER_MAGIC)
- rdu_free(fd);
- if (!rdu_dl_closedir())
- err = real_closedir(dir);
-
- out:
- return err;
-}
-
-#if 0
-extern DIR *opendir (__const char *__name) __nonnull ((1));
-extern int closedir (DIR *__dirp) __nonnull ((1));
-extern struct dirent *__REDIRECT (readdir, (DIR *__dirp), readdir64)
- __nonnull ((1));
-extern struct dirent64 *readdir64 (DIR *__dirp) __nonnull ((1));
-extern int readdir_r (DIR *__restrict __dirp,
- struct dirent *__restrict __entry,
- struct dirent **__restrict __result)
- __nonnull ((1, 2, 3));
-extern int readdir64_r (DIR *__restrict __dirp,
- struct dirent64 *__restrict __entry,
- struct dirent64 **__restrict __result)
- __nonnull ((1, 2, 3));
-extern void rewinddir (DIR *__dirp) __THROW __nonnull ((1));
-extern void seekdir (DIR *__dirp, long int __pos) __THROW __nonnull ((1));
-extern long int telldir (DIR *__dirp) __THROW __nonnull ((1));
-extern int dirfd (DIR *__dirp) __THROW __nonnull ((1));
-extern int scandir (__const char *__restrict __dir,
- struct dirent ***__restrict __namelist,
- int (*__selector) (__const struct dirent *),
- int (*__cmp) (__const void *, __const void *))
- __nonnull ((1, 2));
-extern int scandir64 (__const char *__restrict __dir,
- struct dirent64 ***__restrict __namelist,
- int (*__selector) (__const struct dirent64 *),
- int (*__cmp) (__const void *, __const void *))
- __nonnull ((1, 2));
-extern int alphasort (__const void *__e1, __const void *__e2)
- __THROW __attribute_pure__ __nonnull ((1, 2));
-extern int alphasort64 (__const void *__e1, __const void *__e2)
- __THROW __attribute_pure__ __nonnull ((1, 2));
-extern int versionsort (__const void *__e1, __const void *__e2)
- __THROW __attribute_pure__ __nonnull ((1, 2));
-extern int versionsort64 (__const void *__e1, __const void *__e2)
- __THROW __attribute_pure__ __nonnull ((1, 2));
-extern __ssize_t getdirentries (int __fd, char *__restrict __buf,
- size_t __nbytes,
- __off_t *__restrict __basep)
- __THROW __nonnull ((2, 4));
-extern __ssize_t getdirentries64 (int __fd, char *__restrict __buf,
- size_t __nbytes,
- __off64_t *__restrict __basep)
- __THROW __nonnull ((2, 4));
-#endif
diff --git a/package/aufs2-util/src/umount.aufs b/package/aufs2-util/src/umount.aufs
deleted file mode 100755
index 395689236..000000000
--- a/package/aufs2-util/src/umount.aufs
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh -
-
-# Copyright (C) 2005-2009 Junjiro Okajima
-#
-# This program, aufs 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
-
-#
-# The main purpose of this script is calling auplink.
-#
-
-PATH=/usr/bin:/usr/sbin:/bin:/sbin
-export PATH
-
-set -e
-#set -x; echo $0 $@
-dev="$1"
-shift
-auplink "$dev" flush
-exec umount -i $@ "$dev"
diff --git a/package/autossh/patches/patch-Makefile_in b/package/autossh/patches/patch-Makefile_in
index 098c3fee1..6aa8a369a 100644
--- a/package/autossh/patches/patch-Makefile_in
+++ b/package/autossh/patches/patch-Makefile_in
@@ -1,5 +1,14 @@
--- autossh-1.4b.orig/Makefile.in 2008-04-11 22:47:46.000000000 +0200
-+++ autossh-1.4b/Makefile.in 2010-02-05 17:49:30.511836749 +0100
++++ autossh-1.4b/Makefile.in 2011-01-14 18:20:25.000000000 +0100
+@@ -31,7 +31,7 @@ all: $(TARGET)
+
+
+ $(TARGET): $(OFILES)
+- $(CC) $(CPPFLAGS) -o $(TARGET) $(OFILES) $(LIBS)
++ $(CC) $(LDFLAGS) -o $(TARGET) $(OFILES) $(LIBS)
+
+ clean:
+ - /bin/rm -f *.o *.a *.core *~
@@ -45,18 +45,18 @@ distclean: allclean
- /bin/rm -f Makefile
diff --git a/package/avahi/patches/patch-ltmain_sh b/package/avahi/patches/patch-ltmain_sh
new file mode 100644
index 000000000..2bd6af820
--- /dev/null
+++ b/package/avahi/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- avahi-0.6.25.orig/ltmain.sh 2009-04-14 03:48:18.000000000 +0200
++++ avahi-0.6.25/ltmain.sh 2011-01-14 18:46:07.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/axtls/Makefile b/package/axtls/Makefile
index c3c659666..62dbb7226 100644
--- a/package/axtls/Makefile
+++ b/package/axtls/Makefile
@@ -4,9 +4,9 @@
include ${TOPDIR}/rules.mk
PKG_NAME:= axtls
-PKG_VERSION:= 1.2.2
+PKG_VERSION:= 1.3.0
PKG_RELEASE:= 1
-PKG_MD5SUM:= 03471b5a5874e2ce86025f24b3fa0958
+PKG_MD5SUM:= 4a06dd5b34489f11fbf2b4249a9dd303
PKG_DESCR:= small embedded webserver
PKG_SECTION:= net/security
PKG_DEPENDS:= libaxtls
diff --git a/package/axtls/files/config b/package/axtls/files/config
index ed4e64806..a37878b3a 100644
--- a/package/axtls/files/config
+++ b/package/axtls/files/config
@@ -50,6 +50,7 @@ CONFIG_USE_DEV_URANDOM=y
# CONFIG_OPENSSL_COMPATIBLE is not set
# CONFIG_PERFORMANCE_TESTING is not set
# CONFIG_SSL_TEST is not set
+# CONFIG_AXTLSWRAP is not set
CONFIG_AXHTTPD=y
#
@@ -118,3 +119,6 @@ SQU_KARATSUBA_THRESH=0
# CONFIG_BIGINT_SLIDING_WINDOW is not set
# CONFIG_BIGINT_SQUARE is not set
# CONFIG_BIGINT_CHECK_ON is not set
+CONFIG_INTEGER_32BIT=y
+# CONFIG_INTEGER_16BIT is not set
+# CONFIG_INTEGER_8BIT is not set
diff --git a/package/base-files/Makefile b/package/base-files/Makefile
index db08b8860..dee9fd9a4 100644
--- a/package/base-files/Makefile
+++ b/package/base-files/Makefile
@@ -45,11 +45,14 @@ endif
mkdir -p $(IDIR_BASE_FILES)/usr/lib/ipkg/lists
mkdir -p $(IDIR_BASE_FILES)/etc/crontabs
mkdir -p $(IDIR_BASE_FILES)/{dev,boot,root,sys,proc,tmp,mnt}
+ifeq (${ADK_INSTALL_PACKAGE_NETWORK_SCRIPTS},y)
mkdir -p $(IDIR_BASE_FILES)/etc/network/{if-pre-up.d,if-up.d,if-down.d,if-post-down.d}
+endif
mkdir -p $(IDIR_BASE_FILES)/usr/{lib,bin}
chmod 755 $(IDIR_BASE_FILES)/lib/mdev/init
chmod 600 $(IDIR_BASE_FILES)/etc/shadow
chmod 600 $(IDIR_BASE_FILES)/etc/network/interfaces
+ chmod 1777 ${IDIR_BASE_FILES}/tmp
ln -sf ../proc/mounts $(IDIR_BASE_FILES)/etc/mtab
rm -rf $(IDIR_BASE_FILES)/var
ln -sf tmp $(IDIR_BASE_FILES)/var
diff --git a/package/base-files/src/etc/network/if-pre-up.d/03-bridge b/package/base-files/src/etc/network/if-pre-up.d/03-bridge
index 41ddb2b58..9bdbf8302 100755
--- a/package/base-files/src/etc/network/if-pre-up.d/03-bridge
+++ b/package/base-files/src/etc/network/if-pre-up.d/03-bridge
@@ -15,6 +15,7 @@ case "$IF_BRIDGE_PORTS" in
esac
brctl addbr $IFACE || exit 1
+[[ -n $IF_BRIDGE_FD ]] && brctl setfd $IFACE $IF_BRIDGE_FD
for IF in $INTERFACES; do
if ! grep -q $IF /proc/net/dev; then
diff --git a/package/base-files/src/etc/network/if-pre-up.d/04-wireless b/package/base-files/src/etc/network/if-pre-up.d/04-wireless
index 78442d8ae..ebcec5a12 100755
--- a/package/base-files/src/etc/network/if-pre-up.d/04-wireless
+++ b/package/base-files/src/etc/network/if-pre-up.d/04-wireless
@@ -8,6 +8,8 @@ set -e
[ "$IF_WIRELESS_HWMODE" ] || IF_WIRELESS_HWMODE=g
[ "$IF_WIRELESS_EXTENSION" ] || IF_WIRELESS_EXTENSION=0
+rfkill unblock wlan 2>/dev/null
+
wpa=0
wpa1=0
wpa2=0
diff --git a/package/bash/Makefile b/package/bash/Makefile
index c0b55681e..008d661a7 100644
--- a/package/bash/Makefile
+++ b/package/bash/Makefile
@@ -17,6 +17,8 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,BASH,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
CONFIGURE_ENV+= bash_cv_getenv_redef=no
+CONFIGURE_ARGS+= --disable-rpath \
+ --cache-file=/dev/null
XAKE_FLAGS+= LIBS_FOR_BUILD=''
post-install:
diff --git a/package/bind/Makefile b/package/bind/Makefile
index fdde3bf10..278982c4b 100644
--- a/package/bind/Makefile
+++ b/package/bind/Makefile
@@ -24,8 +24,8 @@ PKGSD_BIND_DNSSEC:= dnssec utilities
PKGSD_BIND_HOST:= host utility
PKGSD_BIND_DIG:= dig utility
-PKG_FLAVOURS:= WITH_IPV6
-PKGFD_WITH_IPV6:= enable IPv6 support
+PKG_FLAVOURS_BIND_SERVER:= WITH_IPV6
+PKGFD_WITH_IPV6:= enable IPv6 support
include ${TOPDIR}/mk/package.mk
diff --git a/package/bind/patches/patch-ltmain_sh b/package/bind/patches/patch-ltmain_sh
new file mode 100644
index 000000000..30b126894
--- /dev/null
+++ b/package/bind/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- bind-9.7.0.orig/ltmain.sh 2009-01-19 02:38:41.000000000 +0100
++++ bind-9.7.0/ltmain.sh 2011-01-14 18:53:09.000000000 +0100
+@@ -1706,7 +1706,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/binutils/patches/patch-ld_Makefile_in b/package/binutils/patches/patch-ld_Makefile_in
new file mode 100644
index 000000000..ff1eeb88f
--- /dev/null
+++ b/package/binutils/patches/patch-ld_Makefile_in
@@ -0,0 +1,20 @@
+--- binutils-2.21.orig/ld/Makefile.in 2010-11-05 11:34:22.000000000 +0100
++++ binutils-2.21/ld/Makefile.in 2011-01-10 21:57:49.000000000 +0100
+@@ -422,7 +422,7 @@ TEXI2DVI = texi2dvi -I $(srcdir) -I $(BF
+ -I $(top_srcdir)/../libiberty
+
+ AM_CPPFLAGS = -I. -I$(srcdir) -I../bfd -I$(BFDDIR) -I$(INCDIR) \
+- @INCINTL@ $(HDEFINES) $(CFLAGS) $(PLUGIN_CFLAGS) \
++ @INCINTL@ $(HDEFINES) $(PLUGIN_CFLAGS) \
+ -DLOCALEDIR="\"$(datadir)/locale\""
+
+ BFDLIB = ../bfd/libbfd.la
+@@ -850,7 +850,7 @@ ld_new_LDADD = $(EMULATION_OFILES) $(EMU
+ #
+ @ENABLE_PLUGINS_TRUE@noinst_LTLIBRARIES = libldtestplug.la
+ @ENABLE_PLUGINS_TRUE@libldtestplug_la_SOURCES = testplug.c
+-@ENABLE_PLUGINS_TRUE@libldtestplug_la_CFLAGS = -g -O2
++@ENABLE_PLUGINS_TRUE@libldtestplug_la_CFLAGS =
+ @ENABLE_PLUGINS_TRUE@libldtestplug_la_LDFLAGS = -no-undefined -rpath /nowhere
+ MAINTAINERCLEANFILES = configdoc.texi ld.1 ld.info
+
diff --git a/package/binutils/patches/patch-ltmain_sh b/package/binutils/patches/patch-ltmain_sh
new file mode 100644
index 000000000..18a178908
--- /dev/null
+++ b/package/binutils/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- binutils-2.21.orig/ltmain.sh 2010-01-09 22:11:32.000000000 +0100
++++ binutils-2.21/ltmain.sh 2011-01-14 19:07:08.000000000 +0100
+@@ -4980,7 +4980,7 @@ func_mode_link ()
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/bitlbee/Makefile b/package/bitlbee/Makefile
index 9c18f0c13..41b56a5ca 100644
--- a/package/bitlbee/Makefile
+++ b/package/bitlbee/Makefile
@@ -19,7 +19,6 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,BITLBEE,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
CONFIG_STYLE:= minimal
-
TCFLAGS+= -fPIC
CONFIGURE_ARGS:= --target=${REAL_GNU_TARGET_NAME} \
--prefix=/usr/ \
@@ -33,13 +32,12 @@ CONFIGURE_ARGS:= --target=${REAL_GNU_TARGET_NAME} \
--strip=0 \
--ipv6=1 \
--ssl=openssl
-
INSTALL_TARGET= install-etc install-bin
post-configure:
@echo 'CFLAGS+="-I${STAGING_TARGET_DIR}/usr/include/iconv"' >> \
${WRKBUILD}/Makefile.settings
- @echo 'LFLAGS+="-L${STAGING_TARGET_DIR}/usr/lib"' >> \
+ @echo 'LFLAGS+=${TARGET_LDFLAGS}' >> \
${WRKBUILD}/Makefile.settings
post-install:
diff --git a/package/bluez/patches/patch-Makefile_in b/package/bluez/patches/patch-Makefile_in
index 4334402d7..2c4cf7336 100644
--- a/package/bluez/patches/patch-Makefile_in
+++ b/package/bluez/patches/patch-Makefile_in
@@ -1,6 +1,6 @@
---- bluez-4.59.orig/Makefile.in Thu Dec 24 17:42:48 2009
-+++ bluez-4.59/Makefile.in Tue Dec 29 01:31:12 2009
-@@ -48,7 +48,6 @@ noinst_PROGRAMS = $(am__EXEEXT_7) $(am__EXEEXT_8) $(am
+--- bluez-4.59.orig/Makefile.in 2009-12-24 17:42:48.000000000 +0100
++++ bluez-4.59/Makefile.in 2011-01-14 19:24:13.000000000 +0100
+@@ -48,7 +48,6 @@ noinst_PROGRAMS = $(am__EXEEXT_7) $(am__
$(am__EXEEXT_10) $(am__EXEEXT_11)
@SBC_TRUE@am__append_1 = sbc/libsbc.la
@SBC_TRUE@am__append_2 = sbc/sbcinfo sbc/sbcdec sbc/sbcenc
@@ -8,7 +8,7 @@
@NETLINK_TRUE@am__append_4 = plugins/netlink.la
@ECHOPLUGIN_TRUE@am__append_5 = echo
@ECHOPLUGIN_TRUE@am__append_6 = plugins/echo.c
-@@ -318,7 +317,6 @@ sbc_libsbc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(
+@@ -318,7 +317,6 @@ sbc_libsbc_la_LINK = $(LIBTOOL) $(AM_V_l
@DUND_TRUE@am__EXEEXT_6 = compat/dund$(EXEEXT)
@SBC_TRUE@am__EXEEXT_7 = sbc/sbcinfo$(EXEEXT) sbc/sbcdec$(EXEEXT) \
@SBC_TRUE@ sbc/sbcenc$(EXEEXT)
@@ -16,7 +16,7 @@
@TOOLS_TRUE@am__EXEEXT_9 = tools/avinfo$(EXEEXT) tools/ppporc$(EXEEXT) \
@TOOLS_TRUE@ tools/hcieventmask$(EXEEXT) \
@TOOLS_TRUE@ tools/hcisecfilter$(EXEEXT)
-@@ -918,8 +916,6 @@ lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
+@@ -918,8 +916,6 @@ lib_libbluetooth_la_DEPENDENCIES = $(loc
@SBC_TRUE@sbc_sbcdec_LDADD = sbc/libsbc.la
@SBC_TRUE@sbc_sbcenc_SOURCES = sbc/sbcenc.c sbc/formats.h
@SBC_TRUE@sbc_sbcenc_LDADD = sbc/libsbc.la
diff --git a/package/bluez/patches/patch-ltmain_sh b/package/bluez/patches/patch-ltmain_sh
new file mode 100644
index 000000000..e323f1b54
--- /dev/null
+++ b/package/bluez/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- bluez-4.59.orig/ltmain.sh 2009-12-24 17:42:43.000000000 +0100
++++ bluez-4.59/ltmain.sh 2011-01-14 19:25:00.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/bogofilter/Makefile b/package/bogofilter/Makefile
index 4f83f73f4..0c8cca392 100644
--- a/package/bogofilter/Makefile
+++ b/package/bogofilter/Makefile
@@ -5,7 +5,7 @@ include ${TOPDIR}/rules.mk
PKG_NAME:= bogofilter
PKG_VERSION:= 1.2.2
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= 39d27c13eae8a5064d68e20d585e60de
PKG_DESCR:= mail filter
PKG_SECTION:= mail
@@ -14,8 +14,6 @@ PKG_BUILDDEP:= libiconv libdb
PKG_URL:= http://bogofilter.sourceforge.net/
PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=bogofilter/}
-PKG_HOST_DEPENDS:= !darwin
-
include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,BOGOFILTER,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
@@ -25,9 +23,13 @@ CONFIGURE_ENV+= LIBS="-liconv" \
CONFIGURE_ARGS+= --without-libsqlite3-prefix \
--without-libqdbm-prefix \
--with-included-gsl \
+ --disable-static \
--with-libdb-prefix=${STAGING_TARGET_DIR}/usr \
--disable-transactions
+pre-build:
+ touch $(WRKBUILD)/src/lexer_v3.l $(WRKBUILD)/src/Makefile.in $(WRKBUILD)/src/lexer_v3.c
+
post-install:
${INSTALL_DIR} ${IDIR_BOGOFILTER}/usr/bin
${INSTALL_BIN} ${WRKINST}/usr/bin/bogofilter \
diff --git a/package/busybox/Makefile b/package/busybox/Makefile
index 6145cb780..bcd582179 100644
--- a/package/busybox/Makefile
+++ b/package/busybox/Makefile
@@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:= busybox
PKG_VERSION:= 1.18.1
-PKG_RELEASE:= 2
+PKG_RELEASE:= 3
PKG_MD5SUM:= f15fe752d8b7012aa5e59f83b88ccb1c
PKG_DESCR:= Core utilities for embedded systems
PKG_SECTION:= base
@@ -23,10 +23,6 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,BUSYBOX,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,UDHCPD,udhcpd,${PKG_VERSION}-${PKG_RELEASE},busybox,${PKGSD_UDHCPD},${PKGSC_UDHCPD}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_UDHCPD}+= udhcpd-install
-
CONFIG_STYLE:= manual
BUILD_STYLE:= manual
INSTALL_STYLE:= manual
@@ -56,7 +52,7 @@ else
IPKG_ARCH="$(CPU_ARCH)" ARCH="$(ARCH)" HOSTCC="$(HOSTCC)" -C $(WRKBUILD) busybox
endif
-do-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+do-install:
ifeq ($(ADK_NATIVE),y)
$(MAKE) V=1 \
IPKG_ARCH="$(CPU_ARCH)" ARCH="$(ARCH)" HOSTCC="$(HOSTCC)" -C $(WRKBUILD) install $(MAKE_TRACE)
diff --git a/package/busybox/config/miscutils/Config.in b/package/busybox/config/miscutils/Config.in
index e28539204..bb7fb2aa7 100644
--- a/package/busybox/config/miscutils/Config.in
+++ b/package/busybox/config/miscutils/Config.in
@@ -547,6 +547,17 @@ config BUSYBOX_READAHEAD
As readahead(2) blocks until each file has been read, it is best to
run this applet as a background job.
+config BUSYBOX_RFKILL
+ bool "rfkill"
+ default y # doesn't build on Ubuntu 9.04
+ help
+ Enable/disable wireless devices.
+
+ rfkill list : list all wireless devices
+ rfkill list bluetooth : list all bluetooth devices
+ rfkill list 1 : list device corresponding to the given index
+ rfkill block|unblock wlan : block/unblock all wlan(wifi) devices
+
config BUSYBOX_RUNLEVEL
bool "runlevel"
default n
diff --git a/package/busybox/patches/007-missing-headers.patch b/package/busybox/patches/007-missing-headers.patch
new file mode 100644
index 000000000..cba28970f
--- /dev/null
+++ b/package/busybox/patches/007-missing-headers.patch
@@ -0,0 +1,10 @@
+--- busybox-1.18.1/include/platform.h~ Mon Dec 20 00:41:03 2010
++++ busybox-1.18.1/include/platform.h Thu Jan 6 20:03:58 2011
+@@ -155,6 +155,7 @@
+ # include <sex.h>
+ #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
+ || defined(__APPLE__)
++# include <sys/param.h> /* contains needed types for the following */
+ # include <sys/resource.h> /* rlimit */
+ # include <machine/endian.h>
+ # define bswap_64 __bswap64
diff --git a/package/bzr/Makefile b/package/bzr/Makefile
index ba8aba484..845ce4827 100644
--- a/package/bzr/Makefile
+++ b/package/bzr/Makefile
@@ -1,12 +1,12 @@
-# This file is part of the OpenADK project. OpenADK is copyrighted
+# This file is part of the OpenADK project. OpenADK is copyrighted
# material, please see the LICENCE file in the top-level directory.
include $(TOPDIR)/rules.mk
PKG_NAME:= bzr
-PKG_VERSION:= 2.3b3
+PKG_VERSION:= 2.3b4
PKG_RELEASE:= 1
-PKG_MD5SUM:= 94f9181b9a4ab84b94cfbc06bd5dfd91
+PKG_MD5SUM:= 62ba2dbd8b13745bc89e24dd4191cdc5
PKG_DESCR:= bazaar
PKG_SECTION:= scm
PKG_DEPENDS:= python2
@@ -25,11 +25,13 @@ INSTALL_STYLE:= manual
include $(TOPDIR)/mk/python.mk
do-build:
- cd $(WRKBUILD); env PYTHONPATH=$(PYTHON_LIBDIR) $(PYTHON) ./setup.py install --prefix="$(WRKINST)/usr"
+ cd $(WRKBUILD); env PYTHONPATH=$(PYTHON_LIBDIR) $(PYTHON) ./setup.py install --prefix=$(WRKINST)/usr build_ext --allow-python-fallback
do-install:
+ $(INSTALL_DIR) $(IDIR_BZR)/usr/lib/python$(PYTHON_VERSION)/site-packages
+ $(CP) $(WRKINST)/usr/lib/python$(PYTHON_VERSION)/site-packages/* \
+ $(IDIR_BZR)/usr/lib/python$(PYTHON_VERSION)/site-packages
$(INSTALL_DIR) $(IDIR_BZR)/usr/bin
- $(INSTALL_BIN) $(WRKINST)/usr/bin/bzr \
- $(IDIR_BZR)/usr/bin
+ $(INSTALL_BIN) $(WRKINST)/usr/bin/bzr $(IDIR_BZR)/usr/bin
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/ca-certificates/Makefile b/package/ca-certificates/Makefile
index 56ee67f15..60716f194 100644
--- a/package/ca-certificates/Makefile
+++ b/package/ca-certificates/Makefile
@@ -15,7 +15,7 @@ PKG_SITES:= http://ftp.debian.org/debian/pool/main/c/ca-certificates/
DISTFILES:= ${PKG_NAME}_${PKG_VERSION}.tar.gz
-PKG_FLAVOURS:= SMALL
+PKG_FLAVOURS_CA_CERTS:= SMALL
PKGFD_SMALL:= Minimal set of CA certificates
include $(TOPDIR)/mk/package.mk
diff --git a/package/cairo/patches/patch-build_ltmain_sh b/package/cairo/patches/patch-build_ltmain_sh
new file mode 100644
index 000000000..d79eba50b
--- /dev/null
+++ b/package/cairo/patches/patch-build_ltmain_sh
@@ -0,0 +1,11 @@
+--- cairo-1.8.10.orig/build/ltmain.sh 2010-02-20 00:39:43.000000000 +0100
++++ cairo-1.8.10/build/ltmain.sh 2011-01-14 20:17:40.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/cairo/patches/patch-src_cairo-features_h b/package/cairo/patches/patch-src_cairo-features_h
new file mode 100644
index 000000000..6466deec7
--- /dev/null
+++ b/package/cairo/patches/patch-src_cairo-features_h
@@ -0,0 +1,15 @@
+--- cairo-1.8.10.orig/src/cairo-features.h 2010-02-19 22:34:38.000000000 +0100
++++ cairo-1.8.10/src/cairo-features.h 2011-01-14 20:12:28.000000000 +0100
+@@ -10,11 +10,11 @@
+ #define CAIRO_HAS_SVG_SURFACE 1
+ #define CAIRO_HAS_USER_FONT 1
+ #define CAIRO_HAS_XLIB_SURFACE 1
+-#define CAIRO_HAS_XLIB_XRENDER_SURFACE 1
+
+ /*#undef CAIRO_HAS_QUARTZ_FONT */
+ /*#undef CAIRO_HAS_QUARTZ_SURFACE */
+ /*#undef CAIRO_HAS_WIN32_FONT */
+ /*#undef CAIRO_HAS_WIN32_SURFACE */
++/*#undef CAIRO_HAS_XLIB_XRENDER_SURFACE */
+
+ #endif
diff --git a/package/ccid/patches/patch-ltmain_sh b/package/ccid/patches/patch-ltmain_sh
new file mode 100644
index 000000000..572c24069
--- /dev/null
+++ b/package/ccid/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- ccid-1.4.1.orig/ltmain.sh 2010-08-04 15:28:29.000000000 +0200
++++ ccid-1.4.1/ltmain.sh 2011-01-14 20:22:38.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/cgilib/patches/patch-ltmain_sh b/package/cgilib/patches/patch-ltmain_sh
index 6eceb3560..f2e06e38b 100644
--- a/package/cgilib/patches/patch-ltmain_sh
+++ b/package/cgilib/patches/patch-ltmain_sh
@@ -1,6 +1,6 @@
$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
--- cgilib-0.7.orig/ltmain.sh 2008-04-29 23:33:55.000000000 +0200
-+++ cgilib-0.7/ltmain.sh 2009-05-09 03:58:09.000000000 +0200
++++ cgilib-0.7/ltmain.sh 2011-01-14 20:26:24.000000000 +0100
@@ -43,8 +43,8 @@ EXIT_FAILURE=1
PROGRAM=ltmain.sh
@@ -65,6 +65,15 @@ $Id: update-patches 24 2008-08-31 14:56:13Z wbx $
continue
;;
+@@ -1676,7 +1706,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
@@ -2135,10 +2165,7 @@ EOF
case $pass in
dlopen) libs="$dlfiles" ;;
diff --git a/package/collectd/Makefile b/package/collectd/Makefile
index 52e6e6ab5..277e061cf 100644
--- a/package/collectd/Makefile
+++ b/package/collectd/Makefile
@@ -13,26 +13,26 @@ PKG_DEPENDS:= libpthread
PKG_URL:= http://collectd.org/
PKG_SITES:= http://collectd.org/files/
-PKG_FLAVOURS:= CPU LOAD MEMORY PING
-PKGFD_CPU:= collect CPU statistics
-PKGFD_LOAD:= collect system load statistics
-PKGFD_MEMORY:= collect memory usage statistics
-PKGFD_PING:= enable ping statistic plugin
+PKG_FLAVOURS_COLLECD:= WITH_CPU WITH_LOAD WITH_MEMORY WITH_PING
+PKGFD_WITH_CPU:= collect CPU statistics
+PKGFD_WITH_LOAD:= collect system load statistics
+PKGFD_WITH_MEMORY:= collect memory usage statistics
+PKGFD_WITH_PING:= enable ping statistic plugin
include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,COLLECTD,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
-ifneq (${ADK_PACKAGE_COLLECTD_CPU},y)
+ifneq (${ADK_PACKAGE_COLLECTD_WITH_CPU},y)
DISABLE_CPU:=--disable-cpu
endif
-ifneq (${ADK_PACKAGE_COLLECTD_LOAD},y)
+ifneq (${ADK_PACKAGE_COLLECTD_WITH_LOAD},y)
DISABLE_LOAD:=--disable-load
endif
-ifneq (${ADK_PACKAGE_COLLECTD_MEMORY},y)
+ifneq (${ADK_PACKAGE_COLLECTD_WITH_MEMORY},y)
DISABLE_MEMORY:=--disable-memory
endif
-ifneq (${ADK_PACKAGE_COLLECTD_PING},y)
+ifneq (${ADK_PACKAGE_COLLECTD_WITH_PING},y)
DISABLE_PING:=--disable-ping
endif
diff --git a/package/collectd/patches/patch-ltmain_sh b/package/collectd/patches/patch-ltmain_sh
new file mode 100644
index 000000000..d53645853
--- /dev/null
+++ b/package/collectd/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- collectd-4.10.0.orig/ltmain.sh 2010-05-01 11:15:57.000000000 +0200
++++ collectd-4.10.0/ltmain.sh 2011-01-14 20:29:06.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/coreutils/Makefile b/package/coreutils/Makefile
index 39ab9fddf..8d35c3c8e 100644
--- a/package/coreutils/Makefile
+++ b/package/coreutils/Makefile
@@ -21,6 +21,8 @@ include $(TOPDIR)/mk/package.mk
#$(eval $(call PKG_template,COREUTILS,$(PKG_NAME),$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,TSORT,tsort,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_TSORT},${PKGSC_TSORT}))
+CONFIGURE_ARGS+= --disable-rpath
+
post-install:
$(INSTALL_DIR) $(IDIR_TSORT)/usr/bin
$(INSTALL_BIN) $(WRKINST)/usr/bin/tsort \
diff --git a/package/cryptsetup/Makefile b/package/cryptsetup/Makefile
index fbccefdfe..8ab2f397d 100644
--- a/package/cryptsetup/Makefile
+++ b/package/cryptsetup/Makefile
@@ -24,7 +24,8 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,CRYPTSETUP,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
-CONFIGURE_ARGS+= --disable-selinux
+CONFIGURE_ARGS+= --disable-selinux \
+ --disable-static
post-install:
${INSTALL_DIR} ${IDIR_CRYPTSETUP}/usr/sbin ${IDIR_CRYPTSETUP}/usr/lib
diff --git a/package/cryptsetup/patches/patch-ltmain_sh b/package/cryptsetup/patches/patch-ltmain_sh
new file mode 100644
index 000000000..4aa161aec
--- /dev/null
+++ b/package/cryptsetup/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- cryptsetup-1.1.3.orig/ltmain.sh 2010-01-17 11:29:15.000000000 +0100
++++ cryptsetup-1.1.3/ltmain.sh 2011-01-14 20:48:34.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/cups/Makefile b/package/cups/Makefile
index 8f764ba1b..aa3bea6fd 100644
--- a/package/cups/Makefile
+++ b/package/cups/Makefile
@@ -21,7 +21,7 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,CUPS,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
CONFIGURE_ENV+= ac_cv_func_sigset=no \
- OPTIM='-fPIC'
+ OPTIM='-fPIC $(TARGET_CFLAGS)'
CONFIGURE_ARGS+= --with-cups-user=cups \
--with-cups-group=cups \
@@ -42,7 +42,7 @@ CONFIGURE_ARGS+= --with-cups-user=cups \
--disable-ssl
FAKE_FLAGS+= DSTROOT="${WRKINST}" STRIP="/bin/true"
-XAKE_FLAGS+= OPTIM='-fPIC'
+XAKE_FLAGS+= OPTIM='-fPIC $(TARGET_CFLAGS)'
post-install:
${INSTALL_DIR} ${IDIR_CUPS}/usr/bin
diff --git a/package/curl/Makefile b/package/curl/Makefile
index ab6e45416..4e1dd6bf5 100644
--- a/package/curl/Makefile
+++ b/package/curl/Makefile
@@ -21,7 +21,7 @@ PKGSS_LIBCURL:= libopenssl zlib
PKGSD_LIBCURL_DEV:= development files for libcurl
PKGSC_LIBCURL_DEV:= devel
-PKG_FLAVOURS:= WITH_IPV6
+PKG_FLAVOURS_CURL:= WITH_IPV6
PKGFD_WITH_IPV6:= enable IPv6 support
include ${TOPDIR}/mk/package.mk
@@ -30,11 +30,6 @@ $(eval $(call PKG_template,CURL,curl,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS
$(eval $(call PKG_template,LIBCURL,libcurl,${PKG_VERSION}-${PKG_RELEASE},${PKGSS_LIBCURL},${PKGSD_LIBCURL},${PKGSC_LIBCURL}))
$(eval $(call PKG_template,LIBCURL_DEV,libcurl-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBCURL_DEV},${PKGSC_LIBCURL_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_CURL}+= curl-install
-SUB_INSTALLS-${ADK_PACKAGE_LIBCURL_DEV}+= libcurl-dev-install
-
CONFIGURE_ENV+= curl_typeof_curl_socklen_t=socklen_t
CONFIGURE_ARGS+= --disable-thread \
--enable-cookies \
@@ -63,14 +58,14 @@ else
CONFIGURE_ARGS+= --disable-ipv6
endif
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
- ${INSTALL_DIR} ${IDIR_LIBCURL}/usr/lib
- ${CP} ${WRKINST}/usr/lib/libcurl.so* ${IDIR_LIBCURL}/usr/lib/
-
curl-install:
${INSTALL_DIR} ${IDIR_CURL}/usr/bin
${INSTALL_BIN} ${WRKINST}/usr/bin/curl ${IDIR_CURL}/usr/bin/
+libcurl-install:
+ ${INSTALL_DIR} ${IDIR_LIBCURL}/usr/lib
+ ${CP} ${WRKINST}/usr/lib/libcurl.so* ${IDIR_LIBCURL}/usr/lib/
+
libcurl-dev-install:
${INSTALL_DIR} ${IDIR_LIBCURL_DEV}/usr/include/curl
${CP} ${WRKINST}/usr/include/curl/*.h \
diff --git a/package/curl/patches/patch-configure b/package/curl/patches/patch-configure
index 21c0b095d..27e43ebf0 100644
--- a/package/curl/patches/patch-configure
+++ b/package/curl/patches/patch-configure
@@ -1,6 +1,6 @@
---- curl-7.19.7.orig/configure 2009-11-04 13:26:02.000000000 +0100
-+++ curl-7.19.7/configure 2009-12-03 21:07:01.000000000 +0100
-@@ -19233,15 +19233,6 @@ fi
+--- curl-7.21.0.orig/configure 2010-06-05 00:32:04.000000000 +0200
++++ curl-7.21.0/configure 2011-01-14 12:05:38.000000000 +0100
+@@ -19714,15 +19714,6 @@ fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
diff --git a/package/curl/patches/patch-ltmain_sh b/package/curl/patches/patch-ltmain_sh
new file mode 100644
index 000000000..b1eef4628
--- /dev/null
+++ b/package/curl/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- curl-7.21.0.orig/ltmain.sh 2010-05-27 21:20:16.000000000 +0200
++++ curl-7.21.0/ltmain.sh 2011-01-14 12:07:25.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/dansguardian/Makefile b/package/dansguardian/Makefile
index 5cc1d08e5..b24b416b7 100644
--- a/package/dansguardian/Makefile
+++ b/package/dansguardian/Makefile
@@ -13,18 +13,25 @@ PKG_DEPENDS:= libpcre zlib
PKG_BUILDDEP:= pcre zlib
PKG_URL:= http://dansguardian.org/
PKG_SITES:= http://dansguardian.org/downloads/2/Stable/
+PKG_NEED_CXX:= 1
PKG_CXX:= DANSGUARDIAN
include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,DANSGUARDIAN,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+LIBRARIES:=-nodefaultlibs -luClibc++ -lgcc -lm
+ifeq ($(ADK_TOOLCHAIN_GCC_USE_SSP),y)
+LIBRARIES+=-lssp
+endif
+
ifeq ($(ADK_COMPILE_DANSGUARDIAN_WITH_UCLIBCXX),y)
CONFIGURE_ENV+= CXXFLAGS="-fno-threadsafe-statics -fno-builtin -nostdinc++ \
-I${STAGING_TARGET_DIR}/usr/include/uClibc++" \
- LIBS="-nodefaultlibs -luClibc++ -lgcc -lm"
+ LIBS="$(LIBRARIES)"
endif
+
CONFIGURE_ARGS+= --enable-orig-ip \
--with-proxyuser=proxy \
--with-proxygroup=proxy
diff --git a/package/dbus/patches/patch-configure b/package/dbus/patches/patch-configure
index f33a192a9..18acacbc8 100644
--- a/package/dbus/patches/patch-configure
+++ b/package/dbus/patches/patch-configure
@@ -1,6 +1,6 @@
---- dbus-1.2.16.orig/configure 2009-07-14 21:43:08.000000000 +0200
-+++ dbus-1.2.16/configure 2010-01-15 19:03:24.000000000 +0100
-@@ -25213,19 +25213,6 @@ if test "x$GCC" = "xyes"; then
+--- dbus-1.2.24.orig/configure 2010-03-23 20:11:22.000000000 +0100
++++ dbus-1.2.24/configure 2011-01-14 19:21:37.000000000 +0100
+@@ -25294,19 +25294,6 @@ if test "x$GCC" = "xyes"; then
;;
esac
diff --git a/package/dbus/patches/patch-ltmain_sh b/package/dbus/patches/patch-ltmain_sh
new file mode 100644
index 000000000..c594b88f2
--- /dev/null
+++ b/package/dbus/patches/patch-ltmain_sh
@@ -0,0 +1,39 @@
+--- dbus-1.2.24.orig/ltmain.sh 2010-03-12 23:22:29.000000000 +0100
++++ dbus-1.2.24/ltmain.sh 2011-01-14 19:22:39.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
+@@ -5516,27 +5516,6 @@ func_mode_link ()
+ esac
+ fi
+
+- # Hardcode the library path.
+- # Skip directories that are in the system default run-time
+- # search path.
+- case " $sys_lib_dlsearch_path " in
+- *" $absdir "*) ;;
+- *)
+- case "$compile_rpath " in
+- *" $absdir "*) ;;
+- *) compile_rpath="$compile_rpath $absdir"
+- esac
+- ;;
+- esac
+- case " $sys_lib_dlsearch_path " in
+- *" $libdir "*) ;;
+- *)
+- case "$finalize_rpath " in
+- *" $libdir "*) ;;
+- *) finalize_rpath="$finalize_rpath $libdir"
+- esac
+- ;;
+- esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
diff --git a/package/digitemp/patches/patch-Makefile b/package/digitemp/patches/patch-Makefile
index 4f19aaae2..95b89e7b3 100644
--- a/package/digitemp/patches/patch-Makefile
+++ b/package/digitemp/patches/patch-Makefile
@@ -1,7 +1,7 @@
do not use static linking on Cygwin
--- digitemp-3.6.0.orig/Makefile 2008-08-28 23:37:00.000000000 +0200
-+++ digitemp-3.6.0/Makefile 2010-01-06 19:12:56.868375000 +0100
-@@ -11,8 +11,8 @@
++++ digitemp-3.6.0/Makefile 2011-01-14 21:37:33.000000000 +0100
+@@ -11,8 +11,9 @@
VERSION = 3.6.0
@@ -9,10 +9,20 @@ do not use static linking on Cygwin
-CFLAGS = -I./src -I./userial -O2 -Wall # -g
+CC ?= gcc
+CFLAGS ?= -I./src -I./userial
++LDFLAGS ?=
OBJS = src/digitemp.o src/device_name.o src/ds2438.o
HDRS = src/digitemp.h src/device_name.h
-@@ -57,7 +57,6 @@ endif
+@@ -45,7 +46,7 @@ DS2490OBJS = userial/ds2490/ownet.o user
+ # If you add a new OSTYPE here please email it to me so that I can add
+ # it to the distribution in the next release
+ # -----------------------------------------------------------------------
+-SYSTYPE := $(shell uname -s)
++SYSTYPE := Linux
+
+ ifeq ($(SYSTYPE), Linux)
+ CFLAGS += -DLINUX
+@@ -57,7 +58,6 @@ endif
ifneq (, $(findstring CYGWIN,$(SYSTYPE)))
CFLAGS += -DCYGWIN
@@ -20,3 +30,20 @@ do not use static linking on Cygwin
endif
ifeq ($(SYSTYPE), SunOS)
+@@ -116,13 +116,13 @@ all: help
+
+ # Build the Linux executable
+ ds9097: $(OBJS) $(HDRS) $(ONEWIREOBJS) $(ONEWIREHDRS) $(DS9097OBJS)
+- $(CC) $(OBJS) $(ONEWIREOBJS) $(DS9097OBJS) -o digitemp_DS9097 $(LIBS)
++ $(CC) $(LDFLAGS) $(OBJS) $(ONEWIREOBJS) $(DS9097OBJS) -o digitemp_DS9097 $(LIBS)
+
+ ds9097u: $(OBJS) $(HDRS) $(ONEWIREOBJS) $(ONEWIREHDRS) $(DS9097UOBJS)
+- $(CC) $(OBJS) $(ONEWIREOBJS) $(DS9097UOBJS) -o digitemp_DS9097U $(LIBS)
++ $(CC) $(LDFLAGS) $(OBJS) $(ONEWIREOBJS) $(DS9097UOBJS) -o digitemp_DS9097U $(LIBS)
+
+ ds2490: $(OBJS) $(HDRS) $(ONEWIREOBJS) $(ONEWIREHDRS) $(DS2490OBJS)
+- $(CC) $(OBJS) $(ONEWIREOBJS) $(DS2490OBJS) -o digitemp_DS2490 $(LIBS)
++ $(CC) $(LDFLAGS) $(OBJS) $(ONEWIREOBJS) $(DS2490OBJS) -o digitemp_DS2490 $(LIBS)
+
+
+ # Clean up the object files and the sub-directory for distributions
diff --git a/package/dillo/Makefile b/package/dillo/Makefile
index 142bbb1b8..1c2bcf500 100644
--- a/package/dillo/Makefile
+++ b/package/dillo/Makefile
@@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:= dillo
PKG_VERSION:= 2.2
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= f8bcd62093f178bed81e46cc54e73f42
PKG_DESCR:= small graphical web browser
PKG_SECTION:= x11/apps
diff --git a/package/dillo/patches/patch-Makefile_in b/package/dillo/patches/patch-Makefile_in
new file mode 100644
index 000000000..6b18010d3
--- /dev/null
+++ b/package/dillo/patches/patch-Makefile_in
@@ -0,0 +1,11 @@
+--- dillo-2.2.orig/Makefile.in 2010-02-11 11:20:01.000000000 +0100
++++ dillo-2.2/Makefile.in 2011-01-07 21:37:49.000000000 +0100
+@@ -242,7 +242,7 @@ target_vendor = @target_vendor@
+ top_build_prefix = @top_build_prefix@
+ top_builddir = @top_builddir@
+ top_srcdir = @top_srcdir@
+-SUBDIRS = lout dw dlib dpip src doc dpid dpi test
++SUBDIRS = lout dw dlib dpip src doc dpid dpi
+ EXTRA_DIST = Doxyfile dillorc install-dpi-local
+ sysconf_DATA = dillorc
+ all: config.h
diff --git a/package/dillo/patches/patch-configure b/package/dillo/patches/patch-configure
new file mode 100644
index 000000000..233acb5a8
--- /dev/null
+++ b/package/dillo/patches/patch-configure
@@ -0,0 +1,14 @@
+--- dillo-2.2.orig/configure 2010-02-11 11:19:59.000000000 +0100
++++ dillo-2.2/configure 2011-01-07 21:35:04.000000000 +0100
+@@ -5830,11 +5830,6 @@ typedef unsigned char bool_t;
+ _______EOF
+
+
+-if test "`$CPP -v < /dev/null 2>&1 | grep '/usr/local/include' 2>&1`" = ""; then
+- CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+- LDFLAGS="$LDFLAGS -L/usr/local/lib"
+-fi
+-
+ for ac_func in gethostbyname
+ do :
+ ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname"
diff --git a/package/dillo/patches/patch-src_IO_Makefile_in b/package/dillo/patches/patch-src_IO_Makefile_in
new file mode 100644
index 000000000..242d86f5a
--- /dev/null
+++ b/package/dillo/patches/patch-src_IO_Makefile_in
@@ -0,0 +1,11 @@
+--- dillo-2.2.orig/src/IO/Makefile.in 2010-02-11 11:20:01.000000000 +0100
++++ dillo-2.2/src/IO/Makefile.in 2011-01-07 21:38:15.000000000 +0100
+@@ -188,7 +188,7 @@ top_build_prefix = @top_build_prefix@
+ top_builddir = @top_builddir@
+ top_srcdir = @top_srcdir@
+ AM_CPPFLAGS = -DDILLO_BINDIR='"$(bindir)/"'
+-AM_CFLAGS = @LIBFLTK_CFLAGS@
++AM_CFLAGS =
+ AM_CXXFLAGS = @LIBFLTK_CXXFLAGS@
+ noinst_LIBRARIES = libDiof.a
+ libDiof_a_SOURCES = \
diff --git a/package/dnsmasq/Makefile b/package/dnsmasq/Makefile
index 3586fe165..6bce7db1e 100644
--- a/package/dnsmasq/Makefile
+++ b/package/dnsmasq/Makefile
@@ -5,7 +5,7 @@ include ${TOPDIR}/rules.mk
PKG_NAME:= dnsmasq
PKG_VERSION:= 2.55
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= b093d7c6bc7f97ae6fd35d048529232a
PKG_DESCR:= A lightweight DNS and DHCP server
PKG_SECTION:= dns
@@ -17,13 +17,10 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,DNSMASQ,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
CONFIG_STYLE:= manual
-INSTALL_STYLE:= manual
-MAKE_FLAGS+= BINDIR=/usr/sbin MANDIR=/usr/man COPTS="${TCFLAGS}"
-
-do-install:
+post-install:
${INSTALL_DIR} ${IDIR_DNSMASQ}/usr/sbin ${IDIR_DNSMASQ}/etc
- ${INSTALL_BIN} ${WRKBUILD}/src/dnsmasq ${IDIR_DNSMASQ}/usr/sbin/
+ ${INSTALL_BIN} ${WRKINST}/usr/sbin/dnsmasq ${IDIR_DNSMASQ}/usr/sbin/
${INSTALL_DATA} ./files/dnsmasq.conf ${IDIR_DNSMASQ}/etc/dnsmasq.conf
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/dnsmasq/patches/patch-Makefile b/package/dnsmasq/patches/patch-Makefile
new file mode 100644
index 000000000..3bc68e266
--- /dev/null
+++ b/package/dnsmasq/patches/patch-Makefile
@@ -0,0 +1,20 @@
+--- dnsmasq-2.55.orig/Makefile 2010-06-06 21:22:30.000000000 +0200
++++ dnsmasq-2.55/Makefile 2011-01-07 21:43:23.000000000 +0100
+@@ -13,7 +13,7 @@
+ # You should have received a copy of the GNU General Public License
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+-PREFIX = /usr/local
++PREFIX = /usr
+ BINDIR = ${PREFIX}/sbin
+ MANDIR = ${PREFIX}/share/man
+ LOCALEDIR = ${PREFIX}/share/locale
+@@ -24,7 +24,7 @@ MSGMERGE = msgmerge
+ MSGFMT = msgfmt
+ XGETTEXT = xgettext
+
+-CFLAGS = -Wall -W -O2
++CFLAGS ?= -Wall
+
+ #################################################################
+
diff --git a/package/dnsmasq/patches/patch-src_config_h b/package/dnsmasq/patches/patch-src_config_h
index 5db49ea9a..c58050bd0 100644
--- a/package/dnsmasq/patches/patch-src_config_h
+++ b/package/dnsmasq/patches/patch-src_config_h
@@ -1,6 +1,6 @@
---- dnsmasq-2.47.orig/src/config.h 2009-02-05 13:14:24.000000000 +0100
-+++ dnsmasq-2.47/src/config.h 2009-03-19 18:40:37.000000000 +0100
-@@ -45,7 +45,7 @@
+--- dnsmasq-2.55.orig/src/config.h 2010-06-07 23:01:19.000000000 +0200
++++ dnsmasq-2.55/src/config.h 2011-01-07 21:40:34.000000000 +0100
+@@ -47,7 +47,7 @@
# elif defined(__sun__) || defined (__sun)
# define LEASEFILE "/var/cache/dnsmasq.leases"
# else
@@ -9,7 +9,7 @@
# endif
#endif
-@@ -282,8 +282,9 @@ typedef unsigned long in_addr_t;
+@@ -269,8 +269,9 @@ NOTES:
/* We assume that systems which don't have IPv6
headers don't have ntop and pton either */
diff --git a/package/dosfstools/Makefile b/package/dosfstools/Makefile
index 89a3cb861..8f6dee573 100644
--- a/package/dosfstools/Makefile
+++ b/package/dosfstools/Makefile
@@ -5,7 +5,7 @@ include ${TOPDIR}/rules.mk
PKG_NAME:= dosfstools
PKG_VERSION:= 3.0.9
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= bd273cf8aa6341c0b52cbac72050bcf4
PKG_DESCR:= Utilities to create and check MS-DOS FAT filesystems
PKG_SECTION:= fs
@@ -17,9 +17,7 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,DOSFSTOOLS,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
CONFIG_STYLE:= manual
-
-XAKE_FLAGS+= PREFIX="" \
- OPTFLAGS="${TARGET_CFLAGS} -D_FILE_OFFSET_BITS=64"
+XAKE_FLAGS+= PREFIX="" OPTFLAGS="-D_FILE_OFFSET_BITS=64"
post-install:
${INSTALL_DIR} ${IDIR_DOSFSTOOLS}/sbin
diff --git a/package/dosfstools/patches/patch-Makefile b/package/dosfstools/patches/patch-Makefile
new file mode 100644
index 000000000..c20b7f4dc
--- /dev/null
+++ b/package/dosfstools/patches/patch-Makefile
@@ -0,0 +1,11 @@
+--- dosfstools-3.0.9.orig/Makefile 2009-10-04 11:03:23.000000000 +0200
++++ dosfstools-3.0.9/Makefile 2011-01-07 21:50:15.000000000 +0100
+@@ -29,7 +29,7 @@ OPTFLAGS = -O2 -fomit-frame-pointer $(sh
+ #WARNFLAGS = -Wall -pedantic -std=c99
+ WARNFLAGS = -Wall
+ DEBUGFLAGS = -g
+-CFLAGS += $(OPTFLAGS) $(WARNFLAGS) $(DEBUGFLAGS)
++CFLAGS += $(WARNFLAGS)
+
+ VPATH = src
+
diff --git a/package/dovecot/Makefile b/package/dovecot/Makefile
index 0716059b0..395a2c70c 100644
--- a/package/dovecot/Makefile
+++ b/package/dovecot/Makefile
@@ -12,7 +12,7 @@ PKG_SECTION:= mail
PKG_URL:= http://www.dovecot.org/
PKG_SITES:= http://www.dovecot.org/releases/2.0/
-PKG_CHOICES:= WITH_OPENSSL WITH_GNUTLS
+PKG_CHOICES_DOVECOT:= WITH_OPENSSL WITH_GNUTLS
PKGCD_WITH_OPENSSL:= use OpenSSL for crypto
PKGCS_WITH_OPENSSL:= libopenssl
PKGCB_WITH_OPENSSL:= openssl
diff --git a/package/dovecot/patches/patch-ltmain_sh b/package/dovecot/patches/patch-ltmain_sh
new file mode 100644
index 000000000..8c7c6bc7d
--- /dev/null
+++ b/package/dovecot/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- dovecot-2.0.5.orig/ltmain.sh 2010-05-24 16:48:06.000000000 +0200
++++ dovecot-2.0.5/ltmain.sh 2011-01-14 22:05:48.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/drbd/patches/patch-drbd_drbd_buildtag_c b/package/drbd/patches/patch-drbd_drbd_buildtag_c
deleted file mode 100644
index 7a8358ea7..000000000
--- a/package/drbd/patches/patch-drbd_drbd_buildtag_c
+++ /dev/null
@@ -1,9 +0,0 @@
---- drbd-8.3.8.1.orig/drbd/drbd_buildtag.c 2010-07-09 10:19:05.000000000 +0200
-+++ drbd-8.3.8.1/drbd/drbd_buildtag.c 2010-11-26 18:59:58.000000000 +0100
-@@ -3,5 +3,5 @@
- const char *drbd_buildtag(void)
- {
- return "GIT-hash: 0d8589fcc32c874df57c930ca1691399b55ec893"
-- " build by lars@soda, 2010-07-09 10:19:24";
-+ " build by wbx@neon.lan, 2010-11-26 18:59:58";
- }
diff --git a/package/drbd/patches/patch-user_Makefile_in b/package/drbd/patches/patch-user_Makefile_in
new file mode 100644
index 000000000..2979decb1
--- /dev/null
+++ b/package/drbd/patches/patch-user_Makefile_in
@@ -0,0 +1,24 @@
+--- drbd-8.3.8.1.orig/user/Makefile.in 2010-05-10 16:09:13.000000000 +0200
++++ drbd-8.3.8.1/user/Makefile.in 2011-01-14 22:16:28.000000000 +0100
+@@ -74,7 +74,7 @@ drbd_strings.c: ../drbd/drbd_strings.c
+ cp $^ $@
+
+ drbdadm: $(drbdadm-obj)
+- $(CC) -o $@ $^
++ $(CC) $(LDFLAGS) -o $@ $^
+
+ drbdadm_scanner.c: drbdadm_scanner.fl drbdadm_parser.h
+ flex -s -odrbdadm_scanner.c drbdadm_scanner.fl
+@@ -83,10 +83,10 @@ drbdmeta_scanner.c: drbdmeta_scanner.fl
+ flex -s -odrbdmeta_scanner.c drbdmeta_scanner.fl
+
+ drbdsetup: $(drbdsetup-obj)
+- $(CC) -o $@ $^
++ $(CC) $(LDFLAGS) -o $@ $^
+
+ drbdmeta: $(drbdmeta-obj)
+- $(CC) -o $@ $^
++ $(CC) $(LDFLAGS) -o $@ $^
+
+ clean:
+ rm -f drbdadm_scanner.c drbdmeta_scanner.c
diff --git a/package/e2fsprogs/Makefile b/package/e2fsprogs/Makefile
index 1eb65d222..7b22a922d 100644
--- a/package/e2fsprogs/Makefile
+++ b/package/e2fsprogs/Makefile
@@ -5,7 +5,7 @@ include ${TOPDIR}/rules.mk
PKG_NAME:= e2fsprogs
PKG_VERSION:= 1.41.14
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= 05f70470aea2ef7efbb0845b2b116720
PKG_DESCR:= Ext2/3/4 filesystem utilities
PKG_SECTION:= fs
@@ -15,7 +15,7 @@ PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=e2fsprogs/}
PKG_CFLINE_E2FSPROGS:= default y if ADK_TARGET_ROOTFS_CF
-PKG_SUBPKGS:= E2FSPROGS LIBUUID LIBCOM_ERR LIBSS LIBBLKID
+PKG_SUBPKGS:= E2FSPROGS LIBUUID LIBCOM_ERR LIBSS LIBBLKID E2FSCK_STATIC
PKGSD_LIBUUID:= UUID library
PKGSC_LIBUUID:= libs
PKGSD_LIBCOM_ERR:= Common error library
@@ -24,6 +24,8 @@ PKGSD_LIBSS:= Subsystem command parsing library
PKGSC_LIBSS:= libs
PKGSD_LIBBLKID:= Libblkid
PKGSC_LIBBLKID:= libs
+PKGSD_E2FSCK_STATIC:= Static build of e2fsck
+PKGSC_E2FSCK_STATIC:= fs
include ${TOPDIR}/mk/package.mk
@@ -32,9 +34,11 @@ $(eval $(call PKG_template,LIBUUID,libuuid,${PKG_VERSION}-${PKG_RELEASE},,${PKGS
$(eval $(call PKG_template,LIBCOM_ERR,libcom-err,${PKG_VERSION}-${PKG_RELEASE},,${PKGSD_LIBCOM_ERR},${PKGSC_LIBCOM_ERR}))
$(eval $(call PKG_template,LIBSS,libss,${PKG_VERSION}-${PKG_RELEASE},,${PKGSD_LIBSS},${PKGSC_LIBSS}))
$(eval $(call PKG_template,LIBBLKID,libblkid,${PKG_VERSION}-${PKG_RELEASE},,${PKGSD_LIBBLKID},${PKGSC_LIBBLKID}))
+$(eval $(call PKG_template,E2FSCK_STATIC,e2fsck-static,${PKG_VERSION}-${PKG_RELEASE},,${PKGSD_E2FSCK_STATIC},${PKGSC_E2FSCK_STATIC}))
-CONFIGURE_ARGS+= --enable-elf-shlibs --disable-tls
+CONFIGURE_ARGS+= --enable-elf-shlibs --disable-rpath
INSTALL_TARGET+= install-libs
+TLDFLAGS+= -lpthread
pre-build:
${MAKE} -C ${WRKBUILD}/util \
@@ -44,7 +48,14 @@ pre-build:
CPPFLAGS="" \
subst
+post-build:
+ ${MAKE} -C ${WRKBUILD}/e2fsck e2fsck.static
+ ${INSTALL_DIR} ${WRKINST}/usr/sbin
+ ${INSTALL_BIN} ${WRKBUILD}/e2fsck/e2fsck.static ${WRKINST}/usr/sbin/
+
post-install:
+ ${INSTALL_DIR} ${IDIR_E2FSPROGS}/etc
+ ${INSTALL_DATA} ${WRKINST}/etc/mke2fs.conf ${IDIR_E2FSPROGS}/etc/
${INSTALL_DIR} ${IDIR_E2FSPROGS}/usr/lib ${IDIR_E2FSPROGS}/usr/sbin
${INSTALL_BIN} ${WRKINST}/usr/sbin/e2fsck ${IDIR_E2FSPROGS}/usr/sbin/
cd $(IDIR_E2FSPROGS)/usr/sbin && ln -sf e2fsck fsck.ext2
@@ -73,5 +84,8 @@ post-install:
${CP} ${WRKBUILD}/lib/uuid/uuid.h \
${STAGING_TARGET_DIR}/usr/include/uuid
${CP} ${WRKINST}/usr/bin/compile_et ${STAGING_HOST_DIR}/bin
+ ${INSTALL_DIR} ${IDIR_E2FSCK_STATIC}/usr/sbin
+ ${INSTALL_BIN} ${WRKINST}/usr/sbin/e2fsck.static \
+ ${IDIR_E2FSCK_STATIC}/usr/sbin/e2fsck
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/e2fsprogs/patches/patch-debugfs_dump_c.orig b/package/e2fsprogs/patches/patch-debugfs_dump_c.orig
deleted file mode 100644
index 7e9b233fa..000000000
--- a/package/e2fsprogs/patches/patch-debugfs_dump_c.orig
+++ /dev/null
@@ -1,10 +0,0 @@
---- e2fsprogs-1.41.14.orig/debugfs/dump.c 2009-08-13 03:39:57.000000000 +0200
-+++ e2fsprogs-1.41.14/debugfs/dump.c 2010-12-25 22:27:59.000000000 +0100
-@@ -19,7 +19,6 @@
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
--#include <utime.h>
- #ifdef HAVE_GETOPT_H
- #include <getopt.h>
- #else
diff --git a/package/e2fsprogs/patches/patch-e2fsck_Makefile_in b/package/e2fsprogs/patches/patch-e2fsck_Makefile_in
new file mode 100644
index 000000000..ac7dc5e86
--- /dev/null
+++ b/package/e2fsprogs/patches/patch-e2fsck_Makefile_in
@@ -0,0 +1,20 @@
+--- e2fsprogs-1.41.14.orig/e2fsck/Makefile.in 2010-12-22 16:49:20.000000000 +0100
++++ e2fsprogs-1.41.14/e2fsck/Makefile.in 2011-01-11 00:34:19.000000000 +0100
+@@ -16,7 +16,7 @@ MANPAGES= e2fsck.8
+ FMANPAGES= e2fsck.conf.5
+ XTRA_CFLAGS= -DRESOURCE_TRACK -I.
+
+-LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBBLKID) $(LIBUUID) $(LIBINTL) $(LIBE2P)
++LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBUUID) $(LIBBLKID) $(LIBINTL) $(LIBE2P)
+ DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBBLKID) $(DEPLIBUUID) \
+ $(DEPLIBE2P)
+
+@@ -119,7 +119,7 @@ e2fsck: $(OBJS) $(DEPLIBS)
+
+ e2fsck.static: $(OBJS) $(STATIC_DEPLIBS)
+ $(E) " LD $@"
+- $(Q) $(LD) $(LDFLAGS_STATIC) -o e2fsck.static $(OBJS) $(STATIC_LIBS)
++ $(LD) $(LDFLAGS_STATIC) -o e2fsck.static $(OBJS) $(STATIC_LIBS)
+
+ e2fsck.profiled: $(PROFILED_OBJS) $(PROFILED_DEPLIBS)
+ $(E) " LD $@"
diff --git a/package/e2fsprogs/patches/patch-e2fsprogs_spec b/package/e2fsprogs/patches/patch-e2fsprogs_spec
deleted file mode 100644
index ad10f98dc..000000000
--- a/package/e2fsprogs/patches/patch-e2fsprogs_spec
+++ /dev/null
@@ -1,11 +0,0 @@
---- e2fsprogs-1.41.14.orig/e2fsprogs.spec 2010-12-13 14:57:34.000000000 +0100
-+++ e2fsprogs-1.41.14/e2fsprogs.spec 2010-12-25 22:24:46.000000000 +0100
-@@ -5,7 +5,7 @@
-
- Summary: Utilities for managing ext2/ext3/ext4 filesystems
- Name: e2fsprogs
--Version: 1.41.13
-+Version: 1.41.14
- Release: 0
- License: GPLv2
- Group: System Environment/Base
diff --git a/package/e2fsprogs/patches/patch-misc_e2undo_c b/package/e2fsprogs/patches/patch-misc_e2undo_c
new file mode 100644
index 000000000..2d1441220
--- /dev/null
+++ b/package/e2fsprogs/patches/patch-misc_e2undo_c
@@ -0,0 +1,11 @@
+ optind seems to need unistd.h, not only getopt.h
+--- e2fsprogs-1.41.12.orig/misc/e2undo.c 2010-05-14 00:59:49.000000000 +0200
++++ e2fsprogs-1.41.12/misc/e2undo.c 2010-10-18 12:03:49.329511558 +0200
+@@ -19,6 +19,7 @@
+ #if HAVE_ERRNO_H
+ #include <errno.h>
+ #endif
++#include <unistd.h>
+ #include "ext2fs/tdb.h"
+ #include "ext2fs/ext2fs.h"
+ #include "nls-enable.h"
diff --git a/package/ebtables/patches/patch-Makefile b/package/ebtables/patches/patch-Makefile
index 62528ec30..f05da74c9 100644
--- a/package/ebtables/patches/patch-Makefile
+++ b/package/ebtables/patches/patch-Makefile
@@ -1,6 +1,6 @@
--- ebtables-v2.0.9-1.orig/Makefile 2009-06-21 15:13:25.000000000 +0200
-+++ ebtables-v2.0.9-1/Makefile 2009-11-29 15:39:30.000000000 +0100
-@@ -8,17 +8,16 @@ PROGDATE:=June\ 2009
++++ ebtables-v2.0.9-1/Makefile 2011-01-14 22:24:16.000000000 +0100
+@@ -8,17 +8,17 @@ PROGDATE:=June\ 2009
# default paths
LIBDIR:=/usr/lib
@@ -16,6 +16,7 @@
-CFLAGS:=-Wall -Wunused
+CFLAGS?=-Wall -Wunused
++LDFLAGS?=
CFLAGS_SH_LIB:=-fPIC
-CC:=gcc
-LD:=ld
@@ -23,16 +24,25 @@
ifeq ($(shell uname -m),sparc64)
CFLAGS+=-DEBT_MIN_ALIGN=8 -DKERNEL_64_USERSPACE_32
-@@ -85,7 +84,7 @@ ebtables-standalone.o: ebtables-standalo
+@@ -85,14 +85,14 @@ ebtables-standalone.o: ebtables-standalo
.PHONY: libebtc
libebtc: $(OBJECTS2)
- $(LD) -shared -soname libebtc.so -o libebtc.so -lc $(OBJECTS2)
-+ $(CC) -shared -o libebtc.so -lc $(OBJECTS2)
++ $(CC) -shared $(LDFLAGS) -o libebtc.so -lc $(OBJECTS2)
ebtables: $(OBJECTS) ebtables-standalone.o libebtc
- $(CC) $(CFLAGS) $(CFLAGS_SH_LIB) -o $@ ebtables-standalone.o -I$(KERNEL_INCLUDES) -L. -Lextensions -lebtc $(EXT_LIBSI) \
-@@ -154,28 +153,29 @@ tmp3:=$(shell printf $(PIPE) | sed 's/\/
+- $(CC) $(CFLAGS) $(CFLAGS_SH_LIB) -o $@ ebtables-standalone.o -I$(KERNEL_INCLUDES) -L. -Lextensions -lebtc $(EXT_LIBSI) \
++ $(CC) $(LDFLAGS) $(CFLAGS) $(CFLAGS_SH_LIB) -o $@ ebtables-standalone.o -I$(KERNEL_INCLUDES) -L. -Lextensions -lebtc $(EXT_LIBSI) \
+ -Wl,-rpath,$(LIBDIR)
+
+ ebtablesu: ebtablesu.c
+- $(CC) $(CFLAGS) $(PROGSPECSD) $< -o $@
++ $(CC) $(LDFLAGS) $(CFLAGS) $(PROGSPECSD) $< -o $@
+
+ ebtablesd.o: ebtablesd.c include/ebtables_u.h
+ $(CC) $(CFLAGS) $(PROGSPECSD) -c $< -o $@ -I$(KERNEL_INCLUDES)
+@@ -154,28 +154,29 @@ tmp3:=$(shell printf $(PIPE) | sed 's/\/
.PHONY: scripts
scripts: ebtables-save ebtables.sysv ebtables-config
cat ebtables-save | sed 's/__EXEC_PATH__/$(tmp1)/g' > ebtables-save_
@@ -69,7 +79,7 @@
.PHONY: install
install: $(MANDIR)/man8/ebtables.8 $(ETHERTYPESFILE) exec scripts
-@@ -199,18 +199,18 @@ release:
+@@ -199,18 +200,18 @@ release:
rm -f extensions/ebt_inat.c
rm -rf $(CVSDIRS)
mkdir -p include/linux/netfilter_bridge
diff --git a/package/eglibc/Makefile b/package/eglibc/Makefile
index 27e271f44..844b49876 100644
--- a/package/eglibc/Makefile
+++ b/package/eglibc/Makefile
@@ -20,14 +20,9 @@ CONFIG_STYLE:= manual
BUILD_STYLE:= manual
INSTALL_STYLE:= manual
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_EGLIBC_DEV}+= eglibc-dev-install
-
-EGLIBC_CONFOPTS:= \
- --build=$(GNU_HOST_NAME) \
+EGLIBC_CONFOPTS:= --build=$(GNU_HOST_NAME) \
--host=$(REAL_GNU_TARGET_NAME) \
- --with-headers=$(TOOLCHAIN_SYSROOT)/usr/include \
+ --with-headers=$(STAGING_TARGET_DIR)/usr/include \
--disable-nls \
--without-cvs \
--disable-profile \
@@ -51,17 +46,33 @@ EGLIBC_ENV:= PATH='${TARGET_PATH}' \
libc_cv_slibdir="/lib"
# compile nothing, eglibc is already build in toolchain directory
-do-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+do-install:
${INSTALL_DIR} $(IDIR_EGLIBC)/lib $(IDIR_EGLIBC)/etc \
- $(IDIR_EGLIBC)/usr/lib
- test -z $(ADK_RUNTIME_TIMEZONE) || \
- $(CP) /usr/share/zoneinfo/$(ADK_RUNTIME_TIMEZONE) \
- $(IDIR_EGLIBC)/etc/localtime
+ $(IDIR_EGLIBC)/usr/lib
+ cd ${STAGING_TARGET_DIR} && for f in UTC ${ADK_RUNTIME_TIMEZONE}; do \
+ test -s usr/share/zoneinfo/"$$f" || continue; \
+ echo usr/share/zoneinfo/"$$f" | \
+ ${TOOLS_DIR}/cpio -pdu ${IDIR_EGLIBC}/; \
+ done
+ tz=; cd ${IDIR_EGLIBC}/usr/share/zoneinfo || exit 1; \
+ for f in UTC ${ADK_RUNTIME_TIMEZONE}; do \
+ test -s "$$f" || continue; \
+ tz=$$f; \
+ done; if test x"$$tz" = x""; then \
+ echo >&2 Error during timezone installation; \
+ exit 1; \
+ else \
+ ln -sf "../usr/share/zoneinfo/$$tz" \
+ ${IDIR_EGLIBC}/etc/localtime; \
+ fi
$(CP) $(STAGING_TARGET_DIR)/lib/ld* $(IDIR_EGLIBC)/lib/
- -for file in libc libcrypt libdl libm libnsl libresolv librt libutil libnss_compat libnss_dns libnss_files; do \
+ -for file in libc libcrypt libdl libm libresolv librt libutil libnss_dns libnss_files; do \
$(CP) $(STAGING_TARGET_DIR)/lib/$$file.so* $(IDIR_EGLIBC)/lib/; \
$(CP) $(STAGING_TARGET_DIR)/lib/$$file-$(PKG_VERSION).so $(IDIR_EGLIBC)/lib/; \
done
+ ${INSTALL_DATA} ${STAGING_TARGET_DIR}/etc/gai.conf ${IDIR_EGLIBC}/etc/
+ ${INSTALL_DATA} ${STAGING_TARGET_DIR}/etc/nscd.conf ${IDIR_EGLIBC}/etc/
+ ${INSTALL_DATA} ${STAGING_TARGET_DIR}/etc/nsswitch.conf ${IDIR_EGLIBC}/etc/
eglibc-dev-install:
${INSTALL_DIR} $(IDIR_EGLIBC_DEV)/lib $(IDIR_EGLIBC_DEV)/usr/lib
@@ -89,6 +100,7 @@ eglibc-dev-install:
PATH='${TARGET_PATH}' \
$(MAKE) -C $(WRKBUILD) \
install-headers install-bootstrap-headers=yes
+ @touch $(IDIR_EGLIBC_DEV)/usr/include/gnu/stubs.h
@find $(IDIR_EGLIBC_DEV) -name .install -exec rm {} \;
@find $(IDIR_EGLIBC_DEV) -name ..install.cmd -exec rm {} \;
# conflicts with libiconv
diff --git a/package/elinks/Makefile b/package/elinks/Makefile
index ec7180d93..fe863ec55 100644
--- a/package/elinks/Makefile
+++ b/package/elinks/Makefile
@@ -15,7 +15,7 @@ PKG_URL:= http://elinks.or.cz/
PKG_SITES:= http://elinks.or.cz/download/
PKG_NOPARALLEL:= 1
-PKG_FLAVOURS:= WITH_IPV6
+PKG_FLAVOURS_ELINKS:= WITH_IPV6
PKGFD_WITH_IPV6:= enable IPv6 support
include ${TOPDIR}/mk/package.mk
@@ -23,7 +23,6 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,ELINKS,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
INSTALL_STYLE:= manual
-
TCFLAGS+= -fPIC
CONFIGURE_ENV+= $(shell echo ac_cv_file_./features.conf | tr [:blank:]-/. _)=yes
CONFIGURE_ENV+= $(shell echo ac_cv_file_${WRKBUILD}/features.conf | tr [:blank:]-/. _)=yes
diff --git a/package/esound/patches/patch-esd_c b/package/esound/patches/patch-esd_c
index ebec477a1..2af302a63 100644
--- a/package/esound/patches/patch-esd_c
+++ b/package/esound/patches/patch-esd_c
@@ -2,9 +2,9 @@ $Id$
cast to double, to avoid sinf, patch from Sven Gugges
---- esound-0.2.38.orig/esd.c 2007-05-03 22:28:35.000000000 +0200
-+++ esound-0.2.38/esd.c 2007-05-19 17:21:23.000000000 +0200
-@@ -131,14 +131,14 @@ void set_audio_buffer( void *buf, esd_fo
+--- esound-0.2.41.orig/esd.c 2008-11-18 21:35:19.000000000 +0100
++++ esound-0.2.41/esd.c 2011-01-14 23:15:33.000000000 +0100
+@@ -134,14 +134,14 @@ void set_audio_buffer( void *buf, esd_fo
{
case ESD_BITS8:
for ( i = 0 ; i < length ; i+=2 ) {
diff --git a/package/esound/patches/patch-ltmain_sh b/package/esound/patches/patch-ltmain_sh
new file mode 100644
index 000000000..316c61433
--- /dev/null
+++ b/package/esound/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- esound-0.2.41.orig/ltmain.sh 2008-06-06 20:28:34.000000000 +0200
++++ esound-0.2.41/ltmain.sh 2011-01-14 23:16:51.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/exmap/Makefile b/package/exmap/Makefile
index 536249af9..9b3c57740 100644
--- a/package/exmap/Makefile
+++ b/package/exmap/Makefile
@@ -33,6 +33,7 @@ CONFIGURE_ARGS+= --disable-doc
CONFIGURE_ENV+= LIBS="-lncurses"
pre-build:
+ GCC_HONOUR_COPTS=s \
KERNEL_PATH=${LINUX_DIR} \
CROSS_COMPILE="${TARGET_CROSS}" \
V=1 ARCH="${ARCH}" KERNELVERSION="2.6" \
diff --git a/package/exmap/patches/autotool.patch b/package/exmap/patches/autotool.patch
new file mode 100644
index 000000000..73ae711f4
--- /dev/null
+++ b/package/exmap/patches/autotool.patch
@@ -0,0 +1,11256 @@
+diff -Nur exmap-console-0.4.1.orig/INSTALL exmap-console-0.4.1/INSTALL
+--- exmap-console-0.4.1.orig/INSTALL 2006-11-03 09:36:03.000000000 +0100
++++ exmap-console-0.4.1/INSTALL 2011-01-11 12:44:16.000000000 +0100
+@@ -1,16 +1,25 @@
+ Installation Instructions
+ *************************
+
+-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+-Software Foundation, Inc.
++Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
++2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+-This file is free documentation; the Free Software Foundation gives
+-unlimited permission to copy, distribute and modify it.
++ Copying and distribution of this file, with or without modification,
++are permitted in any medium without royalty provided the copyright
++notice and this notice are preserved. This file is offered as-is,
++without warranty of any kind.
+
+ Basic Installation
+ ==================
+
+-These are generic installation instructions.
++ Briefly, the shell commands `./configure; make; make install' should
++configure, build, and install this package. The following
++more-detailed instructions are generic; see the `README' file for
++instructions specific to this package. Some packages provide this
++`INSTALL' file but do not implement all of the features documented
++below. The lack of an optional feature in a given package is not
++necessarily a bug. More recommendations for GNU packages can be found
++in *note Makefile Conventions: (standards)Makefile Conventions.
+
+ The `configure' shell script attempts to guess correct values for
+ various system-dependent variables used during compilation. It uses
+@@ -23,9 +32,9 @@
+
+ It can also use an optional file (typically called `config.cache'
+ and enabled with `--cache-file=config.cache' or simply `-C') that saves
+-the results of its tests to speed up reconfiguring. (Caching is
++the results of its tests to speed up reconfiguring. Caching is
+ disabled by default to prevent problems with accidental use of stale
+-cache files.)
++cache files.
+
+ If you need to do unusual things to compile the package, please try
+ to figure out how `configure' could check whether to do them, and mail
+@@ -35,30 +44,37 @@
+ may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+-`configure' by a program called `autoconf'. You only need
+-`configure.ac' if you want to change it or regenerate `configure' using
+-a newer version of `autoconf'.
++`configure' by a program called `autoconf'. You need `configure.ac' if
++you want to change it or regenerate `configure' using a newer version
++of `autoconf'.
+
+-The simplest way to compile this package is:
++ The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+- `./configure' to configure the package for your system. If you're
+- using `csh' on an old version of System V, you might need to type
+- `sh ./configure' instead to prevent `csh' from trying to execute
+- `configure' itself.
++ `./configure' to configure the package for your system.
+
+- Running `configure' takes awhile. While running, it prints some
+- messages telling which features it is checking for.
++ Running `configure' might take a while. While running, it prints
++ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+- the package.
++ the package, generally using the just-built uninstalled binaries.
+
+ 4. Type `make install' to install the programs and any data files and
+- documentation.
++ documentation. When installing into a prefix owned by root, it is
++ recommended that the package be configured and built as a regular
++ user, and only the `make install' phase executed with root
++ privileges.
++
++ 5. Optionally, type `make installcheck' to repeat any self-tests, but
++ this time using the binaries in their final installed location.
++ This target does not install anything. Running this target as a
++ regular user, particularly if the prior `make install' required
++ root privileges, verifies that the installation completed
++ correctly.
+
+- 5. You can remove the program binaries and object files from the
++ 6. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+@@ -67,45 +83,69 @@
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
++ 7. Often, you can also type `make uninstall' to remove the installed
++ files again. In practice, not all packages have tested that
++ uninstallation works correctly, even though it is required by the
++ GNU Coding Standards.
++
++ 8. Some packages, particularly those that use Automake, provide `make
++ distcheck', which can by used by developers to test that all other
++ targets like `make install' and `make uninstall' work correctly.
++ This target is generally not run by end users.
++
+ Compilers and Options
+ =====================
+
+-Some systems require unusual options for compilation or linking that the
+-`configure' script does not know about. Run `./configure --help' for
+-details on some of the pertinent environment variables.
++ Some systems require unusual options for compilation or linking that
++the `configure' script does not know about. Run `./configure --help'
++for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+ by setting variables in the command line or in the environment. Here
+ is an example:
+
+- ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
++ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+ Compiling For Multiple Architectures
+ ====================================
+
+-You can compile the package for more than one kind of computer at the
++ You can compile the package for more than one kind of computer at the
+ same time, by placing the object files for each architecture in their
+-own directory. To do this, you must use a version of `make' that
+-supports the `VPATH' variable, such as GNU `make'. `cd' to the
++own directory. To do this, you can use GNU `make'. `cd' to the
+ directory where you want the object files and executables to go and run
+ the `configure' script. `configure' automatically checks for the
+-source code in the directory that `configure' is in and in `..'.
++source code in the directory that `configure' is in and in `..'. This
++is known as a "VPATH" build.
+
+- If you have to use a `make' that does not support the `VPATH'
+-variable, you have to compile the package for one architecture at a
+-time in the source code directory. After you have installed the
+-package for one architecture, use `make distclean' before reconfiguring
+-for another architecture.
++ With a non-GNU `make', it is safer to compile the package for one
++architecture at a time in the source code directory. After you have
++installed the package for one architecture, use `make distclean' before
++reconfiguring for another architecture.
++
++ On MacOS X 10.5 and later systems, you can create libraries and
++executables that work on multiple system types--known as "fat" or
++"universal" binaries--by specifying multiple `-arch' options to the
++compiler but only a single `-arch' option to the preprocessor. Like
++this:
++
++ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
++ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
++ CPP="gcc -E" CXXCPP="g++ -E"
++
++ This is not guaranteed to produce working output in all cases, you
++may have to build one architecture at a time and combine the results
++using the `lipo' tool if you have problems.
+
+ Installation Names
+ ==================
+
+-By default, `make install' installs the package's commands under
++ By default, `make install' installs the package's commands under
+ `/usr/local/bin', include files under `/usr/local/include', etc. You
+ can specify an installation prefix other than `/usr/local' by giving
+-`configure' the option `--prefix=PREFIX'.
++`configure' the option `--prefix=PREFIX', where PREFIX must be an
++absolute file name.
+
+ You can specify separate installation prefixes for
+ architecture-specific files and architecture-independent files. If you
+@@ -116,16 +156,47 @@
+ In addition, if you use an unusual directory layout you can give
+ options like `--bindir=DIR' to specify different values for particular
+ kinds of files. Run `configure --help' for a list of the directories
+-you can set and what kinds of files go in them.
++you can set and what kinds of files go in them. In general, the
++default for these options is expressed in terms of `${prefix}', so that
++specifying just `--prefix' will affect all of the other directory
++specifications that were not explicitly provided.
++
++ The most portable way to affect installation locations is to pass the
++correct locations to `configure'; however, many packages provide one or
++both of the following shortcuts of passing variable assignments to the
++`make install' command line to change installation locations without
++having to reconfigure or recompile.
++
++ The first method involves providing an override variable for each
++affected directory. For example, `make install
++prefix=/alternate/directory' will choose an alternate location for all
++directory configuration variables that were expressed in terms of
++`${prefix}'. Any directories that were specified during `configure',
++but not in terms of `${prefix}', must each be overridden at install
++time for the entire installation to be relocated. The approach of
++makefile variable overrides for each directory variable is required by
++the GNU Coding Standards, and ideally causes no recompilation.
++However, some platforms have known limitations with the semantics of
++shared libraries that end up requiring recompilation when using this
++method, particularly noticeable in packages that use GNU Libtool.
++
++ The second method involves providing the `DESTDIR' variable. For
++example, `make install DESTDIR=/alternate/directory' will prepend
++`/alternate/directory' before all installation names. The approach of
++`DESTDIR' overrides is not required by the GNU Coding Standards, and
++does not work on platforms that have drive letters. On the other hand,
++it does better at avoiding recompilation issues, and works well even
++when some directory options were not specified in terms of `${prefix}'
++at `configure' time.
++
++Optional Features
++=================
+
+ If the package supports it, you can cause programs to be installed
+ with an extra prefix or suffix on their names by giving `configure' the
+ option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+-Optional Features
+-=================
+-
+-Some packages pay attention to `--enable-FEATURE' options to
++ Some packages pay attention to `--enable-FEATURE' options to
+ `configure', where FEATURE indicates an optional part of the package.
+ They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+ is something like `gnu-as' or `x' (for the X Window System). The
+@@ -137,14 +208,53 @@
+ you can use the `configure' options `--x-includes=DIR' and
+ `--x-libraries=DIR' to specify their locations.
+
++ Some packages offer the ability to configure how verbose the
++execution of `make' will be. For these packages, running `./configure
++--enable-silent-rules' sets the default to minimal output, which can be
++overridden with `make V=1'; while running `./configure
++--disable-silent-rules' sets the default to verbose, which can be
++overridden with `make V=0'.
++
++Particular systems
++==================
++
++ On HP-UX, the default C compiler is not ANSI C compatible. If GNU
++CC is not installed, it is recommended to use the following options in
++order to use an ANSI C compiler:
++
++ ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
++
++and if that doesn't work, install pre-built binaries of GCC for HP-UX.
++
++ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
++parse its `<wchar.h>' header file. The option `-nodtk' can be used as
++a workaround. If GNU CC is not installed, it is therefore recommended
++to try
++
++ ./configure CC="cc"
++
++and if that doesn't work, try
++
++ ./configure CC="cc -nodtk"
++
++ On Solaris, don't put `/usr/ucb' early in your `PATH'. This
++directory contains several dysfunctional programs; working variants of
++these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
++in your `PATH', put it _after_ `/usr/bin'.
++
++ On Haiku, software installed for all users goes in `/boot/common',
++not `/usr/local'. It is recommended to use the following options:
++
++ ./configure --prefix=/boot/common
++
+ Specifying the System Type
+ ==========================
+
+-There may be some features `configure' cannot figure out automatically,
+-but needs to determine by the type of machine the package will run on.
+-Usually, assuming the package is built to be run on the _same_
+-architectures, `configure' can figure that out, but if it prints a
+-message saying it cannot guess the machine type, give it the
++ There may be some features `configure' cannot figure out
++automatically, but needs to determine by the type of machine the package
++will run on. Usually, assuming the package is built to be run on the
++_same_ architectures, `configure' can figure that out, but if it prints
++a message saying it cannot guess the machine type, give it the
+ `--build=TYPE' option. TYPE can either be a short name for the system
+ type, such as `sun4', or a canonical name which has the form:
+
+@@ -152,7 +262,8 @@
+
+ where SYSTEM can have one of these forms:
+
+- OS KERNEL-OS
++ OS
++ KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+ `config.sub' isn't included in this package, then this package doesn't
+@@ -170,9 +281,9 @@
+ Sharing Defaults
+ ================
+
+-If you want to set default values for `configure' scripts to share, you
+-can create a site shell script called `config.site' that gives default
+-values for variables like `CC', `cache_file', and `prefix'.
++ If you want to set default values for `configure' scripts to share,
++you can create a site shell script called `config.site' that gives
++default values for variables like `CC', `cache_file', and `prefix'.
+ `configure' looks for `PREFIX/share/config.site' if it exists, then
+ `PREFIX/etc/config.site' if it exists. Or, you can set the
+ `CONFIG_SITE' environment variable to the location of the site script.
+@@ -181,7 +292,7 @@
+ Defining Variables
+ ==================
+
+-Variables not defined in a site shell script can be set in the
++ Variables not defined in a site shell script can be set in the
+ environment passed to `configure'. However, some packages may run
+ configure again during the build, and the customized values of these
+ variables may be lost. In order to avoid this problem, you should set
+@@ -190,21 +301,29 @@
+ ./configure CC=/usr/local2/bin/gcc
+
+ causes the specified `gcc' to be used as the C compiler (unless it is
+-overridden in the site shell script). Here is a another example:
++overridden in the site shell script).
+
+- /bin/bash ./configure CONFIG_SHELL=/bin/bash
++Unfortunately, this technique does not work for `CONFIG_SHELL' due to
++an Autoconf bug. Until the bug is fixed you can use this workaround:
+
+-Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+-configuration-related scripts to be executed by `/bin/bash'.
++ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+ `configure' Invocation
+ ======================
+
+-`configure' recognizes the following options to control how it operates.
++ `configure' recognizes the following options to control how it
++operates.
+
+ `--help'
+ `-h'
+- Print a summary of the options to `configure', and exit.
++ Print a summary of all of the options to `configure', and exit.
++
++`--help=short'
++`--help=recursive'
++ Print a summary of the options unique to this package's
++ `configure', and exit. The `short' variant lists options used
++ only in the top level, while the `recursive' variant lists options
++ also present in any nested packages.
+
+ `--version'
+ `-V'
+@@ -231,6 +350,16 @@
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
++`--prefix=DIR'
++ Use DIR as the installation prefix. *note Installation Names::
++ for more details, including other options available for fine-tuning
++ the installation locations.
++
++`--no-create'
++`-n'
++ Run the configure checks, but stop before creating any output
++ files.
++
+ `configure' also accepts some other, not widely useful, options. Run
+ `configure --help' for more details.
+
+diff -Nur exmap-console-0.4.1.orig/Makefile.am exmap-console-0.4.1/Makefile.am
+--- exmap-console-0.4.1.orig/Makefile.am 2006-11-06 18:05:01.000000000 +0100
++++ exmap-console-0.4.1/Makefile.am 2011-01-11 12:44:03.000000000 +0100
+@@ -1,4 +1,4 @@
+-SUBDIRS=kernel src doc
++SUBDIRS=src
+
+ DISTCLEANFILES = *~ Makefile.in install-sh missing depcomp *.m4 config.log config.status Makefile
+
+diff -Nur exmap-console-0.4.1.orig/Makefile.in exmap-console-0.4.1/Makefile.in
+--- exmap-console-0.4.1.orig/Makefile.in 2007-02-26 12:44:02.000000000 +0100
++++ exmap-console-0.4.1/Makefile.in 2011-01-11 12:44:16.000000000 +0100
+@@ -1,8 +1,9 @@
+-# Makefile.in generated by automake 1.9.6 from Makefile.am.
++# Makefile.in generated by automake 1.11.1 from Makefile.am.
+ # @configure_input@
+
+ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+-# 2003, 2004, 2005 Free Software Foundation, Inc.
++# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
++# Inc.
+ # This Makefile.in is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+@@ -13,15 +14,12 @@
+ # PARTICULAR PURPOSE.
+
+ @SET_MAKE@
+-srcdir = @srcdir@
+-top_srcdir = @top_srcdir@
+ VPATH = @srcdir@
+ pkgdatadir = $(datadir)/@PACKAGE@
+-pkglibdir = $(libdir)/@PACKAGE@
+ pkgincludedir = $(includedir)/@PACKAGE@
+-top_builddir = .
++pkglibdir = $(libdir)/@PACKAGE@
++pkglibexecdir = $(libexecdir)/@PACKAGE@
+ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+-INSTALL = @INSTALL@
+ install_sh_DATA = $(install_sh) -c -m 644
+ install_sh_PROGRAM = $(install_sh) -c
+ install_sh_SCRIPT = $(install_sh) -c
+@@ -42,17 +40,24 @@
+ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+- configure.lineno configure.status.lineno
++ configure.lineno config.status.lineno
+ mkinstalldirs = $(install_sh) -d
+ CONFIG_CLEAN_FILES =
++CONFIG_CLEAN_VPATH_FILES =
+ SOURCES =
+ DIST_SOURCES =
+ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+- install-exec-recursive install-info-recursive \
+- install-recursive installcheck-recursive installdirs-recursive \
+- pdf-recursive ps-recursive uninstall-info-recursive \
+- uninstall-recursive
++ install-dvi-recursive install-exec-recursive \
++ install-html-recursive install-info-recursive \
++ install-pdf-recursive install-ps-recursive install-recursive \
++ installcheck-recursive installdirs-recursive pdf-recursive \
++ ps-recursive uninstall-recursive
++RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
++ distclean-recursive maintainer-clean-recursive
++AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
++ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
++ distdir dist dist-all distcheck
+ ETAGS = etags
+ CTAGS = ctags
+ DIST_SUBDIRS = $(SUBDIRS)
+@@ -60,16 +65,39 @@
+ distdir = $(PACKAGE)-$(VERSION)
+ top_distdir = $(distdir)
+ am__remove_distdir = \
+- { test ! -d $(distdir) \
+- || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+- && rm -fr $(distdir); }; }
++ { test ! -d "$(distdir)" \
++ || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
++ && rm -fr "$(distdir)"; }; }
++am__relativize = \
++ dir0=`pwd`; \
++ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
++ sed_rest='s,^[^/]*/*,,'; \
++ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
++ sed_butlast='s,/*[^/]*$$,,'; \
++ while test -n "$$dir1"; do \
++ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
++ if test "$$first" != "."; then \
++ if test "$$first" = ".."; then \
++ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
++ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
++ else \
++ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
++ if test "$$first2" = "$$first"; then \
++ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
++ else \
++ dir2="../$$dir2"; \
++ fi; \
++ dir0="$$dir0"/"$$first"; \
++ fi; \
++ fi; \
++ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
++ done; \
++ reldir="$$dir2"
+ DIST_ARCHIVES = $(distdir).tar.gz
+ GZIP_ENV = --best
+ distuninstallcheck_listfiles = find . -type f -print
+ distcleancheck_listfiles = find . -type f -print
+ ACLOCAL = @ACLOCAL@
+-AMDEP_FALSE = @AMDEP_FALSE@
+-AMDEP_TRUE = @AMDEP_TRUE@
+ AMTAR = @AMTAR@
+ AUTOCONF = @AUTOCONF@
+ AUTOHEADER = @AUTOHEADER@
+@@ -82,8 +110,6 @@
+ CYGPATH_W = @CYGPATH_W@
+ DEFS = @DEFS@
+ DEPDIR = @DEPDIR@
+-DODOCS_FALSE = @DODOCS_FALSE@
+-DODOCS_TRUE = @DODOCS_TRUE@
+ ECHO_C = @ECHO_C@
+ ECHO_N = @ECHO_N@
+ ECHO_T = @ECHO_T@
+@@ -91,38 +117,41 @@
+ GCC_CFLAGS = @GCC_CFLAGS@
+ GLIB_CFLAGS = @GLIB_CFLAGS@
+ GLIB_LIBS = @GLIB_LIBS@
+-HAVE_HELPTOMAN_FALSE = @HAVE_HELPTOMAN_FALSE@
+-HAVE_HELPTOMAN_TRUE = @HAVE_HELPTOMAN_TRUE@
+ HELPTOMAN = @HELPTOMAN@
++INSTALL = @INSTALL@
+ INSTALL_DATA = @INSTALL_DATA@
+ INSTALL_PROGRAM = @INSTALL_PROGRAM@
+ INSTALL_SCRIPT = @INSTALL_SCRIPT@
+ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+-INTERACTIVE_FALSE = @INTERACTIVE_FALSE@
+-INTERACTIVE_TRUE = @INTERACTIVE_TRUE@
+ LDFLAGS = @LDFLAGS@
+ LIBOBJS = @LIBOBJS@
+ LIBS = @LIBS@
+ LTLIBOBJS = @LTLIBOBJS@
+ MAKEINFO = @MAKEINFO@
++MKDIR_P = @MKDIR_P@
+ OBJEXT = @OBJEXT@
+ PACKAGE = @PACKAGE@
+ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+ PACKAGE_NAME = @PACKAGE_NAME@
+ PACKAGE_STRING = @PACKAGE_STRING@
+ PACKAGE_TARNAME = @PACKAGE_TARNAME@
++PACKAGE_URL = @PACKAGE_URL@
+ PACKAGE_VERSION = @PACKAGE_VERSION@
+ PATH_SEPARATOR = @PATH_SEPARATOR@
+ PKG_CONFIG = @PKG_CONFIG@
++PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
++PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+ READLINE_CFLAGS = @READLINE_CFLAGS@
+ READLINE_LIBS = @READLINE_LIBS@
+ SET_MAKE = @SET_MAKE@
+ SHELL = @SHELL@
+ STRIP = @STRIP@
+ VERSION = @VERSION@
++abs_builddir = @abs_builddir@
++abs_srcdir = @abs_srcdir@
++abs_top_builddir = @abs_top_builddir@
++abs_top_srcdir = @abs_top_srcdir@
+ ac_ct_CC = @ac_ct_CC@
+-am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+-am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+ am__include = @am__include@
+ am__leading_dot = @am__leading_dot@
+ am__quote = @am__quote@
+@@ -130,6 +159,7 @@
+ am__untar = @am__untar@
+ bindir = @bindir@
+ build_alias = @build_alias@
++builddir = @builddir@
+ datadir = @datadir@
+ datarootdir = @datarootdir@
+ docdir = @docdir@
+@@ -153,9 +183,13 @@
+ psdir = @psdir@
+ sbindir = @sbindir@
+ sharedstatedir = @sharedstatedir@
++srcdir = @srcdir@
+ sysconfdir = @sysconfdir@
+ target_alias = @target_alias@
+-SUBDIRS = kernel src doc
++top_build_prefix = @top_build_prefix@
++top_builddir = @top_builddir@
++top_srcdir = @top_srcdir@
++SUBDIRS = src
+ DISTCLEANFILES = *~ Makefile.in install-sh missing depcomp *.m4 config.log config.status Makefile
+ all: all-recursive
+
+@@ -166,15 +200,15 @@
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+- echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \
+- cd $(srcdir) && $(AUTOMAKE) --gnu \
++ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
++ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+- cd $(top_srcdir) && \
+- $(AUTOMAKE) --gnu Makefile
++ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
++ $(am__cd) $(top_srcdir) && \
++ $(AUTOMAKE) --gnu Makefile
+ .PRECIOUS: Makefile
+ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+@@ -190,10 +224,10 @@
+ $(SHELL) ./config.status --recheck
+
+ $(top_srcdir)/configure: $(am__configure_deps)
+- cd $(srcdir) && $(AUTOCONF)
++ $(am__cd) $(srcdir) && $(AUTOCONF)
+ $(ACLOCAL_M4): $(am__aclocal_m4_deps)
+- cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+-uninstall-info-am:
++ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
++$(am__aclocal_m4_deps):
+
+ # This directory's subdirectories are mostly independent; you can cd
+ # into them and run `make' without going through this Makefile.
+@@ -202,7 +236,7 @@
+ # (which will cause the Makefiles to be regenerated when you run `make');
+ # (2) otherwise, pass the desired values on the `make' command line.
+ $(RECURSIVE_TARGETS):
+- @failcom='exit 1'; \
++ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+@@ -219,16 +253,15 @@
+ else \
+ local_target="$$target"; \
+ fi; \
+- (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
++ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+-mostlyclean-recursive clean-recursive distclean-recursive \
+-maintainer-clean-recursive:
+- @failcom='exit 1'; \
++$(RECURSIVE_CLEAN_TARGETS):
++ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+@@ -254,16 +287,16 @@
+ else \
+ local_target="$$target"; \
+ fi; \
+- (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
++ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+ tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+- test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
++ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+- test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
++ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+@@ -271,14 +304,14 @@
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+- $(AWK) ' { files[$$0] = 1; } \
+- END { for (i in files) print i; }'`; \
++ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
++ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+ tags: TAGS
+
+ TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+- tags=; \
++ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+@@ -290,92 +323,114 @@
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+- tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
++ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+- $(AWK) ' { files[$$0] = 1; } \
+- END { for (i in files) print i; }'`; \
+- if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
++ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
++ END { if (nonempty) { for (i in files) print i; }; }'`; \
++ shift; \
++ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+- $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+- $$tags $$unique; \
++ if test $$# -gt 0; then \
++ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
++ "$$@" $$unique; \
++ else \
++ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
++ $$unique; \
++ fi; \
+ fi
+ ctags: CTAGS
+ CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+- tags=; \
+- here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+- $(AWK) ' { files[$$0] = 1; } \
+- END { for (i in files) print i; }'`; \
+- test -z "$(CTAGS_ARGS)$$tags$$unique" \
++ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
++ END { if (nonempty) { for (i in files) print i; }; }'`; \
++ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+- $$tags $$unique
++ $$unique
+
+ GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+- && cd $(top_srcdir) \
+- && gtags -i $(GTAGS_ARGS) $$here
++ && $(am__cd) $(top_srcdir) \
++ && gtags -i $(GTAGS_ARGS) "$$here"
+
+ distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+ distdir: $(DISTFILES)
+ $(am__remove_distdir)
+- mkdir $(distdir)
+- @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+- topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+- list='$(DISTFILES)'; for file in $$list; do \
+- case $$file in \
+- $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+- $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+- esac; \
++ test -d "$(distdir)" || mkdir "$(distdir)"
++ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
++ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
++ list='$(DISTFILES)'; \
++ dist_files=`for file in $$list; do echo $$file; done | \
++ sed -e "s|^$$srcdirstrip/||;t" \
++ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
++ case $$dist_files in \
++ */*) $(MKDIR_P) `echo "$$dist_files" | \
++ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
++ sort -u` ;; \
++ esac; \
++ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+- dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+- if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+- dir="/$$dir"; \
+- $(mkdir_p) "$(distdir)$$dir"; \
+- else \
+- dir=''; \
+- fi; \
+ if test -d $$d/$$file; then \
++ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
++ if test -d "$(distdir)/$$file"; then \
++ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
++ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+- cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
++ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
++ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+- cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
++ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+- test -f $(distdir)/$$file \
+- || cp -p $$d/$$file $(distdir)/$$file \
++ test -f "$(distdir)/$$file" \
++ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+- list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
++ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+- || $(mkdir_p) "$(distdir)/$$subdir" \
++ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+- distdir=`$(am__cd) $(distdir) && pwd`; \
+- top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+- (cd $$subdir && \
++ fi; \
++ done
++ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
++ if test "$$subdir" = .; then :; else \
++ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
++ $(am__relativize); \
++ new_distdir=$$reldir; \
++ dir1=$$subdir; dir2="$(top_distdir)"; \
++ $(am__relativize); \
++ new_top_distdir=$$reldir; \
++ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
++ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
++ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+- top_distdir="$$top_distdir" \
+- distdir="$$distdir/$$subdir" \
++ top_distdir="$$new_top_distdir" \
++ distdir="$$new_distdir" \
++ am__remove_distdir=: \
++ am__skip_length_check=: \
++ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+- -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
++ -test -n "$(am__skip_mode_fix)" \
++ || find "$(distdir)" -type d ! -perm -755 \
++ -exec chmod u+rwx,go+rx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+- ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
+- || chmod -R a+r $(distdir)
++ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
++ || chmod -R a+r "$(distdir)"
+ dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+@@ -384,6 +439,14 @@
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
++dist-lzma: distdir
++ tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
++ $(am__remove_distdir)
++
++dist-xz: distdir
++ tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz
++ $(am__remove_distdir)
++
+ dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+@@ -407,13 +470,17 @@
+ distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+- GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
++ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+- bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
++ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
++ *.tar.lzma*) \
++ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
++ *.tar.xz*) \
++ xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+- GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
++ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+@@ -421,9 +488,11 @@
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
++ test -d $(distdir)/_build || exit 0; \
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+- && cd $(distdir)/_build \
++ && am__cwd=`pwd` \
++ && $(am__cd) $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+@@ -445,13 +514,15 @@
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+- && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
++ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
++ && cd "$$am__cwd" \
++ || exit 1
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+- sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
++ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+ distuninstallcheck:
+- @cd $(distuninstallcheck_dir) \
++ @$(am__cd) '$(distuninstallcheck_dir)' \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+@@ -493,6 +564,7 @@
+
+ distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
++ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+ maintainer-clean-generic:
+@@ -510,18 +582,38 @@
+
+ html: html-recursive
+
++html-am:
++
+ info: info-recursive
+
+ info-am:
+
+ install-data-am:
+
++install-dvi: install-dvi-recursive
++
++install-dvi-am:
++
+ install-exec-am:
+
++install-html: install-html-recursive
++
++install-html-am:
++
+ install-info: install-info-recursive
+
++install-info-am:
++
+ install-man:
+
++install-pdf: install-pdf-recursive
++
++install-pdf-am:
++
++install-ps: install-ps-recursive
++
++install-ps-am:
++
+ installcheck-am:
+
+ maintainer-clean: maintainer-clean-recursive
+@@ -542,29 +634,32 @@
+
+ ps-am:
+
+-uninstall-am: uninstall-info-am
++uninstall-am:
+
+-uninstall-info: uninstall-info-recursive
++.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
++ install-am install-strip tags-recursive
+
+-.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \
+- check-am clean clean-generic clean-recursive ctags \
+- ctags-recursive dist dist-all dist-bzip2 dist-gzip dist-shar \
+- dist-tarZ dist-zip distcheck distclean distclean-generic \
+- distclean-recursive distclean-tags distcleancheck distdir \
+- distuninstallcheck dvi dvi-am html html-am info info-am \
+- install install-am install-data install-data-am install-exec \
+- install-exec-am install-info install-info-am install-man \
+- install-strip installcheck installcheck-am installdirs \
+- installdirs-am maintainer-clean maintainer-clean-generic \
+- maintainer-clean-recursive mostlyclean mostlyclean-generic \
+- mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \
+- uninstall uninstall-am uninstall-info-am
++.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
++ all all-am am--refresh check check-am clean clean-generic \
++ ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \
++ dist-lzma dist-shar dist-tarZ dist-xz dist-zip distcheck \
++ distclean distclean-generic distclean-tags distcleancheck \
++ distdir distuninstallcheck dvi dvi-am html html-am info \
++ info-am install install-am install-data install-data-am \
++ install-dvi install-dvi-am install-exec install-exec-am \
++ install-html install-html-am install-info install-info-am \
++ install-man install-pdf install-pdf-am install-ps \
++ install-ps-am install-strip installcheck installcheck-am \
++ installdirs installdirs-am maintainer-clean \
++ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
++ pdf-am ps ps-am tags tags-recursive uninstall uninstall-am
+
+
+ local-distclean:
+ $(RM) -rf autom4te.cache
+
+ distclean: distclean-recursive local-distclean
++
+ # Tell versions [3.59,3.63) of GNU make to not export all variables.
+ # Otherwise a system limit (for SysV at least) may be exceeded.
+ .NOEXPORT:
+diff -Nur exmap-console-0.4.1.orig/aclocal.m4 exmap-console-0.4.1/aclocal.m4
+--- exmap-console-0.4.1.orig/aclocal.m4 2007-02-26 12:43:59.000000000 +0100
++++ exmap-console-0.4.1/aclocal.m4 2011-01-11 12:44:15.000000000 +0100
+@@ -1,7 +1,7 @@
+-# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
++# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
+
+ # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+-# 2005 Free Software Foundation, Inc.
++# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+@@ -11,7 +11,16 @@
+ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ # PARTICULAR PURPOSE.
+
++m4_ifndef([AC_AUTOCONF_VERSION],
++ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
++m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
++[m4_warning([this file was generated for autoconf 2.68.
++You have another version of autoconf. It may work, but is not guaranteed to.
++If you have problems, you may need to regenerate the build system entirely.
++To do so, use the procedure documented by the package, typically `autoreconf'.])])
++
+ # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
++# serial 1 (pkg-config-0.24)
+ #
+ # Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+ #
+@@ -39,7 +48,10 @@
+ AC_DEFUN([PKG_PROG_PKG_CONFIG],
+ [m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+ m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+-AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
++AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
++AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
++AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
++
+ if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+ fi
+@@ -52,7 +64,6 @@
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+-
+ fi[]dnl
+ ])# PKG_PROG_PKG_CONFIG
+
+@@ -61,34 +72,31 @@
+ # Check to see whether a particular set of modules exists. Similar
+ # to PKG_CHECK_MODULES(), but does not set variables or print errors.
+ #
+-#
+-# Similar to PKG_CHECK_MODULES, make sure that the first instance of
+-# this or PKG_CHECK_MODULES is called, or make sure to call
+-# PKG_CHECK_EXISTS manually
++# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
++# only at the first occurence in configure.ac, so if the first place
++# it's called might be skipped (such as if it is within an "if", you
++# have to call PKG_CHECK_EXISTS manually
+ # --------------------------------------------------------------
+ AC_DEFUN([PKG_CHECK_EXISTS],
+ [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+ if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+- m4_ifval([$2], [$2], [:])
++ m4_default([$2], [:])
+ m4_ifvaln([$3], [else
+ $3])dnl
+ fi])
+
+-
+ # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+ # ---------------------------------------------
+ m4_define([_PKG_CONFIG],
+-[if test -n "$PKG_CONFIG"; then
+- if test -n "$$1"; then
+- pkg_cv_[]$1="$$1"
+- else
+- PKG_CHECK_EXISTS([$3],
+- [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+- [pkg_failed=yes])
+- fi
+-else
+- pkg_failed=untried
++[if test -n "$$1"; then
++ pkg_cv_[]$1="$$1"
++ elif test -n "$PKG_CONFIG"; then
++ PKG_CHECK_EXISTS([$3],
++ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
++ [pkg_failed=yes])
++ else
++ pkg_failed=untried
+ fi[]dnl
+ ])# _PKG_CONFIG
+
+@@ -130,16 +138,17 @@
+ See the pkg-config man page for more details.])
+
+ if test $pkg_failed = yes; then
++ AC_MSG_RESULT([no])
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+- $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
++ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1`
+ else
+- $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
++ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+- ifelse([$4], , [AC_MSG_ERROR(dnl
++ m4_default([$4], [AC_MSG_ERROR(
+ [Package requirements ($2) were not met:
+
+ $$1_PKG_ERRORS
+@@ -147,28 +156,28 @@
+ Consider adjusting the PKG_CONFIG_PATH environment variable if you
+ installed software in a non-standard prefix.
+
+-_PKG_TEXT
+-])],
+- [$4])
++_PKG_TEXT])[]dnl
++ ])
+ elif test $pkg_failed = untried; then
+- ifelse([$4], , [AC_MSG_FAILURE(dnl
++ AC_MSG_RESULT([no])
++ m4_default([$4], [AC_MSG_FAILURE(
+ [The pkg-config script could not be found or is too old. Make sure it
+ is in your PATH or set the PKG_CONFIG environment variable to the full
+ path to pkg-config.
+
+ _PKG_TEXT
+
+-To get pkg-config, see <http://www.freedesktop.org/software/pkgconfig>.])],
+- [$4])
++To get pkg-config, see <http://pkg-config.freedesktop.org/>.])dnl
++ ])
+ else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+- ifelse([$3], , :, [$3])
++ $3
+ fi[]dnl
+ ])# PKG_CHECK_MODULES
+
+-# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
++# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ #
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+@@ -178,14 +187,31 @@
+ # ----------------------------
+ # Automake X.Y traces this macro to ensure aclocal.m4 has been
+ # generated from the m4 files accompanying Automake X.Y.
+-AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
++# (This private macro should not be called outside this file.)
++AC_DEFUN([AM_AUTOMAKE_VERSION],
++[am__api_version='1.11'
++dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
++dnl require some minimum version. Point them to the right macro.
++m4_if([$1], [1.11.1], [],
++ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
++])
++
++# _AM_AUTOCONF_VERSION(VERSION)
++# -----------------------------
++# aclocal traces this macro to find the Autoconf version.
++# This is a private macro too. Using m4_define simplifies
++# the logic in aclocal, which can simply ignore this definition.
++m4_define([_AM_AUTOCONF_VERSION], [])
+
+ # AM_SET_CURRENT_AUTOMAKE_VERSION
+ # -------------------------------
+-# Call AM_AUTOMAKE_VERSION so it can be traced.
+-# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
++# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
++# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+ AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+- [AM_AUTOMAKE_VERSION([1.9.6])])
++[AM_AUTOMAKE_VERSION([1.11.1])dnl
++m4_ifndef([AC_AUTOCONF_VERSION],
++ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
++_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+ # AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+@@ -242,14 +268,14 @@
+
+ # AM_CONDITIONAL -*- Autoconf -*-
+
+-# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
++# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
+ # Free Software Foundation, Inc.
+ #
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+
+-# serial 7
++# serial 9
+
+ # AM_CONDITIONAL(NAME, SHELL-CONDITION)
+ # -------------------------------------
+@@ -258,8 +284,11 @@
+ [AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+-AC_SUBST([$1_TRUE])
+-AC_SUBST([$1_FALSE])
++AC_SUBST([$1_TRUE])dnl
++AC_SUBST([$1_FALSE])dnl
++_AM_SUBST_NOTMAKE([$1_TRUE])dnl
++_AM_SUBST_NOTMAKE([$1_FALSE])dnl
++m4_define([_AM_COND_VALUE_$1], [$2])dnl
+ if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+@@ -273,15 +302,14 @@
+ Usually this means the macro was only invoked conditionally.]])
+ fi])])
+
+-
+-# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
++# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009
+ # Free Software Foundation, Inc.
+ #
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+
+-# serial 8
++# serial 10
+
+ # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+ # written in clear, in which case automake, when reading aclocal.m4,
+@@ -309,6 +337,7 @@
+ ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
++ [$1], UPC, [depcc="$UPC" am_compiler_list=],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+@@ -337,6 +366,16 @@
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
++ am__universal=false
++ m4_case([$1], [CC],
++ [case " $depcc " in #(
++ *\ -arch\ *\ -arch\ *) am__universal=true ;;
++ esac],
++ [CXX],
++ [case " $depcc " in #(
++ *\ -arch\ *\ -arch\ *) am__universal=true ;;
++ esac])
++
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+@@ -354,7 +393,17 @@
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
++ # We check with `-c' and `-o' for the sake of the "dashmstdout"
++ # mode. It turns out that the SunPro C++ compiler does not properly
++ # handle `-M -o', and we need to detect this. Also, some Intel
++ # versions had trouble with output in subdirs
++ am__obj=sub/conftest.${OBJEXT-o}
++ am__minus_obj="-o $am__obj"
+ case $depmode in
++ gcc)
++ # This depmode causes a compiler race in universal mode.
++ test "$am__universal" = false || continue
++ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+@@ -364,18 +413,23 @@
+ break
+ fi
+ ;;
++ msvisualcpp | msvcmsys)
++ # This compiler won't grok `-c -o', but also, the minuso test has
++ # not run yet. These depmodes are late enough in the game, and
++ # so weak that their functioning should not be impacted.
++ am__obj=conftest.${OBJEXT-o}
++ am__minus_obj=
++ ;;
+ none) break ;;
+ esac
+- # We check with `-c' and `-o' for the sake of the "dashmstdout"
+- # mode. It turns out that the SunPro C++ compiler does not properly
+- # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+- source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
++ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+- $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
++ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
++ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+- grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
++ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+@@ -426,61 +480,74 @@
+ AMDEPBACKSLASH='\'
+ fi
+ AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+-AC_SUBST([AMDEPBACKSLASH])
++AC_SUBST([AMDEPBACKSLASH])dnl
++_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+ ])
+
+ # Generate code to set up dependency tracking. -*- Autoconf -*-
+
+-# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
++# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+ # Free Software Foundation, Inc.
+ #
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+
+-#serial 3
++#serial 5
+
+ # _AM_OUTPUT_DEPENDENCY_COMMANDS
+ # ------------------------------
+ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+-[for mf in $CONFIG_FILES; do
+- # Strip MF so we end up with the name of the file.
+- mf=`echo "$mf" | sed -e 's/:.*$//'`
+- # Check whether this is an Automake generated Makefile or not.
+- # We used to match only the files named `Makefile.in', but
+- # some people rename them; so instead we look at the file content.
+- # Grep'ing the first line is not enough: some people post-process
+- # each Makefile.in and add a new line on top of each file to say so.
+- # So let's grep whole file.
+- if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+- dirpart=`AS_DIRNAME("$mf")`
+- else
+- continue
+- fi
+- # Extract the definition of DEPDIR, am__include, and am__quote
+- # from the Makefile without running `make'.
+- DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+- test -z "$DEPDIR" && continue
+- am__include=`sed -n 's/^am__include = //p' < "$mf"`
+- test -z "am__include" && continue
+- am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+- # When using ansi2knr, U may be empty or an underscore; expand it
+- U=`sed -n 's/^U = //p' < "$mf"`
+- # Find all dependency output files, they are included files with
+- # $(DEPDIR) in their names. We invoke sed twice because it is the
+- # simplest approach to changing $(DEPDIR) to its actual value in the
+- # expansion.
+- for file in `sed -n "
+- s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+- sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+- # Make sure the directory exists.
+- test -f "$dirpart/$file" && continue
+- fdir=`AS_DIRNAME(["$file"])`
+- AS_MKDIR_P([$dirpart/$fdir])
+- # echo "creating $dirpart/$file"
+- echo '# dummy' > "$dirpart/$file"
++[{
++ # Autoconf 2.62 quotes --file arguments for eval, but not when files
++ # are listed without --file. Let's play safe and only enable the eval
++ # if we detect the quoting.
++ case $CONFIG_FILES in
++ *\'*) eval set x "$CONFIG_FILES" ;;
++ *) set x $CONFIG_FILES ;;
++ esac
++ shift
++ for mf
++ do
++ # Strip MF so we end up with the name of the file.
++ mf=`echo "$mf" | sed -e 's/:.*$//'`
++ # Check whether this is an Automake generated Makefile or not.
++ # We used to match only the files named `Makefile.in', but
++ # some people rename them; so instead we look at the file content.
++ # Grep'ing the first line is not enough: some people post-process
++ # each Makefile.in and add a new line on top of each file to say so.
++ # Grep'ing the whole file is not good either: AIX grep has a line
++ # limit of 2048, but all sed's we know have understand at least 4000.
++ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
++ dirpart=`AS_DIRNAME("$mf")`
++ else
++ continue
++ fi
++ # Extract the definition of DEPDIR, am__include, and am__quote
++ # from the Makefile without running `make'.
++ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
++ test -z "$DEPDIR" && continue
++ am__include=`sed -n 's/^am__include = //p' < "$mf"`
++ test -z "am__include" && continue
++ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
++ # When using ansi2knr, U may be empty or an underscore; expand it
++ U=`sed -n 's/^U = //p' < "$mf"`
++ # Find all dependency output files, they are included files with
++ # $(DEPDIR) in their names. We invoke sed twice because it is the
++ # simplest approach to changing $(DEPDIR) to its actual value in the
++ # expansion.
++ for file in `sed -n "
++ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
++ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
++ # Make sure the directory exists.
++ test -f "$dirpart/$file" && continue
++ fdir=`AS_DIRNAME(["$file"])`
++ AS_MKDIR_P([$dirpart/$fdir])
++ # echo "creating $dirpart/$file"
++ echo '# dummy' > "$dirpart/$file"
++ done
+ done
+-done
++}
+ ])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+@@ -499,14 +566,14 @@
+
+ # Do all the work for Automake. -*- Autoconf -*-
+
+-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+-# Free Software Foundation, Inc.
++# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
++# 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
+ #
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+
+-# serial 12
++# serial 16
+
+ # This macro actually does too much. Some checks are only needed if
+ # your package does certain things. But this isn't really a big deal.
+@@ -523,16 +590,20 @@
+ # arguments mandatory, and then we can depend on a new Autoconf
+ # release and drop the old call support.
+ AC_DEFUN([AM_INIT_AUTOMAKE],
+-[AC_PREREQ([2.58])dnl
++[AC_PREREQ([2.62])dnl
+ dnl Autoconf wants to disallow AM_ names. We explicitly allow
+ dnl the ones we care about.
+ m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+ AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+ AC_REQUIRE([AC_PROG_INSTALL])dnl
+-# test to see if srcdir already configured
+-if test "`cd $srcdir && pwd`" != "`pwd`" &&
+- test -f $srcdir/config.status; then
+- AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
++if test "`cd $srcdir && pwd`" != "`pwd`"; then
++ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
++ # is not polluted with repeated "-I."
++ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
++ # test to see if srcdir already configured
++ if test -f $srcdir/config.status; then
++ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
++ fi
+ fi
+
+ # test whether we have cygpath
+@@ -552,6 +623,9 @@
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+ [_AM_SET_OPTIONS([$1])dnl
++dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
++m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
++ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+@@ -567,8 +641,8 @@
+ AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+ AM_MISSING_PROG(AUTOHEADER, autoheader)
+ AM_MISSING_PROG(MAKEINFO, makeinfo)
+-AM_PROG_INSTALL_SH
+-AM_PROG_INSTALL_STRIP
++AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
++AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+ AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+ # We need awk for the "check" target. The system "awk" is bad on
+ # some platforms.
+@@ -576,20 +650,37 @@
+ AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+ AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+ _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+- [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+- [_AM_PROG_TAR([v7])])])
++ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
++ [_AM_PROG_TAR([v7])])])
+ _AM_IF_OPTION([no-dependencies],,
+ [AC_PROVIDE_IFELSE([AC_PROG_CC],
+- [_AM_DEPENDENCIES(CC)],
+- [define([AC_PROG_CC],
+- defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
++ [_AM_DEPENDENCIES(CC)],
++ [define([AC_PROG_CC],
++ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+ AC_PROVIDE_IFELSE([AC_PROG_CXX],
+- [_AM_DEPENDENCIES(CXX)],
+- [define([AC_PROG_CXX],
+- defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
++ [_AM_DEPENDENCIES(CXX)],
++ [define([AC_PROG_CXX],
++ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
++AC_PROVIDE_IFELSE([AC_PROG_OBJC],
++ [_AM_DEPENDENCIES(OBJC)],
++ [define([AC_PROG_OBJC],
++ defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+ ])
++_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
++dnl The `parallel-tests' driver may need to know about EXEEXT, so add the
++dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro
++dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
++AC_CONFIG_COMMANDS_PRE(dnl
++[m4_provide_if([_AM_COMPILER_EXEEXT],
++ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+ ])
+
++dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
++dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
++dnl mangled by Autoconf and run in a shell conditional statement.
++m4_define([_AC_COMPILER_EXEEXT],
++m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
++
+
+ # When config.status generates a header, we must update the stamp-h file.
+ # This file resides in the same directory as the config header
+@@ -600,18 +691,19 @@
+ # our stamp files there.
+ AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+ [# Compute $1's index in $config_headers.
++_am_arg=$1
+ _am_stamp_count=1
+ for _am_header in $config_headers :; do
+ case $_am_header in
+- $1 | $1:* )
++ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+ done
+-echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
++echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+-# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
++# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc.
+ #
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+@@ -622,7 +714,14 @@
+ # Define $install_sh.
+ AC_DEFUN([AM_PROG_INSTALL_SH],
+ [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+-install_sh=${install_sh-"$am_aux_dir/install-sh"}
++if test x"${install_sh}" != xset; then
++ case $am_aux_dir in
++ *\ * | *\ *)
++ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
++ *)
++ install_sh="\${SHELL} $am_aux_dir/install-sh"
++ esac
++fi
+ AC_SUBST(install_sh)])
+
+ # Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+@@ -648,13 +747,13 @@
+
+ # Check to see how 'make' treats includes. -*- Autoconf -*-
+
+-# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
++# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc.
+ #
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+
+-# serial 3
++# serial 4
+
+ # AM_MAKE_INCLUDE()
+ # -----------------
+@@ -663,7 +762,7 @@
+ [am_make=${MAKE-make}
+ cat > confinc << 'END'
+ am__doit:
+- @echo done
++ @echo this is the am__doit target
+ .PHONY: am__doit
+ END
+ # If we don't find an include directive, just comment out the code.
+@@ -673,24 +772,24 @@
+ _am_result=none
+ # First try GNU make style include.
+ echo "include confinc" > confmf
+-# We grep out `Entering directory' and `Leaving directory'
+-# messages which can occur if `w' ends up in MAKEFLAGS.
+-# In particular we don't look at `^make:' because GNU make might
+-# be invoked under some other name (usually "gmake"), in which
+-# case it prints its new name instead of `make'.
+-if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+- am__include=include
+- am__quote=
+- _am_result=GNU
+-fi
++# Ignore all kinds of additional output from `make'.
++case `$am_make -s -f confmf 2> /dev/null` in #(
++*the\ am__doit\ target*)
++ am__include=include
++ am__quote=
++ _am_result=GNU
++ ;;
++esac
+ # Now try BSD make style include.
+ if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+- if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+- am__include=.include
+- am__quote="\""
+- _am_result=BSD
+- fi
++ case `$am_make -s -f confmf 2> /dev/null` in #(
++ *the\ am__doit\ target*)
++ am__include=.include
++ am__quote="\""
++ _am_result=BSD
++ ;;
++ esac
+ fi
+ AC_SUBST([am__include])
+ AC_SUBST([am__quote])
+@@ -700,14 +799,14 @@
+
+ # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+-# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
++# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
+ # Free Software Foundation, Inc.
+ #
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+
+-# serial 4
++# serial 6
+
+ # AM_MISSING_PROG(NAME, PROGRAM)
+ # ------------------------------
+@@ -723,7 +822,15 @@
+ # If it does, set am_missing_run to use it, otherwise, to nothing.
+ AC_DEFUN([AM_MISSING_HAS_RUN],
+ [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+-test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
++AC_REQUIRE_AUX_FILE([missing])dnl
++if test x"${MISSING+set}" != xset; then
++ case $am_aux_dir in
++ *\ * | *\ *)
++ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
++ *)
++ MISSING="\${SHELL} $am_aux_dir/missing" ;;
++ esac
++fi
+ # Use eval to expand $SHELL
+ if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+@@ -733,7 +840,7 @@
+ fi
+ ])
+
+-# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
++# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ #
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+@@ -741,70 +848,33 @@
+
+ # AM_PROG_MKDIR_P
+ # ---------------
+-# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
+-#
+-# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
+-# created by `make install' are always world readable, even if the
+-# installer happens to have an overly restrictive umask (e.g. 077).
+-# This was a mistake. There are at least two reasons why we must not
+-# use `-m 0755':
+-# - it causes special bits like SGID to be ignored,
+-# - it may be too restrictive (some setups expect 775 directories).
+-#
+-# Do not use -m 0755 and let people choose whatever they expect by
+-# setting umask.
+-#
+-# We cannot accept any implementation of `mkdir' that recognizes `-p'.
+-# Some implementations (such as Solaris 8's) are not thread-safe: if a
+-# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
+-# concurrently, both version can detect that a/ is missing, but only
+-# one can create it and the other will error out. Consequently we
+-# restrict ourselves to GNU make (using the --version option ensures
+-# this.)
++# Check for `mkdir -p'.
+ AC_DEFUN([AM_PROG_MKDIR_P],
+-[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+- # We used to keeping the `.' as first argument, in order to
+- # allow $(mkdir_p) to be used without argument. As in
+- # $(mkdir_p) $(somedir)
+- # where $(somedir) is conditionally defined. However this is wrong
+- # for two reasons:
+- # 1. if the package is installed by a user who cannot write `.'
+- # make install will fail,
+- # 2. the above comment should most certainly read
+- # $(mkdir_p) $(DESTDIR)$(somedir)
+- # so it does not work when $(somedir) is undefined and
+- # $(DESTDIR) is not.
+- # To support the latter case, we have to write
+- # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+- # so the `.' trick is pointless.
+- mkdir_p='mkdir -p --'
+-else
+- # On NextStep and OpenStep, the `mkdir' command does not
+- # recognize any option. It will interpret all options as
+- # directories to create, and then abort because `.' already
+- # exists.
+- for d in ./-p ./--version;
+- do
+- test -d $d && rmdir $d
+- done
+- # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+- if test -f "$ac_aux_dir/mkinstalldirs"; then
+- mkdir_p='$(mkinstalldirs)'
+- else
+- mkdir_p='$(install_sh) -d'
+- fi
+-fi
+-AC_SUBST([mkdir_p])])
++[AC_PREREQ([2.60])dnl
++AC_REQUIRE([AC_PROG_MKDIR_P])dnl
++dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
++dnl while keeping a definition of mkdir_p for backward compatibility.
++dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
++dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
++dnl Makefile.ins that do not define MKDIR_P, so we do our own
++dnl adjustment using top_builddir (which is defined more often than
++dnl MKDIR_P).
++AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
++case $mkdir_p in
++ [[\\/$]]* | ?:[[\\/]]*) ;;
++ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
++esac
++])
+
+ # Helper functions for option handling. -*- Autoconf -*-
+
+-# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
++# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc.
+ #
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+
+-# serial 3
++# serial 4
+
+ # _AM_MANGLE_OPTION(NAME)
+ # -----------------------
+@@ -821,7 +891,7 @@
+ # ----------------------------------
+ # OPTIONS is a space-separated list of Automake options.
+ AC_DEFUN([_AM_SET_OPTIONS],
+-[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
++[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+ # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+ # -------------------------------------------
+@@ -831,14 +901,14 @@
+
+ # Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+-# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
++# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
+ # Free Software Foundation, Inc.
+ #
+ # This file is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+
+-# serial 4
++# serial 5
+
+ # AM_SANITY_CHECK
+ # ---------------
+@@ -847,16 +917,29 @@
+ # Just in case
+ sleep 1
+ echo timestamp > conftest.file
++# Reject unsafe characters in $srcdir or the absolute working directory
++# name. Accept space and tab only in the latter.
++am_lf='
++'
++case `pwd` in
++ *[[\\\"\#\$\&\'\`$am_lf]]*)
++ AC_MSG_ERROR([unsafe absolute working directory name]);;
++esac
++case $srcdir in
++ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
++ AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);;
++esac
++
+ # Do `set' in a subshell so we don't clobber the current shell's
+ # arguments. Must try -L first in case configure is actually a
+ # symlink; some systems play weird games with the mod time of symlinks
+ # (eg FreeBSD returns the mod time of the symlink's containing
+ # directory).
+ if (
+- set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
++ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+- set X `ls -t $srcdir/configure conftest.file`
++ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+@@ -906,9 +989,28 @@
+ if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+ fi
+-INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
++INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+ AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
++# Copyright (C) 2006, 2008 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# serial 2
++
++# _AM_SUBST_NOTMAKE(VARIABLE)
++# ---------------------------
++# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
++# This macro is traced by Automake.
++AC_DEFUN([_AM_SUBST_NOTMAKE])
++
++# AM_SUBST_NOTMAKE(VARIABLE)
++# ---------------------------
++# Public sister of _AM_SUBST_NOTMAKE.
++AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
++
+ # Check how to create a tarball. -*- Autoconf -*-
+
+ # Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+diff -Nur exmap-console-0.4.1.orig/configure exmap-console-0.4.1/configure
+--- exmap-console-0.4.1.orig/configure 2007-02-26 12:44:00.000000000 +0100
++++ exmap-console-0.4.1/configure 2011-01-11 12:44:16.000000000 +0100
+@@ -1,58 +1,85 @@
+ #! /bin/sh
+ # Guess values for system-dependent variables and create Makefiles.
+-# Generated by GNU Autoconf 2.60 for exmap-console 0.4.1.
++# Generated by GNU Autoconf 2.68 for exmap-console 0.4.1.
+ #
+ # Report bugs to <tf@o-hand.com>.
+ #
++#
+ # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+-# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
++# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
++# Foundation, Inc.
++#
++#
+ # This configure script is free software; the Free Software Foundation
+ # gives unlimited permission to copy, distribute and modify it.
+-## --------------------- ##
+-## M4sh Initialization. ##
+-## --------------------- ##
++## -------------------- ##
++## M4sh Initialization. ##
++## -------------------- ##
+
+-# Be Bourne compatible
+-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
++# Be more Bourne compatible
++DUALCASE=1; export DUALCASE # for MKS sh
++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+- # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+ else
+- case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
++ case `(set -o) 2>/dev/null` in #(
++ *posix*) :
++ set -o posix ;; #(
++ *) :
++ ;;
++esac
+ fi
+-BIN_SH=xpg4; export BIN_SH # for Tru64
+-DUALCASE=1; export DUALCASE # for MKS sh
+-
+
+-# PATH needs CR
+-# Avoid depending upon Character Ranges.
+-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+-as_cr_digits='0123456789'
+-as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+-# The user is always right.
+-if test "${PATH_SEPARATOR+set}" != set; then
+- echo "#! /bin/sh" >conf$$.sh
+- echo "exit 0" >>conf$$.sh
+- chmod +x conf$$.sh
+- if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+- PATH_SEPARATOR=';'
++as_nl='
++'
++export as_nl
++# Printing a long string crashes Solaris 7 /usr/bin/printf.
++as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
++# Prefer a ksh shell builtin over an external printf program on Solaris,
++# but without wasting forks for bash or zsh.
++if test -z "$BASH_VERSION$ZSH_VERSION" \
++ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
++ as_echo='print -r --'
++ as_echo_n='print -rn --'
++elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
++ as_echo='printf %s\n'
++ as_echo_n='printf %s'
++else
++ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
++ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
++ as_echo_n='/usr/ucb/echo -n'
+ else
+- PATH_SEPARATOR=:
++ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
++ as_echo_n_body='eval
++ arg=$1;
++ case $arg in #(
++ *"$as_nl"*)
++ expr "X$arg" : "X\\(.*\\)$as_nl";
++ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
++ esac;
++ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
++ '
++ export as_echo_n_body
++ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+- rm -f conf$$.sh
++ export as_echo_body
++ as_echo='sh -c $as_echo_body as_echo'
+ fi
+
+-# Support unset when possible.
+-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+- as_unset=unset
+-else
+- as_unset=false
++# The user is always right.
++if test "${PATH_SEPARATOR+set}" != set; then
++ PATH_SEPARATOR=:
++ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
++ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
++ PATH_SEPARATOR=';'
++ }
+ fi
+
+
+@@ -61,20 +88,19 @@
+ # there to prevent editors from complaining about space-tab.
+ # (If _AS_PATH_WALK were called with IFS unset, it would disable word
+ # splitting by setting IFS to empty value.)
+-as_nl='
+-'
+ IFS=" "" $as_nl"
+
+ # Find who we are. Look in the path if we contain no directory separator.
+-case $0 in
++as_myself=
++case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+ for as_dir in $PATH
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+-done
++ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
++ done
+ IFS=$as_save_IFS
+
+ ;;
+@@ -85,352 +111,328 @@
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+- echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+- { (exit 1); exit 1; }
++ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
++ exit 1
+ fi
+
+-# Work around bugs in pre-3.0 UWIN ksh.
+-for as_var in ENV MAIL MAILPATH
+-do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
++# Unset variables that we do not need and which cause bugs (e.g. in
++# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
++# suppresses any "Segmentation fault" message there. '((' could
++# trigger a bug in pdksh 5.2.14.
++for as_var in BASH_ENV ENV MAIL MAILPATH
++do eval test x\${$as_var+set} = xset \
++ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+ done
+ PS1='$ '
+ PS2='> '
+ PS4='+ '
+
+ # NLS nuisances.
+-for as_var in \
+- LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+- LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+- LC_TELEPHONE LC_TIME
+-do
+- if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+- eval $as_var=C; export $as_var
+- else
+- ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+- fi
+-done
+-
+-# Required to use basename.
+-if expr a : '\(a\)' >/dev/null 2>&1 &&
+- test "X`expr 00001 : '.*\(...\)'`" = X001; then
+- as_expr=expr
+-else
+- as_expr=false
+-fi
+-
+-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+- as_basename=basename
+-else
+- as_basename=false
+-fi
+-
+-
+-# Name of the executable.
+-as_me=`$as_basename -- "$0" ||
+-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+- X"$0" : 'X\(//\)$' \| \
+- X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+-echo X/"$0" |
+- sed '/^.*\/\([^/][^/]*\)\/*$/{
+- s//\1/
+- q
+- }
+- /^X\/\(\/\/\)$/{
+- s//\1/
+- q
+- }
+- /^X\/\(\/\).*/{
+- s//\1/
+- q
+- }
+- s/.*/./; q'`
++LC_ALL=C
++export LC_ALL
++LANGUAGE=C
++export LANGUAGE
+
+ # CDPATH.
+-$as_unset CDPATH
+-
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+ if test "x$CONFIG_SHELL" = x; then
+- if (eval ":") 2>/dev/null; then
+- as_have_required=yes
++ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
++ emulate sh
++ NULLCMD=:
++ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
++ # is contrary to our usage. Disable this feature.
++ alias -g '\${1+\"\$@\"}'='\"\$@\"'
++ setopt NO_GLOB_SUBST
+ else
+- as_have_required=no
++ case \`(set -o) 2>/dev/null\` in #(
++ *posix*) :
++ set -o posix ;; #(
++ *) :
++ ;;
++esac
+ fi
+-
+- if test $as_have_required = yes && (eval ":
+-(as_func_return () {
+- (exit \$1)
+-}
+-as_func_success () {
+- as_func_return 0
+-}
+-as_func_failure () {
+- as_func_return 1
+-}
+-as_func_ret_success () {
+- return 0
+-}
+-as_func_ret_failure () {
+- return 1
+-}
++"
++ as_required="as_fn_return () { (exit \$1); }
++as_fn_success () { as_fn_return 0; }
++as_fn_failure () { as_fn_return 1; }
++as_fn_ret_success () { return 0; }
++as_fn_ret_failure () { return 1; }
+
+ exitcode=0
+-if as_func_success; then
+- :
+-else
+- exitcode=1
+- echo as_func_success failed.
+-fi
+-
+-if as_func_failure; then
+- exitcode=1
+- echo as_func_failure succeeded.
+-fi
++as_fn_success || { exitcode=1; echo as_fn_success failed.; }
++as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
++as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
++as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
++if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+-if as_func_ret_success; then
+- :
+ else
+- exitcode=1
+- echo as_func_ret_success failed.
+-fi
+-
+-if as_func_ret_failure; then
+- exitcode=1
+- echo as_func_ret_failure succeeded.
+-fi
+-
+-if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+- :
++ exitcode=1; echo positional parameters were not saved.
++fi
++test x\$exitcode = x0 || exit 1"
++ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
++ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
++ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
++ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
++ if (eval "$as_required") 2>/dev/null; then :
++ as_have_required=yes
+ else
+- exitcode=1
+- echo positional parameters were not saved.
++ as_have_required=no
+ fi
++ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+-test \$exitcode = 0) || { (exit 1); exit 1; }
+-
+-(
+- as_lineno_1=\$LINENO
+- as_lineno_2=\$LINENO
+- test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+- test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+-") 2> /dev/null; then
+- :
+-else
+- as_candidate_shells=
+- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+-for as_dir in /usr/bin/posix$PATH_SEPARATOR/bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
++else
++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++as_found=false
++for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- case $as_dir in
++ as_found=:
++ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+- as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
++ # Try only shells that exist, to save several forks.
++ as_shell=$as_dir/$as_base
++ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
++ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
++ CONFIG_SHELL=$as_shell as_have_required=yes
++ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
++ break 2
++fi
++fi
+ done;;
+ esac
++ as_found=false
+ done
++$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
++ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
++ CONFIG_SHELL=$SHELL as_have_required=yes
++fi; }
+ IFS=$as_save_IFS
+
+
+- for as_shell in $as_candidate_shells $SHELL; do
+- # Try only shells that exist, to save several forks.
+- if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+- { ("$as_shell") 2> /dev/null <<\_ASEOF
+-# Be Bourne compatible
+-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+- emulate sh
+- NULLCMD=:
+- # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+- # is contrary to our usage. Disable this feature.
+- alias -g '${1+"$@"}'='"$@"'
+- setopt NO_GLOB_SUBST
+-else
+- case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+-fi
+-BIN_SH=xpg4; export BIN_SH # for Tru64
+-DUALCASE=1; export DUALCASE # for MKS sh
+-
+-:
+-_ASEOF
+-}; then
+- CONFIG_SHELL=$as_shell
+- as_have_required=yes
+- if { "$as_shell" 2> /dev/null <<\_ASEOF
+-# Be Bourne compatible
+-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+- emulate sh
+- NULLCMD=:
+- # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+- # is contrary to our usage. Disable this feature.
+- alias -g '${1+"$@"}'='"$@"'
+- setopt NO_GLOB_SUBST
+-else
+- case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+-fi
+-BIN_SH=xpg4; export BIN_SH # for Tru64
+-DUALCASE=1; export DUALCASE # for MKS sh
+-
+-:
+-(as_func_return () {
+- (exit $1)
+-}
+-as_func_success () {
+- as_func_return 0
+-}
+-as_func_failure () {
+- as_func_return 1
+-}
+-as_func_ret_success () {
+- return 0
+-}
+-as_func_ret_failure () {
+- return 1
+-}
+-
+-exitcode=0
+-if as_func_success; then
+- :
+-else
+- exitcode=1
+- echo as_func_success failed.
+-fi
+-
+-if as_func_failure; then
+- exitcode=1
+- echo as_func_failure succeeded.
+-fi
+-
+-if as_func_ret_success; then
+- :
+-else
+- exitcode=1
+- echo as_func_ret_success failed.
+-fi
+-
+-if as_func_ret_failure; then
+- exitcode=1
+- echo as_func_ret_failure succeeded.
+-fi
+-
+-if ( set x; as_func_ret_success y && test x = "$1" ); then
+- :
+-else
+- exitcode=1
+- echo positional parameters were not saved.
++ if test "x$CONFIG_SHELL" != x; then :
++ # We cannot yet assume a decent shell, so we have to provide a
++ # neutralization value for shells without unset; and this also
++ # works around shells that cannot unset nonexistent variables.
++ # Preserve -v and -x to the replacement shell.
++ BASH_ENV=/dev/null
++ ENV=/dev/null
++ (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
++ export CONFIG_SHELL
++ case $- in # ((((
++ *v*x* | *x*v* ) as_opts=-vx ;;
++ *v* ) as_opts=-v ;;
++ *x* ) as_opts=-x ;;
++ * ) as_opts= ;;
++ esac
++ exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+ fi
+
+-test $exitcode = 0) || { (exit 1); exit 1; }
+-
+-(
+- as_lineno_1=$LINENO
+- as_lineno_2=$LINENO
+- test "x$as_lineno_1" != "x$as_lineno_2" &&
+- test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+-
+-_ASEOF
+-}; then
+- break
++ if test x$as_have_required = xno; then :
++ $as_echo "$0: This script requires a shell more modern than all"
++ $as_echo "$0: the shells that I found on your system."
++ if test x${ZSH_VERSION+set} = xset ; then
++ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
++ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
++ else
++ $as_echo "$0: Please tell bug-autoconf@gnu.org and tf@o-hand.com
++$0: about your system, including any error possibly output
++$0: before this message. Then install a modern shell, or
++$0: manually run the script under such a shell if you do
++$0: have one."
++ fi
++ exit 1
+ fi
+-
+ fi
+-
+- done
+-
+- if test "x$CONFIG_SHELL" != x; then
+- for as_var in BASH_ENV ENV
+- do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+- done
+- export CONFIG_SHELL
+- exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+ fi
++SHELL=${CONFIG_SHELL-/bin/sh}
++export SHELL
++# Unset more variables known to interfere with behavior of common tools.
++CLICOLOR_FORCE= GREP_OPTIONS=
++unset CLICOLOR_FORCE GREP_OPTIONS
+
++## --------------------- ##
++## M4sh Shell Functions. ##
++## --------------------- ##
++# as_fn_unset VAR
++# ---------------
++# Portably unset VAR.
++as_fn_unset ()
++{
++ { eval $1=; unset $1;}
++}
++as_unset=as_fn_unset
+
+- if test $as_have_required = no; then
+- echo This script requires a shell more modern than all the
+- echo shells that I found on your system. Please install a
+- echo modern shell, or manually run the script under such a
+- echo shell if you do have one.
+- { (exit 1); exit 1; }
+-fi
++# as_fn_set_status STATUS
++# -----------------------
++# Set $? to STATUS, without forking.
++as_fn_set_status ()
++{
++ return $1
++} # as_fn_set_status
+
++# as_fn_exit STATUS
++# -----------------
++# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
++as_fn_exit ()
++{
++ set +e
++ as_fn_set_status $1
++ exit $1
++} # as_fn_exit
++
++# as_fn_mkdir_p
++# -------------
++# Create "$as_dir" as a directory, including parents if necessary.
++as_fn_mkdir_p ()
++{
+
+-fi
++ case $as_dir in #(
++ -*) as_dir=./$as_dir;;
++ esac
++ test -d "$as_dir" || eval $as_mkdir_p || {
++ as_dirs=
++ while :; do
++ case $as_dir in #(
++ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
++ *) as_qdir=$as_dir;;
++ esac
++ as_dirs="'$as_qdir' $as_dirs"
++ as_dir=`$as_dirname -- "$as_dir" ||
++$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$as_dir" : 'X\(//\)[^/]' \| \
++ X"$as_dir" : 'X\(//\)$' \| \
++ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X"$as_dir" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++ test -d "$as_dir" && break
++ done
++ test -z "$as_dirs" || eval "mkdir $as_dirs"
++ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+-fi
+
++} # as_fn_mkdir_p
++# as_fn_append VAR VALUE
++# ----------------------
++# Append the text in VALUE to the end of the definition contained in VAR. Take
++# advantage of any shell optimizations that allow amortized linear growth over
++# repeated appends, instead of the typical quadratic growth present in naive
++# implementations.
++if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
++ eval 'as_fn_append ()
++ {
++ eval $1+=\$2
++ }'
++else
++ as_fn_append ()
++ {
++ eval $1=\$$1\$2
++ }
++fi # as_fn_append
++
++# as_fn_arith ARG...
++# ------------------
++# Perform arithmetic evaluation on the ARGs, and store the result in the
++# global $as_val. Take advantage of shells that can avoid forks. The arguments
++# must be portable across $(()) and expr.
++if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
++ eval 'as_fn_arith ()
++ {
++ as_val=$(( $* ))
++ }'
++else
++ as_fn_arith ()
++ {
++ as_val=`expr "$@" || test $? -eq 1`
++ }
++fi # as_fn_arith
+
+
+-(eval "as_func_return () {
+- (exit \$1)
+-}
+-as_func_success () {
+- as_func_return 0
+-}
+-as_func_failure () {
+- as_func_return 1
+-}
+-as_func_ret_success () {
+- return 0
+-}
+-as_func_ret_failure () {
+- return 1
+-}
++# as_fn_error STATUS ERROR [LINENO LOG_FD]
++# ----------------------------------------
++# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
++# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
++# script with STATUS, using 1 if that was 0.
++as_fn_error ()
++{
++ as_status=$1; test $as_status -eq 0 && as_status=1
++ if test "$4"; then
++ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
++ fi
++ $as_echo "$as_me: error: $2" >&2
++ as_fn_exit $as_status
++} # as_fn_error
+
+-exitcode=0
+-if as_func_success; then
+- :
++if expr a : '\(a\)' >/dev/null 2>&1 &&
++ test "X`expr 00001 : '.*\(...\)'`" = X001; then
++ as_expr=expr
+ else
+- exitcode=1
+- echo as_func_success failed.
+-fi
+-
+-if as_func_failure; then
+- exitcode=1
+- echo as_func_failure succeeded.
++ as_expr=false
+ fi
+
+-if as_func_ret_success; then
+- :
++if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
++ as_basename=basename
+ else
+- exitcode=1
+- echo as_func_ret_success failed.
+-fi
+-
+-if as_func_ret_failure; then
+- exitcode=1
+- echo as_func_ret_failure succeeded.
++ as_basename=false
+ fi
+
+-if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+- :
++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
++ as_dirname=dirname
+ else
+- exitcode=1
+- echo positional parameters were not saved.
++ as_dirname=false
+ fi
+
+-test \$exitcode = 0") || {
+- echo No shell found that supports shell functions.
+- echo Please tell autoconf@gnu.org about your system,
+- echo including any error possibly output before this
+- echo message
+-}
++as_me=`$as_basename -- "$0" ||
++$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
++ X"$0" : 'X\(//\)$' \| \
++ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X/"$0" |
++ sed '/^.*\/\([^/][^/]*\)\/*$/{
++ s//\1/
++ q
++ }
++ /^X\/\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\/\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
+
++# Avoid depending upon Character Ranges.
++as_cr_letters='abcdefghijklmnopqrstuvwxyz'
++as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
++as_cr_Letters=$as_cr_letters$as_cr_LETTERS
++as_cr_digits='0123456789'
++as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+- as_lineno_1=$LINENO
+- as_lineno_2=$LINENO
+- test "x$as_lineno_1" != "x$as_lineno_2" &&
+- test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+-
+- # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+- # uniformly replaced by the line number. The first 'sed' inserts a
+- # line-number line after each line using $LINENO; the second 'sed'
+- # does the real work. The second script uses 'N' to pair each
+- # line-number line with the line containing $LINENO, and appends
+- # trailing '-' during substitution so that $LINENO is not a special
+- # case at line end.
+- # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+- # scripts with optimization help from Paolo Bonzini. Blame Lee
+- # E. McMahon (1931-1989) for sed's syntax. :-)
++ as_lineno_1=$LINENO as_lineno_1a=$LINENO
++ as_lineno_2=$LINENO as_lineno_2a=$LINENO
++ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
++ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
++ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+@@ -447,8 +449,7 @@
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+- { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+- { (exit 1); exit 1; }; }
++ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+@@ -458,49 +459,40 @@
+ exit
+ }
+
+-
+-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+- as_dirname=dirname
+-else
+- as_dirname=false
+-fi
+-
+ ECHO_C= ECHO_N= ECHO_T=
+-case `echo -n x` in
++case `echo -n x` in #(((((
+ -n*)
+- case `echo 'x\c'` in
++ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+- *) ECHO_C='\c';;
++ xy) ECHO_C='\c';;
++ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
++ ECHO_T=' ';;
+ esac;;
+ *)
+ ECHO_N='-n';;
+ esac
+
+-if expr a : '\(a\)' >/dev/null 2>&1 &&
+- test "X`expr 00001 : '.*\(...\)'`" = X001; then
+- as_expr=expr
+-else
+- as_expr=false
+-fi
+-
+ rm -f conf$$ conf$$.exe conf$$.file
+ if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+ else
+ rm -f conf$$.dir
+- mkdir conf$$.dir
++ mkdir conf$$.dir 2>/dev/null
+ fi
+-echo >conf$$.file
+-if ln -s conf$$.file conf$$ 2>/dev/null; then
+- as_ln_s='ln -s'
+- # ... but there are two gotchas:
+- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+- # In both cases, we have to default to `cp -p'.
+- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
++if (echo >conf$$.file) 2>/dev/null; then
++ if ln -s conf$$.file conf$$ 2>/dev/null; then
++ as_ln_s='ln -s'
++ # ... but there are two gotchas:
++ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
++ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
++ # In both cases, we have to default to `cp -p'.
++ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
++ as_ln_s='cp -p'
++ elif ln conf$$.file conf$$ 2>/dev/null; then
++ as_ln_s=ln
++ else
+ as_ln_s='cp -p'
+-elif ln conf$$.file conf$$ 2>/dev/null; then
+- as_ln_s=ln
++ fi
+ else
+ as_ln_s='cp -p'
+ fi
+@@ -508,25 +500,34 @@
+ rmdir conf$$.dir 2>/dev/null
+
+ if mkdir -p . 2>/dev/null; then
+- as_mkdir_p=:
++ as_mkdir_p='mkdir -p "$as_dir"'
+ else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+ fi
+
+-# Find out whether ``test -x'' works. Don't use a zero-byte file, as
+-# systems may use methods other than mode bits to determine executability.
+-cat >conf$$.file <<_ASEOF
+-#! /bin/sh
+-exit 0
+-_ASEOF
+-chmod +x conf$$.file
+-if test -x conf$$.file >/dev/null 2>&1; then
+- as_executable_p="test -x"
++if test -x / >/dev/null 2>&1; then
++ as_test_x='test -x'
+ else
+- as_executable_p=:
++ if ls -dL / >/dev/null 2>&1; then
++ as_ls_L_option=L
++ else
++ as_ls_L_option=
++ fi
++ as_test_x='
++ eval sh -c '\''
++ if test -d "$1"; then
++ test -d "$1/.";
++ else
++ case $1 in #(
++ -*)set "./$1";;
++ esac;
++ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
++ ???[sx]*):;;*)false;;esac;fi
++ '\'' sh
++ '
+ fi
+-rm -f conf$$.file
++as_executable_p=$as_test_x
+
+ # Sed expression to map a string onto a valid CPP name.
+ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+@@ -535,11 +536,11 @@
+ as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+-
+-exec 7<&0 </dev/null 6>&1
++test -n "$DJDIR" || exec 7<&0 </dev/null
++exec 6>&1
+
+ # Name of the host.
+-# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
++# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+ # so uname gets run too.
+ ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+@@ -554,7 +555,6 @@
+ subdirs=
+ MFLAGS=
+ MAKEFLAGS=
+-SHELL=${CONFIG_SHELL-/bin/sh}
+
+ # Identity of this package.
+ PACKAGE_NAME='exmap-console'
+@@ -562,106 +562,128 @@
+ PACKAGE_VERSION='0.4.1'
+ PACKAGE_STRING='exmap-console 0.4.1'
+ PACKAGE_BUGREPORT='tf@o-hand.com'
++PACKAGE_URL=''
+
+ ac_unique_file="src/exmap.c"
+-ac_subst_vars='SHELL
+-PATH_SEPARATOR
+-PACKAGE_NAME
+-PACKAGE_TARNAME
+-PACKAGE_VERSION
+-PACKAGE_STRING
+-PACKAGE_BUGREPORT
+-exec_prefix
+-prefix
+-program_transform_name
+-bindir
+-sbindir
+-libexecdir
+-datarootdir
+-datadir
+-sysconfdir
+-sharedstatedir
+-localstatedir
+-includedir
+-oldincludedir
+-docdir
+-infodir
+-htmldir
+-dvidir
+-pdfdir
+-psdir
+-libdir
+-localedir
+-mandir
+-DEFS
+-ECHO_C
+-ECHO_N
+-ECHO_T
+-LIBS
++ac_subst_vars='am__EXEEXT_FALSE
++am__EXEEXT_TRUE
++LTLIBOBJS
++LIBOBJS
++GCC_CFLAGS
++HAVE_HELPTOMAN_FALSE
++HAVE_HELPTOMAN_TRUE
++HELPTOMAN
++GLIB_LIBS
++GLIB_CFLAGS
++PKG_CONFIG_LIBDIR
++PKG_CONFIG_PATH
++PKG_CONFIG
++DODOCS_FALSE
++DODOCS_TRUE
++READLINE_CFLAGS
++READLINE_LIBS
++INTERACTIVE_FALSE
++INTERACTIVE_TRUE
++am__fastdepCC_FALSE
++am__fastdepCC_TRUE
++CCDEPMODE
++AMDEPBACKSLASH
++AMDEP_FALSE
++AMDEP_TRUE
++am__quote
++am__include
++DEPDIR
++OBJEXT
++EXEEXT
++ac_ct_CC
++CPPFLAGS
++LDFLAGS
++CFLAGS
++CC
++am__untar
++am__tar
++AMTAR
++am__leading_dot
++SET_MAKE
++AWK
++mkdir_p
++MKDIR_P
++INSTALL_STRIP_PROGRAM
++STRIP
++install_sh
++MAKEINFO
++AUTOHEADER
++AUTOMAKE
++AUTOCONF
++ACLOCAL
++VERSION
++PACKAGE
++CYGPATH_W
++am__isrc
++INSTALL_DATA
++INSTALL_SCRIPT
++INSTALL_PROGRAM
++target_alias
++host_alias
+ build_alias
++LIBS
++ECHO_T
++ECHO_N
++ECHO_C
++DEFS
++mandir
++localedir
++libdir
++psdir
++pdfdir
++dvidir
++htmldir
++infodir
++docdir
++oldincludedir
++includedir
++localstatedir
++sharedstatedir
++sysconfdir
++datadir
++datarootdir
++libexecdir
++sbindir
++bindir
++program_transform_name
++prefix
++exec_prefix
++PACKAGE_URL
++PACKAGE_BUGREPORT
++PACKAGE_STRING
++PACKAGE_VERSION
++PACKAGE_TARNAME
++PACKAGE_NAME
++PATH_SEPARATOR
++SHELL'
++ac_subst_files=''
++ac_user_opts='
++enable_option_checking
++with_readline
++enable_dependency_tracking
++enable_doc
++with_help2man
++'
++ ac_precious_vars='build_alias
+ host_alias
+ target_alias
+-INSTALL_PROGRAM
+-INSTALL_SCRIPT
+-INSTALL_DATA
+-CYGPATH_W
+-PACKAGE
+-VERSION
+-ACLOCAL
+-AUTOCONF
+-AUTOMAKE
+-AUTOHEADER
+-MAKEINFO
+-install_sh
+-STRIP
+-INSTALL_STRIP_PROGRAM
+-mkdir_p
+-AWK
+-SET_MAKE
+-am__leading_dot
+-AMTAR
+-am__tar
+-am__untar
+ CC
+ CFLAGS
+ LDFLAGS
++LIBS
+ CPPFLAGS
+-ac_ct_CC
+-EXEEXT
+-OBJEXT
+-DEPDIR
+-am__include
+-am__quote
+-AMDEP_TRUE
+-AMDEP_FALSE
+-AMDEPBACKSLASH
+-CCDEPMODE
+-am__fastdepCC_TRUE
+-am__fastdepCC_FALSE
+-INTERACTIVE_TRUE
+-INTERACTIVE_FALSE
+-READLINE_LIBS
+-READLINE_CFLAGS
+-DODOCS_TRUE
+-DODOCS_FALSE
+-PKG_CONFIG
+-GLIB_CFLAGS
+-GLIB_LIBS
+-HELPTOMAN
+-HAVE_HELPTOMAN_TRUE
+-HAVE_HELPTOMAN_FALSE
+-GCC_CFLAGS
+-LIBOBJS
+-LTLIBOBJS'
+-ac_subst_files=''
+- ac_precious_vars='build_alias
+-host_alias
+-target_alias
+ CC
+-CFLAGS
+ LDFLAGS
++LIBS
+ CPPFLAGS
+ PKG_CONFIG
++PKG_CONFIG_PATH
++PKG_CONFIG_LIBDIR
+ GLIB_CFLAGS
+ GLIB_LIBS'
+
+@@ -669,6 +691,8 @@
+ # Initialize some variables set by options.
+ ac_init_help=
+ ac_init_version=false
++ac_unrecognized_opts=
++ac_unrecognized_sep=
+ # The variables have the same names as the options, with
+ # dashes changed to underlines.
+ cache_file=/dev/null
+@@ -724,8 +748,9 @@
+ fi
+
+ case $ac_option in
+- *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+- *) ac_optarg=yes ;;
++ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
++ *=) ac_optarg= ;;
++ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+@@ -767,13 +792,20 @@
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+- ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
++ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+- expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+- { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+- { (exit 1); exit 1; }; }
+- ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+- eval enable_$ac_feature=no ;;
++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
++ as_fn_error $? "invalid feature name: $ac_useropt"
++ ac_useropt_orig=$ac_useropt
++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
++ case $ac_user_opts in
++ *"
++"enable_$ac_useropt"
++"*) ;;
++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
++ ac_unrecognized_sep=', ';;
++ esac
++ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+@@ -786,13 +818,20 @@
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+- ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
++ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+- expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+- { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+- { (exit 1); exit 1; }; }
+- ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+- eval enable_$ac_feature=\$ac_optarg ;;
++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
++ as_fn_error $? "invalid feature name: $ac_useropt"
++ ac_useropt_orig=$ac_useropt
++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
++ case $ac_user_opts in
++ *"
++"enable_$ac_useropt"
++"*) ;;
++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
++ ac_unrecognized_sep=', ';;
++ esac
++ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+@@ -983,22 +1022,36 @@
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+- ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
++ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+- expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+- { echo "$as_me: error: invalid package name: $ac_package" >&2
+- { (exit 1); exit 1; }; }
+- ac_package=`echo $ac_package| sed 's/-/_/g'`
+- eval with_$ac_package=\$ac_optarg ;;
++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
++ as_fn_error $? "invalid package name: $ac_useropt"
++ ac_useropt_orig=$ac_useropt
++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
++ case $ac_user_opts in
++ *"
++"with_$ac_useropt"
++"*) ;;
++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
++ ac_unrecognized_sep=', ';;
++ esac
++ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+- ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
++ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+- expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+- { echo "$as_me: error: invalid package name: $ac_package" >&2
+- { (exit 1); exit 1; }; }
+- ac_package=`echo $ac_package | sed 's/-/_/g'`
+- eval with_$ac_package=no ;;
++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
++ as_fn_error $? "invalid package name: $ac_useropt"
++ ac_useropt_orig=$ac_useropt
++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
++ case $ac_user_opts in
++ *"
++"with_$ac_useropt"
++"*) ;;
++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
++ ac_unrecognized_sep=', ';;
++ esac
++ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+@@ -1018,26 +1071,26 @@
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+- -*) { echo "$as_me: error: unrecognized option: $ac_option
+-Try \`$0 --help' for more information." >&2
+- { (exit 1); exit 1; }; }
++ -*) as_fn_error $? "unrecognized option: \`$ac_option'
++Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+- expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+- { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+- { (exit 1); exit 1; }; }
++ case $ac_envvar in #(
++ '' | [0-9]* | *[!_$as_cr_alnum]* )
++ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
++ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+- echo "$as_me: WARNING: you should use --build, --host, --target" >&2
++ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+- echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+- : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
++ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
++ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+@@ -1045,23 +1098,36 @@
+
+ if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+- { echo "$as_me: error: missing argument to $ac_option" >&2
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "missing argument to $ac_option"
+ fi
+
+-# Be sure to have absolute directory names.
++if test -n "$ac_unrecognized_opts"; then
++ case $enable_option_checking in
++ no) ;;
++ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
++ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
++ esac
++fi
++
++# Check all directory arguments for consistency.
+ for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+ do
+ eval ac_val=\$$ac_var
++ # Remove trailing slashes.
++ case $ac_val in
++ */ )
++ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
++ eval $ac_var=\$ac_val;;
++ esac
++ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+- { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+ done
+
+ # There might be people who depend on the old broken behavior: `$host'
+@@ -1075,8 +1141,8 @@
+ if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+- echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+- If a cross compiler is detected then cross compile mode will be used." >&2
++ $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
++ If a cross compiler is detected then cross compile mode will be used" >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+@@ -1091,23 +1157,21 @@
+ ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ ac_ls_di=`ls -di .` &&
+ ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+- { echo "$as_me: error: Working directory cannot be determined" >&2
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "working directory cannot be determined"
+ test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+- { echo "$as_me: error: pwd does not report name of working directory" >&2
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "pwd does not report name of working directory"
+
+
+ # Find the source files, if location was not specified.
+ if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+- ac_confdir=`$as_dirname -- "$0" ||
+-$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+- X"$0" : 'X\(//\)[^/]' \| \
+- X"$0" : 'X\(//\)$' \| \
+- X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+-echo X"$0" |
++ ac_confdir=`$as_dirname -- "$as_myself" ||
++$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$as_myself" : 'X\(//\)[^/]' \| \
++ X"$as_myself" : 'X\(//\)$' \| \
++ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+@@ -1134,13 +1198,11 @@
+ fi
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+- { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+ fi
+ ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ ac_abs_confdir=`(
+- cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2
+- { (exit 1); exit 1; }; }
++ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+ # When building in place, set srcdir=.
+ if test "$ac_abs_confdir" = "$ac_pwd"; then
+@@ -1180,7 +1242,7 @@
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+- -q, --quiet, --silent do not print \`checking...' messages
++ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+@@ -1188,9 +1250,9 @@
+
+ Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+- [$ac_default_prefix]
++ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+- [PREFIX]
++ [PREFIX]
+
+ By default, \`make install' will install all the files in
+ \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+@@ -1200,25 +1262,25 @@
+ For better control, use the options below.
+
+ Fine tuning of the installation directories:
+- --bindir=DIR user executables [EPREFIX/bin]
+- --sbindir=DIR system admin executables [EPREFIX/sbin]
+- --libexecdir=DIR program executables [EPREFIX/libexec]
+- --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+- --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+- --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+- --libdir=DIR object code libraries [EPREFIX/lib]
+- --includedir=DIR C header files [PREFIX/include]
+- --oldincludedir=DIR C header files for non-gcc [/usr/include]
+- --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+- --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+- --infodir=DIR info documentation [DATAROOTDIR/info]
+- --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+- --mandir=DIR man documentation [DATAROOTDIR/man]
+- --docdir=DIR documentation root [DATAROOTDIR/doc/exmap-console]
+- --htmldir=DIR html documentation [DOCDIR]
+- --dvidir=DIR dvi documentation [DOCDIR]
+- --pdfdir=DIR pdf documentation [DOCDIR]
+- --psdir=DIR ps documentation [DOCDIR]
++ --bindir=DIR user executables [EPREFIX/bin]
++ --sbindir=DIR system admin executables [EPREFIX/sbin]
++ --libexecdir=DIR program executables [EPREFIX/libexec]
++ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
++ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
++ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
++ --libdir=DIR object code libraries [EPREFIX/lib]
++ --includedir=DIR C header files [PREFIX/include]
++ --oldincludedir=DIR C header files for non-gcc [/usr/include]
++ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
++ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
++ --infodir=DIR info documentation [DATAROOTDIR/info]
++ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
++ --mandir=DIR man documentation [DATAROOTDIR/man]
++ --docdir=DIR documentation root [DATAROOTDIR/doc/exmap-console]
++ --htmldir=DIR html documentation [DOCDIR]
++ --dvidir=DIR dvi documentation [DOCDIR]
++ --pdfdir=DIR pdf documentation [DOCDIR]
++ --psdir=DIR ps documentation [DOCDIR]
+ _ACEOF
+
+ cat <<\_ACEOF
+@@ -1237,12 +1299,12 @@
+ cat <<\_ACEOF
+
+ Optional Features:
++ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
+ --disable-doc Do not build documentation
+- --enable-debug Enable debuggin information
+
+ Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+@@ -1255,9 +1317,14 @@
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+- CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
++ LIBS libraries to pass to the linker, e.g. -l<library>
++ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ PKG_CONFIG path to pkg-config utility
++ PKG_CONFIG_PATH
++ directories to add to pkg-config's search path
++ PKG_CONFIG_LIBDIR
++ path overriding pkg-config's built-in search path
+ GLIB_CFLAGS C compiler flags for GLIB, overriding pkg-config
+ GLIB_LIBS linker flags for GLIB, overriding pkg-config
+
+@@ -1272,15 +1339,17 @@
+ if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+- test -d "$ac_dir" || continue
++ test -d "$ac_dir" ||
++ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
++ continue
+ ac_builddir=.
+
+ case "$ac_dir" in
+ .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *)
+- ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
++ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+- ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
++ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+@@ -1316,7 +1385,7 @@
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+- echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
++ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+@@ -1326,21 +1395,108 @@
+ if $ac_init_version; then
+ cat <<\_ACEOF
+ exmap-console configure 0.4.1
+-generated by GNU Autoconf 2.60
++generated by GNU Autoconf 2.68
+
+-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+-2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
++Copyright (C) 2010 Free Software Foundation, Inc.
+ This configure script is free software; the Free Software Foundation
+ gives unlimited permission to copy, distribute and modify it.
+ _ACEOF
+ exit
+ fi
++
++## ------------------------ ##
++## Autoconf initialization. ##
++## ------------------------ ##
++
++# ac_fn_c_try_compile LINENO
++# --------------------------
++# Try to compile conftest.$ac_ext, and return whether this succeeded.
++ac_fn_c_try_compile ()
++{
++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ rm -f conftest.$ac_objext
++ if { { ac_try="$ac_compile"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_compile") 2>conftest.err
++ ac_status=$?
++ if test -s conftest.err; then
++ grep -v '^ *+' conftest.err >conftest.er1
++ cat conftest.er1 >&5
++ mv -f conftest.er1 conftest.err
++ fi
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; } && {
++ test -z "$ac_c_werror_flag" ||
++ test ! -s conftest.err
++ } && test -s conftest.$ac_objext; then :
++ ac_retval=0
++else
++ $as_echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
++
++ ac_retval=1
++fi
++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
++ as_fn_set_status $ac_retval
++
++} # ac_fn_c_try_compile
++
++# ac_fn_c_try_link LINENO
++# -----------------------
++# Try to link conftest.$ac_ext, and return whether this succeeded.
++ac_fn_c_try_link ()
++{
++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ rm -f conftest.$ac_objext conftest$ac_exeext
++ if { { ac_try="$ac_link"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_link") 2>conftest.err
++ ac_status=$?
++ if test -s conftest.err; then
++ grep -v '^ *+' conftest.err >conftest.er1
++ cat conftest.er1 >&5
++ mv -f conftest.er1 conftest.err
++ fi
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; } && {
++ test -z "$ac_c_werror_flag" ||
++ test ! -s conftest.err
++ } && test -s conftest$ac_exeext && {
++ test "$cross_compiling" = yes ||
++ $as_test_x conftest$ac_exeext
++ }; then :
++ ac_retval=0
++else
++ $as_echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
++
++ ac_retval=1
++fi
++ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
++ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
++ # interfere with the next link command; also delete a directory that is
++ # left behind by Apple's compiler. We do this before executing the actions.
++ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
++ as_fn_set_status $ac_retval
++
++} # ac_fn_c_try_link
+ cat >config.log <<_ACEOF
+ This file contains any messages produced by compilers while
+ running configure, to aid debugging if configure makes a mistake.
+
+ It was created by exmap-console $as_me 0.4.1, which was
+-generated by GNU Autoconf 2.60. Invocation command line was
++generated by GNU Autoconf 2.68. Invocation command line was
+
+ $ $0 $@
+
+@@ -1376,8 +1532,8 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- echo "PATH: $as_dir"
+-done
++ $as_echo "PATH: $as_dir"
++ done
+ IFS=$as_save_IFS
+
+ } >&5
+@@ -1411,12 +1567,12 @@
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+- ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
++ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+- 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
++ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+- ac_configure_args1="$ac_configure_args1 '$ac_arg'"
++ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+@@ -1432,13 +1588,13 @@
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+- ac_configure_args="$ac_configure_args '$ac_arg'"
++ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+ done
+-$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+-$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
++{ ac_configure_args0=; unset ac_configure_args0;}
++{ ac_configure_args1=; unset ac_configure_args1;}
+
+ # When interrupted or exit'd, cleanup temporary files, and complete
+ # config.log. We remove comments because anyway the quotes in there
+@@ -1450,11 +1606,9 @@
+ {
+ echo
+
+- cat <<\_ASBOX
+-## ---------------- ##
++ $as_echo "## ---------------- ##
+ ## Cache variables. ##
+-## ---------------- ##
+-_ASBOX
++## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+ (
+@@ -1463,12 +1617,13 @@
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+- *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+-echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
++ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
++$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+- *) $as_unset $ac_var ;;
++ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
++ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+@@ -1487,128 +1642,136 @@
+ )
+ echo
+
+- cat <<\_ASBOX
+-## ----------------- ##
++ $as_echo "## ----------------- ##
+ ## Output variables. ##
+-## ----------------- ##
+-_ASBOX
++## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+- *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
++ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+- echo "$ac_var='\''$ac_val'\''"
++ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+- cat <<\_ASBOX
+-## ------------------- ##
++ $as_echo "## ------------------- ##
+ ## File substitutions. ##
+-## ------------------- ##
+-_ASBOX
++## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+- *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
++ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+- echo "$ac_var='\''$ac_val'\''"
++ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+- cat <<\_ASBOX
+-## ----------- ##
++ $as_echo "## ----------- ##
+ ## confdefs.h. ##
+-## ----------- ##
+-_ASBOX
++## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+- echo "$as_me: caught signal $ac_signal"
+- echo "$as_me: exit $exit_status"
++ $as_echo "$as_me: caught signal $ac_signal"
++ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+ for ac_signal in 1 2 13 15; do
+- trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
++ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+ done
+ ac_signal=0
+
+ # confdefs.h avoids OS command line length limits that DEFS can exceed.
+ rm -f -r conftest* confdefs.h
+
++$as_echo "/* confdefs.h */" > confdefs.h
++
+ # Predefined preprocessor variables.
+
+ cat >>confdefs.h <<_ACEOF
+ #define PACKAGE_NAME "$PACKAGE_NAME"
+ _ACEOF
+
+-
+ cat >>confdefs.h <<_ACEOF
+ #define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+ _ACEOF
+
+-
+ cat >>confdefs.h <<_ACEOF
+ #define PACKAGE_VERSION "$PACKAGE_VERSION"
+ _ACEOF
+
+-
+ cat >>confdefs.h <<_ACEOF
+ #define PACKAGE_STRING "$PACKAGE_STRING"
+ _ACEOF
+
+-
+ cat >>confdefs.h <<_ACEOF
+ #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+ _ACEOF
+
++cat >>confdefs.h <<_ACEOF
++#define PACKAGE_URL "$PACKAGE_URL"
++_ACEOF
++
+
+ # Let the site file select an alternate cache file if it wants to.
+-# Prefer explicitly selected file to automatically selected ones.
++# Prefer an explicitly selected file to automatically selected ones.
++ac_site_file1=NONE
++ac_site_file2=NONE
+ if test -n "$CONFIG_SITE"; then
+- set x "$CONFIG_SITE"
++ # We do not want a PATH search for config.site.
++ case $CONFIG_SITE in #((
++ -*) ac_site_file1=./$CONFIG_SITE;;
++ */*) ac_site_file1=$CONFIG_SITE;;
++ *) ac_site_file1=./$CONFIG_SITE;;
++ esac
+ elif test "x$prefix" != xNONE; then
+- set x "$prefix/share/config.site" "$prefix/etc/config.site"
++ ac_site_file1=$prefix/share/config.site
++ ac_site_file2=$prefix/etc/config.site
+ else
+- set x "$ac_default_prefix/share/config.site" \
+- "$ac_default_prefix/etc/config.site"
++ ac_site_file1=$ac_default_prefix/share/config.site
++ ac_site_file2=$ac_default_prefix/etc/config.site
+ fi
+-shift
+-for ac_site_file
++for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+ do
+- if test -r "$ac_site_file"; then
+- { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+-echo "$as_me: loading site script $ac_site_file" >&6;}
++ test "x$ac_site_file" = xNONE && continue
++ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
++$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+- . "$ac_site_file"
++ . "$ac_site_file" \
++ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "failed to load site script $ac_site_file
++See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ done
+
+ if test -r "$cache_file"; then
+- # Some versions of bash will fail to source /dev/null (special
+- # files actually), so we avoid doing that.
+- if test -f "$cache_file"; then
+- { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+-echo "$as_me: loading cache $cache_file" >&6;}
++ # Some versions of bash will fail to source /dev/null (special files
++ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
++ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
++$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+ else
+- { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+-echo "$as_me: creating cache $cache_file" >&6;}
++ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
++$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+ fi
+
+@@ -1622,68 +1785,56 @@
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+- { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+-echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
++$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+- { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+-echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
++$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+- { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+-echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+- { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+-echo "$as_me: former value: $ac_old_val" >&2;}
+- { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+-echo "$as_me: current value: $ac_new_val" >&2;}
+- ac_cache_corrupted=:
++ # differences in whitespace do not lead to failure.
++ ac_old_val_w=`echo x $ac_old_val`
++ ac_new_val_w=`echo x $ac_new_val`
++ if test "$ac_old_val_w" != "$ac_new_val_w"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
++$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
++ ac_cache_corrupted=:
++ else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
++$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
++ eval $ac_var=\$ac_old_val
++ fi
++ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
++$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
++ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
++$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+- *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
++ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+- *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
++ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+ done
+ if $ac_cache_corrupted; then
+- { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+-echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+- { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+-echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+- { (exit 1); exit 1; }; }
+-fi
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
++$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
++ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
++fi
++## -------------------- ##
++## Main body of script. ##
++## -------------------- ##
+
+ ac_ext=c
+ ac_cpp='$CPP $CPPFLAGS'
+@@ -1694,7 +1845,8 @@
+
+
+
+-am__api_version="1.9"
++am__api_version='1.11'
++
+ ac_aux_dir=
+ for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+@@ -1712,9 +1864,7 @@
+ fi
+ done
+ if test -z "$ac_aux_dir"; then
+- { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+-echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+ fi
+
+ # These three variables are undocumented and unsupported,
+@@ -1739,22 +1889,23 @@
+ # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+ # OS/2's system install, which has a completely different semantic
+ # ./install, which can be erroneously created by make from ./install.sh.
+-{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+-echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }
++# Reject install programs that cannot install multiple files.
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
++$as_echo_n "checking for a BSD-compatible install... " >&6; }
+ if test -z "$INSTALL"; then
+-if test "${ac_cv_path_install+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++if ${ac_cv_path_install+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+ for as_dir in $PATH
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- # Account for people who put trailing slashes in PATH elements.
+-case $as_dir/ in
+- ./ | .// | /cC/* | \
++ # Account for people who put trailing slashes in PATH elements.
++case $as_dir/ in #((
++ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+- ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
++ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+@@ -1762,7 +1913,7 @@
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; }; then
++ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+@@ -1772,17 +1923,29 @@
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+- ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+- break 3
++ rm -rf conftest.one conftest.two conftest.dir
++ echo one > conftest.one
++ echo two > conftest.two
++ mkdir conftest.dir
++ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
++ test -s conftest.one && test -s conftest.two &&
++ test -s conftest.dir/conftest.one &&
++ test -s conftest.dir/conftest.two
++ then
++ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
++ break 3
++ fi
+ fi
+ fi
+ done
+ done
+ ;;
+ esac
+-done
++
++ done
+ IFS=$as_save_IFS
+
++rm -rf conftest.one conftest.two conftest.dir
+
+ fi
+ if test "${ac_cv_path_install+set}" = set; then
+@@ -1795,8 +1958,8 @@
+ INSTALL=$ac_install_sh
+ fi
+ fi
+-{ echo "$as_me:$LINENO: result: $INSTALL" >&5
+-echo "${ECHO_T}$INSTALL" >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
++$as_echo "$INSTALL" >&6; }
+
+ # Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+ # It thinks the first close brace ends the variable substitution.
+@@ -1806,21 +1969,34 @@
+
+ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+-{ echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+-echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
++$as_echo_n "checking whether build environment is sane... " >&6; }
+ # Just in case
+ sleep 1
+ echo timestamp > conftest.file
++# Reject unsafe characters in $srcdir or the absolute working directory
++# name. Accept space and tab only in the latter.
++am_lf='
++'
++case `pwd` in
++ *[\\\"\#\$\&\'\`$am_lf]*)
++ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
++esac
++case $srcdir in
++ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
++ as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;;
++esac
++
+ # Do `set' in a subshell so we don't clobber the current shell's
+ # arguments. Must try -L first in case configure is actually a
+ # symlink; some systems play weird games with the mod time of symlinks
+ # (eg FreeBSD returns the mod time of the symlink's containing
+ # directory).
+ if (
+- set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
++ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+- set X `ls -t $srcdir/configure conftest.file`
++ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+@@ -1830,11 +2006,8 @@
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+- { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken
+-alias in your environment" >&5
+-echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken
+-alias in your environment" >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
++alias in your environment" "$LINENO" 5
+ fi
+
+ test "$2" = conftest.file
+@@ -1843,204 +2016,50 @@
+ # Ok.
+ :
+ else
+- { { echo "$as_me:$LINENO: error: newly created file is older than distributed files!
+-Check your system clock" >&5
+-echo "$as_me: error: newly created file is older than distributed files!
+-Check your system clock" >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "newly created file is older than distributed files!
++Check your system clock" "$LINENO" 5
+ fi
+-{ echo "$as_me:$LINENO: result: yes" >&5
+-echo "${ECHO_T}yes" >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
+ test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+ # Use a double $ so make ignores it.
+ test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+-# Double any \ or $. echo might interpret backslashes.
++# Double any \ or $.
+ # By default was `s,x,x', remove it if useless.
+-cat <<\_ACEOF >conftest.sed
+-s/[\\$]/&&/g;s/;s,x,x,$//
+-_ACEOF
+-program_transform_name=`echo $program_transform_name | sed -f conftest.sed`
+-rm -f conftest.sed
++ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
++program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+ # expand $ac_aux_dir to an absolute path
+ am_aux_dir=`cd $ac_aux_dir && pwd`
+
+-test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
++if test x"${MISSING+set}" != xset; then
++ case $am_aux_dir in
++ *\ * | *\ *)
++ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
++ *)
++ MISSING="\${SHELL} $am_aux_dir/missing" ;;
++ esac
++fi
+ # Use eval to expand $SHELL
+ if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+ else
+ am_missing_run=
+- { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+-echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+-fi
+-
+-if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+- # We used to keeping the `.' as first argument, in order to
+- # allow $(mkdir_p) to be used without argument. As in
+- # $(mkdir_p) $(somedir)
+- # where $(somedir) is conditionally defined. However this is wrong
+- # for two reasons:
+- # 1. if the package is installed by a user who cannot write `.'
+- # make install will fail,
+- # 2. the above comment should most certainly read
+- # $(mkdir_p) $(DESTDIR)$(somedir)
+- # so it does not work when $(somedir) is undefined and
+- # $(DESTDIR) is not.
+- # To support the latter case, we have to write
+- # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
+- # so the `.' trick is pointless.
+- mkdir_p='mkdir -p --'
+-else
+- # On NextStep and OpenStep, the `mkdir' command does not
+- # recognize any option. It will interpret all options as
+- # directories to create, and then abort because `.' already
+- # exists.
+- for d in ./-p ./--version;
+- do
+- test -d $d && rmdir $d
+- done
+- # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
+- if test -f "$ac_aux_dir/mkinstalldirs"; then
+- mkdir_p='$(mkinstalldirs)'
+- else
+- mkdir_p='$(install_sh) -d'
+- fi
+-fi
+-
+-for ac_prog in gawk mawk nawk awk
+-do
+- # Extract the first word of "$ac_prog", so it can be a program name with args.
+-set dummy $ac_prog; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_AWK+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
+-else
+- if test -n "$AWK"; then
+- ac_cv_prog_AWK="$AWK" # Let the user override the test.
+-else
+-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+-for as_dir in $PATH
+-do
+- IFS=$as_save_IFS
+- test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
+- ac_cv_prog_AWK="$ac_prog"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+- break 2
+- fi
+-done
+-done
+-IFS=$as_save_IFS
+-
+-fi
+-fi
+-AWK=$ac_cv_prog_AWK
+-if test -n "$AWK"; then
+- { echo "$as_me:$LINENO: result: $AWK" >&5
+-echo "${ECHO_T}$AWK" >&6; }
+-else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
++$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+ fi
+
+-
+- test -n "$AWK" && break
+-done
+-
+-{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+-echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; }
+-set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+-if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
+-else
+- cat >conftest.make <<\_ACEOF
+-SHELL = /bin/sh
+-all:
+- @echo '@@@%%%=$(MAKE)=@@@%%%'
+-_ACEOF
+-# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+-case `${MAKE-make} -f conftest.make 2>/dev/null` in
+- *@@@%%%=?*=@@@%%%*)
+- eval ac_cv_prog_make_${ac_make}_set=yes;;
++if test x"${install_sh}" != xset; then
++ case $am_aux_dir in
++ *\ * | *\ *)
++ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+- eval ac_cv_prog_make_${ac_make}_set=no;;
+-esac
+-rm -f conftest.make
+-fi
+-if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+- { echo "$as_me:$LINENO: result: yes" >&5
+-echo "${ECHO_T}yes" >&6; }
+- SET_MAKE=
+-else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
+- SET_MAKE="MAKE=${MAKE-make}"
+-fi
+-
+-rm -rf .tst 2>/dev/null
+-mkdir .tst 2>/dev/null
+-if test -d .tst; then
+- am__leading_dot=.
+-else
+- am__leading_dot=_
+-fi
+-rmdir .tst 2>/dev/null
+-
+-# test to see if srcdir already configured
+-if test "`cd $srcdir && pwd`" != "`pwd`" &&
+- test -f $srcdir/config.status; then
+- { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
+-echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
+- { (exit 1); exit 1; }; }
+-fi
+-
+-# test whether we have cygpath
+-if test -z "$CYGPATH_W"; then
+- if (cygpath --version) >/dev/null 2>/dev/null; then
+- CYGPATH_W='cygpath -w'
+- else
+- CYGPATH_W=echo
+- fi
++ install_sh="\${SHELL} $am_aux_dir/install-sh"
++ esac
+ fi
+
+-
+-# Define the identity of the package.
+- PACKAGE='exmap-console'
+- VERSION='0.4.1'
+-
+-
+-cat >>confdefs.h <<_ACEOF
+-#define PACKAGE "$PACKAGE"
+-_ACEOF
+-
+-
+-cat >>confdefs.h <<_ACEOF
+-#define VERSION "$VERSION"
+-_ACEOF
+-
+-# Some tools Automake needs.
+-
+-ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+-
+-
+-AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+-
+-
+-AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+-
+-
+-AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+-
+-
+-MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+-
+-install_sh=${install_sh-"$am_aux_dir/install-sh"}
+-
+ # Installed binaries are usually stripped using `strip' when the user
+ # run `make install-strip'. However `strip' might not be the right
+ # tool to use in cross-compilation environments, therefore Automake
+@@ -2049,10 +2068,10 @@
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+ set dummy ${ac_tool_prefix}strip; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_STRIP+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_STRIP+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+@@ -2062,25 +2081,25 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ STRIP=$ac_cv_prog_STRIP
+ if test -n "$STRIP"; then
+- { echo "$as_me:$LINENO: result: $STRIP" >&5
+-echo "${ECHO_T}$STRIP" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
++$as_echo "$STRIP" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -2089,10 +2108,10 @@
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+ set dummy strip; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+@@ -2102,48 +2121,224 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+ if test -n "$ac_ct_STRIP"; then
+- { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+-echo "${ECHO_T}$ac_ct_STRIP" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
++$as_echo "$ac_ct_STRIP" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_STRIP" = x; then
++ STRIP=":"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ STRIP=$ac_ct_STRIP
++ fi
++else
++ STRIP="$ac_cv_prog_STRIP"
++fi
++
++fi
++INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
++$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
++if test -z "$MKDIR_P"; then
++ if ${ac_cv_path_mkdir+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_prog in mkdir gmkdir; do
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
++ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
++ 'mkdir (GNU coreutils) '* | \
++ 'mkdir (coreutils) '* | \
++ 'mkdir (fileutils) '4.1*)
++ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
++ break 3;;
++ esac
++ done
++ done
++ done
++IFS=$as_save_IFS
++
++fi
++
++ test -d ./--version && rmdir ./--version
++ if test "${ac_cv_path_mkdir+set}" = set; then
++ MKDIR_P="$ac_cv_path_mkdir -p"
++ else
++ # As a last resort, use the slow shell script. Don't cache a
++ # value for MKDIR_P within a source directory, because that will
++ # break other packages using the cache if that directory is
++ # removed, or if the value is a relative name.
++ MKDIR_P="$ac_install_sh -d"
++ fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
++$as_echo "$MKDIR_P" >&6; }
++
++mkdir_p="$MKDIR_P"
++case $mkdir_p in
++ [\\/$]* | ?:[\\/]*) ;;
++ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
++esac
++
++for ac_prog in gawk mawk nawk awk
++do
++ # Extract the first word of "$ac_prog", so it can be a program name with args.
++set dummy $ac_prog; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_AWK+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$AWK"; then
++ ac_cv_prog_AWK="$AWK" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
++ ac_cv_prog_AWK="$ac_prog"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++AWK=$ac_cv_prog_AWK
++if test -n "$AWK"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
++$as_echo "$AWK" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++ test -n "$AWK" && break
++done
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
++$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
++set x ${MAKE-make}
++ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
++if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ cat >conftest.make <<\_ACEOF
++SHELL = /bin/sh
++all:
++ @echo '@@@%%%=$(MAKE)=@@@%%%'
++_ACEOF
++# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
++case `${MAKE-make} -f conftest.make 2>/dev/null` in
++ *@@@%%%=?*=@@@%%%*)
++ eval ac_cv_prog_make_${ac_make}_set=yes;;
++ *)
++ eval ac_cv_prog_make_${ac_make}_set=no;;
++esac
++rm -f conftest.make
++fi
++if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++ SET_MAKE=
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++ SET_MAKE="MAKE=${MAKE-make}"
++fi
++
++rm -rf .tst 2>/dev/null
++mkdir .tst 2>/dev/null
++if test -d .tst; then
++ am__leading_dot=.
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ am__leading_dot=_
+ fi
++rmdir .tst 2>/dev/null
+
+- if test "x$ac_ct_STRIP" = x; then
+- STRIP=":"
+- else
+- case $cross_compiling:$ac_tool_warned in
+-yes:)
+-{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&5
+-echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+-ac_tool_warned=yes ;;
+-esac
+- STRIP=$ac_ct_STRIP
++if test "`cd $srcdir && pwd`" != "`pwd`"; then
++ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
++ # is not polluted with repeated "-I."
++ am__isrc=' -I$(srcdir)'
++ # test to see if srcdir already configured
++ if test -f $srcdir/config.status; then
++ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+-else
+- STRIP="$ac_cv_prog_STRIP"
+ fi
+
++# test whether we have cygpath
++if test -z "$CYGPATH_W"; then
++ if (cygpath --version) >/dev/null 2>/dev/null; then
++ CYGPATH_W='cygpath -w'
++ else
++ CYGPATH_W=echo
++ fi
+ fi
+-INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
++
++
++# Define the identity of the package.
++ PACKAGE='exmap-console'
++ VERSION='0.4.1'
++
++
++cat >>confdefs.h <<_ACEOF
++#define PACKAGE "$PACKAGE"
++_ACEOF
++
++
++cat >>confdefs.h <<_ACEOF
++#define VERSION "$VERSION"
++_ACEOF
++
++# Some tools Automake needs.
++
++ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
++
++
++AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
++
++
++AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
++
++
++AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
++
++
++MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+ # We need awk for the "check" target. The system "awk" is bad on
+ # some platforms.
+@@ -2165,7 +2360,7 @@
+
+
+ # Check whether --with-readline was given.
+-if test "${with_readline+set}" = set; then
++if test "${with_readline+set}" = set; then :
+ withval=$with_readline; WITH_READLINE=$enableval
+ else
+ WITH_READLINE=yes
+@@ -2182,44 +2377,44 @@
+ am_make=${MAKE-make}
+ cat > confinc << 'END'
+ am__doit:
+- @echo done
++ @echo this is the am__doit target
+ .PHONY: am__doit
+ END
+ # If we don't find an include directive, just comment out the code.
+-{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+-echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
++$as_echo_n "checking for style of include used by $am_make... " >&6; }
+ am__include="#"
+ am__quote=
+ _am_result=none
+ # First try GNU make style include.
+ echo "include confinc" > confmf
+-# We grep out `Entering directory' and `Leaving directory'
+-# messages which can occur if `w' ends up in MAKEFLAGS.
+-# In particular we don't look at `^make:' because GNU make might
+-# be invoked under some other name (usually "gmake"), in which
+-# case it prints its new name instead of `make'.
+-if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+- am__include=include
+- am__quote=
+- _am_result=GNU
+-fi
++# Ignore all kinds of additional output from `make'.
++case `$am_make -s -f confmf 2> /dev/null` in #(
++*the\ am__doit\ target*)
++ am__include=include
++ am__quote=
++ _am_result=GNU
++ ;;
++esac
+ # Now try BSD make style include.
+ if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+- if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+- am__include=.include
+- am__quote="\""
+- _am_result=BSD
+- fi
++ case `$am_make -s -f confmf 2> /dev/null` in #(
++ *the\ am__doit\ target*)
++ am__include=.include
++ am__quote="\""
++ _am_result=BSD
++ ;;
++ esac
+ fi
+
+
+-{ echo "$as_me:$LINENO: result: $_am_result" >&5
+-echo "${ECHO_T}$_am_result" >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
++$as_echo "$_am_result" >&6; }
+ rm -f confinc confmf
+
+ # Check whether --enable-dependency-tracking was given.
+-if test "${enable_dependency_tracking+set}" = set; then
++if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+ fi
+
+@@ -2227,9 +2422,7 @@
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ fi
+-
+-
+-if test "x$enable_dependency_tracking" != xno; then
++ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+ else
+@@ -2238,7 +2431,6 @@
+ fi
+
+
+-
+ ac_ext=c
+ ac_cpp='$CPP $CPPFLAGS'
+ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+@@ -2247,10 +2439,10 @@
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+ set dummy ${ac_tool_prefix}gcc; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+@@ -2260,25 +2452,25 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ CC=$ac_cv_prog_CC
+ if test -n "$CC"; then
+- { echo "$as_me:$LINENO: result: $CC" >&5
+-echo "${ECHO_T}$CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -2287,10 +2479,10 @@
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+ set dummy gcc; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+@@ -2300,25 +2492,25 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ ac_ct_CC=$ac_cv_prog_ac_ct_CC
+ if test -n "$ac_ct_CC"; then
+- { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+-echo "${ECHO_T}$ac_ct_CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
++$as_echo "$ac_ct_CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+ if test "x$ac_ct_CC" = x; then
+@@ -2326,12 +2518,8 @@
+ else
+ case $cross_compiling:$ac_tool_warned in
+ yes:)
+-{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&5
+-echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ ac_tool_warned=yes ;;
+ esac
+ CC=$ac_ct_CC
+@@ -2344,10 +2532,10 @@
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+ set dummy ${ac_tool_prefix}cc; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+@@ -2357,25 +2545,25 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ CC=$ac_cv_prog_CC
+ if test -n "$CC"; then
+- { echo "$as_me:$LINENO: result: $CC" >&5
+-echo "${ECHO_T}$CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -2384,10 +2572,10 @@
+ if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+ set dummy cc; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+@@ -2398,18 +2586,18 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ if test $ac_prog_rejected = yes; then
+@@ -2428,11 +2616,11 @@
+ fi
+ CC=$ac_cv_prog_CC
+ if test -n "$CC"; then
+- { echo "$as_me:$LINENO: result: $CC" >&5
+-echo "${ECHO_T}$CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -2443,10 +2631,10 @@
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+ set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+@@ -2456,25 +2644,25 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ CC=$ac_cv_prog_CC
+ if test -n "$CC"; then
+- { echo "$as_me:$LINENO: result: $CC" >&5
+-echo "${ECHO_T}$CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -2487,10 +2675,10 @@
+ do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+ set dummy $ac_prog; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+@@ -2500,25 +2688,25 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ ac_ct_CC=$ac_cv_prog_ac_ct_CC
+ if test -n "$ac_ct_CC"; then
+- { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+-echo "${ECHO_T}$ac_ct_CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
++$as_echo "$ac_ct_CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -2530,12 +2718,8 @@
+ else
+ case $cross_compiling:$ac_tool_warned in
+ yes:)
+-{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&5
+-echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ ac_tool_warned=yes ;;
+ esac
+ CC=$ac_ct_CC
+@@ -2545,51 +2729,37 @@
+ fi
+
+
+-test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+-See \`config.log' for more details." >&5
+-echo "$as_me: error: no acceptable C compiler found in \$PATH
+-See \`config.log' for more details." >&2;}
+- { (exit 1); exit 1; }; }
++test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "no acceptable C compiler found in \$PATH
++See \`config.log' for more details" "$LINENO" 5; }
+
+ # Provide some information about the compiler.
+-echo "$as_me:$LINENO: checking for C compiler version" >&5
+-ac_compiler=`set X $ac_compile; echo $2`
+-{ (ac_try="$ac_compiler --version >&5"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compiler --version >&5") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }
+-{ (ac_try="$ac_compiler -v >&5"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compiler -v >&5") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }
+-{ (ac_try="$ac_compiler -V >&5"
++$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
++set X $ac_compile
++ac_compiler=$2
++for ac_option in --version -v -V -qversion; do
++ { { ac_try="$ac_compiler $ac_option >&5"
+ case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+ esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compiler -V >&5") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
++ ac_status=$?
++ if test -s conftest.err; then
++ sed '10a\
++... rest of stderr output deleted ...
++ 10q' conftest.err >conftest.er1
++ cat conftest.er1 >&5
++ fi
++ rm -f conftest.er1 conftest.err
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }
++done
+
+-cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ int
+@@ -2601,59 +2771,55 @@
+ }
+ _ACEOF
+ ac_clean_files_save=$ac_clean_files
+-ac_clean_files="$ac_clean_files a.out a.exe b.out"
++ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+ # Try to create an executable without -o first, disregard a.out.
+ # It will help us diagnose broken compilers, and finding out an intuition
+ # of exeext.
+-{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+-echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; }
+-ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+-#
+-# List of possible output files, starting from the most likely.
+-# The algorithm is not robust to junk in `.', hence go to wildcards (a.*)
+-# only as a last resort. b.out is created by i960 compilers.
+-ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out'
+-#
+-# The IRIX 6 linker writes into existing files which may not be
+-# executable, retaining their permissions. Remove them first so a
+-# subsequent execution test works.
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
++$as_echo_n "checking whether the C compiler works... " >&6; }
++ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
++
++# The possible output files:
++ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
++
+ ac_rmfiles=
+ for ac_file in $ac_files
+ do
+ case $ac_file in
+- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+ done
+ rm -f $ac_rmfiles
+
+-if { (ac_try="$ac_link_default"
++if { { ac_try="$ac_link_default"
+ case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+ esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; then
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+ # So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+ # in a Makefile. We should not override ac_cv_exeext if it was cached,
+ # so that the user can short-circuit this test for compilers unknown to
+ # Autoconf.
+-for ac_file in $ac_files
++for ac_file in $ac_files ''
+ do
+ test -f "$ac_file" || continue
+ case $ac_file in
+- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj )
++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+- if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
++ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+@@ -2670,76 +2836,43 @@
+ test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+ else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+-{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+-See \`config.log' for more details." >&5
+-echo "$as_me: error: C compiler cannot create executables
+-See \`config.log' for more details." >&2;}
+- { (exit 77); exit 77; }; }
++ ac_file=''
+ fi
++if test -z "$ac_file"; then :
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++$as_echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
+
++{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error 77 "C compiler cannot create executables
++See \`config.log' for more details" "$LINENO" 5; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
++$as_echo_n "checking for C compiler default output file name... " >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
++$as_echo "$ac_file" >&6; }
+ ac_exeext=$ac_cv_exeext
+-{ echo "$as_me:$LINENO: result: $ac_file" >&5
+-echo "${ECHO_T}$ac_file" >&6; }
+-
+-# Check that the compiler produces executables we can run. If not, either
+-# the compiler is broken, or we cross compile.
+-{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+-echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; }
+-# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+-# If not cross compiling, check that we can run a simple program.
+-if test "$cross_compiling" != yes; then
+- if { ac_try='./$ac_file'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
+- cross_compiling=no
+- else
+- if test "$cross_compiling" = maybe; then
+- cross_compiling=yes
+- else
+- { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+-If you meant to cross compile, use \`--host'.
+-See \`config.log' for more details." >&5
+-echo "$as_me: error: cannot run C compiled programs.
+-If you meant to cross compile, use \`--host'.
+-See \`config.log' for more details." >&2;}
+- { (exit 1); exit 1; }; }
+- fi
+- fi
+-fi
+-{ echo "$as_me:$LINENO: result: yes" >&5
+-echo "${ECHO_T}yes" >&6; }
+
+-rm -f a.out a.exe conftest$ac_cv_exeext b.out
++rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ ac_clean_files=$ac_clean_files_save
+-# Check that the compiler produces executables we can run. If not, either
+-# the compiler is broken, or we cross compile.
+-{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+-echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; }
+-{ echo "$as_me:$LINENO: result: $cross_compiling" >&5
+-echo "${ECHO_T}$cross_compiling" >&6; }
+-
+-{ echo "$as_me:$LINENO: checking for suffix of executables" >&5
+-echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; }
+-if { (ac_try="$ac_link"
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
++$as_echo_n "checking for suffix of executables... " >&6; }
++if { { ac_try="$ac_link"
+ case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+ esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; then
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+ # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+ # work properly (i.e., refer to `conftest.exe'), while it won't with
+@@ -2747,37 +2880,90 @@
+ for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+ done
+ else
+- { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+-See \`config.log' for more details." >&5
+-echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+-See \`config.log' for more details." >&2;}
+- { (exit 1); exit 1; }; }
+-fi
+-
+-rm -f conftest$ac_cv_exeext
+-{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+-echo "${ECHO_T}$ac_cv_exeext" >&6; }
++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "cannot compute suffix of executables: cannot compile and link
++See \`config.log' for more details" "$LINENO" 5; }
++fi
++rm -f conftest conftest$ac_cv_exeext
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
++$as_echo "$ac_cv_exeext" >&6; }
+
+ rm -f conftest.$ac_ext
+ EXEEXT=$ac_cv_exeext
+ ac_exeext=$EXEEXT
+-{ echo "$as_me:$LINENO: checking for suffix of object files" >&5
+-echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; }
+-if test "${ac_cv_objext+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
+-else
+- cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <stdio.h>
++int
++main ()
++{
++FILE *f = fopen ("conftest.out", "w");
++ return ferror (f) || fclose (f) != 0;
++
++ ;
++ return 0;
++}
+ _ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++ac_clean_files="$ac_clean_files conftest.out"
++# Check that the compiler produces executables we can run. If not, either
++# the compiler is broken, or we cross compile.
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
++$as_echo_n "checking whether we are cross compiling... " >&6; }
++if test "$cross_compiling" != yes; then
++ { { ac_try="$ac_link"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_link") 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }
++ if { ac_try='./conftest$ac_cv_exeext'
++ { { case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_try") 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; }; then
++ cross_compiling=no
++ else
++ if test "$cross_compiling" = maybe; then
++ cross_compiling=yes
++ else
++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "cannot run C compiled programs.
++If you meant to cross compile, use \`--host'.
++See \`config.log' for more details" "$LINENO" 5; }
++ fi
++ fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
++$as_echo "$cross_compiling" >&6; }
++
++rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
++ac_clean_files=$ac_clean_files_save
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
++$as_echo_n "checking for suffix of object files... " >&6; }
++if ${ac_cv_objext+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ int
+@@ -2789,51 +2975,46 @@
+ }
+ _ACEOF
+ rm -f conftest.o conftest.obj
+-if { (ac_try="$ac_compile"
++if { { ac_try="$ac_compile"
+ case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+ esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; then
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;;
++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+ done
+ else
+- echo "$as_me: failed program was:" >&5
++ $as_echo "$as_me: failed program was:" >&5
+ sed 's/^/| /' conftest.$ac_ext >&5
+
+-{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+-See \`config.log' for more details." >&5
+-echo "$as_me: error: cannot compute suffix of object files: cannot compile
+-See \`config.log' for more details." >&2;}
+- { (exit 1); exit 1; }; }
++{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "cannot compute suffix of object files: cannot compile
++See \`config.log' for more details" "$LINENO" 5; }
+ fi
+-
+ rm -f conftest.$ac_cv_objext conftest.$ac_ext
+ fi
+-{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+-echo "${ECHO_T}$ac_cv_objext" >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
++$as_echo "$ac_cv_objext" >&6; }
+ OBJEXT=$ac_cv_objext
+ ac_objext=$OBJEXT
+-{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+-echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+-if test "${ac_cv_c_compiler_gnu+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
++$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
++if ${ac_cv_c_compiler_gnu+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+- cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ int
+@@ -2847,71 +3028,34 @@
+ return 0;
+ }
+ _ACEOF
+-rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compile") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest.$ac_objext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
++if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+ else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+- ac_compiler_gnu=no
++ ac_compiler_gnu=no
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+ fi
+-{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+-echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+-GCC=`test $ac_compiler_gnu = yes && echo yes`
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
++$as_echo "$ac_cv_c_compiler_gnu" >&6; }
++if test $ac_compiler_gnu = yes; then
++ GCC=yes
++else
++ GCC=
++fi
+ ac_test_CFLAGS=${CFLAGS+set}
+ ac_save_CFLAGS=$CFLAGS
+-{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+-echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_cc_g+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
++$as_echo_n "checking whether $CC accepts -g... " >&6; }
++if ${ac_cv_prog_cc_g+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+- cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ int
+@@ -2922,51 +3066,11 @@
+ return 0;
+ }
+ _ACEOF
+-rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compile") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest.$ac_objext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
++if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+ else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+- CFLAGS=""
+- cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++ CFLAGS=""
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ int
+@@ -2977,52 +3081,12 @@
+ return 0;
+ }
+ _ACEOF
+-rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compile") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest.$ac_objext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
+- :
+-else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
++if ac_fn_c_try_compile "$LINENO"; then :
+
+- ac_c_werror_flag=$ac_save_c_werror_flag
++else
++ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+- cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ int
+@@ -3033,59 +3097,18 @@
+ return 0;
+ }
+ _ACEOF
+-rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compile") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest.$ac_objext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
++if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+-else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+-
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ fi
+-{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+-echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
++$as_echo "$ac_cv_prog_cc_g" >&6; }
+ if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+ elif test $ac_cv_prog_cc_g = yes; then
+@@ -3101,18 +3124,14 @@
+ CFLAGS=
+ fi
+ fi
+-{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+-echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_cc_c89+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
++$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
++if ${ac_cv_prog_cc_c89+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ ac_cv_prog_cc_c89=no
+ ac_save_CC=$CC
+-cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+ #include <stdarg.h>
+ #include <stdio.h>
+@@ -3169,48 +3188,9 @@
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+ do
+ CC="$ac_save_CC $ac_arg"
+- rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compile") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest.$ac_objext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
++ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+-else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+-
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+ done
+@@ -3221,17 +3201,19 @@
+ # AC_CACHE_VAL
+ case "x$ac_cv_prog_cc_c89" in
+ x)
+- { echo "$as_me:$LINENO: result: none needed" >&5
+-echo "${ECHO_T}none needed" >&6; } ;;
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
++$as_echo "none needed" >&6; } ;;
+ xno)
+- { echo "$as_me:$LINENO: result: unsupported" >&5
+-echo "${ECHO_T}unsupported" >&6; } ;;
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
++$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+- { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+-echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
++$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+ esac
++if test "x$ac_cv_prog_cc_c89" != xno; then :
+
++fi
+
+ ac_ext=c
+ ac_cpp='$CPP $CPPFLAGS'
+@@ -3241,10 +3223,10 @@
+
+ depcc="$CC" am_compiler_list=
+
+-{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+-echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; }
+-if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
++$as_echo_n "checking dependency style of $depcc... " >&6; }
++if ${am_cv_CC_dependencies_compiler_type+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+@@ -3269,6 +3251,11 @@
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
++ am__universal=false
++ case " $depcc " in #(
++ *\ -arch\ *\ -arch\ *) am__universal=true ;;
++ esac
++
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+@@ -3286,7 +3273,17 @@
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
++ # We check with `-c' and `-o' for the sake of the "dashmstdout"
++ # mode. It turns out that the SunPro C++ compiler does not properly
++ # handle `-M -o', and we need to detect this. Also, some Intel
++ # versions had trouble with output in subdirs
++ am__obj=sub/conftest.${OBJEXT-o}
++ am__minus_obj="-o $am__obj"
+ case $depmode in
++ gcc)
++ # This depmode causes a compiler race in universal mode.
++ test "$am__universal" = false || continue
++ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+@@ -3296,18 +3293,23 @@
+ break
+ fi
+ ;;
++ msvisualcpp | msvcmsys)
++ # This compiler won't grok `-c -o', but also, the minuso test has
++ # not run yet. These depmodes are late enough in the game, and
++ # so weak that their functioning should not be impacted.
++ am__obj=conftest.${OBJEXT-o}
++ am__minus_obj=
++ ;;
+ none) break ;;
+ esac
+- # We check with `-c' and `-o' for the sake of the "dashmstdout"
+- # mode. It turns out that the SunPro C++ compiler does not properly
+- # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+- source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
++ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+- $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
++ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
++ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+- grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
++ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+@@ -3331,13 +3333,11 @@
+ fi
+
+ fi
+-{ echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+-echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
++$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+ CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+-
+-
+-if
++ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+@@ -3349,18 +3349,14 @@
+
+
+
+-{ echo "$as_me:$LINENO: checking for readline in -lreadline" >&5
+-echo $ECHO_N "checking for readline in -lreadline... $ECHO_C" >&6; }
+-if test "${ac_cv_lib_readline_readline+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5
++$as_echo_n "checking for readline in -lreadline... " >&6; }
++if ${ac_cv_lib_readline_readline+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ ac_check_lib_save_LIBS=$LIBS
+ LIBS="-lreadline $LIBS"
+-cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ /* Override any GCC internal prototype to avoid an error.
+@@ -3378,72 +3374,31 @@
+ return 0;
+ }
+ _ACEOF
+-rm -f conftest.$ac_objext conftest$ac_exeext
+-if { (ac_try="$ac_link"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_link") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest$ac_exeext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
++if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_readline_readline=yes
+ else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+- ac_cv_lib_readline_readline=no
++ ac_cv_lib_readline_readline=no
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext \
+- conftest$ac_exeext conftest.$ac_ext
++ conftest$ac_exeext conftest.$ac_ext
+ LIBS=$ac_check_lib_save_LIBS
+ fi
+-{ echo "$as_me:$LINENO: result: $ac_cv_lib_readline_readline" >&5
+-echo "${ECHO_T}$ac_cv_lib_readline_readline" >&6; }
+-if test $ac_cv_lib_readline_readline = yes; then
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5
++$as_echo "$ac_cv_lib_readline_readline" >&6; }
++if test "x$ac_cv_lib_readline_readline" = xyes; then :
+ WORKING_READLINE=yes
+ else
+ WORKING_READLINE=no
+ fi
+
+-{ echo "$as_me:$LINENO: checking for add_history in -lhistory" >&5
+-echo $ECHO_N "checking for add_history in -lhistory... $ECHO_C" >&6; }
+-if test "${ac_cv_lib_history_add_history+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for add_history in -lhistory" >&5
++$as_echo_n "checking for add_history in -lhistory... " >&6; }
++if ${ac_cv_lib_history_add_history+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ ac_check_lib_save_LIBS=$LIBS
+ LIBS="-lhistory $LIBS"
+-cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ /* Override any GCC internal prototype to avoid an error.
+@@ -3461,55 +3416,18 @@
+ return 0;
+ }
+ _ACEOF
+-rm -f conftest.$ac_objext conftest$ac_exeext
+-if { (ac_try="$ac_link"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_link") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest$ac_exeext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
++if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_history_add_history=yes
+ else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+- ac_cv_lib_history_add_history=no
++ ac_cv_lib_history_add_history=no
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext \
+- conftest$ac_exeext conftest.$ac_ext
++ conftest$ac_exeext conftest.$ac_ext
+ LIBS=$ac_check_lib_save_LIBS
+ fi
+-{ echo "$as_me:$LINENO: result: $ac_cv_lib_history_add_history" >&5
+-echo "${ECHO_T}$ac_cv_lib_history_add_history" >&6; }
+-if test $ac_cv_lib_history_add_history = yes; then
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_history_add_history" >&5
++$as_echo "$ac_cv_lib_history_add_history" >&6; }
++if test "x$ac_cv_lib_history_add_history" = xyes; then :
+ WORKING_READLINE=yes
+ else
+ WORKING_READLINE=no
+@@ -3524,9 +3442,7 @@
+ fi
+ fi
+
+-
+-
+-if test "x$WITH_READLINE" = "xyes"; then
++ if test "x$WITH_READLINE" = "xyes"; then
+ INTERACTIVE_TRUE=
+ INTERACTIVE_FALSE='#'
+ else
+@@ -3544,7 +3460,7 @@
+
+
+ # Check whether --enable-doc was given.
+-if test "${enable_doc+set}" = set; then
++if test "${enable_doc+set}" = set; then :
+ enableval=$enable_doc; DO_DOCS=$enableval
+ else
+ DO_DOCS=$enableval
+@@ -3553,16 +3469,14 @@
+
+
+ # Check whether --with-help2man was given.
+-if test "${with_help2man+set}" = set; then
++if test "${with_help2man+set}" = set; then :
+ withval=$with_help2man; WITH_H2MAN=$withval
+ else
+ WITH_H2MAN=yes
+ fi
+
+
+-
+-
+-if test "x$DO_DOCS" != "xno"; then
++ if test "x$DO_DOCS" != "xno"; then
+ DODOCS_TRUE=
+ DODOCS_FALSE='#'
+ else
+@@ -3571,14 +3485,6 @@
+ fi
+
+
+-# Check whether --enable-debug was given.
+-if test "${enable_debug+set}" = set; then
+- enableval=$enable_debug; CFLAGS="-g -O0"
+-else
+- CFLAGS="-g -O2"
+-fi
+-
+-
+ CFLAGS="$CFLAGS -DEXMAP_VERSION=\\\"$EXMAP_VERSION\\\" -DEXMAP_PROTOCOL_VERSION=\\\"$EXMAP_PROTOCOL_VERSION\\\""
+
+
+@@ -3591,10 +3497,10 @@
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+ set dummy ${ac_tool_prefix}gcc; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+@@ -3604,25 +3510,25 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ CC=$ac_cv_prog_CC
+ if test -n "$CC"; then
+- { echo "$as_me:$LINENO: result: $CC" >&5
+-echo "${ECHO_T}$CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -3631,10 +3537,10 @@
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+ set dummy gcc; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+@@ -3644,25 +3550,25 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ ac_ct_CC=$ac_cv_prog_ac_ct_CC
+ if test -n "$ac_ct_CC"; then
+- { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+-echo "${ECHO_T}$ac_ct_CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
++$as_echo "$ac_ct_CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+ if test "x$ac_ct_CC" = x; then
+@@ -3670,12 +3576,8 @@
+ else
+ case $cross_compiling:$ac_tool_warned in
+ yes:)
+-{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&5
+-echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ ac_tool_warned=yes ;;
+ esac
+ CC=$ac_ct_CC
+@@ -3688,10 +3590,10 @@
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+ set dummy ${ac_tool_prefix}cc; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+@@ -3701,25 +3603,25 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ CC=$ac_cv_prog_CC
+ if test -n "$CC"; then
+- { echo "$as_me:$LINENO: result: $CC" >&5
+-echo "${ECHO_T}$CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -3728,10 +3630,10 @@
+ if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+ set dummy cc; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+@@ -3742,18 +3644,18 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ if test $ac_prog_rejected = yes; then
+@@ -3772,11 +3674,11 @@
+ fi
+ CC=$ac_cv_prog_CC
+ if test -n "$CC"; then
+- { echo "$as_me:$LINENO: result: $CC" >&5
+-echo "${ECHO_T}$CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -3787,10 +3689,10 @@
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+ set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+@@ -3800,25 +3702,25 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ CC=$ac_cv_prog_CC
+ if test -n "$CC"; then
+- { echo "$as_me:$LINENO: result: $CC" >&5
+-echo "${ECHO_T}$CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -3831,10 +3733,10 @@
+ do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+ set dummy $ac_prog; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+@@ -3844,25 +3746,25 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ fi
+ fi
+ ac_ct_CC=$ac_cv_prog_ac_ct_CC
+ if test -n "$ac_ct_CC"; then
+- { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+-echo "${ECHO_T}$ac_ct_CC" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
++$as_echo "$ac_ct_CC" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -3874,12 +3776,8 @@
+ else
+ case $cross_compiling:$ac_tool_warned in
+ yes:)
+-{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&5
+-echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ ac_tool_warned=yes ;;
+ esac
+ CC=$ac_ct_CC
+@@ -3889,56 +3787,42 @@
+ fi
+
+
+-test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+-See \`config.log' for more details." >&5
+-echo "$as_me: error: no acceptable C compiler found in \$PATH
+-See \`config.log' for more details." >&2;}
+- { (exit 1); exit 1; }; }
++test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "no acceptable C compiler found in \$PATH
++See \`config.log' for more details" "$LINENO" 5; }
+
+ # Provide some information about the compiler.
+-echo "$as_me:$LINENO: checking for C compiler version" >&5
+-ac_compiler=`set X $ac_compile; echo $2`
+-{ (ac_try="$ac_compiler --version >&5"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compiler --version >&5") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }
+-{ (ac_try="$ac_compiler -v >&5"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compiler -v >&5") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }
+-{ (ac_try="$ac_compiler -V >&5"
++$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
++set X $ac_compile
++ac_compiler=$2
++for ac_option in --version -v -V -qversion; do
++ { { ac_try="$ac_compiler $ac_option >&5"
+ case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+ esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compiler -V >&5") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }
+-
+-{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+-echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+-if test "${ac_cv_c_compiler_gnu+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
++ ac_status=$?
++ if test -s conftest.err; then
++ sed '10a\
++... rest of stderr output deleted ...
++ 10q' conftest.err >conftest.er1
++ cat conftest.er1 >&5
++ fi
++ rm -f conftest.er1 conftest.err
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }
++done
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
++$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
++if ${ac_cv_c_compiler_gnu+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+- cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ int
+@@ -3952,71 +3836,34 @@
+ return 0;
+ }
+ _ACEOF
+-rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compile") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest.$ac_objext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
++if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+ else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+- ac_compiler_gnu=no
++ ac_compiler_gnu=no
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+ fi
+-{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+-echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+-GCC=`test $ac_compiler_gnu = yes && echo yes`
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
++$as_echo "$ac_cv_c_compiler_gnu" >&6; }
++if test $ac_compiler_gnu = yes; then
++ GCC=yes
++else
++ GCC=
++fi
+ ac_test_CFLAGS=${CFLAGS+set}
+ ac_save_CFLAGS=$CFLAGS
+-{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+-echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_cc_g+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
++$as_echo_n "checking whether $CC accepts -g... " >&6; }
++if ${ac_cv_prog_cc_g+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+- cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ int
+@@ -4027,51 +3874,11 @@
+ return 0;
+ }
+ _ACEOF
+-rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compile") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest.$ac_objext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
++if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+ else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+- CFLAGS=""
+- cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++ CFLAGS=""
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ int
+@@ -4082,52 +3889,12 @@
+ return 0;
+ }
+ _ACEOF
+-rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compile") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest.$ac_objext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
+- :
+-else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
++if ac_fn_c_try_compile "$LINENO"; then :
+
+- ac_c_werror_flag=$ac_save_c_werror_flag
++else
++ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+- cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+
+ int
+@@ -4138,59 +3905,18 @@
+ return 0;
+ }
+ _ACEOF
+-rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compile") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest.$ac_objext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
++if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+-else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+-
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ fi
+-{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+-echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
++$as_echo "$ac_cv_prog_cc_g" >&6; }
+ if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+ elif test $ac_cv_prog_cc_g = yes; then
+@@ -4206,18 +3932,14 @@
+ CFLAGS=
+ fi
+ fi
+-{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+-echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+-if test "${ac_cv_prog_cc_c89+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
++$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
++if ${ac_cv_prog_cc_c89+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ ac_cv_prog_cc_c89=no
+ ac_save_CC=$CC
+-cat >conftest.$ac_ext <<_ACEOF
+-/* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h. */
+ #include <stdarg.h>
+ #include <stdio.h>
+@@ -4274,48 +3996,9 @@
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+ do
+ CC="$ac_save_CC $ac_arg"
+- rm -f conftest.$ac_objext
+-if { (ac_try="$ac_compile"
+-case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_compile") 2>conftest.er1
+- ac_status=$?
+- grep -v '^ *+' conftest.er1 >conftest.err
+- rm -f conftest.er1
+- cat conftest.err >&5
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); } &&
+- { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; } &&
+- { ac_try='test -s conftest.$ac_objext'
+- { (case "(($ac_try" in
+- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+- *) ac_try_echo=$ac_try;;
+-esac
+-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+- (eval "$ac_try") 2>&5
+- ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; }; then
++ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+-else
+- echo "$as_me: failed program was:" >&5
+-sed 's/^/| /' conftest.$ac_ext >&5
+-
+-
+ fi
+-
+ rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+ done
+@@ -4326,17 +4009,19 @@
+ # AC_CACHE_VAL
+ case "x$ac_cv_prog_cc_c89" in
+ x)
+- { echo "$as_me:$LINENO: result: none needed" >&5
+-echo "${ECHO_T}none needed" >&6; } ;;
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
++$as_echo "none needed" >&6; } ;;
+ xno)
+- { echo "$as_me:$LINENO: result: unsupported" >&5
+-echo "${ECHO_T}unsupported" >&6; } ;;
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
++$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+- { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+-echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
++$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+ esac
++if test "x$ac_cv_prog_cc_c89" != xno; then :
+
++fi
+
+ ac_ext=c
+ ac_cpp='$CPP $CPPFLAGS'
+@@ -4346,10 +4031,10 @@
+
+ depcc="$CC" am_compiler_list=
+
+-{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+-echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; }
+-if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
++$as_echo_n "checking dependency style of $depcc... " >&6; }
++if ${am_cv_CC_dependencies_compiler_type+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+@@ -4374,6 +4059,11 @@
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
++ am__universal=false
++ case " $depcc " in #(
++ *\ -arch\ *\ -arch\ *) am__universal=true ;;
++ esac
++
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+@@ -4391,7 +4081,17 @@
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
++ # We check with `-c' and `-o' for the sake of the "dashmstdout"
++ # mode. It turns out that the SunPro C++ compiler does not properly
++ # handle `-M -o', and we need to detect this. Also, some Intel
++ # versions had trouble with output in subdirs
++ am__obj=sub/conftest.${OBJEXT-o}
++ am__minus_obj="-o $am__obj"
+ case $depmode in
++ gcc)
++ # This depmode causes a compiler race in universal mode.
++ test "$am__universal" = false || continue
++ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+@@ -4401,18 +4101,23 @@
+ break
+ fi
+ ;;
++ msvisualcpp | msvcmsys)
++ # This compiler won't grok `-c -o', but also, the minuso test has
++ # not run yet. These depmodes are late enough in the game, and
++ # so weak that their functioning should not be impacted.
++ am__obj=conftest.${OBJEXT-o}
++ am__minus_obj=
++ ;;
+ none) break ;;
+ esac
+- # We check with `-c' and `-o' for the sake of the "dashmstdout"
+- # mode. It turns out that the SunPro C++ compiler does not properly
+- # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+- source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
++ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+- $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
++ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
++ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+- grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
++ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+@@ -4436,13 +4141,11 @@
+ fi
+
+ fi
+-{ echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+-echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
++$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+ CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+-
+-
+-if
++ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+@@ -4456,14 +4159,18 @@
+
+
+
++
++
++
++
+ if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+ set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_path_PKG_CONFIG+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_path_PKG_CONFIG+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+@@ -4475,14 +4182,14 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ ;;
+@@ -4490,11 +4197,11 @@
+ fi
+ PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+ if test -n "$PKG_CONFIG"; then
+- { echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5
+-echo "${ECHO_T}$PKG_CONFIG" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
++$as_echo "$PKG_CONFIG" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+@@ -4503,10 +4210,10 @@
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+ set dummy pkg-config; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+@@ -4518,14 +4225,14 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ ;;
+@@ -4533,11 +4240,11 @@
+ fi
+ ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+ if test -n "$ac_pt_PKG_CONFIG"; then
+- { echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5
+-echo "${ECHO_T}$ac_pt_PKG_CONFIG" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
++$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+@@ -4545,12 +4252,8 @@
+ else
+ case $cross_compiling:$ac_tool_warned in
+ yes:)
+-{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&5
+-echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+-whose name does not start with the host triplet. If you think this
+-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ ac_tool_warned=yes ;;
+ esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+@@ -4562,63 +4265,60 @@
+ fi
+ if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=0.9.0
+- { echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5
+-echo $ECHO_N "checking pkg-config is at least version $_pkg_min_version... $ECHO_C" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
++$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+- { echo "$as_me:$LINENO: result: yes" >&5
+-echo "${ECHO_T}yes" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ PKG_CONFIG=""
+ fi
+-
+ fi
+
+ pkg_failed=no
+-{ echo "$as_me:$LINENO: checking for GLIB" >&5
+-echo $ECHO_N "checking for GLIB... $ECHO_C" >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLIB" >&5
++$as_echo_n "checking for GLIB... " >&6; }
+
+-if test -n "$PKG_CONFIG"; then
+- if test -n "$GLIB_CFLAGS"; then
+- pkg_cv_GLIB_CFLAGS="$GLIB_CFLAGS"
+- else
+- if test -n "$PKG_CONFIG" && \
+- { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"glib-2.0\"") >&5
++if test -n "$GLIB_CFLAGS"; then
++ pkg_cv_GLIB_CFLAGS="$GLIB_CFLAGS"
++ elif test -n "$PKG_CONFIG"; then
++ if test -n "$PKG_CONFIG" && \
++ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "glib-2.0") 2>&5
+ ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; then
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then
+ pkg_cv_GLIB_CFLAGS=`$PKG_CONFIG --cflags "glib-2.0" 2>/dev/null`
+ else
+ pkg_failed=yes
+ fi
+- fi
+-else
+- pkg_failed=untried
++ else
++ pkg_failed=untried
+ fi
+-if test -n "$PKG_CONFIG"; then
+- if test -n "$GLIB_LIBS"; then
+- pkg_cv_GLIB_LIBS="$GLIB_LIBS"
+- else
+- if test -n "$PKG_CONFIG" && \
+- { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"glib-2.0\"") >&5
++if test -n "$GLIB_LIBS"; then
++ pkg_cv_GLIB_LIBS="$GLIB_LIBS"
++ elif test -n "$PKG_CONFIG"; then
++ if test -n "$PKG_CONFIG" && \
++ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "glib-2.0") 2>&5
+ ac_status=$?
+- echo "$as_me:$LINENO: \$? = $ac_status" >&5
+- (exit $ac_status); }; then
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then
+ pkg_cv_GLIB_LIBS=`$PKG_CONFIG --libs "glib-2.0" 2>/dev/null`
+ else
+ pkg_failed=yes
+ fi
+- fi
+-else
+- pkg_failed=untried
++ else
++ pkg_failed=untried
+ fi
+
+
+
+ if test $pkg_failed = yes; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+
+ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+@@ -4626,25 +4326,14 @@
+ _pkg_short_errors_supported=no
+ fi
+ if test $_pkg_short_errors_supported = yes; then
+- GLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "glib-2.0"`
++ GLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "glib-2.0" 2>&1`
+ else
+- GLIB_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "glib-2.0"`
++ GLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors "glib-2.0" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$GLIB_PKG_ERRORS" >&5
+
+- { { echo "$as_me:$LINENO: error: Package requirements (glib-2.0) were not met:
+-
+-$GLIB_PKG_ERRORS
+-
+-Consider adjusting the PKG_CONFIG_PATH environment variable if you
+-installed software in a non-standard prefix.
+-
+-Alternatively, you may set the environment variables GLIB_CFLAGS
+-and GLIB_LIBS to avoid the need to call pkg-config.
+-See the pkg-config man page for more details.
+-" >&5
+-echo "$as_me: error: Package requirements (glib-2.0) were not met:
++ as_fn_error $? "Package requirements (glib-2.0) were not met:
+
+ $GLIB_PKG_ERRORS
+
+@@ -4653,21 +4342,13 @@
+
+ Alternatively, you may set the environment variables GLIB_CFLAGS
+ and GLIB_LIBS to avoid the need to call pkg-config.
+-See the pkg-config man page for more details.
+-" >&2;}
+- { (exit 1); exit 1; }; }
++See the pkg-config man page for more details." "$LINENO" 5
+ elif test $pkg_failed = untried; then
+- { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it
+-is in your PATH or set the PKG_CONFIG environment variable to the full
+-path to pkg-config.
+-
+-Alternatively, you may set the environment variables GLIB_CFLAGS
+-and GLIB_LIBS to avoid the need to call pkg-config.
+-See the pkg-config man page for more details.
+-
+-To get pkg-config, see <http://www.freedesktop.org/software/pkgconfig>.
+-See \`config.log' for more details." >&5
+-echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
+ is in your PATH or set the PKG_CONFIG environment variable to the full
+ path to pkg-config.
+
+@@ -4675,15 +4356,14 @@
+ and GLIB_LIBS to avoid the need to call pkg-config.
+ See the pkg-config man page for more details.
+
+-To get pkg-config, see <http://www.freedesktop.org/software/pkgconfig>.
+-See \`config.log' for more details." >&2;}
+- { (exit 1); exit 1; }; }
++To get pkg-config, see <http://pkg-config.freedesktop.org/>.
++See \`config.log' for more details" "$LINENO" 5; }
+ else
+ GLIB_CFLAGS=$pkg_cv_GLIB_CFLAGS
+ GLIB_LIBS=$pkg_cv_GLIB_LIBS
+- { echo "$as_me:$LINENO: result: yes" >&5
+-echo "${ECHO_T}yes" >&6; }
+- :
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++
+ fi
+
+
+@@ -4695,10 +4375,10 @@
+ #autodetect, error if not found
+ # Extract the first word of "help2man", so it can be a program name with args.
+ set dummy help2man; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_path_HELPTOMAN+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_path_HELPTOMAN+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ case $HELPTOMAN in
+ [\\/]* | ?:[\\/]*)
+@@ -4710,14 +4390,14 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_HELPTOMAN="$as_dir/$ac_word$ac_exec_ext"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_HELPTOMAN" && ac_cv_path_HELPTOMAN="no"
+@@ -4726,18 +4406,16 @@
+ fi
+ HELPTOMAN=$ac_cv_path_HELPTOMAN
+ if test -n "$HELPTOMAN"; then
+- { echo "$as_me:$LINENO: result: $HELPTOMAN" >&5
+-echo "${ECHO_T}$HELPTOMAN" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HELPTOMAN" >&5
++$as_echo "$HELPTOMAN" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+ if test "x$HELPTOMAN" = "xno" ; then
+- { { echo "$as_me:$LINENO: error: help2man not found -- either install it or use --without-help2man or --disable-doc" >&5
+-echo "$as_me: error: help2man not found -- either install it or use --without-help2man or --disable-doc" >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "help2man not found -- either install it or use --without-help2man or --disable-doc" "$LINENO" 5
+ fi
+ else
+ if test x$WITH_H2MAN = xno ; then
+@@ -4749,10 +4427,10 @@
+ if test x$H2M_PATH = x$WITH_H2MAN ; then
+ # Extract the first word of "$H2M_PROG", so it can be a program name with args.
+ set dummy $H2M_PROG; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_path_HELPTOMAN+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_path_HELPTOMAN+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ case $HELPTOMAN in
+ [\\/]* | ?:[\\/]*)
+@@ -4764,14 +4442,14 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_HELPTOMAN="$as_dir/$ac_word$ac_exec_ext"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_HELPTOMAN" && ac_cv_path_HELPTOMAN="no"
+@@ -4780,21 +4458,21 @@
+ fi
+ HELPTOMAN=$ac_cv_path_HELPTOMAN
+ if test -n "$HELPTOMAN"; then
+- { echo "$as_me:$LINENO: result: $HELPTOMAN" >&5
+-echo "${ECHO_T}$HELPTOMAN" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HELPTOMAN" >&5
++$as_echo "$HELPTOMAN" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+ else
+ # Extract the first word of "$H2M_PROG", so it can be a program name with args.
+ set dummy $H2M_PROG; ac_word=$2
+-{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+-if test "${ac_cv_path_HELPTOMAN+set}" = set; then
+- echo $ECHO_N "(cached) $ECHO_C" >&6
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_path_HELPTOMAN+:} false; then :
++ $as_echo_n "(cached) " >&6
+ else
+ case $HELPTOMAN in
+ [\\/]* | ?:[\\/]*)
+@@ -4806,14 +4484,14 @@
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_HELPTOMAN="$as_dir/$ac_word$ac_exec_ext"
+- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+ done
+-done
++ done
+ IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_HELPTOMAN" && ac_cv_path_HELPTOMAN="no"
+@@ -4822,28 +4500,24 @@
+ fi
+ HELPTOMAN=$ac_cv_path_HELPTOMAN
+ if test -n "$HELPTOMAN"; then
+- { echo "$as_me:$LINENO: result: $HELPTOMAN" >&5
+-echo "${ECHO_T}$HELPTOMAN" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HELPTOMAN" >&5
++$as_echo "$HELPTOMAN" >&6; }
+ else
+- { echo "$as_me:$LINENO: result: no" >&5
+-echo "${ECHO_T}no" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
+ fi
+
+
+ fi
+
+ if test "x$HELPTOMAN" = "xno" ; then
+- { { echo "$as_me:$LINENO: error: $WITH_H2MAN not found" >&5
+-echo "$as_me: error: $WITH_H2MAN not found" >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "$WITH_H2MAN not found" "$LINENO" 5
+ fi
+ fi
+ fi
+ fi
+
+-
+-
+-if test "x$HELPTOMAN" != "xno"; then
++ if test "x$HELPTOMAN" != "xno"; then
+ HAVE_HELPTOMAN_TRUE=
+ HAVE_HELPTOMAN_FALSE='#'
+ else
+@@ -4889,12 +4563,13 @@
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+- *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+-echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
++ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
++$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+- *) $as_unset $ac_var ;;
++ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
++ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+@@ -4902,8 +4577,8 @@
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+- # `set' does not quote correctly, so add quotes (double-quote
+- # substitution turns \\\\ into \\, and sed turns \\ into \).
++ # `set' does not quote correctly, so add quotes: double-quote
++ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+@@ -4925,13 +4600,24 @@
+ :end' >>confcache
+ if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+- test "x$cache_file" != "x/dev/null" &&
+- { echo "$as_me:$LINENO: updating cache $cache_file" >&5
+-echo "$as_me: updating cache $cache_file" >&6;}
+- cat confcache >$cache_file
++ if test "x$cache_file" != "x/dev/null"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
++$as_echo "$as_me: updating cache $cache_file" >&6;}
++ if test ! -f "$cache_file" || test -h "$cache_file"; then
++ cat confcache >"$cache_file"
++ else
++ case $cache_file in #(
++ */* | ?:*)
++ mv -f confcache "$cache_file"$$ &&
++ mv -f "$cache_file"$$ "$cache_file" ;; #(
++ *)
++ mv -f confcache "$cache_file" ;;
++ esac
++ fi
++ fi
+ else
+- { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+-echo "$as_me: not updating unwritable cache $cache_file" >&6;}
++ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
++$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+ fi
+ rm -f confcache
+@@ -4948,6 +4634,12 @@
+ # take arguments), then branch to the quote section. Otherwise,
+ # look for a macro that doesn't take arguments.
+ ac_script='
++:mline
++/\\$/{
++ N
++ s,\\\n,,
++ b mline
++}
+ t clear
+ :clear
+ s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+@@ -4974,69 +4666,62 @@
+
+ ac_libobjs=
+ ac_ltlibobjs=
++U=
+ for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+- ac_i=`echo "$ac_i" | sed "$ac_script"`
++ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+- ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+- ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
++ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
++ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+ done
+ LIBOBJS=$ac_libobjs
+
+ LTLIBOBJS=$ac_ltlibobjs
+
+
++ if test -n "$EXEEXT"; then
++ am__EXEEXT_TRUE=
++ am__EXEEXT_FALSE='#'
++else
++ am__EXEEXT_TRUE='#'
++ am__EXEEXT_FALSE=
++fi
++
+ if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+- { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&5
+-echo "$as_me: error: conditional \"AMDEP\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "conditional \"AMDEP\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
+ fi
+ if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+- { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&5
+-echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
+ fi
+ if test -z "${INTERACTIVE_TRUE}" && test -z "${INTERACTIVE_FALSE}"; then
+- { { echo "$as_me:$LINENO: error: conditional \"INTERACTIVE\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&5
+-echo "$as_me: error: conditional \"INTERACTIVE\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "conditional \"INTERACTIVE\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
+ fi
+ if test -z "${DODOCS_TRUE}" && test -z "${DODOCS_FALSE}"; then
+- { { echo "$as_me:$LINENO: error: conditional \"DODOCS\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&5
+-echo "$as_me: error: conditional \"DODOCS\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "conditional \"DODOCS\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
+ fi
+ if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+- { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&5
+-echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
+ fi
+ if test -z "${HAVE_HELPTOMAN_TRUE}" && test -z "${HAVE_HELPTOMAN_FALSE}"; then
+- { { echo "$as_me:$LINENO: error: conditional \"HAVE_HELPTOMAN\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&5
+-echo "$as_me: error: conditional \"HAVE_HELPTOMAN\" was never defined.
+-Usually this means the macro was only invoked conditionally." >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "conditional \"HAVE_HELPTOMAN\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
+ fi
+
+-: ${CONFIG_STATUS=./config.status}
++: "${CONFIG_STATUS=./config.status}"
++ac_write_fail=0
+ ac_clean_files_save=$ac_clean_files
+ ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+-{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+-echo "$as_me: creating $CONFIG_STATUS" >&6;}
+-cat >$CONFIG_STATUS <<_ACEOF
++{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
++$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
++as_write_fail=0
++cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+ #! $SHELL
+ # Generated by $as_me.
+ # Run this file to recreate the current configuration.
+@@ -5046,55 +4731,79 @@
+ debug=false
+ ac_cs_recheck=false
+ ac_cs_silent=false
+-SHELL=\${CONFIG_SHELL-$SHELL}
+-_ACEOF
+
+-cat >>$CONFIG_STATUS <<\_ACEOF
+-## --------------------- ##
+-## M4sh Initialization. ##
+-## --------------------- ##
++SHELL=\${CONFIG_SHELL-$SHELL}
++export SHELL
++_ASEOF
++cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
++## -------------------- ##
++## M4sh Initialization. ##
++## -------------------- ##
+
+-# Be Bourne compatible
+-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
++# Be more Bourne compatible
++DUALCASE=1; export DUALCASE # for MKS sh
++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+- # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+ else
+- case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
++ case `(set -o) 2>/dev/null` in #(
++ *posix*) :
++ set -o posix ;; #(
++ *) :
++ ;;
++esac
+ fi
+-BIN_SH=xpg4; export BIN_SH # for Tru64
+-DUALCASE=1; export DUALCASE # for MKS sh
+-
+
+-# PATH needs CR
+-# Avoid depending upon Character Ranges.
+-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+-as_cr_digits='0123456789'
+-as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+-# The user is always right.
+-if test "${PATH_SEPARATOR+set}" != set; then
+- echo "#! /bin/sh" >conf$$.sh
+- echo "exit 0" >>conf$$.sh
+- chmod +x conf$$.sh
+- if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+- PATH_SEPARATOR=';'
++as_nl='
++'
++export as_nl
++# Printing a long string crashes Solaris 7 /usr/bin/printf.
++as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
++# Prefer a ksh shell builtin over an external printf program on Solaris,
++# but without wasting forks for bash or zsh.
++if test -z "$BASH_VERSION$ZSH_VERSION" \
++ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
++ as_echo='print -r --'
++ as_echo_n='print -rn --'
++elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
++ as_echo='printf %s\n'
++ as_echo_n='printf %s'
++else
++ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
++ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
++ as_echo_n='/usr/ucb/echo -n'
+ else
+- PATH_SEPARATOR=:
++ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
++ as_echo_n_body='eval
++ arg=$1;
++ case $arg in #(
++ *"$as_nl"*)
++ expr "X$arg" : "X\\(.*\\)$as_nl";
++ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
++ esac;
++ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
++ '
++ export as_echo_n_body
++ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+- rm -f conf$$.sh
++ export as_echo_body
++ as_echo='sh -c $as_echo_body as_echo'
+ fi
+
+-# Support unset when possible.
+-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+- as_unset=unset
+-else
+- as_unset=false
++# The user is always right.
++if test "${PATH_SEPARATOR+set}" != set; then
++ PATH_SEPARATOR=:
++ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
++ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
++ PATH_SEPARATOR=';'
++ }
+ fi
+
+
+@@ -5103,20 +4812,19 @@
+ # there to prevent editors from complaining about space-tab.
+ # (If _AS_PATH_WALK were called with IFS unset, it would disable word
+ # splitting by setting IFS to empty value.)
+-as_nl='
+-'
+ IFS=" "" $as_nl"
+
+ # Find who we are. Look in the path if we contain no directory separator.
+-case $0 in
++as_myself=
++case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+ for as_dir in $PATH
+ do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+-done
++ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
++ done
+ IFS=$as_save_IFS
+
+ ;;
+@@ -5127,32 +4835,111 @@
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+- echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+- { (exit 1); exit 1; }
++ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
++ exit 1
+ fi
+
+-# Work around bugs in pre-3.0 UWIN ksh.
+-for as_var in ENV MAIL MAILPATH
+-do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
++# Unset variables that we do not need and which cause bugs (e.g. in
++# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
++# suppresses any "Segmentation fault" message there. '((' could
++# trigger a bug in pdksh 5.2.14.
++for as_var in BASH_ENV ENV MAIL MAILPATH
++do eval test x\${$as_var+set} = xset \
++ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+ done
+ PS1='$ '
+ PS2='> '
+ PS4='+ '
+
+ # NLS nuisances.
+-for as_var in \
+- LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+- LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+- LC_TELEPHONE LC_TIME
+-do
+- if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+- eval $as_var=C; export $as_var
+- else
+- ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+- fi
+-done
++LC_ALL=C
++export LC_ALL
++LANGUAGE=C
++export LANGUAGE
++
++# CDPATH.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
++
++
++# as_fn_error STATUS ERROR [LINENO LOG_FD]
++# ----------------------------------------
++# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
++# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
++# script with STATUS, using 1 if that was 0.
++as_fn_error ()
++{
++ as_status=$1; test $as_status -eq 0 && as_status=1
++ if test "$4"; then
++ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
++ fi
++ $as_echo "$as_me: error: $2" >&2
++ as_fn_exit $as_status
++} # as_fn_error
++
++
++# as_fn_set_status STATUS
++# -----------------------
++# Set $? to STATUS, without forking.
++as_fn_set_status ()
++{
++ return $1
++} # as_fn_set_status
++
++# as_fn_exit STATUS
++# -----------------
++# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
++as_fn_exit ()
++{
++ set +e
++ as_fn_set_status $1
++ exit $1
++} # as_fn_exit
++
++# as_fn_unset VAR
++# ---------------
++# Portably unset VAR.
++as_fn_unset ()
++{
++ { eval $1=; unset $1;}
++}
++as_unset=as_fn_unset
++# as_fn_append VAR VALUE
++# ----------------------
++# Append the text in VALUE to the end of the definition contained in VAR. Take
++# advantage of any shell optimizations that allow amortized linear growth over
++# repeated appends, instead of the typical quadratic growth present in naive
++# implementations.
++if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
++ eval 'as_fn_append ()
++ {
++ eval $1+=\$2
++ }'
++else
++ as_fn_append ()
++ {
++ eval $1=\$$1\$2
++ }
++fi # as_fn_append
++
++# as_fn_arith ARG...
++# ------------------
++# Perform arithmetic evaluation on the ARGs, and store the result in the
++# global $as_val. Take advantage of shells that can avoid forks. The arguments
++# must be portable across $(()) and expr.
++if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
++ eval 'as_fn_arith ()
++ {
++ as_val=$(( $* ))
++ }'
++else
++ as_fn_arith ()
++ {
++ as_val=`expr "$@" || test $? -eq 1`
++ }
++fi # as_fn_arith
++
+
+-# Required to use basename.
+ if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+@@ -5166,13 +4953,17 @@
+ as_basename=false
+ fi
+
++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
++ as_dirname=dirname
++else
++ as_dirname=false
++fi
+
+-# Name of the executable.
+ as_me=`$as_basename -- "$0" ||
+ $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+-echo X/"$0" |
++$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+@@ -5187,122 +4978,130 @@
+ }
+ s/.*/./; q'`
+
+-# CDPATH.
+-$as_unset CDPATH
+-
+-
+-
+- as_lineno_1=$LINENO
+- as_lineno_2=$LINENO
+- test "x$as_lineno_1" != "x$as_lineno_2" &&
+- test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+-
+- # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+- # uniformly replaced by the line number. The first 'sed' inserts a
+- # line-number line after each line using $LINENO; the second 'sed'
+- # does the real work. The second script uses 'N' to pair each
+- # line-number line with the line containing $LINENO, and appends
+- # trailing '-' during substitution so that $LINENO is not a special
+- # case at line end.
+- # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+- # scripts with optimization help from Paolo Bonzini. Blame Lee
+- # E. McMahon (1931-1989) for sed's syntax. :-)
+- sed -n '
+- p
+- /[$]LINENO/=
+- ' <$as_myself |
+- sed '
+- s/[$]LINENO.*/&-/
+- t lineno
+- b
+- :lineno
+- N
+- :loop
+- s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+- t loop
+- s/-\n.*//
+- ' >$as_me.lineno &&
+- chmod +x "$as_me.lineno" ||
+- { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+- { (exit 1); exit 1; }; }
+-
+- # Don't try to exec as it changes $[0], causing all sort of problems
+- # (the dirname of $[0] is not the place where we might find the
+- # original and so on. Autoconf is especially sensitive to this).
+- . "./$as_me.lineno"
+- # Exit status is that of the last command.
+- exit
+-}
+-
+-
+-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+- as_dirname=dirname
+-else
+- as_dirname=false
+-fi
++# Avoid depending upon Character Ranges.
++as_cr_letters='abcdefghijklmnopqrstuvwxyz'
++as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
++as_cr_Letters=$as_cr_letters$as_cr_LETTERS
++as_cr_digits='0123456789'
++as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ ECHO_C= ECHO_N= ECHO_T=
+-case `echo -n x` in
++case `echo -n x` in #(((((
+ -n*)
+- case `echo 'x\c'` in
++ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+- *) ECHO_C='\c';;
++ xy) ECHO_C='\c';;
++ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
++ ECHO_T=' ';;
+ esac;;
+ *)
+ ECHO_N='-n';;
+ esac
+
+-if expr a : '\(a\)' >/dev/null 2>&1 &&
+- test "X`expr 00001 : '.*\(...\)'`" = X001; then
+- as_expr=expr
+-else
+- as_expr=false
+-fi
+-
+ rm -f conf$$ conf$$.exe conf$$.file
+ if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+ else
+ rm -f conf$$.dir
+- mkdir conf$$.dir
++ mkdir conf$$.dir 2>/dev/null
+ fi
+-echo >conf$$.file
+-if ln -s conf$$.file conf$$ 2>/dev/null; then
+- as_ln_s='ln -s'
+- # ... but there are two gotchas:
+- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+- # In both cases, we have to default to `cp -p'.
+- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
++if (echo >conf$$.file) 2>/dev/null; then
++ if ln -s conf$$.file conf$$ 2>/dev/null; then
++ as_ln_s='ln -s'
++ # ... but there are two gotchas:
++ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
++ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
++ # In both cases, we have to default to `cp -p'.
++ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
++ as_ln_s='cp -p'
++ elif ln conf$$.file conf$$ 2>/dev/null; then
++ as_ln_s=ln
++ else
+ as_ln_s='cp -p'
+-elif ln conf$$.file conf$$ 2>/dev/null; then
+- as_ln_s=ln
++ fi
+ else
+ as_ln_s='cp -p'
+ fi
+ rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+ rmdir conf$$.dir 2>/dev/null
+
++
++# as_fn_mkdir_p
++# -------------
++# Create "$as_dir" as a directory, including parents if necessary.
++as_fn_mkdir_p ()
++{
++
++ case $as_dir in #(
++ -*) as_dir=./$as_dir;;
++ esac
++ test -d "$as_dir" || eval $as_mkdir_p || {
++ as_dirs=
++ while :; do
++ case $as_dir in #(
++ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
++ *) as_qdir=$as_dir;;
++ esac
++ as_dirs="'$as_qdir' $as_dirs"
++ as_dir=`$as_dirname -- "$as_dir" ||
++$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$as_dir" : 'X\(//\)[^/]' \| \
++ X"$as_dir" : 'X\(//\)$' \| \
++ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X"$as_dir" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++ test -d "$as_dir" && break
++ done
++ test -z "$as_dirs" || eval "mkdir $as_dirs"
++ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
++
++
++} # as_fn_mkdir_p
+ if mkdir -p . 2>/dev/null; then
+- as_mkdir_p=:
++ as_mkdir_p='mkdir -p "$as_dir"'
+ else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+ fi
+
+-# Find out whether ``test -x'' works. Don't use a zero-byte file, as
+-# systems may use methods other than mode bits to determine executability.
+-cat >conf$$.file <<_ASEOF
+-#! /bin/sh
+-exit 0
+-_ASEOF
+-chmod +x conf$$.file
+-if test -x conf$$.file >/dev/null 2>&1; then
+- as_executable_p="test -x"
++if test -x / >/dev/null 2>&1; then
++ as_test_x='test -x'
+ else
+- as_executable_p=:
++ if ls -dL / >/dev/null 2>&1; then
++ as_ls_L_option=L
++ else
++ as_ls_L_option=
++ fi
++ as_test_x='
++ eval sh -c '\''
++ if test -d "$1"; then
++ test -d "$1/.";
++ else
++ case $1 in #(
++ -*)set "./$1";;
++ esac;
++ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
++ ???[sx]*):;;*)false;;esac;fi
++ '\'' sh
++ '
+ fi
+-rm -f conf$$.file
++as_executable_p=$as_test_x
+
+ # Sed expression to map a string onto a valid CPP name.
+ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+@@ -5312,13 +5111,19 @@
+
+
+ exec 6>&1
++## ----------------------------------- ##
++## Main body of $CONFIG_STATUS script. ##
++## ----------------------------------- ##
++_ASEOF
++test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+-# Save the log message, to keep $[0] and so on meaningful, and to
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++# Save the log message, to keep $0 and so on meaningful, and to
+ # report actual input values of CONFIG_FILES etc. instead of their
+ # values after options handling.
+ ac_log="
+ This file was extended by exmap-console $as_me 0.4.1, which was
+-generated by GNU Autoconf 2.60. Invocation command line was
++generated by GNU Autoconf 2.68. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+@@ -5331,27 +5136,36 @@
+
+ _ACEOF
+
+-cat >>$CONFIG_STATUS <<_ACEOF
++case $ac_config_files in *"
++"*) set x $ac_config_files; shift; ac_config_files=$*;;
++esac
++
++
++
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ # Files that config.status was made for.
+ config_files="$ac_config_files"
+ config_commands="$ac_config_commands"
+
+ _ACEOF
+
+-cat >>$CONFIG_STATUS <<\_ACEOF
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ ac_cs_usage="\
+-\`$as_me' instantiates files from templates according to the
+-current configuration.
++\`$as_me' instantiates files and other configuration actions
++from templates according to the current configuration. Unless the files
++and actions are specified as TAGs, all are instantiated by default.
+
+-Usage: $0 [OPTIONS] [FILE]...
++Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+- -V, --version print version number, then exit
+- -q, --quiet do not print progress messages
++ -V, --version print version number and configuration settings, then exit
++ --config print configuration, then exit
++ -q, --quiet, --silent
++ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+- --file=FILE[:TEMPLATE]
+- instantiate the configuration file FILE
++ --file=FILE[:TEMPLATE]
++ instantiate the configuration file FILE
+
+ Configuration files:
+ $config_files
+@@ -5359,36 +5173,44 @@
+ Configuration commands:
+ $config_commands
+
+-Report bugs to <bug-autoconf@gnu.org>."
++Report bugs to <tf@o-hand.com>."
+
+ _ACEOF
+-cat >>$CONFIG_STATUS <<_ACEOF
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ ac_cs_version="\\
+ exmap-console config.status 0.4.1
+-configured by $0, generated by GNU Autoconf 2.60,
+- with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
++configured by $0, generated by GNU Autoconf 2.68,
++ with options \\"\$ac_cs_config\\"
+
+-Copyright (C) 2006 Free Software Foundation, Inc.
++Copyright (C) 2010 Free Software Foundation, Inc.
+ This config.status script is free software; the Free Software Foundation
+ gives unlimited permission to copy, distribute and modify it."
+
+ ac_pwd='$ac_pwd'
+ srcdir='$srcdir'
+ INSTALL='$INSTALL'
++MKDIR_P='$MKDIR_P'
++AWK='$AWK'
++test -n "\$AWK" || AWK=awk
+ _ACEOF
+
+-cat >>$CONFIG_STATUS <<\_ACEOF
+-# If no file are specified by the user, then we need to provide default
+-# value. By we need to know if files were specified by the user.
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++# The default lists apply if the user does not specify any file.
+ ac_need_defaults=:
+ while test $# != 0
+ do
+ case $1 in
+- --*=*)
++ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
++ --*=)
++ ac_option=`expr "X$1" : 'X\([^=]*\)='`
++ ac_optarg=
++ ac_shift=:
++ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+@@ -5401,25 +5223,30 @@
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+- echo "$ac_cs_version"; exit ;;
++ $as_echo "$ac_cs_version"; exit ;;
++ --config | --confi | --conf | --con | --co | --c )
++ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+- CONFIG_FILES="$CONFIG_FILES $ac_optarg"
++ case $ac_optarg in
++ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
++ '') as_fn_error $? "missing file argument" ;;
++ esac
++ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+- echo "$ac_cs_usage"; exit ;;
++ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+- -*) { echo "$as_me: error: unrecognized option: $1
+-Try \`$0 --help' for more information." >&2
+- { (exit 1); exit 1; }; } ;;
++ -*) as_fn_error $? "unrecognized option: \`$1'
++Try \`$0 --help' for more information." ;;
+
+- *) ac_config_targets="$ac_config_targets $1"
++ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+@@ -5434,27 +5261,29 @@
+ fi
+
+ _ACEOF
+-cat >>$CONFIG_STATUS <<_ACEOF
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ if \$ac_cs_recheck; then
+- echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+- CONFIG_SHELL=$SHELL
++ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
++ shift
++ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
++ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+- exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
++ exec "\$@"
+ fi
+
+ _ACEOF
+-cat >>$CONFIG_STATUS <<\_ACEOF
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ exec 5>>config.log
+ {
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+ ## Running $as_me. ##
+ _ASBOX
+- echo "$ac_log"
++ $as_echo "$ac_log"
+ } >&5
+
+ _ACEOF
+-cat >>$CONFIG_STATUS <<_ACEOF
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ #
+ # INIT-COMMANDS
+ #
+@@ -5462,7 +5291,7 @@
+
+ _ACEOF
+
+-cat >>$CONFIG_STATUS <<\_ACEOF
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+ # Handling of arguments.
+ for ac_config_target in $ac_config_targets
+@@ -5473,9 +5302,7 @@
+ "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+ "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+
+- *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+-echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+- { (exit 1); exit 1; }; };;
++ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+ done
+
+@@ -5497,200 +5324,194 @@
+ # after its creation but before its name has been assigned to `$tmp'.
+ $debug ||
+ {
+- tmp=
++ tmp= ac_tmp=
+ trap 'exit_status=$?
+- { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
++ : "${ac_tmp:=$tmp}"
++ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+ ' 0
+- trap '{ (exit 1); exit 1; }' 1 2 13 15
++ trap 'as_fn_exit 1' 1 2 13 15
+ }
+ # Create a (secure) tmp directory for tmp files.
+
+ {
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+- test -n "$tmp" && test -d "$tmp"
++ test -d "$tmp"
+ } ||
+ {
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+-} ||
+-{
+- echo "$me: cannot create a temporary directory in ." >&2
+- { (exit 1); exit 1; }
+-}
+-
+-#
+-# Set up the sed scripts for CONFIG_FILES section.
+-#
++} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
++ac_tmp=$tmp
+
+-# No need to generate the scripts if there are no CONFIG_FILES.
+-# This happens for instance when ./config.status config.h
++# Set up the scripts for CONFIG_FILES section.
++# No need to generate them if there are no CONFIG_FILES.
++# This happens for instance with `./config.status config.h'.
+ if test -n "$CONFIG_FILES"; then
+
+-_ACEOF
+
++ac_cr=`echo X | tr X '\015'`
++# On cygwin, bash can eat \r inside `` if the user requested igncr.
++# But we know of no other shell where ac_cr would be empty at this
++# point, so we can use a bashism as a fallback.
++if test "x$ac_cr" = x; then
++ eval ac_cr=\$\'\\r\'
++fi
++ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
++if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
++ ac_cs_awk_cr='\\r'
++else
++ ac_cs_awk_cr=$ac_cr
++fi
++
++echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
++_ACEOF
+
+
++{
++ echo "cat >conf$$subs.awk <<_ACEOF" &&
++ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
++ echo "_ACEOF"
++} >conf$$subs.sh ||
++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
++ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ ac_delim='%!_!# '
+ for ac_last_try in false false false false false :; do
+- cat >conf$$subs.sed <<_ACEOF
+-SHELL!$SHELL$ac_delim
+-PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim
+-PACKAGE_NAME!$PACKAGE_NAME$ac_delim
+-PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim
+-PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim
+-PACKAGE_STRING!$PACKAGE_STRING$ac_delim
+-PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim
+-exec_prefix!$exec_prefix$ac_delim
+-prefix!$prefix$ac_delim
+-program_transform_name!$program_transform_name$ac_delim
+-bindir!$bindir$ac_delim
+-sbindir!$sbindir$ac_delim
+-libexecdir!$libexecdir$ac_delim
+-datarootdir!$datarootdir$ac_delim
+-datadir!$datadir$ac_delim
+-sysconfdir!$sysconfdir$ac_delim
+-sharedstatedir!$sharedstatedir$ac_delim
+-localstatedir!$localstatedir$ac_delim
+-includedir!$includedir$ac_delim
+-oldincludedir!$oldincludedir$ac_delim
+-docdir!$docdir$ac_delim
+-infodir!$infodir$ac_delim
+-htmldir!$htmldir$ac_delim
+-dvidir!$dvidir$ac_delim
+-pdfdir!$pdfdir$ac_delim
+-psdir!$psdir$ac_delim
+-libdir!$libdir$ac_delim
+-localedir!$localedir$ac_delim
+-mandir!$mandir$ac_delim
+-DEFS!$DEFS$ac_delim
+-ECHO_C!$ECHO_C$ac_delim
+-ECHO_N!$ECHO_N$ac_delim
+-ECHO_T!$ECHO_T$ac_delim
+-LIBS!$LIBS$ac_delim
+-build_alias!$build_alias$ac_delim
+-host_alias!$host_alias$ac_delim
+-target_alias!$target_alias$ac_delim
+-INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim
+-INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim
+-INSTALL_DATA!$INSTALL_DATA$ac_delim
+-CYGPATH_W!$CYGPATH_W$ac_delim
+-PACKAGE!$PACKAGE$ac_delim
+-VERSION!$VERSION$ac_delim
+-ACLOCAL!$ACLOCAL$ac_delim
+-AUTOCONF!$AUTOCONF$ac_delim
+-AUTOMAKE!$AUTOMAKE$ac_delim
+-AUTOHEADER!$AUTOHEADER$ac_delim
+-MAKEINFO!$MAKEINFO$ac_delim
+-install_sh!$install_sh$ac_delim
+-STRIP!$STRIP$ac_delim
+-INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim
+-mkdir_p!$mkdir_p$ac_delim
+-AWK!$AWK$ac_delim
+-SET_MAKE!$SET_MAKE$ac_delim
+-am__leading_dot!$am__leading_dot$ac_delim
+-AMTAR!$AMTAR$ac_delim
+-am__tar!$am__tar$ac_delim
+-am__untar!$am__untar$ac_delim
+-CC!$CC$ac_delim
+-CFLAGS!$CFLAGS$ac_delim
+-LDFLAGS!$LDFLAGS$ac_delim
+-CPPFLAGS!$CPPFLAGS$ac_delim
+-ac_ct_CC!$ac_ct_CC$ac_delim
+-EXEEXT!$EXEEXT$ac_delim
+-OBJEXT!$OBJEXT$ac_delim
+-DEPDIR!$DEPDIR$ac_delim
+-am__include!$am__include$ac_delim
+-am__quote!$am__quote$ac_delim
+-AMDEP_TRUE!$AMDEP_TRUE$ac_delim
+-AMDEP_FALSE!$AMDEP_FALSE$ac_delim
+-AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim
+-CCDEPMODE!$CCDEPMODE$ac_delim
+-am__fastdepCC_TRUE!$am__fastdepCC_TRUE$ac_delim
+-am__fastdepCC_FALSE!$am__fastdepCC_FALSE$ac_delim
+-INTERACTIVE_TRUE!$INTERACTIVE_TRUE$ac_delim
+-INTERACTIVE_FALSE!$INTERACTIVE_FALSE$ac_delim
+-READLINE_LIBS!$READLINE_LIBS$ac_delim
+-READLINE_CFLAGS!$READLINE_CFLAGS$ac_delim
+-DODOCS_TRUE!$DODOCS_TRUE$ac_delim
+-DODOCS_FALSE!$DODOCS_FALSE$ac_delim
+-PKG_CONFIG!$PKG_CONFIG$ac_delim
+-GLIB_CFLAGS!$GLIB_CFLAGS$ac_delim
+-GLIB_LIBS!$GLIB_LIBS$ac_delim
+-HELPTOMAN!$HELPTOMAN$ac_delim
+-HAVE_HELPTOMAN_TRUE!$HAVE_HELPTOMAN_TRUE$ac_delim
+-HAVE_HELPTOMAN_FALSE!$HAVE_HELPTOMAN_FALSE$ac_delim
+-GCC_CFLAGS!$GCC_CFLAGS$ac_delim
+-LIBOBJS!$LIBOBJS$ac_delim
+-LTLIBOBJS!$LTLIBOBJS$ac_delim
+-_ACEOF
++ . ./conf$$subs.sh ||
++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 89; then
++ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
++ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+- { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+-echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+- { (exit 1); exit 1; }; }
++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+ done
++rm -f conf$$subs.sh
+
+-ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+-if test -n "$ac_eof"; then
+- ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+- ac_eof=`expr $ac_eof + 1`
+-fi
+-
+-cat >>$CONFIG_STATUS <<_ACEOF
+-cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
+-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+-_ACEOF
+-sed '
+-s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+-s/^/s,@/; s/!/@,|#_!!_#|/
+-:n
+-t n
+-s/'"$ac_delim"'$/,g/; t
+-s/$/\\/; p
+-N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+-' >>$CONFIG_STATUS <conf$$subs.sed
+-rm -f conf$$subs.sed
+-cat >>$CONFIG_STATUS <<_ACEOF
+-:end
+-s/|#_!!_#|//g
+-CEOF$ac_eof
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+ _ACEOF
++sed -n '
++h
++s/^/S["/; s/!.*/"]=/
++p
++g
++s/^[^!]*!//
++:repl
++t repl
++s/'"$ac_delim"'$//
++t delim
++:nl
++h
++s/\(.\{148\}\)..*/\1/
++t more1
++s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
++p
++n
++b repl
++:more1
++s/["\\]/\\&/g; s/^/"/; s/$/"\\/
++p
++g
++s/.\{148\}//
++t nl
++:delim
++h
++s/\(.\{148\}\)..*/\1/
++t more2
++s/["\\]/\\&/g; s/^/"/; s/$/"/
++p
++b
++:more2
++s/["\\]/\\&/g; s/^/"/; s/$/"\\/
++p
++g
++s/.\{148\}//
++t delim
++' <conf$$subs.awk | sed '
++/^[^""]/{
++ N
++ s/\n//
++}
++' >>$CONFIG_STATUS || ac_write_fail=1
++rm -f conf$$subs.awk
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++_ACAWK
++cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
++ for (key in S) S_is_set[key] = 1
++ FS = ""
++
++}
++{
++ line = $ 0
++ nfields = split(line, field, "@")
++ substed = 0
++ len = length(field[1])
++ for (i = 2; i < nfields; i++) {
++ key = field[i]
++ keylen = length(key)
++ if (S_is_set[key]) {
++ value = S[key]
++ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
++ len += length(value) + length(field[++i])
++ substed = 1
++ } else
++ len += 1 + keylen
++ }
++
++ print line
++}
+
++_ACAWK
++_ACEOF
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
++ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
++else
++ cat
++fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
++ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
++_ACEOF
+
+-# VPATH may cause trouble with some makes, so we remove $(srcdir),
+-# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
++# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
++# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+ # trailing colons and then remove the whole line if VPATH becomes empty
+ # (actually we leave an empty line to preserve line numbers).
+ if test "x$srcdir" = x.; then
+- ac_vpsub='/^[ ]*VPATH[ ]*=/{
+-s/:*\$(srcdir):*/:/
+-s/:*\${srcdir}:*/:/
+-s/:*@srcdir@:*/:/
+-s/^\([^=]*=[ ]*\):*/\1/
++ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
++h
++s///
++s/^/:/
++s/[ ]*$/:/
++s/:\$(srcdir):/:/g
++s/:\${srcdir}:/:/g
++s/:@srcdir@:/:/g
++s/^:*//
+ s/:*$//
++x
++s/\(=[ ]*\).*/\1/
++G
++s/\n//
+ s/^[^=]*=[ ]*$//
+ }'
+ fi
+
+-cat >>$CONFIG_STATUS <<\_ACEOF
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ fi # test -n "$CONFIG_FILES"
+
+
+-for ac_tag in :F $CONFIG_FILES :C $CONFIG_COMMANDS
++eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS"
++shift
++for ac_tag
+ do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+- :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
+-echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+- { (exit 1); exit 1; }; };;
++ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+@@ -5709,7 +5530,7 @@
+ for ac_f
+ do
+ case $ac_f in
+- -) ac_f="$tmp/stdin";;
++ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+@@ -5718,26 +5539,34 @@
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+- { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+-echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+- { (exit 1); exit 1; }; };;
++ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+- ac_file_inputs="$ac_file_inputs $ac_f"
++ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
++ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+- configure_input="Generated from "`IFS=:
+- echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
++ configure_input='Generated from '`
++ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
++ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+- { echo "$as_me:$LINENO: creating $ac_file" >&5
+-echo "$as_me: creating $ac_file" >&6;}
++ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
++$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
++ # Neutralize special characters interpreted by sed in replacement strings.
++ case $configure_input in #(
++ *\&* | *\|* | *\\* )
++ ac_sed_conf_input=`$as_echo "$configure_input" |
++ sed 's/[\\\\&|]/\\\\&/g'`;; #(
++ *) ac_sed_conf_input=$configure_input;;
++ esac
+
+ case $ac_tag in
+- *:-:* | *:-) cat >"$tmp/stdin";;
++ *:-:* | *:-) cat >"$ac_tmp/stdin" \
++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+@@ -5747,42 +5576,7 @@
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+-echo X"$ac_file" |
+- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+- s//\1/
+- q
+- }
+- /^X\(\/\/\)[^/].*/{
+- s//\1/
+- q
+- }
+- /^X\(\/\/\)$/{
+- s//\1/
+- q
+- }
+- /^X\(\/\).*/{
+- s//\1/
+- q
+- }
+- s/.*/./; q'`
+- { as_dir="$ac_dir"
+- case $as_dir in #(
+- -*) as_dir=./$as_dir;;
+- esac
+- test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+- as_dirs=
+- while :; do
+- case $as_dir in #(
+- *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
+- *) as_qdir=$as_dir;;
+- esac
+- as_dirs="'$as_qdir' $as_dirs"
+- as_dir=`$as_dirname -- "$as_dir" ||
+-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+- X"$as_dir" : 'X\(//\)[^/]' \| \
+- X"$as_dir" : 'X\(//\)$' \| \
+- X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+-echo X"$as_dir" |
++$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+@@ -5800,20 +5594,15 @@
+ q
+ }
+ s/.*/./; q'`
+- test -d "$as_dir" && break
+- done
+- test -z "$as_dirs" || eval "mkdir $as_dirs"
+- } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+-echo "$as_me: error: cannot create directory $as_dir" >&2;}
+- { (exit 1); exit 1; }; }; }
++ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+ case "$ac_dir" in
+ .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *)
+- ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
++ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+- ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
++ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+@@ -5851,14 +5640,19 @@
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
++ ac_MKDIR_P=$MKDIR_P
++ case $MKDIR_P in
++ [\\/$]* | ?:[\\/]* ) ;;
++ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
++ esac
+ _ACEOF
+
+-cat >>$CONFIG_STATUS <<\_ACEOF
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ # If the template does not know about datarootdir, expand it.
+ # FIXME: This hack should be removed a few years after 2.60.
+ ac_datarootdir_hack=; ac_datarootdir_seen=
+-
+-case `sed -n '/datarootdir/ {
++ac_sed_dataroot='
++/datarootdir/ {
+ p
+ q
+ }
+@@ -5866,36 +5660,37 @@
+ /@docdir@/p
+ /@infodir@/p
+ /@localedir@/p
+-/@mandir@/p
+-' $ac_file_inputs` in
++/@mandir@/p'
++case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+ *datarootdir*) ac_datarootdir_seen=yes;;
+ *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+- { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+-echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
++$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+ _ACEOF
+-cat >>$CONFIG_STATUS <<_ACEOF
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+- s&\\\${datarootdir}&$datarootdir&g' ;;
++ s&\\\${datarootdir}&$datarootdir&g' ;;
+ esac
+ _ACEOF
+
+ # Neutralize VPATH when `$srcdir' = `.'.
+ # Shell code in configure.ac might set extrasub.
+ # FIXME: do we really want to maintain this feature?
+-cat >>$CONFIG_STATUS <<_ACEOF
+- sed "$ac_vpsub
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++ac_sed_extra="$ac_vpsub
+ $extrasub
+ _ACEOF
+-cat >>$CONFIG_STATUS <<\_ACEOF
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ :t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+-s&@configure_input@&$configure_input&;t t
++s|@configure_input@|$ac_sed_conf_input|;t t
+ s&@top_builddir@&$ac_top_builddir_sub&;t t
++s&@top_build_prefix@&$ac_top_build_prefix&;t t
+ s&@srcdir@&$ac_srcdir&;t t
+ s&@abs_srcdir@&$ac_abs_srcdir&;t t
+ s&@top_srcdir@&$ac_top_srcdir&;t t
+@@ -5904,48 +5699,64 @@
+ s&@abs_builddir@&$ac_abs_builddir&;t t
+ s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+ s&@INSTALL@&$ac_INSTALL&;t t
++s&@MKDIR_P@&$ac_MKDIR_P&;t t
+ $ac_datarootdir_hack
+-" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out
++"
++eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
++ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+- { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+- { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+- { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+-which seems to be undefined. Please make sure it is defined." >&5
+-echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+-which seems to be undefined. Please make sure it is defined." >&2;}
++ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
++ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
++ "$ac_tmp/out"`; test -z "$ac_out"; } &&
++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
++which seems to be undefined. Please make sure it is defined" >&5
++$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
++which seems to be undefined. Please make sure it is defined" >&2;}
+
+- rm -f "$tmp/stdin"
++ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+- -) cat "$tmp/out"; rm -f "$tmp/out";;
+- *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;
+- esac
++ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
++ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
++ esac \
++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+- :C) { echo "$as_me:$LINENO: executing $ac_file commands" >&5
+-echo "$as_me: executing $ac_file commands" >&6;}
++ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
++$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+- "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do
+- # Strip MF so we end up with the name of the file.
+- mf=`echo "$mf" | sed -e 's/:.*$//'`
+- # Check whether this is an Automake generated Makefile or not.
+- # We used to match only the files named `Makefile.in', but
+- # some people rename them; so instead we look at the file content.
+- # Grep'ing the first line is not enough: some people post-process
+- # each Makefile.in and add a new line on top of each file to say so.
+- # So let's grep whole file.
+- if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+- dirpart=`$as_dirname -- "$mf" ||
++ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
++ # Autoconf 2.62 quotes --file arguments for eval, but not when files
++ # are listed without --file. Let's play safe and only enable the eval
++ # if we detect the quoting.
++ case $CONFIG_FILES in
++ *\'*) eval set x "$CONFIG_FILES" ;;
++ *) set x $CONFIG_FILES ;;
++ esac
++ shift
++ for mf
++ do
++ # Strip MF so we end up with the name of the file.
++ mf=`echo "$mf" | sed -e 's/:.*$//'`
++ # Check whether this is an Automake generated Makefile or not.
++ # We used to match only the files named `Makefile.in', but
++ # some people rename them; so instead we look at the file content.
++ # Grep'ing the first line is not enough: some people post-process
++ # each Makefile.in and add a new line on top of each file to say so.
++ # Grep'ing the whole file is not good either: AIX grep has a line
++ # limit of 2048, but all sed's we know have understand at least 4000.
++ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
++ dirpart=`$as_dirname -- "$mf" ||
+ $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+-echo X"$mf" |
++$as_echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+@@ -5963,68 +5774,33 @@
+ q
+ }
+ s/.*/./; q'`
+- else
+- continue
+- fi
+- # Extract the definition of DEPDIR, am__include, and am__quote
+- # from the Makefile without running `make'.
+- DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+- test -z "$DEPDIR" && continue
+- am__include=`sed -n 's/^am__include = //p' < "$mf"`
+- test -z "am__include" && continue
+- am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+- # When using ansi2knr, U may be empty or an underscore; expand it
+- U=`sed -n 's/^U = //p' < "$mf"`
+- # Find all dependency output files, they are included files with
+- # $(DEPDIR) in their names. We invoke sed twice because it is the
+- # simplest approach to changing $(DEPDIR) to its actual value in the
+- # expansion.
+- for file in `sed -n "
+- s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+- sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+- # Make sure the directory exists.
+- test -f "$dirpart/$file" && continue
+- fdir=`$as_dirname -- "$file" ||
++ else
++ continue
++ fi
++ # Extract the definition of DEPDIR, am__include, and am__quote
++ # from the Makefile without running `make'.
++ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
++ test -z "$DEPDIR" && continue
++ am__include=`sed -n 's/^am__include = //p' < "$mf"`
++ test -z "am__include" && continue
++ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
++ # When using ansi2knr, U may be empty or an underscore; expand it
++ U=`sed -n 's/^U = //p' < "$mf"`
++ # Find all dependency output files, they are included files with
++ # $(DEPDIR) in their names. We invoke sed twice because it is the
++ # simplest approach to changing $(DEPDIR) to its actual value in the
++ # expansion.
++ for file in `sed -n "
++ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
++ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
++ # Make sure the directory exists.
++ test -f "$dirpart/$file" && continue
++ fdir=`$as_dirname -- "$file" ||
+ $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+-echo X"$file" |
+- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+- s//\1/
+- q
+- }
+- /^X\(\/\/\)[^/].*/{
+- s//\1/
+- q
+- }
+- /^X\(\/\/\)$/{
+- s//\1/
+- q
+- }
+- /^X\(\/\).*/{
+- s//\1/
+- q
+- }
+- s/.*/./; q'`
+- { as_dir=$dirpart/$fdir
+- case $as_dir in #(
+- -*) as_dir=./$as_dir;;
+- esac
+- test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+- as_dirs=
+- while :; do
+- case $as_dir in #(
+- *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
+- *) as_qdir=$as_dir;;
+- esac
+- as_dirs="'$as_qdir' $as_dirs"
+- as_dir=`$as_dirname -- "$as_dir" ||
+-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+- X"$as_dir" : 'X\(//\)[^/]' \| \
+- X"$as_dir" : 'X\(//\)$' \| \
+- X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+-echo X"$as_dir" |
++$as_echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+@@ -6042,27 +5818,25 @@
+ q
+ }
+ s/.*/./; q'`
+- test -d "$as_dir" && break
++ as_dir=$dirpart/$fdir; as_fn_mkdir_p
++ # echo "creating $dirpart/$file"
++ echo '# dummy' > "$dirpart/$file"
+ done
+- test -z "$as_dirs" || eval "mkdir $as_dirs"
+- } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+-echo "$as_me: error: cannot create directory $as_dir" >&2;}
+- { (exit 1); exit 1; }; }; }
+- # echo "creating $dirpart/$file"
+- echo '# dummy' > "$dirpart/$file"
+ done
+-done
++}
+ ;;
+
+ esac
+ done # for ac_tag
+
+
+-{ (exit 0); exit 0; }
++as_fn_exit 0
+ _ACEOF
+-chmod +x $CONFIG_STATUS
+ ac_clean_files=$ac_clean_files_save
+
++test $ac_write_fail = 0 ||
++ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
++
+
+ # configure is writing to config.log, and then calls config.status.
+ # config.status does its own redirection, appending to config.log.
+@@ -6082,14 +5856,18 @@
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+- $ac_cs_success || { (exit 1); exit 1; }
++ $ac_cs_success || as_fn_exit 1
++fi
++if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
++$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+ fi
+
+
+ if test x$WITH_READLINE = xerror ; then
+- { echo "$as_me:$LINENO: result: WARNING: Could not link against readline libraries; interactive mode will not be available." >&5
+-echo "${ECHO_T}WARNING: Could not link against readline libraries; interactive mode will not be available." >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: WARNING: Could not link against readline libraries; interactive mode will not be available." >&5
++$as_echo "WARNING: Could not link against readline libraries; interactive mode will not be available." >&6; }
+ fi
+
+-{ echo "$as_me:$LINENO: result: Type make to build exmap-console." >&5
+-echo "${ECHO_T}Type make to build exmap-console." >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Type make to build exmap-console." >&5
++$as_echo "Type make to build exmap-console." >&6; }
+diff -Nur exmap-console-0.4.1.orig/configure.ac exmap-console-0.4.1/configure.ac
+--- exmap-console-0.4.1.orig/configure.ac 2007-02-26 12:00:48.000000000 +0100
++++ exmap-console-0.4.1/configure.ac 2011-01-11 12:44:09.000000000 +0100
+@@ -46,10 +46,6 @@
+
+ AM_CONDITIONAL(DODOCS, test "x$DO_DOCS" != "xno")
+
+-AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug],
+- [Enable debuggin information]),
+- [CFLAGS="-g -O0"], [CFLAGS="-g -O2"])
+-
+ CFLAGS="$CFLAGS -DEXMAP_VERSION=\\\"$EXMAP_VERSION\\\" -DEXMAP_PROTOCOL_VERSION=\\\"$EXMAP_PROTOCOL_VERSION\\\""
+
+ AC_SUBST(CFLAGS)
+diff -Nur exmap-console-0.4.1.orig/depcomp exmap-console-0.4.1/depcomp
+--- exmap-console-0.4.1.orig/depcomp 2007-02-26 12:44:02.000000000 +0100
++++ exmap-console-0.4.1/depcomp 2011-01-11 12:44:16.000000000 +0100
+@@ -1,9 +1,10 @@
+ #! /bin/sh
+ # depcomp - compile a program generating dependencies as side-effects
+
+-scriptversion=2005-07-09.11
++scriptversion=2009-04-28.21; # UTC
+
+-# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
++# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free
++# Software Foundation, Inc.
+
+ # 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
+@@ -16,9 +17,7 @@
+ # 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 Street, Fifth Floor, Boston, MA
+-# 02110-1301, USA.
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ # As a special exception to the GNU General Public License, if you
+ # distribute this file as part of a program that contains a
+@@ -86,12 +85,34 @@
+ depmode=dashmstdout
+ fi
+
++cygpath_u="cygpath -u -f -"
++if test "$depmode" = msvcmsys; then
++ # This is just like msvisualcpp but w/o cygpath translation.
++ # Just convert the backslash-escaped backslashes to single forward
++ # slashes to satisfy depend.m4
++ cygpath_u="sed s,\\\\\\\\,/,g"
++ depmode=msvisualcpp
++fi
++
+ case "$depmode" in
+ gcc3)
+ ## gcc 3 implements dependency tracking that does exactly what
+ ## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+ ## it if -MD -MP comes after the -MF stuff. Hmm.
+- "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
++## Unfortunately, FreeBSD c89 acceptance of flags depends upon
++## the command line argument order; so add the flags where they
++## appear in depend2.am. Note that the slowdown incurred here
++## affects only configure: in makefiles, %FASTDEP% shortcuts this.
++ for arg
++ do
++ case $arg in
++ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
++ *) set fnord "$@" "$arg" ;;
++ esac
++ shift # fnord
++ shift # $arg
++ done
++ "$@"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+@@ -178,14 +199,14 @@
+ ' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+-' ' ' >> $depfile
+- echo >> $depfile
++' ' ' >> "$depfile"
++ echo >> "$depfile"
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+ ' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+- >> $depfile
++ >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+@@ -201,34 +222,39 @@
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+- stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
+- tmpdepfile="$stripped.u"
++ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
++ test "x$dir" = "x$object" && dir=
++ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
++ tmpdepfile1=$dir$base.u
++ tmpdepfile2=$base.u
++ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
++ tmpdepfile1=$dir$base.u
++ tmpdepfile2=$dir$base.u
++ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+
+- if test -f "$tmpdepfile"; then :
+- else
+- stripped=`echo "$stripped" | sed 's,^.*/,,'`
+- tmpdepfile="$stripped.u"
+- fi
+-
+ if test $stat -eq 0; then :
+ else
+- rm -f "$tmpdepfile"
++ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
++ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
++ do
++ test -f "$tmpdepfile" && break
++ done
+ if test -f "$tmpdepfile"; then
+- outname="$stripped.o"
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+- sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+- sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
++ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
++ # That's a tab and a space in the [].
++ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+@@ -276,6 +302,51 @@
+ rm -f "$tmpdepfile"
+ ;;
+
++hp2)
++ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
++ # compilers, which have integrated preprocessors. The correct option
++ # to use with these is +Maked; it writes dependencies to a file named
++ # 'foo.d', which lands next to the object file, wherever that
++ # happens to be.
++ # Much of this is similar to the tru64 case; see comments there.
++ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
++ test "x$dir" = "x$object" && dir=
++ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
++ if test "$libtool" = yes; then
++ tmpdepfile1=$dir$base.d
++ tmpdepfile2=$dir.libs/$base.d
++ "$@" -Wc,+Maked
++ else
++ tmpdepfile1=$dir$base.d
++ tmpdepfile2=$dir$base.d
++ "$@" +Maked
++ fi
++ stat=$?
++ if test $stat -eq 0; then :
++ else
++ rm -f "$tmpdepfile1" "$tmpdepfile2"
++ exit $stat
++ fi
++
++ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
++ do
++ test -f "$tmpdepfile" && break
++ done
++ if test -f "$tmpdepfile"; then
++ sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
++ # Add `dependent.h:' lines.
++ sed -ne '2,${
++ s/^ *//
++ s/ \\*$//
++ s/$/:/
++ p
++ }' "$tmpdepfile" >> "$depfile"
++ else
++ echo "#dummy" > "$depfile"
++ fi
++ rm -f "$tmpdepfile" "$tmpdepfile2"
++ ;;
++
+ tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+@@ -288,13 +359,13 @@
+
+ if test "$libtool" = yes; then
+ # With Tru64 cc, shared objects can also be used to make a
+- # static library. This mecanism is used in libtool 1.4 series to
++ # static library. This mechanism is used in libtool 1.4 series to
+ # handle both shared and static libraries in a single compilation.
+ # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+ #
+ # With libtool 1.5 this exception was removed, and libtool now
+ # generates 2 separate objects for the 2 libraries. These two
+- # compilations output dependencies in in $dir.libs/$base.o.d and
++ # compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+@@ -345,7 +416,7 @@
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+- while test $1 != '--mode=compile'; do
++ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+@@ -396,32 +467,39 @@
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+- while test $1 != '--mode=compile'; do
++ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+- cleared=no
+- for arg in "$@"; do
++ cleared=no eat=no
++ for arg
++ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
++ if test $eat = yes; then
++ eat=no
++ continue
++ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
++ -arch)
++ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+- obj_suffix="`echo $object | sed 's/^.*\././'`"
++ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+@@ -441,7 +519,7 @@
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+- while test $1 != '--mode=compile'; do
++ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+@@ -479,13 +557,27 @@
+
+ msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+- # always write the preprocessed file to stdout, regardless of -o,
+- # because we must use -o when running libtool.
++ # always write the preprocessed file to stdout.
+ "$@" || exit $?
++
++ # Remove the call to Libtool.
++ if test "$libtool" = yes; then
++ while test "X$1" != 'X--mode=compile'; do
++ shift
++ done
++ shift
++ fi
++
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
++ -o)
++ shift
++ ;;
++ $object)
++ shift
++ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+@@ -498,16 +590,23 @@
+ ;;
+ esac
+ done
+- "$@" -E |
+- sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
++ "$@" -E 2>/dev/null |
++ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+- . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
++ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+- . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
++ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
++msvcmsys)
++ # This case exists only to let depend.m4 do its work. It works by
++ # looking at the text of this script. This case will never be run,
++ # since it is checked for above.
++ exit 1
++ ;;
++
+ none)
+ exec "$@"
+ ;;
+@@ -526,5 +625,6 @@
+ # eval: (add-hook 'write-file-hooks 'time-stamp)
+ # time-stamp-start: "scriptversion="
+ # time-stamp-format: "%:y-%02m-%02d.%02H"
+-# time-stamp-end: "$"
++# time-stamp-time-zone: "UTC"
++# time-stamp-end: "; # UTC"
+ # End:
+diff -Nur exmap-console-0.4.1.orig/doc/Makefile.in exmap-console-0.4.1/doc/Makefile.in
+--- exmap-console-0.4.1.orig/doc/Makefile.in 2007-02-26 12:44:02.000000000 +0100
++++ exmap-console-0.4.1/doc/Makefile.in 2011-01-11 12:44:16.000000000 +0100
+@@ -1,8 +1,9 @@
+-# Makefile.in generated by automake 1.9.6 from Makefile.am.
++# Makefile.in generated by automake 1.11.1 from Makefile.am.
+ # @configure_input@
+
+ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+-# 2003, 2004, 2005 Free Software Foundation, Inc.
++# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
++# Inc.
+ # This Makefile.in is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+@@ -13,15 +14,12 @@
+ # PARTICULAR PURPOSE.
+
+ @SET_MAKE@
+-srcdir = @srcdir@
+-top_srcdir = @top_srcdir@
+ VPATH = @srcdir@
+ pkgdatadir = $(datadir)/@PACKAGE@
+-pkglibdir = $(libdir)/@PACKAGE@
+ pkgincludedir = $(includedir)/@PACKAGE@
+-top_builddir = ..
++pkglibdir = $(libdir)/@PACKAGE@
++pkglibexecdir = $(libexecdir)/@PACKAGE@
+ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+-INSTALL = @INSTALL@
+ install_sh_DATA = $(install_sh) -c -m 644
+ install_sh_PROGRAM = $(install_sh) -c
+ install_sh_SCRIPT = $(install_sh) -c
+@@ -41,16 +39,36 @@
+ $(ACLOCAL_M4)
+ mkinstalldirs = $(install_sh) -d
+ CONFIG_CLEAN_FILES =
++CONFIG_CLEAN_VPATH_FILES =
+ SOURCES =
+ DIST_SOURCES =
++am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
++am__vpath_adj = case $$p in \
++ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
++ *) f=$$p;; \
++ esac;
++am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
++am__install_max = 40
++am__nobase_strip_setup = \
++ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
++am__nobase_strip = \
++ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
++am__nobase_list = $(am__nobase_strip_setup); \
++ for p in $$list; do echo "$$p $$p"; done | \
++ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
++ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
++ if (++n[$$2] == $(am__install_max)) \
++ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
++ END { for (dir in files) print dir, files[dir] }'
++am__base_list = \
++ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
++ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+ man1dir = $(mandir)/man1
+ am__installdirs = "$(DESTDIR)$(man1dir)"
+ NROFF = nroff
+ MANS = $(man_MANS)
+ DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ ACLOCAL = @ACLOCAL@
+-AMDEP_FALSE = @AMDEP_FALSE@
+-AMDEP_TRUE = @AMDEP_TRUE@
+ AMTAR = @AMTAR@
+ AUTOCONF = @AUTOCONF@
+ AUTOHEADER = @AUTOHEADER@
+@@ -63,8 +81,6 @@
+ CYGPATH_W = @CYGPATH_W@
+ DEFS = @DEFS@
+ DEPDIR = @DEPDIR@
+-DODOCS_FALSE = @DODOCS_FALSE@
+-DODOCS_TRUE = @DODOCS_TRUE@
+ ECHO_C = @ECHO_C@
+ ECHO_N = @ECHO_N@
+ ECHO_T = @ECHO_T@
+@@ -72,38 +88,41 @@
+ GCC_CFLAGS = @GCC_CFLAGS@
+ GLIB_CFLAGS = @GLIB_CFLAGS@
+ GLIB_LIBS = @GLIB_LIBS@
+-HAVE_HELPTOMAN_FALSE = @HAVE_HELPTOMAN_FALSE@
+-HAVE_HELPTOMAN_TRUE = @HAVE_HELPTOMAN_TRUE@
+ HELPTOMAN = @HELPTOMAN@
++INSTALL = @INSTALL@
+ INSTALL_DATA = @INSTALL_DATA@
+ INSTALL_PROGRAM = @INSTALL_PROGRAM@
+ INSTALL_SCRIPT = @INSTALL_SCRIPT@
+ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+-INTERACTIVE_FALSE = @INTERACTIVE_FALSE@
+-INTERACTIVE_TRUE = @INTERACTIVE_TRUE@
+ LDFLAGS = @LDFLAGS@
+ LIBOBJS = @LIBOBJS@
+ LIBS = @LIBS@
+ LTLIBOBJS = @LTLIBOBJS@
+ MAKEINFO = @MAKEINFO@
++MKDIR_P = @MKDIR_P@
+ OBJEXT = @OBJEXT@
+ PACKAGE = @PACKAGE@
+ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+ PACKAGE_NAME = @PACKAGE_NAME@
+ PACKAGE_STRING = @PACKAGE_STRING@
+ PACKAGE_TARNAME = @PACKAGE_TARNAME@
++PACKAGE_URL = @PACKAGE_URL@
+ PACKAGE_VERSION = @PACKAGE_VERSION@
+ PATH_SEPARATOR = @PATH_SEPARATOR@
+ PKG_CONFIG = @PKG_CONFIG@
++PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
++PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+ READLINE_CFLAGS = @READLINE_CFLAGS@
+ READLINE_LIBS = @READLINE_LIBS@
+ SET_MAKE = @SET_MAKE@
+ SHELL = @SHELL@
+ STRIP = @STRIP@
+ VERSION = @VERSION@
++abs_builddir = @abs_builddir@
++abs_srcdir = @abs_srcdir@
++abs_top_builddir = @abs_top_builddir@
++abs_top_srcdir = @abs_top_srcdir@
+ ac_ct_CC = @ac_ct_CC@
+-am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+-am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+ am__include = @am__include@
+ am__leading_dot = @am__leading_dot@
+ am__quote = @am__quote@
+@@ -111,6 +130,7 @@
+ am__untar = @am__untar@
+ bindir = @bindir@
+ build_alias = @build_alias@
++builddir = @builddir@
+ datadir = @datadir@
+ datarootdir = @datarootdir@
+ docdir = @docdir@
+@@ -134,8 +154,12 @@
+ psdir = @psdir@
+ sbindir = @sbindir@
+ sharedstatedir = @sharedstatedir@
++srcdir = @srcdir@
+ sysconfdir = @sysconfdir@
+ target_alias = @target_alias@
++top_build_prefix = @top_build_prefix@
++top_builddir = @top_builddir@
++top_srcdir = @top_srcdir@
+ DISTCLEANFILES = *~ Makefile.in
+ @DODOCS_TRUE@@INTERACTIVE_TRUE@interactive = exmapserver.1
+ @DODOCS_TRUE@man_MANS = exmap.1 exmapd.1 $(interactive)
+@@ -146,14 +170,14 @@
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+- && exit 0; \
++ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
++ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \
+- cd $(top_srcdir) && \
+- $(AUTOMAKE) --gnu doc/Makefile
++ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \
++ $(am__cd) $(top_srcdir) && \
++ $(AUTOMAKE) --gnu doc/Makefile
+ .PRECIOUS: Makefile
+ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+@@ -171,52 +195,45 @@
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+ $(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+-uninstall-info-am:
+-install-man1: $(man1_MANS) $(man_MANS)
++$(am__aclocal_m4_deps):
++install-man1: $(man_MANS)
+ @$(NORMAL_INSTALL)
+- test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)"
+- @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+- l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+- for i in $$l2; do \
+- case "$$i" in \
+- *.1*) list="$$list $$i" ;; \
+- esac; \
++ test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
++ @list=''; test -n "$(man1dir)" || exit 0; \
++ { for i in $$list; do echo "$$i"; done; \
++ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
++ sed -n '/\.1[a-z]*$$/p'; \
++ } | while read p; do \
++ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
++ echo "$$d$$p"; echo "$$p"; \
++ done | \
++ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
++ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
++ sed 'N;N;s,\n, ,g' | { \
++ list=; while read file base inst; do \
++ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
++ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
++ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
++ fi; \
+ done; \
+- for i in $$list; do \
+- if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+- else file=$$i; fi; \
+- ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+- case "$$ext" in \
+- 1*) ;; \
+- *) ext='1' ;; \
+- esac; \
+- inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+- inst=`echo $$inst | sed -e 's/^.*\///'`; \
+- inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+- echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+- $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
+- done
++ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
++ while read files; do \
++ test -z "$$files" || { \
++ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
++ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
++ done; }
++
+ uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+- @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+- l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+- for i in $$l2; do \
+- case "$$i" in \
+- *.1*) list="$$list $$i" ;; \
+- esac; \
+- done; \
+- for i in $$list; do \
+- ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+- case "$$ext" in \
+- 1*) ;; \
+- *) ext='1' ;; \
+- esac; \
+- inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+- inst=`echo $$inst | sed -e 's/^.*\///'`; \
+- inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+- echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
+- rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
+- done
++ @list=''; test -n "$(man1dir)" || exit 0; \
++ files=`{ for i in $$list; do echo "$$i"; done; \
++ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
++ sed -n '/\.1[a-z]*$$/p'; \
++ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
++ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
++ test -z "$$files" || { \
++ echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \
++ cd "$(DESTDIR)$(man1dir)" && rm -f $$files; }
+ tags: TAGS
+ TAGS:
+
+@@ -225,29 +242,45 @@
+
+
+ distdir: $(DISTFILES)
+- @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+- topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+- list='$(DISTFILES)'; for file in $$list; do \
+- case $$file in \
+- $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+- $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+- esac; \
++ @list='$(MANS)'; if test -n "$$list"; then \
++ list=`for p in $$list; do \
++ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
++ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
++ if test -n "$$list" && \
++ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
++ echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \
++ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \
++ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \
++ echo " typically \`make maintainer-clean' will remove them" >&2; \
++ exit 1; \
++ else :; fi; \
++ else :; fi
++ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
++ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
++ list='$(DISTFILES)'; \
++ dist_files=`for file in $$list; do echo $$file; done | \
++ sed -e "s|^$$srcdirstrip/||;t" \
++ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
++ case $$dist_files in \
++ */*) $(MKDIR_P) `echo "$$dist_files" | \
++ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
++ sort -u` ;; \
++ esac; \
++ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+- dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+- if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+- dir="/$$dir"; \
+- $(mkdir_p) "$(distdir)$$dir"; \
+- else \
+- dir=''; \
+- fi; \
+ if test -d $$d/$$file; then \
++ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
++ if test -d "$(distdir)/$$file"; then \
++ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
++ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+- cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
++ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
++ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+- cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
++ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+- test -f $(distdir)/$$file \
+- || cp -p $$d/$$file $(distdir)/$$file \
++ test -f "$(distdir)/$$file" \
++ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+@@ -256,7 +289,7 @@
+ all-am: Makefile $(MANS)
+ installdirs:
+ for dir in "$(DESTDIR)$(man1dir)"; do \
+- test -z "$$dir" || $(mkdir_p) "$$dir"; \
++ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+ install: install-am
+ install-exec: install-exec-am
+@@ -278,6 +311,7 @@
+
+ distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
++ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+ maintainer-clean-generic:
+@@ -297,18 +331,38 @@
+
+ html: html-am
+
++html-am:
++
+ info: info-am
+
+ info-am:
+
+ install-data-am: install-man
+
++install-dvi: install-dvi-am
++
++install-dvi-am:
++
+ install-exec-am:
+
++install-html: install-html-am
++
++install-html-am:
++
+ install-info: install-info-am
+
++install-info-am:
++
+ install-man: install-man1
+
++install-pdf: install-pdf-am
++
++install-pdf-am:
++
++install-ps: install-ps-am
++
++install-ps-am:
++
+ installcheck-am:
+
+ maintainer-clean: maintainer-clean-am
+@@ -327,18 +381,22 @@
+
+ ps-am:
+
+-uninstall-am: uninstall-info-am uninstall-man
++uninstall-am: uninstall-man
+
+ uninstall-man: uninstall-man1
+
++.MAKE: install-am install-strip
++
+ .PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+- install install-am install-data install-data-am install-exec \
+- install-exec-am install-info install-info-am install-man \
+- install-man1 install-strip installcheck installcheck-am \
++ install install-am install-data install-data-am install-dvi \
++ install-dvi-am install-exec install-exec-am install-html \
++ install-html-am install-info install-info-am install-man \
++ install-man1 install-pdf install-pdf-am install-ps \
++ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \
+- uninstall-am uninstall-info-am uninstall-man uninstall-man1
++ uninstall-am uninstall-man uninstall-man1
+
+
+ @DODOCS_TRUE@@HAVE_HELPTOMAN_TRUE@exmap.1: ../src/exmap ./man.include
+@@ -349,6 +407,7 @@
+
+ @DODOCS_TRUE@@HAVE_HELPTOMAN_TRUE@@INTERACTIVE_TRUE@exmapserver.1: ../src/exmapserver ./man-s.include
+ @DODOCS_TRUE@@HAVE_HELPTOMAN_TRUE@@INTERACTIVE_TRUE@ $(HELPTOMAN) -N -I ./man-s.include -m "Exmap server" ../src/exmapserver > ./exmapserver.1
++
+ # Tell versions [3.59,3.63) of GNU make to not export all variables.
+ # Otherwise a system limit (for SysV at least) may be exceeded.
+ .NOEXPORT:
+diff -Nur exmap-console-0.4.1.orig/install-sh exmap-console-0.4.1/install-sh
+--- exmap-console-0.4.1.orig/install-sh 2007-02-26 12:44:02.000000000 +0100
++++ exmap-console-0.4.1/install-sh 2011-01-11 12:44:16.000000000 +0100
+@@ -1,7 +1,7 @@
+ #!/bin/sh
+ # install - install a program, script, or datafile
+
+-scriptversion=2005-05-14.22
++scriptversion=2009-04-28.21; # UTC
+
+ # This originates from X11R5 (mit/util/scripts/install.sh), which was
+ # later released in X11R6 (xc/config/util/install.sh) with the
+@@ -39,38 +39,68 @@
+ # when there is no Makefile.
+ #
+ # This script is compatible with the BSD install script, but was written
+-# from scratch. It can only install one file at a time, a restriction
+-# shared with many OS's install programs.
++# from scratch.
++
++nl='
++'
++IFS=" "" $nl"
+
+ # set DOITPROG to echo to test this script
+
+ # Don't use :- since 4.3BSD and earlier shells don't like it.
+-doit="${DOITPROG-}"
++doit=${DOITPROG-}
++if test -z "$doit"; then
++ doit_exec=exec
++else
++ doit_exec=$doit
++fi
+
+-# put in absolute paths if you don't have them in your path; or use env. vars.
++# Put in absolute file names if you don't have them in your path;
++# or use environment vars.
+
+-mvprog="${MVPROG-mv}"
+-cpprog="${CPPROG-cp}"
+-chmodprog="${CHMODPROG-chmod}"
+-chownprog="${CHOWNPROG-chown}"
+-chgrpprog="${CHGRPPROG-chgrp}"
+-stripprog="${STRIPPROG-strip}"
+-rmprog="${RMPROG-rm}"
+-mkdirprog="${MKDIRPROG-mkdir}"
++chgrpprog=${CHGRPPROG-chgrp}
++chmodprog=${CHMODPROG-chmod}
++chownprog=${CHOWNPROG-chown}
++cmpprog=${CMPPROG-cmp}
++cpprog=${CPPROG-cp}
++mkdirprog=${MKDIRPROG-mkdir}
++mvprog=${MVPROG-mv}
++rmprog=${RMPROG-rm}
++stripprog=${STRIPPROG-strip}
++
++posix_glob='?'
++initialize_posix_glob='
++ test "$posix_glob" != "?" || {
++ if (set -f) 2>/dev/null; then
++ posix_glob=
++ else
++ posix_glob=:
++ fi
++ }
++'
++
++posix_mkdir=
++
++# Desired mode of installed file.
++mode=0755
+
+-chmodcmd="$chmodprog 0755"
+-chowncmd=
+ chgrpcmd=
+-stripcmd=
++chmodcmd=$chmodprog
++chowncmd=
++mvcmd=$mvprog
+ rmcmd="$rmprog -f"
+-mvcmd="$mvprog"
++stripcmd=
++
+ src=
+ dst=
+ dir_arg=
+-dstarg=
++dst_arg=
++
++copy_on_change=false
+ no_target_directory=
+
+-usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
++usage="\
++Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+@@ -80,81 +110,86 @@
+ In the 4th, create DIRECTORIES.
+
+ Options:
+--c (ignored)
+--d create directories instead of installing files.
+--g GROUP $chgrpprog installed files to GROUP.
+--m MODE $chmodprog installed files to MODE.
+--o USER $chownprog installed files to USER.
+--s $stripprog installed files.
+--t DIRECTORY install into DIRECTORY.
+--T report an error if DSTFILE is a directory.
+---help display this help and exit.
+---version display version info and exit.
++ --help display this help and exit.
++ --version display version info and exit.
++
++ -c (ignored)
++ -C install only if different (preserve the last data modification time)
++ -d create directories instead of installing files.
++ -g GROUP $chgrpprog installed files to GROUP.
++ -m MODE $chmodprog installed files to MODE.
++ -o USER $chownprog installed files to USER.
++ -s $stripprog installed files.
++ -t DIRECTORY install into DIRECTORY.
++ -T report an error if DSTFILE is a directory.
+
+ Environment variables override the default commands:
+- CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
++ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
++ RMPROG STRIPPROG
+ "
+
+-while test -n "$1"; do
++while test $# -ne 0; do
+ case $1 in
+- -c) shift
+- continue;;
++ -c) ;;
+
+- -d) dir_arg=true
+- shift
+- continue;;
++ -C) copy_on_change=true;;
++
++ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+- shift
+- shift
+- continue;;
++ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+- -m) chmodcmd="$chmodprog $2"
+- shift
+- shift
+- continue;;
++ -m) mode=$2
++ case $mode in
++ *' '* | *' '* | *'
++'* | *'*'* | *'?'* | *'['*)
++ echo "$0: invalid mode: $mode" >&2
++ exit 1;;
++ esac
++ shift;;
+
+ -o) chowncmd="$chownprog $2"
+- shift
+- shift
+- continue;;
+-
+- -s) stripcmd=$stripprog
+- shift
+- continue;;
+-
+- -t) dstarg=$2
+- shift
+- shift
+- continue;;
+-
+- -T) no_target_directory=true
+- shift
+- continue;;
++ shift;;
++
++ -s) stripcmd=$stripprog;;
++
++ -t) dst_arg=$2
++ shift;;
++
++ -T) no_target_directory=true;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+- *) # When -d is used, all remaining arguments are directories to create.
+- # When -t is used, the destination is already specified.
+- test -n "$dir_arg$dstarg" && break
+- # Otherwise, the last argument is the destination. Remove it from $@.
+- for arg
+- do
+- if test -n "$dstarg"; then
+- # $@ is not empty: it contains at least $arg.
+- set fnord "$@" "$dstarg"
+- shift # fnord
+- fi
+- shift # arg
+- dstarg=$arg
+- done
++ --) shift
+ break;;
++
++ -*) echo "$0: invalid option: $1" >&2
++ exit 1;;
++
++ *) break;;
+ esac
++ shift
+ done
+
+-if test -z "$1"; then
++if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
++ # When -d is used, all remaining arguments are directories to create.
++ # When -t is used, the destination is already specified.
++ # Otherwise, the last argument is the destination. Remove it from $@.
++ for arg
++ do
++ if test -n "$dst_arg"; then
++ # $@ is not empty: it contains at least $arg.
++ set fnord "$@" "$dst_arg"
++ shift # fnord
++ fi
++ shift # arg
++ dst_arg=$arg
++ done
++fi
++
++if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+@@ -164,24 +199,47 @@
+ exit 0
+ fi
+
++if test -z "$dir_arg"; then
++ trap '(exit $?); exit' 1 2 13 15
++
++ # Set umask so as not to create temps with too-generous modes.
++ # However, 'strip' requires both read and write access to temps.
++ case $mode in
++ # Optimize common cases.
++ *644) cp_umask=133;;
++ *755) cp_umask=22;;
++
++ *[0-7])
++ if test -z "$stripcmd"; then
++ u_plus_rw=
++ else
++ u_plus_rw='% 200'
++ fi
++ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
++ *)
++ if test -z "$stripcmd"; then
++ u_plus_rw=
++ else
++ u_plus_rw=,u+rw
++ fi
++ cp_umask=$mode$u_plus_rw;;
++ esac
++fi
++
+ for src
+ do
+ # Protect names starting with `-'.
+ case $src in
+- -*) src=./$src ;;
++ -*) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+- src=
+-
+- if test -d "$dst"; then
+- mkdircmd=:
+- chmodcmd=
+- else
+- mkdircmd=$mkdirprog
+- fi
++ dstdir=$dst
++ test -d "$dstdir"
++ dstdir_status=$?
+ else
++
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+@@ -190,71 +248,199 @@
+ exit 1
+ fi
+
+- if test -z "$dstarg"; then
++ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+- dst=$dstarg
++ dst=$dst_arg
+ # Protect names starting with `-'.
+ case $dst in
+- -*) dst=./$dst ;;
++ -*) dst=./$dst;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+- echo "$0: $dstarg: Is a directory" >&2
++ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+- dst=$dst/`basename "$src"`
++ dstdir=$dst
++ dst=$dstdir/`basename "$src"`
++ dstdir_status=0
++ else
++ # Prefer dirname, but fall back on a substitute if dirname fails.
++ dstdir=`
++ (dirname "$dst") 2>/dev/null ||
++ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$dst" : 'X\(//\)[^/]' \| \
++ X"$dst" : 'X\(//\)$' \| \
++ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
++ echo X"$dst" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'
++ `
++
++ test -d "$dstdir"
++ dstdir_status=$?
+ fi
+ fi
+
+- # This sed command emulates the dirname command.
+- dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
+-
+- # Make sure that the destination directory exists.
++ obsolete_mkdir_used=false
+
+- # Skip lots of stat calls in the usual case.
+- if test ! -d "$dstdir"; then
+- defaultIFS='
+- '
+- IFS="${IFS-$defaultIFS}"
+-
+- oIFS=$IFS
+- # Some sh's can't handle IFS=/ for some reason.
+- IFS='%'
+- set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+- shift
+- IFS=$oIFS
++ if test $dstdir_status != 0; then
++ case $posix_mkdir in
++ '')
++ # Create intermediate dirs using mode 755 as modified by the umask.
++ # This is like FreeBSD 'install' as of 1997-10-28.
++ umask=`umask`
++ case $stripcmd.$umask in
++ # Optimize common cases.
++ *[2367][2367]) mkdir_umask=$umask;;
++ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
++
++ *[0-7])
++ mkdir_umask=`expr $umask + 22 \
++ - $umask % 100 % 40 + $umask % 20 \
++ - $umask % 10 % 4 + $umask % 2
++ `;;
++ *) mkdir_umask=$umask,go-w;;
++ esac
++
++ # With -d, create the new directory with the user-specified mode.
++ # Otherwise, rely on $mkdir_umask.
++ if test -n "$dir_arg"; then
++ mkdir_mode=-m$mode
++ else
++ mkdir_mode=
++ fi
++
++ posix_mkdir=false
++ case $umask in
++ *[123567][0-7][0-7])
++ # POSIX mkdir -p sets u+wx bits regardless of umask, which
++ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
++ ;;
++ *)
++ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
++ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
++
++ if (umask $mkdir_umask &&
++ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
++ then
++ if test -z "$dir_arg" || {
++ # Check for POSIX incompatibilities with -m.
++ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
++ # other-writeable bit of parent directory when it shouldn't.
++ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
++ ls_ld_tmpdir=`ls -ld "$tmpdir"`
++ case $ls_ld_tmpdir in
++ d????-?r-*) different_mode=700;;
++ d????-?--*) different_mode=755;;
++ *) false;;
++ esac &&
++ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
++ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
++ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
++ }
++ }
++ then posix_mkdir=:
++ fi
++ rmdir "$tmpdir/d" "$tmpdir"
++ else
++ # Remove any dirs left behind by ancient mkdir implementations.
++ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
++ fi
++ trap '' 0;;
++ esac;;
++ esac
+
+- pathcomp=
++ if
++ $posix_mkdir && (
++ umask $mkdir_umask &&
++ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
++ )
++ then :
++ else
+
+- while test $# -ne 0 ; do
+- pathcomp=$pathcomp$1
++ # The umask is ridiculous, or mkdir does not conform to POSIX,
++ # or it failed possibly due to a race condition. Create the
++ # directory the slow way, step by step, checking for races as we go.
++
++ case $dstdir in
++ /*) prefix='/';;
++ -*) prefix='./';;
++ *) prefix='';;
++ esac
++
++ eval "$initialize_posix_glob"
++
++ oIFS=$IFS
++ IFS=/
++ $posix_glob set -f
++ set fnord $dstdir
+ shift
+- if test ! -d "$pathcomp"; then
+- $mkdirprog "$pathcomp"
+- # mkdir can fail with a `File exist' error in case several
+- # install-sh are creating the directory concurrently. This
+- # is OK.
+- test -d "$pathcomp" || exit
++ $posix_glob set +f
++ IFS=$oIFS
++
++ prefixes=
++
++ for d
++ do
++ test -z "$d" && continue
++
++ prefix=$prefix$d
++ if test -d "$prefix"; then
++ prefixes=
++ else
++ if $posix_mkdir; then
++ (umask=$mkdir_umask &&
++ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
++ # Don't fail if two instances are running concurrently.
++ test -d "$prefix" || exit 1
++ else
++ case $prefix in
++ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
++ *) qprefix=$prefix;;
++ esac
++ prefixes="$prefixes '$qprefix'"
++ fi
++ fi
++ prefix=$prefix/
++ done
++
++ if test -n "$prefixes"; then
++ # Don't fail if two instances are running concurrently.
++ (umask $mkdir_umask &&
++ eval "\$doit_exec \$mkdirprog $prefixes") ||
++ test -d "$dstdir" || exit 1
++ obsolete_mkdir_used=true
+ fi
+- pathcomp=$pathcomp/
+- done
++ fi
+ fi
+
+ if test -n "$dir_arg"; then
+- $doit $mkdircmd "$dst" \
+- && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
+- && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
+- && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
+- && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
+-
++ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
++ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
++ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
++ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+- dstfile=`basename "$dst"`
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+@@ -262,10 +448,9 @@
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+- trap '(exit $?); exit' 1 2 13 15
+
+ # Copy the file name to the temp name.
+- $doit $cpprog "$src" "$dsttmp" &&
++ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+@@ -273,51 +458,63 @@
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+- { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+- && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+- && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+- && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
+-
+- # Now rename the file to the real destination.
+- { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
+- || {
+- # The rename failed, perhaps because mv can't rename something else
+- # to itself, or perhaps because mv is so ancient that it does not
+- # support -f.
+-
+- # Now remove or move aside any old file at destination location.
+- # We try this two ways since rm can't unlink itself on some
+- # systems and the destination file might be busy for other
+- # reasons. In this case, the final cleanup might fail but the new
+- # file should still install successfully.
+- {
+- if test -f "$dstdir/$dstfile"; then
+- $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
+- || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
+- || {
+- echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+- (exit 1); exit 1
+- }
+- else
+- :
+- fi
+- } &&
+-
+- # Now rename the file to the real destination.
+- $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+- }
+- }
+- fi || { (exit 1); exit 1; }
+-done
++ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
++ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
++ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
++ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
++
++ # If -C, don't bother to copy if it wouldn't change the file.
++ if $copy_on_change &&
++ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
++ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
++
++ eval "$initialize_posix_glob" &&
++ $posix_glob set -f &&
++ set X $old && old=:$2:$4:$5:$6 &&
++ set X $new && new=:$2:$4:$5:$6 &&
++ $posix_glob set +f &&
++
++ test "$old" = "$new" &&
++ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
++ then
++ rm -f "$dsttmp"
++ else
++ # Rename the file to the real destination.
++ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+-# The final little trick to "correctly" pass the exit status to the exit trap.
+-{
+- (exit 0); exit 0
+-}
++ # The rename failed, perhaps because mv can't rename something else
++ # to itself, or perhaps because mv is so ancient that it does not
++ # support -f.
++ {
++ # Now remove or move aside any old file at destination location.
++ # We try this two ways since rm can't unlink itself on some
++ # systems and the destination file might be busy for other
++ # reasons. In this case, the final cleanup might fail but the new
++ # file should still install successfully.
++ {
++ test ! -f "$dst" ||
++ $doit $rmcmd -f "$dst" 2>/dev/null ||
++ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
++ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
++ } ||
++ { echo "$0: cannot unlink or rename $dst" >&2
++ (exit 1); exit 1
++ }
++ } &&
++
++ # Now rename the file to the real destination.
++ $doit $mvcmd "$dsttmp" "$dst"
++ }
++ fi || exit 1
++
++ trap '' 0
++ fi
++done
+
+ # Local variables:
+ # eval: (add-hook 'write-file-hooks 'time-stamp)
+ # time-stamp-start: "scriptversion="
+ # time-stamp-format: "%:y-%02m-%02d.%02H"
+-# time-stamp-end: "$"
++# time-stamp-time-zone: "UTC"
++# time-stamp-end: "; # UTC"
+ # End:
+diff -Nur exmap-console-0.4.1.orig/missing exmap-console-0.4.1/missing
+--- exmap-console-0.4.1.orig/missing 2007-02-26 12:44:02.000000000 +0100
++++ exmap-console-0.4.1/missing 2011-01-11 12:44:16.000000000 +0100
+@@ -1,10 +1,10 @@
+ #! /bin/sh
+ # Common stub for a few missing GNU programs while installing.
+
+-scriptversion=2005-06-08.21
++scriptversion=2009-04-28.21; # UTC
+
+-# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005
+-# Free Software Foundation, Inc.
++# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
++# 2008, 2009 Free Software Foundation, Inc.
+ # Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+ # This program is free software; you can redistribute it and/or modify
+@@ -18,9 +18,7 @@
+ # 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 Street, Fifth Floor, Boston, MA
+-# 02110-1301, USA.
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ # As a special exception to the GNU General Public License, if you
+ # distribute this file as part of a program that contains a
+@@ -33,6 +31,8 @@
+ fi
+
+ run=:
++sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
++sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+ # In the cases where this matters, `missing' is being run in the
+ # srcdir already.
+@@ -44,7 +44,7 @@
+
+ msg="missing on your system"
+
+-case "$1" in
++case $1 in
+ --run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+@@ -77,6 +77,7 @@
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
++ autom4te touch the output file, or create a stub one
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+@@ -86,6 +87,9 @@
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
++Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
++\`g' are ignored when checking the name.
++
+ Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+@@ -103,15 +107,22 @@
+
+ esac
+
++# normalize program name to check for.
++program=`echo "$1" | sed '
++ s/^gnu-//; t
++ s/^gnu//; t
++ s/^g//; t'`
++
+ # Now exit if we have it, but it failed. Also exit now if we
+ # don't have it and --version was passed (most likely to detect
+-# the program).
+-case "$1" in
+- lex|yacc)
++# the program). This is about non-GNU programs, so use $1 not
++# $program.
++case $1 in
++ lex*|yacc*)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+- tar)
++ tar*)
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+@@ -135,7 +146,7 @@
+
+ # If it does not exist, or fails to run (possibly an outdated version),
+ # try to emulate it.
+-case "$1" in
++case $program in
+ aclocal*)
+ echo 1>&2 "\
+ WARNING: \`$1' is $msg. You should only need it if
+@@ -145,7 +156,7 @@
+ touch aclocal.m4
+ ;;
+
+- autoconf)
++ autoconf*)
+ echo 1>&2 "\
+ WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+@@ -154,7 +165,7 @@
+ touch configure
+ ;;
+
+- autoheader)
++ autoheader*)
+ echo 1>&2 "\
+ WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+@@ -164,7 +175,7 @@
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+- case "$f" in
++ case $f in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+@@ -184,7 +195,7 @@
+ while read f; do touch "$f"; done
+ ;;
+
+- autom4te)
++ autom4te*)
+ echo 1>&2 "\
+ WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+@@ -192,8 +203,8 @@
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+- file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+- test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
++ file=`echo "$*" | sed -n "$sed_output"`
++ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+@@ -207,80 +218,78 @@
+ fi
+ ;;
+
+- bison|yacc)
++ bison*|yacc*)
+ echo 1>&2 "\
+ WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+- if [ $# -ne 1 ]; then
++ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+- case "$LASTARG" in
++ case $LASTARG in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+- if [ -f "$SRCFILE" ]; then
++ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+- if [ -f "$SRCFILE" ]; then
++ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+- if [ ! -f y.tab.h ]; then
++ if test ! -f y.tab.h; then
+ echo >y.tab.h
+ fi
+- if [ ! -f y.tab.c ]; then
++ if test ! -f y.tab.c; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+- lex|flex)
++ lex*|flex*)
+ echo 1>&2 "\
+ WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+- if [ $# -ne 1 ]; then
++ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+- case "$LASTARG" in
++ case $LASTARG in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+- if [ -f "$SRCFILE" ]; then
++ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+- if [ ! -f lex.yy.c ]; then
++ if test ! -f lex.yy.c; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+- help2man)
++ help2man*)
+ echo 1>&2 "\
+ WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+- file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+- if test -z "$file"; then
+- file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+- fi
+- if [ -f "$file" ]; then
++ file=`echo "$*" | sed -n "$sed_output"`
++ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
++ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+- exit 1
++ exit $?
+ fi
+ ;;
+
+- makeinfo)
++ makeinfo*)
+ echo 1>&2 "\
+ WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+@@ -289,11 +298,17 @@
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ # The file to touch is that specified with -o ...
+- file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
++ file=`echo "$*" | sed -n "$sed_output"`
++ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -z "$file"; then
+ # ... or it is the one specified with @setfilename ...
+ infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+- file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile`
++ file=`sed -n '
++ /^@setfilename/{
++ s/.* \([^ ]*\) *$/\1/
++ p
++ q
++ }' $infile`
+ # ... or it is derived from the source name (dir/f.texi becomes f.info)
+ test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+ fi
+@@ -303,7 +318,7 @@
+ touch $file
+ ;;
+
+- tar)
++ tar*)
+ shift
+
+ # We have already tried tar in the generic part.
+@@ -317,13 +332,13 @@
+ fi
+ firstarg="$1"
+ if shift; then
+- case "$firstarg" in
++ case $firstarg in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+- case "$firstarg" in
++ case $firstarg in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+@@ -356,5 +371,6 @@
+ # eval: (add-hook 'write-file-hooks 'time-stamp)
+ # time-stamp-start: "scriptversion="
+ # time-stamp-format: "%:y-%02m-%02d.%02H"
+-# time-stamp-end: "$"
++# time-stamp-time-zone: "UTC"
++# time-stamp-end: "; # UTC"
+ # End:
+diff -Nur exmap-console-0.4.1.orig/src/Makefile.in exmap-console-0.4.1/src/Makefile.in
+--- exmap-console-0.4.1.orig/src/Makefile.in 2007-02-26 12:44:02.000000000 +0100
++++ exmap-console-0.4.1/src/Makefile.in 2011-01-11 12:44:16.000000000 +0100
+@@ -1,8 +1,9 @@
+-# Makefile.in generated by automake 1.9.6 from Makefile.am.
++# Makefile.in generated by automake 1.11.1 from Makefile.am.
+ # @configure_input@
+
+ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+-# 2003, 2004, 2005 Free Software Foundation, Inc.
++# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
++# Inc.
+ # This Makefile.in is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+ # with or without modifications, as long as this notice is preserved.
+@@ -14,15 +15,12 @@
+
+ @SET_MAKE@
+
+-srcdir = @srcdir@
+-top_srcdir = @top_srcdir@
+ VPATH = @srcdir@
+ pkgdatadir = $(datadir)/@PACKAGE@
+-pkglibdir = $(libdir)/@PACKAGE@
+ pkgincludedir = $(includedir)/@PACKAGE@
+-top_builddir = ..
++pkglibdir = $(libdir)/@PACKAGE@
++pkglibexecdir = $(libexecdir)/@PACKAGE@
+ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+-INSTALL = @INSTALL@
+ install_sh_DATA = $(install_sh) -c -m 644
+ install_sh_PROGRAM = $(install_sh) -c
+ install_sh_SCRIPT = $(install_sh) -c
+@@ -43,8 +41,8 @@
+ $(ACLOCAL_M4)
+ mkinstalldirs = $(install_sh) -d
+ CONFIG_CLEAN_FILES =
++CONFIG_CLEAN_VPATH_FILES =
+ am__installdirs = "$(DESTDIR)$(bindir)"
+-binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+ PROGRAMS = $(bin_PROGRAMS)
+ am__exmap_SOURCES_DIST = interactive.c exmap.c exelf.c
+ @INTERACTIVE_TRUE@am__objects_1 = interactive.$(OBJEXT)
+@@ -58,9 +56,10 @@
+ am_exmapserver_OBJECTS = exmapserver.$(OBJEXT)
+ exmapserver_OBJECTS = $(am_exmapserver_OBJECTS)
+ exmapserver_DEPENDENCIES = $(am__DEPENDENCIES_1)
+-DEFAULT_INCLUDES = -I. -I$(srcdir)
++DEFAULT_INCLUDES = -I.@am__isrc@
+ depcomp = $(SHELL) $(top_srcdir)/depcomp
+ am__depfiles_maybe = depfiles
++am__mv = mv -f
+ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+ CCLD = $(CC)
+@@ -72,8 +71,6 @@
+ CTAGS = ctags
+ DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ ACLOCAL = @ACLOCAL@
+-AMDEP_FALSE = @AMDEP_FALSE@
+-AMDEP_TRUE = @AMDEP_TRUE@
+ AMTAR = @AMTAR@
+ AUTOCONF = @AUTOCONF@
+ AUTOHEADER = @AUTOHEADER@
+@@ -86,8 +83,6 @@
+ CYGPATH_W = @CYGPATH_W@
+ DEFS = @DEFS@
+ DEPDIR = @DEPDIR@
+-DODOCS_FALSE = @DODOCS_FALSE@
+-DODOCS_TRUE = @DODOCS_TRUE@
+ ECHO_C = @ECHO_C@
+ ECHO_N = @ECHO_N@
+ ECHO_T = @ECHO_T@
+@@ -95,38 +90,41 @@
+ GCC_CFLAGS = @GCC_CFLAGS@
+ GLIB_CFLAGS = @GLIB_CFLAGS@
+ GLIB_LIBS = @GLIB_LIBS@
+-HAVE_HELPTOMAN_FALSE = @HAVE_HELPTOMAN_FALSE@
+-HAVE_HELPTOMAN_TRUE = @HAVE_HELPTOMAN_TRUE@
+ HELPTOMAN = @HELPTOMAN@
++INSTALL = @INSTALL@
+ INSTALL_DATA = @INSTALL_DATA@
+ INSTALL_PROGRAM = @INSTALL_PROGRAM@
+ INSTALL_SCRIPT = @INSTALL_SCRIPT@
+ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+-INTERACTIVE_FALSE = @INTERACTIVE_FALSE@
+-INTERACTIVE_TRUE = @INTERACTIVE_TRUE@
+ LDFLAGS = @LDFLAGS@
+ LIBOBJS = @LIBOBJS@
+ LIBS = @LIBS@
+ LTLIBOBJS = @LTLIBOBJS@
+ MAKEINFO = @MAKEINFO@
++MKDIR_P = @MKDIR_P@
+ OBJEXT = @OBJEXT@
+ PACKAGE = @PACKAGE@
+ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+ PACKAGE_NAME = @PACKAGE_NAME@
+ PACKAGE_STRING = @PACKAGE_STRING@
+ PACKAGE_TARNAME = @PACKAGE_TARNAME@
++PACKAGE_URL = @PACKAGE_URL@
+ PACKAGE_VERSION = @PACKAGE_VERSION@
+ PATH_SEPARATOR = @PATH_SEPARATOR@
+ PKG_CONFIG = @PKG_CONFIG@
++PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
++PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+ READLINE_CFLAGS = @READLINE_CFLAGS@
+ READLINE_LIBS = @READLINE_LIBS@
+ SET_MAKE = @SET_MAKE@
+ SHELL = @SHELL@
+ STRIP = @STRIP@
+ VERSION = @VERSION@
++abs_builddir = @abs_builddir@
++abs_srcdir = @abs_srcdir@
++abs_top_builddir = @abs_top_builddir@
++abs_top_srcdir = @abs_top_srcdir@
+ ac_ct_CC = @ac_ct_CC@
+-am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+-am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+ am__include = @am__include@
+ am__leading_dot = @am__leading_dot@
+ am__quote = @am__quote@
+@@ -134,6 +132,7 @@
+ am__untar = @am__untar@
+ bindir = @bindir@
+ build_alias = @build_alias@
++builddir = @builddir@
+ datadir = @datadir@
+ datarootdir = @datarootdir@
+ docdir = @docdir@
+@@ -157,8 +156,12 @@
+ psdir = @psdir@
+ sbindir = @sbindir@
+ sharedstatedir = @sharedstatedir@
++srcdir = @srcdir@
+ sysconfdir = @sysconfdir@
+ target_alias = @target_alias@
++top_build_prefix = @top_build_prefix@
++top_builddir = @top_builddir@
++top_srcdir = @top_srcdir@
+ INCLUDES = -DSBINDIR=\"$(sbindir)\"
+ AM_CFLAGS = $(GCC_CFLAGS) $(GLIB_CFLAGS) $(READLINE_CFLAGS)
+ @INTERACTIVE_TRUE@interactive = interactive.c
+@@ -177,14 +180,14 @@
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+- && exit 0; \
++ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
++ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+- cd $(top_srcdir) && \
+- $(AUTOMAKE) --gnu src/Makefile
++ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
++ $(am__cd) $(top_srcdir) && \
++ $(AUTOMAKE) --gnu src/Makefile
+ .PRECIOUS: Makefile
+ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+@@ -202,38 +205,53 @@
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+ $(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
++$(am__aclocal_m4_deps):
+ install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+- test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+- @list='$(bin_PROGRAMS)'; for p in $$list; do \
+- p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+- if test -f $$p \
+- ; then \
+- f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+- echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+- $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+- else :; fi; \
+- done
++ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
++ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
++ for p in $$list; do echo "$$p $$p"; done | \
++ sed 's/$(EXEEXT)$$//' | \
++ while read p p1; do if test -f $$p; \
++ then echo "$$p"; echo "$$p"; else :; fi; \
++ done | \
++ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
++ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
++ sed 'N;N;N;s,\n, ,g' | \
++ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
++ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
++ if ($$2 == $$4) files[d] = files[d] " " $$1; \
++ else { print "f", $$3 "/" $$4, $$1; } } \
++ END { for (d in files) print "f", d, files[d] }' | \
++ while read type dir files; do \
++ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
++ test -z "$$files" || { \
++ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
++ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
++ } \
++ ; done
+
+ uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+- @list='$(bin_PROGRAMS)'; for p in $$list; do \
+- f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+- echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+- rm -f "$(DESTDIR)$(bindir)/$$f"; \
+- done
++ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
++ files=`for p in $$list; do echo "$$p"; done | \
++ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
++ -e 's/$$/$(EXEEXT)/' `; \
++ test -n "$$list" || exit 0; \
++ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
++ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+ clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+ exmap$(EXEEXT): $(exmap_OBJECTS) $(exmap_DEPENDENCIES)
+ @rm -f exmap$(EXEEXT)
+- $(LINK) $(exmap_LDFLAGS) $(exmap_OBJECTS) $(exmap_LDADD) $(LIBS)
++ $(LINK) $(exmap_OBJECTS) $(exmap_LDADD) $(LIBS)
+ exmapd$(EXEEXT): $(exmapd_OBJECTS) $(exmapd_DEPENDENCIES)
+ @rm -f exmapd$(EXEEXT)
+- $(LINK) $(exmapd_LDFLAGS) $(exmapd_OBJECTS) $(exmapd_LDADD) $(LIBS)
++ $(LINK) $(exmapd_OBJECTS) $(exmapd_LDADD) $(LIBS)
+ exmapserver$(EXEEXT): $(exmapserver_OBJECTS) $(exmapserver_DEPENDENCIES)
+ @rm -f exmapserver$(EXEEXT)
+- $(LINK) $(exmapserver_LDFLAGS) $(exmapserver_OBJECTS) $(exmapserver_LDADD) $(LIBS)
++ $(LINK) $(exmapserver_OBJECTS) $(exmapserver_LDADD) $(LIBS)
+
+ mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+@@ -248,92 +266,98 @@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interactive.Po@am__quote@
+
+ .c.o:
+-@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
++@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
++@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ @am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+ .c.obj:
+-@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
++@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
++@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+-uninstall-info-am:
+
+ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+- $(AWK) ' { files[$$0] = 1; } \
+- END { for (i in files) print i; }'`; \
++ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
++ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+ tags: TAGS
+
+ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+- tags=; \
++ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+- $(AWK) ' { files[$$0] = 1; } \
+- END { for (i in files) print i; }'`; \
+- if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
++ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
++ END { if (nonempty) { for (i in files) print i; }; }'`; \
++ shift; \
++ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+- $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+- $$tags $$unique; \
++ if test $$# -gt 0; then \
++ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
++ "$$@" $$unique; \
++ else \
++ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
++ $$unique; \
++ fi; \
+ fi
+ ctags: CTAGS
+ CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+- tags=; \
+- here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+- $(AWK) ' { files[$$0] = 1; } \
+- END { for (i in files) print i; }'`; \
+- test -z "$(CTAGS_ARGS)$$tags$$unique" \
++ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
++ END { if (nonempty) { for (i in files) print i; }; }'`; \
++ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+- $$tags $$unique
++ $$unique
+
+ GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+- && cd $(top_srcdir) \
+- && gtags -i $(GTAGS_ARGS) $$here
++ && $(am__cd) $(top_srcdir) \
++ && gtags -i $(GTAGS_ARGS) "$$here"
+
+ distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+ distdir: $(DISTFILES)
+- @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+- topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+- list='$(DISTFILES)'; for file in $$list; do \
+- case $$file in \
+- $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+- $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+- esac; \
++ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
++ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
++ list='$(DISTFILES)'; \
++ dist_files=`for file in $$list; do echo $$file; done | \
++ sed -e "s|^$$srcdirstrip/||;t" \
++ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
++ case $$dist_files in \
++ */*) $(MKDIR_P) `echo "$$dist_files" | \
++ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
++ sort -u` ;; \
++ esac; \
++ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+- dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+- if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+- dir="/$$dir"; \
+- $(mkdir_p) "$(distdir)$$dir"; \
+- else \
+- dir=''; \
+- fi; \
+ if test -d $$d/$$file; then \
++ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
++ if test -d "$(distdir)/$$file"; then \
++ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
++ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+- cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
++ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
++ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+- cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
++ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+- test -f $(distdir)/$$file \
+- || cp -p $$d/$$file $(distdir)/$$file \
++ test -f "$(distdir)/$$file" \
++ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+@@ -342,7 +366,7 @@
+ all-am: Makefile $(PROGRAMS)
+ installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+- test -z "$$dir" || $(mkdir_p) "$$dir"; \
++ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+ install: install-am
+ install-exec: install-exec-am
+@@ -364,6 +388,7 @@
+
+ distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
++ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+ maintainer-clean-generic:
+@@ -385,18 +410,38 @@
+
+ html: html-am
+
++html-am:
++
+ info: info-am
+
+ info-am:
+
+ install-data-am:
+
++install-dvi: install-dvi-am
++
++install-dvi-am:
++
+ install-exec-am: install-binPROGRAMS
+
++install-html: install-html-am
++
++install-html-am:
++
+ install-info: install-info-am
+
++install-info-am:
++
+ install-man:
+
++install-pdf: install-pdf-am
++
++install-pdf-am:
++
++install-ps: install-ps-am
++
++install-ps-am:
++
+ installcheck-am:
+
+ maintainer-clean: maintainer-clean-am
+@@ -416,18 +461,23 @@
+
+ ps-am:
+
+-uninstall-am: uninstall-binPROGRAMS uninstall-info-am
++uninstall-am: uninstall-binPROGRAMS
++
++.MAKE: install-am install-strip
+
+ .PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic ctags distclean distclean-compile \
+ distclean-generic distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+- install-data install-data-am install-exec install-exec-am \
+- install-info install-info-am install-man install-strip \
++ install-data install-data-am install-dvi install-dvi-am \
++ install-exec install-exec-am install-html install-html-am \
++ install-info install-info-am install-man install-pdf \
++ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+- uninstall-am uninstall-binPROGRAMS uninstall-info-am
++ uninstall-am uninstall-binPROGRAMS
++
+
+ # Tell versions [3.59,3.63) of GNU make to not export all variables.
+ # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/package/exmap/patches/patch-Makefile_in b/package/exmap/patches/patch-Makefile_in
deleted file mode 100644
index cb3281aff..000000000
--- a/package/exmap/patches/patch-Makefile_in
+++ /dev/null
@@ -1,12 +0,0 @@
-$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- exmap-console-0.4.1.orig/Makefile.in 2007-02-26 12:44:02.000000000 +0100
-+++ exmap-console-0.4.1/Makefile.in 2009-04-18 16:16:03.926793719 +0200
-@@ -155,7 +155,7 @@ sbindir = @sbindir@
- sharedstatedir = @sharedstatedir@
- sysconfdir = @sysconfdir@
- target_alias = @target_alias@
--SUBDIRS = kernel src doc
-+SUBDIRS = src
- DISTCLEANFILES = *~ Makefile.in install-sh missing depcomp *.m4 config.log config.status Makefile
- all: all-recursive
-
diff --git a/package/expat/Makefile b/package/expat/Makefile
index 28fde3a50..0ff841f4c 100644
--- a/package/expat/Makefile
+++ b/package/expat/Makefile
@@ -25,11 +25,7 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LIBEXPAT,libexpat,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,LIBEXPAT_DEV,libexpat-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBEXPAT_DEV},${PKGSC_LIBEXPAT_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBEXPAT_DEV}+= libexpat-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBEXPAT}/usr/lib
${CP} ${WRKINST}/usr/lib/libexpat.so* ${IDIR_LIBEXPAT}/usr/lib/
diff --git a/package/expat/patches/patch-conftools_ltmain_sh b/package/expat/patches/patch-conftools_ltmain_sh
new file mode 100644
index 000000000..7c2364b93
--- /dev/null
+++ b/package/expat/patches/patch-conftools_ltmain_sh
@@ -0,0 +1,11 @@
+--- expat-2.0.1.orig/conftools/ltmain.sh 2006-12-19 20:28:40.000000000 +0100
++++ expat-2.0.1/conftools/ltmain.sh 2011-01-14 01:24:32.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/faad2/patches/patch-ltmain_sh b/package/faad2/patches/patch-ltmain_sh
new file mode 100644
index 000000000..7c24bb64e
--- /dev/null
+++ b/package/faad2/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- faad2-2.7.orig/ltmain.sh 2006-03-22 01:06:55.000000000 +0100
++++ faad2-2.7/ltmain.sh 2011-01-14 23:20:01.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/fetchmail/Makefile b/package/fetchmail/Makefile
index 2734f6d31..f3af7fe66 100644
--- a/package/fetchmail/Makefile
+++ b/package/fetchmail/Makefile
@@ -14,10 +14,10 @@ PKG_SITES:= http://download.berlios.de/fetchmail/
DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tar.bz2
-PKG_FLAVOURS:= SSL
-PKGFD_SSL:= enable SSL support
-PKGFS_SSL:= libopenssl
-PKGFB_SSL:= openssl
+PKG_FLAVOURS_FETCHMAIL:=WITH_SSL
+PKGFD_WITH_SSL:= enable SSL support
+PKGFS_WITH_SSL:= libopenssl
+PKGFB_WITH_SSL:= openssl
include ${TOPDIR}/mk/package.mk
@@ -25,7 +25,7 @@ $(eval $(call PKG_template,FETCHMAIL,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},$
CONFIGURE_ARGS+= --without-hesiod
-ifeq (${ADK_PACKAGE_FETCHMAIL_SSL},y)
+ifeq (${ADK_PACKAGE_FETCHMAIL_WITH_SSL},y)
CONFIGURE_ARGS+= --with-ssl='${STAGING_TARGET_DIR}/usr'
else
CONFIGURE_ARGS+= --without-ssl
diff --git a/package/ffmpeg/Makefile b/package/ffmpeg/Makefile
index bfcb74413..082bfe171 100644
--- a/package/ffmpeg/Makefile
+++ b/package/ffmpeg/Makefile
@@ -27,10 +27,6 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,FFMPEG,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,FFPLAY,ffplay,${PKG_VERSION}-${PKG_RELEASE},${PKGSS_FFPLAY},${PKGSD_FFPLAY},${PKGSC_FFPLAY}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_FFPLAY}+= ffplay-install
-
ifeq ($(ADK_TARGET_CPU_WITH_MMX),y)
CONFIGURE_CPU_OPTS:= --enable-mmx
else
@@ -76,7 +72,7 @@ CONFIGURE_ARGS:= --prefix=/usr \
--enable-libfaad \
${CONFIGURE_CPU_OPTS}
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_FFMPEG}/usr/lib
${CP} ${WRKINST}/usr/lib/libavdevice.so* ${IDIR_FFMPEG}/usr/lib
${CP} ${WRKINST}/usr/lib/libavformat.so* ${IDIR_FFMPEG}/usr/lib
diff --git a/package/file/patches/patch-ltmain_sh b/package/file/patches/patch-ltmain_sh
new file mode 100644
index 000000000..f0bc58c34
--- /dev/null
+++ b/package/file/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- file-5.04.orig/ltmain.sh 2009-02-09 17:40:06.000000000 +0100
++++ file-5.04/ltmain.sh 2011-01-14 23:37:41.000000000 +0100
+@@ -1735,7 +1735,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/findutils/Makefile b/package/findutils/Makefile
index d53312381..0f905d67b 100644
--- a/package/findutils/Makefile
+++ b/package/findutils/Makefile
@@ -13,17 +13,23 @@ PKG_DEPENDS:= libpthread
PKG_URL:= http://www.gnu.org/software/findutils/
PKG_SITES:= http://ftp.gnu.org/pub/gnu/findutils/
+PKG_SUBPKGS:= FINDUTILS LOCATE
+PKGSD_LOCATE:= Locate utility
+
include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,FINDUTILS,$(PKG_NAME),$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+$(eval $(call PKG_template,LOCATE,locate,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LOCATE},${PKG_SECTION}))
CONFIGURE_ENV+= gl_cv_func_wcwidth_works=yes
post-install:
- $(INSTALL_DIR) $(IDIR_FINDUTILS)/usr/bin $(IDIR_FINDUTILS)/usr/libexec
- $(INSTALL_BIN) $(WRKINST)/usr/bin/{find,locate,oldfind,updatedb,xargs} \
+ $(INSTALL_DIR) $(IDIR_FINDUTILS)/usr/bin
+ $(INSTALL_BIN) $(WRKINST)/usr/bin/{find,oldfind,xargs} \
$(IDIR_FINDUTILS)/usr/bin
+ ${INSTALL_DIR} ${IDIR_LOCATE}/usr/{bin,libexec}
+ ${INSTALL_BIN} ${WRKINST}/usr/bin/{locate,updatedb} ${IDIR_LOCATE}/usr/bin/
$(INSTALL_BIN) $(WRKINST)/usr/libexec/{bigram,code,frcode} \
- $(IDIR_FINDUTILS)/usr/libexec
+ $(IDIR_LOCATE)/usr/libexec
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/firefox/Makefile b/package/firefox/Makefile
index 0e1c6fe9f..b5d034065 100644
--- a/package/firefox/Makefile
+++ b/package/firefox/Makefile
@@ -11,7 +11,7 @@ PKG_DESCR:= graphical webbrowser
PKG_SECTION:= x11/apps
PKG_DEPENDS:= libpthread alsa-lib dbus-glib glib libgtk libnotify
PKG_DEPENDS+= nspr nss libjpeg atk pango cairo libxt libx11 libstdcxx
-PKG_DEPENDS+= libxdamage libxfixes libidl libsqlite
+PKG_DEPENDS+= libxdamage libxfixes libidl libsqlite libxcomposite gdk-pixbuf
PKG_BUILDDEP:= alsa-lib dbus-glib glib gtk+ libnotify libIDL libX11
PKG_BUILDDEP+= nspr nss jpeg libXt fontconfig sqlite
PKG_URL:= http://www.mozilla.org/
diff --git a/package/flac/patches/patch-ltmain_sh b/package/flac/patches/patch-ltmain_sh
new file mode 100644
index 000000000..ded69d58a
--- /dev/null
+++ b/package/flac/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- flac-1.2.1.orig/ltmain.sh 2005-04-26 20:23:39.000000000 +0200
++++ flac-1.2.1/ltmain.sh 2011-01-15 11:22:29.000000000 +0100
+@@ -1533,7 +1533,7 @@ EOF
+ # +DA*, +DD* enable 64-bit mode on the HP compiler
+ # -q* pass through compiler args for the IBM compiler
+ # -m* pass through architecture-specific compiler args for GCC
+- -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*)
++ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/fltk/Makefile b/package/fltk/Makefile
index fc2e54ad5..b29de4bc5 100644
--- a/package/fltk/Makefile
+++ b/package/fltk/Makefile
@@ -13,6 +13,9 @@ PKG_BUILDDEP:= libX11 libXi MesaLib freeglut
PKG_URL:= http://www.fltk.org/
PKG_SITES:= http://ftp.funet.fi/pub/mirrors/ftp.easysw.com/pub/fltk/snapshots/
+PKG_NEED_CXX:= 1
+PKG_CXX:= LIBFLTK
+
PKG_SUBPKGS:= LIBFLTK
PKG_ARCH_DEPENDS:= x86 x86_64 mips mipsel mips64 mips64el
@@ -23,6 +26,17 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,LIBFLTK,libfltk,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+LIBRARIES:=-nodefaultlibs -luClibc++ -lgcc -lm
+ifeq ($(ADK_TOOLCHAIN_GCC_USE_SSP),y)
+LIBRARIES+=-lssp
+endif
+
+ifeq ($(ADK_COMPILE_LIBFLTK_WITH_UCLIBCXX),y)
+CONFIGURE_ENV+= CXXFLAGS="-fno-threadsafe-statics -fno-builtin -nostdinc++ \
+ -I${STAGING_TARGET_DIR}/usr/include/uClibc++" \
+ LIBS="$(LIBRARIES)"
+endif
+
post-install:
$(INSTALL_DIR) $(IDIR_LIBFLTK)/usr/lib
$(CP) ${WRKINST}/usr/lib/libfltk*.so* $(IDIR_LIBFLTK)/usr/lib
diff --git a/package/fltk/patches/patch-Makefile b/package/fltk/patches/patch-Makefile
new file mode 100644
index 000000000..466aef887
--- /dev/null
+++ b/package/fltk/patches/patch-Makefile
@@ -0,0 +1,11 @@
+--- fltk-2.0.x-r7513.orig/Makefile 2010-04-15 18:29:49.000000000 +0200
++++ fltk-2.0.x-r7513/Makefile 2011-01-14 22:01:49.000000000 +0100
+@@ -25,7 +25,7 @@
+
+ include makeinclude
+
+-DIRS = src $(LOCALIMAGES) images OpenGL fluid glut test
++DIRS = src $(LOCALIMAGES) images OpenGL fluid
+
+ all: makeinclude
+ for dir in $(DIRS); do\
diff --git a/package/fltk/patches/patch-fltk2-config_in b/package/fltk/patches/patch-fltk2-config_in
new file mode 100644
index 000000000..c4784688a
--- /dev/null
+++ b/package/fltk/patches/patch-fltk2-config_in
@@ -0,0 +1,27 @@
+--- fltk-2.0.x-r7513.orig/fltk2-config.in 2006-04-15 19:43:12.000000000 +0200
++++ fltk-2.0.x-r7513/fltk2-config.in 2011-01-08 23:34:40.000000000 +0100
+@@ -77,7 +77,6 @@ LDLIBS="@LDFLAGS@ @LIBS@"
+ # libraries to link with:
+ LIBNAME="@LIBNAME@"
+ DSONAME="@DSONAME@"
+-DSOLINK="@DSOLINK@"
+ IMAGELIBS="@IMAGELIBS@"
+ SHAREDSUFFIX="@SHAREDSUFFIX@"
+
+@@ -168,7 +167,6 @@ do
+ bindir=${exec_prefix}
+ includedir=${prefix}/include
+ libdir=${prefix}/lib
+- DSOLINK="-Wl,-rpath,${prefix}/lib"
+ ;;
+ --prefix)
+ echo_prefix=yes
+@@ -283,7 +281,7 @@ if test x$use_images = xyes; then
+ LDSTATIC="$libdir/libfltk2_images.a $LDSTATIC $IMAGELIBS"
+ fi
+
+-LDLIBS="$DSOLINK $LDLIBS"
++LDLIBS="$LDLIBS"
+ LDSTATIC="$LDSTATIC_PATHS $LDSTATIC"
+
+ # Answer to user requests
diff --git a/package/fluxbox/Makefile b/package/fluxbox/Makefile
index 885972f1a..74e104d67 100644
--- a/package/fluxbox/Makefile
+++ b/package/fluxbox/Makefile
@@ -14,7 +14,7 @@ PKG_BUILDDEP:= libXpm
PKG_URL:= http://www.fluxbox.org/
PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=fluxbox/}
-PKG_FLAVOURS:= WITH_IMLIB2
+PKG_FLAVOURS_FLUXBOX:= WITH_IMLIB2
PKGFD_WITH_IMLIB2:= enable imlib2 support
PKGFS_WITH_IMLIB2:= imlib2
PKGFB_WITH_IMLIB2:= imlib2
diff --git a/package/font-bh-100dpi/Makefile b/package/font-bh-100dpi/Makefile
index fc0b6c227..94c92880c 100644
--- a/package/font-bh-100dpi/Makefile
+++ b/package/font-bh-100dpi/Makefile
@@ -9,6 +9,7 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= d9383b2ddda241a464343b7b4de370a9
PKG_DESCR:= X fonts
PKG_SECTION:= x11/fonts
+PKG_BUILDDEP:= font-util
PKG_URL:= http://www.x.org/
PKG_SITES:= ${MASTER_SITE_XORG}
diff --git a/package/font-bh-75dpi/Makefile b/package/font-bh-75dpi/Makefile
index 645aac5b4..7aaaba536 100644
--- a/package/font-bh-75dpi/Makefile
+++ b/package/font-bh-75dpi/Makefile
@@ -9,6 +9,7 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= 200b38e879dcbf922ca2a9f71ad44657
PKG_DESCR:= X fonts
PKG_SECTION:= x11/fonts
+PKG_BUILDDEP:= font-util
PKG_URL:= http://www.x.org/
PKG_SITES:= ${MASTER_SITE_XORG}
diff --git a/package/font-bh-lucidatypewriter-100dpi/Makefile b/package/font-bh-lucidatypewriter-100dpi/Makefile
index 8df46f86f..443eb4710 100644
--- a/package/font-bh-lucidatypewriter-100dpi/Makefile
+++ b/package/font-bh-lucidatypewriter-100dpi/Makefile
@@ -9,6 +9,7 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= 8fa38b7845c10ff83d6077a1e238b15b
PKG_DESCR:= X fonts
PKG_SECTION:= x11/fonts
+PKG_BUILDDEP:= font-util
PKG_URL:= http://www.x.org/
PKG_SITES:= ${MASTER_SITE_XORG}
diff --git a/package/font-bh-lucidatypewriter-75dpi/Makefile b/package/font-bh-lucidatypewriter-75dpi/Makefile
index 271fe18ad..ebe555528 100644
--- a/package/font-bh-lucidatypewriter-75dpi/Makefile
+++ b/package/font-bh-lucidatypewriter-75dpi/Makefile
@@ -9,6 +9,7 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= f36b68aabef2d57258131ce6136c6f50
PKG_DESCR:= X fonts
PKG_SECTION:= x11/fonts
+PKG_BUILDDEP:= font-util
PKG_URL:= http://www.x.org/
PKG_SITES:= ${MASTER_SITE_XORG}
diff --git a/package/font-bh-ttf/Makefile b/package/font-bh-ttf/Makefile
index e36e8710e..fd0872fec 100644
--- a/package/font-bh-ttf/Makefile
+++ b/package/font-bh-ttf/Makefile
@@ -9,6 +9,7 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= baea1bb10808857e595f13c6be9cbfbe
PKG_DESCR:= X fonts
PKG_SECTION:= x11/fonts
+PKG_BUILDDEP:= font-util
PKG_URL:= http://www.x.org/
PKG_SITES:= ${MASTER_SITE_XORG}
diff --git a/package/font-bh-type1/Makefile b/package/font-bh-type1/Makefile
index 3cba71409..d9c2ab9dd 100644
--- a/package/font-bh-type1/Makefile
+++ b/package/font-bh-type1/Makefile
@@ -9,6 +9,7 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= 000da66f92370ac59e3df1b6719fdd9a
PKG_DESCR:= X fonts
PKG_SECTION:= x11/fonts
+PKG_BUILDDEP:= font-util
PKG_URL:= http://www.x.org/
PKG_SITES:= ${MASTER_SITE_XORG}
diff --git a/package/font-bitstream-100dpi/Makefile b/package/font-bitstream-100dpi/Makefile
index a65b12d9d..20c1c7937 100644
--- a/package/font-bitstream-100dpi/Makefile
+++ b/package/font-bitstream-100dpi/Makefile
@@ -9,6 +9,7 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= 823c3c2a1a2307bdca5961145e3db37d
PKG_DESCR:= X fonts
PKG_SECTION:= x11/fonts
+PKG_BUILDDEP:= font-util
PKG_URL:= http://www.x.org/
PKG_SITES:= ${MASTER_SITE_XORG}
diff --git a/package/font-bitstream-75dpi/Makefile b/package/font-bitstream-75dpi/Makefile
index 40f4cec26..2bb5c8b83 100644
--- a/package/font-bitstream-75dpi/Makefile
+++ b/package/font-bitstream-75dpi/Makefile
@@ -9,6 +9,7 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= f8e982bcaaed199fdac03e9fc12b2952
PKG_DESCR:= X fonts
PKG_SECTION:= x11/fonts
+PKG_BUILDDEP:= font-util
PKG_URL:= http://www.x.org/
PKG_SITES:= ${MASTER_SITE_XORG}
diff --git a/package/font-bitstream-type1/Makefile b/package/font-bitstream-type1/Makefile
index 97e8ada96..654aea3d9 100644
--- a/package/font-bitstream-type1/Makefile
+++ b/package/font-bitstream-type1/Makefile
@@ -9,6 +9,7 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= 08722299c09753a5540a0752ec5b5fc7
PKG_DESCR:= X fonts
PKG_SECTION:= x11/fonts
+PKG_BUILDDEP:= font-util
PKG_URL:= http://www.x.org/
PKG_SITES:= ${MASTER_SITE_XORG}
diff --git a/package/font-xfree86-type1/Makefile b/package/font-xfree86-type1/Makefile
index 2a08c9b10..559bbb448 100644
--- a/package/font-xfree86-type1/Makefile
+++ b/package/font-xfree86-type1/Makefile
@@ -9,6 +9,7 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= 785f2b6e8d6d0dafec08b8d4c54ae2e3
PKG_DESCR:= X fonts
PKG_SECTION:= x11/fonts
+PKG_BUILDDEP:= font-util
PKG_URL:= http://www.x.org/
PKG_SITES:= ${MASTER_SITE_XORG}
diff --git a/package/fontconfig/Makefile b/package/fontconfig/Makefile
index 119c09e9a..9a836fca9 100644
--- a/package/fontconfig/Makefile
+++ b/package/fontconfig/Makefile
@@ -5,7 +5,7 @@ include ${TOPDIR}/rules.mk
PKG_NAME:= fontconfig
PKG_VERSION:= 2.8.0
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= 77e15a92006ddc2adbb06f840d591c0e
PKG_DESCR:= fontconfig
PKG_SECTION:= libs
@@ -26,7 +26,8 @@ CONFIGURE_ARGS+= --with-arch=${ARCH} \
--disable-docs
post-install:
- ${INSTALL_DIR} ${IDIR_FONTCONFIG}/usr/lib
+ ${INSTALL_DIR} ${IDIR_FONTCONFIG}/usr/lib ${IDIR_FONTCONFIG}/etc/fonts
${CP} ${WRKINST}/usr/lib/libfontconfig.so* ${IDIR_FONTCONFIG}/usr/lib
+ $(CP) ${WRKINST}/etc/fonts/* ${IDIR_FONTCONFIG}/etc/fonts
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/fontconfig/patches/patch-ltmain_sh b/package/fontconfig/patches/patch-ltmain_sh
new file mode 100644
index 000000000..97a052432
--- /dev/null
+++ b/package/fontconfig/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- fontconfig-2.8.0.orig/ltmain.sh 2009-11-16 21:49:43.000000000 +0100
++++ fontconfig-2.8.0/ltmain.sh 2011-01-14 00:39:50.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/freeglut/Makefile b/package/freeglut/Makefile
index fe9b03d0a..b34ac88d8 100644
--- a/package/freeglut/Makefile
+++ b/package/freeglut/Makefile
@@ -13,7 +13,7 @@ PKG_BUILDDEP:= MesaLib
PKG_URL:= http://freeglut.sourceforge.net/
PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=freeglut/}
-PKG_HOST_DEPENDS:= !cygwin !darwin
+PKG_HOST_DEPENDS:= !cygwin
PKG_ARCH_DEPENDS:= x86 x86_64 mips mipsel mips64 mips64el
include $(TOPDIR)/mk/package.mk
diff --git a/package/freeglut/patches/patch-ltmain_sh b/package/freeglut/patches/patch-ltmain_sh
new file mode 100644
index 000000000..7ae2ccf9f
--- /dev/null
+++ b/package/freeglut/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- freeglut-2.6.0.orig/ltmain.sh 2008-04-29 23:33:55.000000000 +0200
++++ freeglut-2.6.0/ltmain.sh 2011-01-14 21:40:47.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/freeradius-client/patches/patch-ltmain_sh b/package/freeradius-client/patches/patch-ltmain_sh
new file mode 100644
index 000000000..9c3f70877
--- /dev/null
+++ b/package/freeradius-client/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- freeradius-client-1.1.6.orig/ltmain.sh 2008-03-05 19:02:55.000000000 +0100
++++ freeradius-client-1.1.6/ltmain.sh 2011-01-15 11:55:40.000000000 +0100
+@@ -1653,7 +1653,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/freeradius-server/patches/patch-ltmain_sh b/package/freeradius-server/patches/patch-ltmain_sh
new file mode 100644
index 000000000..2730428cd
--- /dev/null
+++ b/package/freeradius-server/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- freeradius-server-2.1.8.orig/ltmain.sh 2009-12-30 16:44:35.000000000 +0100
++++ freeradius-server-2.1.8/ltmain.sh 2011-01-15 13:13:33.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/freetype/patches/patch-builds_unix_ltmain_sh b/package/freetype/patches/patch-builds_unix_ltmain_sh
new file mode 100644
index 000000000..0d7344b45
--- /dev/null
+++ b/package/freetype/patches/patch-builds_unix_ltmain_sh
@@ -0,0 +1,11 @@
+--- freetype-2.3.11.orig/builds/unix/ltmain.sh 2009-10-10 20:37:53.000000000 +0200
++++ freetype-2.3.11/builds/unix/ltmain.sh 2011-01-14 00:21:25.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/gatling/patches/patch-GNUmakefile b/package/gatling/patches/patch-GNUmakefile
index d95051e6e..723400f5a 100644
--- a/package/gatling/patches/patch-GNUmakefile
+++ b/package/gatling/patches/patch-GNUmakefile
@@ -1,7 +1,16 @@
$Id$
---- gatling-0.8.orig/GNUmakefile Thu May 19 05:30:26 2005
-+++ gatling-0.8/GNUmakefile Mon Jul 9 11:52:58 2007
-@@ -96,9 +96,10 @@ libiconv: tryiconv.c
+--- gatling-0.11.orig/GNUmakefile 2008-12-05 13:31:01.000000000 +0100
++++ gatling-0.11/GNUmakefile 2011-01-15 14:10:40.000000000 +0100
+@@ -17,7 +17,7 @@ CROSS=
+ #CROSS=i686-mingw32-
+ CC=$(CROSS)gcc
+ CFLAGS=-pipe -Wall
+-LDFLAGS=
++LDFLAGS?=
+
+ path = $(subst :, ,$(PATH))
+ diet_path = $(foreach dir,$(path),$(wildcard $(dir)/diet))
+@@ -147,9 +147,10 @@ havesetresuid.h: trysetresuid.c
dummy.c:
touch $@
@@ -11,5 +20,5 @@ $Id$
- -ranlib $@
+ -${RANLIB} $@
- LDLIBS+=`cat libsocket libiconv`
+ LDLIBS+=`cat libsocket libiconv libcrypt`
diff --git a/package/gcc/Makefile b/package/gcc/Makefile
index 1f2ce8f99..faf1f9e31 100644
--- a/package/gcc/Makefile
+++ b/package/gcc/Makefile
@@ -36,7 +36,8 @@ CONFIGURE_ARGS+= --enable-languages=c,c++ \
--disable-libmudflap \
--disable-libgomp \
--disable-multilib \
- --disable-libstdcxx-pch
+ --disable-libstdcxx-pch \
+ --enable-cxx-flags="${TARGET_LDFLAGS}"
post-install:
${INSTALL_DIR} ${IDIR_GCC}/usr/lib/gcc ${IDIR_GCC}/usr/bin
diff --git a/package/gcc/patches/cross-gcc-fix.patch b/package/gcc/patches/cross-gcc-fix.patch
index 9b5d55318..f39b35fb9 100644
--- a/package/gcc/patches/cross-gcc-fix.patch
+++ b/package/gcc/patches/cross-gcc-fix.patch
@@ -1,7 +1,7 @@
diff -Nur gcc-4.4.2.orig/gcc/Makefile.in gcc-4.4.2/gcc/Makefile.in
---- gcc-4.4.2.orig/gcc/Makefile.in 2009-07-25 19:53:35.000000000 +0200
-+++ gcc-4.4.2/gcc/Makefile.in 2009-11-22 15:30:27.000000000 +0100
-@@ -898,7 +898,8 @@
+--- gcc-4.5.2.orig/gcc/Makefile.in 2010-09-02 15:05:30.000000000 +0200
++++ gcc-4.5.2/gcc/Makefile.in 2011-01-15 14:29:18.000000000 +0100
+@@ -980,7 +980,8 @@ ALL_CXXFLAGS = $(T_CFLAGS) $(CXXFLAGS) $
# Likewise. Put INCLUDES at the beginning: this way, if some autoconf macro
# puts -I options in CPPFLAGS, our include files in the srcdir will always
# win against random include files in /usr/include.
@@ -9,5 +9,5 @@ diff -Nur gcc-4.4.2.orig/gcc/Makefile.in gcc-4.4.2/gcc/Makefile.in
+#ALL_CPPFLAGS = $(INCLUDES) $(CPPFLAGS)
+ALL_CPPFLAGS = $(INCLUDES)
- # Build and host support libraries.
- LIBIBERTY = ../libiberty/libiberty.a
+ # This is the variable to use when using $(COMPILER).
+ ifneq ($(ENABLE_BUILD_WITH_CXX),yes)
diff --git a/package/gcc/patches/ltmain.patch b/package/gcc/patches/ltmain.patch
new file mode 100644
index 000000000..215889b70
--- /dev/null
+++ b/package/gcc/patches/ltmain.patch
@@ -0,0 +1,12 @@
+diff -Nur gcc-4.5.2.orig/ltmain.sh gcc-4.5.2/ltmain.sh
+--- gcc-4.5.2.orig/ltmain.sh 2009-12-05 18:18:53.000000000 +0100
++++ gcc-4.5.2/ltmain.sh 2011-01-15 14:45:07.000000000 +0100
+@@ -4980,7 +4980,7 @@
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/gdb/patches/patch-ltmain_sh b/package/gdb/patches/patch-ltmain_sh
new file mode 100644
index 000000000..98afcfbc0
--- /dev/null
+++ b/package/gdb/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- gdb-7.1.orig/ltmain.sh 2010-01-09 22:11:32.000000000 +0100
++++ gdb-7.1/ltmain.sh 2011-01-15 18:15:38.000000000 +0100
+@@ -4980,7 +4980,7 @@ func_mode_link ()
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/gdk-pixbuf/Makefile b/package/gdk-pixbuf/Makefile
index f1eedeeb1..24b55275c 100644
--- a/package/gdk-pixbuf/Makefile
+++ b/package/gdk-pixbuf/Makefile
@@ -8,6 +8,7 @@ PKG_VERSION:= 2.23.0
PKG_RELEASE:= 2
PKG_MD5SUM:= a7d6c5f2fe2d481149ed3ba807b5c043
PKG_DESCR:= GDK pixbuf library
+PKG_BUILDDEP:= jpeg libtiff
PKG_SECTION:= libs
PKG_SITES:= http://ftp.gnome.org/pub/gnome/sources/gdk-pixbuf/2.23/
diff --git a/package/gdk-pixbuf/patches/patch-ltmain_sh b/package/gdk-pixbuf/patches/patch-ltmain_sh
new file mode 100644
index 000000000..058119f49
--- /dev/null
+++ b/package/gdk-pixbuf/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- gdk-pixbuf-2.23.0.orig/ltmain.sh 2010-12-06 15:06:25.000000000 +0100
++++ gdk-pixbuf-2.23.0/ltmain.sh 2011-01-14 23:45:56.000000000 +0100
+@@ -5840,7 +5840,7 @@ func_mode_link ()
+ # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+- -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
++ -O*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/gettext/Makefile b/package/gettext/Makefile
index 76e73fed0..76d47acd5 100644
--- a/package/gettext/Makefile
+++ b/package/gettext/Makefile
@@ -18,7 +18,7 @@ ifeq ($(ADK_STATIC),y)
PKG_OPTS:= libonly
endif
-WRKDIST= ${WRKDIR}/${PKG_NAME}-${PKG_VERSION}/gettext-runtime
+WRKSRC= ${WRKDIR}/${PKG_NAME}-${PKG_VERSION}/gettext-runtime
include ${TOPDIR}/mk/package.mk
@@ -29,6 +29,7 @@ CONFIGURE_ARGS+= --disable-java \
--disable-csharp \
--enable-nls \
--disable-libasprintf \
+ --disable-rpath \
--enable-threads=posix \
--disable-openmp \
--with-libiconv-prefix='${STAGING_TARGET_DIR}/usr' \
diff --git a/package/gettext/patches/patch-build-aux_ltmain_sh b/package/gettext/patches/patch-build-aux_ltmain_sh
new file mode 100644
index 000000000..e8284a680
--- /dev/null
+++ b/package/gettext/patches/patch-build-aux_ltmain_sh
@@ -0,0 +1,39 @@
+--- gettext-0.18.1.1.orig/build-aux/ltmain.sh 2010-06-06 14:49:57.000000000 +0200
++++ gettext-0.18.1.1/build-aux/ltmain.sh 2011-01-14 12:26:11.000000000 +0100
+@@ -4901,7 +4901,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
+@@ -5652,27 +5652,6 @@ func_mode_link ()
+ esac
+ fi
+
+- # Hardcode the library path.
+- # Skip directories that are in the system default run-time
+- # search path.
+- case " $sys_lib_dlsearch_path " in
+- *" $absdir "*) ;;
+- *)
+- case "$compile_rpath " in
+- *" $absdir "*) ;;
+- *) compile_rpath="$compile_rpath $absdir"
+- esac
+- ;;
+- esac
+- case " $sys_lib_dlsearch_path " in
+- *" $libdir "*) ;;
+- *)
+- case "$finalize_rpath " in
+- *" $libdir "*) ;;
+- *) finalize_rpath="$finalize_rpath $libdir"
+- esac
+- ;;
+- esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
diff --git a/package/gkrellmd/Makefile b/package/gkrellm/Makefile
index 2f2548ca6..1b4a6b118 100644
--- a/package/gkrellmd/Makefile
+++ b/package/gkrellm/Makefile
@@ -3,7 +3,7 @@
include ${TOPDIR}/rules.mk
-PKG_NAME:= gkrellmd
+PKG_NAME:= gkrellm
PKG_VERSION:= 2.3.4
PKG_RELEASE:= 1
PKG_MD5SUM:= 600f4daa395112ed19a3633deb0829ff
@@ -14,12 +14,11 @@ PKG_BUILDDEP:= glib
PKG_URL:= http://members.dslextreme.com/users/billw/gkrellm/gkrellm.html
PKG_SITES:= http://members.dslextreme.com/users/billw/gkrellm/
-DISTFILES:= gkrellm-${PKG_VERSION}.tar.gz
-WRKDIST= ${WRKDIR}/gkrellm-${PKG_VERSION}/server
+WRKSRC= ${WRKDIR}/gkrellm-${PKG_VERSION}/server
include ${TOPDIR}/mk/package.mk
-$(eval $(call PKG_template,GKRELLMD,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+$(eval $(call PKG_template,GKRELLMD,gkrellmd,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
CONFIG_STYLE:= manual
INSTALL_STYLE:= manual
diff --git a/package/gkrellmd/files/gkrellmd.init b/package/gkrellm/files/gkrellmd.init
index 54c42665c..54c42665c 100644
--- a/package/gkrellmd/files/gkrellmd.init
+++ b/package/gkrellm/files/gkrellmd.init
diff --git a/package/gkrellmd/files/gkrellmd.postinst b/package/gkrellm/files/gkrellmd.postinst
index 56b7b06cc..56b7b06cc 100644
--- a/package/gkrellmd/files/gkrellmd.postinst
+++ b/package/gkrellm/files/gkrellmd.postinst
diff --git a/package/gkrellm/patches/patch-server_Makefile b/package/gkrellm/patches/patch-server_Makefile
new file mode 100644
index 000000000..9f070e275
--- /dev/null
+++ b/package/gkrellm/patches/patch-server_Makefile
@@ -0,0 +1,22 @@
+--- gkrellm-2.3.4.orig/server/Makefile 2008-10-03 23:52:48.000000000 +0200
++++ gkrellm-2.3.4/server/Makefile 2011-01-15 18:37:40.000000000 +0100
+@@ -26,7 +26,7 @@ SMANDIR ?= $(INSTALLROOT)/share/man/man1
+ MANMODE ?= 644
+ MANDIRMODE ?= 755
+ INSTALL ?= install
+-LINK_FLAGS ?= -Wl,-E
++LINK_FLAGS ?= -Wl,-E $(LDFLAGS)
+ EXTRAOBJS =
+
+ SHARED_PATH = ../shared
+@@ -109,8 +109,8 @@ endif
+
+ override CC += -Wall $(FLAGS)
+
+-OS_NAME=$(shell uname -s)
+-OS_RELEASE=$(shell uname -r)
++OS_NAME=Linux
++OS_RELEASE=2.6
+
+ OBJS = main.o monitor.o mail.o plugins.o glib.o utils.o sysdeps-unix.o log.o
+
diff --git a/package/glib/Makefile b/package/glib/Makefile
index c8ae30715..8dc9c6339 100644
--- a/package/glib/Makefile
+++ b/package/glib/Makefile
@@ -25,8 +25,8 @@ $(eval $(call PKG_template,GLIB,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_
CONFIGURE_ARGS+= --enable-debug=no \
--disable-mem-pools \
--disable-rebuilds \
- --with-libiconv=gnu \
--disable-fam \
+ --with-libiconv=gnu \
--with-threads=posix
CONFIGURE_ENV+= glib_cv_long_long_format=ll \
glib_cv_stack_grows=no \
@@ -35,6 +35,22 @@ CONFIGURE_ENV+= glib_cv_long_long_format=ll \
ac_cv_func_posix_getpwuid_r=yes \
ac_cv_func_posix_getgrgid_r=yes
+pre-configure:
+ifneq ($(OStype),Darwin)
+ (cd ${WRKBUILD}; rm -rf config.{cache,status}; \
+ ./configure --prefix=$(STAGING_HOST_DIR) \
+ --enable-debug=no \
+ --with-threads=posix \
+ );
+ ${MAKE} -C ${WRKBUILD}/glib
+ ${MAKE} -C ${WRKBUILD}/gthread
+ env CFLAGS="-static" LDFLAGS="-static" ${MAKE} -C ${WRKBUILD}/gio glib-compile-schemas
+ env CFLAGS="-static" LDFLAGS="-static" ${MAKE} -C ${WRKBUILD}/gobject glib-genmarshal
+ $(CP) ${WRKBUILD}/gio/glib-compile-schemas ${STAGING_HOST_DIR}/bin
+ $(CP) ${WRKBUILD}/gobject/.libs/glib-genmarshal ${STAGING_HOST_DIR}/bin
+ ${MAKE} -C ${WRKBUILD} clean
+endif
+
post-install:
${INSTALL_DIR} ${IDIR_GLIB}/usr/lib
${CP} ${WRKINST}/usr/lib/libgio*.so* ${IDIR_GLIB}/usr/lib
diff --git a/package/glib/patches/patch-glib_gconvert_c b/package/glib/patches/patch-glib_gconvert_c
new file mode 100644
index 000000000..bd9db0404
--- /dev/null
+++ b/package/glib/patches/patch-glib_gconvert_c
@@ -0,0 +1,16 @@
+--- glib-2.27.5.orig/glib/gconvert.c 2010-09-13 15:40:53.000000000 +0200
++++ glib-2.27.5/glib/gconvert.c 2011-01-14 17:17:40.000000000 +0100
+@@ -58,13 +58,6 @@
+
+ #include "glibintl.h"
+
+-#if defined(USE_LIBICONV_GNU) && !defined (_LIBICONV_H)
+-#error GNU libiconv in use but included iconv.h not from libiconv
+-#endif
+-#if !defined(USE_LIBICONV_GNU) && defined (_LIBICONV_H)
+-#error GNU libiconv not in use but included iconv.h is from libiconv
+-#endif
+-
+
+ /**
+ * SECTION:conversions
diff --git a/package/glib/patches/patch-ltmain_sh b/package/glib/patches/patch-ltmain_sh
new file mode 100644
index 000000000..559afa25c
--- /dev/null
+++ b/package/glib/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- glib-2.27.5.orig/ltmain.sh 2010-12-06 15:06:25.000000000 +0100
++++ glib-2.27.5/ltmain.sh 2011-01-14 17:22:21.000000000 +0100
+@@ -5840,7 +5840,7 @@ func_mode_link ()
+ # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+- -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
++ -O*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/glibc/Makefile b/package/glibc/Makefile
index 8b4584373..9d890c18b 100644
--- a/package/glibc/Makefile
+++ b/package/glibc/Makefile
@@ -20,16 +20,28 @@ CONFIG_STYLE:= manual
BUILD_STYLE:= manual
INSTALL_STYLE:= manual
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_GLIBC_DEV}+= glibc-dev-install
-
# compile nothing, glibc is already build in toolchain directory
-do-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+do-install:
${INSTALL_DIR} $(IDIR_GLIBC)/lib $(IDIR_GLIBC)/etc
- test -z $(ADK_RUNTIME_TIMEZONE) || \
- $(CP) /usr/share/zoneinfo/$(ADK_RUNTIME_TIMEZONE) \
- $(IDIR_GLIBC)/etc/localtime
+ cd ${STAGING_TARGET_DIR} && for f in UTC ${ADK_RUNTIME_TIMEZONE}; do \
+ test -s usr/share/zoneinfo/"$$f" || continue; \
+ echo usr/share/zoneinfo/"$$f" | \
+ ${TOOLS_DIR}/cpio -pdu ${IDIR_GLIBC}/; \
+ done
+ tz=; cd ${IDIR_GLIBC}/usr/share/zoneinfo || exit 1; \
+ for f in UTC ${ADK_RUNTIME_TIMEZONE}; do \
+ test -s "$$f" || continue; \
+ tz=$$f; \
+ done; if test x"$$tz" = x""; then \
+ echo >&2 Error during timezone installation; \
+ exit 1; \
+ else \
+ ln -sf "../usr/share/zoneinfo/$$tz" \
+ ${IDIR_GLIBC}/etc/localtime; \
+ fi
+ ${CP} ${STAGING_TARGET_DIR}/etc/gai.conf ${IDIR_GLIBC}/etc/
+ ${CP} ${STAGING_TARGET_DIR}/etc/nscd.conf ${IDIR_GLIBC}/etc/
+ ${CP} ${STAGING_TARGET_DIR}/etc/nsswitch.conf ${IDIR_GLIBC}/etc/
$(CP) $(STAGING_TARGET_DIR)/lib/ld*.so* $(IDIR_GLIBC)/lib/
-for file in libc libcrypt libdl libm libresolv librt libutil libnss_compat libnss_dns libnss_files; do \
$(CP) $(STAGING_TARGET_DIR)/lib/$$file.so* $(IDIR_GLIBC)/lib/; \
diff --git a/package/gmp/patches/patch-ltmain_sh b/package/gmp/patches/patch-ltmain_sh
new file mode 100644
index 000000000..c3acfc351
--- /dev/null
+++ b/package/gmp/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- gmp-4.3.2.orig/ltmain.sh 2010-01-07 21:09:02.000000000 +0100
++++ gmp-4.3.2/ltmain.sh 2011-01-15 14:17:38.000000000 +0100
+@@ -1663,7 +1663,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/gnupg/Makefile b/package/gnupg/Makefile
index ff3739775..d28b2b4dc 100644
--- a/package/gnupg/Makefile
+++ b/package/gnupg/Makefile
@@ -29,6 +29,7 @@ CONFIGURE_ARGS+= --disable-asm \
--disable-finger \
--disable-ftp \
--disable-dns-srv \
+ --disable-rpath \
--enable-fake-curl \
--disable-regex
diff --git a/package/gnutls/Makefile b/package/gnutls/Makefile
index 7a289205e..e75ae7f9f 100644
--- a/package/gnutls/Makefile
+++ b/package/gnutls/Makefile
@@ -33,6 +33,7 @@ $(eval $(call PKG_template,LIBGNUTLS_OPENSSL,libgnutls-openssl,${PKG_VERSION}-${
CONFIGURE_ARGS+= --without-libopencdk-prefix \
--disable-camellia \
--with-libgcrypt-prefix=${STAGING_TARGET_DIR}/usr \
+ --disable-rpath \
--without-libz-prefix
post-install:
diff --git a/package/gnutls/patches/patch-build-aux_ltmain_sh b/package/gnutls/patches/patch-build-aux_ltmain_sh
new file mode 100644
index 000000000..564eeb34b
--- /dev/null
+++ b/package/gnutls/patches/patch-build-aux_ltmain_sh
@@ -0,0 +1,11 @@
+--- gnutls-2.8.6.orig/build-aux/ltmain.sh 2010-03-15 11:28:59.000000000 +0100
++++ gnutls-2.8.6/build-aux/ltmain.sh 2011-01-15 19:40:55.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/gnutls/patches/patch-lib_build-aux_ltmain_sh b/package/gnutls/patches/patch-lib_build-aux_ltmain_sh
new file mode 100644
index 000000000..e16ccadeb
--- /dev/null
+++ b/package/gnutls/patches/patch-lib_build-aux_ltmain_sh
@@ -0,0 +1,11 @@
+--- gnutls-2.8.6.orig/lib/build-aux/ltmain.sh 2010-03-15 11:28:24.000000000 +0100
++++ gnutls-2.8.6/lib/build-aux/ltmain.sh 2011-01-15 19:44:32.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/gnutls/patches/patch-libextra_build-aux_ltmain_sh b/package/gnutls/patches/patch-libextra_build-aux_ltmain_sh
new file mode 100644
index 000000000..75df0e2d6
--- /dev/null
+++ b/package/gnutls/patches/patch-libextra_build-aux_ltmain_sh
@@ -0,0 +1,11 @@
+--- gnutls-2.8.6.orig/libextra/build-aux/ltmain.sh 2010-03-15 11:28:49.000000000 +0100
++++ gnutls-2.8.6/libextra/build-aux/ltmain.sh 2011-01-15 19:44:14.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/gpm/patches/patch-src_Makefile_in b/package/gpm/patches/patch-src_Makefile_in
new file mode 100644
index 000000000..3957260ae
--- /dev/null
+++ b/package/gpm/patches/patch-src_Makefile_in
@@ -0,0 +1,51 @@
+--- gpm-1.20.6.orig/src/Makefile.in 2009-02-09 10:58:53.000000000 +0100
++++ gpm-1.20.6/src/Makefile.in 2011-01-11 16:48:43.000000000 +0100
+@@ -59,19 +59,19 @@ STRIP = -s
+
+ # the prog rules are not very clean...
+ prog/%.o: prog/%.c
+- $(CC) -Iheaders @CPPFLAGS@ $(CPPFLAGS) @CFLAGS@ $(CFLAGS) -c -o $@ $<
++ $(CC) -Iheaders @CPPFLAGS@ @CFLAGS@ -c -o $@ $<
+
+ prog/%: prog/%.o
+- $(CC) @LDFLAGS@ $(LDFLAGS) -o $@ $^ @LIBS@ $(LIBS)
++ $(CC) @LDFLAGS@ -o $@ $^ @LIBS@
+
+ %.o: %.c
+- $(CC) @CPPFLAGS@ $(CPPFLAGS) @CFLAGS@ $(CFLAGS) -c -o $@ $<
++ $(CC) @CPPFLAGS@ @CFLAGS@ -c -o $@ $<
+
+ %.lo: %.c
+- $(CC) @CPPFLAGS@ $(CPPFLAGS) @PICFLAGS@ @CFLAGS@ $(CFLAGS) -c -o $@ $<
++ $(CC) @CPPFLAGS@ @PICFLAGS@ @CFLAGS@ -c -o $@ $<
+
+ %: %.o
+- $(CC) @LDFLAGS@ $(LDFLAGS) -o $@ $^ @LIBS@ $(LIBS)
++ $(CC) @LDFLAGS@ -o $@ $^ @LIBS@
+
+ # old, unused, but good rule [dependings]
+ #%.d: $(srcdir)/%.c
+@@ -82,7 +82,7 @@ prog/%: prog/%.o
+ all: gpm lib/libgpm.so.@abi_lev@ lib/libgpm.a $(PROG)
+
+ gpm: $(GOBJ)
+- $(CC) @LDFLAGS@ $(LDFLAGS) -o $@ $(GOBJ) @LIBS@ $(LIBS) -lm
++ $(CC) @LDFLAGS@ -o $@ $(GOBJ) @LIBS@ -lm
+
+ # construct dependings of sourcefiles and link sourcefiles
+ $(DEPFILE) dep: prog/gpm-root.c
+@@ -148,11 +148,11 @@ prog/gpm-root.c: $(srcdir)/prog/gpm-root
+
+ # gpm-root needs an own rule, because gpm-root.c is not in $(srcdir)
+ prog/gpm-root: prog/gpm-root.c lib/libgpm.so.@abi_lev@
+- $(CC) -I. @CPPFLAGS@ $(CPPFLAGS) @CFLAGS@ $(CFLAGS) -c -o $@.o $<
+- $(CC) @LDFLAGS@ $(LDFLAGS) -o $@ $@.o @LIBS@ $(LIBS) lib/libgpm.so.@abi_lev@
++ $(CC) -I. @CPPFLAGS@ @CFLAGS@ -c -o $@.o $<
++ $(CC) @LDFLAGS@ -o $@ $@.o @LIBS@ lib/libgpm.so.@abi_lev@
+
+ prog/mouse-test: prog/mouse-test.o mice.o twiddler.o synaptics.o prog/open_console.o
+- $(CC) @LDFLAGS@ $(LDFLAGS) -o $@ $^ @LIBS@ $(LIBS) -lm
++ $(CC) @LDFLAGS@ -o $@ $^ @LIBS@ -lm
+
+ $(PROG): lib/libgpm.so.@abi_lev@
+
diff --git a/package/gpsd/Makefile b/package/gpsd/Makefile
index 83fac860b..24536e5c1 100644
--- a/package/gpsd/Makefile
+++ b/package/gpsd/Makefile
@@ -14,6 +14,7 @@ PKG_BUILDDEP:= ncurses
PKG_SITES:= http://download.berlios.de/gpsd/
PKG_URL:= http://gpsd.berlios.de/
PKG_CXX:= GPSD
+PKG_NEED_CXX:= 1
PKG_SUBPKGS:= GPSD GPSD_CLIENTS
PKGSD_GPSD_CLIENTS:= GPS client utilities
@@ -31,10 +32,15 @@ CONFIGURE_ENV+= EGREP="grep -E" \
CONFIGURE_ARGS+= --disable-dbus
TCFLAGS+= -fPIC
+LIBRARIES:=-nodefaultlibs -luClibc++
+ifeq ($(ADK_TOOLCHAIN_GCC_USE_SSP),y)
+LIBRARIES+=-lssp -lssp_nonshared
+endif
+
ifeq ($(ADK_COMPILE_GPSD_WITH_UCLIBCXX),y)
-TCXXFLAGS+= -fno-builtin -fno-rtti -nostdinc++ \
+TCXXFLAGS+= -fno-rtti -nostdinc++ \
-I${STAGING_TARGET_DIR}/usr/include/uClibc++
-TLDFLAGS+= -luClibc++ -lc -lm -pthread -nodefaultlibs
+TLDFLAGS+= $(LIBRARIES)
else
TLDFLAGS+= -shared -pthread
endif
diff --git a/package/gpsd/patches/patch-Makefile_in b/package/gpsd/patches/patch-Makefile_in
index bd45358ee..b54aabbac 100644
--- a/package/gpsd/patches/patch-Makefile_in
+++ b/package/gpsd/patches/patch-Makefile_in
@@ -1,5 +1,5 @@
--- gpsd-2.95.orig/Makefile.in 2010-07-14 00:48:24.000000000 +0200
-+++ gpsd-2.95/Makefile.in 2010-07-30 13:04:19.000000000 +0200
++++ gpsd-2.95/Makefile.in 2011-01-15 19:56:22.000000000 +0100
@@ -612,8 +612,8 @@ libgps_la_SOURCES = $(libgps_c_sources)
libgpsd_la_SOURCES = $(libgpsd_c_sources) $(libgpsd_h_sources) \
driver_rtcm2.h packet_states.h
@@ -11,3 +11,12 @@
nodist_libgpsd_la_SOURCES = packet_names.h ais_json.i
libgps_la_LIBADD = $(LIBM) $(LIBC) $(LIBNSL) $(LIBSOCKET) $(LIBPTHREAD)
libgpsd_la_LIBADD = $(LIBM) $(LIBC) $(LIBNSL) $(LIBSOCKET) $(LIBPTHREAD) $(BLUEZ_LIBS) libgps.la
+@@ -996,7 +996,7 @@ clean-libLTLIBRARIES:
+ rm -f "$${dir}/so_locations"; \
+ done
+ libgps.la: $(libgps_la_OBJECTS) $(libgps_la_DEPENDENCIES)
+- $(libgps_la_LINK) -rpath $(libdir) $(libgps_la_OBJECTS) $(libgps_la_LIBADD) $(LIBS)
++ $(libgps_la_LINK) -rpath $(libdir) $(libgps_la_OBJECTS) $(libgps_la_LIBADD) $(LDFLAGS) $(LIBS)
+ libgpsd.la: $(libgpsd_la_OBJECTS) $(libgpsd_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(libgpsd_la_OBJECTS) $(libgpsd_la_LIBADD) $(LIBS)
+ install-binPROGRAMS: $(bin_PROGRAMS)
diff --git a/package/gpsd/patches/patch-ltmain_sh b/package/gpsd/patches/patch-ltmain_sh
new file mode 100644
index 000000000..85a07afac
--- /dev/null
+++ b/package/gpsd/patches/patch-ltmain_sh
@@ -0,0 +1,20 @@
+--- gpsd-2.95.orig/ltmain.sh 2010-06-18 22:54:26.000000000 +0200
++++ gpsd-2.95/ltmain.sh 2011-01-15 20:23:12.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
+@@ -4963,7 +4963,7 @@ func_mode_link ()
+ done
+
+ if test "$linkmode" = lib; then
+- libs="$predeps $libs $compiler_lib_search_path $postdeps"
++ libs="$libs $compiler_lib_search_path"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
diff --git a/package/grep/Makefile b/package/grep/Makefile
index d608bd8be..d9fc4d56c 100644
--- a/package/grep/Makefile
+++ b/package/grep/Makefile
@@ -9,8 +9,10 @@ PKG_RELEASE:= 2
PKG_MD5SUM:= 92258031d98d4f12dfc6a6d24057e672
PKG_DESCR:= global search for a regular expression and print out matched lines
PKG_SECTION:= utils
+PKG_BUILDDEP:= pcre
PKG_URL:= http://www.gnu.org/software/grep/
PKG_SITES:= ftp://ftp.gnu.org/gnu/grep/
+PKG_NOPARALLEL:= 1
include $(TOPDIR)/mk/package.mk
diff --git a/package/gtk+/Makefile b/package/gtk+/Makefile
index 41972cbbc..dd216bf0b 100644
--- a/package/gtk+/Makefile
+++ b/package/gtk+/Makefile
@@ -5,7 +5,7 @@ include ${TOPDIR}/rules.mk
PKG_NAME:= gtk+
PKG_VERSION:= 2.22.1
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= dd1830395a6b9265a1e1989af7a3c5bf
PKG_DESCR:= GTK+ library
PKG_SECTION:= libs
@@ -25,6 +25,13 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LIBGTK,libgtk,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
+CONFIGURE_ARGS+= --disable-gtk-doc-html \
+ --disable-modules \
+ --disable-xinerama \
+ --without-xinput \
+ --disable-gtk-doc \
+ --disable-papi \
+ --disable-introspection
CONFIGURE_ENV+= gio_can_sniff=no \
ac_cv_path_GTK_UPDATE_ICON_CACHE=""
diff --git a/package/gtk+/patches/patch-Makefile_in b/package/gtk+/patches/patch-Makefile_in
new file mode 100644
index 000000000..a3c0845f8
--- /dev/null
+++ b/package/gtk+/patches/patch-Makefile_in
@@ -0,0 +1,13 @@
+--- gtk+-2.22.1.orig/Makefile.in 2010-11-15 17:49:52.000000000 +0100
++++ gtk+-2.22.1/Makefile.in 2011-01-07 22:23:19.000000000 +0100
+@@ -455,8 +455,8 @@ XVFB_START = \
+ || { echo "Gtk+Tests:ERROR: Failed to start Xvfb environment for X11 target tests."; exit 1; } \
+ && DISPLAY=:$$XID && export DISPLAY
+
+-SRC_SUBDIRS = gdk gtk modules demos tests perf
+-SUBDIRS = po po-properties $(SRC_SUBDIRS) docs m4macros build
++SRC_SUBDIRS = gdk gtk modules
++SUBDIRS = po po-properties $(SRC_SUBDIRS) m4macros build
+
+ # require automake 1.4
+ AUTOMAKE_OPTIONS = 1.7
diff --git a/package/gtk+/patches/patch-gtk_Makefile_in b/package/gtk+/patches/patch-gtk_Makefile_in
new file mode 100644
index 000000000..d2c098b84
--- /dev/null
+++ b/package/gtk+/patches/patch-gtk_Makefile_in
@@ -0,0 +1,265 @@
+--- gtk+-2.22.1.orig/gtk/Makefile.in 2010-11-15 17:49:47.000000000 +0100
++++ gtk+-2.22.1/gtk/Makefile.in 2011-01-04 13:33:50.000000000 +0100
+@@ -1595,7 +1595,172 @@ GENERATED_ICONS = \
+ stock-icons/24/folder-remote.png \
+ stock-icons/24/user-home.png \
+ stock-icons/24/user-desktop.png \
+- stock-icons/24/text-x-generic.png
++ stock-icons/24/text-x-generic.png \
++ stock-icons/16/gtk-quit.png \
++ stock-icons/16/gtk-info.png \
++ stock-icons/16/gtk-file.png \
++ stock-icons/16/gtk-open.png \
++ stock-icons/16/gtk-print-preview.png \
++ stock-icons/16/gtk-print.png \
++ stock-icons/16/gtk-properties.png \
++ stock-icons/16/gtk-revert-to-saved-ltr.png \
++ stock-icons/16/gtk-revert-to-saved-rtl.png \
++ stock-icons/16/gtk-save-as.png \
++ stock-icons/16/gtk-new.png \
++ stock-icons/16/gtk-harddisk.png \
++ stock-icons/16/gtk-clear.png \
++ stock-icons/16/gtk-copy.png \
++ stock-icons/16/gtk-cut.png \
++ stock-icons/16/gtk-delete.png \
++ stock-icons/16/gtk-find-and-replace.png \
++ stock-icons/16/gtk-find.png \
++ stock-icons/16/gtk-paste.png \
++ stock-icons/16/gtk-redo-ltr.png \
++ stock-icons/16/gtk-redo-rtl.png \
++ stock-icons/16/gtk-select-all.png \
++ stock-icons/16/gtk-undo-ltr.png \
++ stock-icons/16/gtk-undo-rtl.png \
++ stock-icons/16/gtk-directory.png \
++ stock-icons/16/gtk-unindent-ltr.png \
++ stock-icons/16/gtk-unindent-rtl.png \
++ stock-icons/16/gtk-indent-ltr.png \
++ stock-icons/16/gtk-indent-rtl.png \
++ stock-icons/16/gtk-justify-center.png \
++ stock-icons/16/gtk-justify-fill.png \
++ stock-icons/16/gtk-justify-left.png \
++ stock-icons/16/gtk-justify-right.png \
++ stock-icons/16/gtk-bold.png \
++ stock-icons/16/gtk-italic.png \
++ stock-icons/16/gtk-strikethrough.png \
++ stock-icons/16/gtk-underline.png \
++ stock-icons/16/gtk-goto-bottom.png \
++ stock-icons/16/gtk-go-down.png \
++ stock-icons/16/gtk-goto-first-ltr.png \
++ stock-icons/16/gtk-home.png \
++ stock-icons/16/gtk-jump-to-ltr.png \
++ stock-icons/16/gtk-jump-to-rtl.png \
++ stock-icons/16/gtk-goto-last-ltr.png \
++ stock-icons/16/gtk-go-forward-ltr.png \
++ stock-icons/16/gtk-go-back-ltr.png \
++ stock-icons/16/gtk-goto-top.png \
++ stock-icons/16/gtk-go-up.png \
++ stock-icons/16/gtk-about.png \
++ stock-icons/16/gtk-help.png \
++ stock-icons/16/gtk-missing-image.png \
++ stock-icons/16/gtk-add.png \
++ stock-icons/16/gtk-remove.png \
++ stock-icons/16/gtk-floppy.png \
++ stock-icons/16/gtk-cdrom.png \
++ stock-icons/16/gtk-media-pause.png \
++ stock-icons/16/gtk-media-play-ltr.png \
++ stock-icons/16/gtk-media-play-rtl.png \
++ stock-icons/16/gtk-media-stop.png \
++ stock-icons/16/gtk-media-record.png \
++ stock-icons/16/gtk-media-rewind-ltr.png \
++ stock-icons/16/gtk-media-forward-ltr.png \
++ stock-icons/16/gtk-media-previous-ltr.png \
++ stock-icons/16/gtk-media-next-ltr.png \
++ stock-icons/16/gtk-network.png \
++ stock-icons/16/gtk-print-error.png \
++ stock-icons/16/gtk-print-report.png \
++ stock-icons/16/gtk-print-paused.png \
++ stock-icons/16/gtk-print-warning.png \
++ stock-icons/16/gtk-stop.png \
++ stock-icons/16/gtk-execute.png \
++ stock-icons/16/gtk-spell-check.png \
++ stock-icons/16/gtk-fullscreen.png \
++ stock-icons/16/gtk-refresh.png \
++ stock-icons/16/gtk-leave-fullscreen.png \
++ stock-icons/16/gtk-sort-ascending.png \
++ stock-icons/16/gtk-sort-descending.png \
++ stock-icons/16/gtk-close.png \
++ stock-icons/16/gtk-zoom-fit.png \
++ stock-icons/16/gtk-zoom-in.png \
++ stock-icons/16/gtk-zoom-100.png \
++ stock-icons/16/gtk-zoom-out.png \
++ stock-icons/24/gtk-quit.png \
++ stock-icons/24/gtk-info.png \
++ stock-icons/24/gtk-file.png \
++ stock-icons/24/gtk-open.png \
++ stock-icons/24/gtk-print-preview.png \
++ stock-icons/24/gtk-print.png \
++ stock-icons/24/gtk-properties.png \
++ stock-icons/24/gtk-revert-to-saved-ltr.png \
++ stock-icons/24/gtk-revert-to-saved-rtl.png \
++ stock-icons/24/gtk-save-as.png \
++ stock-icons/24/gtk-new.png \
++ stock-icons/24/gtk-harddisk.png \
++ stock-icons/24/gtk-clear.png \
++ stock-icons/24/gtk-copy.png \
++ stock-icons/24/gtk-cut.png \
++ stock-icons/24/gtk-delete.png \
++ stock-icons/24/gtk-find-and-replace.png \
++ stock-icons/24/gtk-find.png \
++ stock-icons/24/gtk-paste.png \
++ stock-icons/24/gtk-redo-ltr.png \
++ stock-icons/24/gtk-redo-rtl.png \
++ stock-icons/24/gtk-select-all.png \
++ stock-icons/24/gtk-undo-ltr.png \
++ stock-icons/24/gtk-undo-rtl.png \
++ stock-icons/24/gtk-directory.png \
++ stock-icons/24/gtk-unindent-ltr.png \
++ stock-icons/24/gtk-unindent-rtl.png \
++ stock-icons/24/gtk-indent-ltr.png \
++ stock-icons/24/gtk-indent-rtl.png \
++ stock-icons/24/gtk-justify-center.png \
++ stock-icons/24/gtk-justify-fill.png \
++ stock-icons/24/gtk-justify-left.png \
++ stock-icons/24/gtk-justify-right.png \
++ stock-icons/24/gtk-bold.png \
++ stock-icons/24/gtk-italic.png \
++ stock-icons/24/gtk-strikethrough.png \
++ stock-icons/24/gtk-underline.png \
++ stock-icons/24/gtk-goto-bottom.png \
++ stock-icons/24/gtk-go-down.png \
++ stock-icons/24/gtk-goto-first-ltr.png \
++ stock-icons/24/gtk-home.png \
++ stock-icons/24/gtk-jump-to-ltr.png \
++ stock-icons/24/gtk-jump-to-rtl.png \
++ stock-icons/24/gtk-goto-last-ltr.png \
++ stock-icons/24/gtk-go-forward-ltr.png \
++ stock-icons/24/gtk-go-back-ltr.png \
++ stock-icons/24/gtk-goto-top.png \
++ stock-icons/24/gtk-go-up.png \
++ stock-icons/24/gtk-about.png \
++ stock-icons/24/gtk-help.png \
++ stock-icons/24/gtk-missing-image.png \
++ stock-icons/24/gtk-add.png \
++ stock-icons/24/gtk-remove.png \
++ stock-icons/24/gtk-floppy.png \
++ stock-icons/24/gtk-cdrom.png \
++ stock-icons/24/gtk-media-pause.png \
++ stock-icons/24/gtk-media-play-ltr.png \
++ stock-icons/24/gtk-media-play-rtl.png \
++ stock-icons/24/gtk-media-stop.png \
++ stock-icons/24/gtk-media-record.png \
++ stock-icons/24/gtk-media-rewind-ltr.png \
++ stock-icons/24/gtk-media-forward-ltr.png \
++ stock-icons/24/gtk-media-previous-ltr.png \
++ stock-icons/24/gtk-media-next-ltr.png \
++ stock-icons/24/gtk-network.png \
++ stock-icons/24/gtk-print-error.png \
++ stock-icons/24/gtk-print-report.png \
++ stock-icons/24/gtk-print-paused.png \
++ stock-icons/24/gtk-print-warning.png \
++ stock-icons/24/gtk-stop.png \
++ stock-icons/24/gtk-execute.png \
++ stock-icons/24/gtk-spell-check.png \
++ stock-icons/24/gtk-fullscreen.png \
++ stock-icons/24/gtk-refresh.png \
++ stock-icons/24/gtk-leave-fullscreen.png \
++ stock-icons/24/gtk-sort-ascending.png \
++ stock-icons/24/gtk-sort-descending.png \
++ stock-icons/24/gtk-close.png \
++ stock-icons/24/gtk-zoom-fit.png \
++ stock-icons/24/gtk-zoom-in.png \
++ stock-icons/24/gtk-zoom-100.png \
++ stock-icons/24/gtk-zoom-out.png
++
+
+ @CROSS_COMPILING_FALSE@gtk_update_icon_cache_program = \
+ @CROSS_COMPILING_FALSE@ ./gtk-update-icon-cache
+@@ -2866,6 +3031,88 @@ stamp-icons: $(STOCK_ICONS)
+ && $(LN_S) folder.png user-desktop.png \
+ && $(RM) text-x-generic.png \
+ && $(LN_S) document-x-generic.png text-x-generic.png \
++ && $(LN_S) application-exit.png gtk-quit.png \
++ && $(LN_S) dialog-info.png gtk-info.png \
++ && $(LN_S) document-new.png gtk-file.png \
++ && $(LN_S) document-open.png gtk-open.png \
++ && $(LN_S) document-print-preview.png gtk-print-preview.png \
++ && $(LN_S) document-print.png gtk-print.png \
++ && $(LN_S) document-properties.png gtk-properties.png \
++ && $(LN_S) document-revert-ltr.png gtk-revert-to-saved-ltr.png \
++ && $(LN_S) document-revert-rtl.png gtk-revert-to-saved-rtl.png \
++ && $(LN_S) document-save-as.png gtk-save-as.png \
++ && $(LN_S) document-x-generic.png gtk-new.png \
++ && $(LN_S) drive-harddisk.png gtk-harddisk.png \
++ && $(LN_S) edit-clear.png gtk-clear.png \
++ && $(LN_S) edit-copy.png gtk-copy.png \
++ && $(LN_S) edit-cut.png gtk-cut.png \
++ && $(LN_S) edit-delete.png gtk-delete.png \
++ && $(LN_S) edit-find-replace.png gtk-find-and-replace.png \
++ && $(LN_S) edit-find.png gtk-find.png \
++ && $(LN_S) edit-paste.png gtk-paste.png \
++ && $(LN_S) edit-redo-ltr.png gtk-redo-ltr.png \
++ && $(LN_S) edit-redo-rtl.png gtk-redo-rtl.png \
++ && $(LN_S) edit-select-all.png gtk-select-all.png \
++ && $(LN_S) edit-undo-ltr.png gtk-undo-ltr.png \
++ && $(LN_S) edit-undo-rtl.png gtk-undo-rtl.png \
++ && $(LN_S) folder.png gtk-directory.png \
++ && $(LN_S) format-indent-less-ltr.png gtk-unindent-ltr.png \
++ && $(LN_S) format-indent-less-rtl.png gtk-unindent-rtl.png \
++ && $(LN_S) format-indent-more-ltr.png gtk-indent-ltr.png \
++ && $(LN_S) format-indent-more-rtl.png gtk-indent-rtl.png \
++ && $(LN_S) format-justify-center.png gtk-justify-center.png \
++ && $(LN_S) format-justify-fill.png gtk-justify-fill.png \
++ && $(LN_S) format-justify-left.png gtk-justify-left.png \
++ && $(LN_S) format-justify-right.png gtk-justify-right.png \
++ && $(LN_S) format-text-bold.png gtk-bold.png \
++ && $(LN_S) format-text-italic.png gtk-italic.png \
++ && $(LN_S) format-text-strikethrough.png gtk-strikethrough.png \
++ && $(LN_S) format-text-underline.png gtk-underline.png \
++ && $(LN_S) go-bottom.png gtk-goto-bottom.png \
++ && $(LN_S) go-down.png gtk-go-down.png \
++ && $(LN_S) go-first-ltr.png gtk-goto-first-ltr.png \
++ && $(LN_S) go-home.png gtk-home.png \
++ && $(LN_S) go-jump-ltr.png gtk-jump-to-ltr.png \
++ && $(LN_S) go-jump-rtl.png gtk-jump-to-rtl.png \
++ && $(LN_S) go-last-ltr.png gtk-goto-last-ltr.png \
++ && $(LN_S) go-next-ltr.png gtk-go-forward-ltr.png \
++ && $(LN_S) go-previous-ltr.png gtk-go-back-ltr.png \
++ && $(LN_S) go-top.png gtk-goto-top.png \
++ && $(LN_S) go-up.png gtk-go-up.png \
++ && $(LN_S) help-about.png gtk-about.png \
++ && $(LN_S) help-contents.png gtk-help.png \
++ && $(LN_S) image-missing.png gtk-missing-image.png \
++ && $(LN_S) list-add.png gtk-add.png \
++ && $(LN_S) list-remove.png gtk-remove.png \
++ && $(LN_S) media-floppy.png gtk-floppy.png \
++ && $(LN_S) media-optical.png gtk-cdrom.png \
++ && $(LN_S) media-playback-pause.png gtk-media-pause.png \
++ && $(LN_S) media-playback-start-ltr.png gtk-media-play-ltr.png \
++ && $(LN_S) media-playback-start-rtl.png gtk-media-play-rtl.png \
++ && $(LN_S) media-playback-stop.png gtk-media-stop.png \
++ && $(LN_S) media-record.png gtk-media-record.png \
++ && $(LN_S) media-seek-backward-ltr.png gtk-media-rewind-ltr.png \
++ && $(LN_S) media-seek-forward-ltr.png gtk-media-forward-ltr.png \
++ && $(LN_S) media-skip-backward-ltr.png gtk-media-previous-ltr.png \
++ && $(LN_S) media-skip-forward-ltr.png gtk-media-next-ltr.png \
++ && $(LN_S) network-idle.png gtk-network.png \
++ && $(LN_S) printer-error.png gtk-print-error.png \
++ && $(LN_S) printer-info.png gtk-print-report.png \
++ && $(LN_S) printer-paused.png gtk-print-paused.png \
++ && $(LN_S) printer-warning.png gtk-print-warning.png \
++ && $(LN_S) process-stop.png gtk-stop.png \
++ && $(LN_S) system-run.png gtk-execute.png \
++ && $(LN_S) tools-check-spelling.png gtk-spell-check.png \
++ && $(LN_S) view-fullscreen.png gtk-fullscreen.png \
++ && $(LN_S) view-refresh.png gtk-refresh.png \
++ && $(LN_S) view-restore.png gtk-leave-fullscreen.png \
++ && $(LN_S) view-sort-ascending.png gtk-sort-ascending.png \
++ && $(LN_S) view-sort-descending.png gtk-sort-descending.png \
++ && $(LN_S) window-close.png gtk-close.png \
++ && $(LN_S) zoom-fit-best.png gtk-zoom-fit.png \
++ && $(LN_S) zoom-in.png gtk-zoom-in.png \
++ && $(LN_S) zoom-original.png gtk-zoom-100.png \
++ && $(LN_S) zoom-out.png gtk-zoom-out.png \
+ ) done \
+ && touch stamp-icons
+
diff --git a/package/gtk+/patches/patch-gtk_gtktypefuncs_c b/package/gtk+/patches/patch-gtk_gtktypefuncs_c
new file mode 100644
index 000000000..8328bf01c
--- /dev/null
+++ b/package/gtk+/patches/patch-gtk_gtktypefuncs_c
@@ -0,0 +1,78 @@
+--- gtk+-2.22.1.orig/gtk/gtktypefuncs.c 2010-11-15 18:05:27.000000000 +0100
++++ gtk+-2.22.1/gtk/gtktypefuncs.c 2011-01-04 00:15:34.000000000 +0100
+@@ -53,8 +53,8 @@
+ *tp++ = gdk_pixbuf_simple_anim_get_type();
+ *tp++ = gdk_pixbuf_simple_anim_iter_get_type();
+ *tp++ = gdk_pixmap_get_type();
+-*tp++ = gdk_property_state_get_type();
+ *tp++ = gdk_prop_mode_get_type();
++*tp++ = gdk_property_state_get_type();
+ *tp++ = gdk_rectangle_get_type();
+ *tp++ = gdk_rgb_dither_get_type();
+ *tp++ = gdk_screen_get_type();
+@@ -190,14 +190,14 @@
+ *tp++ = gtk_icon_view_drop_position_get_type();
+ *tp++ = gtk_icon_view_get_type();
+ *tp++ = gtk_identifier_get_type();
+-*tp++ = gtk_image_get_type();
+-*tp++ = gtk_image_menu_item_get_type();
+-*tp++ = gtk_image_type_get_type();
+ *tp++ = gtk_im_context_get_type();
+ *tp++ = gtk_im_context_simple_get_type();
+ *tp++ = gtk_im_multicontext_get_type();
+ *tp++ = gtk_im_preedit_style_get_type();
+ *tp++ = gtk_im_status_style_get_type();
++*tp++ = gtk_image_get_type();
++*tp++ = gtk_image_menu_item_get_type();
++*tp++ = gtk_image_type_get_type();
+ *tp++ = gtk_info_bar_get_type();
+ *tp++ = gtk_invisible_get_type();
+ *tp++ = gtk_item_get_type();
+@@ -282,10 +282,10 @@
+ *tp++ = gtk_ruler_get_type();
+ *tp++ = gtk_scale_button_get_type();
+ *tp++ = gtk_scale_get_type();
+-*tp++ = gtk_scrollbar_get_type();
+-*tp++ = gtk_scrolled_window_get_type();
+ *tp++ = gtk_scroll_step_get_type();
+ *tp++ = gtk_scroll_type_get_type();
++*tp++ = gtk_scrollbar_get_type();
++*tp++ = gtk_scrolled_window_get_type();
+ *tp++ = gtk_selection_data_get_type();
+ *tp++ = gtk_selection_mode_get_type();
+ *tp++ = gtk_sensitivity_type_get_type();
+@@ -302,11 +302,11 @@
+ *tp++ = gtk_sort_type_get_type();
+ *tp++ = gtk_spin_button_get_type();
+ *tp++ = gtk_spin_button_update_policy_get_type();
+-*tp++ = gtk_spinner_get_type();
+ *tp++ = gtk_spin_type_get_type();
++*tp++ = gtk_spinner_get_type();
+ *tp++ = gtk_state_type_get_type();
+-*tp++ = gtk_statusbar_get_type();
+ *tp++ = gtk_status_icon_get_type();
++*tp++ = gtk_statusbar_get_type();
+ *tp++ = gtk_style_get_type();
+ *tp++ = gtk_submenu_direction_get_type();
+ *tp++ = gtk_submenu_placement_get_type();
+@@ -330,16 +330,16 @@
+ *tp++ = gtk_toggle_action_get_type();
+ *tp++ = gtk_toggle_button_get_type();
+ *tp++ = gtk_toggle_tool_button_get_type();
+-*tp++ = gtk_toolbar_child_type_get_type();
+-*tp++ = gtk_toolbar_get_type();
+-*tp++ = gtk_toolbar_space_style_get_type();
+-*tp++ = gtk_toolbar_style_get_type();
+ *tp++ = gtk_tool_button_get_type();
+ *tp++ = gtk_tool_item_get_type();
+ *tp++ = gtk_tool_item_group_get_type();
+ *tp++ = gtk_tool_palette_drag_targets_get_type();
+ *tp++ = gtk_tool_palette_get_type();
+ *tp++ = gtk_tool_shell_get_type();
++*tp++ = gtk_toolbar_child_type_get_type();
++*tp++ = gtk_toolbar_get_type();
++*tp++ = gtk_toolbar_space_style_get_type();
++*tp++ = gtk_toolbar_style_get_type();
+ *tp++ = gtk_tooltip_get_type();
+ *tp++ = gtk_tree_drag_dest_get_type();
+ *tp++ = gtk_tree_drag_source_get_type();
diff --git a/package/gtk+/patches/patch-ltmain_sh b/package/gtk+/patches/patch-ltmain_sh
new file mode 100644
index 000000000..2d17e2538
--- /dev/null
+++ b/package/gtk+/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- gtk+-2.22.1.orig/ltmain.sh 2010-08-13 04:09:38.000000000 +0200
++++ gtk+-2.22.1/ltmain.sh 2011-01-14 23:50:15.000000000 +0100
+@@ -5091,7 +5091,7 @@ func_mode_link ()
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/hdparm/patches/patch-Makefile b/package/hdparm/patches/patch-Makefile
index 03c74f509..616b9fccc 100644
--- a/package/hdparm/patches/patch-Makefile
+++ b/package/hdparm/patches/patch-Makefile
@@ -1,32 +1,36 @@
--- hdparm-9.15.orig/Makefile 2008-12-10 01:14:28.000000000 +0100
-+++ hdparm-9.15/Makefile 2010-02-13 12:24:25.000000000 +0100
-@@ -13,7 +13,7 @@ oldmandir = $(manprefix)/man
++++ hdparm-9.15/Makefile 2011-01-15 20:46:42.000000000 +0100
+@@ -13,10 +13,10 @@ oldmandir = $(manprefix)/man
CC ?= gcc
STRIP ?= strip
-
+
-CFLAGS := -O2 -W -Wall -Wbad-function-cast -Wcast-align -Wpointer-arith -Wcast-qual -Wshadow -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -fkeep-inline-functions -Wwrite-strings -Waggregate-return -Wnested-externs -Wtrigraphs $(CFLAGS)
+CFLAGS ?= -O2 -W -Wall -Wbad-function-cast -Wcast-align -Wpointer-arith -Wcast-qual -Wshadow -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -fkeep-inline-functions -Wwrite-strings -Waggregate-return -Wnested-externs -Wtrigraphs $(CFLAGS)
-
+
#LDFLAGS = -s -static
- LDFLAGS = -s
+-LDFLAGS = -s
++LDFLAGS ?= -s
+ INSTALL = install
+ INSTALL_DATA = $(INSTALL) -m 644
+ INSTALL_DIR = $(INSTALL) -m 755 -d
@@ -28,7 +28,6 @@ all: hdparm
-
+
hdparm: hdparm.h sgio.h $(OBJS)
$(CC) $(LDFLAGS) -o hdparm $(OBJS)
- $(STRIP) hdparm
-
+
hdparm.o: hdparm.h sgio.h
-
+
@@ -46,9 +45,9 @@ install: all hdparm.8
- if [ -f $(DESTDIR)$(sbindir)/hdparm ]; then rm -f $(DESTDIR)$(sbindir)/hdparm ; fi
- if [ -f $(DESTDIR)$(mandir)/man8/hdparm.8 ]; then rm -f $(DESTDIR)$(mandir)/man8/hdparm.8 ;\
- elif [ -f $(DESTDIR)$(oldmandir)/man8/hdparm.8 ]; then rm -f $(DESTDIR)$(oldmandir)/man8/hdparm.8 ; fi
+ if [ -f $(DESTDIR)$(sbindir)/hdparm ]; then rm -f $(DESTDIR)$(sbindir)/hdparm ; fi
+ if [ -f $(DESTDIR)$(mandir)/man8/hdparm.8 ]; then rm -f $(DESTDIR)$(mandir)/man8/hdparm.8 ;\
+ elif [ -f $(DESTDIR)$(oldmandir)/man8/hdparm.8 ]; then rm -f $(DESTDIR)$(oldmandir)/man8/hdparm.8 ; fi
- $(INSTALL_PROGRAM) -D hdparm $(DESTDIR)$(sbindir)/hdparm
- if [ -d $(DESTDIR)$(mandir) ]; then $(INSTALL_DATA) -D hdparm.8 $(DESTDIR)$(mandir)/man8/hdparm.8 ;\
- elif [ -d $(DESTDIR)$(oldmandir) ]; then $(INSTALL_DATA) -D hdparm.8 $(DESTDIR)$(oldmandir)/man8/hdparm.8 ; fi
+ $(INSTALL_PROGRAM) hdparm $(DESTDIR)$(sbindir)/hdparm
+ if [ -d $(DESTDIR)$(mandir) ]; then $(INSTALL_DATA) hdparm.8 $(DESTDIR)$(mandir)/man8/hdparm.8 ;\
+ elif [ -d $(DESTDIR)$(oldmandir) ]; then $(INSTALL_DATA) hdparm.8 $(DESTDIR)$(oldmandir)/man8/hdparm.8 ; fi
-
+
clean:
- -rm -f hdparm $(OBJS) core 2>/dev/null
+ -rm -f hdparm $(OBJS) core 2>/dev/null
diff --git a/package/heimdal/Makefile b/package/heimdal/Makefile
index ca7f3e93c..9568237e0 100644
--- a/package/heimdal/Makefile
+++ b/package/heimdal/Makefile
@@ -5,34 +5,32 @@ include $(TOPDIR)/rules.mk
PKG_NAME:= heimdal
PKG_VERSION:= 1.4
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= 31d08bbf47a77827fe97ef3f52b4c9c4
PKG_DESCR:= Kerberos 5 server
PKG_SECTION:= crypto
-PKG_DEPENDS:= libheimdal libheimdal-client libncurses libcom-err
-PKG_BUILDDEP:= openssl ncurses e2fsprogs
+PKG_DEPENDS:= libheimdal libheimdal-client libncurses libcom-err libreadline
+PKG_BUILDDEP:= openssl ncurses e2fsprogs readline
PKG_URL:= http://www.h5l.org/
PKG_SITES:= http://www.h5l.org/dist/src/
PKG_NOPARALLEL:= 1
-PKG_HOST_DEPENDS:= !darwin
-
PKG_SUBPKGS:= HEIMDAL LIBHEIMDAL LIBHEIMDAL_CLIENT
PKGSD_LIBHEIMDAL:= Kerberos 5 server libraries
PKGSC_LIBHEIMDAL:= libs
PKGSD_LIBHEIMDAL_CLIENT:= Kerberos 5 client libraries
PKGSC_LIBHEIMDAL_CLIENT:= libs
-PKG_FLAVOURS:= PKINIT
-PKGFD_PKINIT:= Enable PK-INIT
+PKG_FLAVOURS_HEIMDAL_SERVER:= WITH_PKINIT
+PKGFD_WITH_PKINIT: Enable PK-INIT
-PKG_CHOICES:= WITH_LDAP WITH_BDB
-PKGCD_WITH_LDAP:= use OpenLDAP as database backend
-PKGCS_WITH_LDAP:= libopenldap
-PKGCB_WITH_LDAP:= openldap
-PKGCD_WITH_BDB:= use Berkeley DB as database backend
-PKGCS_WITH_BDB:= libdb
-PKGCB_WITH_BDB:= libdb
+PKG_CHOICES_HEIMDAL_SERVER:= WITH_LDAP WITH_BDB
+PKGCD_WITH_LDAP:= use OpenLDAP as database backend
+PKGCS_WITH_LDAP:= libopenldap
+PKGCB_WITH_LDAP:= openldap
+PKGCD_WITH_BDB:= use Berkeley DB as database backend
+PKGCS_WITH_BDB:= libdb
+PKGCB_WITH_BDB:= libdb
include $(TOPDIR)/mk/package.mk
@@ -45,16 +43,18 @@ CONFIGURE_OPTS:= --with-hdbdir=/etc/heimdal \
--disable-ndbm-db \
--libdir=/usr/lib/heimdal \
--libexecdir=/usr/sbin \
+ --with-openssl=${STAGING_TARGET_DIR}/usr \
+ --with-readline=${STAGING_TARGET_DIR}/usr \
--with-ipv6 \
--sysconfdir=/etc/heimdal
-ifeq ($(ADK_COMPILE_HEIMDAL_WITH_BDB),y)
-CONFIGURE_ARGS+= --enable-berkeley-db
+ifeq ($(ADK_PACKAGE_HEIMDAL_SERVER_WITH_BDB),y)
+CONFIGURE_ARGS+= --with-berkeley-db
else
-CONFIGURE_ARGS+= --disable-berkeley-db
+CONFIGURE_ARGS+= --without-berkeley-db
endif
-ifeq ($(ADK_COMPILE_HEIMDAL_WITH_LDAP),y)
+ifeq ($(ADK_PACKAGE_HEIMDAL_SERVER_WITH_LDAP),y)
CONFIGURE_ARGS+= --with-openldap=yes
CONFIGURE_ARGS+= --with-openldap-include=${STAGING_TARGET_DIR}/usr
CONFIGURE_ARGS+= --with-openldap-lib=${STAGING_TARGET_DIR}/usr
@@ -62,10 +62,11 @@ else
CONFIGURE_ARGS+= --without-openldap
endif
-ifeq ($(ADK_PACKAGE_HEIMDAL_PKINIT),y)
+ifeq ($(ADK_PACKAGE_HEIMDAL_SERVER_WITH_PKINIT),y)
CONFIGURE_OPTS+= --enable-pk-init
else
-CONFIGURE_OPTS+= --disable-pk-init
+CONFIGURE_OPTS+= --disable-pk-init \
+ --disable-kx509
endif
TCFLAGS+= -I${STAGING_TARGET_DIR}/usr/include/et -pthread
@@ -74,29 +75,27 @@ CONFIGURE_ARGS+= ${CONFIGURE_OPTS} --with-cross-tools=${STAGING_HOST_DIR}/bin
CONFIGURE_ENV+= cross_compiling=yes \
ac_cv_func_getaddrinfo_numserv=yes
-ifeq ($(ADK_HOST_CYGWIN),y)
-EXEEXT:= .exe
-endif
-
-pre-configure:
+post-extract:
(cd ${WRKBUILD}; rm -rf config.{cache,status} ; \
./configure --prefix=$(STAGING_HOST_DIR) \
--disable-pk-init \
--without-openldap \
+ --disable-sqlite-cache \
--disable-otp \
);
${MAKE} -C ${WRKBUILD}/include
${MAKE} -C ${WRKBUILD}/lib/roken
${MAKE} -C ${WRKBUILD}/lib/vers
${MAKE} -C ${WRKBUILD}/lib/editline
- ${MAKE} -C ${WRKBUILD}/lib/asn1 asn1_compile$(EXEEXT)
- ${MAKE} -C ${WRKBUILD}/lib/sl slc$(EXEEXT)
- ${INSTALL_BIN} ${WRKBUILD}/lib/roken/make-roken$(EXEEXT) \
- ${STAGING_HOST_DIR}/bin
- ${INSTALL_BIN} ${WRKBUILD}/lib/sl/slc$(EXEEXT) \
- ${STAGING_HOST_DIR}/bin
+ env CFLAGS="-static" LDFLAGS="-static" ${MAKE} -C ${WRKBUILD}/lib/com_err compile_et$(EXEEXT)
+ env CFLAGS="-static" LDFLAGS="-static" ${MAKE} -C ${WRKBUILD}/lib/asn1 asn1_compile$(EXEEXT)
+ env CFLAGS="-static" LDFLAGS="-static" ${MAKE} -C ${WRKBUILD}/lib/sl slc$(EXEEXT)
${MAKE} -C ${WRKBUILD}/lib/roken install
${MAKE} -C ${WRKBUILD}/lib/asn1 install
+ ${MAKE} -C ${WRKBUILD}/lib/sl install
+ $(CP) $(STAGING_HOST_DIR)/libexec/heimdal/{slc,asn1_compile} \
+ $(STAGING_HOST_DIR)/bin
+ ${MAKE} -C ${WRKBUILD}/lib/sl clean
${MAKE} -C ${WRKBUILD}/lib/asn1 clean
${MAKE} -C ${WRKBUILD}/lib/roken clean
${MAKE} -C ${WRKBUILD} clean
diff --git a/package/heimdal/patches/patch-Makefile_in b/package/heimdal/patches/patch-Makefile_in
new file mode 100644
index 000000000..d1883a559
--- /dev/null
+++ b/package/heimdal/patches/patch-Makefile_in
@@ -0,0 +1,24 @@
+--- heimdal-1.4.orig/Makefile.in 2010-09-13 09:24:25.000000000 +0200
++++ heimdal-1.4/Makefile.in 2011-01-12 14:10:53.848658254 +0100
+@@ -114,8 +114,8 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGE
+ distdir dist dist-all distcheck
+ ETAGS = etags
+ CTAGS = ctags
+-DIST_SUBDIRS = include lib kuser kdc admin kadmin kpasswd kcm appl doc \
+- tools tests packages etc po
++DIST_SUBDIRS = include lib kuser kdc admin kadmin kpasswd kcm \
++ tools packages etc
+ DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ distdir = $(PACKAGE)-$(VERSION)
+ top_distdir = $(distdir)
+@@ -392,8 +392,8 @@ LIB_kafs = $(top_builddir)/lib/kafs/libk
+ @KRB5_TRUE@LIB_tsasl = $(top_builddir)/lib/tsasl/libtsasl.la
+ @DCE_TRUE@LIB_kdfs = $(top_builddir)/lib/kdfs/libkdfs.la
+ @KCM_TRUE@kcm_dir = kcm
+-SUBDIRS = include lib kuser kdc admin kadmin kpasswd $(kcm_dir) appl \
+- doc tools tests packages etc po
++SUBDIRS = include lib kuser kdc admin kadmin kpasswd $(kcm_dir) \
++ tools packages etc
+ ACLOCAL_AMFLAGS = -I cf
+ EXTRA_DIST = \
+ TODO \
diff --git a/package/heimdal/patches/patch-configure b/package/heimdal/patches/patch-configure
new file mode 100644
index 000000000..29a003f6b
--- /dev/null
+++ b/package/heimdal/patches/patch-configure
@@ -0,0 +1,19 @@
+--- heimdal-1.4.orig/configure 2010-09-13 09:24:11.000000000 +0200
++++ heimdal-1.4/configure 2011-01-11 18:51:09.154898347 +0100
+@@ -26892,7 +26892,7 @@ rm -fr conftest*
+ fi
+
+ if test "${krb_cv_compile_et_cross}" = yes ; then
+- krb_cv_com_err="cross"
++ krb_cv_com_err="yes"
+ elif test "${krb_cv_compile_et}" = "yes"; then
+ krb_cv_save_LIBS="${LIBS}"
+ LIBS="${LIBS} -lcom_err"
+@@ -26928,6 +26928,7 @@ else
+ krb_cv_com_err="no"
+ fi
+
++krb_cv_com_err="yes"
+ if test "${krb_cv_com_err}" = "yes"; then
+ DIR_com_err=""
+ LIB_com_err="-lcom_err"
diff --git a/package/heimdal/patches/patch-kdc_config_c b/package/heimdal/patches/patch-kdc_config_c
new file mode 100644
index 000000000..104086102
--- /dev/null
+++ b/package/heimdal/patches/patch-kdc_config_c
@@ -0,0 +1,18 @@
+--- heimdal-1.4.orig/kdc/config.c 2010-09-13 09:23:34.000000000 +0200
++++ heimdal-1.4/kdc/config.c 2011-01-12 13:55:17.454913780 +0100
+@@ -347,6 +347,7 @@ configure(krb5_context context, int argc
+
+ #endif
+
++#ifdef PKINIT
+ if (config->enable_pkinit) {
+ if (config->pkinit_kdc_identity == NULL)
+ krb5_errx(context, 1, "pkinit enabled but no identity");
+@@ -361,6 +362,7 @@ configure(krb5_context context, int argc
+ config->pkinit_kdc_revoke);
+
+ }
++#endif
+
+ return config;
+ }
diff --git a/package/heimdal/patches/patch-kdc_kdc-replay_c b/package/heimdal/patches/patch-kdc_kdc-replay_c
new file mode 100644
index 000000000..504e4962f
--- /dev/null
+++ b/package/heimdal/patches/patch-kdc_kdc-replay_c
@@ -0,0 +1,18 @@
+--- heimdal-1.4.orig/kdc/kdc-replay.c 2010-09-13 09:23:34.000000000 +0200
++++ heimdal-1.4/kdc/kdc-replay.c 2011-01-12 14:08:08.048658301 +0100
+@@ -86,6 +86,7 @@ main(int argc, char **argv)
+ if (ret)
+ krb5_err(context, 1, ret, "krb5_kdc_set_dbinfo");
+
++#ifdef PKINIT
+ if (config->enable_pkinit) {
+ if (config->pkinit_kdc_identity == NULL)
+ krb5_errx(context, 1, "pkinit enabled but no identity");
+@@ -100,6 +101,7 @@ main(int argc, char **argv)
+ config->pkinit_kdc_revoke);
+
+ }
++#endif
+
+ if (argc != 2)
+ errx(1, "argc != 2");
diff --git a/package/heimdal/patches/patch-lib_hcrypto_Makefile_in b/package/heimdal/patches/patch-lib_hcrypto_Makefile_in
new file mode 100644
index 000000000..fb16d3504
--- /dev/null
+++ b/package/heimdal/patches/patch-lib_hcrypto_Makefile_in
@@ -0,0 +1,12 @@
+--- heimdal-1.4.orig/lib/hcrypto/Makefile.in 2010-09-13 09:24:20.000000000 +0200
++++ heimdal-1.4/lib/hcrypto/Makefile.in 2011-01-11 20:11:30.955611146 +0100
+@@ -716,6 +716,9 @@ imathsource = \
+ imath/iprime.h
+
+ ltmsources = \
++ libtommath/tommath.h \
++ libtommath/tommath_class.h \
++ libtommath/tommath_superclass.h \
+ libtommath/bncore.c \
+ libtommath/bn_mp_init.c \
+ libtommath/bn_mp_clear.c \
diff --git a/package/heimdal/patches/patch-lib_roken_Makefile_in.orig b/package/heimdal/patches/patch-lib_roken_Makefile_in.orig
deleted file mode 100644
index 7d207e474..000000000
--- a/package/heimdal/patches/patch-lib_roken_Makefile_in.orig
+++ /dev/null
@@ -1,27 +0,0 @@
---- heimdal-1.4.orig/lib/roken/Makefile.in 2010-09-13 09:24:23.000000000 +0200
-+++ heimdal-1.4/lib/roken/Makefile.in 2010-11-10 18:57:00.174995995 +0100
-@@ -1977,18 +1977,13 @@ $(LTLIBOBJS) $(libroken_la_OBJECTS): rok
- .hin.h:
- cp $< $@
-
--@CROSS_COMPILE_FALSE@roken.h: make-roken$(EXEEXT)
--@CROSS_COMPILE_FALSE@ @./make-roken$(EXEEXT) > tmp.h ;\
--@CROSS_COMPILE_FALSE@ if [ -f roken.h ] && cmp -s tmp.h roken.h ; then rm -f tmp.h ; \
--@CROSS_COMPILE_FALSE@ else rm -f roken.h; mv tmp.h roken.h; fi
--
--@CROSS_COMPILE_FALSE@make-roken.c: roken.h.in roken.awk
--@CROSS_COMPILE_FALSE@ $(AWK) -f $(srcdir)/roken.awk $(srcdir)/roken.h.in > make-roken.c
-+roken.h: make-roken$(EXEEXT)
-+ ./make-roken$(EXEEXT) > tmp.h ;\
-+ if [ -f roken.h ] && cmp -s tmp.h roken.h ; then rm -f tmp.h ; \
-+ else rm -f roken.h; mv tmp.h roken.h; fi
-
--@CROSS_COMPILE_TRUE@roken.h: $(top_srcdir)/cf/roken-h-process.pl roken.h.in
--@CROSS_COMPILE_TRUE@ perl $(top_srcdir)/cf/roken-h-process.pl \
--@CROSS_COMPILE_TRUE@ -c $(top_builddir)/include/config.h \
--@CROSS_COMPILE_TRUE@ -p $(srcdir)/roken.h.in -o roken.h
-+make-roken.c: roken.h.in roken.awk
-+ $(AWK) -f $(srcdir)/roken.awk $(srcdir)/roken.h.in > make-roken.c
-
- # Tell versions [3.59,3.63) of GNU make to not export all variables.
- # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/package/heimdal/patches/patch-lib_roken_roken_h_in b/package/heimdal/patches/patch-lib_roken_roken_h_in
deleted file mode 100644
index 59e9a2c52..000000000
--- a/package/heimdal/patches/patch-lib_roken_roken_h_in
+++ /dev/null
@@ -1,11 +0,0 @@
---- heimdal-1.4.orig/lib/roken/roken.h.in 2010-09-13 09:23:34.000000000 +0200
-+++ heimdal-1.4/lib/roken/roken.h.in 2010-11-10 19:46:45.916683899 +0100
-@@ -524,7 +524,7 @@ ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL ge
- ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL strerror(int);
- #endif
-
--#if (!defined(HAVE_STRERROR_R) && !defined(strerror_r)) || (!defined(STRERROR_R_PROTO_COMPATIBLE) && defined(HAVE_STRERROR_R))
-+#if ( !defined(HAVE_STRERROR_R) && !defined(strerror_r)) || (!defined(STRERROR_R_PROTO_COMPATIBLE) && defined(HAVE_STRERROR_R))
- int ROKEN_LIB_FUNCTION rk_strerror_r(int, char *, size_t);
- #else
- #define rk_strerror_r strerror_r
diff --git a/package/heimdal/patches/patch-ltmain_sh b/package/heimdal/patches/patch-ltmain_sh
new file mode 100644
index 000000000..fcf6dad2c
--- /dev/null
+++ b/package/heimdal/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- heimdal-1.4.orig/ltmain.sh 2010-09-13 09:24:01.000000000 +0200
++++ heimdal-1.4/ltmain.sh 2011-01-15 20:52:41.000000000 +0100
+@@ -4238,7 +4238,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/heimdal/src/lib/hcrypto/libtommath/tommath.h b/package/heimdal/src/lib/hcrypto/libtommath/tommath.h
new file mode 100644
index 000000000..426207a29
--- /dev/null
+++ b/package/heimdal/src/lib/hcrypto/libtommath/tommath.h
@@ -0,0 +1,592 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library was designed directly after the MPI library by
+ * Michael Fromberger but has been written from scratch with
+ * additional optimizations in place.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com
+ */
+#ifndef BN_H_
+#define BN_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+
+#include <tommath_class.h>
+
+#ifndef MIN
+ #define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+ #define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+
+/* C++ compilers don't like assigning void * to mp_digit * */
+#define OPT_CAST(x) (x *)
+
+#else
+
+/* C on the other hand doesn't care */
+#define OPT_CAST(x)
+
+#endif
+
+
+/* detect 64-bit mode if possible */
+#if defined(__x86_64__)
+ #if !(defined(MP_64BIT) && defined(MP_16BIT) && defined(MP_8BIT))
+ #define MP_64BIT
+ #endif
+#endif
+
+/* some default configurations.
+ *
+ * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits
+ * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits
+ *
+ * At the very least a mp_digit must be able to hold 7 bits
+ * [any size beyond that is ok provided it doesn't overflow the data type]
+ */
+#ifdef MP_8BIT
+ typedef unsigned char mp_digit;
+ typedef unsigned short mp_word;
+#elif defined(MP_16BIT)
+ typedef unsigned short mp_digit;
+ typedef unsigned long mp_word;
+#elif defined(MP_64BIT)
+ /* for GCC only on supported platforms */
+#ifndef CRYPT
+ typedef unsigned long long ulong64;
+ typedef signed long long long64;
+#endif
+
+ typedef unsigned long mp_digit;
+ typedef unsigned long mp_word __attribute__ ((mode(TI)));
+
+ #define DIGIT_BIT 60
+#else
+ /* this is the default case, 28-bit digits */
+
+ /* this is to make porting into LibTomCrypt easier :-) */
+#ifndef CRYPT
+ #if defined(_MSC_VER) || defined(__BORLANDC__)
+ typedef unsigned __int64 ulong64;
+ typedef signed __int64 long64;
+ #else
+ typedef unsigned long long ulong64;
+ typedef signed long long long64;
+ #endif
+#endif
+
+ typedef unsigned long mp_digit;
+ typedef ulong64 mp_word;
+
+#ifdef MP_31BIT
+ /* this is an extension that uses 31-bit digits */
+ #define DIGIT_BIT 31
+#else
+ /* default case is 28-bit digits, defines MP_28BIT as a handy macro to test */
+ #define DIGIT_BIT 28
+ #define MP_28BIT
+#endif
+#endif
+
+/* define heap macros */
+#ifndef CRYPT
+ /* default to libc stuff */
+ #ifndef XMALLOC
+ #define XMALLOC malloc
+ #define XFREE free
+ #define XREALLOC realloc
+ #define XCALLOC calloc
+ #else
+ /* prototypes for our heap functions */
+ extern void *XMALLOC(size_t n);
+ extern void *XREALLOC(void *p, size_t n);
+ extern void *XCALLOC(size_t n, size_t s);
+ extern void XFREE(void *p);
+ #endif
+#endif
+
+
+/* otherwise the bits per digit is calculated automatically from the size of a mp_digit */
+#ifndef DIGIT_BIT
+ #define DIGIT_BIT ((int)((CHAR_BIT * sizeof(mp_digit) - 1))) /* bits per digit */
+#endif
+
+#define MP_DIGIT_BIT DIGIT_BIT
+#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
+#define MP_DIGIT_MAX MP_MASK
+
+/* equalities */
+#define MP_LT -1 /* less than */
+#define MP_EQ 0 /* equal to */
+#define MP_GT 1 /* greater than */
+
+#define MP_ZPOS 0 /* positive integer */
+#define MP_NEG 1 /* negative */
+
+#define MP_OKAY 0 /* ok result */
+#define MP_MEM -2 /* out of mem */
+#define MP_VAL -3 /* invalid input */
+#define MP_RANGE MP_VAL
+
+#define MP_YES 1 /* yes response */
+#define MP_NO 0 /* no response */
+
+/* Primality generation flags */
+#define LTM_PRIME_BBS 0x0001 /* BBS style prime */
+#define LTM_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */
+#define LTM_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */
+
+typedef int mp_err;
+
+/* you'll have to tune these... */
+extern int KARATSUBA_MUL_CUTOFF,
+ KARATSUBA_SQR_CUTOFF,
+ TOOM_MUL_CUTOFF,
+ TOOM_SQR_CUTOFF;
+
+/* define this to use lower memory usage routines (exptmods mostly) */
+/* #define MP_LOW_MEM */
+
+/* default precision */
+#ifndef MP_PREC
+ #ifndef MP_LOW_MEM
+ #define MP_PREC 32 /* default digits of precision */
+ #else
+ #define MP_PREC 8 /* default digits of precision */
+ #endif
+#endif
+
+/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
+#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
+
+/* the infamous mp_int structure */
+typedef struct {
+ int used, alloc, sign;
+ mp_digit *dp;
+} mp_int;
+
+/* callback for mp_prime_random, should fill dst with random bytes and return how many read [upto len] */
+typedef int ltm_prime_callback(unsigned char *dst, int len, void *dat);
+
+
+#define USED(m) ((m)->used)
+#define DIGIT(m,k) ((m)->dp[(k)])
+#define SIGN(m) ((m)->sign)
+
+/* error code to char* string */
+char *mp_error_to_string(int code);
+
+/* ---> init and deinit bignum functions <--- */
+/* init a bignum */
+int mp_init(mp_int *a);
+
+/* free a bignum */
+void mp_clear(mp_int *a);
+
+/* init a null terminated series of arguments */
+int mp_init_multi(mp_int *mp, ...);
+
+/* clear a null terminated series of arguments */
+void mp_clear_multi(mp_int *mp, ...);
+
+/* exchange two ints */
+void mp_exch(mp_int *a, mp_int *b);
+
+/* shrink ram required for a bignum */
+int mp_shrink(mp_int *a);
+
+/* grow an int to a given size */
+int mp_grow(mp_int *a, int size);
+
+/* init to a given number of digits */
+int mp_init_size(mp_int *a, int size);
+
+/* ---> Basic Manipulations <--- */
+#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
+#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
+#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
+#define mp_isneg(a) (((a)->sign) ? MP_YES : MP_NO)
+
+/* set to zero */
+void mp_zero(mp_int *a);
+
+/* set to zero, multi */
+void mp_zero_multi(mp_int *a, ...);
+
+/* set to a digit */
+void mp_set(mp_int *a, mp_digit b);
+
+/* set a 32-bit const */
+int mp_set_int(mp_int *a, unsigned long b);
+
+/* get a 32-bit value */
+unsigned long mp_get_int(mp_int * a);
+
+/* initialize and set a digit */
+int mp_init_set (mp_int * a, mp_digit b);
+
+/* initialize and set 32-bit value */
+int mp_init_set_int (mp_int * a, unsigned long b);
+
+/* copy, b = a */
+int mp_copy(mp_int *a, mp_int *b);
+
+/* inits and copies, a = b */
+int mp_init_copy(mp_int *a, mp_int *b);
+
+/* trim unused digits */
+void mp_clamp(mp_int *a);
+
+/* ---> digit manipulation <--- */
+
+/* right shift by "b" digits */
+void mp_rshd(mp_int *a, int b);
+
+/* left shift by "b" digits */
+int mp_lshd(mp_int *a, int b);
+
+/* c = a / 2**b */
+int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d);
+
+/* b = a/2 */
+int mp_div_2(mp_int *a, mp_int *b);
+
+/* c = a * 2**b */
+int mp_mul_2d(mp_int *a, int b, mp_int *c);
+
+/* b = a*2 */
+int mp_mul_2(mp_int *a, mp_int *b);
+
+/* c = a mod 2**d */
+int mp_mod_2d(mp_int *a, int b, mp_int *c);
+
+/* computes a = 2**b */
+int mp_2expt(mp_int *a, int b);
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(mp_int *a);
+
+/* I Love Earth! */
+
+/* makes a pseudo-random int of a given size */
+int mp_rand(mp_int *a, int digits);
+
+/* ---> binary operations <--- */
+/* c = a XOR b */
+int mp_xor(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a OR b */
+int mp_or(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a AND b */
+int mp_and(mp_int *a, mp_int *b, mp_int *c);
+
+/* ---> Basic arithmetic <--- */
+
+/* b = -a */
+int mp_neg(mp_int *a, mp_int *b);
+
+/* b = |a| */
+int mp_abs(mp_int *a, mp_int *b);
+
+/* compare a to b */
+int mp_cmp(mp_int *a, mp_int *b);
+
+/* compare |a| to |b| */
+int mp_cmp_mag(mp_int *a, mp_int *b);
+
+/* c = a + b */
+int mp_add(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a - b */
+int mp_sub(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = a * b */
+int mp_mul(mp_int *a, mp_int *b, mp_int *c);
+
+/* b = a*a */
+int mp_sqr(mp_int *a, mp_int *b);
+
+/* a/b => cb + d == a */
+int mp_div(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* c = a mod b, 0 <= c < b */
+int mp_mod(mp_int *a, mp_int *b, mp_int *c);
+
+/* ---> single digit functions <--- */
+
+/* compare against a single digit */
+int mp_cmp_d(mp_int *a, mp_digit b);
+
+/* c = a + b */
+int mp_add_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* c = a - b */
+int mp_sub_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* c = a * b */
+int mp_mul_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* a/b => cb + d == a */
+int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d);
+
+/* a/3 => 3c + d == a */
+int mp_div_3(mp_int *a, mp_int *c, mp_digit *d);
+
+/* c = a**b */
+int mp_expt_d(mp_int *a, mp_digit b, mp_int *c);
+
+/* c = a mod b, 0 <= c < b */
+int mp_mod_d(mp_int *a, mp_digit b, mp_digit *c);
+
+/* ---> number theory <--- */
+
+/* d = a + b (mod c) */
+int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* d = a - b (mod c) */
+int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* d = a * b (mod c) */
+int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* c = a * a (mod b) */
+int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = 1/a (mod b) */
+int mp_invmod(mp_int *a, mp_int *b, mp_int *c);
+
+/* c = (a, b) */
+int mp_gcd(mp_int *a, mp_int *b, mp_int *c);
+
+/* produces value such that U1*a + U2*b = U3 */
+int mp_exteuclid(mp_int *a, mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3);
+
+/* c = [a, b] or (a*b)/(a, b) */
+int mp_lcm(mp_int *a, mp_int *b, mp_int *c);
+
+/* finds one of the b'th root of a, such that |c|**b <= |a|
+ *
+ * returns error if a < 0 and b is even
+ */
+int mp_n_root(mp_int *a, mp_digit b, mp_int *c);
+
+/* special sqrt algo */
+int mp_sqrt(mp_int *arg, mp_int *ret);
+
+/* is number a square? */
+int mp_is_square(mp_int *arg, int *ret);
+
+/* computes the jacobi c = (a | n) (or Legendre if b is prime) */
+int mp_jacobi(mp_int *a, mp_int *n, int *c);
+
+/* used to setup the Barrett reduction for a given modulus b */
+int mp_reduce_setup(mp_int *a, mp_int *b);
+
+/* Barrett Reduction, computes a (mod b) with a precomputed value c
+ *
+ * Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely
+ * compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code].
+ */
+int mp_reduce(mp_int *a, mp_int *b, mp_int *c);
+
+/* setups the montgomery reduction */
+int mp_montgomery_setup(mp_int *a, mp_digit *mp);
+
+/* computes a = B**n mod b without division or multiplication useful for
+ * normalizing numbers in a Montgomery system.
+ */
+int mp_montgomery_calc_normalization(mp_int *a, mp_int *b);
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
+
+/* returns 1 if a is a valid DR modulus */
+int mp_dr_is_modulus(mp_int *a);
+
+/* sets the value of "d" required for mp_dr_reduce */
+void mp_dr_setup(mp_int *a, mp_digit *d);
+
+/* reduces a modulo b using the Diminished Radix method */
+int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp);
+
+/* returns true if a can be reduced with mp_reduce_2k */
+int mp_reduce_is_2k(mp_int *a);
+
+/* determines k value for 2k reduction */
+int mp_reduce_2k_setup(mp_int *a, mp_digit *d);
+
+/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */
+int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d);
+
+/* returns true if a can be reduced with mp_reduce_2k_l */
+int mp_reduce_is_2k_l(mp_int *a);
+
+/* determines k value for 2k reduction */
+int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
+
+/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */
+int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
+
+/* d = a**b (mod c) */
+int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/* ---> Primes <--- */
+
+/* number of primes */
+#ifdef MP_8BIT
+ #define PRIME_SIZE 31
+#else
+ #define PRIME_SIZE 256
+#endif
+
+/* table of first PRIME_SIZE primes */
+extern const mp_digit ltm_prime_tab[];
+
+/* result=1 if a is divisible by one of the first PRIME_SIZE primes */
+int mp_prime_is_divisible(mp_int *a, int *result);
+
+/* performs one Fermat test of "a" using base "b".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+int mp_prime_fermat(mp_int *a, mp_int *b, int *result);
+
+/* performs one Miller-Rabin test of "a" using base "b".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+int mp_prime_miller_rabin(mp_int *a, mp_int *b, int *result);
+
+/* This gives [for a given bit size] the number of trials required
+ * such that Miller-Rabin gives a prob of failure lower than 2^-96
+ */
+int mp_prime_rabin_miller_trials(int size);
+
+/* performs t rounds of Miller-Rabin on "a" using the first
+ * t prime bases. Also performs an initial sieve of trial
+ * division. Determines if "a" is prime with probability
+ * of error no more than (1/4)**t.
+ *
+ * Sets result to 1 if probably prime, 0 otherwise
+ */
+int mp_prime_is_prime(mp_int *a, int t, int *result);
+
+/* finds the next prime after the number "a" using "t" trials
+ * of Miller-Rabin.
+ *
+ * bbs_style = 1 means the prime must be congruent to 3 mod 4
+ */
+int mp_prime_next_prime(mp_int *a, int t, int bbs_style);
+
+/* makes a truly random prime of a given size (bytes),
+ * call with bbs = 1 if you want it to be congruent to 3 mod 4
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ * The prime generated will be larger than 2^(8*size).
+ */
+#define mp_prime_random(a, t, size, bbs, cb, dat) mp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?LTM_PRIME_BBS:0, cb, dat)
+
+/* makes a truly random prime of a given size (bits),
+ *
+ * Flags are as follows:
+ *
+ * LTM_PRIME_BBS - make prime congruent to 3 mod 4
+ * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS)
+ * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero
+ * LTM_PRIME_2MSB_ON - make the 2nd highest bit one
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ */
+int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat);
+
+int mp_find_prime(mp_int *a);
+
+int mp_isprime(mp_int *a);
+
+/* ---> radix conversion <--- */
+int mp_count_bits(mp_int *a);
+
+int mp_unsigned_bin_size(mp_int *a);
+int mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c);
+int mp_to_unsigned_bin(mp_int *a, unsigned char *b);
+int mp_to_unsigned_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen);
+
+int mp_signed_bin_size(mp_int *a);
+int mp_read_signed_bin(mp_int *a, const unsigned char *b, int c);
+int mp_to_signed_bin(mp_int *a, unsigned char *b);
+int mp_to_signed_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen);
+
+int mp_read_radix(mp_int *a, const char *str, int radix);
+int mp_toradix(mp_int *a, char *str, int radix);
+int mp_toradix_n(mp_int * a, char *str, int radix, int maxlen);
+int mp_radix_size(mp_int *a, int radix, int *size);
+
+int mp_fread(mp_int *a, int radix, FILE *stream);
+int mp_fwrite(mp_int *a, int radix, FILE *stream);
+
+#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len))
+#define mp_raw_size(mp) mp_signed_bin_size(mp)
+#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str))
+#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len))
+#define mp_mag_size(mp) mp_unsigned_bin_size(mp)
+#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str))
+
+#define mp_tobinary(M, S) mp_toradix((M), (S), 2)
+#define mp_tooctal(M, S) mp_toradix((M), (S), 8)
+#define mp_todecimal(M, S) mp_toradix((M), (S), 10)
+#define mp_tohex(M, S) mp_toradix((M), (S), 16)
+
+/* lowlevel functions, do not call! */
+int s_mp_add(mp_int *a, mp_int *b, mp_int *c);
+int s_mp_sub(mp_int *a, mp_int *b, mp_int *c);
+#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
+int fast_s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int fast_s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
+int fast_s_mp_sqr(mp_int *a, mp_int *b);
+int s_mp_sqr(mp_int *a, mp_int *b);
+int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c);
+int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c);
+int mp_karatsuba_sqr(mp_int *a, mp_int *b);
+int mp_toom_sqr(mp_int *a, mp_int *b);
+int fast_mp_invmod(mp_int *a, mp_int *b, mp_int *c);
+int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c);
+int fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
+int mp_exptmod_fast(mp_int *G, mp_int *X, mp_int *P, mp_int *Y, int mode);
+int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int mode);
+void bn_reverse(unsigned char *s, int len);
+
+extern const char *mp_s_rmap;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtommath/tommath.h,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2006/03/31 14:18:44 $ */
diff --git a/package/heimdal/src/lib/hcrypto/libtommath/tommath_class.h b/package/heimdal/src/lib/hcrypto/libtommath/tommath_class.h
new file mode 100644
index 000000000..fa95a0277
--- /dev/null
+++ b/package/heimdal/src/lib/hcrypto/libtommath/tommath_class.h
@@ -0,0 +1,1000 @@
+#if !(defined(LTM1) && defined(LTM2) && defined(LTM3))
+#if defined(LTM2)
+#define LTM3
+#endif
+#if defined(LTM1)
+#define LTM2
+#endif
+#define LTM1
+
+#if defined(LTM_ALL)
+#define BN_ERROR_C
+#define BN_FAST_MP_INVMOD_C
+#define BN_FAST_MP_MONTGOMERY_REDUCE_C
+#define BN_FAST_S_MP_MUL_DIGS_C
+#define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+#define BN_FAST_S_MP_SQR_C
+#define BN_MP_2EXPT_C
+#define BN_MP_ABS_C
+#define BN_MP_ADD_C
+#define BN_MP_ADD_D_C
+#define BN_MP_ADDMOD_C
+#define BN_MP_AND_C
+#define BN_MP_CLAMP_C
+#define BN_MP_CLEAR_C
+#define BN_MP_CLEAR_MULTI_C
+#define BN_MP_CMP_C
+#define BN_MP_CMP_D_C
+#define BN_MP_CMP_MAG_C
+#define BN_MP_CNT_LSB_C
+#define BN_MP_COPY_C
+#define BN_MP_COUNT_BITS_C
+#define BN_MP_DIV_C
+#define BN_MP_DIV_2_C
+#define BN_MP_DIV_2D_C
+#define BN_MP_DIV_3_C
+#define BN_MP_DIV_D_C
+#define BN_MP_DR_IS_MODULUS_C
+#define BN_MP_DR_REDUCE_C
+#define BN_MP_DR_SETUP_C
+#define BN_MP_EXCH_C
+#define BN_MP_EXPT_D_C
+#define BN_MP_EXPTMOD_C
+#define BN_MP_EXPTMOD_FAST_C
+#define BN_MP_EXTEUCLID_C
+#define BN_MP_FREAD_C
+#define BN_MP_FWRITE_C
+#define BN_MP_GCD_C
+#define BN_MP_GET_INT_C
+#define BN_MP_GROW_C
+#define BN_MP_INIT_C
+#define BN_MP_INIT_COPY_C
+#define BN_MP_INIT_MULTI_C
+#define BN_MP_INIT_SET_C
+#define BN_MP_INIT_SET_INT_C
+#define BN_MP_INIT_SIZE_C
+#define BN_MP_INVMOD_C
+#define BN_MP_INVMOD_SLOW_C
+#define BN_MP_IS_SQUARE_C
+#define BN_MP_JACOBI_C
+#define BN_MP_KARATSUBA_MUL_C
+#define BN_MP_KARATSUBA_SQR_C
+#define BN_MP_LCM_C
+#define BN_MP_LSHD_C
+#define BN_MP_MOD_C
+#define BN_MP_MOD_2D_C
+#define BN_MP_MOD_D_C
+#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+#define BN_MP_MONTGOMERY_REDUCE_C
+#define BN_MP_MONTGOMERY_SETUP_C
+#define BN_MP_MUL_C
+#define BN_MP_MUL_2_C
+#define BN_MP_MUL_2D_C
+#define BN_MP_MUL_D_C
+#define BN_MP_MULMOD_C
+#define BN_MP_N_ROOT_C
+#define BN_MP_NEG_C
+#define BN_MP_OR_C
+#define BN_MP_PRIME_FERMAT_C
+#define BN_MP_PRIME_IS_DIVISIBLE_C
+#define BN_MP_PRIME_IS_PRIME_C
+#define BN_MP_PRIME_MILLER_RABIN_C
+#define BN_MP_PRIME_NEXT_PRIME_C
+#define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+#define BN_MP_PRIME_RANDOM_EX_C
+#define BN_MP_RADIX_SIZE_C
+#define BN_MP_RADIX_SMAP_C
+#define BN_MP_RAND_C
+#define BN_MP_READ_RADIX_C
+#define BN_MP_READ_SIGNED_BIN_C
+#define BN_MP_READ_UNSIGNED_BIN_C
+#define BN_MP_REDUCE_C
+#define BN_MP_REDUCE_2K_C
+#define BN_MP_REDUCE_2K_L_C
+#define BN_MP_REDUCE_2K_SETUP_C
+#define BN_MP_REDUCE_2K_SETUP_L_C
+#define BN_MP_REDUCE_IS_2K_C
+#define BN_MP_REDUCE_IS_2K_L_C
+#define BN_MP_REDUCE_SETUP_C
+#define BN_MP_RSHD_C
+#define BN_MP_SET_C
+#define BN_MP_SET_INT_C
+#define BN_MP_SHRINK_C
+#define BN_MP_SIGNED_BIN_SIZE_C
+#define BN_MP_SQR_C
+#define BN_MP_SQRMOD_C
+#define BN_MP_SQRT_C
+#define BN_MP_SUB_C
+#define BN_MP_SUB_D_C
+#define BN_MP_SUBMOD_C
+#define BN_MP_TO_SIGNED_BIN_C
+#define BN_MP_TO_SIGNED_BIN_N_C
+#define BN_MP_TO_UNSIGNED_BIN_C
+#define BN_MP_TO_UNSIGNED_BIN_N_C
+#define BN_MP_TOOM_MUL_C
+#define BN_MP_TOOM_SQR_C
+#define BN_MP_TORADIX_C
+#define BN_MP_TORADIX_N_C
+#define BN_MP_UNSIGNED_BIN_SIZE_C
+#define BN_MP_XOR_C
+#define BN_MP_ZERO_C
+#define BN_MP_ZERO_MULTI_C
+#define BN_PRIME_TAB_C
+#define BN_REVERSE_C
+#define BN_S_MP_ADD_C
+#define BN_S_MP_EXPTMOD_C
+#define BN_S_MP_MUL_DIGS_C
+#define BN_S_MP_MUL_HIGH_DIGS_C
+#define BN_S_MP_SQR_C
+#define BN_S_MP_SUB_C
+#define BNCORE_C
+#endif
+
+#if defined(BN_ERROR_C)
+ #define BN_MP_ERROR_TO_STRING_C
+#endif
+
+#if defined(BN_FAST_MP_INVMOD_C)
+ #define BN_MP_ISEVEN_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_COPY_C
+ #define BN_MP_MOD_C
+ #define BN_MP_SET_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_ISODD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CMP_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_CMP_D_C
+ #define BN_MP_ADD_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_FAST_MP_MONTGOMERY_REDUCE_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_FAST_S_MP_MUL_DIGS_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_FAST_S_MP_SQR_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_2EXPT_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_ABS_C)
+ #define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_ADD_C)
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_ADD_D_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_ADDMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_ADD_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_AND_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_CLAMP_C)
+#endif
+
+#if defined(BN_MP_CLEAR_C)
+#endif
+
+#if defined(BN_MP_CLEAR_MULTI_C)
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_CMP_C)
+ #define BN_MP_CMP_MAG_C
+#endif
+
+#if defined(BN_MP_CMP_D_C)
+#endif
+
+#if defined(BN_MP_CMP_MAG_C)
+#endif
+
+#if defined(BN_MP_CNT_LSB_C)
+ #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_COPY_C)
+ #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_COUNT_BITS_C)
+#endif
+
+#if defined(BN_MP_DIV_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_COPY_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_SET_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_ABS_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CMP_C
+ #define BN_MP_SUB_C
+ #define BN_MP_ADD_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_INIT_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DIV_2_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_DIV_2D_C)
+ #define BN_MP_COPY_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_C
+ #define BN_MP_MOD_2D_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_DIV_3_C)
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DIV_D_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_COPY_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_DIV_3_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_DR_IS_MODULUS_C)
+#endif
+
+#if defined(BN_MP_DR_REDUCE_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_DR_SETUP_C)
+#endif
+
+#if defined(BN_MP_EXCH_C)
+#endif
+
+#if defined(BN_MP_EXPT_D_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_SET_C
+ #define BN_MP_SQR_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MUL_C
+#endif
+
+#if defined(BN_MP_EXPTMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_INVMOD_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_ABS_C
+ #define BN_MP_CLEAR_MULTI_C
+ #define BN_MP_REDUCE_IS_2K_L_C
+ #define BN_S_MP_EXPTMOD_C
+ #define BN_MP_DR_IS_MODULUS_C
+ #define BN_MP_REDUCE_IS_2K_C
+ #define BN_MP_ISODD_C
+ #define BN_MP_EXPTMOD_FAST_C
+#endif
+
+#if defined(BN_MP_EXPTMOD_FAST_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_INIT_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MONTGOMERY_SETUP_C
+ #define BN_FAST_MP_MONTGOMERY_REDUCE_C
+ #define BN_MP_MONTGOMERY_REDUCE_C
+ #define BN_MP_DR_SETUP_C
+ #define BN_MP_DR_REDUCE_C
+ #define BN_MP_REDUCE_2K_SETUP_C
+ #define BN_MP_REDUCE_2K_C
+ #define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+ #define BN_MP_MULMOD_C
+ #define BN_MP_SET_C
+ #define BN_MP_MOD_C
+ #define BN_MP_COPY_C
+ #define BN_MP_SQR_C
+ #define BN_MP_MUL_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_EXTEUCLID_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_SET_C
+ #define BN_MP_COPY_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_DIV_C
+ #define BN_MP_MUL_C
+ #define BN_MP_SUB_C
+ #define BN_MP_NEG_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_FREAD_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_S_RMAP_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_CMP_D_C
+#endif
+
+#if defined(BN_MP_FWRITE_C)
+ #define BN_MP_RADIX_SIZE_C
+ #define BN_MP_TORADIX_C
+#endif
+
+#if defined(BN_MP_GCD_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_ABS_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CNT_LSB_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_EXCH_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_GET_INT_C)
+#endif
+
+#if defined(BN_MP_GROW_C)
+#endif
+
+#if defined(BN_MP_INIT_C)
+#endif
+
+#if defined(BN_MP_INIT_COPY_C)
+ #define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_INIT_MULTI_C)
+ #define BN_MP_ERR_C
+ #define BN_MP_INIT_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_INIT_SET_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_C
+#endif
+
+#if defined(BN_MP_INIT_SET_INT_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_INT_C
+#endif
+
+#if defined(BN_MP_INIT_SIZE_C)
+ #define BN_MP_INIT_C
+#endif
+
+#if defined(BN_MP_INVMOD_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_ISODD_C
+ #define BN_FAST_MP_INVMOD_C
+ #define BN_MP_INVMOD_SLOW_C
+#endif
+
+#if defined(BN_MP_INVMOD_SLOW_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_MOD_C
+ #define BN_MP_COPY_C
+ #define BN_MP_ISEVEN_C
+ #define BN_MP_SET_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_ISODD_C
+ #define BN_MP_ADD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CMP_C
+ #define BN_MP_CMP_D_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_IS_SQUARE_C)
+ #define BN_MP_MOD_D_C
+ #define BN_MP_INIT_SET_INT_C
+ #define BN_MP_MOD_C
+ #define BN_MP_GET_INT_C
+ #define BN_MP_SQRT_C
+ #define BN_MP_SQR_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_JACOBI_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CNT_LSB_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_MOD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_KARATSUBA_MUL_C)
+ #define BN_MP_MUL_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_SUB_C
+ #define BN_MP_ADD_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_KARATSUBA_SQR_C)
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_SQR_C
+ #define BN_MP_SUB_C
+ #define BN_S_MP_ADD_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_ADD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_LCM_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_GCD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_DIV_C
+ #define BN_MP_MUL_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_LSHD_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_RSHD_C
+#endif
+
+#if defined(BN_MP_MOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_DIV_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_ADD_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_MOD_2D_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_COPY_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MOD_D_C)
+ #define BN_MP_DIV_D_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_CALC_NORMALIZATION_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_2EXPT_C
+ #define BN_MP_SET_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_REDUCE_C)
+ #define BN_FAST_MP_MONTGOMERY_REDUCE_C
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_SETUP_C)
+#endif
+
+#if defined(BN_MP_MUL_C)
+ #define BN_MP_TOOM_MUL_C
+ #define BN_MP_KARATSUBA_MUL_C
+ #define BN_FAST_S_MP_MUL_DIGS_C
+ #define BN_S_MP_MUL_C
+ #define BN_S_MP_MUL_DIGS_C
+#endif
+
+#if defined(BN_MP_MUL_2_C)
+ #define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_MUL_2D_C)
+ #define BN_MP_COPY_C
+ #define BN_MP_GROW_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MUL_D_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_MULMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_MUL_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_N_ROOT_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_C
+ #define BN_MP_COPY_C
+ #define BN_MP_EXPT_D_C
+ #define BN_MP_MUL_C
+ #define BN_MP_SUB_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_DIV_C
+ #define BN_MP_CMP_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_NEG_C)
+ #define BN_MP_COPY_C
+ #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_OR_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_FERMAT_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_INIT_C
+ #define BN_MP_EXPTMOD_C
+ #define BN_MP_CMP_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_IS_DIVISIBLE_C)
+ #define BN_MP_MOD_D_C
+#endif
+
+#if defined(BN_MP_PRIME_IS_PRIME_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_PRIME_IS_DIVISIBLE_C
+ #define BN_MP_INIT_C
+ #define BN_MP_SET_C
+ #define BN_MP_PRIME_MILLER_RABIN_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_MILLER_RABIN_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_CNT_LSB_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_EXPTMOD_C
+ #define BN_MP_CMP_C
+ #define BN_MP_SQRMOD_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_NEXT_PRIME_C)
+ #define BN_MP_CMP_D_C
+ #define BN_MP_SET_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_ISEVEN_C
+ #define BN_MP_MOD_D_C
+ #define BN_MP_INIT_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_PRIME_MILLER_RABIN_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_PRIME_RABIN_MILLER_TRIALS_C)
+#endif
+
+#if defined(BN_MP_PRIME_RANDOM_EX_C)
+ #define BN_MP_READ_UNSIGNED_BIN_C
+ #define BN_MP_PRIME_IS_PRIME_C
+ #define BN_MP_SUB_D_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_ADD_D_C
+#endif
+
+#if defined(BN_MP_RADIX_SIZE_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_DIV_D_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_RADIX_SMAP_C)
+ #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_RAND_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_LSHD_C
+#endif
+
+#if defined(BN_MP_READ_RADIX_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_S_RMAP_C
+ #define BN_MP_RADIX_SMAP_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_ISZERO_C
+#endif
+
+#if defined(BN_MP_READ_SIGNED_BIN_C)
+ #define BN_MP_READ_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_READ_UNSIGNED_BIN_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_REDUCE_C)
+ #define BN_MP_REDUCE_SETUP_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_MUL_C
+ #define BN_S_MP_MUL_HIGH_DIGS_C
+ #define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ #define BN_MP_MOD_2D_C
+ #define BN_S_MP_MUL_DIGS_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CMP_D_C
+ #define BN_MP_SET_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_ADD_C
+ #define BN_MP_CMP_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_MUL_D_C
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_L_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_MUL_C
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_2EXPT_C
+ #define BN_MP_CLEAR_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_L_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_2EXPT_C
+ #define BN_MP_COUNT_BITS_C
+ #define BN_S_MP_SUB_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_C)
+ #define BN_MP_REDUCE_2K_C
+ #define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_L_C)
+#endif
+
+#if defined(BN_MP_REDUCE_SETUP_C)
+ #define BN_MP_2EXPT_C
+ #define BN_MP_DIV_C
+#endif
+
+#if defined(BN_MP_RSHD_C)
+ #define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SET_C)
+ #define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SET_INT_C)
+ #define BN_MP_ZERO_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_SHRINK_C)
+#endif
+
+#if defined(BN_MP_SIGNED_BIN_SIZE_C)
+ #define BN_MP_UNSIGNED_BIN_SIZE_C
+#endif
+
+#if defined(BN_MP_SQR_C)
+ #define BN_MP_TOOM_SQR_C
+ #define BN_MP_KARATSUBA_SQR_C
+ #define BN_FAST_S_MP_SQR_C
+ #define BN_S_MP_SQR_C
+#endif
+
+#if defined(BN_MP_SQRMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SQR_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_SQRT_C)
+ #define BN_MP_N_ROOT_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_ZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_DIV_C
+ #define BN_MP_ADD_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_SUB_C)
+ #define BN_S_MP_ADD_C
+ #define BN_MP_CMP_MAG_C
+ #define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_SUB_D_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_ADD_D_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_MP_SUBMOD_C)
+ #define BN_MP_INIT_C
+ #define BN_MP_SUB_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_TO_SIGNED_BIN_C)
+ #define BN_MP_TO_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TO_SIGNED_BIN_N_C)
+ #define BN_MP_SIGNED_BIN_SIZE_C
+ #define BN_MP_TO_SIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TO_UNSIGNED_BIN_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_ISZERO_C
+ #define BN_MP_DIV_2D_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_TO_UNSIGNED_BIN_N_C)
+ #define BN_MP_UNSIGNED_BIN_SIZE_C
+ #define BN_MP_TO_UNSIGNED_BIN_C
+#endif
+
+#if defined(BN_MP_TOOM_MUL_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_MOD_2D_C
+ #define BN_MP_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_MUL_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_ADD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_DIV_3_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_TOOM_SQR_C)
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_MOD_2D_C
+ #define BN_MP_COPY_C
+ #define BN_MP_RSHD_C
+ #define BN_MP_SQR_C
+ #define BN_MP_MUL_2_C
+ #define BN_MP_ADD_C
+ #define BN_MP_SUB_C
+ #define BN_MP_DIV_2_C
+ #define BN_MP_MUL_2D_C
+ #define BN_MP_MUL_D_C
+ #define BN_MP_DIV_3_C
+ #define BN_MP_LSHD_C
+ #define BN_MP_CLEAR_MULTI_C
+#endif
+
+#if defined(BN_MP_TORADIX_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_DIV_D_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_TORADIX_N_C)
+ #define BN_MP_ISZERO_C
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_DIV_D_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_S_RMAP_C
+#endif
+
+#if defined(BN_MP_UNSIGNED_BIN_SIZE_C)
+ #define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_XOR_C)
+ #define BN_MP_INIT_COPY_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_ZERO_C)
+#endif
+
+#if defined(BN_PRIME_TAB_C)
+#endif
+
+#if defined(BN_REVERSE_C)
+#endif
+
+#if defined(BN_S_MP_ADD_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BN_S_MP_EXPTMOD_C)
+ #define BN_MP_COUNT_BITS_C
+ #define BN_MP_INIT_C
+ #define BN_MP_CLEAR_C
+ #define BN_MP_REDUCE_SETUP_C
+ #define BN_MP_REDUCE_C
+ #define BN_MP_REDUCE_2K_SETUP_L_C
+ #define BN_MP_REDUCE_2K_L_C
+ #define BN_MP_MOD_C
+ #define BN_MP_COPY_C
+ #define BN_MP_SQR_C
+ #define BN_MP_MUL_C
+ #define BN_MP_SET_C
+ #define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_S_MP_MUL_DIGS_C)
+ #define BN_FAST_S_MP_MUL_DIGS_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_MUL_HIGH_DIGS_C)
+ #define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_SQR_C)
+ #define BN_MP_INIT_SIZE_C
+ #define BN_MP_CLAMP_C
+ #define BN_MP_EXCH_C
+ #define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_S_MP_SUB_C)
+ #define BN_MP_GROW_C
+ #define BN_MP_CLAMP_C
+#endif
+
+#if defined(BNCORE_C)
+#endif
+
+#ifdef LTM3
+#define LTM_LAST
+#endif
+#include <tommath_superclass.h>
+#include <tommath_class.h>
+#else
+#define LTM_LAST
+#endif
+
+/* $Source: /cvs/libtom/libtommath/tommath_class.h,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2005/07/28 11:59:32 $ */
diff --git a/package/heimdal/src/lib/hcrypto/libtommath/tommath_superclass.h b/package/heimdal/src/lib/hcrypto/libtommath/tommath_superclass.h
new file mode 100644
index 000000000..2fdebe683
--- /dev/null
+++ b/package/heimdal/src/lib/hcrypto/libtommath/tommath_superclass.h
@@ -0,0 +1,76 @@
+/* super class file for PK algos */
+
+/* default ... include all MPI */
+#define LTM_ALL
+
+/* RSA only (does not support DH/DSA/ECC) */
+/* #define SC_RSA_1 */
+
+/* For reference.... On an Athlon64 optimizing for speed...
+
+ LTM's mpi.o with all functions [striped] is 142KiB in size.
+
+*/
+
+/* Works for RSA only, mpi.o is 68KiB */
+#ifdef SC_RSA_1
+ #define BN_MP_SHRINK_C
+ #define BN_MP_LCM_C
+ #define BN_MP_PRIME_RANDOM_EX_C
+ #define BN_MP_INVMOD_C
+ #define BN_MP_GCD_C
+ #define BN_MP_MOD_C
+ #define BN_MP_MULMOD_C
+ #define BN_MP_ADDMOD_C
+ #define BN_MP_EXPTMOD_C
+ #define BN_MP_SET_INT_C
+ #define BN_MP_INIT_MULTI_C
+ #define BN_MP_CLEAR_MULTI_C
+ #define BN_MP_UNSIGNED_BIN_SIZE_C
+ #define BN_MP_TO_UNSIGNED_BIN_C
+ #define BN_MP_MOD_D_C
+ #define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+ #define BN_REVERSE_C
+ #define BN_PRIME_TAB_C
+
+ /* other modifiers */
+ #define BN_MP_DIV_SMALL /* Slower division, not critical */
+
+ /* here we are on the last pass so we turn things off. The functions classes are still there
+ * but we remove them specifically from the build. This also invokes tweaks in functions
+ * like removing support for even moduli, etc...
+ */
+#ifdef LTM_LAST
+ #undef BN_MP_TOOM_MUL_C
+ #undef BN_MP_TOOM_SQR_C
+ #undef BN_MP_KARATSUBA_MUL_C
+ #undef BN_MP_KARATSUBA_SQR_C
+ #undef BN_MP_REDUCE_C
+ #undef BN_MP_REDUCE_SETUP_C
+ #undef BN_MP_DR_IS_MODULUS_C
+ #undef BN_MP_DR_SETUP_C
+ #undef BN_MP_DR_REDUCE_C
+ #undef BN_MP_REDUCE_IS_2K_C
+ #undef BN_MP_REDUCE_2K_SETUP_C
+ #undef BN_MP_REDUCE_2K_C
+ #undef BN_S_MP_EXPTMOD_C
+ #undef BN_MP_DIV_3_C
+ #undef BN_S_MP_MUL_HIGH_DIGS_C
+ #undef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ #undef BN_FAST_MP_INVMOD_C
+
+ /* To safely undefine these you have to make sure your RSA key won't exceed the Comba threshold
+ * which is roughly 255 digits [7140 bits for 32-bit machines, 15300 bits for 64-bit machines]
+ * which means roughly speaking you can handle upto 2536-bit RSA keys with these defined without
+ * trouble.
+ */
+ #undef BN_S_MP_MUL_DIGS_C
+ #undef BN_S_MP_SQR_C
+ #undef BN_MP_MONTGOMERY_REDUCE_C
+#endif
+
+#endif
+
+/* $Source: /cvs/libtom/libtommath/tommath_superclass.h,v $ */
+/* $Revision: 1.3 $ */
+/* $Date: 2005/05/14 13:29:17 $ */
diff --git a/package/hostapd/Makefile b/package/hostapd/Makefile
index f57192c27..8e39c52b9 100644
--- a/package/hostapd/Makefile
+++ b/package/hostapd/Makefile
@@ -16,7 +16,7 @@ PKG_SITES:= http://hostap.epitest.fi/releases/
PKG_MULTI:= 1
PKG_SUBPKGS:= HOSTAPD HOSTAPD_UTILS
-PKG_CHOICES:= WITH_OPENSSL WITH_GNUTLS
+PKG_CHOICES_HOSTAPD:= WITH_OPENSSL WITH_GNUTLS
PKGCD_WITH_OPENSSL:= use OpenSSL for crypto
PKGCS_WITH_OPENSSL:= libopenssl
PKGCB_WITH_OPENSSL:= openssl
diff --git a/package/hostapd/files/hostapd.config b/package/hostapd/files/hostapd.config
index 1ac8a7838..205482fc5 100644
--- a/package/hostapd/files/hostapd.config
+++ b/package/hostapd/files/hostapd.config
@@ -33,3 +33,4 @@ CONFIG_NO_VLAN=y
# This can be used to reduce binary size at the cost of disabling a debugging
# option.
CONFIG_NO_DUMP_STATE=y
+CONFIG_LIBNL20=y
diff --git a/package/id3lib/Makefile b/package/id3lib/Makefile
index 17c92c1be..3a20f34d6 100644
--- a/package/id3lib/Makefile
+++ b/package/id3lib/Makefile
@@ -13,6 +13,7 @@ PKG_DEPENDS:= zlib libiconv
PKG_BUILDDEP:= zlib libiconv
PKG_URL:= http://id3lib.sourceforge.net/
PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=id3lib/}
+PKG_NEED_CXX:= 1
PKG_CXX:= ID3LIB
include ${TOPDIR}/mk/package.mk
@@ -22,10 +23,15 @@ $(eval $(call PKG_template,ID3LIB,id3lib,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEP
TCFLAGS+= -fPIC
CONFIGURE_ARGS+= --enable-cxx-warnings=no
+LIBRARIES:=-nodefaultlibs -luClibc++ -lz -lm -lc
+ifeq ($(ADK_TOOLCHAIN_GCC_USE_SSP),y)
+LIBRARIES+=-lssp -fstack-protector
+endif
+
ifeq ($(ADK_COMPILE_ID3LIB_WITH_UCLIBCXX),y)
TCXXFLAGS+= -fno-builtin -fno-rtti -nostdinc++ \
-I${STAGING_TARGET_DIR}/usr/include/uClibc++
-CONFIGURE_ENV+= LIBS="-nodefaultlibs -luClibc++ -lz -lm -lc"
+CONFIGURE_ENV+= LIBS="${LIBRARIES}"
else
TLDFLAGS+= -shared
endif
diff --git a/package/id3lib/patches/patch-ltmain_sh b/package/id3lib/patches/patch-ltmain_sh
new file mode 100644
index 000000000..32b0e7b55
--- /dev/null
+++ b/package/id3lib/patches/patch-ltmain_sh
@@ -0,0 +1,22 @@
+--- id3lib-3.8.3.orig/ltmain.sh 2003-03-02 01:23:00.000000000 +0100
++++ id3lib-3.8.3/ltmain.sh 2011-01-15 19:06:56.000000000 +0100
+@@ -1065,6 +1065,19 @@ compiler."
+ continue
+ ;;
+
++ -fstack-protector*|-flto)
++ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
++ case $arg in
++ *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "")
++ arg="\"$arg\""
++ ;;
++ esac
++ compile_command="$compile_command $arg"
++ finalize_command="$finalize_command $arg"
++ compiler_flags="$compiler_flags $arg"
++ continue
++ ;;
++
+ -no-fast-install)
+ fast_install=no
+ continue
diff --git a/package/imlib2/patches/patch-ltmain_sh b/package/imlib2/patches/patch-ltmain_sh
new file mode 100644
index 000000000..0abed66c0
--- /dev/null
+++ b/package/imlib2/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- imlib2-1.4.4.orig/ltmain.sh 2010-05-05 20:26:26.000000000 +0200
++++ imlib2-1.4.4/ltmain.sh 2011-01-15 11:42:11.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/ipcad/patches/patch-Makefile_in b/package/ipcad/patches/patch-Makefile_in
new file mode 100644
index 000000000..40bcdf546
--- /dev/null
+++ b/package/ipcad/patches/patch-Makefile_in
@@ -0,0 +1,17 @@
+--- ipcad-3.7.3.orig/Makefile.in 2007-04-22 10:08:45.000000000 +0200
++++ ipcad-3.7.3/Makefile.in 2011-01-11 17:16:15.000000000 +0100
+@@ -6,10 +6,10 @@ sysconfdir= @sysconfdir@
+ datadir= @datadir@
+
+ CC= @CC@
+-LDFLAGS+= @LDFLAGS@
+-LIBS+= @LIBS@
+-CFLAGS+= @CFLAGS@ @DEFS@ -W -Wall
+-CPPFLAGS+=-DIPCAD_VERSION=\"@IPCAD_VERSION@\"
++LDFLAGS= @LDFLAGS@
++LIBS= @LIBS@
++CFLAGS= @CFLAGS@ @DEFS@ -W -Wall
++CPPFLAGS=-DIPCAD_VERSION=\"@IPCAD_VERSION@\"
+ CPPFLAGS+=-DCONFIG_FILE=\"${sysconfdir}/ipcad.conf\"
+ CPPFLAGS+=@DEFS@ -D_REENTRANT -D_THREAD_SAFE
+ CPPFLAGS+=-DPSRC_@PSRC@ -DIFST_@IFST@
diff --git a/package/iperf/Makefile b/package/iperf/Makefile
index 7a4f70994..a8db48d59 100644
--- a/package/iperf/Makefile
+++ b/package/iperf/Makefile
@@ -12,12 +12,17 @@ PKG_SECTION:= net
PKG_DEPENDS:= libpthread
PKG_URL:= http://sourceforge.net/projects/iperf
PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=iperf/}
+PKG_NEED_CXX:= 1
PKG_CXX:= IPERF
include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,IPERF,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+ifeq ($(ADK_TOOLCHAIN_GCC_USE_SSP),y)
+TLDFLAGS+= -lssp
+endif
+
ifeq ($(ADK_COMPILE_IPERF_WITH_UCLIBCXX),y)
TCXXFLAGS+= -fno-builtin -fno-rtti -nostdinc++
TLDFLAGS+= -nodefaultlibs
diff --git a/package/iproute2/Makefile b/package/iproute2/Makefile
index 8ffc0ddb0..f0c815e59 100644
--- a/package/iproute2/Makefile
+++ b/package/iproute2/Makefile
@@ -4,9 +4,9 @@
include ${TOPDIR}/rules.mk
PKG_NAME:= iproute2
-PKG_VERSION:= 2.6.34
+PKG_VERSION:= 2.6.37
PKG_RELEASE:= 1
-PKG_MD5SUM:= 5c5742bdac05a1688f266512e685b83c
+PKG_MD5SUM:= 9774ff9d74ebd301bf56bd8d74473786
PKG_DESCR:= iproute2 routing control utility
PKG_SECTION:= route
PKG_URL:= http://www.linuxfoundation.org/en/Net:Iproute2
@@ -15,6 +15,7 @@ PKG_SITES:= http://devresources.linuxfoundation.org/dev/iproute2/download/
PKG_SUBPKGS:= IP TC TC_ATM IFSTAT LNSTAT ROUTEL RTMON SS
PKGSD_TC:= iproute2 traffic control utility
PKGSS_TC:= kmod-sched
+PKGSB_TC:= iptables
PKGSD_TC_ATM:= iproute2 traffic control ATM support library
PKGSS_TC_ATM:= tc libatm
PKGSB_TC_ATM:= linux-atm
@@ -40,57 +41,48 @@ $(eval $(call PKG_template,SS,ss,${PKG_VERSION}-${PKG_RELEASE},,${PKGSD_SS},${PK
TCFLAGS+= -D_GNU_SOURCE
XAKE_FLAGS+= CCOPTS="${TCFLAGS}" MFLAGS="CC=${TARGET_CC}" \
HOSTCFLAGS="-I${LINUX_HEADER_DIR}/include"
-
CONFIGURE_FLAGS+= KERNEL_INCLUDE="${LINUX_DIR}/include"
-INSTALL_y:=
-INSTALL_m:=
-INSTALL_${ADK_PACKAGE_IP}:= install-ip
-INSTALL_${ADK_PACKAGE_TC}:= install-tc
-INSTALL_${ADK_PACKAGE_TC_ATM}:= install-tc-atm
-INSTALL_${ADK_PACKAGE_IFSTAT}:= install-ifstat
-INSTALL_${ADK_PACKAGE_LNSTAT}:= install-lnstat
-INSTALL_${ADK_PACKAGE_ROUTEL}:= install-routel
-INSTALL_${ADK_PACKAGE_RTMON}:= install-rtmon
-INSTALL_${ADK_PACKAGE_SS}:= install-ss
-
-post-install: ${INSTALL_y} ${INSTALL_m}
+post-configure:
+ $(CP) ./files/Config $(WRKBUILD)/
-install-ip:
+ip-install:
${INSTALL_DIR} ${IDIR_IP}/{etc/iproute2,usr/sbin}
${INSTALL_DATA} ${WRKINST}/etc/iproute2/* ${IDIR_IP}/etc/iproute2/
${INSTALL_BIN} ${WRKINST}/sbin/ip ${IDIR_IP}/usr/sbin/ip
-install-tc:
- ${INSTALL_DIR} ${IDIR_TC}/{lib/tc,usr/sbin}
- ${INSTALL_DATA} ${WRKINST}/lib/tc/* ${IDIR_TC}/lib/tc/
+tc-install:
+ ${INSTALL_DIR} ${IDIR_TC}/{lib/tc,usr/sbin,usr/lib/tc}
+ # use ${CP} here, since m_ipt.so is a symlink to m_xt.so
+ ${CP} ${WRKINST}/lib/tc/m_*.so ${IDIR_TC}/lib/tc/
+ ${CP} ${WRKINST}/usr/lib/tc/*.dist ${IDIR_TC}/usr/lib/tc/
${INSTALL_BIN} ${WRKINST}/sbin/tc ${IDIR_TC}/usr/sbin/
-install-tc-atm:
- ${INSTALL_DIR} ${IDIR_TC_ATM}/usr/lib/tc
- ${INSTALL_DATA} ${WRKINST}/usr/lib/tc/q_atm.so \
- ${IDIR_TC_ATM}/usr/lib/tc/
+tc-atm-install:
+ ${INSTALL_DIR} ${IDIR_TC_ATM}/lib/tc
+ ${INSTALL_DATA} ${WRKINST}/lib/tc/q_atm.so \
+ ${IDIR_TC_ATM}/lib/tc/
-install-ifstat:
+ifstat-install:
${INSTALL_DIR} ${IDIR_IFSTAT}/usr/sbin
${INSTALL_BIN} ${WRKINST}/sbin/ifstat ${IDIR_IFSTAT}/usr/sbin
-install-lnstat:
+lnstat-install:
${INSTALL_DIR} ${IDIR_LNSTAT}/usr/sbin
${INSTALL_BIN} ${WRKINST}/sbin/{ln,n}stat ${IDIR_LNSTAT}/usr/sbin
ln -sf lnstat ${IDIR_LNSTAT}/usr/sbin/rtstat
ln -sf lnstat ${IDIR_LNSTAT}/usr/sbin/ctstat
${INSTALL_BIN} ${WRKINST}/sbin/rtacct ${IDIR_LNSTAT}/usr/sbin
-install-routel:
+routel-install:
${INSTALL_DIR} ${IDIR_ROUTEL}/usr/sbin
${INSTALL_BIN} ${WRKINST}/sbin/route{l,f} ${IDIR_ROUTEL}/usr/sbin
-install-rtmon:
+rtmon-install:
${INSTALL_DIR} ${IDIR_RTMON}/usr/sbin
${INSTALL_BIN} ${WRKINST}/sbin/rtmon ${IDIR_RTMON}/usr/sbin
-install-ss:
+ss-install:
${INSTALL_DIR} ${IDIR_SS}/usr/sbin
${INSTALL_BIN} ${WRKINST}/sbin/ss ${IDIR_SS}/usr/sbin
diff --git a/package/iproute2/files/Config b/package/iproute2/files/Config
new file mode 100644
index 000000000..0ba7d387d
--- /dev/null
+++ b/package/iproute2/files/Config
@@ -0,0 +1,2 @@
+TC_CONFIG_ATM:=y
+TC_CONFIG_XT:=y
diff --git a/package/ipsec-tools/Makefile b/package/ipsec-tools/Makefile
index 5e92467cd..f9f2c13d6 100644
--- a/package/ipsec-tools/Makefile
+++ b/package/ipsec-tools/Makefile
@@ -16,8 +16,8 @@ PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=ipsec-tools/}
DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tar.bz2
-PKG_FLAVOURS:= WITH_IPV6
-PKGFD_WITH_IPV6:= enable IPv6 support
+PKG_FLAVOURS_IPSEC_TOOLS:= WITH_IPV6
+PKGFD_WITH_IPV6:= enable IPv6 support
include ${TOPDIR}/mk/package.mk
diff --git a/package/ipsec-tools/patches/patch-ltmain_sh b/package/ipsec-tools/patches/patch-ltmain_sh
new file mode 100644
index 000000000..f0e98067d
--- /dev/null
+++ b/package/ipsec-tools/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- ipsec-tools-0.7.2.orig/ltmain.sh 2009-04-21 16:41:43.000000000 +0200
++++ ipsec-tools-0.7.2/ltmain.sh 2011-01-15 21:50:23.000000000 +0100
+@@ -4238,7 +4238,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/ipset/Makefile b/package/ipset/Makefile
index ff8a0399b..01ba6a8ee 100644
--- a/package/ipset/Makefile
+++ b/package/ipset/Makefile
@@ -12,16 +12,16 @@ PKG_SECTION:= firewall
PKG_URL:= http://ipset.netfilter.org/
PKG_SITES:= http://ipset.netfilter.org/
-PKG_SUBPKGS:= IPSET KMOD_IPSET
-PKGSD_KMOD_IPSET:= ipset kernel module
-PKGSC_KMOD_IPSET:= kernel
+PKG_SUBPKGS:= IPSET IPSET_KMOD
+PKGSD_IPSET_KMOD:= ipset kernel module
+PKGSC_IPSET_KMOD:= kernel
DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tar.bz2
include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,IPSET,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
-$(eval $(call PKG_template,KMOD_IPSET,kmod-ipset,${KERNEL_VERSION}+${PKG_VERSION}-${ADK_TARGET}-${PKG_RELEASE},,${PKGSD_KMOD_IPSET},${PKGSC_KMOD_IPSET}))
+$(eval $(call PKG_template,IPSET_KMOD,ipset-kmod,${KERNEL_VERSION}+${PKG_VERSION}-${ADK_TARGET}-${PKG_RELEASE},,${PKGSD_IPSET_KMOD},${PKGSC_IPSET_KMOD}))
CONFIG_STYLE:= manual
XAKE_FLAGS+= PREFIX=/usr
@@ -39,8 +39,8 @@ post-install:
${INSTALL_BIN} ${WRKINST}/usr/sbin/ipset ${IDIR_IPSET}/usr/sbin
${CP} ${WRKINST}/usr/lib/ipset/*.so ${IDIR_IPSET}/usr/lib/ipset/
# kernel modules (no autoload at the moment)
- ${INSTALL_DIR} ${IDIR_KMOD_IPSET}/lib/modules/${KERNEL_VERSION}/
+ ${INSTALL_DIR} ${IDIR_IPSET_KMOD}/lib/modules/${KERNEL_VERSION}/
${INSTALL_DATA} ${WRKBUILD}/kernel/*.ko \
- ${IDIR_KMOD_IPSET}/lib/modules/${KERNEL_VERSION}
+ ${IDIR_IPSET_KMOD}/lib/modules/${KERNEL_VERSION}
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/iptables-snmp/patches/patch-Makefile_in b/package/iptables-snmp/patches/patch-Makefile_in
new file mode 100644
index 000000000..164003986
--- /dev/null
+++ b/package/iptables-snmp/patches/patch-Makefile_in
@@ -0,0 +1,11 @@
+--- iptables-snmp-0.1.orig/Makefile.in 2005-11-02 13:00:10.000000000 +0100
++++ iptables-snmp-0.1/Makefile.in 2011-01-12 15:44:48.000000000 +0100
+@@ -67,7 +67,7 @@ OTHER = -Iinclude -DIPTABLES_VERSION=$(
+
+ all: iptables-snmp.so
+
+-iptables-snmp.so: $(OBJS) libiptc.a Makefile
++iptables-snmp.so: $(OBJS) Makefile
+ $(CC) $(CFLAGS) $(OTHER) $(DFLAGS) -shared -o $@ $(OBJS) $(LDFLAGS)
+
+ libiptc.a: $(LIBIPTC_OBJS) Makefile
diff --git a/package/iptables-snmp/patches/patch-iptables-snmp_c b/package/iptables-snmp/patches/patch-iptables-snmp_c
new file mode 100644
index 000000000..c129ff0e9
--- /dev/null
+++ b/package/iptables-snmp/patches/patch-iptables-snmp_c
@@ -0,0 +1,12 @@
+--- iptables-snmp-0.1.orig/iptables-snmp.c 2005-11-02 12:10:54.000000000 +0100
++++ iptables-snmp-0.1/iptables-snmp.c 2011-01-12 15:46:19.000000000 +0100
+@@ -37,6 +37,9 @@
+
+ #include "libiptc/libiptc.h"
+
++/* For backward compatibility */
++//typedef struct iptc_handle *iptc_handle_t;
++
+ static oid agent_version_oid[] = {
+ BASE_OID, 1, 0, AGENT_VERSION_INDEX
+ };
diff --git a/package/iptables/Makefile b/package/iptables/Makefile
index aac6179a0..e20e117c5 100644
--- a/package/iptables/Makefile
+++ b/package/iptables/Makefile
@@ -4,9 +4,9 @@
include ${TOPDIR}/rules.mk
PKG_NAME:= iptables
-PKG_VERSION:= 1.4.8
+PKG_VERSION:= 1.4.10
PKG_RELEASE:= 1
-PKG_MD5SUM:= 697ed89f37af4473a5f6349ba2700f2d
+PKG_MD5SUM:= f382fe693f0b59d87bd47bea65eca198
PKG_DESCR:= The netfilter firewalling software
PKG_SECTION:= firewall
PKG_DEPENDS:= kmod-ip-nf-iptables kmod-nf-conntrack
@@ -17,10 +17,7 @@ PKG_DEPENDS+= kmod-netfilter-xt-target-tcpmss
PKG_DEPENDS6:= kmod-ip6-nf-iptables kmod-nf-conntrack-ipv6
PKG_DEPENDS6+= kmod-ip6-nf-filter kmod-ip6-nf-target-reject
PKG_URL:= http://www.netfilter.org
-PKG_SITES:= http://www.netfilter.org/projects/iptables/files/ \
- ftp://ftp.be.netfilter.org/pub/netfilter/iptables/ \
- ftp://ftp.de.netfilter.org/pub/netfilter/iptables/ \
- ftp://ftp.no.netfilter.org/pub/netfilter/iptables/
+PKG_SITES:= http://www.netfilter.org/projects/iptables/files/
PKG_SUBPKGS:= IPTABLES IP6TABLES
@@ -37,9 +34,7 @@ $(eval $(call PKG_template,IP6TABLES,ip6tables,${PKG_VERSION}-${PKG_RELEASE},${P
CONFIGURE_ARGS+= --enable-devel
-SUB_INSTALL-${ADK_PACKAGE_IP6TABLES}+= ip6tables-install
-
-post-install: ${SUB_INSTALL-m} ${SUB_INSTALL-y}
+post-install:
${INSTALL_DIR} ${IDIR_IPTABLES}/{usr/lib,etc,usr/sbin}
${INSTALL_DATA} ./files/firewall.conf ${IDIR_IPTABLES}/etc
${CP} ${WRKINST}/usr/sbin/iptables* ${IDIR_IPTABLES}/usr/sbin/
diff --git a/package/iptables/patches/patch-ltmain_sh b/package/iptables/patches/patch-ltmain_sh
new file mode 100644
index 000000000..fa93f8a96
--- /dev/null
+++ b/package/iptables/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- iptables-1.4.10.orig/ltmain.sh 2010-10-29 16:40:34.000000000 +0200
++++ iptables-1.4.10/ltmain.sh 2011-01-15 21:45:03.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/iptraf/Makefile b/package/iptraf/Makefile
index 98f9e9b5d..ef289ae37 100644
--- a/package/iptraf/Makefile
+++ b/package/iptraf/Makefile
@@ -28,7 +28,7 @@ do-build:
CFLAGS="${TARGET_CFLAGS}" \
DEBUG="" \
INCLUDEDIR="-I../support -I${STAGING_TARGET_DIR}/usr/include" \
- LDOPTS="-L${STAGING_TARGET_DIR}/usr/lib -L${STAGING_TARGET_DIR}/lib" \
+ LDOPTS="${TARGET_LDFLAGS}" \
PLATFORM="-DPLATFORM=\\\"Linux/${ARCH}\\\"" \
TARGET="/usr/bin" \
WORKDIR="/var/lib/iptraf" \
diff --git a/package/irssi/Makefile b/package/irssi/Makefile
index 55894fd7c..32efe957a 100644
--- a/package/irssi/Makefile
+++ b/package/irssi/Makefile
@@ -14,7 +14,7 @@ PKG_BUILDDEP:= glib ncurses
PKG_URL:= http://www.irssi.org/
PKG_SITES:= http://www.irssi.org/files/
-PKG_FLAVOURS:= WITH_SSL WITH_IPV6
+PKG_FLAVOURS_IRSSI:= WITH_SSL WITH_IPV6
PKGFD_WITH_SSL:= enable SSL/TLS support
PKGFS_WITH_SSL:= libopenssl
PKGFB_WITH_SSL:= openssl
diff --git a/package/irssi/patches/patch-build-aux_ltmain_sh b/package/irssi/patches/patch-build-aux_ltmain_sh
new file mode 100644
index 000000000..05bcb0e77
--- /dev/null
+++ b/package/irssi/patches/patch-build-aux_ltmain_sh
@@ -0,0 +1,30 @@
+--- irssi-0.8.15.orig/build-aux/ltmain.sh 2010-04-03 18:21:23.000000000 +0200
++++ irssi-0.8.15/build-aux/ltmain.sh 2011-01-09 00:18:54.000000000 +0100
+@@ -5516,27 +5516,6 @@ func_mode_link ()
+ esac
+ fi
+
+- # Hardcode the library path.
+- # Skip directories that are in the system default run-time
+- # search path.
+- case " $sys_lib_dlsearch_path " in
+- *" $absdir "*) ;;
+- *)
+- case "$compile_rpath " in
+- *" $absdir "*) ;;
+- *) compile_rpath="$compile_rpath $absdir"
+- esac
+- ;;
+- esac
+- case " $sys_lib_dlsearch_path " in
+- *" $libdir "*) ;;
+- *)
+- case "$finalize_rpath " in
+- *" $libdir "*) ;;
+- *) finalize_rpath="$finalize_rpath $libdir"
+- esac
+- ;;
+- esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
diff --git a/package/iw/Makefile b/package/iw/Makefile
index 6510063a9..679377b89 100644
--- a/package/iw/Makefile
+++ b/package/iw/Makefile
@@ -4,9 +4,9 @@
include ${TOPDIR}/rules.mk
PKG_NAME:= iw
-PKG_VERSION:= 0.9.19
+PKG_VERSION:= 0.9.21
PKG_RELEASE:= 1
-PKG_MD5SUM:= 3b88743f9c6ce8a7e2f5fd7d18fdea42
+PKG_MD5SUM:= 726db5f1fd6bc316434414770513ef81
PKG_DESCR:= Tools for setting up WiFi cards via netlink (nl80211)
PKG_SECTION:= wifi
PKG_DEPENDS:= libnl
diff --git a/package/iw/patches/patch-Makefile b/package/iw/patches/patch-Makefile
deleted file mode 100644
index 4c95aee80..000000000
--- a/package/iw/patches/patch-Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
---- iw-0.9.18.orig/Makefile 2009-11-20 17:35:56.000000000 +0100
-+++ iw-0.9.18/Makefile 2010-01-04 23:00:34.031210816 +0100
-@@ -86,10 +86,10 @@ check:
- install: iw iw.8.gz
- @$(NQ) ' INST iw'
- $(Q)$(MKDIR) $(DESTDIR)$(SBINDIR)
-- $(Q)$(INSTALL) -m 755 -t $(DESTDIR)$(SBINDIR) iw
-+ $(Q)$(INSTALL) -m 755 iw $(DESTDIR)$(SBINDIR)
- @$(NQ) ' INST iw.8'
- $(Q)$(MKDIR) $(DESTDIR)$(MANDIR)/man8/
-- $(Q)$(INSTALL) -m 644 -t $(DESTDIR)$(MANDIR)/man8/ iw.8.gz
-+ $(Q)$(INSTALL) -m 644 iw.8.gz $(DESTDIR)$(MANDIR)/man8/
-
- clean:
- $(Q)rm -f iw *.o *~ *.gz version.c *-stamp
diff --git a/package/iw/patches/patch-version_sh b/package/iw/patches/patch-version_sh
index dfc939354..296ac974c 100644
--- a/package/iw/patches/patch-version_sh
+++ b/package/iw/patches/patch-version_sh
@@ -1,5 +1,5 @@
---- iw-0.9.17.orig/version.sh 2009-08-26 11:41:41.000000000 +0200
-+++ iw-0.9.17/version.sh 2009-11-20 23:11:10.000000000 +0100
+--- iw-0.9.21.orig/version.sh 2010-09-24 17:44:07.000000000 +0200
++++ iw-0.9.21/version.sh 2011-01-09 22:41:17.000000000 +0100
@@ -5,20 +5,6 @@ OUT="$1"
echo '#include "iw.h"' > "$OUT"
diff --git a/package/jamvm/patches/patch-ltmain_sh b/package/jamvm/patches/patch-ltmain_sh
new file mode 100644
index 000000000..e7a6c8f5d
--- /dev/null
+++ b/package/jamvm/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- jamvm-1.5.4.orig/ltmain.sh 2009-01-03 07:08:36.000000000 +0100
++++ jamvm-1.5.4/ltmain.sh 2011-01-15 22:06:10.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/jpeg/Makefile b/package/jpeg/Makefile
index b4609e757..911e5c474 100644
--- a/package/jpeg/Makefile
+++ b/package/jpeg/Makefile
@@ -27,11 +27,7 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LIBJPEG,libjpeg,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,JPEG_DEV,libjpeg-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_JPEG_DEV},${PKGSC_JPEG_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_JPEG_DEV}+= jpeg-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBJPEG}/usr/lib
${CP} ${WRKINST}/usr/lib/libjpeg.so* ${IDIR_LIBJPEG}/usr/lib/
diff --git a/package/jpeg/patches/patch-ltmain_sh b/package/jpeg/patches/patch-ltmain_sh
new file mode 100644
index 000000000..3b71ada5f
--- /dev/null
+++ b/package/jpeg/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- jpeg-8b.orig/ltmain.sh 2010-05-02 18:49:25.000000000 +0200
++++ jpeg-8b/ltmain.sh 2011-01-14 00:16:39.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/krb5/Makefile b/package/krb5/Makefile
index 3e49475b6..c7ec9955d 100644
--- a/package/krb5/Makefile
+++ b/package/krb5/Makefile
@@ -27,10 +27,6 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,KRB5_SERVER,krb5-server,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,LIBKRB5,libkrb5,$(PKG_VERSION)-${PKG_RELEASE},,${PKGSD_LIBKRB5},${PKGSC_LIBKRB5}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBKRB5}+= libkrb5-install
-
TCFLAGS+= -I${STAGING_TARGET_DIR}/usr/include/et
CONFIGURE_ARGS+= --disable-static \
--disable-profiled \
@@ -50,7 +46,7 @@ pre-build:
# fix nm call in script, we need the GNU version of nm
$(SED) "s#@@NM@@#${NM}#" ${WRKSRC}/util/export-check.pl
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_KRB5_SERVER}/etc
${INSTALL_DIR} ${IDIR_KRB5_SERVER}/etc/krb5kdc
${INSTALL_DIR} ${IDIR_KRB5_SERVER}/usr/sbin
diff --git a/package/krb5/patches/patch-src_krb5-config_in b/package/krb5/patches/patch-src_krb5-config_in
new file mode 100644
index 000000000..ddc0159a6
--- /dev/null
+++ b/package/krb5/patches/patch-src_krb5-config_in
@@ -0,0 +1,22 @@
+--- krb5-1.8.1.orig/src/krb5-config.in 2010-01-21 23:49:01.000000000 +0100
++++ krb5-1.8.1/src/krb5-config.in 2011-01-09 01:33:14.000000000 +0100
+@@ -34,8 +34,6 @@ libdir=@libdir@
+ CC_LINK='@CC_LINK@'
+ KDB5_DB_LIB=@KDB5_DB_LIB@
+ LDFLAGS='@LDFLAGS@'
+-RPATH_FLAG='@RPATH_FLAG@'
+-PROG_RPATH_FLAGS='@PROG_RPATH_FLAGS@'
+ PTHREAD_CFLAGS='@PTHREAD_CFLAGS@'
+ DL_LIB='@DL_LIB@'
+
+@@ -180,10 +178,7 @@ if test -n "$do_libs"; then
+ # Ugly gross hack for our build tree
+ lib_flags=`echo $CC_LINK | sed -e 's/\$(CC)//' \
+ -e 's/\$(PURE)//' \
+- -e 's#\$(PROG_RPATH_FLAGS)#'"$PROG_RPATH_FLAGS"'#' \
+- -e 's#\$(PROG_RPATH)#'$libdir'#' \
+ -e 's#\$(PROG_LIBPATH)#'$libdirarg'#' \
+- -e 's#\$(RPATH_FLAG)#'"$RPATH_FLAG"'#' \
+ -e 's#\$(LDFLAGS)#'"$LDFLAGS"'#' \
+ -e 's#\$(PTHREAD_CFLAGS)#'"$PTHREAD_CFLAGS"'#' \
+ -e 's#\$(CFLAGS)#'"$CFLAGS"'#'`
diff --git a/package/lame/patches/patch-ltmain_sh b/package/lame/patches/patch-ltmain_sh
new file mode 100644
index 000000000..04a015282
--- /dev/null
+++ b/package/lame/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- lame-398-2.orig/ltmain.sh 2008-01-03 01:00:01.000000000 +0100
++++ lame-398-2/ltmain.sh 2011-01-15 22:13:38.000000000 +0100
+@@ -1693,7 +1693,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libICE/patches/patch-ltmain_sh b/package/libICE/patches/patch-ltmain_sh
new file mode 100644
index 000000000..92bc5c02d
--- /dev/null
+++ b/package/libICE/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libICE-1.0.6.orig/ltmain.sh 2009-05-18 04:30:07.000000000 +0200
++++ libICE-1.0.6/ltmain.sh 2011-01-15 00:09:27.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libSM/patches/patch-ltmain_sh b/package/libSM/patches/patch-ltmain_sh
new file mode 100644
index 000000000..f01192003
--- /dev/null
+++ b/package/libSM/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libSM-1.1.1.orig/ltmain.sh 2009-08-07 14:22:14.000000000 +0200
++++ libSM-1.1.1/ltmain.sh 2011-01-15 00:11:06.000000000 +0100
+@@ -4772,7 +4772,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libX11/Makefile b/package/libX11/Makefile
index 92f1f52aa..322c190a7 100644
--- a/package/libX11/Makefile
+++ b/package/libX11/Makefile
@@ -26,10 +26,6 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,LIBX11,libx11,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,LIBX11_DEV,libx11-dev,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBX11_DEV},${PKGSC_LIBX11_DEV},${PKG_OPTS}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBX11_DEV}+=libx11-dev-install
-
XAKE_FLAGS+= HOSTCPPFLAGS=-I${STAGING_TARGET_DIR}/usr/include/xproto
CONFIGURE_ARGS+= --enable-xlocale \
--disable-specs \
@@ -37,7 +33,7 @@ CONFIGURE_ARGS+= --enable-xlocale \
--disable-malloc0returnsnull \
--without-xcb
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBX11}/usr/lib ${IDIR_LIBX11}/usr/share/X11
${CP} ${WRKINST}/usr/lib/libX11.so* ${IDIR_LIBX11}/usr/lib/
${CP} ${WRKINST}/usr/share/X11/XKeysymDB ${IDIR_LIBX11}/usr/share/X11
diff --git a/package/libX11/patches/patch-ltmain_sh b/package/libX11/patches/patch-ltmain_sh
new file mode 100644
index 000000000..d88493e60
--- /dev/null
+++ b/package/libX11/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libX11-1.3.2.orig/ltmain.sh 2009-10-17 07:26:21.000000000 +0200
++++ libX11-1.3.2/ltmain.sh 2011-01-14 00:51:57.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libXau/Makefile b/package/libXau/Makefile
index 21d31154e..41d6adcaf 100644
--- a/package/libXau/Makefile
+++ b/package/libXau/Makefile
@@ -24,12 +24,7 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,LIBXAU,libxau,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,LIBXAU_DEV,libxau-dev,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBXAU_DEV},${PKGSC_LIBXAU_DEV},${PKG_OPTS}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBXAU_DEV}+=libxau-dev-install
-
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBXAU}/usr/lib
${CP} ${WRKINST}/usr/lib/libXau.so* ${IDIR_LIBXAU}/usr/lib/
diff --git a/package/libXau/patches/patch-ltmain_sh b/package/libXau/patches/patch-ltmain_sh
new file mode 100644
index 000000000..065bd8d32
--- /dev/null
+++ b/package/libXau/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXau-1.0.5.orig/ltmain.sh 2009-05-18 04:20:07.000000000 +0200
++++ libXau-1.0.5/ltmain.sh 2011-01-14 00:48:29.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libXaw/patches/patch-ltmain_sh b/package/libXaw/patches/patch-ltmain_sh
new file mode 100644
index 000000000..d5ae40796
--- /dev/null
+++ b/package/libXaw/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXaw-1.0.7.orig/ltmain.sh 2009-10-17 07:26:21.000000000 +0200
++++ libXaw-1.0.7/ltmain.sh 2011-01-15 22:19:32.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libXcomposite/Makefile b/package/libXcomposite/Makefile
index fc395a708..48b1e3c82 100644
--- a/package/libXcomposite/Makefile
+++ b/package/libXcomposite/Makefile
@@ -25,13 +25,9 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,LIBXCOMPOSITE,libxcomposite,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,LIBXCOMPOSITE_DEV,libxcomposite-dev,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBXCOMPOSITE_DEV},${PKGSC_LIBXCOMPOSITE_DEV},${PKG_OPTS}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBXCOMPOSITE_DEV}+= libxcomposite-dev-install
-
CONFIGURE_ARGS+= --disable-malloc0returnsnull
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBXCOMPOSITE}/usr/lib
${CP} ${WRKINST}/usr/lib/libXcomposite.so* ${IDIR_LIBXCOMPOSITE}/usr/lib/
diff --git a/package/libXcursor/patches/patch-ltmain_sh b/package/libXcursor/patches/patch-ltmain_sh
new file mode 100644
index 000000000..e78e57231
--- /dev/null
+++ b/package/libXcursor/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXcursor-1.1.11.orig/ltmain.sh 2010-10-28 07:48:42.000000000 +0200
++++ libXcursor-1.1.11/ltmain.sh 2011-01-15 22:22:45.000000000 +0100
+@@ -5091,7 +5091,7 @@ func_mode_link ()
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libXdmcp/Makefile b/package/libXdmcp/Makefile
index f4a731f9c..4181933ca 100644
--- a/package/libXdmcp/Makefile
+++ b/package/libXdmcp/Makefile
@@ -24,11 +24,7 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,LIBXDMCP,libxdmcp,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,LIBXDMCP_DEV,libxdmcp-dev,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBXDMCP_DEV},${PKGSC_LIBXDMCP_DEV},${PKG_OPTS}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBXDMCP_DEV}+=libxdmcp-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBXDMCP}/usr/lib
${CP} ${WRKINST}/usr/lib/libXdmcp.so* ${IDIR_LIBXDMCP}/usr/lib/
@@ -37,5 +33,4 @@ libxdmcp-dev-install:
${CP} ${WRKINST}/usr/include/X11/* \
${IDIR_LIBXDMCP_DEV}/usr/include/X11/
-
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/libXdmcp/patches/patch-ltmain_sh b/package/libXdmcp/patches/patch-ltmain_sh
new file mode 100644
index 000000000..3000778e3
--- /dev/null
+++ b/package/libXdmcp/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXdmcp-1.0.3.orig/ltmain.sh 2009-05-18 04:20:38.000000000 +0200
++++ libXdmcp-1.0.3/ltmain.sh 2011-01-14 00:47:12.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libXext/Makefile b/package/libXext/Makefile
index 3763d444f..ec311b067 100644
--- a/package/libXext/Makefile
+++ b/package/libXext/Makefile
@@ -25,13 +25,9 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,LIBXEXT,libxext,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,LIBXEXT_DEV,libxext-dev,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBXEXT_DEV},${PKGSC_LIBXEXT_DEV},${PKG_OPTS}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBXEXT_DEV}+=libxext-dev-install
-
CONFIGURE_ARGS+= --disable-malloc0returnsnull
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBXEXT}/usr/lib
${CP} ${WRKINST}/usr/lib/libXext.so* ${IDIR_LIBXEXT}/usr/lib/
diff --git a/package/libXext/patches/patch-ltmain_sh b/package/libXext/patches/patch-ltmain_sh
new file mode 100644
index 000000000..c82710166
--- /dev/null
+++ b/package/libXext/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXext-1.1.1.orig/ltmain.sh 2009-10-17 07:26:21.000000000 +0200
++++ libXext-1.1.1/ltmain.sh 2011-01-14 01:11:30.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libXfont/patches/patch-ltmain_sh b/package/libXfont/patches/patch-ltmain_sh
new file mode 100644
index 000000000..d901e8b34
--- /dev/null
+++ b/package/libXfont/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXfont-1.4.1.orig/ltmain.sh 2009-09-11 16:54:52.000000000 +0200
++++ libXfont-1.4.1/ltmain.sh 2011-01-15 22:27:42.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libXft/patches/patch-ltmain_sh b/package/libXft/patches/patch-ltmain_sh
new file mode 100644
index 000000000..ea3857e71
--- /dev/null
+++ b/package/libXft/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXft-2.1.9.orig/ltmain.sh 2006-01-10 16:23:50.000000000 +0100
++++ libXft-2.1.9/ltmain.sh 2011-01-15 22:30:29.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libXi/patches/patch-ltmain_sh b/package/libXi/patches/patch-ltmain_sh
new file mode 100644
index 000000000..86a276fc3
--- /dev/null
+++ b/package/libXi/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXi-1.3.orig/ltmain.sh 2009-10-02 04:21:36.000000000 +0200
++++ libXi-1.3/ltmain.sh 2011-01-14 21:38:48.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libXmu/patches/patch-ltmain_sh b/package/libXmu/patches/patch-ltmain_sh
new file mode 100644
index 000000000..f748db34e
--- /dev/null
+++ b/package/libXmu/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXmu-1.0.5.orig/ltmain.sh 2009-09-11 16:54:52.000000000 +0200
++++ libXmu-1.0.5/ltmain.sh 2011-01-15 22:16:42.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libXpm/patches/patch-ltmain_sh b/package/libXpm/patches/patch-ltmain_sh
new file mode 100644
index 000000000..69f53a236
--- /dev/null
+++ b/package/libXpm/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXpm-3.5.8.orig/ltmain.sh 2009-09-11 16:54:52.000000000 +0200
++++ libXpm-3.5.8/ltmain.sh 2011-01-15 11:27:44.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libXt/patches/patch-ltmain_sh b/package/libXt/patches/patch-ltmain_sh
new file mode 100644
index 000000000..d33468526
--- /dev/null
+++ b/package/libXt/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXt-1.0.7.orig/ltmain.sh 2009-09-11 16:54:52.000000000 +0200
++++ libXt-1.0.7/ltmain.sh 2011-01-15 00:13:20.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libXv/patches/patch-ltmain_sh b/package/libXv/patches/patch-ltmain_sh
new file mode 100644
index 000000000..bebaeec5b
--- /dev/null
+++ b/package/libXv/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libXv-1.0.5.orig/ltmain.sh 2009-09-11 16:54:52.000000000 +0200
++++ libXv-1.0.5/ltmain.sh 2011-01-15 22:32:11.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libao/patches/patch-ltmain_sh b/package/libao/patches/patch-ltmain_sh
new file mode 100644
index 000000000..393127801
--- /dev/null
+++ b/package/libao/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libao-0.8.8.orig/ltmain.sh 2007-02-21 12:45:54.000000000 +0100
++++ libao-0.8.8/ltmain.sh 2011-01-15 22:34:13.000000000 +0100
+@@ -1677,7 +1677,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libart/patches/100-cross_compile_fix.patch b/package/libart/patches/100-cross_compile_fix.patch
index aae1acccf..90cfda45f 100644
--- a/package/libart/patches/100-cross_compile_fix.patch
+++ b/package/libart/patches/100-cross_compile_fix.patch
@@ -1,7 +1,7 @@
diff -urN libart.old/Makefile.in libart.dev/Makefile.in
---- libart.old/Makefile.in 2005-01-21 10:52:11.000000000 +0100
-+++ libart.dev/Makefile.in 2005-07-17 19:31:05.000000000 +0200
-@@ -440,9 +440,9 @@
+--- libart_lgpl-2.3.17.orig/Makefile.in 2005-01-21 10:52:11.000000000 +0100
++++ libart_lgpl-2.3.17/Makefile.in 2011-01-15 22:35:19.000000000 +0100
+@@ -440,9 +440,9 @@ testuta$(EXEEXT): $(testuta_OBJECTS) $(t
@rm -f testuta$(EXEEXT)
$(LINK) $(testuta_LDFLAGS) $(testuta_OBJECTS) $(testuta_LDADD) $(LIBS)
diff --git a/package/libart/patches/patch-ltmain_sh b/package/libart/patches/patch-ltmain_sh
new file mode 100644
index 000000000..673d4f7ca
--- /dev/null
+++ b/package/libart/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libart_lgpl-2.3.17.orig/ltmain.sh 2004-07-06 05:30:16.000000000 +0200
++++ libart_lgpl-2.3.17/ltmain.sh 2011-01-15 22:36:41.000000000 +0100
+@@ -1385,7 +1385,7 @@ EOF
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+- -m*)
++ -m*|-fstack-protector*|-flto)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
diff --git a/package/libaudiofile/Makefile b/package/libaudiofile/Makefile
index 4b4f74d35..be4e93c61 100644
--- a/package/libaudiofile/Makefile
+++ b/package/libaudiofile/Makefile
@@ -3,14 +3,14 @@
include ${TOPDIR}/rules.mk
-PKG_NAME:= libaudiofile
-PKG_VERSION:= 0.2.6
-PKG_RELEASE:= 2
-PKG_MD5SUM:= 460f848ce5f4a33ae66b15a4fb7720ec
+PKG_NAME:= audiofile
+PKG_VERSION:= 0.2.7
+PKG_RELEASE:= 1
+PKG_MD5SUM:= a39be317a7b1971b408805dc5e371862
PKG_DESCR:= audiofile library
PKG_SECTION:= libs
-PKG_URL:= http://www.68k.org/~michael/audiofile
-PKG_SITES:= http://www.openadk.org/distfiles/
+PKG_URL:= http://www.68k.org/~michael/audiofile/
+PKG_SITES:= http://www.68k.org/~michael/audiofile/
include ${TOPDIR}/mk/package.mk
diff --git a/package/libaudiofile/patches/001-audiofile-config-libdirs.patch b/package/libaudiofile/patches/001-audiofile-config-libdirs.patch
index ba92d7d4e..ef3ea3c0f 100644
--- a/package/libaudiofile/patches/001-audiofile-config-libdirs.patch
+++ b/package/libaudiofile/patches/001-audiofile-config-libdirs.patch
@@ -1,6 +1,6 @@
---- libaudiofile-0.2.6/audiofile-config.in.orig 2004-03-06 07:39:23.000000000 +0100
-+++ libaudiofile-0.2.6/audiofile-config.in 2005-12-13 14:15:52.000000000 +0100
-@@ -45,7 +45,9 @@
+--- libaudiofile-0.2.6.orig/audiofile-config.in 2004-03-06 07:39:23.000000000 +0100
++++ libaudiofile-0.2.6/audiofile-config.in 2011-01-14 22:38:44.000000000 +0100
+@@ -45,7 +45,9 @@ while test $# -gt 0; do
echo $includes
;;
--libs)
diff --git a/package/libaudiofile/patches/patch-ltmain_sh b/package/libaudiofile/patches/patch-ltmain_sh
new file mode 100644
index 000000000..499a548dd
--- /dev/null
+++ b/package/libaudiofile/patches/patch-ltmain_sh
@@ -0,0 +1,27 @@
+--- audiofile-0.2.7.orig/ltmain.sh 2010-03-22 04:48:34.000000000 +0100
++++ audiofile-0.2.7/ltmain.sh 2011-01-14 23:13:46.000000000 +0100
+@@ -1422,7 +1422,6 @@ EOF
+ esac
+ continue
+ ;;
+-
+ -L*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+ # We need an absolute path.
+@@ -1503,15 +1502,9 @@ EOF
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+- -m*)
++ -m*|-fstack-protector*|-flto)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+- case $arg in
+- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+- arg="\"$arg\""
+- ;;
+- esac
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ if test "$with_gcc" = "yes" ; then
diff --git a/package/libdaemon/patches/patch-ltmain_sh b/package/libdaemon/patches/patch-ltmain_sh
new file mode 100644
index 000000000..40977292e
--- /dev/null
+++ b/package/libdaemon/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libdaemon-0.13.orig/ltmain.sh 2008-06-09 21:51:04.000000000 +0200
++++ libdaemon-0.13/ltmain.sh 2011-01-14 18:34:49.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libdb/patches/patch-dist_ltmain_sh b/package/libdb/patches/patch-dist_ltmain_sh
new file mode 100644
index 000000000..e9ff24a13
--- /dev/null
+++ b/package/libdb/patches/patch-dist_ltmain_sh
@@ -0,0 +1,11 @@
+--- db-4.7.25.orig/dist/ltmain.sh 2006-06-27 03:03:33.000000000 +0200
++++ db-4.7.25/dist/ltmain.sh 2011-01-14 19:32:22.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libdnet/patches/libdnet-1.10-dnet_config.patch b/package/libdnet/patches/libdnet-1.10-dnet_config.patch
index 005ac3305..82dda52ef 100644
--- a/package/libdnet/patches/libdnet-1.10-dnet_config.patch
+++ b/package/libdnet/patches/libdnet-1.10-dnet_config.patch
@@ -1,6 +1,6 @@
---- libdnet-1.10/dnet-config.in.orig 2001-10-19 03:29:00.000000000 +0200
-+++ libdnet-1.10/dnet-config.in 2005-09-20 09:32:53.000000000 +0200
-@@ -45,10 +45,18 @@
+--- libdnet-1.10.orig/dnet-config.in 2001-10-19 03:29:00.000000000 +0200
++++ libdnet-1.10/dnet-config.in 2011-01-14 11:44:00.000000000 +0100
+@@ -45,10 +45,18 @@ while test $# -gt 0; do
done
if test "$echo_cflags" = "yes"; then
diff --git a/package/libdnet/patches/patch-config_ltmain_sh b/package/libdnet/patches/patch-config_ltmain_sh
new file mode 100644
index 000000000..141618689
--- /dev/null
+++ b/package/libdnet/patches/patch-config_ltmain_sh
@@ -0,0 +1,11 @@
+--- libdnet-1.10.orig/config/ltmain.sh 2005-02-26 00:09:06.000000000 +0100
++++ libdnet-1.10/config/ltmain.sh 2011-01-14 12:02:17.000000000 +0100
+@@ -1382,7 +1382,7 @@ EOF
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+- -m*)
++ -m*|-fstack-protector*|-flto)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
diff --git a/package/libdrm/patches/patch-ltmain_sh b/package/libdrm/patches/patch-ltmain_sh
new file mode 100644
index 000000000..ea1a793f9
--- /dev/null
+++ b/package/libdrm/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libdrm-2.4.22.orig/ltmain.sh 2010-01-21 11:04:52.000000000 +0100
++++ libdrm-2.4.22/ltmain.sh 2011-01-14 01:13:30.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libelf/Makefile b/package/libelf/Makefile
index a5847bc87..c8ae86b32 100644
--- a/package/libelf/Makefile
+++ b/package/libelf/Makefile
@@ -2,18 +2,17 @@
# material, please see the LICENCE file in the top-level directory.
include ${TOPDIR}/rules.mk
+include ${TOPDIR}/toolchain/libelf/Makefile.inc
-PKG_NAME:= libelf
-PKG_VERSION:= 0.8.11
-PKG_RELEASE:= 1
-PKG_MD5SUM:= e931910b6d100f6caa32239849947fbf
PKG_DESCR:= elf library
PKG_SECTION:= libs
PKG_SITES:= http://www.mr511.de/software/
+PKG_SUBPKGS:= LIBELF
+
include ${TOPDIR}/mk/package.mk
-$(eval $(call PKG_template,LIBELF,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+$(eval $(call PKG_template,LIBELF,libelf,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
CONFIGURE_ENV+= mr_cv_target_elf=yes \
ac_cv_sizeof_long_long=8
@@ -21,7 +20,7 @@ CONFIGURE_ARGS+= --enable-elf64=yes \
--disable-sanity-checks
FAKE_FLAGS+= instroot="${WRKINST}"
-post-install:
+libelf-install:
${INSTALL_DIR} ${IDIR_LIBELF}/usr/lib
${CP} ${WRKINST}/usr/lib/libelf.so* ${IDIR_LIBELF}/usr/lib/
diff --git a/package/libelf/patches/patch-lib_Makefile_in b/package/libelf/patches/patch-lib_Makefile_in
new file mode 100644
index 000000000..7630c7f5c
--- /dev/null
+++ b/package/libelf/patches/patch-lib_Makefile_in
@@ -0,0 +1,11 @@
+--- libelf-0.8.13.orig/lib/Makefile.in 2009-11-01 14:04:19.000000000 +0100
++++ libelf-0.8.13/lib/Makefile.in 2011-01-15 21:55:08.000000000 +0100
+@@ -158,7 +158,7 @@ libelf.a: $(OBJS) $(LIBOBJS)
+
+ $(SHLIB): libelf.a
+ @$(RM) $(SHLIB)
+- $(LINK_SHLIB) -o $(SHLIB) $(OBJS:.o=.os) $(LIBOBJS:.o=.os) $(DEPSHLIBS)
++ $(LINK_SHLIB) $(LDFLAGS) -o $(SHLIB) $(OBJS:.o=.os) $(LIBOBJS:.o=.os) $(DEPSHLIBS)
+ if test "$(SONAME)" = "$(SHLIB)"; then true; else \
+ $(RM) $(SONAME) && $(LN_S) $(SHLIB) $(SONAME); \
+ fi
diff --git a/package/libevent/Makefile b/package/libevent/Makefile
index 829162b10..a11099ab0 100644
--- a/package/libevent/Makefile
+++ b/package/libevent/Makefile
@@ -21,11 +21,7 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,LIBEVENT,${PKG_NAME},$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,LIBEVENT_DEV,libevent-dev,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBEVENT_DEV},${PKGSC_LIBEVENT_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBEVENT_DEV}+= libevent-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
$(INSTALL_DIR) $(IDIR_LIBEVENT)/usr/lib
$(CP) $(WRKINST)/usr/lib/libevent*.so* \
$(IDIR_LIBEVENT)/usr/lib/
diff --git a/package/libevent/patches/patch-ltmain_sh b/package/libevent/patches/patch-ltmain_sh
new file mode 100644
index 000000000..b2a564fa8
--- /dev/null
+++ b/package/libevent/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libevent-1.3.orig/ltmain.sh 2006-12-09 05:42:31.000000000 +0100
++++ libevent-1.3/ltmain.sh 2011-01-14 12:04:21.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libffi/patches/patch-ltmain_sh b/package/libffi/patches/patch-ltmain_sh
new file mode 100644
index 000000000..02c12cbfb
--- /dev/null
+++ b/package/libffi/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libffi-3.0.9.orig/ltmain.sh 2009-12-31 13:38:48.000000000 +0100
++++ libffi-3.0.9/ltmain.sh 2011-01-14 19:48:53.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libfontenc/patches/patch-ltmain_sh b/package/libfontenc/patches/patch-ltmain_sh
new file mode 100644
index 000000000..7c092bb10
--- /dev/null
+++ b/package/libfontenc/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libfontenc-1.0.5.orig/ltmain.sh 2009-05-18 04:27:25.000000000 +0200
++++ libfontenc-1.0.5/ltmain.sh 2011-01-15 22:24:34.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libgcrypt/patches/patch-ltmain_sh b/package/libgcrypt/patches/patch-ltmain_sh
new file mode 100644
index 000000000..b9caca043
--- /dev/null
+++ b/package/libgcrypt/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libgcrypt-1.4.5.orig/ltmain.sh 2009-04-02 11:25:35.000000000 +0200
++++ libgcrypt-1.4.5/ltmain.sh 2011-01-14 20:42:36.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libgssglue/patches/patch-ltmain_sh b/package/libgssglue/patches/patch-ltmain_sh
new file mode 100644
index 000000000..12459df44
--- /dev/null
+++ b/package/libgssglue/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libgssglue-0.1.orig/ltmain.sh 2005-12-02 22:14:34.000000000 +0100
++++ libgssglue-0.1/ltmain.sh 2011-01-15 22:40:39.000000000 +0100
+@@ -1382,7 +1382,7 @@ EOF
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+- -m*)
++ -m*|-fstack-protector*|-flto)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
diff --git a/package/libiconv/patches/patch-build-aux_ltmain_sh b/package/libiconv/patches/patch-build-aux_ltmain_sh
new file mode 100644
index 000000000..1c6d67d61
--- /dev/null
+++ b/package/libiconv/patches/patch-build-aux_ltmain_sh
@@ -0,0 +1,11 @@
+--- libiconv-1.13.1.orig/build-aux/ltmain.sh 2009-06-21 13:17:33.000000000 +0200
++++ libiconv-1.13.1/build-aux/ltmain.sh 2011-01-14 00:42:49.000000000 +0100
+@@ -4885,7 +4885,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libiconv/patches/patch-libcharset_build-aux_ltmain_sh b/package/libiconv/patches/patch-libcharset_build-aux_ltmain_sh
new file mode 100644
index 000000000..1c0c92ab1
--- /dev/null
+++ b/package/libiconv/patches/patch-libcharset_build-aux_ltmain_sh
@@ -0,0 +1,11 @@
+--- libiconv-1.13.1.orig/libcharset/build-aux/ltmain.sh 2009-06-21 13:17:33.000000000 +0200
++++ libiconv-1.13.1/libcharset/build-aux/ltmain.sh 2011-01-14 00:44:22.000000000 +0100
+@@ -4885,7 +4885,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/liblzo/patches/patch-autoconf_ltmain_sh b/package/liblzo/patches/patch-autoconf_ltmain_sh
new file mode 100644
index 000000000..9984105f8
--- /dev/null
+++ b/package/liblzo/patches/patch-autoconf_ltmain_sh
@@ -0,0 +1,11 @@
+--- lzo-2.03.orig/autoconf/ltmain.sh 2008-04-30 14:51:49.000000000 +0200
++++ lzo-2.03/autoconf/ltmain.sh 2011-01-15 19:26:34.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libmad/Makefile b/package/libmad/Makefile
index 05cd0a948..0b708732d 100644
--- a/package/libmad/Makefile
+++ b/package/libmad/Makefile
@@ -30,10 +30,6 @@ endif
#FPM:=mips
#endif
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBMAD_DEV}+= libmad-dev-install
-
CONFIGURE_ARGS+= --enable-fpm=${FPM} \
--disable-debugging \
--enable-speed
@@ -42,7 +38,7 @@ pre-install:
${INSTALL_DIR} ${WRKINST}/usr/lib/pkgconfig
${CP} ./files/mad.pc ${WRKINST}/usr/lib/pkgconfig
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBMAD}/usr/lib
${CP} ${WRKINST}/usr/lib/libmad.so* ${IDIR_LIBMAD}/usr/lib/
diff --git a/package/libmad/patches/patch-ltmain_sh b/package/libmad/patches/patch-ltmain_sh
new file mode 100644
index 000000000..7dc9efb7d
--- /dev/null
+++ b/package/libmad/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libmad-0.15.1b.orig/ltmain.sh 2004-02-17 02:51:24.000000000 +0100
++++ libmad-0.15.1b/ltmain.sh 2011-01-15 22:43:18.000000000 +0100
+@@ -1372,7 +1372,7 @@ EOF
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+- -m*)
++ -m*|-fstack-protector*|-flto)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
diff --git a/package/libmms/patches/patch-ltmain_sh b/package/libmms/patches/patch-ltmain_sh
new file mode 100644
index 000000000..709251ce3
--- /dev/null
+++ b/package/libmms/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libmms-0.5.orig/ltmain.sh 2009-11-03 10:26:05.000000000 +0100
++++ libmms-0.5/ltmain.sh 2011-01-15 22:44:48.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libmpdclient/patches/patch-build_ltmain_sh b/package/libmpdclient/patches/patch-build_ltmain_sh
new file mode 100644
index 000000000..5f8c6273c
--- /dev/null
+++ b/package/libmpdclient/patches/patch-build_ltmain_sh
@@ -0,0 +1,11 @@
+--- libmpdclient-2.2.orig/build/ltmain.sh 2009-12-09 22:05:28.000000000 +0100
++++ libmpdclient-2.2/build/ltmain.sh 2011-01-15 22:46:18.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libnet/patches/patch-ltmain_sh b/package/libnet/patches/patch-ltmain_sh
new file mode 100644
index 000000000..cc5affa12
--- /dev/null
+++ b/package/libnet/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libnet-1.1.5.orig/ltmain.sh 2007-08-14 20:05:31.000000000 +0200
++++ libnet-1.1.5/ltmain.sh 2011-01-14 22:19:20.000000000 +0100
+@@ -1663,7 +1663,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libnetfilter_conntrack/patches/patch-ltmain_sh b/package/libnetfilter_conntrack/patches/patch-ltmain_sh
new file mode 100644
index 000000000..b29e65024
--- /dev/null
+++ b/package/libnetfilter_conntrack/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libnetfilter_conntrack-0.0.101.orig/ltmain.sh 2009-04-08 00:25:23.000000000 +0200
++++ libnetfilter_conntrack-0.0.101/ltmain.sh 2011-01-14 20:35:18.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libnetfilter_log/patches/patch-ltmain_sh b/package/libnetfilter_log/patches/patch-ltmain_sh
new file mode 100644
index 000000000..e20823d60
--- /dev/null
+++ b/package/libnetfilter_log/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libnetfilter_log-1.0.0.orig/ltmain.sh 2009-12-10 00:55:19.000000000 +0100
++++ libnetfilter_log-1.0.0/ltmain.sh 2011-01-15 22:47:50.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libnetfilter_queue/patches/patch-ltmain_sh b/package/libnetfilter_queue/patches/patch-ltmain_sh
new file mode 100644
index 000000000..98484bd51
--- /dev/null
+++ b/package/libnetfilter_queue/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libnetfilter_queue-0.0.17.orig/ltmain.sh 2008-04-29 23:33:55.000000000 +0200
++++ libnetfilter_queue-0.0.17/ltmain.sh 2011-01-15 22:49:28.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libnfnetlink/patches/patch-ltmain_sh b/package/libnfnetlink/patches/patch-ltmain_sh
new file mode 100644
index 000000000..66d4e2d92
--- /dev/null
+++ b/package/libnfnetlink/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libnfnetlink-1.0.0.orig/ltmain.sh 2008-04-29 23:33:55.000000000 +0200
++++ libnfnetlink-1.0.0/ltmain.sh 2011-01-14 20:31:43.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libnfsidmap/patches/patch-ltmain_sh b/package/libnfsidmap/patches/patch-ltmain_sh
new file mode 100644
index 000000000..75caf5e29
--- /dev/null
+++ b/package/libnfsidmap/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libnfsidmap-0.21b1.orig/ltmain.sh 2004-08-09 17:06:29.000000000 +0200
++++ libnfsidmap-0.21b1/ltmain.sh 2011-01-15 22:51:07.000000000 +0100
+@@ -1382,7 +1382,7 @@ EOF
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+- -m*)
++ -m*|-fstack-protector*|-flto)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
diff --git a/package/libnl/Makefile b/package/libnl/Makefile
index d7021a844..c2878f406 100644
--- a/package/libnl/Makefile
+++ b/package/libnl/Makefile
@@ -4,12 +4,14 @@
include ${TOPDIR}/rules.mk
PKG_NAME:= libnl
-PKG_VERSION:= 1.1
-PKG_RELEASE:= 1
-PKG_MD5SUM:= ae970ccd9144e132b68664f98e7ceeb1
+PKG_VERSION:= 2.0
+PKG_RELEASE:= 2
+PKG_MD5SUM:= 6aaf1e9802a17a7d702bb0638044ffa7
PKG_DESCR:= Netlink library
PKG_SECTION:= libs
-PKG_SITES:= http://downloads.openwrt.org/sources/
+PKG_URL:= http://www.infradead.org/~tgr/libnl/
+PKG_SITES:= http://www.infradead.org/~tgr/libnl/files/
+PKG_NOPARALLEL:= 1
PKG_SUBPKGS:= LIBNL LIBNL_DEV
PKGSD_LIBNL_DEV:= header files for netlink library
@@ -17,16 +19,15 @@ PKGSC_LIBNL_DEV:= devel
include ${TOPDIR}/mk/package.mk
-$(eval $(call PKG_template,LIBNL,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
-$(eval $(call PKG_template,LIBNL_DEV,${PKG_NAME}-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBNL_DEV},${PKGSC_LIBNL_DEV}))
+$(eval $(call PKG_template,LIBNL,libnl,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+$(eval $(call PKG_template,LIBNL_DEV,libnl-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBNL_DEV},${PKGSC_LIBNL_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBNL_DEV}+= libnl-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+libnl-install:
${INSTALL_DIR} ${IDIR_LIBNL}/usr/lib
${CP} ${WRKINST}/usr/lib/libnl.so* ${IDIR_LIBNL}/usr/lib
+ ${CP} ${WRKINST}/usr/lib/libnl-genl.so* ${IDIR_LIBNL}/usr/lib
+ ${CP} ${WRKINST}/usr/lib/libnl-cli.so* ${IDIR_LIBNL}/usr/lib
+ ${CP} ${WRKINST}/usr/lib/libnl-route.so* ${IDIR_LIBNL}/usr/lib
libnl-dev-install:
${INSTALL_DIR} ${IDIR_LIBNL_DEV}/usr/include
diff --git a/package/libnl/patches/patch-include_netlink-local_h b/package/libnl/patches/patch-include_netlink-local_h
deleted file mode 100644
index 02dc66130..000000000
--- a/package/libnl/patches/patch-include_netlink-local_h
+++ /dev/null
@@ -1,20 +0,0 @@
-$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- libnl-1.1.orig/include/netlink-local.h 2008-01-14 16:48:45.000000000 +0100
-+++ libnl-1.1/include/netlink-local.h 2009-05-29 00:17:59.000000000 +0200
-@@ -26,6 +26,7 @@
- #include <sys/socket.h>
- #include <inttypes.h>
- #include <assert.h>
-+#include <limits.h>
-
- #include <arpa/inet.h>
- #include <netdb.h>
-@@ -337,7 +337,7 @@ static inline int nl_cb_call(struct nl_c
- }
-
- #define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
--#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-+#define __offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
- #define __init __attribute__ ((constructor))
- #define __exit __attribute__ ((destructor))
diff --git a/package/libnl/patches/patch-include_netlink-types_h b/package/libnl/patches/patch-include_netlink-types_h
deleted file mode 100644
index 01d181e28..000000000
--- a/package/libnl/patches/patch-include_netlink-types_h
+++ /dev/null
@@ -1,19 +0,0 @@
-$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- libnl-1.1.orig/include/netlink-types.h 2008-01-14 16:48:45.000000000 +0100
-+++ libnl-1.1/include/netlink-types.h 2009-04-16 20:16:45.349364825 +0200
-@@ -95,15 +95,6 @@ struct nl_cache_mngr
-
- struct nl_parser_param;
-
--struct genl_info
--{
-- struct sockaddr_nl * who;
-- struct nlmsghdr * nlh;
-- struct genlmsghdr * genlhdr;
-- void * userhdr;
-- struct nlattr ** attrs;
--};
--
- #define LOOSE_FLAG_COMPARISON 1
-
- #define NL_OBJ_MARK 1
diff --git a/package/libnl/patches/patch-include_netlink_genl_mngt_h b/package/libnl/patches/patch-include_netlink_genl_mngt_h
deleted file mode 100644
index 28ba36d23..000000000
--- a/package/libnl/patches/patch-include_netlink_genl_mngt_h
+++ /dev/null
@@ -1,19 +0,0 @@
-$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- libnl-1.1.orig/include/netlink/genl/mngt.h 2008-01-14 16:48:45.000000000 +0100
-+++ libnl-1.1/include/netlink/genl/mngt.h 2009-04-16 20:16:45.343843731 +0200
-@@ -22,6 +22,15 @@ extern "C" {
-
- struct nl_cache_ops;
-
-+struct genl_info
-+{
-+ struct sockaddr_nl * who;
-+ struct nlmsghdr * nlh;
-+ struct genlmsghdr * genlhdr;
-+ void * userhdr;
-+ struct nlattr ** attrs;
-+};
-+
- /**
- * @ingroup genl_mngt
- * Generic Netlink Command
diff --git a/package/libnl/patches/patch-lib_object_c b/package/libnl/patches/patch-lib_object_c
deleted file mode 100644
index 6d4ba6c8c..000000000
--- a/package/libnl/patches/patch-lib_object_c
+++ /dev/null
@@ -1,12 +0,0 @@
-$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- libnl-1.1.orig/lib/object.c 2008-01-14 16:48:45.000000000 +0100
-+++ libnl-1.1/lib/object.c 2009-05-28 23:20:00.925639994 +0200
-@@ -96,7 +96,7 @@ struct nl_object *nl_object_clone(struct
- {
- struct nl_object *new;
- struct nl_object_ops *ops = obj_ops(obj);
-- int doff = offsetof(struct nl_derived_object, data);
-+ int doff = __offsetof(struct nl_derived_object, data);
- int size;
-
- new = nl_object_alloc(ops);
diff --git a/package/libnl/patches/patch-ltmain_sh b/package/libnl/patches/patch-ltmain_sh
new file mode 100644
index 000000000..2058e0c78
--- /dev/null
+++ b/package/libnl/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libnl-2.0.orig/ltmain.sh 2010-10-13 16:43:44.000000000 +0200
++++ libnl-2.0/ltmain.sh 2011-01-15 21:22:48.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libnl/patches/patch-src_nl-list-caches_c b/package/libnl/patches/patch-src_nl-list-caches_c
deleted file mode 100644
index cb7c8986c..000000000
--- a/package/libnl/patches/patch-src_nl-list-caches_c
+++ /dev/null
@@ -1,11 +0,0 @@
-$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- libnl-1.1.orig/src/nl-list-caches.c 2008-01-14 16:48:45.000000000 +0100
-+++ libnl-1.1/src/nl-list-caches.c 2009-04-16 20:16:45.349364825 +0200
-@@ -10,6 +10,7 @@
- */
-
- #include "utils.h"
-+#include <netlink-local.h>
-
- static void print_usage(void)
- {
diff --git a/package/libnl/patches/patch-src_utils_c b/package/libnl/patches/patch-src_utils_c
deleted file mode 100644
index 05da529a3..000000000
--- a/package/libnl/patches/patch-src_utils_c
+++ /dev/null
@@ -1,11 +0,0 @@
-$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- libnl-1.1.orig/src/utils.c 2008-01-14 16:48:45.000000000 +0100
-+++ libnl-1.1/src/utils.c 2009-04-16 20:16:45.349364825 +0200
-@@ -12,6 +12,7 @@
- #include "utils.h"
-
- #include <stdlib.h>
-+#include <stdarg.h>
-
- int nltool_init(int argc, char *argv[])
- {
diff --git a/package/libnl/patches/patch-src_utils_h b/package/libnl/patches/patch-src_utils_h
deleted file mode 100644
index e19e1e182..000000000
--- a/package/libnl/patches/patch-src_utils_h
+++ /dev/null
@@ -1,11 +0,0 @@
-$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- libnl-1.1.orig/src/utils.h 2008-01-14 16:48:45.000000000 +0100
-+++ libnl-1.1/src/utils.h 2009-04-16 20:16:45.353364776 +0200
-@@ -22,7 +22,6 @@
- #include <sys/types.h>
- #include <sys/socket.h>
-
--#include <netlink-local.h>
- #include <netlink/netlink.h>
- #include <netlink/utils.h>
- #include <netlink/addr.h>
diff --git a/package/libogg/Makefile b/package/libogg/Makefile
index a672bbe3a..f9d5e5fe9 100644
--- a/package/libogg/Makefile
+++ b/package/libogg/Makefile
@@ -21,11 +21,7 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LIBOGG,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,LIBOGG_DEV,libogg-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBOGG_DEV},${PKGSC_LIBOGG_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBOGG_DEV}+= libogg-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBOGG}/usr/lib
${CP} ${WRKINST}/usr/lib/libogg.so* ${IDIR_LIBOGG}/usr/lib/
diff --git a/package/libol/patches/patch-ltmain_sh b/package/libol/patches/patch-ltmain_sh
new file mode 100644
index 000000000..c5f9a8f81
--- /dev/null
+++ b/package/libol/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libol-0.3.18.orig/ltmain.sh 2005-04-01 02:47:06.000000000 +0200
++++ libol-0.3.18/ltmain.sh 2011-01-15 22:53:34.000000000 +0100
+@@ -1382,7 +1382,7 @@ EOF
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+- -m*)
++ -m*|-fstack-protector*|-flto)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
diff --git a/package/libosip2/patches/patch-scripts_ltmain_sh b/package/libosip2/patches/patch-scripts_ltmain_sh
new file mode 100644
index 000000000..e354b4086
--- /dev/null
+++ b/package/libosip2/patches/patch-scripts_ltmain_sh
@@ -0,0 +1,11 @@
+--- libosip2-3.3.0.orig/scripts/ltmain.sh 2008-04-29 22:21:21.000000000 +0200
++++ libosip2-3.3.0/scripts/ltmain.sh 2011-01-15 22:56:16.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libowfat/Makefile b/package/libowfat/Makefile
index c6e21ae01..d1b6150b5 100644
--- a/package/libowfat/Makefile
+++ b/package/libowfat/Makefile
@@ -19,7 +19,8 @@ CONFIG_STYLE:= manual
TCFLAGS+= ${TCPPFLAGS}
MAKE_FILE= GNUmakefile
-MAKE_FLAGS+= DIET= CC='${TARGET_CC}' CROSS=${TARGET_CROSS}
+MAKE_FLAGS+= DIET= CC='${TARGET_CC}' CROSS=${TARGET_CROSS} \
+ LDFLAGS='${TARGET_LDFLAGS}'
FAKE_FLAGS+= prefix='${WRKINST}/usr' \
INCLUDEDIR='${WRKINST}/usr/include/owfat'
diff --git a/package/libowfat/patches/patch-GNUmakefile b/package/libowfat/patches/patch-GNUmakefile
index 24c836bac..553338e2f 100644
--- a/package/libowfat/patches/patch-GNUmakefile
+++ b/package/libowfat/patches/patch-GNUmakefile
@@ -1,6 +1,6 @@
$Id$
---- libowfat-0.25.orig/GNUmakefile 2006-07-16 01:17:01.000000000 +0200
-+++ libowfat-0.25/GNUmakefile 2007-07-06 17:35:01.000000000 +0200
+--- libowfat-0.28.orig/GNUmakefile 2006-07-16 01:17:01.000000000 +0200
++++ libowfat-0.28/GNUmakefile 2011-01-15 13:58:17.000000000 +0100
@@ -18,7 +18,7 @@ all: t $(LIBS) libowfat.a libsocket
CROSS=
#CROSS=i686-mingw-
@@ -10,3 +10,21 @@ $Id$
#CFLAGS=-pipe -Os -march=pentiumpro -mcpu=pentiumpro -fomit-frame-pointer -fschedule-insns2 -Wall
# CFLAGS += -fstrict-aliasing -Wstrict-aliasing=2
+@@ -27,7 +27,7 @@ CFLAGS += -D_REENTRANT
+
+ # startrip
+ ifneq ($(DEBUG),)
+-CFLAGS=-pipe -Wall -g
++CFLAGS=-g -Wall
+ endif
+ path = $(subst :, ,$(PATH))
+ diet_path = $(foreach dir,$(path),$(wildcard $(dir)/diet))
+@@ -147,7 +147,7 @@ CFLAGS+=-I.
+ t.o: iopause.h
+
+ t: t.o libowfat.a libsocket
+- $(DIET) $(CC) -g -o $@ t.o libowfat.a `cat libsocket`
++ $(DIET) $(CC) $(LDFLAGS) -o $@ t.o libowfat.a `cat libsocket`
+
+ .PHONY: all clean tar install rename
+ clean:
diff --git a/package/libowfat/patches/patch-Makefile b/package/libowfat/patches/patch-Makefile
new file mode 100644
index 000000000..226d77837
--- /dev/null
+++ b/package/libowfat/patches/patch-Makefile
@@ -0,0 +1,11 @@
+--- libowfat-0.28.orig/Makefile 2008-11-15 17:06:28.000000000 +0100
++++ libowfat-0.28/Makefile 2011-01-15 13:40:31.000000000 +0100
+@@ -603,7 +603,7 @@ CFLAGS+=-I.
+ t.o: iopause.h
+
+ t: t.o libowfat.a libsocket
+- $(DIET) $(CC) -g -o $@ t.o libowfat.a `cat libsocket`
++ $(DIET) $(CC) $(LDFLAGS) -g -o $@ t.o libowfat.a `cat libsocket`
+
+ .PHONY: all clean tar install rename
+ clean:
diff --git a/package/libp11/Makefile b/package/libp11/Makefile
index 9ba2fec39..8c3536e0e 100644
--- a/package/libp11/Makefile
+++ b/package/libp11/Makefile
@@ -23,11 +23,7 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LIBP11,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,LIBP11_DEV,libp11-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBP11_DEV},${PKGSC_LIBP11_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBP11_DEV}+= libp11-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBP11}/usr/lib
${CP} ${WRKINST}/usr/lib/libp11.so* ${IDIR_LIBP11}/usr/lib
diff --git a/package/libp11/patches/patch-ltmain_sh b/package/libp11/patches/patch-ltmain_sh
new file mode 100644
index 000000000..409b69508
--- /dev/null
+++ b/package/libp11/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libp11-0.2.7.orig/ltmain.sh 2009-10-20 14:38:20.000000000 +0200
++++ libp11-0.2.7/ltmain.sh 2011-01-15 22:58:43.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libpcap/Makefile b/package/libpcap/Makefile
index ebc7701ce..209a337df 100644
--- a/package/libpcap/Makefile
+++ b/package/libpcap/Makefile
@@ -5,14 +5,14 @@ include $(TOPDIR)/rules.mk
PKG_NAME:= libpcap
PKG_VERSION:= 1.1.1
-PKG_RELEASE:= 2
+PKG_RELEASE:= 3
PKG_MD5SUM:= 1bca27d206970badae248cfa471bbb47
PKG_DESCR:= a low-level packet capture library
PKG_SECTION:= libs
PKG_URL:= http://www.tcpdump.org/
PKG_SITES:= http://www.tcpdump.org/release/
-PKG_FLAVOURS:= WITH_IPV6
+PKG_FLAVOURS_LIBPCAP:= WITH_IPV6
PKGFD_WITH_IPV6:= enable IPv6 support
include $(TOPDIR)/mk/package.mk
diff --git a/package/libpcap/patches/patch-pcap-config_in b/package/libpcap/patches/patch-pcap-config_in
new file mode 100644
index 000000000..b50f6fb48
--- /dev/null
+++ b/package/libpcap/patches/patch-pcap-config_in
@@ -0,0 +1,27 @@
+--- libpcap-1.1.1.orig/pcap-config.in 2010-03-12 02:56:54.000000000 +0100
++++ libpcap-1.1.1/pcap-config.in 2011-01-06 21:29:12.000000000 +0100
+@@ -29,16 +29,6 @@ do
+ esac
+ shift
+ done
+-if [ "@V_RPATH_OPT@" != "" ]
+-then
+- #
+- # If libdir isn't /usr/lib, add it to the run-time linker path.
+- #
+- if [ "@libdir@" != "/usr/lib" ]
+- then
+- RPATH=@V_RPATH_OPT@@libdir@
+- fi
+-fi
+ if [ "$static" = 1 ]
+ then
+ #
+@@ -77,6 +67,6 @@ else
+ echo "-I@includedir@"
+ elif [ "$show_libs" = 1 ]
+ then
+- echo "-L@libdir@ $RPATH -lpcap"
++ echo "-L@libdir@ -lpcap"
+ fi
+ fi
diff --git a/package/libpciaccess/patches/patch-ltmain_sh b/package/libpciaccess/patches/patch-ltmain_sh
new file mode 100644
index 000000000..178b522ce
--- /dev/null
+++ b/package/libpciaccess/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libpciaccess-0.11.0.orig/ltmain.sh 2009-11-17 23:55:38.000000000 +0100
++++ libpciaccess-0.11.0/ltmain.sh 2011-01-15 23:00:07.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libpng/Makefile b/package/libpng/Makefile
index 83408d1d3..92365bf63 100644
--- a/package/libpng/Makefile
+++ b/package/libpng/Makefile
@@ -27,11 +27,7 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LIBPNG,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,LIBPNG_DEV,libpng-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBPNG_DEV},${PKGSC_LIBPNG_DEV},${PKG_OPTS}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBPNG_DEV}+= libpng-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBPNG}/usr/lib
${CP} ${WRKINST}/usr/lib/libpng{,12}.so* ${IDIR_LIBPNG}/usr/lib/
diff --git a/package/libpng/patches/patch-ltmain_sh b/package/libpng/patches/patch-ltmain_sh
new file mode 100644
index 000000000..3dc47967e
--- /dev/null
+++ b/package/libpng/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libpng-1.2.44.orig/ltmain.sh 2009-11-22 15:45:24.000000000 +0100
++++ libpng-1.2.44/ltmain.sh 2011-01-14 00:13:24.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/librpcsecgss/patches/patch-ltmain_sh b/package/librpcsecgss/patches/patch-ltmain_sh
new file mode 100644
index 000000000..7c498e575
--- /dev/null
+++ b/package/librpcsecgss/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- librpcsecgss-0.19.orig/ltmain.sh 2009-05-13 23:33:08.000000000 +0200
++++ librpcsecgss-0.19/ltmain.sh 2011-01-15 23:01:58.000000000 +0100
+@@ -1382,7 +1382,7 @@ EOF
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+- -m*)
++ -m*|-fstack-protector*|-flto)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
diff --git a/package/libshout/patches/patch-ltmain_sh b/package/libshout/patches/patch-ltmain_sh
new file mode 100644
index 000000000..16c4c7888
--- /dev/null
+++ b/package/libshout/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libshout-2.2.2.orig/ltmain.sh 2006-01-10 16:23:50.000000000 +0100
++++ libshout-2.2.2/ltmain.sh 2011-01-15 23:03:59.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libstdcxx/Makefile b/package/libstdcxx/Makefile
index eb935fbb8..efdb3ba72 100644
--- a/package/libstdcxx/Makefile
+++ b/package/libstdcxx/Makefile
@@ -27,11 +27,11 @@ BUILD_STYLE:= manual
INSTALL_STYLE:= manual
do-install:
- ${INSTALL_DIR} ${IDIR_LIBSTDCXX}/lib
+ ${INSTALL_DIR} ${IDIR_LIBSTDCXX}/usr/lib
ifeq ($(ADK_NATIVE),y)
- $(CP) /usr/lib/libstdc++.so.* ${IDIR_LIBSTDCXX}/lib
+ $(CP) /usr/lib/libstdc++.so* ${IDIR_LIBSTDCXX}/usr/lib
else
- $(CP) ${STAGING_TARGET_DIR}/lib/libstdc++.so.* ${IDIR_LIBSTDCXX}/lib
+ $(CP) ${STAGING_TARGET_DIR}/lib/libstdc++.so* ${IDIR_LIBSTDCXX}/usr/lib
endif
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/libtasn1/patches/patch-build-aux_ltmain_sh b/package/libtasn1/patches/patch-build-aux_ltmain_sh
new file mode 100644
index 000000000..c48047c43
--- /dev/null
+++ b/package/libtasn1/patches/patch-build-aux_ltmain_sh
@@ -0,0 +1,11 @@
+--- libtasn1-2.2.orig/build-aux/ltmain.sh 2009-05-20 12:03:37.000000000 +0200
++++ libtasn1-2.2/build-aux/ltmain.sh 2011-01-15 19:29:40.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libtiff/Makefile b/package/libtiff/Makefile
index ebd9988bf..27060c07f 100644
--- a/package/libtiff/Makefile
+++ b/package/libtiff/Makefile
@@ -5,7 +5,7 @@ include ${TOPDIR}/rules.mk
PKG_NAME:= libtiff
PKG_VERSION:= 3.9.4
-PKG_RELEASE:= 2
+PKG_RELEASE:= 3
PKG_MD5SUM:= 2006c1bdd12644dbf02956955175afd6
PKG_DESCR:= A library for reading/writing TIFF images
PKG_SECTION:= libs
@@ -28,13 +28,9 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LIBTIFF,libtiff,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,LIBTIFF_DEV,libtiff-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBTIFF_DEV},${PKGSC_LIBTIFF_DEV},${PKG_OPTS}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBTIFF_DEV}+= libtiff-dev-install
+CONFIGURE_ARGS+= --disable-cxx --disable-rpath
-CONFIGURE_ARGS+= --disable-cxx
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBTIFF}/usr/lib
${CP} ${WRKINST}/usr/lib/libtiff.so* ${IDIR_LIBTIFF}/usr/lib/
diff --git a/package/libtiff/patches/patch-Makefile_in b/package/libtiff/patches/patch-Makefile_in
new file mode 100644
index 000000000..529d1cb47
--- /dev/null
+++ b/package/libtiff/patches/patch-Makefile_in
@@ -0,0 +1,11 @@
+--- tiff-3.9.4.orig/Makefile.in 2010-06-15 20:58:54.000000000 +0200
++++ tiff-3.9.4/Makefile.in 2011-01-08 11:52:47.000000000 +0100
+@@ -330,7 +330,7 @@ EXTRA_DIST = \
+ nmake.opt
+
+ dist_doc_DATA = $(docfiles)
+-SUBDIRS = port libtiff tools build contrib test man html
++SUBDIRS = port libtiff build man
+ all: all-recursive
+
+ .SUFFIXES:
diff --git a/package/libtiff/patches/patch-config_ltmain_sh b/package/libtiff/patches/patch-config_ltmain_sh
new file mode 100644
index 000000000..9ac507120
--- /dev/null
+++ b/package/libtiff/patches/patch-config_ltmain_sh
@@ -0,0 +1,11 @@
+--- tiff-3.9.4.orig/config/ltmain.sh 2010-06-11 22:28:18.000000000 +0200
++++ tiff-3.9.4/config/ltmain.sh 2011-01-14 00:30:36.000000000 +0100
+@@ -5091,7 +5091,7 @@ func_mode_link ()
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libtirpc/patches/patch-ltmain_sh b/package/libtirpc/patches/patch-ltmain_sh
new file mode 100644
index 000000000..599235216
--- /dev/null
+++ b/package/libtirpc/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libtirpc-0.2.1.orig/ltmain.sh 2009-11-30 15:10:18.000000000 +0100
++++ libtirpc-0.2.1/ltmain.sh 2011-01-15 23:09:39.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libtool/Makefile b/package/libtool/Makefile
index e22290dcf..bfc3695eb 100644
--- a/package/libtool/Makefile
+++ b/package/libtool/Makefile
@@ -29,12 +29,7 @@ endif
CONFIGURE_ARGS+= --enable-ltdl-install
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBLTDL}+= libltdl-install
-SUB_INSTALLS-${ADK_PACKAGE_LIBLTDL_DEV}+= libltdl-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBTOOL}/usr/bin
${INSTALL_BIN} ${WRKINST}/usr/bin/libtool ${IDIR_LIBTOOL}/usr/bin
${INSTALL_BIN} ${WRKINST}/usr/bin/libtoolize ${IDIR_LIBTOOL}/usr/bin
diff --git a/package/libtool/patches/patch-libltdl_config_ltmain_sh b/package/libtool/patches/patch-libltdl_config_ltmain_sh
new file mode 100644
index 000000000..bc46ecca5
--- /dev/null
+++ b/package/libtool/patches/patch-libltdl_config_ltmain_sh
@@ -0,0 +1,31 @@
+--- libtool-2.4.orig/libltdl/config/ltmain.sh 2010-09-22 16:45:43.000000000 +0200
++++ libtool-2.4/libltdl/config/ltmain.sh 2011-01-15 12:03:36.000000000 +0100
+@@ -136,15 +136,15 @@ progpath="$0"
+
+ : ${CP="cp -f"}
+ test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+-: ${EGREP="grep -E"}
+-: ${FGREP="grep -F"}
+-: ${GREP="grep"}
++: ${EGREP="/usr/bin/grep -E"}
++: ${FGREP="/usr/bin/grep -F"}
++: ${GREP="/usr/bin/grep"}
+ : ${LN_S="ln -s"}
+ : ${MAKE="make"}
+ : ${MKDIR="mkdir"}
+ : ${MV="mv -f"}
+ : ${RM="rm -f"}
+-: ${SED="sed"}
++: ${SED="/Volumes/adk/openadk/scripts/sed"}
+ : ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+ : ${Xsed="$SED -e 1s/^X//"}
+
+@@ -5840,7 +5840,7 @@ func_mode_link ()
+ # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+- -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
++ -O*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libupnp/patches/autotool.patch b/package/libupnp/patches/autotool.patch
index dd3e01157..72a57a5a1 100644
--- a/package/libupnp/patches/autotool.patch
+++ b/package/libupnp/patches/autotool.patch
@@ -16232,7 +16232,7 @@ diff -Nur libupnp-1.6.6.orig/build-aux/ltmain.sh libupnp-1.6.6/build-aux/ltmain.
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
-+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libusb-compat/Makefile b/package/libusb-compat/Makefile
index d7f46c858..728f5b5d1 100644
--- a/package/libusb-compat/Makefile
+++ b/package/libusb-compat/Makefile
@@ -28,11 +28,7 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LIBUSB_COMPAT,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,LIBUSB_COMPAT_DEV,${PKG_NAME}-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBUSB_COMPAT_DEV},${PKGSC_LIBUSB_COMPAT_DEV},${PKG_OPTS}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBUSB_COMPAT_DEV}+= libusb-compat-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBUSB_COMPAT}/usr/lib
${CP} ${WRKINST}/usr/lib/libusb*.so* ${IDIR_LIBUSB_COMPAT}/usr/lib/
diff --git a/package/libusb/Makefile b/package/libusb/Makefile
index 4358bc720..189329275 100644
--- a/package/libusb/Makefile
+++ b/package/libusb/Makefile
@@ -27,11 +27,7 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LIBUSB,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,LIBUSB_DEV,${PKG_NAME}-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBUSB_DEV},${PKGSC_LIBUSB_DEV},${PKG_OPTS}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBUSB_DEV}+= libusb-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBUSB}/usr/lib
${CP} ${WRKINST}/usr/lib/libusb*.so* ${IDIR_LIBUSB}/usr/lib/
diff --git a/package/libusb/patches/patch-ltmain_sh b/package/libusb/patches/patch-ltmain_sh
new file mode 100644
index 000000000..7ac5092b0
--- /dev/null
+++ b/package/libusb/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libusb-1.0.8.orig/ltmain.sh 2010-05-05 00:02:07.000000000 +0200
++++ libusb-1.0.8/ltmain.sh 2011-01-14 19:20:50.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libvirt/Makefile b/package/libvirt/Makefile
index 0db8d6993..03ff483f2 100644
--- a/package/libvirt/Makefile
+++ b/package/libvirt/Makefile
@@ -4,9 +4,9 @@
include ${TOPDIR}/rules.mk
PKG_NAME:= libvirt
-PKG_VERSION:= 0.8.6
+PKG_VERSION:= 0.8.7
PKG_RELEASE:= 1
-PKG_MD5SUM:= 9ed61a02983dc42d0ea0224711ace025
+PKG_MD5SUM:= 596bafb53bb6c079a0703f1726cb2305
PKG_DESCR:= virtualization API
PKG_SECTION:= libs
PKG_DEPENDS:= libxml2 libgnutls python2 libpcap
@@ -28,6 +28,7 @@ CONFIGURE_ARGS+= --without-xen \
--without-openvz \
--without-lxc \
--without-vbox \
+ --without-macvtap \
--disable-silent-rules \
--without-sasl
diff --git a/package/libvirt/patches/patch-build-aux_ltmain_sh b/package/libvirt/patches/patch-build-aux_ltmain_sh
new file mode 100644
index 000000000..356d4e661
--- /dev/null
+++ b/package/libvirt/patches/patch-build-aux_ltmain_sh
@@ -0,0 +1,11 @@
+--- libvirt-0.8.7.orig/build-aux/ltmain.sh 2011-01-04 03:22:29.000000000 +0100
++++ libvirt-0.8.7/build-aux/ltmain.sh 2011-01-15 23:16:47.000000000 +0100
+@@ -5091,7 +5091,7 @@ func_mode_link ()
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libvirt/patches/patch-configure b/package/libvirt/patches/patch-configure
new file mode 100644
index 000000000..87eb324fc
--- /dev/null
+++ b/package/libvirt/patches/patch-configure
@@ -0,0 +1,38 @@
+--- libvirt-0.8.7.orig/configure 2011-01-04 03:22:44.000000000 +0100
++++ libvirt-0.8.7/configure 2011-01-12 18:43:03.000000000 +0100
+@@ -36745,7 +36745,7 @@ $as_echo "$as_me: Found python in enviro
+
+ # Find any Python interpreter.
+ if test -z "$PYTHON"; then
+- for ac_prog in python python2 python3 python3.0 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0
++ for ac_prog in python python2 python3 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0
+ do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+ set dummy $ac_prog; ac_word=$2
+@@ -36920,25 +36920,7 @@ $as_echo "$am_cv_python_pyexecdir" >&6;
+ if test -x "$PYTHON_CONFIG"
+ then
+ PYTHON_INCLUDES=`$PYTHON_CONFIG --includes`
+- else
+- if test -r $PYTHON_EXEC_PREFIX/include/python$PYTHON_VERSION/Python.h
+- then
+- PYTHON_INCLUDES=-I$PYTHON_EXEC_PREFIX/include/python$PYTHON_VERSION
+- else
+- if test -r $prefix/include/python$PYTHON_VERSION/Python.h
+- then
+- PYTHON_INCLUDES=-I$prefix/include/python$PYTHON_VERSION
+- else
+- if test -r /usr/include/python$PYTHON_VERSION/Python.h
+- then
+- PYTHON_INCLUDES=-I/usr/include/python$PYTHON_VERSION
+- else
+- { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find python$PYTHON_VERSION/Python.h, disabling bindings" >&5
+-$as_echo "$as_me: Could not find python$PYTHON_VERSION/Python.h, disabling bindings" >&6;}
+- with_python=no
+- fi
+- fi
+- fi
++ echo "DEBUG: $PYTHON_CONFIG"
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find python interpreter, disabling bindings" >&5
diff --git a/package/libvirt/patches/patch-libvirt_pc b/package/libvirt/patches/patch-libvirt_pc
new file mode 100644
index 000000000..a46fcce14
--- /dev/null
+++ b/package/libvirt/patches/patch-libvirt_pc
@@ -0,0 +1,9 @@
+--- libvirt-0.8.7.orig/libvirt.pc 2011-01-04 03:23:23.000000000 +0100
++++ libvirt-0.8.7/libvirt.pc 2011-01-12 18:31:53.000000000 +0100
+@@ -7,5 +7,5 @@ Name: libvirt
+ Version: 0.8.7
+ Description: libvirt library
+ Requires:
+-Libs: -L${libdir} -lvirt -ldl
++Libs: -L${libdir} -lvirt -lintl
+ Cflags: -I${includedir}
diff --git a/package/libvirt/patches/patch-src_storage_storage_backend_c b/package/libvirt/patches/patch-src_storage_storage_backend_c
index bab29e4bb..7a1713e7b 100644
--- a/package/libvirt/patches/patch-src_storage_storage_backend_c
+++ b/package/libvirt/patches/patch-src_storage_storage_backend_c
@@ -1,6 +1,6 @@
---- libvirt-0.7.4.orig/src/storage/storage_backend.c 2009-11-10 14:32:15.000000000 +0100
-+++ libvirt-0.7.4/src/storage/storage_backend.c 2009-11-23 22:51:40.000000000 +0100
-@@ -136,7 +136,7 @@ virStorageBackendCopyToFD(virConnectPtr
+--- libvirt-0.8.7.orig/src/storage/storage_backend.c 2010-12-22 09:54:05.000000000 +0100
++++ libvirt-0.8.7/src/storage/storage_backend.c 2011-01-12 18:30:49.000000000 +0100
+@@ -131,7 +131,7 @@ virStorageBackendCopyToFD(virStorageVolD
goto cleanup;
}
@@ -8,4 +8,4 @@
+ memset(&zerobuf, 0, sizeof(zerobuf));
if (VIR_ALLOC_N(buf, bytes) < 0) {
- virReportOOMError(conn);
+ ret = -errno;
diff --git a/package/libvorbis/Makefile b/package/libvorbis/Makefile
index 484ffa867..a980c64a7 100644
--- a/package/libvorbis/Makefile
+++ b/package/libvorbis/Makefile
@@ -23,19 +23,17 @@ $(eval $(call PKG_template,LIBVORBIS,libvorbis,${PKG_VERSION}-${PKG_RELEASE},${P
$(eval $(call PKG_template,LIBVORBISENC,libvorbisenc,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,LIBVORBIS_DEV,libvorbis-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_LIBVORBIS_DEV},${PKGSC_LIBVORBIS_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBVORBIS_DEV}+= libvorbis-dev-install
-
CONFIGURE_ENV+= LIBS="-lm -logg"
CONFIGURE_ARGS+= --with-ogg="${STAGING_TARGET_DIR}/usr" \
--with-ogg-includes="${STAGING_TARGET_DIR}/usr/include" \
--with-ogg-libraries="${STAGING_TARGET_DIR}/usr/lib"
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBVORBIS}/usr/lib
${CP} ${WRKINST}/usr/lib/libvorbis.so* ${IDIR_LIBVORBIS}/usr/lib/
${CP} ${WRKINST}/usr/lib/libvorbisfile.so* ${IDIR_LIBVORBIS}/usr/lib/
+
+libvorbisenc-install:
${INSTALL_DIR} ${IDIR_LIBVORBISENC}/usr/lib
${CP} ${WRKINST}/usr/lib/libvorbisenc.so* ${IDIR_LIBVORBISENC}/usr/lib/
diff --git a/package/libvorbis/patches/patch-ltmain_sh b/package/libvorbis/patches/patch-ltmain_sh
new file mode 100644
index 000000000..c3d5bdd93
--- /dev/null
+++ b/package/libvorbis/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libvorbis-1.2.0.orig/ltmain.sh 2006-06-19 21:29:20.000000000 +0200
++++ libvorbis-1.2.0/ltmain.sh 2011-01-15 21:27:10.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libvorbisidec/patches/autotool.patch b/package/libvorbisidec/patches/autotool.patch
index 830eb2e92..584000165 100644
--- a/package/libvorbisidec/patches/autotool.patch
+++ b/package/libvorbisidec/patches/autotool.patch
@@ -31435,7 +31435,7 @@ diff -Nur libvorbisidec-1.0.2+svn15687.orig/ltmain.sh libvorbisidec-1.0.2+svn156
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
-+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libxkbfile/patches/patch-ltmain_sh b/package/libxkbfile/patches/patch-ltmain_sh
new file mode 100644
index 000000000..74e4b6fba
--- /dev/null
+++ b/package/libxkbfile/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libxkbfile-1.0.6.orig/ltmain.sh 2009-09-11 16:54:52.000000000 +0200
++++ libxkbfile-1.0.6/ltmain.sh 2011-01-15 23:25:15.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libxml2/patches/patch-ltmain_sh b/package/libxml2/patches/patch-ltmain_sh
new file mode 100644
index 000000000..e6279239d
--- /dev/null
+++ b/package/libxml2/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libxml2-2.7.6.orig/ltmain.sh 2009-10-06 18:39:54.000000000 +0200
++++ libxml2-2.7.6/ltmain.sh 2011-01-14 00:34:35.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/libxslt/patches/patch-libexslt_Makefile_in b/package/libxslt/patches/patch-libexslt_Makefile_in
new file mode 100644
index 000000000..53165a669
--- /dev/null
+++ b/package/libxslt/patches/patch-libexslt_Makefile_in
@@ -0,0 +1,11 @@
+--- libxslt-1.1.24.orig/libexslt/Makefile.in 2008-05-13 17:52:13.000000000 +0200
++++ libxslt-1.1.24/libexslt/Makefile.in 2011-01-11 17:04:29.000000000 +0100
+@@ -247,7 +247,7 @@ top_builddir = @top_builddir@
+ top_srcdir = @top_srcdir@
+ INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/libxslt -I$(top_srcdir)/libexslt \
+ -I$(top_builddir) -I$(top_builddir)/libxslt \
+- -I$(top_builddir)/libexslt $(LIBXML_CFLAGS) $(CFLAGS)
++ -I$(top_builddir)/libexslt $(LIBXML_CFLAGS)
+
+ AM_CFLAGS = $(LIBGCRYPT_CFLAGS)
+ lib_LTLIBRARIES = libexslt.la
diff --git a/package/libxslt/patches/patch-ltmain_sh b/package/libxslt/patches/patch-ltmain_sh
new file mode 100644
index 000000000..0c416e0cb
--- /dev/null
+++ b/package/libxslt/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- libxslt-1.1.24.orig/ltmain.sh 2007-08-29 14:28:46.000000000 +0200
++++ libxslt-1.1.24/ltmain.sh 2011-01-15 21:29:56.000000000 +0100
+@@ -1663,7 +1663,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/libxslt/patches/patch-xsltproc_Makefile_in b/package/libxslt/patches/patch-xsltproc_Makefile_in
new file mode 100644
index 000000000..3802ce0fa
--- /dev/null
+++ b/package/libxslt/patches/patch-xsltproc_Makefile_in
@@ -0,0 +1,11 @@
+--- libxslt-1.1.24.orig/xsltproc/Makefile.in 2008-05-13 17:52:15.000000000 +0200
++++ libxslt-1.1.24/xsltproc/Makefile.in 2011-01-11 17:06:56.000000000 +0100
+@@ -234,7 +234,7 @@ top_builddir = @top_builddir@
+ top_srcdir = @top_srcdir@
+ INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/libxslt -I$(top_srcdir)/libexslt \
+ -I$(top_builddir) -I$(top_builddir)/libxslt \
+- -I$(top_builddir)/libexslt $(LIBXML_CFLAGS) $(CFLAGS)
++ -I$(top_builddir)/libexslt $(LIBXML_CFLAGS)
+
+ AM_CFLAGS = $(LIBGCRYPT_CFLAGS)
+ xsltproc_SOURCES = xsltproc.c
diff --git a/package/lighttpd/patches/patch-ltmain_sh b/package/lighttpd/patches/patch-ltmain_sh
new file mode 100644
index 000000000..3d6b6bde5
--- /dev/null
+++ b/package/lighttpd/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- lighttpd-1.4.25.orig/ltmain.sh 2009-11-21 16:12:15.000000000 +0100
++++ lighttpd-1.4.25/ltmain.sh 2011-01-15 23:27:09.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/links/Makefile b/package/links/Makefile
index 33be6b148..462d4746b 100644
--- a/package/links/Makefile
+++ b/package/links/Makefile
@@ -14,7 +14,7 @@ PKG_BUILDDEP:= openssl libpng jpeg gpm
PKG_URL:= http://links.twibright.com/
PKG_SITES:= http://links.twibright.com/download/
-PKG_FLAVOURS:= WITH_DIRECTFB
+PKG_FLAVOURS_LINKS:= WITH_DIRECTFB
PKGFD_WITH_DIRECTFB:= enable DirectFB video output support
PKGFS_WITH_DIRECTFB:= directfb
PKGFB_WITH_DIRECTFB:= DirectFB
diff --git a/package/linux-atm/patches/patch-ltmain_sh b/package/linux-atm/patches/patch-ltmain_sh
new file mode 100644
index 000000000..583f17839
--- /dev/null
+++ b/package/linux-atm/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- linux-atm-2.5.1.orig/ltmain.sh 2008-08-30 00:27:10.000000000 +0200
++++ linux-atm-2.5.1/ltmain.sh 2011-01-15 21:47:10.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/logrotate/Makefile b/package/logrotate/Makefile
index 1c7577ac2..884b2d0fb 100644
--- a/package/logrotate/Makefile
+++ b/package/logrotate/Makefile
@@ -18,7 +18,6 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LOGROTATE,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
CONFIG_STYLE:= manual
-
TCFLAGS+= -D_GNU_SOURCE -DVERSION=\"$(PKG_VERSION)\"
post-install:
diff --git a/package/logrotate/patches/patch-Makefile b/package/logrotate/patches/patch-Makefile
index 2b348b75f..755e612b1 100644
--- a/package/logrotate/patches/patch-Makefile
+++ b/package/logrotate/patches/patch-Makefile
@@ -1,6 +1,6 @@
--- logrotate-3.7.8.orig/Makefile 2008-05-19 12:25:54.000000000 +0200
-+++ logrotate-3.7.8/Makefile 2010-02-06 00:00:58.853084930 +0100
-@@ -1,7 +1,7 @@
++++ logrotate-3.7.8/Makefile 2011-01-15 23:45:59.000000000 +0100
+@@ -1,10 +1,10 @@
VERSION = $(shell awk '/Version:/ { print $$2 }' logrotate.spec)
-OS_NAME = $(shell uname -s)
+OS_NAME = Linux
@@ -9,8 +9,32 @@
+CFLAGS ?= -Wall -D_GNU_SOURCE -D$(OS_NAME) -DVERSION=\"$(VERSION)\" $(RPM_OPT_FLAGS) $(LFS)
PROG = logrotate
MAN = logrotate.8
- LOADLIBES = -lpopt
-@@ -96,16 +96,16 @@ test: $(TARGET)
+-LOADLIBES = -lpopt
++LIBS = -lpopt
+ SVNURL= svn+ssh://svn.fedorahosted.org/svn/logrotate
+ SVNPUBURL = http://svn.fedorahosted.org/svn/logrotate
+ SVNTAG = r$(subst .,-,$(VERSION))
+@@ -68,10 +68,7 @@ MANDIR = $(BASEDIR)/man
+ OBJS = logrotate.o log.o config.o basenames.o
+ SOURCES = $(subst .o,.c,$(OBJS) $(LIBOBJS))
+
+-ifeq ($(RPM_OPT_FLAGS),)
+-CFLAGS += -g
+-LDFLAGS = -g
+-endif
++LDFLAGS ?=
+
+ ifeq (.depend,$(wildcard .depend))
+ TARGET=$(PROG)
+@@ -84,6 +81,7 @@ RCSVERSION = $(subst .,-,$(VERSION))
+ all: $(TARGET)
+
+ $(PROG): $(OBJS)
++ $(CC) $(LDFLAGS) -o $(PROG) $^ $(LIBS)
+
+ clean:
+ rm -f $(OBJS) $(PROG) core* .depend
+@@ -96,16 +94,16 @@ test: $(TARGET)
(cd test; ./test)
install:
diff --git a/package/lsof/Makefile b/package/lsof/Makefile
index 8f0706031..8bad858ae 100644
--- a/package/lsof/Makefile
+++ b/package/lsof/Makefile
@@ -5,17 +5,16 @@ include $(TOPDIR)/rules.mk
PKG_NAME:= lsof
PKG_VERSION:= 4.84
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= 6dae655988c810a7042c06a4e2fa3c5f
PKG_DESCR:= list open files
PKG_SECTION:= misc
PKG_URL:= http://people.freebsd.org/~abe/
PKG_SITES:= ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/
-PKG_HOST_DEPENDS:= !darwin
-
DISTFILES:= ${PKG_NAME}_${PKG_VERSION}.tar.gz
-WRKDIST= ${WRKDIR}/${PKG_NAME}_${PKG_VERSION}/${PKG_NAME}_${PKG_VERSION}_src
+WRKDIST= ${WRKDIR}/${PKG_NAME}_${PKG_VERSION}
+WRKSRC= ${WRKDIR}/${PKG_NAME}_${PKG_VERSION}/${PKG_NAME}_${PKG_VERSION}_src
include $(TOPDIR)/mk/package.mk
@@ -24,7 +23,7 @@ $(eval $(call PKG_template,LSOF,$(PKG_NAME),$(PKG_VERSION)-${PKG_RELEASE},${PKG_
CONFIG_STYLE:= minimal
CONFIGURE_PROG:= Configure
CONFIGURE_ARGS:= -n linux
-XAKE_FLAGS+= CC='${TARGET_CC}'
+XAKE_FLAGS+= CC='${TARGET_CC}' CFLAGS='${TARGET_CFLAGS}' CFGL='${TARGET_LDFLAGS} -L./lib -llsof'
INSTALL_STYLE:= manual
post-extract:
diff --git a/package/lsof/patches/patch-Configure b/package/lsof/patches/patch-Configure
deleted file mode 100644
index e99001293..000000000
--- a/package/lsof/patches/patch-Configure
+++ /dev/null
@@ -1,30 +0,0 @@
---- lsof_4.84_src.orig/Configure 2010-07-29 17:59:32.000000000 +0200
-+++ lsof_4.84_src/Configure 2010-10-07 20:03:14.000000000 +0200
-@@ -2739,27 +2739,6 @@ return(0); }
- then
- LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
- fi # }
--
-- # Test for SELinux support.
--
-- LSOF_TMP1=0
-- if test "X$LINUX_HASSELINUX" = "X" # {
-- then
-- if test -r ${LSOF_INCLUDE}/selinux/selinux.h # {
-- then
-- LSOF_TMP1=1
-- fi # }
-- else
-- if test "X$LINUX_HASSELINUX" = "XY" -o "X$LINUX_HASSELINUX" = "Xy" # {
-- then
-- LSOF_TMP1=1
-- fi # }
-- fi # }
-- if test $LSOF_TMP1 -eq 1 # {
-- then
-- LSOF_CFGF="$LSOF_CFGF -DHASSELINUX"
-- LSOF_CFGL="$LSOF_CFGL -lselinux"
-- fi # }
- LSOF_DIALECT_DIR="linux"
- LSOF_CFGF="$LSOF_CFGF -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE"
- ;;
diff --git a/package/lsof/patches/patch-lsof_4_84_src_Configure b/package/lsof/patches/patch-lsof_4_84_src_Configure
new file mode 100644
index 000000000..b1ca02fef
--- /dev/null
+++ b/package/lsof/patches/patch-lsof_4_84_src_Configure
@@ -0,0 +1,17 @@
+--- lsof_4.84.orig/lsof_4.84_src/Configure 2010-07-29 17:59:32.000000000 +0200
++++ lsof_4.84/lsof_4.84_src/Configure 2011-01-15 23:57:34.000000000 +0100
+@@ -5357,12 +5357,12 @@ then
+ if test "X$LSOF_RANLIB" != "X" # {
+ then
+ echo "" >> ${LSOF_LIB}/$LSOF_LIBMKF
+- echo "RANLIB= $LSOF_RANLIB \${LIB}" >> ${LSOF_LIB}/$LSOF_LIBMKF
++ echo "RANLIB?= $LSOF_RANLIB" >> ${LSOF_LIB}/$LSOF_LIBMKF
+ fi # }
+ echo "" >> ${LSOF_LIB}/$LSOF_LIBMKF
+ if test "X$LSOF_CFLAGS_OVERRIDE" = "X" # {
+ then
+- echo "CFLAGS= \${CDEFS} \${INCL} \${DEBUG}" >> ${LSOF_LIB}/$LSOF_LIBMKF
++ echo "CFLAGS?= \${CDEFS} \${INCL} \${DEBUG}" >> ${LSOF_LIB}/$LSOF_LIBMKF
+ else
+ echo "override CFLAGS=\${CDEFS} \${INCL} \${DEBUG}" >> ${LSOF_LIB}/$LSOF_LIBMKF
+ fi # }
diff --git a/package/lsof/patches/patch-dialects_linux_dlsof_h b/package/lsof/patches/patch-lsof_4_84_src_dialects_linux_dlsof_h
index 1b6314849..b15a001b1 100644
--- a/package/lsof/patches/patch-dialects_linux_dlsof_h
+++ b/package/lsof/patches/patch-lsof_4_84_src_dialects_linux_dlsof_h
@@ -1,5 +1,5 @@
---- lsof_4.84_src.orig/dialects/linux/dlsof.h 2010-01-18 20:03:19.000000000 +0100
-+++ lsof_4.84_src/dialects/linux/dlsof.h 2010-10-07 20:35:57.000000000 +0200
+--- lsof_4.84.orig/lsof_4.84_src/dialects/linux/dlsof.h 2010-01-18 20:03:19.000000000 +0100
++++ lsof_4.84/lsof_4.84_src/dialects/linux/dlsof.h 2011-01-16 00:01:43.000000000 +0100
@@ -49,13 +49,7 @@
#include <setjmp.h>
#include <unistd.h>
diff --git a/package/lsof/patches/patch-dialects_linux_machine_h b/package/lsof/patches/patch-lsof_4_84_src_dialects_linux_machine_h
index 011144644..6066b38d8 100644
--- a/package/lsof/patches/patch-dialects_linux_machine_h
+++ b/package/lsof/patches/patch-lsof_4_84_src_dialects_linux_machine_h
@@ -1,5 +1,5 @@
---- lsof_4.84_src.orig/dialects/linux/machine.h 2010-07-29 18:02:52.000000000 +0200
-+++ lsof_4.84_src/dialects/linux/machine.h 2010-10-07 20:03:14.000000000 +0200
+--- lsof_4.84.orig/lsof_4.84_src/dialects/linux/machine.h 2010-07-29 18:02:52.000000000 +0200
++++ lsof_4.84/lsof_4.84_src/dialects/linux/machine.h 2011-01-16 00:01:48.000000000 +0100
@@ -632,6 +632,6 @@
* zeromem is a macro that uses bzero or memset.
*/
diff --git a/package/lsof/patches/patch-lsof_4_84_src_lib_Makefile_skel b/package/lsof/patches/patch-lsof_4_84_src_lib_Makefile_skel
new file mode 100644
index 000000000..8cada0635
--- /dev/null
+++ b/package/lsof/patches/patch-lsof_4_84_src_lib_Makefile_skel
@@ -0,0 +1,11 @@
+--- lsof_4.84.orig/lsof_4.84_src/lib/Makefile.skel 2001-02-13 03:12:22.000000000 +0100
++++ lsof_4.84/lsof_4.84_src/lib/Makefile.skel 2011-01-15 23:58:50.000000000 +0100
+@@ -22,7 +22,7 @@ all: ${LIB}
+
+ ${LIB}: ${OBJ}
+ ${AR}
+- ${RANLIB}
++ ${RANLIB} ${LIB}
+
+ clean: FRC
+ rm -f ${LIB} ${OBJ} errs Makefile.bak a.out core
diff --git a/package/lvm/Makefile b/package/lvm/Makefile
index b45a262e1..67ae4d6cc 100644
--- a/package/lvm/Makefile
+++ b/package/lvm/Makefile
@@ -4,9 +4,9 @@
include ${TOPDIR}/rules.mk
PKG_NAME:= lvm
-PKG_VERSION:= 2.02.79
+PKG_VERSION:= 2.02.80
PKG_RELEASE:= 1
-PKG_MD5SUM:= e6929251a90b0b626c024942a242f337
+PKG_MD5SUM:= 816f4cee75674e3a21fd40f1961279f2
PKG_DESCR:= logical volume management
PKG_SECTION:= fs
PKG_DEPENDS:= libdevmapper libncurses
@@ -31,15 +31,16 @@ CONFIGURE_ARGS+= --with-user="" --with-group="" \
--with-optimisation="" \
--with-lvm1=none
-post-install:
- # lvm
+lvm-install:
${INSTALL_DIR} ${IDIR_LVM}/usr/sbin
${INSTALL_BIN} ${WRKINST}/usr/sbin/lvm ${IDIR_LVM}/usr/sbin/lvm
- # libdevmapper
+
+libdevmapper-install:
${INSTALL_DIR} ${IDIR_LIBDEVMAPPER}/usr/lib
${CP} ${WRKINST}/usr/lib/libdevmapper.so* \
${IDIR_LIBDEVMAPPER}/usr/lib
- # device-mapper
+
+device-mapper-install:
${INSTALL_DIR} ${IDIR_DEVICE_MAPPER}/usr/sbin
${INSTALL_BIN} ${WRKINST}/usr/sbin/dmsetup \
${IDIR_DEVICE_MAPPER}/usr/sbin
diff --git a/package/lvm/patches/patch-Makefile_in b/package/lvm/patches/patch-Makefile_in
new file mode 100644
index 000000000..22b0626e5
--- /dev/null
+++ b/package/lvm/patches/patch-Makefile_in
@@ -0,0 +1,20 @@
+--- LVM2.2.02.79.orig/Makefile.in 2010-11-22 22:39:47.000000000 +0100
++++ LVM2.2.02.79/Makefile.in 2011-01-07 20:54:18.000000000 +0100
+@@ -16,7 +16,7 @@ srcdir = @srcdir@
+ top_srcdir = @top_srcdir@
+ top_builddir = @top_builddir@
+
+-SUBDIRS = doc include man scripts
++SUBDIRS = include man scripts
+
+ ifeq ("@UDEV_RULES@", "yes")
+ SUBDIRS += udev
+@@ -33,7 +33,7 @@ ifeq ("@APPLIB@", "yes")
+ endif
+
+ ifeq ($(MAKECMDGOALS),distclean)
+- SUBDIRS = doc include man scripts \
++ SUBDIRS = include man scripts \
+ lib tools daemons libdm \
+ udev po liblvm test/api test
+ endif
diff --git a/package/lvm/patches/patch-make_tmpl_in b/package/lvm/patches/patch-make_tmpl_in
index 43bd07008..f5286dfa4 100644
--- a/package/lvm/patches/patch-make_tmpl_in
+++ b/package/lvm/patches/patch-make_tmpl_in
@@ -1,5 +1,14 @@
---- LVM2.2.02.79.orig/make.tmpl.in 2010-11-05 17:18:38.000000000 +0100
-+++ LVM2.2.02.79/make.tmpl.in 2010-12-26 22:15:11.000000000 +0100
+--- LVM2.2.02.80.orig/make.tmpl.in 2011-01-10 14:00:53.000000000 +0100
++++ LVM2.2.02.80/make.tmpl.in 2011-01-11 11:39:53.000000000 +0100
+@@ -33,7 +33,7 @@ LIBS = @LIBS@
+ # Extra libraries always linked with static binaries
+ STATIC_LIBS = $(SELINUX_LIBS) $(UDEV_LIBS)
+ DEFS += @DEFS@
+-CFLAGS += @CFLAGS@
++CFLAGS = @CFLAGS@
+ CLDFLAGS += @CLDFLAGS@
+ LDDEPS += @LDDEPS@
+ LDFLAGS += @LDFLAGS@
@@ -322,7 +322,8 @@ $(LIB_SHARED): $(LIB_SHARED).$(LIB_VERSI
$(LN_S) -f $(<F) $@
diff --git a/package/microperl/patches/patch-Makefile_micro b/package/microperl/patches/patch-Makefile_micro
index 38cedeff7..01bca8bdc 100644
--- a/package/microperl/patches/patch-Makefile_micro
+++ b/package/microperl/patches/patch-Makefile_micro
@@ -1,6 +1,15 @@
$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
--- perl-5.10.0.orig/Makefile.micro 2007-12-18 11:47:07.000000000 +0100
-+++ perl-5.10.0/Makefile.micro 2009-09-14 18:52:23.000000000 +0200
++++ perl-5.10.0/Makefile.micro 2011-01-16 00:16:05.000000000 +0100
+@@ -3,7 +3,7 @@ CCFLAGS = -c
+ DEFINES = -DPERL_CORE -DPERL_MICRO -DSTANDARD_C -DPERL_USE_SAFE_PUTENV
+ OPTIMIZE =
+ CFLAGS = $(DEFINES) $(OPTIMIZE)
+-LDFLAGS =
++LDFLAGS ?=
+ LIBS = -lm
+ _O = .o
+ ENV = env
@@ -46,7 +46,7 @@ Config = '$$Config{$$1}'
patch_uconfig:
$(PERL) -MConfig -pi -e "s/^((?:short|int|long(?:dbl|long)?|ptr|double|[iun]v|u?quad|[iu]\d+|fpos|lseek)(?:size|type)|byteorder|d_quad|quadkind|use64.+)=.*/\\1='"$(Config)"'/g" uconfig.shx
diff --git a/package/miredo/patches/patch-admin_ltmain_sh b/package/miredo/patches/patch-admin_ltmain_sh
new file mode 100644
index 000000000..af6e9f095
--- /dev/null
+++ b/package/miredo/patches/patch-admin_ltmain_sh
@@ -0,0 +1,11 @@
+--- miredo-1.2.3.orig/admin/ltmain.sh 2009-12-10 00:55:19.000000000 +0100
++++ miredo-1.2.3/admin/ltmain.sh 2011-01-16 00:19:27.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/mksh/Makefile b/package/mksh/Makefile
index 7ace9de29..84dee864e 100644
--- a/package/mksh/Makefile
+++ b/package/mksh/Makefile
@@ -12,7 +12,7 @@ PKG_SECTION:= shells
PKG_URL:= http://www.mirbsd.org/
PKG_SITES:= ${MASTER_SITE_MIRBSD:distfiles/=dist/mir/mksh/}
-PKG_FLAVOURS:= FULL
+PKG_FLAVOURS_MKSH:= FULL
PKGFD_FULL:= Include all features
DISTFILES= ${PKG_NAME}-R${PKG_VERSION}.cpio.gz
diff --git a/package/moc/patches/patch-ltmain_sh b/package/moc/patches/patch-ltmain_sh
new file mode 100644
index 000000000..b9a79ecd3
--- /dev/null
+++ b/package/moc/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- moc-2.5.0-alpha4.orig/ltmain.sh 2009-09-25 10:57:23.000000000 +0200
++++ moc-2.5.0-alpha4/ltmain.sh 2011-01-16 00:22:15.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/mpd/Makefile b/package/mpd/Makefile
index 522b804b6..b211386b0 100644
--- a/package/mpd/Makefile
+++ b/package/mpd/Makefile
@@ -14,9 +14,9 @@ PKG_BUILDDEP:= glib
PKG_URL:= http://mpd.wikia.com/wiki/Music_Player_Daemon_Wiki
PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=musicpd/}
-PKG_FLAVOURS:= WITH_ALSA WITH_AO WITH_MP3 WITH_MP4 WITH_TREMOR
-PKG_FLAVOURS+= WITH_OGG WITH_FLAC WITH_WAV WITH_MMS WITH_FFMPEG
-PKG_FLAVOURS+= WITH_SHOUT WITH_CURL
+PKG_FLAVOURS_MPD:= WITH_ALSA WITH_AO WITH_MP3 WITH_MP4 WITH_TREMOR
+PKG_FLAVOURS_MPD+= WITH_OGG WITH_FLAC WITH_WAV WITH_MMS WITH_FFMPEG
+PKG_FLAVOURS_MPD+= WITH_SHOUT WITH_CURL
PKGFD_WITH_ALSA:= enable ALSA output
PKGFS_WITH_ALSA:= alsa-lib
diff --git a/package/mpfr/patches/patch-ltmain_sh b/package/mpfr/patches/patch-ltmain_sh
new file mode 100644
index 000000000..117f89c34
--- /dev/null
+++ b/package/mpfr/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- mpfr-2.4.2.orig/ltmain.sh 2009-11-30 03:43:54.000000000 +0100
++++ mpfr-2.4.2/ltmain.sh 2011-01-15 14:26:14.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/mpg123/patches/patch-build_ltmain_sh b/package/mpg123/patches/patch-build_ltmain_sh
new file mode 100644
index 000000000..f2c5aadfa
--- /dev/null
+++ b/package/mpg123/patches/patch-build_ltmain_sh
@@ -0,0 +1,11 @@
+--- mpg123-1.12.1.orig/build/ltmain.sh 2010-03-31 10:28:55.000000000 +0200
++++ mpg123-1.12.1/build/ltmain.sh 2011-01-16 00:25:49.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/mplayer/Makefile b/package/mplayer/Makefile
index bad5c656d..21ad00432 100644
--- a/package/mplayer/Makefile
+++ b/package/mplayer/Makefile
@@ -5,7 +5,7 @@ include ${TOPDIR}/rules.mk
PKG_NAME:= mplayer
PKG_VERSION:= 1.0-32749
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= aadc5d8cca503c8b18b3ed00b3a52cf5
PKG_DESCR:= popular video player
PKG_SECTION:= multimedia
@@ -19,7 +19,7 @@ PKG_SITES:= http://openadk.org/distfiles/
PKG_ARCH_DEPENDS:= x86 x86_64 mips mipsel mips64 mips64el
-PKG_FLAVOURS:= WITH_DIRECTFB
+PKG_FLAVOURS_MPLAYER:= WITH_DIRECTFB
PKGFD_WITH_DIRECTFB:= enable DirectFB video output support
PKGFS_WITH_DIRECTFB:= directfb
PKGFB_WITH_DIRECTFB:= DirectFB
@@ -127,7 +127,7 @@ CONFIGURE_ARGS:= --prefix=/usr \
--disable-xinerama \
--disable-vidix \
--disable-gl \
- --extra-cflags="${TCFLAGS} ${EXTRA_CFLAGS}" \
+ --extra-cflags="${EXTRA_CFLAGS}" \
${CONFIGURE_CPU_OPTS} \
${CONFIGURE_DEBUG} \
${CONFIGURE_DIRECTFB}
diff --git a/package/mplayer/patches/patch-configure b/package/mplayer/patches/patch-configure
new file mode 100644
index 000000000..eb33a8720
--- /dev/null
+++ b/package/mplayer/patches/patch-configure
@@ -0,0 +1,11 @@
+--- mplayer-1.0-32749.orig/configure 2011-01-03 11:27:11.000000000 +0100
++++ mplayer-1.0-32749/configure 2011-01-09 00:35:20.000000000 +0100
+@@ -2554,7 +2554,7 @@ else
+ fi
+
+ cflag_check -mno-omit-leaf-frame-pointer && cflags_no_omit_leaf_frame_pointer="-mno-omit-leaf-frame-pointer"
+-cflag_check -MD -MP && DEPFLAGS="-MD -MP $CFLAGS"
++cflag_check -MD -MP && DEPFLAGS="-MD -MP"
+
+
+ if test -n "$LDFLAGS" ; then
diff --git a/package/mrd6/Makefile b/package/mrd6/Makefile
index 745718a2a..1638eaf9e 100644
--- a/package/mrd6/Makefile
+++ b/package/mrd6/Makefile
@@ -11,6 +11,7 @@ PKG_DESCR:= IPv6 multicast routing daemon
PKG_SECTION:= ipv6
PKG_DEPENDS:= kmod-ipv6
PKG_SITES:= http://www.openadk.org/distfiles/
+PKG_NEED_CXX:= 1
PKG_CXX:= MRD6
WRKBUILD= ${WRKSRC}/src
@@ -21,10 +22,15 @@ $(eval $(call PKG_template,MRD6,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_
CONFIG_STYLE:= manual
+LIBRARIES:=-nodefaultlibs -luClibc++
+ifeq ($(ADK_TOOLCHAIN_GCC_USE_SSP),y)
+LIBRARIES+=-lssp -lssp_nonshared
+endif
+
ifeq (${ADK_COMPILE_MRD6_WITH_UCLIBCXX},y)
-TCXXFLAGS+= -fno-builtin -nostdinc++ -nodefaultlibs \
+TCXXFLAGS+= -fno-builtin -nostdinc++ \
-I${STAGING_TARGET_DIR}/usr/include/uClibc++
-TLDFLAGS+= -nodefaultlibs -luClibc++ -shared
+TLDFLAGS+= -shared ${LIBRARIES}
endif
XAKE_FLAGS+= EXTRA_FLAGS="${TCFLAGS}"
diff --git a/package/mysql/patches/patch-configure b/package/mysql/patches/patch-configure
index aad04ff2b..853c31f7f 100644
--- a/package/mysql/patches/patch-configure
+++ b/package/mysql/patches/patch-configure
@@ -1,6 +1,22 @@
--- mysql-5.1.48.orig/configure 2010-06-03 17:54:47.000000000 +0200
-+++ mysql-5.1.48/configure 2010-07-30 11:04:50.000000000 +0200
-@@ -19825,45 +19825,7 @@ fi
++++ mysql-5.1.48/configure 2011-01-15 12:58:47.000000000 +0100
+@@ -19764,15 +19764,6 @@ fi
+
+
+
+-# Enable the abi_check rule only if gcc is available
+-
+-if test "$GCC" != "yes" || expr "$CC" : ".*icc.*"
+-then
+- ABI_CHECK=""
+-else
+- ABI_CHECK="abi_check"
+-fi
+-
+
+
+ # Look for PS usage. We use double dollar-signs in FIND_PROC because this
+@@ -19825,45 +19816,7 @@ fi
$as_echo_n "checking \"how to check if pid exists\"... " >&6; }
PS=$ac_cv_path_PS
# Linux style
@@ -47,7 +63,7 @@
{ $as_echo "$as_me:$LINENO: result: \"$FIND_PROC\"" >&5
$as_echo "\"$FIND_PROC\"" >&6; }
-@@ -48273,197 +48235,14 @@ $as_echo "$as_me: error: unknown endiann
+@@ -48273,197 +48226,14 @@ $as_echo "$as_me: error: unknown endiann
esac
@@ -245,7 +261,7 @@
{ $as_echo "$as_me:$LINENO: checking whether Solaris libc atomic functions are available" >&5
$as_echo_n "checking whether Solaris libc atomic functions are available... " >&6; }
-@@ -48581,101 +48360,6 @@ fi
+@@ -48581,101 +48351,6 @@ fi
done
diff --git a/package/mysql/patches/patch-include_config_h_in b/package/mysql/patches/patch-include_config_h_in
index 8c39a7c51..361a8b651 100644
--- a/package/mysql/patches/patch-include_config_h_in
+++ b/package/mysql/patches/patch-include_config_h_in
@@ -1,11 +1,11 @@
--- mysql-5.1.48.orig/include/config.h.in 2010-06-03 17:54:04.000000000 +0200
-+++ mysql-5.1.48/include/config.h.in 2010-07-12 22:52:37.985862985 +0200
++++ mysql-5.1.48/include/config.h.in 2011-01-15 13:01:30.000000000 +0100
@@ -856,7 +856,7 @@
/* Define to 1 if you have the `strtoull' function. */
#undef HAVE_STRTOULL
-/* Define to 1 if `st_rdev' is member of `struct stat'. */
-+/* Define to 1 if `struct stat' is a member of `st_rdev'. */
++/* Define to 1 if `st_rdev' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_RDEV
/* Define to 1 if your `struct stat' has `st_rdev'. Deprecated, use
diff --git a/package/mysql/patches/patch-ltmain_sh b/package/mysql/patches/patch-ltmain_sh
new file mode 100644
index 000000000..c5cb790cf
--- /dev/null
+++ b/package/mysql/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- mysql-5.1.48.orig/ltmain.sh 2010-06-03 17:54:04.000000000 +0200
++++ mysql-5.1.48/ltmain.sh 2011-01-15 13:03:34.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/nano/Makefile b/package/nano/Makefile
index df45c05d4..af87dd3f1 100644
--- a/package/nano/Makefile
+++ b/package/nano/Makefile
@@ -14,7 +14,7 @@ PKG_BUILDDEP:= ncurses
PKG_URL:= http://www.nano-editor.org/
PKG_SITES:= http://www.nano-editor.org/dist/v2.2/
-PKG_FLAVOURS:= TINY
+PKG_FLAVOURS_NANO:= TINY
PKGFD_TINY:= tiny nano
include ${TOPDIR}/mk/package.mk
diff --git a/package/ncurses/Makefile b/package/ncurses/Makefile
index c1b142dff..975cfa1b7 100644
--- a/package/ncurses/Makefile
+++ b/package/ncurses/Makefile
@@ -16,15 +16,14 @@ PKG_SUBPKGS:= LIBNCURSES LIBNCURSES_DEV
PKGSD_LIBNCURSES_DEV:= development files for libncurses
PKGSC_LIBNCURSES_DEV:= devel
+PKG_FLAVOURS_LIBNCURSES:= FULL_TERMINFO
+PKGFD_FULL_TERMINFO:= install the complete set of terminfo files as provided upstream
+
include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LIBNCURSES,libncurses,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,LIBNCURSES_DEV,libncurses-dev,${PKG_VERSION}-${PKG_RELEASE},libncurses,${PKGSD_LIBNCURSES_DEV},${PKGSC_LIBNCURSES_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBNCURSES_DEV}+= libncurses-dev-install
-
CONFIGURE_ENV+= ac_cv_linux_vers=2
CONFIGURE_ARGS+= --without-cxx \
--without-cxx-binding \
@@ -64,15 +63,18 @@ pre-configure:
find ${WRKBUILD} -name *.o -exec rm {} \;
find ${WRKBUILD} -name *.a -exec rm {} \;
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
# this is installed as libncurses - make libcurses a "link"
rm -f ${WRKINST}/usr/lib/libcurses.so*
echo 'GROUP(-lncurses)' >${WRKINST}/usr/lib/libcurses.so
# libcurses will not show up in the IPKG, only in STAGING_TARGET_DIR
- ${INSTALL_DIR} ${IDIR_LIBNCURSES}/usr/share/terminfo
${INSTALL_DIR} ${IDIR_LIBNCURSES}/usr/lib
${CP} ${WRKINST}/usr/lib/lib{form,menu,ncurses,panel}.so* \
${IDIR_LIBNCURSES}/usr/lib
+ifeq (${ADK_PACKAGE_LIBNCURSES_FULL_TERMINFO},y)
+ ${INSTALL_DIR} ${IDIR_LIBNCURSES}/usr/share
+ ${CP} ${WRKINST}/usr/share/terminfo ${IDIR_LIBNCURSES}/usr/share/
+else
${INSTALL_DIR} ${IDIR_LIBNCURSES}/usr/share/terminfo/
for f in ansi dumb linux screen vt100 vt102 \
rxvt-unicode vt220 xterm xterm-color xterm-xfree86; do \
@@ -80,6 +82,7 @@ post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
${INSTALL_DATA} ${WRKINST}/usr/share/terminfo/*/$$f \
${IDIR_LIBNCURSES}/usr/share/terminfo/$${f:0:1}/$$f; \
done
+endif
libncurses-dev-install:
${INSTALL_DIR} ${IDIR_LIBNCURSES_DEV}/usr/include
diff --git a/package/neon/patches/patch-ltmain_sh b/package/neon/patches/patch-ltmain_sh
new file mode 100644
index 000000000..2655e933d
--- /dev/null
+++ b/package/neon/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- neon-0.29.4.orig/ltmain.sh 2010-10-01 14:35:13.000000000 +0200
++++ neon-0.29.4/ltmain.sh 2011-01-14 21:29:01.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/net-snmp/Makefile b/package/net-snmp/Makefile
index 38e7941c0..d32401d33 100644
--- a/package/net-snmp/Makefile
+++ b/package/net-snmp/Makefile
@@ -4,13 +4,13 @@
include ${TOPDIR}/rules.mk
PKG_NAME:= net-snmp
-PKG_VERSION:= 5.5
-PKG_RELEASE:= 2
-PKG_MD5SUM:= 5b2551e7bd024fbbee84dca22a5f13a1
+PKG_VERSION:= 5.6.1
+PKG_RELEASE:= 1
+PKG_MD5SUM:= b4e30ead5783b0bb1d280172c6095ea4
PKG_DESCR:= SNMP Agent
PKG_SECTION:= net/misc
-PKG_DEPENDS:= libnetsnmp libelf
-PKG_BUILDDEP:= libelf
+PKG_DEPENDS:= libnetsnmp libelf libnl
+PKG_BUILDDEP:= libelf libnl
PKG_URL:= http://www.net-snmp.org/
PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=net-snmp/}
PKG_NOPARALLEL:= 1
@@ -22,7 +22,7 @@ PKGSD_LIBNETSNMP:= SNMP library
PKGSS_LIBNETSNMP:= libelf
PKGSC_LIBNETSNMP:= libs
-PKG_FLAVOURS:= WITH_IPV6
+PKG_FLAVOURS_SNMPD:= WITH_IPV6
PKGFD_WITH_IPV6:= enable IPv6 support
include ${TOPDIR}/mk/package.mk
@@ -33,7 +33,7 @@ $(eval $(call PKG_template,LIBNETSNMP,libnetsnmp,${PKG_VERSION}-${PKG_RELEASE},$
SNMP_TRANSPORTS_INCLUDED:= UDP TCP Callback Unix
SNMP_TRANSPORTS_EXCLUDED:= Alias
-ifneq (${ADK_PACKAGE_NET_SNMP_WITH_IPV6},)
+ifneq (${ADK_PACKAGE_SNMPD_WITH_IPV6},)
SNMP_TRANSPORTS_INCLUDED+= TCPIPv6 UDPIPv6
else
SNMP_TRANSPORTS_EXCLUDED:= TCPIPv6 UDPIPv6
@@ -61,7 +61,7 @@ CONFIGURE_ARGS+= --with-defaults \
--without-rpm \
--without-zlib
-ifneq (${ADK_PACKAGE_NET_SNMP_WITH_IPV6},)
+ifneq (${ADK_PACKAGE_SNMPD_WITH_IPV6},)
CONFIGURE_ARGS+= --enable-ipv6
else
CONFIGURE_ARGS+= --disable-ipv6
@@ -69,13 +69,17 @@ endif
FAKE_FLAGS+= INSTALL_PREFIX="${WRKINST}"
-post-install:
+libnetsnmp-install:
${INSTALL_DIR} ${IDIR_LIBNETSNMP}/usr/lib
${CP} ${WRKINST}/usr/lib/libnetsnmp*.so* ${IDIR_LIBNETSNMP}/usr/lib/
+
+snmpd-install:
${INSTALL_DIR} ${IDIR_SNMPD}/etc/snmp
${INSTALL_DIR} ${IDIR_SNMPD}/usr/sbin
${INSTALL_DATA} ./files/snmpd.conf ${IDIR_SNMPD}/etc/snmp/snmpd.conf
${INSTALL_BIN} ${WRKINST}/usr/sbin/snmpd ${IDIR_SNMPD}/usr/sbin/snmpd
+
+snmp-utils-install:
${INSTALL_DIR} ${IDIR_SNMP_UTILS}/usr/bin
${CP} ${WRKINST}/usr/bin/snmp{get,set,status,test,trap,walk} \
${IDIR_SNMP_UTILS}/usr/bin/
diff --git a/package/net-snmp/patches/patch-agent_mibgroup_mibII_tcpTable_c b/package/net-snmp/patches/patch-agent_mibgroup_mibII_tcpTable_c
new file mode 100644
index 000000000..f0be57e78
--- /dev/null
+++ b/package/net-snmp/patches/patch-agent_mibgroup_mibII_tcpTable_c
@@ -0,0 +1,48 @@
+--- net-snmp-5.6.1.orig/agent/mibgroup/mibII/tcpTable.c 2010-10-20 15:12:08.000000000 +0200
++++ net-snmp-5.6.1/agent/mibgroup/mibII/tcpTable.c 2011-01-12 14:48:14.000000000 +0100
+@@ -33,6 +33,12 @@
+ #include <netlink/netlink.h>
+ #include <netlink/msg.h>
+ #include <linux/inet_diag.h>
++
++/* libnl 2.0 compatibility code */
++#define nl_handle nl_sock
++#define nl_handle_alloc nl_socket_alloc
++#define nl_handle_alloc_cb nl_socket_alloc_cb
++#define nl_handle_destroy nl_socket_free
+ #endif
+
+ #include <net-snmp/net-snmp-includes.h>
+@@ -565,8 +571,8 @@ tcpTable_load_netlink(void)
+ }
+
+ if (nl_connect(nl, NETLINK_INET_DIAG) < 0) {
+- DEBUGMSGTL(("mibII/tcpTable", "Failed to connect to netlink: %s\n", nl_geterror()));
+- snmp_log(LOG_ERR, "snmpd: Couldn't connect to netlink: %s\n", nl_geterror());
++ DEBUGMSGTL(("mibII/tcpTable", "Failed to connect to netlink: %s\n", nl_geterror(1)));
++ snmp_log(LOG_ERR, "snmpd: Couldn't connect to netlink: %s\n", nl_geterror(1));
+ nl_handle_destroy(nl);
+ return -1;
+ }
+@@ -580,8 +586,8 @@ tcpTable_load_netlink(void)
+ nlmsg_append(nm, &req, sizeof(struct inet_diag_req), 0);
+
+ if (nl_send_auto_complete(nl, nm) < 0) {
+- DEBUGMSGTL(("mibII/tcpTable", "nl_send_autocomplete(): %s\n", nl_geterror()));
+- snmp_log(LOG_ERR, "snmpd: nl_send_autocomplete(): %s\n", nl_geterror());
++ DEBUGMSGTL(("mibII/tcpTable", "nl_send_autocomplete(): %s\n", nl_geterror(1)));
++ snmp_log(LOG_ERR, "snmpd: nl_send_autocomplete(): %s\n", nl_geterror(1));
+ nl_handle_destroy(nl);
+ return -1;
+ }
+@@ -593,8 +599,8 @@ tcpTable_load_netlink(void)
+
+ while (running) {
+ if ((len = nl_recv(nl, &peer, &buf, NULL)) <= 0) {
+- DEBUGMSGTL(("mibII/tcpTable", "nl_recv(): %s\n", nl_geterror()));
+- snmp_log(LOG_ERR, "snmpd: nl_recv(): %s\n", nl_geterror());
++ DEBUGMSGTL(("mibII/tcpTable", "nl_recv(): %s\n", nl_geterror(1)));
++ snmp_log(LOG_ERR, "snmpd: nl_recv(): %s\n", nl_geterror(1));
+ nl_handle_destroy(nl);
+ return -1;
+ }
diff --git a/package/nfs-utils/Makefile b/package/nfs-utils/Makefile
index 86c1a9e71..3d55b6260 100644
--- a/package/nfs-utils/Makefile
+++ b/package/nfs-utils/Makefile
@@ -13,7 +13,7 @@ PKG_DEPENDS:= kmod-nfsd portmap
PKG_URL:= http://sourceforge.net/projects/nfs
PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=nfs/}
-PKG_FLAVOURS:= WITH_KERBEROS WITH_TIRPC
+PKG_FLAVOURS_NFS_UTILS:=WITH_KERBEROS WITH_TIRPC
PKGFD_WITH_KERBEROS:= enable Kerberos support (MIT)
PKGFS_WITH_KERBEROS:= libkrb5 libevent libnfsidmap librpcsecgss libcom-err libgssglue
PKGFB_WITH_KERBEROS:= libnfsidmap krb5 libevent libgssglue librpcsecgss
diff --git a/package/nmap/Makefile b/package/nmap/Makefile
index 57f986ea4..14d7110a4 100644
--- a/package/nmap/Makefile
+++ b/package/nmap/Makefile
@@ -13,6 +13,7 @@ PKG_DEPENDS:= libdnet libpcap libpcre
PKG_BUILDDEP:= libdnet libpcap pcre
PKG_URL:= http://nmap.org/
PKG_SITES:= http://download.insecure.org/nmap/dist/
+PKG_NEED_CXX:= 1
PKG_CXX:= NMAP
DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tar.bz2
@@ -21,11 +22,16 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,NMAP,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+LIBRARIES:=-nodefaultlibs -luClibc++ -lgcc -lm
+ifeq ($(ADK_TOOLCHAIN_GCC_USE_SSP),y)
+LIBRARIES+=-lssp -lssp_nonshared
+endif
+
TCPPFLAGS+= -DNOLUA
ifeq ($(ADK_COMPILE_NMAP_WITH_UCLIBCXX),y)
CONFIGURE_ENV+= CXXFLAGS="-fno-threadsafe-statics -fno-builtin -fno-rtti -nostdinc++ \
-I${STAGING_TARGET_DIR}/usr/include/uClibc++" \
- LIBS="-nodefaultlibs -luClibc++ -lgcc -lm"
+ LIBS="${LIBRARIES}"
endif
CONFIGURE_ARGS+= --without-openssl \
--without-zenmap \
diff --git a/package/nut/Makefile b/package/nut/Makefile
index 833f271e7..6af495cb6 100644
--- a/package/nut/Makefile
+++ b/package/nut/Makefile
@@ -12,16 +12,16 @@ PKG_SECTION:= net/misc
PKG_URL:= http://www.networkupstools.org/
PKG_SITES:= http://www.networkupstools.org/source/2.4/
-PKG_FLAVOURS:= SSL SNMP USB
-PKGFD_SNMP:= enable SNMP support
-PKGFS_SNMP:= libnetsnmp
-PKGFB_SNMP:= net-snmp
-PKGFD_USB:= enable USB support
-PKGFS_USB:= libusb
-PKGFB_USB:= libusb
-PKGFD_SSL:= enable SSL support
-PKGFS_SSL:= libopenssl
-PKGFB_SSL:= openssl
+PKG_FLAVOURS_NUT:= WITH_SSL WITH_SNMP WITH_USB
+PKGFD_WITH_SNMP:= enable SNMP support
+PKGFS_WITH_SNMP:= libnetsnmp
+PKGFB_WITH_SNMP:= net-snmp
+PKGFD_WITH_USB:= enable USB support
+PKGFS_WITH_USB:= libusb
+PKGFB_WITH_USB:= libusb
+PKGFD_WITH_SSL:= enable SSL support
+PKGFS_WITH_SSL:= libopenssl
+PKGFB_WITH_SSL:= openssl
include ${TOPDIR}/mk/package.mk
@@ -65,10 +65,10 @@ $(eval $(call DRIVER_template,RHINO,rhino))
CONFIG_DRIVERS=$(shell echo ${DRIVERS_y} | tr ' ' ',')
INSTALL_DRIVERS_tmp=${DRIVERS_y}
-ifneq (${ADK_PACKAGE_NUT_USB},)
+ifneq (${ADK_PACKAGE_NUT_WITH_USB},)
INSTALL_DRIVERS_tmp+= usbhid-ups tripplite_usb
endif
-ifneq (${ADK_PACKAGE_NUT_SNMP},)
+ifneq (${ADK_PACKAGE_NUT_WITH_SNMP},)
INSTALL_DRIVERS_tmp+= snmp-ups
endif
INSTALL_DRIVERS=$(shell echo ${INSTALL_DRIVERS_tmp} | tr ' ' ',')
@@ -79,7 +79,7 @@ CONFIGURE_ARGS+= --with-linux-hiddev=${LINUX_DIR}/include/linux/hiddev.h \
--with-group=0 \
--with-user=0
-ifneq (${ADK_PACKAGE_NUT_SSL},)
+ifneq (${ADK_PACKAGE_NUT_WITH_SSL},)
CONFIGURE_ARGS+= --with-ssl
CONFIGURE_ENV+= CPPFLAGS="${TCPPFLAGS} ${TLDFLAGS}"
MAKE_FLAGS+= SSL_CFLAGS="${TCPPFLAGS}" SSL_LDFLAGS="${TLDFLAGS} -lssl -lcrypto"
@@ -88,11 +88,11 @@ endif
ALL_TARGET:= all
INSTALL_TARGET:= install
-ifneq (${ADK_PACKAGE_NUT_USB},)
+ifneq (${ADK_PACKAGE_NUT_WITH_USB},)
ALL_TARGET+= usb
INSTALL_TARGET+= install-usb
endif
-ifneq (${ADK_PACKAGE_NUT_SNMP},)
+ifneq (${ADK_PACKAGE_NUT_WITH_SNMP},)
ALL_TARGET+= snmp
INSTALL_TARGET+= install-snmp
endif
@@ -108,10 +108,5 @@ post-install:
${INSTALL_BIN} ${WRKINST}/usr/bin/ups{c,cmd,drvctl,log,rw} \
${IDIR_NUT}/usr/bin/
${INSTALL_DATA} ./files/ups{d,}.conf ${IDIR_NUT}/etc/
-ifneq (${ADK_PACKAGE_NUT_VARDESC},)
- ${INSTALL_DIR} ${IDIR_NUT}/usr/share
- ${INSTALL_DATA} ${WRKINST}/usr/share/cmdvartab \
- ${IDIR_NUT}/usr/share/
-endif
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/nut/patches/patch-ltmain_sh b/package/nut/patches/patch-ltmain_sh
new file mode 100644
index 000000000..806117687
--- /dev/null
+++ b/package/nut/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- nut-2.4.1.orig/ltmain.sh 2009-02-17 10:23:41.000000000 +0100
++++ nut-2.4.1/ltmain.sh 2011-01-16 01:03:10.000000000 +0100
+@@ -4238,7 +4238,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/obexftp/patches/patch-ltmain_sh b/package/obexftp/patches/patch-ltmain_sh
new file mode 100644
index 000000000..2f96170e4
--- /dev/null
+++ b/package/obexftp/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- obexftp-0.23.orig/ltmain.sh 2008-02-08 01:54:46.000000000 +0100
++++ obexftp-0.23/ltmain.sh 2011-01-16 13:40:07.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/opencdk/patches/patch-build-aux_ltmain_sh b/package/opencdk/patches/patch-build-aux_ltmain_sh
new file mode 100644
index 000000000..a47e789b4
--- /dev/null
+++ b/package/opencdk/patches/patch-build-aux_ltmain_sh
@@ -0,0 +1,11 @@
+--- opencdk-0.6.6.orig/build-aux/ltmain.sh 2006-03-11 19:49:04.000000000 +0100
++++ opencdk-0.6.6/build-aux/ltmain.sh 2011-01-15 19:36:27.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/opencdk/patches/patch-configure b/package/opencdk/patches/patch-configure
index 6fc79ec8d..8f21990e8 100644
--- a/package/opencdk/patches/patch-configure
+++ b/package/opencdk/patches/patch-configure
@@ -1,7 +1,7 @@
$Id$
---- opencdk-0.6.4.orig/configure Mon Jun 11 10:25:19 2007
-+++ opencdk-0.6.4/configure Thu Sep 6 15:42:04 2007
-@@ -20379,8 +20379,8 @@ echo "$as_me: error:
+--- opencdk-0.6.6.orig/configure 2007-11-13 13:32:19.000000000 +0100
++++ opencdk-0.6.6/configure 2011-01-15 19:30:41.000000000 +0100
+@@ -20389,8 +20389,8 @@ echo "$as_me: error:
diff --git a/package/opencdk/patches/patch-ltmain_sh b/package/opencdk/patches/patch-ltmain_sh
new file mode 100644
index 000000000..213194a88
--- /dev/null
+++ b/package/opencdk/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- opencdk-0.6.6.orig/ltmain.sh 2006-03-11 19:49:04.000000000 +0100
++++ opencdk-0.6.6/ltmain.sh 2011-01-15 19:31:50.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/openct/Makefile b/package/openct/Makefile
index 1164c4a13..b2e5e8a79 100644
--- a/package/openct/Makefile
+++ b/package/openct/Makefile
@@ -27,11 +27,7 @@ $(eval $(call PKG_template,OPENCT,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PK
$(eval $(call PKG_template,LIBOPENCT,libopenct,${PKG_VERSION}-${PKG_RELEASE},${PKGSS_LIBOPENCT},${PKGSD_LIBOPENCT},${PKGSC_LIBOPENCT}))
$(eval $(call PKG_template,LIBOPENCT_DEV,libopenct-dev,${PKG_VERSION}-${PKG_RELEASE},,${PKGSD_LIBOPENCT_DEV},${PKGSC_LIBOPENCT_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBOPENCT_DEV}+= libopenct-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_OPENCT}/etc ${IDIR_OPENCT}/usr/{sbin,bin}
${INSTALL_BIN} ${WRKINST}/usr/sbin/openct-control \
${IDIR_OPENCT}/usr/sbin
diff --git a/package/openct/patches/patch-ltmain_sh b/package/openct/patches/patch-ltmain_sh
new file mode 100644
index 000000000..54653d706
--- /dev/null
+++ b/package/openct/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- openct-0.6.20.orig/ltmain.sh 2010-02-16 10:03:04.000000000 +0100
++++ openct-0.6.20/ltmain.sh 2011-01-16 13:43:14.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/openldap/Makefile b/package/openldap/Makefile
index 8b53713cb..937c32bc7 100644
--- a/package/openldap/Makefile
+++ b/package/openldap/Makefile
@@ -24,8 +24,8 @@ PKGSC_OPENLDAP_SLAPD:= net/misc
DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tgz
-PKG_FLAVOURS:= WITH_IPV6
-PKGFD_WITH_IPV6:= enable IPv6 support
+PKG_FLAVOURS_OPENLDAP_SLAPD:= WITH_IPV6
+PKGFD_WITH_IPV6:= enable IPv6 support
include ${TOPDIR}/mk/package.mk
@@ -50,7 +50,7 @@ PKG_CONFIGURE_OPTIONS+= --enable-slapd \
--with-tls \
--with-yielding_select="yes" \
-ifneq (${ADK_PACKAGE_OPENLDAP_WITH_IPV6},)
+ifneq (${ADK_PACKAGE_OPENLDAP_SLAPD_WITH_IPV6},)
CONFIGURE_ARGS+= --enable-ipv6
else
CONFIGURE_ARGS+= --disable-ipv6
diff --git a/package/openldap/patches/patch-build_ltmain_sh b/package/openldap/patches/patch-build_ltmain_sh
new file mode 100644
index 000000000..5876849e1
--- /dev/null
+++ b/package/openldap/patches/patch-build_ltmain_sh
@@ -0,0 +1,11 @@
+--- openldap-2.4.23.orig/build/ltmain.sh 2010-04-13 22:22:21.000000000 +0200
++++ openldap-2.4.23/build/ltmain.sh 2011-01-15 12:35:41.000000000 +0100
+@@ -1668,7 +1668,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/openobex/patches/patch-ltmain_sh b/package/openobex/patches/patch-ltmain_sh
new file mode 100644
index 000000000..7772f428f
--- /dev/null
+++ b/package/openobex/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- openobex-1.5.orig/ltmain.sh 2008-08-30 00:29:24.000000000 +0200
++++ openobex-1.5/ltmain.sh 2011-01-16 01:11:57.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/opensc/Makefile b/package/opensc/Makefile
index 96c3e4138..88a85939e 100644
--- a/package/opensc/Makefile
+++ b/package/opensc/Makefile
@@ -32,14 +32,10 @@ CONFIGURE_ARGS+= --disable-man \
--enable-pcsc \
--enable-openct
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBOPENSC_DEV}+= libopensc-dev-install
-
post-extract:
cd ${WRKBUILD} && autoreconf -vif
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_OPENSC}/usr/bin
${INSTALL_DIR} ${IDIR_OPENSC}/usr/share/opensc
${INSTALL_DATA} ${WRKINST}/usr/share/opensc/* \
diff --git a/package/opensc/patches/patch-ltmain_sh b/package/opensc/patches/patch-ltmain_sh
new file mode 100644
index 000000000..7797c4fcc
--- /dev/null
+++ b/package/opensc/patches/patch-ltmain_sh
@@ -0,0 +1,39 @@
+--- opensc-0.11.13.orig/ltmain.sh 2011-01-16 13:51:11.000000000 +0100
++++ opensc-0.11.13/ltmain.sh 2011-01-16 13:46:22.000000000 +0100
+@@ -5840,7 +5840,7 @@ func_mode_link ()
+ # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+- -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
++ -O*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
+@@ -6635,27 +6635,6 @@ func_mode_link ()
+ esac
+ fi
+
+- # Hardcode the library path.
+- # Skip directories that are in the system default run-time
+- # search path.
+- case " $sys_lib_dlsearch_path " in
+- *" $absdir "*) ;;
+- *)
+- case "$compile_rpath " in
+- *" $absdir "*) ;;
+- *) func_append compile_rpath " $absdir" ;;
+- esac
+- ;;
+- esac
+- case " $sys_lib_dlsearch_path " in
+- *" $libdir "*) ;;
+- *)
+- case "$finalize_rpath " in
+- *" $libdir "*) ;;
+- *) func_append finalize_rpath " $libdir" ;;
+- esac
+- ;;
+- esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
diff --git a/package/opensc/patches/patch-src_Makefile_in b/package/opensc/patches/patch-src_Makefile_in
index 63d41a20e..f2891678f 100644
--- a/package/opensc/patches/patch-src_Makefile_in
+++ b/package/opensc/patches/patch-src_Makefile_in
@@ -1,6 +1,6 @@
---- opensc-0.11.13.orig/src/Makefile.in 2010-02-16 10:32:17.000000000 +0100
-+++ opensc-0.11.13/src/Makefile.in 2010-12-15 21:48:57.000000000 +0100
-@@ -260,8 +260,8 @@ MAINTAINERCLEANFILES = $(srcdir)/Makefil
+--- opensc-0.11.13.orig/src/Makefile.in 2011-01-09 00:58:50.000000000 +0100
++++ opensc-0.11.13/src/Makefile.in 2011-01-09 00:56:00.000000000 +0100
+@@ -263,8 +263,8 @@ MAINTAINERCLEANFILES = $(srcdir)/Makefil
EXTRA_DIST = Makefile.mak
# Order IS important
diff --git a/package/openssh/Makefile b/package/openssh/Makefile
index 10b4523bc..fb876c330 100644
--- a/package/openssh/Makefile
+++ b/package/openssh/Makefile
@@ -21,14 +21,14 @@ PKGSD_OPENSSH_CLIENT_UTILS:= OpenSSH client utilities
PKGSD_OPENSSH_SFTP_CLIENT:= OpenSSH sftp client
PKGSD_OPENSSH_SFTP_SERVER:= OpenSSH sftp server
-PKG_CHOICES:= NOKRB WITH_KRB5 WITH_HEIMDAL
-PKGCD_NOKRB:= no Kerberos support
-PKGCD_WITH_KRB5:= with MIT Kerberos
-PKGCS_WITH_KRB5:= libkrb5 libcom-err
-PKGCB_WITH_KRB5:= krb5
-PKGCD_WITH_HEIMDAL:= with Heimdal Kerberos
-PKGCS_WITH_HEIMDAL:= libheimdal libcom-err
-PKGCB_WITH_HEIMDAL:= heimdal
+PKG_CHOICES_OPENSSH_SERVER:= NOKRB WITH_KRB5 WITH_HEIMDAL
+PKGCD_NOKRB:= no Kerberos support
+PKGCD_WITH_KRB5:= with MIT Kerberos
+PKGCS_WITH_KRB5:= libkrb5 libcom-err
+PKGCB_WITH_KRB5:= krb5
+PKGCD_WITH_HEIMDAL:= with Heimdal Kerberos
+PKGCS_WITH_HEIMDAL:= libheimdal libcom-err
+PKGCB_WITH_HEIMDAL:= heimdal
include ${TOPDIR}/mk/package.mk
@@ -56,6 +56,7 @@ CONFIGURE_ARGS+= --disable-strip \
--disable-wtmp \
--disable-wtmpx \
--without-bsd-auth \
+ --without-rpath \
--without-pam \
--without-x \
--without-zlib-version-check \
diff --git a/package/openssl-pkcs11/patches/patch-ltmain_sh b/package/openssl-pkcs11/patches/patch-ltmain_sh
new file mode 100644
index 000000000..317a0b26c
--- /dev/null
+++ b/package/openssl-pkcs11/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- engine_pkcs11-0.1.8.orig/ltmain.sh 2010-01-07 11:21:35.000000000 +0100
++++ engine_pkcs11-0.1.8/ltmain.sh 2011-01-16 13:57:19.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/openssl/Makefile b/package/openssl/Makefile
index f0fdc50fb..472362adc 100644
--- a/package/openssl/Makefile
+++ b/package/openssl/Makefile
@@ -22,9 +22,8 @@ PKGSD_LIBOPENSSL_DEV:= development files for openssl
PKGSC_LIBOPENSSL_DEV:= devel
PKGSS_LIBOPENSSL_DEV:= libopenssl
-PKG_FLAVOURS:= WITH_EC
-PKGFD_WITH_EC:= enable Elliptic Curve crypto
-PKGSUB_WITH_EC:= libopenssl
+PKG_FLAVOURS_LIBOPENSSL:= WITH_EC
+PKGFD_WITH_EC:= enable Elliptic Curve crypto
include ${TOPDIR}/mk/package.mk
@@ -32,10 +31,6 @@ $(eval $(call PKG_template,LIBOPENSSL,libopenssl,${PKG_VERSION}-${PKG_RELEASE},$
$(eval $(call PKG_template,LIBOPENSSL_DEV,libopenssl-dev,${PKG_VERSION}-${PKG_RELEASE},${PKGSS_LIBOPENSSL_DEV},${PKGSD_LIBOPENSSL_DEV},${PKGSC_LIBOPENSSL_DEV}))
$(eval $(call PKG_template,OPENSSL_UTIL,openssl-util,${PKG_VERSION}-${PKG_RELEASE},${PKGSS_OPENSSL_UTIL},${PKGSD_OPENSSL_UTIL},${PKGSC_OPENSSL_UTIL}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBOPENSSL_DEV}+= libopenssl-dev-install
-
CONFIG_STYLE:= manual
BUILD_STYLE:= manual
@@ -44,7 +39,7 @@ FAKE_FLAGS+= INSTALL_PREFIX=${WRKINST}
OPENSSL_OPTIONS:= shared no-err no-krb5 no-threads zlib-dynamic no-engines no-camellia no-idea no-rc5 no-mdc2 no-sha0 no-smime no-aes192 no-ripemd no-cast
-ifeq ($(ADK_PACKAGE_OPENSSL_WITH_EC),)
+ifeq ($(ADK_PACKAGE_LIBOPENSSL_WITH_EC),)
OPENSSL_OPTIONS+= no-ec
endif
@@ -74,10 +69,12 @@ do-build:
OPTIMIZATION_FLAGS="$(TARGET_CFLAGS) -fPIC" \
all build-shared
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_LIBOPENSSL}/usr/lib
${CP} ${WRKINST}/usr/lib/lib*.so* ${IDIR_LIBOPENSSL}/usr/lib
chmod 644 ${IDIR_LIBOPENSSL}/usr/lib/lib*.so*
+
+openssl-util-install:
${INSTALL_DIR} ${IDIR_OPENSSL_UTIL}/usr/bin
${CP} ${WRKINST}/usr/bin/openssl ${IDIR_OPENSSL_UTIL}/usr/bin
${INSTALL_DIR} ${IDIR_OPENSSL_UTIL}/etc/ssl/{,certs,private}
diff --git a/package/openvpn/Makefile b/package/openvpn/Makefile
index 774a63ea9..5c9c8dc6e 100644
--- a/package/openvpn/Makefile
+++ b/package/openvpn/Makefile
@@ -15,7 +15,7 @@ PKG_URL:= http://openvpn.net/
PKG_SITES:= http://openvpn.net/release/
PKG_SUBPKGS:= OPENVPN OPENVPN_EASY_RSA
-PKG_FLAVOURS:= WITH_LZO WITH_MANAGEMENT WITH_HTTPPROXY WITH_SOCKS
+PKG_FLAVOURS_OPENVPN:= WITH_LZO WITH_MANAGEMENT WITH_HTTPPROXY WITH_SOCKS
PKGFD_WITH_LZO:= enable LZO compression support
PKGFS_WITH_LZO:= liblzo
PKGFB_WITH_LZO:= liblzo
@@ -60,11 +60,7 @@ CONFIGURE_ARGS+= --disable-pthread \
--without-ifconfig-path \
--without-route-path
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${OPENVPN_EASY_RSA}+= openvpn-easy-rsa-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} $(IDIR_OPENVPN)/usr/sbin $(IDIR_OPENVPN)/etc/openvpn
${INSTALL_BIN} $(WRKINST)/usr/sbin/openvpn $(IDIR_OPENVPN)/usr/sbin/
$(CP) ./files/openvpn.conf $(IDIR_OPENVPN)/etc/openvpn/
diff --git a/package/oprofile/patches/patch-doc_oprofile_1 b/package/oprofile/patches/patch-doc_oprofile_1
deleted file mode 100644
index 2694725cd..000000000
--- a/package/oprofile/patches/patch-doc_oprofile_1
+++ /dev/null
@@ -1,26 +0,0 @@
---- oprofile-0.9.6.orig/doc/oprofile.1 2009-11-24 16:26:33.000000000 +0100
-+++ oprofile-0.9.6/doc/oprofile.1 2010-07-13 17:55:07.343074887 +0200
-@@ -1,4 +1,4 @@
--.TH OPROFILE 1 "Tue 24 November 2009" "oprofile 0.9.6"
-+.TH OPROFILE 1 "Tue 13 July 2010" "oprofile 0.9.6"
- .UC 4
- .SH NAME
- oprofile \- a system-wide profiler
-@@ -153,7 +153,7 @@ Configuration files
- .I /root/.oprofile/daemonrc
- Configuration file for opcontrol
- .TP
--.I /usr/local/share/oprofile/
-+.I /usr/share/oprofile/
- Event description files used by OProfile.
- .TP
- .I /var/lib/oprofile/samples/oprofiled.log
-@@ -173,7 +173,7 @@ The location of the generated sample fil
- This man page is current for oprofile-0.9.6.
-
- .SH SEE ALSO
--.BR /usr/local/share/doc/oprofile/,
-+.BR /usr/share/doc/oprofile/,
- .BR opcontrol(1),
- .BR opreport(1),
- .BR opannotate(1),
diff --git a/package/oprofile/patches/patch-ltmain_sh b/package/oprofile/patches/patch-ltmain_sh
new file mode 100644
index 000000000..734d4fee0
--- /dev/null
+++ b/package/oprofile/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- oprofile-0.9.6.orig/ltmain.sh 2008-10-01 16:41:58.000000000 +0200
++++ oprofile-0.9.6/ltmain.sh 2011-01-16 14:01:51.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/osiris/patches/patch-configure b/package/osiris/patches/patch-configure
index 7d0b90b3f..b9ae74fe0 100644
--- a/package/osiris/patches/patch-configure
+++ b/package/osiris/patches/patch-configure
@@ -1,7 +1,13 @@
$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
--- osiris-4.2.3.orig/configure 2006-07-28 01:57:51.000000000 +0200
-+++ osiris-4.2.3/configure 2009-12-11 21:26:32.000000000 +0100
-@@ -3403,7 +3403,7 @@ else
++++ osiris-4.2.3/configure 2011-01-16 15:16:06.000000000 +0100
+@@ -1,4 +1,5 @@
+ #! /bin/sh
++set -x
+ # Guess values for system-dependent variables and create Makefiles.
+ # Generated by GNU Autoconf 2.59.
+ #
+@@ -3403,7 +3404,7 @@ else
fi
@@ -10,7 +16,80 @@ $Id: update-patches 24 2008-08-31 14:56:13Z wbx $
AUTOHEADER=echo
if test "x$prefix" = "xNONE" ; then
-@@ -3738,7 +3738,7 @@ CYGWIN*)
+@@ -3573,7 +3574,6 @@ else
+
+ for ssldir in $tryssldir "" /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/pkg /opt /opt/openssl ; do
+ CPPFLAGS="$saved_CPPFLAGS"
+- LDFLAGS="$saved_LDFLAGS"
+
+ # GOD DAMN FUCKING STATIC BINARIES ON SOLARIS CAN EAT MY ASS.
+
+@@ -3596,29 +3596,6 @@ else
+ if test ! -z "$ssldir" -a ! -d "$ssldir" ; then
+ continue;
+ fi
+- if test ! -z "$ssldir" -a "x$ssldir" != "x/usr"; then
+- # Try to use $ssldir/lib if it exists, otherwise
+- # $ssldir
+- if test -d "$ssldir/lib" ; then
+- LDFLAGS="-L$ssldir/lib $saved_LDFLAGS"
+- if test ! -z "$need_dash_r" ; then
+- LDFLAGS="-R$ssldir/lib $LDFLAGS"
+- fi
+- else
+- LDFLAGS="-L$ssldir $saved_LDFLAGS"
+- if test ! -z "$need_dash_r" ; then
+- LDFLAGS="-R$ssldir $LDFLAGS"
+- fi
+- fi
+-
+- # Try to use $ssldir/include if it exists, otherwise
+- # $ssldir
+- if test -d "$ssldir/include" ; then
+- CPPFLAGS="-I$ssldir/include $saved_CPPFLAGS"
+- else
+- CPPFLAGS="-I$ssldir $saved_CPPFLAGS"
+- fi
+- fi
+
+ # Basic test to check for compatible version and correct linking
+
+@@ -3694,34 +3671,6 @@ fi
+ echo "$as_me:$LINENO: result: $ac_cv_openssldir" >&5
+ echo "${ECHO_T}$ac_cv_openssldir" >&6
+
+-if (test ! -z "$ac_cv_openssldir" && test "x$ac_cv_openssldir" != "x(system)") ; then
+-# AC_DEFINE(HAVE_OPENSSL)
+- ssldir=$ac_cv_openssldir
+- if test ! -z "$ssldir" -a "x$ssldir" != "x/usr"; then
+- # Try to use $ssldir/lib if it exists, otherwise
+- # $ssldir
+- if test -d "$ssldir/lib" ; then
+- LDFLAGS="-L$ssldir/lib $saved_LDFLAGS"
+- if test ! -z "$need_dash_r" ; then
+- LDFLAGS="-R$ssldir/lib $LDFLAGS"
+- fi
+- else
+- LDFLAGS="-L$ssldir $saved_LDFLAGS"
+- if test ! -z "$need_dash_r" ; then
+- LDFLAGS="-R$ssldir $LDFLAGS"
+- fi
+- fi
+- # Try to use $ssldir/include if it exists, otherwise
+- # $ssldir
+- if test -d "$ssldir/include" ; then
+- CPPFLAGS="-I$ssldir/include $saved_CPPFLAGS"
+- else
+- CPPFLAGS="-I$ssldir $saved_CPPFLAGS"
+- fi
+- fi
+-fi
+-
+-
+ case "$OS_NAME" in
+ SunOS*)
+ LIBS="$saved_LIBS $ssldir/lib/libssl.a $ssldir/lib/libcrypto.a"
+@@ -3738,7 +3687,7 @@ CYGWIN*)
esac
@@ -19,7 +98,7 @@ $Id: update-patches 24 2008-08-31 14:56:13Z wbx $
case "${OS_NAME}" in
MINGW32*)
-@@ -4448,11 +4448,6 @@ cat >>confdefs.h <<_ACEOF
+@@ -4448,11 +4397,6 @@ cat >>confdefs.h <<_ACEOF
#define SYSTEM_LINUX 1
_ACEOF
@@ -31,7 +110,7 @@ $Id: update-patches 24 2008-08-31 14:56:13Z wbx $
;;
BSD*)
-@@ -11394,7 +11389,6 @@ chmod ug+x src/install/install.sh
+@@ -11394,7 +11338,6 @@ chmod ug+x src/install/install.sh
echo " Osiris MD Directory: ${with_md_root_dir}"
echo " Osiris MD user: ${with_osiris_md_user}"
echo " Osiris MD config dir: ${with_md_conf_dir}"
diff --git a/package/osiris/patches/patch-src_db-4_2_52_dist_configure b/package/osiris/patches/patch-src_db-4_2_52_dist_configure
new file mode 100644
index 000000000..45c04bec4
--- /dev/null
+++ b/package/osiris/patches/patch-src_db-4_2_52_dist_configure
@@ -0,0 +1,12 @@
+--- osiris-4.2.3.orig/src/db-4.2.52/dist/configure 2006-07-28 01:57:51.000000000 +0200
++++ osiris-4.2.3/src/db-4.2.52/dist/configure 2011-01-16 14:41:34.000000000 +0100
+@@ -3498,7 +3498,8 @@ freebsd*)
+ LDFLAGS="$LDFLAGS -pthread";;
+ gnu*|k*bsd*-gnu|linux*)
+ optimize_def="-O2"
+- CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE -D_REENTRANT";;
++ CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE -D_REENTRANT"
++ LDFLAGS="$LDFLAGS -pthread";;
+ hpux*) CPPFLAGS="$CPPFLAGS -D_REENTRANT";;
+ irix*) optimize_def="-O2"
+ CPPFLAGS="$CPPFLAGS -D_SGI_MP_SOURCE";;
diff --git a/package/osiris/patches/patch-src_db-4_2_52_dist_ltmain_sh b/package/osiris/patches/patch-src_db-4_2_52_dist_ltmain_sh
new file mode 100644
index 000000000..8b9084264
--- /dev/null
+++ b/package/osiris/patches/patch-src_db-4_2_52_dist_ltmain_sh
@@ -0,0 +1,11 @@
+--- osiris-4.2.3.orig/src/db-4.2.52/dist/ltmain.sh 2006-07-28 01:57:51.000000000 +0200
++++ osiris-4.2.3/src/db-4.2.52/dist/ltmain.sh 2011-01-16 14:08:34.000000000 +0100
+@@ -1298,7 +1298,7 @@ EOF
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+- -m*)
++ -m*|-fstack-protector*|-flto)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
diff --git a/package/owfs/patches/autotool.patch b/package/owfs/patches/autotool.patch
index 12a4fe090..66bb2e93b 100644
--- a/package/owfs/patches/autotool.patch
+++ b/package/owfs/patches/autotool.patch
@@ -56822,7 +56822,7 @@ diff -Nur owfs-2.7p38.orig/src/scripts/install/ltmain.sh owfs-2.7p38/src/scripts
+ # -tp=* Portland pgcc target processor selection
-64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
-+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|-fstack-protector*|-flto)
func_quote_for_eval "$arg"
arg="$func_quote_for_eval_result"
func_append compile_command " $arg"
diff --git a/package/pango/patches/patch-ltmain_sh b/package/pango/patches/patch-ltmain_sh
new file mode 100644
index 000000000..79b73df6f
--- /dev/null
+++ b/package/pango/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- pango-1.28.3.orig/ltmain.sh 2010-09-29 13:02:28.000000000 +0200
++++ pango-1.28.3/ltmain.sh 2011-01-14 23:41:25.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/pango/patches/patch-tests_runtests_sh b/package/pango/patches/patch-tests_runtests_sh
new file mode 100644
index 000000000..c4675af7a
--- /dev/null
+++ b/package/pango/patches/patch-tests_runtests_sh
@@ -0,0 +1,8 @@
+--- pango-1.28.3.orig/tests/runtests.sh 2010-09-29 13:02:41.000000000 +0200
++++ pango-1.28.3/tests/runtests.sh 2011-01-14 23:40:32.000000000 +0100
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! /bin/bash
+
+ LOGFILE=runtests.log
+ POTENTIAL_TESTS='testboundaries testcolor testboundaries_ucd'
diff --git a/package/parted/patches/patch-build-aux_ltmain_sh b/package/parted/patches/patch-build-aux_ltmain_sh
new file mode 100644
index 000000000..bb54e7146
--- /dev/null
+++ b/package/parted/patches/patch-build-aux_ltmain_sh
@@ -0,0 +1,11 @@
+--- parted-2.3.orig/build-aux/ltmain.sh 2010-05-28 20:29:02.000000000 +0200
++++ parted-2.3/build-aux/ltmain.sh 2011-01-16 15:30:44.000000000 +0100
+@@ -4971,7 +4971,7 @@ func_mode_link ()
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/pciutils/Makefile b/package/pciutils/Makefile
index 2e21cd918..e1176564d 100644
--- a/package/pciutils/Makefile
+++ b/package/pciutils/Makefile
@@ -5,7 +5,7 @@ include ${TOPDIR}/rules.mk
PKG_NAME:= pciutils
PKG_VERSION:= 3.1.7
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= f3e349d22a3714b4272b171649ad5235
PKG_DESCR:= PCI Utilities
PKG_SECTION:= utils
@@ -14,8 +14,6 @@ PKG_BUILDDEP:= zlib
PKG_URL:= http://www.kernel.org/pub/software/utils/pciutils/
PKG_SITES:= http://www.kernel.org/pub/software/utils/pciutils/
-PKG_HOST_DEPENDS:= !darwin
-
include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,PCIUTILS,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
@@ -24,7 +22,8 @@ CONFIG_STYLE:= manual
INSTALL_STYLE:= manual
MAKE_FLAGS+= CC="${TARGET_CC}" \
- CFLAGS="${TCFLAGS}" \
+ CFLAGS="${TARGET_CFLAGS}" \
+ CROSS_COMPILE="${TARGET_CROSS}" \
IDSDIR="/usr/share" \
HOST=${GNU_TARGET_NAME}
ALL_TARGET:=
diff --git a/package/pcre/patches/patch-ltmain_sh b/package/pcre/patches/patch-ltmain_sh
new file mode 100644
index 000000000..b655e96af
--- /dev/null
+++ b/package/pcre/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- pcre-8.02.orig/ltmain.sh 2010-03-19 11:21:04.000000000 +0100
++++ pcre-8.02/ltmain.sh 2011-01-14 21:12:27.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/pcsc-lite/Makefile b/package/pcsc-lite/Makefile
index ca95456cc..096625b96 100644
--- a/package/pcsc-lite/Makefile
+++ b/package/pcsc-lite/Makefile
@@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:= pcsc-lite
PKG_VERSION:= 1.6.6
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= f80d3ecd9569b71d557f283f16295c74
PKG_DESCR:= middleware for smartcards
PKG_SECTION:= crypto
@@ -27,11 +27,7 @@ $(eval $(call PKG_template,PCSC_LITE_DEV,$(PKG_NAME)-dev,$(PKG_VERSION)-${PKG_RE
CONFIGURE_ARGS+= --disable-libhal
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_PCSC_LITE_DEV}+= pcsc-lite-dev-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
$(INSTALL_DIR) $(IDIR_PCSC_LITE)/etc/reader.conf.d
$(INSTALL_DIR) $(IDIR_PCSC_LITE)/usr/sbin
$(INSTALL_DIR) $(IDIR_PCSC_LITE)/usr/lib
diff --git a/package/pcsc-lite/patches/patch-ltmain_sh b/package/pcsc-lite/patches/patch-ltmain_sh
new file mode 100644
index 000000000..62af43733
--- /dev/null
+++ b/package/pcsc-lite/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- pcsc-lite-1.6.6.orig/ltmain.sh 2010-12-12 11:08:23.000000000 +0100
++++ pcsc-lite-1.6.6/ltmain.sh 2011-01-14 20:20:39.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/pcsc-lite/patches/patch-src_Makefile_in b/package/pcsc-lite/patches/patch-src_Makefile_in
new file mode 100644
index 000000000..582fe0bb5
--- /dev/null
+++ b/package/pcsc-lite/patches/patch-src_Makefile_in
@@ -0,0 +1,20 @@
+--- pcsc-lite-1.6.6.orig/src/Makefile.in 2010-12-12 11:08:27.000000000 +0100
++++ pcsc-lite-1.6.6/src/Makefile.in 2011-01-07 19:27:46.000000000 +0100
+@@ -338,7 +338,7 @@ libpcsclite_la_SOURCES = \
+ winscard_msg.c
+
+ libpcsclite_la_LDFLAGS = -version-info 1:0:0
+-libpcsclite_la_CFLAGS = $(CFLAGS) $(PTHREAD_CFLAGS) -DLIBPCSCLITE -DSIMCLIST_NO_DUMPRESTORE
++libpcsclite_la_CFLAGS = $(PTHREAD_CFLAGS) -DLIBPCSCLITE -DSIMCLIST_NO_DUMPRESTORE
+ libpcsclite_la_LIBADD = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+ pcscd_SOURCES = \
+ atrhandler.c \
+@@ -390,7 +390,7 @@ pcscd_SOURCES = \
+ winscard_svc.c \
+ winscard_svc.h
+
+-pcscd_CFLAGS = $(CFLAGS) $(PTHREAD_CFLAGS) $(LIBUSB_CFLAGS) $(LIBHAL_CFLAGS) \
++pcscd_CFLAGS = $(PTHREAD_CFLAGS) $(LIBUSB_CFLAGS) $(LIBHAL_CFLAGS) \
+ -DPCSCD -DSIMCLIST_NO_DUMPRESTORE
+
+ pcscd_LDFLAGS = $(LDFLAGS) -export-dynamic
diff --git a/package/pdnsd/Makefile b/package/pdnsd/Makefile
index a6f8041aa..8e83586b3 100644
--- a/package/pdnsd/Makefile
+++ b/package/pdnsd/Makefile
@@ -13,7 +13,7 @@ PKG_DEPENDS:= libpthread
PKG_URL:= http://www.phys.uu.nl/~rombouts/pdnsd.html
PKG_SITES:= http://www.phys.uu.nl/~rombouts/pdnsd/releases/
-PKG_FLAVOURS:= WITH_IPV6
+PKG_FLAVOURS_PDNSD:= WITH_IPV6
PKGFD_WITH_IPV6:= enable IPv6 support
PKG_HOST_DEPENDS:= !netbsd
diff --git a/package/pipacs/Makefile b/package/pipacs/Makefile
index 612771db5..81d4176e9 100644
--- a/package/pipacs/Makefile
+++ b/package/pipacs/Makefile
@@ -4,6 +4,7 @@
include ${TOPDIR}/rules.mk
PKG_NAME:= pipacs
+PKG_VERSION:= 0.1
PKG_RELEASE:= 2
PKG_DESCR:= an UNIX socket accounting/wiewer program
PKG_SECTION:= net/misc
@@ -17,9 +18,6 @@ $(eval $(call PKG_template,PIPACS,${PKG_NAME},${PKG_RELEASE},${PKG_DEPENDS},${PK
CONFIG_STYLE:= manual
INSTALL_STYLE:= manual
-MAKE_FLAGS+= CFLAGS="${TCFLAGS} ${TCPPFLAGS}" \
- ${TARGET_CONFIGURE_OPTS}
-
do-install:
${INSTALL_DIR} ${IDIR_PIPACS}/usr/bin
${INSTALL_BIN} ${WRKBUILD}/pipacs ${IDIR_PIPACS}/usr/bin
diff --git a/package/pipacs/src/Makefile b/package/pipacs/src/Makefile
index 3a48e88f7..c3f830be6 100644
--- a/package/pipacs/src/Makefile
+++ b/package/pipacs/src/Makefile
@@ -1,14 +1,16 @@
-
+CPPFLAGS?=
+CFLAGS?=
+LDFLAGS?=
EXTRA_CFLAGS := -c -I.
PIPACS_OBJS := pipacs.o parser.o
all: pipacs
%.o: %.c
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ $^
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ $^
pipacs: $(PIPACS_OBJS)
- $(CC) -o $@ $^
+ $(CC) $(LDFLAGS) -o $@ $^
clean:
rm -f *.o *.so pipacs
diff --git a/package/pixman/patches/patch-ltmain_sh b/package/pixman/patches/patch-ltmain_sh
new file mode 100644
index 000000000..b38645c65
--- /dev/null
+++ b/package/pixman/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- pixman-0.16.2.orig/ltmain.sh 2009-04-23 02:27:43.000000000 +0200
++++ pixman-0.16.2/ltmain.sh 2011-01-14 20:10:48.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/ppp/Makefile b/package/ppp/Makefile
index 591f3ca2a..85386cb08 100644
--- a/package/ppp/Makefile
+++ b/package/ppp/Makefile
@@ -31,23 +31,11 @@ $(eval $(call PKG_template,PPP_MOD_PPPSTATS,ppp-mod-pppstats,${PKG_VERSION}-${PK
$(eval $(call PKG_template,PPP_MOD_PPPUMTS,ppp-mod-pppumts,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS_UMTS},${PKG_DESCR},${PKG_SECTION}))
CONFIGURE_ENV+= UNAME_S="Linux"
-XAKE_FLAGS+= CC="${TARGET_CC}" \
- COPTS="${TCFLAGS}" \
- STAGING_TARGET_DIR=${STAGING_TARGET_DIR} \
+XAKE_FLAGS+= STAGING_TARGET_DIR=${STAGING_TARGET_DIR} \
DESTDIR="${WRKINST}/usr" \
TARGET_AR='${TARGET_CROSS}ar'
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_PPP_MOD_PPPOE}+= mod-pppoe-install
-SUB_INSTALLS-${ADK_PACKAGE_PPP_MOD_PPPOA}+= mod-pppoa-install
-SUB_INSTALLS-${ADK_PACKAGE_PPP_MOD_RADIUS}+= mod-radius-install
-SUB_INSTALLS-${ADK_PACKAGE_PPP_MOD_CHAT}+= mod-chat-install
-SUB_INSTALLS-${ADK_PACKAGE_PPP_MOD_PPPDUMP}+= mod-pppdump-install
-SUB_INSTALLS-${ADK_PACKAGE_PPP_MOD_PPPSTATS}+= mod-pppstats-install
-SUB_INSTALLS-${ADK_PACKAGE_PPP_MOD_PPPUMTS}+= mod-pppumts-install
-
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_PPP}/etc/ppp
install -m0600 ./files/etc/ppp/chap-secrets ${IDIR_PPP}/etc/ppp/
${INSTALL_DATA} ./files/etc/ppp/options ${IDIR_PPP}/etc/ppp/
@@ -65,11 +53,13 @@ post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
${INSTALL_BIN} ./files/pon ${IDIR_PPP}/usr/sbin/
${INSTALL_BIN} ./files/poff ${IDIR_PPP}/usr/sbin/
${INSTALL_DIR} ${IDIR_PPP}/etc/ppp/peers
+ifeq (${ADK_INSTALL_PACKAGE_NETWORK_SCRIPTS},y)
$(INSTALL_DIR) ${IDIR_PPP}/etc/network/if-pre-up.d
$(INSTALL_BIN) ./files/ppp.pre-up \
${IDIR_PPP}/etc/network/if-pre-up.d/05-ppp
+endif
-mod-radius-install:
+ppp-mod-radius-install:
${INSTALL_DIR} ${IDIR_PPP_MOD_RADIUS}/etc/radiusclient
${CP} ${WRKBUILD}/pppd/plugins/radius/etc/* \
${IDIR_PPP_MOD_RADIUS}/etc/radiusclient
@@ -78,7 +68,7 @@ mod-radius-install:
${INSTALL_BIN} $(WRKINST)/usr/lib/pppd/$(PKG_VERSION)/radius.so \
${IDIR_PPP_MOD_RADIUS}/usr/lib/pppd/$(PKG_VERSION)
-mod-pppoe-install:
+ppp-mod-pppoe-install:
${INSTALL_DIR} ${IDIR_PPP_MOD_PPPOE}/usr/lib/pppd/$(PKG_VERSION)
${INSTALL_BIN} $(WRKINST)/usr/lib/pppd/$(PKG_VERSION)/rp-pppoe.so \
${IDIR_PPP_MOD_PPPOE}/usr/lib/pppd/$(PKG_VERSION)
@@ -86,7 +76,7 @@ mod-pppoe-install:
${INSTALL_DATA} ./files/etc/ppp/templates/pppoe \
${IDIR_PPP_MOD_PPPOE}/etc/ppp/templates/
-mod-pppoa-install:
+ppp-mod-pppoa-install:
${INSTALL_DIR} ${IDIR_PPP_MOD_PPPOA}/usr/lib/pppd/$(PKG_VERSION)
${INSTALL_BIN} $(WRKINST)/usr/lib/pppd/$(PKG_VERSION)/pppoatm.so \
${IDIR_PPP_MOD_PPPOA}/usr/lib/pppd/$(PKG_VERSION)
@@ -94,27 +84,29 @@ mod-pppoa-install:
${INSTALL_DATA} ./files/etc/ppp/templates/pppoa \
${IDIR_PPP_MOD_PPPOA}/etc/ppp/templates/
-mod-chat-install:
+ppp-mod-chat-install:
${INSTALL_DIR} ${IDIR_PPP_MOD_CHAT}/usr/sbin
${CP} ${WRKINST}/usr/sbin/chat ${IDIR_PPP_MOD_CHAT}/usr/sbin/
-mod-pppdump-install:
+ppp-mod-pppdump-install:
${INSTALL_DIR} ${IDIR_PPP_MOD_PPPDUMP}/usr/sbin
${CP} ${WRKINST}/usr/sbin/pppdump ${IDIR_PPP_MOD_PPPDUMP}/usr/sbin/
-mod-pppstats-install:
+ppp-mod-pppstats-install:
${INSTALL_DIR} ${IDIR_PPP_MOD_PPPSTATS}/usr/sbin
${CP} ${WRKINST}/usr/sbin/pppstats ${IDIR_PPP_MOD_PPPSTATS}/usr/sbin/
-mod-pppumts-install:
+ppp-mod-pppumts-install:
${INSTALL_DIR} ${IDIR_PPP_MOD_PPPUMTS}/etc/ppp/templates
${INSTALL_DATA} ./files/etc/ppp/templates/umts \
${IDIR_PPP_MOD_PPPUMTS}/etc/ppp/templates/
+ifeq (${ADK_INSTALL_PACKAGE_NETWORK_SCRIPTS},y)
$(INSTALL_DIR) ${IDIR_PPP_MOD_PPPUMTS}/etc/network/if-pre-up.d
$(INSTALL_DIR) ${IDIR_PPP_MOD_PPPUMTS}/etc/network/if-post-down.d
$(INSTALL_BIN) ./files/hso.if-up \
${IDIR_PPP_MOD_PPPUMTS}/etc/network/if-pre-up.d/06-hso
$(INSTALL_BIN) ./files/hso.if-down \
${IDIR_PPP_MOD_PPPUMTS}/etc/network/if-post-down.d/06-hso
+endif
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/ppp/patches/patch-chat_Makefile_linux b/package/ppp/patches/patch-chat_Makefile_linux
index 63190f3e3..3d0c3fdff 100644
--- a/package/ppp/patches/patch-chat_Makefile_linux
+++ b/package/ppp/patches/patch-chat_Makefile_linux
@@ -1,6 +1,26 @@
---- ppp-2.4.4.orig/chat/Makefile.linux 2006-06-04 07:07:46.000000000 +0200
-+++ ppp-2.4.4/chat/Makefile.linux 2009-06-05 19:12:00.000000000 +0200
-@@ -25,7 +25,7 @@ chat.o: chat.c
+--- ppp-2.4.5.orig/chat/Makefile.linux 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/chat/Makefile.linux 2011-01-16 15:56:59.000000000 +0100
+@@ -10,22 +10,23 @@ CDEF3= -UNO_SLEEP # Use the usleep fun
+ CDEF4= -DFNDELAY=O_NDELAY # Old name value
+ CDEFS= $(CDEF1) $(CDEF2) $(CDEF3) $(CDEF4)
+
+-COPTS= -O2 -g -pipe
+-CFLAGS= $(COPTS) $(CDEFS)
++CPPFLAGS?=
++CFLAGS?=-O2 -g -pipe
++LDFLAGS?=
+
+ INSTALL= install
+
+ all: chat
+
+ chat: chat.o
+- $(CC) -o chat chat.o
++ $(CC) $(LDFLAGS) -o chat chat.o
+
+ chat.o: chat.c
+- $(CC) -c $(CFLAGS) -o chat.o chat.c
++ $(CC) -c $(CPPFLAGS) $(CFLAGS) -o chat.o chat.c
install: chat
mkdir -p $(BINDIR) $(MANDIR)
diff --git a/package/ppp/patches/patch-include_linux_ppp-comp_h b/package/ppp/patches/patch-include_linux_ppp-comp_h
deleted file mode 100644
index 4ffaea45c..000000000
--- a/package/ppp/patches/patch-include_linux_ppp-comp_h
+++ /dev/null
@@ -1,63 +0,0 @@
---- ppp-2.4.4.orig/include/linux/ppp-comp.h 2002-12-06 10:49:15.000000000 +0100
-+++ ppp-2.4.4/include/linux/ppp-comp.h 2009-06-05 19:12:00.000000000 +0200
-@@ -36,7 +36,7 @@
- */
-
- /*
-- * ==FILEVERSION 20020319==
-+ * ==FILEVERSION 20020715==
- *
- * NOTE TO MAINTAINERS:
- * If you modify this file at all, please set the above date.
-@@ -86,7 +86,7 @@ struct compressor {
-
- /* Compress a packet */
- int (*compress) (void *state, unsigned char *rptr,
-- unsigned char *obuf, int isize, int osize);
-+ unsigned char *obuf, int isize, int osize);
-
- /* Return compression statistics */
- void (*comp_stat) (void *state, struct compstat *stats);
-@@ -107,7 +107,7 @@ struct compressor {
-
- /* Decompress a packet. */
- int (*decompress) (void *state, unsigned char *ibuf, int isize,
-- unsigned char *obuf, int osize);
-+ unsigned char *obuf, int osize);
-
- /* Update state for an incompressible packet received */
- void (*incomp) (void *state, unsigned char *ibuf, int icnt);
-@@ -288,6 +288,33 @@ struct compressor {
- opts |= MPPE_OPT_UNKNOWN; \
- } while (/* CONSTCOND */ 0)
-
-+/* MPPE/MPPC definitions by J.D.*/
-+#define MPPE_STATELESS MPPE_H_BIT /* configuration bit H */
-+#define MPPE_40BIT MPPE_L_BIT /* configuration bit L */
-+#define MPPE_56BIT MPPE_M_BIT /* configuration bit M */
-+#define MPPE_128BIT MPPE_S_BIT /* configuration bit S */
-+#define MPPE_MPPC MPPE_C_BIT /* configuration bit C */
-+
-+/*
-+ * Definitions for Stac LZS.
-+ */
-+
-+#define CI_LZS 17 /* config option for Stac LZS */
-+#define CILEN_LZS 5 /* length of config option */
-+
-+#define LZS_OVHD 4 /* max. LZS overhead */
-+#define LZS_HIST_LEN 2048 /* LZS history size */
-+#define LZS_MAX_CCOUNT 0x0FFF /* max. coherency counter value */
-+
-+#define LZS_MODE_NONE 0
-+#define LZS_MODE_LCB 1
-+#define LZS_MODE_CRC 2
-+#define LZS_MODE_SEQ 3
-+#define LZS_MODE_EXT 4
-+
-+#define LZS_EXT_BIT_FLUSHED 0x80 /* bit A */
-+#define LZS_EXT_BIT_COMP 0x20 /* bit C */
-+
- /*
- * Definitions for other, as yet unsupported, compression methods.
- */
diff --git a/package/ppp/patches/patch-include_net_ppp-comp_h b/package/ppp/patches/patch-include_net_ppp-comp_h
deleted file mode 100644
index 239cf1443..000000000
--- a/package/ppp/patches/patch-include_net_ppp-comp_h
+++ /dev/null
@@ -1,36 +0,0 @@
---- ppp-2.4.4.orig/include/net/ppp-comp.h 2002-12-06 10:49:15.000000000 +0100
-+++ ppp-2.4.4/include/net/ppp-comp.h 2009-06-05 19:12:00.000000000 +0200
-@@ -255,6 +255,33 @@ struct compressor {
- opts |= MPPE_OPT_UNKNOWN; \
- } while (/* CONSTCOND */ 0)
-
-+/* MPPE/MPPC definitions by J.D.*/
-+#define MPPE_STATELESS MPPE_H_BIT /* configuration bit H */
-+#define MPPE_40BIT MPPE_L_BIT /* configuration bit L */
-+#define MPPE_56BIT MPPE_M_BIT /* configuration bit M */
-+#define MPPE_128BIT MPPE_S_BIT /* configuration bit S */
-+#define MPPE_MPPC MPPE_C_BIT /* configuration bit C */
-+
-+/*
-+ * Definitions for Stac LZS.
-+ */
-+
-+#define CI_LZS 17 /* config option for Stac LZS */
-+#define CILEN_LZS 5 /* length of config option */
-+
-+#define LZS_OVHD 4 /* max. LZS overhead */
-+#define LZS_HIST_LEN 2048 /* LZS history size */
-+#define LZS_MAX_CCOUNT 0x0FFF /* max. coherency counter value */
-+
-+#define LZS_MODE_NONE 0
-+#define LZS_MODE_LCB 1
-+#define LZS_MODE_CRC 2
-+#define LZS_MODE_SEQ 3
-+#define LZS_MODE_EXT 4
-+
-+#define LZS_EXT_BIT_FLUSHED 0x80 /* bit A */
-+#define LZS_EXT_BIT_COMP 0x20 /* bit C */
-+
- /*
- * Definitions for other, as yet unsupported, compression methods.
- */
diff --git a/package/ppp/patches/patch-pppd_Makefile_linux b/package/ppp/patches/patch-pppd_Makefile_linux
index 32453b249..a447ae1ea 100644
--- a/package/ppp/patches/patch-pppd_Makefile_linux
+++ b/package/ppp/patches/patch-pppd_Makefile_linux
@@ -1,6 +1,31 @@
---- ppp-2.4.4.orig/pppd/Makefile.linux 2006-06-04 07:07:46.000000000 +0200
-+++ ppp-2.4.4/pppd/Makefile.linux 2009-06-05 19:12:00.000000000 +0200
-@@ -48,7 +48,7 @@ MPPE=y
+--- ppp-2.4.5.orig/pppd/Makefile.linux 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/Makefile.linux 2011-01-16 17:09:40.000000000 +0100
+@@ -2,12 +2,7 @@
+ # pppd makefile for Linux
+ # $Id: Makefile.linux,v 1.70 2007/06/19 02:08:34 carlsonj Exp $
+ #
+-
+-# Default installation locations
+-DESTDIR = $(INSTROOT)@DESTDIR@
+-BINDIR = $(DESTDIR)/sbin
+-MANDIR = $(DESTDIR)/share/man/man8
+-INCDIR = $(DESTDIR)/include
++include ../makedefs.linux
+
+ TARGETS = pppd
+
+@@ -30,10 +25,6 @@ ifeq (.depend,$(wildcard .depend))
+ include .depend
+ endif
+
+-# CC = gcc
+-#
+-COPTS = -O2 -pipe -Wall -g
+-LIBS =
+
+ # Uncomment the next 2 lines to include support for Microsoft's
+ # MS-CHAP authentication protocol. Also, edit plugins/radius/Makefile.linux.
+@@ -48,7 +39,7 @@ MPPE=y
# Uncomment the next line to include support for PPP packet filtering.
# This requires that the libpcap library and headers be installed
# and that the kernel driver support PPP packet filtering.
@@ -9,7 +34,7 @@
# Uncomment the next line to enable multilink PPP (enabled by default)
# Linux distributions: Please leave multilink ENABLED in your builds
-@@ -58,9 +58,9 @@ HAVE_MULTILINK=y
+@@ -58,9 +49,9 @@ HAVE_MULTILINK=y
# Uncomment the next line to enable the TDB database (enabled by default.)
# If you enable multilink, then TDB is automatically enabled also.
# Linux distributions: Please leave TDB ENABLED in your builds.
@@ -21,16 +46,22 @@
#USE_PAM=y
#HAVE_INET6=y
-@@ -77,7 +77,7 @@ MAXOCTETS=y
+@@ -75,11 +66,10 @@ PLUGIN=y
- INCLUDE_DIRS= -I../include
+ MAXOCTETS=y
+-INCLUDE_DIRS= -I../include
+-
-COMPILE_FLAGS= -DHAVE_PATHS_H -DIPX_CHANGE -DHAVE_MMAP
-+COMPILE_FLAGS= -DHAVE_PATHS_H -DHAVE_MMAP
++CPPFLAGS += -I../include
++CPPFLAGS += -DHAVE_PATHS_H -DHAVE_MMAP
- CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS) '-DDESTDIR="@DESTDIR@"'
+-CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS) '-DDESTDIR="@DESTDIR@"'
++CFLAGS+= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS) '-DDESTDIR="@DESTDIR@"'
-@@ -99,7 +99,7 @@ ifdef USE_SRP
+ ifdef CHAPMS
+ CFLAGS += -DCHAPMS=1
+@@ -99,7 +89,7 @@ ifdef USE_SRP
CFLAGS += -DUSE_SRP -DOPENSSL -I/usr/local/ssl/include
LIBS += -lsrp -L/usr/local/ssl/lib -lcrypto
TARGETS += srp-entry
@@ -39,7 +70,7 @@
MANPAGES += srp-entry.8
EXTRACLEAN += srp-entry.o
NEEDDES=y
-@@ -117,10 +117,8 @@ CFLAGS += -DHAS_SHADOW
+@@ -117,10 +107,8 @@ CFLAGS += -DHAS_SHADOW
#LIBS += -lshadow $(LIBS)
endif
@@ -50,7 +81,7 @@
ifdef NEEDDES
ifndef USE_CRYPT
-@@ -200,7 +198,7 @@ all: $(TARGETS)
+@@ -200,16 +188,16 @@ all: $(TARGETS)
install: pppd
mkdir -p $(BINDIR) $(MANDIR)
$(EXTRAINSTALL)
@@ -59,3 +90,20 @@
if chgrp pppusers $(BINDIR)/pppd 2>/dev/null; then \
chmod o-rx,u+s $(BINDIR)/pppd; fi
$(INSTALL) -c -m 444 pppd.8 $(MANDIR)
+
+ pppd: $(PPPDOBJS)
+- $(CC) $(CFLAGS) $(LDFLAGS) -o pppd $(PPPDOBJS) $(LIBS)
++ $(CC) $(LDFLAGS) -o pppd $(PPPDOBJS) $(LIBS)
+
+ srp-entry: srp-entry.c
+- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ srp-entry.c $(LIBS)
++ $(CC) $(LDFLAGS) -o $@ srp-entry.c $(LIBS)
+
+ install-devel:
+ mkdir -p $(INCDIR)/pppd
+@@ -219,4 +207,4 @@ clean:
+ rm -f $(PPPDOBJS) $(EXTRACLEAN) $(TARGETS) *~ #* core
+
+ depend:
+- $(CPP) -M $(CFLAGS) $(PPPDSRCS) >.depend
++ $(CPP) -M $(CPPFLAGS) $(CFLAGS) $(PPPDSRCS) >.depend
diff --git a/package/ppp/patches/patch-pppd_chap_ms_c b/package/ppp/patches/patch-pppd_chap_ms_c
index c20fc8163..b829221d4 100644
--- a/package/ppp/patches/patch-pppd_chap_ms_c
+++ b/package/ppp/patches/patch-pppd_chap_ms_c
@@ -1,6 +1,6 @@
---- ppp-2.4.4.orig/pppd/chap_ms.c 2006-05-21 13:56:40.000000000 +0200
-+++ ppp-2.4.4/pppd/chap_ms.c 2009-06-05 19:12:00.000000000 +0200
-@@ -897,13 +897,17 @@ set_mppe_enc_types(int policy, int types
+--- ppp-2.4.5.orig/pppd/chap_ms.c 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/chap_ms.c 2011-01-16 15:51:05.000000000 +0100
+@@ -898,13 +898,17 @@ set_mppe_enc_types(int policy, int types
/*
* Disable undesirable encryption types. Note that we don't ENABLE
* any encryption types, to avoid overriding manual configuration.
diff --git a/package/ppp/patches/patch-pppd_main_c b/package/ppp/patches/patch-pppd_main_c
index 22e6a64f8..630420deb 100644
--- a/package/ppp/patches/patch-pppd_main_c
+++ b/package/ppp/patches/patch-pppd_main_c
@@ -1,5 +1,5 @@
---- ppp-2.4.4.orig/pppd/main.c 2006-06-04 05:52:50.000000000 +0200
-+++ ppp-2.4.4/pppd/main.c 2009-06-05 19:12:00.000000000 +0200
+--- ppp-2.4.5.orig/pppd/main.c 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/main.c 2011-01-16 15:51:05.000000000 +0100
@@ -90,6 +90,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
@@ -8,7 +8,7 @@
#include "pppd.h"
#include "magic.h"
-@@ -227,6 +228,7 @@ static struct subprocess *children;
+@@ -228,6 +229,7 @@ static struct subprocess *children;
/* Prototypes for procedures local to this file. */
@@ -16,7 +16,7 @@
static void setup_signals __P((void));
static void create_pidfile __P((int pid));
static void create_linkpidfile __P((int pid));
-@@ -529,6 +531,7 @@ main(argc, argv)
+@@ -530,6 +532,7 @@ main(argc, argv)
info("Starting link");
}
@@ -24,7 +24,7 @@
gettimeofday(&start_time, NULL);
script_unsetenv("CONNECT_TIME");
script_unsetenv("BYTES_SENT");
-@@ -1262,6 +1265,36 @@ struct callout {
+@@ -1263,6 +1266,36 @@ struct callout {
static struct callout *callout = NULL; /* Callout list */
static struct timeval timenow; /* Current time */
@@ -61,7 +61,7 @@
/*
* timeout - Schedule a timeout.
-@@ -1332,6 +1365,8 @@ calltimeout()
+@@ -1333,6 +1366,8 @@ calltimeout()
{
struct callout *p;
@@ -70,7 +70,7 @@
while (callout != NULL) {
p = callout;
-@@ -1359,6 +1394,8 @@ timeleft(tvp)
+@@ -1360,6 +1395,8 @@ timeleft(tvp)
{
if (callout == NULL)
return NULL;
diff --git a/package/ppp/patches/patch-pppd_plugins_Makefile_linux b/package/ppp/patches/patch-pppd_plugins_Makefile_linux
new file mode 100644
index 000000000..9f78f3d19
--- /dev/null
+++ b/package/ppp/patches/patch-pppd_plugins_Makefile_linux
@@ -0,0 +1,29 @@
+--- ppp-2.4.5.orig/pppd/plugins/Makefile.linux 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/plugins/Makefile.linux 2011-01-16 17:14:34.000000000 +0100
+@@ -1,13 +1,8 @@
+-#CC = gcc
+-COPTS = -O2 -g
+-CFLAGS = $(COPTS) -I.. -I../../include -fPIC
+-LDFLAGS = -shared
+-INSTALL = install
++include ../../makedefs.linux
+
+-DESTDIR = $(INSTROOT)@DESTDIR@
+-BINDIR = $(DESTDIR)/sbin
+-MANDIR = $(DESTDIR)/share/man/man8
+-LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
++CPPFLAGS += -I.. -I../../include
++CFLAGS += -fPIC
++LDFLAGS += -shared
+
+ SUBDIRS := rp-pppoe pppoatm pppol2tp
+ # Uncomment the next line to include the radius authentication plugin
+@@ -23,7 +18,7 @@ all: $(PLUGINS)
+ for d in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$d all; done
+
+ %.so: %.c
+- $(CC) -o $@ $(LDFLAGS) $(CFLAGS) $^
++ $(CC) -o $@ $(LDFLAGS) $(CPPFLAGS) $(CFLAGS) $^
+
+ VERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../patchlevel.h)
+
diff --git a/package/ppp/patches/patch-pppd_plugins_pppoatm_Makefile_linux b/package/ppp/patches/patch-pppd_plugins_pppoatm_Makefile_linux
new file mode 100644
index 000000000..e7fb3f5e7
--- /dev/null
+++ b/package/ppp/patches/patch-pppd_plugins_pppoatm_Makefile_linux
@@ -0,0 +1,36 @@
+--- ppp-2.4.5.orig/pppd/plugins/pppoatm/Makefile.linux 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/plugins/pppoatm/Makefile.linux 2011-01-16 21:12:55.000000000 +0100
+@@ -1,13 +1,10 @@
+-#CC = gcc
+-COPTS = -O2 -g
+-CFLAGS = $(COPTS) -I../.. -I../../../include -fPIC
+-LDFLAGS = -shared
+-INSTALL = install
++include ../../../makedefs.linux
+
+-#***********************************************************************
++CPPFLAGS += -I../.. -I../../../include
++CFLAGS += -fPIC
++LDFLAGS += -shared
+
+-DESTDIR = $(INSTROOT)@DESTDIR@
+-LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
++#***********************************************************************
+
+ VERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h)
+
+@@ -33,7 +30,7 @@ endif
+ all: $(PLUGIN)
+
+ $(PLUGIN): $(PLUGIN_OBJS)
+- $(CC) $(CFLAGS) -o $@ -shared $^ $(LIBS)
++ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+ install: all
+ $(INSTALL) -d -m 755 $(LIBDIR)
+@@ -43,4 +40,4 @@ clean:
+ rm -f *.o *.so
+
+ %.o: %.c
+- $(CC) $(CFLAGS) -c -o $@ $<
++ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
diff --git a/package/ppp/patches/patch-pppd_plugins_pppol2tp_Makefile_linux b/package/ppp/patches/patch-pppd_plugins_pppol2tp_Makefile_linux
new file mode 100644
index 000000000..4c46c5971
--- /dev/null
+++ b/package/ppp/patches/patch-pppd_plugins_pppol2tp_Makefile_linux
@@ -0,0 +1,41 @@
+--- ppp-2.4.5.orig/pppd/plugins/pppol2tp/Makefile.linux 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/plugins/pppol2tp/Makefile.linux 2011-01-16 21:32:19.000000000 +0100
+@@ -1,13 +1,10 @@
+-#CC = gcc
+-COPTS = -O2 -g
+-CFLAGS = $(COPTS) -I. -I../.. -I../../../include -fPIC
+-LDFLAGS = -shared
+-INSTALL = install
++include ../../../makedefs.linux
+
+-#***********************************************************************
++CPPFLAGS += -I. -I../.. -I../../../include
++#CFLAGS += -fPIC
++#LDFLAGS += -shared
+
+-DESTDIR = @DESTDIR@
+-LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
++#***********************************************************************
+
+ VERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h)
+
+@@ -16,7 +13,11 @@ PLUGINS := pppol2tp.so openl2tp.so
+ all: $(PLUGINS)
+
+ %.so: %.o
+- $(CC) $(CFLAGS) -o $@ -shared $^ $(LIBS)
++ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
++ echo $(LDFLAGS)
++
++%.o: %.c
++ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
+
+ install: all
+ $(INSTALL) -d -m 755 $(LIBDIR)
+@@ -25,5 +26,4 @@ install: all
+ clean:
+ rm -f *.o *.so
+
+-%.o: %.c
+- $(CC) $(CFLAGS) -c -o $@ $<
++.PHONY: clean
diff --git a/package/ppp/patches/patch-pppd_plugins_radius_Makefile_linux b/package/ppp/patches/patch-pppd_plugins_radius_Makefile_linux
index bee2a80cf..d01aeb86c 100644
--- a/package/ppp/patches/patch-pppd_plugins_radius_Makefile_linux
+++ b/package/ppp/patches/patch-pppd_plugins_radius_Makefile_linux
@@ -1,16 +1,28 @@
---- ppp-2.4.4.orig/pppd/plugins/radius/Makefile.linux 2006-06-04 07:04:14.000000000 +0200
-+++ ppp-2.4.4/pppd/plugins/radius/Makefile.linux 2009-06-05 19:12:00.000000000 +0200
-@@ -12,7 +12,8 @@ VERSION = $(shell awk -F '"' '/VERSION/
- INSTALL = install
+--- ppp-2.4.5.orig/pppd/plugins/radius/Makefile.linux 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/plugins/radius/Makefile.linux 2011-01-16 21:35:47.000000000 +0100
+@@ -1,18 +1,14 @@
+ # Makefile for RADIUS plugin
+ #
+ # Copyright 2002 Roaring Penguin Software Inc.
+-#
+
+-DESTDIR = $(INSTROOT)@DESTDIR@
+-MANDIR = $(DESTDIR)/share/man/man8
+-LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
++include ../../../makedefs.linux
+
+-VERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h)
++CPPFLAGS+=-I. -I../.. -I../../../include -DRC_LOG_FACILITY=LOG_DAEMON
+
+-INSTALL = install
++VERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h)
PLUGIN=radius.so radattr.so radrealms.so
-CFLAGS=-I. -I../.. -I../../../include -O2 -fPIC -DRC_LOG_FACILITY=LOG_DAEMON
-+COPTS = -O2
-+CFLAGS=-I. -I../.. -I../../../include $(COPTS) -fPIC -DRC_LOG_FACILITY=LOG_DAEMON
# Uncomment the next line to include support for Microsoft's
# MS-CHAP authentication protocol.
-@@ -36,9 +37,9 @@ all: $(PLUGIN)
+@@ -36,25 +32,26 @@ all: $(PLUGIN)
install: all
$(INSTALL) -d -m 755 $(LIBDIR)
@@ -23,9 +35,21 @@
$(INSTALL) -c -m 444 pppd-radius.8 $(MANDIR)
$(INSTALL) -c -m 444 pppd-radattr.8 $(MANDIR)
-@@ -54,7 +55,7 @@ radrealms.so: radrealms.o
+ radius.so: radius.o libradiusclient.a
+- $(CC) -o radius.so -shared radius.o libradiusclient.a
++ $(CC) $(LDFLAGS) -o radius.so radius.o libradiusclient.a
+
+ radattr.so: radattr.o
+- $(CC) -o radattr.so -shared radattr.o
++ $(CC) $(LDFLAGS) -o radattr.so radattr.o
+
+ radrealms.so: radrealms.o
+- $(CC) -o radrealms.so -shared radrealms.o
++ $(CC) $(LDFLAGS) -o radrealms.so radrealms.o
+
CLIENTOBJS = avpair.o buildreq.o config.o dict.o ip_util.o \
clientid.o sendserver.o lock.o util.o md5.o
++
libradiusclient.a: $(CLIENTOBJS)
- $(AR) rv $@ $?
+ $(TARGET_AR) rcsv $@ $?
diff --git a/package/ppp/patches/patch-pppd_plugins_rp-pppoe_Makefile_linux b/package/ppp/patches/patch-pppd_plugins_rp-pppoe_Makefile_linux
new file mode 100644
index 000000000..09d845f6a
--- /dev/null
+++ b/package/ppp/patches/patch-pppd_plugins_rp-pppoe_Makefile_linux
@@ -0,0 +1,80 @@
+--- ppp-2.4.5.orig/pppd/plugins/rp-pppoe/Makefile.linux 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/plugins/rp-pppoe/Makefile.linux 2011-01-16 21:38:08.000000000 +0100
+@@ -1,6 +1,3 @@
+-# Generated automatically from Makefile.in by configure.
+-#***********************************************************************
+-#
+ # Makefile
+ #
+ # Makefile for Roaring Penguin's Linux PPPoE plugin.
+@@ -13,52 +10,50 @@
+ #
+ # $Id: Makefile.linux,v 1.8 2008/06/09 08:34:23 paulus Exp $
+ #***********************************************************************
+-
+-DESTDIR = $(INSTROOT)@DESTDIR@
+-BINDIR = $(DESTDIR)/sbin
+-LIBDIR = $(DESTDIR)/lib/pppd/$(PPPDVERSION)
+-
+-PPPDVERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h)
+-
+-INSTALL = install
++include ../../../makedefs.linux
+
+ # Version is set ONLY IN THE MAKEFILE! Don't delete this!
+ RP_VERSION=3.8p
+
+-COPTS=-O2 -g
+-CFLAGS=$(COPTS) -I../../../include '-DRP_VERSION="$(RP_VERSION)"'
++CPPFLAGS += -I../../.. -I../../../include '-DRP_VERSION="$(RP_VERSION)"'
++CFLAGS += -fPIC
++LDFLAGS += -shared
++
++VERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h)
++
+ all: rp-pppoe.so pppoe-discovery
+
+ pppoe-discovery: pppoe-discovery.o debug.o
+- $(CC) -o pppoe-discovery pppoe-discovery.o debug.o
++ $(CC) $(LDFLAGS) -o pppoe-discovery pppoe-discovery.o debug.o
+
+ pppoe-discovery.o: pppoe-discovery.c
+- $(CC) $(CFLAGS) -c -o pppoe-discovery.o pppoe-discovery.c
++ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $^
+
+ debug.o: debug.c
+- $(CC) $(CFLAGS) -c -o debug.o debug.c
++ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $^
+
+ rp-pppoe.so: plugin.o discovery.o if.o common.o
+- $(CC) -o rp-pppoe.so -shared plugin.o discovery.o if.o common.o
++ $(CC) $(LDFLAGS) -o $@ $^
+
+ install: all
+ $(INSTALL) -d -m 755 $(LIBDIR)
+- $(INSTALL) -s -c -m 4550 rp-pppoe.so $(LIBDIR)
++ $(INSTALL) -c -m 4550 rp-pppoe.so $(LIBDIR)
+ $(INSTALL) -d -m 755 $(BINDIR)
+- $(INSTALL) -s -c -m 555 pppoe-discovery $(BINDIR)
++ $(INSTALL) -c -m 555 pppoe-discovery $(BINDIR)
+
+ clean:
+ rm -f *.o *.so pppoe-discovery
+
+ plugin.o: plugin.c
+- $(CC) $(CFLAGS) -I../../.. -c -o plugin.o -fPIC plugin.c
++ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o plugin.o plugin.c
+
+ discovery.o: discovery.c
+- $(CC) $(CFLAGS) -I../../.. -c -o discovery.o -fPIC discovery.c
++ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o discovery.o discovery.c
+
+ if.o: if.c
+- $(CC) $(CFLAGS) -I../../.. -c -o if.o -fPIC if.c
++ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o if.o if.c
+
+ common.o: common.c
+- $(CC) $(CFLAGS) -I../../.. -c -o common.o -fPIC common.c
++ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o common.o common.c
+
++.PHONY: clean
diff --git a/package/ppp/patches/patch-pppd_pppd_8 b/package/ppp/patches/patch-pppd_pppd_8
index 4e19f91d2..c877824eb 100644
--- a/package/ppp/patches/patch-pppd_pppd_8
+++ b/package/ppp/patches/patch-pppd_pppd_8
@@ -1,6 +1,6 @@
---- ppp-2.4.4.orig/pppd/pppd.8 2006-06-16 02:01:23.000000000 +0200
-+++ ppp-2.4.4/pppd/pppd.8 2009-06-05 19:12:00.000000000 +0200
-@@ -627,9 +627,29 @@ control, as for the \fIcrtscts\fR option
+--- ppp-2.4.5.orig/pppd/pppd.8 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppd/pppd.8 2011-01-16 15:51:05.000000000 +0100
+@@ -638,9 +638,29 @@ control, as for the \fIcrtscts\fR option
Enables the use of PPP multilink; this is an alias for the `multilink'
option. This option is currently only available under Linux.
.TP
@@ -33,7 +33,7 @@
.TP
.B mpshortseq
Enables the use of short (12-bit) sequence numbers in multilink
-@@ -767,17 +787,11 @@ peer is buggy.
+@@ -778,17 +798,11 @@ peer is buggy.
Disables the use of PPP multilink. This option is currently only
available under Linux.
.TP
@@ -55,7 +55,7 @@
.TP
.B nompshortseq
Disables the use of short (12-bit) sequence numbers in the PPP
-@@ -958,19 +972,6 @@ peer using PAP.
+@@ -980,19 +994,6 @@ peer using PAP.
Require the peer to authenticate itself using CHAP [Challenge
Handshake Authentication Protocol] authentication.
.TP
diff --git a/package/ppp/patches/patch-pppdump_Makefile_linux b/package/ppp/patches/patch-pppdump_Makefile_linux
index 10a5e2728..796548ab7 100644
--- a/package/ppp/patches/patch-pppdump_Makefile_linux
+++ b/package/ppp/patches/patch-pppdump_Makefile_linux
@@ -1,19 +1,33 @@
---- ppp-2.4.4.orig/pppdump/Makefile.linux 2006-06-04 07:04:14.000000000 +0200
-+++ ppp-2.4.4/pppdump/Makefile.linux 2009-06-05 19:12:00.000000000 +0200
-@@ -2,7 +2,8 @@ DESTDIR = $(INSTROOT)@DESTDIR@
- BINDIR = $(DESTDIR)/sbin
- MANDIR = $(DESTDIR)/share/man/man8
+--- ppp-2.4.5.orig/pppdump/Makefile.linux 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppdump/Makefile.linux 2011-01-16 16:58:39.000000000 +0100
+@@ -1,21 +1,19 @@
+-DESTDIR = $(INSTROOT)@DESTDIR@
+-BINDIR = $(DESTDIR)/sbin
+-MANDIR = $(DESTDIR)/share/man/man8
++include ../makedefs.linux
-CFLAGS= -O -I../include/net
-+COPTS = -O
-+CFLAGS= $(COPTS) -I../include/net
++CPPFLAGS+= -I../include/net
OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
- INSTALL= install
-@@ -17,5 +18,5 @@ clean:
+-INSTALL= install
+-
+ all: pppdump
+
+ pppdump: $(OBJS)
+- $(CC) -o pppdump $(OBJS)
+-
+-clean:
+- rm -f pppdump $(OBJS) *~
++ $(CC) $(LDFLAGS) -o pppdump $(OBJS)
install:
mkdir -p $(BINDIR) $(MANDIR)
- $(INSTALL) -s -c pppdump $(BINDIR)
+ $(INSTALL) -c pppdump $(BINDIR)
$(INSTALL) -c -m 444 pppdump.8 $(MANDIR)
++
++clean:
++ rm -f pppdump $(OBJS) *~
++
++.PHONY: clean
diff --git a/package/ppp/patches/patch-pppstats_Makefile_linux b/package/ppp/patches/patch-pppstats_Makefile_linux
index 8c02431dd..81dfd920b 100644
--- a/package/ppp/patches/patch-pppstats_Makefile_linux
+++ b/package/ppp/patches/patch-pppstats_Makefile_linux
@@ -1,11 +1,48 @@
---- ppp-2.4.4.orig/pppstats/Makefile.linux 2006-06-04 07:07:46.000000000 +0200
-+++ ppp-2.4.4/pppstats/Makefile.linux 2009-06-05 19:12:00.000000000 +0200
-@@ -22,7 +22,7 @@ all: pppstats
+--- ppp-2.4.5.orig/pppstats/Makefile.linux 2009-11-16 23:26:07.000000000 +0100
++++ ppp-2.4.5/pppstats/Makefile.linux 2011-01-16 17:11:22.000000000 +0100
+@@ -1,36 +1,27 @@
+ #
+ # pppstats makefile
+ # $Id: Makefile.linux,v 1.9 2006/06/04 05:07:46 paulus Exp $
+-#
+-DESTDIR = $(INSTROOT)@DESTDIR@
+-BINDIR = $(DESTDIR)/sbin
+-MANDIR = $(DESTDIR)/share/man/man8
++include ../makedefs.linux
++
++CPPFLAGS += -I../include
+ PPPSTATSRCS = pppstats.c
+ PPPSTATOBJS = pppstats.o
+
+-#CC = gcc
+-COPTS = -O
+-COMPILE_FLAGS = -I../include
+-LIBS =
+-
+-INSTALL= install
+-
+-CFLAGS = $(COPTS) $(COMPILE_FLAGS)
+-
+ all: pppstats
+
++pppstats: $(PPPSTATSRCS)
++ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDLAGS) -o pppstats pppstats.c $(LIBS)
++
install: pppstats
-mkdir -p $(MANDIR)
- $(INSTALL) -s -c pppstats $(BINDIR)
+ $(INSTALL) -c pppstats $(BINDIR)
$(INSTALL) -c -m 444 pppstats.8 $(MANDIR)
- pppstats: $(PPPSTATSRCS)
+-pppstats: $(PPPSTATSRCS)
+- $(CC) $(CFLAGS) -o pppstats pppstats.c $(LIBS)
+-
+ clean:
+ rm -f pppstats *~ #* core
+
+ depend:
+ cpp -M $(CFLAGS) $(PPPSTATSRCS) >.depend
+-# makedepend $(CFLAGS) $(PPPSTATSRCS)
++
++.PHONY: clean
diff --git a/package/ppp/src/makedefs.linux b/package/ppp/src/makedefs.linux
new file mode 100644
index 000000000..061efabc6
--- /dev/null
+++ b/package/ppp/src/makedefs.linux
@@ -0,0 +1,14 @@
+CC ?= gcc
+CPPFLAGS ?=
+CFLAGS ?= -O -pipe
+LDFLAGS ?=
+LIBS ?=
+
+INSTALL ?= install
+
+# Default installation locations
+DESTDIR = $(INSTROOT)/usr
+BINDIR = $(DESTDIR)/sbin
+MANDIR = $(DESTDIR)/share/man/man8
+INCDIR = $(DESTDIR)/include
+LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
diff --git a/package/pptp/Makefile b/package/pptp/Makefile
index c68d50958..d789c8003 100644
--- a/package/pptp/Makefile
+++ b/package/pptp/Makefile
@@ -19,9 +19,6 @@ $(eval $(call PKG_template,PPTP,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_
CONFIG_STYLE:= manual
INSTALL_STYLE:= manual
-MAKE_FLAGS+= CC="${TARGET_CC}" \
- CFLAGS="${TARGET_CFLAGS}"
-
do-install:
${INSTALL_DIR} ${IDIR_PPTP}/sbin
${INSTALL_DIR} ${IDIR_PPTP}/usr/sbin
diff --git a/package/pptp/patches/patch-Makefile b/package/pptp/patches/patch-Makefile
new file mode 100644
index 000000000..1b7ad4a3d
--- /dev/null
+++ b/package/pptp/patches/patch-Makefile
@@ -0,0 +1,22 @@
+--- pptp-1.6.0.orig/Makefile 2005-02-18 02:42:45.000000000 +0100
++++ pptp-1.6.0/Makefile 2011-01-16 21:44:38.000000000 +0100
+@@ -11,14 +11,15 @@ BINDIR=$(DESTDIR)/usr/sbin
+ MANDIR=$(DESTDIR)/usr/share/man/man8
+ PPPDIR=$(DESTDIR)/etc/ppp
+
+-CC = gcc
++CC ?= gcc
+ RM = rm -f
+ OPTIMIZE= -O0
+ DEBUG = -g
+ INCLUDE =
+-CFLAGS = -Wall $(OPTIMIZE) $(DEBUG) $(INCLUDE)
+-LIBS = -lutil
+-LDFLAGS =
++CPPFLAGS ?=
++CFLAGS ?= -Wall $(OPTIMIZE) $(DEBUG) $(INCLUDE)
++LIBS ?= -lutil
++LDFLAGS ?=
+
+ PPTP_BIN = pptp
+
diff --git a/package/procmail/src/Makefile.new b/package/procmail/src/Makefile.new
index 38b092ce9..8ec246b2b 100644
--- a/package/procmail/src/Makefile.new
+++ b/package/procmail/src/Makefile.new
@@ -6,8 +6,8 @@ PM_OBJ=cstdio.o common.o exopen.o goodies.o locking.o \
FM_OBJ=common.o fields.o formisc.o sublib.o ecommon.o \
acommon.o
-LDFLAGS = -lm -ldl -lc
-CFLAGS = -Os -DPROCMAIL
+LDFLAGS ?= -lm -ldl -lc
+CFLAGS ?= -DPROCMAIL
all: procmail formail
diff --git a/package/proftpd/Makefile b/package/proftpd/Makefile
index 6cfa849ac..fbae31c18 100644
--- a/package/proftpd/Makefile
+++ b/package/proftpd/Makefile
@@ -13,6 +13,9 @@ PKG_URL:= http://www.proftpd.org/
PKG_SITES:= ftp://ftp.proftpd.org/distrib/source/
PKG_NOPARALLEL:= 1
+PKG_FLAVOURS_PROFTPD:= WITH_FTPUSERS
+PKGFD_WITH_FTPUSERS:= install /etc/ftpusers along with proftpd
+
include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,PROFTPD,$(PKG_NAME),$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
@@ -29,5 +32,8 @@ post-install:
$(IDIR_PROFTPD)/usr/bin/
$(INSTALL_BIN) $(WRKINST)/usr/sbin/{ftpshut,proftpd} \
$(IDIR_PROFTPD)/usr/sbin/
+ifeq (${ADK_PACKAGE_PROFTPD_WITH_FTPUSERS},y)
+ ${INSTALL_DATA} ./files/ftpusers ${IDIR_PROFTPD}/etc/
+endif
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/proftpd/files/ftpusers b/package/proftpd/files/ftpusers
new file mode 100644
index 000000000..4bc8872dc
--- /dev/null
+++ b/package/proftpd/files/ftpusers
@@ -0,0 +1,37 @@
+# Provided by ftpbase (dont remove this line!)
+# /etc/ftpusers: list of users disallowed FTP access
+# $Header: /var/cvsroot/gentoo-x86/net-ftp/ftpbase/files/ftpusers,v 1.1 2005/06/28 14:52:26 uberlord Exp $
+
+halt
+operator
+root
+shutdown
+sync
+bin
+daemon
+adm
+lp
+mail
+postmaster
+news
+uucp
+man
+games
+at
+cron
+www
+named
+squid
+gdm
+mysql
+postgres
+guest
+nobody
+alias
+qmaild
+qmaill
+qmailp
+qmailq
+qmailr
+qmails
+postfix
diff --git a/package/proftpd/files/proftpd.conffiles b/package/proftpd/files/proftpd.conffiles
index 9796c366f..3ff0fb2e3 100644
--- a/package/proftpd/files/proftpd.conffiles
+++ b/package/proftpd/files/proftpd.conffiles
@@ -1 +1,2 @@
/etc/proftpd.conf
+/etc/ftpusers
diff --git a/package/python2/Makefile b/package/python2/Makefile
index ac40ca66f..dc9092dd9 100644
--- a/package/python2/Makefile
+++ b/package/python2/Makefile
@@ -9,10 +9,11 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= 15ed56733655e3fab785e49a7278d2fb
PKG_DESCR:= Python scripting language (Version 2)
PKG_SECTION:= lang
-PKG_DEPENDS:= libpthread zlib libffi
-PKG_BUILDDEP:= zlib libffi
+PKG_DEPENDS:= libpthread zlib libffi libopenssl
+PKG_BUILDDEP:= zlib libffi openssl
PKG_URL:= http://www.python.org/
PKG_SITES:= http://www.python.org/ftp/python/${PKG_VERSION}/
+PKG_OPTS:= noscripts
PKG_HOST_DEPENDS:= !netbsd !openbsd !cygwin
@@ -21,7 +22,7 @@ WRKDIST= ${WRKDIR}/Python-${PKG_VERSION}
include ${TOPDIR}/mk/package.mk
-$(eval $(call PKG_template,PYTHON2,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+$(eval $(call PKG_template,PYTHON2,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
MAKE_ENV+= OPT="$(TARGET_CFLAGS)" \
RANLIB="${TARGET_CROSS}ranlib" \
@@ -39,12 +40,12 @@ post-extract:
(cd ${WRKBUILD}; rm -rf config.{cache,status} ; \
OPT="$(HOSTCFLAGS)" \
./configure --without-cxx-main --without-threads \
- --prefix=$(STAGING_HOST_DIR) \
+ --prefix=$(STAGING_HOST_DIR)/usr \
);
$(MAKE) -C ${WRKBUILD} python Parser/pgen
$(MAKE) -C ${WRKBUILD} install
- ${CP} ${WRKBUILD}/Parser/pgen ${STAGING_HOST_DIR}/bin/pgen
- ${CP} ${WRKBUILD}/python ${STAGING_HOST_DIR}/bin/hostpython
+ ${CP} ${WRKBUILD}/Parser/pgen ${STAGING_HOST_DIR}/usr/bin/pgen
+ ${CP} ${WRKBUILD}/python ${STAGING_HOST_DIR}/usr/bin/hostpython
${CP} ${WRKBUILD}/Parser/pgen ${WRKBUILD}/Parser/hostpgen
${CP} ${WRKBUILD}/python ${WRKBUILD}/hostpython
$(MAKE) -C ${WRKBUILD} clean
@@ -61,5 +62,8 @@ post-install:
${CP} ${WRKINST}/usr/lib/python2.7/* ${IDIR_PYTHON2}/usr/lib/python2.7
${CP} ${WRKINST}/usr/include/python2.7/* ${IDIR_PYTHON2}/usr/include/python2.7
-find ${IDIR_PYTHON2} -name "\*.pyc" -o -name "*\.pyo" -exec rm {} \;
+ # workaround, copy host python-config to target scripts directory
+ ${CP} ${STAGING_HOST_DIR}/usr/bin/python*-config ${STAGING_TARGET_DIR}/scripts
+ ${CP} ${STAGING_HOST_DIR}/usr/bin/python*-config ${STAGING_TARGET_DIR}/usr/bin
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/python2/files/python-config.in b/package/python2/files/python-config.in
index 8419bd84a..0074d0304 100644
--- a/package/python2/files/python-config.in
+++ b/package/python2/files/python-config.in
@@ -38,8 +38,8 @@ for opt in opt_flags:
print sysconfig.EXEC_PREFIX
elif opt in ('--includes', '--cflags'):
- flags = ['-I' + re.sub('host/', 'target/usr/', sysconfig.get_python_inc()),
- '-I' + re.sub('host/', 'target/usr/', sysconfig.get_python_inc(plat_specific=True))]
+ flags = ['-I' + re.sub('host_', 'target_', sysconfig.get_python_inc()),
+ '-I' + re.sub('host_', 'target_', sysconfig.get_python_inc(plat_specific=True))]
if opt == '--cflags':
flags.extend(getvar('CFLAGS').split())
print ' '.join(flags)
diff --git a/package/python2/patches/patch-Misc_python_pc b/package/python2/patches/patch-Misc_python_pc
deleted file mode 100644
index 174230d83..000000000
--- a/package/python2/patches/patch-Misc_python_pc
+++ /dev/null
@@ -1,11 +0,0 @@
---- Python-2.7.1.orig/Misc/python.pc 2010-12-27 21:24:34.000000000 +0100
-+++ Python-2.7.1/Misc/python.pc 2010-12-27 21:07:05.000000000 +0100
-@@ -7,7 +7,7 @@ Name: Python
- Description: Python library
- Requires:
- Version: 2.7
--Libs.private: -ldl -framework CoreFoundation
-+Libs.private: -lpthread -ldl -lpthread
- Libs: -L${libdir} -lpython2.7
- Cflags: -I${includedir}/python2.7
-
diff --git a/package/python2/patches/patch-pyconfig_h b/package/python2/patches/patch-pyconfig_h
deleted file mode 100644
index 52e21767c..000000000
--- a/package/python2/patches/patch-pyconfig_h
+++ /dev/null
@@ -1,521 +0,0 @@
---- Python-2.7.1.orig/pyconfig.h 2010-12-27 21:24:34.000000000 +0100
-+++ Python-2.7.1/pyconfig.h 2010-12-27 21:07:05.000000000 +0100
-@@ -32,10 +32,10 @@
-
- /* Define if C doubles are 64-bit IEEE 754 binary format, stored with the
- least significant byte first */
--#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 1
-+/* #undef DOUBLE_IS_LITTLE_ENDIAN_IEEE754 */
-
- /* Define if --enable-ipv6 is specified */
--#define ENABLE_IPV6 1
-+/* #undef ENABLE_IPV6 */
-
- /* Define if flock needs to be linked with bsd library. */
- /* #undef FLOCK_NEEDS_LIBBSD */
-@@ -63,7 +63,7 @@
- #define HAVE_ASINH 1
-
- /* Define to 1 if you have the <asm/types.h> header file. */
--/* #undef HAVE_ASM_TYPES_H */
-+#define HAVE_ASM_TYPES_H 1
-
- /* Define to 1 if you have the `atanh' function. */
- #define HAVE_ATANH 1
-@@ -75,7 +75,7 @@
- /* #undef HAVE_BIND_TEXTDOMAIN_CODESET */
-
- /* Define to 1 if you have the <bluetooth/bluetooth.h> header file. */
--/* #undef HAVE_BLUETOOTH_BLUETOOTH_H */
-+#define HAVE_BLUETOOTH_BLUETOOTH_H 1
-
- /* Define to 1 if you have the <bluetooth.h> header file. */
- /* #undef HAVE_BLUETOOTH_H */
-@@ -126,7 +126,7 @@
- #define HAVE_CTERMID 1
-
- /* Define if you have the 'ctermid_r' function. */
--#define HAVE_CTERMID_R 1
-+/* #undef HAVE_CTERMID_R */
-
- /* Define to 1 if you have the <curses.h> header file. */
- #define HAVE_CURSES_H 1
-@@ -185,7 +185,7 @@
- #define HAVE_DYNAMIC_LOADING 1
-
- /* Define if you have the 'epoll' functions. */
--/* #undef HAVE_EPOLL */
-+#define HAVE_EPOLL 1
-
- /* Define to 1 if you have the `erf' function. */
- #define HAVE_ERF 1
-@@ -215,10 +215,10 @@
- #define HAVE_FCNTL_H 1
-
- /* Define if you have the 'fdatasync' function. */
--/* #undef HAVE_FDATASYNC */
-+#define HAVE_FDATASYNC 1
-
- /* Define to 1 if you have the `finite' function. */
--#define HAVE_FINITE 1
-+/* #undef HAVE_FINITE */
-
- /* Define to 1 if you have the `flock' function. */
- #define HAVE_FLOCK 1
-@@ -227,7 +227,7 @@
- #define HAVE_FORK 1
-
- /* Define to 1 if you have the `forkpty' function. */
--#define HAVE_FORKPTY 1
-+/* #undef HAVE_FORKPTY */
-
- /* Define to 1 if you have the `fpathconf' function. */
- #define HAVE_FPATHCONF 1
-@@ -267,7 +267,7 @@
- #define HAVE_GCC_ASM_FOR_X87 1
-
- /* Define if you have the getaddrinfo function. */
--#define HAVE_GETADDRINFO 1
-+/* #undef HAVE_GETADDRINFO */
-
- /* Define to 1 if you have the `getcwd' function. */
- #define HAVE_GETCWD 1
-@@ -279,10 +279,10 @@
- #define HAVE_GETGROUPS 1
-
- /* Define to 1 if you have the `gethostbyname' function. */
--#define HAVE_GETHOSTBYNAME 1
-+/* #undef HAVE_GETHOSTBYNAME */
-
- /* Define this if you have some version of gethostbyname_r() */
--/* #undef HAVE_GETHOSTBYNAME_R */
-+#define HAVE_GETHOSTBYNAME_R 1
-
- /* Define this if you have the 3-arg version of gethostbyname_r(). */
- /* #undef HAVE_GETHOSTBYNAME_R_3_ARG */
-@@ -291,13 +291,13 @@
- /* #undef HAVE_GETHOSTBYNAME_R_5_ARG */
-
- /* Define this if you have the 6-arg version of gethostbyname_r(). */
--/* #undef HAVE_GETHOSTBYNAME_R_6_ARG */
-+#define HAVE_GETHOSTBYNAME_R_6_ARG 1
-
- /* Define to 1 if you have the `getitimer' function. */
- #define HAVE_GETITIMER 1
-
- /* Define to 1 if you have the `getloadavg' function. */
--#define HAVE_GETLOADAVG 1
-+/* #undef HAVE_GETLOADAVG */
-
- /* Define to 1 if you have the `getlogin' function. */
- #define HAVE_GETLOGIN 1
-@@ -327,25 +327,25 @@
- #define HAVE_GETPWENT 1
-
- /* Define to 1 if you have the `getresgid' function. */
--/* #undef HAVE_GETRESGID */
-+#define HAVE_GETRESGID 1
-
- /* Define to 1 if you have the `getresuid' function. */
--/* #undef HAVE_GETRESUID */
-+#define HAVE_GETRESUID 1
-
- /* Define to 1 if you have the `getsid' function. */
- #define HAVE_GETSID 1
-
- /* Define to 1 if you have the `getspent' function. */
--/* #undef HAVE_GETSPENT */
-+#define HAVE_GETSPENT 1
-
- /* Define to 1 if you have the `getspnam' function. */
--/* #undef HAVE_GETSPNAM */
-+#define HAVE_GETSPNAM 1
-
- /* Define to 1 if you have the `gettimeofday' function. */
- #define HAVE_GETTIMEOFDAY 1
-
- /* Define to 1 if you have the `getwd' function. */
--#define HAVE_GETWD 1
-+/* #undef HAVE_GETWD */
-
- /* Define to 1 if you have the <grp.h> header file. */
- #define HAVE_GRP_H 1
-@@ -381,7 +381,7 @@
- #define HAVE_KILLPG 1
-
- /* Define if you have the 'kqueue' functions. */
--#define HAVE_KQUEUE 1
-+/* #undef HAVE_KQUEUE */
-
- /* Define to 1 if you have the <langinfo.h> header file. */
- #define HAVE_LANGINFO_H 1
-@@ -390,13 +390,13 @@
- and long long is available and at least as big as an off_t. You may need to
- add some flags for configuration and compilation to enable this mode. (For
- Solaris and Linux, the necessary defines are already defined.) */
--/* #undef HAVE_LARGEFILE_SUPPORT */
-+#define HAVE_LARGEFILE_SUPPORT 1
-
- /* Define to 1 if you have the `lchflags' function. */
- /* #undef HAVE_LCHFLAGS */
-
- /* Define to 1 if you have the `lchmod' function. */
--#define HAVE_LCHMOD 1
-+/* #undef HAVE_LCHMOD */
-
- /* Define to 1 if you have the `lchown' function. */
- #define HAVE_LCHOWN 1
-@@ -414,7 +414,7 @@
- /* #undef HAVE_LIBIEEE */
-
- /* Define to 1 if you have the <libintl.h> header file. */
--/* #undef HAVE_LIBINTL_H */
-+#define HAVE_LIBINTL_H 1
-
- /* Define if you have the readline library (-lreadline). */
- #define HAVE_LIBREADLINE 1
-@@ -429,10 +429,10 @@
- #define HAVE_LINK 1
-
- /* Define to 1 if you have the <linux/netlink.h> header file. */
--/* #undef HAVE_LINUX_NETLINK_H */
-+#define HAVE_LINUX_NETLINK_H 1
-
- /* Define to 1 if you have the <linux/tipc.h> header file. */
--/* #undef HAVE_LINUX_TIPC_H */
-+#define HAVE_LINUX_TIPC_H 1
-
- /* Define to 1 if you have the `log1p' function. */
- #define HAVE_LOG1P 1
-@@ -465,7 +465,7 @@
- #define HAVE_MKTIME 1
-
- /* Define to 1 if you have the `mremap' function. */
--/* #undef HAVE_MREMAP */
-+#define HAVE_MREMAP 1
-
- /* Define to 1 if you have the <ncurses.h> header file. */
- #define HAVE_NCURSES_H 1
-@@ -474,16 +474,16 @@
- /* #undef HAVE_NDIR_H */
-
- /* Define to 1 if you have the <netpacket/packet.h> header file. */
--/* #undef HAVE_NETPACKET_PACKET_H */
-+#define HAVE_NETPACKET_PACKET_H 1
-
- /* Define to 1 if you have the `nice' function. */
- #define HAVE_NICE 1
-
- /* Define to 1 if you have the `openpty' function. */
--#define HAVE_OPENPTY 1
-+/* #undef HAVE_OPENPTY */
-
- /* Define if compiling using MacOS X 10.5 SDK or later. */
--#define HAVE_OSX105_SDK 1
-+/* #undef HAVE_OSX105_SDK */
-
- /* Define to 1 if you have the `pathconf' function. */
- #define HAVE_PATHCONF 1
-@@ -519,10 +519,10 @@
- /* #undef HAVE_PTHREAD_INIT */
-
- /* Define to 1 if you have the `pthread_sigmask' function. */
--/* #undef HAVE_PTHREAD_SIGMASK */
-+#define HAVE_PTHREAD_SIGMASK 1
-
- /* Define to 1 if you have the <pty.h> header file. */
--/* #undef HAVE_PTY_H */
-+#define HAVE_PTY_H 1
-
- /* Define to 1 if you have the `putenv' function. */
- #define HAVE_PUTENV 1
-@@ -537,7 +537,7 @@
- #define HAVE_RL_CALLBACK 1
-
- /* Define if you can turn off readline's signal handling. */
--/* #undef HAVE_RL_CATCH_SIGNAL */
-+#define HAVE_RL_CATCH_SIGNAL 1
-
- /* Define if you have readline 2.2 */
- #define HAVE_RL_COMPLETION_APPEND_CHARACTER 1
-@@ -549,7 +549,7 @@
- #define HAVE_RL_COMPLETION_MATCHES 1
-
- /* Define if you have rl_completion_suppress_append */
--/* #undef HAVE_RL_COMPLETION_SUPPRESS_APPEND */
-+#define HAVE_RL_COMPLETION_SUPPRESS_APPEND 1
-
- /* Define if you have readline 4.0 */
- #define HAVE_RL_PRE_INPUT_HOOK 1
-@@ -567,7 +567,7 @@
- #define HAVE_SEM_OPEN 1
-
- /* Define to 1 if you have the `sem_timedwait' function. */
--/* #undef HAVE_SEM_TIMEDWAIT */
-+#define HAVE_SEM_TIMEDWAIT 1
-
- /* Define to 1 if you have the `sem_unlink' function. */
- #define HAVE_SEM_UNLINK 1
-@@ -600,10 +600,10 @@
- #define HAVE_SETREGID 1
-
- /* Define to 1 if you have the `setresgid' function. */
--/* #undef HAVE_SETRESGID */
-+#define HAVE_SETRESGID 1
-
- /* Define to 1 if you have the `setresuid' function. */
--/* #undef HAVE_SETRESUID */
-+#define HAVE_SETRESUID 1
-
- /* Define to 1 if you have the `setreuid' function. */
- #define HAVE_SETREUID 1
-@@ -618,7 +618,7 @@
- #define HAVE_SETVBUF 1
-
- /* Define to 1 if you have the <shadow.h> header file. */
--/* #undef HAVE_SHADOW_H */
-+#define HAVE_SHADOW_H 1
-
- /* Define to 1 if you have the `sigaction' function. */
- #define HAVE_SIGACTION 1
-@@ -630,13 +630,13 @@
- #define HAVE_SIGNAL_H 1
-
- /* Define to 1 if you have the `sigrelse' function. */
--#define HAVE_SIGRELSE 1
-+/* #undef HAVE_SIGRELSE */
-
- /* Define to 1 if you have the `snprintf' function. */
- #define HAVE_SNPRINTF 1
-
- /* Define if sockaddr has sa_len member */
--#define HAVE_SOCKADDR_SA_LEN 1
-+/* #undef HAVE_SOCKADDR_SA_LEN */
-
- /* struct sockaddr_storage (sys/socket.h) */
- #define HAVE_SOCKADDR_STORAGE 1
-@@ -645,7 +645,7 @@
- #define HAVE_SOCKETPAIR 1
-
- /* Define to 1 if you have the <spawn.h> header file. */
--#define HAVE_SPAWN_H 1
-+/* #undef HAVE_SPAWN_H */
-
- /* Define if your compiler provides ssize_t */
- #define HAVE_SSIZE_T 1
-@@ -654,10 +654,10 @@
- #define HAVE_STATVFS 1
-
- /* Define if you have struct stat.st_mtim.tv_nsec */
--/* #undef HAVE_STAT_TV_NSEC */
-+#define HAVE_STAT_TV_NSEC 1
-
- /* Define if you have struct stat.st_mtimensec */
--#define HAVE_STAT_TV_NSEC2 1
-+/* #undef HAVE_STAT_TV_NSEC2 */
-
- /* Define if your compiler supports variable length function prototypes (e.g.
- void fprintf(FILE *, char *, ...);) *and* <stdarg.h> */
-@@ -694,10 +694,10 @@
- #define HAVE_STRUCT_STAT_ST_BLOCKS 1
-
- /* Define to 1 if `st_flags' is a member of `struct stat'. */
--#define HAVE_STRUCT_STAT_ST_FLAGS 1
-+/* #undef HAVE_STRUCT_STAT_ST_FLAGS */
-
- /* Define to 1 if `st_gen' is a member of `struct stat'. */
--#define HAVE_STRUCT_STAT_ST_GEN 1
-+/* #undef HAVE_STRUCT_STAT_ST_GEN */
-
- /* Define to 1 if `st_rdev' is a member of `struct stat'. */
- #define HAVE_STRUCT_STAT_ST_RDEV 1
-@@ -729,10 +729,10 @@
- /* #undef HAVE_SYS_DIR_H */
-
- /* Define to 1 if you have the <sys/epoll.h> header file. */
--/* #undef HAVE_SYS_EPOLL_H */
-+#define HAVE_SYS_EPOLL_H 1
-
- /* Define to 1 if you have the <sys/event.h> header file. */
--#define HAVE_SYS_EVENT_H 1
-+/* #undef HAVE_SYS_EVENT_H */
-
- /* Define to 1 if you have the <sys/file.h> header file. */
- #define HAVE_SYS_FILE_H 1
-@@ -741,7 +741,7 @@
- /* #undef HAVE_SYS_LOADAVG_H */
-
- /* Define to 1 if you have the <sys/lock.h> header file. */
--#define HAVE_SYS_LOCK_H 1
-+/* #undef HAVE_SYS_LOCK_H */
-
- /* Define to 1 if you have the <sys/mkdev.h> header file. */
- /* #undef HAVE_SYS_MKDEV_H */
-@@ -829,7 +829,7 @@
- #define HAVE_TMPNAM 1
-
- /* Define to 1 if you have the `tmpnam_r' function. */
--/* #undef HAVE_TMPNAM_R */
-+#define HAVE_TMPNAM_R 1
-
- /* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
- `HAVE_STRUCT_TM_TM_ZONE' instead. */
-@@ -863,7 +863,7 @@
- /* #undef HAVE_USABLE_WCHAR_T */
-
- /* Define to 1 if you have the <util.h> header file. */
--#define HAVE_UTIL_H 1
-+/* #undef HAVE_UTIL_H */
-
- /* Define to 1 if you have the `utimes' function. */
- #define HAVE_UTIMES 1
-@@ -888,7 +888,7 @@
-
- /* Define if tzset() actually switches the local timezone in a meaningful way.
- */
--#define HAVE_WORKING_TZSET 1
-+/* #undef HAVE_WORKING_TZSET */
-
- /* Define if the zlib library has inflateCopy */
- #define HAVE_ZLIB_COPY 1
-@@ -953,7 +953,7 @@
- /* #undef Py_DEBUG */
-
- /* Defined if Python is built as a shared library. */
--/* #undef Py_ENABLE_SHARED */
-+#define Py_ENABLE_SHARED 1
-
- /* Define as the size of the unicode type. */
- #define Py_UNICODE_SIZE 2
-@@ -980,16 +980,16 @@
- #define SIZEOF_FLOAT 4
-
- /* The size of `fpos_t', as computed by sizeof. */
--#define SIZEOF_FPOS_T 8
-+#define SIZEOF_FPOS_T 20
-
- /* The size of `int', as computed by sizeof. */
- #define SIZEOF_INT 4
-
- /* The size of `long', as computed by sizeof. */
--#define SIZEOF_LONG 8
-+#define SIZEOF_LONG 4
-
- /* The size of `long double', as computed by sizeof. */
--#define SIZEOF_LONG_DOUBLE 16
-+#define SIZEOF_LONG_DOUBLE 12
-
- /* The size of `long long', as computed by sizeof. */
- #define SIZEOF_LONG_LONG 8
-@@ -1001,22 +1001,22 @@
- #define SIZEOF_PID_T 4
-
- /* The size of `pthread_t', as computed by sizeof. */
--#define SIZEOF_PTHREAD_T 8
-+#define SIZEOF_PTHREAD_T 4
-
- /* The size of `short', as computed by sizeof. */
- #define SIZEOF_SHORT 2
-
- /* The size of `size_t', as computed by sizeof. */
--#define SIZEOF_SIZE_T 8
-+#define SIZEOF_SIZE_T 4
-
- /* The size of `time_t', as computed by sizeof. */
--#define SIZEOF_TIME_T 8
-+#define SIZEOF_TIME_T 4
-
- /* The size of `uintptr_t', as computed by sizeof. */
--#define SIZEOF_UINTPTR_T 8
-+#define SIZEOF_UINTPTR_T 4
-
- /* The size of `void *', as computed by sizeof. */
--#define SIZEOF_VOID_P 8
-+#define SIZEOF_VOID_P 4
-
- /* The size of `wchar_t', as computed by sizeof. */
- #define SIZEOF_WCHAR_T 4
-@@ -1032,7 +1032,7 @@
- #define SYS_SELECT_WITH_SYS_TIME 1
-
- /* Define if tanh(-0.) is -0., or if platform doesn't have signed zeros */
--#define TANH_PRESERVES_ZERO_SIGN 1
-+/* #undef TANH_PRESERVES_ZERO_SIGN */
-
- /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
- #define TIME_WITH_SYS_TIME 1
-@@ -1063,10 +1063,10 @@
-
-
- /* Define if you want to use MacPython modules on MacOSX in unix-Python. */
--#define USE_TOOLBOX_OBJECT_GLUE 1
-+/* #undef USE_TOOLBOX_OBJECT_GLUE */
-
- /* Define if a va_list is an array of some kind */
--#define VA_LIST_IS_ARRAY 1
-+/* #undef VA_LIST_IS_ARRAY */
-
- /* Define if you want SIGFPE handled (see Include/pyfpe.h). */
- /* #undef WANT_SIGFPE_HANDLER */
-@@ -1076,7 +1076,7 @@
- /* #undef WANT_WCTYPE_FUNCTIONS */
-
- /* Define if WINDOW in curses.h offers a field _flags. */
--/* #undef WINDOW_HAS_FLAGS */
-+#define WINDOW_HAS_FLAGS 1
-
- /* Define if you want documentation strings in extension modules */
- #define WITH_DOC_STRINGS 1
-@@ -1084,10 +1084,10 @@
- /* Define if you want to use the new-style (Openstep, Rhapsody, MacOS) dynamic
- linker (dyld) instead of the old-style (NextStep) dynamic linker (rld).
- Dyld is necessary to support frameworks. */
--#define WITH_DYLD 1
-+/* #undef WITH_DYLD */
-
- /* Define to 1 if libintl is needed for locale functions. */
--/* #undef WITH_LIBINTL */
-+#define WITH_LIBINTL 1
-
- /* Define if you want to produce an OpenStep/Rhapsody framework (shared
- library plus accessory files). */
-@@ -1097,7 +1097,7 @@
- #define WITH_PYMALLOC 1
-
- /* Define if you want to compile in rudimentary thread support */
--/* #undef WITH_THREAD */
-+#define WITH_THREAD 1
-
- /* Define to profile with the Pentium timestamp counter */
- /* #undef WITH_TSC */
-@@ -1152,7 +1152,7 @@
- /* #undef _POSIX_1_SOURCE */
-
- /* Define to activate features from IEEE Stds 1003.1-2001 */
--/* #undef _POSIX_C_SOURCE */
-+#define _POSIX_C_SOURCE 200112L
-
- /* Define to 1 if you need to in order for `stat' and other things to work. */
- /* #undef _POSIX_SOURCE */
-@@ -1161,7 +1161,7 @@
- /* #undef _POSIX_THREADS */
-
- /* Define to force use of thread-safe errno, h_errno, and other functions */
--/* #undef _REENTRANT */
-+#define _REENTRANT 1
-
- /* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
-@@ -1174,10 +1174,10 @@
- /* #undef _UINT64_T */
-
- /* Define to the level of X/Open that your system supports */
--/* #undef _XOPEN_SOURCE */
-+#define _XOPEN_SOURCE 600
-
- /* Define to activate Unix95-and-earlier features */
--/* #undef _XOPEN_SOURCE_EXTENDED */
-+#define _XOPEN_SOURCE_EXTENDED 1
-
- /* Define on FreeBSD to activate all library features */
- #define __BSD_VISIBLE 1
diff --git a/package/qemu/Makefile b/package/qemu/Makefile
index 1bafddc94..4b8c33c9c 100644
--- a/package/qemu/Makefile
+++ b/package/qemu/Makefile
@@ -5,11 +5,12 @@ include $(TOPDIR)/rules.mk
PKG_NAME:= qemu
PKG_VERSION:= 0.13.0
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= 397a0d665da8ba9d3b9583629f3d6421
PKG_DESCR:= cpu and system emulator
PKG_SECTION:= misc
-PKG_BUILDDEP:= zlib
+PKG_DEPENDS:= zlib libSDL
+PKG_BUILDDEP:= zlib sdl
PKG_URL:= http://wwww.qemu.org/
PKG_SITES:= http://wiki.qemu.org/download/
@@ -24,10 +25,14 @@ CONFIGURE_ARGS+= --host-cc=$(HOSTCC) \
--prefix=/usr \
--sysconfdir=/etc \
--bindir=/usr/bin
+TLDFLAGS+= -pthread -lrt
post-install:
+ $(INSTALL_DIR) $(IDIR_QEMU)/usr/share/qemu
$(INSTALL_DIR) $(IDIR_QEMU)/usr/bin
$(INSTALL_BIN) $(WRKINST)/usr/bin/qemu* \
$(IDIR_QEMU)/usr/bin
+ $(CP) $(WRKINST)/usr/share/qemu/* \
+ $(IDIR_QEMU)/usr/share/qemu
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/qemu/patches/patch-configure b/package/qemu/patches/patch-configure
new file mode 100644
index 000000000..963c407fe
--- /dev/null
+++ b/package/qemu/patches/patch-configure
@@ -0,0 +1,11 @@
+--- qemu-0.13.0.orig/configure 2010-10-15 22:56:09.000000000 +0200
++++ qemu-0.13.0/configure 2011-01-12 22:34:59.000000000 +0100
+@@ -136,7 +136,7 @@ QEMU_CFLAGS="-D_FORTIFY_SOURCE=2 $QEMU_C
+ QEMU_CFLAGS="-I. -I\$(SRC_PATH) $QEMU_CFLAGS"
+ LDFLAGS="-g $LDFLAGS"
+
+-gcc_flags="-Wold-style-declaration -Wold-style-definition -fstack-protector-all"
++gcc_flags="-Wold-style-declaration -Wold-style-definition"
+ cat > $TMPC << EOF
+ int main(void) { return 0; }
+ EOF
diff --git a/package/qemu/patches/patch-hw_vhost_c b/package/qemu/patches/patch-hw_vhost_c
new file mode 100644
index 000000000..71eccb83f
--- /dev/null
+++ b/package/qemu/patches/patch-hw_vhost_c
@@ -0,0 +1,10 @@
+--- qemu-0.13.0.orig/hw/vhost.c 2010-10-15 22:56:09.000000000 +0200
++++ qemu-0.13.0/hw/vhost.c 2011-01-12 21:27:10.000000000 +0100
+@@ -11,7 +11,6 @@
+ */
+
+ #include <sys/ioctl.h>
+-#include <sys/eventfd.h>
+ #include "vhost.h"
+ #include "hw/hw.h"
+ /* For range_get_last */
diff --git a/package/qemu/patches/patch-hw_vhost_net_c b/package/qemu/patches/patch-hw_vhost_net_c
new file mode 100644
index 000000000..325d5a940
--- /dev/null
+++ b/package/qemu/patches/patch-hw_vhost_net_c
@@ -0,0 +1,10 @@
+--- qemu-0.13.0.orig/hw/vhost_net.c 2010-10-15 22:56:09.000000000 +0200
++++ qemu-0.13.0/hw/vhost_net.c 2011-01-12 21:27:20.000000000 +0100
+@@ -20,7 +20,6 @@
+
+ #ifdef CONFIG_VHOST_NET
+ #include <linux/vhost.h>
+-#include <sys/eventfd.h>
+ #include <sys/socket.h>
+ #include <linux/kvm.h>
+ #include <fcntl.h>
diff --git a/package/qingy/patches/patch-ltmain_sh b/package/qingy/patches/patch-ltmain_sh
new file mode 100644
index 000000000..a3cf5ff9b
--- /dev/null
+++ b/package/qingy/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- qingy-1.0.0.orig/ltmain.sh 2008-07-08 17:15:32.000000000 +0200
++++ qingy-1.0.0/ltmain.sh 2011-01-16 22:03:22.000000000 +0100
+@@ -1690,7 +1690,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/quagga/Makefile b/package/quagga/Makefile
index b13c3b197..ee519da73 100644
--- a/package/quagga/Makefile
+++ b/package/quagga/Makefile
@@ -23,7 +23,7 @@ PKGSD_QUAGGA_RIPNGD:= RIPng daemon
PKGSD_QUAGGA_RIPD:= RIP daemon
PKGSD_QUAGGA_VTYSH:= vtysh utility
-PKG_FLAVOURS:= WITH_IPV6
+PKG_FLAVOURS_QUAGGA:= WITH_IPV6
PKGFD_WITH_IPV6:= enable IPv6 support
include ${TOPDIR}/mk/package.mk
diff --git a/package/quagga/patches/patch-ltmain_sh b/package/quagga/patches/patch-ltmain_sh
new file mode 100644
index 000000000..c6711472d
--- /dev/null
+++ b/package/quagga/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- quagga-0.99.17.orig/ltmain.sh 2010-08-19 11:43:02.000000000 +0200
++++ quagga-0.99.17/ltmain.sh 2011-01-16 22:05:52.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/quagga/patches/patch-redhat_quagga_spec b/package/quagga/patches/patch-redhat_quagga_spec
new file mode 100644
index 000000000..bf00ca130
--- /dev/null
+++ b/package/quagga/patches/patch-redhat_quagga_spec
@@ -0,0 +1,11 @@
+--- quagga-0.99.17.orig/redhat/quagga.spec 2010-08-19 11:44:45.000000000 +0200
++++ quagga-0.99.17/redhat/quagga.spec 2011-01-16 22:05:02.000000000 +0100
+@@ -90,7 +90,7 @@
+ Summary: Routing daemon
+ Name: quagga
+ Version: 0.99.17
+-Release: 20100819%{release_rev}
++Release: 20110116%{release_rev}
+ License: GPL
+ Group: System Environment/Daemons
+ Source0: http://www.quagga.net/snapshots/cvs/%{name}-%{version}.tar.gz
diff --git a/package/quagga/patches/patch-vtysh_extract_pl b/package/quagga/patches/patch-vtysh_extract_pl
new file mode 100644
index 000000000..dc3229fd2
--- /dev/null
+++ b/package/quagga/patches/patch-vtysh_extract_pl
@@ -0,0 +1,8 @@
+--- quagga-0.99.17.orig/vtysh/extract.pl 2010-08-19 11:44:45.000000000 +0200
++++ quagga-0.99.17/vtysh/extract.pl 2011-01-16 22:05:03.000000000 +0100
+@@ -1,4 +1,4 @@
+-#!
++#! /opt/local/bin/perl
+ ##
+ ## vtysh/extract.pl. Generated from extract.pl.in by configure.
+ ##
diff --git a/package/rp-pppoe/patches/patch-src_Makefile_in b/package/rp-pppoe/patches/patch-src_Makefile_in
new file mode 100644
index 000000000..448dfe540
--- /dev/null
+++ b/package/rp-pppoe/patches/patch-src_Makefile_in
@@ -0,0 +1,32 @@
+--- rp-pppoe-3.10.orig/src/Makefile.in 2008-06-30 16:00:42.000000000 +0200
++++ rp-pppoe-3.10/src/Makefile.in 2011-01-16 22:17:53.000000000 +0100
+@@ -67,16 +67,16 @@ all: $(TARGETS)
+ @echo "Type 'make install' as root to install the software."
+
+ pppoe-sniff: pppoe-sniff.o if.o common.o debug.o
+- @CC@ -o pppoe-sniff pppoe-sniff.o if.o common.o debug.o
++ @CC@ $(LDFLAGS) -o pppoe-sniff pppoe-sniff.o if.o common.o debug.o
+
+ pppoe-server: pppoe-server.o if.o debug.o common.o md5.o libevent/libevent.a @PPPOE_SERVER_DEPS@
+- @CC@ -o pppoe-server @RDYNAMIC@ pppoe-server.o if.o debug.o common.o md5.o $(PPPOE_SERVER_LIBS) -Llibevent -levent
++ @CC@ $(LDFLAGS) -o pppoe-server @RDYNAMIC@ pppoe-server.o if.o debug.o common.o md5.o $(PPPOE_SERVER_LIBS) ./libevent/libevent.a
+
+ pppoe: pppoe.o if.o debug.o common.o ppp.o discovery.o
+- @CC@ -o pppoe pppoe.o if.o debug.o common.o ppp.o discovery.o
++ @CC@ $(LDFLAGS) -o pppoe pppoe.o if.o debug.o common.o ppp.o discovery.o
+
+ pppoe-relay: relay.o if.o debug.o common.o
+- @CC@ -o pppoe-relay relay.o if.o debug.o common.o
++ @CC@ $(LDFLAGS) -o pppoe-relay relay.o if.o debug.o common.o
+
+ pppoe.o: pppoe.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o pppoe.o pppoe.c
+@@ -113,7 +113,7 @@ relay.o: relay.c relay.h pppoe.h
+
+ # Linux-specific plugin
+ rp-pppoe.so: plugin/libplugin.a plugin/plugin.o
+- @CC@ -o rp-pppoe.so -shared plugin/plugin.o plugin/libplugin.a
++ @CC@ $(LDFLAGS) -o rp-pppoe.so -shared plugin/plugin.o plugin/libplugin.a
+
+ plugin/plugin.o: plugin.c
+ @CC@ '-DRP_VERSION="$(VERSION)"' $(CFLAGS) -I$(PPPD_INCDIR) -c -o plugin/plugin.o -fPIC plugin.c
diff --git a/package/rpcbind/Makefile b/package/rpcbind/Makefile
index cd03c4209..a175dbfdf 100644
--- a/package/rpcbind/Makefile
+++ b/package/rpcbind/Makefile
@@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:= rpcbind
PKG_VERSION:= 0.2.0
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= 1a77ddb1aaea8099ab19c351eeb26316
PKG_DESCR:= converts RPC program numbers into universal addresses
PKG_SECTION:= net/misc
diff --git a/package/rpcbind/files/rpcbind.init b/package/rpcbind/files/rpcbind.init
index de794f72e..439149af4 100644
--- a/package/rpcbind/files/rpcbind.init
+++ b/package/rpcbind/files/rpcbind.init
@@ -11,10 +11,10 @@ autostart)
exec sh $0 start
;;
start)
- /usr/sbin/rpcbind
+ /usr/bin/rpcbind
;;
stop)
- kill $(pgrep -f /usr/sbin/rpcbind)
+ kill $(pgrep -f /usr/bin/rpcbind)
;;
restart)
sh $0 stop
diff --git a/package/rpcbind/patches/patch-ltmain_sh b/package/rpcbind/patches/patch-ltmain_sh
new file mode 100644
index 000000000..1f5fa84b7
--- /dev/null
+++ b/package/rpcbind/patches/patch-ltmain_sh
@@ -0,0 +1,30 @@
+--- rpcbind-0.2.0.orig/ltmain.sh 2008-08-30 00:27:25.000000000 +0200
++++ rpcbind-0.2.0/ltmain.sh 2011-01-09 00:48:19.000000000 +0100
+@@ -2561,27 +2561,6 @@ EOF
+ esac
+ fi
+
+- # Hardcode the library path.
+- # Skip directories that are in the system default run-time
+- # search path.
+- case " $sys_lib_dlsearch_path " in
+- *" $absdir "*) ;;
+- *)
+- case "$compile_rpath " in
+- *" $absdir "*) ;;
+- *) compile_rpath="$compile_rpath $absdir"
+- esac
+- ;;
+- esac
+- case " $sys_lib_dlsearch_path " in
+- *" $libdir "*) ;;
+- *)
+- case "$finalize_rpath " in
+- *" $libdir "*) ;;
+- *) finalize_rpath="$finalize_rpath $libdir"
+- esac
+- ;;
+- esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
diff --git a/package/rrdtool/patches/patch-ltmain_sh b/package/rrdtool/patches/patch-ltmain_sh
new file mode 100644
index 000000000..940e4a403
--- /dev/null
+++ b/package/rrdtool/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- rrdtool-1.2.30.orig/ltmain.sh 2007-03-14 16:47:55.000000000 +0100
++++ rrdtool-1.2.30/ltmain.sh 2011-01-16 22:22:28.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/rtorrent/patches/patch-ltmain_sh b/package/rtorrent/patches/patch-ltmain_sh
new file mode 100644
index 000000000..9b491ecbb
--- /dev/null
+++ b/package/rtorrent/patches/patch-ltmain_sh
@@ -0,0 +1,30 @@
+--- rtorrent-0.8.5.orig/ltmain.sh 2009-06-18 21:37:48.000000000 +0200
++++ rtorrent-0.8.5/ltmain.sh 2011-01-09 01:46:11.000000000 +0100
+@@ -5516,27 +5516,6 @@ func_mode_link ()
+ esac
+ fi
+
+- # Hardcode the library path.
+- # Skip directories that are in the system default run-time
+- # search path.
+- case " $sys_lib_dlsearch_path " in
+- *" $absdir "*) ;;
+- *)
+- case "$compile_rpath " in
+- *" $absdir "*) ;;
+- *) compile_rpath="$compile_rpath $absdir"
+- esac
+- ;;
+- esac
+- case " $sys_lib_dlsearch_path " in
+- *" $libdir "*) ;;
+- *)
+- case "$finalize_rpath " in
+- *" $libdir "*) ;;
+- *) finalize_rpath="$finalize_rpath $libdir"
+- esac
+- ;;
+- esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
diff --git a/package/rtorrent/patches/patch-src_command_download_cc b/package/rtorrent/patches/patch-src_command_download_cc
index 4c1e50a6c..cd5ac7287 100644
--- a/package/rtorrent/patches/patch-src_command_download_cc
+++ b/package/rtorrent/patches/patch-src_command_download_cc
@@ -1,5 +1,5 @@
---- rtorrent-0.8.4.orig/src/command_download.cc 2008-11-19 18:01:20.000000000 +0100
-+++ rtorrent-0.8.4/src/command_download.cc 2009-08-28 18:01:37.606461520 +0200
+--- rtorrent-0.8.5.orig/src/command_download.cc 2009-05-14 14:34:42.000000000 +0200
++++ rtorrent-0.8.5/src/command_download.cc 2011-01-09 01:42:55.000000000 +0100
@@ -36,6 +36,7 @@
#include "config.h"
@@ -7,4 +7,4 @@
+#include <cstdio>
#include <functional>
#include <unistd.h>
- #include <rak/file_stat.h>
+ #include <cstdio>
diff --git a/package/rtorrent/patches/patch-src_command_events_cc b/package/rtorrent/patches/patch-src_command_events_cc
index dcd522735..db6da4a11 100644
--- a/package/rtorrent/patches/patch-src_command_events_cc
+++ b/package/rtorrent/patches/patch-src_command_events_cc
@@ -1,10 +1,10 @@
---- rtorrent-0.8.4.orig/src/command_events.cc 2008-11-11 11:37:20.000000000 +0100
-+++ rtorrent-0.8.4/src/command_events.cc 2009-08-28 18:14:19.096303800 +0200
+--- rtorrent-0.8.5.orig/src/command_events.cc 2009-05-14 14:34:42.000000000 +0200
++++ rtorrent-0.8.5/src/command_events.cc 2011-01-09 01:42:55.000000000 +0100
@@ -36,6 +36,7 @@
#include "config.h"
+#include <cstdio>
#include <functional>
+ #include <cstdio>
#include <rak/file_stat.h>
- #include <rak/path.h>
diff --git a/package/rtorrent/patches/patch-src_command_network_cc b/package/rtorrent/patches/patch-src_command_network_cc
index 5d0405ebe..89a44d351 100644
--- a/package/rtorrent/patches/patch-src_command_network_cc
+++ b/package/rtorrent/patches/patch-src_command_network_cc
@@ -1,11 +1,11 @@
$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- rtorrent-0.8.2.orig/src/command_network.cc 2008-05-07 14:19:11.000000000 +0200
-+++ rtorrent-0.8.2/src/command_network.cc 2009-05-29 01:38:53.000000000 +0200
+--- rtorrent-0.8.5.orig/src/command_network.cc 2009-05-14 14:34:42.000000000 +0200
++++ rtorrent-0.8.5/src/command_network.cc 2011-01-09 01:42:55.000000000 +0100
@@ -36,6 +36,7 @@
#include "config.h"
+#include <cstdio>
#include <functional>
+ #include <cstdio>
#include <rak/address_info.h>
- #include <rak/path.h>
diff --git a/package/rtorrent/patches/patch-src_rpc_parse_cc b/package/rtorrent/patches/patch-src_rpc_parse_cc
index 38530b38e..04a4bd67d 100644
--- a/package/rtorrent/patches/patch-src_rpc_parse_cc
+++ b/package/rtorrent/patches/patch-src_rpc_parse_cc
@@ -1,9 +1,9 @@
$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- rtorrent-0.8.4.orig/src/rpc/parse.cc 2008-08-26 22:14:33.000000000 +0200
-+++ rtorrent-0.8.4/src/rpc/parse.cc 2009-08-28 17:58:13.616282106 +0200
-@@ -38,6 +38,8 @@
-
+--- rtorrent-0.8.5.orig/src/rpc/parse.cc 2009-05-14 14:34:42.000000000 +0200
++++ rtorrent-0.8.5/src/rpc/parse.cc 2011-01-09 01:42:55.000000000 +0100
+@@ -39,6 +39,8 @@
#include <cstring>
+ #include <cstdio>
#include <locale>
+#include <cstdio>
+#include <cstring>
diff --git a/package/rtorrent/patches/patch-src_rpc_scgi_task_cc b/package/rtorrent/patches/patch-src_rpc_scgi_task_cc
index f81092202..d282b8139 100644
--- a/package/rtorrent/patches/patch-src_rpc_scgi_task_cc
+++ b/package/rtorrent/patches/patch-src_rpc_scgi_task_cc
@@ -1,11 +1,11 @@
$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- rtorrent-0.8.2.orig/src/rpc/scgi_task.cc 2008-05-07 14:19:10.000000000 +0200
-+++ rtorrent-0.8.2/src/rpc/scgi_task.cc 2009-05-29 01:29:24.000000000 +0200
+--- rtorrent-0.8.5.orig/src/rpc/scgi_task.cc 2009-05-14 14:34:42.000000000 +0200
++++ rtorrent-0.8.5/src/rpc/scgi_task.cc 2011-01-09 01:42:55.000000000 +0100
@@ -36,6 +36,7 @@
#include "config.h"
+#include <cstdio>
#include <rak/error_number.h>
+ #include <cstdio>
#include <sys/types.h>
- #include <sys/socket.h>
diff --git a/package/rtorrent/patches/patch-src_utils_lockfile_cc b/package/rtorrent/patches/patch-src_utils_lockfile_cc
index 58eafdfc8..31b2cd3fc 100644
--- a/package/rtorrent/patches/patch-src_utils_lockfile_cc
+++ b/package/rtorrent/patches/patch-src_utils_lockfile_cc
@@ -1,11 +1,11 @@
$Id: update-patches 24 2008-08-31 14:56:13Z wbx $
---- rtorrent-0.8.2.orig/src/utils/lockfile.cc 2008-05-07 14:19:11.000000000 +0200
-+++ rtorrent-0.8.2/src/utils/lockfile.cc 2009-05-29 01:34:05.000000000 +0200
+--- rtorrent-0.8.5.orig/src/utils/lockfile.cc 2009-05-14 14:34:42.000000000 +0200
++++ rtorrent-0.8.5/src/utils/lockfile.cc 2011-01-09 01:42:55.000000000 +0100
@@ -39,6 +39,7 @@
#include <algorithm>
#include <cctype>
#include <cerrno>
+#include <cstdio>
#include <cstring>
+ #include <cstdio>
#include <sstream>
- #include <fcntl.h>
diff --git a/package/rtsp/Makefile b/package/rtsp/Makefile
index ec5bb1d91..bc11f10a0 100644
--- a/package/rtsp/Makefile
+++ b/package/rtsp/Makefile
@@ -15,7 +15,7 @@ NO_DISTFILES:= 1
include ${TOPDIR}/mk/package.mk
-$(eval $(call PKG_template,KMOD_RTSP,kmod-rtsp,${KERNEL_VERSION}-${ADK_TARGET}-${PKG_RELEASE},,${PKG_DESCR},${PKG_SECTION}))
+$(eval $(call PKG_template,RTSP_KMOD,rtsp-kmod,${KERNEL_VERSION}-${ADK_TARGET}-${PKG_RELEASE},,${PKG_DESCR},${PKG_SECTION}))
CONFIG_STYLE:= manual
BUILD_STYLE:= manual
@@ -28,11 +28,11 @@ pre-build:
$(MAKE) -C ${WRKBUILD} debug V=1
do-install:
- ${INSTALL_DIR} ${IDIR_KMOD_RTSP}/etc/modules.d/
- echo "nf_conntrack_rtsp" > ${IDIR_KMOD_RTSP}/etc/modules.d/60-nf-nat-rtsp
- echo "nf_nat_rtsp" >> ${IDIR_KMOD_RTSP}/etc/modules.d/60-nf-nat-rtsp
- ${INSTALL_DIR} ${IDIR_KMOD_RTSP}/lib/modules/${KERNEL_VERSION}/
+ ${INSTALL_DIR} ${IDIR_RTSP_KMOD}/etc/modules.d/
+ echo "nf_conntrack_rtsp" > ${IDIR_RTSP_KMOD}/etc/modules.d/60-nf-nat-rtsp
+ echo "nf_nat_rtsp" >> ${IDIR_RTSP_KMOD}/etc/modules.d/60-nf-nat-rtsp
+ ${INSTALL_DIR} ${IDIR_RTSP_KMOD}/lib/modules/${KERNEL_VERSION}/
${INSTALL_DATA} ${WRKBUILD}/*.ko \
- ${IDIR_KMOD_RTSP}/lib/modules/${KERNEL_VERSION}
+ ${IDIR_RTSP_KMOD}/lib/modules/${KERNEL_VERSION}
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/ruby/Makefile b/package/ruby/Makefile
index 8f225a847..e85a609c0 100644
--- a/package/ruby/Makefile
+++ b/package/ruby/Makefile
@@ -23,7 +23,8 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,RUBY,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
MAKE_FILE:= GNUmakefile
-XAKE_FLAGS+= optflags='' debugflags='' BASERUBY="${WRKBUILD}/hostruby"
+XAKE_FLAGS+= optflags='' debugflags='' BASERUBY="${WRKBUILD}/hostruby" \
+ dldflags="$(TARGET_LDFLAGS)"
# uClibc setpgrp does not take arguments
CONFIGURE_ENV+= ac_cv_func_setpgrp_void=yes
CONFIGURE_ARGS+= --disable-install-doc
diff --git a/package/ruby/patches/patch-Makefile_in b/package/ruby/patches/patch-Makefile_in
new file mode 100644
index 000000000..e97548bc2
--- /dev/null
+++ b/package/ruby/patches/patch-Makefile_in
@@ -0,0 +1,11 @@
+--- ruby-1.9.2-p0.orig/Makefile.in 2010-07-11 08:15:13.000000000 +0200
++++ ruby-1.9.2-p0/Makefile.in 2011-01-16 22:34:17.000000000 +0100
+@@ -157,7 +157,7 @@ $(LIBRUBY_A):
+
+ $(LIBRUBY_SO):
+ @-$(PRE_LIBRUBY_UPDATE)
+- $(LDSHARED) $(DLDFLAGS) $(OBJS) $(DLDOBJS) $(SOLIBS) $(OUTFLAG)$@
++ $(LDSHARED) $(LDFLAGS) $(DLDFLAGS) $(OBJS) $(DLDOBJS) $(SOLIBS) $(OUTFLAG)$@
+ -$(OBJCOPY) -w -L '@EXPORT_PREFIX@Init_*' -L '@EXPORT_PREFIX@*_threadptr_*' $@
+ @-$(MINIRUBY) -e 'ARGV.each{|link| File.delete link if File.exist? link; \
+ File.symlink "$(LIBRUBY_SO)", link}' \
diff --git a/package/sane-backends/patches/patch-ltmain_sh b/package/sane-backends/patches/patch-ltmain_sh
new file mode 100644
index 000000000..46c089aa5
--- /dev/null
+++ b/package/sane-backends/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- sane-backends-1.0.20.orig/ltmain.sh 2009-02-10 22:41:47.000000000 +0100
++++ sane-backends-1.0.20/ltmain.sh 2011-01-17 11:25:40.000000000 +0100
+@@ -1680,7 +1680,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/sangam-atm/Makefile b/package/sangam-atm/Makefile
index ef1c080a5..bc6563255 100644
--- a/package/sangam-atm/Makefile
+++ b/package/sangam-atm/Makefile
@@ -22,7 +22,7 @@ BUILD_STYLE:= manual
INSTALL_STYLE:= manual
do-build:
- $(MAKE) ${KERNEL_MAKE_OPTS} LDFLAGS="" SUBDIRS="${WRKBUILD}" modules
+ ${KERNEL_MAKE_ENV} $(MAKE) ${KERNEL_MAKE_OPTS} LDFLAGS="" SUBDIRS="${WRKBUILD}" modules
do-install:
${INSTALL_DIR} ${IDIR_KMOD_SANGAM_ATM}/etc/modules.d/
diff --git a/package/scanlogd/Makefile b/package/scanlogd/Makefile
index bc2d80e68..ef939a1f1 100644
--- a/package/scanlogd/Makefile
+++ b/package/scanlogd/Makefile
@@ -21,10 +21,7 @@ $(eval $(call PKG_template,SCANLOGD,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${
CONFIG_STYLE:= manual
INSTALL_STYLE:= manual
-MAKE_FLAGS+= CC="${TARGET_CC}" LD="${TARGET_CC}" \
- CFLAGS="-c ${TARGET_CFLAGS}" \
- LDFLAGS= \
- PCAP_H="-I${STAGING_TARGET_DIR}/usr/include" \
+MAKE_FLAGS+= PCAP_H="-I${STAGING_TARGET_DIR}/usr/include" \
NIDS_H="-I${STAGING_TARGET_DIR}/usr/include" \
NIDS_L="-L${STAGING_TARGET_DIR}/usr/lib -lnids -lnet -lpcap"
ALL_TARGET:= libnids
diff --git a/package/scanlogd/patches/patch-Makefile b/package/scanlogd/patches/patch-Makefile
new file mode 100644
index 000000000..a2a239302
--- /dev/null
+++ b/package/scanlogd/patches/patch-Makefile
@@ -0,0 +1,14 @@
+--- scanlogd-2.2.6.orig/Makefile 2006-03-05 11:03:15.000000000 +0100
++++ scanlogd-2.2.6/Makefile 2011-01-17 12:03:48.000000000 +0100
+@@ -1,8 +1,8 @@
+-CC = gcc
++CC ?= gcc
+ LD = $(CC)
+ RM = rm -f
+-CFLAGS = -Wall -O2 -fomit-frame-pointer
+-LDFLAGS = -s
++CFLAGS ?= -Wall -O2 -fomit-frame-pointer
++LDFLAGS ?= -s
+
+ PCAP_H = -I/usr/include/pcap
+ PCAP_L = -lpcap
diff --git a/package/scanlogd/patches/patch-params_h b/package/scanlogd/patches/patch-params_h
new file mode 100644
index 000000000..b649c8f8d
--- /dev/null
+++ b/package/scanlogd/patches/patch-params_h
@@ -0,0 +1,20 @@
+--- scanlogd-2.2.6.orig/params.h 2006-03-05 11:13:56.000000000 +0100
++++ scanlogd-2.2.6/params.h 2011-01-17 11:35:06.000000000 +0100
+@@ -19,7 +19,7 @@
+ * An empty directory to chroot to. The directory and its parent directories
+ * must not be writable by anyone but root.
+ */
+-#define SCANLOGD_CHROOT "/var/empty"
++#define SCANLOGD_CHROOT "/tmp/.scanlogd"
+
+ /*
+ * Device to monitor, if you're using libnids or libpcap directly. #undef
+@@ -29,7 +29,7 @@
+ * Recent versions of libpcap support magic device name "any" and recent
+ * libnids supports magic device name "all".
+ */
+-#undef SCANLOGD_DEVICE
++#define SCANLOGD_DEVICE "all"
+
+ /*
+ * Whether we want scanlogd to set the device into promiscuous mode, for
diff --git a/package/sdl-image/Makefile b/package/sdl-image/Makefile
index 37c0b9a98..8d6105e58 100644
--- a/package/sdl-image/Makefile
+++ b/package/sdl-image/Makefile
@@ -26,16 +26,12 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,LIBSDL_IMAGE,libsdl-image,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,LIBSDL_IMAGE_DEV,libsdl-image-dev,$(PKG_VERSION)-${PKG_RELEASE},libsdl-image,${PKGSD_LIBSDL_IMAGE_DEV},${PKGSC_LIBSDL_IMAGE_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBSDL_IMAGE_DEV}+= libsdl-image-dev-install
-
CONFIGURE_ARGS+= --enable-png \
--enable-jpg \
--enable-bmp \
--enable-tif
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
$(INSTALL_DIR) $(IDIR_LIBSDL_IMAGE)/usr/lib
$(CP) ${WRKINST}/usr/lib/libSDL*.so* $(IDIR_LIBSDL_IMAGE)/usr/lib
diff --git a/package/sdl-image/patches/patch-ltmain_sh b/package/sdl-image/patches/patch-ltmain_sh
new file mode 100644
index 000000000..a7eae68fe
--- /dev/null
+++ b/package/sdl-image/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- SDL_image-1.2.10.orig/ltmain.sh 2009-10-13 01:06:51.000000000 +0200
++++ SDL_image-1.2.10/ltmain.sh 2011-01-17 12:10:39.000000000 +0100
+@@ -4766,7 +4766,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/sdl/Makefile b/package/sdl/Makefile
index 9fb10463a..277be34b7 100644
--- a/package/sdl/Makefile
+++ b/package/sdl/Makefile
@@ -9,11 +9,16 @@ PKG_RELEASE:= 1
PKG_MD5SUM:= e52086d1b508fa0b76c52ee30b55bec4
PKG_DESCR:= Simple DirectMedia Layer
PKG_SECTION:= libs
-PKG_DEPENDS:= libusb alsa-lib libpthread tslib
-PKG_BUILDDEP:= libusb alsa-lib tslib
+PKG_DEPENDS:= libusb alsa-lib libpthread libx11 libxext
+PKG_BUILDDEP:= libusb alsa-lib libX11 libXext
PKG_URL:= http://www.libsdl.org/
PKG_SITES:= http://www.libsdl.org/release/
+PKG_FLAVOURS_LIBSDL:= WITH_TSLIB
+PKGFD_WITH_TSLIB:= SDL with touchscreen support
+PKGFS_WITH_TSLIB:= tslib
+PKGFB_WITH_TSLIB:= tslib
+
PKG_SUBPKGS:= LIBSDL LIBSDL_DEV
PKGSD_LIBSDL_DEV:= development files for libsdl
PKGSC_LIBSDL_DEV:= devel
@@ -26,20 +31,18 @@ include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,LIBSDL,libsdl,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,LIBSDL_DEV,libsdl-dev,$(PKG_VERSION)-${PKG_RELEASE},libsdl,${PKGSD_LIBSDL_DEV},${PKGSC_LIBSDL_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_LIBSDL_DEV}+= libsdl-dev-install
-
+ifeq ($(ADK_PACKAGE_SDL_WITH_TSLIB),y)
+CONFIGURE_ARGS+= --enable-input-tslib
+endif
CONFIGURE_ARGS+= --disable-esd \
--disable-oss \
--enable-alsa \
--enable-video-fbcon \
--disable-video-directfb \
--disable-video-opengl \
- --enable-input-tslib \
--with-x
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
$(INSTALL_DIR) $(IDIR_LIBSDL)/usr/lib
$(CP) ${WRKINST}/usr/lib/libSDL*.so* $(IDIR_LIBSDL)/usr/lib
diff --git a/package/sdl/patches/patch-build-scripts_ltmain_sh b/package/sdl/patches/patch-build-scripts_ltmain_sh
new file mode 100644
index 000000000..c2f950420
--- /dev/null
+++ b/package/sdl/patches/patch-build-scripts_ltmain_sh
@@ -0,0 +1,11 @@
+--- SDL-1.2.14.orig/build-scripts/ltmain.sh 2009-10-13 01:07:12.000000000 +0200
++++ SDL-1.2.14/build-scripts/ltmain.sh 2011-01-14 23:31:20.000000000 +0100
+@@ -4766,7 +4766,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/sdl/patches/patch-include_SDL_config_h b/package/sdl/patches/patch-include_SDL_config_h
new file mode 100644
index 000000000..371f7199f
--- /dev/null
+++ b/package/sdl/patches/patch-include_SDL_config_h
@@ -0,0 +1,311 @@
+--- SDL-1.2.14.orig/include/SDL_config.h 2009-10-19 13:51:07.000000000 +0200
++++ SDL-1.2.14/include/SDL_config.h 2011-01-12 11:57:30.000000000 +0100
+@@ -1,3 +1,4 @@
++/* include/SDL_config.h. Generated from SDL_config.h.in by configure. */
+ /*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+@@ -23,23 +24,288 @@
+ #ifndef _SDL_config_h
+ #define _SDL_config_h
+
++/* This is a set of defines to configure the SDL features */
++
++/* General platform specific identifiers */
+ #include "SDL_platform.h"
+
+-/* Add any platform that doesn't build using the configure system */
+-#if defined(__DREAMCAST__)
+-#include "SDL_config_dreamcast.h"
+-#elif defined(__MACOS__)
+-#include "SDL_config_macos.h"
+-#elif defined(__MACOSX__)
+-#include "SDL_config_macosx.h"
+-#elif defined(__SYMBIAN32__)
+-#include "SDL_config_symbian.h" /* must be before win32! */
+-#elif defined(__WIN32__)
+-#include "SDL_config_win32.h"
+-#elif defined(__OS2__)
+-#include "SDL_config_os2.h"
++/* Make sure that this isn't included by Visual C++ */
++#ifdef _MSC_VER
++#error You should copy include/SDL_config.h.default to include/SDL_config.h
++#endif
++
++/* C language features */
++/* #undef const */
++/* #undef inline */
++/* #undef volatile */
++
++/* C datatypes */
++/* #undef size_t */
++/* #undef int8_t */
++/* #undef uint8_t */
++/* #undef int16_t */
++/* #undef uint16_t */
++/* #undef int32_t */
++/* #undef uint32_t */
++/* #undef int64_t */
++/* #undef uint64_t */
++/* #undef uintptr_t */
++#define SDL_HAS_64BIT_TYPE 1
++
++/* Endianness */
++#define SDL_BYTEORDER 1234
++
++/* Comment this if you want to build without any C library requirements */
++#define HAVE_LIBC 1
++#if HAVE_LIBC
++
++/* Useful headers */
++#define HAVE_ALLOCA_H 1
++#define HAVE_SYS_TYPES_H 1
++#define HAVE_STDIO_H 1
++#define STDC_HEADERS 1
++#define HAVE_STDLIB_H 1
++#define HAVE_STDARG_H 1
++#define HAVE_MALLOC_H 1
++#define HAVE_MEMORY_H 1
++#define HAVE_STRING_H 1
++#define HAVE_STRINGS_H 1
++#define HAVE_INTTYPES_H 1
++#define HAVE_STDINT_H 1
++#define HAVE_CTYPE_H 1
++#define HAVE_MATH_H 1
++#define HAVE_ICONV_H 1
++#define HAVE_SIGNAL_H 1
++/* #undef HAVE_ALTIVEC_H */
++
++/* C library functions */
++#define HAVE_MALLOC 1
++#define HAVE_CALLOC 1
++#define HAVE_REALLOC 1
++#define HAVE_FREE 1
++#define HAVE_ALLOCA 1
++#ifndef _WIN32 /* Don't use C runtime versions of these on Windows */
++#define HAVE_GETENV 1
++#define HAVE_PUTENV 1
++#define HAVE_UNSETENV 1
++#endif
++#define HAVE_QSORT 1
++#define HAVE_ABS 1
++#define HAVE_BCOPY 1
++#define HAVE_MEMSET 1
++#define HAVE_MEMCPY 1
++#define HAVE_MEMMOVE 1
++/* #undef HAVE_MEMCMP */
++#define HAVE_STRLEN 1
++#define HAVE_STRLCPY 1
++#define HAVE_STRLCAT 1
++#define HAVE_STRDUP 1
++/* #undef HAVE__STRREV */
++/* #undef HAVE__STRUPR */
++/* #undef HAVE__STRLWR */
++/* #undef HAVE_INDEX */
++/* #undef HAVE_RINDEX */
++#define HAVE_STRCHR 1
++#define HAVE_STRRCHR 1
++#define HAVE_STRSTR 1
++/* #undef HAVE_ITOA */
++/* #undef HAVE__LTOA */
++/* #undef HAVE__UITOA */
++/* #undef HAVE__ULTOA */
++#define HAVE_STRTOL 1
++#define HAVE_STRTOUL 1
++/* #undef HAVE__I64TOA */
++/* #undef HAVE__UI64TOA */
++#define HAVE_STRTOLL 1
++#define HAVE_STRTOULL 1
++/* #undef HAVE_STRTOD */
++#define HAVE_ATOI 1
++#define HAVE_ATOF 1
++#define HAVE_STRCMP 1
++#define HAVE_STRNCMP 1
++/* #undef HAVE__STRICMP */
++#define HAVE_STRCASECMP 1
++/* #undef HAVE__STRNICMP */
++#define HAVE_STRNCASECMP 1
++#define HAVE_SSCANF 1
++#define HAVE_SNPRINTF 1
++#define HAVE_VSNPRINTF 1
++/* #undef HAVE_ICONV */
++#define HAVE_SIGACTION 1
++#define HAVE_SETJMP 1
++#define HAVE_NANOSLEEP 1
++/* #undef HAVE_CLOCK_GETTIME */
++#define HAVE_GETPAGESIZE 1
++#define HAVE_MPROTECT 1
++
+ #else
+-#include "SDL_config_minimal.h"
+-#endif /* platform config */
++/* We may need some replacement for stdarg.h here */
++#include <stdarg.h>
++#endif /* HAVE_LIBC */
++
++/* Allow disabling of core subsystems */
++/* #undef SDL_AUDIO_DISABLED */
++/* #undef SDL_CDROM_DISABLED */
++/* #undef SDL_CPUINFO_DISABLED */
++/* #undef SDL_EVENTS_DISABLED */
++/* #undef SDL_FILE_DISABLED */
++/* #undef SDL_JOYSTICK_DISABLED */
++/* #undef SDL_LOADSO_DISABLED */
++/* #undef SDL_THREADS_DISABLED */
++/* #undef SDL_TIMERS_DISABLED */
++/* #undef SDL_VIDEO_DISABLED */
++
++/* Enable various audio drivers */
++#define SDL_AUDIO_DRIVER_ALSA 1
++#define SDL_AUDIO_DRIVER_ALSA_DYNAMIC "libasound.so.2"
++/* #undef SDL_AUDIO_DRIVER_ARTS */
++/* #undef SDL_AUDIO_DRIVER_ARTS_DYNAMIC */
++/* #undef SDL_AUDIO_DRIVER_BAUDIO */
++/* #undef SDL_AUDIO_DRIVER_BSD */
++/* #undef SDL_AUDIO_DRIVER_COREAUDIO */
++/* #undef SDL_AUDIO_DRIVER_DART */
++/* #undef SDL_AUDIO_DRIVER_DC */
++#define SDL_AUDIO_DRIVER_DISK 1
++#define SDL_AUDIO_DRIVER_DUMMY 1
++/* #undef SDL_AUDIO_DRIVER_DMEDIA */
++/* #undef SDL_AUDIO_DRIVER_DSOUND */
++/* #undef SDL_AUDIO_DRIVER_PULSE */
++/* #undef SDL_AUDIO_DRIVER_PULSE_DYNAMIC */
++/* #undef SDL_AUDIO_DRIVER_ESD */
++/* #undef SDL_AUDIO_DRIVER_ESD_DYNAMIC */
++/* #undef SDL_AUDIO_DRIVER_MINT */
++/* #undef SDL_AUDIO_DRIVER_MMEAUDIO */
++/* #undef SDL_AUDIO_DRIVER_NAS */
++/* #undef SDL_AUDIO_DRIVER_NAS_DYNAMIC */
++/* #undef SDL_AUDIO_DRIVER_OSS */
++/* #undef SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H */
++/* #undef SDL_AUDIO_DRIVER_PAUD */
++/* #undef SDL_AUDIO_DRIVER_QNXNTO */
++/* #undef SDL_AUDIO_DRIVER_SNDMGR */
++/* #undef SDL_AUDIO_DRIVER_SUNAUDIO */
++/* #undef SDL_AUDIO_DRIVER_WAVEOUT */
++
++/* Enable various cdrom drivers */
++/* #undef SDL_CDROM_AIX */
++/* #undef SDL_CDROM_BEOS */
++/* #undef SDL_CDROM_BSDI */
++/* #undef SDL_CDROM_DC */
++/* #undef SDL_CDROM_DUMMY */
++/* #undef SDL_CDROM_FREEBSD */
++#define SDL_CDROM_LINUX 1
++/* #undef SDL_CDROM_MACOS */
++/* #undef SDL_CDROM_MACOSX */
++/* #undef SDL_CDROM_MINT */
++/* #undef SDL_CDROM_OPENBSD */
++/* #undef SDL_CDROM_OS2 */
++/* #undef SDL_CDROM_OSF */
++/* #undef SDL_CDROM_QNX */
++/* #undef SDL_CDROM_WIN32 */
++
++/* Enable various input drivers */
++#define SDL_INPUT_LINUXEV 1
++#define SDL_INPUT_TSLIB 1
++/* #undef SDL_JOYSTICK_BEOS */
++/* #undef SDL_JOYSTICK_DC */
++/* #undef SDL_JOYSTICK_DUMMY */
++/* #undef SDL_JOYSTICK_IOKIT */
++#define SDL_JOYSTICK_LINUX 1
++/* #undef SDL_JOYSTICK_MACOS */
++/* #undef SDL_JOYSTICK_MINT */
++/* #undef SDL_JOYSTICK_OS2 */
++/* #undef SDL_JOYSTICK_RISCOS */
++/* #undef SDL_JOYSTICK_WINMM */
++/* #undef SDL_JOYSTICK_USBHID */
++/* #undef SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
++
++/* Enable various shared object loading systems */
++/* #undef SDL_LOADSO_BEOS */
++/* #undef SDL_LOADSO_DLCOMPAT */
++#define SDL_LOADSO_DLOPEN 1
++/* #undef SDL_LOADSO_DUMMY */
++/* #undef SDL_LOADSO_LDG */
++/* #undef SDL_LOADSO_MACOS */
++/* #undef SDL_LOADSO_OS2 */
++/* #undef SDL_LOADSO_WIN32 */
++
++/* Enable various threading systems */
++/* #undef SDL_THREAD_BEOS */
++/* #undef SDL_THREAD_DC */
++/* #undef SDL_THREAD_OS2 */
++/* #undef SDL_THREAD_PTH */
++#define SDL_THREAD_PTHREAD 1
++#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1
++/* #undef SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP */
++/* #undef SDL_THREAD_SPROC */
++/* #undef SDL_THREAD_WIN32 */
++
++/* Enable various timer systems */
++/* #undef SDL_TIMER_BEOS */
++/* #undef SDL_TIMER_DC */
++/* #undef SDL_TIMER_DUMMY */
++/* #undef SDL_TIMER_MACOS */
++/* #undef SDL_TIMER_MINT */
++/* #undef SDL_TIMER_OS2 */
++/* #undef SDL_TIMER_RISCOS */
++#define SDL_TIMER_UNIX 1
++/* #undef SDL_TIMER_WIN32 */
++/* #undef SDL_TIMER_WINCE */
++
++/* Enable various video drivers */
++/* #undef SDL_VIDEO_DRIVER_AALIB */
++/* #undef SDL_VIDEO_DRIVER_BWINDOW */
++/* #undef SDL_VIDEO_DRIVER_CACA */
++/* #undef SDL_VIDEO_DRIVER_DC */
++/* #undef SDL_VIDEO_DRIVER_DDRAW */
++#define SDL_VIDEO_DRIVER_DGA 1
++/* #undef SDL_VIDEO_DRIVER_DIRECTFB */
++/* #undef SDL_VIDEO_DRIVER_DRAWSPROCKET */
++#define SDL_VIDEO_DRIVER_DUMMY 1
++#define SDL_VIDEO_DRIVER_FBCON 1
++/* #undef SDL_VIDEO_DRIVER_GAPI */
++/* #undef SDL_VIDEO_DRIVER_GEM */
++/* #undef SDL_VIDEO_DRIVER_GGI */
++/* #undef SDL_VIDEO_DRIVER_IPOD */
++/* #undef SDL_VIDEO_DRIVER_NANOX */
++/* #undef SDL_VIDEO_DRIVER_OS2FS */
++/* #undef SDL_VIDEO_DRIVER_PHOTON */
++/* #undef SDL_VIDEO_DRIVER_PICOGUI */
++/* #undef SDL_VIDEO_DRIVER_PS2GS */
++/* #undef SDL_VIDEO_DRIVER_PS3 */
++/* #undef SDL_VIDEO_DRIVER_QTOPIA */
++/* #undef SDL_VIDEO_DRIVER_QUARTZ */
++/* #undef SDL_VIDEO_DRIVER_RISCOS */
++/* #undef SDL_VIDEO_DRIVER_SVGALIB */
++/* #undef SDL_VIDEO_DRIVER_TOOLBOX */
++/* #undef SDL_VIDEO_DRIVER_VGL */
++/* #undef SDL_VIDEO_DRIVER_WINDIB */
++/* #undef SDL_VIDEO_DRIVER_WSCONS */
++#define SDL_VIDEO_DRIVER_X11 1
++#define SDL_VIDEO_DRIVER_X11_DGAMOUSE 1
++#define SDL_VIDEO_DRIVER_X11_DYNAMIC "libX11.so.6"
++#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT "libXext.so.6"
++/* #undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR */
++/* #undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRENDER */
++#define SDL_VIDEO_DRIVER_X11_VIDMODE 1
++#define SDL_VIDEO_DRIVER_X11_XINERAMA 1
++#define SDL_VIDEO_DRIVER_X11_XME 1
++/* #undef SDL_VIDEO_DRIVER_X11_XRANDR */
++#define SDL_VIDEO_DRIVER_X11_XV 1
++/* #undef SDL_VIDEO_DRIVER_XBIOS */
++
++/* Enable OpenGL support */
++/* #undef SDL_VIDEO_OPENGL */
++/* #undef SDL_VIDEO_OPENGL_GLX */
++/* #undef SDL_VIDEO_OPENGL_WGL */
++/* #undef SDL_VIDEO_OPENGL_OSMESA */
++/* #undef SDL_VIDEO_OPENGL_OSMESA_DYNAMIC */
++
++/* Disable screensaver */
++#define SDL_VIDEO_DISABLE_SCREENSAVER 1
++
++/* Enable assembly routines */
++#define SDL_ASSEMBLY_ROUTINES 1
++#define SDL_HERMES_BLITTERS 1
++/* #undef SDL_ALTIVEC_BLITTERS */
+
+ #endif /* _SDL_config_h */
diff --git a/package/sdl/patches/patch-sdl-config_in b/package/sdl/patches/patch-sdl-config_in
new file mode 100644
index 000000000..4d3de58ed
--- /dev/null
+++ b/package/sdl/patches/patch-sdl-config_in
@@ -0,0 +1,16 @@
+--- SDL-1.2.14.orig/sdl-config.in 2009-10-13 01:07:20.000000000 +0200
++++ SDL-1.2.14/sdl-config.in 2011-01-12 21:46:41.000000000 +0100
+@@ -45,11 +45,11 @@ while test $# -gt 0; do
+ echo -I@includedir@/SDL @SDL_CFLAGS@
+ ;;
+ @ENABLE_SHARED_TRUE@ --libs)
+-@ENABLE_SHARED_TRUE@ echo -L@libdir@ @SDL_RLD_FLAGS@ @SDL_LIBS@
++@ENABLE_SHARED_TRUE@ echo @SDL_LIBS@
+ @ENABLE_SHARED_TRUE@ ;;
+ @ENABLE_STATIC_TRUE@@ENABLE_SHARED_TRUE@ --static-libs)
+ @ENABLE_STATIC_TRUE@@ENABLE_SHARED_FALSE@ --libs|--static-libs)
+-@ENABLE_STATIC_TRUE@ echo -L@libdir@ @SDL_RLD_FLAGS@ @SDL_STATIC_LIBS@
++@ENABLE_STATIC_TRUE@ echo @SDL_STATIC_LIBS@
+ @ENABLE_STATIC_TRUE@ ;;
+ *)
+ echo "${usage}" 1>&2
diff --git a/package/sdl/patches/patch-sdl_pc_in b/package/sdl/patches/patch-sdl_pc_in
new file mode 100644
index 000000000..fd0ae8d52
--- /dev/null
+++ b/package/sdl/patches/patch-sdl_pc_in
@@ -0,0 +1,10 @@
+--- SDL-1.2.14.orig/sdl.pc.in 2009-10-13 01:07:20.000000000 +0200
++++ SDL-1.2.14/sdl.pc.in 2011-01-12 21:54:44.000000000 +0100
+@@ -10,6 +10,6 @@ Description: Simple DirectMedia Layer is
+ Version: @SDL_VERSION@
+ Requires:
+ Conflicts:
+-Libs: -L${libdir} @SDL_RLD_FLAGS@ @SDL_LIBS@
++Libs: @SDL_LIBS@
+ Libs.private: @SDL_STATIC_LIBS@
+ Cflags: -I${includedir}/SDL @SDL_CFLAGS@
diff --git a/package/siproxd/patches/patch-libltdl_ltmain_sh b/package/siproxd/patches/patch-libltdl_ltmain_sh
new file mode 100644
index 000000000..84bfc305b
--- /dev/null
+++ b/package/siproxd/patches/patch-libltdl_ltmain_sh
@@ -0,0 +1,11 @@
+--- siproxd-0.7.1.orig/libltdl/ltmain.sh 2008-02-02 18:16:31.000000000 +0100
++++ siproxd-0.7.1/libltdl/ltmain.sh 2011-01-17 12:14:25.000000000 +0100
+@@ -1298,7 +1298,7 @@ EOF
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+- -m*)
++ -m*|-fstack-protector*|-flto)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
diff --git a/package/siproxd/patches/patch-scripts_ltmain_sh b/package/siproxd/patches/patch-scripts_ltmain_sh
new file mode 100644
index 000000000..79b49713d
--- /dev/null
+++ b/package/siproxd/patches/patch-scripts_ltmain_sh
@@ -0,0 +1,11 @@
+--- siproxd-0.7.1.orig/scripts/ltmain.sh 2008-01-27 17:35:27.000000000 +0100
++++ siproxd-0.7.1/scripts/ltmain.sh 2011-01-17 12:17:22.000000000 +0100
+@@ -1301,7 +1301,7 @@ EOF
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+- -m*)
++ -m*|-fstack-protector*|-flto)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
diff --git a/package/snort/patches/patch-ltmain_sh b/package/snort/patches/patch-ltmain_sh
new file mode 100644
index 000000000..09079e090
--- /dev/null
+++ b/package/snort/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- snort-2.8.5.2.orig/ltmain.sh 2007-04-05 16:20:16.000000000 +0200
++++ snort-2.8.5.2/ltmain.sh 2011-01-17 14:42:39.000000000 +0100
+@@ -1653,7 +1653,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/speex/patches/patch-ltmain_sh b/package/speex/patches/patch-ltmain_sh
new file mode 100644
index 000000000..3bacdbcae
--- /dev/null
+++ b/package/speex/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- speex-1.2rc1.orig/ltmain.sh 2006-06-19 21:29:20.000000000 +0200
++++ speex-1.2rc1/ltmain.sh 2011-01-14 12:16:15.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/sqlite/patches/patch-ltmain_sh b/package/sqlite/patches/patch-ltmain_sh
new file mode 100644
index 000000000..7f7d44cb0
--- /dev/null
+++ b/package/sqlite/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- sqlite-3.7.3.orig/ltmain.sh 2010-10-01 22:19:27.000000000 +0200
++++ sqlite-3.7.3/ltmain.sh 2011-01-15 00:16:55.000000000 +0100
+@@ -4772,7 +4772,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/ssmtp/patches/901-strftime_space_padding.patch b/package/ssmtp/patches/901-strftime_space_padding.patch
deleted file mode 100644
index dd0b9b116..000000000
--- a/package/ssmtp/patches/901-strftime_space_padding.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -ruN ssmtp-2.60-old/arpadate.c ssmtp-2.60-new/arpadate.c
---- ssmtp-2.60-old/arpadate.c 2002-12-08 18:30:11.000000000 +0100
-+++ ssmtp-2.60-new/arpadate.c 2004-05-23 18:54:32.000000000 +0200
-@@ -79,7 +79,7 @@
- time_t now;
-
- /* RFC822 format string borrowed from GNU shellutils date.c */
-- const char *format = "%a, %_d %b %Y %H:%M:%S %z";
-+ const char *format = "%a, %d %b %Y %H:%M:%S %z";
-
- now = time(NULL);
-
diff --git a/package/ssmtp/patches/patch-Makefile_in b/package/ssmtp/patches/patch-Makefile_in
new file mode 100644
index 000000000..01150acf4
--- /dev/null
+++ b/package/ssmtp/patches/patch-Makefile_in
@@ -0,0 +1,11 @@
+--- ssmtp-2.61.orig/Makefile.in 2004-07-26 07:32:18.000000000 +0200
++++ ssmtp-2.61/Makefile.in 2011-01-17 15:06:49.000000000 +0100
+@@ -79,7 +79,7 @@ uninstall-sendmail: uninstall
+
+ # Binaries:
+ ssmtp: $(OBJS)
+- $(CC) -o ssmtp $(OBJS) @LIBS@
++ $(CC) @LDFLAGS@ -o ssmtp $(OBJS) @LIBS@
+
+ .PHONY: clean
+ clean:
diff --git a/package/ssmtp/patches/patch-arpadate_c b/package/ssmtp/patches/patch-arpadate_c
new file mode 100644
index 000000000..e753470f6
--- /dev/null
+++ b/package/ssmtp/patches/patch-arpadate_c
@@ -0,0 +1,11 @@
+--- ssmtp-2.61.orig/arpadate.c 2002-12-08 18:30:11.000000000 +0100
++++ ssmtp-2.61/arpadate.c 2011-01-17 15:09:18.000000000 +0100
+@@ -79,7 +79,7 @@ get_arpadate (char *d_string)
+ time_t now;
+
+ /* RFC822 format string borrowed from GNU shellutils date.c */
+- const char *format = "%a, %_d %b %Y %H:%M:%S %z";
++ const char *format = "%a, %d %b %Y %H:%M:%S %z";
+
+ now = time(NULL);
+
diff --git a/package/ssmtp/patches/patch-configure_in b/package/ssmtp/patches/patch-configure_in
new file mode 100644
index 000000000..274ae978e
--- /dev/null
+++ b/package/ssmtp/patches/patch-configure_in
@@ -0,0 +1,13 @@
+--- ssmtp-2.61.orig/configure.in 2004-07-23 06:40:29.000000000 +0200
++++ ssmtp-2.61/configure.in 2011-01-17 14:46:46.000000000 +0100
+@@ -24,8 +24,8 @@ AC_C_CONST
+ AC_STRUCT_TM
+
+ dnl Checks for libraries.
+-AC_CHECK_LIB(nsl, gethostname)
+-AC_CHECK_LIB(socket, socket)
++AC_SEARCH_LIBS(gethostname, nsl)
++AC_SEARCH_LIBS(socket, socket)
+
+ dnl Checks for library functions.
+ AC_TYPE_SIGNAL
diff --git a/package/ssmtp/patches/500-debian-subset-2.61-2.patch b/package/ssmtp/patches/patch-ssmtp_c
index f682c97a1..38d45ca3d 100644
--- a/package/ssmtp/patches/500-debian-subset-2.61-2.patch
+++ b/package/ssmtp/patches/patch-ssmtp_c
@@ -1,17 +1,6 @@
---- ssmtp-2.61.orig/ssmtp.conf
-+++ ssmtp-2.61/ssmtp.conf
-@@ -36,3 +36,8 @@
-
- # Use this RSA certificate.
- #TLSCert=/etc/ssl/certs/ssmtp.pem
-+
-+# Get enhanced (*really* enhanced) debugging information in the logs
-+# If you want to have debugging of the config file parsing, move this option
-+# to the top of the config file and uncomment
-+#Debug=YES
---- ssmtp-2.61.orig/ssmtp.c
-+++ ssmtp-2.61/ssmtp.c
-@@ -93,6 +93,7 @@
+--- ssmtp-2.61.orig/ssmtp.c 2004-07-23 07:58:48.000000000 +0200
++++ ssmtp-2.61/ssmtp.c 2011-01-17 14:46:46.000000000 +0100
+@@ -93,6 +93,7 @@ SSL *ssl;
static char hextab[]="0123456789abcdef";
#endif
@@ -19,7 +8,7 @@
/*
log_event() -- Write event to syslog (or log file if defined)
-@@ -129,7 +130,7 @@
+@@ -129,7 +130,7 @@ void log_event(int priority, char *forma
#endif
}
@@ -28,7 +17,7 @@
int smtp_read(int fd, char *response);
int smtp_read_all(int fd, char *response);
int smtp_okay(int fd, char *response);
-@@ -150,7 +151,7 @@
+@@ -150,7 +151,7 @@ void dead_letter(void)
if(isatty(fileno(stdin))) {
if(log_level > 0) {
log_event(LOG_ERR,
@@ -37,7 +26,7 @@
}
return;
}
-@@ -964,6 +965,17 @@
+@@ -964,6 +965,17 @@ bool_t read_config()
log_event(LOG_INFO, "Set AuthMethod=\"%s\"\n", auth_method);
}
}
@@ -55,7 +44,7 @@
else {
log_event(LOG_INFO, "Unable to set %s=\"%s\"\n", p, q);
}
-@@ -1232,10 +1244,11 @@
+@@ -1232,10 +1244,11 @@ ssize_t fd_puts(int fd, const void *buf,
/*
smtp_write() -- A printf to an fd and append <CR/LF>
*/
@@ -68,7 +57,7 @@
va_start(ap, format);
if(vsnprintf(buf, (BUF_SZ - 2), format, ap) == -1) {
-@@ -1252,7 +1265,9 @@
+@@ -1252,7 +1265,9 @@ void smtp_write(int fd, char *format, ..
}
(void)strcat(buf, "\r\n");
@@ -79,7 +68,7 @@
}
/*
-@@ -1282,6 +1297,8 @@
+@@ -1282,6 +1297,8 @@ int ssmtp(char *argv[])
int i, sock;
uid_t uid;
@@ -88,7 +77,7 @@
uid = getuid();
if((pw = getpwuid(uid)) == (struct passwd *)NULL) {
die("Could not find password entry for UID %d", uid);
-@@ -1335,10 +1352,10 @@
+@@ -1335,10 +1352,10 @@ int ssmtp(char *argv[])
/* If user supplied username and password, then try ELHO */
if(auth_user) {
@@ -101,7 +90,7 @@
}
(void)alarm((unsigned) MEDWAIT);
-@@ -1354,7 +1371,7 @@
+@@ -1354,7 +1371,7 @@ int ssmtp(char *argv[])
}
if(strcasecmp(auth_method, "cram-md5") == 0) {
@@ -110,7 +99,7 @@
(void)alarm((unsigned) MEDWAIT);
if(smtp_read(sock, buf) != 3) {
-@@ -1369,7 +1386,7 @@
+@@ -1369,7 +1386,7 @@ int ssmtp(char *argv[])
#endif
memset(buf, 0, sizeof(buf));
to64frombits(buf, auth_user, strlen(auth_user));
@@ -119,7 +108,7 @@
(void)alarm((unsigned) MEDWAIT);
if(smtp_read(sock, buf) != 3) {
-@@ -1381,7 +1398,7 @@
+@@ -1381,7 +1398,7 @@ int ssmtp(char *argv[])
#ifdef MD5AUTH
}
#endif
@@ -128,7 +117,7 @@
(void)alarm((unsigned) MEDWAIT);
if(smtp_okay(sock, buf) == False) {
-@@ -1390,7 +1407,7 @@
+@@ -1390,7 +1407,7 @@ int ssmtp(char *argv[])
}
/* Send "MAIL FROM:" line */
@@ -137,7 +126,7 @@
(void)alarm((unsigned) MEDWAIT);
-@@ -1408,7 +1425,7 @@
+@@ -1408,7 +1425,7 @@ int ssmtp(char *argv[])
while(rt->next) {
p = rcpt_remap(rt->string);
@@ -146,7 +135,7 @@
(void)alarm((unsigned)MEDWAIT);
-@@ -1425,7 +1442,7 @@
+@@ -1425,7 +1442,7 @@ int ssmtp(char *argv[])
while(p) {
/* RFC822 Address -> "foo@bar" */
q = rcpt_remap(addr_parse(p));
@@ -155,7 +144,7 @@
(void)alarm((unsigned) MEDWAIT);
-@@ -1439,7 +1456,7 @@
+@@ -1439,7 +1456,7 @@ int ssmtp(char *argv[])
}
/* Send DATA */
@@ -164,7 +153,7 @@
(void)alarm((unsigned) MEDWAIT);
if(smtp_read(sock, buf) != 3) {
-@@ -1447,45 +1464,45 @@
+@@ -1447,45 +1464,45 @@ int ssmtp(char *argv[])
die("%s", buf);
}
@@ -218,7 +207,7 @@
(void)alarm((unsigned) MAXWAIT);
if(smtp_okay(sock, buf) == 0) {
-@@ -1495,11 +1512,12 @@
+@@ -1495,11 +1512,12 @@ int ssmtp(char *argv[])
/* Close conection */
(void)signal(SIGALRM, SIG_IGN);
@@ -233,16 +222,3 @@
return(0);
}
---- ssmtp-2.61.orig/configure.in
-+++ ssmtp-2.61/configure.in
-@@ -24,8 +24,8 @@
- AC_STRUCT_TM
-
- dnl Checks for libraries.
--AC_CHECK_LIB(nsl, gethostname)
--AC_CHECK_LIB(socket, socket)
-+AC_SEARCH_LIBS(gethostname, nsl)
-+AC_SEARCH_LIBS(socket, socket)
-
- dnl Checks for library functions.
- AC_TYPE_SIGNAL
diff --git a/package/ssmtp/patches/patch-ssmtp_conf b/package/ssmtp/patches/patch-ssmtp_conf
new file mode 100644
index 000000000..fb8ffae95
--- /dev/null
+++ b/package/ssmtp/patches/patch-ssmtp_conf
@@ -0,0 +1,11 @@
+--- ssmtp-2.61.orig/ssmtp.conf 2004-07-23 07:58:48.000000000 +0200
++++ ssmtp-2.61/ssmtp.conf 2011-01-17 14:46:46.000000000 +0100
+@@ -36,3 +36,8 @@ hostname=_HOSTNAME_
+
+ # Use this RSA certificate.
+ #TLSCert=/etc/ssl/certs/ssmtp.pem
++
++# Get enhanced (*really* enhanced) debugging information in the logs
++# If you want to have debugging of the config file parsing, move this option
++# to the top of the config file and uncomment
++#Debug=YES
diff --git a/package/strongswan/Makefile b/package/strongswan/Makefile
index 6f7f117fe..19d552f85 100644
--- a/package/strongswan/Makefile
+++ b/package/strongswan/Makefile
@@ -18,7 +18,7 @@ PKG_DEPENDS+= kmod-crypto-hmac kmod-crypto-cbc kmod-crypto-authenc
PKG_URL:= http://strongswan.org/index.htm
PKG_SITES:= http://download.strongswan.org/
-PKG_CHOICES:= WITH_GMP WITH_OPENSSL WITH_GNUTLS
+PKG_CHOICES_STRONGSWAN:=WITH_GMP WITH_OPENSSL WITH_GNUTLS
PKGCD_WITH_GMP:= use GMP for crypto
PKGCS_WITH_GMP:= libgmp
PKGCB_WITH_GMP:= gmp
diff --git a/package/strongswan/patches/patch-ltmain_sh b/package/strongswan/patches/patch-ltmain_sh
new file mode 100644
index 000000000..826fc7cbc
--- /dev/null
+++ b/package/strongswan/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- strongswan-4.5.0.orig/ltmain.sh 2010-01-06 11:19:45.000000000 +0100
++++ strongswan-4.5.0/ltmain.sh 2011-01-17 15:14:37.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/subversion/patches/patch-build_ltmain_sh b/package/subversion/patches/patch-build_ltmain_sh
new file mode 100644
index 000000000..afcd82fd9
--- /dev/null
+++ b/package/subversion/patches/patch-build_ltmain_sh
@@ -0,0 +1,39 @@
+--- subversion-1.6.12.orig/build/ltmain.sh 2010-03-31 20:37:12.000000000 +0200
++++ subversion-1.6.12/build/ltmain.sh 2011-01-17 15:25:25.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+@@ -2561,27 +2561,6 @@ EOF
+ esac
+ fi
+
+- # Hardcode the library path.
+- # Skip directories that are in the system default run-time
+- # search path.
+- case " $sys_lib_dlsearch_path " in
+- *" $absdir "*) ;;
+- *)
+- case "$compile_rpath " in
+- *" $absdir "*) ;;
+- *) compile_rpath="$compile_rpath $absdir"
+- esac
+- ;;
+- esac
+- case " $sys_lib_dlsearch_path " in
+- *" $libdir "*) ;;
+- *)
+- case "$finalize_rpath " in
+- *" $libdir "*) ;;
+- *) finalize_rpath="$finalize_rpath $libdir"
+- esac
+- ;;
+- esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
diff --git a/package/sysfsutils/patches/patch-ltmain_sh b/package/sysfsutils/patches/patch-ltmain_sh
new file mode 100644
index 000000000..b47531cfd
--- /dev/null
+++ b/package/sysfsutils/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- sysfsutils-2.1.0.orig/ltmain.sh 2006-05-26 09:57:20.000000000 +0200
++++ sysfsutils-2.1.0/ltmain.sh 2011-01-16 15:35:26.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/syslinux/Makefile b/package/syslinux/Makefile
index c5b8de89c..4a877426f 100644
--- a/package/syslinux/Makefile
+++ b/package/syslinux/Makefile
@@ -13,6 +13,8 @@ PKG_BUILDDEP:= nasm
PKG_URL:= http://syslinux.zytor.com/wiki/index.php/The_Syslinux_Project
PKG_SITES:= http://www.kernel.org/pub/linux/utils/boot/syslinux/
+PKG_HOST_DEPENDS:= !darwin !netbsd !openbsd !cygwin !freebsd
+
include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,SYSLINUX,$(PKG_NAME),$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
diff --git a/package/tcl/Makefile b/package/tcl/Makefile
index d6d257918..7b96c3b45 100644
--- a/package/tcl/Makefile
+++ b/package/tcl/Makefile
@@ -11,8 +11,6 @@ PKG_DESCR:= TCL scripting language
PKG_SECTION:= lang
PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=tcl/}
-PKG_HOST_DEPENDS:= !darwin
-
DISTFILES:= tcl${PKG_VERSION}-src.tar.gz
WRKDIST= ${WRKDIR}/tcl${PKG_VERSION}
WRKSRC= ${WRKDIST}/unix
@@ -25,8 +23,10 @@ TCFLAGS+= -ldl
CONFIGURE_ENV+= tcl_cv_strstr_unbroken=ok \
tcl_cv_strtod_buggy=ok \
tcl_cv_strtod_unbroken=ok \
- tcl_cv_strtoul_unbroken=ok
-CONFIGURE_ARGS+= --enable-man-symlinks
+ tcl_cv_strtoul_unbroken=ok \
+ tcl_cv_sys_version="Linux-2.6"
+CONFIGURE_ARGS+= --enable-man-symlinks \
+ --disable-rpath
INSTALL_TARGET= install-binaries install-libraries
post-install:
diff --git a/package/tcl/patches/patch-unix_configure b/package/tcl/patches/patch-unix_configure
new file mode 100644
index 000000000..393c2b45e
--- /dev/null
+++ b/package/tcl/patches/patch-unix_configure
@@ -0,0 +1,33 @@
+--- tcl8.5.8.orig/unix/configure 2009-11-13 19:38:45.000000000 +0100
++++ tcl8.5.8/unix/configure 2011-01-13 16:22:59.000000000 +0100
+@@ -7968,9 +7968,6 @@ fi
+ LD_SEARCH_FLAGS=""
+ LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH"
+
+-cat >>confdefs.h <<\_ACEOF
+-#define MAC_OSX_TCL 1
+-_ACEOF
+
+ PLAT_OBJS='${MAC_OSX_OBJS}'
+ PLAT_SRCS='${MAC_OSX_SRCS}'
+@@ -17646,11 +17643,6 @@ _ACEOF
+
+
+ cat >>confdefs.h <<\_ACEOF
+-#define TCL_LOAD_FROM_MEMORY 1
+-_ACEOF
+-
+-
+-cat >>confdefs.h <<\_ACEOF
+ #define TCL_WIDE_CLICKS 1
+ _ACEOF
+
+@@ -18817,7 +18809,7 @@ HTML_DIR='$(DISTDIR)/html'
+ # AIX remembers this path and will attempt to use it at run-time to look
+ # up the Tcl library.
+
+-if test "`uname -s`" = "Darwin" ; then
++if test "Linux" = "Darwin" ; then
+
+ if test "`uname -s`" = "Darwin" ; then
+ echo "$as_me:$LINENO: checking how to package libraries" >&5
diff --git a/package/tcl/patches/patch-unix_tclUnixTime_c b/package/tcl/patches/patch-unix_tclUnixTime_c
new file mode 100644
index 000000000..e0334126f
--- /dev/null
+++ b/package/tcl/patches/patch-unix_tclUnixTime_c
@@ -0,0 +1,39 @@
+--- tcl8.5.8.orig/unix/tclUnixTime.c 2008-04-14 19:49:59.000000000 +0200
++++ tcl8.5.8/unix/tclUnixTime.c 2011-01-13 15:59:00.000000000 +0100
+@@ -164,12 +164,6 @@ TclpGetWideClicks(void)
+
+ (*tclGetTimeProcPtr) (&time, tclTimeClientData);
+ now = (Tcl_WideInt) (time.sec*1000000 + time.usec);
+- } else {
+-#ifdef MAC_OSX_TCL
+- now = (Tcl_WideInt) (mach_absolute_time() & INT64_MAX);
+-#else
+-#error Wide high-resolution clicks not implemented on this platform
+-#endif
+ }
+
+ return now;
+@@ -200,23 +194,6 @@ TclpWideClicksToNanoseconds(
+
+ if (tclGetTimeProcPtr != NativeGetTime) {
+ nsec = clicks * 1000;
+- } else {
+-#ifdef MAC_OSX_TCL
+- static mach_timebase_info_data_t tb;
+- static uint64_t maxClicksForUInt64;
+-
+- if (!tb.denom) {
+- mach_timebase_info(&tb);
+- maxClicksForUInt64 = UINT64_MAX / tb.numer;
+- }
+- if ((uint64_t) clicks < maxClicksForUInt64) {
+- nsec = ((uint64_t) clicks) * tb.numer / tb.denom;
+- } else {
+- nsec = ((long double) (uint64_t) clicks) * tb.numer / tb.denom;
+- }
+-#else
+-#error Wide high-resolution clicks not implemented on this platform
+-#endif
+ }
+
+ return nsec;
diff --git a/package/tcp_wrappers/patches/patch-Makefile b/package/tcp_wrappers/patches/patch-Makefile
index ef6edec07..dd737d4d5 100644
--- a/package/tcp_wrappers/patches/patch-Makefile
+++ b/package/tcp_wrappers/patches/patch-Makefile
@@ -1,5 +1,5 @@
--- tcp_wrappers_7.6.orig/Makefile 1997-03-21 19:27:21.000000000 +0100
-+++ tcp_wrappers_7.6/Makefile 2009-06-05 18:46:05.000000000 +0200
++++ tcp_wrappers_7.6/Makefile 2011-01-17 15:40:16.000000000 +0100
@@ -1,5 +1,8 @@
# @(#) Makefile 1.23 97/03/21 19:27:20
@@ -195,41 +195,41 @@
- $(CC) $(CFLAGS) -o $@ tcpd.o $(LIB) $(LIBS)
+$(SHLIB): $(SHLIB_OBJ)
+ rm -f $(SHLIB)
-+ $(CC) -o $(SHLIB) $(SHLINKFLAGS) $(SHLIB_OBJ)
++ $(CC) $(LDFLAGS) -o $(SHLIB) $(SHLINKFLAGS) $(SHLIB_OBJ)
+ ln -s $(notdir $(SHLIB)) $(SHLIBSOMAJ)
+ ln -s $(notdir $(SHLIBSOMAJ)) $(SHLIBSO)
-miscd: miscd.o $(LIB)
- $(CC) $(CFLAGS) -o $@ miscd.o $(LIB) $(LIBS)
+tcpd: tcpd.o $(SHLIB)
-+ $(CC) $(CFLAGS) -o $@ tcpd.o $(SHLIBFLAGS)
++ $(CC) $(LDFLAGS) -o $@ tcpd.o $(SHLIBFLAGS)
-safe_finger: safe_finger.o $(LIB)
- $(CC) $(CFLAGS) -o $@ safe_finger.o $(LIB) $(LIBS)
+miscd: miscd.o $(SHLIB)
-+ $(CC) $(CFLAGS) -o $@ miscd.o $(SHLIBFLAGS)
++ $(CC) $(LDFLAGS) -o $@ miscd.o $(SHLIBFLAGS)
+
+safe_finger: safe_finger.o $(SHLIB)
-+ $(CC) $(CFLAGS) -o $@ safe_finger.o $(SHLIBFLAGS)
++ $(CC) $(LDFLAGS) -o $@ safe_finger.o $(SHLIBFLAGS)
TCPDMATCH_OBJ = tcpdmatch.o fakelog.o inetcf.o scaffold.o
-tcpdmatch: $(TCPDMATCH_OBJ) $(LIB)
- $(CC) $(CFLAGS) -o $@ $(TCPDMATCH_OBJ) $(LIB) $(LIBS)
+tcpdmatch: $(TCPDMATCH_OBJ) $(SHLIB)
-+ $(CC) $(CFLAGS) -o $@ $(TCPDMATCH_OBJ) $(SHLIBFLAGS)
++ $(CC) $(LDFLAGS) -o $@ $(TCPDMATCH_OBJ) $(SHLIBFLAGS)
-try-from: try-from.o fakelog.o $(LIB)
- $(CC) $(CFLAGS) -o $@ try-from.o fakelog.o $(LIB) $(LIBS)
+try-from: try-from.o fakelog.o $(SHLIB)
-+ $(CC) $(CFLAGS) -o $@ try-from.o fakelog.o $(SHLIBFLAGS)
++ $(CC) $(LDFLAGS) -o $@ try-from.o fakelog.o $(SHLIBFLAGS)
TCPDCHK_OBJ = tcpdchk.o fakelog.o inetcf.o scaffold.o
-tcpdchk: $(TCPDCHK_OBJ) $(LIB)
- $(CC) $(CFLAGS) -o $@ $(TCPDCHK_OBJ) $(LIB) $(LIBS)
+tcpdchk: $(TCPDCHK_OBJ) $(SHLIB)
-+ $(CC) $(CFLAGS) -o $@ $(TCPDCHK_OBJ) $(SHLIBFLAGS)
++ $(CC) $(LDFLAGS) -o $@ $(TCPDCHK_OBJ) $(SHLIBFLAGS)
+
+install: install-lib install-bin install-dev
+
diff --git a/package/tcp_wrappers/patches/patch-cflags b/package/tcp_wrappers/patches/patch-cflags
index 0581a2679..3ad8a423f 100644
--- a/package/tcp_wrappers/patches/patch-cflags
+++ b/package/tcp_wrappers/patches/patch-cflags
@@ -1,4 +1,4 @@
--- tcp_wrappers_7.6.orig/cflags 1970-01-01 00:00:00.000000000 +0100
-+++ tcp_wrappers_7.6/cflags 2010-11-11 20:03:51.771239624 +0100
++++ tcp_wrappers_7.6/cflags 2011-01-17 15:32:42.000000000 +0100
@@ -0,0 +1 @@
-+-fno-ident -march=pentium-m -fomit-frame-pointer -O2 -pipe -fwrapv -DFACILITY=LOG_DAEMON -DHOSTS_ACCESS -DDAEMON_UMASK=022 -DREAL_DAEMON_DIR="/usr/sbin" -DPROCESS_OPTIONS -DKILL_IP_OPTIONS -DSEVERITY=LOG_INFO -DRFC931_TIMEOUT=10 -DHOSTS_DENY="/etc/hosts.deny" -DHOSTS_ALLOW="/etc/hosts.allow" -DSYS_ERRLIST_DEFINED -DHAVE_STRERROR -DHAVE_WEAKSYMS -D_REENTRANT -DINET6=1 -Dss_family=__ss_family -Dss_len=__ss_len
++-march=pentium-m -Os -pipe -fomit-frame-pointer -fwrapv -fstack-protector -fno-ident -fhonour-copts -DFACILITY=LOG_DAEMON -DHOSTS_ACCESS -DDAEMON_UMASK=022 -DREAL_DAEMON_DIR="/usr/sbin" -DPROCESS_OPTIONS -DKILL_IP_OPTIONS -DSEVERITY=LOG_INFO -DRFC931_TIMEOUT=10 -DHOSTS_DENY="/etc/hosts.deny" -DHOSTS_ALLOW="/etc/hosts.allow" -DSYS_ERRLIST_DEFINED -DHAVE_STRERROR -DHAVE_WEAKSYMS -D_REENTRANT -DINET6=1 -Dss_family=__ss_family -Dss_len=__ss_len
diff --git a/package/tcpdump/Makefile b/package/tcpdump/Makefile
index 5a25597b3..6eb5d62d3 100644
--- a/package/tcpdump/Makefile
+++ b/package/tcpdump/Makefile
@@ -14,8 +14,9 @@ PKG_BUILDDEP:= libpcap
PKG_URL:= http://www.tcpdump.org/
PKG_SITES:= http://www.tcpdump.org/release/
-PKG_FLAVOURS:= WITH_IPV6
+PKG_FLAVOURS_TCPDUMP:= WITH_IPV6 WITH_CHROOT
PKGFD_WITH_IPV6:= enable IPv6 support
+PKGFD_WITH_CHROOT:= enable chrooting to /var/lib/tcpdump
include ${TOPDIR}/mk/package.mk
@@ -30,11 +31,17 @@ CONFIGURE_ARGS+= --enable-ipv6
else
CONFIGURE_ARGS+= --disable-ipv6
endif
+ifneq (${ADK_PACKAGE_TCPDUMP_WITH_CHROOT},)
+CONFIGURE_ARGS+= --with-chroot="/var/lib/tcpdump"
+endif
XAKE_FLAGS+= CCOPT="${TARGET_CFLAGS}" \
INCLS="-I. -I${STAGING_TARGET_DIR}/usr/include"
post-install:
${INSTALL_DIR} ${IDIR_TCPDUMP}/usr/sbin
${INSTALL_BIN} ${WRKINST}/usr/sbin/tcpdump ${IDIR_TCPDUMP}/usr/sbin/
+ifneq (${ADK_PACKAGE_TCPDUMP_WITH_CHROOT},)
+ ${INSTALL_DIR} ${IDIR_TCPDUMP}/var/lib/tcpdump
+endif
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/traceroute/Makefile b/package/traceroute/Makefile
index d8dd55fb0..65e5342c3 100644
--- a/package/traceroute/Makefile
+++ b/package/traceroute/Makefile
@@ -22,7 +22,7 @@ MAKE_FLAGS+= CC="${TARGET_CC}" \
AR="${TARGET_CROSS}ar" \
RANLIB="${TARGET_CROSS}ranlib" \
CFLAGS="${TCFLAGS}" \
- LDFLAGS="-L${WRKSRC}/libsupp"
+ LDFLAGS="${TARGET_LDFLAGS} -L${WRKSRC}/libsupp"
post-install:
$(INSTALL_DIR) $(IDIR_TRACEROUTE)/usr/bin
diff --git a/package/traceroute/patches/patch-default_rules b/package/traceroute/patches/patch-default_rules
new file mode 100644
index 000000000..1351f747f
--- /dev/null
+++ b/package/traceroute/patches/patch-default_rules
@@ -0,0 +1,11 @@
+--- traceroute-2.0.16.orig/default.rules 2010-09-09 16:20:06.000000000 +0200
++++ traceroute-2.0.16/default.rules 2011-01-17 15:53:37.000000000 +0100
+@@ -44,7 +44,7 @@ ifeq ($(shared),yes)
+ all: $(TARGET).so
+
+ $(TARGET).so: $(OBJS)
+- $(CC) -shared -o $@ -Wl,-soname -Wl,$@ $(OBJS)
++ $(CC) $(LDFLAGS) -shared -o $@ -Wl,-soname -Wl,$@ $(OBJS)
+
+ else
+
diff --git a/package/tslib/Makefile b/package/tslib/Makefile
index ff0afe6c9..17301acf5 100644
--- a/package/tslib/Makefile
+++ b/package/tslib/Makefile
@@ -11,6 +11,7 @@ PKG_DESCR:= touchscreen library
PKG_SECTION:= libs
PKG_URL:= http://tslib.berlios.de/
PKG_SITES:= http://download.berlios.de/tslib/
+PKG_NEED_CXX:= 1
DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tar.bz2
diff --git a/package/tslib/patches/patch-ltmain_sh b/package/tslib/patches/patch-ltmain_sh
new file mode 100644
index 000000000..8abaeff72
--- /dev/null
+++ b/package/tslib/patches/patch-ltmain_sh
@@ -0,0 +1,8416 @@
+--- tslib-1.0.orig/ltmain.sh 1970-01-01 00:00:00.000000000 +0100
++++ tslib-1.0/ltmain.sh 2011-01-14 23:22:44.000000000 +0100
+@@ -0,0 +1,8413 @@
++# Generated from ltmain.m4sh.
++
++# ltmain.sh (GNU libtool) 2.2.6b
++# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
++
++# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc.
++# This is free software; see the source for copying conditions. There is NO
++# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++
++# GNU Libtool 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.
++#
++# As a special exception to the GNU General Public License,
++# if you distribute this file as part of a program or library that
++# is built using GNU Libtool, you may include this file under the
++# same distribution terms that you use for the rest of that program.
++#
++# GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy
++# can be downloaded from http://www.gnu.org/licenses/gpl.html,
++# or obtained by writing to the Free Software Foundation, Inc.,
++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++
++# Usage: $progname [OPTION]... [MODE-ARG]...
++#
++# Provide generalized library-building support services.
++#
++# --config show all configuration variables
++# --debug enable verbose shell tracing
++# -n, --dry-run display commands without modifying any files
++# --features display basic configuration information and exit
++# --mode=MODE use operation mode MODE
++# --preserve-dup-deps don't remove duplicate dependency libraries
++# --quiet, --silent don't print informational messages
++# --tag=TAG use configuration variables from tag TAG
++# -v, --verbose print informational messages (default)
++# --version print version information
++# -h, --help print short or long help message
++#
++# MODE must be one of the following:
++#
++# clean remove files from the build directory
++# compile compile a source file into a libtool object
++# execute automatically set library path, then run a program
++# finish complete the installation of libtool libraries
++# install install libraries or executables
++# link create a library or an executable
++# uninstall remove libraries from an installed directory
++#
++# MODE-ARGS vary depending on the MODE.
++# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
++#
++# When reporting a bug, please describe a test case to reproduce it and
++# include the following information:
++#
++# host-triplet: $host
++# shell: $SHELL
++# compiler: $LTCC
++# compiler flags: $LTCFLAGS
++# linker: $LD (gnu? $with_gnu_ld)
++# $progname: (GNU libtool) 2.2.6b Debian-2.2.6b-2ubuntu1
++# automake: $automake_version
++# autoconf: $autoconf_version
++#
++# Report bugs to <bug-libtool@gnu.org>.
++
++PROGRAM=ltmain.sh
++PACKAGE=libtool
++VERSION="2.2.6b Debian-2.2.6b-2ubuntu1"
++TIMESTAMP=""
++package_revision=1.3017
++
++# Be Bourne compatible
++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
++ emulate sh
++ NULLCMD=:
++ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
++ # is contrary to our usage. Disable this feature.
++ alias -g '${1+"$@"}'='"$@"'
++ setopt NO_GLOB_SUBST
++else
++ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
++fi
++BIN_SH=xpg4; export BIN_SH # for Tru64
++DUALCASE=1; export DUALCASE # for MKS sh
++
++# NLS nuisances: We save the old values to restore during execute mode.
++# Only set LANG and LC_ALL to C if already set.
++# These must not be set unconditionally because not all systems understand
++# e.g. LANG=C (notably SCO).
++lt_user_locale=
++lt_safe_locale=
++for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
++do
++ eval "if test \"\${$lt_var+set}\" = set; then
++ save_$lt_var=\$$lt_var
++ $lt_var=C
++ export $lt_var
++ lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
++ lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
++ fi"
++done
++
++$lt_unset CDPATH
++
++
++
++
++
++: ${CP="cp -f"}
++: ${ECHO="echo"}
++: ${EGREP="/bin/grep -E"}
++: ${FGREP="/bin/grep -F"}
++: ${GREP="/bin/grep"}
++: ${LN_S="ln -s"}
++: ${MAKE="make"}
++: ${MKDIR="mkdir"}
++: ${MV="mv -f"}
++: ${RM="rm -f"}
++: ${SED="/bin/sed"}
++: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
++: ${Xsed="$SED -e 1s/^X//"}
++
++# Global variables:
++EXIT_SUCCESS=0
++EXIT_FAILURE=1
++EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing.
++EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake.
++
++exit_status=$EXIT_SUCCESS
++
++# Make sure IFS has a sensible default
++lt_nl='
++'
++IFS=" $lt_nl"
++
++dirname="s,/[^/]*$,,"
++basename="s,^.*/,,"
++
++# func_dirname_and_basename file append nondir_replacement
++# perform func_basename and func_dirname in a single function
++# call:
++# dirname: Compute the dirname of FILE. If nonempty,
++# add APPEND to the result, otherwise set result
++# to NONDIR_REPLACEMENT.
++# value returned in "$func_dirname_result"
++# basename: Compute filename of FILE.
++# value retuned in "$func_basename_result"
++# Implementation must be kept synchronized with func_dirname
++# and func_basename. For efficiency, we do not delegate to
++# those functions but instead duplicate the functionality here.
++func_dirname_and_basename ()
++{
++ # Extract subdirectory from the argument.
++ func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
++ if test "X$func_dirname_result" = "X${1}"; then
++ func_dirname_result="${3}"
++ else
++ func_dirname_result="$func_dirname_result${2}"
++ fi
++ func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
++}
++
++# Generated shell functions inserted here.
++
++# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
++# is ksh but when the shell is invoked as "sh" and the current value of
++# the _XPG environment variable is not equal to 1 (one), the special
++# positional parameter $0, within a function call, is the name of the
++# function.
++progpath="$0"
++
++# The name of this program:
++# In the unlikely event $progname began with a '-', it would play havoc with
++# func_echo (imagine progname=-n), so we prepend ./ in that case:
++func_dirname_and_basename "$progpath"
++progname=$func_basename_result
++case $progname in
++ -*) progname=./$progname ;;
++esac
++
++# Make sure we have an absolute path for reexecution:
++case $progpath in
++ [\\/]*|[A-Za-z]:\\*) ;;
++ *[\\/]*)
++ progdir=$func_dirname_result
++ progdir=`cd "$progdir" && pwd`
++ progpath="$progdir/$progname"
++ ;;
++ *)
++ save_IFS="$IFS"
++ IFS=:
++ for progdir in $PATH; do
++ IFS="$save_IFS"
++ test -x "$progdir/$progname" && break
++ done
++ IFS="$save_IFS"
++ test -n "$progdir" || progdir=`pwd`
++ progpath="$progdir/$progname"
++ ;;
++esac
++
++# Sed substitution that helps us do robust quoting. It backslashifies
++# metacharacters that are still active within double-quoted strings.
++Xsed="${SED}"' -e 1s/^X//'
++sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
++
++# Same as above, but do not quote variable references.
++double_quote_subst='s/\(["`\\]\)/\\\1/g'
++
++# Re-`\' parameter expansions in output of double_quote_subst that were
++# `\'-ed in input to the same. If an odd number of `\' preceded a '$'
++# in input to double_quote_subst, that '$' was protected from expansion.
++# Since each input `\' is now two `\'s, look for any number of runs of
++# four `\'s followed by two `\'s and then a '$'. `\' that '$'.
++bs='\\'
++bs2='\\\\'
++bs4='\\\\\\\\'
++dollar='\$'
++sed_double_backslash="\
++ s/$bs4/&\\
++/g
++ s/^$bs2$dollar/$bs&/
++ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
++ s/\n//g"
++
++# Standard options:
++opt_dry_run=false
++opt_help=false
++opt_quiet=false
++opt_verbose=false
++opt_warning=:
++
++# func_echo arg...
++# Echo program name prefixed message, along with the current mode
++# name if it has been set yet.
++func_echo ()
++{
++ $ECHO "$progname${mode+: }$mode: $*"
++}
++
++# func_verbose arg...
++# Echo program name prefixed message in verbose mode only.
++func_verbose ()
++{
++ $opt_verbose && func_echo ${1+"$@"}
++
++ # A bug in bash halts the script if the last line of a function
++ # fails when set -e is in force, so we need another command to
++ # work around that:
++ :
++}
++
++# func_error arg...
++# Echo program name prefixed message to standard error.
++func_error ()
++{
++ $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2
++}
++
++# func_warning arg...
++# Echo program name prefixed warning message to standard error.
++func_warning ()
++{
++ $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2
++
++ # bash bug again:
++ :
++}
++
++# func_fatal_error arg...
++# Echo program name prefixed message to standard error, and exit.
++func_fatal_error ()
++{
++ func_error ${1+"$@"}
++ exit $EXIT_FAILURE
++}
++
++# func_fatal_help arg...
++# Echo program name prefixed message to standard error, followed by
++# a help hint, and exit.
++func_fatal_help ()
++{
++ func_error ${1+"$@"}
++ func_fatal_error "$help"
++}
++help="Try \`$progname --help' for more information." ## default
++
++
++# func_grep expression filename
++# Check whether EXPRESSION matches any line of FILENAME, without output.
++func_grep ()
++{
++ $GREP "$1" "$2" >/dev/null 2>&1
++}
++
++
++# func_mkdir_p directory-path
++# Make sure the entire path to DIRECTORY-PATH is available.
++func_mkdir_p ()
++{
++ my_directory_path="$1"
++ my_dir_list=
++
++ if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
++
++ # Protect directory names starting with `-'
++ case $my_directory_path in
++ -*) my_directory_path="./$my_directory_path" ;;
++ esac
++
++ # While some portion of DIR does not yet exist...
++ while test ! -d "$my_directory_path"; do
++ # ...make a list in topmost first order. Use a colon delimited
++ # list incase some portion of path contains whitespace.
++ my_dir_list="$my_directory_path:$my_dir_list"
++
++ # If the last portion added has no slash in it, the list is done
++ case $my_directory_path in */*) ;; *) break ;; esac
++
++ # ...otherwise throw away the child directory and loop
++ my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"`
++ done
++ my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'`
++
++ save_mkdir_p_IFS="$IFS"; IFS=':'
++ for my_dir in $my_dir_list; do
++ IFS="$save_mkdir_p_IFS"
++ # mkdir can fail with a `File exist' error if two processes
++ # try to create one of the directories concurrently. Don't
++ # stop in that case!
++ $MKDIR "$my_dir" 2>/dev/null || :
++ done
++ IFS="$save_mkdir_p_IFS"
++
++ # Bail out if we (or some other process) failed to create a directory.
++ test -d "$my_directory_path" || \
++ func_fatal_error "Failed to create \`$1'"
++ fi
++}
++
++
++# func_mktempdir [string]
++# Make a temporary directory that won't clash with other running
++# libtool processes, and avoids race conditions if possible. If
++# given, STRING is the basename for that directory.
++func_mktempdir ()
++{
++ my_template="${TMPDIR-/tmp}/${1-$progname}"
++
++ if test "$opt_dry_run" = ":"; then
++ # Return a directory name, but don't create it in dry-run mode
++ my_tmpdir="${my_template}-$$"
++ else
++
++ # If mktemp works, use that first and foremost
++ my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
++
++ if test ! -d "$my_tmpdir"; then
++ # Failing that, at least try and use $RANDOM to avoid a race
++ my_tmpdir="${my_template}-${RANDOM-0}$$"
++
++ save_mktempdir_umask=`umask`
++ umask 0077
++ $MKDIR "$my_tmpdir"
++ umask $save_mktempdir_umask
++ fi
++
++ # If we're not in dry-run mode, bomb out on failure
++ test -d "$my_tmpdir" || \
++ func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
++ fi
++
++ $ECHO "X$my_tmpdir" | $Xsed
++}
++
++
++# func_quote_for_eval arg
++# Aesthetically quote ARG to be evaled later.
++# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
++# is double-quoted, suitable for a subsequent eval, whereas
++# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
++# which are still active within double quotes backslashified.
++func_quote_for_eval ()
++{
++ case $1 in
++ *[\\\`\"\$]*)
++ func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;;
++ *)
++ func_quote_for_eval_unquoted_result="$1" ;;
++ esac
++
++ case $func_quote_for_eval_unquoted_result in
++ # Double-quote args containing shell metacharacters to delay
++ # word splitting, command substitution and and variable
++ # expansion for a subsequent eval.
++ # Many Bourne shells cannot handle close brackets correctly
++ # in scan sets, so we specify it separately.
++ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
++ func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
++ ;;
++ *)
++ func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
++ esac
++}
++
++
++# func_quote_for_expand arg
++# Aesthetically quote ARG to be evaled later; same as above,
++# but do not quote variable references.
++func_quote_for_expand ()
++{
++ case $1 in
++ *[\\\`\"]*)
++ my_arg=`$ECHO "X$1" | $Xsed \
++ -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
++ *)
++ my_arg="$1" ;;
++ esac
++
++ case $my_arg in
++ # Double-quote args containing shell metacharacters to delay
++ # word splitting and command substitution for a subsequent eval.
++ # Many Bourne shells cannot handle close brackets correctly
++ # in scan sets, so we specify it separately.
++ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
++ my_arg="\"$my_arg\""
++ ;;
++ esac
++
++ func_quote_for_expand_result="$my_arg"
++}
++
++
++# func_show_eval cmd [fail_exp]
++# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
++# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
++# is given, then evaluate it.
++func_show_eval ()
++{
++ my_cmd="$1"
++ my_fail_exp="${2-:}"
++
++ ${opt_silent-false} || {
++ func_quote_for_expand "$my_cmd"
++ eval "func_echo $func_quote_for_expand_result"
++ }
++
++ if ${opt_dry_run-false}; then :; else
++ eval "$my_cmd"
++ my_status=$?
++ if test "$my_status" -eq 0; then :; else
++ eval "(exit $my_status); $my_fail_exp"
++ fi
++ fi
++}
++
++
++# func_show_eval_locale cmd [fail_exp]
++# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
++# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
++# is given, then evaluate it. Use the saved locale for evaluation.
++func_show_eval_locale ()
++{
++ my_cmd="$1"
++ my_fail_exp="${2-:}"
++
++ ${opt_silent-false} || {
++ func_quote_for_expand "$my_cmd"
++ eval "func_echo $func_quote_for_expand_result"
++ }
++
++ if ${opt_dry_run-false}; then :; else
++ eval "$lt_user_locale
++ $my_cmd"
++ my_status=$?
++ eval "$lt_safe_locale"
++ if test "$my_status" -eq 0; then :; else
++ eval "(exit $my_status); $my_fail_exp"
++ fi
++ fi
++}
++
++
++
++
++
++# func_version
++# Echo version message to standard output and exit.
++func_version ()
++{
++ $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / {
++ s/^# //
++ s/^# *$//
++ s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
++ p
++ }' < "$progpath"
++ exit $?
++}
++
++# func_usage
++# Echo short help message to standard output and exit.
++func_usage ()
++{
++ $SED -n '/^# Usage:/,/# -h/ {
++ s/^# //
++ s/^# *$//
++ s/\$progname/'$progname'/
++ p
++ }' < "$progpath"
++ $ECHO
++ $ECHO "run \`$progname --help | more' for full usage"
++ exit $?
++}
++
++# func_help
++# Echo long help message to standard output and exit.
++func_help ()
++{
++ $SED -n '/^# Usage:/,/# Report bugs to/ {
++ s/^# //
++ s/^# *$//
++ s*\$progname*'$progname'*
++ s*\$host*'"$host"'*
++ s*\$SHELL*'"$SHELL"'*
++ s*\$LTCC*'"$LTCC"'*
++ s*\$LTCFLAGS*'"$LTCFLAGS"'*
++ s*\$LD*'"$LD"'*
++ s/\$with_gnu_ld/'"$with_gnu_ld"'/
++ s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/
++ s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/
++ p
++ }' < "$progpath"
++ exit $?
++}
++
++# func_missing_arg argname
++# Echo program name prefixed message to standard error and set global
++# exit_cmd.
++func_missing_arg ()
++{
++ func_error "missing argument for $1"
++ exit_cmd=exit
++}
++
++exit_cmd=:
++
++
++
++
++
++# Check that we have a working $ECHO.
++if test "X$1" = X--no-reexec; then
++ # Discard the --no-reexec flag, and continue.
++ shift
++elif test "X$1" = X--fallback-echo; then
++ # Avoid inline document here, it may be left over
++ :
++elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then
++ # Yippee, $ECHO works!
++ :
++else
++ # Restart under the correct shell, and then maybe $ECHO will work.
++ exec $SHELL "$progpath" --no-reexec ${1+"$@"}
++fi
++
++if test "X$1" = X--fallback-echo; then
++ # used as fallback echo
++ shift
++ cat <<EOF
++$*
++EOF
++ exit $EXIT_SUCCESS
++fi
++
++magic="%%%MAGIC variable%%%"
++magic_exe="%%%MAGIC EXE variable%%%"
++
++# Global variables.
++# $mode is unset
++nonopt=
++execute_dlfiles=
++preserve_args=
++lo2o="s/\\.lo\$/.${objext}/"
++o2lo="s/\\.${objext}\$/.lo/"
++extracted_archives=
++extracted_serial=0
++
++opt_dry_run=false
++opt_duplicate_deps=false
++opt_silent=false
++opt_debug=:
++
++# If this variable is set in any of the actions, the command in it
++# will be execed at the end. This prevents here-documents from being
++# left over by shells.
++exec_cmd=
++
++# func_fatal_configuration arg...
++# Echo program name prefixed message to standard error, followed by
++# a configuration failure hint, and exit.
++func_fatal_configuration ()
++{
++ func_error ${1+"$@"}
++ func_error "See the $PACKAGE documentation for more information."
++ func_fatal_error "Fatal configuration error."
++}
++
++
++# func_config
++# Display the configuration for all the tags in this script.
++func_config ()
++{
++ re_begincf='^# ### BEGIN LIBTOOL'
++ re_endcf='^# ### END LIBTOOL'
++
++ # Default configuration.
++ $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
++
++ # Now print the configurations for the tags.
++ for tagname in $taglist; do
++ $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
++ done
++
++ exit $?
++}
++
++# func_features
++# Display the features supported by this script.
++func_features ()
++{
++ $ECHO "host: $host"
++ if test "$build_libtool_libs" = yes; then
++ $ECHO "enable shared libraries"
++ else
++ $ECHO "disable shared libraries"
++ fi
++ if test "$build_old_libs" = yes; then
++ $ECHO "enable static libraries"
++ else
++ $ECHO "disable static libraries"
++ fi
++
++ exit $?
++}
++
++# func_enable_tag tagname
++# Verify that TAGNAME is valid, and either flag an error and exit, or
++# enable the TAGNAME tag. We also add TAGNAME to the global $taglist
++# variable here.
++func_enable_tag ()
++{
++ # Global variable:
++ tagname="$1"
++
++ re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
++ re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
++ sed_extractcf="/$re_begincf/,/$re_endcf/p"
++
++ # Validate tagname.
++ case $tagname in
++ *[!-_A-Za-z0-9,/]*)
++ func_fatal_error "invalid tag name: $tagname"
++ ;;
++ esac
++
++ # Don't test for the "default" C tag, as we know it's
++ # there but not specially marked.
++ case $tagname in
++ CC) ;;
++ *)
++ if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
++ taglist="$taglist $tagname"
++
++ # Evaluate the configuration. Be careful to quote the path
++ # and the sed script, to avoid splitting on whitespace, but
++ # also don't use non-portable quotes within backquotes within
++ # quotes we have to do it in 2 steps:
++ extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
++ eval "$extractedcf"
++ else
++ func_error "ignoring unknown tag $tagname"
++ fi
++ ;;
++ esac
++}
++
++# Parse options once, thoroughly. This comes as soon as possible in
++# the script to make things like `libtool --version' happen quickly.
++{
++
++ # Shorthand for --mode=foo, only valid as the first argument
++ case $1 in
++ clean|clea|cle|cl)
++ shift; set dummy --mode clean ${1+"$@"}; shift
++ ;;
++ compile|compil|compi|comp|com|co|c)
++ shift; set dummy --mode compile ${1+"$@"}; shift
++ ;;
++ execute|execut|execu|exec|exe|ex|e)
++ shift; set dummy --mode execute ${1+"$@"}; shift
++ ;;
++ finish|finis|fini|fin|fi|f)
++ shift; set dummy --mode finish ${1+"$@"}; shift
++ ;;
++ install|instal|insta|inst|ins|in|i)
++ shift; set dummy --mode install ${1+"$@"}; shift
++ ;;
++ link|lin|li|l)
++ shift; set dummy --mode link ${1+"$@"}; shift
++ ;;
++ uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
++ shift; set dummy --mode uninstall ${1+"$@"}; shift
++ ;;
++ esac
++
++ # Parse non-mode specific arguments:
++ while test "$#" -gt 0; do
++ opt="$1"
++ shift
++
++ case $opt in
++ --config) func_config ;;
++
++ --debug) preserve_args="$preserve_args $opt"
++ func_echo "enabling shell trace mode"
++ opt_debug='set -x'
++ $opt_debug
++ ;;
++
++ -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break
++ execute_dlfiles="$execute_dlfiles $1"
++ shift
++ ;;
++
++ --dry-run | -n) opt_dry_run=: ;;
++ --features) func_features ;;
++ --finish) mode="finish" ;;
++
++ --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break
++ case $1 in
++ # Valid mode arguments:
++ clean) ;;
++ compile) ;;
++ execute) ;;
++ finish) ;;
++ install) ;;
++ link) ;;
++ relink) ;;
++ uninstall) ;;
++
++ # Catch anything else as an error
++ *) func_error "invalid argument for $opt"
++ exit_cmd=exit
++ break
++ ;;
++ esac
++
++ mode="$1"
++ shift
++ ;;
++
++ --preserve-dup-deps)
++ opt_duplicate_deps=: ;;
++
++ --quiet|--silent) preserve_args="$preserve_args $opt"
++ opt_silent=:
++ ;;
++
++ --verbose| -v) preserve_args="$preserve_args $opt"
++ opt_silent=false
++ ;;
++
++ --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break
++ preserve_args="$preserve_args $opt $1"
++ func_enable_tag "$1" # tagname is set here
++ shift
++ ;;
++
++ # Separate optargs to long options:
++ -dlopen=*|--mode=*|--tag=*)
++ func_opt_split "$opt"
++ set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"}
++ shift
++ ;;
++
++ -\?|-h) func_usage ;;
++ --help) opt_help=: ;;
++ --version) func_version ;;
++
++ -*) func_fatal_help "unrecognized option \`$opt'" ;;
++
++ *) nonopt="$opt"
++ break
++ ;;
++ esac
++ done
++
++
++ case $host in
++ *cygwin* | *mingw* | *pw32* | *cegcc*)
++ # don't eliminate duplications in $postdeps and $predeps
++ opt_duplicate_compiler_generated_deps=:
++ ;;
++ *)
++ opt_duplicate_compiler_generated_deps=$opt_duplicate_deps
++ ;;
++ esac
++
++ # Having warned about all mis-specified options, bail out if
++ # anything was wrong.
++ $exit_cmd $EXIT_FAILURE
++}
++
++# func_check_version_match
++# Ensure that we are using m4 macros, and libtool script from the same
++# release of libtool.
++func_check_version_match ()
++{
++ if test "$package_revision" != "$macro_revision"; then
++ if test "$VERSION" != "$macro_version"; then
++ if test -z "$macro_version"; then
++ cat >&2 <<_LT_EOF
++$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
++$progname: definition of this LT_INIT comes from an older release.
++$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
++$progname: and run autoconf again.
++_LT_EOF
++ else
++ cat >&2 <<_LT_EOF
++$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
++$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
++$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
++$progname: and run autoconf again.
++_LT_EOF
++ fi
++ else
++ cat >&2 <<_LT_EOF
++$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision,
++$progname: but the definition of this LT_INIT comes from revision $macro_revision.
++$progname: You should recreate aclocal.m4 with macros from revision $package_revision
++$progname: of $PACKAGE $VERSION and run autoconf again.
++_LT_EOF
++ fi
++
++ exit $EXIT_MISMATCH
++ fi
++}
++
++
++## ----------- ##
++## Main. ##
++## ----------- ##
++
++$opt_help || {
++ # Sanity checks first:
++ func_check_version_match
++
++ if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
++ func_fatal_configuration "not configured to build any kind of library"
++ fi
++
++ test -z "$mode" && func_fatal_error "error: you must specify a MODE."
++
++
++ # Darwin sucks
++ eval std_shrext=\"$shrext_cmds\"
++
++
++ # Only execute mode is allowed to have -dlopen flags.
++ if test -n "$execute_dlfiles" && test "$mode" != execute; then
++ func_error "unrecognized option \`-dlopen'"
++ $ECHO "$help" 1>&2
++ exit $EXIT_FAILURE
++ fi
++
++ # Change the help message to a mode-specific one.
++ generic_help="$help"
++ help="Try \`$progname --help --mode=$mode' for more information."
++}
++
++
++# func_lalib_p file
++# True iff FILE is a libtool `.la' library or `.lo' object file.
++# This function is only a basic sanity check; it will hardly flush out
++# determined imposters.
++func_lalib_p ()
++{
++ test -f "$1" &&
++ $SED -e 4q "$1" 2>/dev/null \
++ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
++}
++
++# func_lalib_unsafe_p file
++# True iff FILE is a libtool `.la' library or `.lo' object file.
++# This function implements the same check as func_lalib_p without
++# resorting to external programs. To this end, it redirects stdin and
++# closes it afterwards, without saving the original file descriptor.
++# As a safety measure, use it only where a negative result would be
++# fatal anyway. Works if `file' does not exist.
++func_lalib_unsafe_p ()
++{
++ lalib_p=no
++ if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
++ for lalib_p_l in 1 2 3 4
++ do
++ read lalib_p_line
++ case "$lalib_p_line" in
++ \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
++ esac
++ done
++ exec 0<&5 5<&-
++ fi
++ test "$lalib_p" = yes
++}
++
++# func_ltwrapper_script_p file
++# True iff FILE is a libtool wrapper script
++# This function is only a basic sanity check; it will hardly flush out
++# determined imposters.
++func_ltwrapper_script_p ()
++{
++ func_lalib_p "$1"
++}
++
++# func_ltwrapper_executable_p file
++# True iff FILE is a libtool wrapper executable
++# This function is only a basic sanity check; it will hardly flush out
++# determined imposters.
++func_ltwrapper_executable_p ()
++{
++ func_ltwrapper_exec_suffix=
++ case $1 in
++ *.exe) ;;
++ *) func_ltwrapper_exec_suffix=.exe ;;
++ esac
++ $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
++}
++
++# func_ltwrapper_scriptname file
++# Assumes file is an ltwrapper_executable
++# uses $file to determine the appropriate filename for a
++# temporary ltwrapper_script.
++func_ltwrapper_scriptname ()
++{
++ func_ltwrapper_scriptname_result=""
++ if func_ltwrapper_executable_p "$1"; then
++ func_dirname_and_basename "$1" "" "."
++ func_stripname '' '.exe' "$func_basename_result"
++ func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
++ fi
++}
++
++# func_ltwrapper_p file
++# True iff FILE is a libtool wrapper script or wrapper executable
++# This function is only a basic sanity check; it will hardly flush out
++# determined imposters.
++func_ltwrapper_p ()
++{
++ func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
++}
++
++
++# func_execute_cmds commands fail_cmd
++# Execute tilde-delimited COMMANDS.
++# If FAIL_CMD is given, eval that upon failure.
++# FAIL_CMD may read-access the current command in variable CMD!
++func_execute_cmds ()
++{
++ $opt_debug
++ save_ifs=$IFS; IFS='~'
++ for cmd in $1; do
++ IFS=$save_ifs
++ eval cmd=\"$cmd\"
++ func_show_eval "$cmd" "${2-:}"
++ done
++ IFS=$save_ifs
++}
++
++
++# func_source file
++# Source FILE, adding directory component if necessary.
++# Note that it is not necessary on cygwin/mingw to append a dot to
++# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
++# behavior happens only for exec(3), not for open(2)! Also, sourcing
++# `FILE.' does not work on cygwin managed mounts.
++func_source ()
++{
++ $opt_debug
++ case $1 in
++ */* | *\\*) . "$1" ;;
++ *) . "./$1" ;;
++ esac
++}
++
++
++# func_infer_tag arg
++# Infer tagged configuration to use if any are available and
++# if one wasn't chosen via the "--tag" command line option.
++# Only attempt this if the compiler in the base compile
++# command doesn't match the default compiler.
++# arg is usually of the form 'gcc ...'
++func_infer_tag ()
++{
++ $opt_debug
++ if test -n "$available_tags" && test -z "$tagname"; then
++ CC_quoted=
++ for arg in $CC; do
++ func_quote_for_eval "$arg"
++ CC_quoted="$CC_quoted $func_quote_for_eval_result"
++ done
++ case $@ in
++ # Blanks in the command may have been stripped by the calling shell,
++ # but not from the CC environment variable when configure was run.
++ " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;;
++ # Blanks at the start of $base_compile will cause this to fail
++ # if we don't check for them as well.
++ *)
++ for z in $available_tags; do
++ if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
++ # Evaluate the configuration.
++ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
++ CC_quoted=
++ for arg in $CC; do
++ # Double-quote args containing other shell metacharacters.
++ func_quote_for_eval "$arg"
++ CC_quoted="$CC_quoted $func_quote_for_eval_result"
++ done
++ case "$@ " in
++ " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*)
++ # The compiler in the base compile command matches
++ # the one in the tagged configuration.
++ # Assume this is the tagged configuration we want.
++ tagname=$z
++ break
++ ;;
++ esac
++ fi
++ done
++ # If $tagname still isn't set, then no tagged configuration
++ # was found and let the user know that the "--tag" command
++ # line option must be used.
++ if test -z "$tagname"; then
++ func_echo "unable to infer tagged configuration"
++ func_fatal_error "specify a tag with \`--tag'"
++# else
++# func_verbose "using $tagname tagged configuration"
++ fi
++ ;;
++ esac
++ fi
++}
++
++
++
++# func_write_libtool_object output_name pic_name nonpic_name
++# Create a libtool object file (analogous to a ".la" file),
++# but don't create it if we're doing a dry run.
++func_write_libtool_object ()
++{
++ write_libobj=${1}
++ if test "$build_libtool_libs" = yes; then
++ write_lobj=\'${2}\'
++ else
++ write_lobj=none
++ fi
++
++ if test "$build_old_libs" = yes; then
++ write_oldobj=\'${3}\'
++ else
++ write_oldobj=none
++ fi
++
++ $opt_dry_run || {
++ cat >${write_libobj}T <<EOF
++# $write_libobj - a libtool object file
++# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
++#
++# Please DO NOT delete this file!
++# It is necessary for linking the library.
++
++# Name of the PIC object.
++pic_object=$write_lobj
++
++# Name of the non-PIC object
++non_pic_object=$write_oldobj
++
++EOF
++ $MV "${write_libobj}T" "${write_libobj}"
++ }
++}
++
++# func_mode_compile arg...
++func_mode_compile ()
++{
++ $opt_debug
++ # Get the compilation command and the source file.
++ base_compile=
++ srcfile="$nonopt" # always keep a non-empty value in "srcfile"
++ suppress_opt=yes
++ suppress_output=
++ arg_mode=normal
++ libobj=
++ later=
++ pie_flag=
++
++ for arg
++ do
++ case $arg_mode in
++ arg )
++ # do not "continue". Instead, add this to base_compile
++ lastarg="$arg"
++ arg_mode=normal
++ ;;
++
++ target )
++ libobj="$arg"
++ arg_mode=normal
++ continue
++ ;;
++
++ normal )
++ # Accept any command-line options.
++ case $arg in
++ -o)
++ test -n "$libobj" && \
++ func_fatal_error "you cannot specify \`-o' more than once"
++ arg_mode=target
++ continue
++ ;;
++
++ -pie | -fpie | -fPIE)
++ pie_flag="$pie_flag $arg"
++ continue
++ ;;
++
++ -shared | -static | -prefer-pic | -prefer-non-pic)
++ later="$later $arg"
++ continue
++ ;;
++
++ -no-suppress)
++ suppress_opt=no
++ continue
++ ;;
++
++ -Xcompiler)
++ arg_mode=arg # the next one goes into the "base_compile" arg list
++ continue # The current "srcfile" will either be retained or
++ ;; # replaced later. I would guess that would be a bug.
++
++ -Wc,*)
++ func_stripname '-Wc,' '' "$arg"
++ args=$func_stripname_result
++ lastarg=
++ save_ifs="$IFS"; IFS=','
++ for arg in $args; do
++ IFS="$save_ifs"
++ func_quote_for_eval "$arg"
++ lastarg="$lastarg $func_quote_for_eval_result"
++ done
++ IFS="$save_ifs"
++ func_stripname ' ' '' "$lastarg"
++ lastarg=$func_stripname_result
++
++ # Add the arguments to base_compile.
++ base_compile="$base_compile $lastarg"
++ continue
++ ;;
++
++ *)
++ # Accept the current argument as the source file.
++ # The previous "srcfile" becomes the current argument.
++ #
++ lastarg="$srcfile"
++ srcfile="$arg"
++ ;;
++ esac # case $arg
++ ;;
++ esac # case $arg_mode
++
++ # Aesthetically quote the previous argument.
++ func_quote_for_eval "$lastarg"
++ base_compile="$base_compile $func_quote_for_eval_result"
++ done # for arg
++
++ case $arg_mode in
++ arg)
++ func_fatal_error "you must specify an argument for -Xcompile"
++ ;;
++ target)
++ func_fatal_error "you must specify a target with \`-o'"
++ ;;
++ *)
++ # Get the name of the library object.
++ test -z "$libobj" && {
++ func_basename "$srcfile"
++ libobj="$func_basename_result"
++ }
++ ;;
++ esac
++
++ # Recognize several different file suffixes.
++ # If the user specifies -o file.o, it is replaced with file.lo
++ case $libobj in
++ *.[cCFSifmso] | \
++ *.ada | *.adb | *.ads | *.asm | \
++ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
++ *.[fF][09]? | *.for | *.java | *.obj | *.sx)
++ func_xform "$libobj"
++ libobj=$func_xform_result
++ ;;
++ esac
++
++ case $libobj in
++ *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
++ *)
++ func_fatal_error "cannot determine name of library object from \`$libobj'"
++ ;;
++ esac
++
++ func_infer_tag $base_compile
++
++ for arg in $later; do
++ case $arg in
++ -shared)
++ test "$build_libtool_libs" != yes && \
++ func_fatal_configuration "can not build a shared library"
++ build_old_libs=no
++ continue
++ ;;
++
++ -static)
++ build_libtool_libs=no
++ build_old_libs=yes
++ continue
++ ;;
++
++ -prefer-pic)
++ pic_mode=yes
++ continue
++ ;;
++
++ -prefer-non-pic)
++ pic_mode=no
++ continue
++ ;;
++ esac
++ done
++
++ func_quote_for_eval "$libobj"
++ test "X$libobj" != "X$func_quote_for_eval_result" \
++ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \
++ && func_warning "libobj name \`$libobj' may not contain shell special characters."
++ func_dirname_and_basename "$obj" "/" ""
++ objname="$func_basename_result"
++ xdir="$func_dirname_result"
++ lobj=${xdir}$objdir/$objname
++
++ test -z "$base_compile" && \
++ func_fatal_help "you must specify a compilation command"
++
++ # Delete any leftover library objects.
++ if test "$build_old_libs" = yes; then
++ removelist="$obj $lobj $libobj ${libobj}T"
++ else
++ removelist="$lobj $libobj ${libobj}T"
++ fi
++
++ # On Cygwin there's no "real" PIC flag so we must build both object types
++ case $host_os in
++ cygwin* | mingw* | pw32* | os2* | cegcc*)
++ pic_mode=default
++ ;;
++ esac
++ if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
++ # non-PIC code in shared libraries is not supported
++ pic_mode=default
++ fi
++
++ # Calculate the filename of the output object if compiler does
++ # not support -o with -c
++ if test "$compiler_c_o" = no; then
++ output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
++ lockfile="$output_obj.lock"
++ else
++ output_obj=
++ need_locks=no
++ lockfile=
++ fi
++
++ # Lock this critical section if it is needed
++ # We use this script file to make the link, it avoids creating a new file
++ if test "$need_locks" = yes; then
++ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
++ func_echo "Waiting for $lockfile to be removed"
++ sleep 2
++ done
++ elif test "$need_locks" = warn; then
++ if test -f "$lockfile"; then
++ $ECHO "\
++*** ERROR, $lockfile exists and contains:
++`cat $lockfile 2>/dev/null`
++
++This indicates that another process is trying to use the same
++temporary object file, and libtool could not work around it because
++your compiler does not support \`-c' and \`-o' together. If you
++repeat this compilation, it may succeed, by chance, but you had better
++avoid parallel builds (make -j) in this platform, or get a better
++compiler."
++
++ $opt_dry_run || $RM $removelist
++ exit $EXIT_FAILURE
++ fi
++ removelist="$removelist $output_obj"
++ $ECHO "$srcfile" > "$lockfile"
++ fi
++
++ $opt_dry_run || $RM $removelist
++ removelist="$removelist $lockfile"
++ trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
++
++ if test -n "$fix_srcfile_path"; then
++ eval srcfile=\"$fix_srcfile_path\"
++ fi
++ func_quote_for_eval "$srcfile"
++ qsrcfile=$func_quote_for_eval_result
++
++ # Only build a PIC object if we are building libtool libraries.
++ if test "$build_libtool_libs" = yes; then
++ # Without this assignment, base_compile gets emptied.
++ fbsd_hideous_sh_bug=$base_compile
++
++ if test "$pic_mode" != no; then
++ command="$base_compile $qsrcfile $pic_flag"
++ else
++ # Don't build PIC code
++ command="$base_compile $qsrcfile"
++ fi
++
++ func_mkdir_p "$xdir$objdir"
++
++ if test -z "$output_obj"; then
++ # Place PIC objects in $objdir
++ command="$command -o $lobj"
++ fi
++
++ func_show_eval_locale "$command" \
++ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
++
++ if test "$need_locks" = warn &&
++ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
++ $ECHO "\
++*** ERROR, $lockfile contains:
++`cat $lockfile 2>/dev/null`
++
++but it should contain:
++$srcfile
++
++This indicates that another process is trying to use the same
++temporary object file, and libtool could not work around it because
++your compiler does not support \`-c' and \`-o' together. If you
++repeat this compilation, it may succeed, by chance, but you had better
++avoid parallel builds (make -j) in this platform, or get a better
++compiler."
++
++ $opt_dry_run || $RM $removelist
++ exit $EXIT_FAILURE
++ fi
++
++ # Just move the object if needed, then go on to compile the next one
++ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
++ func_show_eval '$MV "$output_obj" "$lobj"' \
++ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
++ fi
++
++ # Allow error messages only from the first compilation.
++ if test "$suppress_opt" = yes; then
++ suppress_output=' >/dev/null 2>&1'
++ fi
++ fi
++
++ # Only build a position-dependent object if we build old libraries.
++ if test "$build_old_libs" = yes; then
++ if test "$pic_mode" != yes; then
++ # Don't build PIC code
++ command="$base_compile $qsrcfile$pie_flag"
++ else
++ command="$base_compile $qsrcfile $pic_flag"
++ fi
++ if test "$compiler_c_o" = yes; then
++ command="$command -o $obj"
++ fi
++
++ # Suppress compiler output if we already did a PIC compilation.
++ command="$command$suppress_output"
++ func_show_eval_locale "$command" \
++ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
++
++ if test "$need_locks" = warn &&
++ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
++ $ECHO "\
++*** ERROR, $lockfile contains:
++`cat $lockfile 2>/dev/null`
++
++but it should contain:
++$srcfile
++
++This indicates that another process is trying to use the same
++temporary object file, and libtool could not work around it because
++your compiler does not support \`-c' and \`-o' together. If you
++repeat this compilation, it may succeed, by chance, but you had better
++avoid parallel builds (make -j) in this platform, or get a better
++compiler."
++
++ $opt_dry_run || $RM $removelist
++ exit $EXIT_FAILURE
++ fi
++
++ # Just move the object if needed
++ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
++ func_show_eval '$MV "$output_obj" "$obj"' \
++ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
++ fi
++ fi
++
++ $opt_dry_run || {
++ func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
++
++ # Unlock the critical section if it was locked
++ if test "$need_locks" != no; then
++ removelist=$lockfile
++ $RM "$lockfile"
++ fi
++ }
++
++ exit $EXIT_SUCCESS
++}
++
++$opt_help || {
++test "$mode" = compile && func_mode_compile ${1+"$@"}
++}
++
++func_mode_help ()
++{
++ # We need to display help for each of the modes.
++ case $mode in
++ "")
++ # Generic help is extracted from the usage comments
++ # at the start of this file.
++ func_help
++ ;;
++
++ clean)
++ $ECHO \
++"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
++
++Remove files from the build directory.
++
++RM is the name of the program to use to delete files associated with each FILE
++(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
++to RM.
++
++If FILE is a libtool library, object or program, all the files associated
++with it are deleted. Otherwise, only FILE itself is deleted using RM."
++ ;;
++
++ compile)
++ $ECHO \
++"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
++
++Compile a source file into a libtool library object.
++
++This mode accepts the following additional options:
++
++ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
++ -no-suppress do not suppress compiler output for multiple passes
++ -prefer-pic try to building PIC objects only
++ -prefer-non-pic try to building non-PIC objects only
++ -shared do not build a \`.o' file suitable for static linking
++ -static only build a \`.o' file suitable for static linking
++
++COMPILE-COMMAND is a command to be used in creating a \`standard' object file
++from the given SOURCEFILE.
++
++The output file name is determined by removing the directory component from
++SOURCEFILE, then substituting the C source code suffix \`.c' with the
++library object suffix, \`.lo'."
++ ;;
++
++ execute)
++ $ECHO \
++"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
++
++Automatically set library path, then run a program.
++
++This mode accepts the following additional options:
++
++ -dlopen FILE add the directory containing FILE to the library path
++
++This mode sets the library path environment variable according to \`-dlopen'
++flags.
++
++If any of the ARGS are libtool executable wrappers, then they are translated
++into their corresponding uninstalled binary, and any of their required library
++directories are added to the library path.
++
++Then, COMMAND is executed, with ARGS as arguments."
++ ;;
++
++ finish)
++ $ECHO \
++"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
++
++Complete the installation of libtool libraries.
++
++Each LIBDIR is a directory that contains libtool libraries.
++
++The commands that this mode executes may require superuser privileges. Use
++the \`--dry-run' option if you just want to see what would be executed."
++ ;;
++
++ install)
++ $ECHO \
++"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
++
++Install executables or libraries.
++
++INSTALL-COMMAND is the installation command. The first component should be
++either the \`install' or \`cp' program.
++
++The following components of INSTALL-COMMAND are treated specially:
++
++ -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation
++
++The rest of the components are interpreted as arguments to that command (only
++BSD-compatible install options are recognized)."
++ ;;
++
++ link)
++ $ECHO \
++"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
++
++Link object files or libraries together to form another library, or to
++create an executable program.
++
++LINK-COMMAND is a command using the C compiler that you would use to create
++a program from several object files.
++
++The following components of LINK-COMMAND are treated specially:
++
++ -all-static do not do any dynamic linking at all
++ -avoid-version do not add a version suffix if possible
++ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
++ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
++ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
++ -export-symbols SYMFILE
++ try to export only the symbols listed in SYMFILE
++ -export-symbols-regex REGEX
++ try to export only the symbols matching REGEX
++ -LLIBDIR search LIBDIR for required installed libraries
++ -lNAME OUTPUT-FILE requires the installed library libNAME
++ -module build a library that can dlopened
++ -no-fast-install disable the fast-install mode
++ -no-install link a not-installable executable
++ -no-undefined declare that a library does not refer to external symbols
++ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
++ -objectlist FILE Use a list of object files found in FILE to specify objects
++ -precious-files-regex REGEX
++ don't remove output files matching REGEX
++ -release RELEASE specify package release information
++ -rpath LIBDIR the created library will eventually be installed in LIBDIR
++ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
++ -shared only do dynamic linking of libtool libraries
++ -shrext SUFFIX override the standard shared library file extension
++ -static do not do any dynamic linking of uninstalled libtool libraries
++ -static-libtool-libs
++ do not do any dynamic linking of libtool libraries
++ -version-info CURRENT[:REVISION[:AGE]]
++ specify library version info [each variable defaults to 0]
++ -weak LIBNAME declare that the target provides the LIBNAME interface
++
++All other options (arguments beginning with \`-') are ignored.
++
++Every other argument is treated as a filename. Files ending in \`.la' are
++treated as uninstalled libtool libraries, other files are standard or library
++object files.
++
++If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
++only library objects (\`.lo' files) may be specified, and \`-rpath' is
++required, except when creating a convenience library.
++
++If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
++using \`ar' and \`ranlib', or on Windows using \`lib'.
++
++If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
++is created, otherwise an executable program is created."
++ ;;
++
++ uninstall)
++ $ECHO \
++"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
++
++Remove libraries from an installation directory.
++
++RM is the name of the program to use to delete files associated with each FILE
++(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
++to RM.
++
++If FILE is a libtool library, all the files associated with it are deleted.
++Otherwise, only FILE itself is deleted using RM."
++ ;;
++
++ *)
++ func_fatal_help "invalid operation mode \`$mode'"
++ ;;
++ esac
++
++ $ECHO
++ $ECHO "Try \`$progname --help' for more information about other modes."
++
++ exit $?
++}
++
++ # Now that we've collected a possible --mode arg, show help if necessary
++ $opt_help && func_mode_help
++
++
++# func_mode_execute arg...
++func_mode_execute ()
++{
++ $opt_debug
++ # The first argument is the command name.
++ cmd="$nonopt"
++ test -z "$cmd" && \
++ func_fatal_help "you must specify a COMMAND"
++
++ # Handle -dlopen flags immediately.
++ for file in $execute_dlfiles; do
++ test -f "$file" \
++ || func_fatal_help "\`$file' is not a file"
++
++ dir=
++ case $file in
++ *.la)
++ # Check to see that this really is a libtool archive.
++ func_lalib_unsafe_p "$file" \
++ || func_fatal_help "\`$lib' is not a valid libtool archive"
++
++ # Read the libtool library.
++ dlname=
++ library_names=
++ func_source "$file"
++
++ # Skip this library if it cannot be dlopened.
++ if test -z "$dlname"; then
++ # Warn if it was a shared library.
++ test -n "$library_names" && \
++ func_warning "\`$file' was not linked with \`-export-dynamic'"
++ continue
++ fi
++
++ func_dirname "$file" "" "."
++ dir="$func_dirname_result"
++
++ if test -f "$dir/$objdir/$dlname"; then
++ dir="$dir/$objdir"
++ else
++ if test ! -f "$dir/$dlname"; then
++ func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
++ fi
++ fi
++ ;;
++
++ *.lo)
++ # Just add the directory containing the .lo file.
++ func_dirname "$file" "" "."
++ dir="$func_dirname_result"
++ ;;
++
++ *)
++ func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
++ continue
++ ;;
++ esac
++
++ # Get the absolute pathname.
++ absdir=`cd "$dir" && pwd`
++ test -n "$absdir" && dir="$absdir"
++
++ # Now add the directory to shlibpath_var.
++ if eval "test -z \"\$$shlibpath_var\""; then
++ eval "$shlibpath_var=\"\$dir\""
++ else
++ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
++ fi
++ done
++
++ # This variable tells wrapper scripts just to set shlibpath_var
++ # rather than running their programs.
++ libtool_execute_magic="$magic"
++
++ # Check if any of the arguments is a wrapper script.
++ args=
++ for file
++ do
++ case $file in
++ -*) ;;
++ *)
++ # Do a test to see if this is really a libtool program.
++ if func_ltwrapper_script_p "$file"; then
++ func_source "$file"
++ # Transform arg to wrapped name.
++ file="$progdir/$program"
++ elif func_ltwrapper_executable_p "$file"; then
++ func_ltwrapper_scriptname "$file"
++ func_source "$func_ltwrapper_scriptname_result"
++ # Transform arg to wrapped name.
++ file="$progdir/$program"
++ fi
++ ;;
++ esac
++ # Quote arguments (to preserve shell metacharacters).
++ func_quote_for_eval "$file"
++ args="$args $func_quote_for_eval_result"
++ done
++
++ if test "X$opt_dry_run" = Xfalse; then
++ if test -n "$shlibpath_var"; then
++ # Export the shlibpath_var.
++ eval "export $shlibpath_var"
++ fi
++
++ # Restore saved environment variables
++ for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
++ do
++ eval "if test \"\${save_$lt_var+set}\" = set; then
++ $lt_var=\$save_$lt_var; export $lt_var
++ else
++ $lt_unset $lt_var
++ fi"
++ done
++
++ # Now prepare to actually exec the command.
++ exec_cmd="\$cmd$args"
++ else
++ # Display what would be done.
++ if test -n "$shlibpath_var"; then
++ eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
++ $ECHO "export $shlibpath_var"
++ fi
++ $ECHO "$cmd$args"
++ exit $EXIT_SUCCESS
++ fi
++}
++
++test "$mode" = execute && func_mode_execute ${1+"$@"}
++
++
++# func_mode_finish arg...
++func_mode_finish ()
++{
++ $opt_debug
++ libdirs="$nonopt"
++ admincmds=
++
++ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
++ for dir
++ do
++ libdirs="$libdirs $dir"
++ done
++
++ for libdir in $libdirs; do
++ if test -n "$finish_cmds"; then
++ # Do each command in the finish commands.
++ func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
++'"$cmd"'"'
++ fi
++ if test -n "$finish_eval"; then
++ # Do the single finish_eval.
++ eval cmds=\"$finish_eval\"
++ $opt_dry_run || eval "$cmds" || admincmds="$admincmds
++ $cmds"
++ fi
++ done
++ fi
++
++ # Exit here if they wanted silent mode.
++ $opt_silent && exit $EXIT_SUCCESS
++
++ $ECHO "X----------------------------------------------------------------------" | $Xsed
++ $ECHO "Libraries have been installed in:"
++ for libdir in $libdirs; do
++ $ECHO " $libdir"
++ done
++ $ECHO
++ $ECHO "If you ever happen to want to link against installed libraries"
++ $ECHO "in a given directory, LIBDIR, you must either use libtool, and"
++ $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'"
++ $ECHO "flag during linking and do at least one of the following:"
++ if test -n "$shlibpath_var"; then
++ $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable"
++ $ECHO " during execution"
++ fi
++ if test -n "$runpath_var"; then
++ $ECHO " - add LIBDIR to the \`$runpath_var' environment variable"
++ $ECHO " during linking"
++ fi
++ if test -n "$hardcode_libdir_flag_spec"; then
++ libdir=LIBDIR
++ eval flag=\"$hardcode_libdir_flag_spec\"
++
++ $ECHO " - use the \`$flag' linker flag"
++ fi
++ if test -n "$admincmds"; then
++ $ECHO " - have your system administrator run these commands:$admincmds"
++ fi
++ if test -f /etc/ld.so.conf; then
++ $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
++ fi
++ $ECHO
++
++ $ECHO "See any operating system documentation about shared libraries for"
++ case $host in
++ solaris2.[6789]|solaris2.1[0-9])
++ $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual"
++ $ECHO "pages."
++ ;;
++ *)
++ $ECHO "more information, such as the ld(1) and ld.so(8) manual pages."
++ ;;
++ esac
++ $ECHO "X----------------------------------------------------------------------" | $Xsed
++ exit $EXIT_SUCCESS
++}
++
++test "$mode" = finish && func_mode_finish ${1+"$@"}
++
++
++# func_mode_install arg...
++func_mode_install ()
++{
++ $opt_debug
++ # There may be an optional sh(1) argument at the beginning of
++ # install_prog (especially on Windows NT).
++ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
++ # Allow the use of GNU shtool's install command.
++ $ECHO "X$nonopt" | $GREP shtool >/dev/null; then
++ # Aesthetically quote it.
++ func_quote_for_eval "$nonopt"
++ install_prog="$func_quote_for_eval_result "
++ arg=$1
++ shift
++ else
++ install_prog=
++ arg=$nonopt
++ fi
++
++ # The real first argument should be the name of the installation program.
++ # Aesthetically quote it.
++ func_quote_for_eval "$arg"
++ install_prog="$install_prog$func_quote_for_eval_result"
++
++ # We need to accept at least all the BSD install flags.
++ dest=
++ files=
++ opts=
++ prev=
++ install_type=
++ isdir=no
++ stripme=
++ for arg
++ do
++ if test -n "$dest"; then
++ files="$files $dest"
++ dest=$arg
++ continue
++ fi
++
++ case $arg in
++ -d) isdir=yes ;;
++ -f)
++ case " $install_prog " in
++ *[\\\ /]cp\ *) ;;
++ *) prev=$arg ;;
++ esac
++ ;;
++ -g | -m | -o)
++ prev=$arg
++ ;;
++ -s)
++ stripme=" -s"
++ continue
++ ;;
++ -*)
++ ;;
++ *)
++ # If the previous option needed an argument, then skip it.
++ if test -n "$prev"; then
++ prev=
++ else
++ dest=$arg
++ continue
++ fi
++ ;;
++ esac
++
++ # Aesthetically quote the argument.
++ func_quote_for_eval "$arg"
++ install_prog="$install_prog $func_quote_for_eval_result"
++ done
++
++ test -z "$install_prog" && \
++ func_fatal_help "you must specify an install program"
++
++ test -n "$prev" && \
++ func_fatal_help "the \`$prev' option requires an argument"
++
++ if test -z "$files"; then
++ if test -z "$dest"; then
++ func_fatal_help "no file or destination specified"
++ else
++ func_fatal_help "you must specify a destination"
++ fi
++ fi
++
++ # Strip any trailing slash from the destination.
++ func_stripname '' '/' "$dest"
++ dest=$func_stripname_result
++
++ # Check to see that the destination is a directory.
++ test -d "$dest" && isdir=yes
++ if test "$isdir" = yes; then
++ destdir="$dest"
++ destname=
++ else
++ func_dirname_and_basename "$dest" "" "."
++ destdir="$func_dirname_result"
++ destname="$func_basename_result"
++
++ # Not a directory, so check to see that there is only one file specified.
++ set dummy $files; shift
++ test "$#" -gt 1 && \
++ func_fatal_help "\`$dest' is not a directory"
++ fi
++ case $destdir in
++ [\\/]* | [A-Za-z]:[\\/]*) ;;
++ *)
++ for file in $files; do
++ case $file in
++ *.lo) ;;
++ *)
++ func_fatal_help "\`$destdir' must be an absolute directory name"
++ ;;
++ esac
++ done
++ ;;
++ esac
++
++ # This variable tells wrapper scripts just to set variables rather
++ # than running their programs.
++ libtool_install_magic="$magic"
++
++ staticlibs=
++ future_libdirs=
++ current_libdirs=
++ for file in $files; do
++
++ # Do each installation.
++ case $file in
++ *.$libext)
++ # Do the static libraries later.
++ staticlibs="$staticlibs $file"
++ ;;
++
++ *.la)
++ # Check to see that this really is a libtool archive.
++ func_lalib_unsafe_p "$file" \
++ || func_fatal_help "\`$file' is not a valid libtool archive"
++
++ library_names=
++ old_library=
++ relink_command=
++ func_source "$file"
++
++ # Add the libdir to current_libdirs if it is the destination.
++ if test "X$destdir" = "X$libdir"; then
++ case "$current_libdirs " in
++ *" $libdir "*) ;;
++ *) current_libdirs="$current_libdirs $libdir" ;;
++ esac
++ else
++ # Note the libdir as a future libdir.
++ case "$future_libdirs " in
++ *" $libdir "*) ;;
++ *) future_libdirs="$future_libdirs $libdir" ;;
++ esac
++ fi
++
++ func_dirname "$file" "/" ""
++ dir="$func_dirname_result"
++ dir="$dir$objdir"
++
++ if test -n "$relink_command"; then
++ # Determine the prefix the user has applied to our future dir.
++ inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"`
++
++ # Don't allow the user to place us outside of our expected
++ # location b/c this prevents finding dependent libraries that
++ # are installed to the same prefix.
++ # At present, this check doesn't affect windows .dll's that
++ # are installed into $libdir/../bin (currently, that works fine)
++ # but it's something to keep an eye on.
++ test "$inst_prefix_dir" = "$destdir" && \
++ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
++
++ if test -n "$inst_prefix_dir"; then
++ # Stick the inst_prefix_dir data into the link command.
++ relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
++ else
++ relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"`
++ fi
++
++ func_warning "relinking \`$file'"
++ func_show_eval "$relink_command" \
++ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
++ fi
++
++ # See the names of the shared library.
++ set dummy $library_names; shift
++ if test -n "$1"; then
++ realname="$1"
++ shift
++
++ srcname="$realname"
++ test -n "$relink_command" && srcname="$realname"T
++
++ # Install the shared library and build the symlinks.
++ func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \
++ 'exit $?'
++ tstripme="$stripme"
++ case $host_os in
++ cygwin* | mingw* | pw32* | cegcc*)
++ case $realname in
++ *.dll.a)
++ tstripme=""
++ ;;
++ esac
++ ;;
++ esac
++ if test -n "$tstripme" && test -n "$striplib"; then
++ func_show_eval "$striplib $destdir/$realname" 'exit $?'
++ fi
++
++ if test "$#" -gt 0; then
++ # Delete the old symlinks, and create new ones.
++ # Try `ln -sf' first, because the `ln' binary might depend on
++ # the symlink we replace! Solaris /bin/ln does not understand -f,
++ # so we also need to try rm && ln -s.
++ for linkname
++ do
++ test "$linkname" != "$realname" \
++ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
++ done
++ fi
++
++ # Do each command in the postinstall commands.
++ lib="$destdir/$realname"
++ func_execute_cmds "$postinstall_cmds" 'exit $?'
++ fi
++
++ # Install the pseudo-library for information purposes.
++ func_basename "$file"
++ name="$func_basename_result"
++ instname="$dir/$name"i
++ func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
++
++ # Maybe install the static library, too.
++ test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
++ ;;
++
++ *.lo)
++ # Install (i.e. copy) a libtool object.
++
++ # Figure out destination file name, if it wasn't already specified.
++ if test -n "$destname"; then
++ destfile="$destdir/$destname"
++ else
++ func_basename "$file"
++ destfile="$func_basename_result"
++ destfile="$destdir/$destfile"
++ fi
++
++ # Deduce the name of the destination old-style object file.
++ case $destfile in
++ *.lo)
++ func_lo2o "$destfile"
++ staticdest=$func_lo2o_result
++ ;;
++ *.$objext)
++ staticdest="$destfile"
++ destfile=
++ ;;
++ *)
++ func_fatal_help "cannot copy a libtool object to \`$destfile'"
++ ;;
++ esac
++
++ # Install the libtool object if requested.
++ test -n "$destfile" && \
++ func_show_eval "$install_prog $file $destfile" 'exit $?'
++
++ # Install the old object if enabled.
++ if test "$build_old_libs" = yes; then
++ # Deduce the name of the old-style object file.
++ func_lo2o "$file"
++ staticobj=$func_lo2o_result
++ func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
++ fi
++ exit $EXIT_SUCCESS
++ ;;
++
++ *)
++ # Figure out destination file name, if it wasn't already specified.
++ if test -n "$destname"; then
++ destfile="$destdir/$destname"
++ else
++ func_basename "$file"
++ destfile="$func_basename_result"
++ destfile="$destdir/$destfile"
++ fi
++
++ # If the file is missing, and there is a .exe on the end, strip it
++ # because it is most likely a libtool script we actually want to
++ # install
++ stripped_ext=""
++ case $file in
++ *.exe)
++ if test ! -f "$file"; then
++ func_stripname '' '.exe' "$file"
++ file=$func_stripname_result
++ stripped_ext=".exe"
++ fi
++ ;;
++ esac
++
++ # Do a test to see if this is really a libtool program.
++ case $host in
++ *cygwin* | *mingw*)
++ if func_ltwrapper_executable_p "$file"; then
++ func_ltwrapper_scriptname "$file"
++ wrapper=$func_ltwrapper_scriptname_result
++ else
++ func_stripname '' '.exe' "$file"
++ wrapper=$func_stripname_result
++ fi
++ ;;
++ *)
++ wrapper=$file
++ ;;
++ esac
++ if func_ltwrapper_script_p "$wrapper"; then
++ notinst_deplibs=
++ relink_command=
++
++ func_source "$wrapper"
++
++ # Check the variables that should have been set.
++ test -z "$generated_by_libtool_version" && \
++ func_fatal_error "invalid libtool wrapper script \`$wrapper'"
++
++ finalize=yes
++ for lib in $notinst_deplibs; do
++ # Check to see that each library is installed.
++ libdir=
++ if test -f "$lib"; then
++ func_source "$lib"
++ fi
++ libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
++ if test -n "$libdir" && test ! -f "$libfile"; then
++ func_warning "\`$lib' has not been installed in \`$libdir'"
++ finalize=no
++ fi
++ done
++
++ relink_command=
++ func_source "$wrapper"
++
++ outputname=
++ if test "$fast_install" = no && test -n "$relink_command"; then
++ $opt_dry_run || {
++ if test "$finalize" = yes; then
++ tmpdir=`func_mktempdir`
++ func_basename "$file$stripped_ext"
++ file="$func_basename_result"
++ outputname="$tmpdir/$file"
++ # Replace the output file specification.
++ relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
++
++ $opt_silent || {
++ func_quote_for_expand "$relink_command"
++ eval "func_echo $func_quote_for_expand_result"
++ }
++ if eval "$relink_command"; then :
++ else
++ func_error "error: relink \`$file' with the above command before installing it"
++ $opt_dry_run || ${RM}r "$tmpdir"
++ continue
++ fi
++ file="$outputname"
++ else
++ func_warning "cannot relink \`$file'"
++ fi
++ }
++ else
++ # Install the binary that we compiled earlier.
++ file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
++ fi
++ fi
++
++ # remove .exe since cygwin /usr/bin/install will append another
++ # one anyway
++ case $install_prog,$host in
++ */usr/bin/install*,*cygwin*)
++ case $file:$destfile in
++ *.exe:*.exe)
++ # this is ok
++ ;;
++ *.exe:*)
++ destfile=$destfile.exe
++ ;;
++ *:*.exe)
++ func_stripname '' '.exe' "$destfile"
++ destfile=$func_stripname_result
++ ;;
++ esac
++ ;;
++ esac
++ func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
++ $opt_dry_run || if test -n "$outputname"; then
++ ${RM}r "$tmpdir"
++ fi
++ ;;
++ esac
++ done
++
++ for file in $staticlibs; do
++ func_basename "$file"
++ name="$func_basename_result"
++
++ # Set up the ranlib parameters.
++ oldlib="$destdir/$name"
++
++ func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
++
++ if test -n "$stripme" && test -n "$old_striplib"; then
++ func_show_eval "$old_striplib $oldlib" 'exit $?'
++ fi
++
++ # Do each command in the postinstall commands.
++ func_execute_cmds "$old_postinstall_cmds" 'exit $?'
++ done
++
++ test -n "$future_libdirs" && \
++ func_warning "remember to run \`$progname --finish$future_libdirs'"
++
++ if test -n "$current_libdirs"; then
++ # Maybe just do a dry run.
++ $opt_dry_run && current_libdirs=" -n$current_libdirs"
++ exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
++ else
++ exit $EXIT_SUCCESS
++ fi
++}
++
++test "$mode" = install && func_mode_install ${1+"$@"}
++
++
++# func_generate_dlsyms outputname originator pic_p
++# Extract symbols from dlprefiles and create ${outputname}S.o with
++# a dlpreopen symbol table.
++func_generate_dlsyms ()
++{
++ $opt_debug
++ my_outputname="$1"
++ my_originator="$2"
++ my_pic_p="${3-no}"
++ my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
++ my_dlsyms=
++
++ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
++ if test -n "$NM" && test -n "$global_symbol_pipe"; then
++ my_dlsyms="${my_outputname}S.c"
++ else
++ func_error "not configured to extract global symbols from dlpreopened files"
++ fi
++ fi
++
++ if test -n "$my_dlsyms"; then
++ case $my_dlsyms in
++ "") ;;
++ *.c)
++ # Discover the nlist of each of the dlfiles.
++ nlist="$output_objdir/${my_outputname}.nm"
++
++ func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
++
++ # Parse the name list into a source file.
++ func_verbose "creating $output_objdir/$my_dlsyms"
++
++ $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
++/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
++/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
++
++#ifdef __cplusplus
++extern \"C\" {
++#endif
++
++/* External symbol declarations for the compiler. */\
++"
++
++ if test "$dlself" = yes; then
++ func_verbose "generating symbol list for \`$output'"
++
++ $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
++
++ # Add our own program objects to the symbol list.
++ progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
++ for progfile in $progfiles; do
++ func_verbose "extracting global C symbols from \`$progfile'"
++ $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'"
++ done
++
++ if test -n "$exclude_expsyms"; then
++ $opt_dry_run || {
++ eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
++ eval '$MV "$nlist"T "$nlist"'
++ }
++ fi
++
++ if test -n "$export_symbols_regex"; then
++ $opt_dry_run || {
++ eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
++ eval '$MV "$nlist"T "$nlist"'
++ }
++ fi
++
++ # Prepare the list of exported symbols
++ if test -z "$export_symbols"; then
++ export_symbols="$output_objdir/$outputname.exp"
++ $opt_dry_run || {
++ $RM $export_symbols
++ eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
++ case $host in
++ *cygwin* | *mingw* | *cegcc* )
++ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
++ eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
++ ;;
++ esac
++ }
++ else
++ $opt_dry_run || {
++ eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
++ eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
++ eval '$MV "$nlist"T "$nlist"'
++ case $host in
++ *cygwin | *mingw* | *cegcc* )
++ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
++ eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
++ ;;
++ esac
++ }
++ fi
++ fi
++
++ for dlprefile in $dlprefiles; do
++ func_verbose "extracting global C symbols from \`$dlprefile'"
++ func_basename "$dlprefile"
++ name="$func_basename_result"
++ $opt_dry_run || {
++ eval '$ECHO ": $name " >> "$nlist"'
++ eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'"
++ }
++ done
++
++ $opt_dry_run || {
++ # Make sure we have at least an empty file.
++ test -f "$nlist" || : > "$nlist"
++
++ if test -n "$exclude_expsyms"; then
++ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
++ $MV "$nlist"T "$nlist"
++ fi
++
++ # Try sorting and uniquifying the output.
++ if $GREP -v "^: " < "$nlist" |
++ if sort -k 3 </dev/null >/dev/null 2>&1; then
++ sort -k 3
++ else
++ sort +2
++ fi |
++ uniq > "$nlist"S; then
++ :
++ else
++ $GREP -v "^: " < "$nlist" > "$nlist"S
++ fi
++
++ if test -f "$nlist"S; then
++ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
++ else
++ $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms"
++ fi
++
++ $ECHO >> "$output_objdir/$my_dlsyms" "\
++
++/* The mapping between symbol names and symbols. */
++typedef struct {
++ const char *name;
++ void *address;
++} lt_dlsymlist;
++"
++ case $host in
++ *cygwin* | *mingw* | *cegcc* )
++ $ECHO >> "$output_objdir/$my_dlsyms" "\
++/* DATA imports from DLLs on WIN32 con't be const, because
++ runtime relocations are performed -- see ld's documentation
++ on pseudo-relocs. */"
++ lt_dlsym_const= ;;
++ *osf5*)
++ echo >> "$output_objdir/$my_dlsyms" "\
++/* This system does not cope well with relocations in const data */"
++ lt_dlsym_const= ;;
++ *)
++ lt_dlsym_const=const ;;
++ esac
++
++ $ECHO >> "$output_objdir/$my_dlsyms" "\
++extern $lt_dlsym_const lt_dlsymlist
++lt_${my_prefix}_LTX_preloaded_symbols[];
++$lt_dlsym_const lt_dlsymlist
++lt_${my_prefix}_LTX_preloaded_symbols[] =
++{\
++ { \"$my_originator\", (void *) 0 },"
++
++ case $need_lib_prefix in
++ no)
++ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
++ ;;
++ *)
++ eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
++ ;;
++ esac
++ $ECHO >> "$output_objdir/$my_dlsyms" "\
++ {0, (void *) 0}
++};
++
++/* This works around a problem in FreeBSD linker */
++#ifdef FREEBSD_WORKAROUND
++static const void *lt_preloaded_setup() {
++ return lt_${my_prefix}_LTX_preloaded_symbols;
++}
++#endif
++
++#ifdef __cplusplus
++}
++#endif\
++"
++ } # !$opt_dry_run
++
++ pic_flag_for_symtable=
++ case "$compile_command " in
++ *" -static "*) ;;
++ *)
++ case $host in
++ # compiling the symbol table file with pic_flag works around
++ # a FreeBSD bug that causes programs to crash when -lm is
++ # linked before any other PIC object. But we must not use
++ # pic_flag when linking with -static. The problem exists in
++ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
++ *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
++ pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
++ *-*-hpux*)
++ pic_flag_for_symtable=" $pic_flag" ;;
++ *)
++ if test "X$my_pic_p" != Xno; then
++ pic_flag_for_symtable=" $pic_flag"
++ fi
++ ;;
++ esac
++ ;;
++ esac
++ symtab_cflags=
++ for arg in $LTCFLAGS; do
++ case $arg in
++ -pie | -fpie | -fPIE) ;;
++ *) symtab_cflags="$symtab_cflags $arg" ;;
++ esac
++ done
++
++ # Now compile the dynamic symbol file.
++ func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
++
++ # Clean up the generated files.
++ func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
++
++ # Transform the symbol file into the correct name.
++ symfileobj="$output_objdir/${my_outputname}S.$objext"
++ case $host in
++ *cygwin* | *mingw* | *cegcc* )
++ if test -f "$output_objdir/$my_outputname.def"; then
++ compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
++ finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
++ else
++ compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
++ finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
++ fi
++ ;;
++ *)
++ compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
++ finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
++ ;;
++ esac
++ ;;
++ *)
++ func_fatal_error "unknown suffix for \`$my_dlsyms'"
++ ;;
++ esac
++ else
++ # We keep going just in case the user didn't refer to
++ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
++ # really was required.
++
++ # Nullify the symbol file.
++ compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
++ finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
++ fi
++}
++
++# func_win32_libid arg
++# return the library type of file 'arg'
++#
++# Need a lot of goo to handle *both* DLLs and import libs
++# Has to be a shell function in order to 'eat' the argument
++# that is supplied when $file_magic_command is called.
++func_win32_libid ()
++{
++ $opt_debug
++ win32_libid_type="unknown"
++ win32_fileres=`file -L $1 2>/dev/null`
++ case $win32_fileres in
++ *ar\ archive\ import\ library*) # definitely import
++ win32_libid_type="x86 archive import"
++ ;;
++ *ar\ archive*) # could be an import, or static
++ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
++ $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
++ win32_nmres=`eval $NM -f posix -A $1 |
++ $SED -n -e '
++ 1,100{
++ / I /{
++ s,.*,import,
++ p
++ q
++ }
++ }'`
++ case $win32_nmres in
++ import*) win32_libid_type="x86 archive import";;
++ *) win32_libid_type="x86 archive static";;
++ esac
++ fi
++ ;;
++ *DLL*)
++ win32_libid_type="x86 DLL"
++ ;;
++ *executable*) # but shell scripts are "executable" too...
++ case $win32_fileres in
++ *MS\ Windows\ PE\ Intel*)
++ win32_libid_type="x86 DLL"
++ ;;
++ esac
++ ;;
++ esac
++ $ECHO "$win32_libid_type"
++}
++
++
++
++# func_extract_an_archive dir oldlib
++func_extract_an_archive ()
++{
++ $opt_debug
++ f_ex_an_ar_dir="$1"; shift
++ f_ex_an_ar_oldlib="$1"
++ func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?'
++ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
++ :
++ else
++ func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
++ fi
++}
++
++
++# func_extract_archives gentop oldlib ...
++func_extract_archives ()
++{
++ $opt_debug
++ my_gentop="$1"; shift
++ my_oldlibs=${1+"$@"}
++ my_oldobjs=""
++ my_xlib=""
++ my_xabs=""
++ my_xdir=""
++
++ for my_xlib in $my_oldlibs; do
++ # Extract the objects.
++ case $my_xlib in
++ [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
++ *) my_xabs=`pwd`"/$my_xlib" ;;
++ esac
++ func_basename "$my_xlib"
++ my_xlib="$func_basename_result"
++ my_xlib_u=$my_xlib
++ while :; do
++ case " $extracted_archives " in
++ *" $my_xlib_u "*)
++ func_arith $extracted_serial + 1
++ extracted_serial=$func_arith_result
++ my_xlib_u=lt$extracted_serial-$my_xlib ;;
++ *) break ;;
++ esac
++ done
++ extracted_archives="$extracted_archives $my_xlib_u"
++ my_xdir="$my_gentop/$my_xlib_u"
++
++ func_mkdir_p "$my_xdir"
++
++ case $host in
++ *-darwin*)
++ func_verbose "Extracting $my_xabs"
++ # Do not bother doing anything if just a dry run
++ $opt_dry_run || {
++ darwin_orig_dir=`pwd`
++ cd $my_xdir || exit $?
++ darwin_archive=$my_xabs
++ darwin_curdir=`pwd`
++ darwin_base_archive=`basename "$darwin_archive"`
++ darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
++ if test -n "$darwin_arches"; then
++ darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
++ darwin_arch=
++ func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
++ for darwin_arch in $darwin_arches ; do
++ func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
++ $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
++ cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
++ func_extract_an_archive "`pwd`" "${darwin_base_archive}"
++ cd "$darwin_curdir"
++ $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
++ done # $darwin_arches
++ ## Okay now we've a bunch of thin objects, gotta fatten them up :)
++ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
++ darwin_file=
++ darwin_files=
++ for darwin_file in $darwin_filelist; do
++ darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
++ $LIPO -create -output "$darwin_file" $darwin_files
++ done # $darwin_filelist
++ $RM -rf unfat-$$
++ cd "$darwin_orig_dir"
++ else
++ cd $darwin_orig_dir
++ func_extract_an_archive "$my_xdir" "$my_xabs"
++ fi # $darwin_arches
++ } # !$opt_dry_run
++ ;;
++ *)
++ func_extract_an_archive "$my_xdir" "$my_xabs"
++ ;;
++ esac
++ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
++ done
++
++ func_extract_archives_result="$my_oldobjs"
++}
++
++
++
++# func_emit_wrapper_part1 [arg=no]
++#
++# Emit the first part of a libtool wrapper script on stdout.
++# For more information, see the description associated with
++# func_emit_wrapper(), below.
++func_emit_wrapper_part1 ()
++{
++ func_emit_wrapper_part1_arg1=no
++ if test -n "$1" ; then
++ func_emit_wrapper_part1_arg1=$1
++ fi
++
++ $ECHO "\
++#! $SHELL
++
++# $output - temporary wrapper script for $objdir/$outputname
++# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
++#
++# The $output program cannot be directly executed until all the libtool
++# libraries that it depends on are installed.
++#
++# This wrapper script should never be moved out of the build directory.
++# If it is, it will not operate correctly.
++
++# Sed substitution that helps us do robust quoting. It backslashifies
++# metacharacters that are still active within double-quoted strings.
++Xsed='${SED} -e 1s/^X//'
++sed_quote_subst='$sed_quote_subst'
++
++# Be Bourne compatible
++if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
++ emulate sh
++ NULLCMD=:
++ # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
++ # is contrary to our usage. Disable this feature.
++ alias -g '\${1+\"\$@\"}'='\"\$@\"'
++ setopt NO_GLOB_SUBST
++else
++ case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
++fi
++BIN_SH=xpg4; export BIN_SH # for Tru64
++DUALCASE=1; export DUALCASE # for MKS sh
++
++# The HP-UX ksh and POSIX shell print the target directory to stdout
++# if CDPATH is set.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
++
++relink_command=\"$relink_command\"
++
++# This environment variable determines our operation mode.
++if test \"\$libtool_install_magic\" = \"$magic\"; then
++ # install mode needs the following variables:
++ generated_by_libtool_version='$macro_version'
++ notinst_deplibs='$notinst_deplibs'
++else
++ # When we are sourced in execute mode, \$file and \$ECHO are already set.
++ if test \"\$libtool_execute_magic\" != \"$magic\"; then
++ ECHO=\"$qecho\"
++ file=\"\$0\"
++ # Make sure echo works.
++ if test \"X\$1\" = X--no-reexec; then
++ # Discard the --no-reexec flag, and continue.
++ shift
++ elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then
++ # Yippee, \$ECHO works!
++ :
++ else
++ # Restart under the correct shell, and then maybe \$ECHO will work.
++ exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
++ fi
++ fi\
++"
++ $ECHO "\
++
++ # Find the directory that this script lives in.
++ thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
++ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
++
++ # Follow symbolic links until we get to the real thisdir.
++ file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
++ while test -n \"\$file\"; do
++ destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
++
++ # If there was a directory component, then change thisdir.
++ if test \"x\$destdir\" != \"x\$file\"; then
++ case \"\$destdir\" in
++ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
++ *) thisdir=\"\$thisdir/\$destdir\" ;;
++ esac
++ fi
++
++ file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
++ file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
++ done
++"
++}
++# end: func_emit_wrapper_part1
++
++# func_emit_wrapper_part2 [arg=no]
++#
++# Emit the second part of a libtool wrapper script on stdout.
++# For more information, see the description associated with
++# func_emit_wrapper(), below.
++func_emit_wrapper_part2 ()
++{
++ func_emit_wrapper_part2_arg1=no
++ if test -n "$1" ; then
++ func_emit_wrapper_part2_arg1=$1
++ fi
++
++ $ECHO "\
++
++ # Usually 'no', except on cygwin/mingw when embedded into
++ # the cwrapper.
++ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1
++ if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
++ # special case for '.'
++ if test \"\$thisdir\" = \".\"; then
++ thisdir=\`pwd\`
++ fi
++ # remove .libs from thisdir
++ case \"\$thisdir\" in
++ *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;;
++ $objdir ) thisdir=. ;;
++ esac
++ fi
++
++ # Try to get the absolute directory name.
++ absdir=\`cd \"\$thisdir\" && pwd\`
++ test -n \"\$absdir\" && thisdir=\"\$absdir\"
++"
++
++ if test "$fast_install" = yes; then
++ $ECHO "\
++ program=lt-'$outputname'$exeext
++ progdir=\"\$thisdir/$objdir\"
++
++ if test ! -f \"\$progdir/\$program\" ||
++ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
++ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
++
++ file=\"\$\$-\$program\"
++
++ if test ! -d \"\$progdir\"; then
++ $MKDIR \"\$progdir\"
++ else
++ $RM \"\$progdir/\$file\"
++ fi"
++
++ $ECHO "\
++
++ # relink executable if necessary
++ if test -n \"\$relink_command\"; then
++ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
++ else
++ $ECHO \"\$relink_command_output\" >&2
++ $RM \"\$progdir/\$file\"
++ exit 1
++ fi
++ fi
++
++ $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
++ { $RM \"\$progdir/\$program\";
++ $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
++ $RM \"\$progdir/\$file\"
++ fi"
++ else
++ $ECHO "\
++ program='$outputname'
++ progdir=\"\$thisdir/$objdir\"
++"
++ fi
++
++ $ECHO "\
++
++ if test -f \"\$progdir/\$program\"; then"
++
++ # Export our shlibpath_var if we have one.
++ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
++ $ECHO "\
++ # Add our own library path to $shlibpath_var
++ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
++
++ # Some systems cannot cope with colon-terminated $shlibpath_var
++ # The second colon is a workaround for a bug in BeOS R4 sed
++ $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
++
++ export $shlibpath_var
++"
++ fi
++
++ # fixup the dll searchpath if we need to.
++ if test -n "$dllsearchpath"; then
++ $ECHO "\
++ # Add the dll search path components to the executable PATH
++ PATH=$dllsearchpath:\$PATH
++"
++ fi
++
++ $ECHO "\
++ if test \"\$libtool_execute_magic\" != \"$magic\"; then
++ # Run the actual program with our arguments.
++"
++ case $host in
++ # Backslashes separate directories on plain windows
++ *-*-mingw | *-*-os2* | *-cegcc*)
++ $ECHO "\
++ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
++"
++ ;;
++
++ *)
++ $ECHO "\
++ exec \"\$progdir/\$program\" \${1+\"\$@\"}
++"
++ ;;
++ esac
++ $ECHO "\
++ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
++ exit 1
++ fi
++ else
++ # The program doesn't exist.
++ \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
++ \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
++ $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
++ exit 1
++ fi
++fi\
++"
++}
++# end: func_emit_wrapper_part2
++
++
++# func_emit_wrapper [arg=no]
++#
++# Emit a libtool wrapper script on stdout.
++# Don't directly open a file because we may want to
++# incorporate the script contents within a cygwin/mingw
++# wrapper executable. Must ONLY be called from within
++# func_mode_link because it depends on a number of variables
++# set therein.
++#
++# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
++# variable will take. If 'yes', then the emitted script
++# will assume that the directory in which it is stored is
++# the $objdir directory. This is a cygwin/mingw-specific
++# behavior.
++func_emit_wrapper ()
++{
++ func_emit_wrapper_arg1=no
++ if test -n "$1" ; then
++ func_emit_wrapper_arg1=$1
++ fi
++
++ # split this up so that func_emit_cwrapperexe_src
++ # can call each part independently.
++ func_emit_wrapper_part1 "${func_emit_wrapper_arg1}"
++ func_emit_wrapper_part2 "${func_emit_wrapper_arg1}"
++}
++
++
++# func_to_host_path arg
++#
++# Convert paths to host format when used with build tools.
++# Intended for use with "native" mingw (where libtool itself
++# is running under the msys shell), or in the following cross-
++# build environments:
++# $build $host
++# mingw (msys) mingw [e.g. native]
++# cygwin mingw
++# *nix + wine mingw
++# where wine is equipped with the `winepath' executable.
++# In the native mingw case, the (msys) shell automatically
++# converts paths for any non-msys applications it launches,
++# but that facility isn't available from inside the cwrapper.
++# Similar accommodations are necessary for $host mingw and
++# $build cygwin. Calling this function does no harm for other
++# $host/$build combinations not listed above.
++#
++# ARG is the path (on $build) that should be converted to
++# the proper representation for $host. The result is stored
++# in $func_to_host_path_result.
++func_to_host_path ()
++{
++ func_to_host_path_result="$1"
++ if test -n "$1" ; then
++ case $host in
++ *mingw* )
++ lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
++ case $build in
++ *mingw* ) # actually, msys
++ # awkward: cmd appends spaces to result
++ lt_sed_strip_trailing_spaces="s/[ ]*\$//"
++ func_to_host_path_tmp1=`( cmd //c echo "$1" |\
++ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""`
++ func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
++ $SED -e "$lt_sed_naive_backslashify"`
++ ;;
++ *cygwin* )
++ func_to_host_path_tmp1=`cygpath -w "$1"`
++ func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
++ $SED -e "$lt_sed_naive_backslashify"`
++ ;;
++ * )
++ # Unfortunately, winepath does not exit with a non-zero
++ # error code, so we are forced to check the contents of
++ # stdout. On the other hand, if the command is not
++ # found, the shell will set an exit code of 127 and print
++ # *an error message* to stdout. So we must check for both
++ # error code of zero AND non-empty stdout, which explains
++ # the odd construction:
++ func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null`
++ if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then
++ func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
++ $SED -e "$lt_sed_naive_backslashify"`
++ else
++ # Allow warning below.
++ func_to_host_path_result=""
++ fi
++ ;;
++ esac
++ if test -z "$func_to_host_path_result" ; then
++ func_error "Could not determine host path corresponding to"
++ func_error " '$1'"
++ func_error "Continuing, but uninstalled executables may not work."
++ # Fallback:
++ func_to_host_path_result="$1"
++ fi
++ ;;
++ esac
++ fi
++}
++# end: func_to_host_path
++
++# func_to_host_pathlist arg
++#
++# Convert pathlists to host format when used with build tools.
++# See func_to_host_path(), above. This function supports the
++# following $build/$host combinations (but does no harm for
++# combinations not listed here):
++# $build $host
++# mingw (msys) mingw [e.g. native]
++# cygwin mingw
++# *nix + wine mingw
++#
++# Path separators are also converted from $build format to
++# $host format. If ARG begins or ends with a path separator
++# character, it is preserved (but converted to $host format)
++# on output.
++#
++# ARG is a pathlist (on $build) that should be converted to
++# the proper representation on $host. The result is stored
++# in $func_to_host_pathlist_result.
++func_to_host_pathlist ()
++{
++ func_to_host_pathlist_result="$1"
++ if test -n "$1" ; then
++ case $host in
++ *mingw* )
++ lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
++ # Remove leading and trailing path separator characters from
++ # ARG. msys behavior is inconsistent here, cygpath turns them
++ # into '.;' and ';.', and winepath ignores them completely.
++ func_to_host_pathlist_tmp2="$1"
++ # Once set for this call, this variable should not be
++ # reassigned. It is used in tha fallback case.
++ func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\
++ $SED -e 's|^:*||' -e 's|:*$||'`
++ case $build in
++ *mingw* ) # Actually, msys.
++ # Awkward: cmd appends spaces to result.
++ lt_sed_strip_trailing_spaces="s/[ ]*\$//"
++ func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\
++ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""`
++ func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\
++ $SED -e "$lt_sed_naive_backslashify"`
++ ;;
++ *cygwin* )
++ func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"`
++ func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\
++ $SED -e "$lt_sed_naive_backslashify"`
++ ;;
++ * )
++ # unfortunately, winepath doesn't convert pathlists
++ func_to_host_pathlist_result=""
++ func_to_host_pathlist_oldIFS=$IFS
++ IFS=:
++ for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do
++ IFS=$func_to_host_pathlist_oldIFS
++ if test -n "$func_to_host_pathlist_f" ; then
++ func_to_host_path "$func_to_host_pathlist_f"
++ if test -n "$func_to_host_path_result" ; then
++ if test -z "$func_to_host_pathlist_result" ; then
++ func_to_host_pathlist_result="$func_to_host_path_result"
++ else
++ func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result"
++ fi
++ fi
++ fi
++ IFS=:
++ done
++ IFS=$func_to_host_pathlist_oldIFS
++ ;;
++ esac
++ if test -z "$func_to_host_pathlist_result" ; then
++ func_error "Could not determine the host path(s) corresponding to"
++ func_error " '$1'"
++ func_error "Continuing, but uninstalled executables may not work."
++ # Fallback. This may break if $1 contains DOS-style drive
++ # specifications. The fix is not to complicate the expression
++ # below, but for the user to provide a working wine installation
++ # with winepath so that path translation in the cross-to-mingw
++ # case works properly.
++ lt_replace_pathsep_nix_to_dos="s|:|;|g"
++ func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\
++ $SED -e "$lt_replace_pathsep_nix_to_dos"`
++ fi
++ # Now, add the leading and trailing path separators back
++ case "$1" in
++ :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result"
++ ;;
++ esac
++ case "$1" in
++ *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;"
++ ;;
++ esac
++ ;;
++ esac
++ fi
++}
++# end: func_to_host_pathlist
++
++# func_emit_cwrapperexe_src
++# emit the source code for a wrapper executable on stdout
++# Must ONLY be called from within func_mode_link because
++# it depends on a number of variable set therein.
++func_emit_cwrapperexe_src ()
++{
++ cat <<EOF
++
++/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
++ Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
++
++ The $output program cannot be directly executed until all the libtool
++ libraries that it depends on are installed.
++
++ This wrapper executable should never be moved out of the build directory.
++ If it is, it will not operate correctly.
++
++ Currently, it simply execs the wrapper *script* "$SHELL $output",
++ but could eventually absorb all of the scripts functionality and
++ exec $objdir/$outputname directly.
++*/
++EOF
++ cat <<"EOF"
++#include <stdio.h>
++#include <stdlib.h>
++#ifdef _MSC_VER
++# include <direct.h>
++# include <process.h>
++# include <io.h>
++# define setmode _setmode
++#else
++# include <unistd.h>
++# include <stdint.h>
++# ifdef __CYGWIN__
++# include <io.h>
++# define HAVE_SETENV
++# ifdef __STRICT_ANSI__
++char *realpath (const char *, char *);
++int putenv (char *);
++int setenv (const char *, const char *, int);
++# endif
++# endif
++#endif
++#include <malloc.h>
++#include <stdarg.h>
++#include <assert.h>
++#include <string.h>
++#include <ctype.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <sys/stat.h>
++
++#if defined(PATH_MAX)
++# define LT_PATHMAX PATH_MAX
++#elif defined(MAXPATHLEN)
++# define LT_PATHMAX MAXPATHLEN
++#else
++# define LT_PATHMAX 1024
++#endif
++
++#ifndef S_IXOTH
++# define S_IXOTH 0
++#endif
++#ifndef S_IXGRP
++# define S_IXGRP 0
++#endif
++
++#ifdef _MSC_VER
++# define S_IXUSR _S_IEXEC
++# define stat _stat
++# ifndef _INTPTR_T_DEFINED
++# define intptr_t int
++# endif
++#endif
++
++#ifndef DIR_SEPARATOR
++# define DIR_SEPARATOR '/'
++# define PATH_SEPARATOR ':'
++#endif
++
++#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
++ defined (__OS2__)
++# define HAVE_DOS_BASED_FILE_SYSTEM
++# define FOPEN_WB "wb"
++# ifndef DIR_SEPARATOR_2
++# define DIR_SEPARATOR_2 '\\'
++# endif
++# ifndef PATH_SEPARATOR_2
++# define PATH_SEPARATOR_2 ';'
++# endif
++#endif
++
++#ifndef DIR_SEPARATOR_2
++# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
++#else /* DIR_SEPARATOR_2 */
++# define IS_DIR_SEPARATOR(ch) \
++ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
++#endif /* DIR_SEPARATOR_2 */
++
++#ifndef PATH_SEPARATOR_2
++# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
++#else /* PATH_SEPARATOR_2 */
++# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
++#endif /* PATH_SEPARATOR_2 */
++
++#ifdef __CYGWIN__
++# define FOPEN_WB "wb"
++#endif
++
++#ifndef FOPEN_WB
++# define FOPEN_WB "w"
++#endif
++#ifndef _O_BINARY
++# define _O_BINARY 0
++#endif
++
++#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
++#define XFREE(stale) do { \
++ if (stale) { free ((void *) stale); stale = 0; } \
++} while (0)
++
++#undef LTWRAPPER_DEBUGPRINTF
++#if defined DEBUGWRAPPER
++# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args
++static void
++ltwrapper_debugprintf (const char *fmt, ...)
++{
++ va_list args;
++ va_start (args, fmt);
++ (void) vfprintf (stderr, fmt, args);
++ va_end (args);
++}
++#else
++# define LTWRAPPER_DEBUGPRINTF(args)
++#endif
++
++const char *program_name = NULL;
++
++void *xmalloc (size_t num);
++char *xstrdup (const char *string);
++const char *base_name (const char *name);
++char *find_executable (const char *wrapper);
++char *chase_symlinks (const char *pathspec);
++int make_executable (const char *path);
++int check_executable (const char *path);
++char *strendzap (char *str, const char *pat);
++void lt_fatal (const char *message, ...);
++void lt_setenv (const char *name, const char *value);
++char *lt_extend_str (const char *orig_value, const char *add, int to_end);
++void lt_opt_process_env_set (const char *arg);
++void lt_opt_process_env_prepend (const char *arg);
++void lt_opt_process_env_append (const char *arg);
++int lt_split_name_value (const char *arg, char** name, char** value);
++void lt_update_exe_path (const char *name, const char *value);
++void lt_update_lib_path (const char *name, const char *value);
++
++static const char *script_text_part1 =
++EOF
++
++ func_emit_wrapper_part1 yes |
++ $SED -e 's/\([\\"]\)/\\\1/g' \
++ -e 's/^/ "/' -e 's/$/\\n"/'
++ echo ";"
++ cat <<EOF
++
++static const char *script_text_part2 =
++EOF
++ func_emit_wrapper_part2 yes |
++ $SED -e 's/\([\\"]\)/\\\1/g' \
++ -e 's/^/ "/' -e 's/$/\\n"/'
++ echo ";"
++
++ cat <<EOF
++const char * MAGIC_EXE = "$magic_exe";
++const char * LIB_PATH_VARNAME = "$shlibpath_var";
++EOF
++
++ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
++ func_to_host_pathlist "$temp_rpath"
++ cat <<EOF
++const char * LIB_PATH_VALUE = "$func_to_host_pathlist_result";
++EOF
++ else
++ cat <<"EOF"
++const char * LIB_PATH_VALUE = "";
++EOF
++ fi
++
++ if test -n "$dllsearchpath"; then
++ func_to_host_pathlist "$dllsearchpath:"
++ cat <<EOF
++const char * EXE_PATH_VARNAME = "PATH";
++const char * EXE_PATH_VALUE = "$func_to_host_pathlist_result";
++EOF
++ else
++ cat <<"EOF"
++const char * EXE_PATH_VARNAME = "";
++const char * EXE_PATH_VALUE = "";
++EOF
++ fi
++
++ if test "$fast_install" = yes; then
++ cat <<EOF
++const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
++EOF
++ else
++ cat <<EOF
++const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
++EOF
++ fi
++
++
++ cat <<"EOF"
++
++#define LTWRAPPER_OPTION_PREFIX "--lt-"
++#define LTWRAPPER_OPTION_PREFIX_LENGTH 5
++
++static const size_t opt_prefix_len = LTWRAPPER_OPTION_PREFIX_LENGTH;
++static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
++
++static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script";
++
++static const size_t env_set_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 7;
++static const char *env_set_opt = LTWRAPPER_OPTION_PREFIX "env-set";
++ /* argument is putenv-style "foo=bar", value of foo is set to bar */
++
++static const size_t env_prepend_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 11;
++static const char *env_prepend_opt = LTWRAPPER_OPTION_PREFIX "env-prepend";
++ /* argument is putenv-style "foo=bar", new value of foo is bar${foo} */
++
++static const size_t env_append_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 10;
++static const char *env_append_opt = LTWRAPPER_OPTION_PREFIX "env-append";
++ /* argument is putenv-style "foo=bar", new value of foo is ${foo}bar */
++
++int
++main (int argc, char *argv[])
++{
++ char **newargz;
++ int newargc;
++ char *tmp_pathspec;
++ char *actual_cwrapper_path;
++ char *actual_cwrapper_name;
++ char *target_name;
++ char *lt_argv_zero;
++ intptr_t rval = 127;
++
++ int i;
++
++ program_name = (char *) xstrdup (base_name (argv[0]));
++ LTWRAPPER_DEBUGPRINTF (("(main) argv[0] : %s\n", argv[0]));
++ LTWRAPPER_DEBUGPRINTF (("(main) program_name : %s\n", program_name));
++
++ /* very simple arg parsing; don't want to rely on getopt */
++ for (i = 1; i < argc; i++)
++ {
++ if (strcmp (argv[i], dumpscript_opt) == 0)
++ {
++EOF
++ case "$host" in
++ *mingw* | *cygwin* )
++ # make stdout use "unix" line endings
++ echo " setmode(1,_O_BINARY);"
++ ;;
++ esac
++
++ cat <<"EOF"
++ printf ("%s", script_text_part1);
++ printf ("%s", script_text_part2);
++ return 0;
++ }
++ }
++
++ newargz = XMALLOC (char *, argc + 1);
++ tmp_pathspec = find_executable (argv[0]);
++ if (tmp_pathspec == NULL)
++ lt_fatal ("Couldn't find %s", argv[0]);
++ LTWRAPPER_DEBUGPRINTF (("(main) found exe (before symlink chase) at : %s\n",
++ tmp_pathspec));
++
++ actual_cwrapper_path = chase_symlinks (tmp_pathspec);
++ LTWRAPPER_DEBUGPRINTF (("(main) found exe (after symlink chase) at : %s\n",
++ actual_cwrapper_path));
++ XFREE (tmp_pathspec);
++
++ actual_cwrapper_name = xstrdup( base_name (actual_cwrapper_path));
++ strendzap (actual_cwrapper_path, actual_cwrapper_name);
++
++ /* wrapper name transforms */
++ strendzap (actual_cwrapper_name, ".exe");
++ tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
++ XFREE (actual_cwrapper_name);
++ actual_cwrapper_name = tmp_pathspec;
++ tmp_pathspec = 0;
++
++ /* target_name transforms -- use actual target program name; might have lt- prefix */
++ target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
++ strendzap (target_name, ".exe");
++ tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
++ XFREE (target_name);
++ target_name = tmp_pathspec;
++ tmp_pathspec = 0;
++
++ LTWRAPPER_DEBUGPRINTF (("(main) libtool target name: %s\n",
++ target_name));
++EOF
++
++ cat <<EOF
++ newargz[0] =
++ XMALLOC (char, (strlen (actual_cwrapper_path) +
++ strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
++ strcpy (newargz[0], actual_cwrapper_path);
++ strcat (newargz[0], "$objdir");
++ strcat (newargz[0], "/");
++EOF
++
++ cat <<"EOF"
++ /* stop here, and copy so we don't have to do this twice */
++ tmp_pathspec = xstrdup (newargz[0]);
++
++ /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
++ strcat (newargz[0], actual_cwrapper_name);
++
++ /* DO want the lt- prefix here if it exists, so use target_name */
++ lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
++ XFREE (tmp_pathspec);
++ tmp_pathspec = NULL;
++EOF
++
++ case $host_os in
++ mingw*)
++ cat <<"EOF"
++ {
++ char* p;
++ while ((p = strchr (newargz[0], '\\')) != NULL)
++ {
++ *p = '/';
++ }
++ while ((p = strchr (lt_argv_zero, '\\')) != NULL)
++ {
++ *p = '/';
++ }
++ }
++EOF
++ ;;
++ esac
++
++ cat <<"EOF"
++ XFREE (target_name);
++ XFREE (actual_cwrapper_path);
++ XFREE (actual_cwrapper_name);
++
++ lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
++ lt_setenv ("DUALCASE", "1"); /* for MSK sh */
++ lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
++ lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
++
++ newargc=0;
++ for (i = 1; i < argc; i++)
++ {
++ if (strncmp (argv[i], env_set_opt, env_set_opt_len) == 0)
++ {
++ if (argv[i][env_set_opt_len] == '=')
++ {
++ const char *p = argv[i] + env_set_opt_len + 1;
++ lt_opt_process_env_set (p);
++ }
++ else if (argv[i][env_set_opt_len] == '\0' && i + 1 < argc)
++ {
++ lt_opt_process_env_set (argv[++i]); /* don't copy */
++ }
++ else
++ lt_fatal ("%s missing required argument", env_set_opt);
++ continue;
++ }
++ if (strncmp (argv[i], env_prepend_opt, env_prepend_opt_len) == 0)
++ {
++ if (argv[i][env_prepend_opt_len] == '=')
++ {
++ const char *p = argv[i] + env_prepend_opt_len + 1;
++ lt_opt_process_env_prepend (p);
++ }
++ else if (argv[i][env_prepend_opt_len] == '\0' && i + 1 < argc)
++ {
++ lt_opt_process_env_prepend (argv[++i]); /* don't copy */
++ }
++ else
++ lt_fatal ("%s missing required argument", env_prepend_opt);
++ continue;
++ }
++ if (strncmp (argv[i], env_append_opt, env_append_opt_len) == 0)
++ {
++ if (argv[i][env_append_opt_len] == '=')
++ {
++ const char *p = argv[i] + env_append_opt_len + 1;
++ lt_opt_process_env_append (p);
++ }
++ else if (argv[i][env_append_opt_len] == '\0' && i + 1 < argc)
++ {
++ lt_opt_process_env_append (argv[++i]); /* don't copy */
++ }
++ else
++ lt_fatal ("%s missing required argument", env_append_opt);
++ continue;
++ }
++ if (strncmp (argv[i], ltwrapper_option_prefix, opt_prefix_len) == 0)
++ {
++ /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
++ namespace, but it is not one of the ones we know about and
++ have already dealt with, above (inluding dump-script), then
++ report an error. Otherwise, targets might begin to believe
++ they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
++ namespace. The first time any user complains about this, we'll
++ need to make LTWRAPPER_OPTION_PREFIX a configure-time option
++ or a configure.ac-settable value.
++ */
++ lt_fatal ("Unrecognized option in %s namespace: '%s'",
++ ltwrapper_option_prefix, argv[i]);
++ }
++ /* otherwise ... */
++ newargz[++newargc] = xstrdup (argv[i]);
++ }
++ newargz[++newargc] = NULL;
++
++ LTWRAPPER_DEBUGPRINTF (("(main) lt_argv_zero : %s\n", (lt_argv_zero ? lt_argv_zero : "<NULL>")));
++ for (i = 0; i < newargc; i++)
++ {
++ LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : "<NULL>")));
++ }
++
++EOF
++
++ case $host_os in
++ mingw*)
++ cat <<"EOF"
++ /* execv doesn't actually work on mingw as expected on unix */
++ rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
++ if (rval == -1)
++ {
++ /* failed to start process */
++ LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno));
++ return 127;
++ }
++ return rval;
++EOF
++ ;;
++ *)
++ cat <<"EOF"
++ execv (lt_argv_zero, newargz);
++ return rval; /* =127, but avoids unused variable warning */
++EOF
++ ;;
++ esac
++
++ cat <<"EOF"
++}
++
++void *
++xmalloc (size_t num)
++{
++ void *p = (void *) malloc (num);
++ if (!p)
++ lt_fatal ("Memory exhausted");
++
++ return p;
++}
++
++char *
++xstrdup (const char *string)
++{
++ return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
++ string) : NULL;
++}
++
++const char *
++base_name (const char *name)
++{
++ const char *base;
++
++#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
++ /* Skip over the disk name in MSDOS pathnames. */
++ if (isalpha ((unsigned char) name[0]) && name[1] == ':')
++ name += 2;
++#endif
++
++ for (base = name; *name; name++)
++ if (IS_DIR_SEPARATOR (*name))
++ base = name + 1;
++ return base;
++}
++
++int
++check_executable (const char *path)
++{
++ struct stat st;
++
++ LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n",
++ path ? (*path ? path : "EMPTY!") : "NULL!"));
++ if ((!path) || (!*path))
++ return 0;
++
++ if ((stat (path, &st) >= 0)
++ && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
++ return 1;
++ else
++ return 0;
++}
++
++int
++make_executable (const char *path)
++{
++ int rval = 0;
++ struct stat st;
++
++ LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n",
++ path ? (*path ? path : "EMPTY!") : "NULL!"));
++ if ((!path) || (!*path))
++ return 0;
++
++ if (stat (path, &st) >= 0)
++ {
++ rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
++ }
++ return rval;
++}
++
++/* Searches for the full path of the wrapper. Returns
++ newly allocated full path name if found, NULL otherwise
++ Does not chase symlinks, even on platforms that support them.
++*/
++char *
++find_executable (const char *wrapper)
++{
++ int has_slash = 0;
++ const char *p;
++ const char *p_next;
++ /* static buffer for getcwd */
++ char tmp[LT_PATHMAX + 1];
++ int tmp_len;
++ char *concat_name;
++
++ LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n",
++ wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"));
++
++ if ((wrapper == NULL) || (*wrapper == '\0'))
++ return NULL;
++
++ /* Absolute path? */
++#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
++ if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
++ {
++ concat_name = xstrdup (wrapper);
++ if (check_executable (concat_name))
++ return concat_name;
++ XFREE (concat_name);
++ }
++ else
++ {
++#endif
++ if (IS_DIR_SEPARATOR (wrapper[0]))
++ {
++ concat_name = xstrdup (wrapper);
++ if (check_executable (concat_name))
++ return concat_name;
++ XFREE (concat_name);
++ }
++#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
++ }
++#endif
++
++ for (p = wrapper; *p; p++)
++ if (*p == '/')
++ {
++ has_slash = 1;
++ break;
++ }
++ if (!has_slash)
++ {
++ /* no slashes; search PATH */
++ const char *path = getenv ("PATH");
++ if (path != NULL)
++ {
++ for (p = path; *p; p = p_next)
++ {
++ const char *q;
++ size_t p_len;
++ for (q = p; *q; q++)
++ if (IS_PATH_SEPARATOR (*q))
++ break;
++ p_len = q - p;
++ p_next = (*q == '\0' ? q : q + 1);
++ if (p_len == 0)
++ {
++ /* empty path: current directory */
++ if (getcwd (tmp, LT_PATHMAX) == NULL)
++ lt_fatal ("getcwd failed");
++ tmp_len = strlen (tmp);
++ concat_name =
++ XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
++ memcpy (concat_name, tmp, tmp_len);
++ concat_name[tmp_len] = '/';
++ strcpy (concat_name + tmp_len + 1, wrapper);
++ }
++ else
++ {
++ concat_name =
++ XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
++ memcpy (concat_name, p, p_len);
++ concat_name[p_len] = '/';
++ strcpy (concat_name + p_len + 1, wrapper);
++ }
++ if (check_executable (concat_name))
++ return concat_name;
++ XFREE (concat_name);
++ }
++ }
++ /* not found in PATH; assume curdir */
++ }
++ /* Relative path | not found in path: prepend cwd */
++ if (getcwd (tmp, LT_PATHMAX) == NULL)
++ lt_fatal ("getcwd failed");
++ tmp_len = strlen (tmp);
++ concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
++ memcpy (concat_name, tmp, tmp_len);
++ concat_name[tmp_len] = '/';
++ strcpy (concat_name + tmp_len + 1, wrapper);
++
++ if (check_executable (concat_name))
++ return concat_name;
++ XFREE (concat_name);
++ return NULL;
++}
++
++char *
++chase_symlinks (const char *pathspec)
++{
++#ifndef S_ISLNK
++ return xstrdup (pathspec);
++#else
++ char buf[LT_PATHMAX];
++ struct stat s;
++ char *tmp_pathspec = xstrdup (pathspec);
++ char *p;
++ int has_symlinks = 0;
++ while (strlen (tmp_pathspec) && !has_symlinks)
++ {
++ LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n",
++ tmp_pathspec));
++ if (lstat (tmp_pathspec, &s) == 0)
++ {
++ if (S_ISLNK (s.st_mode) != 0)
++ {
++ has_symlinks = 1;
++ break;
++ }
++
++ /* search backwards for last DIR_SEPARATOR */
++ p = tmp_pathspec + strlen (tmp_pathspec) - 1;
++ while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
++ p--;
++ if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
++ {
++ /* no more DIR_SEPARATORS left */
++ break;
++ }
++ *p = '\0';
++ }
++ else
++ {
++ char *errstr = strerror (errno);
++ lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr);
++ }
++ }
++ XFREE (tmp_pathspec);
++
++ if (!has_symlinks)
++ {
++ return xstrdup (pathspec);
++ }
++
++ tmp_pathspec = realpath (pathspec, buf);
++ if (tmp_pathspec == 0)
++ {
++ lt_fatal ("Could not follow symlinks for %s", pathspec);
++ }
++ return xstrdup (tmp_pathspec);
++#endif
++}
++
++char *
++strendzap (char *str, const char *pat)
++{
++ size_t len, patlen;
++
++ assert (str != NULL);
++ assert (pat != NULL);
++
++ len = strlen (str);
++ patlen = strlen (pat);
++
++ if (patlen <= len)
++ {
++ str += len - patlen;
++ if (strcmp (str, pat) == 0)
++ *str = '\0';
++ }
++ return str;
++}
++
++static void
++lt_error_core (int exit_status, const char *mode,
++ const char *message, va_list ap)
++{
++ fprintf (stderr, "%s: %s: ", program_name, mode);
++ vfprintf (stderr, message, ap);
++ fprintf (stderr, ".\n");
++
++ if (exit_status >= 0)
++ exit (exit_status);
++}
++
++void
++lt_fatal (const char *message, ...)
++{
++ va_list ap;
++ va_start (ap, message);
++ lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
++ va_end (ap);
++}
++
++void
++lt_setenv (const char *name, const char *value)
++{
++ LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n",
++ (name ? name : "<NULL>"),
++ (value ? value : "<NULL>")));
++ {
++#ifdef HAVE_SETENV
++ /* always make a copy, for consistency with !HAVE_SETENV */
++ char *str = xstrdup (value);
++ setenv (name, str, 1);
++#else
++ int len = strlen (name) + 1 + strlen (value) + 1;
++ char *str = XMALLOC (char, len);
++ sprintf (str, "%s=%s", name, value);
++ if (putenv (str) != EXIT_SUCCESS)
++ {
++ XFREE (str);
++ }
++#endif
++ }
++}
++
++char *
++lt_extend_str (const char *orig_value, const char *add, int to_end)
++{
++ char *new_value;
++ if (orig_value && *orig_value)
++ {
++ int orig_value_len = strlen (orig_value);
++ int add_len = strlen (add);
++ new_value = XMALLOC (char, add_len + orig_value_len + 1);
++ if (to_end)
++ {
++ strcpy (new_value, orig_value);
++ strcpy (new_value + orig_value_len, add);
++ }
++ else
++ {
++ strcpy (new_value, add);
++ strcpy (new_value + add_len, orig_value);
++ }
++ }
++ else
++ {
++ new_value = xstrdup (add);
++ }
++ return new_value;
++}
++
++int
++lt_split_name_value (const char *arg, char** name, char** value)
++{
++ const char *p;
++ int len;
++ if (!arg || !*arg)
++ return 1;
++
++ p = strchr (arg, (int)'=');
++
++ if (!p)
++ return 1;
++
++ *value = xstrdup (++p);
++
++ len = strlen (arg) - strlen (*value);
++ *name = XMALLOC (char, len);
++ strncpy (*name, arg, len-1);
++ (*name)[len - 1] = '\0';
++
++ return 0;
++}
++
++void
++lt_opt_process_env_set (const char *arg)
++{
++ char *name = NULL;
++ char *value = NULL;
++
++ if (lt_split_name_value (arg, &name, &value) != 0)
++ {
++ XFREE (name);
++ XFREE (value);
++ lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg);
++ }
++
++ lt_setenv (name, value);
++ XFREE (name);
++ XFREE (value);
++}
++
++void
++lt_opt_process_env_prepend (const char *arg)
++{
++ char *name = NULL;
++ char *value = NULL;
++ char *new_value = NULL;
++
++ if (lt_split_name_value (arg, &name, &value) != 0)
++ {
++ XFREE (name);
++ XFREE (value);
++ lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg);
++ }
++
++ new_value = lt_extend_str (getenv (name), value, 0);
++ lt_setenv (name, new_value);
++ XFREE (new_value);
++ XFREE (name);
++ XFREE (value);
++}
++
++void
++lt_opt_process_env_append (const char *arg)
++{
++ char *name = NULL;
++ char *value = NULL;
++ char *new_value = NULL;
++
++ if (lt_split_name_value (arg, &name, &value) != 0)
++ {
++ XFREE (name);
++ XFREE (value);
++ lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg);
++ }
++
++ new_value = lt_extend_str (getenv (name), value, 1);
++ lt_setenv (name, new_value);
++ XFREE (new_value);
++ XFREE (name);
++ XFREE (value);
++}
++
++void
++lt_update_exe_path (const char *name, const char *value)
++{
++ LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
++ (name ? name : "<NULL>"),
++ (value ? value : "<NULL>")));
++
++ if (name && *name && value && *value)
++ {
++ char *new_value = lt_extend_str (getenv (name), value, 0);
++ /* some systems can't cope with a ':'-terminated path #' */
++ int len = strlen (new_value);
++ while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
++ {
++ new_value[len-1] = '\0';
++ }
++ lt_setenv (name, new_value);
++ XFREE (new_value);
++ }
++}
++
++void
++lt_update_lib_path (const char *name, const char *value)
++{
++ LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
++ (name ? name : "<NULL>"),
++ (value ? value : "<NULL>")));
++
++ if (name && *name && value && *value)
++ {
++ char *new_value = lt_extend_str (getenv (name), value, 0);
++ lt_setenv (name, new_value);
++ XFREE (new_value);
++ }
++}
++
++
++EOF
++}
++# end: func_emit_cwrapperexe_src
++
++# func_mode_link arg...
++func_mode_link ()
++{
++ $opt_debug
++ case $host in
++ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
++ # It is impossible to link a dll without this setting, and
++ # we shouldn't force the makefile maintainer to figure out
++ # which system we are compiling for in order to pass an extra
++ # flag for every libtool invocation.
++ # allow_undefined=no
++
++ # FIXME: Unfortunately, there are problems with the above when trying
++ # to make a dll which has undefined symbols, in which case not
++ # even a static library is built. For now, we need to specify
++ # -no-undefined on the libtool link line when we can be certain
++ # that all symbols are satisfied, otherwise we get a static library.
++ allow_undefined=yes
++ ;;
++ *)
++ allow_undefined=yes
++ ;;
++ esac
++ libtool_args=$nonopt
++ base_compile="$nonopt $@"
++ compile_command=$nonopt
++ finalize_command=$nonopt
++
++ compile_rpath=
++ finalize_rpath=
++ compile_shlibpath=
++ finalize_shlibpath=
++ convenience=
++ old_convenience=
++ deplibs=
++ old_deplibs=
++ compiler_flags=
++ linker_flags=
++ dllsearchpath=
++ lib_search_path=`pwd`
++ inst_prefix_dir=
++ new_inherited_linker_flags=
++
++ avoid_version=no
++ dlfiles=
++ dlprefiles=
++ dlself=no
++ export_dynamic=no
++ export_symbols=
++ export_symbols_regex=
++ generated=
++ libobjs=
++ ltlibs=
++ module=no
++ no_install=no
++ objs=
++ non_pic_objects=
++ precious_files_regex=
++ prefer_static_libs=no
++ preload=no
++ prev=
++ prevarg=
++ release=
++ rpath=
++ xrpath=
++ perm_rpath=
++ temp_rpath=
++ thread_safe=no
++ vinfo=
++ vinfo_number=no
++ weak_libs=
++ single_module="${wl}-single_module"
++ func_infer_tag $base_compile
++
++ # We need to know -static, to get the right output filenames.
++ for arg
++ do
++ case $arg in
++ -shared)
++ test "$build_libtool_libs" != yes && \
++ func_fatal_configuration "can not build a shared library"
++ build_old_libs=no
++ break
++ ;;
++ -all-static | -static | -static-libtool-libs)
++ case $arg in
++ -all-static)
++ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
++ func_warning "complete static linking is impossible in this configuration"
++ fi
++ if test -n "$link_static_flag"; then
++ dlopen_self=$dlopen_self_static
++ fi
++ prefer_static_libs=yes
++ ;;
++ -static)
++ if test -z "$pic_flag" && test -n "$link_static_flag"; then
++ dlopen_self=$dlopen_self_static
++ fi
++ prefer_static_libs=built
++ ;;
++ -static-libtool-libs)
++ if test -z "$pic_flag" && test -n "$link_static_flag"; then
++ dlopen_self=$dlopen_self_static
++ fi
++ prefer_static_libs=yes
++ ;;
++ esac
++ build_libtool_libs=no
++ build_old_libs=yes
++ break
++ ;;
++ esac
++ done
++
++ # See if our shared archives depend on static archives.
++ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
++
++ # Go through the arguments, transforming them on the way.
++ while test "$#" -gt 0; do
++ arg="$1"
++ shift
++ func_quote_for_eval "$arg"
++ qarg=$func_quote_for_eval_unquoted_result
++ func_append libtool_args " $func_quote_for_eval_result"
++
++ # If the previous option needs an argument, assign it.
++ if test -n "$prev"; then
++ case $prev in
++ output)
++ func_append compile_command " @OUTPUT@"
++ func_append finalize_command " @OUTPUT@"
++ ;;
++ esac
++
++ case $prev in
++ dlfiles|dlprefiles)
++ if test "$preload" = no; then
++ # Add the symbol object into the linking commands.
++ func_append compile_command " @SYMFILE@"
++ func_append finalize_command " @SYMFILE@"
++ preload=yes
++ fi
++ case $arg in
++ *.la | *.lo) ;; # We handle these cases below.
++ force)
++ if test "$dlself" = no; then
++ dlself=needless
++ export_dynamic=yes
++ fi
++ prev=
++ continue
++ ;;
++ self)
++ if test "$prev" = dlprefiles; then
++ dlself=yes
++ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
++ dlself=yes
++ else
++ dlself=needless
++ export_dynamic=yes
++ fi
++ prev=
++ continue
++ ;;
++ *)
++ if test "$prev" = dlfiles; then
++ dlfiles="$dlfiles $arg"
++ else
++ dlprefiles="$dlprefiles $arg"
++ fi
++ prev=
++ continue
++ ;;
++ esac
++ ;;
++ expsyms)
++ export_symbols="$arg"
++ test -f "$arg" \
++ || func_fatal_error "symbol file \`$arg' does not exist"
++ prev=
++ continue
++ ;;
++ expsyms_regex)
++ export_symbols_regex="$arg"
++ prev=
++ continue
++ ;;
++ framework)
++ case $host in
++ *-*-darwin*)
++ case "$deplibs " in
++ *" $qarg.ltframework "*) ;;
++ *) deplibs="$deplibs $qarg.ltframework" # this is fixed later
++ ;;
++ esac
++ ;;
++ esac
++ prev=
++ continue
++ ;;
++ inst_prefix)
++ inst_prefix_dir="$arg"
++ prev=
++ continue
++ ;;
++ objectlist)
++ if test -f "$arg"; then
++ save_arg=$arg
++ moreargs=
++ for fil in `cat "$save_arg"`
++ do
++# moreargs="$moreargs $fil"
++ arg=$fil
++ # A libtool-controlled object.
++
++ # Check to see that this really is a libtool object.
++ if func_lalib_unsafe_p "$arg"; then
++ pic_object=
++ non_pic_object=
++
++ # Read the .lo file
++ func_source "$arg"
++
++ if test -z "$pic_object" ||
++ test -z "$non_pic_object" ||
++ test "$pic_object" = none &&
++ test "$non_pic_object" = none; then
++ func_fatal_error "cannot find name of object for \`$arg'"
++ fi
++
++ # Extract subdirectory from the argument.
++ func_dirname "$arg" "/" ""
++ xdir="$func_dirname_result"
++
++ if test "$pic_object" != none; then
++ # Prepend the subdirectory the object is found in.
++ pic_object="$xdir$pic_object"
++
++ if test "$prev" = dlfiles; then
++ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
++ dlfiles="$dlfiles $pic_object"
++ prev=
++ continue
++ else
++ # If libtool objects are unsupported, then we need to preload.
++ prev=dlprefiles
++ fi
++ fi
++
++ # CHECK ME: I think I busted this. -Ossama
++ if test "$prev" = dlprefiles; then
++ # Preload the old-style object.
++ dlprefiles="$dlprefiles $pic_object"
++ prev=
++ fi
++
++ # A PIC object.
++ func_append libobjs " $pic_object"
++ arg="$pic_object"
++ fi
++
++ # Non-PIC object.
++ if test "$non_pic_object" != none; then
++ # Prepend the subdirectory the object is found in.
++ non_pic_object="$xdir$non_pic_object"
++
++ # A standard non-PIC object
++ func_append non_pic_objects " $non_pic_object"
++ if test -z "$pic_object" || test "$pic_object" = none ; then
++ arg="$non_pic_object"
++ fi
++ else
++ # If the PIC object exists, use it instead.
++ # $xdir was prepended to $pic_object above.
++ non_pic_object="$pic_object"
++ func_append non_pic_objects " $non_pic_object"
++ fi
++ else
++ # Only an error if not doing a dry-run.
++ if $opt_dry_run; then
++ # Extract subdirectory from the argument.
++ func_dirname "$arg" "/" ""
++ xdir="$func_dirname_result"
++
++ func_lo2o "$arg"
++ pic_object=$xdir$objdir/$func_lo2o_result
++ non_pic_object=$xdir$func_lo2o_result
++ func_append libobjs " $pic_object"
++ func_append non_pic_objects " $non_pic_object"
++ else
++ func_fatal_error "\`$arg' is not a valid libtool object"
++ fi
++ fi
++ done
++ else
++ func_fatal_error "link input file \`$arg' does not exist"
++ fi
++ arg=$save_arg
++ prev=
++ continue
++ ;;
++ precious_regex)
++ precious_files_regex="$arg"
++ prev=
++ continue
++ ;;
++ release)
++ release="-$arg"
++ prev=
++ continue
++ ;;
++ rpath | xrpath)
++ # We need an absolute path.
++ case $arg in
++ [\\/]* | [A-Za-z]:[\\/]*) ;;
++ *)
++ func_fatal_error "only absolute run-paths are allowed"
++ ;;
++ esac
++ if test "$prev" = rpath; then
++ case "$rpath " in
++ *" $arg "*) ;;
++ *) rpath="$rpath $arg" ;;
++ esac
++ else
++ case "$xrpath " in
++ *" $arg "*) ;;
++ *) xrpath="$xrpath $arg" ;;
++ esac
++ fi
++ prev=
++ continue
++ ;;
++ shrext)
++ shrext_cmds="$arg"
++ prev=
++ continue
++ ;;
++ weak)
++ weak_libs="$weak_libs $arg"
++ prev=
++ continue
++ ;;
++ xcclinker)
++ linker_flags="$linker_flags $qarg"
++ compiler_flags="$compiler_flags $qarg"
++ prev=
++ func_append compile_command " $qarg"
++ func_append finalize_command " $qarg"
++ continue
++ ;;
++ xcompiler)
++ compiler_flags="$compiler_flags $qarg"
++ prev=
++ func_append compile_command " $qarg"
++ func_append finalize_command " $qarg"
++ continue
++ ;;
++ xlinker)
++ linker_flags="$linker_flags $qarg"
++ compiler_flags="$compiler_flags $wl$qarg"
++ prev=
++ func_append compile_command " $wl$qarg"
++ func_append finalize_command " $wl$qarg"
++ continue
++ ;;
++ *)
++ eval "$prev=\"\$arg\""
++ prev=
++ continue
++ ;;
++ esac
++ fi # test -n "$prev"
++
++ prevarg="$arg"
++
++ case $arg in
++ -all-static)
++ if test -n "$link_static_flag"; then
++ # See comment for -static flag below, for more details.
++ func_append compile_command " $link_static_flag"
++ func_append finalize_command " $link_static_flag"
++ fi
++ continue
++ ;;
++
++ -allow-undefined)
++ # FIXME: remove this flag sometime in the future.
++ func_fatal_error "\`-allow-undefined' must not be used because it is the default"
++ ;;
++
++ -avoid-version)
++ avoid_version=yes
++ continue
++ ;;
++
++ -dlopen)
++ prev=dlfiles
++ continue
++ ;;
++
++ -dlpreopen)
++ prev=dlprefiles
++ continue
++ ;;
++
++ -export-dynamic)
++ export_dynamic=yes
++ continue
++ ;;
++
++ -export-symbols | -export-symbols-regex)
++ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
++ func_fatal_error "more than one -exported-symbols argument is not allowed"
++ fi
++ if test "X$arg" = "X-export-symbols"; then
++ prev=expsyms
++ else
++ prev=expsyms_regex
++ fi
++ continue
++ ;;
++
++ -framework)
++ prev=framework
++ continue
++ ;;
++
++ -inst-prefix-dir)
++ prev=inst_prefix
++ continue
++ ;;
++
++ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
++ # so, if we see these flags be careful not to treat them like -L
++ -L[A-Z][A-Z]*:*)
++ case $with_gcc/$host in
++ no/*-*-irix* | /*-*-irix*)
++ func_append compile_command " $arg"
++ func_append finalize_command " $arg"
++ ;;
++ esac
++ continue
++ ;;
++
++ -L*)
++ func_stripname '-L' '' "$arg"
++ dir=$func_stripname_result
++ if test -z "$dir"; then
++ if test "$#" -gt 0; then
++ func_fatal_error "require no space between \`-L' and \`$1'"
++ else
++ func_fatal_error "need path for \`-L' option"
++ fi
++ fi
++ # We need an absolute path.
++ case $dir in
++ [\\/]* | [A-Za-z]:[\\/]*) ;;
++ *)
++ absdir=`cd "$dir" && pwd`
++ test -z "$absdir" && \
++ func_fatal_error "cannot determine absolute directory name of \`$dir'"
++ dir="$absdir"
++ ;;
++ esac
++ case "$deplibs " in
++ *" -L$dir "*) ;;
++ *)
++ deplibs="$deplibs -L$dir"
++ lib_search_path="$lib_search_path $dir"
++ ;;
++ esac
++ case $host in
++ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
++ testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'`
++ case :$dllsearchpath: in
++ *":$dir:"*) ;;
++ ::) dllsearchpath=$dir;;
++ *) dllsearchpath="$dllsearchpath:$dir";;
++ esac
++ case :$dllsearchpath: in
++ *":$testbindir:"*) ;;
++ ::) dllsearchpath=$testbindir;;
++ *) dllsearchpath="$dllsearchpath:$testbindir";;
++ esac
++ ;;
++ esac
++ continue
++ ;;
++
++ -l*)
++ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
++ case $host in
++ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*)
++ # These systems don't actually have a C or math library (as such)
++ continue
++ ;;
++ *-*-os2*)
++ # These systems don't actually have a C library (as such)
++ test "X$arg" = "X-lc" && continue
++ ;;
++ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
++ # Do not include libc due to us having libc/libc_r.
++ test "X$arg" = "X-lc" && continue
++ ;;
++ *-*-rhapsody* | *-*-darwin1.[012])
++ # Rhapsody C and math libraries are in the System framework
++ deplibs="$deplibs System.ltframework"
++ continue
++ ;;
++ *-*-sco3.2v5* | *-*-sco5v6*)
++ # Causes problems with __ctype
++ test "X$arg" = "X-lc" && continue
++ ;;
++ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
++ # Compiler inserts libc in the correct place for threads to work
++ test "X$arg" = "X-lc" && continue
++ ;;
++ esac
++ elif test "X$arg" = "X-lc_r"; then
++ case $host in
++ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
++ # Do not include libc_r directly, use -pthread flag.
++ continue
++ ;;
++ esac
++ fi
++ deplibs="$deplibs $arg"
++ continue
++ ;;
++
++ -module)
++ module=yes
++ continue
++ ;;
++
++ # Tru64 UNIX uses -model [arg] to determine the layout of C++
++ # classes, name mangling, and exception handling.
++ # Darwin uses the -arch flag to determine output architecture.
++ -model|-arch|-isysroot)
++ compiler_flags="$compiler_flags $arg"
++ func_append compile_command " $arg"
++ func_append finalize_command " $arg"
++ prev=xcompiler
++ continue
++ ;;
++
++ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
++ compiler_flags="$compiler_flags $arg"
++ func_append compile_command " $arg"
++ func_append finalize_command " $arg"
++ case "$new_inherited_linker_flags " in
++ *" $arg "*) ;;
++ * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;;
++ esac
++ continue
++ ;;
++
++ -multi_module)
++ single_module="${wl}-multi_module"
++ continue
++ ;;
++
++ -no-fast-install)
++ fast_install=no
++ continue
++ ;;
++
++ -no-install)
++ case $host in
++ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
++ # The PATH hackery in wrapper scripts is required on Windows
++ # and Darwin in order for the loader to find any dlls it needs.
++ func_warning "\`-no-install' is ignored for $host"
++ func_warning "assuming \`-no-fast-install' instead"
++ fast_install=no
++ ;;
++ *) no_install=yes ;;
++ esac
++ continue
++ ;;
++
++ -no-undefined)
++ allow_undefined=no
++ continue
++ ;;
++
++ -objectlist)
++ prev=objectlist
++ continue
++ ;;
++
++ -o) prev=output ;;
++
++ -precious-files-regex)
++ prev=precious_regex
++ continue
++ ;;
++
++ -release)
++ prev=release
++ continue
++ ;;
++
++ -rpath)
++ prev=rpath
++ continue
++ ;;
++
++ -R)
++ prev=xrpath
++ continue
++ ;;
++
++ -R*)
++ func_stripname '-R' '' "$arg"
++ dir=$func_stripname_result
++ # We need an absolute path.
++ case $dir in
++ [\\/]* | [A-Za-z]:[\\/]*) ;;
++ *)
++ func_fatal_error "only absolute run-paths are allowed"
++ ;;
++ esac
++ case "$xrpath " in
++ *" $dir "*) ;;
++ *) xrpath="$xrpath $dir" ;;
++ esac
++ continue
++ ;;
++
++ -shared)
++ # The effects of -shared are defined in a previous loop.
++ continue
++ ;;
++
++ -shrext)
++ prev=shrext
++ continue
++ ;;
++
++ -static | -static-libtool-libs)
++ # The effects of -static are defined in a previous loop.
++ # We used to do the same as -all-static on platforms that
++ # didn't have a PIC flag, but the assumption that the effects
++ # would be equivalent was wrong. It would break on at least
++ # Digital Unix and AIX.
++ continue
++ ;;
++
++ -thread-safe)
++ thread_safe=yes
++ continue
++ ;;
++
++ -version-info)
++ prev=vinfo
++ continue
++ ;;
++
++ -version-number)
++ prev=vinfo
++ vinfo_number=yes
++ continue
++ ;;
++
++ -weak)
++ prev=weak
++ continue
++ ;;
++
++ -Wc,*)
++ func_stripname '-Wc,' '' "$arg"
++ args=$func_stripname_result
++ arg=
++ save_ifs="$IFS"; IFS=','
++ for flag in $args; do
++ IFS="$save_ifs"
++ func_quote_for_eval "$flag"
++ arg="$arg $wl$func_quote_for_eval_result"
++ compiler_flags="$compiler_flags $func_quote_for_eval_result"
++ done
++ IFS="$save_ifs"
++ func_stripname ' ' '' "$arg"
++ arg=$func_stripname_result
++ ;;
++
++ -Wl,*)
++ func_stripname '-Wl,' '' "$arg"
++ args=$func_stripname_result
++ arg=
++ save_ifs="$IFS"; IFS=','
++ for flag in $args; do
++ IFS="$save_ifs"
++ func_quote_for_eval "$flag"
++ arg="$arg $wl$func_quote_for_eval_result"
++ compiler_flags="$compiler_flags $wl$func_quote_for_eval_result"
++ linker_flags="$linker_flags $func_quote_for_eval_result"
++ done
++ IFS="$save_ifs"
++ func_stripname ' ' '' "$arg"
++ arg=$func_stripname_result
++ ;;
++
++ -Xcompiler)
++ prev=xcompiler
++ continue
++ ;;
++
++ -Xlinker)
++ prev=xlinker
++ continue
++ ;;
++
++ -XCClinker)
++ prev=xcclinker
++ continue
++ ;;
++
++ # -msg_* for osf cc
++ -msg_*)
++ func_quote_for_eval "$arg"
++ arg="$func_quote_for_eval_result"
++ ;;
++
++ # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
++ # -r[0-9][0-9]* specifies the processor on the SGI compiler
++ # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
++ # +DA*, +DD* enable 64-bit mode on the HP compiler
++ # -q* pass through compiler args for the IBM compiler
++ # -m*, -t[45]*, -txscale* pass through architecture-specific
++ # compiler args for GCC
++ # -F/path gives path to uninstalled frameworks, gcc on darwin
++ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
++ # @file GCC response files
++ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
++ func_quote_for_eval "$arg"
++ arg="$func_quote_for_eval_result"
++ func_append compile_command " $arg"
++ func_append finalize_command " $arg"
++ compiler_flags="$compiler_flags $arg"
++ continue
++ ;;
++
++ # Some other compiler flag.
++ -* | +*)
++ func_quote_for_eval "$arg"
++ arg="$func_quote_for_eval_result"
++ ;;
++
++ *.$objext)
++ # A standard object.
++ objs="$objs $arg"
++ ;;
++
++ *.lo)
++ # A libtool-controlled object.
++
++ # Check to see that this really is a libtool object.
++ if func_lalib_unsafe_p "$arg"; then
++ pic_object=
++ non_pic_object=
++
++ # Read the .lo file
++ func_source "$arg"
++
++ if test -z "$pic_object" ||
++ test -z "$non_pic_object" ||
++ test "$pic_object" = none &&
++ test "$non_pic_object" = none; then
++ func_fatal_error "cannot find name of object for \`$arg'"
++ fi
++
++ # Extract subdirectory from the argument.
++ func_dirname "$arg" "/" ""
++ xdir="$func_dirname_result"
++
++ if test "$pic_object" != none; then
++ # Prepend the subdirectory the object is found in.
++ pic_object="$xdir$pic_object"
++
++ if test "$prev" = dlfiles; then
++ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
++ dlfiles="$dlfiles $pic_object"
++ prev=
++ continue
++ else
++ # If libtool objects are unsupported, then we need to preload.
++ prev=dlprefiles
++ fi
++ fi
++
++ # CHECK ME: I think I busted this. -Ossama
++ if test "$prev" = dlprefiles; then
++ # Preload the old-style object.
++ dlprefiles="$dlprefiles $pic_object"
++ prev=
++ fi
++
++ # A PIC object.
++ func_append libobjs " $pic_object"
++ arg="$pic_object"
++ fi
++
++ # Non-PIC object.
++ if test "$non_pic_object" != none; then
++ # Prepend the subdirectory the object is found in.
++ non_pic_object="$xdir$non_pic_object"
++
++ # A standard non-PIC object
++ func_append non_pic_objects " $non_pic_object"
++ if test -z "$pic_object" || test "$pic_object" = none ; then
++ arg="$non_pic_object"
++ fi
++ else
++ # If the PIC object exists, use it instead.
++ # $xdir was prepended to $pic_object above.
++ non_pic_object="$pic_object"
++ func_append non_pic_objects " $non_pic_object"
++ fi
++ else
++ # Only an error if not doing a dry-run.
++ if $opt_dry_run; then
++ # Extract subdirectory from the argument.
++ func_dirname "$arg" "/" ""
++ xdir="$func_dirname_result"
++
++ func_lo2o "$arg"
++ pic_object=$xdir$objdir/$func_lo2o_result
++ non_pic_object=$xdir$func_lo2o_result
++ func_append libobjs " $pic_object"
++ func_append non_pic_objects " $non_pic_object"
++ else
++ func_fatal_error "\`$arg' is not a valid libtool object"
++ fi
++ fi
++ ;;
++
++ *.$libext)
++ # An archive.
++ deplibs="$deplibs $arg"
++ old_deplibs="$old_deplibs $arg"
++ continue
++ ;;
++
++ *.la)
++ # A libtool-controlled library.
++
++ if test "$prev" = dlfiles; then
++ # This library was specified with -dlopen.
++ dlfiles="$dlfiles $arg"
++ prev=
++ elif test "$prev" = dlprefiles; then
++ # The library was specified with -dlpreopen.
++ dlprefiles="$dlprefiles $arg"
++ prev=
++ else
++ deplibs="$deplibs $arg"
++ fi
++ continue
++ ;;
++
++ # Some other compiler argument.
++ *)
++ # Unknown arguments in both finalize_command and compile_command need
++ # to be aesthetically quoted because they are evaled later.
++ func_quote_for_eval "$arg"
++ arg="$func_quote_for_eval_result"
++ ;;
++ esac # arg
++
++ # Now actually substitute the argument into the commands.
++ if test -n "$arg"; then
++ func_append compile_command " $arg"
++ func_append finalize_command " $arg"
++ fi
++ done # argument parsing loop
++
++ test -n "$prev" && \
++ func_fatal_help "the \`$prevarg' option requires an argument"
++
++ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
++ eval arg=\"$export_dynamic_flag_spec\"
++ func_append compile_command " $arg"
++ func_append finalize_command " $arg"
++ fi
++
++ oldlibs=
++ # calculate the name of the file, without its directory
++ func_basename "$output"
++ outputname="$func_basename_result"
++ libobjs_save="$libobjs"
++
++ if test -n "$shlibpath_var"; then
++ # get the directories listed in $shlibpath_var
++ eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
++ else
++ shlib_search_path=
++ fi
++ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
++ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
++
++ func_dirname "$output" "/" ""
++ output_objdir="$func_dirname_result$objdir"
++ # Create the object directory.
++ func_mkdir_p "$output_objdir"
++
++ # Determine the type of output
++ case $output in
++ "")
++ func_fatal_help "you must specify an output file"
++ ;;
++ *.$libext) linkmode=oldlib ;;
++ *.lo | *.$objext) linkmode=obj ;;
++ *.la) linkmode=lib ;;
++ *) linkmode=prog ;; # Anything else should be a program.
++ esac
++
++ specialdeplibs=
++
++ libs=
++ # Find all interdependent deplibs by searching for libraries
++ # that are linked more than once (e.g. -la -lb -la)
++ for deplib in $deplibs; do
++ if $opt_duplicate_deps ; then
++ case "$libs " in
++ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
++ esac
++ fi
++ libs="$libs $deplib"
++ done
++
++ if test "$linkmode" = lib; then
++ libs="$predeps $libs $compiler_lib_search_path $postdeps"
++
++ # Compute libraries that are listed more than once in $predeps
++ # $postdeps and mark them as special (i.e., whose duplicates are
++ # not to be eliminated).
++ pre_post_deps=
++ if $opt_duplicate_compiler_generated_deps; then
++ for pre_post_dep in $predeps $postdeps; do
++ case "$pre_post_deps " in
++ *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
++ esac
++ pre_post_deps="$pre_post_deps $pre_post_dep"
++ done
++ fi
++ pre_post_deps=
++ fi
++
++ deplibs=
++ newdependency_libs=
++ newlib_search_path=
++ need_relink=no # whether we're linking any uninstalled libtool libraries
++ notinst_deplibs= # not-installed libtool libraries
++ notinst_path= # paths that contain not-installed libtool libraries
++
++ case $linkmode in
++ lib)
++ passes="conv dlpreopen link"
++ for file in $dlfiles $dlprefiles; do
++ case $file in
++ *.la) ;;
++ *)
++ func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
++ ;;
++ esac
++ done
++ ;;
++ prog)
++ compile_deplibs=
++ finalize_deplibs=
++ alldeplibs=no
++ newdlfiles=
++ newdlprefiles=
++ passes="conv scan dlopen dlpreopen link"
++ ;;
++ *) passes="conv"
++ ;;
++ esac
++
++ for pass in $passes; do
++ # The preopen pass in lib mode reverses $deplibs; put it back here
++ # so that -L comes before libs that need it for instance...
++ if test "$linkmode,$pass" = "lib,link"; then
++ ## FIXME: Find the place where the list is rebuilt in the wrong
++ ## order, and fix it there properly
++ tmp_deplibs=
++ for deplib in $deplibs; do
++ tmp_deplibs="$deplib $tmp_deplibs"
++ done
++ deplibs="$tmp_deplibs"
++ fi
++
++ if test "$linkmode,$pass" = "lib,link" ||
++ test "$linkmode,$pass" = "prog,scan"; then
++ libs="$deplibs"
++ deplibs=
++ fi
++ if test "$linkmode" = prog; then
++ case $pass in
++ dlopen) libs="$dlfiles" ;;
++ dlpreopen) libs="$dlprefiles" ;;
++ link)
++ libs="$deplibs %DEPLIBS%"
++ test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
++ ;;
++ esac
++ fi
++ if test "$linkmode,$pass" = "lib,dlpreopen"; then
++ # Collect and forward deplibs of preopened libtool libs
++ for lib in $dlprefiles; do
++ # Ignore non-libtool-libs
++ dependency_libs=
++ case $lib in
++ *.la) func_source "$lib" ;;
++ esac
++
++ # Collect preopened libtool deplibs, except any this library
++ # has declared as weak libs
++ for deplib in $dependency_libs; do
++ deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"`
++ case " $weak_libs " in
++ *" $deplib_base "*) ;;
++ *) deplibs="$deplibs $deplib" ;;
++ esac
++ done
++ done
++ libs="$dlprefiles"
++ fi
++ if test "$pass" = dlopen; then
++ # Collect dlpreopened libraries
++ save_deplibs="$deplibs"
++ deplibs=
++ fi
++
++ for deplib in $libs; do
++ lib=
++ found=no
++ case $deplib in
++ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
++ if test "$linkmode,$pass" = "prog,link"; then
++ compile_deplibs="$deplib $compile_deplibs"
++ finalize_deplibs="$deplib $finalize_deplibs"
++ else
++ compiler_flags="$compiler_flags $deplib"
++ if test "$linkmode" = lib ; then
++ case "$new_inherited_linker_flags " in
++ *" $deplib "*) ;;
++ * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
++ esac
++ fi
++ fi
++ continue
++ ;;
++ -l*)
++ if test "$linkmode" != lib && test "$linkmode" != prog; then
++ func_warning "\`-l' is ignored for archives/objects"
++ continue
++ fi
++ func_stripname '-l' '' "$deplib"
++ name=$func_stripname_result
++ if test "$linkmode" = lib; then
++ searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
++ else
++ searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
++ fi
++ for searchdir in $searchdirs; do
++ for search_ext in .la $std_shrext .so .a; do
++ # Search the libtool library
++ lib="$searchdir/lib${name}${search_ext}"
++ if test -f "$lib"; then
++ if test "$search_ext" = ".la"; then
++ found=yes
++ else
++ found=no
++ fi
++ break 2
++ fi
++ done
++ done
++ if test "$found" != yes; then
++ # deplib doesn't seem to be a libtool library
++ if test "$linkmode,$pass" = "prog,link"; then
++ compile_deplibs="$deplib $compile_deplibs"
++ finalize_deplibs="$deplib $finalize_deplibs"
++ else
++ deplibs="$deplib $deplibs"
++ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
++ fi
++ continue
++ else # deplib is a libtool library
++ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
++ # We need to do some special things here, and not later.
++ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
++ case " $predeps $postdeps " in
++ *" $deplib "*)
++ if func_lalib_p "$lib"; then
++ library_names=
++ old_library=
++ func_source "$lib"
++ for l in $old_library $library_names; do
++ ll="$l"
++ done
++ if test "X$ll" = "X$old_library" ; then # only static version available
++ found=no
++ func_dirname "$lib" "" "."
++ ladir="$func_dirname_result"
++ lib=$ladir/$old_library
++ if test "$linkmode,$pass" = "prog,link"; then
++ compile_deplibs="$deplib $compile_deplibs"
++ finalize_deplibs="$deplib $finalize_deplibs"
++ else
++ deplibs="$deplib $deplibs"
++ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
++ fi
++ continue
++ fi
++ fi
++ ;;
++ *) ;;
++ esac
++ fi
++ fi
++ ;; # -l
++ *.ltframework)
++ if test "$linkmode,$pass" = "prog,link"; then
++ compile_deplibs="$deplib $compile_deplibs"
++ finalize_deplibs="$deplib $finalize_deplibs"
++ else
++ deplibs="$deplib $deplibs"
++ if test "$linkmode" = lib ; then
++ case "$new_inherited_linker_flags " in
++ *" $deplib "*) ;;
++ * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
++ esac
++ fi
++ fi
++ continue
++ ;;
++ -L*)
++ case $linkmode in
++ lib)
++ deplibs="$deplib $deplibs"
++ test "$pass" = conv && continue
++ newdependency_libs="$deplib $newdependency_libs"
++ func_stripname '-L' '' "$deplib"
++ newlib_search_path="$newlib_search_path $func_stripname_result"
++ ;;
++ prog)
++ if test "$pass" = conv; then
++ deplibs="$deplib $deplibs"
++ continue
++ fi
++ if test "$pass" = scan; then
++ deplibs="$deplib $deplibs"
++ else
++ compile_deplibs="$deplib $compile_deplibs"
++ finalize_deplibs="$deplib $finalize_deplibs"
++ fi
++ func_stripname '-L' '' "$deplib"
++ newlib_search_path="$newlib_search_path $func_stripname_result"
++ ;;
++ *)
++ func_warning "\`-L' is ignored for archives/objects"
++ ;;
++ esac # linkmode
++ continue
++ ;; # -L
++ -R*)
++ if test "$pass" = link; then
++ func_stripname '-R' '' "$deplib"
++ dir=$func_stripname_result
++ # Make sure the xrpath contains only unique directories.
++ case "$xrpath " in
++ *" $dir "*) ;;
++ *) xrpath="$xrpath $dir" ;;
++ esac
++ fi
++ deplibs="$deplib $deplibs"
++ continue
++ ;;
++ *.la) lib="$deplib" ;;
++ *.$libext)
++ if test "$pass" = conv; then
++ deplibs="$deplib $deplibs"
++ continue
++ fi
++ case $linkmode in
++ lib)
++ # Linking convenience modules into shared libraries is allowed,
++ # but linking other static libraries is non-portable.
++ case " $dlpreconveniencelibs " in
++ *" $deplib "*) ;;
++ *)
++ valid_a_lib=no
++ case $deplibs_check_method in
++ match_pattern*)
++ set dummy $deplibs_check_method; shift
++ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
++ if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \
++ | $EGREP "$match_pattern_regex" > /dev/null; then
++ valid_a_lib=yes
++ fi
++ ;;
++ pass_all)
++ valid_a_lib=yes
++ ;;
++ esac
++ if test "$valid_a_lib" != yes; then
++ $ECHO
++ $ECHO "*** Warning: Trying to link with static lib archive $deplib."
++ $ECHO "*** I have the capability to make that library automatically link in when"
++ $ECHO "*** you link to this library. But I can only do this if you have a"
++ $ECHO "*** shared version of the library, which you do not appear to have"
++ $ECHO "*** because the file extensions .$libext of this argument makes me believe"
++ $ECHO "*** that it is just a static archive that I should not use here."
++ else
++ $ECHO
++ $ECHO "*** Warning: Linking the shared library $output against the"
++ $ECHO "*** static library $deplib is not portable!"
++ deplibs="$deplib $deplibs"
++ fi
++ ;;
++ esac
++ continue
++ ;;
++ prog)
++ if test "$pass" != link; then
++ deplibs="$deplib $deplibs"
++ else
++ compile_deplibs="$deplib $compile_deplibs"
++ finalize_deplibs="$deplib $finalize_deplibs"
++ fi
++ continue
++ ;;
++ esac # linkmode
++ ;; # *.$libext
++ *.lo | *.$objext)
++ if test "$pass" = conv; then
++ deplibs="$deplib $deplibs"
++ elif test "$linkmode" = prog; then
++ if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
++ # If there is no dlopen support or we're linking statically,
++ # we need to preload.
++ newdlprefiles="$newdlprefiles $deplib"
++ compile_deplibs="$deplib $compile_deplibs"
++ finalize_deplibs="$deplib $finalize_deplibs"
++ else
++ newdlfiles="$newdlfiles $deplib"
++ fi
++ fi
++ continue
++ ;;
++ %DEPLIBS%)
++ alldeplibs=yes
++ continue
++ ;;
++ esac # case $deplib
++
++ if test "$found" = yes || test -f "$lib"; then :
++ else
++ func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
++ fi
++
++ # Check to see that this really is a libtool archive.
++ func_lalib_unsafe_p "$lib" \
++ || func_fatal_error "\`$lib' is not a valid libtool archive"
++
++ func_dirname "$lib" "" "."
++ ladir="$func_dirname_result"
++
++ dlname=
++ dlopen=
++ dlpreopen=
++ libdir=
++ library_names=
++ old_library=
++ inherited_linker_flags=
++ # If the library was installed with an old release of libtool,
++ # it will not redefine variables installed, or shouldnotlink
++ installed=yes
++ shouldnotlink=no
++ avoidtemprpath=
++
++
++ # Read the .la file
++ func_source "$lib"
++
++ # Convert "-framework foo" to "foo.ltframework"
++ if test -n "$inherited_linker_flags"; then
++ tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'`
++ for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
++ case " $new_inherited_linker_flags " in
++ *" $tmp_inherited_linker_flag "*) ;;
++ *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";;
++ esac
++ done
++ fi
++ dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
++ if test "$linkmode,$pass" = "lib,link" ||
++ test "$linkmode,$pass" = "prog,scan" ||
++ { test "$linkmode" != prog && test "$linkmode" != lib; }; then
++ test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
++ test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
++ fi
++
++ if test "$pass" = conv; then
++ # Only check for convenience libraries
++ deplibs="$lib $deplibs"
++ if test -z "$libdir"; then
++ if test -z "$old_library"; then
++ func_fatal_error "cannot find name of link library for \`$lib'"
++ fi
++ # It is a libtool convenience library, so add in its objects.
++ convenience="$convenience $ladir/$objdir/$old_library"
++ old_convenience="$old_convenience $ladir/$objdir/$old_library"
++ tmp_libs=
++ for deplib in $dependency_libs; do
++ deplibs="$deplib $deplibs"
++ if $opt_duplicate_deps ; then
++ case "$tmp_libs " in
++ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
++ esac
++ fi
++ tmp_libs="$tmp_libs $deplib"
++ done
++ elif test "$linkmode" != prog && test "$linkmode" != lib; then
++ func_fatal_error "\`$lib' is not a convenience library"
++ fi
++ continue
++ fi # $pass = conv
++
++
++ # Get the name of the library we link against.
++ linklib=
++ for l in $old_library $library_names; do
++ linklib="$l"
++ done
++ if test -z "$linklib"; then
++ func_fatal_error "cannot find name of link library for \`$lib'"
++ fi
++
++ # This library was specified with -dlopen.
++ if test "$pass" = dlopen; then
++ if test -z "$libdir"; then
++ func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
++ fi
++ if test -z "$dlname" ||
++ test "$dlopen_support" != yes ||
++ test "$build_libtool_libs" = no; then
++ # If there is no dlname, no dlopen support or we're linking
++ # statically, we need to preload. We also need to preload any
++ # dependent libraries so libltdl's deplib preloader doesn't
++ # bomb out in the load deplibs phase.
++ dlprefiles="$dlprefiles $lib $dependency_libs"
++ else
++ newdlfiles="$newdlfiles $lib"
++ fi
++ continue
++ fi # $pass = dlopen
++
++ # We need an absolute path.
++ case $ladir in
++ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
++ *)
++ abs_ladir=`cd "$ladir" && pwd`
++ if test -z "$abs_ladir"; then
++ func_warning "cannot determine absolute directory name of \`$ladir'"
++ func_warning "passing it literally to the linker, although it might fail"
++ abs_ladir="$ladir"
++ fi
++ ;;
++ esac
++ func_basename "$lib"
++ laname="$func_basename_result"
++
++ # Find the relevant object directory and library name.
++ if test "X$installed" = Xyes; then
++ if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
++ func_warning "library \`$lib' was moved."
++ dir="$ladir"
++ absdir="$abs_ladir"
++ libdir="$abs_ladir"
++ else
++ dir="$libdir"
++ absdir="$libdir"
++ fi
++ test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
++ else
++ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
++ dir="$ladir"
++ absdir="$abs_ladir"
++ # Remove this search path later
++ notinst_path="$notinst_path $abs_ladir"
++ else
++ dir="$ladir/$objdir"
++ absdir="$abs_ladir/$objdir"
++ # Remove this search path later
++ notinst_path="$notinst_path $abs_ladir"
++ fi
++ fi # $installed = yes
++ func_stripname 'lib' '.la' "$laname"
++ name=$func_stripname_result
++
++ # This library was specified with -dlpreopen.
++ if test "$pass" = dlpreopen; then
++ if test -z "$libdir" && test "$linkmode" = prog; then
++ func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
++ fi
++ # Prefer using a static library (so that no silly _DYNAMIC symbols
++ # are required to link).
++ if test -n "$old_library"; then
++ newdlprefiles="$newdlprefiles $dir/$old_library"
++ # Keep a list of preopened convenience libraries to check
++ # that they are being used correctly in the link pass.
++ test -z "$libdir" && \
++ dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library"
++ # Otherwise, use the dlname, so that lt_dlopen finds it.
++ elif test -n "$dlname"; then
++ newdlprefiles="$newdlprefiles $dir/$dlname"
++ else
++ newdlprefiles="$newdlprefiles $dir/$linklib"
++ fi
++ fi # $pass = dlpreopen
++
++ if test -z "$libdir"; then
++ # Link the convenience library
++ if test "$linkmode" = lib; then
++ deplibs="$dir/$old_library $deplibs"
++ elif test "$linkmode,$pass" = "prog,link"; then
++ compile_deplibs="$dir/$old_library $compile_deplibs"
++ finalize_deplibs="$dir/$old_library $finalize_deplibs"
++ else
++ deplibs="$lib $deplibs" # used for prog,scan pass
++ fi
++ continue
++ fi
++
++
++ if test "$linkmode" = prog && test "$pass" != link; then
++ newlib_search_path="$newlib_search_path $ladir"
++ deplibs="$lib $deplibs"
++
++ linkalldeplibs=no
++ if test "$link_all_deplibs" != no || test -z "$library_names" ||
++ test "$build_libtool_libs" = no; then
++ linkalldeplibs=yes
++ fi
++
++ tmp_libs=
++ for deplib in $dependency_libs; do
++ case $deplib in
++ -L*) func_stripname '-L' '' "$deplib"
++ newlib_search_path="$newlib_search_path $func_stripname_result"
++ ;;
++ esac
++ # Need to link against all dependency_libs?
++ if test "$linkalldeplibs" = yes; then
++ deplibs="$deplib $deplibs"
++ else
++ # Need to hardcode shared library paths
++ # or/and link against static libraries
++ newdependency_libs="$deplib $newdependency_libs"
++ fi
++ if $opt_duplicate_deps ; then
++ case "$tmp_libs " in
++ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
++ esac
++ fi
++ tmp_libs="$tmp_libs $deplib"
++ done # for deplib
++ continue
++ fi # $linkmode = prog...
++
++ if test "$linkmode,$pass" = "prog,link"; then
++ if test -n "$library_names" &&
++ { { test "$prefer_static_libs" = no ||
++ test "$prefer_static_libs,$installed" = "built,yes"; } ||
++ test -z "$old_library"; }; then
++ # We need to hardcode the library path
++ if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
++ # Make sure the rpath contains only unique directories.
++ case "$temp_rpath:" in
++ *"$absdir:"*) ;;
++ *) temp_rpath="$temp_rpath$absdir:" ;;
++ esac
++ fi
++
++ # Hardcode the library path.
++ # Skip directories that are in the system default run-time
++ # search path.
++ case " $sys_lib_dlsearch_path " in
++ *" $absdir "*) ;;
++ *)
++ case "$compile_rpath " in
++ *" $absdir "*) ;;
++ *) compile_rpath="$compile_rpath $absdir"
++ esac
++ ;;
++ esac
++ case " $sys_lib_dlsearch_path " in
++ *" $libdir "*) ;;
++ *)
++ case "$finalize_rpath " in
++ *" $libdir "*) ;;
++ *) finalize_rpath="$finalize_rpath $libdir"
++ esac
++ ;;
++ esac
++ fi # $linkmode,$pass = prog,link...
++
++ if test "$alldeplibs" = yes &&
++ { test "$deplibs_check_method" = pass_all ||
++ { test "$build_libtool_libs" = yes &&
++ test -n "$library_names"; }; }; then
++ # We only need to search for static libraries
++ continue
++ fi
++ fi
++
++ link_static=no # Whether the deplib will be linked statically
++ use_static_libs=$prefer_static_libs
++ if test "$use_static_libs" = built && test "$installed" = yes; then
++ use_static_libs=no
++ fi
++ if test -n "$library_names" &&
++ { test "$use_static_libs" = no || test -z "$old_library"; }; then
++ case $host in
++ *cygwin* | *mingw* | *cegcc*)
++ # No point in relinking DLLs because paths are not encoded
++ notinst_deplibs="$notinst_deplibs $lib"
++ need_relink=no
++ ;;
++ *)
++ if test "$installed" = no; then
++ notinst_deplibs="$notinst_deplibs $lib"
++ need_relink=yes
++ fi
++ ;;
++ esac
++ # This is a shared library
++
++ # Warn about portability, can't link against -module's on some
++ # systems (darwin). Don't bleat about dlopened modules though!
++ dlopenmodule=""
++ for dlpremoduletest in $dlprefiles; do
++ if test "X$dlpremoduletest" = "X$lib"; then
++ dlopenmodule="$dlpremoduletest"
++ break
++ fi
++ done
++ if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
++ $ECHO
++ if test "$linkmode" = prog; then
++ $ECHO "*** Warning: Linking the executable $output against the loadable module"
++ else
++ $ECHO "*** Warning: Linking the shared library $output against the loadable module"
++ fi
++ $ECHO "*** $linklib is not portable!"
++ fi
++ if test "$linkmode" = lib &&
++ test "$hardcode_into_libs" = yes; then
++ # Hardcode the library path.
++ # Skip directories that are in the system default run-time
++ # search path.
++ case " $sys_lib_dlsearch_path " in
++ *" $absdir "*) ;;
++ *)
++ case "$compile_rpath " in
++ *" $absdir "*) ;;
++ *) compile_rpath="$compile_rpath $absdir"
++ esac
++ ;;
++ esac
++ case " $sys_lib_dlsearch_path " in
++ *" $libdir "*) ;;
++ *)
++ case "$finalize_rpath " in
++ *" $libdir "*) ;;
++ *) finalize_rpath="$finalize_rpath $libdir"
++ esac
++ ;;
++ esac
++ fi
++
++ if test -n "$old_archive_from_expsyms_cmds"; then
++ # figure out the soname
++ set dummy $library_names
++ shift
++ realname="$1"
++ shift
++ libname=`eval "\\$ECHO \"$libname_spec\""`
++ # use dlname if we got it. it's perfectly good, no?
++ if test -n "$dlname"; then
++ soname="$dlname"
++ elif test -n "$soname_spec"; then
++ # bleh windows
++ case $host in
++ *cygwin* | mingw* | *cegcc*)
++ func_arith $current - $age
++ major=$func_arith_result
++ versuffix="-$major"
++ ;;
++ esac
++ eval soname=\"$soname_spec\"
++ else
++ soname="$realname"
++ fi
++
++ # Make a new name for the extract_expsyms_cmds to use
++ soroot="$soname"
++ func_basename "$soroot"
++ soname="$func_basename_result"
++ func_stripname 'lib' '.dll' "$soname"
++ newlib=libimp-$func_stripname_result.a
++
++ # If the library has no export list, then create one now
++ if test -f "$output_objdir/$soname-def"; then :
++ else
++ func_verbose "extracting exported symbol list from \`$soname'"
++ func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
++ fi
++
++ # Create $newlib
++ if test -f "$output_objdir/$newlib"; then :; else
++ func_verbose "generating import library for \`$soname'"
++ func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
++ fi
++ # make sure the library variables are pointing to the new library
++ dir=$output_objdir
++ linklib=$newlib
++ fi # test -n "$old_archive_from_expsyms_cmds"
++
++ if test "$linkmode" = prog || test "$mode" != relink; then
++ add_shlibpath=
++ add_dir=
++ add=
++ lib_linked=yes
++ case $hardcode_action in
++ immediate | unsupported)
++ if test "$hardcode_direct" = no; then
++ add="$dir/$linklib"
++ case $host in
++ *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
++ *-*-sysv4*uw2*) add_dir="-L$dir" ;;
++ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
++ *-*-unixware7*) add_dir="-L$dir" ;;
++ *-*-darwin* )
++ # if the lib is a (non-dlopened) module then we can not
++ # link against it, someone is ignoring the earlier warnings
++ if /usr/bin/file -L $add 2> /dev/null |
++ $GREP ": [^:]* bundle" >/dev/null ; then
++ if test "X$dlopenmodule" != "X$lib"; then
++ $ECHO "*** Warning: lib $linklib is a module, not a shared library"
++ if test -z "$old_library" ; then
++ $ECHO
++ $ECHO "*** And there doesn't seem to be a static archive available"
++ $ECHO "*** The link will probably fail, sorry"
++ else
++ add="$dir/$old_library"
++ fi
++ elif test -n "$old_library"; then
++ add="$dir/$old_library"
++ fi
++ fi
++ esac
++ elif test "$hardcode_minus_L" = no; then
++ case $host in
++ *-*-sunos*) add_shlibpath="$dir" ;;
++ esac
++ add_dir="-L$dir"
++ add="-l$name"
++ elif test "$hardcode_shlibpath_var" = no; then
++ add_shlibpath="$dir"
++ add="-l$name"
++ else
++ lib_linked=no
++ fi
++ ;;
++ relink)
++ if test "$hardcode_direct" = yes &&
++ test "$hardcode_direct_absolute" = no; then
++ add="$dir/$linklib"
++ elif test "$hardcode_minus_L" = yes; then
++ add_dir="-L$dir"
++ # Try looking first in the location we're being installed to.
++ if test -n "$inst_prefix_dir"; then
++ case $libdir in
++ [\\/]*)
++ add_dir="$add_dir -L$inst_prefix_dir$libdir"
++ ;;
++ esac
++ fi
++ add="-l$name"
++ elif test "$hardcode_shlibpath_var" = yes; then
++ add_shlibpath="$dir"
++ add="-l$name"
++ else
++ lib_linked=no
++ fi
++ ;;
++ *) lib_linked=no ;;
++ esac
++
++ if test "$lib_linked" != yes; then
++ func_fatal_configuration "unsupported hardcode properties"
++ fi
++
++ if test -n "$add_shlibpath"; then
++ case :$compile_shlibpath: in
++ *":$add_shlibpath:"*) ;;
++ *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
++ esac
++ fi
++ if test "$linkmode" = prog; then
++ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
++ test -n "$add" && compile_deplibs="$add $compile_deplibs"
++ else
++ test -n "$add_dir" && deplibs="$add_dir $deplibs"
++ test -n "$add" && deplibs="$add $deplibs"
++ if test "$hardcode_direct" != yes &&
++ test "$hardcode_minus_L" != yes &&
++ test "$hardcode_shlibpath_var" = yes; then
++ case :$finalize_shlibpath: in
++ *":$libdir:"*) ;;
++ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
++ esac
++ fi
++ fi
++ fi
++
++ if test "$linkmode" = prog || test "$mode" = relink; then
++ add_shlibpath=
++ add_dir=
++ add=
++ # Finalize command for both is simple: just hardcode it.
++ if test "$hardcode_direct" = yes &&
++ test "$hardcode_direct_absolute" = no; then
++ add="$libdir/$linklib"
++ elif test "$hardcode_minus_L" = yes; then
++ add_dir="-L$libdir"
++ add="-l$name"
++ elif test "$hardcode_shlibpath_var" = yes; then
++ case :$finalize_shlibpath: in
++ *":$libdir:"*) ;;
++ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
++ esac
++ add="-l$name"
++ elif test "$hardcode_automatic" = yes; then
++ if test -n "$inst_prefix_dir" &&
++ test -f "$inst_prefix_dir$libdir/$linklib" ; then
++ add="$inst_prefix_dir$libdir/$linklib"
++ else
++ add="$libdir/$linklib"
++ fi
++ else
++ # We cannot seem to hardcode it, guess we'll fake it.
++ add_dir="-L$libdir"
++ # Try looking first in the location we're being installed to.
++ if test -n "$inst_prefix_dir"; then
++ case $libdir in
++ [\\/]*)
++ add_dir="$add_dir -L$inst_prefix_dir$libdir"
++ ;;
++ esac
++ fi
++ add="-l$name"
++ fi
++
++ if test "$linkmode" = prog; then
++ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
++ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
++ else
++ test -n "$add_dir" && deplibs="$add_dir $deplibs"
++ test -n "$add" && deplibs="$add $deplibs"
++ fi
++ fi
++ elif test "$linkmode" = prog; then
++ # Here we assume that one of hardcode_direct or hardcode_minus_L
++ # is not unsupported. This is valid on all known static and
++ # shared platforms.
++ if test "$hardcode_direct" != unsupported; then
++ test -n "$old_library" && linklib="$old_library"
++ compile_deplibs="$dir/$linklib $compile_deplibs"
++ finalize_deplibs="$dir/$linklib $finalize_deplibs"
++ else
++ compile_deplibs="-l$name -L$dir $compile_deplibs"
++ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
++ fi
++ elif test "$build_libtool_libs" = yes; then
++ # Not a shared library
++ if test "$deplibs_check_method" != pass_all; then
++ # We're trying link a shared library against a static one
++ # but the system doesn't support it.
++
++ # Just print a warning and add the library to dependency_libs so
++ # that the program can be linked against the static library.
++ $ECHO
++ $ECHO "*** Warning: This system can not link to static lib archive $lib."
++ $ECHO "*** I have the capability to make that library automatically link in when"
++ $ECHO "*** you link to this library. But I can only do this if you have a"
++ $ECHO "*** shared version of the library, which you do not appear to have."
++ if test "$module" = yes; then
++ $ECHO "*** But as you try to build a module library, libtool will still create "
++ $ECHO "*** a static module, that should work as long as the dlopening application"
++ $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime."
++ if test -z "$global_symbol_pipe"; then
++ $ECHO
++ $ECHO "*** However, this would only work if libtool was able to extract symbol"
++ $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could"
++ $ECHO "*** not find such a program. So, this module is probably useless."
++ $ECHO "*** \`nm' from GNU binutils and a full rebuild may help."
++ fi
++ if test "$build_old_libs" = no; then
++ build_libtool_libs=module
++ build_old_libs=yes
++ else
++ build_libtool_libs=no
++ fi
++ fi
++ else
++ deplibs="$dir/$old_library $deplibs"
++ link_static=yes
++ fi
++ fi # link shared/static library?
++
++ if test "$linkmode" = lib; then
++ if test -n "$dependency_libs" &&
++ { test "$hardcode_into_libs" != yes ||
++ test "$build_old_libs" = yes ||
++ test "$link_static" = yes; }; then
++ # Extract -R from dependency_libs
++ temp_deplibs=
++ for libdir in $dependency_libs; do
++ case $libdir in
++ -R*) func_stripname '-R' '' "$libdir"
++ temp_xrpath=$func_stripname_result
++ case " $xrpath " in
++ *" $temp_xrpath "*) ;;
++ *) xrpath="$xrpath $temp_xrpath";;
++ esac;;
++ *) temp_deplibs="$temp_deplibs $libdir";;
++ esac
++ done
++ dependency_libs="$temp_deplibs"
++ fi
++
++ newlib_search_path="$newlib_search_path $absdir"
++ # Link against this library
++ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
++ # ... and its dependency_libs
++ tmp_libs=
++ for deplib in $dependency_libs; do
++ newdependency_libs="$deplib $newdependency_libs"
++ if $opt_duplicate_deps ; then
++ case "$tmp_libs " in
++ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
++ esac
++ fi
++ tmp_libs="$tmp_libs $deplib"
++ done
++
++ if test "$link_all_deplibs" != no; then
++ # Add the search paths of all dependency libraries
++ for deplib in $dependency_libs; do
++ path=
++ case $deplib in
++ -L*) path="$deplib" ;;
++ *.la)
++ func_dirname "$deplib" "" "."
++ dir="$func_dirname_result"
++ # We need an absolute path.
++ case $dir in
++ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
++ *)
++ absdir=`cd "$dir" && pwd`
++ if test -z "$absdir"; then
++ func_warning "cannot determine absolute directory name of \`$dir'"
++ absdir="$dir"
++ fi
++ ;;
++ esac
++ if $GREP "^installed=no" $deplib > /dev/null; then
++ case $host in
++ *-*-darwin*)
++ depdepl=
++ eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
++ if test -n "$deplibrary_names" ; then
++ for tmp in $deplibrary_names ; do
++ depdepl=$tmp
++ done
++ if test -f "$absdir/$objdir/$depdepl" ; then
++ depdepl="$absdir/$objdir/$depdepl"
++ darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
++ if test -z "$darwin_install_name"; then
++ darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
++ fi
++ compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
++ linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}"
++ path=
++ fi
++ fi
++ ;;
++ *)
++ path="-L$absdir/$objdir"
++ ;;
++ esac
++ else
++ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
++ test -z "$libdir" && \
++ func_fatal_error "\`$deplib' is not a valid libtool archive"
++ test "$absdir" != "$libdir" && \
++ func_warning "\`$deplib' seems to be moved"
++
++ path="-L$absdir"
++ fi
++ ;;
++ esac
++ case " $deplibs " in
++ *" $path "*) ;;
++ *) deplibs="$path $deplibs" ;;
++ esac
++ done
++ fi # link_all_deplibs != no
++ fi # linkmode = lib
++ done # for deplib in $libs
++ if test "$pass" = link; then
++ if test "$linkmode" = "prog"; then
++ compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
++ finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
++ else
++ compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
++ fi
++ fi
++ dependency_libs="$newdependency_libs"
++ if test "$pass" = dlpreopen; then
++ # Link the dlpreopened libraries before other libraries
++ for deplib in $save_deplibs; do
++ deplibs="$deplib $deplibs"
++ done
++ fi
++ if test "$pass" != dlopen; then
++ if test "$pass" != conv; then
++ # Make sure lib_search_path contains only unique directories.
++ lib_search_path=
++ for dir in $newlib_search_path; do
++ case "$lib_search_path " in
++ *" $dir "*) ;;
++ *) lib_search_path="$lib_search_path $dir" ;;
++ esac
++ done
++ newlib_search_path=
++ fi
++
++ if test "$linkmode,$pass" != "prog,link"; then
++ vars="deplibs"
++ else
++ vars="compile_deplibs finalize_deplibs"
++ fi
++ for var in $vars dependency_libs; do
++ # Add libraries to $var in reverse order
++ eval tmp_libs=\"\$$var\"
++ new_libs=
++ for deplib in $tmp_libs; do
++ # FIXME: Pedantically, this is the right thing to do, so
++ # that some nasty dependency loop isn't accidentally
++ # broken:
++ #new_libs="$deplib $new_libs"
++ # Pragmatically, this seems to cause very few problems in
++ # practice:
++ case $deplib in
++ -L*) new_libs="$deplib $new_libs" ;;
++ -R*) ;;
++ *)
++ # And here is the reason: when a library appears more
++ # than once as an explicit dependence of a library, or
++ # is implicitly linked in more than once by the
++ # compiler, it is considered special, and multiple
++ # occurrences thereof are not removed. Compare this
++ # with having the same library being listed as a
++ # dependency of multiple other libraries: in this case,
++ # we know (pedantically, we assume) the library does not
++ # need to be listed more than once, so we keep only the
++ # last copy. This is not always right, but it is rare
++ # enough that we require users that really mean to play
++ # such unportable linking tricks to link the library
++ # using -Wl,-lname, so that libtool does not consider it
++ # for duplicate removal.
++ case " $specialdeplibs " in
++ *" $deplib "*) new_libs="$deplib $new_libs" ;;
++ *)
++ case " $new_libs " in
++ *" $deplib "*) ;;
++ *) new_libs="$deplib $new_libs" ;;
++ esac
++ ;;
++ esac
++ ;;
++ esac
++ done
++ tmp_libs=
++ for deplib in $new_libs; do
++ case $deplib in
++ -L*)
++ case " $tmp_libs " in
++ *" $deplib "*) ;;
++ *) tmp_libs="$tmp_libs $deplib" ;;
++ esac
++ ;;
++ *) tmp_libs="$tmp_libs $deplib" ;;
++ esac
++ done
++ eval $var=\"$tmp_libs\"
++ done # for var
++ fi
++ # Last step: remove runtime libs from dependency_libs
++ # (they stay in deplibs)
++ tmp_libs=
++ for i in $dependency_libs ; do
++ case " $predeps $postdeps $compiler_lib_search_path " in
++ *" $i "*)
++ i=""
++ ;;
++ esac
++ if test -n "$i" ; then
++ tmp_libs="$tmp_libs $i"
++ fi
++ done
++ dependency_libs=$tmp_libs
++ done # for pass
++ if test "$linkmode" = prog; then
++ dlfiles="$newdlfiles"
++ fi
++ if test "$linkmode" = prog || test "$linkmode" = lib; then
++ dlprefiles="$newdlprefiles"
++ fi
++
++ case $linkmode in
++ oldlib)
++ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
++ func_warning "\`-dlopen' is ignored for archives"
++ fi
++
++ case " $deplibs" in
++ *\ -l* | *\ -L*)
++ func_warning "\`-l' and \`-L' are ignored for archives" ;;
++ esac
++
++ test -n "$rpath" && \
++ func_warning "\`-rpath' is ignored for archives"
++
++ test -n "$xrpath" && \
++ func_warning "\`-R' is ignored for archives"
++
++ test -n "$vinfo" && \
++ func_warning "\`-version-info/-version-number' is ignored for archives"
++
++ test -n "$release" && \
++ func_warning "\`-release' is ignored for archives"
++
++ test -n "$export_symbols$export_symbols_regex" && \
++ func_warning "\`-export-symbols' is ignored for archives"
++
++ # Now set the variables for building old libraries.
++ build_libtool_libs=no
++ oldlibs="$output"
++ objs="$objs$old_deplibs"
++ ;;
++
++ lib)
++ # Make sure we only generate libraries of the form `libNAME.la'.
++ case $outputname in
++ lib*)
++ func_stripname 'lib' '.la' "$outputname"
++ name=$func_stripname_result
++ eval shared_ext=\"$shrext_cmds\"
++ eval libname=\"$libname_spec\"
++ ;;
++ *)
++ test "$module" = no && \
++ func_fatal_help "libtool library \`$output' must begin with \`lib'"
++
++ if test "$need_lib_prefix" != no; then
++ # Add the "lib" prefix for modules if required
++ func_stripname '' '.la' "$outputname"
++ name=$func_stripname_result
++ eval shared_ext=\"$shrext_cmds\"
++ eval libname=\"$libname_spec\"
++ else
++ func_stripname '' '.la' "$outputname"
++ libname=$func_stripname_result
++ fi
++ ;;
++ esac
++
++ if test -n "$objs"; then
++ if test "$deplibs_check_method" != pass_all; then
++ func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
++ else
++ $ECHO
++ $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
++ $ECHO "*** objects $objs is not portable!"
++ libobjs="$libobjs $objs"
++ fi
++ fi
++
++ test "$dlself" != no && \
++ func_warning "\`-dlopen self' is ignored for libtool libraries"
++
++ set dummy $rpath
++ shift
++ test "$#" -gt 1 && \
++ func_warning "ignoring multiple \`-rpath's for a libtool library"
++
++ install_libdir="$1"
++
++ oldlibs=
++ if test -z "$rpath"; then
++ if test "$build_libtool_libs" = yes; then
++ # Building a libtool convenience library.
++ # Some compilers have problems with a `.al' extension so
++ # convenience libraries should have the same extension an
++ # archive normally would.
++ oldlibs="$output_objdir/$libname.$libext $oldlibs"
++ build_libtool_libs=convenience
++ build_old_libs=yes
++ fi
++
++ test -n "$vinfo" && \
++ func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
++
++ test -n "$release" && \
++ func_warning "\`-release' is ignored for convenience libraries"
++ else
++
++ # Parse the version information argument.
++ save_ifs="$IFS"; IFS=':'
++ set dummy $vinfo 0 0 0
++ shift
++ IFS="$save_ifs"
++
++ test -n "$7" && \
++ func_fatal_help "too many parameters to \`-version-info'"
++
++ # convert absolute version numbers to libtool ages
++ # this retains compatibility with .la files and attempts
++ # to make the code below a bit more comprehensible
++
++ case $vinfo_number in
++ yes)
++ number_major="$1"
++ number_minor="$2"
++ number_revision="$3"
++ #
++ # There are really only two kinds -- those that
++ # use the current revision as the major version
++ # and those that subtract age and use age as
++ # a minor version. But, then there is irix
++ # which has an extra 1 added just for fun
++ #
++ case $version_type in
++ darwin|linux|osf|windows|none)
++ func_arith $number_major + $number_minor
++ current=$func_arith_result
++ age="$number_minor"
++ revision="$number_revision"
++ ;;
++ freebsd-aout|freebsd-elf|sunos)
++ current="$number_major"
++ revision="$number_minor"
++ age="0"
++ ;;
++ irix|nonstopux)
++ func_arith $number_major + $number_minor
++ current=$func_arith_result
++ age="$number_minor"
++ revision="$number_minor"
++ lt_irix_increment=no
++ ;;
++ *)
++ func_fatal_configuration "$modename: unknown library version type \`$version_type'"
++ ;;
++ esac
++ ;;
++ no)
++ current="$1"
++ revision="$2"
++ age="$3"
++ ;;
++ esac
++
++ # Check that each of the things are valid numbers.
++ case $current in
++ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
++ *)
++ func_error "CURRENT \`$current' must be a nonnegative integer"
++ func_fatal_error "\`$vinfo' is not valid version information"
++ ;;
++ esac
++
++ case $revision in
++ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
++ *)
++ func_error "REVISION \`$revision' must be a nonnegative integer"
++ func_fatal_error "\`$vinfo' is not valid version information"
++ ;;
++ esac
++
++ case $age in
++ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
++ *)
++ func_error "AGE \`$age' must be a nonnegative integer"
++ func_fatal_error "\`$vinfo' is not valid version information"
++ ;;
++ esac
++
++ if test "$age" -gt "$current"; then
++ func_error "AGE \`$age' is greater than the current interface number \`$current'"
++ func_fatal_error "\`$vinfo' is not valid version information"
++ fi
++
++ # Calculate the version variables.
++ major=
++ versuffix=
++ verstring=
++ case $version_type in
++ none) ;;
++
++ darwin)
++ # Like Linux, but with the current version available in
++ # verstring for coding it into the library header
++ func_arith $current - $age
++ major=.$func_arith_result
++ versuffix="$major.$age.$revision"
++ # Darwin ld doesn't like 0 for these options...
++ func_arith $current + 1
++ minor_current=$func_arith_result
++ xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
++ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
++ ;;
++
++ freebsd-aout)
++ major=".$current"
++ versuffix=".$current.$revision";
++ ;;
++
++ freebsd-elf)
++ major=".$current"
++ versuffix=".$current"
++ ;;
++
++ irix | nonstopux)
++ if test "X$lt_irix_increment" = "Xno"; then
++ func_arith $current - $age
++ else
++ func_arith $current - $age + 1
++ fi
++ major=$func_arith_result
++
++ case $version_type in
++ nonstopux) verstring_prefix=nonstopux ;;
++ *) verstring_prefix=sgi ;;
++ esac
++ verstring="$verstring_prefix$major.$revision"
++
++ # Add in all the interfaces that we are compatible with.
++ loop=$revision
++ while test "$loop" -ne 0; do
++ func_arith $revision - $loop
++ iface=$func_arith_result
++ func_arith $loop - 1
++ loop=$func_arith_result
++ verstring="$verstring_prefix$major.$iface:$verstring"
++ done
++
++ # Before this point, $major must not contain `.'.
++ major=.$major
++ versuffix="$major.$revision"
++ ;;
++
++ linux)
++ func_arith $current - $age
++ major=.$func_arith_result
++ versuffix="$major.$age.$revision"
++ ;;
++
++ osf)
++ func_arith $current - $age
++ major=.$func_arith_result
++ versuffix=".$current.$age.$revision"
++ verstring="$current.$age.$revision"
++
++ # Add in all the interfaces that we are compatible with.
++ loop=$age
++ while test "$loop" -ne 0; do
++ func_arith $current - $loop
++ iface=$func_arith_result
++ func_arith $loop - 1
++ loop=$func_arith_result
++ verstring="$verstring:${iface}.0"
++ done
++
++ # Make executables depend on our current version.
++ verstring="$verstring:${current}.0"
++ ;;
++
++ qnx)
++ major=".$current"
++ versuffix=".$current"
++ ;;
++
++ sunos)
++ major=".$current"
++ versuffix=".$current.$revision"
++ ;;
++
++ windows)
++ # Use '-' rather than '.', since we only want one
++ # extension on DOS 8.3 filesystems.
++ func_arith $current - $age
++ major=$func_arith_result
++ versuffix="-$major"
++ ;;
++
++ *)
++ func_fatal_configuration "unknown library version type \`$version_type'"
++ ;;
++ esac
++
++ # Clear the version info if we defaulted, and they specified a release.
++ if test -z "$vinfo" && test -n "$release"; then
++ major=
++ case $version_type in
++ darwin)
++ # we can't check for "0.0" in archive_cmds due to quoting
++ # problems, so we reset it completely
++ verstring=
++ ;;
++ *)
++ verstring="0.0"
++ ;;
++ esac
++ if test "$need_version" = no; then
++ versuffix=
++ else
++ versuffix=".0.0"
++ fi
++ fi
++
++ # Remove version info from name if versioning should be avoided
++ if test "$avoid_version" = yes && test "$need_version" = no; then
++ major=
++ versuffix=
++ verstring=""
++ fi
++
++ # Check to see if the archive will have undefined symbols.
++ if test "$allow_undefined" = yes; then
++ if test "$allow_undefined_flag" = unsupported; then
++ func_warning "undefined symbols not allowed in $host shared libraries"
++ build_libtool_libs=no
++ build_old_libs=yes
++ fi
++ else
++ # Don't allow undefined symbols.
++ allow_undefined_flag="$no_undefined_flag"
++ fi
++
++ fi
++
++ func_generate_dlsyms "$libname" "$libname" "yes"
++ libobjs="$libobjs $symfileobj"
++ test "X$libobjs" = "X " && libobjs=
++
++ if test "$mode" != relink; then
++ # Remove our outputs, but don't remove object files since they
++ # may have been created when compiling PIC objects.
++ removelist=
++ tempremovelist=`$ECHO "$output_objdir/*"`
++ for p in $tempremovelist; do
++ case $p in
++ *.$objext | *.gcno)
++ ;;
++ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
++ if test "X$precious_files_regex" != "X"; then
++ if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
++ then
++ continue
++ fi
++ fi
++ removelist="$removelist $p"
++ ;;
++ *) ;;
++ esac
++ done
++ test -n "$removelist" && \
++ func_show_eval "${RM}r \$removelist"
++ fi
++
++ # Now set the variables for building old libraries.
++ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
++ oldlibs="$oldlibs $output_objdir/$libname.$libext"
++
++ # Transform .lo files to .o files.
++ oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
++ fi
++
++ # Eliminate all temporary directories.
++ #for path in $notinst_path; do
++ # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"`
++ # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"`
++ # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"`
++ #done
++
++ if test -n "$xrpath"; then
++ # If the user specified any rpath flags, then add them.
++ temp_xrpath=
++ for libdir in $xrpath; do
++ temp_xrpath="$temp_xrpath -R$libdir"
++ case "$finalize_rpath " in
++ *" $libdir "*) ;;
++ *) finalize_rpath="$finalize_rpath $libdir" ;;
++ esac
++ done
++ if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
++ dependency_libs="$temp_xrpath $dependency_libs"
++ fi
++ fi
++
++ # Make sure dlfiles contains only unique files that won't be dlpreopened
++ old_dlfiles="$dlfiles"
++ dlfiles=
++ for lib in $old_dlfiles; do
++ case " $dlprefiles $dlfiles " in
++ *" $lib "*) ;;
++ *) dlfiles="$dlfiles $lib" ;;
++ esac
++ done
++
++ # Make sure dlprefiles contains only unique files
++ old_dlprefiles="$dlprefiles"
++ dlprefiles=
++ for lib in $old_dlprefiles; do
++ case "$dlprefiles " in
++ *" $lib "*) ;;
++ *) dlprefiles="$dlprefiles $lib" ;;
++ esac
++ done
++
++ if test "$build_libtool_libs" = yes; then
++ if test -n "$rpath"; then
++ case $host in
++ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*)
++ # these systems don't actually have a c library (as such)!
++ ;;
++ *-*-rhapsody* | *-*-darwin1.[012])
++ # Rhapsody C library is in the System framework
++ deplibs="$deplibs System.ltframework"
++ ;;
++ *-*-netbsd*)
++ # Don't link with libc until the a.out ld.so is fixed.
++ ;;
++ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
++ # Do not include libc due to us having libc/libc_r.
++ ;;
++ *-*-sco3.2v5* | *-*-sco5v6*)
++ # Causes problems with __ctype
++ ;;
++ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
++ # Compiler inserts libc in the correct place for threads to work
++ ;;
++ *)
++ # Add libc to deplibs on all other systems if necessary.
++ if test "$build_libtool_need_lc" = "yes"; then
++ deplibs="$deplibs -lc"
++ fi
++ ;;
++ esac
++ fi
++
++ # Transform deplibs into only deplibs that can be linked in shared.
++ name_save=$name
++ libname_save=$libname
++ release_save=$release
++ versuffix_save=$versuffix
++ major_save=$major
++ # I'm not sure if I'm treating the release correctly. I think
++ # release should show up in the -l (ie -lgmp5) so we don't want to
++ # add it in twice. Is that correct?
++ release=""
++ versuffix=""
++ major=""
++ newdeplibs=
++ droppeddeps=no
++ case $deplibs_check_method in
++ pass_all)
++ # Don't check for shared/static. Everything works.
++ # This might be a little naive. We might want to check
++ # whether the library exists or not. But this is on
++ # osf3 & osf4 and I'm not really sure... Just
++ # implementing what was already the behavior.
++ newdeplibs=$deplibs
++ ;;
++ test_compile)
++ # This code stresses the "libraries are programs" paradigm to its
++ # limits. Maybe even breaks it. We compile a program, linking it
++ # against the deplibs as a proxy for the library. Then we can check
++ # whether they linked in statically or dynamically with ldd.
++ $opt_dry_run || $RM conftest.c
++ cat > conftest.c <<EOF
++ int main() { return 0; }
++EOF
++ $opt_dry_run || $RM conftest
++ if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
++ ldd_output=`ldd conftest`
++ for i in $deplibs; do
++ case $i in
++ -l*)
++ func_stripname -l '' "$i"
++ name=$func_stripname_result
++ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
++ case " $predeps $postdeps " in
++ *" $i "*)
++ newdeplibs="$newdeplibs $i"
++ i=""
++ ;;
++ esac
++ fi
++ if test -n "$i" ; then
++ libname=`eval "\\$ECHO \"$libname_spec\""`
++ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
++ set dummy $deplib_matches; shift
++ deplib_match=$1
++ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
++ newdeplibs="$newdeplibs $i"
++ else
++ droppeddeps=yes
++ $ECHO
++ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
++ $ECHO "*** I have the capability to make that library automatically link in when"
++ $ECHO "*** you link to this library. But I can only do this if you have a"
++ $ECHO "*** shared version of the library, which I believe you do not have"
++ $ECHO "*** because a test_compile did reveal that the linker did not use it for"
++ $ECHO "*** its dynamic dependency list that programs get resolved with at runtime."
++ fi
++ fi
++ ;;
++ *)
++ newdeplibs="$newdeplibs $i"
++ ;;
++ esac
++ done
++ else
++ # Error occurred in the first compile. Let's try to salvage
++ # the situation: Compile a separate program for each library.
++ for i in $deplibs; do
++ case $i in
++ -l*)
++ func_stripname -l '' "$i"
++ name=$func_stripname_result
++ $opt_dry_run || $RM conftest
++ if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
++ ldd_output=`ldd conftest`
++ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
++ case " $predeps $postdeps " in
++ *" $i "*)
++ newdeplibs="$newdeplibs $i"
++ i=""
++ ;;
++ esac
++ fi
++ if test -n "$i" ; then
++ libname=`eval "\\$ECHO \"$libname_spec\""`
++ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
++ set dummy $deplib_matches; shift
++ deplib_match=$1
++ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
++ newdeplibs="$newdeplibs $i"
++ else
++ droppeddeps=yes
++ $ECHO
++ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
++ $ECHO "*** I have the capability to make that library automatically link in when"
++ $ECHO "*** you link to this library. But I can only do this if you have a"
++ $ECHO "*** shared version of the library, which you do not appear to have"
++ $ECHO "*** because a test_compile did reveal that the linker did not use this one"
++ $ECHO "*** as a dynamic dependency that programs can get resolved with at runtime."
++ fi
++ fi
++ else
++ droppeddeps=yes
++ $ECHO
++ $ECHO "*** Warning! Library $i is needed by this library but I was not able to"
++ $ECHO "*** make it link in! You will probably need to install it or some"
++ $ECHO "*** library that it depends on before this library will be fully"
++ $ECHO "*** functional. Installing it before continuing would be even better."
++ fi
++ ;;
++ *)
++ newdeplibs="$newdeplibs $i"
++ ;;
++ esac
++ done
++ fi
++ ;;
++ file_magic*)
++ set dummy $deplibs_check_method; shift
++ file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
++ for a_deplib in $deplibs; do
++ case $a_deplib in
++ -l*)
++ func_stripname -l '' "$a_deplib"
++ name=$func_stripname_result
++ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
++ case " $predeps $postdeps " in
++ *" $a_deplib "*)
++ newdeplibs="$newdeplibs $a_deplib"
++ a_deplib=""
++ ;;
++ esac
++ fi
++ if test -n "$a_deplib" ; then
++ libname=`eval "\\$ECHO \"$libname_spec\""`
++ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
++ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
++ for potent_lib in $potential_libs; do
++ # Follow soft links.
++ if ls -lLd "$potent_lib" 2>/dev/null |
++ $GREP " -> " >/dev/null; then
++ continue
++ fi
++ # The statement above tries to avoid entering an
++ # endless loop below, in case of cyclic links.
++ # We might still enter an endless loop, since a link
++ # loop can be closed while we follow links,
++ # but so what?
++ potlib="$potent_lib"
++ while test -h "$potlib" 2>/dev/null; do
++ potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
++ case $potliblink in
++ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
++ *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
++ esac
++ done
++ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
++ $SED -e 10q |
++ $EGREP "$file_magic_regex" > /dev/null; then
++ newdeplibs="$newdeplibs $a_deplib"
++ a_deplib=""
++ break 2
++ fi
++ done
++ done
++ fi
++ if test -n "$a_deplib" ; then
++ droppeddeps=yes
++ $ECHO
++ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
++ $ECHO "*** I have the capability to make that library automatically link in when"
++ $ECHO "*** you link to this library. But I can only do this if you have a"
++ $ECHO "*** shared version of the library, which you do not appear to have"
++ $ECHO "*** because I did check the linker path looking for a file starting"
++ if test -z "$potlib" ; then
++ $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
++ else
++ $ECHO "*** with $libname and none of the candidates passed a file format test"
++ $ECHO "*** using a file magic. Last file checked: $potlib"
++ fi
++ fi
++ ;;
++ *)
++ # Add a -L argument.
++ newdeplibs="$newdeplibs $a_deplib"
++ ;;
++ esac
++ done # Gone through all deplibs.
++ ;;
++ match_pattern*)
++ set dummy $deplibs_check_method; shift
++ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
++ for a_deplib in $deplibs; do
++ case $a_deplib in
++ -l*)
++ func_stripname -l '' "$a_deplib"
++ name=$func_stripname_result
++ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
++ case " $predeps $postdeps " in
++ *" $a_deplib "*)
++ newdeplibs="$newdeplibs $a_deplib"
++ a_deplib=""
++ ;;
++ esac
++ fi
++ if test -n "$a_deplib" ; then
++ libname=`eval "\\$ECHO \"$libname_spec\""`
++ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
++ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
++ for potent_lib in $potential_libs; do
++ potlib="$potent_lib" # see symlink-check above in file_magic test
++ if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \
++ $EGREP "$match_pattern_regex" > /dev/null; then
++ newdeplibs="$newdeplibs $a_deplib"
++ a_deplib=""
++ break 2
++ fi
++ done
++ done
++ fi
++ if test -n "$a_deplib" ; then
++ droppeddeps=yes
++ $ECHO
++ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
++ $ECHO "*** I have the capability to make that library automatically link in when"
++ $ECHO "*** you link to this library. But I can only do this if you have a"
++ $ECHO "*** shared version of the library, which you do not appear to have"
++ $ECHO "*** because I did check the linker path looking for a file starting"
++ if test -z "$potlib" ; then
++ $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
++ else
++ $ECHO "*** with $libname and none of the candidates passed a file format test"
++ $ECHO "*** using a regex pattern. Last file checked: $potlib"
++ fi
++ fi
++ ;;
++ *)
++ # Add a -L argument.
++ newdeplibs="$newdeplibs $a_deplib"
++ ;;
++ esac
++ done # Gone through all deplibs.
++ ;;
++ none | unknown | *)
++ newdeplibs=""
++ tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \
++ -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'`
++ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
++ for i in $predeps $postdeps ; do
++ # can't use Xsed below, because $i might contain '/'
++ tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"`
++ done
++ fi
++ if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' |
++ $GREP . >/dev/null; then
++ $ECHO
++ if test "X$deplibs_check_method" = "Xnone"; then
++ $ECHO "*** Warning: inter-library dependencies are not supported in this platform."
++ else
++ $ECHO "*** Warning: inter-library dependencies are not known to be supported."
++ fi
++ $ECHO "*** All declared inter-library dependencies are being dropped."
++ droppeddeps=yes
++ fi
++ ;;
++ esac
++ versuffix=$versuffix_save
++ major=$major_save
++ release=$release_save
++ libname=$libname_save
++ name=$name_save
++
++ case $host in
++ *-*-rhapsody* | *-*-darwin1.[012])
++ # On Rhapsody replace the C library with the System framework
++ newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
++ ;;
++ esac
++
++ if test "$droppeddeps" = yes; then
++ if test "$module" = yes; then
++ $ECHO
++ $ECHO "*** Warning: libtool could not satisfy all declared inter-library"
++ $ECHO "*** dependencies of module $libname. Therefore, libtool will create"
++ $ECHO "*** a static module, that should work as long as the dlopening"
++ $ECHO "*** application is linked with the -dlopen flag."
++ if test -z "$global_symbol_pipe"; then
++ $ECHO
++ $ECHO "*** However, this would only work if libtool was able to extract symbol"
++ $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could"
++ $ECHO "*** not find such a program. So, this module is probably useless."
++ $ECHO "*** \`nm' from GNU binutils and a full rebuild may help."
++ fi
++ if test "$build_old_libs" = no; then
++ oldlibs="$output_objdir/$libname.$libext"
++ build_libtool_libs=module
++ build_old_libs=yes
++ else
++ build_libtool_libs=no
++ fi
++ else
++ $ECHO "*** The inter-library dependencies that have been dropped here will be"
++ $ECHO "*** automatically added whenever a program is linked with this library"
++ $ECHO "*** or is declared to -dlopen it."
++
++ if test "$allow_undefined" = no; then
++ $ECHO
++ $ECHO "*** Since this library must not contain undefined symbols,"
++ $ECHO "*** because either the platform does not support them or"
++ $ECHO "*** it was explicitly requested with -no-undefined,"
++ $ECHO "*** libtool will only create a static version of it."
++ if test "$build_old_libs" = no; then
++ oldlibs="$output_objdir/$libname.$libext"
++ build_libtool_libs=module
++ build_old_libs=yes
++ else
++ build_libtool_libs=no
++ fi
++ fi
++ fi
++ fi
++ # Done checking deplibs!
++ deplibs=$newdeplibs
++ fi
++ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
++ case $host in
++ *-*-darwin*)
++ newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
++ new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
++ deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
++ ;;
++ esac
++
++ # move library search paths that coincide with paths to not yet
++ # installed libraries to the beginning of the library search list
++ new_libs=
++ for path in $notinst_path; do
++ case " $new_libs " in
++ *" -L$path/$objdir "*) ;;
++ *)
++ case " $deplibs " in
++ *" -L$path/$objdir "*)
++ new_libs="$new_libs -L$path/$objdir" ;;
++ esac
++ ;;
++ esac
++ done
++ for deplib in $deplibs; do
++ case $deplib in
++ -L*)
++ case " $new_libs " in
++ *" $deplib "*) ;;
++ *) new_libs="$new_libs $deplib" ;;
++ esac
++ ;;
++ *) new_libs="$new_libs $deplib" ;;
++ esac
++ done
++ deplibs="$new_libs"
++
++ # All the library-specific variables (install_libdir is set above).
++ library_names=
++ old_library=
++ dlname=
++
++ # Test again, we may have decided not to build it any more
++ if test "$build_libtool_libs" = yes; then
++ if test "$hardcode_into_libs" = yes; then
++ # Hardcode the library paths
++ hardcode_libdirs=
++ dep_rpath=
++ rpath="$finalize_rpath"
++ test "$mode" != relink && rpath="$compile_rpath$rpath"
++ for libdir in $rpath; do
++ if test -n "$hardcode_libdir_flag_spec"; then
++ if test -n "$hardcode_libdir_separator"; then
++ if test -z "$hardcode_libdirs"; then
++ hardcode_libdirs="$libdir"
++ else
++ # Just accumulate the unique libdirs.
++ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
++ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
++ ;;
++ *)
++ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
++ ;;
++ esac
++ fi
++ else
++ eval flag=\"$hardcode_libdir_flag_spec\"
++ dep_rpath="$dep_rpath $flag"
++ fi
++ elif test -n "$runpath_var"; then
++ case "$perm_rpath " in
++ *" $libdir "*) ;;
++ *) perm_rpath="$perm_rpath $libdir" ;;
++ esac
++ fi
++ done
++ # Substitute the hardcoded libdirs into the rpath.
++ if test -n "$hardcode_libdir_separator" &&
++ test -n "$hardcode_libdirs"; then
++ libdir="$hardcode_libdirs"
++ if test -n "$hardcode_libdir_flag_spec_ld"; then
++ eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
++ else
++ eval dep_rpath=\"$hardcode_libdir_flag_spec\"
++ fi
++ fi
++ if test -n "$runpath_var" && test -n "$perm_rpath"; then
++ # We should set the runpath_var.
++ rpath=
++ for dir in $perm_rpath; do
++ rpath="$rpath$dir:"
++ done
++ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
++ fi
++ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
++ fi
++
++ shlibpath="$finalize_shlibpath"
++ test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
++ if test -n "$shlibpath"; then
++ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
++ fi
++
++ # Get the real and link names of the library.
++ eval shared_ext=\"$shrext_cmds\"
++ eval library_names=\"$library_names_spec\"
++ set dummy $library_names
++ shift
++ realname="$1"
++ shift
++
++ if test -n "$soname_spec"; then
++ eval soname=\"$soname_spec\"
++ else
++ soname="$realname"
++ fi
++ if test -z "$dlname"; then
++ dlname=$soname
++ fi
++
++ lib="$output_objdir/$realname"
++ linknames=
++ for link
++ do
++ linknames="$linknames $link"
++ done
++
++ # Use standard objects if they are pic
++ test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
++ test "X$libobjs" = "X " && libobjs=
++
++ delfiles=
++ if test -n "$export_symbols" && test -n "$include_expsyms"; then
++ $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
++ export_symbols="$output_objdir/$libname.uexp"
++ delfiles="$delfiles $export_symbols"
++ fi
++
++ orig_export_symbols=
++ case $host_os in
++ cygwin* | mingw* | cegcc*)
++ if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
++ # exporting using user supplied symfile
++ if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
++ # and it's NOT already a .def file. Must figure out
++ # which of the given symbols are data symbols and tag
++ # them as such. So, trigger use of export_symbols_cmds.
++ # export_symbols gets reassigned inside the "prepare
++ # the list of exported symbols" if statement, so the
++ # include_expsyms logic still works.
++ orig_export_symbols="$export_symbols"
++ export_symbols=
++ always_export_symbols=yes
++ fi
++ fi
++ ;;
++ esac
++
++ # Prepare the list of exported symbols
++ if test -z "$export_symbols"; then
++ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
++ func_verbose "generating symbol list for \`$libname.la'"
++ export_symbols="$output_objdir/$libname.exp"
++ $opt_dry_run || $RM $export_symbols
++ cmds=$export_symbols_cmds
++ save_ifs="$IFS"; IFS='~'
++ for cmd in $cmds; do
++ IFS="$save_ifs"
++ eval cmd=\"$cmd\"
++ func_len " $cmd"
++ len=$func_len_result
++ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
++ func_show_eval "$cmd" 'exit $?'
++ skipped_export=false
++ else
++ # The command line is too long to execute in one step.
++ func_verbose "using reloadable object file for export list..."
++ skipped_export=:
++ # Break out early, otherwise skipped_export may be
++ # set to false by a later but shorter cmd.
++ break
++ fi
++ done
++ IFS="$save_ifs"
++ if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
++ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
++ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
++ fi
++ fi
++ fi
++
++ if test -n "$export_symbols" && test -n "$include_expsyms"; then
++ tmp_export_symbols="$export_symbols"
++ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
++ $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"'
++ fi
++
++ if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
++ # The given exports_symbols file has to be filtered, so filter it.
++ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
++ # FIXME: $output_objdir/$libname.filter potentially contains lots of
++ # 's' commands which not all seds can handle. GNU sed should be fine
++ # though. Also, the filter scales superlinearly with the number of
++ # global variables. join(1) would be nice here, but unfortunately
++ # isn't a blessed tool.
++ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
++ delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
++ export_symbols=$output_objdir/$libname.def
++ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
++ fi
++
++ tmp_deplibs=
++ for test_deplib in $deplibs; do
++ case " $convenience " in
++ *" $test_deplib "*) ;;
++ *)
++ tmp_deplibs="$tmp_deplibs $test_deplib"
++ ;;
++ esac
++ done
++ deplibs="$tmp_deplibs"
++
++ if test -n "$convenience"; then
++ if test -n "$whole_archive_flag_spec" &&
++ test "$compiler_needs_object" = yes &&
++ test -z "$libobjs"; then
++ # extract the archives, so we have objects to list.
++ # TODO: could optimize this to just extract one archive.
++ whole_archive_flag_spec=
++ fi
++ if test -n "$whole_archive_flag_spec"; then
++ save_libobjs=$libobjs
++ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
++ test "X$libobjs" = "X " && libobjs=
++ else
++ gentop="$output_objdir/${outputname}x"
++ generated="$generated $gentop"
++
++ func_extract_archives $gentop $convenience
++ libobjs="$libobjs $func_extract_archives_result"
++ test "X$libobjs" = "X " && libobjs=
++ fi
++ fi
++
++ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
++ eval flag=\"$thread_safe_flag_spec\"
++ linker_flags="$linker_flags $flag"
++ fi
++
++ # Make a backup of the uninstalled library when relinking
++ if test "$mode" = relink; then
++ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
++ fi
++
++ # Do each of the archive commands.
++ if test "$module" = yes && test -n "$module_cmds" ; then
++ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
++ eval test_cmds=\"$module_expsym_cmds\"
++ cmds=$module_expsym_cmds
++ else
++ eval test_cmds=\"$module_cmds\"
++ cmds=$module_cmds
++ fi
++ else
++ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
++ eval test_cmds=\"$archive_expsym_cmds\"
++ cmds=$archive_expsym_cmds
++ else
++ eval test_cmds=\"$archive_cmds\"
++ cmds=$archive_cmds
++ fi
++ fi
++
++ if test "X$skipped_export" != "X:" &&
++ func_len " $test_cmds" &&
++ len=$func_len_result &&
++ test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
++ :
++ else
++ # The command line is too long to link in one step, link piecewise
++ # or, if using GNU ld and skipped_export is not :, use a linker
++ # script.
++
++ # Save the value of $output and $libobjs because we want to
++ # use them later. If we have whole_archive_flag_spec, we
++ # want to use save_libobjs as it was before
++ # whole_archive_flag_spec was expanded, because we can't
++ # assume the linker understands whole_archive_flag_spec.
++ # This may have to be revisited, in case too many
++ # convenience libraries get linked in and end up exceeding
++ # the spec.
++ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
++ save_libobjs=$libobjs
++ fi
++ save_output=$output
++ output_la=`$ECHO "X$output" | $Xsed -e "$basename"`
++
++ # Clear the reloadable object creation command queue and
++ # initialize k to one.
++ test_cmds=
++ concat_cmds=
++ objlist=
++ last_robj=
++ k=1
++
++ if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
++ output=${output_objdir}/${output_la}.lnkscript
++ func_verbose "creating GNU ld script: $output"
++ $ECHO 'INPUT (' > $output
++ for obj in $save_libobjs
++ do
++ $ECHO "$obj" >> $output
++ done
++ $ECHO ')' >> $output
++ delfiles="$delfiles $output"
++ elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
++ output=${output_objdir}/${output_la}.lnk
++ func_verbose "creating linker input file list: $output"
++ : > $output
++ set x $save_libobjs
++ shift
++ firstobj=
++ if test "$compiler_needs_object" = yes; then
++ firstobj="$1 "
++ shift
++ fi
++ for obj
++ do
++ $ECHO "$obj" >> $output
++ done
++ delfiles="$delfiles $output"
++ output=$firstobj\"$file_list_spec$output\"
++ else
++ if test -n "$save_libobjs"; then
++ func_verbose "creating reloadable object files..."
++ output=$output_objdir/$output_la-${k}.$objext
++ eval test_cmds=\"$reload_cmds\"
++ func_len " $test_cmds"
++ len0=$func_len_result
++ len=$len0
++
++ # Loop over the list of objects to be linked.
++ for obj in $save_libobjs
++ do
++ func_len " $obj"
++ func_arith $len + $func_len_result
++ len=$func_arith_result
++ if test "X$objlist" = X ||
++ test "$len" -lt "$max_cmd_len"; then
++ func_append objlist " $obj"
++ else
++ # The command $test_cmds is almost too long, add a
++ # command to the queue.
++ if test "$k" -eq 1 ; then
++ # The first file doesn't have a previous command to add.
++ eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
++ else
++ # All subsequent reloadable object files will link in
++ # the last one created.
++ eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\"
++ fi
++ last_robj=$output_objdir/$output_la-${k}.$objext
++ func_arith $k + 1
++ k=$func_arith_result
++ output=$output_objdir/$output_la-${k}.$objext
++ objlist=$obj
++ func_len " $last_robj"
++ func_arith $len0 + $func_len_result
++ len=$func_arith_result
++ fi
++ done
++ # Handle the remaining objects by creating one last
++ # reloadable object file. All subsequent reloadable object
++ # files will link in the last one created.
++ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
++ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
++ if test -n "$last_robj"; then
++ eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
++ fi
++ delfiles="$delfiles $output"
++
++ else
++ output=
++ fi
++
++ if ${skipped_export-false}; then
++ func_verbose "generating symbol list for \`$libname.la'"
++ export_symbols="$output_objdir/$libname.exp"
++ $opt_dry_run || $RM $export_symbols
++ libobjs=$output
++ # Append the command to create the export file.
++ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
++ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
++ if test -n "$last_robj"; then
++ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
++ fi
++ fi
++
++ test -n "$save_libobjs" &&
++ func_verbose "creating a temporary reloadable object file: $output"
++
++ # Loop through the commands generated above and execute them.
++ save_ifs="$IFS"; IFS='~'
++ for cmd in $concat_cmds; do
++ IFS="$save_ifs"
++ $opt_silent || {
++ func_quote_for_expand "$cmd"
++ eval "func_echo $func_quote_for_expand_result"
++ }
++ $opt_dry_run || eval "$cmd" || {
++ lt_exit=$?
++
++ # Restore the uninstalled library and exit
++ if test "$mode" = relink; then
++ ( cd "$output_objdir" && \
++ $RM "${realname}T" && \
++ $MV "${realname}U" "$realname" )
++ fi
++
++ exit $lt_exit
++ }
++ done
++ IFS="$save_ifs"
++
++ if test -n "$export_symbols_regex" && ${skipped_export-false}; then
++ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
++ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
++ fi
++ fi
++
++ if ${skipped_export-false}; then
++ if test -n "$export_symbols" && test -n "$include_expsyms"; then
++ tmp_export_symbols="$export_symbols"
++ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
++ $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"'
++ fi
++
++ if test -n "$orig_export_symbols"; then
++ # The given exports_symbols file has to be filtered, so filter it.
++ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
++ # FIXME: $output_objdir/$libname.filter potentially contains lots of
++ # 's' commands which not all seds can handle. GNU sed should be fine
++ # though. Also, the filter scales superlinearly with the number of
++ # global variables. join(1) would be nice here, but unfortunately
++ # isn't a blessed tool.
++ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
++ delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
++ export_symbols=$output_objdir/$libname.def
++ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
++ fi
++ fi
++
++ libobjs=$output
++ # Restore the value of output.
++ output=$save_output
++
++ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
++ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
++ test "X$libobjs" = "X " && libobjs=
++ fi
++ # Expand the library linking commands again to reset the
++ # value of $libobjs for piecewise linking.
++
++ # Do each of the archive commands.
++ if test "$module" = yes && test -n "$module_cmds" ; then
++ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
++ cmds=$module_expsym_cmds
++ else
++ cmds=$module_cmds
++ fi
++ else
++ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
++ cmds=$archive_expsym_cmds
++ else
++ cmds=$archive_cmds
++ fi
++ fi
++ fi
++
++ if test -n "$delfiles"; then
++ # Append the command to remove temporary files to $cmds.
++ eval cmds=\"\$cmds~\$RM $delfiles\"
++ fi
++
++ # Add any objects from preloaded convenience libraries
++ if test -n "$dlprefiles"; then
++ gentop="$output_objdir/${outputname}x"
++ generated="$generated $gentop"
++
++ func_extract_archives $gentop $dlprefiles
++ libobjs="$libobjs $func_extract_archives_result"
++ test "X$libobjs" = "X " && libobjs=
++ fi
++
++ save_ifs="$IFS"; IFS='~'
++ for cmd in $cmds; do
++ IFS="$save_ifs"
++ eval cmd=\"$cmd\"
++ $opt_silent || {
++ func_quote_for_expand "$cmd"
++ eval "func_echo $func_quote_for_expand_result"
++ }
++ $opt_dry_run || eval "$cmd" || {
++ lt_exit=$?
++
++ # Restore the uninstalled library and exit
++ if test "$mode" = relink; then
++ ( cd "$output_objdir" && \
++ $RM "${realname}T" && \
++ $MV "${realname}U" "$realname" )
++ fi
++
++ exit $lt_exit
++ }
++ done
++ IFS="$save_ifs"
++
++ # Restore the uninstalled library and exit
++ if test "$mode" = relink; then
++ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
++
++ if test -n "$convenience"; then
++ if test -z "$whole_archive_flag_spec"; then
++ func_show_eval '${RM}r "$gentop"'
++ fi
++ fi
++
++ exit $EXIT_SUCCESS
++ fi
++
++ # Create links to the real library.
++ for linkname in $linknames; do
++ if test "$realname" != "$linkname"; then
++ func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
++ fi
++ done
++
++ # If -module or -export-dynamic was specified, set the dlname.
++ if test "$module" = yes || test "$export_dynamic" = yes; then
++ # On all known operating systems, these are identical.
++ dlname="$soname"
++ fi
++ fi
++ ;;
++
++ obj)
++ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
++ func_warning "\`-dlopen' is ignored for objects"
++ fi
++
++ case " $deplibs" in
++ *\ -l* | *\ -L*)
++ func_warning "\`-l' and \`-L' are ignored for objects" ;;
++ esac
++
++ test -n "$rpath" && \
++ func_warning "\`-rpath' is ignored for objects"
++
++ test -n "$xrpath" && \
++ func_warning "\`-R' is ignored for objects"
++
++ test -n "$vinfo" && \
++ func_warning "\`-version-info' is ignored for objects"
++
++ test -n "$release" && \
++ func_warning "\`-release' is ignored for objects"
++
++ case $output in
++ *.lo)
++ test -n "$objs$old_deplibs" && \
++ func_fatal_error "cannot build library object \`$output' from non-libtool objects"
++
++ libobj=$output
++ func_lo2o "$libobj"
++ obj=$func_lo2o_result
++ ;;
++ *)
++ libobj=
++ obj="$output"
++ ;;
++ esac
++
++ # Delete the old objects.
++ $opt_dry_run || $RM $obj $libobj
++
++ # Objects from convenience libraries. This assumes
++ # single-version convenience libraries. Whenever we create
++ # different ones for PIC/non-PIC, this we'll have to duplicate
++ # the extraction.
++ reload_conv_objs=
++ gentop=
++ # reload_cmds runs $LD directly, so let us get rid of
++ # -Wl from whole_archive_flag_spec and hope we can get by with
++ # turning comma into space..
++ wl=
++
++ if test -n "$convenience"; then
++ if test -n "$whole_archive_flag_spec"; then
++ eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
++ reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'`
++ else
++ gentop="$output_objdir/${obj}x"
++ generated="$generated $gentop"
++
++ func_extract_archives $gentop $convenience
++ reload_conv_objs="$reload_objs $func_extract_archives_result"
++ fi
++ fi
++
++ # Create the old-style object.
++ reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
++
++ output="$obj"
++ func_execute_cmds "$reload_cmds" 'exit $?'
++
++ # Exit if we aren't doing a library object file.
++ if test -z "$libobj"; then
++ if test -n "$gentop"; then
++ func_show_eval '${RM}r "$gentop"'
++ fi
++
++ exit $EXIT_SUCCESS
++ fi
++
++ if test "$build_libtool_libs" != yes; then
++ if test -n "$gentop"; then
++ func_show_eval '${RM}r "$gentop"'
++ fi
++
++ # Create an invalid libtool object if no PIC, so that we don't
++ # accidentally link it into a program.
++ # $show "echo timestamp > $libobj"
++ # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
++ exit $EXIT_SUCCESS
++ fi
++
++ if test -n "$pic_flag" || test "$pic_mode" != default; then
++ # Only do commands if we really have different PIC objects.
++ reload_objs="$libobjs $reload_conv_objs"
++ output="$libobj"
++ func_execute_cmds "$reload_cmds" 'exit $?'
++ fi
++
++ if test -n "$gentop"; then
++ func_show_eval '${RM}r "$gentop"'
++ fi
++
++ exit $EXIT_SUCCESS
++ ;;
++
++ prog)
++ case $host in
++ *cygwin*) func_stripname '' '.exe' "$output"
++ output=$func_stripname_result.exe;;
++ esac
++ test -n "$vinfo" && \
++ func_warning "\`-version-info' is ignored for programs"
++
++ test -n "$release" && \
++ func_warning "\`-release' is ignored for programs"
++
++ test "$preload" = yes \
++ && test "$dlopen_support" = unknown \
++ && test "$dlopen_self" = unknown \
++ && test "$dlopen_self_static" = unknown && \
++ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
++
++ case $host in
++ *-*-rhapsody* | *-*-darwin1.[012])
++ # On Rhapsody replace the C library is the System framework
++ compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
++ finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
++ ;;
++ esac
++
++ case $host in
++ *-*-darwin*)
++ # Don't allow lazy linking, it breaks C++ global constructors
++ # But is supposedly fixed on 10.4 or later (yay!).
++ if test "$tagname" = CXX ; then
++ case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
++ 10.[0123])
++ compile_command="$compile_command ${wl}-bind_at_load"
++ finalize_command="$finalize_command ${wl}-bind_at_load"
++ ;;
++ esac
++ fi
++ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
++ compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
++ finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
++ ;;
++ esac
++
++
++ # move library search paths that coincide with paths to not yet
++ # installed libraries to the beginning of the library search list
++ new_libs=
++ for path in $notinst_path; do
++ case " $new_libs " in
++ *" -L$path/$objdir "*) ;;
++ *)
++ case " $compile_deplibs " in
++ *" -L$path/$objdir "*)
++ new_libs="$new_libs -L$path/$objdir" ;;
++ esac
++ ;;
++ esac
++ done
++ for deplib in $compile_deplibs; do
++ case $deplib in
++ -L*)
++ case " $new_libs " in
++ *" $deplib "*) ;;
++ *) new_libs="$new_libs $deplib" ;;
++ esac
++ ;;
++ *) new_libs="$new_libs $deplib" ;;
++ esac
++ done
++ compile_deplibs="$new_libs"
++
++
++ compile_command="$compile_command $compile_deplibs"
++ finalize_command="$finalize_command $finalize_deplibs"
++
++ if test -n "$rpath$xrpath"; then
++ # If the user specified any rpath flags, then add them.
++ for libdir in $rpath $xrpath; do
++ # This is the magic to use -rpath.
++ case "$finalize_rpath " in
++ *" $libdir "*) ;;
++ *) finalize_rpath="$finalize_rpath $libdir" ;;
++ esac
++ done
++ fi
++
++ # Now hardcode the library paths
++ rpath=
++ hardcode_libdirs=
++ for libdir in $compile_rpath $finalize_rpath; do
++ if test -n "$hardcode_libdir_flag_spec"; then
++ if test -n "$hardcode_libdir_separator"; then
++ if test -z "$hardcode_libdirs"; then
++ hardcode_libdirs="$libdir"
++ else
++ # Just accumulate the unique libdirs.
++ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
++ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
++ ;;
++ *)
++ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
++ ;;
++ esac
++ fi
++ else
++ eval flag=\"$hardcode_libdir_flag_spec\"
++ rpath="$rpath $flag"
++ fi
++ elif test -n "$runpath_var"; then
++ case "$perm_rpath " in
++ *" $libdir "*) ;;
++ *) perm_rpath="$perm_rpath $libdir" ;;
++ esac
++ fi
++ case $host in
++ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
++ testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
++ case :$dllsearchpath: in
++ *":$libdir:"*) ;;
++ ::) dllsearchpath=$libdir;;
++ *) dllsearchpath="$dllsearchpath:$libdir";;
++ esac
++ case :$dllsearchpath: in
++ *":$testbindir:"*) ;;
++ ::) dllsearchpath=$testbindir;;
++ *) dllsearchpath="$dllsearchpath:$testbindir";;
++ esac
++ ;;
++ esac
++ done
++ # Substitute the hardcoded libdirs into the rpath.
++ if test -n "$hardcode_libdir_separator" &&
++ test -n "$hardcode_libdirs"; then
++ libdir="$hardcode_libdirs"
++ eval rpath=\" $hardcode_libdir_flag_spec\"
++ fi
++ compile_rpath="$rpath"
++
++ rpath=
++ hardcode_libdirs=
++ for libdir in $finalize_rpath; do
++ if test -n "$hardcode_libdir_flag_spec"; then
++ if test -n "$hardcode_libdir_separator"; then
++ if test -z "$hardcode_libdirs"; then
++ hardcode_libdirs="$libdir"
++ else
++ # Just accumulate the unique libdirs.
++ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
++ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
++ ;;
++ *)
++ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
++ ;;
++ esac
++ fi
++ else
++ eval flag=\"$hardcode_libdir_flag_spec\"
++ rpath="$rpath $flag"
++ fi
++ elif test -n "$runpath_var"; then
++ case "$finalize_perm_rpath " in
++ *" $libdir "*) ;;
++ *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
++ esac
++ fi
++ done
++ # Substitute the hardcoded libdirs into the rpath.
++ if test -n "$hardcode_libdir_separator" &&
++ test -n "$hardcode_libdirs"; then
++ libdir="$hardcode_libdirs"
++ eval rpath=\" $hardcode_libdir_flag_spec\"
++ fi
++ finalize_rpath="$rpath"
++
++ if test -n "$libobjs" && test "$build_old_libs" = yes; then
++ # Transform all the library objects into standard objects.
++ compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
++ finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
++ fi
++
++ func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
++
++ # template prelinking step
++ if test -n "$prelink_cmds"; then
++ func_execute_cmds "$prelink_cmds" 'exit $?'
++ fi
++
++ wrappers_required=yes
++ case $host in
++ *cygwin* | *mingw* )
++ if test "$build_libtool_libs" != yes; then
++ wrappers_required=no
++ fi
++ ;;
++ *cegcc)
++ # Disable wrappers for cegcc, we are cross compiling anyway.
++ wrappers_required=no
++ ;;
++ *)
++ if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
++ wrappers_required=no
++ fi
++ ;;
++ esac
++ if test "$wrappers_required" = no; then
++ # Replace the output file specification.
++ compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
++ link_command="$compile_command$compile_rpath"
++
++ # We have no uninstalled library dependencies, so finalize right now.
++ exit_status=0
++ func_show_eval "$link_command" 'exit_status=$?'
++
++ # Delete the generated files.
++ if test -f "$output_objdir/${outputname}S.${objext}"; then
++ func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
++ fi
++
++ exit $exit_status
++ fi
++
++ if test -n "$compile_shlibpath$finalize_shlibpath"; then
++ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
++ fi
++ if test -n "$finalize_shlibpath"; then
++ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
++ fi
++
++ compile_var=
++ finalize_var=
++ if test -n "$runpath_var"; then
++ if test -n "$perm_rpath"; then
++ # We should set the runpath_var.
++ rpath=
++ for dir in $perm_rpath; do
++ rpath="$rpath$dir:"
++ done
++ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
++ fi
++ if test -n "$finalize_perm_rpath"; then
++ # We should set the runpath_var.
++ rpath=
++ for dir in $finalize_perm_rpath; do
++ rpath="$rpath$dir:"
++ done
++ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
++ fi
++ fi
++
++ if test "$no_install" = yes; then
++ # We don't need to create a wrapper script.
++ link_command="$compile_var$compile_command$compile_rpath"
++ # Replace the output file specification.
++ link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
++ # Delete the old output file.
++ $opt_dry_run || $RM $output
++ # Link the executable and exit
++ func_show_eval "$link_command" 'exit $?'
++ exit $EXIT_SUCCESS
++ fi
++
++ if test "$hardcode_action" = relink; then
++ # Fast installation is not supported
++ link_command="$compile_var$compile_command$compile_rpath"
++ relink_command="$finalize_var$finalize_command$finalize_rpath"
++
++ func_warning "this platform does not like uninstalled shared libraries"
++ func_warning "\`$output' will be relinked during installation"
++ else
++ if test "$fast_install" != no; then
++ link_command="$finalize_var$compile_command$finalize_rpath"
++ if test "$fast_install" = yes; then
++ relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
++ else
++ # fast_install is set to needless
++ relink_command=
++ fi
++ else
++ link_command="$compile_var$compile_command$compile_rpath"
++ relink_command="$finalize_var$finalize_command$finalize_rpath"
++ fi
++ fi
++
++ # Replace the output file specification.
++ link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
++
++ # Delete the old output files.
++ $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
++
++ func_show_eval "$link_command" 'exit $?'
++
++ # Now create the wrapper script.
++ func_verbose "creating $output"
++
++ # Quote the relink command for shipping.
++ if test -n "$relink_command"; then
++ # Preserve any variables that may affect compiler behavior
++ for var in $variables_saved_for_relink; do
++ if eval test -z \"\${$var+set}\"; then
++ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
++ elif eval var_value=\$$var; test -z "$var_value"; then
++ relink_command="$var=; export $var; $relink_command"
++ else
++ func_quote_for_eval "$var_value"
++ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
++ fi
++ done
++ relink_command="(cd `pwd`; $relink_command)"
++ relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"`
++ fi
++
++ # Quote $ECHO for shipping.
++ if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then
++ case $progpath in
++ [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
++ *) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
++ esac
++ qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"`
++ else
++ qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"`
++ fi
++
++ # Only actually do things if not in dry run mode.
++ $opt_dry_run || {
++ # win32 will think the script is a binary if it has
++ # a .exe suffix, so we strip it off here.
++ case $output in
++ *.exe) func_stripname '' '.exe' "$output"
++ output=$func_stripname_result ;;
++ esac
++ # test for cygwin because mv fails w/o .exe extensions
++ case $host in
++ *cygwin*)
++ exeext=.exe
++ func_stripname '' '.exe' "$outputname"
++ outputname=$func_stripname_result ;;
++ *) exeext= ;;
++ esac
++ case $host in
++ *cygwin* | *mingw* )
++ func_dirname_and_basename "$output" "" "."
++ output_name=$func_basename_result
++ output_path=$func_dirname_result
++ cwrappersource="$output_path/$objdir/lt-$output_name.c"
++ cwrapper="$output_path/$output_name.exe"
++ $RM $cwrappersource $cwrapper
++ trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
++
++ func_emit_cwrapperexe_src > $cwrappersource
++
++ # The wrapper executable is built using the $host compiler,
++ # because it contains $host paths and files. If cross-
++ # compiling, it, like the target executable, must be
++ # executed on the $host or under an emulation environment.
++ $opt_dry_run || {
++ $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
++ $STRIP $cwrapper
++ }
++
++ # Now, create the wrapper script for func_source use:
++ func_ltwrapper_scriptname $cwrapper
++ $RM $func_ltwrapper_scriptname_result
++ trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
++ $opt_dry_run || {
++ # note: this script will not be executed, so do not chmod.
++ if test "x$build" = "x$host" ; then
++ $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
++ else
++ func_emit_wrapper no > $func_ltwrapper_scriptname_result
++ fi
++ }
++ ;;
++ * )
++ $RM $output
++ trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
++
++ func_emit_wrapper no > $output
++ chmod +x $output
++ ;;
++ esac
++ }
++ exit $EXIT_SUCCESS
++ ;;
++ esac
++
++ # See if we need to build an old-fashioned archive.
++ for oldlib in $oldlibs; do
++
++ if test "$build_libtool_libs" = convenience; then
++ oldobjs="$libobjs_save $symfileobj"
++ addlibs="$convenience"
++ build_libtool_libs=no
++ else
++ if test "$build_libtool_libs" = module; then
++ oldobjs="$libobjs_save"
++ build_libtool_libs=no
++ else
++ oldobjs="$old_deplibs $non_pic_objects"
++ if test "$preload" = yes && test -f "$symfileobj"; then
++ oldobjs="$oldobjs $symfileobj"
++ fi
++ fi
++ addlibs="$old_convenience"
++ fi
++
++ if test -n "$addlibs"; then
++ gentop="$output_objdir/${outputname}x"
++ generated="$generated $gentop"
++
++ func_extract_archives $gentop $addlibs
++ oldobjs="$oldobjs $func_extract_archives_result"
++ fi
++
++ # Do each command in the archive commands.
++ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
++ cmds=$old_archive_from_new_cmds
++ else
++
++ # Add any objects from preloaded convenience libraries
++ if test -n "$dlprefiles"; then
++ gentop="$output_objdir/${outputname}x"
++ generated="$generated $gentop"
++
++ func_extract_archives $gentop $dlprefiles
++ oldobjs="$oldobjs $func_extract_archives_result"
++ fi
++
++ # POSIX demands no paths to be encoded in archives. We have
++ # to avoid creating archives with duplicate basenames if we
++ # might have to extract them afterwards, e.g., when creating a
++ # static archive out of a convenience library, or when linking
++ # the entirety of a libtool archive into another (currently
++ # not supported by libtool).
++ if (for obj in $oldobjs
++ do
++ func_basename "$obj"
++ $ECHO "$func_basename_result"
++ done | sort | sort -uc >/dev/null 2>&1); then
++ :
++ else
++ $ECHO "copying selected object files to avoid basename conflicts..."
++ gentop="$output_objdir/${outputname}x"
++ generated="$generated $gentop"
++ func_mkdir_p "$gentop"
++ save_oldobjs=$oldobjs
++ oldobjs=
++ counter=1
++ for obj in $save_oldobjs
++ do
++ func_basename "$obj"
++ objbase="$func_basename_result"
++ case " $oldobjs " in
++ " ") oldobjs=$obj ;;
++ *[\ /]"$objbase "*)
++ while :; do
++ # Make sure we don't pick an alternate name that also
++ # overlaps.
++ newobj=lt$counter-$objbase
++ func_arith $counter + 1
++ counter=$func_arith_result
++ case " $oldobjs " in
++ *[\ /]"$newobj "*) ;;
++ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
++ esac
++ done
++ func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
++ oldobjs="$oldobjs $gentop/$newobj"
++ ;;
++ *) oldobjs="$oldobjs $obj" ;;
++ esac
++ done
++ fi
++ eval cmds=\"$old_archive_cmds\"
++
++ func_len " $cmds"
++ len=$func_len_result
++ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
++ cmds=$old_archive_cmds
++ else
++ # the command line is too long to link in one step, link in parts
++ func_verbose "using piecewise archive linking..."
++ save_RANLIB=$RANLIB
++ RANLIB=:
++ objlist=
++ concat_cmds=
++ save_oldobjs=$oldobjs
++ oldobjs=
++ # Is there a better way of finding the last object in the list?
++ for obj in $save_oldobjs
++ do
++ last_oldobj=$obj
++ done
++ eval test_cmds=\"$old_archive_cmds\"
++ func_len " $test_cmds"
++ len0=$func_len_result
++ len=$len0
++ for obj in $save_oldobjs
++ do
++ func_len " $obj"
++ func_arith $len + $func_len_result
++ len=$func_arith_result
++ func_append objlist " $obj"
++ if test "$len" -lt "$max_cmd_len"; then
++ :
++ else
++ # the above command should be used before it gets too long
++ oldobjs=$objlist
++ if test "$obj" = "$last_oldobj" ; then
++ RANLIB=$save_RANLIB
++ fi
++ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
++ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
++ objlist=
++ len=$len0
++ fi
++ done
++ RANLIB=$save_RANLIB
++ oldobjs=$objlist
++ if test "X$oldobjs" = "X" ; then
++ eval cmds=\"\$concat_cmds\"
++ else
++ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
++ fi
++ fi
++ fi
++ func_execute_cmds "$cmds" 'exit $?'
++ done
++
++ test -n "$generated" && \
++ func_show_eval "${RM}r$generated"
++
++ # Now create the libtool archive.
++ case $output in
++ *.la)
++ old_library=
++ test "$build_old_libs" = yes && old_library="$libname.$libext"
++ func_verbose "creating $output"
++
++ # Preserve any variables that may affect compiler behavior
++ for var in $variables_saved_for_relink; do
++ if eval test -z \"\${$var+set}\"; then
++ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
++ elif eval var_value=\$$var; test -z "$var_value"; then
++ relink_command="$var=; export $var; $relink_command"
++ else
++ func_quote_for_eval "$var_value"
++ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
++ fi
++ done
++ # Quote the link command for shipping.
++ relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
++ relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"`
++ if test "$hardcode_automatic" = yes ; then
++ relink_command=
++ fi
++
++ # Only create the output if not a dry run.
++ $opt_dry_run || {
++ for installed in no yes; do
++ if test "$installed" = yes; then
++ if test -z "$install_libdir"; then
++ break
++ fi
++ output="$output_objdir/$outputname"i
++ # Replace all uninstalled libtool libraries with the installed ones
++ newdependency_libs=
++ for deplib in $dependency_libs; do
++ case $deplib in
++ *.la)
++ func_basename "$deplib"
++ name="$func_basename_result"
++ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
++ test -z "$libdir" && \
++ func_fatal_error "\`$deplib' is not a valid libtool archive"
++ newdependency_libs="$newdependency_libs $libdir/$name"
++ ;;
++ *) newdependency_libs="$newdependency_libs $deplib" ;;
++ esac
++ done
++ dependency_libs="$newdependency_libs"
++ newdlfiles=
++
++ for lib in $dlfiles; do
++ case $lib in
++ *.la)
++ func_basename "$lib"
++ name="$func_basename_result"
++ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
++ test -z "$libdir" && \
++ func_fatal_error "\`$lib' is not a valid libtool archive"
++ newdlfiles="$newdlfiles $libdir/$name"
++ ;;
++ *) newdlfiles="$newdlfiles $lib" ;;
++ esac
++ done
++ dlfiles="$newdlfiles"
++ newdlprefiles=
++ for lib in $dlprefiles; do
++ case $lib in
++ *.la)
++ # Only pass preopened files to the pseudo-archive (for
++ # eventual linking with the app. that links it) if we
++ # didn't already link the preopened objects directly into
++ # the library:
++ func_basename "$lib"
++ name="$func_basename_result"
++ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
++ test -z "$libdir" && \
++ func_fatal_error "\`$lib' is not a valid libtool archive"
++ newdlprefiles="$newdlprefiles $libdir/$name"
++ ;;
++ esac
++ done
++ dlprefiles="$newdlprefiles"
++ else
++ newdlfiles=
++ for lib in $dlfiles; do
++ case $lib in
++ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
++ *) abs=`pwd`"/$lib" ;;
++ esac
++ newdlfiles="$newdlfiles $abs"
++ done
++ dlfiles="$newdlfiles"
++ newdlprefiles=
++ for lib in $dlprefiles; do
++ case $lib in
++ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
++ *) abs=`pwd`"/$lib" ;;
++ esac
++ newdlprefiles="$newdlprefiles $abs"
++ done
++ dlprefiles="$newdlprefiles"
++ fi
++ $RM $output
++ # place dlname in correct position for cygwin
++ tdlname=$dlname
++ case $host,$output,$installed,$module,$dlname in
++ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
++ esac
++ $ECHO > $output "\
++# $outputname - a libtool library file
++# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
++#
++# Please DO NOT delete this file!
++# It is necessary for linking the library.
++
++# The name that we can dlopen(3).
++dlname='$tdlname'
++
++# Names of this library.
++library_names='$library_names'
++
++# The name of the static archive.
++old_library='$old_library'
++
++# Linker flags that can not go in dependency_libs.
++inherited_linker_flags='$new_inherited_linker_flags'
++
++# Libraries that this one depends upon.
++dependency_libs='$dependency_libs'
++
++# Names of additional weak libraries provided by this library
++weak_library_names='$weak_libs'
++
++# Version information for $libname.
++current=$current
++age=$age
++revision=$revision
++
++# Is this an already installed library?
++installed=$installed
++
++# Should we warn about portability when linking against -modules?
++shouldnotlink=$module
++
++# Files to dlopen/dlpreopen
++dlopen='$dlfiles'
++dlpreopen='$dlprefiles'
++
++# Directory that this library needs to be installed in:
++libdir='$install_libdir'"
++ if test "$installed" = no && test "$need_relink" = yes; then
++ $ECHO >> $output "\
++relink_command=\"$relink_command\""
++ fi
++ done
++ }
++
++ # Do a symbolic link so that the libtool archive can be found in
++ # LD_LIBRARY_PATH before the program is installed.
++ func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
++ ;;
++ esac
++ exit $EXIT_SUCCESS
++}
++
++{ test "$mode" = link || test "$mode" = relink; } &&
++ func_mode_link ${1+"$@"}
++
++
++# func_mode_uninstall arg...
++func_mode_uninstall ()
++{
++ $opt_debug
++ RM="$nonopt"
++ files=
++ rmforce=
++ exit_status=0
++
++ # This variable tells wrapper scripts just to set variables rather
++ # than running their programs.
++ libtool_install_magic="$magic"
++
++ for arg
++ do
++ case $arg in
++ -f) RM="$RM $arg"; rmforce=yes ;;
++ -*) RM="$RM $arg" ;;
++ *) files="$files $arg" ;;
++ esac
++ done
++
++ test -z "$RM" && \
++ func_fatal_help "you must specify an RM program"
++
++ rmdirs=
++
++ origobjdir="$objdir"
++ for file in $files; do
++ func_dirname "$file" "" "."
++ dir="$func_dirname_result"
++ if test "X$dir" = X.; then
++ objdir="$origobjdir"
++ else
++ objdir="$dir/$origobjdir"
++ fi
++ func_basename "$file"
++ name="$func_basename_result"
++ test "$mode" = uninstall && objdir="$dir"
++
++ # Remember objdir for removal later, being careful to avoid duplicates
++ if test "$mode" = clean; then
++ case " $rmdirs " in
++ *" $objdir "*) ;;
++ *) rmdirs="$rmdirs $objdir" ;;
++ esac
++ fi
++
++ # Don't error if the file doesn't exist and rm -f was used.
++ if { test -L "$file"; } >/dev/null 2>&1 ||
++ { test -h "$file"; } >/dev/null 2>&1 ||
++ test -f "$file"; then
++ :
++ elif test -d "$file"; then
++ exit_status=1
++ continue
++ elif test "$rmforce" = yes; then
++ continue
++ fi
++
++ rmfiles="$file"
++
++ case $name in
++ *.la)
++ # Possibly a libtool archive, so verify it.
++ if func_lalib_p "$file"; then
++ func_source $dir/$name
++
++ # Delete the libtool libraries and symlinks.
++ for n in $library_names; do
++ rmfiles="$rmfiles $objdir/$n"
++ done
++ test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
++
++ case "$mode" in
++ clean)
++ case " $library_names " in
++ # " " in the beginning catches empty $dlname
++ *" $dlname "*) ;;
++ *) rmfiles="$rmfiles $objdir/$dlname" ;;
++ esac
++ test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
++ ;;
++ uninstall)
++ if test -n "$library_names"; then
++ # Do each command in the postuninstall commands.
++ func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
++ fi
++
++ if test -n "$old_library"; then
++ # Do each command in the old_postuninstall commands.
++ func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
++ fi
++ # FIXME: should reinstall the best remaining shared library.
++ ;;
++ esac
++ fi
++ ;;
++
++ *.lo)
++ # Possibly a libtool object, so verify it.
++ if func_lalib_p "$file"; then
++
++ # Read the .lo file
++ func_source $dir/$name
++
++ # Add PIC object to the list of files to remove.
++ if test -n "$pic_object" &&
++ test "$pic_object" != none; then
++ rmfiles="$rmfiles $dir/$pic_object"
++ fi
++
++ # Add non-PIC object to the list of files to remove.
++ if test -n "$non_pic_object" &&
++ test "$non_pic_object" != none; then
++ rmfiles="$rmfiles $dir/$non_pic_object"
++ fi
++ fi
++ ;;
++
++ *)
++ if test "$mode" = clean ; then
++ noexename=$name
++ case $file in
++ *.exe)
++ func_stripname '' '.exe' "$file"
++ file=$func_stripname_result
++ func_stripname '' '.exe' "$name"
++ noexename=$func_stripname_result
++ # $file with .exe has already been added to rmfiles,
++ # add $file without .exe
++ rmfiles="$rmfiles $file"
++ ;;
++ esac
++ # Do a test to see if this is a libtool program.
++ if func_ltwrapper_p "$file"; then
++ if func_ltwrapper_executable_p "$file"; then
++ func_ltwrapper_scriptname "$file"
++ relink_command=
++ func_source $func_ltwrapper_scriptname_result
++ rmfiles="$rmfiles $func_ltwrapper_scriptname_result"
++ else
++ relink_command=
++ func_source $dir/$noexename
++ fi
++
++ # note $name still contains .exe if it was in $file originally
++ # as does the version of $file that was added into $rmfiles
++ rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
++ if test "$fast_install" = yes && test -n "$relink_command"; then
++ rmfiles="$rmfiles $objdir/lt-$name"
++ fi
++ if test "X$noexename" != "X$name" ; then
++ rmfiles="$rmfiles $objdir/lt-${noexename}.c"
++ fi
++ fi
++ fi
++ ;;
++ esac
++ func_show_eval "$RM $rmfiles" 'exit_status=1'
++ done
++ objdir="$origobjdir"
++
++ # Try to remove the ${objdir}s in the directories where we deleted files
++ for dir in $rmdirs; do
++ if test -d "$dir"; then
++ func_show_eval "rmdir $dir >/dev/null 2>&1"
++ fi
++ done
++
++ exit $exit_status
++}
++
++{ test "$mode" = uninstall || test "$mode" = clean; } &&
++ func_mode_uninstall ${1+"$@"}
++
++test -z "$mode" && {
++ help="$generic_help"
++ func_fatal_help "you must specify a MODE"
++}
++
++test -z "$exec_cmd" && \
++ func_fatal_help "invalid operation mode \`$mode'"
++
++if test -n "$exec_cmd"; then
++ eval exec "$exec_cmd"
++ exit $EXIT_FAILURE
++fi
++
++exit $exit_status
++
++
++# The TAGs below are defined such that we never get into a situation
++# in which we disable both kinds of libraries. Given conflicting
++# choices, we go for a static library, that is the most portable,
++# since we can't tell whether shared libraries were disabled because
++# the user asked for that or because the platform doesn't support
++# them. This is particularly important on AIX, because we don't
++# support having both static and shared libraries enabled at the same
++# time on that platform, so we default to a shared-only configuration.
++# If a disable-shared tag is given, we'll fallback to a static-only
++# configuration. But we'll never go from static-only to shared-only.
++
++# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
++build_libtool_libs=no
++build_old_libs=yes
++# ### END LIBTOOL TAG CONFIG: disable-shared
++
++# ### BEGIN LIBTOOL TAG CONFIG: disable-static
++build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
++# ### END LIBTOOL TAG CONFIG: disable-static
++
++# Local Variables:
++# mode:shell-script
++# sh-indentation:2
++# End:
++# vi:sw=2
++
diff --git a/package/uclibc++/Config.in.manual b/package/uclibc++/Config.in.manual
index 50729fcaa..b645e03a4 100644
--- a/package/uclibc++/Config.in.manual
+++ b/package/uclibc++/Config.in.manual
@@ -1,7 +1,11 @@
+comment "uClibc++... C++ library for embedded systems (disabled, c++ missing)"
+depends on !ADK_TOOLCHAIN_GCC_CXX
+
config ADK_PACKAGE_UCLIBCXX
prompt "uClibc++............... C++ library for embedded systems"
tristate
depends on ADK_TARGET_LIB_UCLIBC
+ depends on ADK_TOOLCHAIN_GCC_CXX
default n
help
A standard C++ library for embedded systems
diff --git a/package/uclibc++/Makefile b/package/uclibc++/Makefile
index 760258bdd..e718b20bc 100644
--- a/package/uclibc++/Makefile
+++ b/package/uclibc++/Makefile
@@ -11,6 +11,7 @@ PKG_DESCR:= A standard c++ library for embedded systems
PKG_SECTION:= libs
PKG_URL:= http://cxx.uclibc.org/
PKG_SITES:= http://cxx.uclibc.org/src/
+PKG_NEED_CXX:= 1
DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tar.bz2
diff --git a/package/uclibc/Makefile b/package/uclibc/Makefile
index 5538cdfbd..90b9f49f9 100644
--- a/package/uclibc/Makefile
+++ b/package/uclibc/Makefile
@@ -23,17 +23,16 @@ CONFIG_STYLE:= manual
BUILD_STYLE:= manual
INSTALL_STYLE:= manual
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_UCLIBC_DEV}+= uclibc-dev-install
-
# do nothing, uClibc is already build in toolchain directory
-do-install: $(STAGING_TARGET_DIR)/lib/libc.so ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+do-install: $(STAGING_TARGET_DIR)/lib/libc.so
${INSTALL_DIR} $(IDIR_UCLIBC)/lib $(IDIR_UCLIBC)/etc
# create timezone file
test -z $(ADK_RUNTIME_TIMEZONE) || \
grep $(ADK_RUNTIME_TIMEZONE) ./files/tz.lst | \
cut -f 2 > $(IDIR_UCLIBC)/etc/TZ
+ifeq ($(ADK_TOOLCHAIN_GCC_USE_SSP),y)
+ $(CP) $(STAGING_TARGET_DIR)/lib/libssp.so* $(IDIR_UCLIBC)/lib/
+endif
$(CP) $(STAGING_TARGET_DIR)/lib/libc.so* $(IDIR_UCLIBC)/lib/
$(CP) $(STAGING_TARGET_DIR)/lib/libuClibc-$(PKG_VERSION).so \
$(IDIR_UCLIBC)/lib/
diff --git a/package/ulogd/Makefile b/package/ulogd/Makefile
index e1f4d0dc5..3010e7a92 100644
--- a/package/ulogd/Makefile
+++ b/package/ulogd/Makefile
@@ -34,13 +34,6 @@ $(eval $(call PKG_template,ULOGD_MOD_PGSQL,ulogd-mod-pgsql,${PKG_VERSION}-${PKG_
$(eval $(call PKG_template,ULOGD_MOD_SQLITE,ulogd-mod-sqlite,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
$(eval $(call PKG_template,ULOGD_MOD_EXTRA,ulogd-mod-extra,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_ULOGD_MOD_MYSQL}+= ulogd-mod-mysql-install
-SUB_INSTALLS-${ADK_PACKAGE_ULOGD_MOD_PGSQL}+= ulogd-mod-pgsql-install
-SUB_INSTALLS-${ADK_PACKAGE_ULOGD_MOD_SQLITE}+= ulogd-mod-sqlite-install
-SUB_INSTALLS-${ADK_PACKAGE_ULOGD_MOD_EXTRA}+= ulogd-mod-extra-install
-
TCFLAGS+= -fPIC
ifneq (${ADK_PACKAGE_ULOGD_MOD_MYSQL},)
@@ -55,7 +48,7 @@ ifneq (${ADK_PACKAGE_ULOGD_MOD_SQLITE},)
CONFIGURE_ARGS+= --with-sqlite3=${STAGING_TARGET_DIR}/usr
endif
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_ULOGD}/usr/sbin ${IDIR_ULOGD}/usr/lib/ulogd/
${INSTALL_BIN} ${WRKINST}/usr/lib/ulogd/ulogd_raw2packet_BASE.so \
${IDIR_ULOGD}/usr/lib/ulogd/
diff --git a/package/ulogd/patches/patch-ltmain_sh b/package/ulogd/patches/patch-ltmain_sh
new file mode 100644
index 000000000..d5b6fafd8
--- /dev/null
+++ b/package/ulogd/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- ulogd-2.0.0beta4.orig/ltmain.sh 2010-07-16 17:53:39.000000000 +0200
++++ ulogd-2.0.0beta4/ltmain.sh 2011-01-17 16:15:25.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/updatedd/patches/patch-ltmain_sh b/package/updatedd/patches/patch-ltmain_sh
new file mode 100644
index 000000000..3b4dffb54
--- /dev/null
+++ b/package/updatedd/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- updatedd-2.6.orig/ltmain.sh 2006-09-07 22:32:59.000000000 +0200
++++ updatedd-2.6/ltmain.sh 2011-01-17 16:20:16.000000000 +0100
+@@ -1623,7 +1623,7 @@ EOF
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+- -t[45]*|-txscale*|@*)
++ -t[45]*|-txscale*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/util-linux-ng/patches/patch-config_ltmain_sh b/package/util-linux-ng/patches/patch-config_ltmain_sh
new file mode 100644
index 000000000..86ee09448
--- /dev/null
+++ b/package/util-linux-ng/patches/patch-config_ltmain_sh
@@ -0,0 +1,11 @@
+--- util-linux-ng-2.18.orig/config/ltmain.sh 2010-02-04 12:53:55.000000000 +0100
++++ util-linux-ng-2.18/config/ltmain.sh 2011-01-17 16:27:39.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/valgrind/patches/patch-auxprogs_valgrind-listener_c b/package/valgrind/patches/patch-auxprogs_valgrind-listener_c
new file mode 100644
index 000000000..be4b433ed
--- /dev/null
+++ b/package/valgrind/patches/patch-auxprogs_valgrind-listener_c
@@ -0,0 +1,29 @@
+ try to avoid problems with a pre #defined st_atime here, too
+--- valgrind-3.5.0.orig/auxprogs/valgrind-listener.c 2009-08-19 15:37:30.000000000 +0200
++++ valgrind-3.5.0/auxprogs/valgrind-listener.c 2010-12-30 17:23:49.807262269 +0100
+@@ -32,6 +32,12 @@
+
+ /*---------------------------------------------------------------*/
+
++#include "pub_core_basics.h"
++#include "pub_core_libcassert.h" // For VG_BUGS_TO
++#include "pub_core_vki.h" // Avoids warnings from
++ // pub_core_libcfile.h
++#include "pub_core_libcfile.h" // For VG_CLO_DEFAULT_LOGPORT
++
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <string.h>
+@@ -44,12 +50,6 @@
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+
+-#include "pub_core_basics.h"
+-#include "pub_core_libcassert.h" // For VG_BUGS_TO
+-#include "pub_core_vki.h" // Avoids warnings from
+- // pub_core_libcfile.h
+-#include "pub_core_libcfile.h" // For VG_CLO_DEFAULT_LOGPORT
+-
+
+ /*---------------------------------------------------------------*/
+
diff --git a/package/valgrind/patches/patch-coregrind_launcher-linux_c b/package/valgrind/patches/patch-coregrind_launcher-linux_c
new file mode 100644
index 000000000..e94ffd908
--- /dev/null
+++ b/package/valgrind/patches/patch-coregrind_launcher-linux_c
@@ -0,0 +1,29 @@
+ try to avoid errors regarding already #defined st_atime in bits/stat.h or so
+--- valgrind-3.5.0.orig/coregrind/launcher-linux.c 2009-08-19 15:37:47.000000000 +0200
++++ valgrind-3.5.0/coregrind/launcher-linux.c 2010-12-30 17:08:00.035938916 +0100
+@@ -32,6 +32,12 @@
+ and so it doesn't have to conform to Valgrind's arcane rules on
+ no-glibc-usage etc. */
+
++#include "pub_core_debuglog.h"
++#include "pub_core_vki.h" // Avoids warnings from
++ // pub_core_libcfile.h
++#include "pub_core_libcproc.h" // For VALGRIND_LIB, VALGRIND_LAUNCHER
++#include "pub_core_ume.h"
++
+ #include <assert.h>
+ #include <ctype.h>
+ #include <elf.h>
+@@ -45,12 +51,6 @@
+ #include <sys/user.h>
+ #include <unistd.h>
+
+-#include "pub_core_debuglog.h"
+-#include "pub_core_vki.h" // Avoids warnings from
+- // pub_core_libcfile.h
+-#include "pub_core_libcproc.h" // For VALGRIND_LIB, VALGRIND_LAUNCHER
+-#include "pub_core_ume.h"
+-
+
+
+ #define PATH_MAX 4096 /* POSIX refers to this a lot but I dunno
diff --git a/package/vrrpd/patches/patch-Makefile b/package/vrrpd/patches/patch-Makefile
new file mode 100644
index 000000000..4a628b744
--- /dev/null
+++ b/package/vrrpd/patches/patch-Makefile
@@ -0,0 +1,17 @@
+--- vrrpd-1.0.orig/Makefile 2002-09-09 16:51:13.000000000 +0200
++++ vrrpd-1.0/Makefile 2011-01-17 16:36:32.000000000 +0100
+@@ -14,12 +14,10 @@ DBG_OPT=-g
+ #LINKLIB = -lpcap
+ COMMON_CFLAGS= $(MAIN_OPT) $(INCLUDEOPT) $(PROF_OPT) $(DBG_OPT) $(MACHINEOPT)
+
+-# set to compile with GCC
+-CC=gcc
+-CFLAGS= $(COMMON_CFLAGS) -Wall
++CFLAGS?= $(COMMON_CFLAGS) -Wall
+
+ vrrpd : $(VRRPD_OBJS)
+- $(CC) $(PROF_OPT) -o $@ $(VRRPD_OBJS) $(LINKLIB)
++ $(CC) $(LDFLAGS) -o $@ $(VRRPD_OBJS) $(LINKLIB)
+
+ vrrpd.o: vrrpd.h
+ libnetlink.o: libnetlink.h
diff --git a/package/watchdog/Makefile b/package/watchdog/Makefile
index b2c4839f7..ab8f5c570 100644
--- a/package/watchdog/Makefile
+++ b/package/watchdog/Makefile
@@ -18,7 +18,7 @@ $(eval $(call PKG_template,WATCHDOG,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${
post-install:
${INSTALL_DIR} ${IDIR_WATCHDOG}/sbin ${IDIR_WATCHDOG}/etc/
${INSTALL_DATA} ./files/watchdog.conf ${IDIR_WATCHDOG}/etc/
- ${INSTALL_BIN} ${WRKINST}/sbin/watchdog \
+ ${INSTALL_BIN} ${WRKINST}/usr/sbin/watchdog \
${IDIR_WATCHDOG}/sbin/
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/weechat/patches/patch-ltmain_sh b/package/weechat/patches/patch-ltmain_sh
new file mode 100644
index 000000000..33915daef
--- /dev/null
+++ b/package/weechat/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- weechat-0.3.2.orig/ltmain.sh 2010-04-17 11:39:59.000000000 +0200
++++ weechat-0.3.2/ltmain.sh 2011-01-17 16:44:00.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/wget/Makefile b/package/wget/Makefile
index 6629e12b3..e2ff151f4 100644
--- a/package/wget/Makefile
+++ b/package/wget/Makefile
@@ -17,7 +17,8 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,WGET,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
post-install:
- ${INSTALL_DIR} ${IDIR_WGET}/usr/bin
+ ${INSTALL_DIR} ${IDIR_WGET}/etc ${IDIR_WGET}/usr/bin
+ ${INSTALL_DATA} ${WRKINST}/etc/wgetrc ${IDIR_WGET}/etc/
${INSTALL_BIN} ${WRKINST}/usr/bin/wget ${IDIR_WGET}/usr/bin
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/wget/files/wget.conffiles b/package/wget/files/wget.conffiles
new file mode 100644
index 000000000..fc52bd1a2
--- /dev/null
+++ b/package/wget/files/wget.conffiles
@@ -0,0 +1 @@
+/etc/wgetrc
diff --git a/package/wifidog/patches/patch-config_ltmain_sh b/package/wifidog/patches/patch-config_ltmain_sh
new file mode 100644
index 000000000..e2624965b
--- /dev/null
+++ b/package/wifidog/patches/patch-config_ltmain_sh
@@ -0,0 +1,11 @@
+--- wifidog-1.1.5.orig/config/ltmain.sh 2007-08-14 19:43:36.000000000 +0200
++++ wifidog-1.1.5/config/ltmain.sh 2011-01-17 16:54:21.000000000 +0100
+@@ -1663,7 +1663,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/wireless-tools/patches/patch-Makefile b/package/wireless-tools/patches/patch-Makefile
new file mode 100644
index 000000000..e3dcf4af8
--- /dev/null
+++ b/package/wireless-tools/patches/patch-Makefile
@@ -0,0 +1,11 @@
+--- wireless_tools.29.orig/Makefile 2007-09-18 01:56:46.000000000 +0200
++++ wireless_tools.29/Makefile 2011-01-17 16:59:21.000000000 +0100
+@@ -145,7 +145,7 @@ wireless.h:
+
+ # Compilation of the dynamic library
+ $(DYNAMIC): $(OBJS:.o=.so)
+- $(CC) -shared -o $@ -Wl,-soname,$@ $(STRIPFLAGS) $(LIBS) -lc $^
++ $(CC) $(LDFLAGS) -shared -o $@ -Wl,-soname,$@ $(STRIPFLAGS) $(LIBS) -lc $^
+
+ # Compilation of the static library
+ $(STATIC): $(OBJS:.o=.so)
diff --git a/package/wpa_supplicant/Makefile b/package/wpa_supplicant/Makefile
index 7b8be1a0c..aebb85f8d 100644
--- a/package/wpa_supplicant/Makefile
+++ b/package/wpa_supplicant/Makefile
@@ -4,26 +4,27 @@
include ${TOPDIR}/rules.mk
PKG_NAME:= wpa_supplicant
-PKG_VERSION:= 0.7.2
+PKG_VERSION:= 0.7.3
PKG_RELEASE:= 1
-PKG_MD5SUM:= 0e2cb7e4c35667351d8b7ec28c783e6a
+PKG_MD5SUM:= f516f191384a9a546e3f5145c08addda
PKG_DESCR:= WPA Supplicant with support for WPA and WPA2
PKG_SECTION:= wifi
PKG_DEPENDS:= libnl
PKG_BUILDDEP:= libnl
+PKG_URL:= http://hostap.epitest.fi/wpa_supplicant/
PKG_SITES:= http://hostap.epitest.fi/releases/
PKG_DFLT_WPA_SUPPLICANT:= y if ADK_TARGET_SYSTEM_IBM_X40
WRKSRC= ${WRKDIST}/${PKG_NAME}
-PKG_CHOICES:= WITH_OPENSSL WITH_GNUTLS
-PKGCD_WITH_OPENSSL:= use OpenSSL for crypto
-PKGCS_WITH_OPENSSL:= libopenssl
-PKGCB_WITH_OPENSSL:= openssl
-PKGCD_WITH_GNUTLS:= use GnuTLS for crypto
-PKGCS_WITH_GNUTLS:= libgnutls
-PKGCB_WITH_GNUTLS:= gnutls
+PKG_CHOICES_WPA_SUPPLICANT:= WITH_OPENSSL WITH_GNUTLS
+PKGCD_WITH_OPENSSL:= use OpenSSL for crypto
+PKGCS_WITH_OPENSSL:= libopenssl
+PKGCB_WITH_OPENSSL:= openssl
+PKGCD_WITH_GNUTLS:= use GnuTLS for crypto
+PKGCS_WITH_GNUTLS:= libgnutls
+PKGCB_WITH_GNUTLS:= gnutls
include ${TOPDIR}/mk/package.mk
@@ -38,7 +39,7 @@ MAKE_FLAGS+= CPPFLAGS='${TCPPFLAGS}' \
KERNEL=${LINUX_DIR}
do-configure:
- ${CP} files/config ${WRKBUILD}/.config
+ ${CP} ./files/config ${WRKBUILD}/.config
ifneq (${ADK_PACKAGE_WPA_SUPPLICANT_WITH_GNUTLS},)
${SED} "s#openssl#gnutls#" ${WRKBUILD}/.config
endif
diff --git a/package/wpa_supplicant/files/config b/package/wpa_supplicant/files/config
index aa0ee6b17..c3e2702cd 100644
--- a/package/wpa_supplicant/files/config
+++ b/package/wpa_supplicant/files/config
@@ -3,6 +3,7 @@ CONFIG_DRIVER_NL80211=y
CONFIG_DRIVER_WEXT=y
#CONFIG_IEEE8021X_EAPOL=y
CONFIG_CTRL_IFACE=y
+CONFIG_LIBNL20=y
# default
CONFIG_EAP_PSK=y
diff --git a/package/wput/patches/patch-Makefile b/package/wput/patches/patch-Makefile
deleted file mode 100644
index a4b70f58c..000000000
--- a/package/wput/patches/patch-Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
---- wput-0.6.1.orig/Makefile 2007-12-12 18:30:04.000000000 +0100
-+++ wput-0.6.1/Makefile 2010-02-06 04:45:45.273084356 +0100
-@@ -1,6 +1,6 @@
- #wput makefile
- PACKAGE = wput
--prefix = /usr/local
-+prefix = /usr
- datadir = $(prefix)/share
- mandir = $(datadir)/man/man1
- exec_prefix = ${prefix}
-@@ -16,8 +16,8 @@ win-clean:
-
- install: all
- cd po && $(MAKE) $(MAKEDEFS) $@
-- install -m0755 wput $(bindir)
-- install -m0644 doc/wput.1.gz $(mandir)
-+ install -m0755 wput $(DESTDIR)$(bindir)
-+ install -m0644 doc/wput.1.gz $(DESTDIR)$(mandir)
- @echo "----------------"
- @echo "Wput installed. See 'wput -h' or 'man wput' for usage information."
- @echo "Further documentation is located in the doc/USAGE.* files."
diff --git a/package/wput/patches/patch-config_status b/package/wput/patches/patch-config_status
deleted file mode 100644
index 176dcb666..000000000
--- a/package/wput/patches/patch-config_status
+++ /dev/null
@@ -1,160 +0,0 @@
---- wput-0.6.1.orig/config.status 2007-12-12 18:30:04.000000000 +0100
-+++ wput-0.6.1/config.status 2010-02-06 04:45:45.083075667 +0100
-@@ -334,14 +334,14 @@ Report bugs to <bug-autoconf@gnu.org>."
-
- ac_cs_version="\
- wput config.status 0.6
--configured by ./configure, generated by GNU Autoconf 2.61,
-- with options \"\"
-+configured by /home/wbx/openadk/build_qemu-x86_uclibc/w-wput-0.6.1-1/wput-0.6.1/configure, generated by GNU Autoconf 2.61,
-+ with options \"'--build=x86_64-linux-gnu' '--host=i586-linux' '--target=i586-linux' '--program-prefix=' '--program-suffix=' '--prefix=/usr' '--datadir=/usr/share' '--mandir=/usr/share/man' '--libexecdir=/usr/sbin' '--localstatedir=/var' '--sysconfdir=/etc' '--disable-nls' '--enable-shared' '--enable-static' '--disable-dependency-tracking' '--disable-libtool-lock' '--disable-debug' '--disable-g-switch' 'build_alias=x86_64-linux-gnu' 'host_alias=i586-linux' 'target_alias=i586-linux' 'CC=/home/wbx/openadk/cross_qemu-x86_uclibc/host/bin/i586-linux-uclibc-gcc' 'CFLAGS=-fno-ident -Os -pipe -march=i586 -fomit-frame-pointer' 'LDFLAGS=-Wl,-O2 -Wl,-rpath -Wl,/usr/lib -Wl,-rpath-link -Wl,/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib -L/home/wbx/openadk/cross_qemu-x86_uclibc/target/lib -L/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib' 'CPPFLAGS=-I/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/include -DNDEBUG'\"
-
- Copyright (C) 2006 Free Software Foundation, Inc.
- This config.status script is free software; the Free Software Foundation
- gives unlimited permission to copy, distribute and modify it."
-
--ac_pwd='/home/hagen/studium/projects/wput'
-+ac_pwd='/home/wbx/openadk/build_qemu-x86_uclibc/w-wput-0.6.1-1/wput-0.6.1'
- srcdir='.'
- INSTALL='/usr/bin/install -c'
- # If no file are specified by the user, then we need to provide default
-@@ -409,10 +409,10 @@ if $ac_cs_silent; then
- fi
-
- if $ac_cs_recheck; then
-- echo "running CONFIG_SHELL=/bin/bash /bin/bash ./configure " $ac_configure_extra_args " --no-create --no-recursion" >&6
-+ echo "running CONFIG_SHELL=/bin/bash /bin/bash /home/wbx/openadk/build_qemu-x86_uclibc/w-wput-0.6.1-1/wput-0.6.1/configure " '--build=x86_64-linux-gnu' '--host=i586-linux' '--target=i586-linux' '--program-prefix=' '--program-suffix=' '--prefix=/usr' '--datadir=/usr/share' '--mandir=/usr/share/man' '--libexecdir=/usr/sbin' '--localstatedir=/var' '--sysconfdir=/etc' '--disable-nls' '--enable-shared' '--enable-static' '--disable-dependency-tracking' '--disable-libtool-lock' '--disable-debug' '--disable-g-switch' 'build_alias=x86_64-linux-gnu' 'host_alias=i586-linux' 'target_alias=i586-linux' 'CC=/home/wbx/openadk/cross_qemu-x86_uclibc/host/bin/i586-linux-uclibc-gcc' 'CFLAGS=-fno-ident -Os -pipe -march=i586 -fomit-frame-pointer' 'LDFLAGS=-Wl,-O2 -Wl,-rpath -Wl,/usr/lib -Wl,-rpath-link -Wl,/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib -L/home/wbx/openadk/cross_qemu-x86_uclibc/target/lib -L/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib' 'CPPFLAGS=-I/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/include -DNDEBUG' $ac_configure_extra_args " --no-create --no-recursion" >&6
- CONFIG_SHELL=/bin/bash
- export CONFIG_SHELL
-- exec /bin/bash "./configure" $ac_configure_extra_args --no-create --no-recursion
-+ exec /bin/bash "/home/wbx/openadk/build_qemu-x86_uclibc/w-wput-0.6.1-1/wput-0.6.1/configure" '--build=x86_64-linux-gnu' '--host=i586-linux' '--target=i586-linux' '--program-prefix=' '--program-suffix=' '--prefix=/usr' '--datadir=/usr/share' '--mandir=/usr/share/man' '--libexecdir=/usr/sbin' '--localstatedir=/var' '--sysconfdir=/etc' '--disable-nls' '--enable-shared' '--enable-static' '--disable-dependency-tracking' '--disable-libtool-lock' '--disable-debug' '--disable-g-switch' 'build_alias=x86_64-linux-gnu' 'host_alias=i586-linux' 'target_alias=i586-linux' 'CC=/home/wbx/openadk/cross_qemu-x86_uclibc/host/bin/i586-linux-uclibc-gcc' 'CFLAGS=-fno-ident -Os -pipe -march=i586 -fomit-frame-pointer' 'LDFLAGS=-Wl,-O2 -Wl,-rpath -Wl,/usr/lib -Wl,-rpath-link -Wl,/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib -L/home/wbx/openadk/cross_qemu-x86_uclibc/target/lib -L/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib' 'CPPFLAGS=-I/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/include -DNDEBUG' $ac_configure_extra_args --no-create --no-recursion
- fi
-
- exec 5>>config.log
-@@ -510,16 +510,16 @@ s,@PACKAGE_VERSION@,|#_!!_#|0.6,g
- s,@PACKAGE_STRING@,|#_!!_#|wput 0.6,g
- s,@PACKAGE_BUGREPORT@,|#_!!_#|,g
- s,@exec_prefix@,|#_!!_#|${prefix},g
--s,@prefix@,|#_!!_#|/usr/local,g
-+s,@prefix@,|#_!!_#|/usr,g
- s,@program_transform_name@,|#_!!_#|s\,x\,x\,,g
- s,@bindir@,|#_!!_#|${exec_prefix}/bin,g
- s,@sbindir@,|#_!!_#|${exec_prefix}/sbin,g
--s,@libexecdir@,|#_!!_#|${exec_prefix}/libexec,g
-+s,@libexecdir@,|#_!!_#|/usr/sbin,g
- s,@datarootdir@,|#_!!_#|${prefix}/share,g
--s,@datadir@,|#_!!_#|${datarootdir},g
--s,@sysconfdir@,|#_!!_#|${prefix}/etc,g
-+s,@datadir@,|#_!!_#|/usr/share,g
-+s,@sysconfdir@,|#_!!_#|/etc,g
- s,@sharedstatedir@,|#_!!_#|${prefix}/com,g
--s,@localstatedir@,|#_!!_#|${prefix}/var,g
-+s,@localstatedir@,|#_!!_#|/var,g
- s,@includedir@,|#_!!_#|${prefix}/include,g
- s,@oldincludedir@,|#_!!_#|/usr/include,g
- s,@docdir@,|#_!!_#|${datarootdir}/doc/${PACKAGE_TARNAME},g
-@@ -530,25 +530,25 @@ s,@pdfdir@,|#_!!_#|${docdir},g
- s,@psdir@,|#_!!_#|${docdir},g
- s,@libdir@,|#_!!_#|${exec_prefix}/lib,g
- s,@localedir@,|#_!!_#|${datarootdir}/locale,g
--s,@mandir@,|#_!!_#|${datarootdir}/man,g
-+s,@mandir@,|#_!!_#|/usr/share/man,g
- s,@DEFS@,|#_!!_#|-DHAVE_CONFIG_H,g
- s,@ECHO_C@,|#_!!_#|,g
- s,@ECHO_N@,|#_!!_#|-n,g
- s,@ECHO_T@,|#_!!_#|,g
- s,@LIBS@,|#_!!_#|,g
--s,@build_alias@,|#_!!_#|,g
--s,@host_alias@,|#_!!_#|,g
--s,@target_alias@,|#_!!_#|,g
-+s,@build_alias@,|#_!!_#|x86_64-linux-gnu,g
-+s,@host_alias@,|#_!!_#|i586-linux,g
-+s,@target_alias@,|#_!!_#|i586-linux,g
- s,@PACKAGE@,|#_!!_#|wput,g
- s,@VERSION@,|#_!!_#|0.6,g
--s,@CC@,|#_!!_#|gcc,g
--s,@CFLAGS@,|#_!!_#| -Wall -g,g
--s,@LDFLAGS@,|#_!!_#|,g
--s,@CPPFLAGS@,|#_!!_#|,g
--s,@ac_ct_CC@,|#_!!_#|gcc,g
-+s,@CC@,|#_!!_#|/home/wbx/openadk/cross_qemu-x86_uclibc/host/bin/i586-linux-uclibc-gcc,g
-+s,@CFLAGS@,|#_!!_#|-fno-ident -Os -pipe -march=i586 -fomit-frame-pointer -Wall,g
-+s,@LDFLAGS@,|#_!!_#|-Wl\,-O2 -Wl\,-rpath -Wl\,/usr/lib -Wl\,-rpath-link -Wl\,/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib -L/home/wbx/openadk/cross_qemu-x86_uclibc/target/lib -L/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib,g
-+s,@CPPFLAGS@,|#_!!_#|-I/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/include -DNDEBUG,g
-+s,@ac_ct_CC@,|#_!!_#|,g
- s,@EXEEXT@,|#_!!_#|,g
- s,@OBJEXT@,|#_!!_#|o,g
--s,@CPP@,|#_!!_#|gcc -E,g
-+s,@CPP@,|#_!!_#|/home/wbx/openadk/cross_qemu-x86_uclibc/host/bin/i586-linux-uclibc-gcc -E,g
- s,@GREP@,|#_!!_#|/bin/grep,g
- s,@EGREP@,|#_!!_#|/bin/grep -E,g
- s,@SET_MAKE@,|#_!!_#|,g
-@@ -556,29 +556,29 @@ s,@INSTALL_PROGRAM@,|#_!!_#|${INSTALL},g
- s,@INSTALL_SCRIPT@,|#_!!_#|${INSTALL},g
- s,@INSTALL_DATA@,|#_!!_#|${INSTALL} -m 644,g
- s,@MKINSTALLDIRS@,|#_!!_#|$(top_builddir)/./mkinstalldirs,g
--s,@USE_NLS@,|#_!!_#|yes,g
-+s,@USE_NLS@,|#_!!_#|no,g
- s,@MSGFMT@,|#_!!_#|/usr/bin/msgfmt,g
- s,@GMSGFMT@,|#_!!_#|/usr/bin/msgfmt,g
- s,@XGETTEXT@,|#_!!_#|/usr/bin/xgettext,g
- s,@MSGMERGE@,|#_!!_#|/usr/bin/msgmerge,g
--s,@build@,|#_!!_#|i686-pc-linux-gnu,g
--s,@build_cpu@,|#_!!_#|i686,g
-+s,@build@,|#_!!_#|x86_64-pc-linux-gnu,g
-+s,@build_cpu@,|#_!!_#|x86_64,g
- s,@build_vendor@,|#_!!_#|pc,g
- s,@build_os@,|#_!!_#|linux-gnu,g
--s,@host@,|#_!!_#|i686-pc-linux-gnu,g
--s,@host_cpu@,|#_!!_#|i686,g
-+s,@host@,|#_!!_#|i586-pc-linux-gnu,g
-+s,@host_cpu@,|#_!!_#|i586,g
- s,@host_vendor@,|#_!!_#|pc,g
- s,@host_os@,|#_!!_#|Linux,g
--s,@LIBICONV@,|#_!!_#|-liconv,g
--s,@LTLIBICONV@,|#_!!_#|-liconv,g
-+s,@LIBICONV@,|#_!!_#|/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib/libiconv.so -Wl\,-rpath -Wl\,/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib,g
-+s,@LTLIBICONV@,|#_!!_#|-L/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib -liconv -R/home/wbx/openadk/cross_qemu-x86_uclibc/target/usr/lib,g
- s,@INTLLIBS@,|#_!!_#|,g
- s,@LIBINTL@,|#_!!_#|,g
- s,@LTLIBINTL@,|#_!!_#|,g
--s,@POSUB@,|#_!!_#|po,g
-+s,@POSUB@,|#_!!_#|,g
- s,@GETOPT@,|#_!!_#|,g
- s,@MEMDBG@,|#_!!_#|,g
--s,@GNUTLS_CFLAGS@,|#_!!_#|-INONE/include,g
--s,@GNUTLS_LIBS@,|#_!!_#| -lgnutls-openssl,g
-+s,@GNUTLS_CFLAGS@,|#_!!_#|,g
-+s,@GNUTLS_LIBS@,|#_!!_#|,g
- s,@LIBOBJS@,|#_!!_#|,g
- s,@LTLIBOBJS@,|#_!!_#|,g
- :end
-@@ -776,11 +776,11 @@ case `sed -n '/datarootdir/ {
- { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
- echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
- ac_datarootdir_hack='
-- s&@datadir@&${datarootdir}&g
-+ s&@datadir@&/usr/share&g
- s&@docdir@&${datarootdir}/doc/${PACKAGE_TARNAME}&g
- s&@infodir@&${datarootdir}/info&g
- s&@localedir@&${datarootdir}/locale&g
-- s&@mandir@&${datarootdir}/man&g
-+ s&@mandir@&/usr/share/man&g
- s&\${datarootdir}&${prefix}/share&g' ;;
- esac
- sed "/^[ ]*VPATH[ ]*=/{
-@@ -852,14 +852,7 @@ s,^\([ #]*\)[^ ]*\([ ]*HAVE_IOCTL\)[
- s,^\([ #]*\)[^ ]*\([ ]*HAVE_TERMIO_H\)[ (].*,\1define\2 1 ,
- s,^\([ #]*\)[^ ]*\([ ]*HAVE_TERMIO\)[ (].*,\1define\2 1 ,
- s,^\([ #]*\)[^ ]*\([ ]*HAVE_LOCALE_H\)[ (].*,\1define\2 1 ,
--s,^\([ #]*\)[^ ]*\([ ]*HAVE_LIBINTL_H\)[ (].*,\1define\2 1 ,
- s,^\([ #]*\)[^ ]*\([ ]*HAVE_GETOPT_H\)[ (].*,\1define\2 1 ,
--s,^\([ #]*\)[^ ]*\([ ]*ENABLE_NLS\)[ (].*,\1define\2 1 ,
--s,^\([ #]*\)[^ ]*\([ ]*HAVE_GETTEXT\)[ (].*,\1define\2 1 ,
--s,^\([ #]*\)[^ ]*\([ ]*HAVE_DCGETTEXT\)[ (].*,\1define\2 1 ,
--s,^\([ #]*\)[^ ]*\([ ]*HAVE_GNUTLS_OPENSSL_H\)[ (].*,\1define\2 1 ,
--s,^\([ #]*\)[^ ]*\([ ]*HAVE_GNUTLS\)[ (].*,\1define\2 1 ,
--s,^\([ #]*\)[^ ]*\([ ]*HAVE_SSL\)[ (].*,\1define\2 1 ,
- s,^\([ #]*\)[^ ]*\([ ]*HAVE_LONG_LONG\)[ (].*,\1define\2 1 ,
- s,^\([ #]*\)[^ ]*\([ ]*HAVE_UNSIGNED_LONG_LONG\)[ (].*,\1define\2 1 ,
- s,^\([ #]*\)[^ ]*\([ ]*HAVE_LONG_LONG\)[ (].*,\1define\2 1 ,
diff --git a/package/wput/patches/patch-po_Makefile b/package/wput/patches/patch-po_Makefile
deleted file mode 100644
index f636bff65..000000000
--- a/package/wput/patches/patch-po_Makefile
+++ /dev/null
@@ -1,50 +0,0 @@
---- wput-0.6.1.orig/po/Makefile 2007-12-12 18:30:04.000000000 +0100
-+++ wput-0.6.1/po/Makefile 2010-02-06 04:45:45.653081691 +0100
-@@ -20,9 +20,9 @@ srcdir = .
- top_srcdir = ..
-
-
--prefix = /usr/local
-+prefix = /usr
- exec_prefix = ${prefix}
--datadir = ${prefix}/share
-+datadir = /usr/share
- localedir = $(datadir)/locale
- gettextsrcdir = $(datadir)/gettext/po
-
-@@ -124,7 +124,7 @@ EXTRA_LOCALE_CATEGORIES =
- mv t-$@ $@
-
-
--all: all-yes
-+all: all-no
-
- all-yes: stamp-po
- all-no:
-@@ -191,7 +191,7 @@ $(POFILES): $(srcdir)/$(DOMAIN).pot
-
- install: install-exec install-data
- install-exec:
--install-data: install-data-yes
-+install-data: install-data-no
- if test "$(PACKAGE)" = "gettext-tools"; then \
- $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \
- for file in $(DISTFILES.common) Makevars.template; do \
-@@ -250,7 +250,7 @@ install-strip: install
-
- installdirs: installdirs-exec installdirs-data
- installdirs-exec:
--installdirs-data: installdirs-data-yes
-+installdirs-data: installdirs-data-no
- if test "$(PACKAGE)" = "gettext-tools"; then \
- $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \
- else \
-@@ -295,7 +295,7 @@ installcheck:
-
- uninstall: uninstall-exec uninstall-data
- uninstall-exec:
--uninstall-data: uninstall-data-yes
-+uninstall-data: uninstall-data-no
- if test "$(PACKAGE)" = "gettext-tools"; then \
- for file in $(DISTFILES.common) Makevars.template; do \
- rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
diff --git a/package/wput/patches/patch-po_Makefile_in b/package/wput/patches/patch-po_Makefile_in
deleted file mode 100644
index 45610ddbb..000000000
--- a/package/wput/patches/patch-po_Makefile_in
+++ /dev/null
@@ -1,50 +0,0 @@
---- wput-0.6.1.orig/po/Makefile.in 2007-12-12 18:30:04.000000000 +0100
-+++ wput-0.6.1/po/Makefile.in 2010-02-06 04:45:45.453076297 +0100
-@@ -20,9 +20,9 @@ srcdir = .
- top_srcdir = ..
-
-
--prefix = /usr/local
-+prefix = /usr
- exec_prefix = ${prefix}
--datadir = ${prefix}/share
-+datadir = /usr/share
- localedir = $(datadir)/locale
- gettextsrcdir = $(datadir)/gettext/po
-
-@@ -74,7 +74,7 @@ CATALOGS = @CATALOGS@
- mv t-$@ $@
-
-
--all: all-yes
-+all: all-no
-
- all-yes: stamp-po
- all-no:
-@@ -141,7 +141,7 @@ $(POFILES): $(srcdir)/$(DOMAIN).pot
-
- install: install-exec install-data
- install-exec:
--install-data: install-data-yes
-+install-data: install-data-no
- if test "$(PACKAGE)" = "gettext-tools"; then \
- $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \
- for file in $(DISTFILES.common) Makevars.template; do \
-@@ -200,7 +200,7 @@ install-strip: install
-
- installdirs: installdirs-exec installdirs-data
- installdirs-exec:
--installdirs-data: installdirs-data-yes
-+installdirs-data: installdirs-data-no
- if test "$(PACKAGE)" = "gettext-tools"; then \
- $(mkinstalldirs) $(DESTDIR)$(gettextsrcdir); \
- else \
-@@ -245,7 +245,7 @@ installcheck:
-
- uninstall: uninstall-exec uninstall-data
- uninstall-exec:
--uninstall-data: uninstall-data-yes
-+uninstall-data: uninstall-data-no
- if test "$(PACKAGE)" = "gettext-tools"; then \
- for file in $(DISTFILES.common) Makevars.template; do \
- rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
diff --git a/package/wput/patches/patch-src_Makefile b/package/wput/patches/patch-src_Makefile
deleted file mode 100644
index 42f51da44..000000000
--- a/package/wput/patches/patch-src_Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
---- wput-0.6.1.orig/src/Makefile 2007-12-12 18:30:04.000000000 +0100
-+++ wput-0.6.1/src/Makefile 2010-02-06 04:45:45.363075315 +0100
-@@ -1,12 +1,12 @@
- #wput.mk
- #mm make file for wput
- SHELL=/bin/bash
--prefix=/usr/local
-+prefix=/usr
- bindir=${exec_prefix}/bin
- localedir=$(prefix)/share/locale
--CC=gcc
--CFLAGS= -Wall -g -DLOCALEDIR=\"$(localedir)\" -INONE/include
--LIBS= -lgnutls-openssl
-+CC=/home/wbx/openadk/cross_qemu-x86_uclibc/host/bin/i586-linux-uclibc-gcc
-+CFLAGS= -fno-ident -Os -pipe -march=i586 -fomit-frame-pointer -Wall -DLOCALEDIR=\"$(localedir)\"
-+LIBS=
- EXE=../wput
- GETOPT=
- MEMDBG=
diff --git a/package/wput/patches/patch-src_Makefile_in b/package/wput/patches/patch-src_Makefile_in
new file mode 100644
index 000000000..d59c3a721
--- /dev/null
+++ b/package/wput/patches/patch-src_Makefile_in
@@ -0,0 +1,19 @@
+--- wput-0.6.1.orig/src/Makefile.in 2007-12-12 18:30:04.000000000 +0100
++++ wput-0.6.1/src/Makefile.in 2011-01-17 17:04:46.000000000 +0100
+@@ -6,6 +6,7 @@ bindir=@bindir@
+ localedir=$(prefix)/share/locale
+ CC=@CC@
+ CFLAGS= @CFLAGS@ -DLOCALEDIR=\"$(localedir)\" @GNUTLS_CFLAGS@
++LDFLAGS=@LDFLAGS@
+ LIBS=@LIBINTL@ @LIBS@ @GNUTLS_LIBS@
+ EXE=../wput
+ GETOPT=@GETOPT@
+@@ -23,7 +24,7 @@ ftplib.o: socketlib.h ftplib.h
+ ftp-ls.o: ftp.h wget.h url.h
+
+ wput: $(OBJ)
+- $(CC) -o $(EXE) $(OBJ) $(LIBS)
++ $(CC) $(LDFLAGS) -o $(EXE) $(OBJ) $(LIBS)
+ clean:
+ rm -f *.o *~ *.bak ../wput getopt/*.o
+ win-clean: clean
diff --git a/package/wput/patches/patch-src_config_h b/package/wput/patches/patch-src_config_h
deleted file mode 100644
index 52a23c2ed..000000000
--- a/package/wput/patches/patch-src_config_h
+++ /dev/null
@@ -1,27 +0,0 @@
---- wput-0.6.1.orig/src/config.h 2007-12-12 18:30:04.000000000 +0100
-+++ wput-0.6.1/src/config.h 2010-02-06 04:45:45.543084453 +0100
-@@ -7,13 +7,13 @@
- #define HAVE_IOCTL 1
-
- /* Define if you have the <libintl.h> header file. */
--#define HAVE_LIBINTL_H 1
-+/* #undef HAVE_LIBINTL_H */
-
- /* Define if you have the <locale.h> header file. */
- #define HAVE_LOCALE_H 1
-
- /* Define this if you want the NLS support. */
--#define ENABLE_NLS 1
-+/* #undef ENABLE_NLS */
-
- /* Define to 1 if you have the <gnugetopt/getopt.h> header file. */
- /* #undef HAVE_GNUGETOPT_GETOPT_H */
-@@ -64,7 +64,7 @@
- #define STDC_HEADERS 1
-
- /* Define if all libs needed for ssl support are existing */
--#define HAVE_SSL 1
-+/* #undef HAVE_SSL */
-
- /* Define to 1 if you have the long long type */
- #define HAVE_LONG_LONG 1
diff --git a/package/xf86-input-evtouch/patches/patch-ltmain_sh b/package/xf86-input-evtouch/patches/patch-ltmain_sh
new file mode 100644
index 000000000..83e749c0b
--- /dev/null
+++ b/package/xf86-input-evtouch/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- xf86-input-evtouch-0.8.8.orig/ltmain.sh 2008-11-09 22:01:01.000000000 +0100
++++ xf86-input-evtouch-0.8.8/ltmain.sh 2011-01-17 17:08:24.000000000 +0100
+@@ -4238,7 +4238,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/xf86-input-keyboard/patches/patch-ltmain_sh b/package/xf86-input-keyboard/patches/patch-ltmain_sh
new file mode 100644
index 000000000..754d116e2
--- /dev/null
+++ b/package/xf86-input-keyboard/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- xf86-input-keyboard-1.4.0.orig/ltmain.sh 2009-09-14 02:35:10.000000000 +0200
++++ xf86-input-keyboard-1.4.0/ltmain.sh 2011-01-17 17:18:30.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/xf86-input-mouse/patches/patch-ltmain_sh b/package/xf86-input-mouse/patches/patch-ltmain_sh
new file mode 100644
index 000000000..3032ef8fc
--- /dev/null
+++ b/package/xf86-input-mouse/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- xf86-input-mouse-1.5.0.orig/ltmain.sh 2009-04-08 14:13:48.000000000 +0200
++++ xf86-input-mouse-1.5.0/ltmain.sh 2011-01-17 17:28:10.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/xf86-video-cirrus/patches/patch-ltmain_sh b/package/xf86-video-cirrus/patches/patch-ltmain_sh
new file mode 100644
index 000000000..eb8f42a6c
--- /dev/null
+++ b/package/xf86-video-cirrus/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- xf86-video-cirrus-1.3.2.orig/ltmain.sh 2008-08-30 00:27:25.000000000 +0200
++++ xf86-video-cirrus-1.3.2/ltmain.sh 2011-01-17 17:38:35.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/xf86-video-geode/patches/patch-ltmain_sh b/package/xf86-video-geode/patches/patch-ltmain_sh
new file mode 100644
index 000000000..6c6beb7dd
--- /dev/null
+++ b/package/xf86-video-geode/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- xf86-video-geode-2.11.6.orig/ltmain.sh 2009-09-27 14:01:31.000000000 +0200
++++ xf86-video-geode-2.11.6/ltmain.sh 2011-01-17 17:43:27.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/xf86-video-intel/patches/patch-ltmain_sh b/package/xf86-video-intel/patches/patch-ltmain_sh
new file mode 100644
index 000000000..5cf546d2a
--- /dev/null
+++ b/package/xf86-video-intel/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- xf86-video-intel-2.13.0.orig/ltmain.sh 2010-02-25 18:09:43.000000000 +0100
++++ xf86-video-intel-2.13.0/ltmain.sh 2011-01-17 17:47:33.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/xf86-video-siliconmotion/patches/patch-ltmain_sh b/package/xf86-video-siliconmotion/patches/patch-ltmain_sh
new file mode 100644
index 000000000..8c977addb
--- /dev/null
+++ b/package/xf86-video-siliconmotion/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- xf86-video-siliconmotion-1.7.3.orig/ltmain.sh 2008-08-30 00:27:25.000000000 +0200
++++ xf86-video-siliconmotion-1.7.3/ltmain.sh 2011-01-17 17:49:45.000000000 +0100
+@@ -1676,7 +1676,7 @@ EOF
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
diff --git a/package/xorg-server/Makefile b/package/xorg-server/Makefile
index 9aa7eaba9..92d5ddeaa 100644
--- a/package/xorg-server/Makefile
+++ b/package/xorg-server/Makefile
@@ -22,10 +22,10 @@ PKG_SITES:= http://xorg.freedesktop.org/archive/individual/xserver/
PKG_CFLINE_XORG_SERVER:=depends on ADK_TARGET_WITH_VGA
-PKG_FLAVOURS:= WITH_DRI
-PKGFS_WITH_DRI:= mesalib
-PKGFD_WITH_DRI:= enable DRI/DRI2 support
-PKGFB_WITH_DRI:= xf86driproto glproto dri2proto MesaLib
+PKG_FLAVOURS_XORG_SERVER:= WITH_DRI
+PKGFS_WITH_DRI:= mesalib
+PKGFD_WITH_DRI:= enable DRI/DRI2 support
+PKGFB_WITH_DRI:= xf86driproto glproto dri2proto MesaLib
include $(TOPDIR)/mk/package.mk
diff --git a/package/xorg-server/patches/patch-ltmain_sh b/package/xorg-server/patches/patch-ltmain_sh
new file mode 100644
index 000000000..779bb5238
--- /dev/null
+++ b/package/xorg-server/patches/patch-ltmain_sh
@@ -0,0 +1,11 @@
+--- xorg-server-1.7.6.orig/ltmain.sh 2010-02-05 04:18:39.000000000 +0100
++++ xorg-server-1.7.6/ltmain.sh 2011-01-17 16:06:33.000000000 +0100
+@@ -4765,7 +4765,7 @@ func_mode_link ()
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+- -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
++ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-fstack-protector*|-flto)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/xz/patches/patch-build-aux_ltmain_sh b/package/xz/patches/patch-build-aux_ltmain_sh
new file mode 100644
index 000000000..b9ae6dddf
--- /dev/null
+++ b/package/xz/patches/patch-build-aux_ltmain_sh
@@ -0,0 +1,11 @@
+--- xz-5.0.0.orig/build-aux/ltmain.sh 2010-10-23 16:48:07.000000000 +0200
++++ xz-5.0.0/build-aux/ltmain.sh 2011-01-17 17:54:37.000000000 +0100
+@@ -5840,7 +5840,7 @@ func_mode_link ()
+ # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+- -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
++ -O*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
diff --git a/package/zlib/Makefile b/package/zlib/Makefile
index 0bf048448..6270eaf37 100644
--- a/package/zlib/Makefile
+++ b/package/zlib/Makefile
@@ -27,10 +27,6 @@ include ${TOPDIR}/mk/package.mk
$(eval $(call PKG_template,ZLIB,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION},${PKG_OPTS}))
$(eval $(call PKG_template,ZLIB_DEV,${PKG_NAME}-dev,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKGSD_ZLIB_DEV},${PKGSC_ZLIB_DEV}))
-SUB_INSTALLS-y:=
-SUB_INSTALLS-m:=
-SUB_INSTALLS-${ADK_PACKAGE_ZLIB_DEV}+= zlib-dev-install
-
CONFIG_STYLE:= manual
CONFIGURE_ENV+= uname=Linux
@@ -53,7 +49,7 @@ do-configure:
$(CONFIGURE_OPTS) \
);
-post-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y}
+post-install:
${INSTALL_DIR} ${IDIR_ZLIB}/usr/lib
${CP} ${WRKBUILD}/libz.so* ${IDIR_ZLIB}/usr/lib
diff --git a/rules.mk b/rules.mk
index 40d98186b..12ba160f2 100644
--- a/rules.mk
+++ b/rules.mk
@@ -45,11 +45,13 @@ endif
include $(TOPDIR)/mk/vars.mk
-export BASH HOSTCC HOSTCFLAGS MAKE LANGUAGE LC_ALL OStype PATH
+export BASH HOSTCC HOSTCXX MAKE LANGUAGE LC_ALL OStype PATH
+HOSTCFLAGS?= -O2
+HOSTCXXFLAGS?= -O2
HOSTCPPFLAGS?=
HOSTLDFLAGS?=
-TARGET_CFLAGS:= $(strip -fno-ident ${TARGET_CFLAGS})
+TARGET_CFLAGS:= $(strip ${TARGET_CFLAGS} -fno-ident -fhonour-copts)
TARGET_CC:= $(strip ${TARGET_CC})
TARGET_CXX:= $(strip ${TARGET_CXX})
diff --git a/scripts/reloc.sh b/scripts/reloc.sh
new file mode 100755
index 000000000..f7a0a1e3b
--- /dev/null
+++ b/scripts/reloc.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# execute this after relocation of adk directory
+
+olddir=$(grep "^TOPDIR" prereq.mk |cut -d '=' -f 2)
+newdir=$(pwd)
+
+if [ "$olddir" != "$newdir" ];then
+ echo "adk directory relocated!"
+ echo "old directory: $olddir"
+ echo "new directory: $newdir"
+ sed -i -e "s#$olddir#$newdir#g" $(find target_* -name \*.pc|xargs)
+ sed -i -e "s#$olddir#$newdir#g" $(find target_* -name \*.la|xargs)
+ sed -i -e "s#$olddir#$newdir#g" $(find target_*/scripts -type f|xargs)
+ sed -i -e "s#$olddir#$newdir#" target_*/etc/ipkg.conf
+ sed -i -e "s#$olddir#$newdir#" prereq.mk
+fi
diff --git a/scripts/scan-pkgs.sh b/scripts/scan-pkgs.sh
index b08cafc95..a7b3cf492 100644
--- a/scripts/scan-pkgs.sh
+++ b/scripts/scan-pkgs.sh
@@ -85,11 +85,6 @@ if [[ -n $ADK_PACKAGE_XKEYBOARD_CONFIG ]]; then
NEED_INTL="$NEED_INTL xkeyboard-config"
fi
-if [[ -n $ADK_PACKAGE_GLIB ]]; then
- NEED_GLIBZWO="$NEED_GLIBZWO glib"
- NEED_GETTEXT="$NEED_GETTEXT glib"
-fi
-
if [[ -n $ADK_PACKAGE_LIBPCAP ]]; then
NEED_FLEX="$NEED_FLEX libpcap"
NEED_BISON="$NEED_BISON libpcap"
@@ -269,13 +264,6 @@ if [[ -n $NEED_XKBCOMP ]]; then
fi
fi
-if [[ -n $NEED_GLIBZWO ]]; then
- if ! which glib-genmarshal >/dev/null 2>&1; then
- echo >&2 You need libglib2.0-dev to build $NEED_GLIBZWO
- out=1
- fi
-fi
-
if [[ -n $NEED_RPM ]]; then
if ! which rpmbuild >/dev/null 2>&1; then
echo >&2 You need rpmbuild to to use $NEED_RPM package backend
diff --git a/target/Makefile b/target/Makefile
index 719817473..91d5b2bc1 100644
--- a/target/Makefile
+++ b/target/Makefile
@@ -32,6 +32,7 @@ all: install
# only if it does (so the timestamp stays intact)
# 8) remove the temporary .kernelconfig.tmp
###
+ifeq (${ADK_TARGET_KERNEL_CUSTOMISING},y)
config-prepare: $(TOPDIR)/.config
@sed -n '/^ADK_KPACKAGE_KMOD/s//CONFIG/p' ${TOPDIR}/.config | \
sed 's/=y/=m/' >${BUILD_DIR}/.kernelconfig.modules
@@ -39,8 +40,6 @@ config-prepare: $(TOPDIR)/.config
sed 's/=y/=m/' >>${BUILD_DIR}/.kernelconfig.modules
@sed -n '/^ADK_KERNEL/s//CONFIG/p' ${TOPDIR}/.config \
>${BUILD_DIR}/.kernelconfig.kernel
- @sed -n '/^ADK_MOD_KERNEL/s//CONFIG/p' ${TOPDIR}/.config | \
- sed 's/=y/=m/' >${BUILD_DIR}/.kernelconfig.modkernel
@sed -n '/^# ADK_KERNEL/s//# CONFIG/p' ${TOPDIR}/.config \
>${BUILD_DIR}/.kernelconfig.nokernel
ifeq ($(ADK_NATIVE),y)
@@ -71,11 +70,15 @@ ifeq ($(ADK_KERNEL_DEBUG_WITH_KGDB),y)
${BUILD_DIR}/.kernelconfig.board
endif
@cd ${BUILD_DIR} && cat .kernelconfig.board .kernelconfig.nokernel \
- .kernelconfig.kernel .kernelconfig.modkernel .kernelconfig.modules \
+ .kernelconfig.kernel .kernelconfig.modules \
>.kernelconfig.tmp
@cd ${BUILD_DIR} && cmp -s .kernelconfig.tmp .kernelconfig || \
cp .kernelconfig.tmp .kernelconfig
@-rm -f ${BUILD_DIR}/.kernelconfig.tmp
+else
+config-prepare: $(TOPDIR)/.config
+ @cp ${ADK_TARGET_ARCH}/kernel.config ${BUILD_DIR}/.kernelconfig
+endif
prepare: $(ADK_TARGET_ARCH)-prepare
compile: $(ADK_TARGET_ARCH)-compile
diff --git a/target/arm/Makefile b/target/arm/Makefile
index c2885e917..141d2c279 100644
--- a/target/arm/Makefile
+++ b/target/arm/Makefile
@@ -10,10 +10,7 @@ include $(TOPDIR)/mk/image.mk
KERNEL:=$(LINUX_DIR)/kernel-adk
LOADADDR:=0x20008000
-$(TOOLS_BUILD_DIR):
- @mkdir -p $(TOOLS_BUILD_DIR)
-
-tools-compile: $(TOOLS_BUILD_DIR)
+tools-compile:
$(MAKE) -C ../tools/uboot-mkimage
kernel-install: tools-compile
diff --git a/target/config/Config.in b/target/config/Config.in
index 47fde82ce..5e9f42073 100644
--- a/target/config/Config.in
+++ b/target/config/Config.in
@@ -89,6 +89,17 @@ config ADK_HARDWARE_QEMU
config ADK_NATIVE
boolean
+# the inverse of ADK_TARGET_KERNEL_CUSTOMISING,
+# allows for selecting it off (i.e., to disable it)
+config ADK_TARGET_FIXED_KERNEL
+ bool
+ default n
+
+config ADK_TARGET_KERNEL_CUSTOMISING
+ bool
+ default y
+ depends on !ADK_TARGET_FIXED_KERNEL
+
# cpu features
config ADK_TARGET_CPU_WITH_VT
boolean
diff --git a/target/config/Config.in.runtime b/target/config/Config.in.runtime
index aa9cfda6d..88bfee272 100644
--- a/target/config/Config.in.runtime
+++ b/target/config/Config.in.runtime
@@ -49,7 +49,7 @@ config ADK_RUNTIME_CONSOLE_SERIAL
Start getty on serial console. (ttyS0)
config ADK_RUNTIME_CONSOLE_BOTH
- bool "console output on console and serial"
+ bool "console output on VGA and serial"
help
Start getty on VGA console and serial device.
@@ -66,3 +66,77 @@ config ADK_RUNTIME_KBD_LAYOUT
depends on ADK_TARGET_WITH_INPUT
help
Predefine the keyboard layout for the embedded system.
+
+choice
+prompt "Initial login shell for the root user"
+default ADK_ROOTSH_ASH
+
+config ADK_ROOTSH_ASH
+ select BUSYBOX_ASH
+ bool "ash (busybox)"
+ help
+ Use the minimalistic ash variant that is part of busybox
+ as standard login shell for the superuser. This is the
+ default, but discouraged due to its frugality.
+
+config ADK_ROOTSH_BASH
+ select ADK_PACKAGE_BASH
+ bool "bash (GNU Bourne-Again Shell)"
+ help
+ Use GNU bash as standard login shell for the superuser.
+
+config ADK_ROOTSH_MKSH
+ select ADK_PACKAGE_MKSH
+ bool "mksh (MirBSD Korn Shell)"
+ help
+ Use mksh (a Korn Shell variant) as standard login shell
+ for the superuser.
+
+config ADK_ROOTSH_TCSH
+ select ADK_PACKAGE_TCSH
+ bool "tcsh (Tenex C Shell)"
+ help
+ Use tcsh (a C Shell variant) as standard login shell
+ for the superuser.
+
+config ADK_ROOTSH_ZSH
+ select ADK_PACKAGE_ZSH
+ bool "zsh (The Z Shell)"
+ help
+ Use zsh as standard login shell for the superuser.
+
+endchoice
+
+choice
+prompt "System /bin/sh (POSIX script shell)"
+default ADK_BINSH_ASH
+
+config ADK_BINSH_ASH
+ select BUSYBOX_ASH
+ bool "ash (busybox)"
+ help
+ Use the minimalistic ash variant that is part of busybox
+ as system shell. This is the default and rather small and
+ fast, but lacks scripting features.
+
+config ADK_BINSH_BASH
+ select ADK_PACKAGE_BASH
+ bool "bash (GNU Bourne-Again Shell)"
+ help
+ Use GNU bash as system shell. This is discouraged due to
+ its size and slowness.
+
+config ADK_BINSH_MKSH
+ select ADK_PACKAGE_MKSH
+ bool "mksh (MirBSD Korn Shell)"
+ help
+ Use mksh (a Korn Shell variant) as system shell, which is
+ both small and powerful, so quite suited for this task.
+
+config ADK_BINSH_ZSH
+ select ADK_PACKAGE_ZSH
+ bool "zsh (The Z Shell)"
+ help
+ Use zsh as system shell. This is probably a bad idea.
+
+endchoice
diff --git a/target/cris/Makefile b/target/cris/Makefile
index 1e072f78e..a0654575d 100644
--- a/target/cris/Makefile
+++ b/target/cris/Makefile
@@ -9,10 +9,7 @@ include $(TOPDIR)/mk/image.mk
KERNEL:=$(LINUX_DIR)/arch/cris/boot/zImage
-$(TOOLS_BUILD_DIR):
- @mkdir -p $(TOOLS_BUILD_DIR)
-
-tools-compile: $(TOOLS_BUILD_DIR)
+tools-compile:
$(MAKE) -C ../tools/mkfimage
ifneq ($(ADK_HOST_DARWIN),y)
$(MAKE) -C ../tools/e100boot prepare compile install
@@ -24,7 +21,7 @@ kernel-install: tools-compile
PATH='${TARGET_PATH}' mkfimage $(KERNEL) $(BUILD_DIR)/$(TARGET_KERNEL)
ifeq ($(ADK_TARGET_FS),squashfs)
-imageinstall: kernel-install $(BIN_DIR)/$(ROOTFSSQUASHFS)
+imageinstall: kernel-install $(BUILD_DIR)/$(ROOTFSSQUASHFS)
dd if=${BUILD_DIR}/${ROOTFSSQUASHFS} of=${BIN_DIR}/${ROOTFSSQUASHFS} \
bs=4063232 conv=sync $(MAKE_TRACE)
@if [ $$(stat --format=%s ${BIN_DIR}/${ROOTFSSQUASHFS}) -gt 4063232 ];then \
diff --git a/target/linux/config/Config.in.block b/target/linux/config/Config.in.block
index 59fad2d4a..1019477c1 100644
--- a/target/linux/config/Config.in.block
+++ b/target/linux/config/Config.in.block
@@ -120,6 +120,8 @@ config ADK_KERNEL_ATA_PIIX
select ADK_KERNEL_ATA_BMDMA
select ADK_KERNEL_BLK_DEV
select ADK_KERNEL_BLK_DEV_SD
+ default y if ADK_TARGET_SYSTEM_QEMU_MIPS64
+ default y if ADK_TARGET_SYSTEM_QEMU_MIPS64EL
default y if ADK_TARGET_SYSTEM_QEMU_MIPS
default y if ADK_TARGET_SYSTEM_QEMU_MIPSEL
default y if ADK_TARGET_SYSTEM_QEMU_X86
@@ -153,6 +155,8 @@ config ADK_KPACKAGE_KMOD_SATA_AHCI
config ADK_KPACKAGE_KMOD_BLK_DEV_LOOP
prompt "kmod-blk-dev-loop................. Loop mount support"
tristate
+ select ADK_KERNEL_BLOCK
+ select ADK_KERNEL_BLK_DEV
default n
help
Saying Y here will allow you to use a regular file as a block
diff --git a/target/linux/config/Config.in.fs b/target/linux/config/Config.in.fs
index 852d46c6a..f6da0d980 100644
--- a/target/linux/config/Config.in.fs
+++ b/target/linux/config/Config.in.fs
@@ -40,6 +40,7 @@ config ADK_KPACKAGE_KMOD_EXPORTFS
help
config ADK_KERNEL_SQUASHFS
+ prompt ".................................. SquashFS filesystem"
boolean
select ADK_KERNEL_MISC_FILESYSTEMS
default n
@@ -150,7 +151,7 @@ config ADK_KPACKAGE_KMOD_NTFS_FS
Kernel modules for NTFS support
config ADK_KPACKAGE_KMOD_VFAT_FS
- prompt "kmod-vfat-fs....................... VFAT filesystem support"
+ prompt "kmod-vfat-fs...................... VFAT filesystem support"
tristate
select ADK_KPACKAGE_KMOD_NLS if !ADK_KERNEL_NLS
select ADK_KPACKAGE_KMOD_NLS_CODEPAGE_850
diff --git a/target/linux/config/Config.in.input b/target/linux/config/Config.in.input
index 2241c0ed7..754cf7340 100644
--- a/target/linux/config/Config.in.input
+++ b/target/linux/config/Config.in.input
@@ -22,6 +22,13 @@ config ADK_KERNEL_KEYBOARD_ATKBD
default y if ADK_TARGET_SYSTEM_SHUTTLE_SA76G2
default n
+config ADK_KERNEL_INPUT_MOUSE
+ boolean
+ default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C
+ default y if ADK_TARGET_SYSTEM_IBM_X40
+ default y if ADK_TARGET_SYSTEM_SHUTTLE_SA76G2
+ default n
+
config ADK_KERNEL_INPUT_MOUSEDEV
boolean
default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C
diff --git a/target/linux/config/Config.in.leds b/target/linux/config/Config.in.leds
index 54cda3ceb..88acae81e 100644
--- a/target/linux/config/Config.in.leds
+++ b/target/linux/config/Config.in.leds
@@ -1,6 +1,10 @@
config ADK_KERNEL_NEW_LEDS
boolean
+config ADK_KERNEL_LEDS_CLASS
+ boolean
+ select ADK_KERNEL_NEW_LEDS
+
config ADK_KERNEL_LEDS_TRIGGERS
boolean
select ADK_KERNEL_NEW_LEDS
@@ -8,17 +12,27 @@ config ADK_KERNEL_LEDS_TRIGGERS
menu "LEDS driver support"
depends on ADK_TARGET_WITH_LEDS
-config ADK_KPACKAGE_KMOD_LEDS_CLASS
- prompt "LED Class support"
+config ADK_KPACKAGE_KMOD_LEDS_MIKROTIK_RB532
+ prompt "LED suppport for RB532"
tristate
- select ADK_KERNEL_NEW_LEDS
+ select ADK_KERNEL_LEDS_CLASS
+ depends on ADK_TARGET_SYSTEM_MIKROTIK_RB532
+ default y if ADK_TARGET_SYSTEM_MIKROTIK_RB532
+ default n
+
+config ADK_KPACKAGE_KMOD_LEDS_WRAP
+ prompt "LED suppport for WRAP"
+ tristate
+ select ADK_KERNEL_LEDS_CLASS
+ depends on ADK_TARGET_SYSTEM_PCENGINES_WRAP
+ default y if ADK_TARGET_SYSTEM_PCENGINES_WRAP
default n
- help
config ADK_KPACKAGE_KMOD_LEDS_ALIX2
prompt "LED suppport for ALIX2/ALIX3"
tristate
- select ADK_KPACKAGE_KMOD_LEDS_CLASS
+ select ADK_KERNEL_LEDS_CLASS
+ depends on ADK_TARGET_SYSTEM_PCENGINES_ALIX2D2 || ADK_TARGET_SYSTEM_PCENGINES_ALIX2D13
default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D2
default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D13
default n
@@ -27,24 +41,28 @@ config ADK_KPACKAGE_KMOD_LEDS_TRIGGER_TIMER
prompt "LED Timer trigger"
tristate
select ADK_KERNEL_LEDS_TRIGGERS
+ select ADK_KERNEL_LEDS_CLASS
default n
config ADK_KPACKAGE_KMOD_LEDS_TRIGGER_HEARTBEAT
prompt "LED Heartbeat trigger"
tristate
select ADK_KERNEL_LEDS_TRIGGERS
+ select ADK_KERNEL_LEDS_CLASS
default n
config ADK_KPACKAGE_KMOD_LEDS_TRIGGER_DEFAULT_ON
prompt "LED Default On trigger"
tristate
select ADK_KERNEL_LEDS_TRIGGERS
+ select ADK_KERNEL_LEDS_CLASS
default n
config ADK_KPACKAGE_KMOD_NETFILTER_XT_TARGET_LED
prompt "LED IPTables trigger"
tristate
select ADK_KERNEL_LEDS_TRIGGERS
+ select ADK_KERNEL_LEDS_CLASS
select ADK_PACKAGE_IPTABLES
default n
diff --git a/target/linux/config/Config.in.netdevice b/target/linux/config/Config.in.netdevice
index 40573a78f..ef12cbe0c 100644
--- a/target/linux/config/Config.in.netdevice
+++ b/target/linux/config/Config.in.netdevice
@@ -240,10 +240,10 @@ config ADK_KERNEL_RT2X00
select ADK_KPACKAGE_KMOD_FW_LOADER
select ADK_KPACKAGE_KMOD_EEPROM_93CX6
-config ADK_MOD_KERNEL_CFG80211
+config ADK_KERNEL_MOD_CFG80211
tristate
-config ADK_MOD_KERNEL_LIB80211
+config ADK_KERNEL_MOD_LIB80211
tristate
config ADK_KERNEL_CFG80211_WEXT
@@ -269,8 +269,8 @@ config ADK_KPACKAGE_KMOD_MAC80211
tristate
select ADK_KERNEL_WIRELESS
select ADK_KERNEL_WLAN_80211
- select ADK_MOD_KERNEL_CFG80211
- select ADK_MOD_KERNEL_LIB80211
+ select ADK_KERNEL_MOD_CFG80211
+ select ADK_KERNEL_MOD_LIB80211
select ADK_KPACKAGE_KMOD_CRYPTO_AES
select ADK_KPACKAGE_KMOD_CRYPTO_ECB
select ADK_KPACKAGE_KMOD_CRYPTO_ARC4
@@ -319,6 +319,7 @@ config ADK_KPACKAGE_KMOD_B43
tristate
select ADK_KPACKAGE_KMOD_FW_LOADER
depends on ADK_TARGET_WITH_SSB || ADK_TARGET_WITH_MINIPCI
+ default y if ADK_TARGET_SYSTEM_LINKSYS_WRT54G
default n
help
Driver for Broadcom B43xx wireless chips.
diff --git a/target/linux/config/Config.in.network b/target/linux/config/Config.in.network
index b7555bd12..1bbf681dc 100644
--- a/target/linux/config/Config.in.network
+++ b/target/linux/config/Config.in.network
@@ -24,6 +24,10 @@ config ADK_KERNEL_NET_IPGRE_BROADCAST
boolean
default n
+config ADK_KERNEL_NET_IPGRE_DEMUX
+ boolean
+ default n
+
config ADK_KERNEL_PPP_ASYNC
boolean
default n
@@ -134,11 +138,11 @@ config ADK_KPACKAGE_KMOD_NET_IPIP
mobile-IP facilities (allowing laptops to seamlessly move between
networks without changing their IP addresses).
-
config ADK_KPACKAGE_KMOD_NET_IPGRE
prompt "kmod-net-ipgre.................... GRE tunnels over IP"
tristate
- #depends on ADK_KPACKAGE_KMOD_NET_IPGRE_BROADCAST
+ select ADK_KERNEL_NET_IPGRE_BROADCAST
+ select ADK_KERNEL_NET_IPGRE_DEMUX
default n
help
Tunneling means encapsulating data of one protocol type within
diff --git a/target/linux/patches/2.6.36/aufs2.patch b/target/linux/patches/2.6.36/aufs2.patch
new file mode 100644
index 000000000..e9e5fc277
--- /dev/null
+++ b/target/linux/patches/2.6.36/aufs2.patch
@@ -0,0 +1,33532 @@
+diff -Nur linux-2.6.36.orig/fs/Kconfig linux-2.6.36/fs/Kconfig
+--- linux-2.6.36.orig/fs/Kconfig 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/fs/Kconfig 2011-01-10 19:52:38.000000000 +0100
+@@ -189,6 +189,7 @@
+ source "fs/sysv/Kconfig"
+ source "fs/ufs/Kconfig"
+ source "fs/exofs/Kconfig"
++source "fs/aufs/Kconfig"
+
+ endif # MISC_FILESYSTEMS
+
+diff -Nur linux-2.6.36.orig/fs/Makefile linux-2.6.36/fs/Makefile
+--- linux-2.6.36.orig/fs/Makefile 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/fs/Makefile 2011-01-10 19:52:38.000000000 +0100
+@@ -126,3 +126,4 @@
+ obj-$(CONFIG_GFS2_FS) += gfs2/
+ obj-$(CONFIG_EXOFS_FS) += exofs/
+ obj-$(CONFIG_CEPH_FS) += ceph/
++obj-$(CONFIG_AUFS_FS) += aufs/
+diff -Nur linux-2.6.36.orig/fs/aufs/Kconfig linux-2.6.36/fs/aufs/Kconfig
+--- linux-2.6.36.orig/fs/aufs/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/Kconfig 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,180 @@
++config AUFS_FS
++ tristate "Aufs (Advanced multi layered unification filesystem) support"
++ depends on EXPERIMENTAL
++ help
++ Aufs is a stackable unification filesystem such as Unionfs,
++ which unifies several directories and provides a merged single
++ directory.
++ In the early days, aufs was entirely re-designed and
++ re-implemented Unionfs Version 1.x series. Introducing many
++ original ideas, approaches and improvements, it becomes totally
++ different from Unionfs while keeping the basic features.
++
++if AUFS_FS
++choice
++ prompt "Maximum number of branches"
++ default AUFS_BRANCH_MAX_127
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_127
++ bool "127"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_511
++ bool "511"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_1023
++ bool "1023"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_32767
++ bool "32767"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++endchoice
++
++config AUFS_SBILIST
++ bool
++ depends on AUFS_MAGIC_SYSRQ || PROC_FS
++ default y
++ help
++ Automatic configuration for internal use.
++ When aufs supports Magic SysRq or /proc, enabled automatically.
++
++config AUFS_HNOTIFY
++ bool "Detect direct branch access (bypassing aufs)"
++ help
++ If you want to modify files on branches directly, eg. bypassing aufs,
++ and want aufs to detect the changes of them fully, then enable this
++ option and use 'udba=notify' mount option.
++ Currently there is only one available configuration, "fsnotify".
++ It will have a negative impact to the performance.
++ See detail in aufs.5.
++
++choice
++ prompt "method" if AUFS_HNOTIFY
++ default AUFS_HFSNOTIFY
++config AUFS_HFSNOTIFY
++ bool "fsnotify"
++ select FSNOTIFY
++endchoice
++
++config AUFS_EXPORT
++ bool "NFS-exportable aufs"
++ depends on (AUFS_FS = y && EXPORTFS = y) || (AUFS_FS = m && EXPORTFS)
++ help
++ If you want to export your mounted aufs via NFS, then enable this
++ option. There are several requirements for this configuration.
++ See detail in aufs.5.
++
++config AUFS_INO_T_64
++ bool
++ depends on AUFS_EXPORT
++ depends on 64BIT && !(ALPHA || S390)
++ default y
++ help
++ Automatic configuration for internal use.
++ /* typedef unsigned long/int __kernel_ino_t */
++ /* alpha and s390x are int */
++
++config AUFS_RDU
++ bool "Readdir in userspace"
++ help
++ Aufs has two methods to provide a merged view for a directory,
++ by a user-space library and by kernel-space natively. The latter
++ is always enabled but sometimes large and slow.
++ If you enable this option, install the library in aufs2-util
++ package, and set some environment variables for your readdir(3),
++ then the work will be handled in user-space which generally
++ shows better performance in most cases.
++ See detail in aufs.5.
++
++config AUFS_SP_IATTR
++ bool "Respect the attributes (mtime/ctime mainly) of special files"
++ help
++ When you write something to a special file, some attributes of it
++ (mtime/ctime mainly) may be updated. Generally such updates are
++ less important (actually some device drivers and NFS ignore
++ it). But some applications (such like test program) requires
++ such updates. If you need these updates, then enable this
++ configuration which introduces some overhead.
++ Currently this configuration handles FIFO only.
++
++config AUFS_SHWH
++ bool "Show whiteouts"
++ help
++ If you want to make the whiteouts in aufs visible, then enable
++ this option and specify 'shwh' mount option. Although it may
++ sounds like philosophy or something, but in technically it
++ simply shows the name of whiteout with keeping its behaviour.
++
++config AUFS_BR_RAMFS
++ bool "Ramfs (initramfs/rootfs) as an aufs branch"
++ help
++ If you want to use ramfs as an aufs branch fs, then enable this
++ option. Generally tmpfs is recommended.
++ Aufs prohibited them to be a branch fs by default, because
++ initramfs becomes unusable after switch_root or something
++ generally. If you sets initramfs as an aufs branch and boot your
++ system by switch_root, you will meet a problem easily since the
++ files in initramfs may be inaccessible.
++ Unless you are going to use ramfs as an aufs branch fs without
++ switch_root or something, leave it N.
++
++config AUFS_BR_FUSE
++ bool "Fuse fs as an aufs branch"
++ depends on FUSE_FS
++ select AUFS_POLL
++ help
++ If you want to use fuse-based userspace filesystem as an aufs
++ branch fs, then enable this option.
++ It implements the internal poll(2) operation which is
++ implemented by fuse only (curretnly).
++
++config AUFS_POLL
++ bool
++ help
++ Automatic configuration for internal use.
++
++config AUFS_BR_HFSPLUS
++ bool "Hfsplus as an aufs branch"
++ depends on HFSPLUS_FS
++ default y
++ help
++ If you want to use hfsplus fs as an aufs branch fs, then enable
++ this option. This option introduces a small overhead at
++ copying-up a file on hfsplus.
++
++config AUFS_BDEV_LOOP
++ bool
++ depends on BLK_DEV_LOOP
++ default y
++ help
++ Automatic configuration for internal use.
++ Convert =[ym] into =y.
++
++config AUFS_DEBUG
++ bool "Debug aufs"
++ help
++ Enable this to compile aufs internal debug code.
++ It will have a negative impact to the performance.
++
++config AUFS_MAGIC_SYSRQ
++ bool
++ depends on AUFS_DEBUG && MAGIC_SYSRQ
++ default y
++ help
++ Automatic configuration for internal use.
++ When aufs supports Magic SysRq, enabled automatically.
++endif
+diff -Nur linux-2.6.36.orig/fs/aufs/Makefile linux-2.6.36/fs/aufs/Makefile
+--- linux-2.6.36.orig/fs/aufs/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/Makefile 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,38 @@
++
++include ${src}/magic.mk
++ifeq (${CONFIG_AUFS_FS},m)
++include ${src}/conf.mk
++endif
++-include ${src}/priv_def.mk
++
++# cf. include/linux/kernel.h
++# enable pr_debug
++ccflags-y += -DDEBUG
++# sparse doesn't allow spaces
++ccflags-y += -D'pr_fmt(fmt)=AUFS_NAME"\040%s:%d:%s[%d]:\040"fmt,__func__,__LINE__,current->comm,current->pid'
++
++obj-$(CONFIG_AUFS_FS) += aufs.o
++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \
++ wkq.o vfsub.o dcsub.o \
++ cpup.o whout.o wbr_policy.o \
++ dinfo.o dentry.o \
++ dynop.o \
++ finfo.o file.o f_op.o \
++ dir.o vdir.o \
++ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \
++ ioctl.o
++
++# all are boolean
++aufs-$(CONFIG_PROC_FS) += procfs.o plink.o
++aufs-$(CONFIG_SYSFS) += sysfs.o
++aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o
++aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o
++aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o
++aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o
++aufs-$(CONFIG_AUFS_EXPORT) += export.o
++aufs-$(CONFIG_AUFS_POLL) += poll.o
++aufs-$(CONFIG_AUFS_RDU) += rdu.o
++aufs-$(CONFIG_AUFS_SP_IATTR) += f_op_sp.o
++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o
++aufs-$(CONFIG_AUFS_DEBUG) += debug.o
++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o
+diff -Nur linux-2.6.36.orig/fs/aufs/aufs.h linux-2.6.36/fs/aufs/aufs.h
+--- linux-2.6.36.orig/fs/aufs/aufs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/aufs.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * all header files
++ */
++
++#ifndef __AUFS_H__
++#define __AUFS_H__
++
++#ifdef __KERNEL__
++
++#define AuStub(type, name, body, ...) \
++ static inline type name(__VA_ARGS__) { body; }
++
++#define AuStubVoid(name, ...) \
++ AuStub(void, name, , __VA_ARGS__)
++#define AuStubInt0(name, ...) \
++ AuStub(int, name, return 0, __VA_ARGS__)
++
++#include "debug.h"
++
++#include "branch.h"
++#include "cpup.h"
++#include "dcsub.h"
++#include "dbgaufs.h"
++#include "dentry.h"
++#include "dir.h"
++#include "dynop.h"
++#include "file.h"
++#include "fstype.h"
++#include "inode.h"
++#include "loop.h"
++#include "module.h"
++/* never include ./mtx.h */
++#include "opts.h"
++#include "rwsem.h"
++#include "spl.h"
++#include "super.h"
++#include "sysaufs.h"
++#include "vfsub.h"
++#include "whout.h"
++#include "wkq.h"
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/branch.c linux-2.6.36/fs/aufs/branch.c
+--- linux-2.6.36.orig/fs/aufs/branch.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/branch.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,1071 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * branch management
++ */
++
++#include <linux/file.h>
++#include <linux/statfs.h>
++#include "aufs.h"
++
++/*
++ * free a single branch
++ */
++static void au_br_do_free(struct au_branch *br)
++{
++ int i;
++ struct au_wbr *wbr;
++ struct au_dykey **key;
++
++ au_hnotify_fin_br(br);
++
++ if (br->br_xino.xi_file)
++ fput(br->br_xino.xi_file);
++ mutex_destroy(&br->br_xino.xi_nondir_mtx);
++
++ AuDebugOn(atomic_read(&br->br_count));
++
++ wbr = br->br_wbr;
++ if (wbr) {
++ for (i = 0; i < AuBrWh_Last; i++)
++ dput(wbr->wbr_wh[i]);
++ AuDebugOn(atomic_read(&wbr->wbr_wh_running));
++ AuRwDestroy(&wbr->wbr_wh_rwsem);
++ }
++
++ key = br->br_dykey;
++ for (i = 0; i < AuBrDynOp; i++, key++)
++ if (*key)
++ au_dy_put(*key);
++ else
++ break;
++
++ mntput(br->br_mnt);
++ kfree(wbr);
++ kfree(br);
++}
++
++/*
++ * frees all branches
++ */
++void au_br_free(struct au_sbinfo *sbinfo)
++{
++ aufs_bindex_t bmax;
++ struct au_branch **br;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ bmax = sbinfo->si_bend + 1;
++ br = sbinfo->si_branch;
++ while (bmax--)
++ au_br_do_free(*br++);
++}
++
++/*
++ * find the index of a branch which is specified by @br_id.
++ */
++int au_br_index(struct super_block *sb, aufs_bindex_t br_id)
++{
++ aufs_bindex_t bindex, bend;
++
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++)
++ if (au_sbr_id(sb, bindex) == br_id)
++ return bindex;
++ return -1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * add a branch
++ */
++
++static int test_overlap(struct super_block *sb, struct dentry *h_adding,
++ struct dentry *h_root)
++{
++ if (unlikely(h_adding == h_root
++ || au_test_loopback_overlap(sb, h_adding)))
++ return 1;
++ if (h_adding->d_sb != h_root->d_sb)
++ return 0;
++ return au_test_subdir(h_adding, h_root)
++ || au_test_subdir(h_root, h_adding);
++}
++
++/*
++ * returns a newly allocated branch. @new_nbranch is a number of branches
++ * after adding a branch.
++ */
++static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
++ int perm)
++{
++ struct au_branch *add_branch;
++ struct dentry *root;
++ int err;
++
++ err = -ENOMEM;
++ root = sb->s_root;
++ add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS);
++ if (unlikely(!add_branch))
++ goto out;
++
++ err = au_hnotify_init_br(add_branch, perm);
++ if (unlikely(err))
++ goto out_br;
++
++ add_branch->br_wbr = NULL;
++ if (au_br_writable(perm)) {
++ /* may be freed separately at changing the branch permission */
++ add_branch->br_wbr = kmalloc(sizeof(*add_branch->br_wbr),
++ GFP_NOFS);
++ if (unlikely(!add_branch->br_wbr))
++ goto out_hnotify;
++ }
++
++ err = au_sbr_realloc(au_sbi(sb), new_nbranch);
++ if (!err)
++ err = au_di_realloc(au_di(root), new_nbranch);
++ if (!err)
++ err = au_ii_realloc(au_ii(root->d_inode), new_nbranch);
++ if (!err)
++ return add_branch; /* success */
++
++ kfree(add_branch->br_wbr);
++
++out_hnotify:
++ au_hnotify_fin_br(add_branch);
++out_br:
++ kfree(add_branch);
++out:
++ return ERR_PTR(err);
++}
++
++/*
++ * test if the branch permission is legal or not.
++ */
++static int test_br(struct inode *inode, int brperm, char *path)
++{
++ int err;
++
++ err = (au_br_writable(brperm) && IS_RDONLY(inode));
++ if (!err)
++ goto out;
++
++ err = -EINVAL;
++ pr_err("write permission for readonly mount or inode, %s\n", path);
++
++out:
++ return err;
++}
++
++/*
++ * returns:
++ * 0: success, the caller will add it
++ * plus: success, it is already unified, the caller should ignore it
++ * minus: error
++ */
++static int test_add(struct super_block *sb, struct au_opt_add *add, int remount)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct dentry *root;
++ struct inode *inode, *h_inode;
++
++ root = sb->s_root;
++ bend = au_sbend(sb);
++ if (unlikely(bend >= 0
++ && au_find_dbindex(root, add->path.dentry) >= 0)) {
++ err = 1;
++ if (!remount) {
++ err = -EINVAL;
++ pr_err("%s duplicated\n", add->pathname);
++ }
++ goto out;
++ }
++
++ err = -ENOSPC; /* -E2BIG; */
++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex
++ || AUFS_BRANCH_MAX - 1 <= bend)) {
++ pr_err("number of branches exceeded %s\n", add->pathname);
++ goto out;
++ }
++
++ err = -EDOM;
++ if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) {
++ pr_err("bad index %d\n", add->bindex);
++ goto out;
++ }
++
++ inode = add->path.dentry->d_inode;
++ err = -ENOENT;
++ if (unlikely(!inode->i_nlink)) {
++ pr_err("no existence %s\n", add->pathname);
++ goto out;
++ }
++
++ err = -EINVAL;
++ if (unlikely(inode->i_sb == sb)) {
++ pr_err("%s must be outside\n", add->pathname);
++ goto out;
++ }
++
++ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) {
++ pr_err("unsupported filesystem, %s (%s)\n",
++ add->pathname, au_sbtype(inode->i_sb));
++ goto out;
++ }
++
++ err = test_br(add->path.dentry->d_inode, add->perm, add->pathname);
++ if (unlikely(err))
++ goto out;
++
++ if (bend < 0)
++ return 0; /* success */
++
++ err = -EINVAL;
++ for (bindex = 0; bindex <= bend; bindex++)
++ if (unlikely(test_overlap(sb, add->path.dentry,
++ au_h_dptr(root, bindex)))) {
++ pr_err("%s is overlapped\n", add->pathname);
++ goto out;
++ }
++
++ err = 0;
++ if (au_opt_test(au_mntflags(sb), WARN_PERM)) {
++ h_inode = au_h_dptr(root, 0)->d_inode;
++ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO)
++ || h_inode->i_uid != inode->i_uid
++ || h_inode->i_gid != inode->i_gid)
++ pr_warning("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n",
++ add->pathname,
++ inode->i_uid, inode->i_gid,
++ (inode->i_mode & S_IALLUGO),
++ h_inode->i_uid, h_inode->i_gid,
++ (h_inode->i_mode & S_IALLUGO));
++ }
++
++out:
++ return err;
++}
++
++/*
++ * initialize or clean the whiteouts for an adding branch
++ */
++static int au_br_init_wh(struct super_block *sb, struct au_branch *br,
++ int new_perm, struct dentry *h_root)
++{
++ int err, old_perm;
++ aufs_bindex_t bindex;
++ struct mutex *h_mtx;
++ struct au_wbr *wbr;
++ struct au_hinode *hdir;
++
++ wbr = br->br_wbr;
++ old_perm = br->br_perm;
++ br->br_perm = new_perm;
++ hdir = NULL;
++ h_mtx = NULL;
++ bindex = au_br_index(sb, br->br_id);
++ if (0 <= bindex) {
++ hdir = au_hi(sb->s_root->d_inode, bindex);
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ } else {
++ h_mtx = &h_root->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_PARENT);
++ }
++ if (!wbr)
++ err = au_wh_init(h_root, br, sb);
++ else {
++ wbr_wh_write_lock(wbr);
++ err = au_wh_init(h_root, br, sb);
++ wbr_wh_write_unlock(wbr);
++ }
++ if (hdir)
++ au_hn_imtx_unlock(hdir);
++ else
++ mutex_unlock(h_mtx);
++ br->br_perm = old_perm;
++
++ if (!err && wbr && !au_br_writable(new_perm)) {
++ kfree(wbr);
++ br->br_wbr = NULL;
++ }
++
++ return err;
++}
++
++static int au_wbr_init(struct au_branch *br, struct super_block *sb,
++ int perm, struct path *path)
++{
++ int err;
++ struct kstatfs kst;
++ struct au_wbr *wbr;
++ struct dentry *h_dentry;
++
++ wbr = br->br_wbr;
++ au_rw_init(&wbr->wbr_wh_rwsem);
++ memset(wbr->wbr_wh, 0, sizeof(wbr->wbr_wh));
++ atomic_set(&wbr->wbr_wh_running, 0);
++ wbr->wbr_bytes = 0;
++
++ /*
++ * a limit for rmdir/rename a dir
++ * cf. AUFS_MAX_NAMELEN in include/linux/aufs_type.h
++ */
++ err = vfs_statfs(path, &kst);
++ if (unlikely(err))
++ goto out;
++ err = -EINVAL;
++ h_dentry = path->dentry;
++ if (kst.f_namelen >= NAME_MAX)
++ err = au_br_init_wh(sb, br, perm, h_dentry);
++ else
++ pr_err("%.*s(%s), unsupported namelen %ld\n",
++ AuDLNPair(h_dentry), au_sbtype(h_dentry->d_sb),
++ kst.f_namelen);
++
++out:
++ return err;
++}
++
++/* intialize a new branch */
++static int au_br_init(struct au_branch *br, struct super_block *sb,
++ struct au_opt_add *add)
++{
++ int err;
++
++ err = 0;
++ memset(&br->br_xino, 0, sizeof(br->br_xino));
++ mutex_init(&br->br_xino.xi_nondir_mtx);
++ br->br_perm = add->perm;
++ br->br_mnt = add->path.mnt; /* set first, mntget() later */
++ spin_lock_init(&br->br_dykey_lock);
++ memset(br->br_dykey, 0, sizeof(br->br_dykey));
++ atomic_set(&br->br_count, 0);
++ br->br_xino_upper = AUFS_XINO_TRUNC_INIT;
++ atomic_set(&br->br_xino_running, 0);
++ br->br_id = au_new_br_id(sb);
++ AuDebugOn(br->br_id < 0);
++
++ if (au_br_writable(add->perm)) {
++ err = au_wbr_init(br, sb, add->perm, &add->path);
++ if (unlikely(err))
++ goto out_err;
++ }
++
++ if (au_opt_test(au_mntflags(sb), XINO)) {
++ err = au_xino_br(sb, br, add->path.dentry->d_inode->i_ino,
++ au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1);
++ if (unlikely(err)) {
++ AuDebugOn(br->br_xino.xi_file);
++ goto out_err;
++ }
++ }
++
++ sysaufs_br_init(br);
++ mntget(add->path.mnt);
++ goto out; /* success */
++
++out_err:
++ br->br_mnt = NULL;
++out:
++ return err;
++}
++
++static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex,
++ struct au_branch *br, aufs_bindex_t bend,
++ aufs_bindex_t amount)
++{
++ struct au_branch **brp;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ brp = sbinfo->si_branch + bindex;
++ memmove(brp + 1, brp, sizeof(*brp) * amount);
++ *brp = br;
++ sbinfo->si_bend++;
++ if (unlikely(bend < 0))
++ sbinfo->si_bend = 0;
++}
++
++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex,
++ aufs_bindex_t bend, aufs_bindex_t amount)
++{
++ struct au_hdentry *hdp;
++
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ hdp = dinfo->di_hdentry + bindex;
++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount);
++ au_h_dentry_init(hdp);
++ dinfo->di_bend++;
++ if (unlikely(bend < 0))
++ dinfo->di_bstart = 0;
++}
++
++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex,
++ aufs_bindex_t bend, aufs_bindex_t amount)
++{
++ struct au_hinode *hip;
++
++ AuRwMustWriteLock(&iinfo->ii_rwsem);
++
++ hip = iinfo->ii_hinode + bindex;
++ memmove(hip + 1, hip, sizeof(*hip) * amount);
++ hip->hi_inode = NULL;
++ au_hn_init(hip);
++ iinfo->ii_bend++;
++ if (unlikely(bend < 0))
++ iinfo->ii_bstart = 0;
++}
++
++static void au_br_do_add(struct super_block *sb, struct dentry *h_dentry,
++ struct au_branch *br, aufs_bindex_t bindex)
++{
++ struct dentry *root;
++ struct inode *root_inode;
++ aufs_bindex_t bend, amount;
++
++ root = sb->s_root;
++ root_inode = root->d_inode;
++ bend = au_sbend(sb);
++ amount = bend + 1 - bindex;
++ au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount);
++ au_br_do_add_hdp(au_di(root), bindex, bend, amount);
++ au_br_do_add_hip(au_ii(root_inode), bindex, bend, amount);
++ au_set_h_dptr(root, bindex, dget(h_dentry));
++ au_set_h_iptr(root_inode, bindex, au_igrab(h_dentry->d_inode),
++ /*flags*/0);
++}
++
++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount)
++{
++ int err;
++ aufs_bindex_t bend, add_bindex;
++ struct dentry *root, *h_dentry;
++ struct inode *root_inode;
++ struct au_branch *add_branch;
++
++ root = sb->s_root;
++ root_inode = root->d_inode;
++ IMustLock(root_inode);
++ err = test_add(sb, add, remount);
++ if (unlikely(err < 0))
++ goto out;
++ if (err) {
++ err = 0;
++ goto out; /* success */
++ }
++
++ bend = au_sbend(sb);
++ add_branch = au_br_alloc(sb, bend + 2, add->perm);
++ err = PTR_ERR(add_branch);
++ if (IS_ERR(add_branch))
++ goto out;
++
++ err = au_br_init(add_branch, sb, add);
++ if (unlikely(err)) {
++ au_br_do_free(add_branch);
++ goto out;
++ }
++
++ add_bindex = add->bindex;
++ h_dentry = add->path.dentry;
++ if (!remount)
++ au_br_do_add(sb, h_dentry, add_branch, add_bindex);
++ else {
++ sysaufs_brs_del(sb, add_bindex);
++ au_br_do_add(sb, h_dentry, add_branch, add_bindex);
++ sysaufs_brs_add(sb, add_bindex);
++ }
++
++ if (!add_bindex) {
++ au_cpup_attr_all(root_inode, /*force*/1);
++ sb->s_maxbytes = h_dentry->d_sb->s_maxbytes;
++ } else
++ au_add_nlink(root_inode, h_dentry->d_inode);
++
++ /*
++ * this test/set prevents aufs from handling unnecesary notify events
++ * of xino files, in a case of re-adding a writable branch which was
++ * once detached from aufs.
++ */
++ if (au_xino_brid(sb) < 0
++ && au_br_writable(add_branch->br_perm)
++ && !au_test_fs_bad_xino(h_dentry->d_sb)
++ && add_branch->br_xino.xi_file
++ && add_branch->br_xino.xi_file->f_dentry->d_parent == h_dentry)
++ au_xino_brid_set(sb, add_branch->br_id);
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * delete a branch
++ */
++
++/* to show the line number, do not make it inlined function */
++#define AuVerbose(do_info, fmt, ...) do { \
++ if (do_info) \
++ pr_info(fmt, ##__VA_ARGS__); \
++} while (0)
++
++/*
++ * test if the branch is deletable or not.
++ */
++static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
++ unsigned int sigen, const unsigned int verbose)
++{
++ int err, i, j, ndentry;
++ aufs_bindex_t bstart, bend;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry *d;
++ struct inode *inode;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_dcsub_pages(&dpages, root, NULL, NULL);
++ if (unlikely(err))
++ goto out_dpages;
++
++ for (i = 0; !err && i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ ndentry = dpage->ndentry;
++ for (j = 0; !err && j < ndentry; j++) {
++ d = dpage->dentries[j];
++ AuDebugOn(!atomic_read(&d->d_count));
++ if (!au_digen_test(d, sigen)) {
++ di_read_lock_child(d, AuLock_IR);
++ if (unlikely(au_dbrange_test(d))) {
++ di_read_unlock(d, AuLock_IR);
++ continue;
++ }
++ } else {
++ di_write_lock_child(d);
++ if (unlikely(au_dbrange_test(d))) {
++ di_write_unlock(d);
++ continue;
++ }
++ err = au_reval_dpath(d, sigen);
++ if (!err)
++ di_downgrade_lock(d, AuLock_IR);
++ else {
++ di_write_unlock(d);
++ break;
++ }
++ }
++
++ /* AuDbgDentry(d); */
++ inode = d->d_inode;
++ bstart = au_dbstart(d);
++ bend = au_dbend(d);
++ if (bstart <= bindex
++ && bindex <= bend
++ && au_h_dptr(d, bindex)
++ && ((inode && !S_ISDIR(inode->i_mode))
++ || bstart == bend)) {
++ err = -EBUSY;
++ AuVerbose(verbose, "busy %.*s\n", AuDLNPair(d));
++ AuDbgDentry(d);
++ }
++ di_read_unlock(d, AuLock_IR);
++ }
++ }
++
++out_dpages:
++ au_dpages_free(&dpages);
++out:
++ return err;
++}
++
++static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex,
++ unsigned int sigen, const unsigned int verbose)
++{
++ int err;
++ unsigned long long max, ull;
++ struct inode *i, **array;
++ aufs_bindex_t bstart, bend;
++
++ array = au_iarray_alloc(sb, &max);
++ err = PTR_ERR(array);
++ if (IS_ERR(array))
++ goto out;
++
++ err = 0;
++ AuDbg("b%d\n", bindex);
++ for (ull = 0; !err && ull < max; ull++) {
++ i = array[ull];
++ if (i->i_ino == AUFS_ROOT_INO)
++ continue;
++
++ /* AuDbgInode(i); */
++ if (au_iigen(i) == sigen)
++ ii_read_lock_child(i);
++ else {
++ ii_write_lock_child(i);
++ err = au_refresh_hinode_self(i);
++ au_iigen_dec(i);
++ if (!err)
++ ii_downgrade_lock(i);
++ else {
++ ii_write_unlock(i);
++ break;
++ }
++ }
++
++ bstart = au_ibstart(i);
++ bend = au_ibend(i);
++ if (bstart <= bindex
++ && bindex <= bend
++ && au_h_iptr(i, bindex)
++ && (!S_ISDIR(i->i_mode) || bstart == bend)) {
++ err = -EBUSY;
++ AuVerbose(verbose, "busy i%lu\n", i->i_ino);
++ AuDbgInode(i);
++ }
++ ii_read_unlock(i);
++ }
++ au_iarray_free(array, max);
++
++out:
++ return err;
++}
++
++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex,
++ const unsigned int verbose)
++{
++ int err;
++ unsigned int sigen;
++
++ sigen = au_sigen(root->d_sb);
++ DiMustNoWaiters(root);
++ IiMustNoWaiters(root->d_inode);
++ di_write_unlock(root);
++ err = test_dentry_busy(root, bindex, sigen, verbose);
++ if (!err)
++ err = test_inode_busy(root->d_sb, bindex, sigen, verbose);
++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */
++
++ return err;
++}
++
++static void au_br_do_del_brp(struct au_sbinfo *sbinfo,
++ const aufs_bindex_t bindex,
++ const aufs_bindex_t bend)
++{
++ struct au_branch **brp, **p;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ brp = sbinfo->si_branch + bindex;
++ if (bindex < bend)
++ memmove(brp, brp + 1, sizeof(*brp) * (bend - bindex));
++ sbinfo->si_branch[0 + bend] = NULL;
++ sbinfo->si_bend--;
++
++ p = krealloc(sbinfo->si_branch, sizeof(*p) * bend, GFP_NOFS);
++ if (p)
++ sbinfo->si_branch = p;
++ /* harmless error */
++}
++
++static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex,
++ const aufs_bindex_t bend)
++{
++ struct au_hdentry *hdp, *p;
++
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ hdp = dinfo->di_hdentry;
++ if (bindex < bend)
++ memmove(hdp + bindex, hdp + bindex + 1,
++ sizeof(*hdp) * (bend - bindex));
++ hdp[0 + bend].hd_dentry = NULL;
++ dinfo->di_bend--;
++
++ p = krealloc(hdp, sizeof(*p) * bend, GFP_NOFS);
++ if (p)
++ dinfo->di_hdentry = p;
++ /* harmless error */
++}
++
++static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex,
++ const aufs_bindex_t bend)
++{
++ struct au_hinode *hip, *p;
++
++ AuRwMustWriteLock(&iinfo->ii_rwsem);
++
++ hip = iinfo->ii_hinode + bindex;
++ if (bindex < bend)
++ memmove(hip, hip + 1, sizeof(*hip) * (bend - bindex));
++ iinfo->ii_hinode[0 + bend].hi_inode = NULL;
++ au_hn_init(iinfo->ii_hinode + bend);
++ iinfo->ii_bend--;
++
++ p = krealloc(iinfo->ii_hinode, sizeof(*p) * bend, GFP_NOFS);
++ if (p)
++ iinfo->ii_hinode = p;
++ /* harmless error */
++}
++
++static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex,
++ struct au_branch *br)
++{
++ aufs_bindex_t bend;
++ struct au_sbinfo *sbinfo;
++ struct dentry *root;
++ struct inode *inode;
++
++ SiMustWriteLock(sb);
++
++ root = sb->s_root;
++ inode = root->d_inode;
++ sbinfo = au_sbi(sb);
++ bend = sbinfo->si_bend;
++
++ dput(au_h_dptr(root, bindex));
++ au_hiput(au_hi(inode, bindex));
++ au_br_do_free(br);
++
++ au_br_do_del_brp(sbinfo, bindex, bend);
++ au_br_do_del_hdp(au_di(root), bindex, bend);
++ au_br_do_del_hip(au_ii(inode), bindex, bend);
++}
++
++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
++{
++ int err, rerr, i;
++ unsigned int mnt_flags;
++ aufs_bindex_t bindex, bend, br_id;
++ unsigned char do_wh, verbose;
++ struct au_branch *br;
++ struct au_wbr *wbr;
++
++ err = 0;
++ bindex = au_find_dbindex(sb->s_root, del->h_path.dentry);
++ if (bindex < 0) {
++ if (remount)
++ goto out; /* success */
++ err = -ENOENT;
++ pr_err("%s no such branch\n", del->pathname);
++ goto out;
++ }
++ AuDbg("bindex b%d\n", bindex);
++
++ err = -EBUSY;
++ mnt_flags = au_mntflags(sb);
++ verbose = !!au_opt_test(mnt_flags, VERBOSE);
++ bend = au_sbend(sb);
++ if (unlikely(!bend)) {
++ AuVerbose(verbose, "no more branches left\n");
++ goto out;
++ }
++ br = au_sbr(sb, bindex);
++ i = atomic_read(&br->br_count);
++ if (unlikely(i)) {
++ AuVerbose(verbose, "%d file(s) opened\n", i);
++ goto out;
++ }
++
++ wbr = br->br_wbr;
++ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph);
++ if (do_wh) {
++ /* instead of WbrWhMustWriteLock(wbr) */
++ SiMustWriteLock(sb);
++ for (i = 0; i < AuBrWh_Last; i++) {
++ dput(wbr->wbr_wh[i]);
++ wbr->wbr_wh[i] = NULL;
++ }
++ }
++
++ err = test_children_busy(sb->s_root, bindex, verbose);
++ if (unlikely(err)) {
++ if (do_wh)
++ goto out_wh;
++ goto out;
++ }
++
++ err = 0;
++ br_id = br->br_id;
++ if (!remount)
++ au_br_do_del(sb, bindex, br);
++ else {
++ sysaufs_brs_del(sb, bindex);
++ au_br_do_del(sb, bindex, br);
++ sysaufs_brs_add(sb, bindex);
++ }
++
++ if (!bindex) {
++ au_cpup_attr_all(sb->s_root->d_inode, /*force*/1);
++ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes;
++ } else
++ au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode);
++ if (au_opt_test(mnt_flags, PLINK))
++ au_plink_half_refresh(sb, br_id);
++
++ if (au_xino_brid(sb) == br_id)
++ au_xino_brid_set(sb, -1);
++ goto out; /* success */
++
++out_wh:
++ /* revert */
++ rerr = au_br_init_wh(sb, br, br->br_perm, del->h_path.dentry);
++ if (rerr)
++ pr_warning("failed re-creating base whiteout, %s. (%d)\n",
++ del->pathname, rerr);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * change a branch permission
++ */
++
++static void au_warn_ima(void)
++{
++#ifdef CONFIG_IMA
++ /* since it doesn't support mark_files_ro() */
++ AuWarn1("RW -> RO makes IMA to produce wrong message\n");
++#endif
++}
++
++static int do_need_sigen_inc(int a, int b)
++{
++ return au_br_whable(a) && !au_br_whable(b);
++}
++
++static int need_sigen_inc(int old, int new)
++{
++ return do_need_sigen_inc(old, new)
++ || do_need_sigen_inc(new, old);
++}
++
++static unsigned long long au_farray_cb(void *a,
++ unsigned long long max __maybe_unused,
++ void *arg)
++{
++ unsigned long long n;
++ struct file **p, *f;
++ struct super_block *sb = arg;
++
++ n = 0;
++ p = a;
++ lg_global_lock(files_lglock);
++ do_file_list_for_each_entry(sb, f) {
++ if (au_fi(f)
++ && !special_file(f->f_dentry->d_inode->i_mode)) {
++ get_file(f);
++ *p++ = f;
++ n++;
++ AuDebugOn(n > max);
++ }
++ } while_file_list_for_each_entry;
++ lg_global_unlock(files_lglock);
++
++ return n;
++}
++
++static struct file **au_farray_alloc(struct super_block *sb,
++ unsigned long long *max)
++{
++ *max = atomic_long_read(&au_sbi(sb)->si_nfiles);
++ return au_array_alloc(max, au_farray_cb, sb);
++}
++
++static void au_farray_free(struct file **a, unsigned long long max)
++{
++ unsigned long long ull;
++
++ for (ull = 0; ull < max; ull++)
++ if (a[ull])
++ fput(a[ull]);
++ au_array_free(a);
++}
++
++static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
++{
++ int err, do_warn;
++ unsigned long long ull, max;
++ aufs_bindex_t br_id;
++ struct file *file, *hf, **array;
++ struct inode *inode;
++ struct au_hfile *hfile;
++
++ array = au_farray_alloc(sb, &max);
++ err = PTR_ERR(array);
++ if (IS_ERR(array))
++ goto out;
++
++ do_warn = 0;
++ br_id = au_sbr_id(sb, bindex);
++ for (ull = 0; ull < max; ull++) {
++ file = array[ull];
++
++ /* AuDbg("%.*s\n", AuDLNPair(file->f_dentry)); */
++ fi_read_lock(file);
++ if (unlikely(au_test_mmapped(file))) {
++ err = -EBUSY;
++ AuDbgFile(file);
++ FiMustNoWaiters(file);
++ fi_read_unlock(file);
++ goto out_array;
++ }
++
++ inode = file->f_dentry->d_inode;
++ hfile = &au_fi(file)->fi_htop;
++ hf = hfile->hf_file;
++ if (!S_ISREG(inode->i_mode)
++ || !(file->f_mode & FMODE_WRITE)
++ || hfile->hf_br->br_id != br_id
++ || !(hf->f_mode & FMODE_WRITE))
++ array[ull] = NULL;
++ else {
++ do_warn = 1;
++ get_file(file);
++ }
++
++ FiMustNoWaiters(file);
++ fi_read_unlock(file);
++ fput(file);
++ }
++
++ err = 0;
++ if (do_warn)
++ au_warn_ima();
++
++ for (ull = 0; ull < max; ull++) {
++ file = array[ull];
++ if (!file)
++ continue;
++
++ /* todo: already flushed? */
++ /* cf. fs/super.c:mark_files_ro() */
++ /* fi_read_lock(file); */
++ hfile = &au_fi(file)->fi_htop;
++ hf = hfile->hf_file;
++ /* fi_read_unlock(file); */
++ spin_lock(&hf->f_lock);
++ hf->f_mode &= ~FMODE_WRITE;
++ spin_unlock(&hf->f_lock);
++ if (!file_check_writeable(hf)) {
++ file_release_write(hf);
++ mnt_drop_write(hf->f_vfsmnt);
++ }
++ }
++
++out_array:
++ au_farray_free(array, max);
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount,
++ int *do_refresh)
++{
++ int err, rerr;
++ aufs_bindex_t bindex;
++ struct path path;
++ struct dentry *root;
++ struct au_branch *br;
++
++ root = sb->s_root;
++ bindex = au_find_dbindex(root, mod->h_root);
++ if (bindex < 0) {
++ if (remount)
++ return 0; /* success */
++ err = -ENOENT;
++ pr_err("%s no such branch\n", mod->path);
++ goto out;
++ }
++ AuDbg("bindex b%d\n", bindex);
++
++ err = test_br(mod->h_root->d_inode, mod->perm, mod->path);
++ if (unlikely(err))
++ goto out;
++
++ br = au_sbr(sb, bindex);
++ if (br->br_perm == mod->perm)
++ return 0; /* success */
++
++ if (au_br_writable(br->br_perm)) {
++ /* remove whiteout base */
++ err = au_br_init_wh(sb, br, mod->perm, mod->h_root);
++ if (unlikely(err))
++ goto out;
++
++ if (!au_br_writable(mod->perm)) {
++ /* rw --> ro, file might be mmapped */
++ DiMustNoWaiters(root);
++ IiMustNoWaiters(root->d_inode);
++ di_write_unlock(root);
++ err = au_br_mod_files_ro(sb, bindex);
++ /* aufs_write_lock() calls ..._child() */
++ di_write_lock_child(root);
++
++ if (unlikely(err)) {
++ rerr = -ENOMEM;
++ br->br_wbr = kmalloc(sizeof(*br->br_wbr),
++ GFP_NOFS);
++ if (br->br_wbr) {
++ path.mnt = br->br_mnt;
++ path.dentry = mod->h_root;
++ rerr = au_wbr_init(br, sb, br->br_perm,
++ &path);
++ }
++ if (unlikely(rerr)) {
++ AuIOErr("nested error %d (%d)\n",
++ rerr, err);
++ br->br_perm = mod->perm;
++ }
++ }
++ }
++ } else if (au_br_writable(mod->perm)) {
++ /* ro --> rw */
++ err = -ENOMEM;
++ br->br_wbr = kmalloc(sizeof(*br->br_wbr), GFP_NOFS);
++ if (br->br_wbr) {
++ path.mnt = br->br_mnt;
++ path.dentry = mod->h_root;
++ err = au_wbr_init(br, sb, mod->perm, &path);
++ if (unlikely(err)) {
++ kfree(br->br_wbr);
++ br->br_wbr = NULL;
++ }
++ }
++ }
++
++ if (!err) {
++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm);
++ br->br_perm = mod->perm;
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/branch.h linux-2.6.36/fs/aufs/branch.h
+--- linux-2.6.36.orig/fs/aufs/branch.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/branch.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,229 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * branch filesystems and xino for them
++ */
++
++#ifndef __AUFS_BRANCH_H__
++#define __AUFS_BRANCH_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/mount.h>
++#include <linux/aufs_type.h>
++#include "dynop.h"
++#include "rwsem.h"
++#include "super.h"
++
++/* ---------------------------------------------------------------------- */
++
++/* a xino file */
++struct au_xino_file {
++ struct file *xi_file;
++ struct mutex xi_nondir_mtx;
++
++ /* todo: make xino files an array to support huge inode number */
++
++#ifdef CONFIG_DEBUG_FS
++ struct dentry *xi_dbgaufs;
++#endif
++};
++
++/* members for writable branch only */
++enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last};
++struct au_wbr {
++ struct au_rwsem wbr_wh_rwsem;
++ struct dentry *wbr_wh[AuBrWh_Last];
++ atomic_t wbr_wh_running;
++#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */
++#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */
++#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */
++
++ /* mfs mode */
++ unsigned long long wbr_bytes;
++};
++
++/* ext2 has 3 types of operations at least, ext3 has 4 */
++#define AuBrDynOp (AuDyLast * 4)
++
++/* protected by superblock rwsem */
++struct au_branch {
++ struct au_xino_file br_xino;
++
++ aufs_bindex_t br_id;
++
++ int br_perm;
++ struct vfsmount *br_mnt;
++ spinlock_t br_dykey_lock;
++ struct au_dykey *br_dykey[AuBrDynOp];
++ atomic_t br_count;
++
++ struct au_wbr *br_wbr;
++
++ /* xino truncation */
++ blkcnt_t br_xino_upper; /* watermark in blocks */
++ atomic_t br_xino_running;
++
++#ifdef CONFIG_AUFS_HFSNOTIFY
++ struct fsnotify_group *br_hfsn_group;
++ struct fsnotify_ops br_hfsn_ops;
++#endif
++
++#ifdef CONFIG_SYSFS
++ /* an entry under sysfs per mount-point */
++ char br_name[8];
++ struct attribute br_attr;
++#endif
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* branch permission and attribute */
++enum {
++ AuBrPerm_RW, /* writable, linkable wh */
++ AuBrPerm_RO, /* readonly, no wh */
++ AuBrPerm_RR, /* natively readonly, no wh */
++
++ AuBrPerm_RWNoLinkWH, /* un-linkable whiteouts */
++
++ AuBrPerm_ROWH, /* whiteout-able */
++ AuBrPerm_RRWH, /* whiteout-able */
++
++ AuBrPerm_Last
++};
++
++static inline int au_br_writable(int brperm)
++{
++ return brperm == AuBrPerm_RW || brperm == AuBrPerm_RWNoLinkWH;
++}
++
++static inline int au_br_whable(int brperm)
++{
++ return brperm == AuBrPerm_RW
++ || brperm == AuBrPerm_ROWH
++ || brperm == AuBrPerm_RRWH;
++}
++
++static inline int au_br_rdonly(struct au_branch *br)
++{
++ return ((br->br_mnt->mnt_sb->s_flags & MS_RDONLY)
++ || !au_br_writable(br->br_perm))
++ ? -EROFS : 0;
++}
++
++static inline int au_br_hnotifyable(int brperm __maybe_unused)
++{
++#ifdef CONFIG_AUFS_HNOTIFY
++ return brperm != AuBrPerm_RR && brperm != AuBrPerm_RRWH;
++#else
++ return 0;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* branch.c */
++struct au_sbinfo;
++void au_br_free(struct au_sbinfo *sinfo);
++int au_br_index(struct super_block *sb, aufs_bindex_t br_id);
++struct au_opt_add;
++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount);
++struct au_opt_del;
++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount);
++struct au_opt_mod;
++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount,
++ int *do_refresh);
++
++/* xino.c */
++static const loff_t au_loff_max = LLONG_MAX;
++
++int au_xib_trunc(struct super_block *sb);
++ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size,
++ loff_t *pos);
++ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size,
++ loff_t *pos);
++struct file *au_xino_create2(struct file *base_file, struct file *copy_src);
++struct file *au_xino_create(struct super_block *sb, char *fname, int silent);
++ino_t au_xino_new_ino(struct super_block *sb);
++void au_xino_delete_inode(struct inode *inode, const int unlinked);
++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t ino);
++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t *ino);
++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino,
++ struct file *base_file, int do_test);
++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex);
++
++struct au_opt_xino;
++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount);
++void au_xino_clr(struct super_block *sb);
++struct file *au_xino_def(struct super_block *sb);
++int au_xino_path(struct seq_file *seq, struct file *file);
++
++/* ---------------------------------------------------------------------- */
++
++/* Superblock to branch */
++static inline
++aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr(sb, bindex)->br_id;
++}
++
++static inline
++struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr(sb, bindex)->br_mnt;
++}
++
++static inline
++struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr_mnt(sb, bindex)->mnt_sb;
++}
++
++static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex)
++{
++ atomic_dec(&au_sbr(sb, bindex)->br_count);
++}
++
++static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr(sb, bindex)->br_perm;
++}
++
++static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_br_whable(au_sbr_perm(sb, bindex));
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * wbr_wh_read_lock, wbr_wh_write_lock
++ * wbr_wh_read_unlock, wbr_wh_write_unlock, wbr_wh_downgrade_lock
++ */
++AuSimpleRwsemFuncs(wbr_wh, struct au_wbr *wbr, &wbr->wbr_wh_rwsem);
++
++#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&wbr->wbr_wh_rwsem)
++#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&wbr->wbr_wh_rwsem)
++#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&wbr->wbr_wh_rwsem)
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_BRANCH_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/conf.mk linux-2.6.36/fs/aufs/conf.mk
+--- linux-2.6.36.orig/fs/aufs/conf.mk 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/conf.mk 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,37 @@
++
++AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS}
++
++define AuConf
++ifdef ${1}
++AuConfStr += ${1}=${${1}}
++endif
++endef
++
++AuConfAll = BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \
++ SBILIST \
++ HNOTIFY HFSNOTIFY \
++ EXPORT INO_T_64 \
++ RDU \
++ SP_IATTR \
++ SHWH \
++ BR_RAMFS \
++ BR_FUSE POLL \
++ BR_HFSPLUS \
++ BDEV_LOOP \
++ DEBUG MAGIC_SYSRQ
++$(foreach i, ${AuConfAll}, \
++ $(eval $(call AuConf,CONFIG_AUFS_${i})))
++
++AuConfName = ${obj}/conf.str
++${AuConfName}.tmp: FORCE
++ @echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@
++${AuConfName}: ${AuConfName}.tmp
++ @diff -q $< $@ > /dev/null 2>&1 || { \
++ echo ' GEN ' $@; \
++ cp -p $< $@; \
++ }
++FORCE:
++clean-files += ${AuConfName} ${AuConfName}.tmp
++${obj}/sysfs.o: ${AuConfName}
++
++-include ${srctree}/${src}/conf_priv.mk
+diff -Nur linux-2.6.36.orig/fs/aufs/cpup.c linux-2.6.36/fs/aufs/cpup.c
+--- linux-2.6.36.orig/fs/aufs/cpup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/cpup.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,1063 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * copy-up functions, see wbr_policy.c for copy-down
++ */
++
++#include <linux/file.h>
++#include <linux/fs_stack.h>
++#include <linux/mm.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++void au_cpup_attr_flags(struct inode *dst, struct inode *src)
++{
++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE
++ | S_NOATIME | S_NOCMTIME;
++
++ dst->i_flags |= src->i_flags & ~mask;
++ if (au_test_fs_notime(dst->i_sb))
++ dst->i_flags |= S_NOATIME | S_NOCMTIME;
++}
++
++void au_cpup_attr_timesizes(struct inode *inode)
++{
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ fsstack_copy_attr_times(inode, h_inode);
++ fsstack_copy_inode_size(inode, h_inode);
++}
++
++void au_cpup_attr_nlink(struct inode *inode, int force)
++{
++ struct inode *h_inode;
++ struct super_block *sb;
++ aufs_bindex_t bindex, bend;
++
++ sb = inode->i_sb;
++ bindex = au_ibstart(inode);
++ h_inode = au_h_iptr(inode, bindex);
++ if (!force
++ && !S_ISDIR(h_inode->i_mode)
++ && au_opt_test(au_mntflags(sb), PLINK)
++ && au_plink_test(inode))
++ return;
++
++ inode->i_nlink = h_inode->i_nlink;
++
++ /*
++ * fewer nlink makes find(1) noisy, but larger nlink doesn't.
++ * it may includes whplink directory.
++ */
++ if (S_ISDIR(h_inode->i_mode)) {
++ bend = au_ibend(inode);
++ for (bindex++; bindex <= bend; bindex++) {
++ h_inode = au_h_iptr(inode, bindex);
++ if (h_inode)
++ au_add_nlink(inode, h_inode);
++ }
++ }
++}
++
++void au_cpup_attr_changeable(struct inode *inode)
++{
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ inode->i_mode = h_inode->i_mode;
++ inode->i_uid = h_inode->i_uid;
++ inode->i_gid = h_inode->i_gid;
++ au_cpup_attr_timesizes(inode);
++ au_cpup_attr_flags(inode, h_inode);
++}
++
++void au_cpup_igen(struct inode *inode, struct inode *h_inode)
++{
++ struct au_iinfo *iinfo = au_ii(inode);
++
++ IiMustWriteLock(inode);
++
++ iinfo->ii_higen = h_inode->i_generation;
++ iinfo->ii_hsb1 = h_inode->i_sb;
++}
++
++void au_cpup_attr_all(struct inode *inode, int force)
++{
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ au_cpup_attr_changeable(inode);
++ if (inode->i_nlink > 0)
++ au_cpup_attr_nlink(inode, force);
++ inode->i_rdev = h_inode->i_rdev;
++ inode->i_blkbits = h_inode->i_blkbits;
++ au_cpup_igen(inode, h_inode);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */
++
++/* keep the timestamps of the parent dir when cpup */
++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry,
++ struct path *h_path)
++{
++ struct inode *h_inode;
++
++ dt->dt_dentry = dentry;
++ dt->dt_h_path = *h_path;
++ h_inode = h_path->dentry->d_inode;
++ dt->dt_atime = h_inode->i_atime;
++ dt->dt_mtime = h_inode->i_mtime;
++ /* smp_mb(); */
++}
++
++void au_dtime_revert(struct au_dtime *dt)
++{
++ struct iattr attr;
++ int err;
++
++ attr.ia_atime = dt->dt_atime;
++ attr.ia_mtime = dt->dt_mtime;
++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET
++ | ATTR_ATIME | ATTR_ATIME_SET;
++
++ err = vfsub_notify_change(&dt->dt_h_path, &attr);
++ if (unlikely(err))
++ pr_warning("restoring timestamps failed(%d). ignored\n", err);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static noinline_for_stack
++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src)
++{
++ int err, sbits;
++ struct iattr ia;
++ struct path h_path;
++ struct inode *h_isrc, *h_idst;
++
++ h_path.dentry = au_h_dptr(dst, bindex);
++ h_idst = h_path.dentry->d_inode;
++ h_path.mnt = au_sbr_mnt(dst->d_sb, bindex);
++ h_isrc = h_src->d_inode;
++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID
++ | ATTR_ATIME | ATTR_MTIME
++ | ATTR_ATIME_SET | ATTR_MTIME_SET;
++ ia.ia_uid = h_isrc->i_uid;
++ ia.ia_gid = h_isrc->i_gid;
++ ia.ia_atime = h_isrc->i_atime;
++ ia.ia_mtime = h_isrc->i_mtime;
++ if (h_idst->i_mode != h_isrc->i_mode
++ && !S_ISLNK(h_idst->i_mode)) {
++ ia.ia_valid |= ATTR_MODE;
++ ia.ia_mode = h_isrc->i_mode;
++ }
++ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID));
++ au_cpup_attr_flags(h_idst, h_isrc);
++ err = vfsub_notify_change(&h_path, &ia);
++
++ /* is this nfs only? */
++ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) {
++ ia.ia_valid = ATTR_FORCE | ATTR_MODE;
++ ia.ia_mode = h_isrc->i_mode;
++ err = vfsub_notify_change(&h_path, &ia);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_copy_file(struct file *dst, struct file *src, loff_t len,
++ char *buf, unsigned long blksize)
++{
++ int err;
++ size_t sz, rbytes, wbytes;
++ unsigned char all_zero;
++ char *p, *zp;
++ struct mutex *h_mtx;
++ /* reduce stack usage */
++ struct iattr *ia;
++
++ zp = page_address(ZERO_PAGE(0));
++ if (unlikely(!zp))
++ return -ENOMEM; /* possible? */
++
++ err = 0;
++ all_zero = 0;
++ while (len) {
++ AuDbg("len %lld\n", len);
++ sz = blksize;
++ if (len < blksize)
++ sz = len;
++
++ rbytes = 0;
++ /* todo: signal_pending? */
++ while (!rbytes || err == -EAGAIN || err == -EINTR) {
++ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos);
++ err = rbytes;
++ }
++ if (unlikely(err < 0))
++ break;
++
++ all_zero = 0;
++ if (len >= rbytes && rbytes == blksize)
++ all_zero = !memcmp(buf, zp, rbytes);
++ if (!all_zero) {
++ wbytes = rbytes;
++ p = buf;
++ while (wbytes) {
++ size_t b;
++
++ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos);
++ err = b;
++ /* todo: signal_pending? */
++ if (unlikely(err == -EAGAIN || err == -EINTR))
++ continue;
++ if (unlikely(err < 0))
++ break;
++ wbytes -= b;
++ p += b;
++ }
++ } else {
++ loff_t res;
++
++ AuLabel(hole);
++ res = vfsub_llseek(dst, rbytes, SEEK_CUR);
++ err = res;
++ if (unlikely(res < 0))
++ break;
++ }
++ len -= rbytes;
++ err = 0;
++ }
++
++ /* the last block may be a hole */
++ if (!err && all_zero) {
++ AuLabel(last hole);
++
++ err = 1;
++ if (au_test_nfs(dst->f_dentry->d_sb)) {
++ /* nfs requires this step to make last hole */
++ /* is this only nfs? */
++ do {
++ /* todo: signal_pending? */
++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos);
++ } while (err == -EAGAIN || err == -EINTR);
++ if (err == 1)
++ dst->f_pos--;
++ }
++
++ if (err == 1) {
++ ia = (void *)buf;
++ ia->ia_size = dst->f_pos;
++ ia->ia_valid = ATTR_SIZE | ATTR_FILE;
++ ia->ia_file = dst;
++ h_mtx = &dst->f_dentry->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD2);
++ err = vfsub_notify_change(&dst->f_path, ia);
++ mutex_unlock(h_mtx);
++ }
++ }
++
++ return err;
++}
++
++int au_copy_file(struct file *dst, struct file *src, loff_t len)
++{
++ int err;
++ unsigned long blksize;
++ unsigned char do_kfree;
++ char *buf;
++
++ err = -ENOMEM;
++ blksize = dst->f_dentry->d_sb->s_blocksize;
++ if (!blksize || PAGE_SIZE < blksize)
++ blksize = PAGE_SIZE;
++ AuDbg("blksize %lu\n", blksize);
++ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *));
++ if (do_kfree)
++ buf = kmalloc(blksize, GFP_NOFS);
++ else
++ buf = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!buf))
++ goto out;
++
++ if (len > (1 << 22))
++ AuDbg("copying a large file %lld\n", (long long)len);
++
++ src->f_pos = 0;
++ dst->f_pos = 0;
++ err = au_do_copy_file(dst, src, len, buf, blksize);
++ if (do_kfree)
++ kfree(buf);
++ else
++ free_page((unsigned long)buf);
++
++out:
++ return err;
++}
++
++/*
++ * to support a sparse file which is opened with O_APPEND,
++ * we need to close the file.
++ */
++static int au_cp_regular(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len)
++{
++ int err, i;
++ enum { SRC, DST };
++ struct {
++ aufs_bindex_t bindex;
++ unsigned int flags;
++ struct dentry *dentry;
++ struct file *file;
++ void *label, *label_file;
++ } *f, file[] = {
++ {
++ .bindex = bsrc,
++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE,
++ .file = NULL,
++ .label = &&out,
++ .label_file = &&out_src
++ },
++ {
++ .bindex = bdst,
++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE,
++ .file = NULL,
++ .label = &&out_src,
++ .label_file = &&out_dst
++ }
++ };
++ struct super_block *sb;
++
++ /* bsrc branch can be ro/rw. */
++ sb = dentry->d_sb;
++ f = file;
++ for (i = 0; i < 2; i++, f++) {
++ f->dentry = au_h_dptr(dentry, f->bindex);
++ f->file = au_h_open(dentry, f->bindex, f->flags, /*file*/NULL);
++ err = PTR_ERR(f->file);
++ if (IS_ERR(f->file))
++ goto *f->label;
++ err = -EINVAL;
++ if (unlikely(!f->file->f_op))
++ goto *f->label_file;
++ }
++
++ /* try stopping to update while we copyup */
++ IMustLock(file[SRC].dentry->d_inode);
++ err = au_copy_file(file[DST].file, file[SRC].file, len);
++
++out_dst:
++ fput(file[DST].file);
++ au_sbr_put(sb, file[DST].bindex);
++out_src:
++ fput(file[SRC].file);
++ au_sbr_put(sb, file[SRC].bindex);
++out:
++ return err;
++}
++
++static int au_do_cpup_regular(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len,
++ struct inode *h_dir, struct path *h_path)
++{
++ int err, rerr;
++ loff_t l;
++
++ err = 0;
++ l = i_size_read(au_h_iptr(dentry->d_inode, bsrc));
++ if (len == -1 || l < len)
++ len = l;
++ if (len)
++ err = au_cp_regular(dentry, bdst, bsrc, len);
++ if (!err)
++ goto out; /* success */
++
++ rerr = vfsub_unlink(h_dir, h_path, /*force*/0);
++ if (rerr) {
++ AuIOErr("failed unlinking cpup-ed %.*s(%d, %d)\n",
++ AuDLNPair(h_path->dentry), err, rerr);
++ err = -EIO;
++ }
++
++out:
++ return err;
++}
++
++static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src,
++ struct inode *h_dir)
++{
++ int err, symlen;
++ mm_segment_t old_fs;
++ union {
++ char *k;
++ char __user *u;
++ } sym;
++
++ err = -ENOSYS;
++ if (unlikely(!h_src->d_inode->i_op->readlink))
++ goto out;
++
++ err = -ENOMEM;
++ sym.k = __getname_gfp(GFP_NOFS);
++ if (unlikely(!sym.k))
++ goto out;
++
++ old_fs = get_fs();
++ set_fs(KERNEL_DS);
++ symlen = h_src->d_inode->i_op->readlink(h_src, sym.u, PATH_MAX);
++ err = symlen;
++ set_fs(old_fs);
++
++ if (symlen > 0) {
++ sym.k[symlen] = 0;
++ err = vfsub_symlink(h_dir, h_path, sym.k);
++ }
++ __putname(sym.k);
++
++out:
++ return err;
++}
++
++/* return with the lower dst inode is locked */
++static noinline_for_stack
++int cpup_entry(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent)
++{
++ int err;
++ umode_t mode;
++ unsigned int mnt_flags;
++ unsigned char isdir;
++ const unsigned char do_dt = !!au_ftest_cpup(flags, DTIME);
++ struct au_dtime dt;
++ struct path h_path;
++ struct dentry *h_src, *h_dst, *h_parent;
++ struct inode *h_inode, *h_dir;
++ struct super_block *sb;
++
++ /* bsrc branch can be ro/rw. */
++ h_src = au_h_dptr(dentry, bsrc);
++ h_inode = h_src->d_inode;
++ AuDebugOn(h_inode != au_h_iptr(dentry->d_inode, bsrc));
++
++ /* try stopping to be referenced while we are creating */
++ h_dst = au_h_dptr(dentry, bdst);
++ h_parent = h_dst->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++ AuDebugOn(h_parent != h_dst->d_parent);
++
++ sb = dentry->d_sb;
++ h_path.mnt = au_sbr_mnt(sb, bdst);
++ if (do_dt) {
++ h_path.dentry = h_parent;
++ au_dtime_store(&dt, dst_parent, &h_path);
++ }
++ h_path.dentry = h_dst;
++
++ isdir = 0;
++ mode = h_inode->i_mode;
++ switch (mode & S_IFMT) {
++ case S_IFREG:
++ /* try stopping to update while we are referencing */
++ IMustLock(h_inode);
++ err = vfsub_create(h_dir, &h_path, mode | S_IWUSR);
++ if (!err)
++ err = au_do_cpup_regular
++ (dentry, bdst, bsrc, len,
++ au_h_iptr(dst_parent->d_inode, bdst), &h_path);
++ break;
++ case S_IFDIR:
++ isdir = 1;
++ err = vfsub_mkdir(h_dir, &h_path, mode);
++ if (!err) {
++ /*
++ * strange behaviour from the users view,
++ * particularry setattr case
++ */
++ if (au_ibstart(dst_parent->d_inode) == bdst)
++ au_cpup_attr_nlink(dst_parent->d_inode,
++ /*force*/1);
++ au_cpup_attr_nlink(dentry->d_inode, /*force*/1);
++ }
++ break;
++ case S_IFLNK:
++ err = au_do_cpup_symlink(&h_path, h_src, h_dir);
++ break;
++ case S_IFCHR:
++ case S_IFBLK:
++ AuDebugOn(!capable(CAP_MKNOD));
++ /*FALLTHROUGH*/
++ case S_IFIFO:
++ case S_IFSOCK:
++ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev);
++ break;
++ default:
++ AuIOErr("Unknown inode type 0%o\n", mode);
++ err = -EIO;
++ }
++
++ mnt_flags = au_mntflags(sb);
++ if (!au_opt_test(mnt_flags, UDBA_NONE)
++ && !isdir
++ && au_opt_test(mnt_flags, XINO)
++ && h_inode->i_nlink == 1
++ /* todo: unnecessary? */
++ /* && dentry->d_inode->i_nlink == 1 */
++ && bdst < bsrc
++ && !au_ftest_cpup(flags, KEEPLINO))
++ au_xino_write(sb, bsrc, h_inode->i_ino, /*ino*/0);
++ /* ignore this error */
++
++ if (do_dt)
++ au_dtime_revert(&dt);
++ return err;
++}
++
++/*
++ * copyup the @dentry from @bsrc to @bdst.
++ * the caller must set the both of lower dentries.
++ * @len is for truncating when it is -1 copyup the entire file.
++ * in link/rename cases, @dst_parent may be different from the real one.
++ */
++static int au_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent)
++{
++ int err, rerr;
++ aufs_bindex_t old_ibstart;
++ unsigned char isdir, plink;
++ struct au_dtime dt;
++ struct path h_path;
++ struct dentry *h_src, *h_dst, *h_parent;
++ struct inode *dst_inode, *h_dir, *inode;
++ struct super_block *sb;
++
++ AuDebugOn(bsrc <= bdst);
++
++ sb = dentry->d_sb;
++ h_path.mnt = au_sbr_mnt(sb, bdst);
++ h_dst = au_h_dptr(dentry, bdst);
++ h_parent = h_dst->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++
++ h_src = au_h_dptr(dentry, bsrc);
++ inode = dentry->d_inode;
++
++ if (!dst_parent)
++ dst_parent = dget_parent(dentry);
++ else
++ dget(dst_parent);
++
++ plink = !!au_opt_test(au_mntflags(sb), PLINK);
++ dst_inode = au_h_iptr(inode, bdst);
++ if (dst_inode) {
++ if (unlikely(!plink)) {
++ err = -EIO;
++ AuIOErr("hi%lu(i%lu) exists on b%d "
++ "but plink is disabled\n",
++ dst_inode->i_ino, inode->i_ino, bdst);
++ goto out;
++ }
++
++ if (dst_inode->i_nlink) {
++ const int do_dt = au_ftest_cpup(flags, DTIME);
++
++ h_src = au_plink_lkup(inode, bdst);
++ err = PTR_ERR(h_src);
++ if (IS_ERR(h_src))
++ goto out;
++ if (unlikely(!h_src->d_inode)) {
++ err = -EIO;
++ AuIOErr("i%lu exists on a upper branch "
++ "but not pseudo-linked\n",
++ inode->i_ino);
++ dput(h_src);
++ goto out;
++ }
++
++ if (do_dt) {
++ h_path.dentry = h_parent;
++ au_dtime_store(&dt, dst_parent, &h_path);
++ }
++ h_path.dentry = h_dst;
++ err = vfsub_link(h_src, h_dir, &h_path);
++ if (do_dt)
++ au_dtime_revert(&dt);
++ dput(h_src);
++ goto out;
++ } else
++ /* todo: cpup_wh_file? */
++ /* udba work */
++ au_update_ibrange(inode, /*do_put_zero*/1);
++ }
++
++ old_ibstart = au_ibstart(inode);
++ err = cpup_entry(dentry, bdst, bsrc, len, flags, dst_parent);
++ if (unlikely(err))
++ goto out;
++ dst_inode = h_dst->d_inode;
++ mutex_lock_nested(&dst_inode->i_mutex, AuLsc_I_CHILD2);
++
++ err = cpup_iattr(dentry, bdst, h_src);
++ isdir = S_ISDIR(dst_inode->i_mode);
++ if (!err) {
++ if (bdst < old_ibstart) {
++ if (S_ISREG(inode->i_mode)) {
++ err = au_dy_iaop(inode, bdst, dst_inode);
++ if (unlikely(err))
++ goto out_rev;
++ }
++ au_set_ibstart(inode, bdst);
++ }
++ au_set_h_iptr(inode, bdst, au_igrab(dst_inode),
++ au_hi_flags(inode, isdir));
++ mutex_unlock(&dst_inode->i_mutex);
++ if (!isdir
++ && h_src->d_inode->i_nlink > 1
++ && plink)
++ au_plink_append(inode, bdst, h_dst);
++ goto out; /* success */
++ }
++
++ /* revert */
++out_rev:
++ h_path.dentry = h_parent;
++ mutex_unlock(&dst_inode->i_mutex);
++ au_dtime_store(&dt, dst_parent, &h_path);
++ h_path.dentry = h_dst;
++ if (!isdir)
++ rerr = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ else
++ rerr = vfsub_rmdir(h_dir, &h_path);
++ au_dtime_revert(&dt);
++ if (rerr) {
++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr);
++ err = -EIO;
++ }
++
++out:
++ dput(dst_parent);
++ return err;
++}
++
++struct au_cpup_single_args {
++ int *errp;
++ struct dentry *dentry;
++ aufs_bindex_t bdst, bsrc;
++ loff_t len;
++ unsigned int flags;
++ struct dentry *dst_parent;
++};
++
++static void au_call_cpup_single(void *args)
++{
++ struct au_cpup_single_args *a = args;
++ *a->errp = au_cpup_single(a->dentry, a->bdst, a->bsrc, a->len,
++ a->flags, a->dst_parent);
++}
++
++int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent)
++{
++ int err, wkq_err;
++ umode_t mode;
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bsrc);
++ mode = h_dentry->d_inode->i_mode & S_IFMT;
++ if ((mode != S_IFCHR && mode != S_IFBLK)
++ || capable(CAP_MKNOD))
++ err = au_cpup_single(dentry, bdst, bsrc, len, flags,
++ dst_parent);
++ else {
++ struct au_cpup_single_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .bdst = bdst,
++ .bsrc = bsrc,
++ .len = len,
++ .flags = flags,
++ .dst_parent = dst_parent
++ };
++ wkq_err = au_wkq_wait(au_call_cpup_single, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
++
++/*
++ * copyup the @dentry from the first active lower branch to @bdst,
++ * using au_cpup_single().
++ */
++static int au_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ unsigned int flags)
++{
++ int err;
++ aufs_bindex_t bsrc, bend;
++
++ bend = au_dbend(dentry);
++ for (bsrc = bdst + 1; bsrc <= bend; bsrc++)
++ if (au_h_dptr(dentry, bsrc))
++ break;
++
++ err = au_lkup_neg(dentry, bdst);
++ if (!err) {
++ err = au_cpup_single(dentry, bdst, bsrc, len, flags, NULL);
++ if (!err)
++ return 0; /* success */
++
++ /* revert */
++ au_set_h_dptr(dentry, bdst, NULL);
++ au_set_dbstart(dentry, bsrc);
++ }
++
++ return err;
++}
++
++struct au_cpup_simple_args {
++ int *errp;
++ struct dentry *dentry;
++ aufs_bindex_t bdst;
++ loff_t len;
++ unsigned int flags;
++};
++
++static void au_call_cpup_simple(void *args)
++{
++ struct au_cpup_simple_args *a = args;
++ *a->errp = au_cpup_simple(a->dentry, a->bdst, a->len, a->flags);
++}
++
++int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ unsigned int flags)
++{
++ int err, wkq_err;
++ unsigned char do_sio;
++ struct dentry *parent;
++ struct inode *h_dir;
++
++ parent = dget_parent(dentry);
++ h_dir = au_h_iptr(parent->d_inode, bdst);
++ do_sio = !!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE);
++ if (!do_sio) {
++ /*
++ * testing CAP_MKNOD is for generic fs,
++ * but CAP_FSETID is for xfs only, currently.
++ */
++ umode_t mode = dentry->d_inode->i_mode;
++ do_sio = (((mode & (S_IFCHR | S_IFBLK))
++ && !capable(CAP_MKNOD))
++ || ((mode & (S_ISUID | S_ISGID))
++ && !capable(CAP_FSETID)));
++ }
++ if (!do_sio)
++ err = au_cpup_simple(dentry, bdst, len, flags);
++ else {
++ struct au_cpup_simple_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .bdst = bdst,
++ .len = len,
++ .flags = flags
++ };
++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * copyup the deleted file for writing.
++ */
++static int au_do_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *wh_dentry, struct file *file,
++ loff_t len)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct au_dinfo *dinfo;
++ struct dentry *h_d_dst, *h_d_start;
++ struct au_hdentry *hdp;
++
++ dinfo = au_di(dentry);
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ bstart = dinfo->di_bstart;
++ hdp = dinfo->di_hdentry;
++ h_d_dst = hdp[0 + bdst].hd_dentry;
++ dinfo->di_bstart = bdst;
++ hdp[0 + bdst].hd_dentry = wh_dentry;
++ if (file) {
++ h_d_start = hdp[0 + bstart].hd_dentry;
++ hdp[0 + bstart].hd_dentry = au_hf_top(file)->f_dentry;
++ }
++ err = au_cpup_single(dentry, bdst, bstart, len, !AuCpup_DTIME,
++ /*h_parent*/NULL);
++ if (file) {
++ if (!err)
++ err = au_reopen_nondir(file);
++ hdp[0 + bstart].hd_dentry = h_d_start;
++ }
++ hdp[0 + bdst].hd_dentry = h_d_dst;
++ dinfo->di_bstart = bstart;
++
++ return err;
++}
++
++static int au_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ struct file *file)
++{
++ int err;
++ struct au_dtime dt;
++ struct dentry *parent, *h_parent, *wh_dentry;
++ struct au_branch *br;
++ struct path h_path;
++
++ br = au_sbr(dentry->d_sb, bdst);
++ parent = dget_parent(dentry);
++ h_parent = au_h_dptr(parent, bdst);
++ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out;
++
++ h_path.dentry = h_parent;
++ h_path.mnt = br->br_mnt;
++ au_dtime_store(&dt, parent, &h_path);
++ err = au_do_cpup_wh(dentry, bdst, wh_dentry, file, len);
++ if (unlikely(err))
++ goto out_wh;
++
++ dget(wh_dentry);
++ h_path.dentry = wh_dentry;
++ if (!S_ISDIR(wh_dentry->d_inode->i_mode))
++ err = vfsub_unlink(h_parent->d_inode, &h_path, /*force*/0);
++ else
++ err = vfsub_rmdir(h_parent->d_inode, &h_path);
++ if (unlikely(err)) {
++ AuIOErr("failed remove copied-up tmp file %.*s(%d)\n",
++ AuDLNPair(wh_dentry), err);
++ err = -EIO;
++ }
++ au_dtime_revert(&dt);
++ au_set_hi_wh(dentry->d_inode, bdst, wh_dentry);
++
++out_wh:
++ dput(wh_dentry);
++out:
++ dput(parent);
++ return err;
++}
++
++struct au_cpup_wh_args {
++ int *errp;
++ struct dentry *dentry;
++ aufs_bindex_t bdst;
++ loff_t len;
++ struct file *file;
++};
++
++static void au_call_cpup_wh(void *args)
++{
++ struct au_cpup_wh_args *a = args;
++ *a->errp = au_cpup_wh(a->dentry, a->bdst, a->len, a->file);
++}
++
++int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ struct file *file)
++{
++ int err, wkq_err;
++ struct dentry *parent, *h_orph, *h_parent, *h_dentry;
++ struct inode *dir, *h_dir, *h_tmpdir, *h_inode;
++ struct au_wbr *wbr;
++
++ parent = dget_parent(dentry);
++ dir = parent->d_inode;
++ h_orph = NULL;
++ h_parent = NULL;
++ h_dir = au_igrab(au_h_iptr(dir, bdst));
++ h_tmpdir = h_dir;
++ if (!h_dir->i_nlink) {
++ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr;
++ h_orph = wbr->wbr_orph;
++
++ h_parent = dget(au_h_dptr(parent, bdst));
++ au_set_h_dptr(parent, bdst, dget(h_orph));
++ h_tmpdir = h_orph->d_inode;
++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0);
++
++ /* this temporary unlock is safe */
++ if (file)
++ h_dentry = au_hf_top(file)->f_dentry;
++ else
++ h_dentry = au_h_dptr(dentry, au_dbstart(dentry));
++ h_inode = h_dentry->d_inode;
++ IMustLock(h_inode);
++ mutex_unlock(&h_inode->i_mutex);
++ mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3);
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ /* todo: au_h_open_pre()? */
++ }
++
++ if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE))
++ err = au_cpup_wh(dentry, bdst, len, file);
++ else {
++ struct au_cpup_wh_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .bdst = bdst,
++ .len = len,
++ .file = file
++ };
++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ if (h_orph) {
++ mutex_unlock(&h_tmpdir->i_mutex);
++ /* todo: au_h_open_post()? */
++ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0);
++ au_set_h_dptr(parent, bdst, h_parent);
++ }
++ iput(h_dir);
++ dput(parent);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * generic routine for both of copy-up and copy-down.
++ */
++/* cf. revalidate function in file.c */
++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst,
++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent, void *arg),
++ void *arg)
++{
++ int err;
++ struct au_pin pin;
++ struct dentry *d, *parent, *h_parent, *real_parent;
++
++ err = 0;
++ parent = dget_parent(dentry);
++ if (IS_ROOT(parent))
++ goto out;
++
++ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2,
++ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE);
++
++ /* do not use au_dpage */
++ real_parent = parent;
++ while (1) {
++ dput(parent);
++ parent = dget_parent(dentry);
++ h_parent = au_h_dptr(parent, bdst);
++ if (h_parent)
++ goto out; /* success */
++
++ /* find top dir which is necessary to cpup */
++ do {
++ d = parent;
++ dput(parent);
++ parent = dget_parent(d);
++ di_read_lock_parent3(parent, !AuLock_IR);
++ h_parent = au_h_dptr(parent, bdst);
++ di_read_unlock(parent, !AuLock_IR);
++ } while (!h_parent);
++
++ if (d != real_parent)
++ di_write_lock_child3(d);
++
++ /* somebody else might create while we were sleeping */
++ if (!au_h_dptr(d, bdst) || !au_h_dptr(d, bdst)->d_inode) {
++ if (au_h_dptr(d, bdst))
++ au_update_dbstart(d);
++
++ au_pin_set_dentry(&pin, d);
++ err = au_do_pin(&pin);
++ if (!err) {
++ err = cp(d, bdst, h_parent, arg);
++ au_unpin(&pin);
++ }
++ }
++
++ if (d != real_parent)
++ di_write_unlock(d);
++ if (unlikely(err))
++ break;
++ }
++
++out:
++ dput(parent);
++ return err;
++}
++
++static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent __maybe_unused ,
++ void *arg __maybe_unused)
++{
++ return au_sio_cpup_simple(dentry, bdst, -1, AuCpup_DTIME);
++}
++
++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst)
++{
++ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL);
++}
++
++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst)
++{
++ int err;
++ struct dentry *parent;
++ struct inode *dir;
++
++ parent = dget_parent(dentry);
++ dir = parent->d_inode;
++ err = 0;
++ if (au_h_iptr(dir, bdst))
++ goto out;
++
++ di_read_unlock(parent, AuLock_IR);
++ di_write_lock_parent(parent);
++ /* someone else might change our inode while we were sleeping */
++ if (!au_h_iptr(dir, bdst))
++ err = au_cpup_dirs(dentry, bdst);
++ di_downgrade_lock(parent, AuLock_IR);
++
++out:
++ dput(parent);
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/cpup.h linux-2.6.36/fs/aufs/cpup.h
+--- linux-2.6.36.orig/fs/aufs/cpup.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/cpup.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,83 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * copy-up/down functions
++ */
++
++#ifndef __AUFS_CPUP_H__
++#define __AUFS_CPUP_H__
++
++#ifdef __KERNEL__
++
++#include <linux/path.h>
++#include <linux/time.h>
++#include <linux/aufs_type.h>
++
++struct inode;
++struct file;
++
++void au_cpup_attr_flags(struct inode *dst, struct inode *src);
++void au_cpup_attr_timesizes(struct inode *inode);
++void au_cpup_attr_nlink(struct inode *inode, int force);
++void au_cpup_attr_changeable(struct inode *inode);
++void au_cpup_igen(struct inode *inode, struct inode *h_inode);
++void au_cpup_attr_all(struct inode *inode, int force);
++
++/* ---------------------------------------------------------------------- */
++
++/* cpup flags */
++#define AuCpup_DTIME 1 /* do dtime_store/revert */
++#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino,
++ for link(2) */
++#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name)
++#define au_fset_cpup(flags, name) \
++ do { (flags) |= AuCpup_##name; } while (0)
++#define au_fclr_cpup(flags, name) \
++ do { (flags) &= ~AuCpup_##name; } while (0)
++
++int au_copy_file(struct file *dst, struct file *src, loff_t len);
++int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent);
++int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ unsigned int flags);
++int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ struct file *file);
++
++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst,
++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent, void *arg),
++ void *arg);
++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst);
++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst);
++
++/* ---------------------------------------------------------------------- */
++
++/* keep timestamps when copyup */
++struct au_dtime {
++ struct dentry *dt_dentry;
++ struct path dt_h_path;
++ struct timespec dt_atime, dt_mtime;
++};
++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry,
++ struct path *h_path);
++void au_dtime_revert(struct au_dtime *dt);
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_CPUP_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/dbgaufs.c linux-2.6.36/fs/aufs/dbgaufs.c
+--- linux-2.6.36.orig/fs/aufs/dbgaufs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/dbgaufs.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,334 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * debugfs interface
++ */
++
++#include <linux/debugfs.h>
++#include "aufs.h"
++
++#ifndef CONFIG_SYSFS
++#error DEBUG_FS depends upon SYSFS
++#endif
++
++static struct dentry *dbgaufs;
++static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH;
++
++/* 20 is max digits length of ulong 64 */
++struct dbgaufs_arg {
++ int n;
++ char a[20 * 4];
++};
++
++/*
++ * common function for all XINO files
++ */
++static int dbgaufs_xi_release(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ kfree(file->private_data);
++ return 0;
++}
++
++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt)
++{
++ int err;
++ struct kstat st;
++ struct dbgaufs_arg *p;
++
++ err = -ENOMEM;
++ p = kmalloc(sizeof(*p), GFP_NOFS);
++ if (unlikely(!p))
++ goto out;
++
++ err = 0;
++ p->n = 0;
++ file->private_data = p;
++ if (!xf)
++ goto out;
++
++ err = vfs_getattr(xf->f_vfsmnt, xf->f_dentry, &st);
++ if (!err) {
++ if (do_fcnt)
++ p->n = snprintf
++ (p->a, sizeof(p->a), "%ld, %llux%lu %lld\n",
++ (long)file_count(xf), st.blocks, st.blksize,
++ (long long)st.size);
++ else
++ p->n = snprintf(p->a, sizeof(p->a), "%llux%lu %lld\n",
++ st.blocks, st.blksize,
++ (long long)st.size);
++ AuDebugOn(p->n >= sizeof(p->a));
++ } else {
++ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err);
++ err = 0;
++ }
++
++out:
++ return err;
++
++}
++
++static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct dbgaufs_arg *p;
++
++ p = file->private_data;
++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int dbgaufs_xib_open(struct inode *inode, struct file *file)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++
++ sbinfo = inode->i_private;
++ sb = sbinfo->si_sb;
++ si_noflush_read_lock(sb);
++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0);
++ si_read_unlock(sb);
++ return err;
++}
++
++static const struct file_operations dbgaufs_xib_fop = {
++ .owner = THIS_MODULE,
++ .open = dbgaufs_xib_open,
++ .release = dbgaufs_xi_release,
++ .read = dbgaufs_xi_read
++};
++
++/* ---------------------------------------------------------------------- */
++
++#define DbgaufsXi_PREFIX "xi"
++
++static int dbgaufs_xino_open(struct inode *inode, struct file *file)
++{
++ int err;
++ long l;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++ struct file *xf;
++ struct qstr *name;
++
++ err = -ENOENT;
++ xf = NULL;
++ name = &file->f_dentry->d_name;
++ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX)
++ || memcmp(name->name, DbgaufsXi_PREFIX,
++ sizeof(DbgaufsXi_PREFIX) - 1)))
++ goto out;
++ err = strict_strtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l);
++ if (unlikely(err))
++ goto out;
++
++ sbinfo = inode->i_private;
++ sb = sbinfo->si_sb;
++ si_noflush_read_lock(sb);
++ if (l <= au_sbend(sb)) {
++ xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file;
++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1);
++ } else
++ err = -ENOENT;
++ si_read_unlock(sb);
++
++out:
++ return err;
++}
++
++static const struct file_operations dbgaufs_xino_fop = {
++ .owner = THIS_MODULE,
++ .open = dbgaufs_xino_open,
++ .release = dbgaufs_xi_release,
++ .read = dbgaufs_xi_read
++};
++
++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
++{
++ aufs_bindex_t bend;
++ struct au_branch *br;
++ struct au_xino_file *xi;
++
++ if (!au_sbi(sb)->si_dbgaufs)
++ return;
++
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ xi = &br->br_xino;
++ if (xi->xi_dbgaufs) {
++ debugfs_remove(xi->xi_dbgaufs);
++ xi->xi_dbgaufs = NULL;
++ }
++ }
++}
++
++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
++{
++ struct au_sbinfo *sbinfo;
++ struct dentry *parent;
++ struct au_branch *br;
++ struct au_xino_file *xi;
++ aufs_bindex_t bend;
++ char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */
++
++ sbinfo = au_sbi(sb);
++ parent = sbinfo->si_dbgaufs;
++ if (!parent)
++ return;
++
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex);
++ br = au_sbr(sb, bindex);
++ xi = &br->br_xino;
++ AuDebugOn(xi->xi_dbgaufs);
++ xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent,
++ sbinfo, &dbgaufs_xino_fop);
++ /* ignore an error */
++ if (unlikely(!xi->xi_dbgaufs))
++ AuWarn1("failed %s under debugfs\n", name);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_EXPORT
++static int dbgaufs_xigen_open(struct inode *inode, struct file *file)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++
++ sbinfo = inode->i_private;
++ sb = sbinfo->si_sb;
++ si_noflush_read_lock(sb);
++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0);
++ si_read_unlock(sb);
++ return err;
++}
++
++static const struct file_operations dbgaufs_xigen_fop = {
++ .owner = THIS_MODULE,
++ .open = dbgaufs_xigen_open,
++ .release = dbgaufs_xi_release,
++ .read = dbgaufs_xi_read
++};
++
++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo)
++{
++ int err;
++
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++
++ err = -EIO;
++ sbinfo->si_dbgaufs_xigen = debugfs_create_file
++ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
++ &dbgaufs_xigen_fop);
++ if (sbinfo->si_dbgaufs_xigen)
++ err = 0;
++
++ return err;
++}
++#else
++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo)
++{
++ return 0;
++}
++#endif /* CONFIG_AUFS_EXPORT */
++
++/* ---------------------------------------------------------------------- */
++
++void dbgaufs_si_fin(struct au_sbinfo *sbinfo)
++{
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++
++ debugfs_remove_recursive(sbinfo->si_dbgaufs);
++ sbinfo->si_dbgaufs = NULL;
++ kobject_put(&sbinfo->si_kobj);
++}
++
++int dbgaufs_si_init(struct au_sbinfo *sbinfo)
++{
++ int err;
++ char name[SysaufsSiNameLen];
++
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++
++ err = -ENOENT;
++ if (!dbgaufs) {
++ AuErr1("/debug/aufs is uninitialized\n");
++ goto out;
++ }
++
++ err = -EIO;
++ sysaufs_name(sbinfo, name);
++ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs);
++ if (unlikely(!sbinfo->si_dbgaufs))
++ goto out;
++ kobject_get(&sbinfo->si_kobj);
++
++ sbinfo->si_dbgaufs_xib = debugfs_create_file
++ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
++ &dbgaufs_xib_fop);
++ if (unlikely(!sbinfo->si_dbgaufs_xib))
++ goto out_dir;
++
++ err = dbgaufs_xigen_init(sbinfo);
++ if (!err)
++ goto out; /* success */
++
++out_dir:
++ dbgaufs_si_fin(sbinfo);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void dbgaufs_fin(void)
++{
++ debugfs_remove(dbgaufs);
++}
++
++int __init dbgaufs_init(void)
++{
++ int err;
++
++ err = -EIO;
++ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL);
++ if (dbgaufs)
++ err = 0;
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/dbgaufs.h linux-2.6.36/fs/aufs/dbgaufs.h
+--- linux-2.6.36.orig/fs/aufs/dbgaufs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/dbgaufs.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * debugfs interface
++ */
++
++#ifndef __DBGAUFS_H__
++#define __DBGAUFS_H__
++
++#ifdef __KERNEL__
++
++#include <linux/init.h>
++#include <linux/aufs_type.h>
++
++struct super_block;
++struct au_sbinfo;
++
++#ifdef CONFIG_DEBUG_FS
++/* dbgaufs.c */
++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex);
++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex);
++void dbgaufs_si_fin(struct au_sbinfo *sbinfo);
++int dbgaufs_si_init(struct au_sbinfo *sbinfo);
++void dbgaufs_fin(void);
++int __init dbgaufs_init(void);
++#else
++AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex)
++AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex)
++AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo)
++AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo)
++AuStubVoid(dbgaufs_fin, void)
++AuStubInt0(__init dbgaufs_init, void)
++#endif /* CONFIG_DEBUG_FS */
++
++#endif /* __KERNEL__ */
++#endif /* __DBGAUFS_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/dcsub.c linux-2.6.36/fs/aufs/dcsub.c
+--- linux-2.6.36.orig/fs/aufs/dcsub.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/dcsub.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,210 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sub-routines for dentry cache
++ */
++
++#include "aufs.h"
++
++static void au_dpage_free(struct au_dpage *dpage)
++{
++ int i;
++ struct dentry **p;
++
++ p = dpage->dentries;
++ for (i = 0; i < dpage->ndentry; i++)
++ dput(*p++);
++ free_page((unsigned long)dpage->dentries);
++}
++
++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp)
++{
++ int err;
++ void *p;
++
++ err = -ENOMEM;
++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp);
++ if (unlikely(!dpages->dpages))
++ goto out;
++
++ p = (void *)__get_free_page(gfp);
++ if (unlikely(!p))
++ goto out_dpages;
++
++ dpages->dpages[0].ndentry = 0;
++ dpages->dpages[0].dentries = p;
++ dpages->ndpage = 1;
++ return 0; /* success */
++
++out_dpages:
++ kfree(dpages->dpages);
++out:
++ return err;
++}
++
++void au_dpages_free(struct au_dcsub_pages *dpages)
++{
++ int i;
++ struct au_dpage *p;
++
++ p = dpages->dpages;
++ for (i = 0; i < dpages->ndpage; i++)
++ au_dpage_free(p++);
++ kfree(dpages->dpages);
++}
++
++static int au_dpages_append(struct au_dcsub_pages *dpages,
++ struct dentry *dentry, gfp_t gfp)
++{
++ int err, sz;
++ struct au_dpage *dpage;
++ void *p;
++
++ dpage = dpages->dpages + dpages->ndpage - 1;
++ sz = PAGE_SIZE / sizeof(dentry);
++ if (unlikely(dpage->ndentry >= sz)) {
++ AuLabel(new dpage);
++ err = -ENOMEM;
++ sz = dpages->ndpage * sizeof(*dpages->dpages);
++ p = au_kzrealloc(dpages->dpages, sz,
++ sz + sizeof(*dpages->dpages), gfp);
++ if (unlikely(!p))
++ goto out;
++
++ dpages->dpages = p;
++ dpage = dpages->dpages + dpages->ndpage;
++ p = (void *)__get_free_page(gfp);
++ if (unlikely(!p))
++ goto out;
++
++ dpage->ndentry = 0;
++ dpage->dentries = p;
++ dpages->ndpage++;
++ }
++
++ /* d_count can be zero */
++ dpage->dentries[dpage->ndentry++] = dget_locked(dentry);
++ return 0; /* success */
++
++out:
++ return err;
++}
++
++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
++ au_dpages_test test, void *arg)
++{
++ int err;
++ struct dentry *this_parent = root;
++ struct list_head *next;
++ struct super_block *sb = root->d_sb;
++
++ err = 0;
++ spin_lock(&dcache_lock);
++repeat:
++ next = this_parent->d_subdirs.next;
++resume:
++ if (this_parent->d_sb == sb
++ && !IS_ROOT(this_parent)
++ && au_di(this_parent)
++ && (!test || test(this_parent, arg))) {
++ err = au_dpages_append(dpages, this_parent, GFP_ATOMIC);
++ if (unlikely(err))
++ goto out;
++ }
++
++ while (next != &this_parent->d_subdirs) {
++ struct list_head *tmp = next;
++ struct dentry *dentry = list_entry(tmp, struct dentry,
++ d_u.d_child);
++ next = tmp->next;
++ if (!list_empty(&dentry->d_subdirs)) {
++ this_parent = dentry;
++ goto repeat;
++ }
++ if (dentry->d_sb == sb
++ && au_di(dentry)
++ && (!test || test(dentry, arg))) {
++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
++ if (unlikely(err))
++ goto out;
++ }
++ }
++
++ if (this_parent != root) {
++ next = this_parent->d_u.d_child.next;
++ this_parent = this_parent->d_parent; /* dcache_lock is locked */
++ goto resume;
++ }
++out:
++ spin_unlock(&dcache_lock);
++ return err;
++}
++
++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
++ int do_include, au_dpages_test test, void *arg)
++{
++ int err;
++
++ err = 0;
++ spin_lock(&dcache_lock);
++ if (do_include && (!test || test(dentry, arg))) {
++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
++ if (unlikely(err))
++ goto out;
++ }
++ while (!IS_ROOT(dentry)) {
++ dentry = dentry->d_parent; /* dcache_lock is locked */
++ if (!test || test(dentry, arg)) {
++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
++ if (unlikely(err))
++ break;
++ }
++ }
++
++out:
++ spin_unlock(&dcache_lock);
++
++ return err;
++}
++
++static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg)
++{
++ return au_di(dentry) && dentry->d_sb == arg;
++}
++
++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
++ struct dentry *dentry, int do_include)
++{
++ return au_dcsub_pages_rev(dpages, dentry, do_include,
++ au_dcsub_dpages_aufs, dentry->d_sb);
++}
++
++int au_test_subdir(struct dentry *d1, struct dentry *d2)
++{
++ struct path path[2] = {
++ {
++ .dentry = d1
++ },
++ {
++ .dentry = d2
++ }
++ };
++
++ return path_is_under(path + 0, path + 1);
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/dcsub.h linux-2.6.36/fs/aufs/dcsub.h
+--- linux-2.6.36.orig/fs/aufs/dcsub.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/dcsub.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,100 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sub-routines for dentry cache
++ */
++
++#ifndef __AUFS_DCSUB_H__
++#define __AUFS_DCSUB_H__
++
++#ifdef __KERNEL__
++
++#include <linux/dcache.h>
++#include <linux/fs.h>
++#include <linux/types.h>
++
++struct dentry;
++
++struct au_dpage {
++ int ndentry;
++ struct dentry **dentries;
++};
++
++struct au_dcsub_pages {
++ int ndpage;
++ struct au_dpage *dpages;
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* dcsub.c */
++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp);
++void au_dpages_free(struct au_dcsub_pages *dpages);
++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg);
++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
++ au_dpages_test test, void *arg);
++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
++ int do_include, au_dpages_test test, void *arg);
++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
++ struct dentry *dentry, int do_include);
++int au_test_subdir(struct dentry *d1, struct dentry *d2);
++
++/* ---------------------------------------------------------------------- */
++
++static inline int au_d_removed(struct dentry *d)
++{
++ return !IS_ROOT(d) && d_unhashed(d);
++}
++
++static inline int au_d_hashed_positive(struct dentry *d)
++{
++ int err;
++ struct inode *inode = d->d_inode;
++ err = 0;
++ if (unlikely(d_unhashed(d) || !inode || !inode->i_nlink))
++ err = -ENOENT;
++ return err;
++}
++
++static inline int au_d_alive(struct dentry *d)
++{
++ int err;
++ struct inode *inode;
++ err = 0;
++ if (!IS_ROOT(d))
++ err = au_d_hashed_positive(d);
++ else {
++ inode = d->d_inode;
++ if (unlikely(au_d_removed(d) || !inode || !inode->i_nlink))
++ err = -ENOENT;
++ }
++ return err;
++}
++
++static inline int au_alive_dir(struct dentry *d)
++{
++ int err;
++ err = au_d_alive(d);
++ if (unlikely(err || IS_DEADDIR(d->d_inode)))
++ err = -ENOENT;
++ return err;
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DCSUB_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/debug.c linux-2.6.36/fs/aufs/debug.c
+--- linux-2.6.36.orig/fs/aufs/debug.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/debug.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,468 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * debug print functions
++ */
++
++#include <linux/module.h>
++#include <linux/vt_kern.h>
++#include "aufs.h"
++
++int aufs_debug;
++MODULE_PARM_DESC(debug, "debug print");
++module_param_named(debug, aufs_debug, int, S_IRUGO | S_IWUSR | S_IWGRP);
++
++char *au_plevel = KERN_DEBUG;
++#define dpri(fmt, ...) do { \
++ if ((au_plevel \
++ && strcmp(au_plevel, KERN_DEBUG)) \
++ || au_debug_test()) \
++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \
++} while (0)
++
++/* ---------------------------------------------------------------------- */
++
++void au_dpri_whlist(struct au_nhash *whlist)
++{
++ unsigned long ul, n;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++
++ n = whlist->nh_num;
++ head = whlist->nh_head;
++ for (ul = 0; ul < n; ul++) {
++ hlist_for_each_entry(tpos, pos, head, wh_hash)
++ dpri("b%d, %.*s, %d\n",
++ tpos->wh_bindex,
++ tpos->wh_str.len, tpos->wh_str.name,
++ tpos->wh_str.len);
++ head++;
++ }
++}
++
++void au_dpri_vdir(struct au_vdir *vdir)
++{
++ unsigned long ul;
++ union au_vdir_deblk_p p;
++ unsigned char *o;
++
++ if (!vdir || IS_ERR(vdir)) {
++ dpri("err %ld\n", PTR_ERR(vdir));
++ return;
++ }
++
++ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %lu\n",
++ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk,
++ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version);
++ for (ul = 0; ul < vdir->vd_nblk; ul++) {
++ p.deblk = vdir->vd_deblk[ul];
++ o = p.deblk;
++ dpri("[%lu]: %p\n", ul, o);
++ }
++}
++
++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode,
++ struct dentry *wh)
++{
++ char *n = NULL;
++ int l = 0;
++
++ if (!inode || IS_ERR(inode)) {
++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode));
++ return -1;
++ }
++
++ /* the type of i_blocks depends upon CONFIG_LSF */
++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long)
++ && sizeof(inode->i_blocks) != sizeof(u64));
++ if (wh) {
++ n = (void *)wh->d_name.name;
++ l = wh->d_name.len;
++ }
++
++ dpri("i%d: i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu,"
++ " ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n",
++ bindex,
++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??",
++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode,
++ i_size_read(inode), (unsigned long long)inode->i_blocks,
++ (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff,
++ inode->i_mapping ? inode->i_mapping->nrpages : 0,
++ inode->i_state, inode->i_flags, inode->i_version,
++ inode->i_generation,
++ l ? ", wh " : "", l, n);
++ return 0;
++}
++
++void au_dpri_inode(struct inode *inode)
++{
++ struct au_iinfo *iinfo;
++ aufs_bindex_t bindex;
++ int err;
++
++ err = do_pri_inode(-1, inode, NULL);
++ if (err || !au_test_aufs(inode->i_sb))
++ return;
++
++ iinfo = au_ii(inode);
++ if (!iinfo)
++ return;
++ dpri("i-1: bstart %d, bend %d, gen %d\n",
++ iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode));
++ if (iinfo->ii_bstart < 0)
++ return;
++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++)
++ do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode,
++ iinfo->ii_hinode[0 + bindex].hi_whdentry);
++}
++
++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry)
++{
++ struct dentry *wh = NULL;
++
++ if (!dentry || IS_ERR(dentry)) {
++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry));
++ return -1;
++ }
++ /* do not call dget_parent() here */
++ dpri("d%d: %.*s?/%.*s, %s, cnt %d, flags 0x%x\n",
++ bindex,
++ AuDLNPair(dentry->d_parent), AuDLNPair(dentry),
++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??",
++ atomic_read(&dentry->d_count), dentry->d_flags);
++ if (bindex >= 0 && dentry->d_inode && au_test_aufs(dentry->d_sb)) {
++ struct au_iinfo *iinfo = au_ii(dentry->d_inode);
++ if (iinfo)
++ wh = iinfo->ii_hinode[0 + bindex].hi_whdentry;
++ }
++ do_pri_inode(bindex, dentry->d_inode, wh);
++ return 0;
++}
++
++void au_dpri_dentry(struct dentry *dentry)
++{
++ struct au_dinfo *dinfo;
++ aufs_bindex_t bindex;
++ int err;
++ struct au_hdentry *hdp;
++
++ err = do_pri_dentry(-1, dentry);
++ if (err || !au_test_aufs(dentry->d_sb))
++ return;
++
++ dinfo = au_di(dentry);
++ if (!dinfo)
++ return;
++ dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n",
++ dinfo->di_bstart, dinfo->di_bend,
++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry));
++ if (dinfo->di_bstart < 0)
++ return;
++ hdp = dinfo->di_hdentry;
++ for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++)
++ do_pri_dentry(bindex, hdp[0 + bindex].hd_dentry);
++}
++
++static int do_pri_file(aufs_bindex_t bindex, struct file *file)
++{
++ char a[32];
++
++ if (!file || IS_ERR(file)) {
++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file));
++ return -1;
++ }
++ a[0] = 0;
++ if (bindex < 0
++ && file->f_dentry
++ && au_test_aufs(file->f_dentry->d_sb)
++ && au_fi(file))
++ snprintf(a, sizeof(a), ", gen %d, mmapped %d",
++ au_figen(file), !!au_fi(file)->fi_hvmop);
++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n",
++ bindex, file->f_mode, file->f_flags, (long)file_count(file),
++ file->f_version, file->f_pos, a);
++ if (file->f_dentry)
++ do_pri_dentry(bindex, file->f_dentry);
++ return 0;
++}
++
++void au_dpri_file(struct file *file)
++{
++ struct au_finfo *finfo;
++ struct au_fidir *fidir;
++ struct au_hfile *hfile;
++ aufs_bindex_t bindex;
++ int err;
++
++ err = do_pri_file(-1, file);
++ if (err || !file->f_dentry || !au_test_aufs(file->f_dentry->d_sb))
++ return;
++
++ finfo = au_fi(file);
++ if (!finfo)
++ return;
++ if (finfo->fi_btop < 0)
++ return;
++ fidir = finfo->fi_hdir;
++ if (!fidir)
++ do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file);
++ else
++ for (bindex = finfo->fi_btop;
++ bindex >= 0 && bindex <= fidir->fd_bbot;
++ bindex++) {
++ hfile = fidir->fd_hfile + bindex;
++ do_pri_file(bindex, hfile ? hfile->hf_file : NULL);
++ }
++}
++
++static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br)
++{
++ struct vfsmount *mnt;
++ struct super_block *sb;
++
++ if (!br || IS_ERR(br))
++ goto out;
++ mnt = br->br_mnt;
++ if (!mnt || IS_ERR(mnt))
++ goto out;
++ sb = mnt->mnt_sb;
++ if (!sb || IS_ERR(sb))
++ goto out;
++
++ dpri("s%d: {perm 0x%x, cnt %d, wbr %p}, "
++ "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, "
++ "xino %d\n",
++ bindex, br->br_perm, atomic_read(&br->br_count), br->br_wbr,
++ au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev),
++ sb->s_flags, sb->s_count,
++ atomic_read(&sb->s_active), !!br->br_xino.xi_file);
++ return 0;
++
++out:
++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br));
++ return -1;
++}
++
++void au_dpri_sb(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++ aufs_bindex_t bindex;
++ int err;
++ /* to reuduce stack size */
++ struct {
++ struct vfsmount mnt;
++ struct au_branch fake;
++ } *a;
++
++ /* this function can be called from magic sysrq */
++ a = kzalloc(sizeof(*a), GFP_ATOMIC);
++ if (unlikely(!a)) {
++ dpri("no memory\n");
++ return;
++ }
++
++ a->mnt.mnt_sb = sb;
++ a->fake.br_perm = 0;
++ a->fake.br_mnt = &a->mnt;
++ a->fake.br_xino.xi_file = NULL;
++ atomic_set(&a->fake.br_count, 0);
++ smp_mb(); /* atomic_set */
++ err = do_pri_br(-1, &a->fake);
++ kfree(a);
++ dpri("dev 0x%x\n", sb->s_dev);
++ if (err || !au_test_aufs(sb))
++ return;
++
++ sbinfo = au_sbi(sb);
++ if (!sbinfo)
++ return;
++ dpri("nw %d, gen %u, kobj %d\n",
++ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation,
++ atomic_read(&sbinfo->si_kobj.kref.refcount));
++ for (bindex = 0; bindex <= sbinfo->si_bend; bindex++)
++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]);
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_dbg_sleep_jiffy(int jiffy)
++{
++ while (jiffy)
++ jiffy = schedule_timeout_uninterruptible(jiffy);
++}
++
++void au_dbg_iattr(struct iattr *ia)
++{
++#define AuBit(name) if (ia->ia_valid & ATTR_ ## name) \
++ dpri(#name "\n")
++ AuBit(MODE);
++ AuBit(UID);
++ AuBit(GID);
++ AuBit(SIZE);
++ AuBit(ATIME);
++ AuBit(MTIME);
++ AuBit(CTIME);
++ AuBit(ATIME_SET);
++ AuBit(MTIME_SET);
++ AuBit(FORCE);
++ AuBit(ATTR_FLAG);
++ AuBit(KILL_SUID);
++ AuBit(KILL_SGID);
++ AuBit(FILE);
++ AuBit(KILL_PRIV);
++ AuBit(OPEN);
++ AuBit(TIMES_SET);
++#undef AuBit
++ dpri("ia_file %p\n", ia->ia_file);
++}
++
++/* ---------------------------------------------------------------------- */
++
++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line)
++{
++ struct inode *h_inode, *inode = dentry->d_inode;
++ struct dentry *h_dentry;
++ aufs_bindex_t bindex, bend, bi;
++
++ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */)
++ return;
++
++ bend = au_dbend(dentry);
++ bi = au_ibend(inode);
++ if (bi < bend)
++ bend = bi;
++ bindex = au_dbstart(dentry);
++ bi = au_ibstart(inode);
++ if (bi > bindex)
++ bindex = bi;
++
++ for (; bindex <= bend; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++ h_inode = au_h_iptr(inode, bindex);
++ if (unlikely(h_inode != h_dentry->d_inode)) {
++ int old = au_debug_test();
++ if (!old)
++ au_debug(1);
++ AuDbg("b%d, %s:%d\n", bindex, func, line);
++ AuDbgDentry(dentry);
++ AuDbgInode(inode);
++ if (!old)
++ au_debug(0);
++ BUG();
++ }
++ }
++}
++
++void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen)
++{
++ struct dentry *parent;
++
++ parent = dget_parent(dentry);
++ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode));
++ AuDebugOn(IS_ROOT(dentry));
++ AuDebugOn(au_digen_test(parent, sigen));
++ dput(parent);
++}
++
++void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen)
++{
++ struct dentry *parent;
++ struct inode *inode;
++
++ parent = dget_parent(dentry);
++ inode = dentry->d_inode;
++ AuDebugOn(inode && S_ISDIR(dentry->d_inode->i_mode));
++ AuDebugOn(au_digen_test(parent, sigen));
++ dput(parent);
++}
++
++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen)
++{
++ int err, i, j;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ AuDebugOn(err);
++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1);
++ AuDebugOn(err);
++ for (i = dpages.ndpage - 1; !err && i >= 0; i--) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ for (j = dpage->ndentry - 1; !err && j >= 0; j--)
++ AuDebugOn(au_digen_test(dentries[j], sigen));
++ }
++ au_dpages_free(&dpages);
++}
++
++void au_dbg_verify_kthread(void)
++{
++ if (current->flags & PF_WQ_WORKER) {
++ au_dbg_blocked();
++ WARN_ON(1);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_debug_sbinfo_init(struct au_sbinfo *sbinfo __maybe_unused)
++{
++#ifdef AuForceNoPlink
++ au_opt_clr(sbinfo->si_mntflags, PLINK);
++#endif
++#ifdef AuForceNoXino
++ au_opt_clr(sbinfo->si_mntflags, XINO);
++#endif
++#ifdef AuForceNoRefrof
++ au_opt_clr(sbinfo->si_mntflags, REFROF);
++#endif
++#ifdef AuForceHnotify
++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_HNOTIFY);
++#endif
++#ifdef AuForceRd0
++ sbinfo->si_rdblk = 0;
++ sbinfo->si_rdhash = 0;
++#endif
++}
++
++int __init au_debug_init(void)
++{
++ aufs_bindex_t bindex;
++ struct au_vdir_destr destr;
++
++ bindex = -1;
++ AuDebugOn(bindex >= 0);
++
++ destr.len = -1;
++ AuDebugOn(destr.len < NAME_MAX);
++
++#ifdef CONFIG_4KSTACKS
++ pr_warning("CONFIG_4KSTACKS is defined.\n");
++#endif
++
++#ifdef AuForceNoBrs
++ sysaufs_brs = 0;
++#endif
++
++ return 0;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/debug.h linux-2.6.36/fs/aufs/debug.h
+--- linux-2.6.36.orig/fs/aufs/debug.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/debug.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,245 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * debug print functions
++ */
++
++#ifndef __AUFS_DEBUG_H__
++#define __AUFS_DEBUG_H__
++
++#ifdef __KERNEL__
++
++#include <asm/system.h>
++#include <linux/bug.h>
++/* #include <linux/err.h> */
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kallsyms.h>
++/* #include <linux/kernel.h> */
++#include <linux/delay.h>
++/* #include <linux/kd.h> */
++#include <linux/sysrq.h>
++#include <linux/aufs_type.h>
++
++#include <asm/system.h>
++
++#ifdef CONFIG_AUFS_DEBUG
++#define AuDebugOn(a) BUG_ON(a)
++
++/* module parameter */
++extern int aufs_debug;
++static inline void au_debug(int n)
++{
++ aufs_debug = n;
++ smp_mb();
++}
++
++static inline int au_debug_test(void)
++{
++ return aufs_debug;
++}
++#else
++#define AuDebugOn(a) do {} while (0)
++AuStubVoid(au_debug, int n)
++AuStubInt0(au_debug_test, void)
++#endif /* CONFIG_AUFS_DEBUG */
++
++/* ---------------------------------------------------------------------- */
++
++/* debug print */
++
++#define AuDbg(fmt, ...) do { \
++ if (au_debug_test()) \
++ pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \
++} while (0)
++#define AuLabel(l) AuDbg(#l "\n")
++#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__)
++#define AuWarn1(fmt, ...) do { \
++ static unsigned char _c; \
++ if (!_c++) \
++ pr_warning(fmt, ##__VA_ARGS__); \
++} while (0)
++
++#define AuErr1(fmt, ...) do { \
++ static unsigned char _c; \
++ if (!_c++) \
++ pr_err(fmt, ##__VA_ARGS__); \
++} while (0)
++
++#define AuIOErr1(fmt, ...) do { \
++ static unsigned char _c; \
++ if (!_c++) \
++ AuIOErr(fmt, ##__VA_ARGS__); \
++} while (0)
++
++#define AuUnsupportMsg "This operation is not supported." \
++ " Please report this application to aufs-users ML."
++#define AuUnsupport(fmt, ...) do { \
++ pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \
++ dump_stack(); \
++} while (0)
++
++#define AuTraceErr(e) do { \
++ if (unlikely((e) < 0)) \
++ AuDbg("err %d\n", (int)(e)); \
++} while (0)
++
++#define AuTraceErrPtr(p) do { \
++ if (IS_ERR(p)) \
++ AuDbg("err %ld\n", PTR_ERR(p)); \
++} while (0)
++
++/* dirty macros for debug print, use with "%.*s" and caution */
++#define AuLNPair(qstr) (qstr)->len, (qstr)->name
++#define AuDLNPair(d) AuLNPair(&(d)->d_name)
++
++/* ---------------------------------------------------------------------- */
++
++struct au_sbinfo;
++struct au_finfo;
++struct dentry;
++#ifdef CONFIG_AUFS_DEBUG
++extern char *au_plevel;
++struct au_nhash;
++void au_dpri_whlist(struct au_nhash *whlist);
++struct au_vdir;
++void au_dpri_vdir(struct au_vdir *vdir);
++struct inode;
++void au_dpri_inode(struct inode *inode);
++void au_dpri_dentry(struct dentry *dentry);
++struct file;
++void au_dpri_file(struct file *filp);
++struct super_block;
++void au_dpri_sb(struct super_block *sb);
++
++void au_dbg_sleep_jiffy(int jiffy);
++struct iattr;
++void au_dbg_iattr(struct iattr *ia);
++
++#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__)
++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line);
++void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen);
++void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen);
++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen);
++void au_dbg_verify_kthread(void);
++
++int __init au_debug_init(void);
++void au_debug_sbinfo_init(struct au_sbinfo *sbinfo);
++#define AuDbgWhlist(w) do { \
++ AuDbg(#w "\n"); \
++ au_dpri_whlist(w); \
++} while (0)
++
++#define AuDbgVdir(v) do { \
++ AuDbg(#v "\n"); \
++ au_dpri_vdir(v); \
++} while (0)
++
++#define AuDbgInode(i) do { \
++ AuDbg(#i "\n"); \
++ au_dpri_inode(i); \
++} while (0)
++
++#define AuDbgDentry(d) do { \
++ AuDbg(#d "\n"); \
++ au_dpri_dentry(d); \
++} while (0)
++
++#define AuDbgFile(f) do { \
++ AuDbg(#f "\n"); \
++ au_dpri_file(f); \
++} while (0)
++
++#define AuDbgSb(sb) do { \
++ AuDbg(#sb "\n"); \
++ au_dpri_sb(sb); \
++} while (0)
++
++#define AuDbgSleep(sec) do { \
++ AuDbg("sleep %d sec\n", sec); \
++ ssleep(sec); \
++} while (0)
++
++#define AuDbgSleepJiffy(jiffy) do { \
++ AuDbg("sleep %d jiffies\n", jiffy); \
++ au_dbg_sleep_jiffy(jiffy); \
++} while (0)
++
++#define AuDbgIAttr(ia) do { \
++ AuDbg("ia_valid 0x%x\n", (ia)->ia_valid); \
++ au_dbg_iattr(ia); \
++} while (0)
++
++#define AuDbgSym(addr) do { \
++ char sym[KSYM_SYMBOL_LEN]; \
++ sprint_symbol(sym, (unsigned long)addr); \
++ AuDbg("%s\n", sym); \
++} while (0)
++
++#define AuInfoSym(addr) do { \
++ char sym[KSYM_SYMBOL_LEN]; \
++ sprint_symbol(sym, (unsigned long)addr); \
++ AuInfo("%s\n", sym); \
++} while (0)
++#else
++AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry)
++AuStubVoid(au_dbg_verify_dir_parent, struct dentry *dentry, unsigned int sigen)
++AuStubVoid(au_dbg_verify_nondir_parent, struct dentry *dentry,
++ unsigned int sigen)
++AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen)
++AuStubVoid(au_dbg_verify_kthread, void)
++AuStubInt0(__init au_debug_init, void)
++AuStubVoid(au_debug_sbinfo_init, struct au_sbinfo *sbinfo)
++
++#define AuDbgWhlist(w) do {} while (0)
++#define AuDbgVdir(v) do {} while (0)
++#define AuDbgInode(i) do {} while (0)
++#define AuDbgDentry(d) do {} while (0)
++#define AuDbgFile(f) do {} while (0)
++#define AuDbgSb(sb) do {} while (0)
++#define AuDbgSleep(sec) do {} while (0)
++#define AuDbgSleepJiffy(jiffy) do {} while (0)
++#define AuDbgIAttr(ia) do {} while (0)
++#define AuDbgSym(addr) do {} while (0)
++#define AuInfoSym(addr) do {} while (0)
++#endif /* CONFIG_AUFS_DEBUG */
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_MAGIC_SYSRQ
++int __init au_sysrq_init(void);
++void au_sysrq_fin(void);
++
++#ifdef CONFIG_HW_CONSOLE
++#define au_dbg_blocked() do { \
++ WARN_ON(1); \
++ handle_sysrq('w'); \
++} while (0)
++#else
++AuStubVoid(au_dbg_blocked, void)
++#endif
++
++#else
++AuStubInt0(__init au_sysrq_init, void)
++AuStubVoid(au_sysrq_fin, void)
++AuStubVoid(au_dbg_blocked, void)
++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DEBUG_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/dentry.c linux-2.6.36/fs/aufs/dentry.c
+--- linux-2.6.36.orig/fs/aufs/dentry.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/dentry.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,1131 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * lookup and dentry operations
++ */
++
++#include <linux/namei.h>
++#include "aufs.h"
++
++static void au_h_nd(struct nameidata *h_nd, struct nameidata *nd)
++{
++ if (nd) {
++ *h_nd = *nd;
++
++ /*
++ * gave up supporting LOOKUP_CREATE/OPEN for lower fs,
++ * due to whiteout and branch permission.
++ */
++ h_nd->flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE
++ | LOOKUP_FOLLOW | LOOKUP_EXCL);
++ /* unnecessary? */
++ h_nd->intent.open.file = NULL;
++ } else
++ memset(h_nd, 0, sizeof(*h_nd));
++}
++
++struct au_lkup_one_args {
++ struct dentry **errp;
++ struct qstr *name;
++ struct dentry *h_parent;
++ struct au_branch *br;
++ struct nameidata *nd;
++};
++
++struct dentry *au_lkup_one(struct qstr *name, struct dentry *h_parent,
++ struct au_branch *br, struct nameidata *nd)
++{
++ struct dentry *h_dentry;
++ int err;
++ struct nameidata h_nd;
++
++ if (au_test_fs_null_nd(h_parent->d_sb))
++ return vfsub_lookup_one_len(name->name, h_parent, name->len);
++
++ au_h_nd(&h_nd, nd);
++ h_nd.path.dentry = h_parent;
++ h_nd.path.mnt = br->br_mnt;
++
++ err = __lookup_one_len(name->name, &h_nd.last, NULL, name->len);
++ h_dentry = ERR_PTR(err);
++ if (!err) {
++ path_get(&h_nd.path);
++ h_dentry = vfsub_lookup_hash(&h_nd);
++ path_put(&h_nd.path);
++ }
++
++ AuTraceErrPtr(h_dentry);
++ return h_dentry;
++}
++
++static void au_call_lkup_one(void *args)
++{
++ struct au_lkup_one_args *a = args;
++ *a->errp = au_lkup_one(a->name, a->h_parent, a->br, a->nd);
++}
++
++#define AuLkup_ALLOW_NEG 1
++#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name)
++#define au_fset_lkup(flags, name) \
++ do { (flags) |= AuLkup_##name; } while (0)
++#define au_fclr_lkup(flags, name) \
++ do { (flags) &= ~AuLkup_##name; } while (0)
++
++struct au_do_lookup_args {
++ unsigned int flags;
++ mode_t type;
++ struct nameidata *nd;
++};
++
++/*
++ * returns positive/negative dentry, NULL or an error.
++ * NULL means whiteout-ed or not-found.
++ */
++static struct dentry*
++au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
++ aufs_bindex_t bindex, struct qstr *wh_name,
++ struct au_do_lookup_args *args)
++{
++ struct dentry *h_dentry;
++ struct inode *h_inode, *inode;
++ struct au_branch *br;
++ int wh_found, opq;
++ unsigned char wh_able;
++ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG);
++
++ wh_found = 0;
++ br = au_sbr(dentry->d_sb, bindex);
++ wh_able = !!au_br_whable(br->br_perm);
++ if (wh_able)
++ wh_found = au_wh_test(h_parent, wh_name, br, /*try_sio*/0);
++ h_dentry = ERR_PTR(wh_found);
++ if (!wh_found)
++ goto real_lookup;
++ if (unlikely(wh_found < 0))
++ goto out;
++
++ /* We found a whiteout */
++ /* au_set_dbend(dentry, bindex); */
++ au_set_dbwh(dentry, bindex);
++ if (!allow_neg)
++ return NULL; /* success */
++
++real_lookup:
++ h_dentry = au_lkup_one(&dentry->d_name, h_parent, br, args->nd);
++ if (IS_ERR(h_dentry))
++ goto out;
++
++ h_inode = h_dentry->d_inode;
++ if (!h_inode) {
++ if (!allow_neg)
++ goto out_neg;
++ } else if (wh_found
++ || (args->type && args->type != (h_inode->i_mode & S_IFMT)))
++ goto out_neg;
++
++ if (au_dbend(dentry) <= bindex)
++ au_set_dbend(dentry, bindex);
++ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry))
++ au_set_dbstart(dentry, bindex);
++ au_set_h_dptr(dentry, bindex, h_dentry);
++
++ inode = dentry->d_inode;
++ if (!h_inode || !S_ISDIR(h_inode->i_mode) || !wh_able
++ || (inode && !S_ISDIR(inode->i_mode)))
++ goto out; /* success */
++
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ opq = au_diropq_test(h_dentry, br);
++ mutex_unlock(&h_inode->i_mutex);
++ if (opq > 0)
++ au_set_dbdiropq(dentry, bindex);
++ else if (unlikely(opq < 0)) {
++ au_set_h_dptr(dentry, bindex, NULL);
++ h_dentry = ERR_PTR(opq);
++ }
++ goto out;
++
++out_neg:
++ dput(h_dentry);
++ h_dentry = NULL;
++out:
++ return h_dentry;
++}
++
++static int au_test_shwh(struct super_block *sb, const struct qstr *name)
++{
++ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH)
++ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)))
++ return -EPERM;
++ return 0;
++}
++
++/*
++ * returns the number of lower positive dentries,
++ * otherwise an error.
++ * can be called at unlinking with @type is zero.
++ */
++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type,
++ struct nameidata *nd)
++{
++ int npositive, err;
++ aufs_bindex_t bindex, btail, bdiropq;
++ unsigned char isdir;
++ struct qstr whname;
++ struct au_do_lookup_args args = {
++ .flags = 0,
++ .type = type,
++ .nd = nd
++ };
++ const struct qstr *name = &dentry->d_name;
++ struct dentry *parent;
++ struct inode *inode;
++
++ err = au_test_shwh(dentry->d_sb, name);
++ if (unlikely(err))
++ goto out;
++
++ err = au_wh_name_alloc(&whname, name);
++ if (unlikely(err))
++ goto out;
++
++ inode = dentry->d_inode;
++ isdir = !!(inode && S_ISDIR(inode->i_mode));
++ if (!type)
++ au_fset_lkup(args.flags, ALLOW_NEG);
++
++ npositive = 0;
++ parent = dget_parent(dentry);
++ btail = au_dbtaildir(parent);
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ struct dentry *h_parent, *h_dentry;
++ struct inode *h_inode, *h_dir;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry) {
++ if (h_dentry->d_inode)
++ npositive++;
++ if (type != S_IFDIR)
++ break;
++ continue;
++ }
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent)
++ continue;
++ h_dir = h_parent->d_inode;
++ if (!h_dir || !S_ISDIR(h_dir->i_mode))
++ continue;
++
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname,
++ &args);
++ mutex_unlock(&h_dir->i_mutex);
++ err = PTR_ERR(h_dentry);
++ if (IS_ERR(h_dentry))
++ goto out_parent;
++ au_fclr_lkup(args.flags, ALLOW_NEG);
++
++ if (au_dbwh(dentry) >= 0)
++ break;
++ if (!h_dentry)
++ continue;
++ h_inode = h_dentry->d_inode;
++ if (!h_inode)
++ continue;
++ npositive++;
++ if (!args.type)
++ args.type = h_inode->i_mode & S_IFMT;
++ if (args.type != S_IFDIR)
++ break;
++ else if (isdir) {
++ /* the type of lower may be different */
++ bdiropq = au_dbdiropq(dentry);
++ if (bdiropq >= 0 && bdiropq <= bindex)
++ break;
++ }
++ }
++
++ if (npositive) {
++ AuLabel(positive);
++ au_update_dbstart(dentry);
++ }
++ err = npositive;
++ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE)
++ && au_dbstart(dentry) < 0)) {
++ err = -EIO;
++ AuIOErr("both of real entry and whiteout found, %.*s, err %d\n",
++ AuDLNPair(dentry), err);
++ }
++
++out_parent:
++ dput(parent);
++ kfree(whname.name);
++out:
++ return err;
++}
++
++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent,
++ struct au_branch *br)
++{
++ struct dentry *dentry;
++ int wkq_err;
++
++ if (!au_test_h_perm_sio(parent->d_inode, MAY_EXEC))
++ dentry = au_lkup_one(name, parent, br, /*nd*/NULL);
++ else {
++ struct au_lkup_one_args args = {
++ .errp = &dentry,
++ .name = name,
++ .h_parent = parent,
++ .br = br,
++ .nd = NULL
++ };
++
++ wkq_err = au_wkq_wait(au_call_lkup_one, &args);
++ if (unlikely(wkq_err))
++ dentry = ERR_PTR(wkq_err);
++ }
++
++ return dentry;
++}
++
++/*
++ * lookup @dentry on @bindex which should be negative.
++ */
++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ int err;
++ struct dentry *parent, *h_parent, *h_dentry;
++
++ parent = dget_parent(dentry);
++ h_parent = au_h_dptr(parent, bindex);
++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent,
++ au_sbr(dentry->d_sb, bindex));
++ err = PTR_ERR(h_dentry);
++ if (IS_ERR(h_dentry))
++ goto out;
++ if (unlikely(h_dentry->d_inode)) {
++ err = -EIO;
++ AuIOErr("%.*s should be negative on b%d.\n",
++ AuDLNPair(h_dentry), bindex);
++ dput(h_dentry);
++ goto out;
++ }
++
++ err = 0;
++ if (bindex < au_dbstart(dentry))
++ au_set_dbstart(dentry, bindex);
++ if (au_dbend(dentry) < bindex)
++ au_set_dbend(dentry, bindex);
++ au_set_h_dptr(dentry, bindex, h_dentry);
++
++out:
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* subset of struct inode */
++struct au_iattr {
++ unsigned long i_ino;
++ /* unsigned int i_nlink; */
++ uid_t i_uid;
++ gid_t i_gid;
++ u64 i_version;
++/*
++ loff_t i_size;
++ blkcnt_t i_blocks;
++*/
++ umode_t i_mode;
++};
++
++static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode)
++{
++ ia->i_ino = h_inode->i_ino;
++ /* ia->i_nlink = h_inode->i_nlink; */
++ ia->i_uid = h_inode->i_uid;
++ ia->i_gid = h_inode->i_gid;
++ ia->i_version = h_inode->i_version;
++/*
++ ia->i_size = h_inode->i_size;
++ ia->i_blocks = h_inode->i_blocks;
++*/
++ ia->i_mode = (h_inode->i_mode & S_IFMT);
++}
++
++static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode)
++{
++ return ia->i_ino != h_inode->i_ino
++ /* || ia->i_nlink != h_inode->i_nlink */
++ || ia->i_uid != h_inode->i_uid
++ || ia->i_gid != h_inode->i_gid
++ || ia->i_version != h_inode->i_version
++/*
++ || ia->i_size != h_inode->i_size
++ || ia->i_blocks != h_inode->i_blocks
++*/
++ || ia->i_mode != (h_inode->i_mode & S_IFMT);
++}
++
++static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent,
++ struct au_branch *br)
++{
++ int err;
++ struct au_iattr ia;
++ struct inode *h_inode;
++ struct dentry *h_d;
++ struct super_block *h_sb;
++
++ err = 0;
++ memset(&ia, -1, sizeof(ia));
++ h_sb = h_dentry->d_sb;
++ h_inode = h_dentry->d_inode;
++ if (h_inode)
++ au_iattr_save(&ia, h_inode);
++ else if (au_test_nfs(h_sb) || au_test_fuse(h_sb))
++ /* nfs d_revalidate may return 0 for negative dentry */
++ /* fuse d_revalidate always return 0 for negative dentry */
++ goto out;
++
++ /* main purpose is namei.c:cached_lookup() and d_revalidate */
++ h_d = au_lkup_one(&h_dentry->d_name, h_parent, br, /*nd*/NULL);
++ err = PTR_ERR(h_d);
++ if (IS_ERR(h_d))
++ goto out;
++
++ err = 0;
++ if (unlikely(h_d != h_dentry
++ || h_d->d_inode != h_inode
++ || (h_inode && au_iattr_test(&ia, h_inode))))
++ err = au_busy_or_stale();
++ dput(h_d);
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
++ struct dentry *h_parent, struct au_branch *br)
++{
++ int err;
++
++ err = 0;
++ if (udba == AuOpt_UDBA_REVAL) {
++ IMustLock(h_dir);
++ err = (h_dentry->d_parent->d_inode != h_dir);
++ } else if (udba == AuOpt_UDBA_HNOTIFY)
++ err = au_h_verify_dentry(h_dentry, h_parent, br);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent)
++{
++ int err;
++ aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq;
++ struct au_hdentry tmp, *p, *q;
++ struct au_dinfo *dinfo;
++ struct super_block *sb;
++
++ DiMustWriteLock(dentry);
++
++ sb = dentry->d_sb;
++ dinfo = au_di(dentry);
++ bend = dinfo->di_bend;
++ bwh = dinfo->di_bwh;
++ bdiropq = dinfo->di_bdiropq;
++ p = dinfo->di_hdentry + dinfo->di_bstart;
++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) {
++ if (!p->hd_dentry)
++ continue;
++
++ new_bindex = au_br_index(sb, p->hd_id);
++ if (new_bindex == bindex)
++ continue;
++
++ if (dinfo->di_bwh == bindex)
++ bwh = new_bindex;
++ if (dinfo->di_bdiropq == bindex)
++ bdiropq = new_bindex;
++ if (new_bindex < 0) {
++ au_hdput(p);
++ p->hd_dentry = NULL;
++ continue;
++ }
++
++ /* swap two lower dentries, and loop again */
++ q = dinfo->di_hdentry + new_bindex;
++ tmp = *q;
++ *q = *p;
++ *p = tmp;
++ if (tmp.hd_dentry) {
++ bindex--;
++ p--;
++ }
++ }
++
++ dinfo->di_bwh = -1;
++ if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh))
++ dinfo->di_bwh = bwh;
++
++ dinfo->di_bdiropq = -1;
++ if (bdiropq >= 0
++ && bdiropq <= au_sbend(sb)
++ && au_sbr_whable(sb, bdiropq))
++ dinfo->di_bdiropq = bdiropq;
++
++ err = -EIO;
++ dinfo->di_bstart = -1;
++ dinfo->di_bend = -1;
++ bend = au_dbend(parent);
++ p = dinfo->di_hdentry;
++ for (bindex = 0; bindex <= bend; bindex++, p++)
++ if (p->hd_dentry) {
++ dinfo->di_bstart = bindex;
++ break;
++ }
++
++ if (dinfo->di_bstart >= 0) {
++ p = dinfo->di_hdentry + bend;
++ for (bindex = bend; bindex >= 0; bindex--, p--)
++ if (p->hd_dentry) {
++ dinfo->di_bend = bindex;
++ err = 0;
++ break;
++ }
++ }
++
++ return err;
++}
++
++static void au_do_hide(struct dentry *dentry)
++{
++ struct inode *inode;
++
++ inode = dentry->d_inode;
++ if (inode) {
++ if (!S_ISDIR(inode->i_mode)) {
++ if (inode->i_nlink && !d_unhashed(dentry))
++ drop_nlink(inode);
++ } else {
++ clear_nlink(inode);
++ /* stop next lookup */
++ inode->i_flags |= S_DEAD;
++ }
++ smp_mb(); /* necessary? */
++ }
++ d_drop(dentry);
++}
++
++static int au_hide_children(struct dentry *parent)
++{
++ int err, i, j, ndentry;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry *dentry;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_dcsub_pages(&dpages, parent, NULL, NULL);
++ if (unlikely(err))
++ goto out_dpages;
++
++ /* in reverse order */
++ for (i = dpages.ndpage - 1; i >= 0; i--) {
++ dpage = dpages.dpages + i;
++ ndentry = dpage->ndentry;
++ for (j = ndentry - 1; j >= 0; j--) {
++ dentry = dpage->dentries[j];
++ if (dentry != parent)
++ au_do_hide(dentry);
++ }
++ }
++
++out_dpages:
++ au_dpages_free(&dpages);
++out:
++ return err;
++}
++
++static void au_hide(struct dentry *dentry)
++{
++ int err;
++ struct inode *inode;
++
++ AuDbgDentry(dentry);
++ inode = dentry->d_inode;
++ if (inode && S_ISDIR(inode->i_mode)) {
++ /* shrink_dcache_parent(dentry); */
++ err = au_hide_children(dentry);
++ if (unlikely(err))
++ AuIOErr("%.*s, failed hiding children, ignored %d\n",
++ AuDLNPair(dentry), err);
++ }
++ au_do_hide(dentry);
++}
++
++/*
++ * By adding a dirty branch, a cached dentry may be affected in various ways.
++ *
++ * a dirty branch is added
++ * - on the top of layers
++ * - in the middle of layers
++ * - to the bottom of layers
++ *
++ * on the added branch there exists
++ * - a whiteout
++ * - a diropq
++ * - a same named entry
++ * + exist
++ * * negative --> positive
++ * * positive --> positive
++ * - type is unchanged
++ * - type is changed
++ * + doesn't exist
++ * * negative --> negative
++ * * positive --> negative (rejected by au_br_del() for non-dir case)
++ * - none
++ */
++static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo,
++ struct au_dinfo *tmp)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct {
++ struct dentry *dentry;
++ struct inode *inode;
++ mode_t mode;
++ } orig_h, tmp_h;
++ struct au_hdentry *hd;
++ struct inode *inode, *h_inode;
++ struct dentry *h_dentry;
++
++ err = 0;
++ AuDebugOn(dinfo->di_bstart < 0);
++ orig_h.dentry = dinfo->di_hdentry[dinfo->di_bstart].hd_dentry;
++ orig_h.inode = orig_h.dentry->d_inode;
++ orig_h.mode = 0;
++ if (orig_h.inode)
++ orig_h.mode = orig_h.inode->i_mode & S_IFMT;
++ memset(&tmp_h, 0, sizeof(tmp_h));
++ if (tmp->di_bstart >= 0) {
++ tmp_h.dentry = tmp->di_hdentry[tmp->di_bstart].hd_dentry;
++ tmp_h.inode = tmp_h.dentry->d_inode;
++ if (tmp_h.inode)
++ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT;
++ }
++
++ inode = dentry->d_inode;
++ if (!orig_h.inode) {
++ AuDbg("nagative originally\n");
++ if (inode) {
++ au_hide(dentry);
++ goto out;
++ }
++ AuDebugOn(inode);
++ AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
++ AuDebugOn(dinfo->di_bdiropq != -1);
++
++ if (!tmp_h.inode) {
++ AuDbg("negative --> negative\n");
++ /* should have only one negative lower */
++ if (tmp->di_bstart >= 0
++ && tmp->di_bstart < dinfo->di_bstart) {
++ AuDebugOn(tmp->di_bstart != tmp->di_bend);
++ AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
++ au_set_h_dptr(dentry, dinfo->di_bstart, NULL);
++ au_di_cp(dinfo, tmp);
++ hd = tmp->di_hdentry + tmp->di_bstart;
++ au_set_h_dptr(dentry, tmp->di_bstart,
++ dget(hd->hd_dentry));
++ }
++ au_dbg_verify_dinode(dentry);
++ } else {
++ AuDbg("negative --> positive\n");
++ /*
++ * similar to the behaviour of creating with bypassing
++ * aufs.
++ * unhash it in order to force an error in the
++ * succeeding create operation.
++ * we should not set S_DEAD here.
++ */
++ d_drop(dentry);
++ /* au_di_swap(tmp, dinfo); */
++ au_dbg_verify_dinode(dentry);
++ }
++ } else {
++ AuDbg("positive originally\n");
++ /* inode may be NULL */
++ AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode);
++ if (!tmp_h.inode) {
++ AuDbg("positive --> negative\n");
++ /* or bypassing aufs */
++ au_hide(dentry);
++ if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_bstart)
++ dinfo->di_bwh = tmp->di_bwh;
++ if (inode)
++ err = au_refresh_hinode_self(inode);
++ au_dbg_verify_dinode(dentry);
++ } else if (orig_h.mode == tmp_h.mode) {
++ AuDbg("positive --> positive, same type\n");
++ if (!S_ISDIR(orig_h.mode)
++ && dinfo->di_bstart > tmp->di_bstart) {
++ /*
++ * similar to the behaviour of removing and
++ * creating.
++ */
++ au_hide(dentry);
++ if (inode)
++ err = au_refresh_hinode_self(inode);
++ au_dbg_verify_dinode(dentry);
++ } else {
++ /* fill empty slots */
++ if (dinfo->di_bstart > tmp->di_bstart)
++ dinfo->di_bstart = tmp->di_bstart;
++ if (dinfo->di_bend < tmp->di_bend)
++ dinfo->di_bend = tmp->di_bend;
++ dinfo->di_bwh = tmp->di_bwh;
++ dinfo->di_bdiropq = tmp->di_bdiropq;
++ hd = tmp->di_hdentry;
++ bend = dinfo->di_bend;
++ for (bindex = tmp->di_bstart; bindex <= bend;
++ bindex++) {
++ if (au_h_dptr(dentry, bindex))
++ continue;
++ h_dentry = hd[bindex].hd_dentry;
++ if (!h_dentry)
++ continue;
++ h_inode = h_dentry->d_inode;
++ AuDebugOn(!h_inode);
++ AuDebugOn(orig_h.mode
++ != (h_inode->i_mode
++ & S_IFMT));
++ au_set_h_dptr(dentry, bindex,
++ dget(h_dentry));
++ }
++ err = au_refresh_hinode(inode, dentry);
++ au_dbg_verify_dinode(dentry);
++ }
++ } else {
++ AuDbg("positive --> positive, different type\n");
++ /* similar to the behaviour of removing and creating */
++ au_hide(dentry);
++ if (inode)
++ err = au_refresh_hinode_self(inode);
++ au_dbg_verify_dinode(dentry);
++ }
++ }
++
++out:
++ return err;
++}
++
++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent)
++{
++ int err, ebrange;
++ unsigned int sigen;
++ struct au_dinfo *dinfo, *tmp;
++ struct super_block *sb;
++ struct inode *inode;
++
++ DiMustWriteLock(dentry);
++ AuDebugOn(IS_ROOT(dentry));
++ AuDebugOn(!parent->d_inode);
++
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ sigen = au_sigen(sb);
++ err = au_digen_test(parent, sigen);
++ if (unlikely(err))
++ goto out;
++
++ dinfo = au_di(dentry);
++ err = au_di_realloc(dinfo, au_sbend(sb) + 1);
++ if (unlikely(err))
++ goto out;
++ ebrange = au_dbrange_test(dentry);
++ if (!ebrange)
++ ebrange = au_do_refresh_hdentry(dentry, parent);
++
++ if (d_unhashed(dentry) || ebrange) {
++ AuDebugOn(au_dbstart(dentry) < 0 && au_dbend(dentry) >= 0);
++ if (inode)
++ err = au_refresh_hinode_self(inode);
++ au_dbg_verify_dinode(dentry);
++ if (!err)
++ goto out_dgen; /* success */
++ goto out;
++ }
++
++ /* temporary dinfo */
++ AuDbgDentry(dentry);
++ err = -ENOMEM;
++ tmp = au_di_alloc(sb, AuLsc_DI_TMP);
++ if (unlikely(!tmp))
++ goto out;
++ au_di_swap(tmp, dinfo);
++ /* returns the number of positive dentries */
++ /*
++ * if current working dir is removed, it returns an error.
++ * but the dentry is legal.
++ */
++ err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0, /*nd*/NULL);
++ AuDbgDentry(dentry);
++ au_di_swap(tmp, dinfo);
++ if (err == -ENOENT)
++ err = 0;
++ if (err >= 0) {
++ /* compare/refresh by dinfo */
++ AuDbgDentry(dentry);
++ err = au_refresh_by_dinfo(dentry, dinfo, tmp);
++ au_dbg_verify_dinode(dentry);
++ AuTraceErr(err);
++ }
++ au_rw_write_unlock(&tmp->di_rwsem);
++ au_di_free(tmp);
++ if (unlikely(err))
++ goto out;
++
++out_dgen:
++ au_update_digen(dentry);
++out:
++ if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) {
++ AuIOErr("failed refreshing %.*s, %d\n",
++ AuDLNPair(dentry), err);
++ AuDbgDentry(dentry);
++ }
++ AuTraceErr(err);
++ return err;
++}
++
++static noinline_for_stack
++int au_do_h_d_reval(struct dentry *h_dentry, struct nameidata *nd,
++ struct dentry *dentry, aufs_bindex_t bindex)
++{
++ int err, valid;
++ int (*reval)(struct dentry *, struct nameidata *);
++
++ err = 0;
++ reval = NULL;
++ if (h_dentry->d_op)
++ reval = h_dentry->d_op->d_revalidate;
++ if (!reval)
++ goto out;
++
++ AuDbg("b%d\n", bindex);
++ if (au_test_fs_null_nd(h_dentry->d_sb))
++ /* it may return tri-state */
++ valid = reval(h_dentry, NULL);
++ else {
++ struct nameidata h_nd;
++ int locked;
++ struct dentry *parent;
++
++ au_h_nd(&h_nd, nd);
++ parent = nd->path.dentry;
++ locked = (nd && nd->path.dentry != dentry);
++ if (locked)
++ di_read_lock_parent(parent, AuLock_IR);
++ BUG_ON(bindex > au_dbend(parent));
++ h_nd.path.dentry = au_h_dptr(parent, bindex);
++ BUG_ON(!h_nd.path.dentry);
++ h_nd.path.mnt = au_sbr(parent->d_sb, bindex)->br_mnt;
++ path_get(&h_nd.path);
++ valid = reval(h_dentry, &h_nd);
++ path_put(&h_nd.path);
++ if (locked)
++ di_read_unlock(parent, AuLock_IR);
++ }
++
++ if (unlikely(valid < 0))
++ err = valid;
++ else if (!valid)
++ err = -EINVAL;
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++/* todo: remove this */
++static int h_d_revalidate(struct dentry *dentry, struct inode *inode,
++ struct nameidata *nd, int do_udba)
++{
++ int err;
++ umode_t mode, h_mode;
++ aufs_bindex_t bindex, btail, bstart, ibs, ibe;
++ unsigned char plus, unhashed, is_root, h_plus;
++ struct inode *h_inode, *h_cached_inode;
++ struct dentry *h_dentry;
++ struct qstr *name, *h_name;
++
++ err = 0;
++ plus = 0;
++ mode = 0;
++ ibs = -1;
++ ibe = -1;
++ unhashed = !!d_unhashed(dentry);
++ is_root = !!IS_ROOT(dentry);
++ name = &dentry->d_name;
++
++ /*
++ * Theoretically, REVAL test should be unnecessary in case of
++ * {FS,I}NOTIFY.
++ * But {fs,i}notify doesn't fire some necessary events,
++ * IN_ATTRIB for atime/nlink/pageio
++ * IN_DELETE for NFS dentry
++ * Let's do REVAL test too.
++ */
++ if (do_udba && inode) {
++ mode = (inode->i_mode & S_IFMT);
++ plus = (inode->i_nlink > 0);
++ ibs = au_ibstart(inode);
++ ibe = au_ibend(inode);
++ }
++
++ bstart = au_dbstart(dentry);
++ btail = bstart;
++ if (inode && S_ISDIR(inode->i_mode))
++ btail = au_dbtaildir(dentry);
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++
++ AuDbg("b%d, %.*s\n", bindex, AuDLNPair(h_dentry));
++ h_name = &h_dentry->d_name;
++ if (unlikely(do_udba
++ && !is_root
++ && (unhashed != !!d_unhashed(h_dentry)
++ || name->len != h_name->len
++ || memcmp(name->name, h_name->name, name->len))
++ )) {
++ AuDbg("unhash 0x%x 0x%x, %.*s %.*s\n",
++ unhashed, d_unhashed(h_dentry),
++ AuDLNPair(dentry), AuDLNPair(h_dentry));
++ goto err;
++ }
++
++ err = au_do_h_d_reval(h_dentry, nd, dentry, bindex);
++ if (unlikely(err))
++ /* do not goto err, to keep the errno */
++ break;
++
++ /* todo: plink too? */
++ if (!do_udba)
++ continue;
++
++ /* UDBA tests */
++ h_inode = h_dentry->d_inode;
++ if (unlikely(!!inode != !!h_inode))
++ goto err;
++
++ h_plus = plus;
++ h_mode = mode;
++ h_cached_inode = h_inode;
++ if (h_inode) {
++ h_mode = (h_inode->i_mode & S_IFMT);
++ h_plus = (h_inode->i_nlink > 0);
++ }
++ if (inode && ibs <= bindex && bindex <= ibe)
++ h_cached_inode = au_h_iptr(inode, bindex);
++
++ if (unlikely(plus != h_plus
++ || mode != h_mode
++ || h_cached_inode != h_inode))
++ goto err;
++ continue;
++
++ err:
++ err = -EINVAL;
++ break;
++ }
++
++ return err;
++}
++
++/* todo: consolidate with do_refresh() and au_reval_for_attr() */
++static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen)
++{
++ int err;
++ struct dentry *parent;
++
++ if (!au_digen_test(dentry, sigen))
++ return 0;
++
++ parent = dget_parent(dentry);
++ di_read_lock_parent(parent, AuLock_IR);
++ AuDebugOn(au_digen_test(parent, sigen));
++ au_dbg_verify_gen(parent, sigen);
++ err = au_refresh_dentry(dentry, parent);
++ di_read_unlock(parent, AuLock_IR);
++ dput(parent);
++ AuTraceErr(err);
++ return err;
++}
++
++int au_reval_dpath(struct dentry *dentry, unsigned int sigen)
++{
++ int err;
++ struct dentry *d, *parent;
++ struct inode *inode;
++
++ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR))
++ return simple_reval_dpath(dentry, sigen);
++
++ /* slow loop, keep it simple and stupid */
++ /* cf: au_cpup_dirs() */
++ err = 0;
++ parent = NULL;
++ while (au_digen_test(dentry, sigen)) {
++ d = dentry;
++ while (1) {
++ dput(parent);
++ parent = dget_parent(d);
++ if (!au_digen_test(parent, sigen))
++ break;
++ d = parent;
++ }
++
++ inode = d->d_inode;
++ if (d != dentry)
++ di_write_lock_child2(d);
++
++ /* someone might update our dentry while we were sleeping */
++ if (au_digen_test(d, sigen)) {
++ /*
++ * todo: consolidate with simple_reval_dpath(),
++ * do_refresh() and au_reval_for_attr().
++ */
++ di_read_lock_parent(parent, AuLock_IR);
++ err = au_refresh_dentry(d, parent);
++ di_read_unlock(parent, AuLock_IR);
++ }
++
++ if (d != dentry)
++ di_write_unlock(d);
++ dput(parent);
++ if (unlikely(err))
++ break;
++ }
++
++ return err;
++}
++
++/*
++ * if valid returns 1, otherwise 0.
++ */
++static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
++{
++ int valid, err;
++ unsigned int sigen;
++ unsigned char do_udba;
++ struct super_block *sb;
++ struct inode *inode;
++
++ valid = 0;
++ if (unlikely(!au_di(dentry)))
++ goto out;
++
++ valid = 1;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ /*
++ * todo: very ugly
++ * i_mutex of parent dir may be held,
++ * but we should not return 'invalid' due to busy.
++ */
++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM);
++ if (unlikely(err)) {
++ valid = err;
++ AuTraceErr(err);
++ goto out;
++ }
++ if (unlikely(au_dbrange_test(dentry))) {
++ err = -EINVAL;
++ AuTraceErr(err);
++ goto out_dgrade;
++ }
++
++ sigen = au_sigen(sb);
++ if (au_digen_test(dentry, sigen)) {
++ AuDebugOn(IS_ROOT(dentry));
++ err = au_reval_dpath(dentry, sigen);
++ if (unlikely(err)) {
++ AuTraceErr(err);
++ goto out_dgrade;
++ }
++ }
++ di_downgrade_lock(dentry, AuLock_IR);
++
++ err = -EINVAL;
++ if (inode && (IS_DEADDIR(inode) || !inode->i_nlink))
++ goto out_inval;
++
++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE);
++ if (do_udba && inode) {
++ aufs_bindex_t bstart = au_ibstart(inode);
++ struct inode *h_inode;
++
++ if (bstart >= 0) {
++ h_inode = au_h_iptr(inode, bstart);
++ if (h_inode && au_test_higen(inode, h_inode))
++ goto out_inval;
++ }
++ }
++
++ err = h_d_revalidate(dentry, inode, nd, do_udba);
++ if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) {
++ err = -EIO;
++ AuDbg("both of real entry and whiteout found, %.*s, err %d\n",
++ AuDLNPair(dentry), err);
++ }
++ goto out_inval;
++
++out_dgrade:
++ di_downgrade_lock(dentry, AuLock_IR);
++out_inval:
++ aufs_read_unlock(dentry, AuLock_IR);
++ AuTraceErr(err);
++ valid = !err;
++out:
++ if (!valid) {
++ AuDbg("%.*s invalid, %d\n", AuDLNPair(dentry), valid);
++ d_drop(dentry);
++ }
++ return valid;
++}
++
++static void aufs_d_release(struct dentry *dentry)
++{
++ if (au_di(dentry)) {
++ au_di_fin(dentry);
++ au_hn_di_reinit(dentry);
++ }
++}
++
++const struct dentry_operations aufs_dop = {
++ .d_revalidate = aufs_d_revalidate,
++ .d_release = aufs_d_release
++};
+diff -Nur linux-2.6.36.orig/fs/aufs/dentry.h linux-2.6.36/fs/aufs/dentry.h
+--- linux-2.6.36.orig/fs/aufs/dentry.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/dentry.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,237 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * lookup and dentry operations
++ */
++
++#ifndef __AUFS_DENTRY_H__
++#define __AUFS_DENTRY_H__
++
++#ifdef __KERNEL__
++
++#include <linux/dcache.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++
++struct au_hdentry {
++ struct dentry *hd_dentry;
++ aufs_bindex_t hd_id;
++};
++
++struct au_dinfo {
++ atomic_t di_generation;
++
++ struct au_rwsem di_rwsem;
++ aufs_bindex_t di_bstart, di_bend, di_bwh, di_bdiropq;
++ struct au_hdentry *di_hdentry;
++} ____cacheline_aligned_in_smp;
++
++/* ---------------------------------------------------------------------- */
++
++/* dentry.c */
++extern const struct dentry_operations aufs_dop;
++struct au_branch;
++struct dentry *au_lkup_one(struct qstr *name, struct dentry *h_parent,
++ struct au_branch *br, struct nameidata *nd);
++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent,
++ struct au_branch *br);
++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
++ struct dentry *h_parent, struct au_branch *br);
++
++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type,
++ struct nameidata *nd);
++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex);
++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent);
++int au_reval_dpath(struct dentry *dentry, unsigned int sigen);
++
++/* dinfo.c */
++void au_di_init_once(void *_di);
++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc);
++void au_di_free(struct au_dinfo *dinfo);
++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b);
++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src);
++int au_di_init(struct dentry *dentry);
++void au_di_fin(struct dentry *dentry);
++int au_di_realloc(struct au_dinfo *dinfo, int nbr);
++
++void di_read_lock(struct dentry *d, int flags, unsigned int lsc);
++void di_read_unlock(struct dentry *d, int flags);
++void di_downgrade_lock(struct dentry *d, int flags);
++void di_write_lock(struct dentry *d, unsigned int lsc);
++void di_write_unlock(struct dentry *d);
++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir);
++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir);
++void di_write_unlock2(struct dentry *d1, struct dentry *d2);
++
++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex);
++aufs_bindex_t au_dbtail(struct dentry *dentry);
++aufs_bindex_t au_dbtaildir(struct dentry *dentry);
++
++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_dentry);
++int au_digen_test(struct dentry *dentry, unsigned int sigen);
++int au_dbrange_test(struct dentry *dentry);
++void au_update_digen(struct dentry *dentry);
++void au_update_dbrange(struct dentry *dentry, int do_put_zero);
++void au_update_dbstart(struct dentry *dentry);
++void au_update_dbend(struct dentry *dentry);
++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry);
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_dinfo *au_di(struct dentry *dentry)
++{
++ return dentry->d_fsdata;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* lock subclass for dinfo */
++enum {
++ AuLsc_DI_CHILD, /* child first */
++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */
++ AuLsc_DI_CHILD3, /* copyup dirs */
++ AuLsc_DI_PARENT,
++ AuLsc_DI_PARENT2,
++ AuLsc_DI_PARENT3,
++ AuLsc_DI_TMP /* temp for replacing dinfo */
++};
++
++/*
++ * di_read_lock_child, di_write_lock_child,
++ * di_read_lock_child2, di_write_lock_child2,
++ * di_read_lock_child3, di_write_lock_child3,
++ * di_read_lock_parent, di_write_lock_parent,
++ * di_read_lock_parent2, di_write_lock_parent2,
++ * di_read_lock_parent3, di_write_lock_parent3,
++ */
++#define AuReadLockFunc(name, lsc) \
++static inline void di_read_lock_##name(struct dentry *d, int flags) \
++{ di_read_lock(d, flags, AuLsc_DI_##lsc); }
++
++#define AuWriteLockFunc(name, lsc) \
++static inline void di_write_lock_##name(struct dentry *d) \
++{ di_write_lock(d, AuLsc_DI_##lsc); }
++
++#define AuRWLockFuncs(name, lsc) \
++ AuReadLockFunc(name, lsc) \
++ AuWriteLockFunc(name, lsc)
++
++AuRWLockFuncs(child, CHILD);
++AuRWLockFuncs(child2, CHILD2);
++AuRWLockFuncs(child3, CHILD3);
++AuRWLockFuncs(parent, PARENT);
++AuRWLockFuncs(parent2, PARENT2);
++AuRWLockFuncs(parent3, PARENT3);
++
++#undef AuReadLockFunc
++#undef AuWriteLockFunc
++#undef AuRWLockFuncs
++
++#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem)
++#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem)
++#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem)
++
++/* ---------------------------------------------------------------------- */
++
++/* todo: memory barrier? */
++static inline unsigned int au_digen(struct dentry *d)
++{
++ return atomic_read(&au_di(d)->di_generation);
++}
++
++static inline void au_h_dentry_init(struct au_hdentry *hdentry)
++{
++ hdentry->hd_dentry = NULL;
++}
++
++static inline void au_hdput(struct au_hdentry *hd)
++{
++ if (hd)
++ dput(hd->hd_dentry);
++}
++
++static inline aufs_bindex_t au_dbstart(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bstart;
++}
++
++static inline aufs_bindex_t au_dbend(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bend;
++}
++
++static inline aufs_bindex_t au_dbwh(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bwh;
++}
++
++static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bdiropq;
++}
++
++/* todo: hard/soft set? */
++static inline void au_set_dbstart(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ au_di(dentry)->di_bstart = bindex;
++}
++
++static inline void au_set_dbend(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ au_di(dentry)->di_bend = bindex;
++}
++
++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ /* dbwh can be outside of bstart - bend range */
++ au_di(dentry)->di_bwh = bindex;
++}
++
++static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ au_di(dentry)->di_bdiropq = bindex;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_HNOTIFY
++static inline void au_digen_dec(struct dentry *d)
++{
++ atomic_dec(&au_di(d)->di_generation);
++}
++
++static inline void au_hn_di_reinit(struct dentry *dentry)
++{
++ dentry->d_fsdata = NULL;
++}
++#else
++AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused)
++#endif /* CONFIG_AUFS_HNOTIFY */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DENTRY_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/dinfo.c linux-2.6.36/fs/aufs/dinfo.c
+--- linux-2.6.36.orig/fs/aufs/dinfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/dinfo.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,494 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * dentry private data
++ */
++
++#include "aufs.h"
++
++void au_di_init_once(void *_dinfo)
++{
++ struct au_dinfo *dinfo = _dinfo;
++ static struct lock_class_key aufs_di;
++
++ au_rw_init(&dinfo->di_rwsem);
++ au_rw_class(&dinfo->di_rwsem, &aufs_di);
++}
++
++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc)
++{
++ struct au_dinfo *dinfo;
++ int nbr, i;
++
++ dinfo = au_cache_alloc_dinfo();
++ if (unlikely(!dinfo))
++ goto out;
++
++ nbr = au_sbend(sb) + 1;
++ if (nbr <= 0)
++ nbr = 1;
++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS);
++ if (dinfo->di_hdentry) {
++ au_rw_write_lock_nested(&dinfo->di_rwsem, lsc);
++ dinfo->di_bstart = -1;
++ dinfo->di_bend = -1;
++ dinfo->di_bwh = -1;
++ dinfo->di_bdiropq = -1;
++ for (i = 0; i < nbr; i++)
++ dinfo->di_hdentry[i].hd_id = -1;
++ goto out;
++ }
++
++ au_cache_free_dinfo(dinfo);
++ dinfo = NULL;
++
++out:
++ return dinfo;
++}
++
++void au_di_free(struct au_dinfo *dinfo)
++{
++ struct au_hdentry *p;
++ aufs_bindex_t bend, bindex;
++
++ /* dentry may not be revalidated */
++ bindex = dinfo->di_bstart;
++ if (bindex >= 0) {
++ bend = dinfo->di_bend;
++ p = dinfo->di_hdentry + bindex;
++ while (bindex++ <= bend)
++ au_hdput(p++);
++ }
++ kfree(dinfo->di_hdentry);
++ au_cache_free_dinfo(dinfo);
++}
++
++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b)
++{
++ struct au_hdentry *p;
++ aufs_bindex_t bi;
++
++ AuRwMustWriteLock(&a->di_rwsem);
++ AuRwMustWriteLock(&b->di_rwsem);
++
++#define DiSwap(v, name) \
++ do { \
++ v = a->di_##name; \
++ a->di_##name = b->di_##name; \
++ b->di_##name = v; \
++ } while (0)
++
++ DiSwap(p, hdentry);
++ DiSwap(bi, bstart);
++ DiSwap(bi, bend);
++ DiSwap(bi, bwh);
++ DiSwap(bi, bdiropq);
++ /* smp_mb(); */
++
++#undef DiSwap
++}
++
++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src)
++{
++ AuRwMustWriteLock(&dst->di_rwsem);
++ AuRwMustWriteLock(&src->di_rwsem);
++
++ dst->di_bstart = src->di_bstart;
++ dst->di_bend = src->di_bend;
++ dst->di_bwh = src->di_bwh;
++ dst->di_bdiropq = src->di_bdiropq;
++ /* smp_mb(); */
++}
++
++int au_di_init(struct dentry *dentry)
++{
++ int err;
++ struct super_block *sb;
++ struct au_dinfo *dinfo;
++
++ err = 0;
++ sb = dentry->d_sb;
++ dinfo = au_di_alloc(sb, AuLsc_DI_CHILD);
++ if (dinfo) {
++ atomic_set(&dinfo->di_generation, au_sigen(sb));
++ /* smp_mb(); */ /* atomic_set */
++ dentry->d_op = &aufs_dop;
++ dentry->d_fsdata = dinfo;
++ } else
++ err = -ENOMEM;
++
++ return err;
++}
++
++void au_di_fin(struct dentry *dentry)
++{
++ struct au_dinfo *dinfo;
++
++ dinfo = au_di(dentry);
++ AuRwDestroy(&dinfo->di_rwsem);
++ au_di_free(dinfo);
++}
++
++int au_di_realloc(struct au_dinfo *dinfo, int nbr)
++{
++ int err, sz;
++ struct au_hdentry *hdp;
++
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ err = -ENOMEM;
++ sz = sizeof(*hdp) * (dinfo->di_bend + 1);
++ if (!sz)
++ sz = sizeof(*hdp);
++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS);
++ if (hdp) {
++ dinfo->di_hdentry = hdp;
++ err = 0;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void do_ii_write_lock(struct inode *inode, unsigned int lsc)
++{
++ switch (lsc) {
++ case AuLsc_DI_CHILD:
++ ii_write_lock_child(inode);
++ break;
++ case AuLsc_DI_CHILD2:
++ ii_write_lock_child2(inode);
++ break;
++ case AuLsc_DI_CHILD3:
++ ii_write_lock_child3(inode);
++ break;
++ case AuLsc_DI_PARENT:
++ ii_write_lock_parent(inode);
++ break;
++ case AuLsc_DI_PARENT2:
++ ii_write_lock_parent2(inode);
++ break;
++ case AuLsc_DI_PARENT3:
++ ii_write_lock_parent3(inode);
++ break;
++ default:
++ BUG();
++ }
++}
++
++static void do_ii_read_lock(struct inode *inode, unsigned int lsc)
++{
++ switch (lsc) {
++ case AuLsc_DI_CHILD:
++ ii_read_lock_child(inode);
++ break;
++ case AuLsc_DI_CHILD2:
++ ii_read_lock_child2(inode);
++ break;
++ case AuLsc_DI_CHILD3:
++ ii_read_lock_child3(inode);
++ break;
++ case AuLsc_DI_PARENT:
++ ii_read_lock_parent(inode);
++ break;
++ case AuLsc_DI_PARENT2:
++ ii_read_lock_parent2(inode);
++ break;
++ case AuLsc_DI_PARENT3:
++ ii_read_lock_parent3(inode);
++ break;
++ default:
++ BUG();
++ }
++}
++
++void di_read_lock(struct dentry *d, int flags, unsigned int lsc)
++{
++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc);
++ if (d->d_inode) {
++ if (au_ftest_lock(flags, IW))
++ do_ii_write_lock(d->d_inode, lsc);
++ else if (au_ftest_lock(flags, IR))
++ do_ii_read_lock(d->d_inode, lsc);
++ }
++}
++
++void di_read_unlock(struct dentry *d, int flags)
++{
++ if (d->d_inode) {
++ if (au_ftest_lock(flags, IW)) {
++ au_dbg_verify_dinode(d);
++ ii_write_unlock(d->d_inode);
++ } else if (au_ftest_lock(flags, IR)) {
++ au_dbg_verify_dinode(d);
++ ii_read_unlock(d->d_inode);
++ }
++ }
++ au_rw_read_unlock(&au_di(d)->di_rwsem);
++}
++
++void di_downgrade_lock(struct dentry *d, int flags)
++{
++ if (d->d_inode && au_ftest_lock(flags, IR))
++ ii_downgrade_lock(d->d_inode);
++ au_rw_dgrade_lock(&au_di(d)->di_rwsem);
++}
++
++void di_write_lock(struct dentry *d, unsigned int lsc)
++{
++ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc);
++ if (d->d_inode)
++ do_ii_write_lock(d->d_inode, lsc);
++}
++
++void di_write_unlock(struct dentry *d)
++{
++ au_dbg_verify_dinode(d);
++ if (d->d_inode)
++ ii_write_unlock(d->d_inode);
++ au_rw_write_unlock(&au_di(d)->di_rwsem);
++}
++
++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir)
++{
++ AuDebugOn(d1 == d2
++ || d1->d_inode == d2->d_inode
++ || d1->d_sb != d2->d_sb);
++
++ if (isdir && au_test_subdir(d1, d2)) {
++ di_write_lock_child(d1);
++ di_write_lock_child2(d2);
++ } else {
++ /* there should be no races */
++ di_write_lock_child(d2);
++ di_write_lock_child2(d1);
++ }
++}
++
++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir)
++{
++ AuDebugOn(d1 == d2
++ || d1->d_inode == d2->d_inode
++ || d1->d_sb != d2->d_sb);
++
++ if (isdir && au_test_subdir(d1, d2)) {
++ di_write_lock_parent(d1);
++ di_write_lock_parent2(d2);
++ } else {
++ /* there should be no races */
++ di_write_lock_parent(d2);
++ di_write_lock_parent2(d1);
++ }
++}
++
++void di_write_unlock2(struct dentry *d1, struct dentry *d2)
++{
++ di_write_unlock(d1);
++ if (d1->d_inode == d2->d_inode)
++ au_rw_write_unlock(&au_di(d2)->di_rwsem);
++ else
++ di_write_unlock(d2);
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ struct dentry *d;
++
++ DiMustAnyLock(dentry);
++
++ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry))
++ return NULL;
++ AuDebugOn(bindex < 0);
++ d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry;
++ AuDebugOn(d && (atomic_read(&d->d_count) <= 0));
++ return d;
++}
++
++aufs_bindex_t au_dbtail(struct dentry *dentry)
++{
++ aufs_bindex_t bend, bwh;
++
++ bend = au_dbend(dentry);
++ if (0 <= bend) {
++ bwh = au_dbwh(dentry);
++ if (!bwh)
++ return bwh;
++ if (0 < bwh && bwh < bend)
++ return bwh - 1;
++ }
++ return bend;
++}
++
++aufs_bindex_t au_dbtaildir(struct dentry *dentry)
++{
++ aufs_bindex_t bend, bopq;
++
++ bend = au_dbtail(dentry);
++ if (0 <= bend) {
++ bopq = au_dbdiropq(dentry);
++ if (0 <= bopq && bopq < bend)
++ bend = bopq;
++ }
++ return bend;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_dentry)
++{
++ struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex;
++ struct au_branch *br;
++
++ DiMustWriteLock(dentry);
++
++ au_hdput(hd);
++ hd->hd_dentry = h_dentry;
++ if (h_dentry) {
++ br = au_sbr(dentry->d_sb, bindex);
++ hd->hd_id = br->br_id;
++ }
++}
++
++int au_dbrange_test(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bstart, bend;
++
++ err = 0;
++ bstart = au_dbstart(dentry);
++ bend = au_dbend(dentry);
++ if (bstart >= 0)
++ AuDebugOn(bend < 0 && bstart > bend);
++ else {
++ err = -EIO;
++ AuDebugOn(bend >= 0);
++ }
++
++ return err;
++}
++
++int au_digen_test(struct dentry *dentry, unsigned int sigen)
++{
++ int err;
++
++ err = 0;
++ if (unlikely(au_digen(dentry) != sigen
++ || au_iigen_test(dentry->d_inode, sigen)))
++ err = -EIO;
++
++ return err;
++}
++
++void au_update_digen(struct dentry *dentry)
++{
++ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb));
++ /* smp_mb(); */ /* atomic_set */
++}
++
++void au_update_dbrange(struct dentry *dentry, int do_put_zero)
++{
++ struct au_dinfo *dinfo;
++ struct dentry *h_d;
++ struct au_hdentry *hdp;
++
++ DiMustWriteLock(dentry);
++
++ dinfo = au_di(dentry);
++ if (!dinfo || dinfo->di_bstart < 0)
++ return;
++
++ hdp = dinfo->di_hdentry;
++ if (do_put_zero) {
++ aufs_bindex_t bindex, bend;
++
++ bend = dinfo->di_bend;
++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++) {
++ h_d = hdp[0 + bindex].hd_dentry;
++ if (h_d && !h_d->d_inode)
++ au_set_h_dptr(dentry, bindex, NULL);
++ }
++ }
++
++ dinfo->di_bstart = -1;
++ while (++dinfo->di_bstart <= dinfo->di_bend)
++ if (hdp[0 + dinfo->di_bstart].hd_dentry)
++ break;
++ if (dinfo->di_bstart > dinfo->di_bend) {
++ dinfo->di_bstart = -1;
++ dinfo->di_bend = -1;
++ return;
++ }
++
++ dinfo->di_bend++;
++ while (0 <= --dinfo->di_bend)
++ if (hdp[0 + dinfo->di_bend].hd_dentry)
++ break;
++ AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0);
++}
++
++void au_update_dbstart(struct dentry *dentry)
++{
++ aufs_bindex_t bindex, bend;
++ struct dentry *h_dentry;
++
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++ if (h_dentry->d_inode) {
++ au_set_dbstart(dentry, bindex);
++ return;
++ }
++ au_set_h_dptr(dentry, bindex, NULL);
++ }
++}
++
++void au_update_dbend(struct dentry *dentry)
++{
++ aufs_bindex_t bindex, bstart;
++ struct dentry *h_dentry;
++
++ bstart = au_dbstart(dentry);
++ for (bindex = au_dbend(dentry); bindex >= bstart; bindex--) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++ if (h_dentry->d_inode) {
++ au_set_dbend(dentry, bindex);
++ return;
++ }
++ au_set_h_dptr(dentry, bindex, NULL);
++ }
++}
++
++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry)
++{
++ aufs_bindex_t bindex, bend;
++
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++)
++ if (au_h_dptr(dentry, bindex) == h_dentry)
++ return bindex;
++ return -1;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/dir.c linux-2.6.36/fs/aufs/dir.c
+--- linux-2.6.36.orig/fs/aufs/dir.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/dir.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,648 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * directory operations
++ */
++
++#include <linux/file.h>
++#include <linux/fs_stack.h>
++#include "aufs.h"
++
++void au_add_nlink(struct inode *dir, struct inode *h_dir)
++{
++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode));
++
++ dir->i_nlink += h_dir->i_nlink - 2;
++ if (h_dir->i_nlink < 2)
++ dir->i_nlink += 2;
++}
++
++void au_sub_nlink(struct inode *dir, struct inode *h_dir)
++{
++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode));
++
++ dir->i_nlink -= h_dir->i_nlink - 2;
++ if (h_dir->i_nlink < 2)
++ dir->i_nlink -= 2;
++}
++
++loff_t au_dir_size(struct file *file, struct dentry *dentry)
++{
++ loff_t sz;
++ aufs_bindex_t bindex, bend;
++ struct file *h_file;
++ struct dentry *h_dentry;
++
++ sz = 0;
++ if (file) {
++ AuDebugOn(!file->f_dentry);
++ AuDebugOn(!file->f_dentry->d_inode);
++ AuDebugOn(!S_ISDIR(file->f_dentry->d_inode->i_mode));
++
++ bend = au_fbend_dir(file);
++ for (bindex = au_fbstart(file);
++ bindex <= bend && sz < KMALLOC_MAX_SIZE;
++ bindex++) {
++ h_file = au_hf_dir(file, bindex);
++ if (h_file
++ && h_file->f_dentry
++ && h_file->f_dentry->d_inode)
++ sz += i_size_read(h_file->f_dentry->d_inode);
++ }
++ } else {
++ AuDebugOn(!dentry);
++ AuDebugOn(!dentry->d_inode);
++ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode));
++
++ bend = au_dbtaildir(dentry);
++ for (bindex = au_dbstart(dentry);
++ bindex <= bend && sz < KMALLOC_MAX_SIZE;
++ bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry && h_dentry->d_inode)
++ sz += i_size_read(h_dentry->d_inode);
++ }
++ }
++ if (sz < KMALLOC_MAX_SIZE)
++ sz = roundup_pow_of_two(sz);
++ if (sz > KMALLOC_MAX_SIZE)
++ sz = KMALLOC_MAX_SIZE;
++ else if (sz < NAME_MAX) {
++ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX);
++ sz = AUFS_RDBLK_DEF;
++ }
++ return sz;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int reopen_dir(struct file *file)
++{
++ int err;
++ unsigned int flags;
++ aufs_bindex_t bindex, btail, bstart;
++ struct dentry *dentry, *h_dentry;
++ struct file *h_file;
++
++ /* open all lower dirs */
++ dentry = file->f_dentry;
++ bstart = au_dbstart(dentry);
++ for (bindex = au_fbstart(file); bindex < bstart; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++ au_set_fbstart(file, bstart);
++
++ btail = au_dbtaildir(dentry);
++ for (bindex = au_fbend_dir(file); btail < bindex; bindex--)
++ au_set_h_fptr(file, bindex, NULL);
++ au_set_fbend_dir(file, btail);
++
++ flags = vfsub_file_flags(file);
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++ h_file = au_hf_dir(file, bindex);
++ if (h_file)
++ continue;
++
++ h_file = au_h_open(dentry, bindex, flags, file);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out; /* close all? */
++ au_set_h_fptr(file, bindex, h_file);
++ }
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ err = 0;
++
++out:
++ return err;
++}
++
++static int do_open_dir(struct file *file, int flags)
++{
++ int err;
++ aufs_bindex_t bindex, btail;
++ struct dentry *dentry, *h_dentry;
++ struct file *h_file;
++
++ FiMustWriteLock(file);
++
++ dentry = file->f_dentry;
++ err = au_alive_dir(dentry);
++ if (unlikely(err))
++ goto out;
++
++ file->f_version = dentry->d_inode->i_version;
++ bindex = au_dbstart(dentry);
++ au_set_fbstart(file, bindex);
++ btail = au_dbtaildir(dentry);
++ au_set_fbend_dir(file, btail);
++ for (; !err && bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++
++ h_file = au_h_open(dentry, bindex, flags, file);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ break;
++ }
++ au_set_h_fptr(file, bindex, h_file);
++ }
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ if (!err)
++ return 0; /* success */
++
++ /* close all */
++ for (bindex = au_fbstart(file); bindex <= btail; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++ au_set_fbstart(file, -1);
++ au_set_fbend_dir(file, -1);
++
++out:
++ return err;
++}
++
++static int aufs_open_dir(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ int err;
++ struct super_block *sb;
++ struct au_fidir *fidir;
++
++ err = -ENOMEM;
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ fidir = au_fidir_alloc(sb);
++ if (fidir) {
++ err = au_do_open(file, do_open_dir, fidir);
++ if (unlikely(err))
++ kfree(fidir);
++ }
++ si_read_unlock(sb);
++ return err;
++}
++
++static int aufs_release_dir(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ struct au_vdir *vdir_cache;
++ struct super_block *sb;
++ struct au_finfo *finfo;
++ struct au_fidir *fidir;
++ aufs_bindex_t bindex, bend;
++
++ sb = file->f_dentry->d_sb;
++ finfo = au_fi(file);
++ fidir = finfo->fi_hdir;
++ if (fidir) {
++ /* remove me from sb->s_files */
++ file_sb_list_del(file);
++
++ vdir_cache = fidir->fd_vdir_cache; /* lock-free */
++ if (vdir_cache)
++ au_vdir_free(vdir_cache);
++
++ bindex = finfo->fi_btop;
++ if (bindex >= 0) {
++ /*
++ * calls fput() instead of filp_close(),
++ * since no dnotify or lock for the lower file.
++ */
++ bend = fidir->fd_bbot;
++ for (; bindex <= bend; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++ }
++ kfree(fidir);
++ finfo->fi_hdir = NULL;
++ }
++ au_finfo_fin(file);
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_flush_dir(struct file *file, fl_owner_t id)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct file *h_file;
++
++ err = 0;
++ bend = au_fbend_dir(file);
++ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) {
++ h_file = au_hf_dir(file, bindex);
++ if (h_file)
++ err = vfsub_flush(h_file, id);
++ }
++ return err;
++}
++
++static int aufs_flush_dir(struct file *file, fl_owner_t id)
++{
++ return au_do_flush(file, id, au_do_flush_dir);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct inode *inode;
++ struct super_block *sb;
++
++ err = 0;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ IMustLock(inode);
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); !err && bindex <= bend; bindex++) {
++ struct path h_path;
++ struct inode *h_inode;
++
++ if (au_test_ro(sb, bindex, inode))
++ continue;
++ h_path.dentry = au_h_dptr(dentry, bindex);
++ if (!h_path.dentry)
++ continue;
++ h_inode = h_path.dentry->d_inode;
++ if (!h_inode)
++ continue;
++
++ /* no mnt_want_write() */
++ /* cf. fs/nsfd/vfs.c and fs/nfsd/nfs4recover.c */
++ /* todo: inotiry fired? */
++ h_path.mnt = au_sbr_mnt(sb, bindex);
++ mutex_lock(&h_inode->i_mutex);
++ err = filemap_fdatawrite(h_inode->i_mapping);
++ AuDebugOn(!h_inode->i_fop);
++ if (!err && h_inode->i_fop->fsync)
++ err = h_inode->i_fop->fsync(NULL, datasync);
++ if (!err)
++ err = filemap_fdatawrite(h_inode->i_mapping);
++ if (!err)
++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
++ mutex_unlock(&h_inode->i_mutex);
++ }
++
++ return err;
++}
++
++static int au_do_fsync_dir(struct file *file, int datasync)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct file *h_file;
++ struct super_block *sb;
++ struct inode *inode;
++ struct mutex *h_mtx;
++
++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ sb = file->f_dentry->d_sb;
++ inode = file->f_dentry->d_inode;
++ bend = au_fbend_dir(file);
++ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) {
++ h_file = au_hf_dir(file, bindex);
++ if (!h_file || au_test_ro(sb, bindex, inode))
++ continue;
++
++ err = vfs_fsync(h_file, datasync);
++ if (!err) {
++ h_mtx = &h_file->f_dentry->d_inode->i_mutex;
++ mutex_lock(h_mtx);
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL);
++ /*ignore*/
++ mutex_unlock(h_mtx);
++ }
++ }
++
++out:
++ return err;
++}
++
++/*
++ * @file may be NULL
++ */
++static int aufs_fsync_dir(struct file *file, int datasync)
++{
++ int err;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ IMustLock(dentry->d_inode);
++
++ err = 0;
++ sb = dentry->d_sb;
++ si_noflush_read_lock(sb);
++ if (file)
++ err = au_do_fsync_dir(file, datasync);
++ else {
++ di_write_lock_child(dentry);
++ err = au_do_fsync_dir_no_file(dentry, datasync);
++ }
++ au_cpup_attr_timesizes(dentry->d_inode);
++ di_write_unlock(dentry);
++ if (file)
++ fi_write_unlock(file);
++
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++ int err;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ IMustLock(inode);
++
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++ err = au_alive_dir(dentry);
++ if (!err)
++ err = au_vdir_init(file);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ if (!au_test_nfsd()) {
++ err = au_vdir_fill_de(file, dirent, filldir);
++ fsstack_copy_attr_atime(inode,
++ au_h_iptr(inode, au_ibstart(inode)));
++ } else {
++ /*
++ * nfsd filldir may call lookup_one_len(), vfs_getattr(),
++ * encode_fh() and others.
++ */
++ struct inode *h_inode = au_h_iptr(inode, au_ibstart(inode));
++
++ di_read_unlock(dentry, AuLock_IR);
++ si_read_unlock(sb);
++ err = au_vdir_fill_de(file, dirent, filldir);
++ fsstack_copy_attr_atime(inode, h_inode);
++ fi_write_unlock(file);
++
++ AuTraceErr(err);
++ return err;
++ }
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#define AuTestEmpty_WHONLY 1
++#define AuTestEmpty_CALLED (1 << 1)
++#define AuTestEmpty_SHWH (1 << 2)
++#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name)
++#define au_fset_testempty(flags, name) \
++ do { (flags) |= AuTestEmpty_##name; } while (0)
++#define au_fclr_testempty(flags, name) \
++ do { (flags) &= ~AuTestEmpty_##name; } while (0)
++
++#ifndef CONFIG_AUFS_SHWH
++#undef AuTestEmpty_SHWH
++#define AuTestEmpty_SHWH 0
++#endif
++
++struct test_empty_arg {
++ struct au_nhash *whlist;
++ unsigned int flags;
++ int err;
++ aufs_bindex_t bindex;
++};
++
++static int test_empty_cb(void *__arg, const char *__name, int namelen,
++ loff_t offset __maybe_unused, u64 ino,
++ unsigned int d_type)
++{
++ struct test_empty_arg *arg = __arg;
++ char *name = (void *)__name;
++
++ arg->err = 0;
++ au_fset_testempty(arg->flags, CALLED);
++ /* smp_mb(); */
++ if (name[0] == '.'
++ && (namelen == 1 || (name[1] == '.' && namelen == 2)))
++ goto out; /* success */
++
++ if (namelen <= AUFS_WH_PFX_LEN
++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
++ if (au_ftest_testempty(arg->flags, WHONLY)
++ && !au_nhash_test_known_wh(arg->whlist, name, namelen))
++ arg->err = -ENOTEMPTY;
++ goto out;
++ }
++
++ name += AUFS_WH_PFX_LEN;
++ namelen -= AUFS_WH_PFX_LEN;
++ if (!au_nhash_test_known_wh(arg->whlist, name, namelen))
++ arg->err = au_nhash_append_wh
++ (arg->whlist, name, namelen, ino, d_type, arg->bindex,
++ au_ftest_testempty(arg->flags, SHWH));
++
++out:
++ /* smp_mb(); */
++ AuTraceErr(arg->err);
++ return arg->err;
++}
++
++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg)
++{
++ int err;
++ struct file *h_file;
++
++ h_file = au_h_open(dentry, arg->bindex,
++ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE,
++ /*file*/NULL);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out;
++
++ err = 0;
++ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE)
++ && !h_file->f_dentry->d_inode->i_nlink)
++ goto out_put;
++
++ do {
++ arg->err = 0;
++ au_fclr_testempty(arg->flags, CALLED);
++ /* smp_mb(); */
++ err = vfsub_readdir(h_file, test_empty_cb, arg);
++ if (err >= 0)
++ err = arg->err;
++ } while (!err && au_ftest_testempty(arg->flags, CALLED));
++
++out_put:
++ fput(h_file);
++ au_sbr_put(dentry->d_sb, arg->bindex);
++out:
++ return err;
++}
++
++struct do_test_empty_args {
++ int *errp;
++ struct dentry *dentry;
++ struct test_empty_arg *arg;
++};
++
++static void call_do_test_empty(void *args)
++{
++ struct do_test_empty_args *a = args;
++ *a->errp = do_test_empty(a->dentry, a->arg);
++}
++
++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg)
++{
++ int err, wkq_err;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++
++ h_dentry = au_h_dptr(dentry, arg->bindex);
++ h_inode = h_dentry->d_inode;
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ);
++ mutex_unlock(&h_inode->i_mutex);
++ if (!err)
++ err = do_test_empty(dentry, arg);
++ else {
++ struct do_test_empty_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .arg = arg
++ };
++ unsigned int flags = arg->flags;
++
++ wkq_err = au_wkq_wait(call_do_test_empty, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ arg->flags = flags;
++ }
++
++ return err;
++}
++
++int au_test_empty_lower(struct dentry *dentry)
++{
++ int err;
++ unsigned int rdhash;
++ aufs_bindex_t bindex, bstart, btail;
++ struct au_nhash whlist;
++ struct test_empty_arg arg;
++
++ SiMustAnyLock(dentry->d_sb);
++
++ rdhash = au_sbi(dentry->d_sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry));
++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++
++ arg.flags = 0;
++ arg.whlist = &whlist;
++ bstart = au_dbstart(dentry);
++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH))
++ au_fset_testempty(arg.flags, SHWH);
++ arg.bindex = bstart;
++ err = do_test_empty(dentry, &arg);
++ if (unlikely(err))
++ goto out_whlist;
++
++ au_fset_testempty(arg.flags, WHONLY);
++ btail = au_dbtaildir(dentry);
++ for (bindex = bstart + 1; !err && bindex <= btail; bindex++) {
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry && h_dentry->d_inode) {
++ arg.bindex = bindex;
++ err = do_test_empty(dentry, &arg);
++ }
++ }
++
++out_whlist:
++ au_nhash_wh_free(&whlist);
++out:
++ return err;
++}
++
++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist)
++{
++ int err;
++ struct test_empty_arg arg;
++ aufs_bindex_t bindex, btail;
++
++ err = 0;
++ arg.whlist = whlist;
++ arg.flags = AuTestEmpty_WHONLY;
++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH))
++ au_fset_testempty(arg.flags, SHWH);
++ btail = au_dbtaildir(dentry);
++ for (bindex = au_dbstart(dentry); !err && bindex <= btail; bindex++) {
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry && h_dentry->d_inode) {
++ arg.bindex = bindex;
++ err = sio_test_empty(dentry, &arg);
++ }
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++const struct file_operations aufs_dir_fop = {
++ .owner = THIS_MODULE,
++ .read = generic_read_dir,
++ .readdir = aufs_readdir,
++ .unlocked_ioctl = aufs_ioctl_dir,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = aufs_compat_ioctl_dir,
++#endif
++ .open = aufs_open_dir,
++ .release = aufs_release_dir,
++ .flush = aufs_flush_dir,
++ .fsync = aufs_fsync_dir
++};
+diff -Nur linux-2.6.36.orig/fs/aufs/dir.h linux-2.6.36/fs/aufs/dir.h
+--- linux-2.6.36.orig/fs/aufs/dir.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/dir.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,138 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * directory operations
++ */
++
++#ifndef __AUFS_DIR_H__
++#define __AUFS_DIR_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/aufs_type.h>
++
++/* ---------------------------------------------------------------------- */
++
++/* need to be faster and smaller */
++
++struct au_nhash {
++ unsigned int nh_num;
++ struct hlist_head *nh_head;
++};
++
++struct au_vdir_destr {
++ unsigned char len;
++ unsigned char name[0];
++} __packed;
++
++struct au_vdir_dehstr {
++ struct hlist_node hash;
++ struct au_vdir_destr *str;
++} ____cacheline_aligned_in_smp;
++
++struct au_vdir_de {
++ ino_t de_ino;
++ unsigned char de_type;
++ /* caution: packed */
++ struct au_vdir_destr de_str;
++} __packed;
++
++struct au_vdir_wh {
++ struct hlist_node wh_hash;
++#ifdef CONFIG_AUFS_SHWH
++ ino_t wh_ino;
++ aufs_bindex_t wh_bindex;
++ unsigned char wh_type;
++#else
++ aufs_bindex_t wh_bindex;
++#endif
++ /* caution: packed */
++ struct au_vdir_destr wh_str;
++} __packed;
++
++union au_vdir_deblk_p {
++ unsigned char *deblk;
++ struct au_vdir_de *de;
++};
++
++struct au_vdir {
++ unsigned char **vd_deblk;
++ unsigned long vd_nblk;
++ struct {
++ unsigned long ul;
++ union au_vdir_deblk_p p;
++ } vd_last;
++
++ unsigned long vd_version;
++ unsigned int vd_deblk_sz;
++ unsigned long vd_jiffy;
++} ____cacheline_aligned_in_smp;
++
++/* ---------------------------------------------------------------------- */
++
++/* dir.c */
++extern const struct file_operations aufs_dir_fop;
++void au_add_nlink(struct inode *dir, struct inode *h_dir);
++void au_sub_nlink(struct inode *dir, struct inode *h_dir);
++loff_t au_dir_size(struct file *file, struct dentry *dentry);
++int au_test_empty_lower(struct dentry *dentry);
++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist);
++
++/* vdir.c */
++unsigned int au_rdhash_est(loff_t sz);
++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp);
++void au_nhash_wh_free(struct au_nhash *whlist);
++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
++ int limit);
++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen);
++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino,
++ unsigned int d_type, aufs_bindex_t bindex,
++ unsigned char shwh);
++void au_vdir_free(struct au_vdir *vdir);
++int au_vdir_init(struct file *file);
++int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir);
++
++/* ioctl.c */
++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg);
++
++#ifdef CONFIG_AUFS_RDU
++/* rdu.c */
++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
++#ifdef CONFIG_COMPAT
++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg);
++#endif
++#else
++static inline long au_rdu_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ return -EINVAL;
++}
++#ifdef CONFIG_COMPAT
++static inline long au_rdu_compat_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ return -EINVAL;
++}
++#endif
++#endif
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DIR_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/dynop.c linux-2.6.36/fs/aufs/dynop.c
+--- linux-2.6.36.orig/fs/aufs/dynop.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/dynop.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,425 @@
++/*
++ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * dynamically customizable operations for regular files
++ */
++
++#include "aufs.h"
++
++#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop)
++
++/*
++ * How large will these lists be?
++ * Usually just a few elements, 20-30 at most for each, I guess.
++ */
++static struct au_splhead dynop[AuDyLast];
++
++static struct au_dykey *dy_gfind_get(struct au_splhead *spl, const void *h_op)
++{
++ struct au_dykey *key, *tmp;
++ struct list_head *head;
++
++ key = NULL;
++ head = &spl->head;
++ rcu_read_lock();
++ list_for_each_entry_rcu(tmp, head, dk_list)
++ if (tmp->dk_op.dy_hop == h_op) {
++ key = tmp;
++ kref_get(&key->dk_kref);
++ break;
++ }
++ rcu_read_unlock();
++
++ return key;
++}
++
++static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key)
++{
++ struct au_dykey **k, *found;
++ const void *h_op = key->dk_op.dy_hop;
++ int i;
++
++ found = NULL;
++ k = br->br_dykey;
++ for (i = 0; i < AuBrDynOp; i++)
++ if (k[i]) {
++ if (k[i]->dk_op.dy_hop == h_op) {
++ found = k[i];
++ break;
++ }
++ } else
++ break;
++ if (!found) {
++ spin_lock(&br->br_dykey_lock);
++ for (; i < AuBrDynOp; i++)
++ if (k[i]) {
++ if (k[i]->dk_op.dy_hop == h_op) {
++ found = k[i];
++ break;
++ }
++ } else {
++ k[i] = key;
++ break;
++ }
++ spin_unlock(&br->br_dykey_lock);
++ BUG_ON(i == AuBrDynOp); /* expand the array */
++ }
++
++ return found;
++}
++
++/* kref_get() if @key is already added */
++static struct au_dykey *dy_gadd(struct au_splhead *spl, struct au_dykey *key)
++{
++ struct au_dykey *tmp, *found;
++ struct list_head *head;
++ const void *h_op = key->dk_op.dy_hop;
++
++ found = NULL;
++ head = &spl->head;
++ spin_lock(&spl->spin);
++ list_for_each_entry(tmp, head, dk_list)
++ if (tmp->dk_op.dy_hop == h_op) {
++ kref_get(&tmp->dk_kref);
++ found = tmp;
++ break;
++ }
++ if (!found)
++ list_add_rcu(&key->dk_list, head);
++ spin_unlock(&spl->spin);
++
++ if (!found)
++ DyPrSym(key);
++ return found;
++}
++
++static void dy_free_rcu(struct rcu_head *rcu)
++{
++ struct au_dykey *key;
++
++ key = container_of(rcu, struct au_dykey, dk_rcu);
++ DyPrSym(key);
++ kfree(key);
++}
++
++static void dy_free(struct kref *kref)
++{
++ struct au_dykey *key;
++ struct au_splhead *spl;
++
++ key = container_of(kref, struct au_dykey, dk_kref);
++ spl = dynop + key->dk_op.dy_type;
++ au_spl_del_rcu(&key->dk_list, spl);
++ call_rcu(&key->dk_rcu, dy_free_rcu);
++}
++
++void au_dy_put(struct au_dykey *key)
++{
++ kref_put(&key->dk_kref, dy_free);
++}
++
++/* ---------------------------------------------------------------------- */
++
++#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *))
++
++#ifdef CONFIG_AUFS_DEBUG
++#define DyDbgDeclare(cnt) unsigned int cnt = 0
++#define DyDbgInc(cnt) do { cnt++; } while (0)
++#else
++#define DyDbgDeclare(cnt) do {} while (0)
++#define DyDbgInc(cnt) do {} while (0)
++#endif
++
++#define DySet(func, dst, src, h_op, h_sb) do { \
++ DyDbgInc(cnt); \
++ if (h_op->func) { \
++ if (src.func) \
++ dst.func = src.func; \
++ else \
++ AuDbg("%s %s\n", au_sbtype(h_sb), #func); \
++ } \
++} while (0)
++
++#define DySetForce(func, dst, src) do { \
++ AuDebugOn(!src.func); \
++ DyDbgInc(cnt); \
++ dst.func = src.func; \
++} while (0)
++
++#define DySetAop(func) \
++ DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb)
++#define DySetAopForce(func) \
++ DySetForce(func, dyaop->da_op, aufs_aop)
++
++static void dy_aop(struct au_dykey *key, const void *h_op,
++ struct super_block *h_sb __maybe_unused)
++{
++ struct au_dyaop *dyaop = (void *)key;
++ const struct address_space_operations *h_aop = h_op;
++ DyDbgDeclare(cnt);
++
++ AuDbg("%s\n", au_sbtype(h_sb));
++
++ DySetAop(writepage);
++ DySetAopForce(readpage); /* force */
++ DySetAop(sync_page);
++ DySetAop(writepages);
++ DySetAop(set_page_dirty);
++ DySetAop(readpages);
++ DySetAop(write_begin);
++ DySetAop(write_end);
++ DySetAop(bmap);
++ DySetAop(invalidatepage);
++ DySetAop(releasepage);
++ /* these two will be changed according to an aufs mount option */
++ DySetAop(direct_IO);
++ DySetAop(get_xip_mem);
++ DySetAop(migratepage);
++ DySetAop(launder_page);
++ DySetAop(is_partially_uptodate);
++ DySetAop(error_remove_page);
++
++ DyDbgSize(cnt, *h_aop);
++ dyaop->da_get_xip_mem = h_aop->get_xip_mem;
++}
++
++#define DySetVmop(func) \
++ DySet(func, dyvmop->dv_op, aufs_vm_ops, h_vmop, h_sb)
++#define DySetVmopForce(func) \
++ DySetForce(func, dyvmop->dv_op, aufs_vm_ops)
++
++static void dy_vmop(struct au_dykey *key, const void *h_op,
++ struct super_block *h_sb __maybe_unused)
++{
++ struct au_dyvmop *dyvmop = (void *)key;
++ const struct vm_operations_struct *h_vmop = h_op;
++ DyDbgDeclare(cnt);
++
++ AuDbg("%s\n", au_sbtype(h_sb));
++
++ DySetVmop(open);
++ DySetVmop(close);
++ DySetVmop(fault);
++ DySetVmop(page_mkwrite);
++ DySetVmop(access);
++#ifdef CONFIG_NUMA
++ DySetVmop(set_policy);
++ DySetVmop(get_policy);
++ DySetVmop(migrate);
++#endif
++
++ DyDbgSize(cnt, *h_vmop);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void dy_bug(struct kref *kref)
++{
++ BUG();
++}
++
++static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br)
++{
++ struct au_dykey *key, *old;
++ struct au_splhead *spl;
++ struct op {
++ unsigned int sz;
++ void (*set)(struct au_dykey *key, const void *h_op,
++ struct super_block *h_sb __maybe_unused);
++ };
++ static const struct op a[] = {
++ [AuDy_AOP] = {
++ .sz = sizeof(struct au_dyaop),
++ .set = dy_aop
++ },
++ [AuDy_VMOP] = {
++ .sz = sizeof(struct au_dyvmop),
++ .set = dy_vmop
++ }
++ };
++ const struct op *p;
++
++ spl = dynop + op->dy_type;
++ key = dy_gfind_get(spl, op->dy_hop);
++ if (key)
++ goto out_add; /* success */
++
++ p = a + op->dy_type;
++ key = kzalloc(p->sz, GFP_NOFS);
++ if (unlikely(!key)) {
++ key = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++
++ key->dk_op.dy_hop = op->dy_hop;
++ kref_init(&key->dk_kref);
++ p->set(key, op->dy_hop, br->br_mnt->mnt_sb);
++ old = dy_gadd(spl, key);
++ if (old) {
++ kfree(key);
++ key = old;
++ }
++
++out_add:
++ old = dy_bradd(br, key);
++ if (old)
++ /* its ref-count should never be zero here */
++ kref_put(&key->dk_kref, dy_bug);
++out:
++ return key;
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * Aufs prohibits O_DIRECT by defaut even if the branch supports it.
++ * This behaviour is neccessary to return an error from open(O_DIRECT) instead
++ * of the succeeding I/O. The dio mount option enables O_DIRECT and makes
++ * open(O_DIRECT) always succeed, but the succeeding I/O may return an error.
++ * See the aufs manual in detail.
++ *
++ * To keep this behaviour, aufs has to set NULL to ->get_xip_mem too, and the
++ * performance of fadvise() and madvise() may be affected.
++ */
++static void dy_adx(struct au_dyaop *dyaop, int do_dx)
++{
++ if (!do_dx) {
++ dyaop->da_op.direct_IO = NULL;
++ dyaop->da_op.get_xip_mem = NULL;
++ } else {
++ dyaop->da_op.direct_IO = aufs_aop.direct_IO;
++ dyaop->da_op.get_xip_mem = aufs_aop.get_xip_mem;
++ if (!dyaop->da_get_xip_mem)
++ dyaop->da_op.get_xip_mem = NULL;
++ }
++}
++
++static struct au_dyaop *dy_aget(struct au_branch *br,
++ const struct address_space_operations *h_aop,
++ int do_dx)
++{
++ struct au_dyaop *dyaop;
++ struct au_dynop op;
++
++ op.dy_type = AuDy_AOP;
++ op.dy_haop = h_aop;
++ dyaop = (void *)dy_get(&op, br);
++ if (IS_ERR(dyaop))
++ goto out;
++ dy_adx(dyaop, do_dx);
++
++out:
++ return dyaop;
++}
++
++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex,
++ struct inode *h_inode)
++{
++ int err, do_dx;
++ struct super_block *sb;
++ struct au_branch *br;
++ struct au_dyaop *dyaop;
++
++ AuDebugOn(!S_ISREG(h_inode->i_mode));
++ IiMustWriteLock(inode);
++
++ sb = inode->i_sb;
++ br = au_sbr(sb, bindex);
++ do_dx = !!au_opt_test(au_mntflags(sb), DIO);
++ dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx);
++ err = PTR_ERR(dyaop);
++ if (IS_ERR(dyaop))
++ /* unnecessary to call dy_fput() */
++ goto out;
++
++ err = 0;
++ inode->i_mapping->a_ops = &dyaop->da_op;
++
++out:
++ return err;
++}
++
++/*
++ * Is it safe to replace a_ops during the inode/file is in operation?
++ * Yes, I hope so.
++ */
++int au_dy_irefresh(struct inode *inode)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct inode *h_inode;
++
++ err = 0;
++ if (S_ISREG(inode->i_mode)) {
++ bstart = au_ibstart(inode);
++ h_inode = au_h_iptr(inode, bstart);
++ err = au_dy_iaop(inode, bstart, h_inode);
++ }
++ return err;
++}
++
++void au_dy_arefresh(int do_dx)
++{
++ struct au_splhead *spl;
++ struct list_head *head;
++ struct au_dykey *key;
++
++ spl = dynop + AuDy_AOP;
++ head = &spl->head;
++ spin_lock(&spl->spin);
++ list_for_each_entry(key, head, dk_list)
++ dy_adx((void *)key, do_dx);
++ spin_unlock(&spl->spin);
++}
++
++const struct vm_operations_struct *
++au_dy_vmop(struct file *file, struct au_branch *br,
++ const struct vm_operations_struct *h_vmop)
++{
++ struct au_dyvmop *dyvmop;
++ struct au_dynop op;
++
++ op.dy_type = AuDy_VMOP;
++ op.dy_hvmop = h_vmop;
++ dyvmop = (void *)dy_get(&op, br);
++ if (IS_ERR(dyvmop))
++ return (void *)dyvmop;
++ return &dyvmop->dv_op;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void __init au_dy_init(void)
++{
++ int i;
++
++ /* make sure that 'struct au_dykey *' can be any type */
++ BUILD_BUG_ON(offsetof(struct au_dyaop, da_key));
++ BUILD_BUG_ON(offsetof(struct au_dyvmop, dv_key));
++
++ for (i = 0; i < AuDyLast; i++)
++ au_spl_init(dynop + i);
++}
++
++void au_dy_fin(void)
++{
++ int i;
++
++ for (i = 0; i < AuDyLast; i++)
++ WARN_ON(!list_empty(&dynop[i].head));
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/dynop.h linux-2.6.36/fs/aufs/dynop.h
+--- linux-2.6.36.orig/fs/aufs/dynop.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/dynop.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,89 @@
++/*
++ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * dynamically customizable operations (for regular files only)
++ */
++
++#ifndef __AUFS_DYNOP_H__
++#define __AUFS_DYNOP_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/rcupdate.h>
++#include <linux/aufs_type.h>
++#include "inode.h"
++
++enum {AuDy_AOP, AuDy_VMOP, AuDyLast};
++
++struct au_dynop {
++ int dy_type;
++ union {
++ const void *dy_hop;
++ const struct address_space_operations *dy_haop;
++ const struct vm_operations_struct *dy_hvmop;
++ };
++};
++
++struct au_dykey {
++ union {
++ struct list_head dk_list;
++ struct rcu_head dk_rcu;
++ };
++ struct au_dynop dk_op;
++
++ /*
++ * during I am in the branch local array, kref is gotten. when the
++ * branch is removed, kref is put.
++ */
++ struct kref dk_kref;
++};
++
++/* stop unioning since their sizes are very different from each other */
++struct au_dyaop {
++ struct au_dykey da_key;
++ struct address_space_operations da_op; /* not const */
++ int (*da_get_xip_mem)(struct address_space *, pgoff_t, int,
++ void **, unsigned long *);
++};
++
++struct au_dyvmop {
++ struct au_dykey dv_key;
++ struct vm_operations_struct dv_op; /* not const */
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* dynop.c */
++struct au_branch;
++void au_dy_put(struct au_dykey *key);
++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex,
++ struct inode *h_inode);
++int au_dy_irefresh(struct inode *inode);
++void au_dy_arefresh(int do_dio);
++const struct vm_operations_struct *
++au_dy_vmop(struct file *file, struct au_branch *br,
++ const struct vm_operations_struct *h_vmop);
++
++void __init au_dy_init(void);
++void au_dy_fin(void);
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DYNOP_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/export.c linux-2.6.36/fs/aufs/export.c
+--- linux-2.6.36.orig/fs/aufs/export.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/export.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,798 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * export via nfs
++ */
++
++#include <linux/exportfs.h>
++#include <linux/file.h>
++#include <linux/mnt_namespace.h>
++#include <linux/namei.h>
++#include <linux/nsproxy.h>
++#include <linux/random.h>
++#include <linux/writeback.h>
++#include "aufs.h"
++
++union conv {
++#ifdef CONFIG_AUFS_INO_T_64
++ __u32 a[2];
++#else
++ __u32 a[1];
++#endif
++ ino_t ino;
++};
++
++static ino_t decode_ino(__u32 *a)
++{
++ union conv u;
++
++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a));
++ u.a[0] = a[0];
++#ifdef CONFIG_AUFS_INO_T_64
++ u.a[1] = a[1];
++#endif
++ return u.ino;
++}
++
++static void encode_ino(__u32 *a, ino_t ino)
++{
++ union conv u;
++
++ u.ino = ino;
++ a[0] = u.a[0];
++#ifdef CONFIG_AUFS_INO_T_64
++ a[1] = u.a[1];
++#endif
++}
++
++/* NFS file handle */
++enum {
++ Fh_br_id,
++ Fh_sigen,
++#ifdef CONFIG_AUFS_INO_T_64
++ /* support 64bit inode number */
++ Fh_ino1,
++ Fh_ino2,
++ Fh_dir_ino1,
++ Fh_dir_ino2,
++#else
++ Fh_ino1,
++ Fh_dir_ino1,
++#endif
++ Fh_igen,
++ Fh_h_type,
++ Fh_tail,
++
++ Fh_ino = Fh_ino1,
++ Fh_dir_ino = Fh_dir_ino1
++};
++
++static int au_test_anon(struct dentry *dentry)
++{
++ return !!(dentry->d_flags & DCACHE_DISCONNECTED);
++}
++
++/* ---------------------------------------------------------------------- */
++/* inode generation external table */
++
++void au_xigen_inc(struct inode *inode)
++{
++ loff_t pos;
++ ssize_t sz;
++ __u32 igen;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++ sb = inode->i_sb;
++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO));
++
++ sbinfo = au_sbi(sb);
++ pos = inode->i_ino;
++ pos *= sizeof(igen);
++ igen = inode->i_generation + 1;
++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen,
++ sizeof(igen), &pos);
++ if (sz == sizeof(igen))
++ return; /* success */
++
++ if (unlikely(sz >= 0))
++ AuIOErr("xigen error (%zd)\n", sz);
++}
++
++int au_xigen_new(struct inode *inode)
++{
++ int err;
++ loff_t pos;
++ ssize_t sz;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ err = 0;
++ /* todo: dirty, at mount time */
++ if (inode->i_ino == AUFS_ROOT_INO)
++ goto out;
++ sb = inode->i_sb;
++ SiMustAnyLock(sb);
++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
++ goto out;
++
++ err = -EFBIG;
++ pos = inode->i_ino;
++ if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) {
++ AuIOErr1("too large i%lld\n", pos);
++ goto out;
++ }
++ pos *= sizeof(inode->i_generation);
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ file = sbinfo->si_xigen;
++ BUG_ON(!file);
++
++ if (i_size_read(file->f_dentry->d_inode)
++ < pos + sizeof(inode->i_generation)) {
++ inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next);
++ sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation,
++ sizeof(inode->i_generation), &pos);
++ } else
++ sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation,
++ sizeof(inode->i_generation), &pos);
++ if (sz == sizeof(inode->i_generation))
++ goto out; /* success */
++
++ err = sz;
++ if (unlikely(sz >= 0)) {
++ err = -EIO;
++ AuIOErr("xigen error (%zd)\n", sz);
++ }
++
++out:
++ return err;
++}
++
++int au_xigen_set(struct super_block *sb, struct file *base)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ file = au_xino_create2(base, sbinfo->si_xigen);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ err = 0;
++ if (sbinfo->si_xigen)
++ fput(sbinfo->si_xigen);
++ sbinfo->si_xigen = file;
++
++out:
++ return err;
++}
++
++void au_xigen_clr(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ if (sbinfo->si_xigen) {
++ fput(sbinfo->si_xigen);
++ sbinfo->si_xigen = NULL;
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino,
++ ino_t dir_ino)
++{
++ struct dentry *dentry, *d;
++ struct inode *inode;
++ unsigned int sigen;
++
++ dentry = NULL;
++ inode = ilookup(sb, ino);
++ if (!inode)
++ goto out;
++
++ dentry = ERR_PTR(-ESTALE);
++ sigen = au_sigen(sb);
++ if (unlikely(is_bad_inode(inode)
++ || IS_DEADDIR(inode)
++ || sigen != au_iigen(inode)))
++ goto out_iput;
++
++ dentry = NULL;
++ if (!dir_ino || S_ISDIR(inode->i_mode))
++ dentry = d_find_alias(inode);
++ else {
++ spin_lock(&dcache_lock);
++ list_for_each_entry(d, &inode->i_dentry, d_alias)
++ if (!au_test_anon(d)
++ && d->d_parent->d_inode->i_ino == dir_ino) {
++ dentry = dget_locked(d);
++ break;
++ }
++ spin_unlock(&dcache_lock);
++ }
++ if (unlikely(dentry && au_digen_test(dentry, sigen))) {
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++ }
++
++out_iput:
++ iput(inode);
++out:
++ return dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* todo: dirty? */
++/* if exportfs_decode_fh() passed vfsmount*, we could be happy */
++
++struct au_compare_mnt_args {
++ /* input */
++ struct super_block *sb;
++
++ /* output */
++ struct vfsmount *mnt;
++};
++
++static int au_compare_mnt(struct vfsmount *mnt, void *arg)
++{
++ struct au_compare_mnt_args *a = arg;
++
++ if (mnt->mnt_sb != a->sb)
++ return 0;
++ a->mnt = mntget(mnt);
++ return 1;
++}
++
++static struct vfsmount *au_mnt_get(struct super_block *sb)
++{
++ int err;
++ struct au_compare_mnt_args args = {
++ .sb = sb
++ };
++ struct mnt_namespace *ns;
++
++ br_read_lock(vfsmount_lock);
++ /* no get/put ?? */
++ AuDebugOn(!current->nsproxy);
++ ns = current->nsproxy->mnt_ns;
++ AuDebugOn(!ns);
++ err = iterate_mounts(au_compare_mnt, &args, ns->root);
++ br_read_unlock(vfsmount_lock);
++ AuDebugOn(!err);
++ AuDebugOn(!args.mnt);
++ return args.mnt;
++}
++
++struct au_nfsd_si_lock {
++ unsigned int sigen;
++ aufs_bindex_t bindex, br_id;
++ unsigned char force_lock;
++};
++
++static int si_nfsd_read_lock(struct super_block *sb,
++ struct au_nfsd_si_lock *nsi_lock)
++{
++ int err;
++ aufs_bindex_t bindex;
++
++ si_read_lock(sb, AuLock_FLUSH);
++
++ /* branch id may be wrapped around */
++ err = 0;
++ bindex = au_br_index(sb, nsi_lock->br_id);
++ if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb))
++ goto out; /* success */
++
++ err = -ESTALE;
++ bindex = -1;
++ if (!nsi_lock->force_lock)
++ si_read_unlock(sb);
++
++out:
++ nsi_lock->bindex = bindex;
++ return err;
++}
++
++struct find_name_by_ino {
++ int called, found;
++ ino_t ino;
++ char *name;
++ int namelen;
++};
++
++static int
++find_name_by_ino(void *arg, const char *name, int namelen, loff_t offset,
++ u64 ino, unsigned int d_type)
++{
++ struct find_name_by_ino *a = arg;
++
++ a->called++;
++ if (a->ino != ino)
++ return 0;
++
++ memcpy(a->name, name, namelen);
++ a->namelen = namelen;
++ a->found = 1;
++ return 1;
++}
++
++static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino,
++ struct au_nfsd_si_lock *nsi_lock)
++{
++ struct dentry *dentry, *parent;
++ struct file *file;
++ struct inode *dir;
++ struct find_name_by_ino arg;
++ int err;
++
++ parent = path->dentry;
++ if (nsi_lock)
++ si_read_unlock(parent->d_sb);
++ file = vfsub_dentry_open(path, au_dir_roflags);
++ dentry = (void *)file;
++ if (IS_ERR(file))
++ goto out;
++
++ dentry = ERR_PTR(-ENOMEM);
++ arg.name = __getname_gfp(GFP_NOFS);
++ if (unlikely(!arg.name))
++ goto out_file;
++ arg.ino = ino;
++ arg.found = 0;
++ do {
++ arg.called = 0;
++ /* smp_mb(); */
++ err = vfsub_readdir(file, find_name_by_ino, &arg);
++ } while (!err && !arg.found && arg.called);
++ dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_name;
++ dentry = ERR_PTR(-ENOENT);
++ if (!arg.found)
++ goto out_name;
++
++ /* do not call au_lkup_one() */
++ dir = parent->d_inode;
++ mutex_lock(&dir->i_mutex);
++ dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen);
++ mutex_unlock(&dir->i_mutex);
++ AuTraceErrPtr(dentry);
++ if (IS_ERR(dentry))
++ goto out_name;
++ AuDebugOn(au_test_anon(dentry));
++ if (unlikely(!dentry->d_inode)) {
++ dput(dentry);
++ dentry = ERR_PTR(-ENOENT);
++ }
++
++out_name:
++ __putname(arg.name);
++out_file:
++ fput(file);
++out:
++ if (unlikely(nsi_lock
++ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0))
++ if (!IS_ERR(dentry)) {
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++ }
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino,
++ ino_t dir_ino,
++ struct au_nfsd_si_lock *nsi_lock)
++{
++ struct dentry *dentry;
++ struct path path;
++
++ if (dir_ino != AUFS_ROOT_INO) {
++ path.dentry = decode_by_ino(sb, dir_ino, 0);
++ dentry = path.dentry;
++ if (!path.dentry || IS_ERR(path.dentry))
++ goto out;
++ AuDebugOn(au_test_anon(path.dentry));
++ } else
++ path.dentry = dget(sb->s_root);
++
++ path.mnt = au_mnt_get(sb);
++ dentry = au_lkup_by_ino(&path, ino, nsi_lock);
++ path_put(&path);
++
++out:
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int h_acceptable(void *expv, struct dentry *dentry)
++{
++ return 1;
++}
++
++static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath,
++ char *buf, int len, struct super_block *sb)
++{
++ char *p;
++ int n;
++ struct path path;
++
++ p = d_path(h_rootpath, buf, len);
++ if (IS_ERR(p))
++ goto out;
++ n = strlen(p);
++
++ path.mnt = h_rootpath->mnt;
++ path.dentry = h_parent;
++ p = d_path(&path, buf, len);
++ if (IS_ERR(p))
++ goto out;
++ if (n != 1)
++ p += n;
++
++ path.mnt = au_mnt_get(sb);
++ path.dentry = sb->s_root;
++ p = d_path(&path, buf, len - strlen(p));
++ mntput(path.mnt);
++ if (IS_ERR(p))
++ goto out;
++ if (n != 1)
++ p[strlen(p)] = '/';
++
++out:
++ AuTraceErrPtr(p);
++ return p;
++}
++
++static
++struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh,
++ int fh_len, struct au_nfsd_si_lock *nsi_lock)
++{
++ struct dentry *dentry, *h_parent, *root;
++ struct super_block *h_sb;
++ char *pathname, *p;
++ struct vfsmount *h_mnt;
++ struct au_branch *br;
++ int err;
++ struct path path;
++
++ br = au_sbr(sb, nsi_lock->bindex);
++ h_mnt = br->br_mnt;
++ h_sb = h_mnt->mnt_sb;
++ /* todo: call lower fh_to_dentry()? fh_to_parent()? */
++ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail),
++ fh_len - Fh_tail, fh[Fh_h_type],
++ h_acceptable, /*context*/NULL);
++ dentry = h_parent;
++ if (unlikely(!h_parent || IS_ERR(h_parent))) {
++ AuWarn1("%s decode_fh failed, %ld\n",
++ au_sbtype(h_sb), PTR_ERR(h_parent));
++ goto out;
++ }
++ dentry = NULL;
++ if (unlikely(au_test_anon(h_parent))) {
++ AuWarn1("%s decode_fh returned a disconnected dentry\n",
++ au_sbtype(h_sb));
++ goto out_h_parent;
++ }
++
++ dentry = ERR_PTR(-ENOMEM);
++ pathname = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!pathname))
++ goto out_h_parent;
++
++ root = sb->s_root;
++ path.mnt = h_mnt;
++ di_read_lock_parent(root, !AuLock_IR);
++ path.dentry = au_h_dptr(root, nsi_lock->bindex);
++ di_read_unlock(root, !AuLock_IR);
++ p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb);
++ dentry = (void *)p;
++ if (IS_ERR(p))
++ goto out_pathname;
++
++ si_read_unlock(sb);
++ err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
++ dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_relock;
++
++ dentry = ERR_PTR(-ENOENT);
++ AuDebugOn(au_test_anon(path.dentry));
++ if (unlikely(!path.dentry->d_inode))
++ goto out_path;
++
++ if (ino != path.dentry->d_inode->i_ino)
++ dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL);
++ else
++ dentry = dget(path.dentry);
++
++out_path:
++ path_put(&path);
++out_relock:
++ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0))
++ if (!IS_ERR(dentry)) {
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++ }
++out_pathname:
++ free_page((unsigned long)pathname);
++out_h_parent:
++ dput(h_parent);
++out:
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct dentry *
++aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
++ int fh_type)
++{
++ struct dentry *dentry;
++ __u32 *fh = fid->raw;
++ struct au_branch *br;
++ ino_t ino, dir_ino;
++ struct au_nfsd_si_lock nsi_lock = {
++ .force_lock = 0
++ };
++
++ dentry = ERR_PTR(-ESTALE);
++ /* it should never happen, but the file handle is unreliable */
++ if (unlikely(fh_len < Fh_tail))
++ goto out;
++ nsi_lock.sigen = fh[Fh_sigen];
++ nsi_lock.br_id = fh[Fh_br_id];
++
++ /* branch id may be wrapped around */
++ br = NULL;
++ if (unlikely(si_nfsd_read_lock(sb, &nsi_lock)))
++ goto out;
++ nsi_lock.force_lock = 1;
++
++ /* is this inode still cached? */
++ ino = decode_ino(fh + Fh_ino);
++ /* it should never happen */
++ if (unlikely(ino == AUFS_ROOT_INO))
++ goto out;
++
++ dir_ino = decode_ino(fh + Fh_dir_ino);
++ dentry = decode_by_ino(sb, ino, dir_ino);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++ if (dentry)
++ goto accept;
++
++ /* is the parent dir cached? */
++ br = au_sbr(sb, nsi_lock.bindex);
++ atomic_inc(&br->br_count);
++ dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++ if (dentry)
++ goto accept;
++
++ /* lookup path */
++ dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++ if (unlikely(!dentry))
++ /* todo?: make it ESTALE */
++ goto out_unlock;
++
++accept:
++ if (!au_digen_test(dentry, au_sigen(sb))
++ && dentry->d_inode->i_generation == fh[Fh_igen])
++ goto out_unlock; /* success */
++
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++out_unlock:
++ if (br)
++ atomic_dec(&br->br_count);
++ si_read_unlock(sb);
++out:
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++#if 0 /* reserved for future use */
++/* support subtreecheck option */
++static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid,
++ int fh_len, int fh_type)
++{
++ struct dentry *parent;
++ __u32 *fh = fid->raw;
++ ino_t dir_ino;
++
++ dir_ino = decode_ino(fh + Fh_dir_ino);
++ parent = decode_by_ino(sb, dir_ino, 0);
++ if (IS_ERR(parent))
++ goto out;
++ if (!parent)
++ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]),
++ dir_ino, fh, fh_len);
++
++out:
++ AuTraceErrPtr(parent);
++ return parent;
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
++ int connectable)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct super_block *sb, *h_sb;
++ struct inode *inode;
++ struct dentry *parent, *h_parent;
++ struct au_branch *br;
++
++ AuDebugOn(au_test_anon(dentry));
++
++ parent = NULL;
++ err = -ENOSPC;
++ if (unlikely(*max_len <= Fh_tail)) {
++ AuWarn1("NFSv2 client (max_len %d)?\n", *max_len);
++ goto out;
++ }
++
++ err = FILEID_ROOT;
++ if (IS_ROOT(dentry)) {
++ AuDebugOn(dentry->d_inode->i_ino != AUFS_ROOT_INO);
++ goto out;
++ }
++
++ h_parent = NULL;
++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR | AuLock_GEN);
++ if (unlikely(err))
++ goto out;
++
++ inode = dentry->d_inode;
++ AuDebugOn(!inode);
++ sb = dentry->d_sb;
++#ifdef CONFIG_AUFS_DEBUG
++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
++ AuWarn1("NFS-exporting requires xino\n");
++#endif
++ err = -EIO;
++ parent = dget_parent(dentry);
++ di_read_lock_parent(parent, !AuLock_IR);
++ bend = au_dbtaildir(parent);
++ for (bindex = au_dbstart(parent); bindex <= bend; bindex++) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (h_parent) {
++ dget(h_parent);
++ break;
++ }
++ }
++ if (unlikely(!h_parent))
++ goto out_unlock;
++
++ err = -EPERM;
++ br = au_sbr(sb, bindex);
++ h_sb = br->br_mnt->mnt_sb;
++ if (unlikely(!h_sb->s_export_op)) {
++ AuErr1("%s branch is not exportable\n", au_sbtype(h_sb));
++ goto out_dput;
++ }
++
++ fh[Fh_br_id] = br->br_id;
++ fh[Fh_sigen] = au_sigen(sb);
++ encode_ino(fh + Fh_ino, inode->i_ino);
++ encode_ino(fh + Fh_dir_ino, parent->d_inode->i_ino);
++ fh[Fh_igen] = inode->i_generation;
++
++ *max_len -= Fh_tail;
++ fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail),
++ max_len,
++ /*connectable or subtreecheck*/0);
++ err = fh[Fh_h_type];
++ *max_len += Fh_tail;
++ /* todo: macros? */
++ if (err != 255)
++ err = 99;
++ else
++ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb));
++
++out_dput:
++ dput(h_parent);
++out_unlock:
++ di_read_unlock(parent, !AuLock_IR);
++ dput(parent);
++ aufs_read_unlock(dentry, AuLock_IR);
++out:
++ if (unlikely(err < 0))
++ err = 255;
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_commit_metadata(struct inode *inode)
++{
++ int err;
++ aufs_bindex_t bindex;
++ struct super_block *sb;
++ struct inode *h_inode;
++ int (*f)(struct inode *inode);
++
++ sb = inode->i_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ ii_write_lock_child(inode);
++ bindex = au_ibstart(inode);
++ AuDebugOn(bindex < 0);
++ h_inode = au_h_iptr(inode, bindex);
++
++ f = h_inode->i_sb->s_export_op->commit_metadata;
++ if (f)
++ err = f(h_inode);
++ else {
++ struct writeback_control wbc = {
++ .sync_mode = WB_SYNC_ALL,
++ .nr_to_write = 0 /* metadata only */
++ };
++
++ err = sync_inode(h_inode, &wbc);
++ }
++
++ au_cpup_attr_timesizes(inode);
++ ii_write_unlock(inode);
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct export_operations aufs_export_op = {
++ .fh_to_dentry = aufs_fh_to_dentry,
++ /* .fh_to_parent = aufs_fh_to_parent, */
++ .encode_fh = aufs_encode_fh,
++ .commit_metadata = aufs_commit_metadata
++};
++
++void au_export_init(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++ __u32 u;
++
++ sb->s_export_op = &aufs_export_op;
++ sbinfo = au_sbi(sb);
++ sbinfo->si_xigen = NULL;
++ get_random_bytes(&u, sizeof(u));
++ BUILD_BUG_ON(sizeof(u) != sizeof(int));
++ atomic_set(&sbinfo->si_xigen_next, u);
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/f_op.c linux-2.6.36/fs/aufs/f_op.c
+--- linux-2.6.36.orig/fs/aufs/f_op.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/f_op.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,906 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * file and vm operations
++ */
++
++#include <linux/file.h>
++#include <linux/fs_stack.h>
++#include <linux/mman.h>
++#include <linux/mm.h>
++#include <linux/security.h>
++#include "aufs.h"
++
++int au_do_open_nondir(struct file *file, int flags)
++{
++ int err;
++ aufs_bindex_t bindex;
++ struct file *h_file;
++ struct dentry *dentry;
++ struct au_finfo *finfo;
++
++ FiMustWriteLock(file);
++
++ dentry = file->f_dentry;
++ err = au_d_alive(dentry);
++ if (unlikely(err))
++ goto out;
++
++ finfo = au_fi(file);
++ memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop));
++ finfo->fi_hvmop = NULL;
++ bindex = au_dbstart(dentry);
++ h_file = au_h_open(dentry, bindex, flags, file);
++ if (IS_ERR(h_file))
++ err = PTR_ERR(h_file);
++ else {
++ au_set_fbstart(file, bindex);
++ au_set_h_fptr(file, bindex, h_file);
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ }
++
++out:
++ return err;
++}
++
++static int aufs_open_nondir(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ int err;
++ struct super_block *sb;
++
++ AuDbg("%.*s, f_ flags 0x%x, f_mode 0x%x\n",
++ AuDLNPair(file->f_dentry), vfsub_file_flags(file),
++ file->f_mode);
++
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_do_open(file, au_do_open_nondir, /*fidir*/NULL);
++ si_read_unlock(sb);
++ return err;
++}
++
++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file)
++{
++ struct au_finfo *finfo;
++ aufs_bindex_t bindex;
++
++ finfo = au_fi(file);
++ bindex = finfo->fi_btop;
++ if (bindex >= 0) {
++ /* remove me from sb->s_files */
++ file_sb_list_del(file);
++ au_set_h_fptr(file, bindex, NULL);
++ }
++
++ au_finfo_fin(file);
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_flush_nondir(struct file *file, fl_owner_t id)
++{
++ int err;
++ struct file *h_file;
++
++ err = 0;
++ h_file = au_hf_top(file);
++ if (h_file)
++ err = vfsub_flush(h_file, id);
++ return err;
++}
++
++static int aufs_flush_nondir(struct file *file, fl_owner_t id)
++{
++ return au_do_flush(file, id, au_do_flush_nondir);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static ssize_t aufs_read(struct file *file, char __user *buf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++ struct dentry *dentry;
++ struct file *h_file;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ h_file = au_hf_top(file);
++ err = vfsub_read_u(h_file, buf, count, ppos);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++/*
++ * todo: very ugly
++ * it locks both of i_mutex and si_rwsem for read in safe.
++ * if the plink maintenance mode continues forever (that is the problem),
++ * may loop forever.
++ */
++static void au_mtx_and_read_lock(struct inode *inode)
++{
++ int err;
++ struct super_block *sb = inode->i_sb;
++
++ while (1) {
++ mutex_lock(&inode->i_mutex);
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (!err)
++ break;
++ mutex_unlock(&inode->i_mutex);
++ si_read_lock(sb, AuLock_NOPLMW);
++ si_read_unlock(sb);
++ }
++}
++
++static ssize_t aufs_write(struct file *file, const char __user *ubuf,
++ size_t count, loff_t *ppos)
++{
++ ssize_t err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *h_file;
++ char __user *buf = (char __user *)ubuf;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ au_mtx_and_read_lock(inode);
++
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ h_file = au_hf_top(file);
++ au_unpin(&pin);
++ err = vfsub_write_u(h_file, buf, count, ppos);
++ au_cpup_attr_timesizes(inode);
++ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out:
++ si_read_unlock(inode->i_sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++
++static ssize_t au_do_aio(struct file *h_file, int rw, struct kiocb *kio,
++ const struct iovec *iov, unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ struct file *file;
++ ssize_t (*func)(struct kiocb *, const struct iovec *, unsigned long,
++ loff_t);
++
++ err = security_file_permission(h_file, rw);
++ if (unlikely(err))
++ goto out;
++
++ err = -ENOSYS;
++ func = NULL;
++ if (rw == MAY_READ)
++ func = h_file->f_op->aio_read;
++ else if (rw == MAY_WRITE)
++ func = h_file->f_op->aio_write;
++ if (func) {
++ file = kio->ki_filp;
++ kio->ki_filp = h_file;
++ err = func(kio, iov, nv, pos);
++ kio->ki_filp = file;
++ } else
++ /* currently there is no such fs */
++ WARN_ON_ONCE(1);
++
++out:
++ return err;
++}
++
++static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ struct file *file, *h_file;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ file = kio->ki_filp;
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ h_file = au_hf_top(file);
++ err = au_do_aio(h_file, MAY_READ, kio, iov, nv, pos);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++static ssize_t aufs_aio_write(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *file, *h_file;
++
++ file = kio->ki_filp;
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ au_mtx_and_read_lock(inode);
++
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ au_unpin(&pin);
++ h_file = au_hf_top(file);
++ err = au_do_aio(h_file, MAY_WRITE, kio, iov, nv, pos);
++ au_cpup_attr_timesizes(inode);
++ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out:
++ si_read_unlock(inode->i_sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++
++static ssize_t aufs_splice_read(struct file *file, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ ssize_t err;
++ struct file *h_file;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ err = -EINVAL;
++ h_file = au_hf_top(file);
++ if (au_test_loopback_kthread()) {
++ file->f_mapping = h_file->f_mapping;
++ smp_mb(); /* unnecessary? */
++ }
++ err = vfsub_splice_to(h_file, ppos, pipe, len, flags);
++ /* todo: necessasry? */
++ /* file->f_ra = h_file->f_ra; */
++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++static ssize_t
++aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos,
++ size_t len, unsigned int flags)
++{
++ ssize_t err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *h_file;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ au_mtx_and_read_lock(inode);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ h_file = au_hf_top(file);
++ au_unpin(&pin);
++ err = vfsub_splice_from(pipe, h_file, ppos, len, flags);
++ au_cpup_attr_timesizes(inode);
++ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out:
++ si_read_unlock(inode->i_sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct file *au_safe_file(struct vm_area_struct *vma)
++{
++ struct file *file;
++
++ file = vma->vm_file;
++ if (au_fi(file) && au_test_aufs(file->f_dentry->d_sb))
++ return file;
++ return NULL;
++}
++
++static void au_reset_file(struct vm_area_struct *vma, struct file *file)
++{
++ vma->vm_file = file;
++ /* smp_mb(); */ /* flush vm_file */
++}
++
++static int aufs_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
++{
++ int err;
++ static DECLARE_WAIT_QUEUE_HEAD(wq);
++ struct file *file, *h_file;
++ struct au_finfo *finfo;
++
++ /* todo: non-robr mode, user vm_file as it is? */
++ wait_event(wq, (file = au_safe_file(vma)));
++
++ /* do not revalidate, no si lock */
++ finfo = au_fi(file);
++ AuDebugOn(finfo->fi_hdir);
++ h_file = finfo->fi_htop.hf_file;
++ AuDebugOn(!h_file || !finfo->fi_hvmop);
++
++ mutex_lock(&finfo->fi_vm_mtx);
++ vma->vm_file = h_file;
++ err = finfo->fi_hvmop->fault(vma, vmf);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ au_reset_file(vma, file);
++ mutex_unlock(&finfo->fi_vm_mtx);
++#if 0 /* def CONFIG_SMP */
++ /* wake_up_nr(&wq, online_cpu - 1); */
++ wake_up_all(&wq);
++#else
++ wake_up(&wq);
++#endif
++
++ return err;
++}
++
++static int aufs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
++{
++ int err;
++ static DECLARE_WAIT_QUEUE_HEAD(wq);
++ struct file *file, *h_file;
++ struct au_finfo *finfo;
++
++ wait_event(wq, (file = au_safe_file(vma)));
++
++ finfo = au_fi(file);
++ AuDebugOn(finfo->fi_hdir);
++ h_file = finfo->fi_htop.hf_file;
++ AuDebugOn(!h_file || !finfo->fi_hvmop);
++
++ mutex_lock(&finfo->fi_vm_mtx);
++ vma->vm_file = h_file;
++ err = finfo->fi_hvmop->page_mkwrite(vma, vmf);
++ au_reset_file(vma, file);
++ mutex_unlock(&finfo->fi_vm_mtx);
++ wake_up(&wq);
++
++ return err;
++}
++
++static void aufs_vm_close(struct vm_area_struct *vma)
++{
++ static DECLARE_WAIT_QUEUE_HEAD(wq);
++ struct file *file, *h_file;
++ struct au_finfo *finfo;
++
++ wait_event(wq, (file = au_safe_file(vma)));
++
++ finfo = au_fi(file);
++ AuDebugOn(finfo->fi_hdir);
++ h_file = finfo->fi_htop.hf_file;
++ AuDebugOn(!h_file || !finfo->fi_hvmop);
++
++ mutex_lock(&finfo->fi_vm_mtx);
++ vma->vm_file = h_file;
++ finfo->fi_hvmop->close(vma);
++ au_reset_file(vma, file);
++ mutex_unlock(&finfo->fi_vm_mtx);
++ wake_up(&wq);
++}
++
++const struct vm_operations_struct aufs_vm_ops = {
++ .close = aufs_vm_close,
++ .fault = aufs_fault,
++ .page_mkwrite = aufs_page_mkwrite
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */
++#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b)
++
++static unsigned long au_arch_prot_conv(unsigned long flags)
++{
++ /* currently ppc64 only */
++#ifdef CONFIG_PPC64
++ /* cf. linux/arch/powerpc/include/asm/mman.h */
++ AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO);
++ return AuConv_VM_PROT(flags, SAO);
++#else
++ AuDebugOn(arch_calc_vm_prot_bits(-1));
++ return 0;
++#endif
++}
++
++static unsigned long au_prot_conv(unsigned long flags)
++{
++ return AuConv_VM_PROT(flags, READ)
++ | AuConv_VM_PROT(flags, WRITE)
++ | AuConv_VM_PROT(flags, EXEC)
++ | au_arch_prot_conv(flags);
++}
++
++/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */
++#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b)
++
++static unsigned long au_flag_conv(unsigned long flags)
++{
++ return AuConv_VM_MAP(flags, GROWSDOWN)
++ | AuConv_VM_MAP(flags, DENYWRITE)
++ | AuConv_VM_MAP(flags, EXECUTABLE)
++ | AuConv_VM_MAP(flags, LOCKED);
++}
++
++static struct vm_operations_struct *
++au_hvmop(struct file *h_file, struct vm_area_struct *vma, unsigned long *flags)
++{
++ struct vm_operations_struct *h_vmop;
++ unsigned long prot;
++ int err;
++
++ h_vmop = ERR_PTR(-ENODEV);
++ if (!h_file->f_op || !h_file->f_op->mmap)
++ goto out;
++
++ prot = au_prot_conv(vma->vm_flags);
++ err = security_file_mmap(h_file, /*reqprot*/prot, prot,
++ au_flag_conv(vma->vm_flags), vma->vm_start, 0);
++ h_vmop = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ err = h_file->f_op->mmap(h_file, vma);
++ h_vmop = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ /* oops, it became 'const' */
++ h_vmop = (struct vm_operations_struct *)vma->vm_ops;
++ *flags = vma->vm_flags;
++ err = do_munmap(current->mm, vma->vm_start,
++ vma->vm_end - vma->vm_start);
++ if (unlikely(err)) {
++ AuIOErr("failed internal unmapping %.*s, %d\n",
++ AuDLNPair(h_file->f_dentry), err);
++ h_vmop = ERR_PTR(-EIO);
++ }
++
++out:
++ return h_vmop;
++}
++
++/*
++ * This is another ugly approach to keep the lock order, particularly
++ * mm->mmap_sem and aufs rwsem. The previous approach was reverted and you can
++ * find it in git-log, if you want.
++ *
++ * native readdir: i_mutex, copy_to_user, mmap_sem
++ * aufs readdir: i_mutex, rwsem, nested-i_mutex, copy_to_user, mmap_sem
++ *
++ * Before aufs_mmap() mmap_sem is acquired already, but aufs_mmap() has to
++ * acquire aufs rwsem. It introduces a circular locking dependency.
++ * To address this problem, aufs_mmap() delegates the part which requires aufs
++ * rwsem to its internal workqueue.
++ */
++
++/* very ugly approach */
++#include "mtx.h"
++
++struct au_mmap_pre_args {
++ /* input */
++ struct file *file;
++ struct vm_area_struct *vma;
++
++ /* output */
++ int *errp;
++ struct file *h_file;
++ struct au_branch *br;
++ int mmapped;
++};
++
++static int au_mmap_pre(struct file *file, struct vm_area_struct *vma,
++ struct file **h_file, struct au_branch **br,
++ int *mmapped)
++{
++ int err;
++ aufs_bindex_t bstart;
++ const unsigned char wlock
++ = !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED);
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ *mmapped = !!au_test_mmapped(file);
++ if (wlock) {
++ struct au_pin pin;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_write_unlock(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ au_unpin(&pin);
++ } else
++ di_write_unlock(dentry);
++ bstart = au_fbstart(file);
++ *br = au_sbr(sb, bstart);
++ *h_file = au_hf_top(file);
++ get_file(*h_file);
++ au_fi_mmap_lock(file);
++
++out_unlock:
++ fi_write_unlock(file);
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++static void au_call_mmap_pre(void *args)
++{
++ struct au_mmap_pre_args *a = args;
++ *a->errp = au_mmap_pre(a->file, a->vma, &a->h_file, &a->br,
++ &a->mmapped);
++}
++
++static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ int err, wkq_err;
++ unsigned long h_vmflags;
++ struct au_finfo *finfo;
++ struct dentry *h_dentry;
++ struct vm_operations_struct *h_vmop, *vmop;
++ struct au_mmap_pre_args args = {
++ .file = file,
++ .vma = vma,
++ .errp = &err
++ };
++
++ wkq_err = au_wkq_wait_pre(au_call_mmap_pre, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ if (unlikely(err))
++ goto out;
++ finfo = au_fi(file);
++ mutex_set_owner(&finfo->fi_mmap);
++
++ h_dentry = args.h_file->f_dentry;
++ if (!args.mmapped && au_test_fs_bad_mapping(h_dentry->d_sb)) {
++ /*
++ * by this assignment, f_mapping will differs from aufs inode
++ * i_mapping.
++ * if someone else mixes the use of f_dentry->d_inode and
++ * f_mapping->host, then a problem may arise.
++ */
++ file->f_mapping = args.h_file->f_mapping;
++ }
++
++ /* always try this internal mmap to get vma flags */
++ h_vmflags = 0; /* gcc warning */
++ h_vmop = au_hvmop(args.h_file, vma, &h_vmflags);
++ err = PTR_ERR(h_vmop);
++ if (IS_ERR(h_vmop))
++ goto out_unlock;
++ AuDebugOn(args.mmapped && h_vmop != finfo->fi_hvmop);
++
++ vmop = (void *)au_dy_vmop(file, args.br, h_vmop);
++ err = PTR_ERR(vmop);
++ if (IS_ERR(vmop))
++ goto out_unlock;
++
++ /*
++ * unnecessary to handle MAP_DENYWRITE and deny_write_access()?
++ * currently MAP_DENYWRITE from userspace is ignored, but elf loader
++ * sets it. when FMODE_EXEC is set (by open_exec() or sys_uselib()),
++ * both of the aufs file and the lower file is deny_write_access()-ed.
++ * finally I hope we can skip handlling MAP_DENYWRITE here.
++ */
++ err = generic_file_mmap(file, vma);
++ if (unlikely(err))
++ goto out_unlock;
++
++ vma->vm_ops = vmop;
++ vma->vm_flags = h_vmflags;
++ if (!args.mmapped)
++ finfo->fi_hvmop = h_vmop;
++
++ vfsub_file_accessed(args.h_file);
++ /* update without lock, I don't think it a problem */
++ fsstack_copy_attr_atime(file->f_dentry->d_inode, h_dentry->d_inode);
++
++out_unlock:
++ au_fi_mmap_unlock(file);
++ fput(args.h_file);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_fsync_nondir(struct file *file, int datasync)
++{
++ int err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *h_file;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ IMustLock(file->f_mapping->host);
++ if (inode != file->f_mapping->host) {
++ mutex_unlock(&file->f_mapping->host->i_mutex);
++ mutex_lock(&inode->i_mutex);
++ }
++ IMustLock(inode);
++
++ sb = dentry->d_sb;
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out;
++
++ err = 0; /* -EBADF; */ /* posix? */
++ if (unlikely(!(file->f_mode & FMODE_WRITE)))
++ goto out_si;
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out_si;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++ au_unpin(&pin);
++
++ err = -EINVAL;
++ h_file = au_hf_top(file);
++ if (h_file->f_op && h_file->f_op->fsync) {
++ struct mutex *h_mtx;
++
++ /*
++ * no filemap_fdatawrite() since aufs file has no its own
++ * mapping, but dir.
++ */
++ h_mtx = &h_file->f_dentry->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ err = h_file->f_op->fsync(h_file, datasync);
++ if (!err)
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL);
++ /*ignore*/
++ au_cpup_attr_timesizes(inode);
++ mutex_unlock(h_mtx);
++ }
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out_si:
++ si_read_unlock(sb);
++out:
++ if (inode != file->f_mapping->host) {
++ mutex_unlock(&inode->i_mutex);
++ mutex_lock(&file->f_mapping->host->i_mutex);
++ }
++ return err;
++}
++
++/* no one supports this operation, currently */
++#if 0
++static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync)
++{
++ int err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *file, *h_file;
++
++ file = kio->ki_filp;
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ au_mtx_and_read_lock(inode);
++
++ err = 0; /* -EBADF; */ /* posix? */
++ if (unlikely(!(file->f_mode & FMODE_WRITE)))
++ goto out;
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++ au_unpin(&pin);
++
++ err = -ENOSYS;
++ h_file = au_hf_top(file);
++ if (h_file->f_op && h_file->f_op->aio_fsync) {
++ struct dentry *h_d;
++ struct mutex *h_mtx;
++
++ h_d = h_file->f_dentry;
++ h_mtx = &h_d->d_inode->i_mutex;
++ if (!is_sync_kiocb(kio)) {
++ get_file(h_file);
++ fput(file);
++ }
++ kio->ki_filp = h_file;
++ err = h_file->f_op->aio_fsync(kio, datasync);
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ if (!err)
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL);
++ /*ignore*/
++ au_cpup_attr_timesizes(inode);
++ mutex_unlock(h_mtx);
++ }
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out:
++ si_read_unlock(inode->sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++#endif
++
++static int aufs_fasync(int fd, struct file *file, int flag)
++{
++ int err;
++ struct file *h_file;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ h_file = au_hf_top(file);
++ if (h_file->f_op && h_file->f_op->fasync)
++ err = h_file->f_op->fasync(fd, h_file, flag);
++
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* no one supports this operation, currently */
++#if 0
++static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset,
++ size_t len, loff_t *pos , int more)
++{
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++const struct file_operations aufs_file_fop = {
++ .owner = THIS_MODULE,
++ /*
++ * while generic_file_llseek/_unlocked() don't use BKL,
++ * don't use it since it operates file->f_mapping->host.
++ * in aufs, it may be a real file and may confuse users by UDBA.
++ */
++ /* .llseek = generic_file_llseek, */
++
++ .read = aufs_read,
++ .write = aufs_write,
++ .aio_read = aufs_aio_read,
++ .aio_write = aufs_aio_write,
++#ifdef CONFIG_AUFS_POLL
++ .poll = aufs_poll,
++#endif
++ .unlocked_ioctl = aufs_ioctl_nondir,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = aufs_ioctl_nondir, /* same */
++#endif
++ .mmap = aufs_mmap,
++ .open = aufs_open_nondir,
++ .flush = aufs_flush_nondir,
++ .release = aufs_release_nondir,
++ .fsync = aufs_fsync_nondir,
++ /* .aio_fsync = aufs_aio_fsync_nondir, */
++ .fasync = aufs_fasync,
++ /* .sendpage = aufs_sendpage, */
++ .splice_write = aufs_splice_write,
++ .splice_read = aufs_splice_read,
++#if 0
++ .aio_splice_write = aufs_aio_splice_write,
++ .aio_splice_read = aufs_aio_splice_read
++#endif
++};
+diff -Nur linux-2.6.36.orig/fs/aufs/f_op_sp.c linux-2.6.36/fs/aufs/f_op_sp.c
+--- linux-2.6.36.orig/fs/aufs/f_op_sp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/f_op_sp.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,299 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * file operations for special files.
++ * while they exist in aufs virtually,
++ * their file I/O is handled out of aufs.
++ */
++
++#include <linux/fs_stack.h>
++#include "aufs.h"
++
++static ssize_t aufs_aio_read_sp(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ aufs_bindex_t bstart;
++ unsigned char wbr;
++ struct file *file, *h_file;
++ struct super_block *sb;
++
++ file = kio->ki_filp;
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ fi_read_lock(file);
++ bstart = au_fbstart(file);
++ h_file = au_hf_top(file);
++ fi_read_unlock(file);
++ wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm);
++ si_read_unlock(sb);
++
++ /* do not change the file in kio */
++ AuDebugOn(!h_file->f_op || !h_file->f_op->aio_read);
++ err = h_file->f_op->aio_read(kio, iov, nv, pos);
++ if (err > 0 && wbr)
++ file_accessed(h_file);
++
++ return err;
++}
++
++static ssize_t aufs_aio_write_sp(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ aufs_bindex_t bstart;
++ unsigned char wbr;
++ struct super_block *sb;
++ struct file *file, *h_file;
++
++ file = kio->ki_filp;
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ fi_read_lock(file);
++ bstart = au_fbstart(file);
++ h_file = au_hf_top(file);
++ fi_read_unlock(file);
++ wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm);
++ si_read_unlock(sb);
++
++ /* do not change the file in kio */
++ AuDebugOn(!h_file->f_op || !h_file->f_op->aio_write);
++ err = h_file->f_op->aio_write(kio, iov, nv, pos);
++ if (err > 0 && wbr)
++ file_update_time(h_file);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_release_sp(struct inode *inode, struct file *file)
++{
++ int err;
++ struct file *h_file;
++
++ fi_read_lock(file);
++ h_file = au_hf_top(file);
++ fi_read_unlock(file);
++ /* close this fifo in aufs */
++ err = h_file->f_op->release(inode, file); /* ignore */
++ aufs_release_nondir(inode, file); /* ignore */
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* currently, support only FIFO */
++enum {
++ AuSp_FIFO, AuSp_FIFO_R, AuSp_FIFO_W, AuSp_FIFO_RW,
++ /* AuSp_SOCK, AuSp_CHR, AuSp_BLK, */
++ AuSp_Last
++};
++static int aufs_open_sp(struct inode *inode, struct file *file);
++static struct au_sp_fop {
++ int done;
++ struct file_operations fop; /* not 'const' */
++ spinlock_t spin;
++} au_sp_fop[AuSp_Last] = {
++ [AuSp_FIFO] = {
++ .fop = {
++ .owner = THIS_MODULE,
++ .open = aufs_open_sp
++ }
++ }
++};
++
++static void au_init_fop_sp(struct file *file)
++{
++ struct au_sp_fop *p;
++ int i;
++ struct file *h_file;
++
++ p = au_sp_fop;
++ if (unlikely(!p->done)) {
++ /* initialize first time only */
++ static DEFINE_SPINLOCK(spin);
++
++ spin_lock(&spin);
++ if (!p->done) {
++ BUILD_BUG_ON(sizeof(au_sp_fop)/sizeof(*au_sp_fop)
++ != AuSp_Last);
++ for (i = 0; i < AuSp_Last; i++)
++ spin_lock_init(&p[i].spin);
++ p->done = 1;
++ }
++ spin_unlock(&spin);
++ }
++
++ switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) {
++ case FMODE_READ:
++ i = AuSp_FIFO_R;
++ break;
++ case FMODE_WRITE:
++ i = AuSp_FIFO_W;
++ break;
++ case FMODE_READ | FMODE_WRITE:
++ i = AuSp_FIFO_RW;
++ break;
++ default:
++ BUG();
++ }
++
++ p += i;
++ if (unlikely(!p->done)) {
++ /* initialize first time only */
++ h_file = au_hf_top(file);
++ spin_lock(&p->spin);
++ if (!p->done) {
++ p->fop = *h_file->f_op;
++ p->fop.owner = THIS_MODULE;
++ if (p->fop.aio_read)
++ p->fop.aio_read = aufs_aio_read_sp;
++ if (p->fop.aio_write)
++ p->fop.aio_write = aufs_aio_write_sp;
++ p->fop.release = aufs_release_sp;
++ p->done = 1;
++ }
++ spin_unlock(&p->spin);
++ }
++ file->f_op = &p->fop;
++}
++
++static int au_cpup_sp(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bcpup;
++ struct au_pin pin;
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = 0
++ };
++
++ AuDbg("%.*s\n", AuDLNPair(dentry));
++
++ di_read_unlock(dentry, AuLock_IR);
++ di_write_lock_child(dentry);
++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
++ if (unlikely(err < 0))
++ goto out;
++ bcpup = err;
++ err = 0;
++ if (bcpup == au_dbstart(dentry))
++ goto out; /* success */
++
++ err = au_pin(&pin, dentry, bcpup, au_opt_udba(dentry->d_sb),
++ AuPin_MNT_WRITE);
++ if (!err) {
++ err = au_sio_cpup_simple(dentry, bcpup, -1, AuCpup_DTIME);
++ au_unpin(&pin);
++ }
++
++out:
++ di_downgrade_lock(dentry, AuLock_IR);
++ return err;
++}
++
++static int au_do_open_sp(struct file *file, int flags)
++{
++ int err;
++ struct dentry *dentry;
++ struct super_block *sb;
++ struct file *h_file;
++ struct inode *h_inode;
++
++ dentry = file->f_dentry;
++ AuDbg("%.*s\n", AuDLNPair(dentry));
++
++ /*
++ * try copying-up.
++ * operate on the ro branch is not an error.
++ */
++ au_cpup_sp(dentry); /* ignore */
++
++ /* prepare h_file */
++ err = au_do_open_nondir(file, vfsub_file_flags(file));
++ if (unlikely(err))
++ goto out;
++
++ sb = dentry->d_sb;
++ h_file = au_hf_top(file);
++ h_inode = h_file->f_dentry->d_inode;
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ si_read_unlock(sb);
++ /* open this fifo in aufs */
++ err = h_inode->i_fop->open(file->f_dentry->d_inode, file);
++ si_noflush_read_lock(sb);
++ fi_write_lock(file);
++ di_read_lock_child(dentry, AuLock_IR);
++ if (!err)
++ au_init_fop_sp(file);
++
++out:
++ return err;
++}
++
++static int aufs_open_sp(struct inode *inode, struct file *file)
++{
++ int err;
++ struct super_block *sb;
++
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_do_open(file, au_do_open_sp, /*fidir*/NULL);
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev)
++{
++ init_special_inode(inode, mode, rdev);
++
++ switch (mode & S_IFMT) {
++ case S_IFIFO:
++ inode->i_fop = &au_sp_fop[AuSp_FIFO].fop;
++ /*FALLTHROUGH*/
++ case S_IFCHR:
++ case S_IFBLK:
++ case S_IFSOCK:
++ break;
++ default:
++ AuDebugOn(1);
++ }
++}
++
++int au_special_file(umode_t mode)
++{
++ int ret;
++
++ ret = 0;
++ switch (mode & S_IFMT) {
++ case S_IFIFO:
++#if 0
++ case S_IFCHR:
++ case S_IFBLK:
++ case S_IFSOCK:
++#endif
++ ret = 1;
++ }
++
++ return ret;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/file.c linux-2.6.36/fs/aufs/file.c
+--- linux-2.6.36.orig/fs/aufs/file.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/file.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,676 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * handling file/dir, and address_space operation
++ */
++
++#include <linux/file.h>
++#include <linux/fsnotify.h>
++#include <linux/namei.h>
++#include <linux/pagemap.h>
++#include "aufs.h"
++
++/* drop flags for writing */
++unsigned int au_file_roflags(unsigned int flags)
++{
++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC);
++ flags |= O_RDONLY | O_NOATIME;
++ return flags;
++}
++
++/* common functions to regular file and dir */
++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
++ struct file *file)
++{
++ struct file *h_file;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++ struct super_block *sb;
++ struct au_branch *br;
++ struct path h_path;
++ int err, exec_flag;
++
++ /* a race condition can happen between open and unlink/rmdir */
++ h_file = ERR_PTR(-ENOENT);
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (au_test_nfsd() && !h_dentry)
++ goto out;
++ h_inode = h_dentry->d_inode;
++ if (au_test_nfsd() && !h_inode)
++ goto out;
++ if (unlikely((!d_unhashed(dentry) && au_d_removed(h_dentry))
++ || !h_inode
++ /* || !dentry->d_inode->i_nlink */
++ ))
++ goto out;
++
++ sb = dentry->d_sb;
++ br = au_sbr(sb, bindex);
++ h_file = ERR_PTR(-EACCES);
++ exec_flag = flags & vfsub_fmode_to_uint(FMODE_EXEC);
++ if (exec_flag && (br->br_mnt->mnt_flags & MNT_NOEXEC))
++ goto out;
++
++ /* drop flags for writing */
++ if (au_test_ro(sb, bindex, dentry->d_inode))
++ flags = au_file_roflags(flags);
++ flags &= ~O_CREAT;
++ atomic_inc(&br->br_count);
++ h_path.dentry = h_dentry;
++ h_path.mnt = br->br_mnt;
++ if (!au_special_file(h_inode->i_mode))
++ h_file = vfsub_dentry_open(&h_path, flags);
++ else {
++ /* this block depends upon the configuration */
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ si_read_unlock(sb);
++ h_file = vfsub_dentry_open(&h_path, flags);
++ si_noflush_read_lock(sb);
++ fi_write_lock(file);
++ di_read_lock_child(dentry, AuLock_IR);
++ }
++ if (IS_ERR(h_file))
++ goto out_br;
++
++ if (exec_flag) {
++ err = deny_write_access(h_file);
++ if (unlikely(err)) {
++ fput(h_file);
++ h_file = ERR_PTR(err);
++ goto out_br;
++ }
++ }
++ fsnotify_open(h_file);
++ goto out; /* success */
++
++out_br:
++ atomic_dec(&br->br_count);
++out:
++ return h_file;
++}
++
++int au_do_open(struct file *file, int (*open)(struct file *file, int flags),
++ struct au_fidir *fidir)
++{
++ int err;
++ struct dentry *dentry;
++
++ err = au_finfo_init(file, fidir);
++ if (unlikely(err))
++ goto out;
++
++ dentry = file->f_dentry;
++ di_read_lock_child(dentry, AuLock_IR);
++ err = open(file, vfsub_file_flags(file));
++ di_read_unlock(dentry, AuLock_IR);
++
++ fi_write_unlock(file);
++ if (unlikely(err)) {
++ au_fi(file)->fi_hdir = NULL;
++ au_finfo_fin(file);
++ }
++
++out:
++ return err;
++}
++
++int au_reopen_nondir(struct file *file)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct dentry *dentry;
++ struct file *h_file, *h_file_tmp;
++
++ dentry = file->f_dentry;
++ AuDebugOn(au_special_file(dentry->d_inode->i_mode));
++ bstart = au_dbstart(dentry);
++ h_file_tmp = NULL;
++ if (au_fbstart(file) == bstart) {
++ h_file = au_hf_top(file);
++ if (file->f_mode == h_file->f_mode)
++ return 0; /* success */
++ h_file_tmp = h_file;
++ get_file(h_file_tmp);
++ au_set_h_fptr(file, bstart, NULL);
++ }
++ AuDebugOn(au_fi(file)->fi_hdir);
++ AuDebugOn(au_fbstart(file) < bstart);
++
++ h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC,
++ file);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out; /* todo: close all? */
++
++ err = 0;
++ au_set_fbstart(file, bstart);
++ au_set_h_fptr(file, bstart, h_file);
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++
++out:
++ if (h_file_tmp)
++ fput(h_file_tmp);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_reopen_wh(struct file *file, aufs_bindex_t btgt,
++ struct dentry *hi_wh)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct au_dinfo *dinfo;
++ struct dentry *h_dentry;
++ struct au_hdentry *hdp;
++
++ dinfo = au_di(file->f_dentry);
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ bstart = dinfo->di_bstart;
++ dinfo->di_bstart = btgt;
++ hdp = dinfo->di_hdentry;
++ h_dentry = hdp[0 + btgt].hd_dentry;
++ hdp[0 + btgt].hd_dentry = hi_wh;
++ err = au_reopen_nondir(file);
++ hdp[0 + btgt].hd_dentry = h_dentry;
++ dinfo->di_bstart = bstart;
++
++ return err;
++}
++
++static int au_ready_to_write_wh(struct file *file, loff_t len,
++ aufs_bindex_t bcpup)
++{
++ int err;
++ struct inode *inode, *h_inode;
++ struct dentry *dentry, *h_dentry, *hi_wh;
++
++ dentry = file->f_dentry;
++ au_update_dbstart(dentry);
++ inode = dentry->d_inode;
++ h_inode = NULL;
++ if (au_dbstart(dentry) <= bcpup && au_dbend(dentry) >= bcpup) {
++ h_dentry = au_h_dptr(dentry, bcpup);
++ if (h_dentry)
++ h_inode = h_dentry->d_inode;
++ }
++ hi_wh = au_hi_wh(inode, bcpup);
++ if (!hi_wh && !h_inode)
++ err = au_sio_cpup_wh(dentry, bcpup, len, file);
++ else
++ /* already copied-up after unlink */
++ err = au_reopen_wh(file, bcpup, hi_wh);
++
++ if (!err
++ && inode->i_nlink > 1
++ && au_opt_test(au_mntflags(dentry->d_sb), PLINK))
++ au_plink_append(inode, bcpup, au_h_dptr(dentry, bcpup));
++
++ return err;
++}
++
++/*
++ * prepare the @file for writing.
++ */
++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
++{
++ int err;
++ aufs_bindex_t bstart, bcpup, dbstart;
++ struct dentry *dentry, *parent, *h_dentry;
++ struct inode *h_inode, *inode;
++ struct super_block *sb;
++ struct file *h_file;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ AuDebugOn(au_special_file(inode->i_mode));
++ bstart = au_fbstart(file);
++ err = au_test_ro(sb, bstart, inode);
++ if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) {
++ err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0);
++ goto out;
++ }
++
++ /* need to cpup or reopen */
++ parent = dget_parent(dentry);
++ di_write_lock_parent(parent);
++ err = AuWbrCopyup(au_sbi(sb), dentry);
++ bcpup = err;
++ if (unlikely(err < 0))
++ goto out_dgrade;
++ err = 0;
++
++ if (!d_unhashed(dentry) && !au_h_dptr(parent, bcpup)) {
++ err = au_cpup_dirs(dentry, bcpup);
++ if (unlikely(err))
++ goto out_dgrade;
++ }
++
++ err = au_pin(pin, dentry, bcpup, AuOpt_UDBA_NONE,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (unlikely(err))
++ goto out_dgrade;
++
++ h_dentry = au_hf_top(file)->f_dentry;
++ h_inode = h_dentry->d_inode;
++ dbstart = au_dbstart(dentry);
++ if (dbstart <= bcpup) {
++ h_dentry = au_h_dptr(dentry, bcpup);
++ AuDebugOn(!h_dentry);
++ h_inode = h_dentry->d_inode;
++ AuDebugOn(!h_inode);
++ bstart = bcpup;
++ }
++
++ if (dbstart <= bcpup /* just reopen */
++ || !d_unhashed(dentry) /* copyup and reopen */
++ ) {
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ h_file = au_h_open_pre(dentry, bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else {
++ di_downgrade_lock(parent, AuLock_IR);
++ if (dbstart > bcpup)
++ err = au_sio_cpup_simple(dentry, bcpup, len,
++ AuCpup_DTIME);
++ if (!err)
++ err = au_reopen_nondir(file);
++ }
++ mutex_unlock(&h_inode->i_mutex);
++ au_h_open_post(dentry, bstart, h_file);
++ } else { /* copyup as wh and reopen */
++ /*
++ * since writable hfsplus branch is not supported,
++ * h_open_pre/post() are unnecessary.
++ */
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ err = au_ready_to_write_wh(file, len, bcpup);
++ di_downgrade_lock(parent, AuLock_IR);
++ mutex_unlock(&h_inode->i_mutex);
++ }
++
++ if (!err) {
++ au_pin_set_parent_lflag(pin, /*lflag*/0);
++ goto out_dput; /* success */
++ }
++ au_unpin(pin);
++ goto out_unlock;
++
++out_dgrade:
++ di_downgrade_lock(parent, AuLock_IR);
++out_unlock:
++ di_read_unlock(parent, AuLock_IR);
++out_dput:
++ dput(parent);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_do_flush(struct file *file, fl_owner_t id,
++ int (*flush)(struct file *file, fl_owner_t id))
++{
++ int err;
++ struct dentry *dentry;
++ struct super_block *sb;
++ struct inode *inode;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ si_noflush_read_lock(sb);
++ fi_read_lock(file);
++ ii_read_lock_child(inode);
++
++ err = flush(file, id);
++ au_cpup_attr_timesizes(inode);
++
++ ii_read_unlock(inode);
++ fi_read_unlock(file);
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_file_refresh_by_inode(struct file *file, int *need_reopen)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct au_pin pin;
++ struct au_finfo *finfo;
++ struct dentry *dentry, *parent, *hi_wh;
++ struct inode *inode;
++ struct super_block *sb;
++
++ FiMustWriteLock(file);
++
++ err = 0;
++ finfo = au_fi(file);
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ bstart = au_ibstart(inode);
++ if (bstart == finfo->fi_btop || IS_ROOT(dentry))
++ goto out;
++
++ parent = dget_parent(dentry);
++ if (au_test_ro(sb, bstart, inode)) {
++ di_read_lock_parent(parent, !AuLock_IR);
++ err = AuWbrCopyup(au_sbi(sb), dentry);
++ bstart = err;
++ di_read_unlock(parent, !AuLock_IR);
++ if (unlikely(err < 0))
++ goto out_parent;
++ err = 0;
++ }
++
++ di_read_lock_parent(parent, AuLock_IR);
++ hi_wh = au_hi_wh(inode, bstart);
++ if (!S_ISDIR(inode->i_mode)
++ && au_opt_test(au_mntflags(sb), PLINK)
++ && au_plink_test(inode)
++ && !d_unhashed(dentry)) {
++ err = au_test_and_cpup_dirs(dentry, bstart);
++ if (unlikely(err))
++ goto out_unlock;
++
++ /* always superio. */
++ err = au_pin(&pin, dentry, bstart, AuOpt_UDBA_NONE,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (!err)
++ err = au_sio_cpup_simple(dentry, bstart, -1,
++ AuCpup_DTIME);
++ au_unpin(&pin);
++ } else if (hi_wh) {
++ /* already copied-up after unlink */
++ err = au_reopen_wh(file, bstart, hi_wh);
++ *need_reopen = 0;
++ }
++
++out_unlock:
++ di_read_unlock(parent, AuLock_IR);
++out_parent:
++ dput(parent);
++out:
++ return err;
++}
++
++static void au_do_refresh_dir(struct file *file)
++{
++ aufs_bindex_t bindex, bend, new_bindex, brid;
++ struct au_hfile *p, tmp, *q;
++ struct au_finfo *finfo;
++ struct super_block *sb;
++ struct au_fidir *fidir;
++
++ FiMustWriteLock(file);
++
++ sb = file->f_dentry->d_sb;
++ finfo = au_fi(file);
++ fidir = finfo->fi_hdir;
++ AuDebugOn(!fidir);
++ p = fidir->fd_hfile + finfo->fi_btop;
++ brid = p->hf_br->br_id;
++ bend = fidir->fd_bbot;
++ for (bindex = finfo->fi_btop; bindex <= bend; bindex++, p++) {
++ if (!p->hf_file)
++ continue;
++
++ new_bindex = au_br_index(sb, p->hf_br->br_id);
++ if (new_bindex == bindex)
++ continue;
++ if (new_bindex < 0) {
++ au_set_h_fptr(file, bindex, NULL);
++ continue;
++ }
++
++ /* swap two lower inode, and loop again */
++ q = fidir->fd_hfile + new_bindex;
++ tmp = *q;
++ *q = *p;
++ *p = tmp;
++ if (tmp.hf_file) {
++ bindex--;
++ p--;
++ }
++ }
++
++ p = fidir->fd_hfile;
++ if (!au_test_mmapped(file) && !au_d_removed(file->f_dentry)) {
++ bend = au_sbend(sb);
++ for (finfo->fi_btop = 0; finfo->fi_btop <= bend;
++ finfo->fi_btop++, p++)
++ if (p->hf_file) {
++ if (p->hf_file->f_dentry
++ && p->hf_file->f_dentry->d_inode)
++ break;
++ else
++ au_hfput(p, file);
++ }
++ } else {
++ bend = au_br_index(sb, brid);
++ for (finfo->fi_btop = 0; finfo->fi_btop < bend;
++ finfo->fi_btop++, p++)
++ if (p->hf_file)
++ au_hfput(p, file);
++ bend = au_sbend(sb);
++ }
++
++ p = fidir->fd_hfile + bend;
++ for (fidir->fd_bbot = bend; fidir->fd_bbot >= finfo->fi_btop;
++ fidir->fd_bbot--, p--)
++ if (p->hf_file) {
++ if (p->hf_file->f_dentry
++ && p->hf_file->f_dentry->d_inode)
++ break;
++ else
++ au_hfput(p, file);
++ }
++ AuDebugOn(fidir->fd_bbot < finfo->fi_btop);
++}
++
++/*
++ * after branch manipulating, refresh the file.
++ */
++static int refresh_file(struct file *file, int (*reopen)(struct file *file))
++{
++ int err, need_reopen;
++ aufs_bindex_t bend, bindex;
++ struct dentry *dentry;
++ struct au_finfo *finfo;
++ struct au_hfile *hfile;
++
++ dentry = file->f_dentry;
++ finfo = au_fi(file);
++ if (!finfo->fi_hdir) {
++ hfile = &finfo->fi_htop;
++ AuDebugOn(!hfile->hf_file);
++ bindex = au_br_index(dentry->d_sb, hfile->hf_br->br_id);
++ AuDebugOn(bindex < 0);
++ if (bindex != finfo->fi_btop)
++ au_set_fbstart(file, bindex);
++ } else {
++ err = au_fidir_realloc(finfo, au_sbend(dentry->d_sb) + 1);
++ if (unlikely(err))
++ goto out;
++ au_do_refresh_dir(file);
++ }
++
++ err = 0;
++ need_reopen = 1;
++ if (!au_test_mmapped(file))
++ err = au_file_refresh_by_inode(file, &need_reopen);
++ if (!err && need_reopen && !au_d_removed(dentry))
++ err = reopen(file);
++ if (!err) {
++ au_update_figen(file);
++ goto out; /* success */
++ }
++
++ /* error, close all lower files */
++ if (finfo->fi_hdir) {
++ bend = au_fbend_dir(file);
++ for (bindex = au_fbstart(file); bindex <= bend; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++ }
++
++out:
++ return err;
++}
++
++/* common function to regular file and dir */
++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
++ int wlock)
++{
++ int err;
++ unsigned int sigen, figen;
++ aufs_bindex_t bstart;
++ unsigned char pseudo_link;
++ struct dentry *dentry;
++ struct inode *inode;
++
++ err = 0;
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ AuDebugOn(au_special_file(inode->i_mode));
++ sigen = au_sigen(dentry->d_sb);
++ fi_write_lock(file);
++ figen = au_figen(file);
++ di_write_lock_child(dentry);
++ bstart = au_dbstart(dentry);
++ pseudo_link = (bstart != au_ibstart(inode));
++ if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) {
++ if (!wlock) {
++ di_downgrade_lock(dentry, AuLock_IR);
++ fi_downgrade_lock(file);
++ }
++ goto out; /* success */
++ }
++
++ AuDbg("sigen %d, figen %d\n", sigen, figen);
++ if (au_digen_test(dentry, sigen)) {
++ err = au_reval_dpath(dentry, sigen);
++ AuDebugOn(!err && au_digen_test(dentry, sigen));
++ }
++
++ if (!err)
++ err = refresh_file(file, reopen);
++ if (!err) {
++ if (!wlock) {
++ di_downgrade_lock(dentry, AuLock_IR);
++ fi_downgrade_lock(file);
++ }
++ } else {
++ di_write_unlock(dentry);
++ fi_write_unlock(file);
++ }
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* cf. aufs_nopage() */
++/* for madvise(2) */
++static int aufs_readpage(struct file *file __maybe_unused, struct page *page)
++{
++ unlock_page(page);
++ return 0;
++}
++
++/* it will never be called, but necessary to support O_DIRECT */
++static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb,
++ const struct iovec *iov, loff_t offset,
++ unsigned long nr_segs)
++{ BUG(); return 0; }
++
++/*
++ * it will never be called, but madvise and fadvise behaves differently
++ * when get_xip_mem is defined
++ */
++static int aufs_get_xip_mem(struct address_space *mapping, pgoff_t pgoff,
++ int create, void **kmem, unsigned long *pfn)
++{ BUG(); return 0; }
++
++/* they will never be called. */
++#ifdef CONFIG_AUFS_DEBUG
++static int aufs_write_begin(struct file *file, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned flags,
++ struct page **pagep, void **fsdata)
++{ AuUnsupport(); return 0; }
++static int aufs_write_end(struct file *file, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned copied,
++ struct page *page, void *fsdata)
++{ AuUnsupport(); return 0; }
++static int aufs_writepage(struct page *page, struct writeback_control *wbc)
++{ AuUnsupport(); return 0; }
++static void aufs_sync_page(struct page *page)
++{ AuUnsupport(); }
++
++static int aufs_set_page_dirty(struct page *page)
++{ AuUnsupport(); return 0; }
++static void aufs_invalidatepage(struct page *page, unsigned long offset)
++{ AuUnsupport(); }
++static int aufs_releasepage(struct page *page, gfp_t gfp)
++{ AuUnsupport(); return 0; }
++static int aufs_migratepage(struct address_space *mapping, struct page *newpage,
++ struct page *page)
++{ AuUnsupport(); return 0; }
++static int aufs_launder_page(struct page *page)
++{ AuUnsupport(); return 0; }
++static int aufs_is_partially_uptodate(struct page *page,
++ read_descriptor_t *desc,
++ unsigned long from)
++{ AuUnsupport(); return 0; }
++static int aufs_error_remove_page(struct address_space *mapping,
++ struct page *page)
++{ AuUnsupport(); return 0; }
++#endif /* CONFIG_AUFS_DEBUG */
++
++const struct address_space_operations aufs_aop = {
++ .readpage = aufs_readpage,
++ .direct_IO = aufs_direct_IO,
++ .get_xip_mem = aufs_get_xip_mem,
++#ifdef CONFIG_AUFS_DEBUG
++ .writepage = aufs_writepage,
++ .sync_page = aufs_sync_page,
++ /* no writepages, because of writepage */
++ .set_page_dirty = aufs_set_page_dirty,
++ /* no readpages, because of readpage */
++ .write_begin = aufs_write_begin,
++ .write_end = aufs_write_end,
++ /* no bmap, no block device */
++ .invalidatepage = aufs_invalidatepage,
++ .releasepage = aufs_releasepage,
++ .migratepage = aufs_migratepage,
++ .launder_page = aufs_launder_page,
++ .is_partially_uptodate = aufs_is_partially_uptodate,
++ .error_remove_page = aufs_error_remove_page
++#endif /* CONFIG_AUFS_DEBUG */
++};
+diff -Nur linux-2.6.36.orig/fs/aufs/file.h linux-2.6.36/fs/aufs/file.h
+--- linux-2.6.36.orig/fs/aufs/file.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/file.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,238 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * file operations
++ */
++
++#ifndef __AUFS_FILE_H__
++#define __AUFS_FILE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/poll.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++
++struct au_branch;
++struct au_hfile {
++ struct file *hf_file;
++ struct au_branch *hf_br;
++};
++
++struct au_vdir;
++struct au_fidir {
++ aufs_bindex_t fd_bbot;
++ aufs_bindex_t fd_nent;
++ struct au_vdir *fd_vdir_cache;
++ struct au_hfile fd_hfile[];
++};
++
++static inline int au_fidir_sz(int nent)
++{
++ AuDebugOn(nent < 0);
++ return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent;
++}
++
++struct au_finfo {
++ atomic_t fi_generation;
++
++ struct au_rwsem fi_rwsem;
++ aufs_bindex_t fi_btop;
++
++ /* do not union them */
++ struct { /* for non-dir */
++ struct au_hfile fi_htop;
++ struct vm_operations_struct *fi_hvmop;
++ struct mutex fi_vm_mtx;
++ struct mutex fi_mmap;
++ };
++ struct au_fidir *fi_hdir; /* for dir only */
++} ____cacheline_aligned_in_smp;
++
++/* ---------------------------------------------------------------------- */
++
++/* file.c */
++extern const struct address_space_operations aufs_aop;
++unsigned int au_file_roflags(unsigned int flags);
++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
++ struct file *file);
++int au_do_open(struct file *file, int (*open)(struct file *file, int flags),
++ struct au_fidir *fidir);
++int au_reopen_nondir(struct file *file);
++struct au_pin;
++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin);
++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
++ int wlock);
++int au_do_flush(struct file *file, fl_owner_t id,
++ int (*flush)(struct file *file, fl_owner_t id));
++
++/* poll.c */
++#ifdef CONFIG_AUFS_POLL
++unsigned int aufs_poll(struct file *file, poll_table *wait);
++#endif
++
++#ifdef CONFIG_AUFS_BR_HFSPLUS
++/* hfsplus.c */
++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex);
++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex,
++ struct file *h_file);
++#else
++static inline
++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ return NULL;
++}
++
++AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex,
++ struct file *h_file);
++#endif
++
++/* f_op.c */
++extern const struct file_operations aufs_file_fop;
++extern const struct vm_operations_struct aufs_vm_ops;
++int au_do_open_nondir(struct file *file, int flags);
++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file);
++
++#ifdef CONFIG_AUFS_SP_IATTR
++/* f_op_sp.c */
++int au_special_file(umode_t mode);
++void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev);
++#else
++AuStubInt0(au_special_file, umode_t mode)
++static inline void au_init_special_fop(struct inode *inode, umode_t mode,
++ dev_t rdev)
++{
++ init_special_inode(inode, mode, rdev);
++}
++#endif
++
++/* finfo.c */
++void au_hfput(struct au_hfile *hf, struct file *file);
++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex,
++ struct file *h_file);
++
++void au_update_figen(struct file *file);
++void au_fi_mmap_lock(struct file *file);
++void au_fi_mmap_unlock(struct file *file);
++struct au_fidir *au_fidir_alloc(struct super_block *sb);
++int au_fidir_realloc(struct au_finfo *finfo, int nbr);
++
++void au_fi_init_once(void *_fi);
++void au_finfo_fin(struct file *file);
++int au_finfo_init(struct file *file, struct au_fidir *fidir);
++
++/* ioctl.c */
++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg);
++#ifdef CONFIG_COMPAT
++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
++ unsigned long arg);
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_finfo *au_fi(struct file *file)
++{
++ return file->private_data;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * fi_read_lock, fi_write_lock,
++ * fi_read_unlock, fi_write_unlock, fi_downgrade_lock
++ */
++AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem);
++
++#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem)
++#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem)
++#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem)
++
++/* ---------------------------------------------------------------------- */
++
++/* todo: hard/soft set? */
++static inline aufs_bindex_t au_fbstart(struct file *file)
++{
++ FiMustAnyLock(file);
++ return au_fi(file)->fi_btop;
++}
++
++static inline aufs_bindex_t au_fbend_dir(struct file *file)
++{
++ FiMustAnyLock(file);
++ AuDebugOn(!au_fi(file)->fi_hdir);
++ return au_fi(file)->fi_hdir->fd_bbot;
++}
++
++static inline struct au_vdir *au_fvdir_cache(struct file *file)
++{
++ FiMustAnyLock(file);
++ AuDebugOn(!au_fi(file)->fi_hdir);
++ return au_fi(file)->fi_hdir->fd_vdir_cache;
++}
++
++static inline void au_set_fbstart(struct file *file, aufs_bindex_t bindex)
++{
++ FiMustWriteLock(file);
++ au_fi(file)->fi_btop = bindex;
++}
++
++static inline void au_set_fbend_dir(struct file *file, aufs_bindex_t bindex)
++{
++ FiMustWriteLock(file);
++ AuDebugOn(!au_fi(file)->fi_hdir);
++ au_fi(file)->fi_hdir->fd_bbot = bindex;
++}
++
++static inline void au_set_fvdir_cache(struct file *file,
++ struct au_vdir *vdir_cache)
++{
++ FiMustWriteLock(file);
++ AuDebugOn(!au_fi(file)->fi_hdir);
++ au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache;
++}
++
++static inline struct file *au_hf_top(struct file *file)
++{
++ FiMustAnyLock(file);
++ AuDebugOn(au_fi(file)->fi_hdir);
++ return au_fi(file)->fi_htop.hf_file;
++}
++
++static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex)
++{
++ FiMustAnyLock(file);
++ AuDebugOn(!au_fi(file)->fi_hdir);
++ return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file;
++}
++
++/* todo: memory barrier? */
++static inline unsigned int au_figen(struct file *f)
++{
++ return atomic_read(&au_fi(f)->fi_generation);
++}
++
++static inline int au_test_mmapped(struct file *f)
++{
++ FiMustAnyLock(f);
++ return !!(au_fi(f)->fi_hvmop);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_FILE_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/finfo.c linux-2.6.36/fs/aufs/finfo.c
+--- linux-2.6.36.orig/fs/aufs/finfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/finfo.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,174 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * file private data
++ */
++
++#include <linux/file.h>
++#include "aufs.h"
++
++void au_hfput(struct au_hfile *hf, struct file *file)
++{
++ /* todo: direct access f_flags */
++ if (vfsub_file_flags(file) & vfsub_fmode_to_uint(FMODE_EXEC))
++ allow_write_access(hf->hf_file);
++ fput(hf->hf_file);
++ hf->hf_file = NULL;
++ atomic_dec(&hf->hf_br->br_count);
++ hf->hf_br = NULL;
++}
++
++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val)
++{
++ struct au_finfo *finfo = au_fi(file);
++ struct au_hfile *hf;
++ struct au_fidir *fidir;
++
++ fidir = finfo->fi_hdir;
++ if (!fidir) {
++ AuDebugOn(finfo->fi_btop != bindex);
++ hf = &finfo->fi_htop;
++ } else
++ hf = fidir->fd_hfile + bindex;
++
++ if (hf && hf->hf_file)
++ au_hfput(hf, file);
++ if (val) {
++ FiMustWriteLock(file);
++ hf->hf_file = val;
++ hf->hf_br = au_sbr(file->f_dentry->d_sb, bindex);
++ }
++}
++
++void au_update_figen(struct file *file)
++{
++ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_dentry));
++ /* smp_mb(); */ /* atomic_set */
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_fi_mmap_lock(struct file *file)
++{
++ FiMustWriteLock(file);
++ lockdep_off();
++ mutex_lock(&au_fi(file)->fi_mmap);
++ lockdep_on();
++}
++
++void au_fi_mmap_unlock(struct file *file)
++{
++ lockdep_off();
++ mutex_unlock(&au_fi(file)->fi_mmap);
++ lockdep_on();
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_fidir *au_fidir_alloc(struct super_block *sb)
++{
++ struct au_fidir *fidir;
++ int nbr;
++
++ nbr = au_sbend(sb) + 1;
++ if (nbr < 2)
++ nbr = 2; /* initial allocate for 2 branches */
++ fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS);
++ if (fidir) {
++ fidir->fd_bbot = -1;
++ fidir->fd_nent = nbr;
++ fidir->fd_vdir_cache = NULL;
++ }
++
++ return fidir;
++}
++
++int au_fidir_realloc(struct au_finfo *finfo, int nbr)
++{
++ int err;
++ struct au_fidir *fidir, *p;
++
++ AuRwMustWriteLock(&finfo->fi_rwsem);
++ fidir = finfo->fi_hdir;
++ AuDebugOn(!fidir);
++
++ err = -ENOMEM;
++ p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr),
++ GFP_NOFS);
++ if (p) {
++ p->fd_nent = nbr;
++ finfo->fi_hdir = p;
++ err = 0;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_finfo_fin(struct file *file)
++{
++ struct au_finfo *finfo;
++
++ au_nfiles_dec(file->f_dentry->d_sb);
++
++ finfo = au_fi(file);
++ AuDebugOn(finfo->fi_hdir);
++ AuRwDestroy(&finfo->fi_rwsem);
++ au_cache_free_finfo(finfo);
++}
++
++void au_fi_init_once(void *_finfo)
++{
++ struct au_finfo *finfo = _finfo;
++ static struct lock_class_key aufs_fi, aufs_fi_vm, aufs_fi_mmap;
++
++ au_rw_init(&finfo->fi_rwsem);
++ au_rw_class(&finfo->fi_rwsem, &aufs_fi);
++ mutex_init(&finfo->fi_vm_mtx);
++ lockdep_set_class(&finfo->fi_vm_mtx, &aufs_fi_vm);
++ mutex_init(&finfo->fi_mmap);
++ lockdep_set_class(&finfo->fi_mmap, &aufs_fi_mmap);
++}
++
++int au_finfo_init(struct file *file, struct au_fidir *fidir)
++{
++ int err;
++ struct au_finfo *finfo;
++ struct dentry *dentry;
++
++ err = -ENOMEM;
++ dentry = file->f_dentry;
++ finfo = au_cache_alloc_finfo();
++ if (unlikely(!finfo))
++ goto out;
++
++ err = 0;
++ au_nfiles_inc(dentry->d_sb);
++ au_rw_write_lock(&finfo->fi_rwsem);
++ finfo->fi_btop = -1;
++ finfo->fi_hdir = fidir;
++ atomic_set(&finfo->fi_generation, au_digen(dentry));
++ /* smp_mb(); */ /* atomic_set */
++
++ file->private_data = finfo;
++
++out:
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/fstype.h linux-2.6.36/fs/aufs/fstype.h
+--- linux-2.6.36.orig/fs/aufs/fstype.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/fstype.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,497 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * judging filesystem type
++ */
++
++#ifndef __AUFS_FSTYPE_H__
++#define __AUFS_FSTYPE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/magic.h>
++#include <linux/romfs_fs.h>
++#include <linux/aufs_type.h>
++
++static inline int au_test_aufs(struct super_block *sb)
++{
++ return sb->s_magic == AUFS_SUPER_MAGIC;
++}
++
++static inline const char *au_sbtype(struct super_block *sb)
++{
++ return sb->s_type->name;
++}
++
++static inline int au_test_iso9660(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE)
++ return sb->s_magic == ROMFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_romfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE)
++ return sb->s_magic == ISOFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_cramfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE)
++ return sb->s_magic == CRAMFS_MAGIC;
++#endif
++ return 0;
++}
++
++static inline int au_test_nfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE)
++ return sb->s_magic == NFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_fuse(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE)
++ return sb->s_magic == FUSE_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_xfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_XFS_FS) || defined(CONFIG_XFS_FS_MODULE)
++ return sb->s_magic == XFS_SB_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_tmpfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_TMPFS
++ return sb->s_magic == TMPFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_ECRYPT_FS) || defined(CONFIG_ECRYPT_FS_MODULE)
++ return !strcmp(au_sbtype(sb), "ecryptfs");
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_smbfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_SMB_FS) || defined(CONFIG_SMB_FS_MODULE)
++ return sb->s_magic == SMB_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ocfs2(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_OCFS2_FS) || defined(CONFIG_OCFS2_FS_MODULE)
++ return sb->s_magic == OCFS2_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ocfs2_dlmfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_OCFS2_FS_O2CB) || defined(CONFIG_OCFS2_FS_O2CB_MODULE)
++ return sb->s_magic == DLMFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_coda(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CODA_FS) || defined(CONFIG_CODA_FS_MODULE)
++ return sb->s_magic == CODA_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_v9fs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_9P_FS) || defined(CONFIG_9P_FS_MODULE)
++ return sb->s_magic == V9FS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ext4(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_EXT4DEV_FS) || defined(CONFIG_EXT4DEV_FS_MODULE)
++ return sb->s_magic == EXT4_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_sysv(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_SYSV_FS) || defined(CONFIG_SYSV_FS_MODULE)
++ return !strcmp(au_sbtype(sb), "sysv");
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ramfs(struct super_block *sb)
++{
++ return sb->s_magic == RAMFS_MAGIC;
++}
++
++static inline int au_test_ubifs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_UBIFS_FS) || defined(CONFIG_UBIFS_FS_MODULE)
++ return sb->s_magic == UBIFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_procfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_PROC_FS
++ return sb->s_magic == PROC_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_sysfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_SYSFS
++ return sb->s_magic == SYSFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_configfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CONFIGFS_FS) || defined(CONFIG_CONFIGFS_FS_MODULE)
++ return sb->s_magic == CONFIGFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_minix(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_MINIX_FS) || defined(CONFIG_MINIX_FS_MODULE)
++ return sb->s_magic == MINIX3_SUPER_MAGIC
++ || sb->s_magic == MINIX2_SUPER_MAGIC
++ || sb->s_magic == MINIX2_SUPER_MAGIC2
++ || sb->s_magic == MINIX_SUPER_MAGIC
++ || sb->s_magic == MINIX_SUPER_MAGIC2;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_cifs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CIFS_FS) || defined(CONFIGCIFS_FS_MODULE)
++ return sb->s_magic == CIFS_MAGIC_NUMBER;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_fat(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_FAT_FS) || defined(CONFIG_FAT_FS_MODULE)
++ return sb->s_magic == MSDOS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_msdos(struct super_block *sb)
++{
++ return au_test_fat(sb);
++}
++
++static inline int au_test_vfat(struct super_block *sb)
++{
++ return au_test_fat(sb);
++}
++
++static inline int au_test_securityfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_SECURITYFS
++ return sb->s_magic == SECURITYFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_squashfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_SQUASHFS) || defined(CONFIG_SQUASHFS_MODULE)
++ return sb->s_magic == SQUASHFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_btrfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_BTRFS_FS) || defined(CONFIG_BTRFS_FS_MODULE)
++ return sb->s_magic == BTRFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_xenfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_XENFS) || defined(CONFIG_XENFS_MODULE)
++ return sb->s_magic == XENFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_debugfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_DEBUG_FS
++ return sb->s_magic == DEBUGFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_nilfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_NILFS) || defined(CONFIG_NILFS_MODULE)
++ return sb->s_magic == NILFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_hfsplus(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_HFSPLUS_FS) || defined(CONFIG_HFSPLUS_FS_MODULE)
++ return sb->s_magic == HFSPLUS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * they can't be an aufs branch.
++ */
++static inline int au_test_fs_unsuppoted(struct super_block *sb)
++{
++ return
++#ifndef CONFIG_AUFS_BR_RAMFS
++ au_test_ramfs(sb) ||
++#endif
++ au_test_procfs(sb)
++ || au_test_sysfs(sb)
++ || au_test_configfs(sb)
++ || au_test_debugfs(sb)
++ || au_test_securityfs(sb)
++ || au_test_xenfs(sb)
++ || au_test_ecryptfs(sb)
++ /* || !strcmp(au_sbtype(sb), "unionfs") */
++ || au_test_aufs(sb); /* will be supported in next version */
++}
++
++/*
++ * If the filesystem supports NFS-export, then it has to support NULL as
++ * a nameidata parameter for ->create(), ->lookup() and ->d_revalidate().
++ * We can apply this principle when we handle a lower filesystem.
++ */
++static inline int au_test_fs_null_nd(struct super_block *sb)
++{
++ return !!sb->s_export_op;
++}
++
++static inline int au_test_fs_remote(struct super_block *sb)
++{
++ return !au_test_tmpfs(sb)
++#ifdef CONFIG_AUFS_BR_RAMFS
++ && !au_test_ramfs(sb)
++#endif
++ && !(sb->s_type->fs_flags & FS_REQUIRES_DEV);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * Note: these functions (below) are created after reading ->getattr() in all
++ * filesystems under linux/fs. it means we have to do so in every update...
++ */
++
++/*
++ * some filesystems require getattr to refresh the inode attributes before
++ * referencing.
++ * in most cases, we can rely on the inode attribute in NFS (or every remote fs)
++ * and leave the work for d_revalidate()
++ */
++static inline int au_test_fs_refresh_iattr(struct super_block *sb)
++{
++ return au_test_nfs(sb)
++ || au_test_fuse(sb)
++ /* || au_test_smbfs(sb) */ /* untested */
++ /* || au_test_ocfs2(sb) */ /* untested */
++ /* || au_test_btrfs(sb) */ /* untested */
++ /* || au_test_coda(sb) */ /* untested */
++ /* || au_test_v9fs(sb) */ /* untested */
++ ;
++}
++
++/*
++ * filesystems which don't maintain i_size or i_blocks.
++ */
++static inline int au_test_fs_bad_iattr_size(struct super_block *sb)
++{
++ return au_test_xfs(sb)
++ || au_test_btrfs(sb)
++ || au_test_ubifs(sb)
++ || au_test_hfsplus(sb) /* maintained, but incorrect */
++ /* || au_test_ext4(sb) */ /* untested */
++ /* || au_test_ocfs2(sb) */ /* untested */
++ /* || au_test_ocfs2_dlmfs(sb) */ /* untested */
++ /* || au_test_sysv(sb) */ /* untested */
++ /* || au_test_minix(sb) */ /* untested */
++ ;
++}
++
++/*
++ * filesystems which don't store the correct value in some of their inode
++ * attributes.
++ */
++static inline int au_test_fs_bad_iattr(struct super_block *sb)
++{
++ return au_test_fs_bad_iattr_size(sb)
++ /* || au_test_cifs(sb) */ /* untested */
++ || au_test_fat(sb)
++ || au_test_msdos(sb)
++ || au_test_vfat(sb);
++}
++
++/* they don't check i_nlink in link(2) */
++static inline int au_test_fs_no_limit_nlink(struct super_block *sb)
++{
++ return au_test_tmpfs(sb)
++#ifdef CONFIG_AUFS_BR_RAMFS
++ || au_test_ramfs(sb)
++#endif
++ || au_test_ubifs(sb)
++ || au_test_btrfs(sb)
++ || au_test_hfsplus(sb);
++}
++
++/*
++ * filesystems which sets S_NOATIME and S_NOCMTIME.
++ */
++static inline int au_test_fs_notime(struct super_block *sb)
++{
++ return au_test_nfs(sb)
++ || au_test_fuse(sb)
++ || au_test_ubifs(sb)
++ /* || au_test_cifs(sb) */ /* untested */
++ ;
++}
++
++/*
++ * filesystems which requires replacing i_mapping.
++ */
++static inline int au_test_fs_bad_mapping(struct super_block *sb)
++{
++ return au_test_fuse(sb)
++ || au_test_ubifs(sb);
++}
++
++/* temporary support for i#1 in cramfs */
++static inline int au_test_fs_unique_ino(struct inode *inode)
++{
++ if (au_test_cramfs(inode->i_sb))
++ return inode->i_ino != 1;
++ return 1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * the filesystem where the xino files placed must support i/o after unlink and
++ * maintain i_size and i_blocks.
++ */
++static inline int au_test_fs_bad_xino(struct super_block *sb)
++{
++ return au_test_fs_remote(sb)
++ || au_test_fs_bad_iattr_size(sb)
++#ifdef CONFIG_AUFS_BR_RAMFS
++ || !(au_test_ramfs(sb) || au_test_fs_null_nd(sb))
++#else
++ || !au_test_fs_null_nd(sb) /* to keep xino code simple */
++#endif
++ /* don't want unnecessary work for xino */
++ || au_test_aufs(sb)
++ || au_test_ecryptfs(sb)
++ || au_test_nilfs(sb);
++}
++
++static inline int au_test_fs_trunc_xino(struct super_block *sb)
++{
++ return au_test_tmpfs(sb)
++ || au_test_ramfs(sb);
++}
++
++/*
++ * test if the @sb is real-readonly.
++ */
++static inline int au_test_fs_rr(struct super_block *sb)
++{
++ return au_test_squashfs(sb)
++ || au_test_iso9660(sb)
++ || au_test_cramfs(sb)
++ || au_test_romfs(sb);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_FSTYPE_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/hfsnotify.c linux-2.6.36/fs/aufs/hfsnotify.c
+--- linux-2.6.36.orig/fs/aufs/hfsnotify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/hfsnotify.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,247 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * fsnotify for the lower directories
++ */
++
++#include "aufs.h"
++
++/* FS_IN_IGNORED is unnecessary */
++static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE
++ | FS_CREATE | FS_EVENT_ON_CHILD);
++static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq);
++
++static void au_hfsn_free_mark(struct fsnotify_mark *mark)
++{
++ struct au_hnotify *hn = container_of(mark, struct au_hnotify,
++ hn_mark);
++ AuDbg("here\n");
++ hn->hn_mark_dead = 1;
++ smp_mb();
++ wake_up_all(&au_hfsn_wq);
++}
++
++static int au_hfsn_alloc(struct au_hinode *hinode)
++{
++ struct au_hnotify *hn;
++ struct super_block *sb;
++ struct au_branch *br;
++ struct fsnotify_mark *mark;
++ aufs_bindex_t bindex;
++
++ hn = hinode->hi_notify;
++ sb = hn->hn_aufs_inode->i_sb;
++ bindex = au_br_index(sb, hinode->hi_id);
++ br = au_sbr(sb, bindex);
++ hn->hn_mark_dead = 0;
++ mark = &hn->hn_mark;
++ fsnotify_init_mark(mark, au_hfsn_free_mark);
++ mark->mask = AuHfsnMask;
++ /*
++ * by udba rename or rmdir, aufs assign a new inode to the known
++ * h_inode, so specify 1 to allow dups.
++ */
++ return fsnotify_add_mark(mark, br->br_hfsn_group, hinode->hi_inode,
++ /*mnt*/NULL, /*allow_dups*/1);
++}
++
++static void au_hfsn_free(struct au_hinode *hinode)
++{
++ struct au_hnotify *hn;
++ struct fsnotify_mark *mark;
++
++ hn = hinode->hi_notify;
++ mark = &hn->hn_mark;
++ fsnotify_destroy_mark(mark);
++ fsnotify_put_mark(mark);
++
++ /* TODO: bad approach */
++ wait_event(au_hfsn_wq, hn->hn_mark_dead);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void au_hfsn_ctl(struct au_hinode *hinode, int do_set)
++{
++ struct fsnotify_mark *mark;
++
++ mark = &hinode->hi_notify->hn_mark;
++ spin_lock(&mark->lock);
++ if (do_set) {
++ AuDebugOn(mark->mask & AuHfsnMask);
++ mark->mask |= AuHfsnMask;
++ } else {
++ AuDebugOn(!(mark->mask & AuHfsnMask));
++ mark->mask &= ~AuHfsnMask;
++ }
++ spin_unlock(&mark->lock);
++ /* fsnotify_recalc_inode_mask(hinode->hi_inode); */
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* #define AuDbgHnotify */
++#ifdef AuDbgHnotify
++static char *au_hfsn_name(u32 mask)
++{
++#ifdef CONFIG_AUFS_DEBUG
++#define test_ret(flag) if (mask & flag) \
++ return #flag;
++ test_ret(FS_ACCESS);
++ test_ret(FS_MODIFY);
++ test_ret(FS_ATTRIB);
++ test_ret(FS_CLOSE_WRITE);
++ test_ret(FS_CLOSE_NOWRITE);
++ test_ret(FS_OPEN);
++ test_ret(FS_MOVED_FROM);
++ test_ret(FS_MOVED_TO);
++ test_ret(FS_CREATE);
++ test_ret(FS_DELETE);
++ test_ret(FS_DELETE_SELF);
++ test_ret(FS_MOVE_SELF);
++ test_ret(FS_UNMOUNT);
++ test_ret(FS_Q_OVERFLOW);
++ test_ret(FS_IN_IGNORED);
++ test_ret(FS_IN_ISDIR);
++ test_ret(FS_IN_ONESHOT);
++ test_ret(FS_EVENT_ON_CHILD);
++ return "";
++#undef test_ret
++#else
++ return "??";
++#endif
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static int au_hfsn_handle_event(struct fsnotify_group *group,
++ struct fsnotify_mark *inode_mark,
++ struct fsnotify_mark *vfsmount_mark,
++ struct fsnotify_event *event)
++{
++ int err;
++ struct au_hnotify *hnotify;
++ struct inode *h_dir, *h_inode;
++ __u32 mask;
++ struct qstr h_child_qstr = {
++ .name = event->file_name,
++ .len = event->name_len
++ };
++
++ AuDebugOn(event->data_type != FSNOTIFY_EVENT_INODE);
++
++ err = 0;
++ /* if FS_UNMOUNT happens, there must be another bug */
++ mask = event->mask;
++ AuDebugOn(mask & FS_UNMOUNT);
++ if (mask & (FS_IN_IGNORED | FS_UNMOUNT))
++ goto out;
++
++ h_dir = event->to_tell;
++ h_inode = event->inode;
++#ifdef AuDbgHnotify
++ au_debug(1);
++ if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1
++ || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) {
++ AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n",
++ h_dir->i_ino, mask, au_hfsn_name(mask),
++ AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0);
++ /* WARN_ON(1); */
++ }
++ au_debug(0);
++#endif
++
++ AuDebugOn(!inode_mark);
++ hnotify = container_of(inode_mark, struct au_hnotify, hn_mark);
++ err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode);
++
++out:
++ return err;
++}
++
++/* isn't it waste to ask every registered 'group'? */
++/* copied from linux/fs/notify/inotify/inotify_fsnotiry.c */
++/* it should be exported to modules */
++static bool au_hfsn_should_send_event(struct fsnotify_group *group,
++ struct inode *h_inode,
++ struct fsnotify_mark *inode_mark,
++ struct fsnotify_mark *vfsmount_mark,
++ __u32 mask, void *data, int data_type)
++{
++ mask = (mask & ~FS_EVENT_ON_CHILD);
++ return inode_mark->mask & mask;
++}
++
++static struct fsnotify_ops au_hfsn_ops = {
++ .should_send_event = au_hfsn_should_send_event,
++ .handle_event = au_hfsn_handle_event
++};
++
++/* ---------------------------------------------------------------------- */
++
++static void au_hfsn_fin_br(struct au_branch *br)
++{
++ if (br->br_hfsn_group)
++ fsnotify_put_group(br->br_hfsn_group);
++}
++
++static int au_hfsn_init_br(struct au_branch *br, int perm)
++{
++ br->br_hfsn_group = NULL;
++ br->br_hfsn_ops = au_hfsn_ops;
++ return 0;
++}
++
++static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm)
++{
++ int err;
++
++ err = 0;
++ if (udba != AuOpt_UDBA_HNOTIFY
++ || !au_br_hnotifyable(perm)) {
++ au_hfsn_fin_br(br);
++ br->br_hfsn_group = NULL;
++ goto out;
++ }
++
++ if (br->br_hfsn_group)
++ goto out;
++
++ br->br_hfsn_group = fsnotify_alloc_group(&br->br_hfsn_ops);
++ if (IS_ERR(br->br_hfsn_group)) {
++ err = PTR_ERR(br->br_hfsn_group);
++ pr_err("fsnotify_alloc_group() failed, %d\n", err);
++ br->br_hfsn_group = NULL;
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++const struct au_hnotify_op au_hnotify_op = {
++ .ctl = au_hfsn_ctl,
++ .alloc = au_hfsn_alloc,
++ .free = au_hfsn_free,
++
++ .reset_br = au_hfsn_reset_br,
++ .fin_br = au_hfsn_fin_br,
++ .init_br = au_hfsn_init_br
++};
+diff -Nur linux-2.6.36.orig/fs/aufs/hfsplus.c linux-2.6.36/fs/aufs/hfsplus.c
+--- linux-2.6.36.orig/fs/aufs/hfsplus.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/hfsplus.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,58 @@
++/*
++ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * special support for filesystems which aqucires an inode mutex
++ * at final closing a file, eg, hfsplus.
++ *
++ * This trick is very simple and stupid, just to open the file before really
++ * neceeary open to tell hfsplus that this is not the final closing.
++ * The caller should call au_h_open_pre() after acquiring the inode mutex,
++ * and au_h_open_post() after releasing it.
++ */
++
++#include <linux/file.h>
++#include "aufs.h"
++
++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ struct file *h_file;
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ AuDebugOn(!h_dentry);
++ AuDebugOn(!h_dentry->d_inode);
++ IMustLock(h_dentry->d_inode);
++
++ h_file = NULL;
++ if (au_test_hfsplus(h_dentry->d_sb)
++ && S_ISREG(h_dentry->d_inode->i_mode))
++ h_file = au_h_open(dentry, bindex,
++ O_RDONLY | O_NOATIME | O_LARGEFILE,
++ /*file*/NULL);
++ return h_file;
++}
++
++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex,
++ struct file *h_file)
++{
++ if (h_file) {
++ fput(h_file);
++ au_sbr_put(dentry->d_sb, bindex);
++ }
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/hnotify.c linux-2.6.36/fs/aufs/hnotify.c
+--- linux-2.6.36.orig/fs/aufs/hnotify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/hnotify.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,694 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * abstraction to notify the direct changes on lower directories
++ */
++
++#include "aufs.h"
++
++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode)
++{
++ int err;
++ struct au_hnotify *hn;
++
++ err = -ENOMEM;
++ hn = au_cache_alloc_hnotify();
++ if (hn) {
++ hn->hn_aufs_inode = inode;
++ hinode->hi_notify = hn;
++ err = au_hnotify_op.alloc(hinode);
++ AuTraceErr(err);
++ if (unlikely(err)) {
++ hinode->hi_notify = NULL;
++ au_cache_free_hnotify(hn);
++ /*
++ * The upper dir was removed by udba, but the same named
++ * dir left. In this case, aufs assignes a new inode
++ * number and set the monitor again.
++ * For the lower dir, the old monitnor is still left.
++ */
++ if (err == -EEXIST)
++ err = 0;
++ }
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++void au_hn_free(struct au_hinode *hinode)
++{
++ struct au_hnotify *hn;
++
++ hn = hinode->hi_notify;
++ if (hn) {
++ au_hnotify_op.free(hinode);
++ au_cache_free_hnotify(hn);
++ hinode->hi_notify = NULL;
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_hn_ctl(struct au_hinode *hinode, int do_set)
++{
++ if (hinode->hi_notify)
++ au_hnotify_op.ctl(hinode, do_set);
++}
++
++void au_hn_reset(struct inode *inode, unsigned int flags)
++{
++ aufs_bindex_t bindex, bend;
++ struct inode *hi;
++ struct dentry *iwhdentry;
++
++ bend = au_ibend(inode);
++ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
++ hi = au_h_iptr(inode, bindex);
++ if (!hi)
++ continue;
++
++ /* mutex_lock_nested(&hi->i_mutex, AuLsc_I_CHILD); */
++ iwhdentry = au_hi_wh(inode, bindex);
++ if (iwhdentry)
++ dget(iwhdentry);
++ au_igrab(hi);
++ au_set_h_iptr(inode, bindex, NULL, 0);
++ au_set_h_iptr(inode, bindex, au_igrab(hi),
++ flags & ~AuHi_XINO);
++ iput(hi);
++ dput(iwhdentry);
++ /* mutex_unlock(&hi->i_mutex); */
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int hn_xino(struct inode *inode, struct inode *h_inode)
++{
++ int err;
++ aufs_bindex_t bindex, bend, bfound, bstart;
++ struct inode *h_i;
++
++ err = 0;
++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
++ pr_warning("branch root dir was changed\n");
++ goto out;
++ }
++
++ bfound = -1;
++ bend = au_ibend(inode);
++ bstart = au_ibstart(inode);
++#if 0 /* reserved for future use */
++ if (bindex == bend) {
++ /* keep this ino in rename case */
++ goto out;
++ }
++#endif
++ for (bindex = bstart; bindex <= bend; bindex++)
++ if (au_h_iptr(inode, bindex) == h_inode) {
++ bfound = bindex;
++ break;
++ }
++ if (bfound < 0)
++ goto out;
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ h_i = au_h_iptr(inode, bindex);
++ if (!h_i)
++ continue;
++
++ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0);
++ /* ignore this error */
++ /* bad action? */
++ }
++
++ /* children inode number will be broken */
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int hn_gen_tree(struct dentry *dentry)
++{
++ int err, i, j, ndentry;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_dcsub_pages(&dpages, dentry, NULL, NULL);
++ if (unlikely(err))
++ goto out_dpages;
++
++ for (i = 0; i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ ndentry = dpage->ndentry;
++ for (j = 0; j < ndentry; j++) {
++ struct dentry *d;
++
++ d = dentries[j];
++ if (IS_ROOT(d))
++ continue;
++
++ au_digen_dec(d);
++ if (d->d_inode)
++ /* todo: reset children xino?
++ cached children only? */
++ au_iigen_dec(d->d_inode);
++ }
++ }
++
++out_dpages:
++ au_dpages_free(&dpages);
++
++ /* discard children */
++ dentry_unhash(dentry);
++ dput(dentry);
++out:
++ return err;
++}
++
++/*
++ * return 0 if processed.
++ */
++static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode,
++ const unsigned int isdir)
++{
++ int err;
++ struct dentry *d;
++ struct qstr *dname;
++
++ err = 1;
++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
++ pr_warning("branch root dir was changed\n");
++ err = 0;
++ goto out;
++ }
++
++ if (!isdir) {
++ AuDebugOn(!name);
++ au_iigen_dec(inode);
++ spin_lock(&dcache_lock);
++ list_for_each_entry(d, &inode->i_dentry, d_alias) {
++ dname = &d->d_name;
++ if (dname->len != nlen
++ && memcmp(dname->name, name, nlen))
++ continue;
++ err = 0;
++ au_digen_dec(d);
++ break;
++ }
++ spin_unlock(&dcache_lock);
++ } else {
++ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR);
++ d = d_find_alias(inode);
++ if (!d) {
++ au_iigen_dec(inode);
++ goto out;
++ }
++
++ dname = &d->d_name;
++ if (dname->len == nlen && !memcmp(dname->name, name, nlen))
++ err = hn_gen_tree(d);
++ dput(d);
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir)
++{
++ int err;
++ struct inode *inode;
++
++ inode = dentry->d_inode;
++ if (IS_ROOT(dentry)
++ /* || (inode && inode->i_ino == AUFS_ROOT_INO) */
++ ) {
++ pr_warning("branch root dir was changed\n");
++ return 0;
++ }
++
++ err = 0;
++ if (!isdir) {
++ au_digen_dec(dentry);
++ if (inode)
++ au_iigen_dec(inode);
++ } else {
++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR);
++ if (inode)
++ err = hn_gen_tree(dentry);
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* hnotify job flags */
++#define AuHnJob_XINO0 1
++#define AuHnJob_GEN (1 << 1)
++#define AuHnJob_DIRENT (1 << 2)
++#define AuHnJob_ISDIR (1 << 3)
++#define AuHnJob_TRYXINO0 (1 << 4)
++#define AuHnJob_MNTPNT (1 << 5)
++#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name)
++#define au_fset_hnjob(flags, name) \
++ do { (flags) |= AuHnJob_##name; } while (0)
++#define au_fclr_hnjob(flags, name) \
++ do { (flags) &= ~AuHnJob_##name; } while (0)
++
++enum {
++ AuHn_CHILD,
++ AuHn_PARENT,
++ AuHnLast
++};
++
++struct au_hnotify_args {
++ struct inode *h_dir, *dir, *h_child_inode;
++ u32 mask;
++ unsigned int flags[AuHnLast];
++ unsigned int h_child_nlen;
++ char h_child_name[];
++};
++
++struct hn_job_args {
++ unsigned int flags;
++ struct inode *inode, *h_inode, *dir, *h_dir;
++ struct dentry *dentry;
++ char *h_name;
++ int h_nlen;
++};
++
++static int hn_job(struct hn_job_args *a)
++{
++ const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR);
++
++ /* reset xino */
++ if (au_ftest_hnjob(a->flags, XINO0) && a->inode)
++ hn_xino(a->inode, a->h_inode); /* ignore this error */
++
++ if (au_ftest_hnjob(a->flags, TRYXINO0)
++ && a->inode
++ && a->h_inode) {
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ if (!a->h_inode->i_nlink)
++ hn_xino(a->inode, a->h_inode); /* ignore this error */
++ mutex_unlock(&a->h_inode->i_mutex);
++ }
++
++ /* make the generation obsolete */
++ if (au_ftest_hnjob(a->flags, GEN)) {
++ int err = -1;
++ if (a->inode)
++ err = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode,
++ isdir);
++ if (err && a->dentry)
++ hn_gen_by_name(a->dentry, isdir);
++ /* ignore this error */
++ }
++
++ /* make dir entries obsolete */
++ if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) {
++ struct au_vdir *vdir;
++
++ vdir = au_ivdir(a->inode);
++ if (vdir)
++ vdir->vd_jiffy = 0;
++ /* IMustLock(a->inode); */
++ /* a->inode->i_version++; */
++ }
++
++ /* can do nothing but warn */
++ if (au_ftest_hnjob(a->flags, MNTPNT)
++ && a->dentry
++ && d_mountpoint(a->dentry))
++ pr_warning("mount-point %.*s is removed or renamed\n",
++ AuDLNPair(a->dentry));
++
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen,
++ struct inode *dir)
++{
++ struct dentry *dentry, *d, *parent;
++ struct qstr *dname;
++
++ parent = d_find_alias(dir);
++ if (!parent)
++ return NULL;
++
++ dentry = NULL;
++ spin_lock(&dcache_lock);
++ list_for_each_entry(d, &parent->d_subdirs, d_u.d_child) {
++ /* AuDbg("%.*s\n", AuDLNPair(d)); */
++ dname = &d->d_name;
++ if (dname->len != nlen || memcmp(dname->name, name, nlen))
++ continue;
++ if (au_di(d))
++ au_digen_dec(d);
++ else
++ continue;
++ if (!atomic_read(&d->d_count))
++ continue;
++
++ dentry = dget(d);
++ break;
++ }
++ spin_unlock(&dcache_lock);
++ dput(parent);
++
++ if (dentry)
++ di_write_lock_child(dentry);
++
++ return dentry;
++}
++
++static struct inode *lookup_wlock_by_ino(struct super_block *sb,
++ aufs_bindex_t bindex, ino_t h_ino)
++{
++ struct inode *inode;
++ ino_t ino;
++ int err;
++
++ inode = NULL;
++ err = au_xino_read(sb, bindex, h_ino, &ino);
++ if (!err && ino)
++ inode = ilookup(sb, ino);
++ if (!inode)
++ goto out;
++
++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
++ pr_warning("wrong root branch\n");
++ iput(inode);
++ inode = NULL;
++ goto out;
++ }
++
++ ii_write_lock_child(inode);
++
++out:
++ return inode;
++}
++
++static void au_hn_bh(void *_args)
++{
++ struct au_hnotify_args *a = _args;
++ struct super_block *sb;
++ aufs_bindex_t bindex, bend, bfound;
++ unsigned char xino, try_iput;
++ int err;
++ struct inode *inode;
++ ino_t h_ino;
++ struct hn_job_args args;
++ struct dentry *dentry;
++ struct au_sbinfo *sbinfo;
++
++ AuDebugOn(!_args);
++ AuDebugOn(!a->h_dir);
++ AuDebugOn(!a->dir);
++ AuDebugOn(!a->mask);
++ AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n",
++ a->mask, a->dir->i_ino, a->h_dir->i_ino,
++ a->h_child_inode ? a->h_child_inode->i_ino : 0);
++
++ inode = NULL;
++ dentry = NULL;
++ /*
++ * do not lock a->dir->i_mutex here
++ * because of d_revalidate() may cause a deadlock.
++ */
++ sb = a->dir->i_sb;
++ AuDebugOn(!sb);
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!sbinfo);
++ si_write_lock(sb, AuLock_NOPLMW);
++
++ ii_read_lock_parent(a->dir);
++ bfound = -1;
++ bend = au_ibend(a->dir);
++ for (bindex = au_ibstart(a->dir); bindex <= bend; bindex++)
++ if (au_h_iptr(a->dir, bindex) == a->h_dir) {
++ bfound = bindex;
++ break;
++ }
++ ii_read_unlock(a->dir);
++ if (unlikely(bfound < 0))
++ goto out;
++
++ xino = !!au_opt_test(au_mntflags(sb), XINO);
++ h_ino = 0;
++ if (a->h_child_inode)
++ h_ino = a->h_child_inode->i_ino;
++
++ if (a->h_child_nlen
++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN)
++ || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT)))
++ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen,
++ a->dir);
++ try_iput = 0;
++ if (dentry)
++ inode = dentry->d_inode;
++ if (xino && !inode && h_ino
++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0)
++ || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0)
++ || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) {
++ inode = lookup_wlock_by_ino(sb, bfound, h_ino);
++ try_iput = 1;
++ }
++
++ args.flags = a->flags[AuHn_CHILD];
++ args.dentry = dentry;
++ args.inode = inode;
++ args.h_inode = a->h_child_inode;
++ args.dir = a->dir;
++ args.h_dir = a->h_dir;
++ args.h_name = a->h_child_name;
++ args.h_nlen = a->h_child_nlen;
++ err = hn_job(&args);
++ if (dentry) {
++ if (au_di(dentry))
++ di_write_unlock(dentry);
++ dput(dentry);
++ }
++ if (inode && try_iput) {
++ ii_write_unlock(inode);
++ iput(inode);
++ }
++
++ ii_write_lock_parent(a->dir);
++ args.flags = a->flags[AuHn_PARENT];
++ args.dentry = NULL;
++ args.inode = a->dir;
++ args.h_inode = a->h_dir;
++ args.dir = NULL;
++ args.h_dir = NULL;
++ args.h_name = NULL;
++ args.h_nlen = 0;
++ err = hn_job(&args);
++ ii_write_unlock(a->dir);
++
++out:
++ iput(a->h_child_inode);
++ iput(a->h_dir);
++ iput(a->dir);
++ si_write_unlock(sb);
++ au_nwt_done(&sbinfo->si_nowait);
++ kfree(a);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask,
++ struct qstr *h_child_qstr, struct inode *h_child_inode)
++{
++ int err, len;
++ unsigned int flags[AuHnLast];
++ unsigned char isdir, isroot, wh;
++ struct inode *dir;
++ struct au_hnotify_args *args;
++ char *p, *h_child_name;
++
++ err = 0;
++ AuDebugOn(!hnotify || !hnotify->hn_aufs_inode);
++ dir = igrab(hnotify->hn_aufs_inode);
++ if (!dir)
++ goto out;
++
++ isroot = (dir->i_ino == AUFS_ROOT_INO);
++ wh = 0;
++ h_child_name = (void *)h_child_qstr->name;
++ len = h_child_qstr->len;
++ if (h_child_name) {
++ if (len > AUFS_WH_PFX_LEN
++ && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
++ h_child_name += AUFS_WH_PFX_LEN;
++ len -= AUFS_WH_PFX_LEN;
++ wh = 1;
++ }
++ }
++
++ isdir = 0;
++ if (h_child_inode)
++ isdir = !!S_ISDIR(h_child_inode->i_mode);
++ flags[AuHn_PARENT] = AuHnJob_ISDIR;
++ flags[AuHn_CHILD] = 0;
++ if (isdir)
++ flags[AuHn_CHILD] = AuHnJob_ISDIR;
++ au_fset_hnjob(flags[AuHn_PARENT], DIRENT);
++ au_fset_hnjob(flags[AuHn_CHILD], GEN);
++ switch (mask & FS_EVENTS_POSS_ON_CHILD) {
++ case FS_MOVED_FROM:
++ case FS_MOVED_TO:
++ au_fset_hnjob(flags[AuHn_CHILD], XINO0);
++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT);
++ /*FALLTHROUGH*/
++ case FS_CREATE:
++ AuDebugOn(!h_child_name || !h_child_inode);
++ break;
++
++ case FS_DELETE:
++ /*
++ * aufs never be able to get this child inode.
++ * revalidation should be in d_revalidate()
++ * by checking i_nlink, i_generation or d_unhashed().
++ */
++ AuDebugOn(!h_child_name);
++ au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0);
++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT);
++ break;
++
++ default:
++ AuDebugOn(1);
++ }
++
++ if (wh)
++ h_child_inode = NULL;
++
++ err = -ENOMEM;
++ /* iput() and kfree() will be called in au_hnotify() */
++ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS);
++ if (unlikely(!args)) {
++ AuErr1("no memory\n");
++ iput(dir);
++ goto out;
++ }
++ args->flags[AuHn_PARENT] = flags[AuHn_PARENT];
++ args->flags[AuHn_CHILD] = flags[AuHn_CHILD];
++ args->mask = mask;
++ args->dir = dir;
++ args->h_dir = igrab(h_dir);
++ if (h_child_inode)
++ h_child_inode = igrab(h_child_inode); /* can be NULL */
++ args->h_child_inode = h_child_inode;
++ args->h_child_nlen = len;
++ if (len) {
++ p = (void *)args;
++ p += sizeof(*args);
++ memcpy(p, h_child_name, len);
++ p[len] = 0;
++ }
++
++ err = au_wkq_nowait(au_hn_bh, args, dir->i_sb);
++ if (unlikely(err)) {
++ pr_err("wkq %d\n", err);
++ iput(args->h_child_inode);
++ iput(args->h_dir);
++ iput(args->dir);
++ kfree(args);
++ }
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm)
++{
++ int err;
++
++ AuDebugOn(!(udba & AuOptMask_UDBA));
++
++ err = 0;
++ if (au_hnotify_op.reset_br)
++ err = au_hnotify_op.reset_br(udba, br, perm);
++
++ return err;
++}
++
++int au_hnotify_init_br(struct au_branch *br, int perm)
++{
++ int err;
++
++ err = 0;
++ if (au_hnotify_op.init_br)
++ err = au_hnotify_op.init_br(br, perm);
++
++ return err;
++}
++
++void au_hnotify_fin_br(struct au_branch *br)
++{
++ if (au_hnotify_op.fin_br)
++ au_hnotify_op.fin_br(br);
++}
++
++static void au_hn_destroy_cache(void)
++{
++ kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]);
++ au_cachep[AuCache_HNOTIFY] = NULL;
++}
++
++int __init au_hnotify_init(void)
++{
++ int err;
++
++ err = -ENOMEM;
++ au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify);
++ if (au_cachep[AuCache_HNOTIFY]) {
++ err = 0;
++ if (au_hnotify_op.init)
++ err = au_hnotify_op.init();
++ if (unlikely(err))
++ au_hn_destroy_cache();
++ }
++ AuTraceErr(err);
++ return err;
++}
++
++void au_hnotify_fin(void)
++{
++ if (au_hnotify_op.fin)
++ au_hnotify_op.fin();
++ /* cf. au_cache_fin() */
++ if (au_cachep[AuCache_HNOTIFY])
++ au_hn_destroy_cache();
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/i_op.c linux-2.6.36/fs/aufs/i_op.c
+--- linux-2.6.36.orig/fs/aufs/i_op.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/i_op.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,971 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode operations (except add/del/rename)
++ */
++
++#include <linux/device_cgroup.h>
++#include <linux/fs_stack.h>
++#include <linux/mm.h>
++#include <linux/namei.h>
++#include <linux/security.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++static int h_permission(struct inode *h_inode, int mask,
++ struct vfsmount *h_mnt, int brperm)
++{
++ int err;
++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
++
++ err = -EACCES;
++ if ((write_mask && IS_IMMUTABLE(h_inode))
++ || ((mask & MAY_EXEC)
++ && S_ISREG(h_inode->i_mode)
++ && ((h_mnt->mnt_flags & MNT_NOEXEC)
++ || !(h_inode->i_mode & S_IXUGO))))
++ goto out;
++
++ /*
++ * - skip the lower fs test in the case of write to ro branch.
++ * - nfs dir permission write check is optimized, but a policy for
++ * link/rename requires a real check.
++ */
++ if ((write_mask && !au_br_writable(brperm))
++ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode)
++ && write_mask && !(mask & MAY_READ))
++ || !h_inode->i_op->permission) {
++ /* AuLabel(generic_permission); */
++ err = generic_permission(h_inode, mask,
++ h_inode->i_op->check_acl);
++ } else {
++ /* AuLabel(h_inode->permission); */
++ err = h_inode->i_op->permission(h_inode, mask);
++ AuTraceErr(err);
++ }
++
++ if (!err)
++ err = devcgroup_inode_permission(h_inode, mask);
++ if (!err)
++ err = security_inode_permission(h_inode, mask);
++
++#if 0
++ if (!err) {
++ /* todo: do we need to call ima_path_check()? */
++ struct path h_path = {
++ .dentry =
++ .mnt = h_mnt
++ };
++ err = ima_path_check(&h_path,
++ mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
++ IMA_COUNT_LEAVE);
++ }
++#endif
++
++out:
++ return err;
++}
++
++static int aufs_permission(struct inode *inode, int mask)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ const unsigned char isdir = !!S_ISDIR(inode->i_mode),
++ write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
++ struct inode *h_inode;
++ struct super_block *sb;
++ struct au_branch *br;
++
++ sb = inode->i_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ ii_read_lock_child(inode);
++#if 0
++ err = au_iigen_test(inode, au_sigen(sb));
++ if (unlikely(err))
++ goto out;
++#endif
++
++ if (!isdir || write_mask) {
++ err = au_busy_or_stale();
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ if (unlikely(!h_inode
++ || (h_inode->i_mode & S_IFMT)
++ != (inode->i_mode & S_IFMT)))
++ goto out;
++
++ err = 0;
++ bindex = au_ibstart(inode);
++ br = au_sbr(sb, bindex);
++ err = h_permission(h_inode, mask, br->br_mnt, br->br_perm);
++ if (write_mask
++ && !err
++ && !special_file(h_inode->i_mode)) {
++ /* test whether the upper writable branch exists */
++ err = -EROFS;
++ for (; bindex >= 0; bindex--)
++ if (!au_br_rdonly(au_sbr(sb, bindex))) {
++ err = 0;
++ break;
++ }
++ }
++ goto out;
++ }
++
++ /* non-write to dir */
++ err = 0;
++ bend = au_ibend(inode);
++ for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) {
++ h_inode = au_h_iptr(inode, bindex);
++ if (h_inode) {
++ err = au_busy_or_stale();
++ if (unlikely(!S_ISDIR(h_inode->i_mode)))
++ break;
++
++ br = au_sbr(sb, bindex);
++ err = h_permission(h_inode, mask, br->br_mnt,
++ br->br_perm);
++ }
++ }
++
++out:
++ ii_read_unlock(inode);
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry,
++ struct nameidata *nd)
++{
++ struct dentry *ret, *parent;
++ struct inode *inode;
++ struct super_block *sb;
++ int err, npositive;
++
++ IMustLock(dir);
++
++ sb = dir->i_sb;
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ ret = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ ret = ERR_PTR(-ENAMETOOLONG);
++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
++ goto out_si;
++ err = au_di_init(dentry);
++ ret = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_si;
++
++ npositive = 0; /* suppress a warning */
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_read_lock_parent(parent, AuLock_IR);
++ err = au_alive_dir(parent);
++ if (!err)
++ err = au_digen_test(parent, au_sigen(sb));
++ if (!err) {
++ npositive = au_lkup_dentry(dentry, au_dbstart(parent),
++ /*type*/0, nd);
++ err = npositive;
++ }
++ di_read_unlock(parent, AuLock_IR);
++ ret = ERR_PTR(err);
++ if (unlikely(err < 0))
++ goto out_unlock;
++
++ inode = NULL;
++ if (npositive) {
++ inode = au_new_inode(dentry, /*must_new*/0);
++ ret = (void *)inode;
++ }
++ if (IS_ERR(inode))
++ goto out_unlock;
++
++ ret = d_splice_alias(inode, dentry);
++ if (unlikely(IS_ERR(ret) && inode)) {
++ ii_write_unlock(inode);
++ iput(inode);
++ }
++
++out_unlock:
++ di_write_unlock(dentry);
++out_si:
++ si_read_unlock(sb);
++out:
++ return ret;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent,
++ const unsigned char add_entry, aufs_bindex_t bcpup,
++ aufs_bindex_t bstart)
++{
++ int err;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++
++ if (add_entry)
++ IMustLock(parent->d_inode);
++ else
++ di_write_lock_parent(parent);
++
++ err = 0;
++ if (!au_h_dptr(parent, bcpup)) {
++ if (bstart < bcpup)
++ err = au_cpdown_dirs(dentry, bcpup);
++ else
++ err = au_cpup_dirs(dentry, bcpup);
++ }
++ if (!err && add_entry) {
++ h_parent = au_h_dptr(parent, bcpup);
++ h_dir = h_parent->d_inode;
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
++ err = au_lkup_neg(dentry, bcpup);
++ /* todo: no unlock here */
++ mutex_unlock(&h_dir->i_mutex);
++
++ AuDbg("bcpup %d\n", bcpup);
++ if (!err) {
++ if (!dentry->d_inode)
++ au_set_h_dptr(dentry, bstart, NULL);
++ au_update_dbrange(dentry, /*do_put_zero*/0);
++ }
++ }
++
++ if (!add_entry)
++ di_write_unlock(parent);
++ if (!err)
++ err = bcpup; /* success */
++
++ AuTraceErr(err);
++ return err;
++}
++
++/*
++ * decide the branch and the parent dir where we will create a new entry.
++ * returns new bindex or an error.
++ * copyup the parent dir if needed.
++ */
++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry,
++ struct au_wr_dir_args *args)
++{
++ int err;
++ aufs_bindex_t bcpup, bstart, src_bstart;
++ const unsigned char add_entry = !!au_ftest_wrdir(args->flags,
++ ADD_ENTRY);
++ struct super_block *sb;
++ struct dentry *parent;
++ struct au_sbinfo *sbinfo;
++
++ sb = dentry->d_sb;
++ sbinfo = au_sbi(sb);
++ parent = dget_parent(dentry);
++ bstart = au_dbstart(dentry);
++ bcpup = bstart;
++ if (args->force_btgt < 0) {
++ if (src_dentry) {
++ src_bstart = au_dbstart(src_dentry);
++ if (src_bstart < bstart)
++ bcpup = src_bstart;
++ } else if (add_entry) {
++ err = AuWbrCreate(sbinfo, dentry,
++ au_ftest_wrdir(args->flags, ISDIR));
++ bcpup = err;
++ }
++
++ if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) {
++ if (add_entry)
++ err = AuWbrCopyup(sbinfo, dentry);
++ else {
++ if (!IS_ROOT(dentry)) {
++ di_read_lock_parent(parent, !AuLock_IR);
++ err = AuWbrCopyup(sbinfo, dentry);
++ di_read_unlock(parent, !AuLock_IR);
++ } else
++ err = AuWbrCopyup(sbinfo, dentry);
++ }
++ bcpup = err;
++ if (unlikely(err < 0))
++ goto out;
++ }
++ } else {
++ bcpup = args->force_btgt;
++ AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode));
++ }
++
++ AuDbg("bstart %d, bcpup %d\n", bstart, bcpup);
++ err = bcpup;
++ if (bcpup == bstart)
++ goto out; /* success */
++
++ /* copyup the new parent into the branch we process */
++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart);
++ if (err >= 0) {
++ if (!dentry->d_inode) {
++ au_set_h_dptr(dentry, bstart, NULL);
++ au_set_dbstart(dentry, bcpup);
++ au_set_dbend(dentry, bcpup);
++ }
++ AuDebugOn(add_entry && !au_h_dptr(dentry, bcpup));
++ }
++
++out:
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct dentry *au_pinned_h_parent(struct au_pin *pin)
++{
++ if (pin && pin->parent)
++ return au_h_dptr(pin->parent, pin->bindex);
++ return NULL;
++}
++
++void au_unpin(struct au_pin *p)
++{
++ if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE))
++ mnt_drop_write(p->h_mnt);
++ if (!p->hdir)
++ return;
++
++ au_hn_imtx_unlock(p->hdir);
++ if (!au_ftest_pin(p->flags, DI_LOCKED))
++ di_read_unlock(p->parent, AuLock_IR);
++ iput(p->hdir->hi_inode);
++ dput(p->parent);
++ p->parent = NULL;
++ p->hdir = NULL;
++ p->h_mnt = NULL;
++}
++
++int au_do_pin(struct au_pin *p)
++{
++ int err;
++ struct super_block *sb;
++ struct dentry *h_dentry, *h_parent;
++ struct au_branch *br;
++ struct inode *h_dir;
++
++ err = 0;
++ sb = p->dentry->d_sb;
++ br = au_sbr(sb, p->bindex);
++ if (IS_ROOT(p->dentry)) {
++ if (au_ftest_pin(p->flags, MNT_WRITE)) {
++ p->h_mnt = br->br_mnt;
++ err = mnt_want_write(p->h_mnt);
++ if (unlikely(err)) {
++ au_fclr_pin(p->flags, MNT_WRITE);
++ goto out_err;
++ }
++ }
++ goto out;
++ }
++
++ h_dentry = NULL;
++ if (p->bindex <= au_dbend(p->dentry))
++ h_dentry = au_h_dptr(p->dentry, p->bindex);
++
++ p->parent = dget_parent(p->dentry);
++ if (!au_ftest_pin(p->flags, DI_LOCKED))
++ di_read_lock(p->parent, AuLock_IR, p->lsc_di);
++
++ h_dir = NULL;
++ h_parent = au_h_dptr(p->parent, p->bindex);
++ p->hdir = au_hi(p->parent->d_inode, p->bindex);
++ if (p->hdir)
++ h_dir = p->hdir->hi_inode;
++
++ /*
++ * udba case, or
++ * if DI_LOCKED is not set, then p->parent may be different
++ * and h_parent can be NULL.
++ */
++ if (unlikely(!p->hdir || !h_dir || !h_parent)) {
++ err = -EBUSY;
++ if (!au_ftest_pin(p->flags, DI_LOCKED))
++ di_read_unlock(p->parent, AuLock_IR);
++ dput(p->parent);
++ p->parent = NULL;
++ goto out_err;
++ }
++
++ au_igrab(h_dir);
++ au_hn_imtx_lock_nested(p->hdir, p->lsc_hi);
++
++ if (unlikely(p->hdir->hi_inode != h_parent->d_inode)) {
++ err = -EBUSY;
++ goto out_unpin;
++ }
++ if (h_dentry) {
++ err = au_h_verify(h_dentry, p->udba, h_dir, h_parent, br);
++ if (unlikely(err)) {
++ au_fclr_pin(p->flags, MNT_WRITE);
++ goto out_unpin;
++ }
++ }
++
++ if (au_ftest_pin(p->flags, MNT_WRITE)) {
++ p->h_mnt = br->br_mnt;
++ err = mnt_want_write(p->h_mnt);
++ if (unlikely(err)) {
++ au_fclr_pin(p->flags, MNT_WRITE);
++ goto out_unpin;
++ }
++ }
++ goto out; /* success */
++
++out_unpin:
++ au_unpin(p);
++out_err:
++ pr_err("err %d\n", err);
++ err = au_busy_or_stale();
++out:
++ return err;
++}
++
++void au_pin_init(struct au_pin *p, struct dentry *dentry,
++ aufs_bindex_t bindex, int lsc_di, int lsc_hi,
++ unsigned int udba, unsigned char flags)
++{
++ p->dentry = dentry;
++ p->udba = udba;
++ p->lsc_di = lsc_di;
++ p->lsc_hi = lsc_hi;
++ p->flags = flags;
++ p->bindex = bindex;
++
++ p->parent = NULL;
++ p->hdir = NULL;
++ p->h_mnt = NULL;
++}
++
++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int udba, unsigned char flags)
++{
++ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2,
++ udba, flags);
++ return au_do_pin(pin);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * ->setattr() and ->getattr() are called in various cases.
++ * chmod, stat: dentry is revalidated.
++ * fchmod, fstat: file and dentry are not revalidated, additionally they may be
++ * unhashed.
++ * for ->setattr(), ia->ia_file is passed from ftruncate only.
++ */
++/* todo: consolidate with do_refresh() and simple_reval_dpath() */
++static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen)
++{
++ int err;
++ struct inode *inode;
++ struct dentry *parent;
++
++ err = 0;
++ inode = dentry->d_inode;
++ if (au_digen_test(dentry, sigen)) {
++ parent = dget_parent(dentry);
++ di_read_lock_parent(parent, AuLock_IR);
++ err = au_refresh_dentry(dentry, parent);
++ di_read_unlock(parent, AuLock_IR);
++ dput(parent);
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++#define AuIcpup_DID_CPUP 1
++#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name)
++#define au_fset_icpup(flags, name) \
++ do { (flags) |= AuIcpup_##name; } while (0)
++#define au_fclr_icpup(flags, name) \
++ do { (flags) &= ~AuIcpup_##name; } while (0)
++
++struct au_icpup_args {
++ unsigned char flags;
++ unsigned char pin_flags;
++ aufs_bindex_t btgt;
++ unsigned int udba;
++ struct au_pin pin;
++ struct path h_path;
++ struct inode *h_inode;
++};
++
++static int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia,
++ struct au_icpup_args *a)
++{
++ int err;
++ loff_t sz;
++ aufs_bindex_t bstart, ibstart;
++ struct dentry *hi_wh, *parent;
++ struct inode *inode;
++ struct file *h_file;
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = 0
++ };
++
++ bstart = au_dbstart(dentry);
++ inode = dentry->d_inode;
++ if (S_ISDIR(inode->i_mode))
++ au_fset_wrdir(wr_dir_args.flags, ISDIR);
++ /* plink or hi_wh() case */
++ ibstart = au_ibstart(inode);
++ if (bstart != ibstart && !au_test_ro(inode->i_sb, ibstart, inode))
++ wr_dir_args.force_btgt = ibstart;
++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
++ if (unlikely(err < 0))
++ goto out;
++ a->btgt = err;
++ if (err != bstart)
++ au_fset_icpup(a->flags, DID_CPUP);
++
++ err = 0;
++ a->pin_flags = AuPin_MNT_WRITE;
++ parent = NULL;
++ if (!IS_ROOT(dentry)) {
++ au_fset_pin(a->pin_flags, DI_LOCKED);
++ parent = dget_parent(dentry);
++ di_write_lock_parent(parent);
++ }
++
++ err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags);
++ if (unlikely(err))
++ goto out_parent;
++
++ a->h_path.dentry = au_h_dptr(dentry, bstart);
++ a->h_inode = a->h_path.dentry->d_inode;
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ sz = -1;
++ if ((ia->ia_valid & ATTR_SIZE) && ia->ia_size < i_size_read(a->h_inode))
++ sz = ia->ia_size;
++
++ h_file = NULL;
++ hi_wh = NULL;
++ if (au_ftest_icpup(a->flags, DID_CPUP) && au_d_removed(dentry)) {
++ hi_wh = au_hi_wh(inode, a->btgt);
++ if (!hi_wh) {
++ err = au_sio_cpup_wh(dentry, a->btgt, sz, /*file*/NULL);
++ if (unlikely(err))
++ goto out_unlock;
++ hi_wh = au_hi_wh(inode, a->btgt);
++ /* todo: revalidate hi_wh? */
++ }
++ }
++
++ if (parent) {
++ au_pin_set_parent_lflag(&a->pin, /*lflag*/0);
++ di_downgrade_lock(parent, AuLock_IR);
++ dput(parent);
++ parent = NULL;
++ }
++ if (!au_ftest_icpup(a->flags, DID_CPUP))
++ goto out; /* success */
++
++ if (!d_unhashed(dentry)) {
++ h_file = au_h_open_pre(dentry, bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_simple(dentry, a->btgt, sz,
++ AuCpup_DTIME);
++ if (!err)
++ a->h_path.dentry = au_h_dptr(dentry, a->btgt);
++ } else if (!hi_wh)
++ a->h_path.dentry = au_h_dptr(dentry, a->btgt);
++ else
++ a->h_path.dentry = hi_wh; /* do not dget here */
++
++out_unlock:
++ mutex_unlock(&a->h_inode->i_mutex);
++ au_h_open_post(dentry, bstart, h_file);
++ a->h_inode = a->h_path.dentry->d_inode;
++ if (!err) {
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ goto out; /* success */
++ }
++
++ au_unpin(&a->pin);
++out_parent:
++ if (parent) {
++ di_write_unlock(parent);
++ dput(parent);
++ }
++out:
++ return err;
++}
++
++static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
++{
++ int err;
++ struct inode *inode;
++ struct super_block *sb;
++ struct file *file;
++ struct au_icpup_args *a;
++
++ inode = dentry->d_inode;
++ IMustLock(inode);
++
++ err = -ENOMEM;
++ a = kzalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
++ ia->ia_valid &= ~ATTR_MODE;
++
++ file = NULL;
++ sb = dentry->d_sb;
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out_kfree;
++
++ if (ia->ia_valid & ATTR_FILE) {
++ /* currently ftruncate(2) only */
++ AuDebugOn(!S_ISREG(inode->i_mode));
++ file = ia->ia_file;
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out_si;
++ ia->ia_file = au_hf_top(file);
++ a->udba = AuOpt_UDBA_NONE;
++ } else {
++ /* fchmod() doesn't pass ia_file */
++ a->udba = au_opt_udba(sb);
++ /* no au_d_removed(), to set UDBA_NONE for root */
++ if (d_unhashed(dentry))
++ a->udba = AuOpt_UDBA_NONE;
++ di_write_lock_child(dentry);
++ if (a->udba != AuOpt_UDBA_NONE) {
++ AuDebugOn(IS_ROOT(dentry));
++ err = au_reval_for_attr(dentry, au_sigen(sb));
++ if (unlikely(err))
++ goto out_dentry;
++ }
++ }
++
++ err = au_pin_and_icpup(dentry, ia, a);
++ if (unlikely(err < 0))
++ goto out_dentry;
++ if (au_ftest_icpup(a->flags, DID_CPUP)) {
++ ia->ia_file = NULL;
++ ia->ia_valid &= ~ATTR_FILE;
++ }
++
++ a->h_path.mnt = au_sbr_mnt(sb, a->btgt);
++ if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME))
++ == (ATTR_MODE | ATTR_CTIME)) {
++ err = security_path_chmod(a->h_path.dentry, a->h_path.mnt,
++ ia->ia_mode);
++ if (unlikely(err))
++ goto out_unlock;
++ } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID))
++ && (ia->ia_valid & ATTR_CTIME)) {
++ err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid);
++ if (unlikely(err))
++ goto out_unlock;
++ }
++
++ if (ia->ia_valid & ATTR_SIZE) {
++ struct file *f;
++
++ if (ia->ia_size < i_size_read(inode))
++ /* unmap only */
++ truncate_setsize(inode, ia->ia_size);
++
++ f = NULL;
++ if (ia->ia_valid & ATTR_FILE)
++ f = ia->ia_file;
++ mutex_unlock(&a->h_inode->i_mutex);
++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f);
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ } else
++ err = vfsub_notify_change(&a->h_path, ia);
++ if (!err)
++ au_cpup_attr_changeable(inode);
++
++out_unlock:
++ mutex_unlock(&a->h_inode->i_mutex);
++ au_unpin(&a->pin);
++ if (unlikely(err))
++ au_update_dbstart(dentry);
++out_dentry:
++ di_write_unlock(dentry);
++ if (file) {
++ fi_write_unlock(file);
++ ia->ia_file = file;
++ ia->ia_valid |= ATTR_FILE;
++ }
++out_si:
++ si_read_unlock(sb);
++out_kfree:
++ kfree(a);
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static void au_refresh_iattr(struct inode *inode, struct kstat *st,
++ unsigned int nlink)
++{
++ inode->i_mode = st->mode;
++ inode->i_uid = st->uid;
++ inode->i_gid = st->gid;
++ inode->i_atime = st->atime;
++ inode->i_mtime = st->mtime;
++ inode->i_ctime = st->ctime;
++
++ au_cpup_attr_nlink(inode, /*force*/0);
++ if (S_ISDIR(inode->i_mode)) {
++ inode->i_nlink -= nlink;
++ inode->i_nlink += st->nlink;
++ }
++
++ spin_lock(&inode->i_lock);
++ inode->i_blocks = st->blocks;
++ i_size_write(inode, st->size);
++ spin_unlock(&inode->i_lock);
++}
++
++static int aufs_getattr(struct vfsmount *mnt __maybe_unused,
++ struct dentry *dentry, struct kstat *st)
++{
++ int err;
++ unsigned int mnt_flags;
++ aufs_bindex_t bindex;
++ unsigned char udba_none, positive;
++ struct super_block *sb, *h_sb;
++ struct inode *inode;
++ struct vfsmount *h_mnt;
++ struct dentry *h_dentry;
++
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out;
++ mnt_flags = au_mntflags(sb);
++ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE);
++
++ /* support fstat(2) */
++ if (!au_d_removed(dentry) && !udba_none) {
++ unsigned int sigen = au_sigen(sb);
++ err = au_digen_test(dentry, sigen);
++ if (!err) {
++ di_read_lock_child(dentry, AuLock_IR);
++ err = au_dbrange_test(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ } else {
++ AuDebugOn(IS_ROOT(dentry));
++ di_write_lock_child(dentry);
++ err = au_dbrange_test(dentry);
++ if (!err)
++ err = au_reval_for_attr(dentry, sigen);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++ }
++ } else
++ di_read_lock_child(dentry, AuLock_IR);
++
++ bindex = au_ibstart(inode);
++ h_mnt = au_sbr_mnt(sb, bindex);
++ h_sb = h_mnt->mnt_sb;
++ if (!au_test_fs_bad_iattr(h_sb) && udba_none)
++ goto out_fill; /* success */
++
++ h_dentry = NULL;
++ if (au_dbstart(dentry) == bindex)
++ h_dentry = dget(au_h_dptr(dentry, bindex));
++ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) {
++ h_dentry = au_plink_lkup(inode, bindex);
++ if (IS_ERR(h_dentry))
++ goto out_fill; /* pretending success */
++ }
++ /* illegally overlapped or something */
++ if (unlikely(!h_dentry))
++ goto out_fill; /* pretending success */
++
++ positive = !!h_dentry->d_inode;
++ if (positive)
++ err = vfs_getattr(h_mnt, h_dentry, st);
++ dput(h_dentry);
++ if (!err) {
++ if (positive)
++ au_refresh_iattr(inode, st, h_dentry->d_inode->i_nlink);
++ goto out_fill; /* success */
++ }
++ AuTraceErr(err);
++ goto out_unlock;
++
++out_fill:
++ generic_fillattr(inode, st);
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ si_read_unlock(sb);
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int h_readlink(struct dentry *dentry, int bindex, char __user *buf,
++ int bufsiz)
++{
++ int err;
++ struct super_block *sb;
++ struct dentry *h_dentry;
++
++ err = -EINVAL;
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (unlikely(!h_dentry->d_inode->i_op->readlink))
++ goto out;
++
++ err = security_inode_readlink(h_dentry);
++ if (unlikely(err))
++ goto out;
++
++ sb = dentry->d_sb;
++ if (!au_test_ro(sb, bindex, dentry->d_inode)) {
++ vfsub_touch_atime(au_sbr_mnt(sb, bindex), h_dentry);
++ fsstack_copy_attr_atime(dentry->d_inode, h_dentry->d_inode);
++ }
++ err = h_dentry->d_inode->i_op->readlink(h_dentry, buf, bufsiz);
++
++out:
++ return err;
++}
++
++static int aufs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
++{
++ int err;
++
++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN);
++ if (unlikely(err))
++ goto out;
++ err = au_d_hashed_positive(dentry);
++ if (!err)
++ err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz);
++ aufs_read_unlock(dentry, AuLock_IR);
++
++out:
++ return err;
++}
++
++static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ int err;
++ mm_segment_t old_fs;
++ union {
++ char *k;
++ char __user *u;
++ } buf;
++
++ err = -ENOMEM;
++ buf.k = __getname_gfp(GFP_NOFS);
++ if (unlikely(!buf.k))
++ goto out;
++
++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN);
++ if (unlikely(err))
++ goto out_name;
++
++ err = au_d_hashed_positive(dentry);
++ if (!err) {
++ old_fs = get_fs();
++ set_fs(KERNEL_DS);
++ err = h_readlink(dentry, au_dbstart(dentry), buf.u, PATH_MAX);
++ set_fs(old_fs);
++ }
++ aufs_read_unlock(dentry, AuLock_IR);
++
++ if (err >= 0) {
++ buf.k[err] = 0;
++ /* will be freed by put_link */
++ nd_set_link(nd, buf.k);
++ return NULL; /* success */
++ }
++
++out_name:
++ __putname(buf.k);
++out:
++ path_put(&nd->path);
++ AuTraceErr(err);
++ return ERR_PTR(err);
++}
++
++static void aufs_put_link(struct dentry *dentry __maybe_unused,
++ struct nameidata *nd, void *cookie __maybe_unused)
++{
++ __putname(nd_get_link(nd));
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void aufs_truncate_range(struct inode *inode __maybe_unused,
++ loff_t start __maybe_unused,
++ loff_t end __maybe_unused)
++{
++ AuUnsupport();
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct inode_operations aufs_symlink_iop = {
++ .permission = aufs_permission,
++ .setattr = aufs_setattr,
++ .getattr = aufs_getattr,
++ .readlink = aufs_readlink,
++ .follow_link = aufs_follow_link,
++ .put_link = aufs_put_link
++};
++
++struct inode_operations aufs_dir_iop = {
++ .create = aufs_create,
++ .lookup = aufs_lookup,
++ .link = aufs_link,
++ .unlink = aufs_unlink,
++ .symlink = aufs_symlink,
++ .mkdir = aufs_mkdir,
++ .rmdir = aufs_rmdir,
++ .mknod = aufs_mknod,
++ .rename = aufs_rename,
++
++ .permission = aufs_permission,
++ .setattr = aufs_setattr,
++ .getattr = aufs_getattr
++};
++
++struct inode_operations aufs_iop = {
++ .permission = aufs_permission,
++ .setattr = aufs_setattr,
++ .getattr = aufs_getattr,
++ .truncate_range = aufs_truncate_range
++};
+diff -Nur linux-2.6.36.orig/fs/aufs/i_op_add.c linux-2.6.36/fs/aufs/i_op_add.c
+--- linux-2.6.36.orig/fs/aufs/i_op_add.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/i_op_add.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,702 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode operations (add entry)
++ */
++
++#include "aufs.h"
++
++/*
++ * final procedure of adding a new entry, except link(2).
++ * remove whiteout, instantiate, copyup the parent dir's times and size
++ * and update version.
++ * if it failed, re-create the removed whiteout.
++ */
++static int epilog(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct dentry *dentry)
++{
++ int err, rerr;
++ aufs_bindex_t bwh;
++ struct path h_path;
++ struct inode *inode, *h_dir;
++ struct dentry *wh;
++
++ bwh = -1;
++ if (wh_dentry) {
++ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */
++ IMustLock(h_dir);
++ AuDebugOn(au_h_iptr(dir, bindex) != h_dir);
++ bwh = au_dbwh(dentry);
++ h_path.dentry = wh_dentry;
++ h_path.mnt = au_sbr_mnt(dir->i_sb, bindex);
++ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path,
++ dentry);
++ if (unlikely(err))
++ goto out;
++ }
++
++ inode = au_new_inode(dentry, /*must_new*/1);
++ if (!IS_ERR(inode)) {
++ d_instantiate(dentry, inode);
++ dir = dentry->d_parent->d_inode; /* dir inode is locked */
++ IMustLock(dir);
++ if (au_ibstart(dir) == au_dbstart(dentry))
++ au_cpup_attr_timesizes(dir);
++ dir->i_version++;
++ return 0; /* success */
++ }
++
++ err = PTR_ERR(inode);
++ if (!wh_dentry)
++ goto out;
++
++ /* revert */
++ /* dir inode is locked */
++ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent);
++ rerr = PTR_ERR(wh);
++ if (IS_ERR(wh)) {
++ AuIOErr("%.*s reverting whiteout failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ } else
++ dput(wh);
++
++out:
++ return err;
++}
++
++static int au_d_may_add(struct dentry *dentry)
++{
++ int err;
++
++ err = 0;
++ if (unlikely(d_unhashed(dentry)))
++ err = -ENOENT;
++ if (unlikely(dentry->d_inode))
++ err = -EEXIST;
++ return err;
++}
++
++/*
++ * simple tests for the adding inode operations.
++ * following the checks in vfs, plus the parent-child relationship.
++ */
++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir)
++{
++ int err;
++ umode_t h_mode;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++
++ err = -ENAMETOOLONG;
++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
++ goto out;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ h_inode = h_dentry->d_inode;
++ if (!dentry->d_inode) {
++ err = -EEXIST;
++ if (unlikely(h_inode))
++ goto out;
++ } else {
++ /* rename(2) case */
++ err = -EIO;
++ if (unlikely(!h_inode || !h_inode->i_nlink))
++ goto out;
++
++ h_mode = h_inode->i_mode;
++ if (!isdir) {
++ err = -EISDIR;
++ if (unlikely(S_ISDIR(h_mode)))
++ goto out;
++ } else if (unlikely(!S_ISDIR(h_mode))) {
++ err = -ENOTDIR;
++ goto out;
++ }
++ }
++
++ err = 0;
++ /* expected parent dir is locked */
++ if (unlikely(h_parent != h_dentry->d_parent))
++ err = -EIO;
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++/*
++ * initial procedure of adding a new entry.
++ * prepare writable branch and the parent dir, lock it,
++ * and lookup whiteout for the new entry.
++ */
++static struct dentry*
++lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt,
++ struct dentry *src_dentry, struct au_pin *pin,
++ struct au_wr_dir_args *wr_dir_args)
++{
++ struct dentry *wh_dentry, *h_parent;
++ struct super_block *sb;
++ struct au_branch *br;
++ int err;
++ unsigned int udba;
++ aufs_bindex_t bcpup;
++
++ AuDbg("%.*s\n", AuDLNPair(dentry));
++
++ err = au_wr_dir(dentry, src_dentry, wr_dir_args);
++ bcpup = err;
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err < 0))
++ goto out;
++
++ sb = dentry->d_sb;
++ udba = au_opt_udba(sb);
++ err = au_pin(pin, dentry, bcpup, udba,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ h_parent = au_pinned_h_parent(pin);
++ if (udba != AuOpt_UDBA_NONE
++ && au_dbstart(dentry) == bcpup)
++ err = au_may_add(dentry, bcpup, h_parent,
++ au_ftest_wrdir(wr_dir_args->flags, ISDIR));
++ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
++ err = -ENAMETOOLONG;
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_unpin;
++
++ br = au_sbr(sb, bcpup);
++ if (dt) {
++ struct path tmp = {
++ .dentry = h_parent,
++ .mnt = br->br_mnt
++ };
++ au_dtime_store(dt, au_pinned_parent(pin), &tmp);
++ }
++
++ wh_dentry = NULL;
++ if (bcpup != au_dbwh(dentry))
++ goto out; /* success */
++
++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br);
++
++out_unpin:
++ if (IS_ERR(wh_dentry))
++ au_unpin(pin);
++out:
++ return wh_dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++enum { Mknod, Symlink, Creat };
++struct simple_arg {
++ int type;
++ union {
++ struct {
++ int mode;
++ struct nameidata *nd;
++ } c;
++ struct {
++ const char *symname;
++ } s;
++ struct {
++ int mode;
++ dev_t dev;
++ } m;
++ } u;
++};
++
++static int add_simple(struct inode *dir, struct dentry *dentry,
++ struct simple_arg *arg)
++{
++ int err;
++ aufs_bindex_t bstart;
++ unsigned char created;
++ struct au_dtime dt;
++ struct au_pin pin;
++ struct path h_path;
++ struct dentry *wh_dentry, *parent;
++ struct inode *h_dir;
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = AuWrDir_ADD_ENTRY
++ };
++
++ AuDbg("%.*s\n", AuDLNPair(dentry));
++ IMustLock(dir);
++
++ parent = dentry->d_parent; /* dir inode is locked */
++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
++ if (unlikely(err))
++ goto out;
++ err = au_d_may_add(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ di_write_lock_parent(parent);
++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin,
++ &wr_dir_args);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_parent;
++
++ bstart = au_dbstart(dentry);
++ h_path.dentry = au_h_dptr(dentry, bstart);
++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
++ h_dir = au_pinned_h_dir(&pin);
++ switch (arg->type) {
++ case Creat:
++ err = vfsub_create(h_dir, &h_path, arg->u.c.mode);
++ break;
++ case Symlink:
++ err = vfsub_symlink(h_dir, &h_path, arg->u.s.symname);
++ break;
++ case Mknod:
++ err = vfsub_mknod(h_dir, &h_path, arg->u.m.mode, arg->u.m.dev);
++ break;
++ default:
++ BUG();
++ }
++ created = !err;
++ if (!err)
++ err = epilog(dir, bstart, wh_dentry, dentry);
++
++ /* revert */
++ if (unlikely(created && err && h_path.dentry->d_inode)) {
++ int rerr;
++ rerr = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ if (rerr) {
++ AuIOErr("%.*s revert failure(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ }
++ au_dtime_revert(&dt);
++ }
++
++ au_unpin(&pin);
++ dput(wh_dentry);
++
++out_parent:
++ di_write_unlock(parent);
++out_unlock:
++ if (unlikely(err)) {
++ au_update_dbstart(dentry);
++ d_drop(dentry);
++ }
++ aufs_read_unlock(dentry, AuLock_DW);
++out:
++ return err;
++}
++
++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
++{
++ struct simple_arg arg = {
++ .type = Mknod,
++ .u.m = {
++ .mode = mode,
++ .dev = dev
++ }
++ };
++ return add_simple(dir, dentry, &arg);
++}
++
++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
++{
++ struct simple_arg arg = {
++ .type = Symlink,
++ .u.s.symname = symname
++ };
++ return add_simple(dir, dentry, &arg);
++}
++
++int aufs_create(struct inode *dir, struct dentry *dentry, int mode,
++ struct nameidata *nd)
++{
++ struct simple_arg arg = {
++ .type = Creat,
++ .u.c = {
++ .mode = mode,
++ .nd = nd
++ }
++ };
++ return add_simple(dir, dentry, &arg);
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_link_args {
++ aufs_bindex_t bdst, bsrc;
++ struct au_pin pin;
++ struct path h_path;
++ struct dentry *src_parent, *parent;
++};
++
++static int au_cpup_before_link(struct dentry *src_dentry,
++ struct au_link_args *a)
++{
++ int err;
++ struct dentry *h_src_dentry;
++ struct mutex *h_mtx;
++ struct file *h_file;
++
++ di_read_lock_parent(a->src_parent, AuLock_IR);
++ err = au_test_and_cpup_dirs(src_dentry, a->bdst);
++ if (unlikely(err))
++ goto out;
++
++ h_src_dentry = au_h_dptr(src_dentry, a->bsrc);
++ h_mtx = &h_src_dentry->d_inode->i_mutex;
++ err = au_pin(&a->pin, src_dentry, a->bdst,
++ au_opt_udba(src_dentry->d_sb),
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (unlikely(err))
++ goto out;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ h_file = au_h_open_pre(src_dentry, a->bsrc);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_simple(src_dentry, a->bdst, a->bsrc,
++ AuCpup_DTIME /* | AuCpup_KEEPLINO */);
++ mutex_unlock(h_mtx);
++ au_h_open_post(src_dentry, a->bsrc, h_file);
++ au_unpin(&a->pin);
++
++out:
++ di_read_unlock(a->src_parent, AuLock_IR);
++ return err;
++}
++
++static int au_cpup_or_link(struct dentry *src_dentry, struct au_link_args *a)
++{
++ int err;
++ unsigned char plink;
++ struct inode *h_inode, *inode;
++ struct dentry *h_src_dentry;
++ struct super_block *sb;
++ struct file *h_file;
++
++ plink = 0;
++ h_inode = NULL;
++ sb = src_dentry->d_sb;
++ inode = src_dentry->d_inode;
++ if (au_ibstart(inode) <= a->bdst)
++ h_inode = au_h_iptr(inode, a->bdst);
++ if (!h_inode || !h_inode->i_nlink) {
++ /* copyup src_dentry as the name of dentry. */
++ au_set_dbstart(src_dentry, a->bdst);
++ au_set_h_dptr(src_dentry, a->bdst, dget(a->h_path.dentry));
++ h_inode = au_h_dptr(src_dentry, a->bsrc)->d_inode;
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ h_file = au_h_open_pre(src_dentry, a->bsrc);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_single(src_dentry, a->bdst, a->bsrc,
++ -1, AuCpup_KEEPLINO,
++ a->parent);
++ mutex_unlock(&h_inode->i_mutex);
++ au_h_open_post(src_dentry, a->bsrc, h_file);
++ au_set_h_dptr(src_dentry, a->bdst, NULL);
++ au_set_dbstart(src_dentry, a->bsrc);
++ } else {
++ /* the inode of src_dentry already exists on a.bdst branch */
++ h_src_dentry = d_find_alias(h_inode);
++ if (!h_src_dentry && au_plink_test(inode)) {
++ plink = 1;
++ h_src_dentry = au_plink_lkup(inode, a->bdst);
++ err = PTR_ERR(h_src_dentry);
++ if (IS_ERR(h_src_dentry))
++ goto out;
++
++ if (unlikely(!h_src_dentry->d_inode)) {
++ dput(h_src_dentry);
++ h_src_dentry = NULL;
++ }
++
++ }
++ if (h_src_dentry) {
++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
++ &a->h_path);
++ dput(h_src_dentry);
++ } else {
++ AuIOErr("no dentry found for hi%lu on b%d\n",
++ h_inode->i_ino, a->bdst);
++ err = -EIO;
++ }
++ }
++
++ if (!err && !plink)
++ au_plink_append(inode, a->bdst, a->h_path.dentry);
++
++out:
++ return err;
++}
++
++int aufs_link(struct dentry *src_dentry, struct inode *dir,
++ struct dentry *dentry)
++{
++ int err, rerr;
++ struct au_dtime dt;
++ struct au_link_args *a;
++ struct dentry *wh_dentry, *h_src_dentry;
++ struct inode *inode;
++ struct super_block *sb;
++ struct au_wr_dir_args wr_dir_args = {
++ /* .force_btgt = -1, */
++ .flags = AuWrDir_ADD_ENTRY
++ };
++
++ IMustLock(dir);
++ inode = src_dentry->d_inode;
++ IMustLock(inode);
++
++ err = -ENOMEM;
++ a = kzalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ a->parent = dentry->d_parent; /* dir inode is locked */
++ err = aufs_read_and_write_lock2(dentry, src_dentry,
++ AuLock_NOPLM | AuLock_GEN);
++ if (unlikely(err))
++ goto out_kfree;
++ err = au_d_hashed_positive(src_dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ err = au_d_may_add(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++
++ a->src_parent = dget_parent(src_dentry);
++ wr_dir_args.force_btgt = au_dbstart(src_dentry);
++
++ di_write_lock_parent(a->parent);
++ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt);
++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin,
++ &wr_dir_args);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_parent;
++
++ err = 0;
++ sb = dentry->d_sb;
++ a->bdst = au_dbstart(dentry);
++ a->h_path.dentry = au_h_dptr(dentry, a->bdst);
++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst);
++ a->bsrc = au_dbstart(src_dentry);
++ if (au_opt_test(au_mntflags(sb), PLINK)) {
++ if (a->bdst < a->bsrc
++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */)
++ err = au_cpup_or_link(src_dentry, a);
++ else {
++ h_src_dentry = au_h_dptr(src_dentry, a->bdst);
++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
++ &a->h_path);
++ }
++ } else {
++ /*
++ * copyup src_dentry to the branch we process,
++ * and then link(2) to it.
++ */
++ if (a->bdst < a->bsrc
++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) {
++ au_unpin(&a->pin);
++ di_write_unlock(a->parent);
++ err = au_cpup_before_link(src_dentry, a);
++ di_write_lock_parent(a->parent);
++ if (!err)
++ err = au_pin(&a->pin, dentry, a->bdst,
++ au_opt_udba(sb),
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (unlikely(err))
++ goto out_wh;
++ }
++ if (!err) {
++ h_src_dentry = au_h_dptr(src_dentry, a->bdst);
++ err = -ENOENT;
++ if (h_src_dentry && h_src_dentry->d_inode)
++ err = vfsub_link(h_src_dentry,
++ au_pinned_h_dir(&a->pin),
++ &a->h_path);
++ }
++ }
++ if (unlikely(err))
++ goto out_unpin;
++
++ if (wh_dentry) {
++ a->h_path.dentry = wh_dentry;
++ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path,
++ dentry);
++ if (unlikely(err))
++ goto out_revert;
++ }
++
++ dir->i_version++;
++ if (au_ibstart(dir) == au_dbstart(dentry))
++ au_cpup_attr_timesizes(dir);
++ inc_nlink(inode);
++ inode->i_ctime = dir->i_ctime;
++ d_instantiate(dentry, au_igrab(inode));
++ if (d_unhashed(a->h_path.dentry))
++ /* some filesystem calls d_drop() */
++ d_drop(dentry);
++ goto out_unpin; /* success */
++
++out_revert:
++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, /*force*/0);
++ if (unlikely(rerr)) {
++ AuIOErr("%.*s reverting failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ }
++ au_dtime_revert(&dt);
++out_unpin:
++ au_unpin(&a->pin);
++out_wh:
++ dput(wh_dentry);
++out_parent:
++ di_write_unlock(a->parent);
++ dput(a->src_parent);
++out_unlock:
++ if (unlikely(err)) {
++ au_update_dbstart(dentry);
++ d_drop(dentry);
++ }
++ aufs_read_and_write_unlock2(dentry, src_dentry);
++out_kfree:
++ kfree(a);
++out:
++ return err;
++}
++
++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++ int err, rerr;
++ aufs_bindex_t bindex;
++ unsigned char diropq;
++ struct path h_path;
++ struct dentry *wh_dentry, *parent, *opq_dentry;
++ struct mutex *h_mtx;
++ struct super_block *sb;
++ struct {
++ struct au_pin pin;
++ struct au_dtime dt;
++ } *a; /* reduce the stack usage */
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR
++ };
++
++ IMustLock(dir);
++
++ err = -ENOMEM;
++ a = kmalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
++ if (unlikely(err))
++ goto out_free;
++ err = au_d_may_add(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_write_lock_parent(parent);
++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL,
++ &a->pin, &wr_dir_args);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_parent;
++
++ sb = dentry->d_sb;
++ bindex = au_dbstart(dentry);
++ h_path.dentry = au_h_dptr(dentry, bindex);
++ h_path.mnt = au_sbr_mnt(sb, bindex);
++ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode);
++ if (unlikely(err))
++ goto out_unpin;
++
++ /* make the dir opaque */
++ diropq = 0;
++ h_mtx = &h_path.dentry->d_inode->i_mutex;
++ if (wh_dentry
++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) {
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ opq_dentry = au_diropq_create(dentry, bindex);
++ mutex_unlock(h_mtx);
++ err = PTR_ERR(opq_dentry);
++ if (IS_ERR(opq_dentry))
++ goto out_dir;
++ dput(opq_dentry);
++ diropq = 1;
++ }
++
++ err = epilog(dir, bindex, wh_dentry, dentry);
++ if (!err) {
++ inc_nlink(dir);
++ goto out_unpin; /* success */
++ }
++
++ /* revert */
++ if (diropq) {
++ AuLabel(revert opq);
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ rerr = au_diropq_remove(dentry, bindex);
++ mutex_unlock(h_mtx);
++ if (rerr) {
++ AuIOErr("%.*s reverting diropq failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ }
++ }
++
++out_dir:
++ AuLabel(revert dir);
++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path);
++ if (rerr) {
++ AuIOErr("%.*s reverting dir failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ }
++ au_dtime_revert(&a->dt);
++out_unpin:
++ au_unpin(&a->pin);
++ dput(wh_dentry);
++out_parent:
++ di_write_unlock(parent);
++out_unlock:
++ if (unlikely(err)) {
++ au_update_dbstart(dentry);
++ d_drop(dentry);
++ }
++ aufs_read_unlock(dentry, AuLock_DW);
++out_free:
++ kfree(a);
++out:
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/i_op_del.c linux-2.6.36/fs/aufs/i_op_del.c
+--- linux-2.6.36.orig/fs/aufs/i_op_del.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/i_op_del.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,481 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode operations (del entry)
++ */
++
++#include "aufs.h"
++
++/*
++ * decide if a new whiteout for @dentry is necessary or not.
++ * when it is necessary, prepare the parent dir for the upper branch whose
++ * branch index is @bcpup for creation. the actual creation of the whiteout will
++ * be done by caller.
++ * return value:
++ * 0: wh is unnecessary
++ * plus: wh is necessary
++ * minus: error
++ */
++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup)
++{
++ int need_wh, err;
++ aufs_bindex_t bstart;
++ struct super_block *sb;
++
++ sb = dentry->d_sb;
++ bstart = au_dbstart(dentry);
++ if (*bcpup < 0) {
++ *bcpup = bstart;
++ if (au_test_ro(sb, bstart, dentry->d_inode)) {
++ err = AuWbrCopyup(au_sbi(sb), dentry);
++ *bcpup = err;
++ if (unlikely(err < 0))
++ goto out;
++ }
++ } else
++ AuDebugOn(bstart < *bcpup
++ || au_test_ro(sb, *bcpup, dentry->d_inode));
++ AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart);
++
++ if (*bcpup != bstart) {
++ err = au_cpup_dirs(dentry, *bcpup);
++ if (unlikely(err))
++ goto out;
++ need_wh = 1;
++ } else {
++ struct au_dinfo *dinfo, *tmp;
++
++ need_wh = -ENOMEM;
++ dinfo = au_di(dentry);
++ tmp = au_di_alloc(sb, AuLsc_DI_TMP);
++ if (tmp) {
++ au_di_cp(tmp, dinfo);
++ au_di_swap(tmp, dinfo);
++ /* returns the number of positive dentries */
++ need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0,
++ /*nd*/NULL);
++ au_di_swap(tmp, dinfo);
++ au_rw_write_unlock(&tmp->di_rwsem);
++ au_di_free(tmp);
++ }
++ }
++ AuDbg("need_wh %d\n", need_wh);
++ err = need_wh;
++
++out:
++ return err;
++}
++
++/*
++ * simple tests for the del-entry operations.
++ * following the checks in vfs, plus the parent-child relationship.
++ */
++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir)
++{
++ int err;
++ umode_t h_mode;
++ struct dentry *h_dentry, *h_latest;
++ struct inode *h_inode;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ h_inode = h_dentry->d_inode;
++ if (dentry->d_inode) {
++ err = -ENOENT;
++ if (unlikely(!h_inode || !h_inode->i_nlink))
++ goto out;
++
++ h_mode = h_inode->i_mode;
++ if (!isdir) {
++ err = -EISDIR;
++ if (unlikely(S_ISDIR(h_mode)))
++ goto out;
++ } else if (unlikely(!S_ISDIR(h_mode))) {
++ err = -ENOTDIR;
++ goto out;
++ }
++ } else {
++ /* rename(2) case */
++ err = -EIO;
++ if (unlikely(h_inode))
++ goto out;
++ }
++
++ err = -ENOENT;
++ /* expected parent dir is locked */
++ if (unlikely(h_parent != h_dentry->d_parent))
++ goto out;
++ err = 0;
++
++ /*
++ * rmdir a dir may break the consistency on some filesystem.
++ * let's try heavy test.
++ */
++ err = -EACCES;
++ if (unlikely(au_test_h_perm(h_parent->d_inode, MAY_EXEC | MAY_WRITE)))
++ goto out;
++
++ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent,
++ au_sbr(dentry->d_sb, bindex));
++ err = -EIO;
++ if (IS_ERR(h_latest))
++ goto out;
++ if (h_latest == h_dentry)
++ err = 0;
++ dput(h_latest);
++
++out:
++ return err;
++}
++
++/*
++ * decide the branch where we operate for @dentry. the branch index will be set
++ * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent
++ * dir for reverting.
++ * when a new whiteout is necessary, create it.
++ */
++static struct dentry*
++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup,
++ struct au_dtime *dt, struct au_pin *pin)
++{
++ struct dentry *wh_dentry;
++ struct super_block *sb;
++ struct path h_path;
++ int err, need_wh;
++ unsigned int udba;
++ aufs_bindex_t bcpup;
++
++ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup);
++ wh_dentry = ERR_PTR(need_wh);
++ if (unlikely(need_wh < 0))
++ goto out;
++
++ sb = dentry->d_sb;
++ udba = au_opt_udba(sb);
++ bcpup = *rbcpup;
++ err = au_pin(pin, dentry, bcpup, udba,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ h_path.dentry = au_pinned_h_parent(pin);
++ if (udba != AuOpt_UDBA_NONE
++ && au_dbstart(dentry) == bcpup) {
++ err = au_may_del(dentry, bcpup, h_path.dentry, isdir);
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_unpin;
++ }
++
++ h_path.mnt = au_sbr_mnt(sb, bcpup);
++ au_dtime_store(dt, au_pinned_parent(pin), &h_path);
++ wh_dentry = NULL;
++ if (!need_wh)
++ goto out; /* success, no need to create whiteout */
++
++ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_unpin;
++
++ /* returns with the parent is locked and wh_dentry is dget-ed */
++ goto out; /* success */
++
++out_unpin:
++ au_unpin(pin);
++out:
++ return wh_dentry;
++}
++
++/*
++ * when removing a dir, rename it to a unique temporary whiteout-ed name first
++ * in order to be revertible and save time for removing many child whiteouts
++ * under the dir.
++ * returns 1 when there are too many child whiteout and caller should remove
++ * them asynchronously. returns 0 when the number of children is enough small to
++ * remove now or the branch fs is a remote fs.
++ * otherwise return an error.
++ */
++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex,
++ struct au_nhash *whlist, struct inode *dir)
++{
++ int rmdir_later, err, dirwh;
++ struct dentry *h_dentry;
++ struct super_block *sb;
++
++ sb = dentry->d_sb;
++ SiMustAnyLock(sb);
++ h_dentry = au_h_dptr(dentry, bindex);
++ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex));
++ if (unlikely(err))
++ goto out;
++
++ /* stop monitoring */
++ au_hn_free(au_hi(dentry->d_inode, bindex));
++
++ if (!au_test_fs_remote(h_dentry->d_sb)) {
++ dirwh = au_sbi(sb)->si_dirwh;
++ rmdir_later = (dirwh <= 1);
++ if (!rmdir_later)
++ rmdir_later = au_nhash_test_longer_wh(whlist, bindex,
++ dirwh);
++ if (rmdir_later)
++ return rmdir_later;
++ }
++
++ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist);
++ if (unlikely(err)) {
++ AuIOErr("rmdir %.*s, b%d failed, %d. ignored\n",
++ AuDLNPair(h_dentry), bindex, err);
++ err = 0;
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++/*
++ * final procedure for deleting a entry.
++ * maintain dentry and iattr.
++ */
++static void epilog(struct inode *dir, struct dentry *dentry,
++ aufs_bindex_t bindex)
++{
++ struct inode *inode;
++
++ inode = dentry->d_inode;
++ d_drop(dentry);
++ inode->i_ctime = dir->i_ctime;
++
++ if (au_ibstart(dir) == bindex)
++ au_cpup_attr_timesizes(dir);
++ dir->i_version++;
++}
++
++/*
++ * when an error happened, remove the created whiteout and revert everything.
++ */
++static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex,
++ aufs_bindex_t bwh, struct dentry *wh_dentry,
++ struct dentry *dentry, struct au_dtime *dt)
++{
++ int rerr;
++ struct path h_path = {
++ .dentry = wh_dentry,
++ .mnt = au_sbr_mnt(dir->i_sb, bindex)
++ };
++
++ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry);
++ if (!rerr) {
++ au_set_dbwh(dentry, bwh);
++ au_dtime_revert(dt);
++ return 0;
++ }
++
++ AuIOErr("%.*s reverting whiteout failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ return -EIO;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int aufs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bwh, bindex, bstart;
++ struct au_dtime dt;
++ struct au_pin pin;
++ struct path h_path;
++ struct inode *inode, *h_dir;
++ struct dentry *parent, *wh_dentry;
++
++ IMustLock(dir);
++
++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
++ if (unlikely(err))
++ goto out;
++ err = au_d_hashed_positive(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ inode = dentry->d_inode;
++ IMustLock(inode);
++ err = -EISDIR;
++ if (unlikely(S_ISDIR(inode->i_mode)))
++ goto out_unlock; /* possible? */
++
++ bstart = au_dbstart(dentry);
++ bwh = au_dbwh(dentry);
++ bindex = -1;
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_write_lock_parent(parent);
++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_parent;
++
++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
++ h_path.dentry = au_h_dptr(dentry, bstart);
++ dget(h_path.dentry);
++ if (bindex == bstart) {
++ h_dir = au_pinned_h_dir(&pin);
++ err = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ } else {
++ /* dir inode is locked */
++ h_dir = wh_dentry->d_parent->d_inode;
++ IMustLock(h_dir);
++ err = 0;
++ }
++
++ if (!err) {
++ vfsub_drop_nlink(inode);
++ epilog(dir, dentry, bindex);
++
++ /* update target timestamps */
++ if (bindex == bstart) {
++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
++ inode->i_ctime = h_path.dentry->d_inode->i_ctime;
++ } else
++ /* todo: this timestamp may be reverted later */
++ inode->i_ctime = h_dir->i_ctime;
++ goto out_unpin; /* success */
++ }
++
++ /* revert */
++ if (wh_dentry) {
++ int rerr;
++
++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, &dt);
++ if (rerr)
++ err = rerr;
++ }
++
++out_unpin:
++ au_unpin(&pin);
++ dput(wh_dentry);
++ dput(h_path.dentry);
++out_parent:
++ di_write_unlock(parent);
++out_unlock:
++ aufs_read_unlock(dentry, AuLock_DW);
++out:
++ return err;
++}
++
++int aufs_rmdir(struct inode *dir, struct dentry *dentry)
++{
++ int err, rmdir_later;
++ aufs_bindex_t bwh, bindex, bstart;
++ struct au_dtime dt;
++ struct au_pin pin;
++ struct inode *inode;
++ struct dentry *parent, *wh_dentry, *h_dentry;
++ struct au_whtmp_rmdir *args;
++
++ IMustLock(dir);
++
++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN);
++ if (unlikely(err))
++ goto out;
++
++ /* VFS already unhashes it */
++ inode = dentry->d_inode;
++ err = -ENOENT;
++ if (unlikely(!inode || !inode->i_nlink
++ || IS_DEADDIR(inode)))
++ goto out_unlock;
++ IMustLock(inode);
++ err = -ENOTDIR;
++ if (unlikely(!S_ISDIR(inode->i_mode)))
++ goto out_unlock; /* possible? */
++
++ err = -ENOMEM;
++ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS);
++ if (unlikely(!args))
++ goto out_unlock;
++
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_write_lock_parent(parent);
++ err = au_test_empty(dentry, &args->whlist);
++ if (unlikely(err))
++ goto out_parent;
++
++ bstart = au_dbstart(dentry);
++ bwh = au_dbwh(dentry);
++ bindex = -1;
++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &dt, &pin);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_parent;
++
++ h_dentry = au_h_dptr(dentry, bstart);
++ dget(h_dentry);
++ rmdir_later = 0;
++ if (bindex == bstart) {
++ err = renwh_and_rmdir(dentry, bstart, &args->whlist, dir);
++ if (err > 0) {
++ rmdir_later = err;
++ err = 0;
++ }
++ } else {
++ /* stop monitoring */
++ au_hn_free(au_hi(inode, bstart));
++
++ /* dir inode is locked */
++ IMustLock(wh_dentry->d_parent->d_inode);
++ err = 0;
++ }
++
++ if (!err) {
++ vfsub_dead_dir(inode);
++ au_set_dbdiropq(dentry, -1);
++ epilog(dir, dentry, bindex);
++
++ if (rmdir_later) {
++ au_whtmp_kick_rmdir(dir, bstart, h_dentry, args);
++ args = NULL;
++ }
++
++ goto out_unpin; /* success */
++ }
++
++ /* revert */
++ AuLabel(revert);
++ if (wh_dentry) {
++ int rerr;
++
++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, &dt);
++ if (rerr)
++ err = rerr;
++ }
++
++out_unpin:
++ au_unpin(&pin);
++ dput(wh_dentry);
++ dput(h_dentry);
++out_parent:
++ di_write_unlock(parent);
++ if (args)
++ au_whtmp_rmdir_free(args);
++out_unlock:
++ aufs_read_unlock(dentry, AuLock_DW);
++out:
++ AuTraceErr(err);
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/i_op_ren.c linux-2.6.36/fs/aufs/i_op_ren.c
+--- linux-2.6.36.orig/fs/aufs/i_op_ren.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/i_op_ren.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,1017 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode operation (rename entry)
++ * todo: this is crazy monster
++ */
++
++#include "aufs.h"
++
++enum { AuSRC, AuDST, AuSrcDst };
++enum { AuPARENT, AuCHILD, AuParentChild };
++
++#define AuRen_ISDIR 1
++#define AuRen_ISSAMEDIR (1 << 1)
++#define AuRen_WHSRC (1 << 2)
++#define AuRen_WHDST (1 << 3)
++#define AuRen_MNT_WRITE (1 << 4)
++#define AuRen_DT_DSTDIR (1 << 5)
++#define AuRen_DIROPQ (1 << 6)
++#define AuRen_CPUP (1 << 7)
++#define au_ftest_ren(flags, name) ((flags) & AuRen_##name)
++#define au_fset_ren(flags, name) \
++ do { (flags) |= AuRen_##name; } while (0)
++#define au_fclr_ren(flags, name) \
++ do { (flags) &= ~AuRen_##name; } while (0)
++
++struct au_ren_args {
++ struct {
++ struct dentry *dentry, *h_dentry, *parent, *h_parent,
++ *wh_dentry;
++ struct inode *dir, *inode;
++ struct au_hinode *hdir;
++ struct au_dtime dt[AuParentChild];
++ aufs_bindex_t bstart;
++ } sd[AuSrcDst];
++
++#define src_dentry sd[AuSRC].dentry
++#define src_dir sd[AuSRC].dir
++#define src_inode sd[AuSRC].inode
++#define src_h_dentry sd[AuSRC].h_dentry
++#define src_parent sd[AuSRC].parent
++#define src_h_parent sd[AuSRC].h_parent
++#define src_wh_dentry sd[AuSRC].wh_dentry
++#define src_hdir sd[AuSRC].hdir
++#define src_h_dir sd[AuSRC].hdir->hi_inode
++#define src_dt sd[AuSRC].dt
++#define src_bstart sd[AuSRC].bstart
++
++#define dst_dentry sd[AuDST].dentry
++#define dst_dir sd[AuDST].dir
++#define dst_inode sd[AuDST].inode
++#define dst_h_dentry sd[AuDST].h_dentry
++#define dst_parent sd[AuDST].parent
++#define dst_h_parent sd[AuDST].h_parent
++#define dst_wh_dentry sd[AuDST].wh_dentry
++#define dst_hdir sd[AuDST].hdir
++#define dst_h_dir sd[AuDST].hdir->hi_inode
++#define dst_dt sd[AuDST].dt
++#define dst_bstart sd[AuDST].bstart
++
++ struct dentry *h_trap;
++ struct au_branch *br;
++ struct au_hinode *src_hinode;
++ struct path h_path;
++ struct au_nhash whlist;
++ aufs_bindex_t btgt, src_bwh, src_bdiropq;
++
++ unsigned int flags;
++
++ struct au_whtmp_rmdir *thargs;
++ struct dentry *h_dst;
++};
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * functions for reverting.
++ * when an error happened in a single rename systemcall, we should revert
++ * everything as if nothing happend.
++ * we don't need to revert the copied-up/down the parent dir since they are
++ * harmless.
++ */
++
++#define RevertFailure(fmt, ...) do { \
++ AuIOErr("revert failure: " fmt " (%d, %d)\n", \
++ ##__VA_ARGS__, err, rerr); \
++ err = -EIO; \
++} while (0)
++
++static void au_ren_rev_diropq(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
++ rerr = au_diropq_remove(a->src_dentry, a->btgt);
++ au_hn_imtx_unlock(a->src_hinode);
++ au_set_dbdiropq(a->src_dentry, a->src_bdiropq);
++ if (rerr)
++ RevertFailure("remove diropq %.*s", AuDLNPair(a->src_dentry));
++}
++
++static void au_ren_rev_rename(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = au_lkup_one(&a->src_dentry->d_name, a->src_h_parent,
++ a->br, /*nd*/NULL);
++ rerr = PTR_ERR(a->h_path.dentry);
++ if (IS_ERR(a->h_path.dentry)) {
++ RevertFailure("au_lkup_one %.*s", AuDLNPair(a->src_dentry));
++ return;
++ }
++
++ rerr = vfsub_rename(a->dst_h_dir,
++ au_h_dptr(a->src_dentry, a->btgt),
++ a->src_h_dir, &a->h_path);
++ d_drop(a->h_path.dentry);
++ dput(a->h_path.dentry);
++ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */
++ if (rerr)
++ RevertFailure("rename %.*s", AuDLNPair(a->src_dentry));
++}
++
++static void au_ren_rev_cpup(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = a->dst_h_dentry;
++ rerr = vfsub_unlink(a->dst_h_dir, &a->h_path, /*force*/0);
++ au_set_h_dptr(a->src_dentry, a->btgt, NULL);
++ au_set_dbstart(a->src_dentry, a->src_bstart);
++ if (rerr)
++ RevertFailure("unlink %.*s", AuDLNPair(a->dst_h_dentry));
++}
++
++static void au_ren_rev_whtmp(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = au_lkup_one(&a->dst_dentry->d_name, a->dst_h_parent,
++ a->br, /*nd*/NULL);
++ rerr = PTR_ERR(a->h_path.dentry);
++ if (IS_ERR(a->h_path.dentry)) {
++ RevertFailure("lookup %.*s", AuDLNPair(a->dst_dentry));
++ return;
++ }
++ if (a->h_path.dentry->d_inode) {
++ d_drop(a->h_path.dentry);
++ dput(a->h_path.dentry);
++ return;
++ }
++
++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path);
++ d_drop(a->h_path.dentry);
++ dput(a->h_path.dentry);
++ if (!rerr)
++ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst));
++ else
++ RevertFailure("rename %.*s", AuDLNPair(a->h_dst));
++}
++
++static void au_ren_rev_whsrc(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = a->src_wh_dentry;
++ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry);
++ au_set_dbwh(a->src_dentry, a->src_bwh);
++ if (rerr)
++ RevertFailure("unlink %.*s", AuDLNPair(a->src_wh_dentry));
++}
++#undef RevertFailure
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * when we have to copyup the renaming entry, do it with the rename-target name
++ * in order to minimize the cost (the later actual rename is unnecessary).
++ * otherwise rename it on the target branch.
++ */
++static int au_ren_or_cpup(struct au_ren_args *a)
++{
++ int err;
++ struct dentry *d;
++
++ d = a->src_dentry;
++ if (au_dbstart(d) == a->btgt) {
++ a->h_path.dentry = a->dst_h_dentry;
++ if (au_ftest_ren(a->flags, DIROPQ)
++ && au_dbdiropq(d) == a->btgt)
++ au_fclr_ren(a->flags, DIROPQ);
++ AuDebugOn(au_dbstart(d) != a->btgt);
++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt),
++ a->dst_h_dir, &a->h_path);
++ } else {
++ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex;
++ struct file *h_file;
++
++ au_fset_ren(a->flags, CPUP);
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ au_set_dbstart(d, a->btgt);
++ au_set_h_dptr(d, a->btgt, dget(a->dst_h_dentry));
++ h_file = au_h_open_pre(d, a->src_bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_single(d, a->btgt, a->src_bstart, -1,
++ !AuCpup_DTIME, a->dst_parent);
++ mutex_unlock(h_mtx);
++ au_h_open_post(d, a->src_bstart, h_file);
++ if (!err) {
++ d = a->dst_dentry;
++ au_set_h_dptr(d, a->btgt, NULL);
++ au_update_dbstart(d);
++ } else {
++ au_set_h_dptr(d, a->btgt, NULL);
++ au_set_dbstart(d, a->src_bstart);
++ }
++ }
++ if (!err && a->h_dst)
++ /* it will be set to dinfo later */
++ dget(a->h_dst);
++
++ return err;
++}
++
++/* cf. aufs_rmdir() */
++static int au_ren_del_whtmp(struct au_ren_args *a)
++{
++ int err;
++ struct inode *dir;
++
++ dir = a->dst_dir;
++ SiMustAnyLock(dir->i_sb);
++ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt,
++ au_sbi(dir->i_sb)->si_dirwh)
++ || au_test_fs_remote(a->h_dst->d_sb)) {
++ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist);
++ if (unlikely(err))
++ pr_warning("failed removing whtmp dir %.*s (%d), "
++ "ignored.\n", AuDLNPair(a->h_dst), err);
++ } else {
++ au_nhash_wh_free(&a->thargs->whlist);
++ a->thargs->whlist = a->whlist;
++ a->whlist.nh_num = 0;
++ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs);
++ dput(a->h_dst);
++ a->thargs = NULL;
++ }
++
++ return 0;
++}
++
++/* make it 'opaque' dir. */
++static int au_ren_diropq(struct au_ren_args *a)
++{
++ int err;
++ struct dentry *diropq;
++
++ err = 0;
++ a->src_bdiropq = au_dbdiropq(a->src_dentry);
++ a->src_hinode = au_hi(a->src_inode, a->btgt);
++ au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
++ diropq = au_diropq_create(a->src_dentry, a->btgt);
++ au_hn_imtx_unlock(a->src_hinode);
++ if (IS_ERR(diropq))
++ err = PTR_ERR(diropq);
++ dput(diropq);
++
++ return err;
++}
++
++static int do_rename(struct au_ren_args *a)
++{
++ int err;
++ struct dentry *d, *h_d;
++
++ /* prepare workqueue args for asynchronous rmdir */
++ h_d = a->dst_h_dentry;
++ if (au_ftest_ren(a->flags, ISDIR) && h_d->d_inode) {
++ err = -ENOMEM;
++ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, GFP_NOFS);
++ if (unlikely(!a->thargs))
++ goto out;
++ a->h_dst = dget(h_d);
++ }
++
++ /* create whiteout for src_dentry */
++ if (au_ftest_ren(a->flags, WHSRC)) {
++ a->src_bwh = au_dbwh(a->src_dentry);
++ AuDebugOn(a->src_bwh >= 0);
++ a->src_wh_dentry
++ = au_wh_create(a->src_dentry, a->btgt, a->src_h_parent);
++ err = PTR_ERR(a->src_wh_dentry);
++ if (IS_ERR(a->src_wh_dentry))
++ goto out_thargs;
++ }
++
++ /* lookup whiteout for dentry */
++ if (au_ftest_ren(a->flags, WHDST)) {
++ h_d = au_wh_lkup(a->dst_h_parent, &a->dst_dentry->d_name,
++ a->br);
++ err = PTR_ERR(h_d);
++ if (IS_ERR(h_d))
++ goto out_whsrc;
++ if (!h_d->d_inode)
++ dput(h_d);
++ else
++ a->dst_wh_dentry = h_d;
++ }
++
++ /* rename dentry to tmpwh */
++ if (a->thargs) {
++ err = au_whtmp_ren(a->dst_h_dentry, a->br);
++ if (unlikely(err))
++ goto out_whdst;
++
++ d = a->dst_dentry;
++ au_set_h_dptr(d, a->btgt, NULL);
++ err = au_lkup_neg(d, a->btgt);
++ if (unlikely(err))
++ goto out_whtmp;
++ a->dst_h_dentry = au_h_dptr(d, a->btgt);
++ }
++
++ /* cpup src */
++ if (a->dst_h_dentry->d_inode && a->src_bstart != a->btgt) {
++ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex;
++ struct file *h_file;
++
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ AuDebugOn(au_dbstart(a->src_dentry) != a->src_bstart);
++ h_file = au_h_open_pre(a->src_dentry, a->src_bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_simple(a->src_dentry, a->btgt, -1,
++ !AuCpup_DTIME);
++ mutex_unlock(h_mtx);
++ au_h_open_post(a->src_dentry, a->src_bstart, h_file);
++ if (unlikely(err))
++ goto out_whtmp;
++ }
++
++ /* rename by vfs_rename or cpup */
++ d = a->dst_dentry;
++ if (au_ftest_ren(a->flags, ISDIR)
++ && (a->dst_wh_dentry
++ || au_dbdiropq(d) == a->btgt
++ /* hide the lower to keep xino */
++ || a->btgt < au_dbend(d)
++ || au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ)))
++ au_fset_ren(a->flags, DIROPQ);
++ err = au_ren_or_cpup(a);
++ if (unlikely(err))
++ /* leave the copied-up one */
++ goto out_whtmp;
++
++ /* make dir opaque */
++ if (au_ftest_ren(a->flags, DIROPQ)) {
++ err = au_ren_diropq(a);
++ if (unlikely(err))
++ goto out_rename;
++ }
++
++ /* update target timestamps */
++ AuDebugOn(au_dbstart(a->src_dentry) != a->btgt);
++ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt);
++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/
++ a->src_inode->i_ctime = a->h_path.dentry->d_inode->i_ctime;
++
++ /* remove whiteout for dentry */
++ if (a->dst_wh_dentry) {
++ a->h_path.dentry = a->dst_wh_dentry;
++ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path,
++ a->dst_dentry);
++ if (unlikely(err))
++ goto out_diropq;
++ }
++
++ /* remove whtmp */
++ if (a->thargs)
++ au_ren_del_whtmp(a); /* ignore this error */
++
++ err = 0;
++ goto out_success;
++
++out_diropq:
++ if (au_ftest_ren(a->flags, DIROPQ))
++ au_ren_rev_diropq(err, a);
++out_rename:
++ if (!au_ftest_ren(a->flags, CPUP))
++ au_ren_rev_rename(err, a);
++ else
++ au_ren_rev_cpup(err, a);
++ dput(a->h_dst);
++out_whtmp:
++ if (a->thargs)
++ au_ren_rev_whtmp(err, a);
++out_whdst:
++ dput(a->dst_wh_dentry);
++ a->dst_wh_dentry = NULL;
++out_whsrc:
++ if (a->src_wh_dentry)
++ au_ren_rev_whsrc(err, a);
++out_success:
++ dput(a->src_wh_dentry);
++ dput(a->dst_wh_dentry);
++out_thargs:
++ if (a->thargs) {
++ dput(a->h_dst);
++ au_whtmp_rmdir_free(a->thargs);
++ a->thargs = NULL;
++ }
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * test if @dentry dir can be rename destination or not.
++ * success means, it is a logically empty dir.
++ */
++static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist)
++{
++ return au_test_empty(dentry, whlist);
++}
++
++/*
++ * test if @dentry dir can be rename source or not.
++ * if it can, return 0 and @children is filled.
++ * success means,
++ * - it is a logically empty dir.
++ * - or, it exists on writable branch and has no children including whiteouts
++ * on the lower branch.
++ */
++static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt)
++{
++ int err;
++ unsigned int rdhash;
++ aufs_bindex_t bstart;
++
++ bstart = au_dbstart(dentry);
++ if (bstart != btgt) {
++ struct au_nhash whlist;
++
++ SiMustAnyLock(dentry->d_sb);
++ rdhash = au_sbi(dentry->d_sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL,
++ dentry));
++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_test_empty(dentry, &whlist);
++ au_nhash_wh_free(&whlist);
++ goto out;
++ }
++
++ if (bstart == au_dbtaildir(dentry))
++ return 0; /* success */
++
++ err = au_test_empty_lower(dentry);
++
++out:
++ if (err == -ENOTEMPTY) {
++ AuWarn1("renaming dir who has child(ren) on multiple branches,"
++ " is not supported\n");
++ err = -EXDEV;
++ }
++ return err;
++}
++
++/* side effect: sets whlist and h_dentry */
++static int au_ren_may_dir(struct au_ren_args *a)
++{
++ int err;
++ unsigned int rdhash;
++ struct dentry *d;
++
++ d = a->dst_dentry;
++ SiMustAnyLock(d->d_sb);
++
++ err = 0;
++ if (au_ftest_ren(a->flags, ISDIR) && a->dst_inode) {
++ rdhash = au_sbi(d->d_sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d));
++ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++
++ au_set_dbstart(d, a->dst_bstart);
++ err = may_rename_dstdir(d, &a->whlist);
++ au_set_dbstart(d, a->btgt);
++ }
++ a->dst_h_dentry = au_h_dptr(d, au_dbstart(d));
++ if (unlikely(err))
++ goto out;
++
++ d = a->src_dentry;
++ a->src_h_dentry = au_h_dptr(d, au_dbstart(d));
++ if (au_ftest_ren(a->flags, ISDIR)) {
++ err = may_rename_srcdir(d, a->btgt);
++ if (unlikely(err)) {
++ au_nhash_wh_free(&a->whlist);
++ a->whlist.nh_num = 0;
++ }
++ }
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * simple tests for rename.
++ * following the checks in vfs, plus the parent-child relationship.
++ */
++static int au_may_ren(struct au_ren_args *a)
++{
++ int err, isdir;
++ struct inode *h_inode;
++
++ if (a->src_bstart == a->btgt) {
++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent,
++ au_ftest_ren(a->flags, ISDIR));
++ if (unlikely(err))
++ goto out;
++ err = -EINVAL;
++ if (unlikely(a->src_h_dentry == a->h_trap))
++ goto out;
++ }
++
++ err = 0;
++ if (a->dst_bstart != a->btgt)
++ goto out;
++
++ err = -EIO;
++ h_inode = a->dst_h_dentry->d_inode;
++ isdir = !!au_ftest_ren(a->flags, ISDIR);
++ if (!a->dst_dentry->d_inode) {
++ if (unlikely(h_inode))
++ goto out;
++ err = au_may_add(a->dst_dentry, a->btgt, a->dst_h_parent,
++ isdir);
++ } else {
++ if (unlikely(!h_inode || !h_inode->i_nlink))
++ goto out;
++ err = au_may_del(a->dst_dentry, a->btgt, a->dst_h_parent,
++ isdir);
++ if (unlikely(err))
++ goto out;
++ err = -ENOTEMPTY;
++ if (unlikely(a->dst_h_dentry == a->h_trap))
++ goto out;
++ err = 0;
++ }
++
++out:
++ if (unlikely(err == -ENOENT || err == -EEXIST))
++ err = -EIO;
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * locking order
++ * (VFS)
++ * - src_dir and dir by lock_rename()
++ * - inode if exitsts
++ * (aufs)
++ * - lock all
++ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls,
++ * + si_read_lock
++ * + di_write_lock2_child()
++ * + di_write_lock_child()
++ * + ii_write_lock_child()
++ * + di_write_lock_child2()
++ * + ii_write_lock_child2()
++ * + src_parent and parent
++ * + di_write_lock_parent()
++ * + ii_write_lock_parent()
++ * + di_write_lock_parent2()
++ * + ii_write_lock_parent2()
++ * + lower src_dir and dir by vfsub_lock_rename()
++ * + verify the every relationships between child and parent. if any
++ * of them failed, unlock all and return -EBUSY.
++ */
++static void au_ren_unlock(struct au_ren_args *a)
++{
++ struct super_block *sb;
++
++ sb = a->dst_dentry->d_sb;
++ if (au_ftest_ren(a->flags, MNT_WRITE))
++ mnt_drop_write(a->br->br_mnt);
++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir,
++ a->dst_h_parent, a->dst_hdir);
++}
++
++static int au_ren_lock(struct au_ren_args *a)
++{
++ int err;
++ unsigned int udba;
++
++ err = 0;
++ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt);
++ a->src_hdir = au_hi(a->src_dir, a->btgt);
++ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt);
++ a->dst_hdir = au_hi(a->dst_dir, a->btgt);
++ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir,
++ a->dst_h_parent, a->dst_hdir);
++ udba = au_opt_udba(a->src_dentry->d_sb);
++ if (unlikely(a->src_hdir->hi_inode != a->src_h_parent->d_inode
++ || a->dst_hdir->hi_inode != a->dst_h_parent->d_inode))
++ err = au_busy_or_stale();
++ if (!err && au_dbstart(a->src_dentry) == a->btgt)
++ err = au_h_verify(a->src_h_dentry, udba,
++ a->src_h_parent->d_inode, a->src_h_parent,
++ a->br);
++ if (!err && au_dbstart(a->dst_dentry) == a->btgt)
++ err = au_h_verify(a->dst_h_dentry, udba,
++ a->dst_h_parent->d_inode, a->dst_h_parent,
++ a->br);
++ if (!err) {
++ err = mnt_want_write(a->br->br_mnt);
++ if (unlikely(err))
++ goto out_unlock;
++ au_fset_ren(a->flags, MNT_WRITE);
++ goto out; /* success */
++ }
++
++ err = au_busy_or_stale();
++
++out_unlock:
++ au_ren_unlock(a);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void au_ren_refresh_dir(struct au_ren_args *a)
++{
++ struct inode *dir;
++
++ dir = a->dst_dir;
++ dir->i_version++;
++ if (au_ftest_ren(a->flags, ISDIR)) {
++ /* is this updating defined in POSIX? */
++ au_cpup_attr_timesizes(a->src_inode);
++ au_cpup_attr_nlink(dir, /*force*/1);
++ }
++
++ if (au_ibstart(dir) == a->btgt)
++ au_cpup_attr_timesizes(dir);
++
++ if (au_ftest_ren(a->flags, ISSAMEDIR))
++ return;
++
++ dir = a->src_dir;
++ dir->i_version++;
++ if (au_ftest_ren(a->flags, ISDIR))
++ au_cpup_attr_nlink(dir, /*force*/1);
++ if (au_ibstart(dir) == a->btgt)
++ au_cpup_attr_timesizes(dir);
++}
++
++static void au_ren_refresh(struct au_ren_args *a)
++{
++ aufs_bindex_t bend, bindex;
++ struct dentry *d, *h_d;
++ struct inode *i, *h_i;
++ struct super_block *sb;
++
++ d = a->dst_dentry;
++ d_drop(d);
++ if (a->h_dst)
++ /* already dget-ed by au_ren_or_cpup() */
++ au_set_h_dptr(d, a->btgt, a->h_dst);
++
++ i = a->dst_inode;
++ if (i) {
++ if (!au_ftest_ren(a->flags, ISDIR))
++ vfsub_drop_nlink(i);
++ else {
++ vfsub_dead_dir(i);
++ au_cpup_attr_timesizes(i);
++ }
++ au_update_dbrange(d, /*do_put_zero*/1);
++ } else {
++ bend = a->btgt;
++ for (bindex = au_dbstart(d); bindex < bend; bindex++)
++ au_set_h_dptr(d, bindex, NULL);
++ bend = au_dbend(d);
++ for (bindex = a->btgt + 1; bindex <= bend; bindex++)
++ au_set_h_dptr(d, bindex, NULL);
++ au_update_dbrange(d, /*do_put_zero*/0);
++ }
++
++ d = a->src_dentry;
++ au_set_dbwh(d, -1);
++ bend = au_dbend(d);
++ for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
++ h_d = au_h_dptr(d, bindex);
++ if (h_d)
++ au_set_h_dptr(d, bindex, NULL);
++ }
++ au_set_dbend(d, a->btgt);
++
++ sb = d->d_sb;
++ i = a->src_inode;
++ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i))
++ return; /* success */
++
++ bend = au_ibend(i);
++ for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
++ h_i = au_h_iptr(i, bindex);
++ if (h_i) {
++ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0);
++ /* ignore this error */
++ au_set_h_iptr(i, bindex, NULL, 0);
++ }
++ }
++ au_set_ibend(i, a->btgt);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* mainly for link(2) and rename(2) */
++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt)
++{
++ aufs_bindex_t bdiropq, bwh;
++ struct dentry *parent;
++ struct au_branch *br;
++
++ parent = dentry->d_parent;
++ IMustLock(parent->d_inode); /* dir is locked */
++
++ bdiropq = au_dbdiropq(parent);
++ bwh = au_dbwh(dentry);
++ br = au_sbr(dentry->d_sb, btgt);
++ if (au_br_rdonly(br)
++ || (0 <= bdiropq && bdiropq < btgt)
++ || (0 <= bwh && bwh < btgt))
++ btgt = -1;
++
++ AuDbg("btgt %d\n", btgt);
++ return btgt;
++}
++
++/* sets src_bstart, dst_bstart and btgt */
++static int au_ren_wbr(struct au_ren_args *a)
++{
++ int err;
++ struct au_wr_dir_args wr_dir_args = {
++ /* .force_btgt = -1, */
++ .flags = AuWrDir_ADD_ENTRY
++ };
++
++ a->src_bstart = au_dbstart(a->src_dentry);
++ a->dst_bstart = au_dbstart(a->dst_dentry);
++ if (au_ftest_ren(a->flags, ISDIR))
++ au_fset_wrdir(wr_dir_args.flags, ISDIR);
++ wr_dir_args.force_btgt = a->src_bstart;
++ if (a->dst_inode && a->dst_bstart < a->src_bstart)
++ wr_dir_args.force_btgt = a->dst_bstart;
++ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt);
++ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args);
++ a->btgt = err;
++
++ return err;
++}
++
++static void au_ren_dt(struct au_ren_args *a)
++{
++ a->h_path.dentry = a->src_h_parent;
++ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path);
++ if (!au_ftest_ren(a->flags, ISSAMEDIR)) {
++ a->h_path.dentry = a->dst_h_parent;
++ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path);
++ }
++
++ au_fclr_ren(a->flags, DT_DSTDIR);
++ if (!au_ftest_ren(a->flags, ISDIR))
++ return;
++
++ a->h_path.dentry = a->src_h_dentry;
++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path);
++ if (a->dst_h_dentry->d_inode) {
++ au_fset_ren(a->flags, DT_DSTDIR);
++ a->h_path.dentry = a->dst_h_dentry;
++ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path);
++ }
++}
++
++static void au_ren_rev_dt(int err, struct au_ren_args *a)
++{
++ struct dentry *h_d;
++ struct mutex *h_mtx;
++
++ au_dtime_revert(a->src_dt + AuPARENT);
++ if (!au_ftest_ren(a->flags, ISSAMEDIR))
++ au_dtime_revert(a->dst_dt + AuPARENT);
++
++ if (au_ftest_ren(a->flags, ISDIR) && err != -EIO) {
++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry;
++ h_mtx = &h_d->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ au_dtime_revert(a->src_dt + AuCHILD);
++ mutex_unlock(h_mtx);
++
++ if (au_ftest_ren(a->flags, DT_DSTDIR)) {
++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry;
++ h_mtx = &h_d->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ au_dtime_revert(a->dst_dt + AuCHILD);
++ mutex_unlock(h_mtx);
++ }
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry,
++ struct inode *_dst_dir, struct dentry *_dst_dentry)
++{
++ int err, flags;
++ /* reduce stack space */
++ struct au_ren_args *a;
++
++ AuDbg("%.*s, %.*s\n", AuDLNPair(_src_dentry), AuDLNPair(_dst_dentry));
++ IMustLock(_src_dir);
++ IMustLock(_dst_dir);
++
++ err = -ENOMEM;
++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE);
++ a = kzalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ a->src_dir = _src_dir;
++ a->src_dentry = _src_dentry;
++ a->src_inode = a->src_dentry->d_inode;
++ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */
++ a->dst_dir = _dst_dir;
++ a->dst_dentry = _dst_dentry;
++ a->dst_inode = a->dst_dentry->d_inode;
++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */
++ if (a->dst_inode) {
++ IMustLock(a->dst_inode);
++ au_igrab(a->dst_inode);
++ }
++
++ err = -ENOTDIR;
++ flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN;
++ if (S_ISDIR(a->src_inode->i_mode)) {
++ au_fset_ren(a->flags, ISDIR);
++ if (unlikely(a->dst_inode && !S_ISDIR(a->dst_inode->i_mode)))
++ goto out_free;
++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry,
++ AuLock_DIR | flags);
++ } else
++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry,
++ flags);
++ if (unlikely(err))
++ goto out_free;
++
++ err = au_d_hashed_positive(a->src_dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ err = -ENOENT;
++ if (a->dst_inode) {
++ /*
++ * If it is a dir, VFS unhash dst_dentry before this
++ * function. It means we cannot rely upon d_unhashed().
++ */
++ if (unlikely(!a->dst_inode->i_nlink))
++ goto out_unlock;
++ if (!S_ISDIR(a->dst_inode->i_mode)) {
++ err = au_d_hashed_positive(a->dst_dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ } else if (unlikely(IS_DEADDIR(a->dst_inode)))
++ goto out_unlock;
++ } else if (unlikely(d_unhashed(a->dst_dentry)))
++ goto out_unlock;
++
++ au_fset_ren(a->flags, ISSAMEDIR); /* temporary */
++ di_write_lock_parent(a->dst_parent);
++
++ /* which branch we process */
++ err = au_ren_wbr(a);
++ if (unlikely(err < 0))
++ goto out_parent;
++ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt);
++ a->h_path.mnt = a->br->br_mnt;
++
++ /* are they available to be renamed */
++ err = au_ren_may_dir(a);
++ if (unlikely(err))
++ goto out_children;
++
++ /* prepare the writable parent dir on the same branch */
++ if (a->dst_bstart == a->btgt) {
++ au_fset_ren(a->flags, WHDST);
++ } else {
++ err = au_cpup_dirs(a->dst_dentry, a->btgt);
++ if (unlikely(err))
++ goto out_children;
++ }
++
++ if (a->src_dir != a->dst_dir) {
++ /*
++ * this temporary unlock is safe,
++ * because both dir->i_mutex are locked.
++ */
++ di_write_unlock(a->dst_parent);
++ di_write_lock_parent(a->src_parent);
++ err = au_wr_dir_need_wh(a->src_dentry,
++ au_ftest_ren(a->flags, ISDIR),
++ &a->btgt);
++ di_write_unlock(a->src_parent);
++ di_write_lock2_parent(a->src_parent, a->dst_parent, /*isdir*/1);
++ au_fclr_ren(a->flags, ISSAMEDIR);
++ } else
++ err = au_wr_dir_need_wh(a->src_dentry,
++ au_ftest_ren(a->flags, ISDIR),
++ &a->btgt);
++ if (unlikely(err < 0))
++ goto out_children;
++ if (err)
++ au_fset_ren(a->flags, WHSRC);
++
++ /* lock them all */
++ err = au_ren_lock(a);
++ if (unlikely(err))
++ goto out_children;
++
++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE))
++ err = au_may_ren(a);
++ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN))
++ err = -ENAMETOOLONG;
++ if (unlikely(err))
++ goto out_hdir;
++
++ /* store timestamps to be revertible */
++ au_ren_dt(a);
++
++ /* here we go */
++ err = do_rename(a);
++ if (unlikely(err))
++ goto out_dt;
++
++ /* update dir attributes */
++ au_ren_refresh_dir(a);
++
++ /* dput/iput all lower dentries */
++ au_ren_refresh(a);
++
++ goto out_hdir; /* success */
++
++out_dt:
++ au_ren_rev_dt(err, a);
++out_hdir:
++ au_ren_unlock(a);
++out_children:
++ au_nhash_wh_free(&a->whlist);
++ if (err && a->dst_inode && a->dst_bstart != a->btgt) {
++ AuDbg("bstart %d, btgt %d\n", a->dst_bstart, a->btgt);
++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL);
++ au_set_dbstart(a->dst_dentry, a->dst_bstart);
++ }
++out_parent:
++ if (!err)
++ d_move(a->src_dentry, a->dst_dentry);
++ else {
++ au_update_dbstart(a->dst_dentry);
++ if (!a->dst_inode)
++ d_drop(a->dst_dentry);
++ }
++ if (au_ftest_ren(a->flags, ISSAMEDIR))
++ di_write_unlock(a->dst_parent);
++ else
++ di_write_unlock2(a->src_parent, a->dst_parent);
++out_unlock:
++ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry);
++out_free:
++ iput(a->dst_inode);
++ if (a->thargs)
++ au_whtmp_rmdir_free(a->thargs);
++ kfree(a);
++out:
++ AuTraceErr(err);
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/iinfo.c linux-2.6.36/fs/aufs/iinfo.c
+--- linux-2.6.36.orig/fs/aufs/iinfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/iinfo.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,263 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode private data
++ */
++
++#include "aufs.h"
++
++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex)
++{
++ struct inode *h_inode;
++
++ IiMustAnyLock(inode);
++
++ h_inode = au_ii(inode)->ii_hinode[0 + bindex].hi_inode;
++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0);
++ return h_inode;
++}
++
++/* todo: hard/soft set? */
++void au_hiput(struct au_hinode *hinode)
++{
++ au_hn_free(hinode);
++ dput(hinode->hi_whdentry);
++ iput(hinode->hi_inode);
++}
++
++unsigned int au_hi_flags(struct inode *inode, int isdir)
++{
++ unsigned int flags;
++ const unsigned int mnt_flags = au_mntflags(inode->i_sb);
++
++ flags = 0;
++ if (au_opt_test(mnt_flags, XINO))
++ au_fset_hi(flags, XINO);
++ if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY))
++ au_fset_hi(flags, HNOTIFY);
++ return flags;
++}
++
++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
++ struct inode *h_inode, unsigned int flags)
++{
++ struct au_hinode *hinode;
++ struct inode *hi;
++ struct au_iinfo *iinfo = au_ii(inode);
++
++ IiMustWriteLock(inode);
++
++ hinode = iinfo->ii_hinode + bindex;
++ hi = hinode->hi_inode;
++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0);
++
++ if (hi)
++ au_hiput(hinode);
++ hinode->hi_inode = h_inode;
++ if (h_inode) {
++ int err;
++ struct super_block *sb = inode->i_sb;
++ struct au_branch *br;
++
++ AuDebugOn(inode->i_mode
++ && (h_inode->i_mode & S_IFMT)
++ != (inode->i_mode & S_IFMT));
++ if (bindex == iinfo->ii_bstart)
++ au_cpup_igen(inode, h_inode);
++ br = au_sbr(sb, bindex);
++ hinode->hi_id = br->br_id;
++ if (au_ftest_hi(flags, XINO)) {
++ err = au_xino_write(sb, bindex, h_inode->i_ino,
++ inode->i_ino);
++ if (unlikely(err))
++ AuIOErr1("failed au_xino_write() %d\n", err);
++ }
++
++ if (au_ftest_hi(flags, HNOTIFY)
++ && au_br_hnotifyable(br->br_perm)) {
++ err = au_hn_alloc(hinode, inode);
++ if (unlikely(err))
++ AuIOErr1("au_hn_alloc() %d\n", err);
++ }
++ }
++}
++
++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_wh)
++{
++ struct au_hinode *hinode;
++
++ IiMustWriteLock(inode);
++
++ hinode = au_ii(inode)->ii_hinode + bindex;
++ AuDebugOn(hinode->hi_whdentry);
++ hinode->hi_whdentry = h_wh;
++}
++
++void au_update_iigen(struct inode *inode)
++{
++ atomic_set(&au_ii(inode)->ii_generation, au_sigen(inode->i_sb));
++ /* smp_mb(); */ /* atomic_set */
++}
++
++/* it may be called at remount time, too */
++void au_update_ibrange(struct inode *inode, int do_put_zero)
++{
++ struct au_iinfo *iinfo;
++ aufs_bindex_t bindex, bend;
++
++ iinfo = au_ii(inode);
++ if (!iinfo)
++ return;
++
++ IiMustWriteLock(inode);
++
++ if (do_put_zero && iinfo->ii_bstart >= 0) {
++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
++ bindex++) {
++ struct inode *h_i;
++
++ h_i = iinfo->ii_hinode[0 + bindex].hi_inode;
++ if (h_i && !h_i->i_nlink)
++ au_set_h_iptr(inode, bindex, NULL, 0);
++ }
++ }
++
++ iinfo->ii_bstart = -1;
++ iinfo->ii_bend = -1;
++ bend = au_sbend(inode->i_sb);
++ for (bindex = 0; bindex <= bend; bindex++)
++ if (iinfo->ii_hinode[0 + bindex].hi_inode) {
++ iinfo->ii_bstart = bindex;
++ break;
++ }
++ if (iinfo->ii_bstart >= 0)
++ for (bindex = bend; bindex >= iinfo->ii_bstart; bindex--)
++ if (iinfo->ii_hinode[0 + bindex].hi_inode) {
++ iinfo->ii_bend = bindex;
++ break;
++ }
++ AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend);
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_icntnr_init_once(void *_c)
++{
++ struct au_icntnr *c = _c;
++ struct au_iinfo *iinfo = &c->iinfo;
++ static struct lock_class_key aufs_ii;
++
++ au_rw_init(&iinfo->ii_rwsem);
++ au_rw_class(&iinfo->ii_rwsem, &aufs_ii);
++ inode_init_once(&c->vfs_inode);
++}
++
++int au_iinfo_init(struct inode *inode)
++{
++ struct au_iinfo *iinfo;
++ struct super_block *sb;
++ int nbr, i;
++
++ sb = inode->i_sb;
++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo);
++ nbr = au_sbend(sb) + 1;
++ if (unlikely(nbr <= 0))
++ nbr = 1;
++ iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS);
++ if (iinfo->ii_hinode) {
++ au_ninodes_inc(sb);
++ for (i = 0; i < nbr; i++)
++ iinfo->ii_hinode[i].hi_id = -1;
++
++ atomic_set(&iinfo->ii_generation, au_sigen(sb));
++ /* smp_mb(); */ /* atomic_set */
++ iinfo->ii_bstart = -1;
++ iinfo->ii_bend = -1;
++ iinfo->ii_vdir = NULL;
++ return 0;
++ }
++ return -ENOMEM;
++}
++
++int au_ii_realloc(struct au_iinfo *iinfo, int nbr)
++{
++ int err, sz;
++ struct au_hinode *hip;
++
++ AuRwMustWriteLock(&iinfo->ii_rwsem);
++
++ err = -ENOMEM;
++ sz = sizeof(*hip) * (iinfo->ii_bend + 1);
++ if (!sz)
++ sz = sizeof(*hip);
++ hip = au_kzrealloc(iinfo->ii_hinode, sz, sizeof(*hip) * nbr, GFP_NOFS);
++ if (hip) {
++ iinfo->ii_hinode = hip;
++ err = 0;
++ }
++
++ return err;
++}
++
++void au_iinfo_fin(struct inode *inode)
++{
++ struct au_iinfo *iinfo;
++ struct au_hinode *hi;
++ struct super_block *sb;
++ aufs_bindex_t bindex, bend;
++ const unsigned char unlinked = !inode->i_nlink;
++
++ iinfo = au_ii(inode);
++ /* bad_inode case */
++ if (!iinfo)
++ return;
++
++ sb = inode->i_sb;
++ au_ninodes_dec(sb);
++ if (si_pid_test(sb))
++ au_xino_delete_inode(inode, unlinked);
++ else {
++ /*
++ * it is safe to hide the dependency between sbinfo and
++ * sb->s_umount.
++ */
++ lockdep_off();
++ si_noflush_read_lock(sb);
++ au_xino_delete_inode(inode, unlinked);
++ si_read_unlock(sb);
++ lockdep_on();
++ }
++
++ if (iinfo->ii_vdir)
++ au_vdir_free(iinfo->ii_vdir);
++
++ bindex = iinfo->ii_bstart;
++ if (bindex >= 0) {
++ hi = iinfo->ii_hinode + bindex;
++ bend = iinfo->ii_bend;
++ while (bindex++ <= bend) {
++ if (hi->hi_inode)
++ au_hiput(hi);
++ hi++;
++ }
++ }
++ kfree(iinfo->ii_hinode);
++ AuRwDestroy(&iinfo->ii_rwsem);
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/inode.c linux-2.6.36/fs/aufs/inode.c
+--- linux-2.6.36.orig/fs/aufs/inode.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/inode.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,471 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode functions
++ */
++
++#include "aufs.h"
++
++struct inode *au_igrab(struct inode *inode)
++{
++ if (inode) {
++ AuDebugOn(!atomic_read(&inode->i_count));
++ atomic_inc(&inode->i_count);
++ }
++ return inode;
++}
++
++static void au_refresh_hinode_attr(struct inode *inode, int do_version)
++{
++ au_cpup_attr_all(inode, /*force*/0);
++ au_update_iigen(inode);
++ if (do_version)
++ inode->i_version++;
++}
++
++static int au_ii_refresh(struct inode *inode, int *update)
++{
++ int err, e;
++ umode_t type;
++ aufs_bindex_t bindex, new_bindex;
++ struct super_block *sb;
++ struct au_iinfo *iinfo;
++ struct au_hinode *p, *q, tmp;
++
++ IiMustWriteLock(inode);
++
++ *update = 0;
++ sb = inode->i_sb;
++ type = inode->i_mode & S_IFMT;
++ iinfo = au_ii(inode);
++ err = au_ii_realloc(iinfo, au_sbend(sb) + 1);
++ if (unlikely(err))
++ goto out;
++
++ AuDebugOn(iinfo->ii_bstart < 0);
++ p = iinfo->ii_hinode + iinfo->ii_bstart;
++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
++ bindex++, p++) {
++ if (!p->hi_inode)
++ continue;
++
++ AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT));
++ new_bindex = au_br_index(sb, p->hi_id);
++ if (new_bindex == bindex)
++ continue;
++
++ if (new_bindex < 0) {
++ *update = 1;
++ au_hiput(p);
++ p->hi_inode = NULL;
++ continue;
++ }
++
++ if (new_bindex < iinfo->ii_bstart)
++ iinfo->ii_bstart = new_bindex;
++ if (iinfo->ii_bend < new_bindex)
++ iinfo->ii_bend = new_bindex;
++ /* swap two lower inode, and loop again */
++ q = iinfo->ii_hinode + new_bindex;
++ tmp = *q;
++ *q = *p;
++ *p = tmp;
++ if (tmp.hi_inode) {
++ bindex--;
++ p--;
++ }
++ }
++ au_update_ibrange(inode, /*do_put_zero*/0);
++ e = au_dy_irefresh(inode);
++ if (unlikely(e && !err))
++ err = e;
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++int au_refresh_hinode_self(struct inode *inode)
++{
++ int err, update;
++
++ err = au_ii_refresh(inode, &update);
++ if (!err)
++ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode));
++
++ AuTraceErr(err);
++ return err;
++}
++
++int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
++{
++ int err, e, update;
++ unsigned int flags;
++ umode_t mode;
++ aufs_bindex_t bindex, bend;
++ unsigned char isdir;
++ struct au_hinode *p;
++ struct au_iinfo *iinfo;
++
++ err = au_ii_refresh(inode, &update);
++ if (unlikely(err))
++ goto out;
++
++ update = 0;
++ iinfo = au_ii(inode);
++ p = iinfo->ii_hinode + iinfo->ii_bstart;
++ mode = (inode->i_mode & S_IFMT);
++ isdir = S_ISDIR(mode);
++ flags = au_hi_flags(inode, isdir);
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
++ struct inode *h_i;
++ struct dentry *h_d;
++
++ h_d = au_h_dptr(dentry, bindex);
++ if (!h_d || !h_d->d_inode)
++ continue;
++
++ AuDebugOn(mode != (h_d->d_inode->i_mode & S_IFMT));
++ if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) {
++ h_i = au_h_iptr(inode, bindex);
++ if (h_i) {
++ if (h_i == h_d->d_inode)
++ continue;
++ err = -EIO;
++ break;
++ }
++ }
++ if (bindex < iinfo->ii_bstart)
++ iinfo->ii_bstart = bindex;
++ if (iinfo->ii_bend < bindex)
++ iinfo->ii_bend = bindex;
++ au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags);
++ update = 1;
++ }
++ au_update_ibrange(inode, /*do_put_zero*/0);
++ e = au_dy_irefresh(inode);
++ if (unlikely(e && !err))
++ err = e;
++ if (!err)
++ au_refresh_hinode_attr(inode, update && isdir);
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int set_inode(struct inode *inode, struct dentry *dentry)
++{
++ int err;
++ unsigned int flags;
++ umode_t mode;
++ aufs_bindex_t bindex, bstart, btail;
++ unsigned char isdir;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++ struct au_iinfo *iinfo;
++
++ IiMustWriteLock(inode);
++
++ err = 0;
++ isdir = 0;
++ bstart = au_dbstart(dentry);
++ h_inode = au_h_dptr(dentry, bstart)->d_inode;
++ mode = h_inode->i_mode;
++ switch (mode & S_IFMT) {
++ case S_IFREG:
++ btail = au_dbtail(dentry);
++ inode->i_op = &aufs_iop;
++ inode->i_fop = &aufs_file_fop;
++ err = au_dy_iaop(inode, bstart, h_inode);
++ if (unlikely(err))
++ goto out;
++ break;
++ case S_IFDIR:
++ isdir = 1;
++ btail = au_dbtaildir(dentry);
++ inode->i_op = &aufs_dir_iop;
++ inode->i_fop = &aufs_dir_fop;
++ break;
++ case S_IFLNK:
++ btail = au_dbtail(dentry);
++ inode->i_op = &aufs_symlink_iop;
++ break;
++ case S_IFBLK:
++ case S_IFCHR:
++ case S_IFIFO:
++ case S_IFSOCK:
++ btail = au_dbtail(dentry);
++ inode->i_op = &aufs_iop;
++ au_init_special_fop(inode, mode, h_inode->i_rdev);
++ break;
++ default:
++ AuIOErr("Unknown file type 0%o\n", mode);
++ err = -EIO;
++ goto out;
++ }
++
++ /* do not set hnotify for whiteouted dirs (SHWH mode) */
++ flags = au_hi_flags(inode, isdir);
++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)
++ && au_ftest_hi(flags, HNOTIFY)
++ && dentry->d_name.len > AUFS_WH_PFX_LEN
++ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))
++ au_fclr_hi(flags, HNOTIFY);
++ iinfo = au_ii(inode);
++ iinfo->ii_bstart = bstart;
++ iinfo->ii_bend = btail;
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry)
++ au_set_h_iptr(inode, bindex,
++ au_igrab(h_dentry->d_inode), flags);
++ }
++ au_cpup_attr_all(inode, /*force*/1);
++
++out:
++ return err;
++}
++
++/*
++ * successful returns with iinfo write_locked
++ * minus: errno
++ * zero: success, matched
++ * plus: no error, but unmatched
++ */
++static int reval_inode(struct inode *inode, struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct inode *h_inode, *h_dinode;
++
++ /*
++ * before this function, if aufs got any iinfo lock, it must be only
++ * one, the parent dir.
++ * it can happen by UDBA and the obsoleted inode number.
++ */
++ err = -EIO;
++ if (unlikely(inode->i_ino == parent_ino(dentry)))
++ goto out;
++
++ err = 1;
++ ii_write_lock_new_child(inode);
++ h_dinode = au_h_dptr(dentry, au_dbstart(dentry))->d_inode;
++ bend = au_ibend(inode);
++ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
++ h_inode = au_h_iptr(inode, bindex);
++ if (h_inode && h_inode == h_dinode) {
++ err = 0;
++ if (au_iigen_test(inode, au_digen(dentry)))
++ err = au_refresh_hinode(inode, dentry);
++ break;
++ }
++ }
++
++ if (unlikely(err))
++ ii_write_unlock(inode);
++out:
++ return err;
++}
++
++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ unsigned int d_type, ino_t *ino)
++{
++ int err;
++ struct mutex *mtx;
++
++ /* prevent hardlinked inode number from race condition */
++ mtx = NULL;
++ if (d_type != DT_DIR) {
++ mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx;
++ mutex_lock(mtx);
++ }
++ err = au_xino_read(sb, bindex, h_ino, ino);
++ if (unlikely(err))
++ goto out;
++
++ if (!*ino) {
++ err = -EIO;
++ *ino = au_xino_new_ino(sb);
++ if (unlikely(!*ino))
++ goto out;
++ err = au_xino_write(sb, bindex, h_ino, *ino);
++ if (unlikely(err))
++ goto out;
++ }
++
++out:
++ if (mtx)
++ mutex_unlock(mtx);
++ return err;
++}
++
++/* successful returns with iinfo write_locked */
++/* todo: return with unlocked? */
++struct inode *au_new_inode(struct dentry *dentry, int must_new)
++{
++ struct inode *inode, *h_inode;
++ struct dentry *h_dentry;
++ struct super_block *sb;
++ struct mutex *mtx;
++ ino_t h_ino, ino;
++ int err;
++ aufs_bindex_t bstart;
++
++ sb = dentry->d_sb;
++ bstart = au_dbstart(dentry);
++ h_dentry = au_h_dptr(dentry, bstart);
++ h_inode = h_dentry->d_inode;
++ h_ino = h_inode->i_ino;
++
++ /*
++ * stop 'race'-ing between hardlinks under different
++ * parents.
++ */
++ mtx = NULL;
++ if (!S_ISDIR(h_inode->i_mode))
++ mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx;
++
++new_ino:
++ if (mtx)
++ mutex_lock(mtx);
++ err = au_xino_read(sb, bstart, h_ino, &ino);
++ inode = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ if (!ino) {
++ ino = au_xino_new_ino(sb);
++ if (unlikely(!ino)) {
++ inode = ERR_PTR(-EIO);
++ goto out;
++ }
++ }
++
++ AuDbg("i%lu\n", (unsigned long)ino);
++ inode = au_iget_locked(sb, ino);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out;
++
++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW));
++ if (inode->i_state & I_NEW) {
++ ii_write_lock_new_child(inode);
++ err = set_inode(inode, dentry);
++ if (!err) {
++ unlock_new_inode(inode);
++ goto out; /* success */
++ }
++
++ /*
++ * iget_failed() calls iput(), but we need to call
++ * ii_write_unlock() after iget_failed(). so dirty hack for
++ * i_count.
++ */
++ atomic_inc(&inode->i_count);
++ iget_failed(inode);
++ ii_write_unlock(inode);
++ au_xino_write(sb, bstart, h_ino, /*ino*/0);
++ /* ignore this error */
++ goto out_iput;
++ } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) {
++ /*
++ * horrible race condition between lookup, readdir and copyup
++ * (or something).
++ */
++ if (mtx)
++ mutex_unlock(mtx);
++ err = reval_inode(inode, dentry);
++ if (unlikely(err < 0)) {
++ mtx = NULL;
++ goto out_iput;
++ }
++
++ if (!err) {
++ mtx = NULL;
++ goto out; /* success */
++ } else if (mtx)
++ mutex_lock(mtx);
++ }
++
++ if (unlikely(au_test_fs_unique_ino(h_dentry->d_inode)))
++ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir,"
++ " b%d, %s, %.*s, hi%lu, i%lu.\n",
++ bstart, au_sbtype(h_dentry->d_sb), AuDLNPair(dentry),
++ (unsigned long)h_ino, (unsigned long)ino);
++ ino = 0;
++ err = au_xino_write(sb, bstart, h_ino, /*ino*/0);
++ if (!err) {
++ iput(inode);
++ if (mtx)
++ mutex_unlock(mtx);
++ goto new_ino;
++ }
++
++out_iput:
++ iput(inode);
++ inode = ERR_PTR(err);
++out:
++ if (mtx)
++ mutex_unlock(mtx);
++ return inode;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
++ struct inode *inode)
++{
++ int err;
++
++ err = au_br_rdonly(au_sbr(sb, bindex));
++
++ /* pseudo-link after flushed may happen out of bounds */
++ if (!err
++ && inode
++ && au_ibstart(inode) <= bindex
++ && bindex <= au_ibend(inode)) {
++ /*
++ * permission check is unnecessary since vfsub routine
++ * will be called later
++ */
++ struct inode *hi = au_h_iptr(inode, bindex);
++ if (hi)
++ err = IS_IMMUTABLE(hi) ? -EROFS : 0;
++ }
++
++ return err;
++}
++
++int au_test_h_perm(struct inode *h_inode, int mask)
++{
++ if (!current_fsuid())
++ return 0;
++ return inode_permission(h_inode, mask);
++}
++
++int au_test_h_perm_sio(struct inode *h_inode, int mask)
++{
++ if (au_test_nfs(h_inode->i_sb)
++ && (mask & MAY_WRITE)
++ && S_ISDIR(h_inode->i_mode))
++ mask |= MAY_READ; /* force permission check */
++ return au_test_h_perm(h_inode, mask);
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/inode.h linux-2.6.36/fs/aufs/inode.h
+--- linux-2.6.36.orig/fs/aufs/inode.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/inode.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,546 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode operations
++ */
++
++#ifndef __AUFS_INODE_H__
++#define __AUFS_INODE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/fsnotify.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++
++struct vfsmount;
++
++struct au_hnotify {
++#ifdef CONFIG_AUFS_HNOTIFY
++#ifdef CONFIG_AUFS_HFSNOTIFY
++ /* never use fsnotify_add_vfsmount_mark() */
++ struct fsnotify_mark hn_mark;
++ int hn_mark_dead;
++#endif
++ struct inode *hn_aufs_inode; /* no get/put */
++#endif
++} ____cacheline_aligned_in_smp;
++
++struct au_hinode {
++ struct inode *hi_inode;
++ aufs_bindex_t hi_id;
++#ifdef CONFIG_AUFS_HNOTIFY
++ struct au_hnotify *hi_notify;
++#endif
++
++ /* reference to the copied-up whiteout with get/put */
++ struct dentry *hi_whdentry;
++};
++
++struct au_vdir;
++struct au_iinfo {
++ atomic_t ii_generation;
++ struct super_block *ii_hsb1; /* no get/put */
++
++ struct au_rwsem ii_rwsem;
++ aufs_bindex_t ii_bstart, ii_bend;
++ __u32 ii_higen;
++ struct au_hinode *ii_hinode;
++ struct au_vdir *ii_vdir;
++};
++
++struct au_icntnr {
++ struct au_iinfo iinfo;
++ struct inode vfs_inode;
++} ____cacheline_aligned_in_smp;
++
++/* au_pin flags */
++#define AuPin_DI_LOCKED 1
++#define AuPin_MNT_WRITE (1 << 1)
++#define au_ftest_pin(flags, name) ((flags) & AuPin_##name)
++#define au_fset_pin(flags, name) \
++ do { (flags) |= AuPin_##name; } while (0)
++#define au_fclr_pin(flags, name) \
++ do { (flags) &= ~AuPin_##name; } while (0)
++
++struct au_pin {
++ /* input */
++ struct dentry *dentry;
++ unsigned int udba;
++ unsigned char lsc_di, lsc_hi, flags;
++ aufs_bindex_t bindex;
++
++ /* output */
++ struct dentry *parent;
++ struct au_hinode *hdir;
++ struct vfsmount *h_mnt;
++};
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_iinfo *au_ii(struct inode *inode)
++{
++ struct au_iinfo *iinfo;
++
++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo);
++ if (iinfo->ii_hinode)
++ return iinfo;
++ return NULL; /* debugging bad_inode case */
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* inode.c */
++struct inode *au_igrab(struct inode *inode);
++int au_refresh_hinode_self(struct inode *inode);
++int au_refresh_hinode(struct inode *inode, struct dentry *dentry);
++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ unsigned int d_type, ino_t *ino);
++struct inode *au_new_inode(struct dentry *dentry, int must_new);
++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
++ struct inode *inode);
++int au_test_h_perm(struct inode *h_inode, int mask);
++int au_test_h_perm_sio(struct inode *h_inode, int mask);
++
++static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex,
++ ino_t h_ino, unsigned int d_type, ino_t *ino)
++{
++#ifdef CONFIG_AUFS_SHWH
++ return au_ino(sb, bindex, h_ino, d_type, ino);
++#else
++ return 0;
++#endif
++}
++
++/* i_op.c */
++extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop;
++
++/* au_wr_dir flags */
++#define AuWrDir_ADD_ENTRY 1
++#define AuWrDir_ISDIR (1 << 1)
++#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name)
++#define au_fset_wrdir(flags, name) \
++ do { (flags) |= AuWrDir_##name; } while (0)
++#define au_fclr_wrdir(flags, name) \
++ do { (flags) &= ~AuWrDir_##name; } while (0)
++
++struct au_wr_dir_args {
++ aufs_bindex_t force_btgt;
++ unsigned char flags;
++};
++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry,
++ struct au_wr_dir_args *args);
++
++struct dentry *au_pinned_h_parent(struct au_pin *pin);
++void au_pin_init(struct au_pin *pin, struct dentry *dentry,
++ aufs_bindex_t bindex, int lsc_di, int lsc_hi,
++ unsigned int udba, unsigned char flags);
++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int udba, unsigned char flags) __must_check;
++int au_do_pin(struct au_pin *pin) __must_check;
++void au_unpin(struct au_pin *pin);
++
++/* i_op_add.c */
++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir);
++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev);
++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
++int aufs_create(struct inode *dir, struct dentry *dentry, int mode,
++ struct nameidata *nd);
++int aufs_link(struct dentry *src_dentry, struct inode *dir,
++ struct dentry *dentry);
++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
++
++/* i_op_del.c */
++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup);
++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir);
++int aufs_unlink(struct inode *dir, struct dentry *dentry);
++int aufs_rmdir(struct inode *dir, struct dentry *dentry);
++
++/* i_op_ren.c */
++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt);
++int aufs_rename(struct inode *src_dir, struct dentry *src_dentry,
++ struct inode *dir, struct dentry *dentry);
++
++/* iinfo.c */
++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex);
++void au_hiput(struct au_hinode *hinode);
++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_wh);
++unsigned int au_hi_flags(struct inode *inode, int isdir);
++
++/* hinode flags */
++#define AuHi_XINO 1
++#define AuHi_HNOTIFY (1 << 1)
++#define au_ftest_hi(flags, name) ((flags) & AuHi_##name)
++#define au_fset_hi(flags, name) \
++ do { (flags) |= AuHi_##name; } while (0)
++#define au_fclr_hi(flags, name) \
++ do { (flags) &= ~AuHi_##name; } while (0)
++
++#ifndef CONFIG_AUFS_HNOTIFY
++#undef AuHi_HNOTIFY
++#define AuHi_HNOTIFY 0
++#endif
++
++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
++ struct inode *h_inode, unsigned int flags);
++
++void au_update_iigen(struct inode *inode);
++void au_update_ibrange(struct inode *inode, int do_put_zero);
++
++void au_icntnr_init_once(void *_c);
++int au_iinfo_init(struct inode *inode);
++void au_iinfo_fin(struct inode *inode);
++int au_ii_realloc(struct au_iinfo *iinfo, int nbr);
++
++#ifdef CONFIG_PROC_FS
++/* plink.c */
++int au_plink_maint(struct super_block *sb, int flags);
++void au_plink_maint_leave(struct au_sbinfo *sbinfo);
++int au_plink_maint_enter(struct super_block *sb);
++#ifdef CONFIG_AUFS_DEBUG
++void au_plink_list(struct super_block *sb);
++#else
++AuStubVoid(au_plink_list, struct super_block *sb)
++#endif
++int au_plink_test(struct inode *inode);
++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex);
++void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_dentry);
++void au_plink_put(struct super_block *sb, int verbose);
++void au_plink_clean(struct super_block *sb, int verbose);
++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id);
++#else
++AuStubInt0(au_plink_maint, struct super_block *sb, int flags);
++AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo);
++AuStubInt0(au_plink_maint_enter, struct super_block *sb);
++AuStubVoid(au_plink_list, struct super_block *sb);
++AuStubInt0(au_plink_test, struct inode *inode);
++AuStub(struct dentry *, au_plink_lkup, return NULL,
++ struct inode *inode, aufs_bindex_t bindex);
++AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_dentry);
++AuStubVoid(au_plink_put, struct super_block *sb, int verbose);
++AuStubVoid(au_plink_clean, struct super_block *sb, int verbose);
++AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id);
++#endif /* CONFIG_PROC_FS */
++
++/* ---------------------------------------------------------------------- */
++
++/* lock subclass for iinfo */
++enum {
++ AuLsc_II_CHILD, /* child first */
++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */
++ AuLsc_II_CHILD3, /* copyup dirs */
++ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */
++ AuLsc_II_PARENT2,
++ AuLsc_II_PARENT3, /* copyup dirs */
++ AuLsc_II_NEW_CHILD
++};
++
++/*
++ * ii_read_lock_child, ii_write_lock_child,
++ * ii_read_lock_child2, ii_write_lock_child2,
++ * ii_read_lock_child3, ii_write_lock_child3,
++ * ii_read_lock_parent, ii_write_lock_parent,
++ * ii_read_lock_parent2, ii_write_lock_parent2,
++ * ii_read_lock_parent3, ii_write_lock_parent3,
++ * ii_read_lock_new_child, ii_write_lock_new_child,
++ */
++#define AuReadLockFunc(name, lsc) \
++static inline void ii_read_lock_##name(struct inode *i) \
++{ \
++ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \
++}
++
++#define AuWriteLockFunc(name, lsc) \
++static inline void ii_write_lock_##name(struct inode *i) \
++{ \
++ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \
++}
++
++#define AuRWLockFuncs(name, lsc) \
++ AuReadLockFunc(name, lsc) \
++ AuWriteLockFunc(name, lsc)
++
++AuRWLockFuncs(child, CHILD);
++AuRWLockFuncs(child2, CHILD2);
++AuRWLockFuncs(child3, CHILD3);
++AuRWLockFuncs(parent, PARENT);
++AuRWLockFuncs(parent2, PARENT2);
++AuRWLockFuncs(parent3, PARENT3);
++AuRWLockFuncs(new_child, NEW_CHILD);
++
++#undef AuReadLockFunc
++#undef AuWriteLockFunc
++#undef AuRWLockFuncs
++
++/*
++ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock
++ */
++AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem);
++
++#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem)
++#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem)
++#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem)
++
++/* ---------------------------------------------------------------------- */
++
++static inline void au_icntnr_init(struct au_icntnr *c)
++{
++#ifdef CONFIG_AUFS_DEBUG
++ c->vfs_inode.i_mode = 0;
++#endif
++}
++
++static inline unsigned int au_iigen(struct inode *inode)
++{
++ return atomic_read(&au_ii(inode)->ii_generation);
++}
++
++/* tiny test for inode number */
++/* tmpfs generation is too rough */
++static inline int au_test_higen(struct inode *inode, struct inode *h_inode)
++{
++ struct au_iinfo *iinfo;
++
++ iinfo = au_ii(inode);
++ AuRwMustAnyLock(&iinfo->ii_rwsem);
++ return !(iinfo->ii_hsb1 == h_inode->i_sb
++ && iinfo->ii_higen == h_inode->i_generation);
++}
++
++static inline void au_iigen_dec(struct inode *inode)
++{
++ atomic_dec(&au_ii(inode)->ii_generation);
++}
++
++static inline int au_iigen_test(struct inode *inode, unsigned int sigen)
++{
++ int err;
++
++ err = 0;
++ if (unlikely(inode && au_iigen(inode) != sigen))
++ err = -EIO;
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static inline aufs_bindex_t au_ii_br_id(struct inode *inode,
++ aufs_bindex_t bindex)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_hinode[0 + bindex].hi_id;
++}
++
++static inline aufs_bindex_t au_ibstart(struct inode *inode)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_bstart;
++}
++
++static inline aufs_bindex_t au_ibend(struct inode *inode)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_bend;
++}
++
++static inline struct au_vdir *au_ivdir(struct inode *inode)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_vdir;
++}
++
++static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_hinode[0 + bindex].hi_whdentry;
++}
++
++static inline void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex)
++{
++ IiMustWriteLock(inode);
++ au_ii(inode)->ii_bstart = bindex;
++}
++
++static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex)
++{
++ IiMustWriteLock(inode);
++ au_ii(inode)->ii_bend = bindex;
++}
++
++static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir)
++{
++ IiMustWriteLock(inode);
++ au_ii(inode)->ii_vdir = vdir;
++}
++
++static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_hinode + bindex;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct dentry *au_pinned_parent(struct au_pin *pin)
++{
++ if (pin)
++ return pin->parent;
++ return NULL;
++}
++
++static inline struct inode *au_pinned_h_dir(struct au_pin *pin)
++{
++ if (pin && pin->hdir)
++ return pin->hdir->hi_inode;
++ return NULL;
++}
++
++static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin)
++{
++ if (pin)
++ return pin->hdir;
++ return NULL;
++}
++
++static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry)
++{
++ if (pin)
++ pin->dentry = dentry;
++}
++
++static inline void au_pin_set_parent_lflag(struct au_pin *pin,
++ unsigned char lflag)
++{
++ if (pin) {
++ if (lflag)
++ au_fset_pin(pin->flags, DI_LOCKED);
++ else
++ au_fclr_pin(pin->flags, DI_LOCKED);
++ }
++}
++
++static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent)
++{
++ if (pin) {
++ dput(pin->parent);
++ pin->parent = dget(parent);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_branch;
++#ifdef CONFIG_AUFS_HNOTIFY
++struct au_hnotify_op {
++ void (*ctl)(struct au_hinode *hinode, int do_set);
++ int (*alloc)(struct au_hinode *hinode);
++ void (*free)(struct au_hinode *hinode);
++
++ void (*fin)(void);
++ int (*init)(void);
++
++ int (*reset_br)(unsigned int udba, struct au_branch *br, int perm);
++ void (*fin_br)(struct au_branch *br);
++ int (*init_br)(struct au_branch *br, int perm);
++};
++
++/* hnotify.c */
++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode);
++void au_hn_free(struct au_hinode *hinode);
++void au_hn_ctl(struct au_hinode *hinode, int do_set);
++void au_hn_reset(struct inode *inode, unsigned int flags);
++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask,
++ struct qstr *h_child_qstr, struct inode *h_child_inode);
++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm);
++int au_hnotify_init_br(struct au_branch *br, int perm);
++void au_hnotify_fin_br(struct au_branch *br);
++int __init au_hnotify_init(void);
++void au_hnotify_fin(void);
++
++/* hfsnotify.c */
++extern const struct au_hnotify_op au_hnotify_op;
++
++static inline
++void au_hn_init(struct au_hinode *hinode)
++{
++ hinode->hi_notify = NULL;
++}
++
++#else
++static inline
++int au_hn_alloc(struct au_hinode *hinode __maybe_unused,
++ struct inode *inode __maybe_unused)
++{
++ return -EOPNOTSUPP;
++}
++
++AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused)
++AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused,
++ int do_set __maybe_unused)
++AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused,
++ unsigned int flags __maybe_unused)
++AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused,
++ struct au_branch *br __maybe_unused,
++ int perm __maybe_unused)
++AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused,
++ int perm __maybe_unused)
++AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused)
++AuStubInt0(__init au_hnotify_init, void)
++AuStubVoid(au_hnotify_fin, void)
++AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused)
++#endif /* CONFIG_AUFS_HNOTIFY */
++
++static inline void au_hn_suspend(struct au_hinode *hdir)
++{
++ au_hn_ctl(hdir, /*do_set*/0);
++}
++
++static inline void au_hn_resume(struct au_hinode *hdir)
++{
++ au_hn_ctl(hdir, /*do_set*/1);
++}
++
++static inline void au_hn_imtx_lock(struct au_hinode *hdir)
++{
++ mutex_lock(&hdir->hi_inode->i_mutex);
++ au_hn_suspend(hdir);
++}
++
++static inline void au_hn_imtx_lock_nested(struct au_hinode *hdir,
++ unsigned int sc __maybe_unused)
++{
++ mutex_lock_nested(&hdir->hi_inode->i_mutex, sc);
++ au_hn_suspend(hdir);
++}
++
++static inline void au_hn_imtx_unlock(struct au_hinode *hdir)
++{
++ au_hn_resume(hdir);
++ mutex_unlock(&hdir->hi_inode->i_mutex);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_INODE_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/ioctl.c linux-2.6.36/fs/aufs/ioctl.c
+--- linux-2.6.36.orig/fs/aufs/ioctl.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/ioctl.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,150 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * ioctl
++ * plink-management and readdir in userspace.
++ * assist the pathconf(3) wrapper library.
++ */
++
++#include <linux/file.h>
++#include "aufs.h"
++
++static int au_wbr_fd(struct path *path)
++{
++ int err, fd;
++ aufs_bindex_t wbi, bindex, bend;
++ struct file *h_file;
++ struct super_block *sb;
++ struct dentry *root;
++ struct au_branch *wbr;
++
++ err = get_unused_fd();
++ if (unlikely(err < 0))
++ goto out;
++ fd = err;
++
++ wbi = 0;
++ sb = path->dentry->d_sb;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_IR);
++ wbr = au_sbr(sb, wbi);
++ if (!(path->mnt->mnt_flags & MNT_READONLY)
++ && !au_br_writable(wbr->br_perm)) {
++ bend = au_sbend(sb);
++ for (bindex = 1; bindex <= bend; bindex++) {
++ wbr = au_sbr(sb, bindex);
++ if (au_br_writable(wbr->br_perm)) {
++ wbi = bindex;
++ break;
++ }
++ }
++ wbr = au_sbr(sb, wbi);
++ }
++ AuDbg("wbi %d\n", wbi);
++ h_file = au_h_open(root, wbi, O_RDONLY | O_DIRECTORY | O_LARGEFILE,
++ NULL);
++ aufs_read_unlock(root, AuLock_IR);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out_fd;
++
++ atomic_dec(&wbr->br_count); /* cf. au_h_open() */
++ fd_install(fd, h_file);
++ err = fd;
++ goto out; /* success */
++
++out_fd:
++ put_unused_fd(fd);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err;
++
++ switch (cmd) {
++ case AUFS_CTL_RDU:
++ case AUFS_CTL_RDU_INO:
++ err = au_rdu_ioctl(file, cmd, arg);
++ break;
++
++ case AUFS_CTL_WBR_FD:
++ err = au_wbr_fd(&file->f_path);
++ break;
++
++ default:
++ /* do not call the lower */
++ AuDbg("0x%x\n", cmd);
++ err = -ENOTTY;
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err;
++
++ switch (cmd) {
++ case AUFS_CTL_WBR_FD:
++ err = au_wbr_fd(&file->f_path);
++ break;
++
++ default:
++ /* do not call the lower */
++ AuDbg("0x%x\n", cmd);
++ err = -ENOTTY;
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++#ifdef CONFIG_COMPAT
++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ long err;
++
++ switch (cmd) {
++ case AUFS_CTL_RDU:
++ case AUFS_CTL_RDU_INO:
++ err = au_rdu_compat_ioctl(file, cmd, arg);
++ break;
++
++ default:
++ err = aufs_ioctl_dir(file, cmd, arg);
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++#if 0 /* unused yet */
++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg));
++}
++#endif
++#endif
+diff -Nur linux-2.6.36.orig/fs/aufs/loop.c linux-2.6.36/fs/aufs/loop.c
+--- linux-2.6.36.orig/fs/aufs/loop.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/loop.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,63 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * support for loopback block device as a branch
++ */
++
++#include <linux/loop.h>
++#include "aufs.h"
++
++/*
++ * test if two lower dentries have overlapping branches.
++ */
++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding)
++{
++ struct super_block *h_sb;
++ struct loop_device *l;
++
++ h_sb = h_adding->d_sb;
++ if (MAJOR(h_sb->s_dev) != LOOP_MAJOR)
++ return 0;
++
++ l = h_sb->s_bdev->bd_disk->private_data;
++ h_adding = l->lo_backing_file->f_dentry;
++ /*
++ * h_adding can be local NFS.
++ * in this case aufs cannot detect the loop.
++ */
++ if (unlikely(h_adding->d_sb == sb))
++ return 1;
++ return !!au_test_subdir(h_adding, sb->s_root);
++}
++
++/* true if a kernel thread named 'loop[0-9].*' accesses a file */
++int au_test_loopback_kthread(void)
++{
++ int ret;
++ struct task_struct *tsk = current;
++
++ ret = 0;
++ if (tsk->flags & PF_KTHREAD) {
++ const char c = tsk->comm[4];
++ ret = ('0' <= c && c <= '9'
++ && !strncmp(tsk->comm, "loop", 4));
++ }
++
++ return ret;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/loop.h linux-2.6.36/fs/aufs/loop.h
+--- linux-2.6.36.orig/fs/aufs/loop.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/loop.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,42 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * support for loopback mount as a branch
++ */
++
++#ifndef __AUFS_LOOP_H__
++#define __AUFS_LOOP_H__
++
++#ifdef __KERNEL__
++
++struct dentry;
++struct super_block;
++
++#ifdef CONFIG_AUFS_BDEV_LOOP
++/* loop.c */
++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding);
++int au_test_loopback_kthread(void);
++#else
++AuStubInt0(au_test_loopback_overlap, struct super_block *sb,
++ struct dentry *h_adding)
++AuStubInt0(au_test_loopback_kthread, void)
++#endif /* BLK_DEV_LOOP */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_LOOP_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/magic.mk linux-2.6.36/fs/aufs/magic.mk
+--- linux-2.6.36.orig/fs/aufs/magic.mk 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/magic.mk 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,54 @@
++
++# defined in ${srctree}/fs/fuse/inode.c
++# tristate
++ifdef CONFIG_FUSE_FS
++ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546
++endif
++
++# defined in ${srctree}/fs/ocfs2/ocfs2_fs.h
++# tristate
++ifdef CONFIG_OCFS2_FS
++ccflags-y += -DOCFS2_SUPER_MAGIC=0x7461636f
++endif
++
++# defined in ${srctree}/fs/ocfs2/dlm/userdlm.h
++# tristate
++ifdef CONFIG_OCFS2_FS_O2CB
++ccflags-y += -DDLMFS_MAGIC=0x76a9f425
++endif
++
++# defined in ${srctree}/fs/cifs/cifsfs.c
++# tristate
++ifdef CONFIG_CIFS_FS
++ccflags-y += -DCIFS_MAGIC_NUMBER=0xFF534D42
++endif
++
++# defined in ${srctree}/fs/xfs/xfs_sb.h
++# tristate
++ifdef CONFIG_XFS_FS
++ccflags-y += -DXFS_SB_MAGIC=0x58465342
++endif
++
++# defined in ${srctree}/fs/configfs/mount.c
++# tristate
++ifdef CONFIG_CONFIGFS_FS
++ccflags-y += -DCONFIGFS_MAGIC=0x62656570
++endif
++
++# defined in ${srctree}/fs/9p/v9fs.h
++# tristate
++ifdef CONFIG_9P_FS
++ccflags-y += -DV9FS_MAGIC=0x01021997
++endif
++
++# defined in ${srctree}/fs/ubifs/ubifs.h
++# tristate
++ifdef CONFIG_UBIFS_FS
++ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905
++endif
++
++# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h
++# tristate
++ifdef CONFIG_HFSPLUS_FS
++ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b
++endif
+diff -Nur linux-2.6.36.orig/fs/aufs/module.c linux-2.6.36/fs/aufs/module.c
+--- linux-2.6.36.orig/fs/aufs/module.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/module.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,182 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * module global variables and operations
++ */
++
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include "aufs.h"
++
++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp)
++{
++ if (new_sz <= nused)
++ return p;
++
++ p = krealloc(p, new_sz, gfp);
++ if (p)
++ memset(p + nused, 0, new_sz - nused);
++ return p;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * aufs caches
++ */
++struct kmem_cache *au_cachep[AuCache_Last];
++static int __init au_cache_init(void)
++{
++ au_cachep[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once);
++ if (au_cachep[AuCache_DINFO])
++ au_cachep[AuCache_ICNTNR] = AuCacheCtor(au_icntnr,
++ au_icntnr_init_once);
++ if (au_cachep[AuCache_ICNTNR])
++ au_cachep[AuCache_FINFO] = AuCacheCtor(au_finfo,
++ au_fi_init_once);
++ if (au_cachep[AuCache_FINFO])
++ au_cachep[AuCache_VDIR] = AuCache(au_vdir);
++ if (au_cachep[AuCache_VDIR])
++ au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr);
++ if (au_cachep[AuCache_DEHSTR])
++ return 0;
++
++ return -ENOMEM;
++}
++
++static void au_cache_fin(void)
++{
++ int i;
++
++ /* including AuCache_HNOTIFY */
++ for (i = 0; i < AuCache_Last; i++)
++ if (au_cachep[i]) {
++ kmem_cache_destroy(au_cachep[i]);
++ au_cachep[i] = NULL;
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_dir_roflags;
++
++#ifdef CONFIG_AUFS_SBILIST
++struct au_splhead au_sbilist;
++#endif
++
++/*
++ * functions for module interface.
++ */
++MODULE_LICENSE("GPL");
++/* MODULE_LICENSE("GPL v2"); */
++MODULE_AUTHOR("Junjiro R. Okajima <aufs-users@lists.sourceforge.net>");
++MODULE_DESCRIPTION(AUFS_NAME
++ " -- Advanced multi layered unification filesystem");
++MODULE_VERSION(AUFS_VERSION);
++
++/* this module parameter has no meaning when SYSFS is disabled */
++int sysaufs_brs = 1;
++MODULE_PARM_DESC(brs, "use <sysfs>/fs/aufs/si_*/brN");
++module_param_named(brs, sysaufs_brs, int, S_IRUGO);
++
++/* ---------------------------------------------------------------------- */
++
++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */
++
++int au_seq_path(struct seq_file *seq, struct path *path)
++{
++ return seq_path(seq, path, au_esc_chars);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int __init aufs_init(void)
++{
++ int err, i;
++ char *p;
++
++ p = au_esc_chars;
++ for (i = 1; i <= ' '; i++)
++ *p++ = i;
++ *p++ = '\\';
++ *p++ = '\x7f';
++ *p = 0;
++
++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE);
++
++ au_sbilist_init();
++ sysaufs_brs_init();
++ au_debug_init();
++ au_dy_init();
++ err = sysaufs_init();
++ if (unlikely(err))
++ goto out;
++ err = au_procfs_init();
++ if (unlikely(err))
++ goto out_sysaufs;
++ err = au_wkq_init();
++ if (unlikely(err))
++ goto out_procfs;
++ err = au_hnotify_init();
++ if (unlikely(err))
++ goto out_wkq;
++ err = au_sysrq_init();
++ if (unlikely(err))
++ goto out_hin;
++ err = au_cache_init();
++ if (unlikely(err))
++ goto out_sysrq;
++ err = register_filesystem(&aufs_fs_type);
++ if (unlikely(err))
++ goto out_cache;
++ /* since we define pr_fmt, call printk directly */
++ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n");
++ goto out; /* success */
++
++out_cache:
++ au_cache_fin();
++out_sysrq:
++ au_sysrq_fin();
++out_hin:
++ au_hnotify_fin();
++out_wkq:
++ au_wkq_fin();
++out_procfs:
++ au_procfs_fin();
++out_sysaufs:
++ sysaufs_fin();
++ au_dy_fin();
++out:
++ return err;
++}
++
++static void __exit aufs_exit(void)
++{
++ unregister_filesystem(&aufs_fs_type);
++ au_cache_fin();
++ au_sysrq_fin();
++ au_hnotify_fin();
++ au_wkq_fin();
++ au_procfs_fin();
++ sysaufs_fin();
++ au_dy_fin();
++}
++
++module_init(aufs_init);
++module_exit(aufs_exit);
+diff -Nur linux-2.6.36.orig/fs/aufs/module.h linux-2.6.36/fs/aufs/module.h
+--- linux-2.6.36.orig/fs/aufs/module.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/module.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,91 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * module initialization and module-global
++ */
++
++#ifndef __AUFS_MODULE_H__
++#define __AUFS_MODULE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/slab.h>
++
++struct path;
++struct seq_file;
++
++/* module parameters */
++extern int sysaufs_brs;
++
++/* ---------------------------------------------------------------------- */
++
++extern int au_dir_roflags;
++
++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp);
++int au_seq_path(struct seq_file *seq, struct path *path);
++
++#ifdef CONFIG_PROC_FS
++/* procfs.c */
++int __init au_procfs_init(void);
++void au_procfs_fin(void);
++#else
++AuStubInt0(au_procfs_init, void);
++AuStubVoid(au_procfs_fin, void);
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++/* kmem cache */
++enum {
++ AuCache_DINFO,
++ AuCache_ICNTNR,
++ AuCache_FINFO,
++ AuCache_VDIR,
++ AuCache_DEHSTR,
++#ifdef CONFIG_AUFS_HNOTIFY
++ AuCache_HNOTIFY,
++#endif
++ AuCache_Last
++};
++
++#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD)
++#define AuCache(type) KMEM_CACHE(type, AuCacheFlags)
++#define AuCacheCtor(type, ctor) \
++ kmem_cache_create(#type, sizeof(struct type), \
++ __alignof__(struct type), AuCacheFlags, ctor)
++
++extern struct kmem_cache *au_cachep[];
++
++#define AuCacheFuncs(name, index) \
++static inline struct au_##name *au_cache_alloc_##name(void) \
++{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \
++static inline void au_cache_free_##name(struct au_##name *p) \
++{ kmem_cache_free(au_cachep[AuCache_##index], p); }
++
++AuCacheFuncs(dinfo, DINFO);
++AuCacheFuncs(icntnr, ICNTNR);
++AuCacheFuncs(finfo, FINFO);
++AuCacheFuncs(vdir, VDIR);
++AuCacheFuncs(vdir_dehstr, DEHSTR);
++#ifdef CONFIG_AUFS_HNOTIFY
++AuCacheFuncs(hnotify, HNOTIFY);
++#endif
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_MODULE_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/mtx.h linux-2.6.36/fs/aufs/mtx.h
+--- linux-2.6.36.orig/fs/aufs/mtx.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/mtx.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * very ugly approach for aufs_mmap()
++ * never include this file from other than f_op.c.
++ * see f_op.c in detail.
++ */
++
++#ifndef __AUFS_MTX_H__
++#define __AUFS_MTX_H__
++
++#ifdef __KERNEL__
++
++/* copied from ../kernel/mutex{,-debug}.h */
++struct mutex;
++struct thread_info;
++#ifdef CONFIG_DEBUG_MUTEXES
++static inline void mutex_set_owner(struct mutex *lock)
++{
++ lock->owner = current_thread_info();
++}
++#else
++static inline void mutex_set_owner(struct mutex *lock)
++{
++#ifdef CONFIG_SMP
++ lock->owner = current_thread_info();
++#endif
++}
++#endif
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_MTX_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/opts.c linux-2.6.36/fs/aufs/opts.c
+--- linux-2.6.36.orig/fs/aufs/opts.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/opts.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,1595 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * mount options/flags
++ */
++
++#include <linux/file.h>
++#include <linux/jiffies.h>
++#include <linux/namei.h>
++#include <linux/types.h> /* a distribution requires */
++#include <linux/parser.h>
++#include "aufs.h"
++
++/* ---------------------------------------------------------------------- */
++
++enum {
++ Opt_br,
++ Opt_add, Opt_del, Opt_mod, Opt_reorder, Opt_append, Opt_prepend,
++ Opt_idel, Opt_imod, Opt_ireorder,
++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, Opt_rendir,
++ Opt_rdblk_def, Opt_rdhash_def,
++ Opt_xino, Opt_zxino, Opt_noxino,
++ Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino,
++ Opt_trunc_xino_path, Opt_itrunc_xino,
++ Opt_trunc_xib, Opt_notrunc_xib,
++ Opt_shwh, Opt_noshwh,
++ Opt_plink, Opt_noplink, Opt_list_plink,
++ Opt_udba,
++ Opt_dio, Opt_nodio,
++ /* Opt_lock, Opt_unlock, */
++ Opt_cmd, Opt_cmd_args,
++ Opt_diropq_a, Opt_diropq_w,
++ Opt_warn_perm, Opt_nowarn_perm,
++ Opt_wbr_copyup, Opt_wbr_create,
++ Opt_refrof, Opt_norefrof,
++ Opt_verbose, Opt_noverbose,
++ Opt_sum, Opt_nosum, Opt_wsum,
++ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err
++};
++
++static match_table_t options = {
++ {Opt_br, "br=%s"},
++ {Opt_br, "br:%s"},
++
++ {Opt_add, "add=%d:%s"},
++ {Opt_add, "add:%d:%s"},
++ {Opt_add, "ins=%d:%s"},
++ {Opt_add, "ins:%d:%s"},
++ {Opt_append, "append=%s"},
++ {Opt_append, "append:%s"},
++ {Opt_prepend, "prepend=%s"},
++ {Opt_prepend, "prepend:%s"},
++
++ {Opt_del, "del=%s"},
++ {Opt_del, "del:%s"},
++ /* {Opt_idel, "idel:%d"}, */
++ {Opt_mod, "mod=%s"},
++ {Opt_mod, "mod:%s"},
++ /* {Opt_imod, "imod:%d:%s"}, */
++
++ {Opt_dirwh, "dirwh=%d"},
++
++ {Opt_xino, "xino=%s"},
++ {Opt_noxino, "noxino"},
++ {Opt_trunc_xino, "trunc_xino"},
++ {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"},
++ {Opt_notrunc_xino, "notrunc_xino"},
++ {Opt_trunc_xino_path, "trunc_xino=%s"},
++ {Opt_itrunc_xino, "itrunc_xino=%d"},
++ /* {Opt_zxino, "zxino=%s"}, */
++ {Opt_trunc_xib, "trunc_xib"},
++ {Opt_notrunc_xib, "notrunc_xib"},
++
++#ifdef CONFIG_PROC_FS
++ {Opt_plink, "plink"},
++#else
++ {Opt_ignore_silent, "plink"},
++#endif
++
++ {Opt_noplink, "noplink"},
++
++#ifdef CONFIG_AUFS_DEBUG
++ {Opt_list_plink, "list_plink"},
++#endif
++
++ {Opt_udba, "udba=%s"},
++
++ {Opt_dio, "dio"},
++ {Opt_nodio, "nodio"},
++
++ {Opt_diropq_a, "diropq=always"},
++ {Opt_diropq_a, "diropq=a"},
++ {Opt_diropq_w, "diropq=whiteouted"},
++ {Opt_diropq_w, "diropq=w"},
++
++ {Opt_warn_perm, "warn_perm"},
++ {Opt_nowarn_perm, "nowarn_perm"},
++
++ /* keep them temporary */
++ {Opt_ignore_silent, "coo=%s"},
++ {Opt_ignore_silent, "nodlgt"},
++ {Opt_ignore_silent, "nodirperm1"},
++ {Opt_ignore_silent, "clean_plink"},
++
++#ifdef CONFIG_AUFS_SHWH
++ {Opt_shwh, "shwh"},
++#endif
++ {Opt_noshwh, "noshwh"},
++
++ {Opt_rendir, "rendir=%d"},
++
++ {Opt_refrof, "refrof"},
++ {Opt_norefrof, "norefrof"},
++
++ {Opt_verbose, "verbose"},
++ {Opt_verbose, "v"},
++ {Opt_noverbose, "noverbose"},
++ {Opt_noverbose, "quiet"},
++ {Opt_noverbose, "q"},
++ {Opt_noverbose, "silent"},
++
++ {Opt_sum, "sum"},
++ {Opt_nosum, "nosum"},
++ {Opt_wsum, "wsum"},
++
++ {Opt_rdcache, "rdcache=%d"},
++ {Opt_rdblk, "rdblk=%d"},
++ {Opt_rdblk_def, "rdblk=def"},
++ {Opt_rdhash, "rdhash=%d"},
++ {Opt_rdhash_def, "rdhash=def"},
++
++ {Opt_wbr_create, "create=%s"},
++ {Opt_wbr_create, "create_policy=%s"},
++ {Opt_wbr_copyup, "cpup=%s"},
++ {Opt_wbr_copyup, "copyup=%s"},
++ {Opt_wbr_copyup, "copyup_policy=%s"},
++
++ /* internal use for the scripts */
++ {Opt_ignore_silent, "si=%s"},
++
++ {Opt_br, "dirs=%s"},
++ {Opt_ignore, "debug=%d"},
++ {Opt_ignore, "delete=whiteout"},
++ {Opt_ignore, "delete=all"},
++ {Opt_ignore, "imap=%s"},
++
++ /* temporary workaround, due to old mount(8)? */
++ {Opt_ignore_silent, "relatime"},
++
++ {Opt_err, NULL}
++};
++
++/* ---------------------------------------------------------------------- */
++
++static const char *au_parser_pattern(int val, struct match_token *token)
++{
++ while (token->pattern) {
++ if (token->token == val)
++ return token->pattern;
++ token++;
++ }
++ BUG();
++ return "??";
++}
++
++/* ---------------------------------------------------------------------- */
++
++static match_table_t brperms = {
++ {AuBrPerm_RO, AUFS_BRPERM_RO},
++ {AuBrPerm_RR, AUFS_BRPERM_RR},
++ {AuBrPerm_RW, AUFS_BRPERM_RW},
++
++ {AuBrPerm_ROWH, AUFS_BRPERM_ROWH},
++ {AuBrPerm_RRWH, AUFS_BRPERM_RRWH},
++ {AuBrPerm_RWNoLinkWH, AUFS_BRPERM_RWNLWH},
++
++ {AuBrPerm_ROWH, "nfsro"},
++ {AuBrPerm_RO, NULL}
++};
++
++static int noinline_for_stack br_perm_val(char *perm)
++{
++ int val;
++ substring_t args[MAX_OPT_ARGS];
++
++ val = match_token(perm, brperms, args);
++ return val;
++}
++
++const char *au_optstr_br_perm(int brperm)
++{
++ return au_parser_pattern(brperm, (void *)brperms);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static match_table_t udbalevel = {
++ {AuOpt_UDBA_REVAL, "reval"},
++ {AuOpt_UDBA_NONE, "none"},
++#ifdef CONFIG_AUFS_HNOTIFY
++ {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */
++#ifdef CONFIG_AUFS_HFSNOTIFY
++ {AuOpt_UDBA_HNOTIFY, "fsnotify"},
++#endif
++#endif
++ {-1, NULL}
++};
++
++static int noinline_for_stack udba_val(char *str)
++{
++ substring_t args[MAX_OPT_ARGS];
++
++ return match_token(str, udbalevel, args);
++}
++
++const char *au_optstr_udba(int udba)
++{
++ return au_parser_pattern(udba, (void *)udbalevel);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static match_table_t au_wbr_create_policy = {
++ {AuWbrCreate_TDP, "tdp"},
++ {AuWbrCreate_TDP, "top-down-parent"},
++ {AuWbrCreate_RR, "rr"},
++ {AuWbrCreate_RR, "round-robin"},
++ {AuWbrCreate_MFS, "mfs"},
++ {AuWbrCreate_MFS, "most-free-space"},
++ {AuWbrCreate_MFSV, "mfs:%d"},
++ {AuWbrCreate_MFSV, "most-free-space:%d"},
++
++ {AuWbrCreate_MFSRR, "mfsrr:%d"},
++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"},
++ {AuWbrCreate_PMFS, "pmfs"},
++ {AuWbrCreate_PMFSV, "pmfs:%d"},
++
++ {-1, NULL}
++};
++
++/*
++ * cf. linux/lib/parser.c and cmdline.c
++ * gave up calling memparse() since it uses simple_strtoull() instead of
++ * strict_...().
++ */
++static int noinline_for_stack
++au_match_ull(substring_t *s, unsigned long long *result)
++{
++ int err;
++ unsigned int len;
++ char a[32];
++
++ err = -ERANGE;
++ len = s->to - s->from;
++ if (len + 1 <= sizeof(a)) {
++ memcpy(a, s->from, len);
++ a[len] = '\0';
++ err = strict_strtoull(a, 0, result);
++ }
++ return err;
++}
++
++static int au_wbr_mfs_wmark(substring_t *arg, char *str,
++ struct au_opt_wbr_create *create)
++{
++ int err;
++ unsigned long long ull;
++
++ err = 0;
++ if (!au_match_ull(arg, &ull))
++ create->mfsrr_watermark = ull;
++ else {
++ pr_err("bad integer in %s\n", str);
++ err = -EINVAL;
++ }
++
++ return err;
++}
++
++static int au_wbr_mfs_sec(substring_t *arg, char *str,
++ struct au_opt_wbr_create *create)
++{
++ int n, err;
++
++ err = 0;
++ if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC)
++ create->mfs_second = n;
++ else {
++ pr_err("bad integer in %s\n", str);
++ err = -EINVAL;
++ }
++
++ return err;
++}
++
++static int noinline_for_stack
++au_wbr_create_val(char *str, struct au_opt_wbr_create *create)
++{
++ int err, e;
++ substring_t args[MAX_OPT_ARGS];
++
++ err = match_token(str, au_wbr_create_policy, args);
++ create->wbr_create = err;
++ switch (err) {
++ case AuWbrCreate_MFSRRV:
++ e = au_wbr_mfs_wmark(&args[0], str, create);
++ if (!e)
++ e = au_wbr_mfs_sec(&args[1], str, create);
++ if (unlikely(e))
++ err = e;
++ break;
++ case AuWbrCreate_MFSRR:
++ e = au_wbr_mfs_wmark(&args[0], str, create);
++ if (unlikely(e)) {
++ err = e;
++ break;
++ }
++ /*FALLTHROUGH*/
++ case AuWbrCreate_MFS:
++ case AuWbrCreate_PMFS:
++ create->mfs_second = AUFS_MFS_DEF_SEC;
++ break;
++ case AuWbrCreate_MFSV:
++ case AuWbrCreate_PMFSV:
++ e = au_wbr_mfs_sec(&args[0], str, create);
++ if (unlikely(e))
++ err = e;
++ break;
++ }
++
++ return err;
++}
++
++const char *au_optstr_wbr_create(int wbr_create)
++{
++ return au_parser_pattern(wbr_create, (void *)au_wbr_create_policy);
++}
++
++static match_table_t au_wbr_copyup_policy = {
++ {AuWbrCopyup_TDP, "tdp"},
++ {AuWbrCopyup_TDP, "top-down-parent"},
++ {AuWbrCopyup_BUP, "bup"},
++ {AuWbrCopyup_BUP, "bottom-up-parent"},
++ {AuWbrCopyup_BU, "bu"},
++ {AuWbrCopyup_BU, "bottom-up"},
++ {-1, NULL}
++};
++
++static int noinline_for_stack au_wbr_copyup_val(char *str)
++{
++ substring_t args[MAX_OPT_ARGS];
++
++ return match_token(str, au_wbr_copyup_policy, args);
++}
++
++const char *au_optstr_wbr_copyup(int wbr_copyup)
++{
++ return au_parser_pattern(wbr_copyup, (void *)au_wbr_copyup_policy);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
++
++static void dump_opts(struct au_opts *opts)
++{
++#ifdef CONFIG_AUFS_DEBUG
++ /* reduce stack space */
++ union {
++ struct au_opt_add *add;
++ struct au_opt_del *del;
++ struct au_opt_mod *mod;
++ struct au_opt_xino *xino;
++ struct au_opt_xino_itrunc *xino_itrunc;
++ struct au_opt_wbr_create *create;
++ } u;
++ struct au_opt *opt;
++
++ opt = opts->opt;
++ while (opt->type != Opt_tail) {
++ switch (opt->type) {
++ case Opt_add:
++ u.add = &opt->add;
++ AuDbg("add {b%d, %s, 0x%x, %p}\n",
++ u.add->bindex, u.add->pathname, u.add->perm,
++ u.add->path.dentry);
++ break;
++ case Opt_del:
++ case Opt_idel:
++ u.del = &opt->del;
++ AuDbg("del {%s, %p}\n",
++ u.del->pathname, u.del->h_path.dentry);
++ break;
++ case Opt_mod:
++ case Opt_imod:
++ u.mod = &opt->mod;
++ AuDbg("mod {%s, 0x%x, %p}\n",
++ u.mod->path, u.mod->perm, u.mod->h_root);
++ break;
++ case Opt_append:
++ u.add = &opt->add;
++ AuDbg("append {b%d, %s, 0x%x, %p}\n",
++ u.add->bindex, u.add->pathname, u.add->perm,
++ u.add->path.dentry);
++ break;
++ case Opt_prepend:
++ u.add = &opt->add;
++ AuDbg("prepend {b%d, %s, 0x%x, %p}\n",
++ u.add->bindex, u.add->pathname, u.add->perm,
++ u.add->path.dentry);
++ break;
++ case Opt_dirwh:
++ AuDbg("dirwh %d\n", opt->dirwh);
++ break;
++ case Opt_rdcache:
++ AuDbg("rdcache %d\n", opt->rdcache);
++ break;
++ case Opt_rdblk:
++ AuDbg("rdblk %u\n", opt->rdblk);
++ break;
++ case Opt_rdblk_def:
++ AuDbg("rdblk_def\n");
++ break;
++ case Opt_rdhash:
++ AuDbg("rdhash %u\n", opt->rdhash);
++ break;
++ case Opt_rdhash_def:
++ AuDbg("rdhash_def\n");
++ break;
++ case Opt_xino:
++ u.xino = &opt->xino;
++ AuDbg("xino {%s %.*s}\n",
++ u.xino->path,
++ AuDLNPair(u.xino->file->f_dentry));
++ break;
++ case Opt_trunc_xino:
++ AuLabel(trunc_xino);
++ break;
++ case Opt_notrunc_xino:
++ AuLabel(notrunc_xino);
++ break;
++ case Opt_trunc_xino_path:
++ case Opt_itrunc_xino:
++ u.xino_itrunc = &opt->xino_itrunc;
++ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex);
++ break;
++
++ case Opt_noxino:
++ AuLabel(noxino);
++ break;
++ case Opt_trunc_xib:
++ AuLabel(trunc_xib);
++ break;
++ case Opt_notrunc_xib:
++ AuLabel(notrunc_xib);
++ break;
++ case Opt_shwh:
++ AuLabel(shwh);
++ break;
++ case Opt_noshwh:
++ AuLabel(noshwh);
++ break;
++ case Opt_plink:
++ AuLabel(plink);
++ break;
++ case Opt_noplink:
++ AuLabel(noplink);
++ break;
++ case Opt_list_plink:
++ AuLabel(list_plink);
++ break;
++ case Opt_udba:
++ AuDbg("udba %d, %s\n",
++ opt->udba, au_optstr_udba(opt->udba));
++ break;
++ case Opt_dio:
++ AuLabel(dio);
++ break;
++ case Opt_nodio:
++ AuLabel(nodio);
++ break;
++ case Opt_diropq_a:
++ AuLabel(diropq_a);
++ break;
++ case Opt_diropq_w:
++ AuLabel(diropq_w);
++ break;
++ case Opt_warn_perm:
++ AuLabel(warn_perm);
++ break;
++ case Opt_nowarn_perm:
++ AuLabel(nowarn_perm);
++ break;
++ case Opt_refrof:
++ AuLabel(refrof);
++ break;
++ case Opt_norefrof:
++ AuLabel(norefrof);
++ break;
++ case Opt_verbose:
++ AuLabel(verbose);
++ break;
++ case Opt_noverbose:
++ AuLabel(noverbose);
++ break;
++ case Opt_sum:
++ AuLabel(sum);
++ break;
++ case Opt_nosum:
++ AuLabel(nosum);
++ break;
++ case Opt_wsum:
++ AuLabel(wsum);
++ break;
++ case Opt_wbr_create:
++ u.create = &opt->wbr_create;
++ AuDbg("create %d, %s\n", u.create->wbr_create,
++ au_optstr_wbr_create(u.create->wbr_create));
++ switch (u.create->wbr_create) {
++ case AuWbrCreate_MFSV:
++ case AuWbrCreate_PMFSV:
++ AuDbg("%d sec\n", u.create->mfs_second);
++ break;
++ case AuWbrCreate_MFSRR:
++ AuDbg("%llu watermark\n",
++ u.create->mfsrr_watermark);
++ break;
++ case AuWbrCreate_MFSRRV:
++ AuDbg("%llu watermark, %d sec\n",
++ u.create->mfsrr_watermark,
++ u.create->mfs_second);
++ break;
++ }
++ break;
++ case Opt_wbr_copyup:
++ AuDbg("copyup %d, %s\n", opt->wbr_copyup,
++ au_optstr_wbr_copyup(opt->wbr_copyup));
++ break;
++ default:
++ BUG();
++ }
++ opt++;
++ }
++#endif
++}
++
++void au_opts_free(struct au_opts *opts)
++{
++ struct au_opt *opt;
++
++ opt = opts->opt;
++ while (opt->type != Opt_tail) {
++ switch (opt->type) {
++ case Opt_add:
++ case Opt_append:
++ case Opt_prepend:
++ path_put(&opt->add.path);
++ break;
++ case Opt_del:
++ case Opt_idel:
++ path_put(&opt->del.h_path);
++ break;
++ case Opt_mod:
++ case Opt_imod:
++ dput(opt->mod.h_root);
++ break;
++ case Opt_xino:
++ fput(opt->xino.file);
++ break;
++ }
++ opt++;
++ }
++}
++
++static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags,
++ aufs_bindex_t bindex)
++{
++ int err;
++ struct au_opt_add *add = &opt->add;
++ char *p;
++
++ add->bindex = bindex;
++ add->perm = AuBrPerm_Last;
++ add->pathname = opt_str;
++ p = strchr(opt_str, '=');
++ if (p) {
++ *p++ = 0;
++ if (*p)
++ add->perm = br_perm_val(p);
++ }
++
++ err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path);
++ if (!err) {
++ if (!p) {
++ add->perm = AuBrPerm_RO;
++ if (au_test_fs_rr(add->path.dentry->d_sb))
++ add->perm = AuBrPerm_RR;
++ else if (!bindex && !(sb_flags & MS_RDONLY))
++ add->perm = AuBrPerm_RW;
++ }
++ opt->type = Opt_add;
++ goto out;
++ }
++ pr_err("lookup failed %s (%d)\n", add->pathname, err);
++ err = -EINVAL;
++
++out:
++ return err;
++}
++
++static int au_opts_parse_del(struct au_opt_del *del, substring_t args[])
++{
++ int err;
++
++ del->pathname = args[0].from;
++ AuDbg("del path %s\n", del->pathname);
++
++ err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path);
++ if (unlikely(err))
++ pr_err("lookup failed %s (%d)\n", del->pathname, err);
++
++ return err;
++}
++
++#if 0 /* reserved for future use */
++static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex,
++ struct au_opt_del *del, substring_t args[])
++{
++ int err;
++ struct dentry *root;
++
++ err = -EINVAL;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_FLUSH);
++ if (bindex < 0 || au_sbend(sb) < bindex) {
++ pr_err("out of bounds, %d\n", bindex);
++ goto out;
++ }
++
++ err = 0;
++ del->h_path.dentry = dget(au_h_dptr(root, bindex));
++ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex));
++
++out:
++ aufs_read_unlock(root, !AuLock_IR);
++ return err;
++}
++#endif
++
++static int noinline_for_stack
++au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[])
++{
++ int err;
++ struct path path;
++ char *p;
++
++ err = -EINVAL;
++ mod->path = args[0].from;
++ p = strchr(mod->path, '=');
++ if (unlikely(!p)) {
++ pr_err("no permssion %s\n", args[0].from);
++ goto out;
++ }
++
++ *p++ = 0;
++ err = vfsub_kern_path(mod->path, lkup_dirflags, &path);
++ if (unlikely(err)) {
++ pr_err("lookup failed %s (%d)\n", mod->path, err);
++ goto out;
++ }
++
++ mod->perm = br_perm_val(p);
++ AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p);
++ mod->h_root = dget(path.dentry);
++ path_put(&path);
++
++out:
++ return err;
++}
++
++#if 0 /* reserved for future use */
++static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex,
++ struct au_opt_mod *mod, substring_t args[])
++{
++ int err;
++ struct dentry *root;
++
++ err = -EINVAL;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_FLUSH);
++ if (bindex < 0 || au_sbend(sb) < bindex) {
++ pr_err("out of bounds, %d\n", bindex);
++ goto out;
++ }
++
++ err = 0;
++ mod->perm = br_perm_val(args[1].from);
++ AuDbg("mod path %s, perm 0x%x, %s\n",
++ mod->path, mod->perm, args[1].from);
++ mod->h_root = dget(au_h_dptr(root, bindex));
++
++out:
++ aufs_read_unlock(root, !AuLock_IR);
++ return err;
++}
++#endif
++
++static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino,
++ substring_t args[])
++{
++ int err;
++ struct file *file;
++
++ file = au_xino_create(sb, args[0].from, /*silent*/0);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++
++ err = -EINVAL;
++ if (unlikely(file->f_dentry->d_sb == sb)) {
++ fput(file);
++ pr_err("%s must be outside\n", args[0].from);
++ goto out;
++ }
++
++ err = 0;
++ xino->file = file;
++ xino->path = args[0].from;
++
++out:
++ return err;
++}
++
++static int noinline_for_stack
++au_opts_parse_xino_itrunc_path(struct super_block *sb,
++ struct au_opt_xino_itrunc *xino_itrunc,
++ substring_t args[])
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct path path;
++ struct dentry *root;
++
++ err = vfsub_kern_path(args[0].from, lkup_dirflags, &path);
++ if (unlikely(err)) {
++ pr_err("lookup failed %s (%d)\n", args[0].from, err);
++ goto out;
++ }
++
++ xino_itrunc->bindex = -1;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_FLUSH);
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ if (au_h_dptr(root, bindex) == path.dentry) {
++ xino_itrunc->bindex = bindex;
++ break;
++ }
++ }
++ aufs_read_unlock(root, !AuLock_IR);
++ path_put(&path);
++
++ if (unlikely(xino_itrunc->bindex < 0)) {
++ pr_err("no such branch %s\n", args[0].from);
++ err = -EINVAL;
++ }
++
++out:
++ return err;
++}
++
++/* called without aufs lock */
++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
++{
++ int err, n, token;
++ aufs_bindex_t bindex;
++ unsigned char skipped;
++ struct dentry *root;
++ struct au_opt *opt, *opt_tail;
++ char *opt_str;
++ /* reduce the stack space */
++ union {
++ struct au_opt_xino_itrunc *xino_itrunc;
++ struct au_opt_wbr_create *create;
++ } u;
++ struct {
++ substring_t args[MAX_OPT_ARGS];
++ } *a;
++
++ err = -ENOMEM;
++ a = kmalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ root = sb->s_root;
++ err = 0;
++ bindex = 0;
++ opt = opts->opt;
++ opt_tail = opt + opts->max_opt - 1;
++ opt->type = Opt_tail;
++ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) {
++ err = -EINVAL;
++ skipped = 0;
++ token = match_token(opt_str, options, a->args);
++ switch (token) {
++ case Opt_br:
++ err = 0;
++ while (!err && (opt_str = strsep(&a->args[0].from, ":"))
++ && *opt_str) {
++ err = opt_add(opt, opt_str, opts->sb_flags,
++ bindex++);
++ if (unlikely(!err && ++opt > opt_tail)) {
++ err = -E2BIG;
++ break;
++ }
++ opt->type = Opt_tail;
++ skipped = 1;
++ }
++ break;
++ case Opt_add:
++ if (unlikely(match_int(&a->args[0], &n))) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ bindex = n;
++ err = opt_add(opt, a->args[1].from, opts->sb_flags,
++ bindex);
++ if (!err)
++ opt->type = token;
++ break;
++ case Opt_append:
++ err = opt_add(opt, a->args[0].from, opts->sb_flags,
++ /*dummy bindex*/1);
++ if (!err)
++ opt->type = token;
++ break;
++ case Opt_prepend:
++ err = opt_add(opt, a->args[0].from, opts->sb_flags,
++ /*bindex*/0);
++ if (!err)
++ opt->type = token;
++ break;
++ case Opt_del:
++ err = au_opts_parse_del(&opt->del, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#if 0 /* reserved for future use */
++ case Opt_idel:
++ del->pathname = "(indexed)";
++ if (unlikely(match_int(&args[0], &n))) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ err = au_opts_parse_idel(sb, n, &opt->del, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#endif
++ case Opt_mod:
++ err = au_opts_parse_mod(&opt->mod, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#ifdef IMOD /* reserved for future use */
++ case Opt_imod:
++ u.mod->path = "(indexed)";
++ if (unlikely(match_int(&a->args[0], &n))) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ err = au_opts_parse_imod(sb, n, &opt->mod, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#endif
++ case Opt_xino:
++ err = au_opts_parse_xino(sb, &opt->xino, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++
++ case Opt_trunc_xino_path:
++ err = au_opts_parse_xino_itrunc_path
++ (sb, &opt->xino_itrunc, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++
++ case Opt_itrunc_xino:
++ u.xino_itrunc = &opt->xino_itrunc;
++ if (unlikely(match_int(&a->args[0], &n))) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ u.xino_itrunc->bindex = n;
++ aufs_read_lock(root, AuLock_FLUSH);
++ if (n < 0 || au_sbend(sb) < n) {
++ pr_err("out of bounds, %d\n", n);
++ aufs_read_unlock(root, !AuLock_IR);
++ break;
++ }
++ aufs_read_unlock(root, !AuLock_IR);
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_dirwh:
++ if (unlikely(match_int(&a->args[0], &opt->dirwh)))
++ break;
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_rdcache:
++ if (unlikely(match_int(&a->args[0], &n))) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ if (unlikely(n > AUFS_RDCACHE_MAX)) {
++ pr_err("rdcache must be smaller than %d\n",
++ AUFS_RDCACHE_MAX);
++ break;
++ }
++ opt->rdcache = n;
++ err = 0;
++ opt->type = token;
++ break;
++ case Opt_rdblk:
++ if (unlikely(match_int(&a->args[0], &n)
++ || n < 0
++ || n > KMALLOC_MAX_SIZE)) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ if (unlikely(n && n < NAME_MAX)) {
++ pr_err("rdblk must be larger than %d\n",
++ NAME_MAX);
++ break;
++ }
++ opt->rdblk = n;
++ err = 0;
++ opt->type = token;
++ break;
++ case Opt_rdhash:
++ if (unlikely(match_int(&a->args[0], &n)
++ || n < 0
++ || n * sizeof(struct hlist_head)
++ > KMALLOC_MAX_SIZE)) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ opt->rdhash = n;
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_trunc_xino:
++ case Opt_notrunc_xino:
++ case Opt_noxino:
++ case Opt_trunc_xib:
++ case Opt_notrunc_xib:
++ case Opt_shwh:
++ case Opt_noshwh:
++ case Opt_plink:
++ case Opt_noplink:
++ case Opt_list_plink:
++ case Opt_dio:
++ case Opt_nodio:
++ case Opt_diropq_a:
++ case Opt_diropq_w:
++ case Opt_warn_perm:
++ case Opt_nowarn_perm:
++ case Opt_refrof:
++ case Opt_norefrof:
++ case Opt_verbose:
++ case Opt_noverbose:
++ case Opt_sum:
++ case Opt_nosum:
++ case Opt_wsum:
++ case Opt_rdblk_def:
++ case Opt_rdhash_def:
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_udba:
++ opt->udba = udba_val(a->args[0].from);
++ if (opt->udba >= 0) {
++ err = 0;
++ opt->type = token;
++ } else
++ pr_err("wrong value, %s\n", opt_str);
++ break;
++
++ case Opt_wbr_create:
++ u.create = &opt->wbr_create;
++ u.create->wbr_create
++ = au_wbr_create_val(a->args[0].from, u.create);
++ if (u.create->wbr_create >= 0) {
++ err = 0;
++ opt->type = token;
++ } else
++ pr_err("wrong value, %s\n", opt_str);
++ break;
++ case Opt_wbr_copyup:
++ opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from);
++ if (opt->wbr_copyup >= 0) {
++ err = 0;
++ opt->type = token;
++ } else
++ pr_err("wrong value, %s\n", opt_str);
++ break;
++
++ case Opt_ignore:
++ pr_warning("ignored %s\n", opt_str);
++ /*FALLTHROUGH*/
++ case Opt_ignore_silent:
++ skipped = 1;
++ err = 0;
++ break;
++ case Opt_err:
++ pr_err("unknown option %s\n", opt_str);
++ break;
++ }
++
++ if (!err && !skipped) {
++ if (unlikely(++opt > opt_tail)) {
++ err = -E2BIG;
++ opt--;
++ opt->type = Opt_tail;
++ break;
++ }
++ opt->type = Opt_tail;
++ }
++ }
++
++ kfree(a);
++ dump_opts(opts);
++ if (unlikely(err))
++ au_opts_free(opts);
++
++out:
++ return err;
++}
++
++static int au_opt_wbr_create(struct super_block *sb,
++ struct au_opt_wbr_create *create)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ err = 1; /* handled */
++ sbinfo = au_sbi(sb);
++ if (sbinfo->si_wbr_create_ops->fin) {
++ err = sbinfo->si_wbr_create_ops->fin(sb);
++ if (!err)
++ err = 1;
++ }
++
++ sbinfo->si_wbr_create = create->wbr_create;
++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create;
++ switch (create->wbr_create) {
++ case AuWbrCreate_MFSRRV:
++ case AuWbrCreate_MFSRR:
++ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark;
++ /*FALLTHROUGH*/
++ case AuWbrCreate_MFS:
++ case AuWbrCreate_MFSV:
++ case AuWbrCreate_PMFS:
++ case AuWbrCreate_PMFSV:
++ sbinfo->si_wbr_mfs.mfs_expire
++ = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC);
++ break;
++ }
++
++ if (sbinfo->si_wbr_create_ops->init)
++ sbinfo->si_wbr_create_ops->init(sb); /* ignore */
++
++ return err;
++}
++
++/*
++ * returns,
++ * plus: processed without an error
++ * zero: unprocessed
++ */
++static int au_opt_simple(struct super_block *sb, struct au_opt *opt,
++ struct au_opts *opts)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ err = 1; /* handled */
++ sbinfo = au_sbi(sb);
++ switch (opt->type) {
++ case Opt_udba:
++ sbinfo->si_mntflags &= ~AuOptMask_UDBA;
++ sbinfo->si_mntflags |= opt->udba;
++ opts->given_udba |= opt->udba;
++ break;
++
++ case Opt_plink:
++ au_opt_set(sbinfo->si_mntflags, PLINK);
++ break;
++ case Opt_noplink:
++ if (au_opt_test(sbinfo->si_mntflags, PLINK))
++ au_plink_put(sb, /*verbose*/1);
++ au_opt_clr(sbinfo->si_mntflags, PLINK);
++ break;
++ case Opt_list_plink:
++ if (au_opt_test(sbinfo->si_mntflags, PLINK))
++ au_plink_list(sb);
++ break;
++
++ case Opt_dio:
++ au_opt_set(sbinfo->si_mntflags, DIO);
++ au_fset_opts(opts->flags, REFRESH_DYAOP);
++ break;
++ case Opt_nodio:
++ au_opt_clr(sbinfo->si_mntflags, DIO);
++ au_fset_opts(opts->flags, REFRESH_DYAOP);
++ break;
++
++ case Opt_diropq_a:
++ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ);
++ break;
++ case Opt_diropq_w:
++ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ);
++ break;
++
++ case Opt_warn_perm:
++ au_opt_set(sbinfo->si_mntflags, WARN_PERM);
++ break;
++ case Opt_nowarn_perm:
++ au_opt_clr(sbinfo->si_mntflags, WARN_PERM);
++ break;
++
++ case Opt_refrof:
++ au_opt_set(sbinfo->si_mntflags, REFROF);
++ break;
++ case Opt_norefrof:
++ au_opt_clr(sbinfo->si_mntflags, REFROF);
++ break;
++
++ case Opt_verbose:
++ au_opt_set(sbinfo->si_mntflags, VERBOSE);
++ break;
++ case Opt_noverbose:
++ au_opt_clr(sbinfo->si_mntflags, VERBOSE);
++ break;
++
++ case Opt_sum:
++ au_opt_set(sbinfo->si_mntflags, SUM);
++ break;
++ case Opt_wsum:
++ au_opt_clr(sbinfo->si_mntflags, SUM);
++ au_opt_set(sbinfo->si_mntflags, SUM_W);
++ case Opt_nosum:
++ au_opt_clr(sbinfo->si_mntflags, SUM);
++ au_opt_clr(sbinfo->si_mntflags, SUM_W);
++ break;
++
++ case Opt_wbr_create:
++ err = au_opt_wbr_create(sb, &opt->wbr_create);
++ break;
++ case Opt_wbr_copyup:
++ sbinfo->si_wbr_copyup = opt->wbr_copyup;
++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup;
++ break;
++
++ case Opt_dirwh:
++ sbinfo->si_dirwh = opt->dirwh;
++ break;
++
++ case Opt_rdcache:
++ sbinfo->si_rdcache
++ = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC);
++ break;
++ case Opt_rdblk:
++ sbinfo->si_rdblk = opt->rdblk;
++ break;
++ case Opt_rdblk_def:
++ sbinfo->si_rdblk = AUFS_RDBLK_DEF;
++ break;
++ case Opt_rdhash:
++ sbinfo->si_rdhash = opt->rdhash;
++ break;
++ case Opt_rdhash_def:
++ sbinfo->si_rdhash = AUFS_RDHASH_DEF;
++ break;
++
++ case Opt_shwh:
++ au_opt_set(sbinfo->si_mntflags, SHWH);
++ break;
++ case Opt_noshwh:
++ au_opt_clr(sbinfo->si_mntflags, SHWH);
++ break;
++
++ case Opt_trunc_xino:
++ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO);
++ break;
++ case Opt_notrunc_xino:
++ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO);
++ break;
++
++ case Opt_trunc_xino_path:
++ case Opt_itrunc_xino:
++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex);
++ if (!err)
++ err = 1;
++ break;
++
++ case Opt_trunc_xib:
++ au_fset_opts(opts->flags, TRUNC_XIB);
++ break;
++ case Opt_notrunc_xib:
++ au_fclr_opts(opts->flags, TRUNC_XIB);
++ break;
++
++ default:
++ err = 0;
++ break;
++ }
++
++ return err;
++}
++
++/*
++ * returns tri-state.
++ * plus: processed without an error
++ * zero: unprocessed
++ * minus: error
++ */
++static int au_opt_br(struct super_block *sb, struct au_opt *opt,
++ struct au_opts *opts)
++{
++ int err, do_refresh;
++
++ err = 0;
++ switch (opt->type) {
++ case Opt_append:
++ opt->add.bindex = au_sbend(sb) + 1;
++ if (opt->add.bindex < 0)
++ opt->add.bindex = 0;
++ goto add;
++ case Opt_prepend:
++ opt->add.bindex = 0;
++ add:
++ case Opt_add:
++ err = au_br_add(sb, &opt->add,
++ au_ftest_opts(opts->flags, REMOUNT));
++ if (!err) {
++ err = 1;
++ au_fset_opts(opts->flags, REFRESH);
++ }
++ break;
++
++ case Opt_del:
++ case Opt_idel:
++ err = au_br_del(sb, &opt->del,
++ au_ftest_opts(opts->flags, REMOUNT));
++ if (!err) {
++ err = 1;
++ au_fset_opts(opts->flags, TRUNC_XIB);
++ au_fset_opts(opts->flags, REFRESH);
++ }
++ break;
++
++ case Opt_mod:
++ case Opt_imod:
++ err = au_br_mod(sb, &opt->mod,
++ au_ftest_opts(opts->flags, REMOUNT),
++ &do_refresh);
++ if (!err) {
++ err = 1;
++ if (do_refresh)
++ au_fset_opts(opts->flags, REFRESH);
++ }
++ break;
++ }
++
++ return err;
++}
++
++static int au_opt_xino(struct super_block *sb, struct au_opt *opt,
++ struct au_opt_xino **opt_xino,
++ struct au_opts *opts)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct dentry *root, *parent, *h_root;
++
++ err = 0;
++ switch (opt->type) {
++ case Opt_xino:
++ err = au_xino_set(sb, &opt->xino,
++ !!au_ftest_opts(opts->flags, REMOUNT));
++ if (unlikely(err))
++ break;
++
++ *opt_xino = &opt->xino;
++ au_xino_brid_set(sb, -1);
++
++ /* safe d_parent access */
++ parent = opt->xino.file->f_dentry->d_parent;
++ root = sb->s_root;
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ h_root = au_h_dptr(root, bindex);
++ if (h_root == parent) {
++ au_xino_brid_set(sb, au_sbr_id(sb, bindex));
++ break;
++ }
++ }
++ break;
++
++ case Opt_noxino:
++ au_xino_clr(sb);
++ au_xino_brid_set(sb, -1);
++ *opt_xino = (void *)-1;
++ break;
++ }
++
++ return err;
++}
++
++int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
++ unsigned int pending)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ unsigned char do_plink, skip, do_free;
++ struct au_branch *br;
++ struct au_wbr *wbr;
++ struct dentry *root;
++ struct inode *dir, *h_dir;
++ struct au_sbinfo *sbinfo;
++ struct au_hinode *hdir;
++
++ SiMustAnyLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA));
++
++ if (!(sb_flags & MS_RDONLY)) {
++ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0))))
++ pr_warning("first branch should be rw\n");
++ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH)))
++ pr_warning("shwh should be used with ro\n");
++ }
++
++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY)
++ && !au_opt_test(sbinfo->si_mntflags, XINO))
++ pr_warning("udba=*notify requires xino\n");
++
++ err = 0;
++ root = sb->s_root;
++ dir = root->d_inode;
++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK);
++ bend = au_sbend(sb);
++ for (bindex = 0; !err && bindex <= bend; bindex++) {
++ skip = 0;
++ h_dir = au_h_iptr(dir, bindex);
++ br = au_sbr(sb, bindex);
++ do_free = 0;
++
++ wbr = br->br_wbr;
++ if (wbr)
++ wbr_wh_read_lock(wbr);
++
++ switch (br->br_perm) {
++ case AuBrPerm_RO:
++ case AuBrPerm_ROWH:
++ case AuBrPerm_RR:
++ case AuBrPerm_RRWH:
++ do_free = !!wbr;
++ skip = (!wbr
++ || (!wbr->wbr_whbase
++ && !wbr->wbr_plink
++ && !wbr->wbr_orph));
++ break;
++
++ case AuBrPerm_RWNoLinkWH:
++ /* skip = (!br->br_whbase && !br->br_orph); */
++ skip = (!wbr || !wbr->wbr_whbase);
++ if (skip && wbr) {
++ if (do_plink)
++ skip = !!wbr->wbr_plink;
++ else
++ skip = !wbr->wbr_plink;
++ }
++ break;
++
++ case AuBrPerm_RW:
++ /* skip = (br->br_whbase && br->br_ohph); */
++ skip = (wbr && wbr->wbr_whbase);
++ if (skip) {
++ if (do_plink)
++ skip = !!wbr->wbr_plink;
++ else
++ skip = !wbr->wbr_plink;
++ }
++ break;
++
++ default:
++ BUG();
++ }
++ if (wbr)
++ wbr_wh_read_unlock(wbr);
++
++ if (skip)
++ continue;
++
++ hdir = au_hi(dir, bindex);
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ if (wbr)
++ wbr_wh_write_lock(wbr);
++ err = au_wh_init(au_h_dptr(root, bindex), br, sb);
++ if (wbr)
++ wbr_wh_write_unlock(wbr);
++ au_hn_imtx_unlock(hdir);
++
++ if (!err && do_free) {
++ kfree(wbr);
++ br->br_wbr = NULL;
++ }
++ }
++
++ return err;
++}
++
++int au_opts_mount(struct super_block *sb, struct au_opts *opts)
++{
++ int err;
++ unsigned int tmp;
++ aufs_bindex_t bindex, bend;
++ struct au_opt *opt;
++ struct au_opt_xino *opt_xino, xino;
++ struct au_sbinfo *sbinfo;
++ struct au_branch *br;
++
++ SiMustWriteLock(sb);
++
++ err = 0;
++ opt_xino = NULL;
++ opt = opts->opt;
++ while (err >= 0 && opt->type != Opt_tail)
++ err = au_opt_simple(sb, opt++, opts);
++ if (err > 0)
++ err = 0;
++ else if (unlikely(err < 0))
++ goto out;
++
++ /* disable xino and udba temporary */
++ sbinfo = au_sbi(sb);
++ tmp = sbinfo->si_mntflags;
++ au_opt_clr(sbinfo->si_mntflags, XINO);
++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL);
++
++ opt = opts->opt;
++ while (err >= 0 && opt->type != Opt_tail)
++ err = au_opt_br(sb, opt++, opts);
++ if (err > 0)
++ err = 0;
++ else if (unlikely(err < 0))
++ goto out;
++
++ bend = au_sbend(sb);
++ if (unlikely(bend < 0)) {
++ err = -EINVAL;
++ pr_err("no branches\n");
++ goto out;
++ }
++
++ if (au_opt_test(tmp, XINO))
++ au_opt_set(sbinfo->si_mntflags, XINO);
++ opt = opts->opt;
++ while (!err && opt->type != Opt_tail)
++ err = au_opt_xino(sb, opt++, &opt_xino, opts);
++ if (unlikely(err))
++ goto out;
++
++ err = au_opts_verify(sb, sb->s_flags, tmp);
++ if (unlikely(err))
++ goto out;
++
++ /* restore xino */
++ if (au_opt_test(tmp, XINO) && !opt_xino) {
++ xino.file = au_xino_def(sb);
++ err = PTR_ERR(xino.file);
++ if (IS_ERR(xino.file))
++ goto out;
++
++ err = au_xino_set(sb, &xino, /*remount*/0);
++ fput(xino.file);
++ if (unlikely(err))
++ goto out;
++ }
++
++ /* restore udba */
++ tmp &= AuOptMask_UDBA;
++ sbinfo->si_mntflags &= ~AuOptMask_UDBA;
++ sbinfo->si_mntflags |= tmp;
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ err = au_hnotify_reset_br(tmp, br, br->br_perm);
++ if (unlikely(err))
++ AuIOErr("hnotify failed on br %d, %d, ignored\n",
++ bindex, err);
++ /* go on even if err */
++ }
++ if (au_opt_test(tmp, UDBA_HNOTIFY)) {
++ struct inode *dir = sb->s_root->d_inode;
++ au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO);
++ }
++
++out:
++ return err;
++}
++
++int au_opts_remount(struct super_block *sb, struct au_opts *opts)
++{
++ int err, rerr;
++ struct inode *dir;
++ struct au_opt_xino *opt_xino;
++ struct au_opt *opt;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ dir = sb->s_root->d_inode;
++ sbinfo = au_sbi(sb);
++ err = 0;
++ opt_xino = NULL;
++ opt = opts->opt;
++ while (err >= 0 && opt->type != Opt_tail) {
++ err = au_opt_simple(sb, opt, opts);
++ if (!err)
++ err = au_opt_br(sb, opt, opts);
++ if (!err)
++ err = au_opt_xino(sb, opt, &opt_xino, opts);
++ opt++;
++ }
++ if (err > 0)
++ err = 0;
++ AuTraceErr(err);
++ /* go on even err */
++
++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0);
++ if (unlikely(rerr && !err))
++ err = rerr;
++
++ if (au_ftest_opts(opts->flags, TRUNC_XIB)) {
++ rerr = au_xib_trunc(sb);
++ if (unlikely(rerr && !err))
++ err = rerr;
++ }
++
++ /* will be handled by the caller */
++ if (!au_ftest_opts(opts->flags, REFRESH)
++ && (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO)))
++ au_fset_opts(opts->flags, REFRESH);
++
++ AuDbg("status 0x%x\n", opts->flags);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++unsigned int au_opt_udba(struct super_block *sb)
++{
++ return au_mntflags(sb) & AuOptMask_UDBA;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/opts.h linux-2.6.36/fs/aufs/opts.h
+--- linux-2.6.36.orig/fs/aufs/opts.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/opts.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,210 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * mount options/flags
++ */
++
++#ifndef __AUFS_OPTS_H__
++#define __AUFS_OPTS_H__
++
++#ifdef __KERNEL__
++
++#include <linux/path.h>
++#include <linux/aufs_type.h>
++
++struct file;
++struct super_block;
++
++/* ---------------------------------------------------------------------- */
++
++/* mount flags */
++#define AuOpt_XINO 1 /* external inode number bitmap
++ and translation table */
++#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */
++#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */
++#define AuOpt_UDBA_REVAL (1 << 3)
++#define AuOpt_UDBA_HNOTIFY (1 << 4)
++#define AuOpt_SHWH (1 << 5) /* show whiteout */
++#define AuOpt_PLINK (1 << 6) /* pseudo-link */
++#define AuOpt_DIRPERM1 (1 << 7) /* unimplemented */
++#define AuOpt_REFROF (1 << 8) /* unimplemented */
++#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */
++#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */
++#define AuOpt_SUM_W (1 << 11) /* unimplemented */
++#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */
++#define AuOpt_VERBOSE (1 << 13) /* busy inode when del-branch */
++#define AuOpt_DIO (1 << 14) /* direct io */
++
++#ifndef CONFIG_AUFS_HNOTIFY
++#undef AuOpt_UDBA_HNOTIFY
++#define AuOpt_UDBA_HNOTIFY 0
++#endif
++#ifndef CONFIG_AUFS_SHWH
++#undef AuOpt_SHWH
++#define AuOpt_SHWH 0
++#endif
++
++#define AuOpt_Def (AuOpt_XINO \
++ | AuOpt_UDBA_REVAL \
++ | AuOpt_PLINK \
++ /* | AuOpt_DIRPERM1 */ \
++ | AuOpt_WARN_PERM)
++#define AuOptMask_UDBA (AuOpt_UDBA_NONE \
++ | AuOpt_UDBA_REVAL \
++ | AuOpt_UDBA_HNOTIFY)
++
++#define au_opt_test(flags, name) (flags & AuOpt_##name)
++#define au_opt_set(flags, name) do { \
++ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \
++ ((flags) |= AuOpt_##name); \
++} while (0)
++#define au_opt_set_udba(flags, name) do { \
++ (flags) &= ~AuOptMask_UDBA; \
++ ((flags) |= AuOpt_##name); \
++} while (0)
++#define au_opt_clr(flags, name) do { \
++ ((flags) &= ~AuOpt_##name); \
++} while (0)
++
++static inline unsigned int au_opts_plink(unsigned int mntflags)
++{
++#ifdef CONFIG_PROC_FS
++ return mntflags;
++#else
++ return mntflags & ~AuOpt_PLINK;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* policies to select one among multiple writable branches */
++enum {
++ AuWbrCreate_TDP, /* top down parent */
++ AuWbrCreate_RR, /* round robin */
++ AuWbrCreate_MFS, /* most free space */
++ AuWbrCreate_MFSV, /* mfs with seconds */
++ AuWbrCreate_MFSRR, /* mfs then rr */
++ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */
++ AuWbrCreate_PMFS, /* parent and mfs */
++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */
++
++ AuWbrCreate_Def = AuWbrCreate_TDP
++};
++
++enum {
++ AuWbrCopyup_TDP, /* top down parent */
++ AuWbrCopyup_BUP, /* bottom up parent */
++ AuWbrCopyup_BU, /* bottom up */
++
++ AuWbrCopyup_Def = AuWbrCopyup_TDP
++};
++
++/* ---------------------------------------------------------------------- */
++
++struct au_opt_add {
++ aufs_bindex_t bindex;
++ char *pathname;
++ int perm;
++ struct path path;
++};
++
++struct au_opt_del {
++ char *pathname;
++ struct path h_path;
++};
++
++struct au_opt_mod {
++ char *path;
++ int perm;
++ struct dentry *h_root;
++};
++
++struct au_opt_xino {
++ char *path;
++ struct file *file;
++};
++
++struct au_opt_xino_itrunc {
++ aufs_bindex_t bindex;
++};
++
++struct au_opt_wbr_create {
++ int wbr_create;
++ int mfs_second;
++ unsigned long long mfsrr_watermark;
++};
++
++struct au_opt {
++ int type;
++ union {
++ struct au_opt_xino xino;
++ struct au_opt_xino_itrunc xino_itrunc;
++ struct au_opt_add add;
++ struct au_opt_del del;
++ struct au_opt_mod mod;
++ int dirwh;
++ int rdcache;
++ unsigned int rdblk;
++ unsigned int rdhash;
++ int udba;
++ struct au_opt_wbr_create wbr_create;
++ int wbr_copyup;
++ };
++};
++
++/* opts flags */
++#define AuOpts_REMOUNT 1
++#define AuOpts_REFRESH (1 << 1)
++#define AuOpts_TRUNC_XIB (1 << 2)
++#define AuOpts_REFRESH_DYAOP (1 << 3)
++#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name)
++#define au_fset_opts(flags, name) \
++ do { (flags) |= AuOpts_##name; } while (0)
++#define au_fclr_opts(flags, name) \
++ do { (flags) &= ~AuOpts_##name; } while (0)
++
++struct au_opts {
++ struct au_opt *opt;
++ int max_opt;
++
++ unsigned int given_udba;
++ unsigned int flags;
++ unsigned long sb_flags;
++};
++
++/* ---------------------------------------------------------------------- */
++
++const char *au_optstr_br_perm(int brperm);
++const char *au_optstr_udba(int udba);
++const char *au_optstr_wbr_copyup(int wbr_copyup);
++const char *au_optstr_wbr_create(int wbr_create);
++
++void au_opts_free(struct au_opts *opts);
++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts);
++int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
++ unsigned int pending);
++int au_opts_mount(struct super_block *sb, struct au_opts *opts);
++int au_opts_remount(struct super_block *sb, struct au_opts *opts);
++
++unsigned int au_opt_udba(struct super_block *sb);
++
++/* ---------------------------------------------------------------------- */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_OPTS_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/plink.c linux-2.6.36/fs/aufs/plink.c
+--- linux-2.6.36.orig/fs/aufs/plink.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/plink.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,515 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * pseudo-link
++ */
++
++#include "aufs.h"
++
++/*
++ * the pseudo-link maintenance mode.
++ * during a user process maintains the pseudo-links,
++ * prohibit adding a new plink and branch manipulation.
++ *
++ * Flags
++ * NOPLM:
++ * For entry functions which will handle plink, and i_mutex is already held
++ * in VFS.
++ * They cannot wait and should return an error at once.
++ * Callers has to check the error.
++ * NOPLMW:
++ * For entry functions which will handle plink, but i_mutex is not held
++ * in VFS.
++ * They can wait the plink maintenance mode to finish.
++ *
++ * They behave like F_SETLK and F_SETLKW.
++ * If the caller never handle plink, then both flags are unnecessary.
++ */
++
++int au_plink_maint(struct super_block *sb, int flags)
++{
++ int err;
++ pid_t pid, ppid;
++ struct au_sbinfo *sbi;
++
++ SiMustAnyLock(sb);
++
++ err = 0;
++ if (!au_opt_test(au_mntflags(sb), PLINK))
++ goto out;
++
++ sbi = au_sbi(sb);
++ pid = sbi->si_plink_maint_pid;
++ if (!pid || pid == current->pid)
++ goto out;
++
++ /* todo: it highly depends upon /sbin/mount.aufs */
++ rcu_read_lock();
++ ppid = task_pid_vnr(rcu_dereference(current->real_parent));
++ rcu_read_unlock();
++ if (pid == ppid)
++ goto out;
++
++ if (au_ftest_lock(flags, NOPLMW)) {
++ /* if there is no i_mutex lock in VFS, we don't need to wait */
++ /* AuDebugOn(!lockdep_depth(current)); */
++ while (sbi->si_plink_maint_pid) {
++ si_read_unlock(sb);
++ /* gave up wake_up_bit() */
++ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid);
++
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&sbi->si_nowait);
++ si_noflush_read_lock(sb);
++ }
++ } else if (au_ftest_lock(flags, NOPLM)) {
++ AuDbg("ppid %d, pid %d\n", ppid, pid);
++ err = -EAGAIN;
++ }
++
++out:
++ return err;
++}
++
++void au_plink_maint_leave(struct au_sbinfo *sbinfo)
++{
++ spin_lock(&sbinfo->si_plink_maint_lock);
++ sbinfo->si_plink_maint_pid = 0;
++ spin_unlock(&sbinfo->si_plink_maint_lock);
++ wake_up_all(&sbinfo->si_plink_wq);
++}
++
++int au_plink_maint_enter(struct super_block *sb)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ /* make sure i am the only one in this fs */
++ si_write_lock(sb, AuLock_FLUSH);
++ if (au_opt_test(au_mntflags(sb), PLINK)) {
++ spin_lock(&sbinfo->si_plink_maint_lock);
++ if (!sbinfo->si_plink_maint_pid)
++ sbinfo->si_plink_maint_pid = current->pid;
++ else
++ err = -EBUSY;
++ spin_unlock(&sbinfo->si_plink_maint_lock);
++ }
++ si_write_unlock(sb);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct pseudo_link {
++ union {
++ struct list_head list;
++ struct rcu_head rcu;
++ };
++ struct inode *inode;
++};
++
++#ifdef CONFIG_AUFS_DEBUG
++void au_plink_list(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink;
++
++ SiMustAnyLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
++
++ plink_list = &sbinfo->si_plink.head;
++ rcu_read_lock();
++ list_for_each_entry_rcu(plink, plink_list, list)
++ AuDbg("%lu\n", plink->inode->i_ino);
++ rcu_read_unlock();
++}
++#endif
++
++/* is the inode pseudo-linked? */
++int au_plink_test(struct inode *inode)
++{
++ int found;
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink;
++
++ sbinfo = au_sbi(inode->i_sb);
++ AuRwMustAnyLock(&sbinfo->si_rwsem);
++ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK));
++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM));
++
++ found = 0;
++ plink_list = &sbinfo->si_plink.head;
++ rcu_read_lock();
++ list_for_each_entry_rcu(plink, plink_list, list)
++ if (plink->inode == inode) {
++ found = 1;
++ break;
++ }
++ rcu_read_unlock();
++ return found;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * generate a name for plink.
++ * the file will be stored under AUFS_WH_PLINKDIR.
++ */
++/* 20 is max digits length of ulong 64 */
++#define PLINK_NAME_LEN ((20 + 1) * 2)
++
++static int plink_name(char *name, int len, struct inode *inode,
++ aufs_bindex_t bindex)
++{
++ int rlen;
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, bindex);
++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino);
++ return rlen;
++}
++
++struct au_do_plink_lkup_args {
++ struct dentry **errp;
++ struct qstr *tgtname;
++ struct dentry *h_parent;
++ struct au_branch *br;
++};
++
++static struct dentry *au_do_plink_lkup(struct qstr *tgtname,
++ struct dentry *h_parent,
++ struct au_branch *br)
++{
++ struct dentry *h_dentry;
++ struct mutex *h_mtx;
++
++ h_mtx = &h_parent->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD2);
++ h_dentry = au_lkup_one(tgtname, h_parent, br, /*nd*/NULL);
++ mutex_unlock(h_mtx);
++ return h_dentry;
++}
++
++static void au_call_do_plink_lkup(void *args)
++{
++ struct au_do_plink_lkup_args *a = args;
++ *a->errp = au_do_plink_lkup(a->tgtname, a->h_parent, a->br);
++}
++
++/* lookup the plink-ed @inode under the branch at @bindex */
++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex)
++{
++ struct dentry *h_dentry, *h_parent;
++ struct au_branch *br;
++ struct inode *h_dir;
++ int wkq_err;
++ char a[PLINK_NAME_LEN];
++ struct qstr tgtname = {
++ .name = a
++ };
++
++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM));
++
++ br = au_sbr(inode->i_sb, bindex);
++ h_parent = br->br_wbr->wbr_plink;
++ h_dir = h_parent->d_inode;
++ tgtname.len = plink_name(a, sizeof(a), inode, bindex);
++
++ if (current_fsuid()) {
++ struct au_do_plink_lkup_args args = {
++ .errp = &h_dentry,
++ .tgtname = &tgtname,
++ .h_parent = h_parent,
++ .br = br
++ };
++
++ wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args);
++ if (unlikely(wkq_err))
++ h_dentry = ERR_PTR(wkq_err);
++ } else
++ h_dentry = au_do_plink_lkup(&tgtname, h_parent, br);
++
++ return h_dentry;
++}
++
++/* create a pseudo-link */
++static int do_whplink(struct qstr *tgt, struct dentry *h_parent,
++ struct dentry *h_dentry, struct au_branch *br)
++{
++ int err;
++ struct path h_path = {
++ .mnt = br->br_mnt
++ };
++ struct inode *h_dir;
++
++ h_dir = h_parent->d_inode;
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2);
++again:
++ h_path.dentry = au_lkup_one(tgt, h_parent, br, /*nd*/NULL);
++ err = PTR_ERR(h_path.dentry);
++ if (IS_ERR(h_path.dentry))
++ goto out;
++
++ err = 0;
++ /* wh.plink dir is not monitored */
++ /* todo: is it really safe? */
++ if (h_path.dentry->d_inode
++ && h_path.dentry->d_inode != h_dentry->d_inode) {
++ err = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ dput(h_path.dentry);
++ h_path.dentry = NULL;
++ if (!err)
++ goto again;
++ }
++ if (!err && !h_path.dentry->d_inode)
++ err = vfsub_link(h_dentry, h_dir, &h_path);
++ dput(h_path.dentry);
++
++out:
++ mutex_unlock(&h_dir->i_mutex);
++ return err;
++}
++
++struct do_whplink_args {
++ int *errp;
++ struct qstr *tgt;
++ struct dentry *h_parent;
++ struct dentry *h_dentry;
++ struct au_branch *br;
++};
++
++static void call_do_whplink(void *args)
++{
++ struct do_whplink_args *a = args;
++ *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br);
++}
++
++static int whplink(struct dentry *h_dentry, struct inode *inode,
++ aufs_bindex_t bindex, struct au_branch *br)
++{
++ int err, wkq_err;
++ struct au_wbr *wbr;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++ char a[PLINK_NAME_LEN];
++ struct qstr tgtname = {
++ .name = a
++ };
++
++ wbr = au_sbr(inode->i_sb, bindex)->br_wbr;
++ h_parent = wbr->wbr_plink;
++ h_dir = h_parent->d_inode;
++ tgtname.len = plink_name(a, sizeof(a), inode, bindex);
++
++ /* always superio. */
++ if (current_fsuid()) {
++ struct do_whplink_args args = {
++ .errp = &err,
++ .tgt = &tgtname,
++ .h_parent = h_parent,
++ .h_dentry = h_dentry,
++ .br = br
++ };
++ wkq_err = au_wkq_wait(call_do_whplink, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ } else
++ err = do_whplink(&tgtname, h_parent, h_dentry, br);
++
++ return err;
++}
++
++/* free a single plink */
++static void do_put_plink(struct pseudo_link *plink, int do_del)
++{
++ if (do_del)
++ list_del(&plink->list);
++ iput(plink->inode);
++ kfree(plink);
++}
++
++static void do_put_plink_rcu(struct rcu_head *rcu)
++{
++ struct pseudo_link *plink;
++
++ plink = container_of(rcu, struct pseudo_link, rcu);
++ iput(plink->inode);
++ kfree(plink);
++}
++
++/*
++ * create a new pseudo-link for @h_dentry on @bindex.
++ * the linked inode is held in aufs @inode.
++ */
++void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_dentry)
++{
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink, *tmp;
++ int found, err, cnt;
++
++ sb = inode->i_sb;
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
++
++ cnt = 0;
++ found = 0;
++ plink_list = &sbinfo->si_plink.head;
++ rcu_read_lock();
++ list_for_each_entry_rcu(plink, plink_list, list) {
++ cnt++;
++ if (plink->inode == inode) {
++ found = 1;
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (found)
++ return;
++
++ tmp = kmalloc(sizeof(*plink), GFP_NOFS);
++ if (tmp)
++ tmp->inode = au_igrab(inode);
++ else {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ spin_lock(&sbinfo->si_plink.spin);
++ list_for_each_entry(plink, plink_list, list) {
++ if (plink->inode == inode) {
++ found = 1;
++ break;
++ }
++ }
++ if (!found)
++ list_add_rcu(&tmp->list, plink_list);
++ spin_unlock(&sbinfo->si_plink.spin);
++ if (!found) {
++ cnt++;
++ WARN_ONCE(cnt > AUFS_PLINK_WARN,
++ "unexpectedly many pseudo links, %d\n", cnt);
++ err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex));
++ } else {
++ do_put_plink(tmp, 0);
++ return;
++ }
++
++out:
++ if (unlikely(err)) {
++ pr_warning("err %d, damaged pseudo link.\n", err);
++ if (tmp) {
++ au_spl_del_rcu(&tmp->list, &sbinfo->si_plink);
++ call_rcu(&tmp->rcu, do_put_plink_rcu);
++ }
++ }
++}
++
++/* free all plinks */
++void au_plink_put(struct super_block *sb, int verbose)
++{
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink, *tmp;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
++
++ plink_list = &sbinfo->si_plink.head;
++ /* no spin_lock since sbinfo is write-locked */
++ WARN(verbose && !list_empty(plink_list), "pseudo-link is not flushed");
++ list_for_each_entry_safe(plink, tmp, plink_list, list)
++ do_put_plink(plink, 0);
++ INIT_LIST_HEAD(plink_list);
++}
++
++void au_plink_clean(struct super_block *sb, int verbose)
++{
++ struct dentry *root;
++
++ root = sb->s_root;
++ aufs_write_lock(root);
++ if (au_opt_test(au_mntflags(sb), PLINK))
++ au_plink_put(sb, verbose);
++ aufs_write_unlock(root);
++}
++
++/* free the plinks on a branch specified by @br_id */
++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id)
++{
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink, *tmp;
++ struct inode *inode;
++ aufs_bindex_t bstart, bend, bindex;
++ unsigned char do_put;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
++
++ plink_list = &sbinfo->si_plink.head;
++ /* no spin_lock since sbinfo is write-locked */
++ list_for_each_entry_safe(plink, tmp, plink_list, list) {
++ do_put = 0;
++ inode = au_igrab(plink->inode);
++ ii_write_lock_child(inode);
++ bstart = au_ibstart(inode);
++ bend = au_ibend(inode);
++ if (bstart >= 0) {
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ if (!au_h_iptr(inode, bindex)
++ || au_ii_br_id(inode, bindex) != br_id)
++ continue;
++ au_set_h_iptr(inode, bindex, NULL, 0);
++ do_put = 1;
++ break;
++ }
++ } else
++ do_put_plink(plink, 1);
++
++ if (do_put) {
++ for (bindex = bstart; bindex <= bend; bindex++)
++ if (au_h_iptr(inode, bindex)) {
++ do_put = 0;
++ break;
++ }
++ if (do_put)
++ do_put_plink(plink, 1);
++ }
++ ii_write_unlock(inode);
++ iput(inode);
++ }
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/poll.c linux-2.6.36/fs/aufs/poll.c
+--- linux-2.6.36.orig/fs/aufs/poll.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/poll.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,56 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * poll operation
++ * There is only one filesystem which implements ->poll operation, currently.
++ */
++
++#include "aufs.h"
++
++unsigned int aufs_poll(struct file *file, poll_table *wait)
++{
++ unsigned int mask;
++ int err;
++ struct file *h_file;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ /* We should pretend an error happened. */
++ mask = POLLERR /* | POLLIN | POLLOUT */;
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ /* it is not an error if h_file has no operation */
++ mask = DEFAULT_POLLMASK;
++ h_file = au_hf_top(file);
++ if (h_file->f_op && h_file->f_op->poll)
++ mask = h_file->f_op->poll(h_file, wait);
++
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++
++out:
++ si_read_unlock(sb);
++ AuTraceErr((int)mask);
++ return mask;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/procfs.c linux-2.6.36/fs/aufs/procfs.c
+--- linux-2.6.36.orig/fs/aufs/procfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/procfs.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,169 @@
++/*
++ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * procfs interfaces
++ */
++
++#include <linux/proc_fs.h>
++#include "aufs.h"
++
++static int au_procfs_plm_release(struct inode *inode, struct file *file)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = file->private_data;
++ if (sbinfo) {
++ au_plink_maint_leave(sbinfo);
++ kobject_put(&sbinfo->si_kobj);
++ }
++
++ return 0;
++}
++
++static void au_procfs_plm_write_clean(struct file *file)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = file->private_data;
++ if (sbinfo)
++ au_plink_clean(sbinfo->si_sb, /*verbose*/0);
++}
++
++static int au_procfs_plm_write_si(struct file *file, unsigned long id)
++{
++ int err;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++ err = -EBUSY;
++ if (unlikely(file->private_data))
++ goto out;
++
++ sb = NULL;
++ spin_lock(&au_sbilist.spin);
++ list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
++ if (id == sysaufs_si_id(sbinfo)) {
++ kobject_get(&sbinfo->si_kobj);
++ sb = sbinfo->si_sb;
++ break;
++ }
++ spin_unlock(&au_sbilist.spin);
++
++ err = -EINVAL;
++ if (unlikely(!sb))
++ goto out;
++
++ err = au_plink_maint_enter(sb);
++ if (!err)
++ /* keep kobject_get() */
++ file->private_data = sbinfo;
++ else
++ kobject_put(&sbinfo->si_kobj);
++out:
++ return err;
++}
++
++/*
++ * Accept a valid "si=xxxx" only.
++ * Once it is accepted successfully, accept "clean" too.
++ */
++static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf,
++ size_t count, loff_t *ppos)
++{
++ ssize_t err;
++ unsigned long id;
++ /* last newline is allowed */
++ char buf[3 + sizeof(unsigned long) * 2 + 1];
++
++ err = -EACCES;
++ if (unlikely(!capable(CAP_SYS_ADMIN)))
++ goto out;
++
++ err = -EINVAL;
++ if (unlikely(count > sizeof(buf)))
++ goto out;
++
++ err = copy_from_user(buf, ubuf, count);
++ if (unlikely(err)) {
++ err = -EFAULT;
++ goto out;
++ }
++ buf[count] = 0;
++
++ err = -EINVAL;
++ if (!strcmp("clean", buf)) {
++ au_procfs_plm_write_clean(file);
++ goto out_success;
++ } else if (unlikely(strncmp("si=", buf, 3)))
++ goto out;
++
++ err = strict_strtoul(buf + 3, 16, &id);
++ if (unlikely(err))
++ goto out;
++
++ err = au_procfs_plm_write_si(file, id);
++ if (unlikely(err))
++ goto out;
++
++out_success:
++ err = count; /* success */
++out:
++ return err;
++}
++
++static const struct file_operations au_procfs_plm_fop = {
++ .write = au_procfs_plm_write,
++ .release = au_procfs_plm_release,
++ .owner = THIS_MODULE
++};
++
++/* ---------------------------------------------------------------------- */
++
++static struct proc_dir_entry *au_procfs_dir;
++
++void au_procfs_fin(void)
++{
++ remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir);
++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL);
++}
++
++int __init au_procfs_init(void)
++{
++ int err;
++ struct proc_dir_entry *entry;
++
++ err = -ENOMEM;
++ au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL);
++ if (unlikely(!au_procfs_dir))
++ goto out;
++
++ entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | S_IWUSR,
++ au_procfs_dir, &au_procfs_plm_fop);
++ if (unlikely(!entry))
++ goto out_dir;
++
++ err = 0;
++ goto out; /* success */
++
++
++out_dir:
++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL);
++out:
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/rdu.c linux-2.6.36/fs/aufs/rdu.c
+--- linux-2.6.36.orig/fs/aufs/rdu.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/rdu.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,383 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * readdir in userspace.
++ */
++
++#include <linux/compat.h>
++#include <linux/fs_stack.h>
++#include <linux/security.h>
++#include <linux/uaccess.h>
++#include <linux/aufs_type.h>
++#include "aufs.h"
++
++/* bits for struct aufs_rdu.flags */
++#define AuRdu_CALLED 1
++#define AuRdu_CONT (1 << 1)
++#define AuRdu_FULL (1 << 2)
++#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name)
++#define au_fset_rdu(flags, name) \
++ do { (flags) |= AuRdu_##name; } while (0)
++#define au_fclr_rdu(flags, name) \
++ do { (flags) &= ~AuRdu_##name; } while (0)
++
++struct au_rdu_arg {
++ struct aufs_rdu *rdu;
++ union au_rdu_ent_ul ent;
++ unsigned long end;
++
++ struct super_block *sb;
++ int err;
++};
++
++static int au_rdu_fill(void *__arg, const char *name, int nlen,
++ loff_t offset, u64 h_ino, unsigned int d_type)
++{
++ int err, len;
++ struct au_rdu_arg *arg = __arg;
++ struct aufs_rdu *rdu = arg->rdu;
++ struct au_rdu_ent ent;
++
++ err = 0;
++ arg->err = 0;
++ au_fset_rdu(rdu->cookie.flags, CALLED);
++ len = au_rdu_len(nlen);
++ if (arg->ent.ul + len < arg->end) {
++ ent.ino = h_ino;
++ ent.bindex = rdu->cookie.bindex;
++ ent.type = d_type;
++ ent.nlen = nlen;
++ if (unlikely(nlen > AUFS_MAX_NAMELEN))
++ ent.type = DT_UNKNOWN;
++
++ err = -EFAULT;
++ if (copy_to_user(arg->ent.e, &ent, sizeof(ent)))
++ goto out;
++ if (copy_to_user(arg->ent.e->name, name, nlen))
++ goto out;
++ /* the terminating NULL */
++ if (__put_user(0, arg->ent.e->name + nlen))
++ goto out;
++ err = 0;
++ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */
++ arg->ent.ul += len;
++ rdu->rent++;
++ } else {
++ err = -EFAULT;
++ au_fset_rdu(rdu->cookie.flags, FULL);
++ rdu->full = 1;
++ rdu->tail = arg->ent;
++ }
++
++out:
++ /* AuTraceErr(err); */
++ return err;
++}
++
++static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg)
++{
++ int err;
++ loff_t offset;
++ struct au_rdu_cookie *cookie = &arg->rdu->cookie;
++
++ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET);
++ err = offset;
++ if (unlikely(offset != cookie->h_pos))
++ goto out;
++
++ err = 0;
++ do {
++ arg->err = 0;
++ au_fclr_rdu(cookie->flags, CALLED);
++ /* smp_mb(); */
++ err = vfsub_readdir(h_file, au_rdu_fill, arg);
++ if (err >= 0)
++ err = arg->err;
++ } while (!err
++ && au_ftest_rdu(cookie->flags, CALLED)
++ && !au_ftest_rdu(cookie->flags, FULL));
++ cookie->h_pos = h_file->f_pos;
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int au_rdu(struct file *file, struct aufs_rdu *rdu)
++{
++ int err;
++ aufs_bindex_t bend;
++ struct au_rdu_arg arg;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *h_file;
++ struct au_rdu_cookie *cookie = &rdu->cookie;
++
++ err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz);
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ goto out;
++ }
++ rdu->rent = 0;
++ rdu->tail = rdu->ent;
++ rdu->full = 0;
++ arg.rdu = rdu;
++ arg.ent = rdu->ent;
++ arg.end = arg.ent.ul;
++ arg.end += rdu->sz;
++
++ err = -ENOTDIR;
++ if (unlikely(!file->f_op || !file->f_op->readdir))
++ goto out;
++
++ err = security_file_permission(file, MAY_READ);
++ AuTraceErr(err);
++ if (unlikely(err))
++ goto out;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++#if 1
++ mutex_lock(&inode->i_mutex);
++#else
++ err = mutex_lock_killable(&inode->i_mutex);
++ AuTraceErr(err);
++ if (unlikely(err))
++ goto out;
++#endif
++
++ arg.sb = inode->i_sb;
++ err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out_mtx;
++ err = au_alive_dir(dentry);
++ if (unlikely(err))
++ goto out_si;
++ /* todo: reval? */
++ fi_read_lock(file);
++
++ err = -EAGAIN;
++ if (unlikely(au_ftest_rdu(cookie->flags, CONT)
++ && cookie->generation != au_figen(file)))
++ goto out_unlock;
++
++ err = 0;
++ if (!rdu->blk) {
++ rdu->blk = au_sbi(arg.sb)->si_rdblk;
++ if (!rdu->blk)
++ rdu->blk = au_dir_size(file, /*dentry*/NULL);
++ }
++ bend = au_fbstart(file);
++ if (cookie->bindex < bend)
++ cookie->bindex = bend;
++ bend = au_fbend_dir(file);
++ /* AuDbg("b%d, b%d\n", cookie->bindex, bend); */
++ for (; !err && cookie->bindex <= bend;
++ cookie->bindex++, cookie->h_pos = 0) {
++ h_file = au_hf_dir(file, cookie->bindex);
++ if (!h_file)
++ continue;
++
++ au_fclr_rdu(cookie->flags, FULL);
++ err = au_rdu_do(h_file, &arg);
++ AuTraceErr(err);
++ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err))
++ break;
++ }
++ AuDbg("rent %llu\n", rdu->rent);
++
++ if (!err && !au_ftest_rdu(cookie->flags, CONT)) {
++ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH);
++ au_fset_rdu(cookie->flags, CONT);
++ cookie->generation = au_figen(file);
++ }
++
++ ii_read_lock_child(inode);
++ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode)));
++ ii_read_unlock(inode);
++
++out_unlock:
++ fi_read_unlock(file);
++out_si:
++ si_read_unlock(arg.sb);
++out_mtx:
++ mutex_unlock(&inode->i_mutex);
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu)
++{
++ int err;
++ ino_t ino;
++ unsigned long long nent;
++ union au_rdu_ent_ul *u;
++ struct au_rdu_ent ent;
++ struct super_block *sb;
++
++ err = 0;
++ nent = rdu->nent;
++ u = &rdu->ent;
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ while (nent-- > 0) {
++ err = copy_from_user(&ent, u->e, sizeof(ent));
++ if (!err)
++ err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino));
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ break;
++ }
++
++ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */
++ if (!ent.wh)
++ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino);
++ else
++ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type,
++ &ino);
++ if (unlikely(err)) {
++ AuTraceErr(err);
++ break;
++ }
++
++ err = __put_user(ino, &u->e->ino);
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ break;
++ }
++ u->ul += au_rdu_len(ent.nlen);
++ }
++ si_read_unlock(sb);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_rdu_verify(struct aufs_rdu *rdu)
++{
++ AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | "
++ "%llu, b%d, 0x%x, g%u}\n",
++ rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ],
++ rdu->blk,
++ rdu->rent, rdu->shwh, rdu->full,
++ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags,
++ rdu->cookie.generation);
++
++ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu))
++ return 0;
++
++ AuDbg("%u:%u\n",
++ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu));
++ return -EINVAL;
++}
++
++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err, e;
++ struct aufs_rdu rdu;
++ void __user *p = (void __user *)arg;
++
++ err = copy_from_user(&rdu, p, sizeof(rdu));
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ goto out;
++ }
++ err = au_rdu_verify(&rdu);
++ if (unlikely(err))
++ goto out;
++
++ switch (cmd) {
++ case AUFS_CTL_RDU:
++ err = au_rdu(file, &rdu);
++ if (unlikely(err))
++ break;
++
++ e = copy_to_user(p, &rdu, sizeof(rdu));
++ if (unlikely(e)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ }
++ break;
++ case AUFS_CTL_RDU_INO:
++ err = au_rdu_ino(file, &rdu);
++ break;
++
++ default:
++ /* err = -ENOTTY; */
++ err = -EINVAL;
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++#ifdef CONFIG_COMPAT
++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err, e;
++ struct aufs_rdu rdu;
++ void __user *p = compat_ptr(arg);
++
++ /* todo: get_user()? */
++ err = copy_from_user(&rdu, p, sizeof(rdu));
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ goto out;
++ }
++ rdu.ent.e = compat_ptr(rdu.ent.ul);
++ err = au_rdu_verify(&rdu);
++ if (unlikely(err))
++ goto out;
++
++ switch (cmd) {
++ case AUFS_CTL_RDU:
++ err = au_rdu(file, &rdu);
++ if (unlikely(err))
++ break;
++
++ rdu.ent.ul = ptr_to_compat(rdu.ent.e);
++ rdu.tail.ul = ptr_to_compat(rdu.tail.e);
++ e = copy_to_user(p, &rdu, sizeof(rdu));
++ if (unlikely(e)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ }
++ break;
++ case AUFS_CTL_RDU_INO:
++ err = au_rdu_ino(file, &rdu);
++ break;
++
++ default:
++ /* err = -ENOTTY; */
++ err = -EINVAL;
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++#endif
+diff -Nur linux-2.6.36.orig/fs/aufs/rwsem.h linux-2.6.36/fs/aufs/rwsem.h
+--- linux-2.6.36.orig/fs/aufs/rwsem.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/rwsem.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,189 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * simple read-write semaphore wrappers
++ */
++
++#ifndef __AUFS_RWSEM_H__
++#define __AUFS_RWSEM_H__
++
++#ifdef __KERNEL__
++
++#include <linux/rwsem.h>
++#include "debug.h"
++
++struct au_rwsem {
++ struct rw_semaphore rwsem;
++#ifdef CONFIG_AUFS_DEBUG
++ /* just for debugging, not almighty counter */
++ atomic_t rcnt, wcnt;
++#endif
++};
++
++#ifdef CONFIG_AUFS_DEBUG
++#define AuDbgCntInit(rw) do { \
++ atomic_set(&(rw)->rcnt, 0); \
++ atomic_set(&(rw)->wcnt, 0); \
++ smp_mb(); /* atomic set */ \
++} while (0)
++
++#define AuDbgRcntInc(rw) atomic_inc(&(rw)->rcnt)
++#define AuDbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0)
++#define AuDbgWcntInc(rw) atomic_inc(&(rw)->wcnt)
++#define AuDbgWcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->wcnt) < 0)
++#else
++#define AuDbgCntInit(rw) do {} while (0)
++#define AuDbgRcntInc(rw) do {} while (0)
++#define AuDbgRcntDec(rw) do {} while (0)
++#define AuDbgWcntInc(rw) do {} while (0)
++#define AuDbgWcntDec(rw) do {} while (0)
++#endif /* CONFIG_AUFS_DEBUG */
++
++/* to debug easier, do not make them inlined functions */
++#define AuRwMustNoWaiters(rw) AuDebugOn(!list_empty(&(rw)->rwsem.wait_list))
++/* rwsem_is_locked() is unusable */
++#define AuRwMustReadLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0)
++#define AuRwMustWriteLock(rw) AuDebugOn(atomic_read(&(rw)->wcnt) <= 0)
++#define AuRwMustAnyLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0 \
++ && atomic_read(&(rw)->wcnt) <= 0)
++#define AuRwDestroy(rw) AuDebugOn(atomic_read(&(rw)->rcnt) \
++ || atomic_read(&(rw)->wcnt))
++
++#define au_rw_class(rw, key) lockdep_set_class(&(rw)->rwsem, key)
++
++static inline void au_rw_init(struct au_rwsem *rw)
++{
++ AuDbgCntInit(rw);
++ init_rwsem(&rw->rwsem);
++}
++
++static inline void au_rw_init_wlock(struct au_rwsem *rw)
++{
++ au_rw_init(rw);
++ down_write(&rw->rwsem);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_init_wlock_nested(struct au_rwsem *rw,
++ unsigned int lsc)
++{
++ au_rw_init(rw);
++ down_write_nested(&rw->rwsem, lsc);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_read_lock(struct au_rwsem *rw)
++{
++ down_read(&rw->rwsem);
++ AuDbgRcntInc(rw);
++}
++
++static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc)
++{
++ down_read_nested(&rw->rwsem, lsc);
++ AuDbgRcntInc(rw);
++}
++
++static inline void au_rw_read_unlock(struct au_rwsem *rw)
++{
++ AuRwMustReadLock(rw);
++ AuDbgRcntDec(rw);
++ up_read(&rw->rwsem);
++}
++
++static inline void au_rw_dgrade_lock(struct au_rwsem *rw)
++{
++ AuRwMustWriteLock(rw);
++ AuDbgRcntInc(rw);
++ AuDbgWcntDec(rw);
++ downgrade_write(&rw->rwsem);
++}
++
++static inline void au_rw_write_lock(struct au_rwsem *rw)
++{
++ down_write(&rw->rwsem);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_write_lock_nested(struct au_rwsem *rw,
++ unsigned int lsc)
++{
++ down_write_nested(&rw->rwsem, lsc);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_write_unlock(struct au_rwsem *rw)
++{
++ AuRwMustWriteLock(rw);
++ AuDbgWcntDec(rw);
++ up_write(&rw->rwsem);
++}
++
++/* why is not _nested version defined */
++static inline int au_rw_read_trylock(struct au_rwsem *rw)
++{
++ int ret = down_read_trylock(&rw->rwsem);
++ if (ret)
++ AuDbgRcntInc(rw);
++ return ret;
++}
++
++static inline int au_rw_write_trylock(struct au_rwsem *rw)
++{
++ int ret = down_write_trylock(&rw->rwsem);
++ if (ret)
++ AuDbgWcntInc(rw);
++ return ret;
++}
++
++#undef AuDbgCntInit
++#undef AuDbgRcntInc
++#undef AuDbgRcntDec
++#undef AuDbgWcntInc
++#undef AuDbgWcntDec
++
++#define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \
++static inline void prefix##_read_lock(param) \
++{ au_rw_read_lock(rwsem); } \
++static inline void prefix##_write_lock(param) \
++{ au_rw_write_lock(rwsem); } \
++static inline int prefix##_read_trylock(param) \
++{ return au_rw_read_trylock(rwsem); } \
++static inline int prefix##_write_trylock(param) \
++{ return au_rw_write_trylock(rwsem); }
++/* why is not _nested version defined */
++/* static inline void prefix##_read_trylock_nested(param, lsc)
++{ au_rw_read_trylock_nested(rwsem, lsc)); }
++static inline void prefix##_write_trylock_nestd(param, lsc)
++{ au_rw_write_trylock_nested(rwsem, lsc); } */
++
++#define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \
++static inline void prefix##_read_unlock(param) \
++{ au_rw_read_unlock(rwsem); } \
++static inline void prefix##_write_unlock(param) \
++{ au_rw_write_unlock(rwsem); } \
++static inline void prefix##_downgrade_lock(param) \
++{ au_rw_dgrade_lock(rwsem); }
++
++#define AuSimpleRwsemFuncs(prefix, param, rwsem) \
++ AuSimpleLockRwsemFuncs(prefix, param, rwsem) \
++ AuSimpleUnlockRwsemFuncs(prefix, param, rwsem)
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_RWSEM_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/sbinfo.c linux-2.6.36/fs/aufs/sbinfo.c
+--- linux-2.6.36.orig/fs/aufs/sbinfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/sbinfo.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,345 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * superblock private data
++ */
++
++#include <linux/jiffies.h>
++#include "aufs.h"
++
++/*
++ * they are necessary regardless sysfs is disabled.
++ */
++void au_si_free(struct kobject *kobj)
++{
++ struct au_sbinfo *sbinfo;
++ char *locked __maybe_unused; /* debug only */
++
++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
++ AuDebugOn(!list_empty(&sbinfo->si_plink.head));
++ AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len));
++
++ au_rw_write_lock(&sbinfo->si_rwsem);
++ au_br_free(sbinfo);
++ au_rw_write_unlock(&sbinfo->si_rwsem);
++
++ AuDebugOn(radix_tree_gang_lookup
++ (&sbinfo->au_si_pid.tree, (void **)&locked,
++ /*first_index*/PID_MAX_DEFAULT - 1,
++ /*max_items*/sizeof(locked)/sizeof(*locked)));
++
++ kfree(sbinfo->si_branch);
++ kfree(sbinfo->au_si_pid.bitmap);
++ mutex_destroy(&sbinfo->si_xib_mtx);
++ AuRwDestroy(&sbinfo->si_rwsem);
++
++ kfree(sbinfo);
++}
++
++int au_si_alloc(struct super_block *sb)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ static struct lock_class_key aufs_si;
++
++ err = -ENOMEM;
++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS);
++ if (unlikely(!sbinfo))
++ goto out;
++
++ BUILD_BUG_ON(sizeof(unsigned long) !=
++ sizeof(*sbinfo->au_si_pid.bitmap));
++ sbinfo->au_si_pid.bitmap = kcalloc(BITS_TO_LONGS(PID_MAX_DEFAULT),
++ sizeof(*sbinfo->au_si_pid.bitmap),
++ GFP_NOFS);
++ if (unlikely(!sbinfo->au_si_pid.bitmap))
++ goto out_sbinfo;
++
++ /* will be reallocated separately */
++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS);
++ if (unlikely(!sbinfo->si_branch))
++ goto out_pidmap;
++
++ err = sysaufs_si_init(sbinfo);
++ if (unlikely(err))
++ goto out_br;
++
++ au_nwt_init(&sbinfo->si_nowait);
++ au_rw_init_wlock(&sbinfo->si_rwsem);
++ au_rw_class(&sbinfo->si_rwsem, &aufs_si);
++ spin_lock_init(&sbinfo->au_si_pid.tree_lock);
++ INIT_RADIX_TREE(&sbinfo->au_si_pid.tree, GFP_ATOMIC | __GFP_NOFAIL);
++
++ atomic_long_set(&sbinfo->si_ninodes, 0);
++ atomic_long_set(&sbinfo->si_nfiles, 0);
++
++ sbinfo->si_bend = -1;
++
++ sbinfo->si_wbr_copyup = AuWbrCopyup_Def;
++ sbinfo->si_wbr_create = AuWbrCreate_Def;
++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup;
++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create;
++
++ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def);
++
++ mutex_init(&sbinfo->si_xib_mtx);
++ sbinfo->si_xino_brid = -1;
++ /* leave si_xib_last_pindex and si_xib_next_bit */
++
++ sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC);
++ sbinfo->si_rdblk = AUFS_RDBLK_DEF;
++ sbinfo->si_rdhash = AUFS_RDHASH_DEF;
++ sbinfo->si_dirwh = AUFS_DIRWH_DEF;
++
++ au_spl_init(&sbinfo->si_plink);
++ init_waitqueue_head(&sbinfo->si_plink_wq);
++ spin_lock_init(&sbinfo->si_plink_maint_lock);
++
++ /* leave other members for sysaufs and si_mnt. */
++ sbinfo->si_sb = sb;
++ sb->s_fs_info = sbinfo;
++ si_pid_set(sb);
++ au_debug_sbinfo_init(sbinfo);
++ return 0; /* success */
++
++out_br:
++ kfree(sbinfo->si_branch);
++out_pidmap:
++ kfree(sbinfo->au_si_pid.bitmap);
++out_sbinfo:
++ kfree(sbinfo);
++out:
++ return err;
++}
++
++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr)
++{
++ int err, sz;
++ struct au_branch **brp;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ err = -ENOMEM;
++ sz = sizeof(*brp) * (sbinfo->si_bend + 1);
++ if (unlikely(!sz))
++ sz = sizeof(*brp);
++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS);
++ if (brp) {
++ sbinfo->si_branch = brp;
++ err = 0;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++unsigned int au_sigen_inc(struct super_block *sb)
++{
++ unsigned int gen;
++
++ SiMustWriteLock(sb);
++
++ gen = ++au_sbi(sb)->si_generation;
++ au_update_digen(sb->s_root);
++ au_update_iigen(sb->s_root->d_inode);
++ sb->s_root->d_inode->i_version++;
++ return gen;
++}
++
++aufs_bindex_t au_new_br_id(struct super_block *sb)
++{
++ aufs_bindex_t br_id;
++ int i;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ for (i = 0; i <= AUFS_BRANCH_MAX; i++) {
++ br_id = ++sbinfo->si_last_br_id;
++ AuDebugOn(br_id < 0);
++ if (br_id && au_br_index(sb, br_id) < 0)
++ return br_id;
++ }
++
++ return -1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* it is ok that new 'nwt' tasks are appended while we are sleeping */
++int si_read_lock(struct super_block *sb, int flags)
++{
++ int err;
++
++ err = 0;
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++
++ si_noflush_read_lock(sb);
++ err = au_plink_maint(sb, flags);
++ if (unlikely(err))
++ si_read_unlock(sb);
++
++ return err;
++}
++
++int si_write_lock(struct super_block *sb, int flags)
++{
++ int err;
++
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++
++ si_noflush_write_lock(sb);
++ err = au_plink_maint(sb, flags);
++ if (unlikely(err))
++ si_write_unlock(sb);
++
++ return err;
++}
++
++/* dentry and super_block lock. call at entry point */
++int aufs_read_lock(struct dentry *dentry, int flags)
++{
++ int err;
++ struct super_block *sb;
++
++ sb = dentry->d_sb;
++ err = si_read_lock(sb, flags);
++ if (unlikely(err))
++ goto out;
++
++ if (au_ftest_lock(flags, DW))
++ di_write_lock_child(dentry);
++ else
++ di_read_lock_child(dentry, flags);
++
++ if (au_ftest_lock(flags, GEN)) {
++ err = au_digen_test(dentry, au_sigen(sb));
++ AuDebugOn(!err && au_dbrange_test(dentry));
++ if (unlikely(err))
++ aufs_read_unlock(dentry, flags);
++ }
++
++out:
++ return err;
++}
++
++void aufs_read_unlock(struct dentry *dentry, int flags)
++{
++ if (au_ftest_lock(flags, DW))
++ di_write_unlock(dentry);
++ else
++ di_read_unlock(dentry, flags);
++ si_read_unlock(dentry->d_sb);
++}
++
++void aufs_write_lock(struct dentry *dentry)
++{
++ si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW);
++ di_write_lock_child(dentry);
++}
++
++void aufs_write_unlock(struct dentry *dentry)
++{
++ di_write_unlock(dentry);
++ si_write_unlock(dentry->d_sb);
++}
++
++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags)
++{
++ int err;
++ unsigned int sigen;
++ struct super_block *sb;
++
++ sb = d1->d_sb;
++ err = si_read_lock(sb, flags);
++ if (unlikely(err))
++ goto out;
++
++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR));
++
++ if (au_ftest_lock(flags, GEN)) {
++ sigen = au_sigen(sb);
++ err = au_digen_test(d1, sigen);
++ AuDebugOn(!err && au_dbrange_test(d1));
++ if (!err) {
++ err = au_digen_test(d2, sigen);
++ AuDebugOn(!err && au_dbrange_test(d2));
++ }
++ if (unlikely(err))
++ aufs_read_and_write_unlock2(d1, d2);
++ }
++
++out:
++ return err;
++}
++
++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2)
++{
++ di_write_unlock2(d1, d2);
++ si_read_unlock(d1->d_sb);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int si_pid_test_slow(struct super_block *sb)
++{
++ void *p;
++
++ rcu_read_lock();
++ p = radix_tree_lookup(&au_sbi(sb)->au_si_pid.tree, current->pid);
++ rcu_read_unlock();
++
++ return (long)p;
++}
++
++void si_pid_set_slow(struct super_block *sb)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++
++ AuDebugOn(si_pid_test_slow(sb));
++
++ sbinfo = au_sbi(sb);
++ err = radix_tree_preload(GFP_NOFS | __GFP_NOFAIL);
++ AuDebugOn(err);
++ spin_lock(&sbinfo->au_si_pid.tree_lock);
++ err = radix_tree_insert(&sbinfo->au_si_pid.tree, current->pid,
++ (void *)1);
++ spin_unlock(&sbinfo->au_si_pid.tree_lock);
++ AuDebugOn(err);
++ radix_tree_preload_end();
++}
++
++void si_pid_clr_slow(struct super_block *sb)
++{
++ void *p;
++ struct au_sbinfo *sbinfo;
++
++ AuDebugOn(!si_pid_test_slow(sb));
++
++ sbinfo = au_sbi(sb);
++ spin_lock(&sbinfo->au_si_pid.tree_lock);
++ p = radix_tree_delete(&sbinfo->au_si_pid.tree, current->pid);
++ spin_unlock(&sbinfo->au_si_pid.tree_lock);
++ AuDebugOn(1 != (long)p);
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/spl.h linux-2.6.36/fs/aufs/spl.h
+--- linux-2.6.36.orig/fs/aufs/spl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/spl.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,66 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * simple list protected by a spinlock
++ */
++
++#ifndef __AUFS_SPL_H__
++#define __AUFS_SPL_H__
++
++#ifdef __KERNEL__
++
++#include <linux/spinlock.h>
++#include <linux/list.h>
++#include <linux/rculist.h>
++
++struct au_splhead {
++ spinlock_t spin;
++ struct list_head head;
++};
++
++static inline void au_spl_init(struct au_splhead *spl)
++{
++ spin_lock_init(&spl->spin);
++ INIT_LIST_HEAD(&spl->head);
++}
++
++static inline void au_spl_add(struct list_head *list, struct au_splhead *spl)
++{
++ spin_lock(&spl->spin);
++ list_add(list, &spl->head);
++ spin_unlock(&spl->spin);
++}
++
++static inline void au_spl_del(struct list_head *list, struct au_splhead *spl)
++{
++ spin_lock(&spl->spin);
++ list_del(list);
++ spin_unlock(&spl->spin);
++}
++
++static inline void au_spl_del_rcu(struct list_head *list,
++ struct au_splhead *spl)
++{
++ spin_lock(&spl->spin);
++ list_del_rcu(list);
++ spin_unlock(&spl->spin);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_SPL_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/super.c linux-2.6.36/fs/aufs/super.c
+--- linux-2.6.36.orig/fs/aufs/super.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/super.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,913 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * mount and super_block operations
++ */
++
++#include <linux/buffer_head.h>
++#include <linux/jiffies.h>
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include <linux/statfs.h>
++#include <linux/vmalloc.h>
++#include <linux/writeback.h>
++#include "aufs.h"
++
++/*
++ * super_operations
++ */
++static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused)
++{
++ struct au_icntnr *c;
++
++ c = au_cache_alloc_icntnr();
++ if (c) {
++ au_icntnr_init(c);
++ c->vfs_inode.i_version = 1; /* sigen(sb); */
++ c->iinfo.ii_hinode = NULL;
++ return &c->vfs_inode;
++ }
++ return NULL;
++}
++
++static void aufs_destroy_inode(struct inode *inode)
++{
++ au_iinfo_fin(inode);
++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode));
++}
++
++struct inode *au_iget_locked(struct super_block *sb, ino_t ino)
++{
++ struct inode *inode;
++ int err;
++
++ inode = iget_locked(sb, ino);
++ if (unlikely(!inode)) {
++ inode = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++ if (!(inode->i_state & I_NEW))
++ goto out;
++
++ err = au_xigen_new(inode);
++ if (!err)
++ err = au_iinfo_init(inode);
++ if (!err)
++ inode->i_version++;
++ else {
++ iget_failed(inode);
++ inode = ERR_PTR(err);
++ }
++
++out:
++ /* never return NULL */
++ AuDebugOn(!inode);
++ AuTraceErrPtr(inode);
++ return inode;
++}
++
++/* lock free root dinfo */
++static int au_show_brs(struct seq_file *seq, struct super_block *sb)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct path path;
++ struct au_hdentry *hdp;
++ struct au_branch *br;
++
++ err = 0;
++ bend = au_sbend(sb);
++ hdp = au_di(sb->s_root)->di_hdentry;
++ for (bindex = 0; !err && bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ path.mnt = br->br_mnt;
++ path.dentry = hdp[bindex].hd_dentry;
++ err = au_seq_path(seq, &path);
++ if (err > 0)
++ err = seq_printf(seq, "=%s",
++ au_optstr_br_perm(br->br_perm));
++ if (!err && bindex != bend)
++ err = seq_putc(seq, ':');
++ }
++
++ return err;
++}
++
++static void au_show_wbr_create(struct seq_file *m, int v,
++ struct au_sbinfo *sbinfo)
++{
++ const char *pat;
++
++ AuRwMustAnyLock(&sbinfo->si_rwsem);
++
++ seq_printf(m, ",create=");
++ pat = au_optstr_wbr_create(v);
++ switch (v) {
++ case AuWbrCreate_TDP:
++ case AuWbrCreate_RR:
++ case AuWbrCreate_MFS:
++ case AuWbrCreate_PMFS:
++ seq_printf(m, pat);
++ break;
++ case AuWbrCreate_MFSV:
++ seq_printf(m, /*pat*/"mfs:%lu",
++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
++ / MSEC_PER_SEC);
++ break;
++ case AuWbrCreate_PMFSV:
++ seq_printf(m, /*pat*/"pmfs:%lu",
++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
++ / MSEC_PER_SEC);
++ break;
++ case AuWbrCreate_MFSRR:
++ seq_printf(m, /*pat*/"mfsrr:%llu",
++ sbinfo->si_wbr_mfs.mfsrr_watermark);
++ break;
++ case AuWbrCreate_MFSRRV:
++ seq_printf(m, /*pat*/"mfsrr:%llu:%lu",
++ sbinfo->si_wbr_mfs.mfsrr_watermark,
++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
++ / MSEC_PER_SEC);
++ break;
++ }
++}
++
++static int au_show_xino(struct seq_file *seq, struct vfsmount *mnt)
++{
++#ifdef CONFIG_SYSFS
++ return 0;
++#else
++ int err;
++ const int len = sizeof(AUFS_XINO_FNAME) - 1;
++ aufs_bindex_t bindex, brid;
++ struct super_block *sb;
++ struct qstr *name;
++ struct file *f;
++ struct dentry *d, *h_root;
++ struct au_hdentry *hdp;
++
++ AuRwMustAnyLock(&sbinfo->si_rwsem);
++
++ err = 0;
++ sb = mnt->mnt_sb;
++ f = au_sbi(sb)->si_xib;
++ if (!f)
++ goto out;
++
++ /* stop printing the default xino path on the first writable branch */
++ h_root = NULL;
++ brid = au_xino_brid(sb);
++ if (brid >= 0) {
++ bindex = au_br_index(sb, brid);
++ hdp = au_di(sb->s_root)->di_hdentry;
++ h_root = hdp[0 + bindex].hd_dentry;
++ }
++ d = f->f_dentry;
++ name = &d->d_name;
++ /* safe ->d_parent because the file is unlinked */
++ if (d->d_parent == h_root
++ && name->len == len
++ && !memcmp(name->name, AUFS_XINO_FNAME, len))
++ goto out;
++
++ seq_puts(seq, ",xino=");
++ err = au_xino_path(seq, f);
++
++out:
++ return err;
++#endif
++}
++
++/* seq_file will re-call me in case of too long string */
++static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt)
++{
++ int err;
++ unsigned int mnt_flags, v;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++#define AuBool(name, str) do { \
++ v = au_opt_test(mnt_flags, name); \
++ if (v != au_opt_test(AuOpt_Def, name)) \
++ seq_printf(m, ",%s" #str, v ? "" : "no"); \
++} while (0)
++
++#define AuStr(name, str) do { \
++ v = mnt_flags & AuOptMask_##name; \
++ if (v != (AuOpt_Def & AuOptMask_##name)) \
++ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \
++} while (0)
++
++#define AuUInt(name, str, val) do { \
++ if (val != AUFS_##name##_DEF) \
++ seq_printf(m, "," #str "=%u", val); \
++} while (0)
++
++ /* lock free root dinfo */
++ sb = mnt->mnt_sb;
++ si_noflush_read_lock(sb);
++ sbinfo = au_sbi(sb);
++ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo));
++
++ mnt_flags = au_mntflags(sb);
++ if (au_opt_test(mnt_flags, XINO)) {
++ err = au_show_xino(m, mnt);
++ if (unlikely(err))
++ goto out;
++ } else
++ seq_puts(m, ",noxino");
++
++ AuBool(TRUNC_XINO, trunc_xino);
++ AuStr(UDBA, udba);
++ AuBool(SHWH, shwh);
++ AuBool(PLINK, plink);
++ AuBool(DIO, dio);
++ /* AuBool(DIRPERM1, dirperm1); */
++ /* AuBool(REFROF, refrof); */
++
++ v = sbinfo->si_wbr_create;
++ if (v != AuWbrCreate_Def)
++ au_show_wbr_create(m, v, sbinfo);
++
++ v = sbinfo->si_wbr_copyup;
++ if (v != AuWbrCopyup_Def)
++ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v));
++
++ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ);
++ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ))
++ seq_printf(m, ",diropq=%c", v ? 'a' : 'w');
++
++ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh);
++
++ v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC;
++ AuUInt(RDCACHE, rdcache, v);
++
++ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk);
++ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash);
++
++ AuBool(SUM, sum);
++ /* AuBool(SUM_W, wsum); */
++ AuBool(WARN_PERM, warn_perm);
++ AuBool(VERBOSE, verbose);
++
++out:
++ /* be sure to print "br:" last */
++ if (!sysaufs_brs) {
++ seq_puts(m, ",br:");
++ au_show_brs(m, sb);
++ }
++ si_read_unlock(sb);
++ return 0;
++
++#undef AuBool
++#undef AuStr
++#undef AuUInt
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* sum mode which returns the summation for statfs(2) */
++
++static u64 au_add_till_max(u64 a, u64 b)
++{
++ u64 old;
++
++ old = a;
++ a += b;
++ if (old < a)
++ return a;
++ return ULLONG_MAX;
++}
++
++static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf)
++{
++ int err;
++ u64 blocks, bfree, bavail, files, ffree;
++ aufs_bindex_t bend, bindex, i;
++ unsigned char shared;
++ struct path h_path;
++ struct super_block *h_sb;
++
++ blocks = 0;
++ bfree = 0;
++ bavail = 0;
++ files = 0;
++ ffree = 0;
++
++ err = 0;
++ bend = au_sbend(sb);
++ for (bindex = bend; bindex >= 0; bindex--) {
++ h_path.mnt = au_sbr_mnt(sb, bindex);
++ h_sb = h_path.mnt->mnt_sb;
++ shared = 0;
++ for (i = bindex + 1; !shared && i <= bend; i++)
++ shared = (au_sbr_sb(sb, i) == h_sb);
++ if (shared)
++ continue;
++
++ /* sb->s_root for NFS is unreliable */
++ h_path.dentry = h_path.mnt->mnt_root;
++ err = vfs_statfs(&h_path, buf);
++ if (unlikely(err))
++ goto out;
++
++ blocks = au_add_till_max(blocks, buf->f_blocks);
++ bfree = au_add_till_max(bfree, buf->f_bfree);
++ bavail = au_add_till_max(bavail, buf->f_bavail);
++ files = au_add_till_max(files, buf->f_files);
++ ffree = au_add_till_max(ffree, buf->f_ffree);
++ }
++
++ buf->f_blocks = blocks;
++ buf->f_bfree = bfree;
++ buf->f_bavail = bavail;
++ buf->f_files = files;
++ buf->f_ffree = ffree;
++
++out:
++ return err;
++}
++
++static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ int err;
++ struct path h_path;
++ struct super_block *sb;
++
++ /* lock free root dinfo */
++ sb = dentry->d_sb;
++ si_noflush_read_lock(sb);
++ if (!au_opt_test(au_mntflags(sb), SUM)) {
++ /* sb->s_root for NFS is unreliable */
++ h_path.mnt = au_sbr_mnt(sb, 0);
++ h_path.dentry = h_path.mnt->mnt_root;
++ err = vfs_statfs(&h_path, buf);
++ } else
++ err = au_statfs_sum(sb, buf);
++ si_read_unlock(sb);
++
++ if (!err) {
++ buf->f_type = AUFS_SUPER_MAGIC;
++ buf->f_namelen = AUFS_MAX_NAMELEN;
++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid));
++ }
++ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* final actions when unmounting a file system */
++static void aufs_put_super(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = au_sbi(sb);
++ if (!sbinfo)
++ return;
++
++ dbgaufs_si_fin(sbinfo);
++ kobject_put(&sbinfo->si_kobj);
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_array_free(void *array)
++{
++ if (array) {
++ if (!is_vmalloc_addr(array))
++ kfree(array);
++ else
++ vfree(array);
++ }
++}
++
++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg)
++{
++ void *array;
++ unsigned long long n;
++
++ array = NULL;
++ n = 0;
++ if (!*hint)
++ goto out;
++
++ if (*hint > ULLONG_MAX / sizeof(array)) {
++ array = ERR_PTR(-EMFILE);
++ pr_err("hint %llu\n", *hint);
++ goto out;
++ }
++
++ array = kmalloc(sizeof(array) * *hint, GFP_NOFS);
++ if (unlikely(!array))
++ array = vmalloc(sizeof(array) * *hint);
++ if (unlikely(!array)) {
++ array = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++
++ n = cb(array, *hint, arg);
++ AuDebugOn(n > *hint);
++
++out:
++ *hint = n;
++ return array;
++}
++
++static unsigned long long au_iarray_cb(void *a,
++ unsigned long long max __maybe_unused,
++ void *arg)
++{
++ unsigned long long n;
++ struct inode **p, *inode;
++ struct list_head *head;
++
++ n = 0;
++ p = a;
++ head = arg;
++ spin_lock(&inode_lock);
++ list_for_each_entry(inode, head, i_sb_list) {
++ if (!is_bad_inode(inode)
++ && au_ii(inode)->ii_bstart >= 0) {
++ au_igrab(inode);
++ *p++ = inode;
++ n++;
++ AuDebugOn(n > max);
++ }
++ }
++ spin_unlock(&inode_lock);
++
++ return n;
++}
++
++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max)
++{
++ *max = atomic_long_read(&au_sbi(sb)->si_ninodes);
++ return au_array_alloc(max, au_iarray_cb, &sb->s_inodes);
++}
++
++void au_iarray_free(struct inode **a, unsigned long long max)
++{
++ unsigned long long ull;
++
++ for (ull = 0; ull < max; ull++)
++ iput(a[ull]);
++ au_array_free(a);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * refresh dentry and inode at remount time.
++ */
++/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */
++static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags,
++ struct dentry *parent)
++{
++ int err;
++
++ di_write_lock_child(dentry);
++ di_read_lock_parent(parent, AuLock_IR);
++ err = au_refresh_dentry(dentry, parent);
++ if (!err && dir_flags)
++ au_hn_reset(dentry->d_inode, dir_flags);
++ di_read_unlock(parent, AuLock_IR);
++ di_write_unlock(dentry);
++
++ return err;
++}
++
++static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen,
++ struct au_sbinfo *sbinfo,
++ const unsigned int dir_flags)
++{
++ int err;
++ struct dentry *parent;
++ struct inode *inode;
++
++ err = 0;
++ parent = dget_parent(dentry);
++ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) {
++ inode = dentry->d_inode;
++ if (inode) {
++ if (!S_ISDIR(inode->i_mode))
++ err = au_do_refresh(dentry, /*dir_flags*/0,
++ parent);
++ else {
++ err = au_do_refresh(dentry, dir_flags, parent);
++ if (unlikely(err))
++ au_fset_si(sbinfo, FAILED_REFRESH_DIR);
++ }
++ } else
++ err = au_do_refresh(dentry, /*dir_flags*/0, parent);
++ AuDbgDentry(dentry);
++ }
++ dput(parent);
++
++ AuTraceErr(err);
++ return err;
++}
++
++static int au_refresh_d(struct super_block *sb)
++{
++ int err, i, j, ndentry, e;
++ unsigned int sigen;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries, *d;
++ struct au_sbinfo *sbinfo;
++ struct dentry *root = sb->s_root;
++ const unsigned int dir_flags = au_hi_flags(root->d_inode, /*isdir*/1);
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_dcsub_pages(&dpages, root, NULL, NULL);
++ if (unlikely(err))
++ goto out_dpages;
++
++ sigen = au_sigen(sb);
++ sbinfo = au_sbi(sb);
++ for (i = 0; i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ ndentry = dpage->ndentry;
++ for (j = 0; j < ndentry; j++) {
++ d = dentries[j];
++ e = au_do_refresh_d(d, sigen, sbinfo, dir_flags);
++ if (unlikely(e && !err))
++ err = e;
++ /* go on even err */
++ }
++ }
++
++out_dpages:
++ au_dpages_free(&dpages);
++out:
++ return err;
++}
++
++static int au_refresh_i(struct super_block *sb)
++{
++ int err, e;
++ unsigned int sigen;
++ unsigned long long max, ull;
++ struct inode *inode, **array;
++
++ array = au_iarray_alloc(sb, &max);
++ err = PTR_ERR(array);
++ if (IS_ERR(array))
++ goto out;
++
++ err = 0;
++ sigen = au_sigen(sb);
++ for (ull = 0; ull < max; ull++) {
++ inode = array[ull];
++ if (au_iigen(inode) != sigen) {
++ ii_write_lock_child(inode);
++ e = au_refresh_hinode_self(inode);
++ ii_write_unlock(inode);
++ if (unlikely(e)) {
++ pr_err("error %d, i%lu\n", e, inode->i_ino);
++ if (!err)
++ err = e;
++ /* go on even if err */
++ }
++ }
++ }
++
++ au_iarray_free(array, max);
++
++out:
++ return err;
++}
++
++static void au_remount_refresh(struct super_block *sb)
++{
++ int err, e;
++ unsigned int udba;
++ aufs_bindex_t bindex, bend;
++ struct dentry *root;
++ struct inode *inode;
++ struct au_branch *br;
++
++ au_sigen_inc(sb);
++ au_fclr_si(au_sbi(sb), FAILED_REFRESH_DIR);
++
++ root = sb->s_root;
++ DiMustNoWaiters(root);
++ inode = root->d_inode;
++ IiMustNoWaiters(inode);
++
++ udba = au_opt_udba(sb);
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ err = au_hnotify_reset_br(udba, br, br->br_perm);
++ if (unlikely(err))
++ AuIOErr("hnotify failed on br %d, %d, ignored\n",
++ bindex, err);
++ /* go on even if err */
++ }
++ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1));
++
++ di_write_unlock(root);
++ err = au_refresh_d(sb);
++ e = au_refresh_i(sb);
++ if (unlikely(e && !err))
++ err = e;
++ /* aufs_write_lock() calls ..._child() */
++ di_write_lock_child(root);
++
++ au_cpup_attr_all(inode, /*force*/1);
++
++ if (unlikely(err))
++ AuIOErr("refresh failed, ignored, %d\n", err);
++}
++
++/* stop extra interpretation of errno in mount(8), and strange error messages */
++static int cvt_err(int err)
++{
++ AuTraceErr(err);
++
++ switch (err) {
++ case -ENOENT:
++ case -ENOTDIR:
++ case -EEXIST:
++ case -EIO:
++ err = -EINVAL;
++ }
++ return err;
++}
++
++static int aufs_remount_fs(struct super_block *sb, int *flags, char *data)
++{
++ int err, do_dx;
++ unsigned int mntflags;
++ struct au_opts opts;
++ struct dentry *root;
++ struct inode *inode;
++ struct au_sbinfo *sbinfo;
++
++ err = 0;
++ root = sb->s_root;
++ if (!data || !*data) {
++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (!err) {
++ di_write_lock_child(root);
++ err = au_opts_verify(sb, *flags, /*pending*/0);
++ aufs_write_unlock(root);
++ }
++ goto out;
++ }
++
++ err = -ENOMEM;
++ memset(&opts, 0, sizeof(opts));
++ opts.opt = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!opts.opt))
++ goto out;
++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt);
++ opts.flags = AuOpts_REMOUNT;
++ opts.sb_flags = *flags;
++
++ /* parse it before aufs lock */
++ err = au_opts_parse(sb, data, &opts);
++ if (unlikely(err))
++ goto out_opts;
++
++ sbinfo = au_sbi(sb);
++ inode = root->d_inode;
++ mutex_lock(&inode->i_mutex);
++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out_mtx;
++ di_write_lock_child(root);
++
++ /* au_opts_remount() may return an error */
++ err = au_opts_remount(sb, &opts);
++ au_opts_free(&opts);
++
++ if (au_ftest_opts(opts.flags, REFRESH))
++ au_remount_refresh(sb);
++
++ if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) {
++ mntflags = au_mntflags(sb);
++ do_dx = !!au_opt_test(mntflags, DIO);
++ au_dy_arefresh(do_dx);
++ }
++
++ aufs_write_unlock(root);
++
++out_mtx:
++ mutex_unlock(&inode->i_mutex);
++out_opts:
++ free_page((unsigned long)opts.opt);
++out:
++ err = cvt_err(err);
++ AuTraceErr(err);
++ return err;
++}
++
++static const struct super_operations aufs_sop = {
++ .alloc_inode = aufs_alloc_inode,
++ .destroy_inode = aufs_destroy_inode,
++ /* always deleting, no clearing */
++ .drop_inode = generic_delete_inode,
++ .show_options = aufs_show_options,
++ .statfs = aufs_statfs,
++ .put_super = aufs_put_super,
++ .remount_fs = aufs_remount_fs
++};
++
++/* ---------------------------------------------------------------------- */
++
++static int alloc_root(struct super_block *sb)
++{
++ int err;
++ struct inode *inode;
++ struct dentry *root;
++
++ err = -ENOMEM;
++ inode = au_iget_locked(sb, AUFS_ROOT_INO);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out;
++
++ inode->i_op = &aufs_dir_iop;
++ inode->i_fop = &aufs_dir_fop;
++ inode->i_mode = S_IFDIR;
++ inode->i_nlink = 2;
++ unlock_new_inode(inode);
++
++ root = d_alloc_root(inode);
++ if (unlikely(!root))
++ goto out_iput;
++ err = PTR_ERR(root);
++ if (IS_ERR(root))
++ goto out_iput;
++
++ err = au_di_init(root);
++ if (!err) {
++ sb->s_root = root;
++ return 0; /* success */
++ }
++ dput(root);
++ goto out; /* do not iput */
++
++out_iput:
++ iget_failed(inode);
++out:
++ return err;
++
++}
++
++static int aufs_fill_super(struct super_block *sb, void *raw_data,
++ int silent __maybe_unused)
++{
++ int err;
++ struct au_opts opts;
++ struct dentry *root;
++ struct inode *inode;
++ char *arg = raw_data;
++
++ if (unlikely(!arg || !*arg)) {
++ err = -EINVAL;
++ pr_err("no arg\n");
++ goto out;
++ }
++
++ err = -ENOMEM;
++ memset(&opts, 0, sizeof(opts));
++ opts.opt = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!opts.opt))
++ goto out;
++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt);
++ opts.sb_flags = sb->s_flags;
++
++ err = au_si_alloc(sb);
++ if (unlikely(err))
++ goto out_opts;
++
++ /* all timestamps always follow the ones on the branch */
++ sb->s_flags |= MS_NOATIME | MS_NODIRATIME;
++ sb->s_op = &aufs_sop;
++ sb->s_magic = AUFS_SUPER_MAGIC;
++ sb->s_maxbytes = 0;
++ au_export_init(sb);
++
++ err = alloc_root(sb);
++ if (unlikely(err)) {
++ si_write_unlock(sb);
++ goto out_info;
++ }
++ root = sb->s_root;
++ inode = root->d_inode;
++
++ /*
++ * actually we can parse options regardless aufs lock here.
++ * but at remount time, parsing must be done before aufs lock.
++ * so we follow the same rule.
++ */
++ ii_write_lock_parent(inode);
++ aufs_write_unlock(root);
++ err = au_opts_parse(sb, arg, &opts);
++ if (unlikely(err))
++ goto out_root;
++
++ /* lock vfs_inode first, then aufs. */
++ mutex_lock(&inode->i_mutex);
++ aufs_write_lock(root);
++ err = au_opts_mount(sb, &opts);
++ au_opts_free(&opts);
++ aufs_write_unlock(root);
++ mutex_unlock(&inode->i_mutex);
++ if (!err)
++ goto out_opts; /* success */
++
++out_root:
++ dput(root);
++ sb->s_root = NULL;
++out_info:
++ kobject_put(&au_sbi(sb)->si_kobj);
++ sb->s_fs_info = NULL;
++out_opts:
++ free_page((unsigned long)opts.opt);
++out:
++ AuTraceErr(err);
++ err = cvt_err(err);
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_get_sb(struct file_system_type *fs_type, int flags,
++ const char *dev_name __maybe_unused, void *raw_data,
++ struct vfsmount *mnt)
++{
++ int err;
++ struct super_block *sb;
++
++ /* all timestamps always follow the ones on the branch */
++ /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */
++ err = get_sb_nodev(fs_type, flags, raw_data, aufs_fill_super, mnt);
++ if (!err) {
++ sb = mnt->mnt_sb;
++ si_write_lock(sb, !AuLock_FLUSH);
++ sysaufs_brs_add(sb, 0);
++ si_write_unlock(sb);
++ au_sbilist_add(sb);
++ }
++ return err;
++}
++
++static void aufs_kill_sb(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = au_sbi(sb);
++ if (sbinfo) {
++ au_sbilist_del(sb);
++ aufs_write_lock(sb->s_root);
++ if (sbinfo->si_wbr_create_ops->fin)
++ sbinfo->si_wbr_create_ops->fin(sb);
++ if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) {
++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE);
++ au_remount_refresh(sb);
++ }
++ if (au_opt_test(sbinfo->si_mntflags, PLINK))
++ au_plink_put(sb, /*verbose*/1);
++ au_xino_clr(sb);
++ aufs_write_unlock(sb->s_root);
++ au_nwt_flush(&sbinfo->si_nowait);
++ }
++ generic_shutdown_super(sb);
++}
++
++struct file_system_type aufs_fs_type = {
++ .name = AUFS_FSTYPE,
++ .fs_flags =
++ FS_RENAME_DOES_D_MOVE /* a race between rename and others */
++ | FS_REVAL_DOT, /* for NFS branch and udba */
++ .get_sb = aufs_get_sb,
++ .kill_sb = aufs_kill_sb,
++ /* no need to __module_get() and module_put(). */
++ .owner = THIS_MODULE,
++};
+diff -Nur linux-2.6.36.orig/fs/aufs/super.h linux-2.6.36/fs/aufs/super.h
+--- linux-2.6.36.orig/fs/aufs/super.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/super.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,527 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * super_block operations
++ */
++
++#ifndef __AUFS_SUPER_H__
++#define __AUFS_SUPER_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++#include "spl.h"
++#include "wkq.h"
++
++typedef ssize_t (*au_readf_t)(struct file *, char __user *, size_t, loff_t *);
++typedef ssize_t (*au_writef_t)(struct file *, const char __user *, size_t,
++ loff_t *);
++
++/* policies to select one among multiple writable branches */
++struct au_wbr_copyup_operations {
++ int (*copyup)(struct dentry *dentry);
++};
++
++struct au_wbr_create_operations {
++ int (*create)(struct dentry *dentry, int isdir);
++ int (*init)(struct super_block *sb);
++ int (*fin)(struct super_block *sb);
++};
++
++struct au_wbr_mfs {
++ struct mutex mfs_lock; /* protect this structure */
++ unsigned long mfs_jiffy;
++ unsigned long mfs_expire;
++ aufs_bindex_t mfs_bindex;
++
++ unsigned long long mfsrr_bytes;
++ unsigned long long mfsrr_watermark;
++};
++
++struct au_branch;
++struct au_sbinfo {
++ /* nowait tasks in the system-wide workqueue */
++ struct au_nowait_tasks si_nowait;
++
++ /*
++ * tried sb->s_umount, but failed due to the dependecy between i_mutex.
++ * rwsem for au_sbinfo is necessary.
++ */
++ struct au_rwsem si_rwsem;
++
++ /* prevent recursive locking in deleting inode */
++ struct {
++ unsigned long *bitmap;
++ spinlock_t tree_lock;
++ struct radix_tree_root tree;
++ } au_si_pid;
++
++ /*
++ * dirty approach to protect sb->sb_inodes and ->s_files from remount.
++ */
++ atomic_long_t si_ninodes, si_nfiles;
++
++ /* branch management */
++ unsigned int si_generation;
++
++ /* see above flags */
++ unsigned char au_si_status;
++
++ aufs_bindex_t si_bend;
++
++ /* dirty trick to keep br_id plus */
++ unsigned int si_last_br_id :
++ sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1;
++ struct au_branch **si_branch;
++
++ /* policy to select a writable branch */
++ unsigned char si_wbr_copyup;
++ unsigned char si_wbr_create;
++ struct au_wbr_copyup_operations *si_wbr_copyup_ops;
++ struct au_wbr_create_operations *si_wbr_create_ops;
++
++ /* round robin */
++ atomic_t si_wbr_rr_next;
++
++ /* most free space */
++ struct au_wbr_mfs si_wbr_mfs;
++
++ /* mount flags */
++ /* include/asm-ia64/siginfo.h defines a macro named si_flags */
++ unsigned int si_mntflags;
++
++ /* external inode number (bitmap and translation table) */
++ au_readf_t si_xread;
++ au_writef_t si_xwrite;
++ struct file *si_xib;
++ struct mutex si_xib_mtx; /* protect xib members */
++ unsigned long *si_xib_buf;
++ unsigned long si_xib_last_pindex;
++ int si_xib_next_bit;
++ aufs_bindex_t si_xino_brid;
++ /* reserved for future use */
++ /* unsigned long long si_xib_limit; */ /* Max xib file size */
++
++#ifdef CONFIG_AUFS_EXPORT
++ /* i_generation */
++ struct file *si_xigen;
++ atomic_t si_xigen_next;
++#endif
++
++ /* vdir parameters */
++ unsigned long si_rdcache; /* max cache time in jiffies */
++ unsigned int si_rdblk; /* deblk size */
++ unsigned int si_rdhash; /* hash size */
++
++ /*
++ * If the number of whiteouts are larger than si_dirwh, leave all of
++ * them after au_whtmp_ren to reduce the cost of rmdir(2).
++ * future fsck.aufs or kernel thread will remove them later.
++ * Otherwise, remove all whiteouts and the dir in rmdir(2).
++ */
++ unsigned int si_dirwh;
++
++ /*
++ * rename(2) a directory with all children.
++ */
++ /* reserved for future use */
++ /* int si_rendir; */
++
++ /* pseudo_link list */
++ struct au_splhead si_plink;
++ wait_queue_head_t si_plink_wq;
++ spinlock_t si_plink_maint_lock;
++ pid_t si_plink_maint_pid;
++
++ /*
++ * sysfs and lifetime management.
++ * this is not a small structure and it may be a waste of memory in case
++ * of sysfs is disabled, particulary when many aufs-es are mounted.
++ * but using sysfs is majority.
++ */
++ struct kobject si_kobj;
++#ifdef CONFIG_DEBUG_FS
++ struct dentry *si_dbgaufs, *si_dbgaufs_xib;
++#ifdef CONFIG_AUFS_EXPORT
++ struct dentry *si_dbgaufs_xigen;
++#endif
++#endif
++
++#ifdef CONFIG_AUFS_SBILIST
++ struct list_head si_list;
++#endif
++
++ /* dirty, necessary for unmounting, sysfs and sysrq */
++ struct super_block *si_sb;
++};
++
++/* sbinfo status flags */
++/*
++ * set true when refresh_dirs() failed at remount time.
++ * then try refreshing dirs at access time again.
++ * if it is false, refreshing dirs at access time is unnecesary
++ */
++#define AuSi_FAILED_REFRESH_DIR 1
++static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi,
++ unsigned int flag)
++{
++ AuRwMustAnyLock(&sbi->si_rwsem);
++ return sbi->au_si_status & flag;
++}
++#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name)
++#define au_fset_si(sbinfo, name) do { \
++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \
++ (sbinfo)->au_si_status |= AuSi_##name; \
++} while (0)
++#define au_fclr_si(sbinfo, name) do { \
++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \
++ (sbinfo)->au_si_status &= ~AuSi_##name; \
++} while (0)
++
++/* ---------------------------------------------------------------------- */
++
++/* policy to select one among writable branches */
++#define AuWbrCopyup(sbinfo, ...) \
++ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__))
++#define AuWbrCreate(sbinfo, ...) \
++ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__))
++
++/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */
++#define AuLock_DW 1 /* write-lock dentry */
++#define AuLock_IR (1 << 1) /* read-lock inode */
++#define AuLock_IW (1 << 2) /* write-lock inode */
++#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */
++#define AuLock_DIR (1 << 4) /* target is a dir */
++#define AuLock_NOPLM (1 << 5) /* return err in plm mode */
++#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */
++#define AuLock_GEN (1 << 7) /* test digen/iigen */
++#define au_ftest_lock(flags, name) ((flags) & AuLock_##name)
++#define au_fset_lock(flags, name) \
++ do { (flags) |= AuLock_##name; } while (0)
++#define au_fclr_lock(flags, name) \
++ do { (flags) &= ~AuLock_##name; } while (0)
++
++/* ---------------------------------------------------------------------- */
++
++/* super.c */
++extern struct file_system_type aufs_fs_type;
++struct inode *au_iget_locked(struct super_block *sb, ino_t ino);
++typedef unsigned long long (*au_arraycb_t)(void *array, unsigned long long max,
++ void *arg);
++void au_array_free(void *array);
++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg);
++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max);
++void au_iarray_free(struct inode **a, unsigned long long max);
++
++/* sbinfo.c */
++void au_si_free(struct kobject *kobj);
++int au_si_alloc(struct super_block *sb);
++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr);
++
++unsigned int au_sigen_inc(struct super_block *sb);
++aufs_bindex_t au_new_br_id(struct super_block *sb);
++
++int si_read_lock(struct super_block *sb, int flags);
++int si_write_lock(struct super_block *sb, int flags);
++int aufs_read_lock(struct dentry *dentry, int flags);
++void aufs_read_unlock(struct dentry *dentry, int flags);
++void aufs_write_lock(struct dentry *dentry);
++void aufs_write_unlock(struct dentry *dentry);
++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags);
++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2);
++
++int si_pid_test_slow(struct super_block *sb);
++void si_pid_set_slow(struct super_block *sb);
++void si_pid_clr_slow(struct super_block *sb);
++
++/* wbr_policy.c */
++extern struct au_wbr_copyup_operations au_wbr_copyup_ops[];
++extern struct au_wbr_create_operations au_wbr_create_ops[];
++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst);
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_sbinfo *au_sbi(struct super_block *sb)
++{
++ return sb->s_fs_info;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_EXPORT
++void au_export_init(struct super_block *sb);
++
++static inline int au_test_nfsd(void)
++{
++ struct task_struct *tsk = current;
++
++ return (tsk->flags & PF_KTHREAD)
++ && !strcmp(tsk->comm, "nfsd");
++}
++
++void au_xigen_inc(struct inode *inode);
++int au_xigen_new(struct inode *inode);
++int au_xigen_set(struct super_block *sb, struct file *base);
++void au_xigen_clr(struct super_block *sb);
++
++static inline int au_busy_or_stale(void)
++{
++ if (!au_test_nfsd())
++ return -EBUSY;
++ return -ESTALE;
++}
++#else
++AuStubVoid(au_export_init, struct super_block *sb)
++AuStubInt0(au_test_nfsd, void)
++AuStubVoid(au_xigen_inc, struct inode *inode)
++AuStubInt0(au_xigen_new, struct inode *inode)
++AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base)
++AuStubVoid(au_xigen_clr, struct super_block *sb)
++static inline int au_busy_or_stale(void)
++{
++ return -EBUSY;
++}
++#endif /* CONFIG_AUFS_EXPORT */
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_SBILIST
++/* module.c */
++extern struct au_splhead au_sbilist;
++
++static inline void au_sbilist_init(void)
++{
++ au_spl_init(&au_sbilist);
++}
++
++static inline void au_sbilist_add(struct super_block *sb)
++{
++ au_spl_add(&au_sbi(sb)->si_list, &au_sbilist);
++}
++
++static inline void au_sbilist_del(struct super_block *sb)
++{
++ au_spl_del(&au_sbi(sb)->si_list, &au_sbilist);
++}
++#else
++AuStubVoid(au_sbilist_init, void)
++AuStubVoid(au_sbilist_add, struct super_block*)
++AuStubVoid(au_sbilist_del, struct super_block*)
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo)
++{
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++#ifdef CONFIG_DEBUG_FS
++ sbinfo->si_dbgaufs = NULL;
++ sbinfo->si_dbgaufs_xib = NULL;
++#ifdef CONFIG_AUFS_EXPORT
++ sbinfo->si_dbgaufs_xigen = NULL;
++#endif
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++
++static inline pid_t si_pid_bit(void)
++{
++ /* the origin of pid is 1, but the bitmap's is 0 */
++ return current->pid - 1;
++}
++
++static inline int si_pid_test(struct super_block *sb)
++{
++ pid_t bit = si_pid_bit();
++ if (bit < PID_MAX_DEFAULT)
++ return test_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
++ else
++ return si_pid_test_slow(sb);
++}
++
++static inline void si_pid_set(struct super_block *sb)
++{
++ pid_t bit = si_pid_bit();
++ if (bit < PID_MAX_DEFAULT) {
++ AuDebugOn(test_bit(bit, au_sbi(sb)->au_si_pid.bitmap));
++ set_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
++ /* smp_mb(); */
++ } else
++ si_pid_set_slow(sb);
++}
++
++static inline void si_pid_clr(struct super_block *sb)
++{
++ pid_t bit = si_pid_bit();
++ if (bit < PID_MAX_DEFAULT) {
++ AuDebugOn(!test_bit(bit, au_sbi(sb)->au_si_pid.bitmap));
++ clear_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
++ /* smp_mb(); */
++ } else
++ si_pid_clr_slow(sb);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* lock superblock. mainly for entry point functions */
++/*
++ * __si_read_lock, __si_write_lock,
++ * __si_read_unlock, __si_write_unlock, __si_downgrade_lock
++ */
++AuSimpleRwsemFuncs(__si, struct super_block *sb, &au_sbi(sb)->si_rwsem);
++
++#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem)
++#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem)
++#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem)
++
++static inline void si_noflush_read_lock(struct super_block *sb)
++{
++ __si_read_lock(sb);
++ si_pid_set(sb);
++}
++
++static inline int si_noflush_read_trylock(struct super_block *sb)
++{
++ int locked = __si_read_trylock(sb);
++ if (locked)
++ si_pid_set(sb);
++ return locked;
++}
++
++static inline void si_noflush_write_lock(struct super_block *sb)
++{
++ __si_write_lock(sb);
++ si_pid_set(sb);
++}
++
++static inline int si_noflush_write_trylock(struct super_block *sb)
++{
++ int locked = __si_write_trylock(sb);
++ if (locked)
++ si_pid_set(sb);
++ return locked;
++}
++
++#if 0 /* unused */
++static inline int si_read_trylock(struct super_block *sb, int flags)
++{
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++ return si_noflush_read_trylock(sb);
++}
++#endif
++
++static inline void si_read_unlock(struct super_block *sb)
++{
++ si_pid_clr(sb);
++ __si_read_unlock(sb);
++}
++
++#if 0 /* unused */
++static inline int si_write_trylock(struct super_block *sb, int flags)
++{
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++ return si_noflush_write_trylock(sb);
++}
++#endif
++
++static inline void si_write_unlock(struct super_block *sb)
++{
++ si_pid_clr(sb);
++ __si_write_unlock(sb);
++}
++
++#if 0 /* unused */
++static inline void si_downgrade_lock(struct super_block *sb)
++{
++ __si_downgrade_lock(sb);
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static inline aufs_bindex_t au_sbend(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_bend;
++}
++
++static inline unsigned int au_mntflags(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_mntflags;
++}
++
++static inline unsigned int au_sigen(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_generation;
++}
++
++static inline void au_ninodes_inc(struct super_block *sb)
++{
++ atomic_long_inc(&au_sbi(sb)->si_ninodes);
++}
++
++static inline void au_ninodes_dec(struct super_block *sb)
++{
++ AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_ninodes));
++ atomic_long_dec(&au_sbi(sb)->si_ninodes);
++}
++
++static inline void au_nfiles_inc(struct super_block *sb)
++{
++ atomic_long_inc(&au_sbi(sb)->si_nfiles);
++}
++
++static inline void au_nfiles_dec(struct super_block *sb)
++{
++ AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_nfiles));
++ atomic_long_dec(&au_sbi(sb)->si_nfiles);
++}
++
++static inline struct au_branch *au_sbr(struct super_block *sb,
++ aufs_bindex_t bindex)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_branch[0 + bindex];
++}
++
++static inline void au_xino_brid_set(struct super_block *sb, aufs_bindex_t brid)
++{
++ SiMustWriteLock(sb);
++ au_sbi(sb)->si_xino_brid = brid;
++}
++
++static inline aufs_bindex_t au_xino_brid(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_xino_brid;
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_SUPER_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/sysaufs.c linux-2.6.36/fs/aufs/sysaufs.c
+--- linux-2.6.36.orig/fs/aufs/sysaufs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/sysaufs.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,107 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sysfs interface and lifetime management
++ * they are necessary regardless sysfs is disabled.
++ */
++
++#include <linux/fs.h>
++#include <linux/random.h>
++#include <linux/sysfs.h>
++#include "aufs.h"
++
++unsigned long sysaufs_si_mask;
++struct kset *sysaufs_kset;
++
++#define AuSiAttr(_name) { \
++ .attr = { .name = __stringify(_name), .mode = 0444 }, \
++ .show = sysaufs_si_##_name, \
++}
++
++static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path);
++struct attribute *sysaufs_si_attrs[] = {
++ &sysaufs_si_attr_xi_path.attr,
++ NULL,
++};
++
++static const struct sysfs_ops au_sbi_ops = {
++ .show = sysaufs_si_show
++};
++
++static struct kobj_type au_sbi_ktype = {
++ .release = au_si_free,
++ .sysfs_ops = &au_sbi_ops,
++ .default_attrs = sysaufs_si_attrs
++};
++
++/* ---------------------------------------------------------------------- */
++
++int sysaufs_si_init(struct au_sbinfo *sbinfo)
++{
++ int err;
++
++ sbinfo->si_kobj.kset = sysaufs_kset;
++ /* cf. sysaufs_name() */
++ err = kobject_init_and_add
++ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL,
++ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo));
++
++ dbgaufs_si_null(sbinfo);
++ if (!err) {
++ err = dbgaufs_si_init(sbinfo);
++ if (unlikely(err))
++ kobject_put(&sbinfo->si_kobj);
++ }
++ return err;
++}
++
++void sysaufs_fin(void)
++{
++ dbgaufs_fin();
++ sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group);
++ kset_unregister(sysaufs_kset);
++}
++
++int __init sysaufs_init(void)
++{
++ int err;
++
++ do {
++ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask));
++ } while (!sysaufs_si_mask);
++
++ err = -EINVAL;
++ sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj);
++ if (unlikely(!sysaufs_kset))
++ goto out;
++ err = PTR_ERR(sysaufs_kset);
++ if (IS_ERR(sysaufs_kset))
++ goto out;
++ err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group);
++ if (unlikely(err)) {
++ kset_unregister(sysaufs_kset);
++ goto out;
++ }
++
++ err = dbgaufs_init();
++ if (unlikely(err))
++ sysaufs_fin();
++out:
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/sysaufs.h linux-2.6.36/fs/aufs/sysaufs.h
+--- linux-2.6.36.orig/fs/aufs/sysaufs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/sysaufs.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,105 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sysfs interface and mount lifetime management
++ */
++
++#ifndef __SYSAUFS_H__
++#define __SYSAUFS_H__
++
++#ifdef __KERNEL__
++
++#include <linux/sysfs.h>
++#include <linux/aufs_type.h>
++#include "module.h"
++
++struct super_block;
++struct au_sbinfo;
++
++struct sysaufs_si_attr {
++ struct attribute attr;
++ int (*show)(struct seq_file *seq, struct super_block *sb);
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* sysaufs.c */
++extern unsigned long sysaufs_si_mask;
++extern struct kset *sysaufs_kset;
++extern struct attribute *sysaufs_si_attrs[];
++int sysaufs_si_init(struct au_sbinfo *sbinfo);
++int __init sysaufs_init(void);
++void sysaufs_fin(void);
++
++/* ---------------------------------------------------------------------- */
++
++/* some people doesn't like to show a pointer in kernel */
++static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo)
++{
++ return sysaufs_si_mask ^ (unsigned long)sbinfo;
++}
++
++#define SysaufsSiNamePrefix "si_"
++#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16)
++static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name)
++{
++ snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx",
++ sysaufs_si_id(sbinfo));
++}
++
++struct au_branch;
++#ifdef CONFIG_SYSFS
++/* sysfs.c */
++extern struct attribute_group *sysaufs_attr_group;
++
++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb);
++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
++ char *buf);
++
++void sysaufs_br_init(struct au_branch *br);
++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex);
++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex);
++
++#define sysaufs_brs_init() do {} while (0)
++
++#else
++#define sysaufs_attr_group NULL
++
++AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb)
++
++static inline
++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
++ char *buf)
++{
++ return 0;
++}
++
++AuStubVoid(sysaufs_br_init, struct au_branch *br)
++AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex)
++AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex)
++
++static inline void sysaufs_brs_init(void)
++{
++ sysaufs_brs = 0;
++}
++
++#endif /* CONFIG_SYSFS */
++
++#endif /* __KERNEL__ */
++#endif /* __SYSAUFS_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/sysfs.c linux-2.6.36/fs/aufs/sysfs.c
+--- linux-2.6.36.orig/fs/aufs/sysfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/sysfs.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,250 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sysfs interface
++ */
++
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include <linux/sysfs.h>
++#include "aufs.h"
++
++#ifdef CONFIG_AUFS_FS_MODULE
++/* this entry violates the "one line per file" policy of sysfs */
++static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
++{
++ ssize_t err;
++ static char *conf =
++/* this file is generated at compiling */
++#include "conf.str"
++ ;
++
++ err = snprintf(buf, PAGE_SIZE, conf);
++ if (unlikely(err >= PAGE_SIZE))
++ err = -EFBIG;
++ return err;
++}
++
++static struct kobj_attribute au_config_attr = __ATTR_RO(config);
++#endif
++
++static struct attribute *au_attr[] = {
++#ifdef CONFIG_AUFS_FS_MODULE
++ &au_config_attr.attr,
++#endif
++ NULL, /* need to NULL terminate the list of attributes */
++};
++
++static struct attribute_group sysaufs_attr_group_body = {
++ .attrs = au_attr
++};
++
++struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body;
++
++/* ---------------------------------------------------------------------- */
++
++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb)
++{
++ int err;
++
++ SiMustAnyLock(sb);
++
++ err = 0;
++ if (au_opt_test(au_mntflags(sb), XINO)) {
++ err = au_xino_path(seq, au_sbi(sb)->si_xib);
++ seq_putc(seq, '\n');
++ }
++ return err;
++}
++
++/*
++ * the lifetime of branch is independent from the entry under sysfs.
++ * sysfs handles the lifetime of the entry, and never call ->show() after it is
++ * unlinked.
++ */
++static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb,
++ aufs_bindex_t bindex)
++{
++ struct path path;
++ struct dentry *root;
++ struct au_branch *br;
++
++ AuDbg("b%d\n", bindex);
++
++ root = sb->s_root;
++ di_read_lock_parent(root, !AuLock_IR);
++ br = au_sbr(sb, bindex);
++ path.mnt = br->br_mnt;
++ path.dentry = au_h_dptr(root, bindex);
++ au_seq_path(seq, &path);
++ di_read_unlock(root, !AuLock_IR);
++ seq_printf(seq, "=%s\n", au_optstr_br_perm(br->br_perm));
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct seq_file *au_seq(char *p, ssize_t len)
++{
++ struct seq_file *seq;
++
++ seq = kzalloc(sizeof(*seq), GFP_NOFS);
++ if (seq) {
++ /* mutex_init(&seq.lock); */
++ seq->buf = p;
++ seq->size = len;
++ return seq; /* success */
++ }
++
++ seq = ERR_PTR(-ENOMEM);
++ return seq;
++}
++
++#define SysaufsBr_PREFIX "br"
++
++/* todo: file size may exceed PAGE_SIZE */
++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
++ char *buf)
++{
++ ssize_t err;
++ long l;
++ aufs_bindex_t bend;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++ struct seq_file *seq;
++ char *name;
++ struct attribute **cattr;
++
++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
++ sb = sbinfo->si_sb;
++
++ /*
++ * prevent a race condition between sysfs and aufs.
++ * for instance, sysfs_file_read() calls sysfs_get_active_two() which
++ * prohibits maintaining the sysfs entries.
++ * hew we acquire read lock after sysfs_get_active_two().
++ * on the other hand, the remount process may maintain the sysfs/aufs
++ * entries after acquiring write lock.
++ * it can cause a deadlock.
++ * simply we gave up processing read here.
++ */
++ err = -EBUSY;
++ if (unlikely(!si_noflush_read_trylock(sb)))
++ goto out;
++
++ seq = au_seq(buf, PAGE_SIZE);
++ err = PTR_ERR(seq);
++ if (IS_ERR(seq))
++ goto out_unlock;
++
++ name = (void *)attr->name;
++ cattr = sysaufs_si_attrs;
++ while (*cattr) {
++ if (!strcmp(name, (*cattr)->name)) {
++ err = container_of(*cattr, struct sysaufs_si_attr, attr)
++ ->show(seq, sb);
++ goto out_seq;
++ }
++ cattr++;
++ }
++
++ bend = au_sbend(sb);
++ if (!strncmp(name, SysaufsBr_PREFIX, sizeof(SysaufsBr_PREFIX) - 1)) {
++ name += sizeof(SysaufsBr_PREFIX) - 1;
++ err = strict_strtol(name, 10, &l);
++ if (!err) {
++ if (l <= bend)
++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l);
++ else
++ err = -ENOENT;
++ }
++ goto out_seq;
++ }
++ BUG();
++
++out_seq:
++ if (!err) {
++ err = seq->count;
++ /* sysfs limit */
++ if (unlikely(err == PAGE_SIZE))
++ err = -EFBIG;
++ }
++ kfree(seq);
++out_unlock:
++ si_read_unlock(sb);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void sysaufs_br_init(struct au_branch *br)
++{
++ struct attribute *attr = &br->br_attr;
++
++ sysfs_attr_init(attr);
++ attr->name = br->br_name;
++ attr->mode = S_IRUGO;
++}
++
++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
++{
++ struct au_branch *br;
++ struct kobject *kobj;
++ aufs_bindex_t bend;
++
++ dbgaufs_brs_del(sb, bindex);
++
++ if (!sysaufs_brs)
++ return;
++
++ kobj = &au_sbi(sb)->si_kobj;
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ sysfs_remove_file(kobj, &br->br_attr);
++ }
++}
++
++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
++{
++ int err;
++ aufs_bindex_t bend;
++ struct kobject *kobj;
++ struct au_branch *br;
++
++ dbgaufs_brs_add(sb, bindex);
++
++ if (!sysaufs_brs)
++ return;
++
++ kobj = &au_sbi(sb)->si_kobj;
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ snprintf(br->br_name, sizeof(br->br_name), SysaufsBr_PREFIX
++ "%d", bindex);
++ err = sysfs_create_file(kobj, &br->br_attr);
++ if (unlikely(err))
++ pr_warning("failed %s under sysfs(%d)\n",
++ br->br_name, err);
++ }
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/sysrq.c linux-2.6.36/fs/aufs/sysrq.c
+--- linux-2.6.36.orig/fs/aufs/sysrq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/sysrq.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,148 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * magic sysrq hanlder
++ */
++
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++/* #include <linux/sysrq.h> */
++#include <linux/writeback.h>
++#include "aufs.h"
++
++/* ---------------------------------------------------------------------- */
++
++static void sysrq_sb(struct super_block *sb)
++{
++ char *plevel;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ plevel = au_plevel;
++ au_plevel = KERN_WARNING;
++
++ sbinfo = au_sbi(sb);
++ /* since we define pr_fmt, call printk directly */
++ printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo));
++ printk(KERN_WARNING AUFS_NAME ": superblock\n");
++ au_dpri_sb(sb);
++
++#if 0
++ printk(KERN_WARNING AUFS_NAME ": root dentry\n");
++ au_dpri_dentry(sb->s_root);
++ printk(KERN_WARNING AUFS_NAME ": root inode\n");
++ au_dpri_inode(sb->s_root->d_inode);
++#endif
++
++#if 0
++ do {
++ int err, i, j, ndentry;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++
++ err = au_dpages_init(&dpages, GFP_ATOMIC);
++ if (unlikely(err))
++ break;
++ err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL);
++ if (!err)
++ for (i = 0; i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ ndentry = dpage->ndentry;
++ for (j = 0; j < ndentry; j++)
++ au_dpri_dentry(dpage->dentries[j]);
++ }
++ au_dpages_free(&dpages);
++ } while (0);
++#endif
++
++#if 1
++ {
++ struct inode *i;
++ printk(KERN_WARNING AUFS_NAME ": isolated inode\n");
++ spin_lock(&inode_lock);
++ list_for_each_entry(i, &sb->s_inodes, i_sb_list)
++ if (1 || list_empty(&i->i_dentry))
++ au_dpri_inode(i);
++ spin_unlock(&inode_lock);
++ }
++#endif
++ printk(KERN_WARNING AUFS_NAME ": files\n");
++ lg_global_lock(files_lglock);
++ do_file_list_for_each_entry(sb, file) {
++ umode_t mode;
++ mode = file->f_dentry->d_inode->i_mode;
++ if (!special_file(mode) || au_special_file(mode))
++ au_dpri_file(file);
++ } while_file_list_for_each_entry;
++ lg_global_unlock(files_lglock);
++ printk(KERN_WARNING AUFS_NAME ": done\n");
++
++ au_plevel = plevel;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* module parameter */
++static char *aufs_sysrq_key = "a";
++module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO);
++MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME);
++
++static void au_sysrq(int key __maybe_unused)
++{
++ struct au_sbinfo *sbinfo;
++
++ lockdep_off();
++ spin_lock(&au_sbilist.spin);
++ list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
++ sysrq_sb(sbinfo->si_sb);
++ spin_unlock(&au_sbilist.spin);
++ lockdep_on();
++}
++
++static struct sysrq_key_op au_sysrq_op = {
++ .handler = au_sysrq,
++ .help_msg = "Aufs",
++ .action_msg = "Aufs",
++ .enable_mask = SYSRQ_ENABLE_DUMP
++};
++
++/* ---------------------------------------------------------------------- */
++
++int __init au_sysrq_init(void)
++{
++ int err;
++ char key;
++
++ err = -1;
++ key = *aufs_sysrq_key;
++ if ('a' <= key && key <= 'z')
++ err = register_sysrq_key(key, &au_sysrq_op);
++ if (unlikely(err))
++ pr_err("err %d, sysrq=%c\n", err, key);
++ return err;
++}
++
++void au_sysrq_fin(void)
++{
++ int err;
++ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op);
++ if (unlikely(err))
++ pr_err("err %d (ignored)\n", err);
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/vdir.c linux-2.6.36/fs/aufs/vdir.c
+--- linux-2.6.36.orig/fs/aufs/vdir.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/vdir.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,886 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * virtual or vertical directory
++ */
++
++#include <linux/hash.h>
++#include "aufs.h"
++
++static unsigned int calc_size(int nlen)
++{
++ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t));
++}
++
++static int set_deblk_end(union au_vdir_deblk_p *p,
++ union au_vdir_deblk_p *deblk_end)
++{
++ if (calc_size(0) <= deblk_end->deblk - p->deblk) {
++ p->de->de_str.len = 0;
++ /* smp_mb(); */
++ return 0;
++ }
++ return -1; /* error */
++}
++
++/* returns true or false */
++static int is_deblk_end(union au_vdir_deblk_p *p,
++ union au_vdir_deblk_p *deblk_end)
++{
++ if (calc_size(0) <= deblk_end->deblk - p->deblk)
++ return !p->de->de_str.len;
++ return 1;
++}
++
++static unsigned char *last_deblk(struct au_vdir *vdir)
++{
++ return vdir->vd_deblk[vdir->vd_nblk - 1];
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* estimate the apropriate size for name hash table */
++unsigned int au_rdhash_est(loff_t sz)
++{
++ unsigned int n;
++
++ n = UINT_MAX;
++ sz >>= 10;
++ if (sz < n)
++ n = sz;
++ if (sz < AUFS_RDHASH_DEF)
++ n = AUFS_RDHASH_DEF;
++ /* pr_info("n %u\n", n); */
++ return n;
++}
++
++/*
++ * the allocated memory has to be freed by
++ * au_nhash_wh_free() or au_nhash_de_free().
++ */
++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp)
++{
++ struct hlist_head *head;
++ unsigned int u;
++
++ head = kmalloc(sizeof(*nhash->nh_head) * num_hash, gfp);
++ if (head) {
++ nhash->nh_num = num_hash;
++ nhash->nh_head = head;
++ for (u = 0; u < num_hash; u++)
++ INIT_HLIST_HEAD(head++);
++ return 0; /* success */
++ }
++
++ return -ENOMEM;
++}
++
++static void nhash_count(struct hlist_head *head)
++{
++#if 0
++ unsigned long n;
++ struct hlist_node *pos;
++
++ n = 0;
++ hlist_for_each(pos, head)
++ n++;
++ pr_info("%lu\n", n);
++#endif
++}
++
++static void au_nhash_wh_do_free(struct hlist_head *head)
++{
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos, *node;
++
++ hlist_for_each_entry_safe(tpos, pos, node, head, wh_hash) {
++ /* hlist_del(pos); */
++ kfree(tpos);
++ }
++}
++
++static void au_nhash_de_do_free(struct hlist_head *head)
++{
++ struct au_vdir_dehstr *tpos;
++ struct hlist_node *pos, *node;
++
++ hlist_for_each_entry_safe(tpos, pos, node, head, hash) {
++ /* hlist_del(pos); */
++ au_cache_free_vdir_dehstr(tpos);
++ }
++}
++
++static void au_nhash_do_free(struct au_nhash *nhash,
++ void (*free)(struct hlist_head *head))
++{
++ unsigned int n;
++ struct hlist_head *head;
++
++ n = nhash->nh_num;
++ if (!n)
++ return;
++
++ head = nhash->nh_head;
++ while (n-- > 0) {
++ nhash_count(head);
++ free(head++);
++ }
++ kfree(nhash->nh_head);
++}
++
++void au_nhash_wh_free(struct au_nhash *whlist)
++{
++ au_nhash_do_free(whlist, au_nhash_wh_do_free);
++}
++
++static void au_nhash_de_free(struct au_nhash *delist)
++{
++ au_nhash_do_free(delist, au_nhash_de_do_free);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
++ int limit)
++{
++ int num;
++ unsigned int u, n;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++
++ num = 0;
++ n = whlist->nh_num;
++ head = whlist->nh_head;
++ for (u = 0; u < n; u++, head++)
++ hlist_for_each_entry(tpos, pos, head, wh_hash)
++ if (tpos->wh_bindex == btgt && ++num > limit)
++ return 1;
++ return 0;
++}
++
++static struct hlist_head *au_name_hash(struct au_nhash *nhash,
++ unsigned char *name,
++ unsigned int len)
++{
++ unsigned int v;
++ /* const unsigned int magic_bit = 12; */
++
++ AuDebugOn(!nhash->nh_num || !nhash->nh_head);
++
++ v = 0;
++ while (len--)
++ v += *name++;
++ /* v = hash_long(v, magic_bit); */
++ v %= nhash->nh_num;
++ return nhash->nh_head + v;
++}
++
++static int au_nhash_test_name(struct au_vdir_destr *str, const char *name,
++ int nlen)
++{
++ return str->len == nlen && !memcmp(str->name, name, nlen);
++}
++
++/* returns found or not */
++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen)
++{
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++ struct au_vdir_destr *str;
++
++ head = au_name_hash(whlist, name, nlen);
++ hlist_for_each_entry(tpos, pos, head, wh_hash) {
++ str = &tpos->wh_str;
++ AuDbg("%.*s\n", str->len, str->name);
++ if (au_nhash_test_name(str, name, nlen))
++ return 1;
++ }
++ return 0;
++}
++
++/* returns found(true) or not */
++static int test_known(struct au_nhash *delist, char *name, int nlen)
++{
++ struct hlist_head *head;
++ struct au_vdir_dehstr *tpos;
++ struct hlist_node *pos;
++ struct au_vdir_destr *str;
++
++ head = au_name_hash(delist, name, nlen);
++ hlist_for_each_entry(tpos, pos, head, hash) {
++ str = tpos->str;
++ AuDbg("%.*s\n", str->len, str->name);
++ if (au_nhash_test_name(str, name, nlen))
++ return 1;
++ }
++ return 0;
++}
++
++static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino,
++ unsigned char d_type)
++{
++#ifdef CONFIG_AUFS_SHWH
++ wh->wh_ino = ino;
++ wh->wh_type = d_type;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino,
++ unsigned int d_type, aufs_bindex_t bindex,
++ unsigned char shwh)
++{
++ int err;
++ struct au_vdir_destr *str;
++ struct au_vdir_wh *wh;
++
++ AuDbg("%.*s\n", nlen, name);
++ AuDebugOn(!whlist->nh_num || !whlist->nh_head);
++
++ err = -ENOMEM;
++ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS);
++ if (unlikely(!wh))
++ goto out;
++
++ err = 0;
++ wh->wh_bindex = bindex;
++ if (shwh)
++ au_shwh_init_wh(wh, ino, d_type);
++ str = &wh->wh_str;
++ str->len = nlen;
++ memcpy(str->name, name, nlen);
++ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen));
++ /* smp_mb(); */
++
++out:
++ return err;
++}
++
++static int append_deblk(struct au_vdir *vdir)
++{
++ int err;
++ unsigned long ul;
++ const unsigned int deblk_sz = vdir->vd_deblk_sz;
++ union au_vdir_deblk_p p, deblk_end;
++ unsigned char **o;
++
++ err = -ENOMEM;
++ o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1),
++ GFP_NOFS);
++ if (unlikely(!o))
++ goto out;
++
++ vdir->vd_deblk = o;
++ p.deblk = kmalloc(deblk_sz, GFP_NOFS);
++ if (p.deblk) {
++ ul = vdir->vd_nblk++;
++ vdir->vd_deblk[ul] = p.deblk;
++ vdir->vd_last.ul = ul;
++ vdir->vd_last.p.deblk = p.deblk;
++ deblk_end.deblk = p.deblk + deblk_sz;
++ err = set_deblk_end(&p, &deblk_end);
++ }
++
++out:
++ return err;
++}
++
++static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino,
++ unsigned int d_type, struct au_nhash *delist)
++{
++ int err;
++ unsigned int sz;
++ const unsigned int deblk_sz = vdir->vd_deblk_sz;
++ union au_vdir_deblk_p p, *room, deblk_end;
++ struct au_vdir_dehstr *dehstr;
++
++ p.deblk = last_deblk(vdir);
++ deblk_end.deblk = p.deblk + deblk_sz;
++ room = &vdir->vd_last.p;
++ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk
++ || !is_deblk_end(room, &deblk_end));
++
++ sz = calc_size(nlen);
++ if (unlikely(sz > deblk_end.deblk - room->deblk)) {
++ err = append_deblk(vdir);
++ if (unlikely(err))
++ goto out;
++
++ p.deblk = last_deblk(vdir);
++ deblk_end.deblk = p.deblk + deblk_sz;
++ /* smp_mb(); */
++ AuDebugOn(room->deblk != p.deblk);
++ }
++
++ err = -ENOMEM;
++ dehstr = au_cache_alloc_vdir_dehstr();
++ if (unlikely(!dehstr))
++ goto out;
++
++ dehstr->str = &room->de->de_str;
++ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen));
++ room->de->de_ino = ino;
++ room->de->de_type = d_type;
++ room->de->de_str.len = nlen;
++ memcpy(room->de->de_str.name, name, nlen);
++
++ err = 0;
++ room->deblk += sz;
++ if (unlikely(set_deblk_end(room, &deblk_end)))
++ err = append_deblk(vdir);
++ /* smp_mb(); */
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_vdir_free(struct au_vdir *vdir)
++{
++ unsigned char **deblk;
++
++ deblk = vdir->vd_deblk;
++ while (vdir->vd_nblk--)
++ kfree(*deblk++);
++ kfree(vdir->vd_deblk);
++ au_cache_free_vdir(vdir);
++}
++
++static struct au_vdir *alloc_vdir(struct file *file)
++{
++ struct au_vdir *vdir;
++ struct super_block *sb;
++ int err;
++
++ sb = file->f_dentry->d_sb;
++ SiMustAnyLock(sb);
++
++ err = -ENOMEM;
++ vdir = au_cache_alloc_vdir();
++ if (unlikely(!vdir))
++ goto out;
++
++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS);
++ if (unlikely(!vdir->vd_deblk))
++ goto out_free;
++
++ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk;
++ if (!vdir->vd_deblk_sz) {
++ /* estimate the apropriate size for deblk */
++ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL);
++ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */
++ }
++ vdir->vd_nblk = 0;
++ vdir->vd_version = 0;
++ vdir->vd_jiffy = 0;
++ err = append_deblk(vdir);
++ if (!err)
++ return vdir; /* success */
++
++ kfree(vdir->vd_deblk);
++
++out_free:
++ au_cache_free_vdir(vdir);
++out:
++ vdir = ERR_PTR(err);
++ return vdir;
++}
++
++static int reinit_vdir(struct au_vdir *vdir)
++{
++ int err;
++ union au_vdir_deblk_p p, deblk_end;
++
++ while (vdir->vd_nblk > 1) {
++ kfree(vdir->vd_deblk[vdir->vd_nblk - 1]);
++ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */
++ vdir->vd_nblk--;
++ }
++ p.deblk = vdir->vd_deblk[0];
++ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz;
++ err = set_deblk_end(&p, &deblk_end);
++ /* keep vd_dblk_sz */
++ vdir->vd_last.ul = 0;
++ vdir->vd_last.p.deblk = vdir->vd_deblk[0];
++ vdir->vd_version = 0;
++ vdir->vd_jiffy = 0;
++ /* smp_mb(); */
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#define AuFillVdir_CALLED 1
++#define AuFillVdir_WHABLE (1 << 1)
++#define AuFillVdir_SHWH (1 << 2)
++#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name)
++#define au_fset_fillvdir(flags, name) \
++ do { (flags) |= AuFillVdir_##name; } while (0)
++#define au_fclr_fillvdir(flags, name) \
++ do { (flags) &= ~AuFillVdir_##name; } while (0)
++
++#ifndef CONFIG_AUFS_SHWH
++#undef AuFillVdir_SHWH
++#define AuFillVdir_SHWH 0
++#endif
++
++struct fillvdir_arg {
++ struct file *file;
++ struct au_vdir *vdir;
++ struct au_nhash delist;
++ struct au_nhash whlist;
++ aufs_bindex_t bindex;
++ unsigned int flags;
++ int err;
++};
++
++static int fillvdir(void *__arg, const char *__name, int nlen,
++ loff_t offset __maybe_unused, u64 h_ino,
++ unsigned int d_type)
++{
++ struct fillvdir_arg *arg = __arg;
++ char *name = (void *)__name;
++ struct super_block *sb;
++ ino_t ino;
++ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH);
++
++ arg->err = 0;
++ sb = arg->file->f_dentry->d_sb;
++ au_fset_fillvdir(arg->flags, CALLED);
++ /* smp_mb(); */
++ if (nlen <= AUFS_WH_PFX_LEN
++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
++ if (test_known(&arg->delist, name, nlen)
++ || au_nhash_test_known_wh(&arg->whlist, name, nlen))
++ goto out; /* already exists or whiteouted */
++
++ sb = arg->file->f_dentry->d_sb;
++ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino);
++ if (!arg->err) {
++ if (unlikely(nlen > AUFS_MAX_NAMELEN))
++ d_type = DT_UNKNOWN;
++ arg->err = append_de(arg->vdir, name, nlen, ino,
++ d_type, &arg->delist);
++ }
++ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) {
++ name += AUFS_WH_PFX_LEN;
++ nlen -= AUFS_WH_PFX_LEN;
++ if (au_nhash_test_known_wh(&arg->whlist, name, nlen))
++ goto out; /* already whiteouted */
++
++ if (shwh)
++ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type,
++ &ino);
++ if (!arg->err) {
++ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN)
++ d_type = DT_UNKNOWN;
++ arg->err = au_nhash_append_wh
++ (&arg->whlist, name, nlen, ino, d_type,
++ arg->bindex, shwh);
++ }
++ }
++
++out:
++ if (!arg->err)
++ arg->vdir->vd_jiffy = jiffies;
++ /* smp_mb(); */
++ AuTraceErr(arg->err);
++ return arg->err;
++}
++
++static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir,
++ struct au_nhash *whlist, struct au_nhash *delist)
++{
++#ifdef CONFIG_AUFS_SHWH
++ int err;
++ unsigned int nh, u;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos, *n;
++ char *p, *o;
++ struct au_vdir_destr *destr;
++
++ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH));
++
++ err = -ENOMEM;
++ o = p = __getname_gfp(GFP_NOFS);
++ if (unlikely(!p))
++ goto out;
++
++ err = 0;
++ nh = whlist->nh_num;
++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
++ p += AUFS_WH_PFX_LEN;
++ for (u = 0; u < nh; u++) {
++ head = whlist->nh_head + u;
++ hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) {
++ destr = &tpos->wh_str;
++ memcpy(p, destr->name, destr->len);
++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN,
++ tpos->wh_ino, tpos->wh_type, delist);
++ if (unlikely(err))
++ break;
++ }
++ }
++
++ __putname(o);
++
++out:
++ AuTraceErr(err);
++ return err;
++#else
++ return 0;
++#endif
++}
++
++static int au_do_read_vdir(struct fillvdir_arg *arg)
++{
++ int err;
++ unsigned int rdhash;
++ loff_t offset;
++ aufs_bindex_t bend, bindex, bstart;
++ unsigned char shwh;
++ struct file *hf, *file;
++ struct super_block *sb;
++
++ file = arg->file;
++ sb = file->f_dentry->d_sb;
++ SiMustAnyLock(sb);
++
++ rdhash = au_sbi(sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL));
++ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out_delist;
++
++ err = 0;
++ arg->flags = 0;
++ shwh = 0;
++ if (au_opt_test(au_mntflags(sb), SHWH)) {
++ shwh = 1;
++ au_fset_fillvdir(arg->flags, SHWH);
++ }
++ bstart = au_fbstart(file);
++ bend = au_fbend_dir(file);
++ for (bindex = bstart; !err && bindex <= bend; bindex++) {
++ hf = au_hf_dir(file, bindex);
++ if (!hf)
++ continue;
++
++ offset = vfsub_llseek(hf, 0, SEEK_SET);
++ err = offset;
++ if (unlikely(offset))
++ break;
++
++ arg->bindex = bindex;
++ au_fclr_fillvdir(arg->flags, WHABLE);
++ if (shwh
++ || (bindex != bend
++ && au_br_whable(au_sbr_perm(sb, bindex))))
++ au_fset_fillvdir(arg->flags, WHABLE);
++ do {
++ arg->err = 0;
++ au_fclr_fillvdir(arg->flags, CALLED);
++ /* smp_mb(); */
++ err = vfsub_readdir(hf, fillvdir, arg);
++ if (err >= 0)
++ err = arg->err;
++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED));
++ }
++
++ if (!err && shwh)
++ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist);
++
++ au_nhash_wh_free(&arg->whlist);
++
++out_delist:
++ au_nhash_de_free(&arg->delist);
++out:
++ return err;
++}
++
++static int read_vdir(struct file *file, int may_read)
++{
++ int err;
++ unsigned long expire;
++ unsigned char do_read;
++ struct fillvdir_arg arg;
++ struct inode *inode;
++ struct au_vdir *vdir, *allocated;
++
++ err = 0;
++ inode = file->f_dentry->d_inode;
++ IMustLock(inode);
++ SiMustAnyLock(inode->i_sb);
++
++ allocated = NULL;
++ do_read = 0;
++ expire = au_sbi(inode->i_sb)->si_rdcache;
++ vdir = au_ivdir(inode);
++ if (!vdir) {
++ do_read = 1;
++ vdir = alloc_vdir(file);
++ err = PTR_ERR(vdir);
++ if (IS_ERR(vdir))
++ goto out;
++ err = 0;
++ allocated = vdir;
++ } else if (may_read
++ && (inode->i_version != vdir->vd_version
++ || time_after(jiffies, vdir->vd_jiffy + expire))) {
++ do_read = 1;
++ err = reinit_vdir(vdir);
++ if (unlikely(err))
++ goto out;
++ }
++
++ if (!do_read)
++ return 0; /* success */
++
++ arg.file = file;
++ arg.vdir = vdir;
++ err = au_do_read_vdir(&arg);
++ if (!err) {
++ /* file->f_pos = 0; */
++ vdir->vd_version = inode->i_version;
++ vdir->vd_last.ul = 0;
++ vdir->vd_last.p.deblk = vdir->vd_deblk[0];
++ if (allocated)
++ au_set_ivdir(inode, allocated);
++ } else if (allocated)
++ au_vdir_free(allocated);
++
++out:
++ return err;
++}
++
++static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src)
++{
++ int err, rerr;
++ unsigned long ul, n;
++ const unsigned int deblk_sz = src->vd_deblk_sz;
++
++ AuDebugOn(tgt->vd_nblk != 1);
++
++ err = -ENOMEM;
++ if (tgt->vd_nblk < src->vd_nblk) {
++ unsigned char **p;
++
++ p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk,
++ GFP_NOFS);
++ if (unlikely(!p))
++ goto out;
++ tgt->vd_deblk = p;
++ }
++
++ if (tgt->vd_deblk_sz != deblk_sz) {
++ unsigned char *p;
++
++ tgt->vd_deblk_sz = deblk_sz;
++ p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS);
++ if (unlikely(!p))
++ goto out;
++ tgt->vd_deblk[0] = p;
++ }
++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz);
++ tgt->vd_version = src->vd_version;
++ tgt->vd_jiffy = src->vd_jiffy;
++
++ n = src->vd_nblk;
++ for (ul = 1; ul < n; ul++) {
++ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz,
++ GFP_NOFS);
++ if (unlikely(!tgt->vd_deblk[ul]))
++ goto out;
++ tgt->vd_nblk++;
++ }
++ tgt->vd_nblk = n;
++ tgt->vd_last.ul = tgt->vd_last.ul;
++ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul];
++ tgt->vd_last.p.deblk += src->vd_last.p.deblk
++ - src->vd_deblk[src->vd_last.ul];
++ /* smp_mb(); */
++ return 0; /* success */
++
++out:
++ rerr = reinit_vdir(tgt);
++ BUG_ON(rerr);
++ return err;
++}
++
++int au_vdir_init(struct file *file)
++{
++ int err;
++ struct inode *inode;
++ struct au_vdir *vdir_cache, *allocated;
++
++ err = read_vdir(file, !file->f_pos);
++ if (unlikely(err))
++ goto out;
++
++ allocated = NULL;
++ vdir_cache = au_fvdir_cache(file);
++ if (!vdir_cache) {
++ vdir_cache = alloc_vdir(file);
++ err = PTR_ERR(vdir_cache);
++ if (IS_ERR(vdir_cache))
++ goto out;
++ allocated = vdir_cache;
++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) {
++ err = reinit_vdir(vdir_cache);
++ if (unlikely(err))
++ goto out;
++ } else
++ return 0; /* success */
++
++ inode = file->f_dentry->d_inode;
++ err = copy_vdir(vdir_cache, au_ivdir(inode));
++ if (!err) {
++ file->f_version = inode->i_version;
++ if (allocated)
++ au_set_fvdir_cache(file, allocated);
++ } else if (allocated)
++ au_vdir_free(allocated);
++
++out:
++ return err;
++}
++
++static loff_t calc_offset(struct au_vdir *vdir)
++{
++ loff_t offset;
++ union au_vdir_deblk_p p;
++
++ p.deblk = vdir->vd_deblk[vdir->vd_last.ul];
++ offset = vdir->vd_last.p.deblk - p.deblk;
++ offset += vdir->vd_deblk_sz * vdir->vd_last.ul;
++ return offset;
++}
++
++/* returns true or false */
++static int seek_vdir(struct file *file)
++{
++ int valid;
++ unsigned int deblk_sz;
++ unsigned long ul, n;
++ loff_t offset;
++ union au_vdir_deblk_p p, deblk_end;
++ struct au_vdir *vdir_cache;
++
++ valid = 1;
++ vdir_cache = au_fvdir_cache(file);
++ offset = calc_offset(vdir_cache);
++ AuDbg("offset %lld\n", offset);
++ if (file->f_pos == offset)
++ goto out;
++
++ vdir_cache->vd_last.ul = 0;
++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0];
++ if (!file->f_pos)
++ goto out;
++
++ valid = 0;
++ deblk_sz = vdir_cache->vd_deblk_sz;
++ ul = div64_u64(file->f_pos, deblk_sz);
++ AuDbg("ul %lu\n", ul);
++ if (ul >= vdir_cache->vd_nblk)
++ goto out;
++
++ n = vdir_cache->vd_nblk;
++ for (; ul < n; ul++) {
++ p.deblk = vdir_cache->vd_deblk[ul];
++ deblk_end.deblk = p.deblk + deblk_sz;
++ offset = ul;
++ offset *= deblk_sz;
++ while (!is_deblk_end(&p, &deblk_end) && offset < file->f_pos) {
++ unsigned int l;
++
++ l = calc_size(p.de->de_str.len);
++ offset += l;
++ p.deblk += l;
++ }
++ if (!is_deblk_end(&p, &deblk_end)) {
++ valid = 1;
++ vdir_cache->vd_last.ul = ul;
++ vdir_cache->vd_last.p = p;
++ break;
++ }
++ }
++
++out:
++ /* smp_mb(); */
++ AuTraceErr(!valid);
++ return valid;
++}
++
++int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir)
++{
++ int err;
++ unsigned int l, deblk_sz;
++ union au_vdir_deblk_p deblk_end;
++ struct au_vdir *vdir_cache;
++ struct au_vdir_de *de;
++
++ vdir_cache = au_fvdir_cache(file);
++ if (!seek_vdir(file))
++ return 0;
++
++ deblk_sz = vdir_cache->vd_deblk_sz;
++ while (1) {
++ deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul];
++ deblk_end.deblk += deblk_sz;
++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) {
++ de = vdir_cache->vd_last.p.de;
++ AuDbg("%.*s, off%lld, i%lu, dt%d\n",
++ de->de_str.len, de->de_str.name, file->f_pos,
++ (unsigned long)de->de_ino, de->de_type);
++ err = filldir(dirent, de->de_str.name, de->de_str.len,
++ file->f_pos, de->de_ino, de->de_type);
++ if (unlikely(err)) {
++ AuTraceErr(err);
++ /* todo: ignore the error caused by udba? */
++ /* return err; */
++ return 0;
++ }
++
++ l = calc_size(de->de_str.len);
++ vdir_cache->vd_last.p.deblk += l;
++ file->f_pos += l;
++ }
++ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) {
++ vdir_cache->vd_last.ul++;
++ vdir_cache->vd_last.p.deblk
++ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul];
++ file->f_pos = deblk_sz * vdir_cache->vd_last.ul;
++ continue;
++ }
++ break;
++ }
++
++ /* smp_mb(); */
++ return 0;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/vfsub.c linux-2.6.36/fs/aufs/vfsub.c
+--- linux-2.6.36.orig/fs/aufs/vfsub.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/vfsub.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,790 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sub-routines for VFS
++ */
++
++#include <linux/file.h>
++#include <linux/ima.h>
++#include <linux/namei.h>
++#include <linux/security.h>
++#include <linux/splice.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++int vfsub_update_h_iattr(struct path *h_path, int *did)
++{
++ int err;
++ struct kstat st;
++ struct super_block *h_sb;
++
++ /* for remote fs, leave work for its getattr or d_revalidate */
++ /* for bad i_attr fs, handle them in aufs_getattr() */
++ /* still some fs may acquire i_mutex. we need to skip them */
++ err = 0;
++ if (!did)
++ did = &err;
++ h_sb = h_path->dentry->d_sb;
++ *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb));
++ if (*did)
++ err = vfs_getattr(h_path->mnt, h_path->dentry, &st);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_conv_oflags(int flags)
++{
++ int mask = 0;
++
++#ifdef CONFIG_IMA
++ fmode_t fmode;
++
++ /* mask = MAY_OPEN; */
++ fmode = OPEN_FMODE(flags);
++ if (fmode & FMODE_READ)
++ mask |= MAY_READ;
++ if ((fmode & FMODE_WRITE)
++ || (flags & O_TRUNC))
++ mask |= MAY_WRITE;
++ /*
++ * if (flags & O_APPEND)
++ * mask |= MAY_APPEND;
++ */
++ if (flags & vfsub_fmode_to_uint(FMODE_EXEC))
++ mask |= MAY_EXEC;
++
++ AuDbg("flags 0x%x, mask 0x%x\n", flags, mask);
++#endif
++
++ return mask;
++}
++
++struct file *vfsub_dentry_open(struct path *path, int flags)
++{
++ struct file *file;
++ int err;
++
++ path_get(path);
++ file = dentry_open(path->dentry, path->mnt,
++ flags /* | vfsub_fmode_to_uint(FMODE_NONOTIFY) */,
++ current_cred());
++ if (IS_ERR(file))
++ goto out;
++
++ err = ima_file_check(file, au_conv_oflags(flags));
++ if (unlikely(err)) {
++ fput(file);
++ file = ERR_PTR(err);
++ }
++out:
++ return file;
++}
++
++struct file *vfsub_filp_open(const char *path, int oflags, int mode)
++{
++ struct file *file;
++
++ file = filp_open(path,
++ oflags /* | vfsub_fmode_to_uint(FMODE_NONOTIFY) */,
++ mode);
++ if (IS_ERR(file))
++ goto out;
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++
++out:
++ return file;
++}
++
++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path)
++{
++ int err;
++
++ err = kern_path(name, flags, path);
++ if (!err && path->dentry->d_inode)
++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
++ int len)
++{
++ struct path path = {
++ .mnt = NULL
++ };
++
++ /* VFS checks it too, but by WARN_ON_ONCE() */
++ IMustLock(parent->d_inode);
++
++ path.dentry = lookup_one_len(name, parent, len);
++ if (IS_ERR(path.dentry))
++ goto out;
++ if (path.dentry->d_inode)
++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/
++
++out:
++ AuTraceErrPtr(path.dentry);
++ return path.dentry;
++}
++
++struct dentry *vfsub_lookup_hash(struct nameidata *nd)
++{
++ struct path path = {
++ .mnt = nd->path.mnt
++ };
++
++ IMustLock(nd->path.dentry->d_inode);
++
++ path.dentry = lookup_hash(nd);
++ if (IS_ERR(path.dentry))
++ goto out;
++ if (path.dentry->d_inode)
++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/
++
++out:
++ AuTraceErrPtr(path.dentry);
++ return path.dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2)
++{
++ struct dentry *d;
++
++ d = lock_rename(d1, d2);
++ au_hn_suspend(hdir1);
++ if (hdir1 != hdir2)
++ au_hn_suspend(hdir2);
++
++ return d;
++}
++
++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2)
++{
++ au_hn_resume(hdir1);
++ if (hdir1 != hdir2)
++ au_hn_resume(hdir2);
++ unlock_rename(d1, d2);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int vfsub_create(struct inode *dir, struct path *path, int mode)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_mknod(path, d, mode, 0);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ if (au_test_fs_null_nd(dir->i_sb))
++ err = vfs_create(dir, path->dentry, mode, NULL);
++ else {
++ struct nameidata h_nd;
++
++ memset(&h_nd, 0, sizeof(h_nd));
++ h_nd.flags = LOOKUP_CREATE;
++ h_nd.intent.open.flags = O_CREAT
++ | vfsub_fmode_to_uint(FMODE_READ);
++ h_nd.intent.open.create_mode = mode;
++ h_nd.path.dentry = path->dentry->d_parent;
++ h_nd.path.mnt = path->mnt;
++ path_get(&h_nd.path);
++ err = vfs_create(dir, path->dentry, mode, &h_nd);
++ path_put(&h_nd.path);
++ }
++
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++int vfsub_symlink(struct inode *dir, struct path *path, const char *symname)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_symlink(path, d, symname);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_symlink(dir, path->dentry, symname);
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_mknod(path, d, mode, dev);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_mknod(dir, path->dentry, mode, dev);
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++static int au_test_nlink(struct inode *inode)
++{
++ const unsigned int link_max = UINT_MAX >> 1; /* rough margin */
++
++ if (!au_test_fs_no_limit_nlink(inode->i_sb)
++ || inode->i_nlink < link_max)
++ return 0;
++ return -EMLINK;
++}
++
++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ err = au_test_nlink(src_dentry->d_inode);
++ if (unlikely(err))
++ return err;
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_link(src_dentry, path, d);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_link(src_dentry, dir, path->dentry);
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ /* fuse has different memory inode for the same inumber */
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ tmp.dentry = src_dentry;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry,
++ struct inode *dir, struct path *path)
++{
++ int err;
++ struct path tmp = {
++ .mnt = path->mnt
++ };
++ struct dentry *d;
++
++ IMustLock(dir);
++ IMustLock(src_dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ tmp.dentry = src_dentry->d_parent;
++ err = security_path_rename(&tmp, src_dentry, path, d);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_rename(src_dir, src_dentry, dir, path->dentry);
++ if (!err) {
++ int did;
++
++ tmp.dentry = d->d_parent;
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = src_dentry;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ tmp.dentry = src_dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++int vfsub_mkdir(struct inode *dir, struct path *path, int mode)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_mkdir(path, d, mode);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_mkdir(dir, path->dentry, mode);
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++int vfsub_rmdir(struct inode *dir, struct path *path)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_rmdir(path, d);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_rmdir(dir, path->dentry);
++ if (!err) {
++ struct path tmp = {
++ .dentry = path->dentry->d_parent,
++ .mnt = path->mnt
++ };
++
++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++
++ err = vfs_read(file, ubuf, count, ppos);
++ if (err >= 0)
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++/* todo: kernel_read()? */
++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++ union {
++ void *k;
++ char __user *u;
++ } buf;
++
++ buf.k = kbuf;
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ err = vfsub_read_u(file, buf.u, count, ppos);
++ set_fs(oldfs);
++ return err;
++}
++
++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++
++ err = vfs_write(file, ubuf, count, ppos);
++ if (err >= 0)
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++ union {
++ void *k;
++ const char __user *u;
++ } buf;
++
++ buf.k = kbuf;
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ err = vfsub_write_u(file, buf.u, count, ppos);
++ set_fs(oldfs);
++ return err;
++}
++
++int vfsub_flush(struct file *file, fl_owner_t id)
++{
++ int err;
++
++ err = 0;
++ if (file->f_op && file->f_op->flush) {
++ err = file->f_op->flush(file, id);
++ if (!err)
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL);
++ /*ignore*/
++ }
++ return err;
++}
++
++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg)
++{
++ int err;
++
++ err = vfs_readdir(file, filldir, arg);
++ if (err >= 0)
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++long vfsub_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ long err;
++
++ err = do_splice_to(in, ppos, pipe, len, flags);
++ file_accessed(in);
++ if (err >= 0)
++ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
++{
++ long err;
++
++ err = do_splice_from(pipe, out, ppos, len, flags);
++ if (err >= 0)
++ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */
++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
++ struct file *h_file)
++{
++ int err;
++ struct inode *h_inode;
++
++ h_inode = h_path->dentry->d_inode;
++ if (!h_file) {
++ err = mnt_want_write(h_path->mnt);
++ if (err)
++ goto out;
++ err = inode_permission(h_inode, MAY_WRITE);
++ if (err)
++ goto out_mnt;
++ err = get_write_access(h_inode);
++ if (err)
++ goto out_mnt;
++ err = break_lease(h_inode, O_WRONLY);
++ if (err)
++ goto out_inode;
++ }
++
++ err = locks_verify_truncate(h_inode, h_file, length);
++ if (!err)
++ err = security_path_truncate(h_path);
++ if (!err)
++ err = do_truncate(h_path->dentry, length, attr, h_file);
++
++out_inode:
++ if (!h_file)
++ put_write_access(h_inode);
++out_mnt:
++ if (!h_file)
++ mnt_drop_write(h_path->mnt);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_vfsub_mkdir_args {
++ int *errp;
++ struct inode *dir;
++ struct path *path;
++ int mode;
++};
++
++static void au_call_vfsub_mkdir(void *args)
++{
++ struct au_vfsub_mkdir_args *a = args;
++ *a->errp = vfsub_mkdir(a->dir, a->path, a->mode);
++}
++
++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode)
++{
++ int err, do_sio, wkq_err;
++
++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
++ if (!do_sio)
++ err = vfsub_mkdir(dir, path, mode);
++ else {
++ struct au_vfsub_mkdir_args args = {
++ .errp = &err,
++ .dir = dir,
++ .path = path,
++ .mode = mode
++ };
++ wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
++
++struct au_vfsub_rmdir_args {
++ int *errp;
++ struct inode *dir;
++ struct path *path;
++};
++
++static void au_call_vfsub_rmdir(void *args)
++{
++ struct au_vfsub_rmdir_args *a = args;
++ *a->errp = vfsub_rmdir(a->dir, a->path);
++}
++
++int vfsub_sio_rmdir(struct inode *dir, struct path *path)
++{
++ int err, do_sio, wkq_err;
++
++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
++ if (!do_sio)
++ err = vfsub_rmdir(dir, path);
++ else {
++ struct au_vfsub_rmdir_args args = {
++ .errp = &err,
++ .dir = dir,
++ .path = path
++ };
++ wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct notify_change_args {
++ int *errp;
++ struct path *path;
++ struct iattr *ia;
++};
++
++static void call_notify_change(void *args)
++{
++ struct notify_change_args *a = args;
++ struct inode *h_inode;
++
++ h_inode = a->path->dentry->d_inode;
++ IMustLock(h_inode);
++
++ *a->errp = -EPERM;
++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
++ *a->errp = notify_change(a->path->dentry, a->ia);
++ if (!*a->errp)
++ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/
++ }
++ AuTraceErr(*a->errp);
++}
++
++int vfsub_notify_change(struct path *path, struct iattr *ia)
++{
++ int err;
++ struct notify_change_args args = {
++ .errp = &err,
++ .path = path,
++ .ia = ia
++ };
++
++ call_notify_change(&args);
++
++ return err;
++}
++
++int vfsub_sio_notify_change(struct path *path, struct iattr *ia)
++{
++ int err, wkq_err;
++ struct notify_change_args args = {
++ .errp = &err,
++ .path = path,
++ .ia = ia
++ };
++
++ wkq_err = au_wkq_wait(call_notify_change, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct unlink_args {
++ int *errp;
++ struct inode *dir;
++ struct path *path;
++};
++
++static void call_unlink(void *args)
++{
++ struct unlink_args *a = args;
++ struct dentry *d = a->path->dentry;
++ struct inode *h_inode;
++ const int stop_sillyrename = (au_test_nfs(d->d_sb)
++ && atomic_read(&d->d_count) == 1);
++
++ IMustLock(a->dir);
++
++ a->path->dentry = d->d_parent;
++ *a->errp = security_path_unlink(a->path, d);
++ a->path->dentry = d;
++ if (unlikely(*a->errp))
++ return;
++
++ if (!stop_sillyrename)
++ dget(d);
++ h_inode = d->d_inode;
++ if (h_inode)
++ atomic_inc(&h_inode->i_count);
++
++ *a->errp = vfs_unlink(a->dir, d);
++ if (!*a->errp) {
++ struct path tmp = {
++ .dentry = d->d_parent,
++ .mnt = a->path->mnt
++ };
++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/
++ }
++
++ if (!stop_sillyrename)
++ dput(d);
++ if (h_inode)
++ iput(h_inode);
++
++ AuTraceErr(*a->errp);
++}
++
++/*
++ * @dir: must be locked.
++ * @dentry: target dentry.
++ */
++int vfsub_unlink(struct inode *dir, struct path *path, int force)
++{
++ int err;
++ struct unlink_args args = {
++ .errp = &err,
++ .dir = dir,
++ .path = path
++ };
++
++ if (!force)
++ call_unlink(&args);
++ else {
++ int wkq_err;
++
++ wkq_err = au_wkq_wait(call_unlink, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/vfsub.h linux-2.6.36/fs/aufs/vfsub.h
+--- linux-2.6.36.orig/fs/aufs/vfsub.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/vfsub.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,226 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sub-routines for VFS
++ */
++
++#ifndef __AUFS_VFSUB_H__
++#define __AUFS_VFSUB_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/lglock.h>
++#include "debug.h"
++
++/* copied from linux/fs/internal.h */
++DECLARE_BRLOCK(vfsmount_lock);
++extern void file_sb_list_del(struct file *f);
++
++/* copied from linux/fs/file_table.c */
++DECLARE_LGLOCK(files_lglock);
++#ifdef CONFIG_SMP
++/*
++ * These macros iterate all files on all CPUs for a given superblock.
++ * files_lglock must be held globally.
++ */
++#define do_file_list_for_each_entry(__sb, __file) \
++{ \
++ int i; \
++ for_each_possible_cpu(i) { \
++ struct list_head *list; \
++ list = per_cpu_ptr((__sb)->s_files, i); \
++ list_for_each_entry((__file), list, f_u.fu_list)
++
++#define while_file_list_for_each_entry \
++ } \
++}
++
++#else
++
++#define do_file_list_for_each_entry(__sb, __file) \
++{ \
++ struct list_head *list; \
++ list = &(sb)->s_files; \
++ list_for_each_entry((__file), list, f_u.fu_list)
++
++#define while_file_list_for_each_entry \
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++/* lock subclass for lower inode */
++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */
++/* reduce? gave up. */
++enum {
++ AuLsc_I_Begin = I_MUTEX_QUOTA, /* 4 */
++ AuLsc_I_PARENT, /* lower inode, parent first */
++ AuLsc_I_PARENT2, /* copyup dirs */
++ AuLsc_I_PARENT3, /* copyup wh */
++ AuLsc_I_CHILD,
++ AuLsc_I_CHILD2,
++ AuLsc_I_End
++};
++
++/* to debug easier, do not make them inlined functions */
++#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx))
++#define IMustLock(i) MtxMustLock(&(i)->i_mutex)
++
++/* ---------------------------------------------------------------------- */
++
++static inline void vfsub_drop_nlink(struct inode *inode)
++{
++ AuDebugOn(!inode->i_nlink);
++ drop_nlink(inode);
++}
++
++static inline void vfsub_dead_dir(struct inode *inode)
++{
++ AuDebugOn(!S_ISDIR(inode->i_mode));
++ inode->i_flags |= S_DEAD;
++ clear_nlink(inode);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int vfsub_update_h_iattr(struct path *h_path, int *did);
++struct file *vfsub_dentry_open(struct path *path, int flags);
++struct file *vfsub_filp_open(const char *path, int oflags, int mode);
++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path);
++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
++ int len);
++struct dentry *vfsub_lookup_hash(struct nameidata *nd);
++
++/* ---------------------------------------------------------------------- */
++
++struct au_hinode;
++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2);
++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2);
++
++int vfsub_create(struct inode *dir, struct path *path, int mode);
++int vfsub_symlink(struct inode *dir, struct path *path,
++ const char *symname);
++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev);
++int vfsub_link(struct dentry *src_dentry, struct inode *dir,
++ struct path *path);
++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry,
++ struct inode *hdir, struct path *path);
++int vfsub_mkdir(struct inode *dir, struct path *path, int mode);
++int vfsub_rmdir(struct inode *dir, struct path *path);
++
++/* ---------------------------------------------------------------------- */
++
++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count,
++ loff_t *ppos);
++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count,
++ loff_t *ppos);
++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count,
++ loff_t *ppos);
++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count,
++ loff_t *ppos);
++int vfsub_flush(struct file *file, fl_owner_t id);
++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg);
++
++static inline unsigned int vfsub_file_flags(struct file *file)
++{
++ unsigned int flags;
++
++ spin_lock(&file->f_lock);
++ flags = file->f_flags;
++ spin_unlock(&file->f_lock);
++
++ return flags;
++}
++
++static inline void vfsub_file_accessed(struct file *h_file)
++{
++ file_accessed(h_file);
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/
++}
++
++static inline void vfsub_touch_atime(struct vfsmount *h_mnt,
++ struct dentry *h_dentry)
++{
++ struct path h_path = {
++ .dentry = h_dentry,
++ .mnt = h_mnt
++ };
++ touch_atime(h_mnt, h_dentry);
++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
++}
++
++long vfsub_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags);
++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags);
++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
++ struct file *h_file);
++
++/* ---------------------------------------------------------------------- */
++
++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin)
++{
++ loff_t err;
++
++ err = vfs_llseek(file, offset, origin);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* dirty workaround for strict type of fmode_t */
++union vfsub_fmu {
++ fmode_t fm;
++ unsigned int ui;
++};
++
++static inline unsigned int vfsub_fmode_to_uint(fmode_t fm)
++{
++ union vfsub_fmu u = {
++ .fm = fm
++ };
++
++ BUILD_BUG_ON(sizeof(u.fm) != sizeof(u.ui));
++
++ return u.ui;
++}
++
++static inline fmode_t vfsub_uint_to_fmode(unsigned int ui)
++{
++ union vfsub_fmu u = {
++ .ui = ui
++ };
++
++ return u.fm;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode);
++int vfsub_sio_rmdir(struct inode *dir, struct path *path);
++int vfsub_sio_notify_change(struct path *path, struct iattr *ia);
++int vfsub_notify_change(struct path *path, struct iattr *ia);
++int vfsub_unlink(struct inode *dir, struct path *path, int force);
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_VFSUB_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/wbr_policy.c linux-2.6.36/fs/aufs/wbr_policy.c
+--- linux-2.6.36.orig/fs/aufs/wbr_policy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/wbr_policy.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,700 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * policies for selecting one among multiple writable branches
++ */
++
++#include <linux/statfs.h>
++#include "aufs.h"
++
++/* subset of cpup_attr() */
++static noinline_for_stack
++int au_cpdown_attr(struct path *h_path, struct dentry *h_src)
++{
++ int err, sbits;
++ struct iattr ia;
++ struct inode *h_isrc;
++
++ h_isrc = h_src->d_inode;
++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID;
++ ia.ia_mode = h_isrc->i_mode;
++ ia.ia_uid = h_isrc->i_uid;
++ ia.ia_gid = h_isrc->i_gid;
++ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID));
++ au_cpup_attr_flags(h_path->dentry->d_inode, h_isrc);
++ err = vfsub_sio_notify_change(h_path, &ia);
++
++ /* is this nfs only? */
++ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) {
++ ia.ia_valid = ATTR_FORCE | ATTR_MODE;
++ ia.ia_mode = h_isrc->i_mode;
++ err = vfsub_sio_notify_change(h_path, &ia);
++ }
++
++ return err;
++}
++
++#define AuCpdown_PARENT_OPQ 1
++#define AuCpdown_WHED (1 << 1)
++#define AuCpdown_MADE_DIR (1 << 2)
++#define AuCpdown_DIROPQ (1 << 3)
++#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name)
++#define au_fset_cpdown(flags, name) \
++ do { (flags) |= AuCpdown_##name; } while (0)
++#define au_fclr_cpdown(flags, name) \
++ do { (flags) &= ~AuCpdown_##name; } while (0)
++
++struct au_cpdown_dir_args {
++ struct dentry *parent;
++ unsigned int flags;
++};
++
++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst,
++ struct au_cpdown_dir_args *a)
++{
++ int err;
++ struct dentry *opq_dentry;
++
++ opq_dentry = au_diropq_create(dentry, bdst);
++ err = PTR_ERR(opq_dentry);
++ if (IS_ERR(opq_dentry))
++ goto out;
++ dput(opq_dentry);
++ au_fset_cpdown(a->flags, DIROPQ);
++
++out:
++ return err;
++}
++
++static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent,
++ struct inode *dir, aufs_bindex_t bdst)
++{
++ int err;
++ struct path h_path;
++ struct au_branch *br;
++
++ br = au_sbr(dentry->d_sb, bdst);
++ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br);
++ err = PTR_ERR(h_path.dentry);
++ if (IS_ERR(h_path.dentry))
++ goto out;
++
++ err = 0;
++ if (h_path.dentry->d_inode) {
++ h_path.mnt = br->br_mnt;
++ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path,
++ dentry);
++ }
++ dput(h_path.dentry);
++
++out:
++ return err;
++}
++
++static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent, void *arg)
++{
++ int err, rerr;
++ aufs_bindex_t bopq, bstart;
++ struct path h_path;
++ struct dentry *parent;
++ struct inode *h_dir, *h_inode, *inode, *dir;
++ struct au_cpdown_dir_args *args = arg;
++
++ bstart = au_dbstart(dentry);
++ /* dentry is di-locked */
++ parent = dget_parent(dentry);
++ dir = parent->d_inode;
++ h_dir = h_parent->d_inode;
++ AuDebugOn(h_dir != au_h_iptr(dir, bdst));
++ IMustLock(h_dir);
++
++ err = au_lkup_neg(dentry, bdst);
++ if (unlikely(err < 0))
++ goto out;
++ h_path.dentry = au_h_dptr(dentry, bdst);
++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst);
++ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path,
++ S_IRWXU | S_IRUGO | S_IXUGO);
++ if (unlikely(err))
++ goto out_put;
++ au_fset_cpdown(args->flags, MADE_DIR);
++
++ bopq = au_dbdiropq(dentry);
++ au_fclr_cpdown(args->flags, WHED);
++ au_fclr_cpdown(args->flags, DIROPQ);
++ if (au_dbwh(dentry) == bdst)
++ au_fset_cpdown(args->flags, WHED);
++ if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst)
++ au_fset_cpdown(args->flags, PARENT_OPQ);
++ h_inode = h_path.dentry->d_inode;
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ if (au_ftest_cpdown(args->flags, WHED)) {
++ err = au_cpdown_dir_opq(dentry, bdst, args);
++ if (unlikely(err)) {
++ mutex_unlock(&h_inode->i_mutex);
++ goto out_dir;
++ }
++ }
++
++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart));
++ mutex_unlock(&h_inode->i_mutex);
++ if (unlikely(err))
++ goto out_opq;
++
++ if (au_ftest_cpdown(args->flags, WHED)) {
++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst);
++ if (unlikely(err))
++ goto out_opq;
++ }
++
++ inode = dentry->d_inode;
++ if (au_ibend(inode) < bdst)
++ au_set_ibend(inode, bdst);
++ au_set_h_iptr(inode, bdst, au_igrab(h_inode),
++ au_hi_flags(inode, /*isdir*/1));
++ goto out; /* success */
++
++ /* revert */
++out_opq:
++ if (au_ftest_cpdown(args->flags, DIROPQ)) {
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ rerr = au_diropq_remove(dentry, bdst);
++ mutex_unlock(&h_inode->i_mutex);
++ if (unlikely(rerr)) {
++ AuIOErr("failed removing diropq for %.*s b%d (%d)\n",
++ AuDLNPair(dentry), bdst, rerr);
++ err = -EIO;
++ goto out;
++ }
++ }
++out_dir:
++ if (au_ftest_cpdown(args->flags, MADE_DIR)) {
++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path);
++ if (unlikely(rerr)) {
++ AuIOErr("failed removing %.*s b%d (%d)\n",
++ AuDLNPair(dentry), bdst, rerr);
++ err = -EIO;
++ }
++ }
++out_put:
++ au_set_h_dptr(dentry, bdst, NULL);
++ if (au_dbend(dentry) == bdst)
++ au_update_dbend(dentry);
++out:
++ dput(parent);
++ return err;
++}
++
++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst)
++{
++ int err;
++ struct au_cpdown_dir_args args = {
++ .parent = dget_parent(dentry),
++ .flags = 0
++ };
++
++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &args);
++ dput(args.parent);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* policies for create */
++
++static int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ int err, i, j, ndentry;
++ aufs_bindex_t bopq;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries, *parent, *d;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ parent = dget_parent(dentry);
++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0);
++ if (unlikely(err))
++ goto out_free;
++
++ err = bindex;
++ for (i = 0; i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ ndentry = dpage->ndentry;
++ for (j = 0; j < ndentry; j++) {
++ d = dentries[j];
++ di_read_lock_parent2(d, !AuLock_IR);
++ bopq = au_dbdiropq(d);
++ di_read_unlock(d, !AuLock_IR);
++ if (bopq >= 0 && bopq < err)
++ err = bopq;
++ }
++ }
++
++out_free:
++ dput(parent);
++ au_dpages_free(&dpages);
++out:
++ return err;
++}
++
++static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex)
++{
++ for (; bindex >= 0; bindex--)
++ if (!au_br_rdonly(au_sbr(sb, bindex)))
++ return bindex;
++ return -EROFS;
++}
++
++/* top down parent */
++static int au_wbr_create_tdp(struct dentry *dentry, int isdir __maybe_unused)
++{
++ int err;
++ aufs_bindex_t bstart, bindex;
++ struct super_block *sb;
++ struct dentry *parent, *h_parent;
++
++ sb = dentry->d_sb;
++ bstart = au_dbstart(dentry);
++ err = bstart;
++ if (!au_br_rdonly(au_sbr(sb, bstart)))
++ goto out;
++
++ err = -EROFS;
++ parent = dget_parent(dentry);
++ for (bindex = au_dbstart(parent); bindex < bstart; bindex++) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent || !h_parent->d_inode)
++ continue;
++
++ if (!au_br_rdonly(au_sbr(sb, bindex))) {
++ err = bindex;
++ break;
++ }
++ }
++ dput(parent);
++
++ /* bottom up here */
++ if (unlikely(err < 0)) {
++ err = au_wbr_bu(sb, bstart - 1);
++ if (err >= 0)
++ err = au_wbr_nonopq(dentry, err);
++ }
++
++out:
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* an exception for the policy other than tdp */
++static int au_wbr_create_exp(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bwh, bdiropq;
++ struct dentry *parent;
++
++ err = -1;
++ bwh = au_dbwh(dentry);
++ parent = dget_parent(dentry);
++ bdiropq = au_dbdiropq(parent);
++ if (bwh >= 0) {
++ if (bdiropq >= 0)
++ err = min(bdiropq, bwh);
++ else
++ err = bwh;
++ AuDbg("%d\n", err);
++ } else if (bdiropq >= 0) {
++ err = bdiropq;
++ AuDbg("%d\n", err);
++ }
++ dput(parent);
++
++ if (err >= 0)
++ err = au_wbr_nonopq(dentry, err);
++
++ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err)))
++ err = -1;
++
++ AuDbg("%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* round robin */
++static int au_wbr_create_init_rr(struct super_block *sb)
++{
++ int err;
++
++ err = au_wbr_bu(sb, au_sbend(sb));
++ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */
++ /* smp_mb(); */
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++static int au_wbr_create_rr(struct dentry *dentry, int isdir)
++{
++ int err, nbr;
++ unsigned int u;
++ aufs_bindex_t bindex, bend;
++ struct super_block *sb;
++ atomic_t *next;
++
++ err = au_wbr_create_exp(dentry);
++ if (err >= 0)
++ goto out;
++
++ sb = dentry->d_sb;
++ next = &au_sbi(sb)->si_wbr_rr_next;
++ bend = au_sbend(sb);
++ nbr = bend + 1;
++ for (bindex = 0; bindex <= bend; bindex++) {
++ if (!isdir) {
++ err = atomic_dec_return(next) + 1;
++ /* modulo for 0 is meaningless */
++ if (unlikely(!err))
++ err = atomic_dec_return(next) + 1;
++ } else
++ err = atomic_read(next);
++ AuDbg("%d\n", err);
++ u = err;
++ err = u % nbr;
++ AuDbg("%d\n", err);
++ if (!au_br_rdonly(au_sbr(sb, err)))
++ break;
++ err = -EROFS;
++ }
++
++ if (err >= 0)
++ err = au_wbr_nonopq(dentry, err);
++
++out:
++ AuDbg("%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* most free space */
++static void au_mfs(struct dentry *dentry)
++{
++ struct super_block *sb;
++ struct au_branch *br;
++ struct au_wbr_mfs *mfs;
++ aufs_bindex_t bindex, bend;
++ int err;
++ unsigned long long b, bavail;
++ struct path h_path;
++ /* reduce the stack usage */
++ struct kstatfs *st;
++
++ st = kmalloc(sizeof(*st), GFP_NOFS);
++ if (unlikely(!st)) {
++ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM);
++ return;
++ }
++
++ bavail = 0;
++ sb = dentry->d_sb;
++ mfs = &au_sbi(sb)->si_wbr_mfs;
++ MtxMustLock(&mfs->mfs_lock);
++ mfs->mfs_bindex = -EROFS;
++ mfs->mfsrr_bytes = 0;
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (au_br_rdonly(br))
++ continue;
++
++ /* sb->s_root for NFS is unreliable */
++ h_path.mnt = br->br_mnt;
++ h_path.dentry = h_path.mnt->mnt_root;
++ err = vfs_statfs(&h_path, st);
++ if (unlikely(err)) {
++ AuWarn1("failed statfs, b%d, %d\n", bindex, err);
++ continue;
++ }
++
++ /* when the available size is equal, select the lower one */
++ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail)
++ || sizeof(b) < sizeof(st->f_bsize));
++ b = st->f_bavail * st->f_bsize;
++ br->br_wbr->wbr_bytes = b;
++ if (b >= bavail) {
++ bavail = b;
++ mfs->mfs_bindex = bindex;
++ mfs->mfs_jiffy = jiffies;
++ }
++ }
++
++ mfs->mfsrr_bytes = bavail;
++ AuDbg("b%d\n", mfs->mfs_bindex);
++ kfree(st);
++}
++
++static int au_wbr_create_mfs(struct dentry *dentry, int isdir __maybe_unused)
++{
++ int err;
++ struct super_block *sb;
++ struct au_wbr_mfs *mfs;
++
++ err = au_wbr_create_exp(dentry);
++ if (err >= 0)
++ goto out;
++
++ sb = dentry->d_sb;
++ mfs = &au_sbi(sb)->si_wbr_mfs;
++ mutex_lock(&mfs->mfs_lock);
++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire)
++ || mfs->mfs_bindex < 0
++ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex)))
++ au_mfs(dentry);
++ mutex_unlock(&mfs->mfs_lock);
++ err = mfs->mfs_bindex;
++
++ if (err >= 0)
++ err = au_wbr_nonopq(dentry, err);
++
++out:
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++static int au_wbr_create_init_mfs(struct super_block *sb)
++{
++ struct au_wbr_mfs *mfs;
++
++ mfs = &au_sbi(sb)->si_wbr_mfs;
++ mutex_init(&mfs->mfs_lock);
++ mfs->mfs_jiffy = 0;
++ mfs->mfs_bindex = -EROFS;
++
++ return 0;
++}
++
++static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused)
++{
++ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock);
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* most free space and then round robin */
++static int au_wbr_create_mfsrr(struct dentry *dentry, int isdir)
++{
++ int err;
++ struct au_wbr_mfs *mfs;
++
++ err = au_wbr_create_mfs(dentry, isdir);
++ if (err >= 0) {
++ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs;
++ mutex_lock(&mfs->mfs_lock);
++ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark)
++ err = au_wbr_create_rr(dentry, isdir);
++ mutex_unlock(&mfs->mfs_lock);
++ }
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++static int au_wbr_create_init_mfsrr(struct super_block *sb)
++{
++ int err;
++
++ au_wbr_create_init_mfs(sb); /* ignore */
++ err = au_wbr_create_init_rr(sb);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* top down parent and most free space */
++static int au_wbr_create_pmfs(struct dentry *dentry, int isdir)
++{
++ int err, e2;
++ unsigned long long b;
++ aufs_bindex_t bindex, bstart, bend;
++ struct super_block *sb;
++ struct dentry *parent, *h_parent;
++ struct au_branch *br;
++
++ err = au_wbr_create_tdp(dentry, isdir);
++ if (unlikely(err < 0))
++ goto out;
++ parent = dget_parent(dentry);
++ bstart = au_dbstart(parent);
++ bend = au_dbtaildir(parent);
++ if (bstart == bend)
++ goto out_parent; /* success */
++
++ e2 = au_wbr_create_mfs(dentry, isdir);
++ if (e2 < 0)
++ goto out_parent; /* success */
++
++ /* when the available size is equal, select upper one */
++ sb = dentry->d_sb;
++ br = au_sbr(sb, err);
++ b = br->br_wbr->wbr_bytes;
++ AuDbg("b%d, %llu\n", err, b);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent || !h_parent->d_inode)
++ continue;
++
++ br = au_sbr(sb, bindex);
++ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) {
++ b = br->br_wbr->wbr_bytes;
++ err = bindex;
++ AuDbg("b%d, %llu\n", err, b);
++ }
++ }
++
++ if (err >= 0)
++ err = au_wbr_nonopq(dentry, err);
++
++out_parent:
++ dput(parent);
++out:
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* policies for copyup */
++
++/* top down parent */
++static int au_wbr_copyup_tdp(struct dentry *dentry)
++{
++ return au_wbr_create_tdp(dentry, /*isdir, anything is ok*/0);
++}
++
++/* bottom up parent */
++static int au_wbr_copyup_bup(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bindex, bstart;
++ struct dentry *parent, *h_parent;
++ struct super_block *sb;
++
++ err = -EROFS;
++ sb = dentry->d_sb;
++ parent = dget_parent(dentry);
++ bstart = au_dbstart(parent);
++ for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent || !h_parent->d_inode)
++ continue;
++
++ if (!au_br_rdonly(au_sbr(sb, bindex))) {
++ err = bindex;
++ break;
++ }
++ }
++ dput(parent);
++
++ /* bottom up here */
++ if (unlikely(err < 0))
++ err = au_wbr_bu(sb, bstart - 1);
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* bottom up */
++static int au_wbr_copyup_bu(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bstart;
++
++ bstart = au_dbstart(dentry);
++ err = au_wbr_bu(dentry->d_sb, bstart);
++ AuDbg("b%d\n", err);
++ if (err > bstart)
++ err = au_wbr_nonopq(dentry, err);
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_wbr_copyup_operations au_wbr_copyup_ops[] = {
++ [AuWbrCopyup_TDP] = {
++ .copyup = au_wbr_copyup_tdp
++ },
++ [AuWbrCopyup_BUP] = {
++ .copyup = au_wbr_copyup_bup
++ },
++ [AuWbrCopyup_BU] = {
++ .copyup = au_wbr_copyup_bu
++ }
++};
++
++struct au_wbr_create_operations au_wbr_create_ops[] = {
++ [AuWbrCreate_TDP] = {
++ .create = au_wbr_create_tdp
++ },
++ [AuWbrCreate_RR] = {
++ .create = au_wbr_create_rr,
++ .init = au_wbr_create_init_rr
++ },
++ [AuWbrCreate_MFS] = {
++ .create = au_wbr_create_mfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_MFSV] = {
++ .create = au_wbr_create_mfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_MFSRR] = {
++ .create = au_wbr_create_mfsrr,
++ .init = au_wbr_create_init_mfsrr,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_MFSRRV] = {
++ .create = au_wbr_create_mfsrr,
++ .init = au_wbr_create_init_mfsrr,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_PMFS] = {
++ .create = au_wbr_create_pmfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_PMFSV] = {
++ .create = au_wbr_create_pmfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ }
++};
+diff -Nur linux-2.6.36.orig/fs/aufs/whout.c linux-2.6.36/fs/aufs/whout.c
+--- linux-2.6.36.orig/fs/aufs/whout.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/whout.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,1062 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * whiteout for logical deletion and opaque directory
++ */
++
++#include <linux/fs.h>
++#include "aufs.h"
++
++#define WH_MASK S_IRUGO
++
++/*
++ * If a directory contains this file, then it is opaque. We start with the
++ * .wh. flag so that it is blocked by lookup.
++ */
++static struct qstr diropq_name = {
++ .name = AUFS_WH_DIROPQ,
++ .len = sizeof(AUFS_WH_DIROPQ) - 1
++};
++
++/*
++ * generate whiteout name, which is NOT terminated by NULL.
++ * @name: original d_name.name
++ * @len: original d_name.len
++ * @wh: whiteout qstr
++ * returns zero when succeeds, otherwise error.
++ * succeeded value as wh->name should be freed by kfree().
++ */
++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name)
++{
++ char *p;
++
++ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN))
++ return -ENAMETOOLONG;
++
++ wh->len = name->len + AUFS_WH_PFX_LEN;
++ p = kmalloc(wh->len, GFP_NOFS);
++ wh->name = p;
++ if (p) {
++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
++ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len);
++ /* smp_mb(); */
++ return 0;
++ }
++ return -ENOMEM;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * test if the @wh_name exists under @h_parent.
++ * @try_sio specifies the necessary of super-io.
++ */
++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name,
++ struct au_branch *br, int try_sio)
++{
++ int err;
++ struct dentry *wh_dentry;
++
++ if (!try_sio)
++ wh_dentry = au_lkup_one(wh_name, h_parent, br, /*nd*/NULL);
++ else
++ wh_dentry = au_sio_lkup_one(wh_name, h_parent, br);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out;
++
++ err = 0;
++ if (!wh_dentry->d_inode)
++ goto out_wh; /* success */
++
++ err = 1;
++ if (S_ISREG(wh_dentry->d_inode->i_mode))
++ goto out_wh; /* success */
++
++ err = -EIO;
++ AuIOErr("%.*s Invalid whiteout entry type 0%o.\n",
++ AuDLNPair(wh_dentry), wh_dentry->d_inode->i_mode);
++
++out_wh:
++ dput(wh_dentry);
++out:
++ return err;
++}
++
++/*
++ * test if the @h_dentry sets opaque or not.
++ */
++int au_diropq_test(struct dentry *h_dentry, struct au_branch *br)
++{
++ int err;
++ struct inode *h_dir;
++
++ h_dir = h_dentry->d_inode;
++ err = au_wh_test(h_dentry, &diropq_name, br,
++ au_test_h_perm_sio(h_dir, MAY_EXEC));
++ return err;
++}
++
++/*
++ * returns a negative dentry whose name is unique and temporary.
++ */
++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
++ struct qstr *prefix)
++{
++ struct dentry *dentry;
++ int i;
++ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN_MIN + 1],
++ *name, *p;
++ /* strict atomic_t is unnecessary here */
++ static unsigned short cnt;
++ struct qstr qs;
++
++ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN);
++
++ name = defname;
++ qs.len = sizeof(defname) - DNAME_INLINE_LEN_MIN + prefix->len - 1;
++ if (unlikely(prefix->len > DNAME_INLINE_LEN_MIN)) {
++ dentry = ERR_PTR(-ENAMETOOLONG);
++ if (unlikely(qs.len > NAME_MAX))
++ goto out;
++ dentry = ERR_PTR(-ENOMEM);
++ name = kmalloc(qs.len + 1, GFP_NOFS);
++ if (unlikely(!name))
++ goto out;
++ }
++
++ /* doubly whiteout-ed */
++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2);
++ p = name + AUFS_WH_PFX_LEN * 2;
++ memcpy(p, prefix->name, prefix->len);
++ p += prefix->len;
++ *p++ = '.';
++ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN);
++
++ qs.name = name;
++ for (i = 0; i < 3; i++) {
++ sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++);
++ dentry = au_sio_lkup_one(&qs, h_parent, br);
++ if (IS_ERR(dentry) || !dentry->d_inode)
++ goto out_name;
++ dput(dentry);
++ }
++ /* pr_warning("could not get random name\n"); */
++ dentry = ERR_PTR(-EEXIST);
++ AuDbg("%.*s\n", AuLNPair(&qs));
++ BUG();
++
++out_name:
++ if (name != defname)
++ kfree(name);
++out:
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++/*
++ * rename the @h_dentry on @br to the whiteouted temporary name.
++ */
++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br)
++{
++ int err;
++ struct path h_path = {
++ .mnt = br->br_mnt
++ };
++ struct inode *h_dir;
++ struct dentry *h_parent;
++
++ h_parent = h_dentry->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++
++ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name);
++ err = PTR_ERR(h_path.dentry);
++ if (IS_ERR(h_path.dentry))
++ goto out;
++
++ /* under the same dir, no need to lock_rename() */
++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path);
++ AuTraceErr(err);
++ dput(h_path.dentry);
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * functions for removing a whiteout
++ */
++
++static int do_unlink_wh(struct inode *h_dir, struct path *h_path)
++{
++ int force;
++
++ /*
++ * forces superio when the dir has a sticky bit.
++ * this may be a violation of unix fs semantics.
++ */
++ force = (h_dir->i_mode & S_ISVTX)
++ && h_path->dentry->d_inode->i_uid != current_fsuid();
++ return vfsub_unlink(h_dir, h_path, force);
++}
++
++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path,
++ struct dentry *dentry)
++{
++ int err;
++
++ err = do_unlink_wh(h_dir, h_path);
++ if (!err && dentry)
++ au_set_dbwh(dentry, -1);
++
++ return err;
++}
++
++static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh,
++ struct au_branch *br)
++{
++ int err;
++ struct path h_path = {
++ .mnt = br->br_mnt
++ };
++
++ err = 0;
++ h_path.dentry = au_lkup_one(wh, h_parent, br, /*nd*/NULL);
++ if (IS_ERR(h_path.dentry))
++ err = PTR_ERR(h_path.dentry);
++ else {
++ if (h_path.dentry->d_inode
++ && S_ISREG(h_path.dentry->d_inode->i_mode))
++ err = do_unlink_wh(h_parent->d_inode, &h_path);
++ dput(h_path.dentry);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * initialize/clean whiteout for a branch
++ */
++
++static void au_wh_clean(struct inode *h_dir, struct path *whpath,
++ const int isdir)
++{
++ int err;
++
++ if (!whpath->dentry->d_inode)
++ return;
++
++ err = mnt_want_write(whpath->mnt);
++ if (!err) {
++ if (isdir)
++ err = vfsub_rmdir(h_dir, whpath);
++ else
++ err = vfsub_unlink(h_dir, whpath, /*force*/0);
++ mnt_drop_write(whpath->mnt);
++ }
++ if (unlikely(err))
++ pr_warning("failed removing %.*s (%d), ignored.\n",
++ AuDLNPair(whpath->dentry), err);
++}
++
++static int test_linkable(struct dentry *h_root)
++{
++ struct inode *h_dir = h_root->d_inode;
++
++ if (h_dir->i_op->link)
++ return 0;
++
++ pr_err("%.*s (%s) doesn't support link(2), use noplink and rw+nolwh\n",
++ AuDLNPair(h_root), au_sbtype(h_root->d_sb));
++ return -ENOSYS;
++}
++
++/* todo: should this mkdir be done in /sbin/mount.aufs helper? */
++static int au_whdir(struct inode *h_dir, struct path *path)
++{
++ int err;
++
++ err = -EEXIST;
++ if (!path->dentry->d_inode) {
++ int mode = S_IRWXU;
++
++ if (au_test_nfs(path->dentry->d_sb))
++ mode |= S_IXUGO;
++ err = mnt_want_write(path->mnt);
++ if (!err) {
++ err = vfsub_mkdir(h_dir, path, mode);
++ mnt_drop_write(path->mnt);
++ }
++ } else if (S_ISDIR(path->dentry->d_inode->i_mode))
++ err = 0;
++ else
++ pr_err("unknown %.*s exists\n", AuDLNPair(path->dentry));
++
++ return err;
++}
++
++struct au_wh_base {
++ const struct qstr *name;
++ struct dentry *dentry;
++};
++
++static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[],
++ struct path *h_path)
++{
++ h_path->dentry = base[AuBrWh_BASE].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/0);
++ h_path->dentry = base[AuBrWh_PLINK].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++ h_path->dentry = base[AuBrWh_ORPH].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++}
++
++/*
++ * returns tri-state,
++ * minus: error, caller should print the mesage
++ * zero: succuess
++ * plus: error, caller should NOT print the mesage
++ */
++static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr,
++ int do_plink, struct au_wh_base base[],
++ struct path *h_path)
++{
++ int err;
++ struct inode *h_dir;
++
++ h_dir = h_root->d_inode;
++ h_path->dentry = base[AuBrWh_BASE].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/0);
++ h_path->dentry = base[AuBrWh_PLINK].dentry;
++ if (do_plink) {
++ err = test_linkable(h_root);
++ if (unlikely(err)) {
++ err = 1;
++ goto out;
++ }
++
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry);
++ } else
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++ h_path->dentry = base[AuBrWh_ORPH].dentry;
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry);
++
++out:
++ return err;
++}
++
++/*
++ * for the moment, aufs supports the branch filesystem which does not support
++ * link(2). testing on FAT which does not support i_op->setattr() fully either,
++ * copyup failed. finally, such filesystem will not be used as the writable
++ * branch.
++ *
++ * returns tri-state, see above.
++ */
++static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr,
++ int do_plink, struct au_wh_base base[],
++ struct path *h_path)
++{
++ int err;
++ struct inode *h_dir;
++
++ WbrWhMustWriteLock(wbr);
++
++ err = test_linkable(h_root);
++ if (unlikely(err)) {
++ err = 1;
++ goto out;
++ }
++
++ /*
++ * todo: should this create be done in /sbin/mount.aufs helper?
++ */
++ err = -EEXIST;
++ h_dir = h_root->d_inode;
++ if (!base[AuBrWh_BASE].dentry->d_inode) {
++ err = mnt_want_write(h_path->mnt);
++ if (!err) {
++ h_path->dentry = base[AuBrWh_BASE].dentry;
++ err = vfsub_create(h_dir, h_path, WH_MASK);
++ mnt_drop_write(h_path->mnt);
++ }
++ } else if (S_ISREG(base[AuBrWh_BASE].dentry->d_inode->i_mode))
++ err = 0;
++ else
++ pr_err("unknown %.*s/%.*s exists\n",
++ AuDLNPair(h_root), AuDLNPair(base[AuBrWh_BASE].dentry));
++ if (unlikely(err))
++ goto out;
++
++ h_path->dentry = base[AuBrWh_PLINK].dentry;
++ if (do_plink) {
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry);
++ } else
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry);
++
++ h_path->dentry = base[AuBrWh_ORPH].dentry;
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry);
++
++out:
++ return err;
++}
++
++/*
++ * initialize the whiteout base file/dir for @br.
++ */
++int au_wh_init(struct dentry *h_root, struct au_branch *br,
++ struct super_block *sb)
++{
++ int err, i;
++ const unsigned char do_plink
++ = !!au_opt_test(au_mntflags(sb), PLINK);
++ struct path path = {
++ .mnt = br->br_mnt
++ };
++ struct inode *h_dir;
++ struct au_wbr *wbr = br->br_wbr;
++ static const struct qstr base_name[] = {
++ [AuBrWh_BASE] = {
++ .name = AUFS_BASE_NAME,
++ .len = sizeof(AUFS_BASE_NAME) - 1
++ },
++ [AuBrWh_PLINK] = {
++ .name = AUFS_PLINKDIR_NAME,
++ .len = sizeof(AUFS_PLINKDIR_NAME) - 1
++ },
++ [AuBrWh_ORPH] = {
++ .name = AUFS_ORPHDIR_NAME,
++ .len = sizeof(AUFS_ORPHDIR_NAME) - 1
++ }
++ };
++ struct au_wh_base base[] = {
++ [AuBrWh_BASE] = {
++ .name = base_name + AuBrWh_BASE,
++ .dentry = NULL
++ },
++ [AuBrWh_PLINK] = {
++ .name = base_name + AuBrWh_PLINK,
++ .dentry = NULL
++ },
++ [AuBrWh_ORPH] = {
++ .name = base_name + AuBrWh_ORPH,
++ .dentry = NULL
++ }
++ };
++
++ if (wbr)
++ WbrWhMustWriteLock(wbr);
++
++ for (i = 0; i < AuBrWh_Last; i++) {
++ /* doubly whiteouted */
++ struct dentry *d;
++
++ d = au_wh_lkup(h_root, (void *)base[i].name, br);
++ err = PTR_ERR(d);
++ if (IS_ERR(d))
++ goto out;
++
++ base[i].dentry = d;
++ AuDebugOn(wbr
++ && wbr->wbr_wh[i]
++ && wbr->wbr_wh[i] != base[i].dentry);
++ }
++
++ if (wbr)
++ for (i = 0; i < AuBrWh_Last; i++) {
++ dput(wbr->wbr_wh[i]);
++ wbr->wbr_wh[i] = NULL;
++ }
++
++ err = 0;
++ switch (br->br_perm) {
++ case AuBrPerm_RO:
++ case AuBrPerm_ROWH:
++ case AuBrPerm_RR:
++ case AuBrPerm_RRWH:
++ h_dir = h_root->d_inode;
++ au_wh_init_ro(h_dir, base, &path);
++ break;
++
++ case AuBrPerm_RWNoLinkWH:
++ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path);
++ if (err > 0)
++ goto out;
++ else if (err)
++ goto out_err;
++ break;
++
++ case AuBrPerm_RW:
++ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path);
++ if (err > 0)
++ goto out;
++ else if (err)
++ goto out_err;
++ break;
++
++ default:
++ BUG();
++ }
++ goto out; /* success */
++
++out_err:
++ pr_err("an error(%d) on the writable branch %.*s(%s)\n",
++ err, AuDLNPair(h_root), au_sbtype(h_root->d_sb));
++out:
++ for (i = 0; i < AuBrWh_Last; i++)
++ dput(base[i].dentry);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * whiteouts are all hard-linked usually.
++ * when its link count reaches a ceiling, we create a new whiteout base
++ * asynchronously.
++ */
++
++struct reinit_br_wh {
++ struct super_block *sb;
++ struct au_branch *br;
++};
++
++static void reinit_br_wh(void *arg)
++{
++ int err;
++ aufs_bindex_t bindex;
++ struct path h_path;
++ struct reinit_br_wh *a = arg;
++ struct au_wbr *wbr;
++ struct inode *dir;
++ struct dentry *h_root;
++ struct au_hinode *hdir;
++
++ err = 0;
++ wbr = a->br->br_wbr;
++ /* big aufs lock */
++ si_noflush_write_lock(a->sb);
++ if (!au_br_writable(a->br->br_perm))
++ goto out;
++ bindex = au_br_index(a->sb, a->br->br_id);
++ if (unlikely(bindex < 0))
++ goto out;
++
++ di_read_lock_parent(a->sb->s_root, AuLock_IR);
++ dir = a->sb->s_root->d_inode;
++ hdir = au_hi(dir, bindex);
++ h_root = au_h_dptr(a->sb->s_root, bindex);
++
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ wbr_wh_write_lock(wbr);
++ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode,
++ h_root, a->br);
++ if (!err) {
++ err = mnt_want_write(a->br->br_mnt);
++ if (!err) {
++ h_path.dentry = wbr->wbr_whbase;
++ h_path.mnt = a->br->br_mnt;
++ err = vfsub_unlink(hdir->hi_inode, &h_path, /*force*/0);
++ mnt_drop_write(a->br->br_mnt);
++ }
++ } else {
++ pr_warning("%.*s is moved, ignored\n",
++ AuDLNPair(wbr->wbr_whbase));
++ err = 0;
++ }
++ dput(wbr->wbr_whbase);
++ wbr->wbr_whbase = NULL;
++ if (!err)
++ err = au_wh_init(h_root, a->br, a->sb);
++ wbr_wh_write_unlock(wbr);
++ au_hn_imtx_unlock(hdir);
++ di_read_unlock(a->sb->s_root, AuLock_IR);
++
++out:
++ if (wbr)
++ atomic_dec(&wbr->wbr_wh_running);
++ atomic_dec(&a->br->br_count);
++ si_write_unlock(a->sb);
++ au_nwt_done(&au_sbi(a->sb)->si_nowait);
++ kfree(arg);
++ if (unlikely(err))
++ AuIOErr("err %d\n", err);
++}
++
++static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br)
++{
++ int do_dec, wkq_err;
++ struct reinit_br_wh *arg;
++
++ do_dec = 1;
++ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1)
++ goto out;
++
++ /* ignore ENOMEM */
++ arg = kmalloc(sizeof(*arg), GFP_NOFS);
++ if (arg) {
++ /*
++ * dec(wh_running), kfree(arg) and dec(br_count)
++ * in reinit function
++ */
++ arg->sb = sb;
++ arg->br = br;
++ atomic_inc(&br->br_count);
++ wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb);
++ if (unlikely(wkq_err)) {
++ atomic_dec(&br->br_wbr->wbr_wh_running);
++ atomic_dec(&br->br_count);
++ kfree(arg);
++ }
++ do_dec = 0;
++ }
++
++out:
++ if (do_dec)
++ atomic_dec(&br->br_wbr->wbr_wh_running);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create the whiteout @wh.
++ */
++static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex,
++ struct dentry *wh)
++{
++ int err;
++ struct path h_path = {
++ .dentry = wh
++ };
++ struct au_branch *br;
++ struct au_wbr *wbr;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++
++ h_parent = wh->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++
++ br = au_sbr(sb, bindex);
++ h_path.mnt = br->br_mnt;
++ wbr = br->br_wbr;
++ wbr_wh_read_lock(wbr);
++ if (wbr->wbr_whbase) {
++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path);
++ if (!err || err != -EMLINK)
++ goto out;
++
++ /* link count full. re-initialize br_whbase. */
++ kick_reinit_br_wh(sb, br);
++ }
++
++ /* return this error in this context */
++ err = vfsub_create(h_dir, &h_path, WH_MASK);
++
++out:
++ wbr_wh_read_unlock(wbr);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create or remove the diropq.
++ */
++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int flags)
++{
++ struct dentry *opq_dentry, *h_dentry;
++ struct super_block *sb;
++ struct au_branch *br;
++ int err;
++
++ sb = dentry->d_sb;
++ br = au_sbr(sb, bindex);
++ h_dentry = au_h_dptr(dentry, bindex);
++ opq_dentry = au_lkup_one(&diropq_name, h_dentry, br, /*nd*/NULL);
++ if (IS_ERR(opq_dentry))
++ goto out;
++
++ if (au_ftest_diropq(flags, CREATE)) {
++ err = link_or_create_wh(sb, bindex, opq_dentry);
++ if (!err) {
++ au_set_dbdiropq(dentry, bindex);
++ goto out; /* success */
++ }
++ } else {
++ struct path tmp = {
++ .dentry = opq_dentry,
++ .mnt = br->br_mnt
++ };
++ err = do_unlink_wh(au_h_iptr(dentry->d_inode, bindex), &tmp);
++ if (!err)
++ au_set_dbdiropq(dentry, -1);
++ }
++ dput(opq_dentry);
++ opq_dentry = ERR_PTR(err);
++
++out:
++ return opq_dentry;
++}
++
++struct do_diropq_args {
++ struct dentry **errp;
++ struct dentry *dentry;
++ aufs_bindex_t bindex;
++ unsigned int flags;
++};
++
++static void call_do_diropq(void *args)
++{
++ struct do_diropq_args *a = args;
++ *a->errp = do_diropq(a->dentry, a->bindex, a->flags);
++}
++
++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int flags)
++{
++ struct dentry *diropq, *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!au_test_h_perm_sio(h_dentry->d_inode, MAY_EXEC | MAY_WRITE))
++ diropq = do_diropq(dentry, bindex, flags);
++ else {
++ int wkq_err;
++ struct do_diropq_args args = {
++ .errp = &diropq,
++ .dentry = dentry,
++ .bindex = bindex,
++ .flags = flags
++ };
++
++ wkq_err = au_wkq_wait(call_do_diropq, &args);
++ if (unlikely(wkq_err))
++ diropq = ERR_PTR(wkq_err);
++ }
++
++ return diropq;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * lookup whiteout dentry.
++ * @h_parent: lower parent dentry which must exist and be locked
++ * @base_name: name of dentry which will be whiteouted
++ * returns dentry for whiteout.
++ */
++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name,
++ struct au_branch *br)
++{
++ int err;
++ struct qstr wh_name;
++ struct dentry *wh_dentry;
++
++ err = au_wh_name_alloc(&wh_name, base_name);
++ wh_dentry = ERR_PTR(err);
++ if (!err) {
++ wh_dentry = au_lkup_one(&wh_name, h_parent, br, /*nd*/NULL);
++ kfree(wh_name.name);
++ }
++ return wh_dentry;
++}
++
++/*
++ * link/create a whiteout for @dentry on @bindex.
++ */
++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent)
++{
++ struct dentry *wh_dentry;
++ struct super_block *sb;
++ int err;
++
++ sb = dentry->d_sb;
++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex));
++ if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) {
++ err = link_or_create_wh(sb, bindex, wh_dentry);
++ if (!err)
++ au_set_dbwh(dentry, bindex);
++ else {
++ dput(wh_dentry);
++ wh_dentry = ERR_PTR(err);
++ }
++ }
++
++ return wh_dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* Delete all whiteouts in this directory on branch bindex. */
++static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist,
++ aufs_bindex_t bindex, struct au_branch *br)
++{
++ int err;
++ unsigned long ul, n;
++ struct qstr wh_name;
++ char *p;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++ struct au_vdir_destr *str;
++
++ err = -ENOMEM;
++ p = __getname_gfp(GFP_NOFS);
++ wh_name.name = p;
++ if (unlikely(!wh_name.name))
++ goto out;
++
++ err = 0;
++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
++ p += AUFS_WH_PFX_LEN;
++ n = whlist->nh_num;
++ head = whlist->nh_head;
++ for (ul = 0; !err && ul < n; ul++, head++) {
++ hlist_for_each_entry(tpos, pos, head, wh_hash) {
++ if (tpos->wh_bindex != bindex)
++ continue;
++
++ str = &tpos->wh_str;
++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) {
++ memcpy(p, str->name, str->len);
++ wh_name.len = AUFS_WH_PFX_LEN + str->len;
++ err = unlink_wh_name(h_dentry, &wh_name, br);
++ if (!err)
++ continue;
++ break;
++ }
++ AuIOErr("whiteout name too long %.*s\n",
++ str->len, str->name);
++ err = -EIO;
++ break;
++ }
++ }
++ __putname(wh_name.name);
++
++out:
++ return err;
++}
++
++struct del_wh_children_args {
++ int *errp;
++ struct dentry *h_dentry;
++ struct au_nhash *whlist;
++ aufs_bindex_t bindex;
++ struct au_branch *br;
++};
++
++static void call_del_wh_children(void *args)
++{
++ struct del_wh_children_args *a = args;
++ *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br);
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp)
++{
++ struct au_whtmp_rmdir *whtmp;
++ int err;
++ unsigned int rdhash;
++
++ SiMustAnyLock(sb);
++
++ whtmp = kmalloc(sizeof(*whtmp), gfp);
++ if (unlikely(!whtmp)) {
++ whtmp = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++
++ whtmp->dir = NULL;
++ whtmp->br = NULL;
++ whtmp->wh_dentry = NULL;
++ /* no estimation for dir size */
++ rdhash = au_sbi(sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = AUFS_RDHASH_DEF;
++ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp);
++ if (unlikely(err)) {
++ kfree(whtmp);
++ whtmp = ERR_PTR(err);
++ }
++
++out:
++ return whtmp;
++}
++
++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp)
++{
++ if (whtmp->br)
++ atomic_dec(&whtmp->br->br_count);
++ dput(whtmp->wh_dentry);
++ iput(whtmp->dir);
++ au_nhash_wh_free(&whtmp->whlist);
++ kfree(whtmp);
++}
++
++/*
++ * rmdir the whiteouted temporary named dir @h_dentry.
++ * @whlist: whiteouted children.
++ */
++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_nhash *whlist)
++{
++ int err;
++ struct path h_tmp;
++ struct inode *wh_inode, *h_dir;
++ struct au_branch *br;
++
++ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */
++ IMustLock(h_dir);
++
++ br = au_sbr(dir->i_sb, bindex);
++ wh_inode = wh_dentry->d_inode;
++ mutex_lock_nested(&wh_inode->i_mutex, AuLsc_I_CHILD);
++
++ /*
++ * someone else might change some whiteouts while we were sleeping.
++ * it means this whlist may have an obsoleted entry.
++ */
++ if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE))
++ err = del_wh_children(wh_dentry, whlist, bindex, br);
++ else {
++ int wkq_err;
++ struct del_wh_children_args args = {
++ .errp = &err,
++ .h_dentry = wh_dentry,
++ .whlist = whlist,
++ .bindex = bindex,
++ .br = br
++ };
++
++ wkq_err = au_wkq_wait(call_del_wh_children, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++ mutex_unlock(&wh_inode->i_mutex);
++
++ if (!err) {
++ h_tmp.dentry = wh_dentry;
++ h_tmp.mnt = br->br_mnt;
++ err = vfsub_rmdir(h_dir, &h_tmp);
++ }
++
++ if (!err) {
++ if (au_ibstart(dir) == bindex) {
++ /* todo: dir->i_mutex is necessary */
++ au_cpup_attr_timesizes(dir);
++ vfsub_drop_nlink(dir);
++ }
++ return 0; /* success */
++ }
++
++ pr_warning("failed removing %.*s(%d), ignored\n",
++ AuDLNPair(wh_dentry), err);
++ return err;
++}
++
++static void call_rmdir_whtmp(void *args)
++{
++ int err;
++ aufs_bindex_t bindex;
++ struct au_whtmp_rmdir *a = args;
++ struct super_block *sb;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++ struct au_hinode *hdir;
++
++ /* rmdir by nfsd may cause deadlock with this i_mutex */
++ /* mutex_lock(&a->dir->i_mutex); */
++ err = -EROFS;
++ sb = a->dir->i_sb;
++ si_read_lock(sb, !AuLock_FLUSH);
++ if (!au_br_writable(a->br->br_perm))
++ goto out;
++ bindex = au_br_index(sb, a->br->br_id);
++ if (unlikely(bindex < 0))
++ goto out;
++
++ err = -EIO;
++ ii_write_lock_parent(a->dir);
++ h_parent = dget_parent(a->wh_dentry);
++ h_dir = h_parent->d_inode;
++ hdir = au_hi(a->dir, bindex);
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent,
++ a->br);
++ if (!err) {
++ err = mnt_want_write(a->br->br_mnt);
++ if (!err) {
++ err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry,
++ &a->whlist);
++ mnt_drop_write(a->br->br_mnt);
++ }
++ }
++ au_hn_imtx_unlock(hdir);
++ dput(h_parent);
++ ii_write_unlock(a->dir);
++
++out:
++ /* mutex_unlock(&a->dir->i_mutex); */
++ au_whtmp_rmdir_free(a);
++ si_read_unlock(sb);
++ au_nwt_done(&au_sbi(sb)->si_nowait);
++ if (unlikely(err))
++ AuIOErr("err %d\n", err);
++}
++
++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args)
++{
++ int wkq_err;
++ struct super_block *sb;
++
++ IMustLock(dir);
++
++ /* all post-process will be done in do_rmdir_whtmp(). */
++ sb = dir->i_sb;
++ args->dir = au_igrab(dir);
++ args->br = au_sbr(sb, bindex);
++ atomic_inc(&args->br->br_count);
++ args->wh_dentry = dget(wh_dentry);
++ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb);
++ if (unlikely(wkq_err)) {
++ pr_warning("rmdir error %.*s (%d), ignored\n",
++ AuDLNPair(wh_dentry), wkq_err);
++ au_whtmp_rmdir_free(args);
++ }
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/whout.h linux-2.6.36/fs/aufs/whout.h
+--- linux-2.6.36.orig/fs/aufs/whout.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/whout.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,89 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * whiteout for logical deletion and opaque directory
++ */
++
++#ifndef __AUFS_WHOUT_H__
++#define __AUFS_WHOUT_H__
++
++#ifdef __KERNEL__
++
++#include <linux/aufs_type.h>
++#include "dir.h"
++
++/* whout.c */
++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name);
++struct au_branch;
++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name,
++ struct au_branch *br, int try_sio);
++int au_diropq_test(struct dentry *h_dentry, struct au_branch *br);
++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
++ struct qstr *prefix);
++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br);
++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path,
++ struct dentry *dentry);
++int au_wh_init(struct dentry *h_parent, struct au_branch *br,
++ struct super_block *sb);
++
++/* diropq flags */
++#define AuDiropq_CREATE 1
++#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name)
++#define au_fset_diropq(flags, name) \
++ do { (flags) |= AuDiropq_##name; } while (0)
++#define au_fclr_diropq(flags, name) \
++ do { (flags) &= ~AuDiropq_##name; } while (0)
++
++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int flags);
++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name,
++ struct au_branch *br);
++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent);
++
++/* real rmdir for the whiteout-ed dir */
++struct au_whtmp_rmdir {
++ struct inode *dir;
++ struct au_branch *br;
++ struct dentry *wh_dentry;
++ struct au_nhash whlist;
++};
++
++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp);
++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp);
++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_nhash *whlist);
++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args);
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct dentry *au_diropq_create(struct dentry *dentry,
++ aufs_bindex_t bindex)
++{
++ return au_diropq_sio(dentry, bindex, AuDiropq_CREATE);
++}
++
++static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE));
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_WHOUT_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/wkq.c linux-2.6.36/fs/aufs/wkq.c
+--- linux-2.6.36.orig/fs/aufs/wkq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/wkq.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,236 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * workqueue for asynchronous/super-io operations
++ * todo: try new dredential scheme
++ */
++
++#include <linux/module.h>
++#include "aufs.h"
++
++/* internal workqueue named AUFS_WKQ_NAME and AUFS_WKQ_PRE_NAME */
++enum {
++ AuWkq_INORMAL,
++ AuWkq_IPRE
++};
++
++static struct {
++ char *name;
++ struct workqueue_struct *wkq;
++} au_wkq[] = {
++ [AuWkq_INORMAL] = {
++ .name = AUFS_WKQ_NAME
++ },
++ [AuWkq_IPRE] = {
++ .name = AUFS_WKQ_PRE_NAME
++ }
++};
++
++struct au_wkinfo {
++ struct work_struct wk;
++ struct kobject *kobj;
++
++ unsigned int flags; /* see wkq.h */
++
++ au_wkq_func_t func;
++ void *args;
++
++ struct completion *comp;
++};
++
++/* ---------------------------------------------------------------------- */
++
++static void wkq_func(struct work_struct *wk)
++{
++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk);
++
++ AuDebugOn(current_fsuid());
++ AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY);
++
++ wkinfo->func(wkinfo->args);
++ if (au_ftest_wkq(wkinfo->flags, WAIT))
++ complete(wkinfo->comp);
++ else {
++ kobject_put(wkinfo->kobj);
++ module_put(THIS_MODULE);
++ kfree(wkinfo);
++ }
++}
++
++/*
++ * Since struct completion is large, try allocating it dynamically.
++ */
++#if defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS)
++#define AuWkqCompDeclare(name) struct completion *comp = NULL
++
++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp)
++{
++ *comp = kmalloc(sizeof(**comp), GFP_NOFS);
++ if (*comp) {
++ init_completion(*comp);
++ wkinfo->comp = *comp;
++ return 0;
++ }
++ return -ENOMEM;
++}
++
++static void au_wkq_comp_free(struct completion *comp)
++{
++ kfree(comp);
++}
++
++#else
++
++/* no braces */
++#define AuWkqCompDeclare(name) \
++ DECLARE_COMPLETION_ONSTACK(_ ## name); \
++ struct completion *comp = &_ ## name
++
++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp)
++{
++ wkinfo->comp = *comp;
++ return 0;
++}
++
++static void au_wkq_comp_free(struct completion *comp __maybe_unused)
++{
++ /* empty */
++}
++#endif /* 4KSTACKS */
++
++static void au_wkq_run(struct au_wkinfo *wkinfo, unsigned int flags)
++{
++ struct workqueue_struct *wkq;
++
++ au_dbg_verify_kthread();
++ if (flags & AuWkq_WAIT) {
++ INIT_WORK_ON_STACK(&wkinfo->wk, wkq_func);
++ wkq = au_wkq[AuWkq_INORMAL].wkq;
++ if (flags & AuWkq_PRE)
++ wkq = au_wkq[AuWkq_IPRE].wkq;
++ queue_work(wkq, &wkinfo->wk);
++ } else {
++ INIT_WORK(&wkinfo->wk, wkq_func);
++ schedule_work(&wkinfo->wk);
++ }
++}
++
++/*
++ * Be careful. It is easy to make deadlock happen.
++ * processA: lock, wkq and wait
++ * processB: wkq and wait, lock in wkq
++ * --> deadlock
++ */
++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args)
++{
++ int err;
++ AuWkqCompDeclare(comp);
++ struct au_wkinfo wkinfo = {
++ .flags = flags,
++ .func = func,
++ .args = args
++ };
++
++ err = au_wkq_comp_alloc(&wkinfo, &comp);
++ if (!err) {
++ au_wkq_run(&wkinfo, flags);
++ /* no timeout, no interrupt */
++ wait_for_completion(wkinfo.comp);
++ au_wkq_comp_free(comp);
++ destroy_work_on_stack(&wkinfo.wk);
++ }
++
++ return err;
++
++}
++
++/*
++ * Note: dget/dput() in func for aufs dentries are not supported. It will be a
++ * problem in a concurrent umounting.
++ */
++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb)
++{
++ int err;
++ struct au_wkinfo *wkinfo;
++
++ atomic_inc(&au_sbi(sb)->si_nowait.nw_len);
++
++ /*
++ * wkq_func() must free this wkinfo.
++ * it highly depends upon the implementation of workqueue.
++ */
++ err = 0;
++ wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS);
++ if (wkinfo) {
++ wkinfo->kobj = &au_sbi(sb)->si_kobj;
++ wkinfo->flags = !AuWkq_WAIT;
++ wkinfo->func = func;
++ wkinfo->args = args;
++ wkinfo->comp = NULL;
++ kobject_get(wkinfo->kobj);
++ __module_get(THIS_MODULE);
++
++ au_wkq_run(wkinfo, !AuWkq_WAIT);
++ } else {
++ err = -ENOMEM;
++ au_nwt_done(&au_sbi(sb)->si_nowait);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_nwt_init(struct au_nowait_tasks *nwt)
++{
++ atomic_set(&nwt->nw_len, 0);
++ /* smp_mb(); */ /* atomic_set */
++ init_waitqueue_head(&nwt->nw_wq);
++}
++
++void au_wkq_fin(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(au_wkq); i++)
++ if (au_wkq[i].wkq)
++ destroy_workqueue(au_wkq[i].wkq);
++}
++
++int __init au_wkq_init(void)
++{
++ int err, i;
++
++ err = 0;
++ for (i = 0; !err && i < ARRAY_SIZE(au_wkq); i++) {
++ BUILD_BUG_ON(!WQ_RESCUER);
++ au_wkq[i].wkq = alloc_workqueue(au_wkq[i].name, !WQ_RESCUER,
++ WQ_DFL_ACTIVE);
++ if (IS_ERR(au_wkq[i].wkq))
++ err = PTR_ERR(au_wkq[i].wkq);
++ else if (!au_wkq[i].wkq)
++ err = -ENOMEM;
++ if (unlikely(err))
++ au_wkq[i].wkq = NULL;
++ }
++ if (unlikely(err))
++ au_wkq_fin();
++
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/aufs/wkq.h linux-2.6.36/fs/aufs/wkq.h
+--- linux-2.6.36.orig/fs/aufs/wkq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/wkq.h 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,90 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * workqueue for asynchronous/super-io operations
++ * todo: try new credentials management scheme
++ */
++
++#ifndef __AUFS_WKQ_H__
++#define __AUFS_WKQ_H__
++
++#ifdef __KERNEL__
++
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/aufs_type.h>
++
++struct super_block;
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue
++ */
++struct au_nowait_tasks {
++ atomic_t nw_len;
++ wait_queue_head_t nw_wq;
++};
++
++/* ---------------------------------------------------------------------- */
++
++typedef void (*au_wkq_func_t)(void *args);
++
++/* wkq flags */
++#define AuWkq_WAIT 1
++#define AuWkq_PRE (1 << 1)
++#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name)
++#define au_fset_wkq(flags, name) \
++ do { (flags) |= AuWkq_##name; } while (0)
++#define au_fclr_wkq(flags, name) \
++ do { (flags) &= ~AuWkq_##name; } while (0)
++
++/* wkq.c */
++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args);
++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb);
++void au_nwt_init(struct au_nowait_tasks *nwt);
++int __init au_wkq_init(void);
++void au_wkq_fin(void);
++
++/* ---------------------------------------------------------------------- */
++
++static inline int au_wkq_wait_pre(au_wkq_func_t func, void *args)
++{
++ return au_wkq_do_wait(AuWkq_WAIT | AuWkq_PRE, func, args);
++}
++
++static inline int au_wkq_wait(au_wkq_func_t func, void *args)
++{
++ return au_wkq_do_wait(AuWkq_WAIT, func, args);
++}
++
++static inline void au_nwt_done(struct au_nowait_tasks *nwt)
++{
++ if (atomic_dec_and_test(&nwt->nw_len))
++ wake_up_all(&nwt->nw_wq);
++}
++
++static inline int au_nwt_flush(struct au_nowait_tasks *nwt)
++{
++ wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len));
++ return 0;
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_WKQ_H__ */
+diff -Nur linux-2.6.36.orig/fs/aufs/xino.c linux-2.6.36/fs/aufs/xino.c
+--- linux-2.6.36.orig/fs/aufs/xino.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/aufs/xino.c 2011-01-10 19:24:41.000000000 +0100
+@@ -0,0 +1,1265 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * external inode number translation table and bitmap
++ */
++
++#include <linux/file.h>
++#include <linux/seq_file.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++ssize_t xino_fread(au_readf_t func, struct file *file, void *kbuf, size_t size,
++ loff_t *pos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++ union {
++ void *k;
++ char __user *u;
++ } buf;
++
++ buf.k = kbuf;
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ do {
++ /* todo: signal_pending? */
++ err = func(file, buf.u, size, pos);
++ } while (err == -EAGAIN || err == -EINTR);
++ set_fs(oldfs);
++
++#if 0 /* reserved for future use */
++ if (err > 0)
++ fsnotify_access(file->f_dentry);
++#endif
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static ssize_t do_xino_fwrite(au_writef_t func, struct file *file, void *kbuf,
++ size_t size, loff_t *pos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++ union {
++ void *k;
++ const char __user *u;
++ } buf;
++
++ buf.k = kbuf;
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ do {
++ /* todo: signal_pending? */
++ err = func(file, buf.u, size, pos);
++ } while (err == -EAGAIN || err == -EINTR);
++ set_fs(oldfs);
++
++#if 0 /* reserved for future use */
++ if (err > 0)
++ fsnotify_modify(file->f_dentry);
++#endif
++
++ return err;
++}
++
++struct do_xino_fwrite_args {
++ ssize_t *errp;
++ au_writef_t func;
++ struct file *file;
++ void *buf;
++ size_t size;
++ loff_t *pos;
++};
++
++static void call_do_xino_fwrite(void *args)
++{
++ struct do_xino_fwrite_args *a = args;
++ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos);
++}
++
++ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size,
++ loff_t *pos)
++{
++ ssize_t err;
++
++ /* todo: signal block and no wkq? */
++ if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) {
++ lockdep_off();
++ err = do_xino_fwrite(func, file, buf, size, pos);
++ lockdep_on();
++ } else {
++ /*
++ * it breaks RLIMIT_FSIZE and normal user's limit,
++ * users should care about quota and real 'filesystem full.'
++ */
++ int wkq_err;
++ struct do_xino_fwrite_args args = {
++ .errp = &err,
++ .func = func,
++ .file = file,
++ .buf = buf,
++ .size = size,
++ .pos = pos
++ };
++
++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create a new xinofile at the same place/path as @base_file.
++ */
++struct file *au_xino_create2(struct file *base_file, struct file *copy_src)
++{
++ struct file *file;
++ struct dentry *base, *parent;
++ struct inode *dir;
++ struct qstr *name;
++ struct path path;
++ int err;
++
++ base = base_file->f_dentry;
++ parent = base->d_parent; /* dir inode is locked */
++ dir = parent->d_inode;
++ IMustLock(dir);
++
++ file = ERR_PTR(-EINVAL);
++ name = &base->d_name;
++ path.dentry = vfsub_lookup_one_len(name->name, parent, name->len);
++ if (IS_ERR(path.dentry)) {
++ file = (void *)path.dentry;
++ pr_err("%.*s lookup err %ld\n",
++ AuLNPair(name), PTR_ERR(path.dentry));
++ goto out;
++ }
++
++ /* no need to mnt_want_write() since we call dentry_open() later */
++ err = vfs_create(dir, path.dentry, S_IRUGO | S_IWUGO, NULL);
++ if (unlikely(err)) {
++ file = ERR_PTR(err);
++ pr_err("%.*s create err %d\n", AuLNPair(name), err);
++ goto out_dput;
++ }
++
++ path.mnt = base_file->f_vfsmnt;
++ file = vfsub_dentry_open(&path,
++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE
++ /* | FMODE_NONOTIFY */);
++ if (IS_ERR(file)) {
++ pr_err("%.*s open err %ld\n", AuLNPair(name), PTR_ERR(file));
++ goto out_dput;
++ }
++
++ err = vfsub_unlink(dir, &file->f_path, /*force*/0);
++ if (unlikely(err)) {
++ pr_err("%.*s unlink err %d\n", AuLNPair(name), err);
++ goto out_fput;
++ }
++
++ if (copy_src) {
++ /* no one can touch copy_src xino */
++ err = au_copy_file(file, copy_src,
++ i_size_read(copy_src->f_dentry->d_inode));
++ if (unlikely(err)) {
++ pr_err("%.*s copy err %d\n", AuLNPair(name), err);
++ goto out_fput;
++ }
++ }
++ goto out_dput; /* success */
++
++out_fput:
++ fput(file);
++ file = ERR_PTR(err);
++out_dput:
++ dput(path.dentry);
++out:
++ return file;
++}
++
++struct au_xino_lock_dir {
++ struct au_hinode *hdir;
++ struct dentry *parent;
++ struct mutex *mtx;
++};
++
++static void au_xino_lock_dir(struct super_block *sb, struct file *xino,
++ struct au_xino_lock_dir *ldir)
++{
++ aufs_bindex_t brid, bindex;
++
++ ldir->hdir = NULL;
++ bindex = -1;
++ brid = au_xino_brid(sb);
++ if (brid >= 0)
++ bindex = au_br_index(sb, brid);
++ if (bindex >= 0) {
++ ldir->hdir = au_hi(sb->s_root->d_inode, bindex);
++ au_hn_imtx_lock_nested(ldir->hdir, AuLsc_I_PARENT);
++ } else {
++ ldir->parent = dget_parent(xino->f_dentry);
++ ldir->mtx = &ldir->parent->d_inode->i_mutex;
++ mutex_lock_nested(ldir->mtx, AuLsc_I_PARENT);
++ }
++}
++
++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir)
++{
++ if (ldir->hdir)
++ au_hn_imtx_unlock(ldir->hdir);
++ else {
++ mutex_unlock(ldir->mtx);
++ dput(ldir->parent);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* trucate xino files asynchronously */
++
++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex)
++{
++ int err;
++ aufs_bindex_t bi, bend;
++ struct au_branch *br;
++ struct file *new_xino, *file;
++ struct super_block *h_sb;
++ struct au_xino_lock_dir ldir;
++
++ err = -EINVAL;
++ bend = au_sbend(sb);
++ if (unlikely(bindex < 0 || bend < bindex))
++ goto out;
++ br = au_sbr(sb, bindex);
++ file = br->br_xino.xi_file;
++ if (!file)
++ goto out;
++
++ au_xino_lock_dir(sb, file, &ldir);
++ /* mnt_want_write() is unnecessary here */
++ new_xino = au_xino_create2(file, file);
++ au_xino_unlock_dir(&ldir);
++ err = PTR_ERR(new_xino);
++ if (IS_ERR(new_xino))
++ goto out;
++ err = 0;
++ fput(file);
++ br->br_xino.xi_file = new_xino;
++
++ h_sb = br->br_mnt->mnt_sb;
++ for (bi = 0; bi <= bend; bi++) {
++ if (unlikely(bi == bindex))
++ continue;
++ br = au_sbr(sb, bi);
++ if (br->br_mnt->mnt_sb != h_sb)
++ continue;
++
++ fput(br->br_xino.xi_file);
++ br->br_xino.xi_file = new_xino;
++ get_file(new_xino);
++ }
++
++out:
++ return err;
++}
++
++struct xino_do_trunc_args {
++ struct super_block *sb;
++ struct au_branch *br;
++};
++
++static void xino_do_trunc(void *_args)
++{
++ struct xino_do_trunc_args *args = _args;
++ struct super_block *sb;
++ struct au_branch *br;
++ struct inode *dir;
++ int err;
++ aufs_bindex_t bindex;
++
++ err = 0;
++ sb = args->sb;
++ dir = sb->s_root->d_inode;
++ br = args->br;
++
++ si_noflush_write_lock(sb);
++ ii_read_lock_parent(dir);
++ bindex = au_br_index(sb, br->br_id);
++ err = au_xino_trunc(sb, bindex);
++ if (!err
++ && br->br_xino.xi_file->f_dentry->d_inode->i_blocks
++ >= br->br_xino_upper)
++ br->br_xino_upper += AUFS_XINO_TRUNC_STEP;
++
++ ii_read_unlock(dir);
++ if (unlikely(err))
++ pr_warning("err b%d, (%d)\n", bindex, err);
++ atomic_dec(&br->br_xino_running);
++ atomic_dec(&br->br_count);
++ si_write_unlock(sb);
++ au_nwt_done(&au_sbi(sb)->si_nowait);
++ kfree(args);
++}
++
++static void xino_try_trunc(struct super_block *sb, struct au_branch *br)
++{
++ struct xino_do_trunc_args *args;
++ int wkq_err;
++
++ if (br->br_xino.xi_file->f_dentry->d_inode->i_blocks
++ < br->br_xino_upper)
++ return;
++
++ if (atomic_inc_return(&br->br_xino_running) > 1)
++ goto out;
++
++ /* lock and kfree() will be called in trunc_xino() */
++ args = kmalloc(sizeof(*args), GFP_NOFS);
++ if (unlikely(!args)) {
++ AuErr1("no memory\n");
++ goto out_args;
++ }
++
++ atomic_inc(&br->br_count);
++ args->sb = sb;
++ args->br = br;
++ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb);
++ if (!wkq_err)
++ return; /* success */
++
++ pr_err("wkq %d\n", wkq_err);
++ atomic_dec(&br->br_count);
++
++out_args:
++ kfree(args);
++out:
++ atomic_dec(&br->br_xino_running);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_xino_do_write(au_writef_t write, struct file *file,
++ ino_t h_ino, ino_t ino)
++{
++ loff_t pos;
++ ssize_t sz;
++
++ pos = h_ino;
++ if (unlikely(au_loff_max / sizeof(ino) - 1 < pos)) {
++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino);
++ return -EFBIG;
++ }
++ pos *= sizeof(ino);
++ sz = xino_fwrite(write, file, &ino, sizeof(ino), &pos);
++ if (sz == sizeof(ino))
++ return 0; /* success */
++
++ AuIOErr("write failed (%zd)\n", sz);
++ return -EIO;
++}
++
++/*
++ * write @ino to the xinofile for the specified branch{@sb, @bindex}
++ * at the position of @h_ino.
++ * even if @ino is zero, it is written to the xinofile and means no entry.
++ * if the size of the xino file on a specific filesystem exceeds the watermark,
++ * try truncating it.
++ */
++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t ino)
++{
++ int err;
++ unsigned int mnt_flags;
++ struct au_branch *br;
++
++ BUILD_BUG_ON(sizeof(long long) != sizeof(au_loff_max)
++ || ((loff_t)-1) > 0);
++ SiMustAnyLock(sb);
++
++ mnt_flags = au_mntflags(sb);
++ if (!au_opt_test(mnt_flags, XINO))
++ return 0;
++
++ br = au_sbr(sb, bindex);
++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file,
++ h_ino, ino);
++ if (!err) {
++ if (au_opt_test(mnt_flags, TRUNC_XINO)
++ && au_test_fs_trunc_xino(br->br_mnt->mnt_sb))
++ xino_try_trunc(sb, br);
++ return 0; /* success */
++ }
++
++ AuIOErr("write failed (%d)\n", err);
++ return -EIO;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* aufs inode number bitmap */
++
++static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE;
++static ino_t xib_calc_ino(unsigned long pindex, int bit)
++{
++ ino_t ino;
++
++ AuDebugOn(bit < 0 || page_bits <= bit);
++ ino = AUFS_FIRST_INO + pindex * page_bits + bit;
++ return ino;
++}
++
++static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit)
++{
++ AuDebugOn(ino < AUFS_FIRST_INO);
++ ino -= AUFS_FIRST_INO;
++ *pindex = ino / page_bits;
++ *bit = ino % page_bits;
++}
++
++static int xib_pindex(struct super_block *sb, unsigned long pindex)
++{
++ int err;
++ loff_t pos;
++ ssize_t sz;
++ struct au_sbinfo *sbinfo;
++ struct file *xib;
++ unsigned long *p;
++
++ sbinfo = au_sbi(sb);
++ MtxMustLock(&sbinfo->si_xib_mtx);
++ AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE
++ || !au_opt_test(sbinfo->si_mntflags, XINO));
++
++ if (pindex == sbinfo->si_xib_last_pindex)
++ return 0;
++
++ xib = sbinfo->si_xib;
++ p = sbinfo->si_xib_buf;
++ pos = sbinfo->si_xib_last_pindex;
++ pos *= PAGE_SIZE;
++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos);
++ if (unlikely(sz != PAGE_SIZE))
++ goto out;
++
++ pos = pindex;
++ pos *= PAGE_SIZE;
++ if (i_size_read(xib->f_dentry->d_inode) >= pos + PAGE_SIZE)
++ sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos);
++ else {
++ memset(p, 0, PAGE_SIZE);
++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos);
++ }
++ if (sz == PAGE_SIZE) {
++ sbinfo->si_xib_last_pindex = pindex;
++ return 0; /* success */
++ }
++
++out:
++ AuIOErr1("write failed (%zd)\n", sz);
++ err = sz;
++ if (sz >= 0)
++ err = -EIO;
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void au_xib_clear_bit(struct inode *inode)
++{
++ int err, bit;
++ unsigned long pindex;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++ AuDebugOn(inode->i_nlink);
++
++ sb = inode->i_sb;
++ xib_calc_bit(inode->i_ino, &pindex, &bit);
++ AuDebugOn(page_bits <= bit);
++ sbinfo = au_sbi(sb);
++ mutex_lock(&sbinfo->si_xib_mtx);
++ err = xib_pindex(sb, pindex);
++ if (!err) {
++ clear_bit(bit, sbinfo->si_xib_buf);
++ sbinfo->si_xib_next_bit = bit;
++ }
++ mutex_unlock(&sbinfo->si_xib_mtx);
++}
++
++/* for s_op->delete_inode() */
++void au_xino_delete_inode(struct inode *inode, const int unlinked)
++{
++ int err;
++ unsigned int mnt_flags;
++ aufs_bindex_t bindex, bend, bi;
++ unsigned char try_trunc;
++ struct au_iinfo *iinfo;
++ struct super_block *sb;
++ struct au_hinode *hi;
++ struct inode *h_inode;
++ struct au_branch *br;
++ au_writef_t xwrite;
++
++ sb = inode->i_sb;
++ mnt_flags = au_mntflags(sb);
++ if (!au_opt_test(mnt_flags, XINO)
++ || inode->i_ino == AUFS_ROOT_INO)
++ return;
++
++ if (unlinked) {
++ au_xigen_inc(inode);
++ au_xib_clear_bit(inode);
++ }
++
++ iinfo = au_ii(inode);
++ if (!iinfo)
++ return;
++
++ bindex = iinfo->ii_bstart;
++ if (bindex < 0)
++ return;
++
++ xwrite = au_sbi(sb)->si_xwrite;
++ try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO);
++ hi = iinfo->ii_hinode + bindex;
++ bend = iinfo->ii_bend;
++ for (; bindex <= bend; bindex++, hi++) {
++ h_inode = hi->hi_inode;
++ if (!h_inode
++ || (!unlinked && h_inode->i_nlink))
++ continue;
++
++ /* inode may not be revalidated */
++ bi = au_br_index(sb, hi->hi_id);
++ if (bi < 0)
++ continue;
++
++ br = au_sbr(sb, bi);
++ err = au_xino_do_write(xwrite, br->br_xino.xi_file,
++ h_inode->i_ino, /*ino*/0);
++ if (!err && try_trunc
++ && au_test_fs_trunc_xino(br->br_mnt->mnt_sb))
++ xino_try_trunc(sb, br);
++ }
++}
++
++/* get an unused inode number from bitmap */
++ino_t au_xino_new_ino(struct super_block *sb)
++{
++ ino_t ino;
++ unsigned long *p, pindex, ul, pend;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++ int free_bit, err;
++
++ if (!au_opt_test(au_mntflags(sb), XINO))
++ return iunique(sb, AUFS_FIRST_INO);
++
++ sbinfo = au_sbi(sb);
++ mutex_lock(&sbinfo->si_xib_mtx);
++ p = sbinfo->si_xib_buf;
++ free_bit = sbinfo->si_xib_next_bit;
++ if (free_bit < page_bits && !test_bit(free_bit, p))
++ goto out; /* success */
++ free_bit = find_first_zero_bit(p, page_bits);
++ if (free_bit < page_bits)
++ goto out; /* success */
++
++ pindex = sbinfo->si_xib_last_pindex;
++ for (ul = pindex - 1; ul < ULONG_MAX; ul--) {
++ err = xib_pindex(sb, ul);
++ if (unlikely(err))
++ goto out_err;
++ free_bit = find_first_zero_bit(p, page_bits);
++ if (free_bit < page_bits)
++ goto out; /* success */
++ }
++
++ file = sbinfo->si_xib;
++ pend = i_size_read(file->f_dentry->d_inode) / PAGE_SIZE;
++ for (ul = pindex + 1; ul <= pend; ul++) {
++ err = xib_pindex(sb, ul);
++ if (unlikely(err))
++ goto out_err;
++ free_bit = find_first_zero_bit(p, page_bits);
++ if (free_bit < page_bits)
++ goto out; /* success */
++ }
++ BUG();
++
++out:
++ set_bit(free_bit, p);
++ sbinfo->si_xib_next_bit = free_bit + 1;
++ pindex = sbinfo->si_xib_last_pindex;
++ mutex_unlock(&sbinfo->si_xib_mtx);
++ ino = xib_calc_ino(pindex, free_bit);
++ AuDbg("i%lu\n", (unsigned long)ino);
++ return ino;
++out_err:
++ mutex_unlock(&sbinfo->si_xib_mtx);
++ AuDbg("i0\n");
++ return 0;
++}
++
++/*
++ * read @ino from xinofile for the specified branch{@sb, @bindex}
++ * at the position of @h_ino.
++ * if @ino does not exist and @do_new is true, get new one.
++ */
++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t *ino)
++{
++ int err;
++ ssize_t sz;
++ loff_t pos;
++ struct file *file;
++ struct au_sbinfo *sbinfo;
++
++ *ino = 0;
++ if (!au_opt_test(au_mntflags(sb), XINO))
++ return 0; /* no xino */
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ pos = h_ino;
++ if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) {
++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino);
++ return -EFBIG;
++ }
++ pos *= sizeof(*ino);
++
++ file = au_sbr(sb, bindex)->br_xino.xi_file;
++ if (i_size_read(file->f_dentry->d_inode) < pos + sizeof(*ino))
++ return 0; /* no ino */
++
++ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos);
++ if (sz == sizeof(*ino))
++ return 0; /* success */
++
++ err = sz;
++ if (unlikely(sz >= 0)) {
++ err = -EIO;
++ AuIOErr("xino read error (%zd)\n", sz);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* create and set a new xino file */
++
++struct file *au_xino_create(struct super_block *sb, char *fname, int silent)
++{
++ struct file *file;
++ struct dentry *h_parent, *d;
++ struct inode *h_dir;
++ int err;
++
++ /*
++ * at mount-time, and the xino file is the default path,
++ * hnotify is disabled so we have no notify events to ignore.
++ * when a user specified the xino, we cannot get au_hdir to be ignored.
++ */
++ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE
++ /* | FMODE_NONOTIFY */,
++ S_IRUGO | S_IWUGO);
++ if (IS_ERR(file)) {
++ if (!silent)
++ pr_err("open %s(%ld)\n", fname, PTR_ERR(file));
++ return file;
++ }
++
++ /* keep file count */
++ h_parent = dget_parent(file->f_dentry);
++ h_dir = h_parent->d_inode;
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
++ /* mnt_want_write() is unnecessary here */
++ err = vfsub_unlink(h_dir, &file->f_path, /*force*/0);
++ mutex_unlock(&h_dir->i_mutex);
++ dput(h_parent);
++ if (unlikely(err)) {
++ if (!silent)
++ pr_err("unlink %s(%d)\n", fname, err);
++ goto out;
++ }
++
++ err = -EINVAL;
++ d = file->f_dentry;
++ if (unlikely(sb == d->d_sb)) {
++ if (!silent)
++ pr_err("%s must be outside\n", fname);
++ goto out;
++ }
++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) {
++ if (!silent)
++ pr_err("xino doesn't support %s(%s)\n",
++ fname, au_sbtype(d->d_sb));
++ goto out;
++ }
++ return file; /* success */
++
++out:
++ fput(file);
++ file = ERR_PTR(err);
++ return file;
++}
++
++/*
++ * find another branch who is on the same filesystem of the specified
++ * branch{@btgt}. search until @bend.
++ */
++static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt,
++ aufs_bindex_t bend)
++{
++ aufs_bindex_t bindex;
++ struct super_block *tgt_sb = au_sbr_sb(sb, btgt);
++
++ for (bindex = 0; bindex < btgt; bindex++)
++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex)))
++ return bindex;
++ for (bindex++; bindex <= bend; bindex++)
++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex)))
++ return bindex;
++ return -1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * initialize the xinofile for the specified branch @br
++ * at the place/path where @base_file indicates.
++ * test whether another branch is on the same filesystem or not,
++ * if @do_test is true.
++ */
++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino,
++ struct file *base_file, int do_test)
++{
++ int err;
++ ino_t ino;
++ aufs_bindex_t bend, bindex;
++ struct au_branch *shared_br, *b;
++ struct file *file;
++ struct super_block *tgt_sb;
++
++ shared_br = NULL;
++ bend = au_sbend(sb);
++ if (do_test) {
++ tgt_sb = br->br_mnt->mnt_sb;
++ for (bindex = 0; bindex <= bend; bindex++) {
++ b = au_sbr(sb, bindex);
++ if (tgt_sb == b->br_mnt->mnt_sb) {
++ shared_br = b;
++ break;
++ }
++ }
++ }
++
++ if (!shared_br || !shared_br->br_xino.xi_file) {
++ struct au_xino_lock_dir ldir;
++
++ au_xino_lock_dir(sb, base_file, &ldir);
++ /* mnt_want_write() is unnecessary here */
++ file = au_xino_create2(base_file, NULL);
++ au_xino_unlock_dir(&ldir);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ br->br_xino.xi_file = file;
++ } else {
++ br->br_xino.xi_file = shared_br->br_xino.xi_file;
++ get_file(br->br_xino.xi_file);
++ }
++
++ ino = AUFS_ROOT_INO;
++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file,
++ h_ino, ino);
++ if (unlikely(err)) {
++ fput(br->br_xino.xi_file);
++ br->br_xino.xi_file = NULL;
++ }
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* trucate a xino bitmap file */
++
++/* todo: slow */
++static int do_xib_restore(struct super_block *sb, struct file *file, void *page)
++{
++ int err, bit;
++ ssize_t sz;
++ unsigned long pindex;
++ loff_t pos, pend;
++ struct au_sbinfo *sbinfo;
++ au_readf_t func;
++ ino_t *ino;
++ unsigned long *p;
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ MtxMustLock(&sbinfo->si_xib_mtx);
++ p = sbinfo->si_xib_buf;
++ func = sbinfo->si_xread;
++ pend = i_size_read(file->f_dentry->d_inode);
++ pos = 0;
++ while (pos < pend) {
++ sz = xino_fread(func, file, page, PAGE_SIZE, &pos);
++ err = sz;
++ if (unlikely(sz <= 0))
++ goto out;
++
++ err = 0;
++ for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) {
++ if (unlikely(*ino < AUFS_FIRST_INO))
++ continue;
++
++ xib_calc_bit(*ino, &pindex, &bit);
++ AuDebugOn(page_bits <= bit);
++ err = xib_pindex(sb, pindex);
++ if (!err)
++ set_bit(bit, p);
++ else
++ goto out;
++ }
++ }
++
++out:
++ return err;
++}
++
++static int xib_restore(struct super_block *sb)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ void *page;
++
++ err = -ENOMEM;
++ page = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!page))
++ goto out;
++
++ err = 0;
++ bend = au_sbend(sb);
++ for (bindex = 0; !err && bindex <= bend; bindex++)
++ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0)
++ err = do_xib_restore
++ (sb, au_sbr(sb, bindex)->br_xino.xi_file, page);
++ else
++ AuDbg("b%d\n", bindex);
++ free_page((unsigned long)page);
++
++out:
++ return err;
++}
++
++int au_xib_trunc(struct super_block *sb)
++{
++ int err;
++ ssize_t sz;
++ loff_t pos;
++ struct au_xino_lock_dir ldir;
++ struct au_sbinfo *sbinfo;
++ unsigned long *p;
++ struct file *file;
++
++ SiMustWriteLock(sb);
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ if (!au_opt_test(sbinfo->si_mntflags, XINO))
++ goto out;
++
++ file = sbinfo->si_xib;
++ if (i_size_read(file->f_dentry->d_inode) <= PAGE_SIZE)
++ goto out;
++
++ au_xino_lock_dir(sb, file, &ldir);
++ /* mnt_want_write() is unnecessary here */
++ file = au_xino_create2(sbinfo->si_xib, NULL);
++ au_xino_unlock_dir(&ldir);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = file;
++
++ p = sbinfo->si_xib_buf;
++ memset(p, 0, PAGE_SIZE);
++ pos = 0;
++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos);
++ if (unlikely(sz != PAGE_SIZE)) {
++ err = sz;
++ AuIOErr("err %d\n", err);
++ if (sz >= 0)
++ err = -EIO;
++ goto out;
++ }
++
++ mutex_lock(&sbinfo->si_xib_mtx);
++ /* mnt_want_write() is unnecessary here */
++ err = xib_restore(sb);
++ mutex_unlock(&sbinfo->si_xib_mtx);
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * xino mount option handlers
++ */
++static au_readf_t find_readf(struct file *h_file)
++{
++ const struct file_operations *fop = h_file->f_op;
++
++ if (fop) {
++ if (fop->read)
++ return fop->read;
++ if (fop->aio_read)
++ return do_sync_read;
++ }
++ return ERR_PTR(-ENOSYS);
++}
++
++static au_writef_t find_writef(struct file *h_file)
++{
++ const struct file_operations *fop = h_file->f_op;
++
++ if (fop) {
++ if (fop->write)
++ return fop->write;
++ if (fop->aio_write)
++ return do_sync_write;
++ }
++ return ERR_PTR(-ENOSYS);
++}
++
++/* xino bitmap */
++static void xino_clear_xib(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ sbinfo->si_xread = NULL;
++ sbinfo->si_xwrite = NULL;
++ if (sbinfo->si_xib)
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = NULL;
++ free_page((unsigned long)sbinfo->si_xib_buf);
++ sbinfo->si_xib_buf = NULL;
++}
++
++static int au_xino_set_xib(struct super_block *sb, struct file *base)
++{
++ int err;
++ loff_t pos;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ file = au_xino_create2(base, sbinfo->si_xib);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ if (sbinfo->si_xib)
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = file;
++ sbinfo->si_xread = find_readf(file);
++ sbinfo->si_xwrite = find_writef(file);
++
++ err = -ENOMEM;
++ if (!sbinfo->si_xib_buf)
++ sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS);
++ if (unlikely(!sbinfo->si_xib_buf))
++ goto out_unset;
++
++ sbinfo->si_xib_last_pindex = 0;
++ sbinfo->si_xib_next_bit = 0;
++ if (i_size_read(file->f_dentry->d_inode) < PAGE_SIZE) {
++ pos = 0;
++ err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf,
++ PAGE_SIZE, &pos);
++ if (unlikely(err != PAGE_SIZE))
++ goto out_free;
++ }
++ err = 0;
++ goto out; /* success */
++
++out_free:
++ free_page((unsigned long)sbinfo->si_xib_buf);
++ sbinfo->si_xib_buf = NULL;
++ if (err >= 0)
++ err = -EIO;
++out_unset:
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = NULL;
++ sbinfo->si_xread = NULL;
++ sbinfo->si_xwrite = NULL;
++out:
++ return err;
++}
++
++/* xino for each branch */
++static void xino_clear_br(struct super_block *sb)
++{
++ aufs_bindex_t bindex, bend;
++ struct au_branch *br;
++
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (!br || !br->br_xino.xi_file)
++ continue;
++
++ fput(br->br_xino.xi_file);
++ br->br_xino.xi_file = NULL;
++ }
++}
++
++static int au_xino_set_br(struct super_block *sb, struct file *base)
++{
++ int err;
++ ino_t ino;
++ aufs_bindex_t bindex, bend, bshared;
++ struct {
++ struct file *old, *new;
++ } *fpair, *p;
++ struct au_branch *br;
++ struct inode *inode;
++ au_writef_t writef;
++
++ SiMustWriteLock(sb);
++
++ err = -ENOMEM;
++ bend = au_sbend(sb);
++ fpair = kcalloc(bend + 1, sizeof(*fpair), GFP_NOFS);
++ if (unlikely(!fpair))
++ goto out;
++
++ inode = sb->s_root->d_inode;
++ ino = AUFS_ROOT_INO;
++ writef = au_sbi(sb)->si_xwrite;
++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) {
++ br = au_sbr(sb, bindex);
++ bshared = is_sb_shared(sb, bindex, bindex - 1);
++ if (bshared >= 0) {
++ /* shared xino */
++ *p = fpair[bshared];
++ get_file(p->new);
++ }
++
++ if (!p->new) {
++ /* new xino */
++ p->old = br->br_xino.xi_file;
++ p->new = au_xino_create2(base, br->br_xino.xi_file);
++ err = PTR_ERR(p->new);
++ if (IS_ERR(p->new)) {
++ p->new = NULL;
++ goto out_pair;
++ }
++ }
++
++ err = au_xino_do_write(writef, p->new,
++ au_h_iptr(inode, bindex)->i_ino, ino);
++ if (unlikely(err))
++ goto out_pair;
++ }
++
++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) {
++ br = au_sbr(sb, bindex);
++ if (br->br_xino.xi_file)
++ fput(br->br_xino.xi_file);
++ get_file(p->new);
++ br->br_xino.xi_file = p->new;
++ }
++
++out_pair:
++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++)
++ if (p->new)
++ fput(p->new);
++ else
++ break;
++ kfree(fpair);
++out:
++ return err;
++}
++
++void au_xino_clr(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ au_xigen_clr(sb);
++ xino_clear_xib(sb);
++ xino_clear_br(sb);
++ sbinfo = au_sbi(sb);
++ /* lvalue, do not call au_mntflags() */
++ au_opt_clr(sbinfo->si_mntflags, XINO);
++}
++
++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount)
++{
++ int err, skip;
++ struct dentry *parent, *cur_parent;
++ struct qstr *dname, *cur_name;
++ struct file *cur_xino;
++ struct inode *dir;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ parent = dget_parent(xino->file->f_dentry);
++ if (remount) {
++ skip = 0;
++ dname = &xino->file->f_dentry->d_name;
++ cur_xino = sbinfo->si_xib;
++ if (cur_xino) {
++ cur_parent = dget_parent(cur_xino->f_dentry);
++ cur_name = &cur_xino->f_dentry->d_name;
++ skip = (cur_parent == parent
++ && dname->len == cur_name->len
++ && !memcmp(dname->name, cur_name->name,
++ dname->len));
++ dput(cur_parent);
++ }
++ if (skip)
++ goto out;
++ }
++
++ au_opt_set(sbinfo->si_mntflags, XINO);
++ dir = parent->d_inode;
++ mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT);
++ /* mnt_want_write() is unnecessary here */
++ err = au_xino_set_xib(sb, xino->file);
++ if (!err)
++ err = au_xigen_set(sb, xino->file);
++ if (!err)
++ err = au_xino_set_br(sb, xino->file);
++ mutex_unlock(&dir->i_mutex);
++ if (!err)
++ goto out; /* success */
++
++ /* reset all */
++ AuIOErr("failed creating xino(%d).\n", err);
++
++out:
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create a xinofile at the default place/path.
++ */
++struct file *au_xino_def(struct super_block *sb)
++{
++ struct file *file;
++ char *page, *p;
++ struct au_branch *br;
++ struct super_block *h_sb;
++ struct path path;
++ aufs_bindex_t bend, bindex, bwr;
++
++ br = NULL;
++ bend = au_sbend(sb);
++ bwr = -1;
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (au_br_writable(br->br_perm)
++ && !au_test_fs_bad_xino(br->br_mnt->mnt_sb)) {
++ bwr = bindex;
++ break;
++ }
++ }
++
++ if (bwr >= 0) {
++ file = ERR_PTR(-ENOMEM);
++ page = __getname_gfp(GFP_NOFS);
++ if (unlikely(!page))
++ goto out;
++ path.mnt = br->br_mnt;
++ path.dentry = au_h_dptr(sb->s_root, bwr);
++ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME));
++ file = (void *)p;
++ if (!IS_ERR(p)) {
++ strcat(p, "/" AUFS_XINO_FNAME);
++ AuDbg("%s\n", p);
++ file = au_xino_create(sb, p, /*silent*/0);
++ if (!IS_ERR(file))
++ au_xino_brid_set(sb, br->br_id);
++ }
++ __putname(page);
++ } else {
++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0);
++ if (IS_ERR(file))
++ goto out;
++ h_sb = file->f_dentry->d_sb;
++ if (unlikely(au_test_fs_bad_xino(h_sb))) {
++ pr_err("xino doesn't support %s(%s)\n",
++ AUFS_XINO_DEFPATH, au_sbtype(h_sb));
++ fput(file);
++ file = ERR_PTR(-EINVAL);
++ }
++ if (!IS_ERR(file))
++ au_xino_brid_set(sb, -1);
++ }
++
++out:
++ return file;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_xino_path(struct seq_file *seq, struct file *file)
++{
++ int err;
++
++ err = au_seq_path(seq, &file->f_path);
++ if (unlikely(err < 0))
++ goto out;
++
++ err = 0;
++#define Deleted "\\040(deleted)"
++ seq->count -= sizeof(Deleted) - 1;
++ AuDebugOn(memcmp(seq->buf + seq->count, Deleted,
++ sizeof(Deleted) - 1));
++#undef Deleted
++
++out:
++ return err;
++}
+diff -Nur linux-2.6.36.orig/fs/file_table.c linux-2.6.36/fs/file_table.c
+--- linux-2.6.36.orig/fs/file_table.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/fs/file_table.c 2011-01-10 19:52:38.000000000 +0100
+@@ -394,6 +394,8 @@
+ }
+ }
+
++EXPORT_SYMBOL(file_sb_list_del);
++
+ #ifdef CONFIG_SMP
+
+ /*
+diff -Nur linux-2.6.36.orig/fs/inode.c linux-2.6.36/fs/inode.c
+--- linux-2.6.36.orig/fs/inode.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/fs/inode.c 2011-01-10 19:52:38.000000000 +0100
+@@ -83,6 +83,7 @@
+ * the i_state of an inode while it is in use..
+ */
+ DEFINE_SPINLOCK(inode_lock);
++EXPORT_SYMBOL(inode_lock);
+
+ /*
+ * iprune_sem provides exclusion between the kswapd or try_to_free_pages
+diff -Nur linux-2.6.36.orig/fs/namei.c linux-2.6.36/fs/namei.c
+--- linux-2.6.36.orig/fs/namei.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/fs/namei.c 2011-01-10 19:52:38.000000000 +0100
+@@ -347,6 +347,7 @@
+
+ return 0;
+ }
++EXPORT_SYMBOL(deny_write_access);
+
+ /**
+ * path_get - get a reference to a path
+@@ -1159,7 +1160,7 @@
+ * needs parent already locked. Doesn't follow mounts.
+ * SMP-safe.
+ */
+-static struct dentry *lookup_hash(struct nameidata *nd)
++struct dentry *lookup_hash(struct nameidata *nd)
+ {
+ int err;
+
+@@ -1168,8 +1169,9 @@
+ return ERR_PTR(err);
+ return __lookup_hash(&nd->last, nd->path.dentry, nd);
+ }
++EXPORT_SYMBOL(lookup_hash);
+
+-static int __lookup_one_len(const char *name, struct qstr *this,
++int __lookup_one_len(const char *name, struct qstr *this,
+ struct dentry *base, int len)
+ {
+ unsigned long hash;
+@@ -1190,6 +1192,7 @@
+ this->hash = end_name_hash(hash);
+ return 0;
+ }
++EXPORT_SYMBOL(__lookup_one_len);
+
+ /**
+ * lookup_one_len - filesystem helper to lookup single pathname component
+diff -Nur linux-2.6.36.orig/fs/namei.c.orig linux-2.6.36/fs/namei.c.orig
+--- linux-2.6.36.orig/fs/namei.c.orig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/namei.c.orig 2011-01-10 19:52:38.000000000 +0100
+@@ -0,0 +1,2921 @@
++/*
++ * linux/fs/namei.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ */
++
++/*
++ * Some corrections by tytso.
++ */
++
++/* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname
++ * lookup logic.
++ */
++/* [Feb-Apr 2000, AV] Rewrite to the new namespace architecture.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/namei.h>
++#include <linux/pagemap.h>
++#include <linux/fsnotify.h>
++#include <linux/personality.h>
++#include <linux/security.h>
++#include <linux/ima.h>
++#include <linux/syscalls.h>
++#include <linux/mount.h>
++#include <linux/audit.h>
++#include <linux/capability.h>
++#include <linux/file.h>
++#include <linux/fcntl.h>
++#include <linux/device_cgroup.h>
++#include <linux/fs_struct.h>
++#include <asm/uaccess.h>
++
++#include "internal.h"
++
++/* [Feb-1997 T. Schoebel-Theuer]
++ * Fundamental changes in the pathname lookup mechanisms (namei)
++ * were necessary because of omirr. The reason is that omirr needs
++ * to know the _real_ pathname, not the user-supplied one, in case
++ * of symlinks (and also when transname replacements occur).
++ *
++ * The new code replaces the old recursive symlink resolution with
++ * an iterative one (in case of non-nested symlink chains). It does
++ * this with calls to <fs>_follow_link().
++ * As a side effect, dir_namei(), _namei() and follow_link() are now
++ * replaced with a single function lookup_dentry() that can handle all
++ * the special cases of the former code.
++ *
++ * With the new dcache, the pathname is stored at each inode, at least as
++ * long as the refcount of the inode is positive. As a side effect, the
++ * size of the dcache depends on the inode cache and thus is dynamic.
++ *
++ * [29-Apr-1998 C. Scott Ananian] Updated above description of symlink
++ * resolution to correspond with current state of the code.
++ *
++ * Note that the symlink resolution is not *completely* iterative.
++ * There is still a significant amount of tail- and mid- recursion in
++ * the algorithm. Also, note that <fs>_readlink() is not used in
++ * lookup_dentry(): lookup_dentry() on the result of <fs>_readlink()
++ * may return different results than <fs>_follow_link(). Many virtual
++ * filesystems (including /proc) exhibit this behavior.
++ */
++
++/* [24-Feb-97 T. Schoebel-Theuer] Side effects caused by new implementation:
++ * New symlink semantics: when open() is called with flags O_CREAT | O_EXCL
++ * and the name already exists in form of a symlink, try to create the new
++ * name indicated by the symlink. The old code always complained that the
++ * name already exists, due to not following the symlink even if its target
++ * is nonexistent. The new semantics affects also mknod() and link() when
++ * the name is a symlink pointing to a non-existant name.
++ *
++ * I don't know which semantics is the right one, since I have no access
++ * to standards. But I found by trial that HP-UX 9.0 has the full "new"
++ * semantics implemented, while SunOS 4.1.1 and Solaris (SunOS 5.4) have the
++ * "old" one. Personally, I think the new semantics is much more logical.
++ * Note that "ln old new" where "new" is a symlink pointing to a non-existing
++ * file does succeed in both HP-UX and SunOs, but not in Solaris
++ * and in the old Linux semantics.
++ */
++
++/* [16-Dec-97 Kevin Buhr] For security reasons, we change some symlink
++ * semantics. See the comments in "open_namei" and "do_link" below.
++ *
++ * [10-Sep-98 Alan Modra] Another symlink change.
++ */
++
++/* [Feb-Apr 2000 AV] Complete rewrite. Rules for symlinks:
++ * inside the path - always follow.
++ * in the last component in creation/removal/renaming - never follow.
++ * if LOOKUP_FOLLOW passed - follow.
++ * if the pathname has trailing slashes - follow.
++ * otherwise - don't follow.
++ * (applied in that order).
++ *
++ * [Jun 2000 AV] Inconsistent behaviour of open() in case if flags==O_CREAT
++ * restored for 2.4. This is the last surviving part of old 4.2BSD bug.
++ * During the 2.4 we need to fix the userland stuff depending on it -
++ * hopefully we will be able to get rid of that wart in 2.5. So far only
++ * XEmacs seems to be relying on it...
++ */
++/*
++ * [Sep 2001 AV] Single-semaphore locking scheme (kudos to David Holland)
++ * implemented. Let's see if raised priority of ->s_vfs_rename_mutex gives
++ * any extra contention...
++ */
++
++/* In order to reduce some races, while at the same time doing additional
++ * checking and hopefully speeding things up, we copy filenames to the
++ * kernel data space before using them..
++ *
++ * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
++ * PATH_MAX includes the nul terminator --RR.
++ */
++static int do_getname(const char __user *filename, char *page)
++{
++ int retval;
++ unsigned long len = PATH_MAX;
++
++ if (!segment_eq(get_fs(), KERNEL_DS)) {
++ if ((unsigned long) filename >= TASK_SIZE)
++ return -EFAULT;
++ if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
++ len = TASK_SIZE - (unsigned long) filename;
++ }
++
++ retval = strncpy_from_user(page, filename, len);
++ if (retval > 0) {
++ if (retval < len)
++ return 0;
++ return -ENAMETOOLONG;
++ } else if (!retval)
++ retval = -ENOENT;
++ return retval;
++}
++
++char * getname(const char __user * filename)
++{
++ char *tmp, *result;
++
++ result = ERR_PTR(-ENOMEM);
++ tmp = __getname();
++ if (tmp) {
++ int retval = do_getname(filename, tmp);
++
++ result = tmp;
++ if (retval < 0) {
++ __putname(tmp);
++ result = ERR_PTR(retval);
++ }
++ }
++ audit_getname(result);
++ return result;
++}
++
++#ifdef CONFIG_AUDITSYSCALL
++void putname(const char *name)
++{
++ if (unlikely(!audit_dummy_context()))
++ audit_putname(name);
++ else
++ __putname(name);
++}
++EXPORT_SYMBOL(putname);
++#endif
++
++/*
++ * This does basic POSIX ACL permission checking
++ */
++static int acl_permission_check(struct inode *inode, int mask,
++ int (*check_acl)(struct inode *inode, int mask))
++{
++ umode_t mode = inode->i_mode;
++
++ mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
++
++ if (current_fsuid() == inode->i_uid)
++ mode >>= 6;
++ else {
++ if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
++ int error = check_acl(inode, mask);
++ if (error != -EAGAIN)
++ return error;
++ }
++
++ if (in_group_p(inode->i_gid))
++ mode >>= 3;
++ }
++
++ /*
++ * If the DACs are ok we don't need any capability check.
++ */
++ if ((mask & ~mode) == 0)
++ return 0;
++ return -EACCES;
++}
++
++/**
++ * generic_permission - check for access rights on a Posix-like filesystem
++ * @inode: inode to check access rights for
++ * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
++ * @check_acl: optional callback to check for Posix ACLs
++ *
++ * Used to check for read/write/execute permissions on a file.
++ * We use "fsuid" for this, letting us set arbitrary permissions
++ * for filesystem access without changing the "normal" uids which
++ * are used for other things..
++ */
++int generic_permission(struct inode *inode, int mask,
++ int (*check_acl)(struct inode *inode, int mask))
++{
++ int ret;
++
++ /*
++ * Do the basic POSIX ACL permission checks.
++ */
++ ret = acl_permission_check(inode, mask, check_acl);
++ if (ret != -EACCES)
++ return ret;
++
++ /*
++ * Read/write DACs are always overridable.
++ * Executable DACs are overridable if at least one exec bit is set.
++ */
++ if (!(mask & MAY_EXEC) || execute_ok(inode))
++ if (capable(CAP_DAC_OVERRIDE))
++ return 0;
++
++ /*
++ * Searching includes executable on directories, else just read.
++ */
++ mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
++ if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))
++ if (capable(CAP_DAC_READ_SEARCH))
++ return 0;
++
++ return -EACCES;
++}
++
++/**
++ * inode_permission - check for access rights to a given inode
++ * @inode: inode to check permission on
++ * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
++ *
++ * Used to check for read/write/execute permissions on an inode.
++ * We use "fsuid" for this, letting us set arbitrary permissions
++ * for filesystem access without changing the "normal" uids which
++ * are used for other things.
++ */
++int inode_permission(struct inode *inode, int mask)
++{
++ int retval;
++
++ if (mask & MAY_WRITE) {
++ umode_t mode = inode->i_mode;
++
++ /*
++ * Nobody gets write access to a read-only fs.
++ */
++ if (IS_RDONLY(inode) &&
++ (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
++ return -EROFS;
++
++ /*
++ * Nobody gets write access to an immutable file.
++ */
++ if (IS_IMMUTABLE(inode))
++ return -EACCES;
++ }
++
++ if (inode->i_op->permission)
++ retval = inode->i_op->permission(inode, mask);
++ else
++ retval = generic_permission(inode, mask, inode->i_op->check_acl);
++
++ if (retval)
++ return retval;
++
++ retval = devcgroup_inode_permission(inode, mask);
++ if (retval)
++ return retval;
++
++ return security_inode_permission(inode, mask);
++}
++
++/**
++ * file_permission - check for additional access rights to a given file
++ * @file: file to check access rights for
++ * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
++ *
++ * Used to check for read/write/execute permissions on an already opened
++ * file.
++ *
++ * Note:
++ * Do not use this function in new code. All access checks should
++ * be done using inode_permission().
++ */
++int file_permission(struct file *file, int mask)
++{
++ return inode_permission(file->f_path.dentry->d_inode, mask);
++}
++
++/*
++ * get_write_access() gets write permission for a file.
++ * put_write_access() releases this write permission.
++ * This is used for regular files.
++ * We cannot support write (and maybe mmap read-write shared) accesses and
++ * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode
++ * can have the following values:
++ * 0: no writers, no VM_DENYWRITE mappings
++ * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
++ * > 0: (i_writecount) users are writing to the file.
++ *
++ * Normally we operate on that counter with atomic_{inc,dec} and it's safe
++ * except for the cases where we don't hold i_writecount yet. Then we need to
++ * use {get,deny}_write_access() - these functions check the sign and refuse
++ * to do the change if sign is wrong. Exclusion between them is provided by
++ * the inode->i_lock spinlock.
++ */
++
++int get_write_access(struct inode * inode)
++{
++ spin_lock(&inode->i_lock);
++ if (atomic_read(&inode->i_writecount) < 0) {
++ spin_unlock(&inode->i_lock);
++ return -ETXTBSY;
++ }
++ atomic_inc(&inode->i_writecount);
++ spin_unlock(&inode->i_lock);
++
++ return 0;
++}
++
++int deny_write_access(struct file * file)
++{
++ struct inode *inode = file->f_path.dentry->d_inode;
++
++ spin_lock(&inode->i_lock);
++ if (atomic_read(&inode->i_writecount) > 0) {
++ spin_unlock(&inode->i_lock);
++ return -ETXTBSY;
++ }
++ atomic_dec(&inode->i_writecount);
++ spin_unlock(&inode->i_lock);
++
++ return 0;
++}
++EXPORT_SYMBOL(deny_write_access);
++
++/**
++ * path_get - get a reference to a path
++ * @path: path to get the reference to
++ *
++ * Given a path increment the reference count to the dentry and the vfsmount.
++ */
++void path_get(struct path *path)
++{
++ mntget(path->mnt);
++ dget(path->dentry);
++}
++EXPORT_SYMBOL(path_get);
++
++/**
++ * path_put - put a reference to a path
++ * @path: path to put the reference to
++ *
++ * Given a path decrement the reference count to the dentry and the vfsmount.
++ */
++void path_put(struct path *path)
++{
++ dput(path->dentry);
++ mntput(path->mnt);
++}
++EXPORT_SYMBOL(path_put);
++
++/**
++ * release_open_intent - free up open intent resources
++ * @nd: pointer to nameidata
++ */
++void release_open_intent(struct nameidata *nd)
++{
++ if (nd->intent.open.file->f_path.dentry == NULL)
++ put_filp(nd->intent.open.file);
++ else
++ fput(nd->intent.open.file);
++}
++
++static inline struct dentry *
++do_revalidate(struct dentry *dentry, struct nameidata *nd)
++{
++ int status = dentry->d_op->d_revalidate(dentry, nd);
++ if (unlikely(status <= 0)) {
++ /*
++ * The dentry failed validation.
++ * If d_revalidate returned 0 attempt to invalidate
++ * the dentry otherwise d_revalidate is asking us
++ * to return a fail status.
++ */
++ if (!status) {
++ if (!d_invalidate(dentry)) {
++ dput(dentry);
++ dentry = NULL;
++ }
++ } else {
++ dput(dentry);
++ dentry = ERR_PTR(status);
++ }
++ }
++ return dentry;
++}
++
++/*
++ * force_reval_path - force revalidation of a dentry
++ *
++ * In some situations the path walking code will trust dentries without
++ * revalidating them. This causes problems for filesystems that depend on
++ * d_revalidate to handle file opens (e.g. NFSv4). When FS_REVAL_DOT is set
++ * (which indicates that it's possible for the dentry to go stale), force
++ * a d_revalidate call before proceeding.
++ *
++ * Returns 0 if the revalidation was successful. If the revalidation fails,
++ * either return the error returned by d_revalidate or -ESTALE if the
++ * revalidation it just returned 0. If d_revalidate returns 0, we attempt to
++ * invalidate the dentry. It's up to the caller to handle putting references
++ * to the path if necessary.
++ */
++static int
++force_reval_path(struct path *path, struct nameidata *nd)
++{
++ int status;
++ struct dentry *dentry = path->dentry;
++
++ /*
++ * only check on filesystems where it's possible for the dentry to
++ * become stale. It's assumed that if this flag is set then the
++ * d_revalidate op will also be defined.
++ */
++ if (!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT))
++ return 0;
++
++ status = dentry->d_op->d_revalidate(dentry, nd);
++ if (status > 0)
++ return 0;
++
++ if (!status) {
++ d_invalidate(dentry);
++ status = -ESTALE;
++ }
++ return status;
++}
++
++/*
++ * Short-cut version of permission(), for calling on directories
++ * during pathname resolution. Combines parts of permission()
++ * and generic_permission(), and tests ONLY for MAY_EXEC permission.
++ *
++ * If appropriate, check DAC only. If not appropriate, or
++ * short-cut DAC fails, then call ->permission() to do more
++ * complete permission check.
++ */
++static int exec_permission(struct inode *inode)
++{
++ int ret;
++
++ if (inode->i_op->permission) {
++ ret = inode->i_op->permission(inode, MAY_EXEC);
++ if (!ret)
++ goto ok;
++ return ret;
++ }
++ ret = acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl);
++ if (!ret)
++ goto ok;
++
++ if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH))
++ goto ok;
++
++ return ret;
++ok:
++ return security_inode_permission(inode, MAY_EXEC);
++}
++
++static __always_inline void set_root(struct nameidata *nd)
++{
++ if (!nd->root.mnt)
++ get_fs_root(current->fs, &nd->root);
++}
++
++static int link_path_walk(const char *, struct nameidata *);
++
++static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
++{
++ if (IS_ERR(link))
++ goto fail;
++
++ if (*link == '/') {
++ set_root(nd);
++ path_put(&nd->path);
++ nd->path = nd->root;
++ path_get(&nd->root);
++ }
++
++ return link_path_walk(link, nd);
++fail:
++ path_put(&nd->path);
++ return PTR_ERR(link);
++}
++
++static void path_put_conditional(struct path *path, struct nameidata *nd)
++{
++ dput(path->dentry);
++ if (path->mnt != nd->path.mnt)
++ mntput(path->mnt);
++}
++
++static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
++{
++ dput(nd->path.dentry);
++ if (nd->path.mnt != path->mnt) {
++ mntput(nd->path.mnt);
++ nd->path.mnt = path->mnt;
++ }
++ nd->path.dentry = path->dentry;
++}
++
++static __always_inline int
++__do_follow_link(struct path *path, struct nameidata *nd, void **p)
++{
++ int error;
++ struct dentry *dentry = path->dentry;
++
++ touch_atime(path->mnt, dentry);
++ nd_set_link(nd, NULL);
++
++ if (path->mnt != nd->path.mnt) {
++ path_to_nameidata(path, nd);
++ dget(dentry);
++ }
++ mntget(path->mnt);
++ nd->last_type = LAST_BIND;
++ *p = dentry->d_inode->i_op->follow_link(dentry, nd);
++ error = PTR_ERR(*p);
++ if (!IS_ERR(*p)) {
++ char *s = nd_get_link(nd);
++ error = 0;
++ if (s)
++ error = __vfs_follow_link(nd, s);
++ else if (nd->last_type == LAST_BIND) {
++ error = force_reval_path(&nd->path, nd);
++ if (error)
++ path_put(&nd->path);
++ }
++ }
++ return error;
++}
++
++/*
++ * This limits recursive symlink follows to 8, while
++ * limiting consecutive symlinks to 40.
++ *
++ * Without that kind of total limit, nasty chains of consecutive
++ * symlinks can cause almost arbitrarily long lookups.
++ */
++static inline int do_follow_link(struct path *path, struct nameidata *nd)
++{
++ void *cookie;
++ int err = -ELOOP;
++ if (current->link_count >= MAX_NESTED_LINKS)
++ goto loop;
++ if (current->total_link_count >= 40)
++ goto loop;
++ BUG_ON(nd->depth >= MAX_NESTED_LINKS);
++ cond_resched();
++ err = security_inode_follow_link(path->dentry, nd);
++ if (err)
++ goto loop;
++ current->link_count++;
++ current->total_link_count++;
++ nd->depth++;
++ err = __do_follow_link(path, nd, &cookie);
++ if (!IS_ERR(cookie) && path->dentry->d_inode->i_op->put_link)
++ path->dentry->d_inode->i_op->put_link(path->dentry, nd, cookie);
++ path_put(path);
++ current->link_count--;
++ nd->depth--;
++ return err;
++loop:
++ path_put_conditional(path, nd);
++ path_put(&nd->path);
++ return err;
++}
++
++int follow_up(struct path *path)
++{
++ struct vfsmount *parent;
++ struct dentry *mountpoint;
++
++ br_read_lock(vfsmount_lock);
++ parent = path->mnt->mnt_parent;
++ if (parent == path->mnt) {
++ br_read_unlock(vfsmount_lock);
++ return 0;
++ }
++ mntget(parent);
++ mountpoint = dget(path->mnt->mnt_mountpoint);
++ br_read_unlock(vfsmount_lock);
++ dput(path->dentry);
++ path->dentry = mountpoint;
++ mntput(path->mnt);
++ path->mnt = parent;
++ return 1;
++}
++
++/* no need for dcache_lock, as serialization is taken care in
++ * namespace.c
++ */
++static int __follow_mount(struct path *path)
++{
++ int res = 0;
++ while (d_mountpoint(path->dentry)) {
++ struct vfsmount *mounted = lookup_mnt(path);
++ if (!mounted)
++ break;
++ dput(path->dentry);
++ if (res)
++ mntput(path->mnt);
++ path->mnt = mounted;
++ path->dentry = dget(mounted->mnt_root);
++ res = 1;
++ }
++ return res;
++}
++
++static void follow_mount(struct path *path)
++{
++ while (d_mountpoint(path->dentry)) {
++ struct vfsmount *mounted = lookup_mnt(path);
++ if (!mounted)
++ break;
++ dput(path->dentry);
++ mntput(path->mnt);
++ path->mnt = mounted;
++ path->dentry = dget(mounted->mnt_root);
++ }
++}
++
++/* no need for dcache_lock, as serialization is taken care in
++ * namespace.c
++ */
++int follow_down(struct path *path)
++{
++ struct vfsmount *mounted;
++
++ mounted = lookup_mnt(path);
++ if (mounted) {
++ dput(path->dentry);
++ mntput(path->mnt);
++ path->mnt = mounted;
++ path->dentry = dget(mounted->mnt_root);
++ return 1;
++ }
++ return 0;
++}
++
++static __always_inline void follow_dotdot(struct nameidata *nd)
++{
++ set_root(nd);
++
++ while(1) {
++ struct dentry *old = nd->path.dentry;
++
++ if (nd->path.dentry == nd->root.dentry &&
++ nd->path.mnt == nd->root.mnt) {
++ break;
++ }
++ if (nd->path.dentry != nd->path.mnt->mnt_root) {
++ /* rare case of legitimate dget_parent()... */
++ nd->path.dentry = dget_parent(nd->path.dentry);
++ dput(old);
++ break;
++ }
++ if (!follow_up(&nd->path))
++ break;
++ }
++ follow_mount(&nd->path);
++}
++
++/*
++ * Allocate a dentry with name and parent, and perform a parent
++ * directory ->lookup on it. Returns the new dentry, or ERR_PTR
++ * on error. parent->d_inode->i_mutex must be held. d_lookup must
++ * have verified that no child exists while under i_mutex.
++ */
++static struct dentry *d_alloc_and_lookup(struct dentry *parent,
++ struct qstr *name, struct nameidata *nd)
++{
++ struct inode *inode = parent->d_inode;
++ struct dentry *dentry;
++ struct dentry *old;
++
++ /* Don't create child dentry for a dead directory. */
++ if (unlikely(IS_DEADDIR(inode)))
++ return ERR_PTR(-ENOENT);
++
++ dentry = d_alloc(parent, name);
++ if (unlikely(!dentry))
++ return ERR_PTR(-ENOMEM);
++
++ old = inode->i_op->lookup(inode, dentry, nd);
++ if (unlikely(old)) {
++ dput(dentry);
++ dentry = old;
++ }
++ return dentry;
++}
++
++/*
++ * It's more convoluted than I'd like it to be, but... it's still fairly
++ * small and for now I'd prefer to have fast path as straight as possible.
++ * It _is_ time-critical.
++ */
++static int do_lookup(struct nameidata *nd, struct qstr *name,
++ struct path *path)
++{
++ struct vfsmount *mnt = nd->path.mnt;
++ struct dentry *dentry, *parent;
++ struct inode *dir;
++ /*
++ * See if the low-level filesystem might want
++ * to use its own hash..
++ */
++ if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {
++ int err = nd->path.dentry->d_op->d_hash(nd->path.dentry, name);
++ if (err < 0)
++ return err;
++ }
++
++ /*
++ * Rename seqlock is not required here because in the off chance
++ * of a false negative due to a concurrent rename, we're going to
++ * do the non-racy lookup, below.
++ */
++ dentry = __d_lookup(nd->path.dentry, name);
++ if (!dentry)
++ goto need_lookup;
++found:
++ if (dentry->d_op && dentry->d_op->d_revalidate)
++ goto need_revalidate;
++done:
++ path->mnt = mnt;
++ path->dentry = dentry;
++ __follow_mount(path);
++ return 0;
++
++need_lookup:
++ parent = nd->path.dentry;
++ dir = parent->d_inode;
++
++ mutex_lock(&dir->i_mutex);
++ /*
++ * First re-do the cached lookup just in case it was created
++ * while we waited for the directory semaphore, or the first
++ * lookup failed due to an unrelated rename.
++ *
++ * This could use version numbering or similar to avoid unnecessary
++ * cache lookups, but then we'd have to do the first lookup in the
++ * non-racy way. However in the common case here, everything should
++ * be hot in cache, so would it be a big win?
++ */
++ dentry = d_lookup(parent, name);
++ if (likely(!dentry)) {
++ dentry = d_alloc_and_lookup(parent, name, nd);
++ mutex_unlock(&dir->i_mutex);
++ if (IS_ERR(dentry))
++ goto fail;
++ goto done;
++ }
++ /*
++ * Uhhuh! Nasty case: the cache was re-populated while
++ * we waited on the semaphore. Need to revalidate.
++ */
++ mutex_unlock(&dir->i_mutex);
++ goto found;
++
++need_revalidate:
++ dentry = do_revalidate(dentry, nd);
++ if (!dentry)
++ goto need_lookup;
++ if (IS_ERR(dentry))
++ goto fail;
++ goto done;
++
++fail:
++ return PTR_ERR(dentry);
++}
++
++/*
++ * This is a temporary kludge to deal with "automount" symlinks; proper
++ * solution is to trigger them on follow_mount(), so that do_lookup()
++ * would DTRT. To be killed before 2.6.34-final.
++ */
++static inline int follow_on_final(struct inode *inode, unsigned lookup_flags)
++{
++ return inode && unlikely(inode->i_op->follow_link) &&
++ ((lookup_flags & LOOKUP_FOLLOW) || S_ISDIR(inode->i_mode));
++}
++
++/*
++ * Name resolution.
++ * This is the basic name resolution function, turning a pathname into
++ * the final dentry. We expect 'base' to be positive and a directory.
++ *
++ * Returns 0 and nd will have valid dentry and mnt on success.
++ * Returns error and drops reference to input namei data on failure.
++ */
++static int link_path_walk(const char *name, struct nameidata *nd)
++{
++ struct path next;
++ struct inode *inode;
++ int err;
++ unsigned int lookup_flags = nd->flags;
++
++ while (*name=='/')
++ name++;
++ if (!*name)
++ goto return_reval;
++
++ inode = nd->path.dentry->d_inode;
++ if (nd->depth)
++ lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);
++
++ /* At this point we know we have a real path component. */
++ for(;;) {
++ unsigned long hash;
++ struct qstr this;
++ unsigned int c;
++
++ nd->flags |= LOOKUP_CONTINUE;
++ err = exec_permission(inode);
++ if (err)
++ break;
++
++ this.name = name;
++ c = *(const unsigned char *)name;
++
++ hash = init_name_hash();
++ do {
++ name++;
++ hash = partial_name_hash(c, hash);
++ c = *(const unsigned char *)name;
++ } while (c && (c != '/'));
++ this.len = name - (const char *) this.name;
++ this.hash = end_name_hash(hash);
++
++ /* remove trailing slashes? */
++ if (!c)
++ goto last_component;
++ while (*++name == '/');
++ if (!*name)
++ goto last_with_slashes;
++
++ /*
++ * "." and ".." are special - ".." especially so because it has
++ * to be able to know about the current root directory and
++ * parent relationships.
++ */
++ if (this.name[0] == '.') switch (this.len) {
++ default:
++ break;
++ case 2:
++ if (this.name[1] != '.')
++ break;
++ follow_dotdot(nd);
++ inode = nd->path.dentry->d_inode;
++ /* fallthrough */
++ case 1:
++ continue;
++ }
++ /* This does the actual lookups.. */
++ err = do_lookup(nd, &this, &next);
++ if (err)
++ break;
++
++ err = -ENOENT;
++ inode = next.dentry->d_inode;
++ if (!inode)
++ goto out_dput;
++
++ if (inode->i_op->follow_link) {
++ err = do_follow_link(&next, nd);
++ if (err)
++ goto return_err;
++ err = -ENOENT;
++ inode = nd->path.dentry->d_inode;
++ if (!inode)
++ break;
++ } else
++ path_to_nameidata(&next, nd);
++ err = -ENOTDIR;
++ if (!inode->i_op->lookup)
++ break;
++ continue;
++ /* here ends the main loop */
++
++last_with_slashes:
++ lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
++last_component:
++ /* Clear LOOKUP_CONTINUE iff it was previously unset */
++ nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;
++ if (lookup_flags & LOOKUP_PARENT)
++ goto lookup_parent;
++ if (this.name[0] == '.') switch (this.len) {
++ default:
++ break;
++ case 2:
++ if (this.name[1] != '.')
++ break;
++ follow_dotdot(nd);
++ inode = nd->path.dentry->d_inode;
++ /* fallthrough */
++ case 1:
++ goto return_reval;
++ }
++ err = do_lookup(nd, &this, &next);
++ if (err)
++ break;
++ inode = next.dentry->d_inode;
++ if (follow_on_final(inode, lookup_flags)) {
++ err = do_follow_link(&next, nd);
++ if (err)
++ goto return_err;
++ inode = nd->path.dentry->d_inode;
++ } else
++ path_to_nameidata(&next, nd);
++ err = -ENOENT;
++ if (!inode)
++ break;
++ if (lookup_flags & LOOKUP_DIRECTORY) {
++ err = -ENOTDIR;
++ if (!inode->i_op->lookup)
++ break;
++ }
++ goto return_base;
++lookup_parent:
++ nd->last = this;
++ nd->last_type = LAST_NORM;
++ if (this.name[0] != '.')
++ goto return_base;
++ if (this.len == 1)
++ nd->last_type = LAST_DOT;
++ else if (this.len == 2 && this.name[1] == '.')
++ nd->last_type = LAST_DOTDOT;
++ else
++ goto return_base;
++return_reval:
++ /*
++ * We bypassed the ordinary revalidation routines.
++ * We may need to check the cached dentry for staleness.
++ */
++ if (nd->path.dentry && nd->path.dentry->d_sb &&
++ (nd->path.dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) {
++ err = -ESTALE;
++ /* Note: we do not d_invalidate() */
++ if (!nd->path.dentry->d_op->d_revalidate(
++ nd->path.dentry, nd))
++ break;
++ }
++return_base:
++ return 0;
++out_dput:
++ path_put_conditional(&next, nd);
++ break;
++ }
++ path_put(&nd->path);
++return_err:
++ return err;
++}
++
++static int path_walk(const char *name, struct nameidata *nd)
++{
++ struct path save = nd->path;
++ int result;
++
++ current->total_link_count = 0;
++
++ /* make sure the stuff we saved doesn't go away */
++ path_get(&save);
++
++ result = link_path_walk(name, nd);
++ if (result == -ESTALE) {
++ /* nd->path had been dropped */
++ current->total_link_count = 0;
++ nd->path = save;
++ path_get(&nd->path);
++ nd->flags |= LOOKUP_REVAL;
++ result = link_path_walk(name, nd);
++ }
++
++ path_put(&save);
++
++ return result;
++}
++
++static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
++{
++ int retval = 0;
++ int fput_needed;
++ struct file *file;
++
++ nd->last_type = LAST_ROOT; /* if there are only slashes... */
++ nd->flags = flags;
++ nd->depth = 0;
++ nd->root.mnt = NULL;
++
++ if (*name=='/') {
++ set_root(nd);
++ nd->path = nd->root;
++ path_get(&nd->root);
++ } else if (dfd == AT_FDCWD) {
++ get_fs_pwd(current->fs, &nd->path);
++ } else {
++ struct dentry *dentry;
++
++ file = fget_light(dfd, &fput_needed);
++ retval = -EBADF;
++ if (!file)
++ goto out_fail;
++
++ dentry = file->f_path.dentry;
++
++ retval = -ENOTDIR;
++ if (!S_ISDIR(dentry->d_inode->i_mode))
++ goto fput_fail;
++
++ retval = file_permission(file, MAY_EXEC);
++ if (retval)
++ goto fput_fail;
++
++ nd->path = file->f_path;
++ path_get(&file->f_path);
++
++ fput_light(file, fput_needed);
++ }
++ return 0;
++
++fput_fail:
++ fput_light(file, fput_needed);
++out_fail:
++ return retval;
++}
++
++/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
++static int do_path_lookup(int dfd, const char *name,
++ unsigned int flags, struct nameidata *nd)
++{
++ int retval = path_init(dfd, name, flags, nd);
++ if (!retval)
++ retval = path_walk(name, nd);
++ if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
++ nd->path.dentry->d_inode))
++ audit_inode(name, nd->path.dentry);
++ if (nd->root.mnt) {
++ path_put(&nd->root);
++ nd->root.mnt = NULL;
++ }
++ return retval;
++}
++
++int path_lookup(const char *name, unsigned int flags,
++ struct nameidata *nd)
++{
++ return do_path_lookup(AT_FDCWD, name, flags, nd);
++}
++
++int kern_path(const char *name, unsigned int flags, struct path *path)
++{
++ struct nameidata nd;
++ int res = do_path_lookup(AT_FDCWD, name, flags, &nd);
++ if (!res)
++ *path = nd.path;
++ return res;
++}
++
++/**
++ * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair
++ * @dentry: pointer to dentry of the base directory
++ * @mnt: pointer to vfs mount of the base directory
++ * @name: pointer to file name
++ * @flags: lookup flags
++ * @nd: pointer to nameidata
++ */
++int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
++ const char *name, unsigned int flags,
++ struct nameidata *nd)
++{
++ int retval;
++
++ /* same as do_path_lookup */
++ nd->last_type = LAST_ROOT;
++ nd->flags = flags;
++ nd->depth = 0;
++
++ nd->path.dentry = dentry;
++ nd->path.mnt = mnt;
++ path_get(&nd->path);
++ nd->root = nd->path;
++ path_get(&nd->root);
++
++ retval = path_walk(name, nd);
++ if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
++ nd->path.dentry->d_inode))
++ audit_inode(name, nd->path.dentry);
++
++ path_put(&nd->root);
++ nd->root.mnt = NULL;
++
++ return retval;
++}
++
++static struct dentry *__lookup_hash(struct qstr *name,
++ struct dentry *base, struct nameidata *nd)
++{
++ struct dentry *dentry;
++ struct inode *inode;
++ int err;
++
++ inode = base->d_inode;
++
++ /*
++ * See if the low-level filesystem might want
++ * to use its own hash..
++ */
++ if (base->d_op && base->d_op->d_hash) {
++ err = base->d_op->d_hash(base, name);
++ dentry = ERR_PTR(err);
++ if (err < 0)
++ goto out;
++ }
++
++ /*
++ * Don't bother with __d_lookup: callers are for creat as
++ * well as unlink, so a lot of the time it would cost
++ * a double lookup.
++ */
++ dentry = d_lookup(base, name);
++
++ if (dentry && dentry->d_op && dentry->d_op->d_revalidate)
++ dentry = do_revalidate(dentry, nd);
++
++ if (!dentry)
++ dentry = d_alloc_and_lookup(base, name, nd);
++out:
++ return dentry;
++}
++
++/*
++ * Restricted form of lookup. Doesn't follow links, single-component only,
++ * needs parent already locked. Doesn't follow mounts.
++ * SMP-safe.
++ */
++static struct dentry *lookup_hash(struct nameidata *nd)
++{
++ int err;
++
++ err = exec_permission(nd->path.dentry->d_inode);
++ if (err)
++ return ERR_PTR(err);
++ return __lookup_hash(&nd->last, nd->path.dentry, nd);
++}
++EXPORT_SYMBOL(lookup_hash);
++
++static int __lookup_one_len(const char *name, struct qstr *this,
++ struct dentry *base, int len)
++{
++ unsigned long hash;
++ unsigned int c;
++
++ this->name = name;
++ this->len = len;
++ if (!len)
++ return -EACCES;
++
++ hash = init_name_hash();
++ while (len--) {
++ c = *(const unsigned char *)name++;
++ if (c == '/' || c == '\0')
++ return -EACCES;
++ hash = partial_name_hash(c, hash);
++ }
++ this->hash = end_name_hash(hash);
++ return 0;
++}
++EXPORT_SYMBOL(__lookup_one_len);
++
++/**
++ * lookup_one_len - filesystem helper to lookup single pathname component
++ * @name: pathname component to lookup
++ * @base: base directory to lookup from
++ * @len: maximum length @len should be interpreted to
++ *
++ * Note that this routine is purely a helper for filesystem usage and should
++ * not be called by generic code. Also note that by using this function the
++ * nameidata argument is passed to the filesystem methods and a filesystem
++ * using this helper needs to be prepared for that.
++ */
++struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
++{
++ int err;
++ struct qstr this;
++
++ WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex));
++
++ err = __lookup_one_len(name, &this, base, len);
++ if (err)
++ return ERR_PTR(err);
++
++ err = exec_permission(base->d_inode);
++ if (err)
++ return ERR_PTR(err);
++ return __lookup_hash(&this, base, NULL);
++}
++
++int user_path_at(int dfd, const char __user *name, unsigned flags,
++ struct path *path)
++{
++ struct nameidata nd;
++ char *tmp = getname(name);
++ int err = PTR_ERR(tmp);
++ if (!IS_ERR(tmp)) {
++
++ BUG_ON(flags & LOOKUP_PARENT);
++
++ err = do_path_lookup(dfd, tmp, flags, &nd);
++ putname(tmp);
++ if (!err)
++ *path = nd.path;
++ }
++ return err;
++}
++
++static int user_path_parent(int dfd, const char __user *path,
++ struct nameidata *nd, char **name)
++{
++ char *s = getname(path);
++ int error;
++
++ if (IS_ERR(s))
++ return PTR_ERR(s);
++
++ error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd);
++ if (error)
++ putname(s);
++ else
++ *name = s;
++
++ return error;
++}
++
++/*
++ * It's inline, so penalty for filesystems that don't use sticky bit is
++ * minimal.
++ */
++static inline int check_sticky(struct inode *dir, struct inode *inode)
++{
++ uid_t fsuid = current_fsuid();
++
++ if (!(dir->i_mode & S_ISVTX))
++ return 0;
++ if (inode->i_uid == fsuid)
++ return 0;
++ if (dir->i_uid == fsuid)
++ return 0;
++ return !capable(CAP_FOWNER);
++}
++
++/*
++ * Check whether we can remove a link victim from directory dir, check
++ * whether the type of victim is right.
++ * 1. We can't do it if dir is read-only (done in permission())
++ * 2. We should have write and exec permissions on dir
++ * 3. We can't remove anything from append-only dir
++ * 4. We can't do anything with immutable dir (done in permission())
++ * 5. If the sticky bit on dir is set we should either
++ * a. be owner of dir, or
++ * b. be owner of victim, or
++ * c. have CAP_FOWNER capability
++ * 6. If the victim is append-only or immutable we can't do antyhing with
++ * links pointing to it.
++ * 7. If we were asked to remove a directory and victim isn't one - ENOTDIR.
++ * 8. If we were asked to remove a non-directory and victim isn't one - EISDIR.
++ * 9. We can't remove a root or mountpoint.
++ * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
++ * nfs_async_unlink().
++ */
++static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
++{
++ int error;
++
++ if (!victim->d_inode)
++ return -ENOENT;
++
++ BUG_ON(victim->d_parent->d_inode != dir);
++ audit_inode_child(victim, dir);
++
++ error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
++ if (error)
++ return error;
++ if (IS_APPEND(dir))
++ return -EPERM;
++ if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
++ IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode))
++ return -EPERM;
++ if (isdir) {
++ if (!S_ISDIR(victim->d_inode->i_mode))
++ return -ENOTDIR;
++ if (IS_ROOT(victim))
++ return -EBUSY;
++ } else if (S_ISDIR(victim->d_inode->i_mode))
++ return -EISDIR;
++ if (IS_DEADDIR(dir))
++ return -ENOENT;
++ if (victim->d_flags & DCACHE_NFSFS_RENAMED)
++ return -EBUSY;
++ return 0;
++}
++
++/* Check whether we can create an object with dentry child in directory
++ * dir.
++ * 1. We can't do it if child already exists (open has special treatment for
++ * this case, but since we are inlined it's OK)
++ * 2. We can't do it if dir is read-only (done in permission())
++ * 3. We should have write and exec permissions on dir
++ * 4. We can't do it if dir is immutable (done in permission())
++ */
++static inline int may_create(struct inode *dir, struct dentry *child)
++{
++ if (child->d_inode)
++ return -EEXIST;
++ if (IS_DEADDIR(dir))
++ return -ENOENT;
++ return inode_permission(dir, MAY_WRITE | MAY_EXEC);
++}
++
++/*
++ * p1 and p2 should be directories on the same fs.
++ */
++struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
++{
++ struct dentry *p;
++
++ if (p1 == p2) {
++ mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
++ return NULL;
++ }
++
++ mutex_lock(&p1->d_inode->i_sb->s_vfs_rename_mutex);
++
++ p = d_ancestor(p2, p1);
++ if (p) {
++ mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT);
++ mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD);
++ return p;
++ }
++
++ p = d_ancestor(p1, p2);
++ if (p) {
++ mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
++ mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD);
++ return p;
++ }
++
++ mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
++ mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD);
++ return NULL;
++}
++
++void unlock_rename(struct dentry *p1, struct dentry *p2)
++{
++ mutex_unlock(&p1->d_inode->i_mutex);
++ if (p1 != p2) {
++ mutex_unlock(&p2->d_inode->i_mutex);
++ mutex_unlock(&p1->d_inode->i_sb->s_vfs_rename_mutex);
++ }
++}
++
++int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
++ struct nameidata *nd)
++{
++ int error = may_create(dir, dentry);
++
++ if (error)
++ return error;
++
++ if (!dir->i_op->create)
++ return -EACCES; /* shouldn't it be ENOSYS? */
++ mode &= S_IALLUGO;
++ mode |= S_IFREG;
++ error = security_inode_create(dir, dentry, mode);
++ if (error)
++ return error;
++ error = dir->i_op->create(dir, dentry, mode, nd);
++ if (!error)
++ fsnotify_create(dir, dentry);
++ return error;
++}
++
++int may_open(struct path *path, int acc_mode, int flag)
++{
++ struct dentry *dentry = path->dentry;
++ struct inode *inode = dentry->d_inode;
++ int error;
++
++ if (!inode)
++ return -ENOENT;
++
++ switch (inode->i_mode & S_IFMT) {
++ case S_IFLNK:
++ return -ELOOP;
++ case S_IFDIR:
++ if (acc_mode & MAY_WRITE)
++ return -EISDIR;
++ break;
++ case S_IFBLK:
++ case S_IFCHR:
++ if (path->mnt->mnt_flags & MNT_NODEV)
++ return -EACCES;
++ /*FALLTHRU*/
++ case S_IFIFO:
++ case S_IFSOCK:
++ flag &= ~O_TRUNC;
++ break;
++ }
++
++ error = inode_permission(inode, acc_mode);
++ if (error)
++ return error;
++
++ /*
++ * An append-only file must be opened in append mode for writing.
++ */
++ if (IS_APPEND(inode)) {
++ if ((flag & O_ACCMODE) != O_RDONLY && !(flag & O_APPEND))
++ return -EPERM;
++ if (flag & O_TRUNC)
++ return -EPERM;
++ }
++
++ /* O_NOATIME can only be set by the owner or superuser */
++ if (flag & O_NOATIME && !is_owner_or_cap(inode))
++ return -EPERM;
++
++ /*
++ * Ensure there are no outstanding leases on the file.
++ */
++ return break_lease(inode, flag);
++}
++
++static int handle_truncate(struct path *path)
++{
++ struct inode *inode = path->dentry->d_inode;
++ int error = get_write_access(inode);
++ if (error)
++ return error;
++ /*
++ * Refuse to truncate files with mandatory locks held on them.
++ */
++ error = locks_verify_locked(inode);
++ if (!error)
++ error = security_path_truncate(path);
++ if (!error) {
++ error = do_truncate(path->dentry, 0,
++ ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
++ NULL);
++ }
++ put_write_access(inode);
++ return error;
++}
++
++/*
++ * Be careful about ever adding any more callers of this
++ * function. Its flags must be in the namei format, not
++ * what get passed to sys_open().
++ */
++static int __open_namei_create(struct nameidata *nd, struct path *path,
++ int open_flag, int mode)
++{
++ int error;
++ struct dentry *dir = nd->path.dentry;
++
++ if (!IS_POSIXACL(dir->d_inode))
++ mode &= ~current_umask();
++ error = security_path_mknod(&nd->path, path->dentry, mode, 0);
++ if (error)
++ goto out_unlock;
++ error = vfs_create(dir->d_inode, path->dentry, mode, nd);
++out_unlock:
++ mutex_unlock(&dir->d_inode->i_mutex);
++ dput(nd->path.dentry);
++ nd->path.dentry = path->dentry;
++ if (error)
++ return error;
++ /* Don't check for write permission, don't truncate */
++ return may_open(&nd->path, 0, open_flag & ~O_TRUNC);
++}
++
++/*
++ * Note that while the flag value (low two bits) for sys_open means:
++ * 00 - read-only
++ * 01 - write-only
++ * 10 - read-write
++ * 11 - special
++ * it is changed into
++ * 00 - no permissions needed
++ * 01 - read-permission
++ * 10 - write-permission
++ * 11 - read-write
++ * for the internal routines (ie open_namei()/follow_link() etc)
++ * This is more logical, and also allows the 00 "no perm needed"
++ * to be used for symlinks (where the permissions are checked
++ * later).
++ *
++*/
++static inline int open_to_namei_flags(int flag)
++{
++ if ((flag+1) & O_ACCMODE)
++ flag++;
++ return flag;
++}
++
++static int open_will_truncate(int flag, struct inode *inode)
++{
++ /*
++ * We'll never write to the fs underlying
++ * a device file.
++ */
++ if (special_file(inode->i_mode))
++ return 0;
++ return (flag & O_TRUNC);
++}
++
++static struct file *finish_open(struct nameidata *nd,
++ int open_flag, int acc_mode)
++{
++ struct file *filp;
++ int will_truncate;
++ int error;
++
++ will_truncate = open_will_truncate(open_flag, nd->path.dentry->d_inode);
++ if (will_truncate) {
++ error = mnt_want_write(nd->path.mnt);
++ if (error)
++ goto exit;
++ }
++ error = may_open(&nd->path, acc_mode, open_flag);
++ if (error) {
++ if (will_truncate)
++ mnt_drop_write(nd->path.mnt);
++ goto exit;
++ }
++ filp = nameidata_to_filp(nd);
++ if (!IS_ERR(filp)) {
++ error = ima_file_check(filp, acc_mode);
++ if (error) {
++ fput(filp);
++ filp = ERR_PTR(error);
++ }
++ }
++ if (!IS_ERR(filp)) {
++ if (will_truncate) {
++ error = handle_truncate(&nd->path);
++ if (error) {
++ fput(filp);
++ filp = ERR_PTR(error);
++ }
++ }
++ }
++ /*
++ * It is now safe to drop the mnt write
++ * because the filp has had a write taken
++ * on its behalf.
++ */
++ if (will_truncate)
++ mnt_drop_write(nd->path.mnt);
++ return filp;
++
++exit:
++ if (!IS_ERR(nd->intent.open.file))
++ release_open_intent(nd);
++ path_put(&nd->path);
++ return ERR_PTR(error);
++}
++
++static struct file *do_last(struct nameidata *nd, struct path *path,
++ int open_flag, int acc_mode,
++ int mode, const char *pathname)
++{
++ struct dentry *dir = nd->path.dentry;
++ struct file *filp;
++ int error = -EISDIR;
++
++ switch (nd->last_type) {
++ case LAST_DOTDOT:
++ follow_dotdot(nd);
++ dir = nd->path.dentry;
++ case LAST_DOT:
++ if (nd->path.mnt->mnt_sb->s_type->fs_flags & FS_REVAL_DOT) {
++ if (!dir->d_op->d_revalidate(dir, nd)) {
++ error = -ESTALE;
++ goto exit;
++ }
++ }
++ /* fallthrough */
++ case LAST_ROOT:
++ if (open_flag & O_CREAT)
++ goto exit;
++ /* fallthrough */
++ case LAST_BIND:
++ audit_inode(pathname, dir);
++ goto ok;
++ }
++
++ /* trailing slashes? */
++ if (nd->last.name[nd->last.len]) {
++ if (open_flag & O_CREAT)
++ goto exit;
++ nd->flags |= LOOKUP_DIRECTORY | LOOKUP_FOLLOW;
++ }
++
++ /* just plain open? */
++ if (!(open_flag & O_CREAT)) {
++ error = do_lookup(nd, &nd->last, path);
++ if (error)
++ goto exit;
++ error = -ENOENT;
++ if (!path->dentry->d_inode)
++ goto exit_dput;
++ if (path->dentry->d_inode->i_op->follow_link)
++ return NULL;
++ error = -ENOTDIR;
++ if (nd->flags & LOOKUP_DIRECTORY) {
++ if (!path->dentry->d_inode->i_op->lookup)
++ goto exit_dput;
++ }
++ path_to_nameidata(path, nd);
++ audit_inode(pathname, nd->path.dentry);
++ goto ok;
++ }
++
++ /* OK, it's O_CREAT */
++ mutex_lock(&dir->d_inode->i_mutex);
++
++ path->dentry = lookup_hash(nd);
++ path->mnt = nd->path.mnt;
++
++ error = PTR_ERR(path->dentry);
++ if (IS_ERR(path->dentry)) {
++ mutex_unlock(&dir->d_inode->i_mutex);
++ goto exit;
++ }
++
++ if (IS_ERR(nd->intent.open.file)) {
++ error = PTR_ERR(nd->intent.open.file);
++ goto exit_mutex_unlock;
++ }
++
++ /* Negative dentry, just create the file */
++ if (!path->dentry->d_inode) {
++ /*
++ * This write is needed to ensure that a
++ * ro->rw transition does not occur between
++ * the time when the file is created and when
++ * a permanent write count is taken through
++ * the 'struct file' in nameidata_to_filp().
++ */
++ error = mnt_want_write(nd->path.mnt);
++ if (error)
++ goto exit_mutex_unlock;
++ error = __open_namei_create(nd, path, open_flag, mode);
++ if (error) {
++ mnt_drop_write(nd->path.mnt);
++ goto exit;
++ }
++ filp = nameidata_to_filp(nd);
++ mnt_drop_write(nd->path.mnt);
++ if (!IS_ERR(filp)) {
++ error = ima_file_check(filp, acc_mode);
++ if (error) {
++ fput(filp);
++ filp = ERR_PTR(error);
++ }
++ }
++ return filp;
++ }
++
++ /*
++ * It already exists.
++ */
++ mutex_unlock(&dir->d_inode->i_mutex);
++ audit_inode(pathname, path->dentry);
++
++ error = -EEXIST;
++ if (open_flag & O_EXCL)
++ goto exit_dput;
++
++ if (__follow_mount(path)) {
++ error = -ELOOP;
++ if (open_flag & O_NOFOLLOW)
++ goto exit_dput;
++ }
++
++ error = -ENOENT;
++ if (!path->dentry->d_inode)
++ goto exit_dput;
++
++ if (path->dentry->d_inode->i_op->follow_link)
++ return NULL;
++
++ path_to_nameidata(path, nd);
++ error = -EISDIR;
++ if (S_ISDIR(path->dentry->d_inode->i_mode))
++ goto exit;
++ok:
++ filp = finish_open(nd, open_flag, acc_mode);
++ return filp;
++
++exit_mutex_unlock:
++ mutex_unlock(&dir->d_inode->i_mutex);
++exit_dput:
++ path_put_conditional(path, nd);
++exit:
++ if (!IS_ERR(nd->intent.open.file))
++ release_open_intent(nd);
++ path_put(&nd->path);
++ return ERR_PTR(error);
++}
++
++/*
++ * Note that the low bits of the passed in "open_flag"
++ * are not the same as in the local variable "flag". See
++ * open_to_namei_flags() for more details.
++ */
++struct file *do_filp_open(int dfd, const char *pathname,
++ int open_flag, int mode, int acc_mode)
++{
++ struct file *filp;
++ struct nameidata nd;
++ int error;
++ struct path path;
++ int count = 0;
++ int flag = open_to_namei_flags(open_flag);
++ int force_reval = 0;
++
++ if (!(open_flag & O_CREAT))
++ mode = 0;
++
++ /*
++ * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only
++ * check for O_DSYNC if the need any syncing at all we enforce it's
++ * always set instead of having to deal with possibly weird behaviour
++ * for malicious applications setting only __O_SYNC.
++ */
++ if (open_flag & __O_SYNC)
++ open_flag |= O_DSYNC;
++
++ if (!acc_mode)
++ acc_mode = MAY_OPEN | ACC_MODE(open_flag);
++
++ /* O_TRUNC implies we need access checks for write permissions */
++ if (open_flag & O_TRUNC)
++ acc_mode |= MAY_WRITE;
++
++ /* Allow the LSM permission hook to distinguish append
++ access from general write access. */
++ if (open_flag & O_APPEND)
++ acc_mode |= MAY_APPEND;
++
++ /* find the parent */
++reval:
++ error = path_init(dfd, pathname, LOOKUP_PARENT, &nd);
++ if (error)
++ return ERR_PTR(error);
++ if (force_reval)
++ nd.flags |= LOOKUP_REVAL;
++
++ current->total_link_count = 0;
++ error = link_path_walk(pathname, &nd);
++ if (error) {
++ filp = ERR_PTR(error);
++ goto out;
++ }
++ if (unlikely(!audit_dummy_context()) && (open_flag & O_CREAT))
++ audit_inode(pathname, nd.path.dentry);
++
++ /*
++ * We have the parent and last component.
++ */
++
++ error = -ENFILE;
++ filp = get_empty_filp();
++ if (filp == NULL)
++ goto exit_parent;
++ nd.intent.open.file = filp;
++ filp->f_flags = open_flag;
++ nd.intent.open.flags = flag;
++ nd.intent.open.create_mode = mode;
++ nd.flags &= ~LOOKUP_PARENT;
++ nd.flags |= LOOKUP_OPEN;
++ if (open_flag & O_CREAT) {
++ nd.flags |= LOOKUP_CREATE;
++ if (open_flag & O_EXCL)
++ nd.flags |= LOOKUP_EXCL;
++ }
++ if (open_flag & O_DIRECTORY)
++ nd.flags |= LOOKUP_DIRECTORY;
++ if (!(open_flag & O_NOFOLLOW))
++ nd.flags |= LOOKUP_FOLLOW;
++ filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
++ while (unlikely(!filp)) { /* trailing symlink */
++ struct path holder;
++ struct inode *inode = path.dentry->d_inode;
++ void *cookie;
++ error = -ELOOP;
++ /* S_ISDIR part is a temporary automount kludge */
++ if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(inode->i_mode))
++ goto exit_dput;
++ if (count++ == 32)
++ goto exit_dput;
++ /*
++ * This is subtle. Instead of calling do_follow_link() we do
++ * the thing by hands. The reason is that this way we have zero
++ * link_count and path_walk() (called from ->follow_link)
++ * honoring LOOKUP_PARENT. After that we have the parent and
++ * last component, i.e. we are in the same situation as after
++ * the first path_walk(). Well, almost - if the last component
++ * is normal we get its copy stored in nd->last.name and we will
++ * have to putname() it when we are done. Procfs-like symlinks
++ * just set LAST_BIND.
++ */
++ nd.flags |= LOOKUP_PARENT;
++ error = security_inode_follow_link(path.dentry, &nd);
++ if (error)
++ goto exit_dput;
++ error = __do_follow_link(&path, &nd, &cookie);
++ if (unlikely(error)) {
++ /* nd.path had been dropped */
++ if (!IS_ERR(cookie) && inode->i_op->put_link)
++ inode->i_op->put_link(path.dentry, &nd, cookie);
++ path_put(&path);
++ release_open_intent(&nd);
++ filp = ERR_PTR(error);
++ goto out;
++ }
++ holder = path;
++ nd.flags &= ~LOOKUP_PARENT;
++ filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
++ if (inode->i_op->put_link)
++ inode->i_op->put_link(holder.dentry, &nd, cookie);
++ path_put(&holder);
++ }
++out:
++ if (nd.root.mnt)
++ path_put(&nd.root);
++ if (filp == ERR_PTR(-ESTALE) && !force_reval) {
++ force_reval = 1;
++ goto reval;
++ }
++ return filp;
++
++exit_dput:
++ path_put_conditional(&path, &nd);
++ if (!IS_ERR(nd.intent.open.file))
++ release_open_intent(&nd);
++exit_parent:
++ path_put(&nd.path);
++ filp = ERR_PTR(error);
++ goto out;
++}
++
++/**
++ * filp_open - open file and return file pointer
++ *
++ * @filename: path to open
++ * @flags: open flags as per the open(2) second argument
++ * @mode: mode for the new file if O_CREAT is set, else ignored
++ *
++ * This is the helper to open a file from kernelspace if you really
++ * have to. But in generally you should not do this, so please move
++ * along, nothing to see here..
++ */
++struct file *filp_open(const char *filename, int flags, int mode)
++{
++ return do_filp_open(AT_FDCWD, filename, flags, mode, 0);
++}
++EXPORT_SYMBOL(filp_open);
++
++/**
++ * lookup_create - lookup a dentry, creating it if it doesn't exist
++ * @nd: nameidata info
++ * @is_dir: directory flag
++ *
++ * Simple function to lookup and return a dentry and create it
++ * if it doesn't exist. Is SMP-safe.
++ *
++ * Returns with nd->path.dentry->d_inode->i_mutex locked.
++ */
++struct dentry *lookup_create(struct nameidata *nd, int is_dir)
++{
++ struct dentry *dentry = ERR_PTR(-EEXIST);
++
++ mutex_lock_nested(&nd->path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
++ /*
++ * Yucky last component or no last component at all?
++ * (foo/., foo/.., /////)
++ */
++ if (nd->last_type != LAST_NORM)
++ goto fail;
++ nd->flags &= ~LOOKUP_PARENT;
++ nd->flags |= LOOKUP_CREATE | LOOKUP_EXCL;
++ nd->intent.open.flags = O_EXCL;
++
++ /*
++ * Do the final lookup.
++ */
++ dentry = lookup_hash(nd);
++ if (IS_ERR(dentry))
++ goto fail;
++
++ if (dentry->d_inode)
++ goto eexist;
++ /*
++ * Special case - lookup gave negative, but... we had foo/bar/
++ * From the vfs_mknod() POV we just have a negative dentry -
++ * all is fine. Let's be bastards - you had / on the end, you've
++ * been asking for (non-existent) directory. -ENOENT for you.
++ */
++ if (unlikely(!is_dir && nd->last.name[nd->last.len])) {
++ dput(dentry);
++ dentry = ERR_PTR(-ENOENT);
++ }
++ return dentry;
++eexist:
++ dput(dentry);
++ dentry = ERR_PTR(-EEXIST);
++fail:
++ return dentry;
++}
++EXPORT_SYMBOL_GPL(lookup_create);
++
++int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
++{
++ int error = may_create(dir, dentry);
++
++ if (error)
++ return error;
++
++ if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
++ return -EPERM;
++
++ if (!dir->i_op->mknod)
++ return -EPERM;
++
++ error = devcgroup_inode_mknod(mode, dev);
++ if (error)
++ return error;
++
++ error = security_inode_mknod(dir, dentry, mode, dev);
++ if (error)
++ return error;
++
++ error = dir->i_op->mknod(dir, dentry, mode, dev);
++ if (!error)
++ fsnotify_create(dir, dentry);
++ return error;
++}
++
++static int may_mknod(mode_t mode)
++{
++ switch (mode & S_IFMT) {
++ case S_IFREG:
++ case S_IFCHR:
++ case S_IFBLK:
++ case S_IFIFO:
++ case S_IFSOCK:
++ case 0: /* zero mode translates to S_IFREG */
++ return 0;
++ case S_IFDIR:
++ return -EPERM;
++ default:
++ return -EINVAL;
++ }
++}
++
++SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode,
++ unsigned, dev)
++{
++ int error;
++ char *tmp;
++ struct dentry *dentry;
++ struct nameidata nd;
++
++ if (S_ISDIR(mode))
++ return -EPERM;
++
++ error = user_path_parent(dfd, filename, &nd, &tmp);
++ if (error)
++ return error;
++
++ dentry = lookup_create(&nd, 0);
++ if (IS_ERR(dentry)) {
++ error = PTR_ERR(dentry);
++ goto out_unlock;
++ }
++ if (!IS_POSIXACL(nd.path.dentry->d_inode))
++ mode &= ~current_umask();
++ error = may_mknod(mode);
++ if (error)
++ goto out_dput;
++ error = mnt_want_write(nd.path.mnt);
++ if (error)
++ goto out_dput;
++ error = security_path_mknod(&nd.path, dentry, mode, dev);
++ if (error)
++ goto out_drop_write;
++ switch (mode & S_IFMT) {
++ case 0: case S_IFREG:
++ error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
++ break;
++ case S_IFCHR: case S_IFBLK:
++ error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,
++ new_decode_dev(dev));
++ break;
++ case S_IFIFO: case S_IFSOCK:
++ error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
++ break;
++ }
++out_drop_write:
++ mnt_drop_write(nd.path.mnt);
++out_dput:
++ dput(dentry);
++out_unlock:
++ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
++ path_put(&nd.path);
++ putname(tmp);
++
++ return error;
++}
++
++SYSCALL_DEFINE3(mknod, const char __user *, filename, int, mode, unsigned, dev)
++{
++ return sys_mknodat(AT_FDCWD, filename, mode, dev);
++}
++
++int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++ int error = may_create(dir, dentry);
++
++ if (error)
++ return error;
++
++ if (!dir->i_op->mkdir)
++ return -EPERM;
++
++ mode &= (S_IRWXUGO|S_ISVTX);
++ error = security_inode_mkdir(dir, dentry, mode);
++ if (error)
++ return error;
++
++ error = dir->i_op->mkdir(dir, dentry, mode);
++ if (!error)
++ fsnotify_mkdir(dir, dentry);
++ return error;
++}
++
++SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, int, mode)
++{
++ int error = 0;
++ char * tmp;
++ struct dentry *dentry;
++ struct nameidata nd;
++
++ error = user_path_parent(dfd, pathname, &nd, &tmp);
++ if (error)
++ goto out_err;
++
++ dentry = lookup_create(&nd, 1);
++ error = PTR_ERR(dentry);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++
++ if (!IS_POSIXACL(nd.path.dentry->d_inode))
++ mode &= ~current_umask();
++ error = mnt_want_write(nd.path.mnt);
++ if (error)
++ goto out_dput;
++ error = security_path_mkdir(&nd.path, dentry, mode);
++ if (error)
++ goto out_drop_write;
++ error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
++out_drop_write:
++ mnt_drop_write(nd.path.mnt);
++out_dput:
++ dput(dentry);
++out_unlock:
++ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
++ path_put(&nd.path);
++ putname(tmp);
++out_err:
++ return error;
++}
++
++SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
++{
++ return sys_mkdirat(AT_FDCWD, pathname, mode);
++}
++
++/*
++ * We try to drop the dentry early: we should have
++ * a usage count of 2 if we're the only user of this
++ * dentry, and if that is true (possibly after pruning
++ * the dcache), then we drop the dentry now.
++ *
++ * A low-level filesystem can, if it choses, legally
++ * do a
++ *
++ * if (!d_unhashed(dentry))
++ * return -EBUSY;
++ *
++ * if it cannot handle the case of removing a directory
++ * that is still in use by something else..
++ */
++void dentry_unhash(struct dentry *dentry)
++{
++ dget(dentry);
++ shrink_dcache_parent(dentry);
++ spin_lock(&dcache_lock);
++ spin_lock(&dentry->d_lock);
++ if (atomic_read(&dentry->d_count) == 2)
++ __d_drop(dentry);
++ spin_unlock(&dentry->d_lock);
++ spin_unlock(&dcache_lock);
++}
++
++int vfs_rmdir(struct inode *dir, struct dentry *dentry)
++{
++ int error = may_delete(dir, dentry, 1);
++
++ if (error)
++ return error;
++
++ if (!dir->i_op->rmdir)
++ return -EPERM;
++
++ mutex_lock(&dentry->d_inode->i_mutex);
++ dentry_unhash(dentry);
++ if (d_mountpoint(dentry))
++ error = -EBUSY;
++ else {
++ error = security_inode_rmdir(dir, dentry);
++ if (!error) {
++ error = dir->i_op->rmdir(dir, dentry);
++ if (!error) {
++ dentry->d_inode->i_flags |= S_DEAD;
++ dont_mount(dentry);
++ }
++ }
++ }
++ mutex_unlock(&dentry->d_inode->i_mutex);
++ if (!error) {
++ d_delete(dentry);
++ }
++ dput(dentry);
++
++ return error;
++}
++
++static long do_rmdir(int dfd, const char __user *pathname)
++{
++ int error = 0;
++ char * name;
++ struct dentry *dentry;
++ struct nameidata nd;
++
++ error = user_path_parent(dfd, pathname, &nd, &name);
++ if (error)
++ return error;
++
++ switch(nd.last_type) {
++ case LAST_DOTDOT:
++ error = -ENOTEMPTY;
++ goto exit1;
++ case LAST_DOT:
++ error = -EINVAL;
++ goto exit1;
++ case LAST_ROOT:
++ error = -EBUSY;
++ goto exit1;
++ }
++
++ nd.flags &= ~LOOKUP_PARENT;
++
++ mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
++ dentry = lookup_hash(&nd);
++ error = PTR_ERR(dentry);
++ if (IS_ERR(dentry))
++ goto exit2;
++ error = mnt_want_write(nd.path.mnt);
++ if (error)
++ goto exit3;
++ error = security_path_rmdir(&nd.path, dentry);
++ if (error)
++ goto exit4;
++ error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
++exit4:
++ mnt_drop_write(nd.path.mnt);
++exit3:
++ dput(dentry);
++exit2:
++ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
++exit1:
++ path_put(&nd.path);
++ putname(name);
++ return error;
++}
++
++SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
++{
++ return do_rmdir(AT_FDCWD, pathname);
++}
++
++int vfs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int error = may_delete(dir, dentry, 0);
++
++ if (error)
++ return error;
++
++ if (!dir->i_op->unlink)
++ return -EPERM;
++
++ mutex_lock(&dentry->d_inode->i_mutex);
++ if (d_mountpoint(dentry))
++ error = -EBUSY;
++ else {
++ error = security_inode_unlink(dir, dentry);
++ if (!error) {
++ error = dir->i_op->unlink(dir, dentry);
++ if (!error)
++ dont_mount(dentry);
++ }
++ }
++ mutex_unlock(&dentry->d_inode->i_mutex);
++
++ /* We don't d_delete() NFS sillyrenamed files--they still exist. */
++ if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
++ fsnotify_link_count(dentry->d_inode);
++ d_delete(dentry);
++ }
++
++ return error;
++}
++
++/*
++ * Make sure that the actual truncation of the file will occur outside its
++ * directory's i_mutex. Truncate can take a long time if there is a lot of
++ * writeout happening, and we don't want to prevent access to the directory
++ * while waiting on the I/O.
++ */
++static long do_unlinkat(int dfd, const char __user *pathname)
++{
++ int error;
++ char *name;
++ struct dentry *dentry;
++ struct nameidata nd;
++ struct inode *inode = NULL;
++
++ error = user_path_parent(dfd, pathname, &nd, &name);
++ if (error)
++ return error;
++
++ error = -EISDIR;
++ if (nd.last_type != LAST_NORM)
++ goto exit1;
++
++ nd.flags &= ~LOOKUP_PARENT;
++
++ mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
++ dentry = lookup_hash(&nd);
++ error = PTR_ERR(dentry);
++ if (!IS_ERR(dentry)) {
++ /* Why not before? Because we want correct error value */
++ if (nd.last.name[nd.last.len])
++ goto slashes;
++ inode = dentry->d_inode;
++ if (inode)
++ atomic_inc(&inode->i_count);
++ error = mnt_want_write(nd.path.mnt);
++ if (error)
++ goto exit2;
++ error = security_path_unlink(&nd.path, dentry);
++ if (error)
++ goto exit3;
++ error = vfs_unlink(nd.path.dentry->d_inode, dentry);
++exit3:
++ mnt_drop_write(nd.path.mnt);
++ exit2:
++ dput(dentry);
++ }
++ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
++ if (inode)
++ iput(inode); /* truncate the inode here */
++exit1:
++ path_put(&nd.path);
++ putname(name);
++ return error;
++
++slashes:
++ error = !dentry->d_inode ? -ENOENT :
++ S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
++ goto exit2;
++}
++
++SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag)
++{
++ if ((flag & ~AT_REMOVEDIR) != 0)
++ return -EINVAL;
++
++ if (flag & AT_REMOVEDIR)
++ return do_rmdir(dfd, pathname);
++
++ return do_unlinkat(dfd, pathname);
++}
++
++SYSCALL_DEFINE1(unlink, const char __user *, pathname)
++{
++ return do_unlinkat(AT_FDCWD, pathname);
++}
++
++int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
++{
++ int error = may_create(dir, dentry);
++
++ if (error)
++ return error;
++
++ if (!dir->i_op->symlink)
++ return -EPERM;
++
++ error = security_inode_symlink(dir, dentry, oldname);
++ if (error)
++ return error;
++
++ error = dir->i_op->symlink(dir, dentry, oldname);
++ if (!error)
++ fsnotify_create(dir, dentry);
++ return error;
++}
++
++SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
++ int, newdfd, const char __user *, newname)
++{
++ int error;
++ char *from;
++ char *to;
++ struct dentry *dentry;
++ struct nameidata nd;
++
++ from = getname(oldname);
++ if (IS_ERR(from))
++ return PTR_ERR(from);
++
++ error = user_path_parent(newdfd, newname, &nd, &to);
++ if (error)
++ goto out_putname;
++
++ dentry = lookup_create(&nd, 0);
++ error = PTR_ERR(dentry);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++
++ error = mnt_want_write(nd.path.mnt);
++ if (error)
++ goto out_dput;
++ error = security_path_symlink(&nd.path, dentry, from);
++ if (error)
++ goto out_drop_write;
++ error = vfs_symlink(nd.path.dentry->d_inode, dentry, from);
++out_drop_write:
++ mnt_drop_write(nd.path.mnt);
++out_dput:
++ dput(dentry);
++out_unlock:
++ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
++ path_put(&nd.path);
++ putname(to);
++out_putname:
++ putname(from);
++ return error;
++}
++
++SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newname)
++{
++ return sys_symlinkat(oldname, AT_FDCWD, newname);
++}
++
++int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
++{
++ struct inode *inode = old_dentry->d_inode;
++ int error;
++
++ if (!inode)
++ return -ENOENT;
++
++ error = may_create(dir, new_dentry);
++ if (error)
++ return error;
++
++ if (dir->i_sb != inode->i_sb)
++ return -EXDEV;
++
++ /*
++ * A link to an append-only or immutable file cannot be created.
++ */
++ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
++ return -EPERM;
++ if (!dir->i_op->link)
++ return -EPERM;
++ if (S_ISDIR(inode->i_mode))
++ return -EPERM;
++
++ error = security_inode_link(old_dentry, dir, new_dentry);
++ if (error)
++ return error;
++
++ mutex_lock(&inode->i_mutex);
++ error = dir->i_op->link(old_dentry, dir, new_dentry);
++ mutex_unlock(&inode->i_mutex);
++ if (!error)
++ fsnotify_link(dir, inode, new_dentry);
++ return error;
++}
++
++/*
++ * Hardlinks are often used in delicate situations. We avoid
++ * security-related surprises by not following symlinks on the
++ * newname. --KAB
++ *
++ * We don't follow them on the oldname either to be compatible
++ * with linux 2.0, and to avoid hard-linking to directories
++ * and other special files. --ADM
++ */
++SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
++ int, newdfd, const char __user *, newname, int, flags)
++{
++ struct dentry *new_dentry;
++ struct nameidata nd;
++ struct path old_path;
++ int error;
++ char *to;
++
++ if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
++ return -EINVAL;
++
++ error = user_path_at(olddfd, oldname,
++ flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
++ &old_path);
++ if (error)
++ return error;
++
++ error = user_path_parent(newdfd, newname, &nd, &to);
++ if (error)
++ goto out;
++ error = -EXDEV;
++ if (old_path.mnt != nd.path.mnt)
++ goto out_release;
++ new_dentry = lookup_create(&nd, 0);
++ error = PTR_ERR(new_dentry);
++ if (IS_ERR(new_dentry))
++ goto out_unlock;
++ error = mnt_want_write(nd.path.mnt);
++ if (error)
++ goto out_dput;
++ error = security_path_link(old_path.dentry, &nd.path, new_dentry);
++ if (error)
++ goto out_drop_write;
++ error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
++out_drop_write:
++ mnt_drop_write(nd.path.mnt);
++out_dput:
++ dput(new_dentry);
++out_unlock:
++ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
++out_release:
++ path_put(&nd.path);
++ putname(to);
++out:
++ path_put(&old_path);
++
++ return error;
++}
++
++SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname)
++{
++ return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
++}
++
++/*
++ * The worst of all namespace operations - renaming directory. "Perverted"
++ * doesn't even start to describe it. Somebody in UCB had a heck of a trip...
++ * Problems:
++ * a) we can get into loop creation. Check is done in is_subdir().
++ * b) race potential - two innocent renames can create a loop together.
++ * That's where 4.4 screws up. Current fix: serialization on
++ * sb->s_vfs_rename_mutex. We might be more accurate, but that's another
++ * story.
++ * c) we have to lock _three_ objects - parents and victim (if it exists).
++ * And that - after we got ->i_mutex on parents (until then we don't know
++ * whether the target exists). Solution: try to be smart with locking
++ * order for inodes. We rely on the fact that tree topology may change
++ * only under ->s_vfs_rename_mutex _and_ that parent of the object we
++ * move will be locked. Thus we can rank directories by the tree
++ * (ancestors first) and rank all non-directories after them.
++ * That works since everybody except rename does "lock parent, lookup,
++ * lock child" and rename is under ->s_vfs_rename_mutex.
++ * HOWEVER, it relies on the assumption that any object with ->lookup()
++ * has no more than 1 dentry. If "hybrid" objects will ever appear,
++ * we'd better make sure that there's no link(2) for them.
++ * d) some filesystems don't support opened-but-unlinked directories,
++ * either because of layout or because they are not ready to deal with
++ * all cases correctly. The latter will be fixed (taking this sort of
++ * stuff into VFS), but the former is not going away. Solution: the same
++ * trick as in rmdir().
++ * e) conversion from fhandle to dentry may come in the wrong moment - when
++ * we are removing the target. Solution: we will have to grab ->i_mutex
++ * in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on
++ * ->i_mutex on parents, which works but leads to some truly excessive
++ * locking].
++ */
++static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry)
++{
++ int error = 0;
++ struct inode *target;
++
++ /*
++ * If we are going to change the parent - check write permissions,
++ * we'll need to flip '..'.
++ */
++ if (new_dir != old_dir) {
++ error = inode_permission(old_dentry->d_inode, MAY_WRITE);
++ if (error)
++ return error;
++ }
++
++ error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
++ if (error)
++ return error;
++
++ target = new_dentry->d_inode;
++ if (target)
++ mutex_lock(&target->i_mutex);
++ if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
++ error = -EBUSY;
++ else {
++ if (target)
++ dentry_unhash(new_dentry);
++ error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
++ }
++ if (target) {
++ if (!error) {
++ target->i_flags |= S_DEAD;
++ dont_mount(new_dentry);
++ }
++ mutex_unlock(&target->i_mutex);
++ if (d_unhashed(new_dentry))
++ d_rehash(new_dentry);
++ dput(new_dentry);
++ }
++ if (!error)
++ if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
++ d_move(old_dentry,new_dentry);
++ return error;
++}
++
++static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry)
++{
++ struct inode *target;
++ int error;
++
++ error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
++ if (error)
++ return error;
++
++ dget(new_dentry);
++ target = new_dentry->d_inode;
++ if (target)
++ mutex_lock(&target->i_mutex);
++ if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
++ error = -EBUSY;
++ else
++ error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
++ if (!error) {
++ if (target)
++ dont_mount(new_dentry);
++ if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
++ d_move(old_dentry, new_dentry);
++ }
++ if (target)
++ mutex_unlock(&target->i_mutex);
++ dput(new_dentry);
++ return error;
++}
++
++int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry)
++{
++ int error;
++ int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
++ const unsigned char *old_name;
++
++ if (old_dentry->d_inode == new_dentry->d_inode)
++ return 0;
++
++ error = may_delete(old_dir, old_dentry, is_dir);
++ if (error)
++ return error;
++
++ if (!new_dentry->d_inode)
++ error = may_create(new_dir, new_dentry);
++ else
++ error = may_delete(new_dir, new_dentry, is_dir);
++ if (error)
++ return error;
++
++ if (!old_dir->i_op->rename)
++ return -EPERM;
++
++ old_name = fsnotify_oldname_init(old_dentry->d_name.name);
++
++ if (is_dir)
++ error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
++ else
++ error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
++ if (!error)
++ fsnotify_move(old_dir, new_dir, old_name, is_dir,
++ new_dentry->d_inode, old_dentry);
++ fsnotify_oldname_free(old_name);
++
++ return error;
++}
++
++SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
++ int, newdfd, const char __user *, newname)
++{
++ struct dentry *old_dir, *new_dir;
++ struct dentry *old_dentry, *new_dentry;
++ struct dentry *trap;
++ struct nameidata oldnd, newnd;
++ char *from;
++ char *to;
++ int error;
++
++ error = user_path_parent(olddfd, oldname, &oldnd, &from);
++ if (error)
++ goto exit;
++
++ error = user_path_parent(newdfd, newname, &newnd, &to);
++ if (error)
++ goto exit1;
++
++ error = -EXDEV;
++ if (oldnd.path.mnt != newnd.path.mnt)
++ goto exit2;
++
++ old_dir = oldnd.path.dentry;
++ error = -EBUSY;
++ if (oldnd.last_type != LAST_NORM)
++ goto exit2;
++
++ new_dir = newnd.path.dentry;
++ if (newnd.last_type != LAST_NORM)
++ goto exit2;
++
++ oldnd.flags &= ~LOOKUP_PARENT;
++ newnd.flags &= ~LOOKUP_PARENT;
++ newnd.flags |= LOOKUP_RENAME_TARGET;
++
++ trap = lock_rename(new_dir, old_dir);
++
++ old_dentry = lookup_hash(&oldnd);
++ error = PTR_ERR(old_dentry);
++ if (IS_ERR(old_dentry))
++ goto exit3;
++ /* source must exist */
++ error = -ENOENT;
++ if (!old_dentry->d_inode)
++ goto exit4;
++ /* unless the source is a directory trailing slashes give -ENOTDIR */
++ if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
++ error = -ENOTDIR;
++ if (oldnd.last.name[oldnd.last.len])
++ goto exit4;
++ if (newnd.last.name[newnd.last.len])
++ goto exit4;
++ }
++ /* source should not be ancestor of target */
++ error = -EINVAL;
++ if (old_dentry == trap)
++ goto exit4;
++ new_dentry = lookup_hash(&newnd);
++ error = PTR_ERR(new_dentry);
++ if (IS_ERR(new_dentry))
++ goto exit4;
++ /* target should not be an ancestor of source */
++ error = -ENOTEMPTY;
++ if (new_dentry == trap)
++ goto exit5;
++
++ error = mnt_want_write(oldnd.path.mnt);
++ if (error)
++ goto exit5;
++ error = security_path_rename(&oldnd.path, old_dentry,
++ &newnd.path, new_dentry);
++ if (error)
++ goto exit6;
++ error = vfs_rename(old_dir->d_inode, old_dentry,
++ new_dir->d_inode, new_dentry);
++exit6:
++ mnt_drop_write(oldnd.path.mnt);
++exit5:
++ dput(new_dentry);
++exit4:
++ dput(old_dentry);
++exit3:
++ unlock_rename(new_dir, old_dir);
++exit2:
++ path_put(&newnd.path);
++ putname(to);
++exit1:
++ path_put(&oldnd.path);
++ putname(from);
++exit:
++ return error;
++}
++
++SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname)
++{
++ return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname);
++}
++
++int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link)
++{
++ int len;
++
++ len = PTR_ERR(link);
++ if (IS_ERR(link))
++ goto out;
++
++ len = strlen(link);
++ if (len > (unsigned) buflen)
++ len = buflen;
++ if (copy_to_user(buffer, link, len))
++ len = -EFAULT;
++out:
++ return len;
++}
++
++/*
++ * A helper for ->readlink(). This should be used *ONLY* for symlinks that
++ * have ->follow_link() touching nd only in nd_set_link(). Using (or not
++ * using) it for any given inode is up to filesystem.
++ */
++int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
++{
++ struct nameidata nd;
++ void *cookie;
++ int res;
++
++ nd.depth = 0;
++ cookie = dentry->d_inode->i_op->follow_link(dentry, &nd);
++ if (IS_ERR(cookie))
++ return PTR_ERR(cookie);
++
++ res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd));
++ if (dentry->d_inode->i_op->put_link)
++ dentry->d_inode->i_op->put_link(dentry, &nd, cookie);
++ return res;
++}
++
++int vfs_follow_link(struct nameidata *nd, const char *link)
++{
++ return __vfs_follow_link(nd, link);
++}
++
++/* get the link contents into pagecache */
++static char *page_getlink(struct dentry * dentry, struct page **ppage)
++{
++ char *kaddr;
++ struct page *page;
++ struct address_space *mapping = dentry->d_inode->i_mapping;
++ page = read_mapping_page(mapping, 0, NULL);
++ if (IS_ERR(page))
++ return (char*)page;
++ *ppage = page;
++ kaddr = kmap(page);
++ nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1);
++ return kaddr;
++}
++
++int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
++{
++ struct page *page = NULL;
++ char *s = page_getlink(dentry, &page);
++ int res = vfs_readlink(dentry,buffer,buflen,s);
++ if (page) {
++ kunmap(page);
++ page_cache_release(page);
++ }
++ return res;
++}
++
++void *page_follow_link_light(struct dentry *dentry, struct nameidata *nd)
++{
++ struct page *page = NULL;
++ nd_set_link(nd, page_getlink(dentry, &page));
++ return page;
++}
++
++void page_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
++{
++ struct page *page = cookie;
++
++ if (page) {
++ kunmap(page);
++ page_cache_release(page);
++ }
++}
++
++/*
++ * The nofs argument instructs pagecache_write_begin to pass AOP_FLAG_NOFS
++ */
++int __page_symlink(struct inode *inode, const char *symname, int len, int nofs)
++{
++ struct address_space *mapping = inode->i_mapping;
++ struct page *page;
++ void *fsdata;
++ int err;
++ char *kaddr;
++ unsigned int flags = AOP_FLAG_UNINTERRUPTIBLE;
++ if (nofs)
++ flags |= AOP_FLAG_NOFS;
++
++retry:
++ err = pagecache_write_begin(NULL, mapping, 0, len-1,
++ flags, &page, &fsdata);
++ if (err)
++ goto fail;
++
++ kaddr = kmap_atomic(page, KM_USER0);
++ memcpy(kaddr, symname, len-1);
++ kunmap_atomic(kaddr, KM_USER0);
++
++ err = pagecache_write_end(NULL, mapping, 0, len-1, len-1,
++ page, fsdata);
++ if (err < 0)
++ goto fail;
++ if (err < len-1)
++ goto retry;
++
++ mark_inode_dirty(inode);
++ return 0;
++fail:
++ return err;
++}
++
++int page_symlink(struct inode *inode, const char *symname, int len)
++{
++ return __page_symlink(inode, symname, len,
++ !(mapping_gfp_mask(inode->i_mapping) & __GFP_FS));
++}
++
++const struct inode_operations page_symlink_inode_operations = {
++ .readlink = generic_readlink,
++ .follow_link = page_follow_link_light,
++ .put_link = page_put_link,
++};
++
++EXPORT_SYMBOL(user_path_at);
++EXPORT_SYMBOL(follow_down);
++EXPORT_SYMBOL(follow_up);
++EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
++EXPORT_SYMBOL(getname);
++EXPORT_SYMBOL(lock_rename);
++EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(page_follow_link_light);
++EXPORT_SYMBOL(page_put_link);
++EXPORT_SYMBOL(page_readlink);
++EXPORT_SYMBOL(__page_symlink);
++EXPORT_SYMBOL(page_symlink);
++EXPORT_SYMBOL(page_symlink_inode_operations);
++EXPORT_SYMBOL(path_lookup);
++EXPORT_SYMBOL(kern_path);
++EXPORT_SYMBOL(vfs_path_lookup);
++EXPORT_SYMBOL(inode_permission);
++EXPORT_SYMBOL(file_permission);
++EXPORT_SYMBOL(unlock_rename);
++EXPORT_SYMBOL(vfs_create);
++EXPORT_SYMBOL(vfs_follow_link);
++EXPORT_SYMBOL(vfs_link);
++EXPORT_SYMBOL(vfs_mkdir);
++EXPORT_SYMBOL(vfs_mknod);
++EXPORT_SYMBOL(generic_permission);
++EXPORT_SYMBOL(vfs_readlink);
++EXPORT_SYMBOL(vfs_rename);
++EXPORT_SYMBOL(vfs_rmdir);
++EXPORT_SYMBOL(vfs_symlink);
++EXPORT_SYMBOL(vfs_unlink);
++EXPORT_SYMBOL(dentry_unhash);
++EXPORT_SYMBOL(generic_readlink);
+diff -Nur linux-2.6.36.orig/fs/namespace.c linux-2.6.36/fs/namespace.c
+--- linux-2.6.36.orig/fs/namespace.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/fs/namespace.c 2011-01-10 19:52:38.000000000 +0100
+@@ -1322,6 +1322,7 @@
+ }
+ return 0;
+ }
++EXPORT_SYMBOL(iterate_mounts);
+
+ static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end)
+ {
+diff -Nur linux-2.6.36.orig/fs/notify/group.c linux-2.6.36/fs/notify/group.c
+--- linux-2.6.36.orig/fs/notify/group.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/fs/notify/group.c 2011-01-10 19:52:38.000000000 +0100
+@@ -22,6 +22,7 @@
+ #include <linux/srcu.h>
+ #include <linux/rculist.h>
+ #include <linux/wait.h>
++#include <linux/module.h>
+
+ #include <linux/fsnotify_backend.h>
+ #include "fsnotify.h"
+@@ -70,6 +71,7 @@
+ if (atomic_dec_and_test(&group->refcnt))
+ fsnotify_destroy_group(group);
+ }
++EXPORT_SYMBOL(fsnotify_put_group);
+
+ /*
+ * Create a new fsnotify_group and hold a reference for the group returned.
+@@ -102,3 +104,4 @@
+
+ return group;
+ }
++EXPORT_SYMBOL(fsnotify_alloc_group);
+diff -Nur linux-2.6.36.orig/fs/notify/mark.c linux-2.6.36/fs/notify/mark.c
+--- linux-2.6.36.orig/fs/notify/mark.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/fs/notify/mark.c 2011-01-10 19:52:38.000000000 +0100
+@@ -113,6 +113,7 @@
+ if (atomic_dec_and_test(&mark->refcnt))
+ mark->free_mark(mark);
+ }
++EXPORT_SYMBOL(fsnotify_put_mark);
+
+ /*
+ * Any time a mark is getting freed we end up here.
+@@ -190,6 +191,7 @@
+ if (unlikely(atomic_dec_and_test(&group->num_marks)))
+ fsnotify_final_destroy_group(group);
+ }
++EXPORT_SYMBOL(fsnotify_destroy_mark);
+
+ void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask)
+ {
+@@ -277,6 +279,7 @@
+
+ return ret;
+ }
++EXPORT_SYMBOL(fsnotify_add_mark);
+
+ /*
+ * clear any marks in a group in which mark->flags & flags is true
+@@ -332,6 +335,7 @@
+ atomic_set(&mark->refcnt, 1);
+ mark->free_mark = free_mark;
+ }
++EXPORT_SYMBOL(fsnotify_init_mark);
+
+ static int fsnotify_mark_destroy(void *ignored)
+ {
+diff -Nur linux-2.6.36.orig/fs/open.c linux-2.6.36/fs/open.c
+--- linux-2.6.36.orig/fs/open.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/fs/open.c 2011-01-10 19:52:38.000000000 +0100
+@@ -60,6 +60,7 @@
+ mutex_unlock(&dentry->d_inode->i_mutex);
+ return ret;
+ }
++EXPORT_SYMBOL(do_truncate);
+
+ static long do_sys_truncate(const char __user *pathname, loff_t length)
+ {
+diff -Nur linux-2.6.36.orig/fs/splice.c linux-2.6.36/fs/splice.c
+--- linux-2.6.36.orig/fs/splice.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/fs/splice.c 2011-01-10 19:52:38.000000000 +0100
+@@ -1092,8 +1092,8 @@
+ /*
+ * Attempt to initiate a splice from pipe to file.
+ */
+-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+- loff_t *ppos, size_t len, unsigned int flags)
++long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
+ {
+ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
+ loff_t *, size_t, unsigned int);
+@@ -1116,13 +1116,14 @@
+
+ return splice_write(pipe, out, ppos, len, flags);
+ }
++EXPORT_SYMBOL(do_splice_from);
+
+ /*
+ * Attempt to initiate a splice from a file to a pipe.
+ */
+-static long do_splice_to(struct file *in, loff_t *ppos,
+- struct pipe_inode_info *pipe, size_t len,
+- unsigned int flags)
++long do_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
+ {
+ ssize_t (*splice_read)(struct file *, loff_t *,
+ struct pipe_inode_info *, size_t, unsigned int);
+@@ -1142,6 +1143,7 @@
+
+ return splice_read(in, ppos, pipe, len, flags);
+ }
++EXPORT_SYMBOL(do_splice_to);
+
+ /**
+ * splice_direct_to_actor - splices data directly between two non-pipes
+diff -Nur linux-2.6.36.orig/fs/splice.c.orig linux-2.6.36/fs/splice.c.orig
+--- linux-2.6.36.orig/fs/splice.c.orig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/splice.c.orig 2011-01-10 19:52:38.000000000 +0100
+@@ -0,0 +1,2076 @@
++/*
++ * "splice": joining two ropes together by interweaving their strands.
++ *
++ * This is the "extended pipe" functionality, where a pipe is used as
++ * an arbitrary in-memory buffer. Think of a pipe as a small kernel
++ * buffer that you can use to transfer data from one end to the other.
++ *
++ * The traditional unix read/write is extended with a "splice()" operation
++ * that transfers data buffers to or from a pipe buffer.
++ *
++ * Named by Larry McVoy, original implementation from Linus, extended by
++ * Jens to support splicing to files, network, direct splicing, etc and
++ * fixing lots of bugs.
++ *
++ * Copyright (C) 2005-2006 Jens Axboe <axboe@kernel.dk>
++ * Copyright (C) 2005-2006 Linus Torvalds <torvalds@osdl.org>
++ * Copyright (C) 2006 Ingo Molnar <mingo@elte.hu>
++ *
++ */
++#include <linux/fs.h>
++#include <linux/file.h>
++#include <linux/pagemap.h>
++#include <linux/splice.h>
++#include <linux/memcontrol.h>
++#include <linux/mm_inline.h>
++#include <linux/swap.h>
++#include <linux/writeback.h>
++#include <linux/buffer_head.h>
++#include <linux/module.h>
++#include <linux/syscalls.h>
++#include <linux/uio.h>
++#include <linux/security.h>
++#include <linux/gfp.h>
++
++/*
++ * Attempt to steal a page from a pipe buffer. This should perhaps go into
++ * a vm helper function, it's already simplified quite a bit by the
++ * addition of remove_mapping(). If success is returned, the caller may
++ * attempt to reuse this page for another destination.
++ */
++static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe,
++ struct pipe_buffer *buf)
++{
++ struct page *page = buf->page;
++ struct address_space *mapping;
++
++ lock_page(page);
++
++ mapping = page_mapping(page);
++ if (mapping) {
++ WARN_ON(!PageUptodate(page));
++
++ /*
++ * At least for ext2 with nobh option, we need to wait on
++ * writeback completing on this page, since we'll remove it
++ * from the pagecache. Otherwise truncate wont wait on the
++ * page, allowing the disk blocks to be reused by someone else
++ * before we actually wrote our data to them. fs corruption
++ * ensues.
++ */
++ wait_on_page_writeback(page);
++
++ if (page_has_private(page) &&
++ !try_to_release_page(page, GFP_KERNEL))
++ goto out_unlock;
++
++ /*
++ * If we succeeded in removing the mapping, set LRU flag
++ * and return good.
++ */
++ if (remove_mapping(mapping, page)) {
++ buf->flags |= PIPE_BUF_FLAG_LRU;
++ return 0;
++ }
++ }
++
++ /*
++ * Raced with truncate or failed to remove page from current
++ * address space, unlock and return failure.
++ */
++out_unlock:
++ unlock_page(page);
++ return 1;
++}
++
++static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe,
++ struct pipe_buffer *buf)
++{
++ page_cache_release(buf->page);
++ buf->flags &= ~PIPE_BUF_FLAG_LRU;
++}
++
++/*
++ * Check whether the contents of buf is OK to access. Since the content
++ * is a page cache page, IO may be in flight.
++ */
++static int page_cache_pipe_buf_confirm(struct pipe_inode_info *pipe,
++ struct pipe_buffer *buf)
++{
++ struct page *page = buf->page;
++ int err;
++
++ if (!PageUptodate(page)) {
++ lock_page(page);
++
++ /*
++ * Page got truncated/unhashed. This will cause a 0-byte
++ * splice, if this is the first page.
++ */
++ if (!page->mapping) {
++ err = -ENODATA;
++ goto error;
++ }
++
++ /*
++ * Uh oh, read-error from disk.
++ */
++ if (!PageUptodate(page)) {
++ err = -EIO;
++ goto error;
++ }
++
++ /*
++ * Page is ok afterall, we are done.
++ */
++ unlock_page(page);
++ }
++
++ return 0;
++error:
++ unlock_page(page);
++ return err;
++}
++
++static const struct pipe_buf_operations page_cache_pipe_buf_ops = {
++ .can_merge = 0,
++ .map = generic_pipe_buf_map,
++ .unmap = generic_pipe_buf_unmap,
++ .confirm = page_cache_pipe_buf_confirm,
++ .release = page_cache_pipe_buf_release,
++ .steal = page_cache_pipe_buf_steal,
++ .get = generic_pipe_buf_get,
++};
++
++static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe,
++ struct pipe_buffer *buf)
++{
++ if (!(buf->flags & PIPE_BUF_FLAG_GIFT))
++ return 1;
++
++ buf->flags |= PIPE_BUF_FLAG_LRU;
++ return generic_pipe_buf_steal(pipe, buf);
++}
++
++static const struct pipe_buf_operations user_page_pipe_buf_ops = {
++ .can_merge = 0,
++ .map = generic_pipe_buf_map,
++ .unmap = generic_pipe_buf_unmap,
++ .confirm = generic_pipe_buf_confirm,
++ .release = page_cache_pipe_buf_release,
++ .steal = user_page_pipe_buf_steal,
++ .get = generic_pipe_buf_get,
++};
++
++/**
++ * splice_to_pipe - fill passed data into a pipe
++ * @pipe: pipe to fill
++ * @spd: data to fill
++ *
++ * Description:
++ * @spd contains a map of pages and len/offset tuples, along with
++ * the struct pipe_buf_operations associated with these pages. This
++ * function will link that data to the pipe.
++ *
++ */
++ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
++ struct splice_pipe_desc *spd)
++{
++ unsigned int spd_pages = spd->nr_pages;
++ int ret, do_wakeup, page_nr;
++
++ ret = 0;
++ do_wakeup = 0;
++ page_nr = 0;
++
++ pipe_lock(pipe);
++
++ for (;;) {
++ if (!pipe->readers) {
++ send_sig(SIGPIPE, current, 0);
++ if (!ret)
++ ret = -EPIPE;
++ break;
++ }
++
++ if (pipe->nrbufs < pipe->buffers) {
++ int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
++ struct pipe_buffer *buf = pipe->bufs + newbuf;
++
++ buf->page = spd->pages[page_nr];
++ buf->offset = spd->partial[page_nr].offset;
++ buf->len = spd->partial[page_nr].len;
++ buf->private = spd->partial[page_nr].private;
++ buf->ops = spd->ops;
++ if (spd->flags & SPLICE_F_GIFT)
++ buf->flags |= PIPE_BUF_FLAG_GIFT;
++
++ pipe->nrbufs++;
++ page_nr++;
++ ret += buf->len;
++
++ if (pipe->inode)
++ do_wakeup = 1;
++
++ if (!--spd->nr_pages)
++ break;
++ if (pipe->nrbufs < pipe->buffers)
++ continue;
++
++ break;
++ }
++
++ if (spd->flags & SPLICE_F_NONBLOCK) {
++ if (!ret)
++ ret = -EAGAIN;
++ break;
++ }
++
++ if (signal_pending(current)) {
++ if (!ret)
++ ret = -ERESTARTSYS;
++ break;
++ }
++
++ if (do_wakeup) {
++ smp_mb();
++ if (waitqueue_active(&pipe->wait))
++ wake_up_interruptible_sync(&pipe->wait);
++ kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
++ do_wakeup = 0;
++ }
++
++ pipe->waiting_writers++;
++ pipe_wait(pipe);
++ pipe->waiting_writers--;
++ }
++
++ pipe_unlock(pipe);
++
++ if (do_wakeup) {
++ smp_mb();
++ if (waitqueue_active(&pipe->wait))
++ wake_up_interruptible(&pipe->wait);
++ kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
++ }
++
++ while (page_nr < spd_pages)
++ spd->spd_release(spd, page_nr++);
++
++ return ret;
++}
++
++static void spd_release_page(struct splice_pipe_desc *spd, unsigned int i)
++{
++ page_cache_release(spd->pages[i]);
++}
++
++/*
++ * Check if we need to grow the arrays holding pages and partial page
++ * descriptions.
++ */
++int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
++{
++ if (pipe->buffers <= PIPE_DEF_BUFFERS)
++ return 0;
++
++ spd->pages = kmalloc(pipe->buffers * sizeof(struct page *), GFP_KERNEL);
++ spd->partial = kmalloc(pipe->buffers * sizeof(struct partial_page), GFP_KERNEL);
++
++ if (spd->pages && spd->partial)
++ return 0;
++
++ kfree(spd->pages);
++ kfree(spd->partial);
++ return -ENOMEM;
++}
++
++void splice_shrink_spd(struct pipe_inode_info *pipe,
++ struct splice_pipe_desc *spd)
++{
++ if (pipe->buffers <= PIPE_DEF_BUFFERS)
++ return;
++
++ kfree(spd->pages);
++ kfree(spd->partial);
++}
++
++static int
++__generic_file_splice_read(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ struct address_space *mapping = in->f_mapping;
++ unsigned int loff, nr_pages, req_pages;
++ struct page *pages[PIPE_DEF_BUFFERS];
++ struct partial_page partial[PIPE_DEF_BUFFERS];
++ struct page *page;
++ pgoff_t index, end_index;
++ loff_t isize;
++ int error, page_nr;
++ struct splice_pipe_desc spd = {
++ .pages = pages,
++ .partial = partial,
++ .flags = flags,
++ .ops = &page_cache_pipe_buf_ops,
++ .spd_release = spd_release_page,
++ };
++
++ if (splice_grow_spd(pipe, &spd))
++ return -ENOMEM;
++
++ index = *ppos >> PAGE_CACHE_SHIFT;
++ loff = *ppos & ~PAGE_CACHE_MASK;
++ req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
++ nr_pages = min(req_pages, pipe->buffers);
++
++ /*
++ * Lookup the (hopefully) full range of pages we need.
++ */
++ spd.nr_pages = find_get_pages_contig(mapping, index, nr_pages, spd.pages);
++ index += spd.nr_pages;
++
++ /*
++ * If find_get_pages_contig() returned fewer pages than we needed,
++ * readahead/allocate the rest and fill in the holes.
++ */
++ if (spd.nr_pages < nr_pages)
++ page_cache_sync_readahead(mapping, &in->f_ra, in,
++ index, req_pages - spd.nr_pages);
++
++ error = 0;
++ while (spd.nr_pages < nr_pages) {
++ /*
++ * Page could be there, find_get_pages_contig() breaks on
++ * the first hole.
++ */
++ page = find_get_page(mapping, index);
++ if (!page) {
++ /*
++ * page didn't exist, allocate one.
++ */
++ page = page_cache_alloc_cold(mapping);
++ if (!page)
++ break;
++
++ error = add_to_page_cache_lru(page, mapping, index,
++ GFP_KERNEL);
++ if (unlikely(error)) {
++ page_cache_release(page);
++ if (error == -EEXIST)
++ continue;
++ break;
++ }
++ /*
++ * add_to_page_cache() locks the page, unlock it
++ * to avoid convoluting the logic below even more.
++ */
++ unlock_page(page);
++ }
++
++ spd.pages[spd.nr_pages++] = page;
++ index++;
++ }
++
++ /*
++ * Now loop over the map and see if we need to start IO on any
++ * pages, fill in the partial map, etc.
++ */
++ index = *ppos >> PAGE_CACHE_SHIFT;
++ nr_pages = spd.nr_pages;
++ spd.nr_pages = 0;
++ for (page_nr = 0; page_nr < nr_pages; page_nr++) {
++ unsigned int this_len;
++
++ if (!len)
++ break;
++
++ /*
++ * this_len is the max we'll use from this page
++ */
++ this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff);
++ page = spd.pages[page_nr];
++
++ if (PageReadahead(page))
++ page_cache_async_readahead(mapping, &in->f_ra, in,
++ page, index, req_pages - page_nr);
++
++ /*
++ * If the page isn't uptodate, we may need to start io on it
++ */
++ if (!PageUptodate(page)) {
++ lock_page(page);
++
++ /*
++ * Page was truncated, or invalidated by the
++ * filesystem. Redo the find/create, but this time the
++ * page is kept locked, so there's no chance of another
++ * race with truncate/invalidate.
++ */
++ if (!page->mapping) {
++ unlock_page(page);
++ page = find_or_create_page(mapping, index,
++ mapping_gfp_mask(mapping));
++
++ if (!page) {
++ error = -ENOMEM;
++ break;
++ }
++ page_cache_release(spd.pages[page_nr]);
++ spd.pages[page_nr] = page;
++ }
++ /*
++ * page was already under io and is now done, great
++ */
++ if (PageUptodate(page)) {
++ unlock_page(page);
++ goto fill_it;
++ }
++
++ /*
++ * need to read in the page
++ */
++ error = mapping->a_ops->readpage(in, page);
++ if (unlikely(error)) {
++ /*
++ * We really should re-lookup the page here,
++ * but it complicates things a lot. Instead
++ * lets just do what we already stored, and
++ * we'll get it the next time we are called.
++ */
++ if (error == AOP_TRUNCATED_PAGE)
++ error = 0;
++
++ break;
++ }
++ }
++fill_it:
++ /*
++ * i_size must be checked after PageUptodate.
++ */
++ isize = i_size_read(mapping->host);
++ end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
++ if (unlikely(!isize || index > end_index))
++ break;
++
++ /*
++ * if this is the last page, see if we need to shrink
++ * the length and stop
++ */
++ if (end_index == index) {
++ unsigned int plen;
++
++ /*
++ * max good bytes in this page
++ */
++ plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
++ if (plen <= loff)
++ break;
++
++ /*
++ * force quit after adding this page
++ */
++ this_len = min(this_len, plen - loff);
++ len = this_len;
++ }
++
++ spd.partial[page_nr].offset = loff;
++ spd.partial[page_nr].len = this_len;
++ len -= this_len;
++ loff = 0;
++ spd.nr_pages++;
++ index++;
++ }
++
++ /*
++ * Release any pages at the end, if we quit early. 'page_nr' is how far
++ * we got, 'nr_pages' is how many pages are in the map.
++ */
++ while (page_nr < nr_pages)
++ page_cache_release(spd.pages[page_nr++]);
++ in->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
++
++ if (spd.nr_pages)
++ error = splice_to_pipe(pipe, &spd);
++
++ splice_shrink_spd(pipe, &spd);
++ return error;
++}
++
++/**
++ * generic_file_splice_read - splice data from file to a pipe
++ * @in: file to splice from
++ * @ppos: position in @in
++ * @pipe: pipe to splice to
++ * @len: number of bytes to splice
++ * @flags: splice modifier flags
++ *
++ * Description:
++ * Will read pages from given file and fill them into a pipe. Can be
++ * used as long as the address_space operations for the source implements
++ * a readpage() hook.
++ *
++ */
++ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ loff_t isize, left;
++ int ret;
++
++ isize = i_size_read(in->f_mapping->host);
++ if (unlikely(*ppos >= isize))
++ return 0;
++
++ left = isize - *ppos;
++ if (unlikely(left < len))
++ len = left;
++
++ ret = __generic_file_splice_read(in, ppos, pipe, len, flags);
++ if (ret > 0) {
++ *ppos += ret;
++ file_accessed(in);
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL(generic_file_splice_read);
++
++static const struct pipe_buf_operations default_pipe_buf_ops = {
++ .can_merge = 0,
++ .map = generic_pipe_buf_map,
++ .unmap = generic_pipe_buf_unmap,
++ .confirm = generic_pipe_buf_confirm,
++ .release = generic_pipe_buf_release,
++ .steal = generic_pipe_buf_steal,
++ .get = generic_pipe_buf_get,
++};
++
++static ssize_t kernel_readv(struct file *file, const struct iovec *vec,
++ unsigned long vlen, loff_t offset)
++{
++ mm_segment_t old_fs;
++ loff_t pos = offset;
++ ssize_t res;
++
++ old_fs = get_fs();
++ set_fs(get_ds());
++ /* The cast to a user pointer is valid due to the set_fs() */
++ res = vfs_readv(file, (const struct iovec __user *)vec, vlen, &pos);
++ set_fs(old_fs);
++
++ return res;
++}
++
++static ssize_t kernel_write(struct file *file, const char *buf, size_t count,
++ loff_t pos)
++{
++ mm_segment_t old_fs;
++ ssize_t res;
++
++ old_fs = get_fs();
++ set_fs(get_ds());
++ /* The cast to a user pointer is valid due to the set_fs() */
++ res = vfs_write(file, (const char __user *)buf, count, &pos);
++ set_fs(old_fs);
++
++ return res;
++}
++
++ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ unsigned int nr_pages;
++ unsigned int nr_freed;
++ size_t offset;
++ struct page *pages[PIPE_DEF_BUFFERS];
++ struct partial_page partial[PIPE_DEF_BUFFERS];
++ struct iovec *vec, __vec[PIPE_DEF_BUFFERS];
++ ssize_t res;
++ size_t this_len;
++ int error;
++ int i;
++ struct splice_pipe_desc spd = {
++ .pages = pages,
++ .partial = partial,
++ .flags = flags,
++ .ops = &default_pipe_buf_ops,
++ .spd_release = spd_release_page,
++ };
++
++ if (splice_grow_spd(pipe, &spd))
++ return -ENOMEM;
++
++ res = -ENOMEM;
++ vec = __vec;
++ if (pipe->buffers > PIPE_DEF_BUFFERS) {
++ vec = kmalloc(pipe->buffers * sizeof(struct iovec), GFP_KERNEL);
++ if (!vec)
++ goto shrink_ret;
++ }
++
++ offset = *ppos & ~PAGE_CACHE_MASK;
++ nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
++
++ for (i = 0; i < nr_pages && i < pipe->buffers && len; i++) {
++ struct page *page;
++
++ page = alloc_page(GFP_USER);
++ error = -ENOMEM;
++ if (!page)
++ goto err;
++
++ this_len = min_t(size_t, len, PAGE_CACHE_SIZE - offset);
++ vec[i].iov_base = (void __user *) page_address(page);
++ vec[i].iov_len = this_len;
++ spd.pages[i] = page;
++ spd.nr_pages++;
++ len -= this_len;
++ offset = 0;
++ }
++
++ res = kernel_readv(in, vec, spd.nr_pages, *ppos);
++ if (res < 0) {
++ error = res;
++ goto err;
++ }
++
++ error = 0;
++ if (!res)
++ goto err;
++
++ nr_freed = 0;
++ for (i = 0; i < spd.nr_pages; i++) {
++ this_len = min_t(size_t, vec[i].iov_len, res);
++ spd.partial[i].offset = 0;
++ spd.partial[i].len = this_len;
++ if (!this_len) {
++ __free_page(spd.pages[i]);
++ spd.pages[i] = NULL;
++ nr_freed++;
++ }
++ res -= this_len;
++ }
++ spd.nr_pages -= nr_freed;
++
++ res = splice_to_pipe(pipe, &spd);
++ if (res > 0)
++ *ppos += res;
++
++shrink_ret:
++ if (vec != __vec)
++ kfree(vec);
++ splice_shrink_spd(pipe, &spd);
++ return res;
++
++err:
++ for (i = 0; i < spd.nr_pages; i++)
++ __free_page(spd.pages[i]);
++
++ res = error;
++ goto shrink_ret;
++}
++EXPORT_SYMBOL(default_file_splice_read);
++
++/*
++ * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos'
++ * using sendpage(). Return the number of bytes sent.
++ */
++static int pipe_to_sendpage(struct pipe_inode_info *pipe,
++ struct pipe_buffer *buf, struct splice_desc *sd)
++{
++ struct file *file = sd->u.file;
++ loff_t pos = sd->pos;
++ int ret, more;
++
++ ret = buf->ops->confirm(pipe, buf);
++ if (!ret) {
++ more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
++ if (file->f_op && file->f_op->sendpage)
++ ret = file->f_op->sendpage(file, buf->page, buf->offset,
++ sd->len, &pos, more);
++ else
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++
++/*
++ * This is a little more tricky than the file -> pipe splicing. There are
++ * basically three cases:
++ *
++ * - Destination page already exists in the address space and there
++ * are users of it. For that case we have no other option that
++ * copying the data. Tough luck.
++ * - Destination page already exists in the address space, but there
++ * are no users of it. Make sure it's uptodate, then drop it. Fall
++ * through to last case.
++ * - Destination page does not exist, we can add the pipe page to
++ * the page cache and avoid the copy.
++ *
++ * If asked to move pages to the output file (SPLICE_F_MOVE is set in
++ * sd->flags), we attempt to migrate pages from the pipe to the output
++ * file address space page cache. This is possible if no one else has
++ * the pipe page referenced outside of the pipe and page cache. If
++ * SPLICE_F_MOVE isn't set, or we cannot move the page, we simply create
++ * a new page in the output file page cache and fill/dirty that.
++ */
++int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
++ struct splice_desc *sd)
++{
++ struct file *file = sd->u.file;
++ struct address_space *mapping = file->f_mapping;
++ unsigned int offset, this_len;
++ struct page *page;
++ void *fsdata;
++ int ret;
++
++ /*
++ * make sure the data in this buffer is uptodate
++ */
++ ret = buf->ops->confirm(pipe, buf);
++ if (unlikely(ret))
++ return ret;
++
++ offset = sd->pos & ~PAGE_CACHE_MASK;
++
++ this_len = sd->len;
++ if (this_len + offset > PAGE_CACHE_SIZE)
++ this_len = PAGE_CACHE_SIZE - offset;
++
++ ret = pagecache_write_begin(file, mapping, sd->pos, this_len,
++ AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata);
++ if (unlikely(ret))
++ goto out;
++
++ if (buf->page != page) {
++ /*
++ * Careful, ->map() uses KM_USER0!
++ */
++ char *src = buf->ops->map(pipe, buf, 1);
++ char *dst = kmap_atomic(page, KM_USER1);
++
++ memcpy(dst + offset, src + buf->offset, this_len);
++ flush_dcache_page(page);
++ kunmap_atomic(dst, KM_USER1);
++ buf->ops->unmap(pipe, buf, src);
++ }
++ ret = pagecache_write_end(file, mapping, sd->pos, this_len, this_len,
++ page, fsdata);
++out:
++ return ret;
++}
++EXPORT_SYMBOL(pipe_to_file);
++
++static void wakeup_pipe_writers(struct pipe_inode_info *pipe)
++{
++ smp_mb();
++ if (waitqueue_active(&pipe->wait))
++ wake_up_interruptible(&pipe->wait);
++ kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
++}
++
++/**
++ * splice_from_pipe_feed - feed available data from a pipe to a file
++ * @pipe: pipe to splice from
++ * @sd: information to @actor
++ * @actor: handler that splices the data
++ *
++ * Description:
++ * This function loops over the pipe and calls @actor to do the
++ * actual moving of a single struct pipe_buffer to the desired
++ * destination. It returns when there's no more buffers left in
++ * the pipe or if the requested number of bytes (@sd->total_len)
++ * have been copied. It returns a positive number (one) if the
++ * pipe needs to be filled with more data, zero if the required
++ * number of bytes have been copied and -errno on error.
++ *
++ * This, together with splice_from_pipe_{begin,end,next}, may be
++ * used to implement the functionality of __splice_from_pipe() when
++ * locking is required around copying the pipe buffers to the
++ * destination.
++ */
++int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd,
++ splice_actor *actor)
++{
++ int ret;
++
++ while (pipe->nrbufs) {
++ struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
++ const struct pipe_buf_operations *ops = buf->ops;
++
++ sd->len = buf->len;
++ if (sd->len > sd->total_len)
++ sd->len = sd->total_len;
++
++ ret = actor(pipe, buf, sd);
++ if (ret <= 0) {
++ if (ret == -ENODATA)
++ ret = 0;
++ return ret;
++ }
++ buf->offset += ret;
++ buf->len -= ret;
++
++ sd->num_spliced += ret;
++ sd->len -= ret;
++ sd->pos += ret;
++ sd->total_len -= ret;
++
++ if (!buf->len) {
++ buf->ops = NULL;
++ ops->release(pipe, buf);
++ pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1);
++ pipe->nrbufs--;
++ if (pipe->inode)
++ sd->need_wakeup = true;
++ }
++
++ if (!sd->total_len)
++ return 0;
++ }
++
++ return 1;
++}
++EXPORT_SYMBOL(splice_from_pipe_feed);
++
++/**
++ * splice_from_pipe_next - wait for some data to splice from
++ * @pipe: pipe to splice from
++ * @sd: information about the splice operation
++ *
++ * Description:
++ * This function will wait for some data and return a positive
++ * value (one) if pipe buffers are available. It will return zero
++ * or -errno if no more data needs to be spliced.
++ */
++int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd)
++{
++ while (!pipe->nrbufs) {
++ if (!pipe->writers)
++ return 0;
++
++ if (!pipe->waiting_writers && sd->num_spliced)
++ return 0;
++
++ if (sd->flags & SPLICE_F_NONBLOCK)
++ return -EAGAIN;
++
++ if (signal_pending(current))
++ return -ERESTARTSYS;
++
++ if (sd->need_wakeup) {
++ wakeup_pipe_writers(pipe);
++ sd->need_wakeup = false;
++ }
++
++ pipe_wait(pipe);
++ }
++
++ return 1;
++}
++EXPORT_SYMBOL(splice_from_pipe_next);
++
++/**
++ * splice_from_pipe_begin - start splicing from pipe
++ * @sd: information about the splice operation
++ *
++ * Description:
++ * This function should be called before a loop containing
++ * splice_from_pipe_next() and splice_from_pipe_feed() to
++ * initialize the necessary fields of @sd.
++ */
++void splice_from_pipe_begin(struct splice_desc *sd)
++{
++ sd->num_spliced = 0;
++ sd->need_wakeup = false;
++}
++EXPORT_SYMBOL(splice_from_pipe_begin);
++
++/**
++ * splice_from_pipe_end - finish splicing from pipe
++ * @pipe: pipe to splice from
++ * @sd: information about the splice operation
++ *
++ * Description:
++ * This function will wake up pipe writers if necessary. It should
++ * be called after a loop containing splice_from_pipe_next() and
++ * splice_from_pipe_feed().
++ */
++void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd)
++{
++ if (sd->need_wakeup)
++ wakeup_pipe_writers(pipe);
++}
++EXPORT_SYMBOL(splice_from_pipe_end);
++
++/**
++ * __splice_from_pipe - splice data from a pipe to given actor
++ * @pipe: pipe to splice from
++ * @sd: information to @actor
++ * @actor: handler that splices the data
++ *
++ * Description:
++ * This function does little more than loop over the pipe and call
++ * @actor to do the actual moving of a single struct pipe_buffer to
++ * the desired destination. See pipe_to_file, pipe_to_sendpage, or
++ * pipe_to_user.
++ *
++ */
++ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
++ splice_actor *actor)
++{
++ int ret;
++
++ splice_from_pipe_begin(sd);
++ do {
++ ret = splice_from_pipe_next(pipe, sd);
++ if (ret > 0)
++ ret = splice_from_pipe_feed(pipe, sd, actor);
++ } while (ret > 0);
++ splice_from_pipe_end(pipe, sd);
++
++ return sd->num_spliced ? sd->num_spliced : ret;
++}
++EXPORT_SYMBOL(__splice_from_pipe);
++
++/**
++ * splice_from_pipe - splice data from a pipe to a file
++ * @pipe: pipe to splice from
++ * @out: file to splice to
++ * @ppos: position in @out
++ * @len: how many bytes to splice
++ * @flags: splice modifier flags
++ * @actor: handler that splices the data
++ *
++ * Description:
++ * See __splice_from_pipe. This function locks the pipe inode,
++ * otherwise it's identical to __splice_from_pipe().
++ *
++ */
++ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags,
++ splice_actor *actor)
++{
++ ssize_t ret;
++ struct splice_desc sd = {
++ .total_len = len,
++ .flags = flags,
++ .pos = *ppos,
++ .u.file = out,
++ };
++
++ pipe_lock(pipe);
++ ret = __splice_from_pipe(pipe, &sd, actor);
++ pipe_unlock(pipe);
++
++ return ret;
++}
++
++/**
++ * generic_file_splice_write - splice data from a pipe to a file
++ * @pipe: pipe info
++ * @out: file to write to
++ * @ppos: position in @out
++ * @len: number of bytes to splice
++ * @flags: splice modifier flags
++ *
++ * Description:
++ * Will either move or copy pages (determined by @flags options) from
++ * the given pipe inode to the given file.
++ *
++ */
++ssize_t
++generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
++{
++ struct address_space *mapping = out->f_mapping;
++ struct inode *inode = mapping->host;
++ struct splice_desc sd = {
++ .total_len = len,
++ .flags = flags,
++ .pos = *ppos,
++ .u.file = out,
++ };
++ ssize_t ret;
++
++ pipe_lock(pipe);
++
++ splice_from_pipe_begin(&sd);
++ do {
++ ret = splice_from_pipe_next(pipe, &sd);
++ if (ret <= 0)
++ break;
++
++ mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
++ ret = file_remove_suid(out);
++ if (!ret) {
++ file_update_time(out);
++ ret = splice_from_pipe_feed(pipe, &sd, pipe_to_file);
++ }
++ mutex_unlock(&inode->i_mutex);
++ } while (ret > 0);
++ splice_from_pipe_end(pipe, &sd);
++
++ pipe_unlock(pipe);
++
++ if (sd.num_spliced)
++ ret = sd.num_spliced;
++
++ if (ret > 0) {
++ unsigned long nr_pages;
++ int err;
++
++ nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
++
++ err = generic_write_sync(out, *ppos, ret);
++ if (err)
++ ret = err;
++ else
++ *ppos += ret;
++ balance_dirty_pages_ratelimited_nr(mapping, nr_pages);
++ }
++
++ return ret;
++}
++
++EXPORT_SYMBOL(generic_file_splice_write);
++
++static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
++ struct splice_desc *sd)
++{
++ int ret;
++ void *data;
++
++ ret = buf->ops->confirm(pipe, buf);
++ if (ret)
++ return ret;
++
++ data = buf->ops->map(pipe, buf, 0);
++ ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos);
++ buf->ops->unmap(pipe, buf, data);
++
++ return ret;
++}
++
++static ssize_t default_file_splice_write(struct pipe_inode_info *pipe,
++ struct file *out, loff_t *ppos,
++ size_t len, unsigned int flags)
++{
++ ssize_t ret;
++
++ ret = splice_from_pipe(pipe, out, ppos, len, flags, write_pipe_buf);
++ if (ret > 0)
++ *ppos += ret;
++
++ return ret;
++}
++
++/**
++ * generic_splice_sendpage - splice data from a pipe to a socket
++ * @pipe: pipe to splice from
++ * @out: socket to write to
++ * @ppos: position in @out
++ * @len: number of bytes to splice
++ * @flags: splice modifier flags
++ *
++ * Description:
++ * Will send @len bytes from the pipe to a network socket. No data copying
++ * is involved.
++ *
++ */
++ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
++{
++ return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_sendpage);
++}
++
++EXPORT_SYMBOL(generic_splice_sendpage);
++
++/*
++ * Attempt to initiate a splice from pipe to file.
++ */
++static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
++{
++ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
++ loff_t *, size_t, unsigned int);
++ int ret;
++
++ if (unlikely(!(out->f_mode & FMODE_WRITE)))
++ return -EBADF;
++
++ if (unlikely(out->f_flags & O_APPEND))
++ return -EINVAL;
++
++ ret = rw_verify_area(WRITE, out, ppos, len);
++ if (unlikely(ret < 0))
++ return ret;
++
++ if (out->f_op && out->f_op->splice_write)
++ splice_write = out->f_op->splice_write;
++ else
++ splice_write = default_file_splice_write;
++
++ return splice_write(pipe, out, ppos, len, flags);
++}
++EXPORT_SYMBOL(do_splice_from);
++
++/*
++ * Attempt to initiate a splice from a file to a pipe.
++ */
++static long do_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ ssize_t (*splice_read)(struct file *, loff_t *,
++ struct pipe_inode_info *, size_t, unsigned int);
++ int ret;
++
++ if (unlikely(!(in->f_mode & FMODE_READ)))
++ return -EBADF;
++
++ ret = rw_verify_area(READ, in, ppos, len);
++ if (unlikely(ret < 0))
++ return ret;
++
++ if (in->f_op && in->f_op->splice_read)
++ splice_read = in->f_op->splice_read;
++ else
++ splice_read = default_file_splice_read;
++
++ return splice_read(in, ppos, pipe, len, flags);
++}
++EXPORT_SYMBOL(do_splice_to);
++
++/**
++ * splice_direct_to_actor - splices data directly between two non-pipes
++ * @in: file to splice from
++ * @sd: actor information on where to splice to
++ * @actor: handles the data splicing
++ *
++ * Description:
++ * This is a special case helper to splice directly between two
++ * points, without requiring an explicit pipe. Internally an allocated
++ * pipe is cached in the process, and reused during the lifetime of
++ * that process.
++ *
++ */
++ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
++ splice_direct_actor *actor)
++{
++ struct pipe_inode_info *pipe;
++ long ret, bytes;
++ umode_t i_mode;
++ size_t len;
++ int i, flags;
++
++ /*
++ * We require the input being a regular file, as we don't want to
++ * randomly drop data for eg socket -> socket splicing. Use the
++ * piped splicing for that!
++ */
++ i_mode = in->f_path.dentry->d_inode->i_mode;
++ if (unlikely(!S_ISREG(i_mode) && !S_ISBLK(i_mode)))
++ return -EINVAL;
++
++ /*
++ * neither in nor out is a pipe, setup an internal pipe attached to
++ * 'out' and transfer the wanted data from 'in' to 'out' through that
++ */
++ pipe = current->splice_pipe;
++ if (unlikely(!pipe)) {
++ pipe = alloc_pipe_info(NULL);
++ if (!pipe)
++ return -ENOMEM;
++
++ /*
++ * We don't have an immediate reader, but we'll read the stuff
++ * out of the pipe right after the splice_to_pipe(). So set
++ * PIPE_READERS appropriately.
++ */
++ pipe->readers = 1;
++
++ current->splice_pipe = pipe;
++ }
++
++ /*
++ * Do the splice.
++ */
++ ret = 0;
++ bytes = 0;
++ len = sd->total_len;
++ flags = sd->flags;
++
++ /*
++ * Don't block on output, we have to drain the direct pipe.
++ */
++ sd->flags &= ~SPLICE_F_NONBLOCK;
++
++ while (len) {
++ size_t read_len;
++ loff_t pos = sd->pos, prev_pos = pos;
++
++ ret = do_splice_to(in, &pos, pipe, len, flags);
++ if (unlikely(ret <= 0))
++ goto out_release;
++
++ read_len = ret;
++ sd->total_len = read_len;
++
++ /*
++ * NOTE: nonblocking mode only applies to the input. We
++ * must not do the output in nonblocking mode as then we
++ * could get stuck data in the internal pipe:
++ */
++ ret = actor(pipe, sd);
++ if (unlikely(ret <= 0)) {
++ sd->pos = prev_pos;
++ goto out_release;
++ }
++
++ bytes += ret;
++ len -= ret;
++ sd->pos = pos;
++
++ if (ret < read_len) {
++ sd->pos = prev_pos + ret;
++ goto out_release;
++ }
++ }
++
++done:
++ pipe->nrbufs = pipe->curbuf = 0;
++ file_accessed(in);
++ return bytes;
++
++out_release:
++ /*
++ * If we did an incomplete transfer we must release
++ * the pipe buffers in question:
++ */
++ for (i = 0; i < pipe->buffers; i++) {
++ struct pipe_buffer *buf = pipe->bufs + i;
++
++ if (buf->ops) {
++ buf->ops->release(pipe, buf);
++ buf->ops = NULL;
++ }
++ }
++
++ if (!bytes)
++ bytes = ret;
++
++ goto done;
++}
++EXPORT_SYMBOL(splice_direct_to_actor);
++
++static int direct_splice_actor(struct pipe_inode_info *pipe,
++ struct splice_desc *sd)
++{
++ struct file *file = sd->u.file;
++
++ return do_splice_from(pipe, file, &file->f_pos, sd->total_len,
++ sd->flags);
++}
++
++/**
++ * do_splice_direct - splices data directly between two files
++ * @in: file to splice from
++ * @ppos: input file offset
++ * @out: file to splice to
++ * @len: number of bytes to splice
++ * @flags: splice modifier flags
++ *
++ * Description:
++ * For use by do_sendfile(). splice can easily emulate sendfile, but
++ * doing it in the application would incur an extra system call
++ * (splice in + splice out, as compared to just sendfile()). So this helper
++ * can splice directly through a process-private pipe.
++ *
++ */
++long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
++ size_t len, unsigned int flags)
++{
++ struct splice_desc sd = {
++ .len = len,
++ .total_len = len,
++ .flags = flags,
++ .pos = *ppos,
++ .u.file = out,
++ };
++ long ret;
++
++ ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
++ if (ret > 0)
++ *ppos = sd.pos;
++
++ return ret;
++}
++
++static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
++ struct pipe_inode_info *opipe,
++ size_t len, unsigned int flags);
++/*
++ * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same
++ * location, so checking ->i_pipe is not enough to verify that this is a
++ * pipe.
++ */
++static inline struct pipe_inode_info *pipe_info(struct inode *inode)
++{
++ if (S_ISFIFO(inode->i_mode))
++ return inode->i_pipe;
++
++ return NULL;
++}
++
++/*
++ * Determine where to splice to/from.
++ */
++static long do_splice(struct file *in, loff_t __user *off_in,
++ struct file *out, loff_t __user *off_out,
++ size_t len, unsigned int flags)
++{
++ struct pipe_inode_info *ipipe;
++ struct pipe_inode_info *opipe;
++ loff_t offset, *off;
++ long ret;
++
++ ipipe = pipe_info(in->f_path.dentry->d_inode);
++ opipe = pipe_info(out->f_path.dentry->d_inode);
++
++ if (ipipe && opipe) {
++ if (off_in || off_out)
++ return -ESPIPE;
++
++ if (!(in->f_mode & FMODE_READ))
++ return -EBADF;
++
++ if (!(out->f_mode & FMODE_WRITE))
++ return -EBADF;
++
++ /* Splicing to self would be fun, but... */
++ if (ipipe == opipe)
++ return -EINVAL;
++
++ return splice_pipe_to_pipe(ipipe, opipe, len, flags);
++ }
++
++ if (ipipe) {
++ if (off_in)
++ return -ESPIPE;
++ if (off_out) {
++ if (!(out->f_mode & FMODE_PWRITE))
++ return -EINVAL;
++ if (copy_from_user(&offset, off_out, sizeof(loff_t)))
++ return -EFAULT;
++ off = &offset;
++ } else
++ off = &out->f_pos;
++
++ ret = do_splice_from(ipipe, out, off, len, flags);
++
++ if (off_out && copy_to_user(off_out, off, sizeof(loff_t)))
++ ret = -EFAULT;
++
++ return ret;
++ }
++
++ if (opipe) {
++ if (off_out)
++ return -ESPIPE;
++ if (off_in) {
++ if (!(in->f_mode & FMODE_PREAD))
++ return -EINVAL;
++ if (copy_from_user(&offset, off_in, sizeof(loff_t)))
++ return -EFAULT;
++ off = &offset;
++ } else
++ off = &in->f_pos;
++
++ ret = do_splice_to(in, off, opipe, len, flags);
++
++ if (off_in && copy_to_user(off_in, off, sizeof(loff_t)))
++ ret = -EFAULT;
++
++ return ret;
++ }
++
++ return -EINVAL;
++}
++
++/*
++ * Map an iov into an array of pages and offset/length tupples. With the
++ * partial_page structure, we can map several non-contiguous ranges into
++ * our ones pages[] map instead of splitting that operation into pieces.
++ * Could easily be exported as a generic helper for other users, in which
++ * case one would probably want to add a 'max_nr_pages' parameter as well.
++ */
++static int get_iovec_page_array(const struct iovec __user *iov,
++ unsigned int nr_vecs, struct page **pages,
++ struct partial_page *partial, int aligned,
++ unsigned int pipe_buffers)
++{
++ int buffers = 0, error = 0;
++
++ while (nr_vecs) {
++ unsigned long off, npages;
++ struct iovec entry;
++ void __user *base;
++ size_t len;
++ int i;
++
++ error = -EFAULT;
++ if (copy_from_user(&entry, iov, sizeof(entry)))
++ break;
++
++ base = entry.iov_base;
++ len = entry.iov_len;
++
++ /*
++ * Sanity check this iovec. 0 read succeeds.
++ */
++ error = 0;
++ if (unlikely(!len))
++ break;
++ error = -EFAULT;
++ if (!access_ok(VERIFY_READ, base, len))
++ break;
++
++ /*
++ * Get this base offset and number of pages, then map
++ * in the user pages.
++ */
++ off = (unsigned long) base & ~PAGE_MASK;
++
++ /*
++ * If asked for alignment, the offset must be zero and the
++ * length a multiple of the PAGE_SIZE.
++ */
++ error = -EINVAL;
++ if (aligned && (off || len & ~PAGE_MASK))
++ break;
++
++ npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
++ if (npages > pipe_buffers - buffers)
++ npages = pipe_buffers - buffers;
++
++ error = get_user_pages_fast((unsigned long)base, npages,
++ 0, &pages[buffers]);
++
++ if (unlikely(error <= 0))
++ break;
++
++ /*
++ * Fill this contiguous range into the partial page map.
++ */
++ for (i = 0; i < error; i++) {
++ const int plen = min_t(size_t, len, PAGE_SIZE - off);
++
++ partial[buffers].offset = off;
++ partial[buffers].len = plen;
++
++ off = 0;
++ len -= plen;
++ buffers++;
++ }
++
++ /*
++ * We didn't complete this iov, stop here since it probably
++ * means we have to move some of this into a pipe to
++ * be able to continue.
++ */
++ if (len)
++ break;
++
++ /*
++ * Don't continue if we mapped fewer pages than we asked for,
++ * or if we mapped the max number of pages that we have
++ * room for.
++ */
++ if (error < npages || buffers == pipe_buffers)
++ break;
++
++ nr_vecs--;
++ iov++;
++ }
++
++ if (buffers)
++ return buffers;
++
++ return error;
++}
++
++static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
++ struct splice_desc *sd)
++{
++ char *src;
++ int ret;
++
++ ret = buf->ops->confirm(pipe, buf);
++ if (unlikely(ret))
++ return ret;
++
++ /*
++ * See if we can use the atomic maps, by prefaulting in the
++ * pages and doing an atomic copy
++ */
++ if (!fault_in_pages_writeable(sd->u.userptr, sd->len)) {
++ src = buf->ops->map(pipe, buf, 1);
++ ret = __copy_to_user_inatomic(sd->u.userptr, src + buf->offset,
++ sd->len);
++ buf->ops->unmap(pipe, buf, src);
++ if (!ret) {
++ ret = sd->len;
++ goto out;
++ }
++ }
++
++ /*
++ * No dice, use slow non-atomic map and copy
++ */
++ src = buf->ops->map(pipe, buf, 0);
++
++ ret = sd->len;
++ if (copy_to_user(sd->u.userptr, src + buf->offset, sd->len))
++ ret = -EFAULT;
++
++ buf->ops->unmap(pipe, buf, src);
++out:
++ if (ret > 0)
++ sd->u.userptr += ret;
++ return ret;
++}
++
++/*
++ * For lack of a better implementation, implement vmsplice() to userspace
++ * as a simple copy of the pipes pages to the user iov.
++ */
++static long vmsplice_to_user(struct file *file, const struct iovec __user *iov,
++ unsigned long nr_segs, unsigned int flags)
++{
++ struct pipe_inode_info *pipe;
++ struct splice_desc sd;
++ ssize_t size;
++ int error;
++ long ret;
++
++ pipe = pipe_info(file->f_path.dentry->d_inode);
++ if (!pipe)
++ return -EBADF;
++
++ pipe_lock(pipe);
++
++ error = ret = 0;
++ while (nr_segs) {
++ void __user *base;
++ size_t len;
++
++ /*
++ * Get user address base and length for this iovec.
++ */
++ error = get_user(base, &iov->iov_base);
++ if (unlikely(error))
++ break;
++ error = get_user(len, &iov->iov_len);
++ if (unlikely(error))
++ break;
++
++ /*
++ * Sanity check this iovec. 0 read succeeds.
++ */
++ if (unlikely(!len))
++ break;
++ if (unlikely(!base)) {
++ error = -EFAULT;
++ break;
++ }
++
++ if (unlikely(!access_ok(VERIFY_WRITE, base, len))) {
++ error = -EFAULT;
++ break;
++ }
++
++ sd.len = 0;
++ sd.total_len = len;
++ sd.flags = flags;
++ sd.u.userptr = base;
++ sd.pos = 0;
++
++ size = __splice_from_pipe(pipe, &sd, pipe_to_user);
++ if (size < 0) {
++ if (!ret)
++ ret = size;
++
++ break;
++ }
++
++ ret += size;
++
++ if (size < len)
++ break;
++
++ nr_segs--;
++ iov++;
++ }
++
++ pipe_unlock(pipe);
++
++ if (!ret)
++ ret = error;
++
++ return ret;
++}
++
++/*
++ * vmsplice splices a user address range into a pipe. It can be thought of
++ * as splice-from-memory, where the regular splice is splice-from-file (or
++ * to file). In both cases the output is a pipe, naturally.
++ */
++static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
++ unsigned long nr_segs, unsigned int flags)
++{
++ struct pipe_inode_info *pipe;
++ struct page *pages[PIPE_DEF_BUFFERS];
++ struct partial_page partial[PIPE_DEF_BUFFERS];
++ struct splice_pipe_desc spd = {
++ .pages = pages,
++ .partial = partial,
++ .flags = flags,
++ .ops = &user_page_pipe_buf_ops,
++ .spd_release = spd_release_page,
++ };
++ long ret;
++
++ pipe = pipe_info(file->f_path.dentry->d_inode);
++ if (!pipe)
++ return -EBADF;
++
++ if (splice_grow_spd(pipe, &spd))
++ return -ENOMEM;
++
++ spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages,
++ spd.partial, flags & SPLICE_F_GIFT,
++ pipe->buffers);
++ if (spd.nr_pages <= 0)
++ ret = spd.nr_pages;
++ else
++ ret = splice_to_pipe(pipe, &spd);
++
++ splice_shrink_spd(pipe, &spd);
++ return ret;
++}
++
++/*
++ * Note that vmsplice only really supports true splicing _from_ user memory
++ * to a pipe, not the other way around. Splicing from user memory is a simple
++ * operation that can be supported without any funky alignment restrictions
++ * or nasty vm tricks. We simply map in the user memory and fill them into
++ * a pipe. The reverse isn't quite as easy, though. There are two possible
++ * solutions for that:
++ *
++ * - memcpy() the data internally, at which point we might as well just
++ * do a regular read() on the buffer anyway.
++ * - Lots of nasty vm tricks, that are neither fast nor flexible (it
++ * has restriction limitations on both ends of the pipe).
++ *
++ * Currently we punt and implement it as a normal copy, see pipe_to_user().
++ *
++ */
++SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, iov,
++ unsigned long, nr_segs, unsigned int, flags)
++{
++ struct file *file;
++ long error;
++ int fput;
++
++ if (unlikely(nr_segs > UIO_MAXIOV))
++ return -EINVAL;
++ else if (unlikely(!nr_segs))
++ return 0;
++
++ error = -EBADF;
++ file = fget_light(fd, &fput);
++ if (file) {
++ if (file->f_mode & FMODE_WRITE)
++ error = vmsplice_to_pipe(file, iov, nr_segs, flags);
++ else if (file->f_mode & FMODE_READ)
++ error = vmsplice_to_user(file, iov, nr_segs, flags);
++
++ fput_light(file, fput);
++ }
++
++ return error;
++}
++
++SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in,
++ int, fd_out, loff_t __user *, off_out,
++ size_t, len, unsigned int, flags)
++{
++ long error;
++ struct file *in, *out;
++ int fput_in, fput_out;
++
++ if (unlikely(!len))
++ return 0;
++
++ error = -EBADF;
++ in = fget_light(fd_in, &fput_in);
++ if (in) {
++ if (in->f_mode & FMODE_READ) {
++ out = fget_light(fd_out, &fput_out);
++ if (out) {
++ if (out->f_mode & FMODE_WRITE)
++ error = do_splice(in, off_in,
++ out, off_out,
++ len, flags);
++ fput_light(out, fput_out);
++ }
++ }
++
++ fput_light(in, fput_in);
++ }
++
++ return error;
++}
++
++/*
++ * Make sure there's data to read. Wait for input if we can, otherwise
++ * return an appropriate error.
++ */
++static int ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
++{
++ int ret;
++
++ /*
++ * Check ->nrbufs without the inode lock first. This function
++ * is speculative anyways, so missing one is ok.
++ */
++ if (pipe->nrbufs)
++ return 0;
++
++ ret = 0;
++ pipe_lock(pipe);
++
++ while (!pipe->nrbufs) {
++ if (signal_pending(current)) {
++ ret = -ERESTARTSYS;
++ break;
++ }
++ if (!pipe->writers)
++ break;
++ if (!pipe->waiting_writers) {
++ if (flags & SPLICE_F_NONBLOCK) {
++ ret = -EAGAIN;
++ break;
++ }
++ }
++ pipe_wait(pipe);
++ }
++
++ pipe_unlock(pipe);
++ return ret;
++}
++
++/*
++ * Make sure there's writeable room. Wait for room if we can, otherwise
++ * return an appropriate error.
++ */
++static int opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
++{
++ int ret;
++
++ /*
++ * Check ->nrbufs without the inode lock first. This function
++ * is speculative anyways, so missing one is ok.
++ */
++ if (pipe->nrbufs < pipe->buffers)
++ return 0;
++
++ ret = 0;
++ pipe_lock(pipe);
++
++ while (pipe->nrbufs >= pipe->buffers) {
++ if (!pipe->readers) {
++ send_sig(SIGPIPE, current, 0);
++ ret = -EPIPE;
++ break;
++ }
++ if (flags & SPLICE_F_NONBLOCK) {
++ ret = -EAGAIN;
++ break;
++ }
++ if (signal_pending(current)) {
++ ret = -ERESTARTSYS;
++ break;
++ }
++ pipe->waiting_writers++;
++ pipe_wait(pipe);
++ pipe->waiting_writers--;
++ }
++
++ pipe_unlock(pipe);
++ return ret;
++}
++
++/*
++ * Splice contents of ipipe to opipe.
++ */
++static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
++ struct pipe_inode_info *opipe,
++ size_t len, unsigned int flags)
++{
++ struct pipe_buffer *ibuf, *obuf;
++ int ret = 0, nbuf;
++ bool input_wakeup = false;
++
++
++retry:
++ ret = ipipe_prep(ipipe, flags);
++ if (ret)
++ return ret;
++
++ ret = opipe_prep(opipe, flags);
++ if (ret)
++ return ret;
++
++ /*
++ * Potential ABBA deadlock, work around it by ordering lock
++ * grabbing by pipe info address. Otherwise two different processes
++ * could deadlock (one doing tee from A -> B, the other from B -> A).
++ */
++ pipe_double_lock(ipipe, opipe);
++
++ do {
++ if (!opipe->readers) {
++ send_sig(SIGPIPE, current, 0);
++ if (!ret)
++ ret = -EPIPE;
++ break;
++ }
++
++ if (!ipipe->nrbufs && !ipipe->writers)
++ break;
++
++ /*
++ * Cannot make any progress, because either the input
++ * pipe is empty or the output pipe is full.
++ */
++ if (!ipipe->nrbufs || opipe->nrbufs >= opipe->buffers) {
++ /* Already processed some buffers, break */
++ if (ret)
++ break;
++
++ if (flags & SPLICE_F_NONBLOCK) {
++ ret = -EAGAIN;
++ break;
++ }
++
++ /*
++ * We raced with another reader/writer and haven't
++ * managed to process any buffers. A zero return
++ * value means EOF, so retry instead.
++ */
++ pipe_unlock(ipipe);
++ pipe_unlock(opipe);
++ goto retry;
++ }
++
++ ibuf = ipipe->bufs + ipipe->curbuf;
++ nbuf = (opipe->curbuf + opipe->nrbufs) & (opipe->buffers - 1);
++ obuf = opipe->bufs + nbuf;
++
++ if (len >= ibuf->len) {
++ /*
++ * Simply move the whole buffer from ipipe to opipe
++ */
++ *obuf = *ibuf;
++ ibuf->ops = NULL;
++ opipe->nrbufs++;
++ ipipe->curbuf = (ipipe->curbuf + 1) & (ipipe->buffers - 1);
++ ipipe->nrbufs--;
++ input_wakeup = true;
++ } else {
++ /*
++ * Get a reference to this pipe buffer,
++ * so we can copy the contents over.
++ */
++ ibuf->ops->get(ipipe, ibuf);
++ *obuf = *ibuf;
++
++ /*
++ * Don't inherit the gift flag, we need to
++ * prevent multiple steals of this page.
++ */
++ obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
++
++ obuf->len = len;
++ opipe->nrbufs++;
++ ibuf->offset += obuf->len;
++ ibuf->len -= obuf->len;
++ }
++ ret += obuf->len;
++ len -= obuf->len;
++ } while (len);
++
++ pipe_unlock(ipipe);
++ pipe_unlock(opipe);
++
++ /*
++ * If we put data in the output pipe, wakeup any potential readers.
++ */
++ if (ret > 0) {
++ smp_mb();
++ if (waitqueue_active(&opipe->wait))
++ wake_up_interruptible(&opipe->wait);
++ kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN);
++ }
++ if (input_wakeup)
++ wakeup_pipe_writers(ipipe);
++
++ return ret;
++}
++
++/*
++ * Link contents of ipipe to opipe.
++ */
++static int link_pipe(struct pipe_inode_info *ipipe,
++ struct pipe_inode_info *opipe,
++ size_t len, unsigned int flags)
++{
++ struct pipe_buffer *ibuf, *obuf;
++ int ret = 0, i = 0, nbuf;
++
++ /*
++ * Potential ABBA deadlock, work around it by ordering lock
++ * grabbing by pipe info address. Otherwise two different processes
++ * could deadlock (one doing tee from A -> B, the other from B -> A).
++ */
++ pipe_double_lock(ipipe, opipe);
++
++ do {
++ if (!opipe->readers) {
++ send_sig(SIGPIPE, current, 0);
++ if (!ret)
++ ret = -EPIPE;
++ break;
++ }
++
++ /*
++ * If we have iterated all input buffers or ran out of
++ * output room, break.
++ */
++ if (i >= ipipe->nrbufs || opipe->nrbufs >= opipe->buffers)
++ break;
++
++ ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (ipipe->buffers-1));
++ nbuf = (opipe->curbuf + opipe->nrbufs) & (opipe->buffers - 1);
++
++ /*
++ * Get a reference to this pipe buffer,
++ * so we can copy the contents over.
++ */
++ ibuf->ops->get(ipipe, ibuf);
++
++ obuf = opipe->bufs + nbuf;
++ *obuf = *ibuf;
++
++ /*
++ * Don't inherit the gift flag, we need to
++ * prevent multiple steals of this page.
++ */
++ obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
++
++ if (obuf->len > len)
++ obuf->len = len;
++
++ opipe->nrbufs++;
++ ret += obuf->len;
++ len -= obuf->len;
++ i++;
++ } while (len);
++
++ /*
++ * return EAGAIN if we have the potential of some data in the
++ * future, otherwise just return 0
++ */
++ if (!ret && ipipe->waiting_writers && (flags & SPLICE_F_NONBLOCK))
++ ret = -EAGAIN;
++
++ pipe_unlock(ipipe);
++ pipe_unlock(opipe);
++
++ /*
++ * If we put data in the output pipe, wakeup any potential readers.
++ */
++ if (ret > 0) {
++ smp_mb();
++ if (waitqueue_active(&opipe->wait))
++ wake_up_interruptible(&opipe->wait);
++ kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN);
++ }
++
++ return ret;
++}
++
++/*
++ * This is a tee(1) implementation that works on pipes. It doesn't copy
++ * any data, it simply references the 'in' pages on the 'out' pipe.
++ * The 'flags' used are the SPLICE_F_* variants, currently the only
++ * applicable one is SPLICE_F_NONBLOCK.
++ */
++static long do_tee(struct file *in, struct file *out, size_t len,
++ unsigned int flags)
++{
++ struct pipe_inode_info *ipipe = pipe_info(in->f_path.dentry->d_inode);
++ struct pipe_inode_info *opipe = pipe_info(out->f_path.dentry->d_inode);
++ int ret = -EINVAL;
++
++ /*
++ * Duplicate the contents of ipipe to opipe without actually
++ * copying the data.
++ */
++ if (ipipe && opipe && ipipe != opipe) {
++ /*
++ * Keep going, unless we encounter an error. The ipipe/opipe
++ * ordering doesn't really matter.
++ */
++ ret = ipipe_prep(ipipe, flags);
++ if (!ret) {
++ ret = opipe_prep(opipe, flags);
++ if (!ret)
++ ret = link_pipe(ipipe, opipe, len, flags);
++ }
++ }
++
++ return ret;
++}
++
++SYSCALL_DEFINE4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags)
++{
++ struct file *in;
++ int error, fput_in;
++
++ if (unlikely(!len))
++ return 0;
++
++ error = -EBADF;
++ in = fget_light(fdin, &fput_in);
++ if (in) {
++ if (in->f_mode & FMODE_READ) {
++ int fput_out;
++ struct file *out = fget_light(fdout, &fput_out);
++
++ if (out) {
++ if (out->f_mode & FMODE_WRITE)
++ error = do_tee(in, out, len, flags);
++ fput_light(out, fput_out);
++ }
++ }
++ fput_light(in, fput_in);
++ }
++
++ return error;
++}
+diff -Nur linux-2.6.36.orig/security/commoncap.c linux-2.6.36/security/commoncap.c
+--- linux-2.6.36.orig/security/commoncap.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/security/commoncap.c 2011-01-10 19:52:38.000000000 +0100
+@@ -951,3 +951,4 @@
+ }
+ return ret;
+ }
++EXPORT_SYMBOL(cap_file_mmap);
+diff -Nur linux-2.6.36.orig/security/device_cgroup.c linux-2.6.36/security/device_cgroup.c
+--- linux-2.6.36.orig/security/device_cgroup.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/security/device_cgroup.c 2011-01-10 19:52:38.000000000 +0100
+@@ -515,6 +515,7 @@
+
+ return -EPERM;
+ }
++EXPORT_SYMBOL(devcgroup_inode_permission);
+
+ int devcgroup_inode_mknod(int mode, dev_t dev)
+ {
+diff -Nur linux-2.6.36.orig/security/security.c linux-2.6.36/security/security.c
+--- linux-2.6.36.orig/security/security.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/security/security.c 2011-01-10 19:52:38.000000000 +0100
+@@ -376,6 +376,7 @@
+ return 0;
+ return security_ops->path_mkdir(dir, dentry, mode);
+ }
++EXPORT_SYMBOL(security_path_mkdir);
+
+ int security_path_rmdir(struct path *dir, struct dentry *dentry)
+ {
+@@ -383,6 +384,7 @@
+ return 0;
+ return security_ops->path_rmdir(dir, dentry);
+ }
++EXPORT_SYMBOL(security_path_rmdir);
+
+ int security_path_unlink(struct path *dir, struct dentry *dentry)
+ {
+@@ -390,6 +392,7 @@
+ return 0;
+ return security_ops->path_unlink(dir, dentry);
+ }
++EXPORT_SYMBOL(security_path_unlink);
+
+ int security_path_symlink(struct path *dir, struct dentry *dentry,
+ const char *old_name)
+@@ -398,6 +401,7 @@
+ return 0;
+ return security_ops->path_symlink(dir, dentry, old_name);
+ }
++EXPORT_SYMBOL(security_path_symlink);
+
+ int security_path_link(struct dentry *old_dentry, struct path *new_dir,
+ struct dentry *new_dentry)
+@@ -406,6 +410,7 @@
+ return 0;
+ return security_ops->path_link(old_dentry, new_dir, new_dentry);
+ }
++EXPORT_SYMBOL(security_path_link);
+
+ int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
+ struct path *new_dir, struct dentry *new_dentry)
+@@ -416,6 +421,7 @@
+ return security_ops->path_rename(old_dir, old_dentry, new_dir,
+ new_dentry);
+ }
++EXPORT_SYMBOL(security_path_rename);
+
+ int security_path_truncate(struct path *path)
+ {
+@@ -423,6 +429,7 @@
+ return 0;
+ return security_ops->path_truncate(path);
+ }
++EXPORT_SYMBOL(security_path_truncate);
+
+ int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+ mode_t mode)
+@@ -431,6 +438,7 @@
+ return 0;
+ return security_ops->path_chmod(dentry, mnt, mode);
+ }
++EXPORT_SYMBOL(security_path_chmod);
+
+ int security_path_chown(struct path *path, uid_t uid, gid_t gid)
+ {
+@@ -438,6 +446,7 @@
+ return 0;
+ return security_ops->path_chown(path, uid, gid);
+ }
++EXPORT_SYMBOL(security_path_chown);
+
+ int security_path_chroot(struct path *path)
+ {
+@@ -514,6 +523,7 @@
+ return 0;
+ return security_ops->inode_readlink(dentry);
+ }
++EXPORT_SYMBOL(security_inode_readlink);
+
+ int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
+ {
+@@ -528,6 +538,7 @@
+ return 0;
+ return security_ops->inode_permission(inode, mask);
+ }
++EXPORT_SYMBOL(security_inode_permission);
+
+ int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
+ {
+@@ -627,6 +638,7 @@
+
+ return fsnotify_perm(file, mask);
+ }
++EXPORT_SYMBOL(security_file_permission);
+
+ int security_file_alloc(struct file *file)
+ {
+@@ -654,6 +666,7 @@
+ return ret;
+ return ima_file_mmap(file, prot);
+ }
++EXPORT_SYMBOL(security_file_mmap);
+
+ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
+ unsigned long prot)
diff --git a/target/linux/patches/2.6.36/brcm.patch b/target/linux/patches/2.6.36/brcm.patch
index 44db7d0d5..10a9a4947 100644
--- a/target/linux/patches/2.6.36/brcm.patch
+++ b/target/linux/patches/2.6.36/brcm.patch
@@ -1,4 +1,3 @@
-diff -Nur linux-2.6.36.orig/arch/mips/bcm47xx/Makefile linux-2.6.36/arch/mips/bcm47xx/Makefile
--- linux-2.6.36.orig/arch/mips/bcm47xx/Makefile 2010-10-20 22:30:22.000000000 +0200
+++ linux-2.6.36/arch/mips/bcm47xx/Makefile 2010-12-22 16:39:15.000000000 +0100
@@ -3,4 +3,4 @@
@@ -7,16 +6,16 @@ diff -Nur linux-2.6.36.orig/arch/mips/bcm47xx/Makefile linux-2.6.36/arch/mips/bc
-obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
+obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o platform.o
-diff -Nur linux-2.6.36.orig/arch/mips/bcm47xx/platform.c linux-2.6.36/arch/mips/bcm47xx/platform.c
---- linux-2.6.36.orig/arch/mips/bcm47xx/platform.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/arch/mips/bcm47xx/platform.c 2010-12-22 16:57:43.000000000 +0100
-@@ -0,0 +1,81 @@
+--- /dev/null Fri Jan 7 17:21:57 2011
++++ linux-2.6.36/arch/mips/bcm47xx/platform.c Fri Jan 7 17:21:42 2011
+@@ -0,0 +1,147 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
-+ * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
++ * Copyright (C) 2010, 2011 Waldemar Brodkorb <wbx@openadk.org>
++ * Copyright © 2007, 2011 Thorsten Glaser <tg@freewrt.org>
+ */
+
+#include <linux/platform_device.h>
@@ -28,19 +27,35 @@ diff -Nur linux-2.6.36.orig/arch/mips/bcm47xx/platform.c linux-2.6.36/arch/mips/
+#include <asm/mach-bcm47xx/nvram.h>
+
+#define NVRAM_FLASH_SIZE 0x10000
++#define CFGFS_FLASH_SIZE (64 * 1024)
+
+static struct mtd_partition bcm47xx_partitions[] = {
++#define SLOT_CFE 0
+ {
+ .name = "cfe",
+ .offset = 0,
+ .size = 0x40000, /* 256k */
+ .mask_flags = MTD_WRITEABLE /* force read-only */
+ },
++#define SLOT_LINUX 1
+ {
+ .name = "linux",
+ .offset = 0,
+ .size = 0,
+ },
++#define SLOT_ROOTFS 2
++ {
++ .name = "rootfs",
++ .offset = 0,
++ .size = 0,
++ },
++#define SLOT_CFGFS 3
++ {
++ .name = "cfgfs",
++ .offset = 0,
++ .size = 0,
++ },
++#define SLOT_NVRAM 4
+ {
+ .name = "nvram",
+ .offset = 0,
@@ -69,18 +84,67 @@ diff -Nur linux-2.6.36.orig/arch/mips/bcm47xx/platform.c linux-2.6.36/arch/mips/
+ &bcm47xx_flash,
+};
+
++struct bcm47xx_trx_header {
++#define BCM47XX_TRX_MAGIC 0x30524448
++ u32 magic;
++ u32 len;
++ u32 crc32;
++ u32 flag_version;
++ u32 offsets[3];
++};
++
++#define UPTODOWN(slot, psize) do { \
++ posn -= psize; left -= psize; \
++ bcm47xx_partitions[slot].offset = posn; \
++ bcm47xx_partitions[slot].size = psize; \
++} while (/* CONSTCOND */ 0)
++
+static int __init bcm47xx_register_devices(void)
+{
+ u32 flash_size;
++ size_t left, posn;
+ struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
++ struct bcm47xx_trx_header *trx_hdr;
++
++ trx_hdr = (void *)KSEG1ADDR(mcore->flash_window + 0x40000);
+
+ /* devices might have 2, 4 or 8 MB flash size */
++#ifdef BCM47XX_OVERRIDE_FLASHSIZE
++ flash_size = BCM47XX_OVERRIDE_FLASHSIZE;
++ mcore->flash_window_size = flash_size;
++#define BCM47XX_OVERRODE_FLASHSIZE " (overridden)"
++#else
+ flash_size = mcore->flash_window_size;
-+ printk(KERN_INFO "FLASH SIZE: %x\n", flash_size);
-+ bcm47xx_partitions[1].offset = 0x40000;
-+ bcm47xx_partitions[1].size = flash_size - NVRAM_FLASH_SIZE - 0x40000;
-+ bcm47xx_partitions[2].offset = flash_size - NVRAM_FLASH_SIZE;
-+ bcm47xx_partitions[2].size = NVRAM_FLASH_SIZE;
++#define BCM47XX_OVERRODE_FLASHSIZE ""
++#endif
++ printk(KERN_INFO "FLASH SIZE%s: %x\n", BCM47XX_OVERRODE_FLASHSIZE,
++ flash_size);
++
++ left = flash_size - 0x40000;
++ posn = flash_size;
++ UPTODOWN(SLOT_NVRAM, NVRAM_FLASH_SIZE);
++ UPTODOWN(SLOT_CFGFS, CFGFS_FLASH_SIZE);
++ bcm47xx_partitions[SLOT_LINUX].offset = 0x40000;
++ bcm47xx_partitions[SLOT_LINUX].size = left;
++
++ if (trx_hdr->magic == BCM47XX_TRX_MAGIC) {
++ bcm47xx_partitions[SLOT_ROOTFS].offset =
++ bcm47xx_partitions[SLOT_LINUX].offset +
++ trx_hdr->offsets[1];
++ bcm47xx_partitions[SLOT_ROOTFS].size =
++ bcm47xx_partitions[SLOT_LINUX].size -
++ trx_hdr->offsets[1];
++ } else
++ printk("bcm47xx/platform: no TRX header found\n");
++
++ printk(KERN_INFO "=== Flash map dump ===\n");
++ for (posn = 0; posn < bcm47xx_flash_data.nr_parts; ++posn)
++ printk(KERN_INFO " #%u %08X @%08X '%s'\n",
++ (unsigned int)posn,
++ (unsigned int)bcm47xx_partitions[posn].size,
++ (unsigned int)bcm47xx_partitions[posn].offset,
++ bcm47xx_partitions[posn].name);
++ printk(KERN_INFO "=== Hope this works, have a nice day\n");
+
+ bcm47xx_flash_data.width = mcore->flash_buswidth;
+ bcm47xx_flash_resource.start = mcore->flash_window;
@@ -92,7 +156,6 @@ diff -Nur linux-2.6.36.orig/arch/mips/bcm47xx/platform.c linux-2.6.36/arch/mips/
+}
+
+device_initcall(bcm47xx_register_devices);
-diff -Nur linux-2.6.36.orig/drivers/ssb/driver_mipscore.c linux-2.6.36/drivers/ssb/driver_mipscore.c
--- linux-2.6.36.orig/drivers/ssb/driver_mipscore.c 2010-10-20 22:30:22.000000000 +0200
+++ linux-2.6.36/drivers/ssb/driver_mipscore.c 2010-12-22 16:38:53.000000000 +0100
@@ -193,7 +193,7 @@
diff --git a/target/linux/patches/2.6.36/yaffs2.patch b/target/linux/patches/2.6.36/yaffs2.patch
index ab8924e0f..4a52d3f10 100644
--- a/target/linux/patches/2.6.36/yaffs2.patch
+++ b/target/linux/patches/2.6.36/yaffs2.patch
@@ -1,6 +1,6 @@
diff -Nur linux-2.6.36.orig/fs/Kconfig linux-2.6.36/fs/Kconfig
---- linux-2.6.36.orig/fs/Kconfig 2010-10-20 22:30:22.000000000 +0200
-+++ linux-2.6.36/fs/Kconfig 2010-11-18 18:15:51.000000000 +0100
+--- linux-2.6.36.orig/fs/Kconfig 2011-01-10 19:28:45.000000000 +0100
++++ linux-2.6.36/fs/Kconfig 2011-01-10 19:29:29.000000000 +0100
@@ -174,6 +174,7 @@
source "fs/befs/Kconfig"
source "fs/bfs/Kconfig"
@@ -10,16 +10,19 @@ diff -Nur linux-2.6.36.orig/fs/Kconfig linux-2.6.36/fs/Kconfig
# UBIFS File system configuration
source "fs/ubifs/Kconfig"
diff -Nur linux-2.6.36.orig/fs/Makefile linux-2.6.36/fs/Makefile
---- linux-2.6.36.orig/fs/Makefile 2010-10-20 22:30:22.000000000 +0200
-+++ linux-2.6.36/fs/Makefile 2010-11-18 18:15:51.000000000 +0100
-@@ -126,3 +126,4 @@
+--- linux-2.6.36.orig/fs/Makefile 2011-01-10 19:28:45.000000000 +0100
++++ linux-2.6.36/fs/Makefile 2011-01-10 19:30:04.000000000 +0100
+@@ -124,6 +124,7 @@
+ obj-$(CONFIG_OCFS2_FS) += ocfs2/
+ obj-$(CONFIG_BTRFS_FS) += btrfs/
obj-$(CONFIG_GFS2_FS) += gfs2/
++obj-$(CONFIG_YAFFS_FS) += yaffs2/
obj-$(CONFIG_EXOFS_FS) += exofs/
obj-$(CONFIG_CEPH_FS) += ceph/
-+obj-$(CONFIG_YAFFS_FS) += yaffs2/
+ obj-$(CONFIG_AUFS_FS) += aufs/
diff -Nur linux-2.6.36.orig/fs/yaffs2/Kconfig linux-2.6.36/fs/yaffs2/Kconfig
--- linux-2.6.36.orig/fs/yaffs2/Kconfig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/Kconfig 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/Kconfig 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,161 @@
+#
+# YAFFS file system configurations
@@ -184,7 +187,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/Kconfig linux-2.6.36/fs/yaffs2/Kconfig
+ If unsure, say Y.
diff -Nur linux-2.6.36.orig/fs/yaffs2/Makefile linux-2.6.36/fs/yaffs2/Makefile
--- linux-2.6.36.orig/fs/yaffs2/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/Makefile 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/Makefile 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,17 @@
+#
+# Makefile for the linux YAFFS filesystem routines.
@@ -205,7 +208,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/Makefile linux-2.6.36/fs/yaffs2/Makefile
+
diff -Nur linux-2.6.36.orig/fs/yaffs2/moduleconfig.h linux-2.6.36/fs/yaffs2/moduleconfig.h
--- linux-2.6.36.orig/fs/yaffs2/moduleconfig.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/moduleconfig.h 2010-11-18 18:49:02.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/moduleconfig.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,81 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -290,7 +293,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/moduleconfig.h linux-2.6.36/fs/yaffs2/modu
+#endif /* __YAFFS_CONFIG_H__ */
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_allocator.c linux-2.6.36/fs/yaffs2/yaffs_allocator.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_allocator.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_allocator.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_allocator.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,397 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -691,7 +694,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_allocator.c linux-2.6.36/fs/yaffs2/y
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_allocator.h linux-2.6.36/fs/yaffs2/yaffs_allocator.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_allocator.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_allocator.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_allocator.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,30 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -725,7 +728,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_allocator.h linux-2.6.36/fs/yaffs2/y
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_attribs.c linux-2.6.36/fs/yaffs2/yaffs_attribs.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_attribs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_attribs.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_attribs.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,124 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -853,7 +856,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_attribs.c linux-2.6.36/fs/yaffs2/yaf
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_attribs.h linux-2.6.36/fs/yaffs2/yaffs_attribs.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_attribs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_attribs.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_attribs.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,28 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -885,7 +888,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_attribs.h linux-2.6.36/fs/yaffs2/yaf
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_bitmap.c linux-2.6.36/fs/yaffs2/yaffs_bitmap.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_bitmap.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_bitmap.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_bitmap.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,104 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -993,7 +996,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_bitmap.c linux-2.6.36/fs/yaffs2/yaff
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_bitmap.h linux-2.6.36/fs/yaffs2/yaffs_bitmap.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_bitmap.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_bitmap.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_bitmap.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -1030,7 +1033,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_bitmap.h linux-2.6.36/fs/yaffs2/yaff
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_checkptrw.c linux-2.6.36/fs/yaffs2/yaffs_checkptrw.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_checkptrw.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_checkptrw.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,420 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -1454,7 +1457,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_checkptrw.c linux-2.6.36/fs/yaffs2/y
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_checkptrw.h linux-2.6.36/fs/yaffs2/yaffs_checkptrw.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_checkptrw.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_checkptrw.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -1491,7 +1494,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_checkptrw.h linux-2.6.36/fs/yaffs2/y
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_ecc.c linux-2.6.36/fs/yaffs2/yaffs_ecc.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_ecc.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_ecc.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_ecc.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,322 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -1817,7 +1820,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_ecc.c linux-2.6.36/fs/yaffs2/yaffs_e
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_ecc.h linux-2.6.36/fs/yaffs2/yaffs_ecc.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_ecc.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_ecc.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_ecc.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,44 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -1865,7 +1868,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_ecc.h linux-2.6.36/fs/yaffs2/yaffs_e
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_getblockinfo.h linux-2.6.36/fs/yaffs2/yaffs_getblockinfo.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_getblockinfo.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_getblockinfo.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,36 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -1905,7 +1908,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_getblockinfo.h linux-2.6.36/fs/yaffs
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_guts.c linux-2.6.36/fs/yaffs2/yaffs_guts.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_guts.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_guts.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_guts.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,5227 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -7136,7 +7139,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_guts.c linux-2.6.36/fs/yaffs2/yaffs_
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_guts.h linux-2.6.36/fs/yaffs2/yaffs_guts.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_guts.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_guts.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_guts.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,914 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -8054,7 +8057,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_guts.h linux-2.6.36/fs/yaffs2/yaffs_
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_linux.h linux-2.6.36/fs/yaffs2/yaffs_linux.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_linux.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_linux.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_linux.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,41 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -8099,7 +8102,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_linux.h linux-2.6.36/fs/yaffs2/yaffs
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif.c linux-2.6.36/fs/yaffs2/yaffs_mtdif.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_mtdif.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,54 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -8157,7 +8160,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif.c linux-2.6.36/fs/yaffs2/yaffs
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif.h linux-2.6.36/fs/yaffs2/yaffs_mtdif.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_mtdif.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,23 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -8184,7 +8187,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif.h linux-2.6.36/fs/yaffs2/yaffs
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif1.c linux-2.6.36/fs/yaffs2/yaffs_mtdif1.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif1.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_mtdif1.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif1.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,365 @@
+/*
+ * YAFFS: Yet another FFS. A NAND-flash specific file system.
@@ -8553,7 +8556,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif1.c linux-2.6.36/fs/yaffs2/yaff
+#endif /*MTD_VERSION */
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif1.h linux-2.6.36/fs/yaffs2/yaffs_mtdif1.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif1.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_mtdif1.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif1.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,29 @@
+/*
+ * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
@@ -8586,7 +8589,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif1.h linux-2.6.36/fs/yaffs2/yaff
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif2.c linux-2.6.36/fs/yaffs2/yaffs_mtdif2.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif2.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_mtdif2.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif2.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,261 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -8851,7 +8854,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif2.c linux-2.6.36/fs/yaffs2/yaff
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif2.h linux-2.6.36/fs/yaffs2/yaffs_mtdif2.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif2.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_mtdif2.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif2.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,29 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -8884,7 +8887,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif2.h linux-2.6.36/fs/yaffs2/yaff
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nameval.c linux-2.6.36/fs/yaffs2/yaffs_nameval.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_nameval.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_nameval.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_nameval.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,201 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -9089,7 +9092,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nameval.c linux-2.6.36/fs/yaffs2/yaf
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nameval.h linux-2.6.36/fs/yaffs2/yaffs_nameval.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_nameval.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_nameval.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_nameval.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,28 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -9121,7 +9124,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nameval.h linux-2.6.36/fs/yaffs2/yaf
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nand.c linux-2.6.36/fs/yaffs2/yaffs_nand.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_nand.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_nand.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_nand.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,128 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -9253,7 +9256,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nand.c linux-2.6.36/fs/yaffs2/yaffs_
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nand.h linux-2.6.36/fs/yaffs2/yaffs_nand.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_nand.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_nand.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_nand.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,38 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -9295,7 +9298,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nand.h linux-2.6.36/fs/yaffs2/yaffs_
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags1.c linux-2.6.36/fs/yaffs2/yaffs_packedtags1.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_packedtags1.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_packedtags1.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,53 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -9352,7 +9355,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags1.c linux-2.6.36/fs/yaffs2
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags1.h linux-2.6.36/fs/yaffs2/yaffs_packedtags1.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_packedtags1.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_packedtags1.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,39 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -9395,7 +9398,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags1.h linux-2.6.36/fs/yaffs2
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags2.c linux-2.6.36/fs/yaffs2/yaffs_packedtags2.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_packedtags2.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_packedtags2.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,197 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -9596,7 +9599,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags2.c linux-2.6.36/fs/yaffs2
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags2.h linux-2.6.36/fs/yaffs2/yaffs_packedtags2.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_packedtags2.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_packedtags2.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,47 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -9647,7 +9650,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags2.h linux-2.6.36/fs/yaffs2
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagscompat.c linux-2.6.36/fs/yaffs2/yaffs_tagscompat.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_tagscompat.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_tagscompat.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,454 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -10105,7 +10108,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagscompat.c linux-2.6.36/fs/yaffs2/
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagscompat.h linux-2.6.36/fs/yaffs2/yaffs_tagscompat.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_tagscompat.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_tagscompat.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,36 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -10145,7 +10148,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagscompat.h linux-2.6.36/fs/yaffs2/
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagsvalidity.c linux-2.6.36/fs/yaffs2/yaffs_tagsvalidity.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_tagsvalidity.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_tagsvalidity.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_tagsvalidity.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,27 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -10176,7 +10179,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagsvalidity.c linux-2.6.36/fs/yaffs
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.36/fs/yaffs2/yaffs_tagsvalidity.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_tagsvalidity.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_tagsvalidity.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_tagsvalidity.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,23 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -10203,7 +10206,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.36/fs/yaffs
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_trace.h linux-2.6.36/fs/yaffs2/yaffs_trace.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_trace.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_trace.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_trace.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,59 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -10266,7 +10269,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_trace.h linux-2.6.36/fs/yaffs2/yaffs
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_verify.c linux-2.6.36/fs/yaffs2/yaffs_verify.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_verify.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_verify.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_verify.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,546 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -10816,7 +10819,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_verify.c linux-2.6.36/fs/yaffs2/yaff
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_verify.h linux-2.6.36/fs/yaffs2/yaffs_verify.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_verify.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_verify.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_verify.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,43 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -10863,7 +10866,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_verify.h linux-2.6.36/fs/yaffs2/yaff
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_vfs.c linux-2.6.36/fs/yaffs2/yaffs_vfs.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_vfs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_vfs.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_vfs.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,3565 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -14432,7 +14435,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_vfs.c linux-2.6.36/fs/yaffs2/yaffs_v
+MODULE_LICENSE("GPL");
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs1.c linux-2.6.36/fs/yaffs2/yaffs_yaffs1.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_yaffs1.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_yaffs1.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,437 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -14873,7 +14876,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs1.c linux-2.6.36/fs/yaffs2/yaff
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs1.h linux-2.6.36/fs/yaffs2/yaffs_yaffs1.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_yaffs1.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_yaffs1.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,22 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -14899,7 +14902,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs1.h linux-2.6.36/fs/yaffs2/yaff
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs2.c linux-2.6.36/fs/yaffs2/yaffs_yaffs2.c
--- linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_yaffs2.c 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_yaffs2.c 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,1620 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
@@ -16523,7 +16526,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs2.c linux-2.6.36/fs/yaffs2/yaff
+}
diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs2.h linux-2.6.36/fs/yaffs2/yaffs_yaffs2.h
--- linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yaffs_yaffs2.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_yaffs2.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,39 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
@@ -16566,7 +16569,7 @@ diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs2.h linux-2.6.36/fs/yaffs2/yaff
+#endif
diff -Nur linux-2.6.36.orig/fs/yaffs2/yportenv.h linux-2.6.36/fs/yaffs2/yportenv.h
--- linux-2.6.36.orig/fs/yaffs2/yportenv.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.36/fs/yaffs2/yportenv.h 2010-11-18 18:15:51.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yportenv.h 2011-01-10 19:29:29.000000000 +0100
@@ -0,0 +1,339 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
diff --git a/target/linux/patches/2.6.37/ar7.patch b/target/linux/patches/2.6.37/ar7.patch
new file mode 100644
index 000000000..5f3b69ce1
--- /dev/null
+++ b/target/linux/patches/2.6.37/ar7.patch
@@ -0,0 +1,90 @@
+diff -Nur linux-2.6.36.orig/arch/mips/Kconfig linux-2.6.36/arch/mips/Kconfig
+--- linux-2.6.36.orig/arch/mips/Kconfig 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/mips/Kconfig 2010-12-16 21:02:19.000000000 +0100
+@@ -46,7 +46,6 @@
+ select CEVT_R4K
+ select CSRC_R4K
+ select IRQ_CPU
+- select NO_EXCEPT_FILL
+ select SWAP_IO_SPACE
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_HAS_EARLY_PRINTK
+diff -Nur linux-2.6.36.orig/arch/mips/ar7/prom.c linux-2.6.36/arch/mips/ar7/prom.c
+--- linux-2.6.36.orig/arch/mips/ar7/prom.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/mips/ar7/prom.c 2010-12-16 21:02:19.000000000 +0100
+@@ -206,6 +206,14 @@
+ if (strstr(arcs_cmdline, "console="))
+ return;
+
++#ifdef CONFIG_KGDB
++ if (!strstr(prom_getcmdline(), "nokgdb")) {
++ strcat(prom_getcmdline(), " console=kgdb");
++ kgdb_enabled = 1;
++ return;
++ }
++#endif
++
+ s = prom_getenv("modetty0");
+ if (s) {
+ baud = simple_strtoul(s, &p, 10);
+diff -Nur linux-2.6.36.orig/drivers/mtd/ar7part.c linux-2.6.36/drivers/mtd/ar7part.c
+--- linux-2.6.36.orig/drivers/mtd/ar7part.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/mtd/ar7part.c 2010-12-16 21:02:19.000000000 +0100
+@@ -28,7 +28,7 @@
+ #include <linux/bootmem.h>
+ #include <linux/magic.h>
+
+-#define AR7_PARTS 4
++#define AR7_PARTS 5
+ #define ROOT_OFFSET 0xe0000
+
+ #define LOADER_MAGIC1 le32_to_cpu(0xfeedfa42)
+@@ -122,14 +122,19 @@
+
+ ar7_parts[2].name = "linux";
+ ar7_parts[2].offset = pre_size;
+- ar7_parts[2].size = master->size - pre_size - post_size;
++ ar7_parts[2].size = master->size - pre_size - post_size - 2*master->erasesize;
+ ar7_parts[2].mask_flags = 0;
+
+ ar7_parts[3].name = "rootfs";
+ ar7_parts[3].offset = root_offset;
+- ar7_parts[3].size = master->size - root_offset - post_size;
++ ar7_parts[3].size = master->size - root_offset - post_size - 2*master->erasesize;
+ ar7_parts[3].mask_flags = 0;
+
++ ar7_parts[4].name = "cfgfs";
++ ar7_parts[4].offset = master->size - 2*master->erasesize;
++ ar7_parts[4].size = 2*master->erasesize;
++ ar7_parts[4].mask_flags = 0;
++
+ *pparts = ar7_parts;
+ return AR7_PARTS;
+ }
+diff -Nur linux-2.6.36.orig/drivers/mtd/maps/physmap.c linux-2.6.36/drivers/mtd/maps/physmap.c
+--- linux-2.6.36.orig/drivers/mtd/maps/physmap.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/mtd/maps/physmap.c 2010-12-16 21:02:19.000000000 +0100
+@@ -79,7 +79,7 @@
+ "map_rom",
+ NULL };
+ #ifdef CONFIG_MTD_PARTITIONS
+-static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
++static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", "ar7part", NULL };
+ #endif
+
+ static int physmap_flash_probe(struct platform_device *dev)
+diff -Nur linux-2.6.36.orig/drivers/serial/8250.c linux-2.6.36/drivers/serial/8250.c
+--- linux-2.6.36.orig/drivers/serial/8250.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/serial/8250.c 2010-12-16 21:02:19.000000000 +0100
+@@ -2761,7 +2761,11 @@
+ {
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+
++#ifdef CONFIG_AR7
++ wait_for_xmitr(up, BOTH_EMPTY);
++#else
+ wait_for_xmitr(up, UART_LSR_THRE);
++#endif
+ serial_out(up, UART_TX, ch);
+ }
+
diff --git a/target/linux/patches/2.6.37/ar71xx.patch b/target/linux/patches/2.6.37/ar71xx.patch
new file mode 100644
index 000000000..059ac9dd5
--- /dev/null
+++ b/target/linux/patches/2.6.37/ar71xx.patch
@@ -0,0 +1,18667 @@
+diff -Nur linux-2.6.37.orig/arch/mips/Kconfig linux-2.6.37/arch/mips/Kconfig
+--- linux-2.6.37.orig/arch/mips/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -65,6 +65,23 @@
+ Support for the Texas Instruments AR7 System-on-a-Chip
+ family: TNETD7100, 7200 and 7300.
+
++config ATHEROS_AR71XX
++ bool "Atheros AR71xx based boards"
++ select CEVT_R4K
++ select CSRC_R4K
++ select DMA_NONCOHERENT
++ select HW_HAS_PCI
++ select IRQ_CPU
++ select ARCH_REQUIRE_GPIOLIB
++ select SYS_HAS_CPU_MIPS32_R1
++ select SYS_HAS_CPU_MIPS32_R2
++ select SYS_SUPPORTS_32BIT_KERNEL
++ select SYS_SUPPORTS_BIG_ENDIAN
++ select SYS_HAS_EARLY_PRINTK
++ select MIPS_MACHINE
++ help
++ Support for Atheros AR71xx based boards.
++
+ config BCM47XX
+ bool "Broadcom BCM47XX based boards"
+ select CEVT_R4K
+@@ -717,6 +734,7 @@
+ endchoice
+
+ source "arch/mips/alchemy/Kconfig"
++source "arch/mips/ar71xx/Kconfig"
+ source "arch/mips/bcm63xx/Kconfig"
+ source "arch/mips/jazz/Kconfig"
+ source "arch/mips/jz4740/Kconfig"
+@@ -880,9 +898,15 @@
+ config MIPS_DISABLE_OBSOLETE_IDE
+ bool
+
++config MYLOADER
++ bool
++
+ config SYNC_R4K
+ bool
+
++config MIPS_MACHINE
++ def_bool n
++
+ config NO_IOPORT
+ def_bool n
+
+diff -Nur linux-2.6.37.orig/arch/mips/Makefile linux-2.6.37/arch/mips/Makefile
+--- linux-2.6.37.orig/arch/mips/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -158,6 +158,13 @@
+ endif
+ cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1
+
++#
++# Atheros AR71xx
++#
++core-$(CONFIG_ATHEROS_AR71XX) += arch/mips/ar71xx/
++cflags-$(CONFIG_ATHEROS_AR71XX) += -I$(srctree)/arch/mips/include/asm/mach-ar71xx
++load-$(CONFIG_ATHEROS_AR71XX) += 0xffffffff80060000
++
+ cflags-$(CONFIG_CPU_R4000_WORKAROUNDS) += $(call cc-option,-mfix-r4000,)
+ cflags-$(CONFIG_CPU_R4400_WORKAROUNDS) += $(call cc-option,-mfix-r4400,)
+ cflags-$(CONFIG_CPU_DADDI_WORKAROUNDS) += $(call cc-option,-mno-daddi,)
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/Kconfig linux-2.6.37/arch/mips/ar71xx/Kconfig
+--- linux-2.6.37.orig/arch/mips/ar71xx/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,264 @@
++if ATHEROS_AR71XX
++
++menu "Atheros AR71xx machine selection"
++
++config AR71XX_MACH_AP81
++ bool "Atheros AP81 board support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ default n
++
++config AR71XX_MACH_AP83
++ bool "Atheros AP83 board support"
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ default n
++
++config AR71XX_MACH_DIR_600_A1
++ bool "D-Link DIR-600 rev. A1 support"
++ select AR71XX_DEV_AP91_ETH
++ select AR71XX_DEV_AP91_PCI if PCI
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_NVRAM
++ default n
++
++config AR71XX_MACH_DIR_615_C1
++ bool "D-Link DIR-615 rev. C1 support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_NVRAM
++ default n
++
++config AR71XX_MACH_DIR_825_B1
++ bool "D-Link DIR-825 rev. B1 board support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AP94_PCI if PCI
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ default n
++
++config AR71XX_MACH_PB42
++ bool "Atheros PB42 board support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_PB42_PCI if PCI
++ default n
++
++config AR71XX_MACH_PB44
++ bool "Atheros PB44 board support"
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_PB42_PCI if PCI
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ default n
++
++config AR71XX_MACH_PB92
++ bool "Atheros PB92 board support"
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_PB9X_PCI if PCI
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ default n
++
++config AR71XX_MACH_AW_NR580
++ bool "AzureWave AW-NR580 board support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_PB42_PCI if PCI
++ select AR71XX_DEV_LEDS_GPIO
++ default n
++
++config AR71XX_MACH_WZR_HP_G300NH
++ bool "Buffalo WZR-HP-G300NH board support"
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ default y
++
++config AR71XX_MACH_WP543
++ bool "Compex WP543/WPJ543 board support"
++ select MYLOADER
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_PB42_PCI if PCI
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ default n
++
++config AR71XX_MACH_WRT160NL
++ bool "Linksys WRT160NL board support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ select AR71XX_NVRAM
++ default n
++
++config AR71XX_MACH_WRT400N
++ bool "Linksys WRT400N board support"
++ select AR71XX_DEV_AP94_PCI if PCI
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ default n
++
++config AR71XX_MACH_RB4XX
++ bool "MikroTik RouterBOARD 4xx series support"
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ default n
++
++config AR71XX_MACH_RB750
++ bool "MikroTik RouterBOARD 750 support"
++ select AR71XX_DEV_AP91_ETH
++ default n
++
++config AR71XX_MACH_WNDR3700
++ bool "NETGEAR WNDR3700 board support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AP94_PCI if PCI
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ default n
++
++config AR71XX_MACH_WNR2000
++ bool "NETGEAR WNR2000 board support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ default n
++
++config AR71XX_MACH_MZK_W04NU
++ bool "Planex MZK-W04NU board support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ default n
++
++config AR71XX_MACH_MZK_W300NH
++ bool "Planex MZK-W300NH board support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ default n
++
++config AR71XX_MACH_NBG460N
++ bool "Zyxel NBG460N/550N/550NH board support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ default n
++
++config AR71XX_MACH_TL_WR741ND
++ bool "TP-LINK TL-WR741ND support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AP91_ETH
++ select AR71XX_DEV_AP91_PCI if PCI
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ default n
++
++config AR71XX_MACH_TL_WR841N_V1
++ bool "TP-LINK TL-WR841N v1 support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_PB42_PCI if PCI
++ select AR71XX_DEV_DSA
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ default n
++
++config AR71XX_MACH_TL_WR941ND
++ bool "TP-LINK TL-WR941ND support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_DSA
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ default n
++
++config AR71XX_MACH_TL_WR1043ND
++ bool "TP-LINK TL-WR1043ND support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_USB
++ default n
++
++config AR71XX_MACH_TEW_632BRP
++ bool "TRENDnet TEW-632BRP support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AR913X_WMAC
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_NVRAM
++ default n
++
++config AR71XX_MACH_UBNT
++ bool "Ubiquiti AR71xx based boards support"
++ select AR71XX_DEV_M25P80
++ select AR71XX_DEV_AP91_PCI if PCI
++ select AR71XX_DEV_GPIO_BUTTONS
++ select AR71XX_DEV_LEDS_GPIO
++ select AR71XX_DEV_PB42_PCI if PCI
++ select AR71XX_DEV_USB
++ default n
++
++endmenu
++
++config AR71XX_DEV_M25P80
++ def_bool n
++
++config AR71XX_DEV_AP91_PCI
++ def_bool n
++
++config AR71XX_DEV_AP91_ETH
++ def_bool n
++
++config AR71XX_DEV_AP94_PCI
++ def_bool n
++
++config AR71XX_DEV_AR913X_WMAC
++ def_bool n
++
++config AR71XX_DEV_DSA
++ def_bool n
++
++config AR71XX_DEV_GPIO_BUTTONS
++ def_bool n
++
++config AR71XX_DEV_LEDS_GPIO
++ def_bool n
++
++config AR71XX_DEV_PB42_PCI
++ def_bool n
++
++config AR71XX_DEV_PB9X_PCI
++ def_bool n
++
++config AR71XX_DEV_USB
++ def_bool n
++
++config AR71XX_NVRAM
++ def_bool n
++
++endif
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/Makefile linux-2.6.37/arch/mips/ar71xx/Makefile
+--- linux-2.6.37.orig/arch/mips/ar71xx/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,54 @@
++#
++# Makefile for the Atheros AR71xx SoC specific parts of the kernel
++#
++# Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++# Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++#
++# This program is free software; you can redistribute it and/or modify it
++# under the terms of the GNU General Public License version 2 as published
++# by the Free Software Foundation.
++
++obj-y := prom.o irq.o setup.o devices.o gpio.o ar71xx.o
++
++obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
++obj-$(CONFIG_PCI) += pci.o
++
++obj-$(CONFIG_AR71XX_DEV_AP91_ETH) += dev-ap91-eth.o
++obj-$(CONFIG_AR71XX_DEV_AP91_PCI) += dev-ap91-pci.o
++obj-$(CONFIG_AR71XX_DEV_AP94_PCI) += dev-ap94-pci.o
++obj-$(CONFIG_AR71XX_DEV_AR913X_WMAC) += dev-ar913x-wmac.o
++obj-$(CONFIG_AR71XX_DEV_DSA) += dev-dsa.o
++obj-$(CONFIG_AR71XX_DEV_GPIO_BUTTONS) += dev-gpio-buttons.o
++obj-$(CONFIG_AR71XX_DEV_LEDS_GPIO) += dev-leds-gpio.o
++obj-$(CONFIG_AR71XX_DEV_M25P80) += dev-m25p80.o
++obj-$(CONFIG_AR71XX_DEV_PB42_PCI) += dev-pb42-pci.o
++obj-$(CONFIG_AR71XX_DEV_PB9X_PCI) += dev-pb9x-pci.o
++obj-$(CONFIG_AR71XX_DEV_USB) += dev-usb.o
++
++obj-$(CONFIG_AR71XX_NVRAM) += nvram.o
++
++obj-$(CONFIG_AR71XX_MACH_AP81) += mach-ap81.o
++obj-$(CONFIG_AR71XX_MACH_AP83) += mach-ap83.o
++obj-$(CONFIG_AR71XX_MACH_AW_NR580) += mach-aw-nr580.o
++obj-$(CONFIG_AR71XX_MACH_DIR_600_A1) += mach-dir-600-a1.o
++obj-$(CONFIG_AR71XX_MACH_DIR_615_C1) += mach-dir-615-c1.o
++obj-$(CONFIG_AR71XX_MACH_DIR_825_B1) += mach-dir-825-b1.o
++obj-$(CONFIG_AR71XX_MACH_MZK_W04NU) += mach-mzk-w04nu.o
++obj-$(CONFIG_AR71XX_MACH_MZK_W300NH) += mach-mzk-w300nh.o
++obj-$(CONFIG_AR71XX_MACH_NBG460N) += mach-nbg460n.o
++obj-$(CONFIG_AR71XX_MACH_PB42) += mach-pb42.o
++obj-$(CONFIG_AR71XX_MACH_PB44) += mach-pb44.o
++obj-$(CONFIG_AR71XX_MACH_PB92) += mach-pb92.o
++obj-$(CONFIG_AR71XX_MACH_RB4XX) += mach-rb4xx.o
++obj-$(CONFIG_AR71XX_MACH_RB750) += mach-rb750.o
++obj-$(CONFIG_AR71XX_MACH_TEW_632BRP) += mach-tew-632brp.o
++obj-$(CONFIG_AR71XX_MACH_TL_WR741ND) += mach-tl-wr741nd.o
++obj-$(CONFIG_AR71XX_MACH_TL_WR841N_V1) += mach-tl-wr841n.o
++obj-$(CONFIG_AR71XX_MACH_TL_WR941ND) += mach-tl-wr941nd.o
++obj-$(CONFIG_AR71XX_MACH_TL_WR1043ND) += mach-tl-wr1043nd.o
++obj-$(CONFIG_AR71XX_MACH_UBNT) += mach-ubnt.o
++obj-$(CONFIG_AR71XX_MACH_WNDR3700) += mach-wndr3700.o
++obj-$(CONFIG_AR71XX_MACH_WNR2000) += mach-wnr2000.o
++obj-$(CONFIG_AR71XX_MACH_WP543) += mach-wp543.o
++obj-$(CONFIG_AR71XX_MACH_WRT160NL) += mach-wrt160nl.o
++obj-$(CONFIG_AR71XX_MACH_WRT400N) += mach-wrt400n.o
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/ar71xx.c linux-2.6.37/arch/mips/ar71xx/ar71xx.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/ar71xx.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/ar71xx.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,177 @@
++/*
++ * AR71xx SoC routines
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/mutex.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++static DEFINE_MUTEX(ar71xx_flash_mutex);
++
++void __iomem *ar71xx_ddr_base;
++EXPORT_SYMBOL_GPL(ar71xx_ddr_base);
++
++void __iomem *ar71xx_pll_base;
++EXPORT_SYMBOL_GPL(ar71xx_pll_base);
++
++void __iomem *ar71xx_reset_base;
++EXPORT_SYMBOL_GPL(ar71xx_reset_base);
++
++void __iomem *ar71xx_gpio_base;
++EXPORT_SYMBOL_GPL(ar71xx_gpio_base);
++
++void __iomem *ar71xx_usb_ctrl_base;
++EXPORT_SYMBOL_GPL(ar71xx_usb_ctrl_base);
++
++void ar71xx_device_stop(u32 mask)
++{
++ unsigned long flags;
++ u32 mask_inv;
++ u32 t;
++
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7130:
++ case AR71XX_SOC_AR7141:
++ case AR71XX_SOC_AR7161:
++ local_irq_save(flags);
++ t = ar71xx_reset_rr(AR71XX_RESET_REG_RESET_MODULE);
++ ar71xx_reset_wr(AR71XX_RESET_REG_RESET_MODULE, t | mask);
++ local_irq_restore(flags);
++ break;
++
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ mask_inv = mask & RESET_MODULE_USB_OHCI_DLL_7240;
++ local_irq_save(flags);
++ t = ar71xx_reset_rr(AR724X_RESET_REG_RESET_MODULE);
++ t |= mask;
++ t &= ~mask_inv;
++ ar71xx_reset_wr(AR724X_RESET_REG_RESET_MODULE, t);
++ local_irq_restore(flags);
++ break;
++
++ case AR71XX_SOC_AR9130:
++ case AR71XX_SOC_AR9132:
++ local_irq_save(flags);
++ t = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE);
++ ar71xx_reset_wr(AR91XX_RESET_REG_RESET_MODULE, t | mask);
++ local_irq_restore(flags);
++ break;
++
++ default:
++ BUG();
++ }
++}
++EXPORT_SYMBOL_GPL(ar71xx_device_stop);
++
++void ar71xx_device_start(u32 mask)
++{
++ unsigned long flags;
++ u32 mask_inv;
++ u32 t;
++
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7130:
++ case AR71XX_SOC_AR7141:
++ case AR71XX_SOC_AR7161:
++ local_irq_save(flags);
++ t = ar71xx_reset_rr(AR71XX_RESET_REG_RESET_MODULE);
++ ar71xx_reset_wr(AR71XX_RESET_REG_RESET_MODULE, t & ~mask);
++ local_irq_restore(flags);
++ break;
++
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ mask_inv = mask & RESET_MODULE_USB_OHCI_DLL_7240;
++ local_irq_save(flags);
++ t = ar71xx_reset_rr(AR724X_RESET_REG_RESET_MODULE);
++ t &= ~mask;
++ t |= mask_inv;
++ ar71xx_reset_wr(AR724X_RESET_REG_RESET_MODULE, t);
++ local_irq_restore(flags);
++ break;
++
++ case AR71XX_SOC_AR9130:
++ case AR71XX_SOC_AR9132:
++ local_irq_save(flags);
++ t = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE);
++ ar71xx_reset_wr(AR91XX_RESET_REG_RESET_MODULE, t & ~mask);
++ local_irq_restore(flags);
++ break;
++
++ default:
++ BUG();
++ }
++}
++EXPORT_SYMBOL_GPL(ar71xx_device_start);
++
++int ar71xx_device_stopped(u32 mask)
++{
++ unsigned long flags;
++ u32 t;
++
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7130:
++ case AR71XX_SOC_AR7141:
++ case AR71XX_SOC_AR7161:
++ local_irq_save(flags);
++ t = ar71xx_reset_rr(AR71XX_RESET_REG_RESET_MODULE);
++ local_irq_restore(flags);
++ break;
++
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ local_irq_save(flags);
++ t = ar71xx_reset_rr(AR724X_RESET_REG_RESET_MODULE);
++ local_irq_restore(flags);
++ break;
++
++ case AR71XX_SOC_AR9130:
++ case AR71XX_SOC_AR9132:
++ local_irq_save(flags);
++ t = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE);
++ local_irq_restore(flags);
++ break;
++
++ default:
++ BUG();
++ }
++
++ return ((t & mask) == mask);
++}
++EXPORT_SYMBOL_GPL(ar71xx_device_stopped);
++
++void ar71xx_ddr_flush(u32 reg)
++{
++ ar71xx_ddr_wr(reg, 1);
++ while ((ar71xx_ddr_rr(reg) & 0x1));
++
++ ar71xx_ddr_wr(reg, 1);
++ while ((ar71xx_ddr_rr(reg) & 0x1));
++}
++EXPORT_SYMBOL_GPL(ar71xx_ddr_flush);
++
++void ar71xx_flash_acquire(void)
++{
++ mutex_lock(&ar71xx_flash_mutex);
++}
++EXPORT_SYMBOL_GPL(ar71xx_flash_acquire);
++
++void ar71xx_flash_release(void)
++{
++ mutex_unlock(&ar71xx_flash_mutex);
++}
++EXPORT_SYMBOL_GPL(ar71xx_flash_release);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-ap91-eth.c linux-2.6.37/arch/mips/ar71xx/dev-ap91-eth.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-ap91-eth.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-ap91-eth.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,70 @@
++/*
++ * Atheros AP91 reference board ethernet initialization
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "devices.h"
++#include "dev-dsa.h"
++#include "dev-ap91-eth.h"
++
++static struct dsa_chip_data ap91_dsa_chip = {
++ .port_names[0] = "cpu",
++ .port_names[1] = "lan1",
++ .port_names[2] = "lan2",
++ .port_names[3] = "lan3",
++ .port_names[4] = "lan4",
++};
++
++static struct dsa_platform_data ap91_dsa_data = {
++ .nr_chips = 1,
++ .chip = &ap91_dsa_chip,
++};
++
++static void ap91_eth_set_port_name(unsigned port, const char *name)
++{
++ if (port < 1 || port > 5)
++ return;
++
++ if (name)
++ ap91_dsa_chip.port_names[port] = (char *) name;
++}
++
++void __init ap91_eth_init(u8 *mac_addr, const char *port_names[])
++{
++ if (mac_addr)
++ ar71xx_set_mac_base(mac_addr);
++
++ if (port_names) {
++ int i;
++
++ for (i = 0; i < AP91_ETH_NUM_PORT_NAMES; i++)
++ ap91_eth_set_port_name(i + 1, port_names[i]);
++ }
++
++ /* WAN port */
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++ ar71xx_eth0_data.fifo_cfg1 = 0x0fff0000;
++ ar71xx_eth0_data.fifo_cfg2 = 0x00001fff;
++ ar71xx_eth0_data.fifo_cfg3 = 0x008001ff;
++
++ /* LAN ports */
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.speed = SPEED_1000;
++ ar71xx_eth1_data.duplex = DUPLEX_FULL;
++ ar71xx_eth1_data.fifo_cfg1 = 0x0fff0000;
++ ar71xx_eth1_data.fifo_cfg2 = 0x00001fff;
++ ar71xx_eth1_data.fifo_cfg3 = 0x008001ff;
++
++ ar71xx_add_device_mdio(0x0);
++ ar71xx_add_device_eth(1);
++ ar71xx_add_device_eth(0);
++
++ ar71xx_add_device_dsa(1, &ap91_dsa_data);
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-ap91-eth.h linux-2.6.37/arch/mips/ar71xx/dev-ap91-eth.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-ap91-eth.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-ap91-eth.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,23 @@
++/*
++ * Atheros AP91 reference board ethernet initialization
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_AP91_ETH_H
++#define _AR71XX_DEV_AP91_ETH_H
++
++#define AP91_ETH_NUM_PORT_NAMES 4
++
++#if defined(CONFIG_AR71XX_DEV_AP91_ETH)
++void ap91_eth_init(u8 *mac_addr, const char *port_names[]) __init;
++#else
++static inline void ap91_eth_init(u8 *mac_addr) { }
++#endif
++
++#endif /* _AR71XX_DEV_AP91_ETH_H */
++
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-ap91-pci.c linux-2.6.37/arch/mips/ar71xx/dev-ap91-pci.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-ap91-pci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-ap91-pci.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,114 @@
++/*
++ * Atheros AP91 reference board PCI initialization
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/pci.h>
++#include <linux/ath9k_platform.h>
++#include <linux/delay.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#include "dev-ap91-pci.h"
++
++static struct ath9k_platform_data ap91_wmac_data;
++static char ap91_wmac_mac[6];
++static int ap91_pci_fixup_enabled;
++
++static struct ar71xx_pci_irq ap91_pci_irqs[] __initdata = {
++ {
++ .slot = 0,
++ .pin = 1,
++ .irq = AR71XX_PCI_IRQ_DEV0,
++ }
++};
++
++static int ap91_pci_plat_dev_init(struct pci_dev *dev)
++{
++ switch(PCI_SLOT(dev->devfn)) {
++ case 0:
++ dev->dev.platform_data = &ap91_wmac_data;
++ break;
++ }
++
++ return 0;
++}
++
++static void ap91_pci_fixup(struct pci_dev *dev)
++{
++ void __iomem *mem;
++ u16 *cal_data;
++ u16 cmd;
++ u32 val;
++
++ if (!ap91_pci_fixup_enabled)
++ return;
++
++ printk(KERN_INFO "PCI: fixup device %s\n", pci_name(dev));
++
++ cal_data = ap91_wmac_data.eeprom_data;
++ if (*cal_data != 0xa55a) {
++ printk(KERN_ERR "PCI: no calibration data found for %s\n",
++ pci_name(dev));
++ return;
++ }
++
++ mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000);
++ if (!mem) {
++ printk(KERN_ERR "PCI: ioremap error for device %s\n",
++ pci_name(dev));
++ return;
++ }
++
++ /* Setup the PCI device to allow access to the internal registers */
++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0xffff);
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
++ pci_write_config_word(dev, PCI_COMMAND, cmd);
++
++ /* set pointer to first reg address */
++ cal_data += 3;
++ while (*cal_data != 0xffff) {
++ u32 reg;
++ reg = *cal_data++;
++ val = *cal_data++;
++ val |= (*cal_data++) << 16;
++
++ __raw_writel(val, mem + reg);
++ udelay(100);
++ }
++
++ pci_read_config_dword(dev, PCI_VENDOR_ID, &val);
++ dev->vendor = val & 0xffff;
++ dev->device = (val >> 16) & 0xffff;
++
++ pci_read_config_dword(dev, PCI_CLASS_REVISION, &val);
++ dev->revision = val & 0xff;
++ dev->class = val >> 8; /* upper 3 bytes */
++
++ iounmap(mem);
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ap91_pci_fixup);
++
++void __init ap91_pci_init(u8 *cal_data, u8 *mac_addr)
++{
++ if (cal_data)
++ memcpy(ap91_wmac_data.eeprom_data, cal_data,
++ sizeof(ap91_wmac_data.eeprom_data));
++
++ if (mac_addr) {
++ memcpy(ap91_wmac_mac, mac_addr, sizeof(ap91_wmac_mac));
++ ap91_wmac_data.macaddr = ap91_wmac_mac;
++ }
++
++ ar71xx_pci_plat_dev_init = ap91_pci_plat_dev_init;
++ ar71xx_pci_init(ARRAY_SIZE(ap91_pci_irqs), ap91_pci_irqs);
++
++ ap91_pci_fixup_enabled = 1;
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-ap91-pci.h linux-2.6.37/arch/mips/ar71xx/dev-ap91-pci.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-ap91-pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-ap91-pci.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,21 @@
++/*
++ * Atheros AP91 reference board PCI initialization
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_AP91_PCI_H
++#define _AR71XX_DEV_AP91_PCI_H
++
++#if defined(CONFIG_AR71XX_DEV_AP91_PCI)
++void ap91_pci_init(u8 *cal_data, u8 *mac_addr) __init;
++#else
++static inline void ap91_pci_init(u8 *cal_data, u8 *mac_addr) { }
++#endif
++
++#endif /* _AR71XX_DEV_AP91_PCI_H */
++
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-ap94-pci.c linux-2.6.37/arch/mips/ar71xx/dev-ap94-pci.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-ap94-pci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-ap94-pci.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,159 @@
++/*
++ * Atheros AP94 reference board PCI initialization
++ *
++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/pci.h>
++#include <linux/ath9k_platform.h>
++#include <linux/delay.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#include "dev-ap94-pci.h"
++
++static struct ath9k_platform_data ap94_wmac0_data;
++static struct ath9k_platform_data ap94_wmac1_data;
++static char ap94_wmac0_mac[6];
++static char ap94_wmac1_mac[6];
++static int ap94_pci_fixup_enabled;
++
++static struct ar71xx_pci_irq ap94_pci_irqs[] __initdata = {
++ {
++ .slot = 0,
++ .pin = 1,
++ .irq = AR71XX_PCI_IRQ_DEV0,
++ }, {
++ .slot = 1,
++ .pin = 1,
++ .irq = AR71XX_PCI_IRQ_DEV1,
++ }
++};
++
++static int ap94_pci_plat_dev_init(struct pci_dev *dev)
++{
++ switch(PCI_SLOT(dev->devfn)) {
++ case 17:
++ dev->dev.platform_data = &ap94_wmac0_data;
++ break;
++
++ case 18:
++ dev->dev.platform_data = &ap94_wmac1_data;
++ break;
++ }
++
++ return 0;
++}
++
++static void ap94_pci_fixup(struct pci_dev *dev)
++{
++ void __iomem *mem;
++ u16 *cal_data;
++ u16 cmd;
++ u32 bar0;
++ u32 val;
++
++ if (!ap94_pci_fixup_enabled)
++ return;
++
++ switch (PCI_SLOT(dev->devfn)) {
++ case 17:
++ cal_data = ap94_wmac0_data.eeprom_data;
++ break;
++ case 18:
++ cal_data = ap94_wmac1_data.eeprom_data;
++ break;
++ default:
++ return;
++ }
++
++ if (*cal_data != 0xa55a) {
++ printk(KERN_ERR "PCI: no calibration data found for %s\n",
++ pci_name(dev));
++ return;
++ }
++
++ mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000);
++ if (!mem) {
++ printk(KERN_ERR "PCI: ioremap error for device %s\n",
++ pci_name(dev));
++ return;
++ }
++
++ printk(KERN_INFO "PCI: fixup device %s\n", pci_name(dev));
++
++ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0);
++
++ /* Setup the PCI device to allow access to the internal registers */
++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, AR71XX_PCI_MEM_BASE);
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
++ pci_write_config_word(dev, PCI_COMMAND, cmd);
++
++ /* set pointer to first reg address */
++ cal_data += 3;
++ while (*cal_data != 0xffff) {
++ u32 reg;
++ reg = *cal_data++;
++ val = *cal_data++;
++ val |= (*cal_data++) << 16;
++
++ __raw_writel(val, mem + reg);
++ udelay(100);
++ }
++
++ pci_read_config_dword(dev, PCI_VENDOR_ID, &val);
++ dev->vendor = val & 0xffff;
++ dev->device = (val >> 16) & 0xffff;
++
++ pci_read_config_dword(dev, PCI_CLASS_REVISION, &val);
++ dev->revision = val & 0xff;
++ dev->class = val >> 8; /* upper 3 bytes */
++
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
++ pci_write_config_word(dev, PCI_COMMAND, cmd);
++
++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, bar0);
++
++ iounmap(mem);
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ap94_pci_fixup);
++
++void __init ap94_pci_enable_quirk_wndr3700(void)
++{
++ ap94_wmac0_data.quirk_wndr3700 = 1;
++ ap94_wmac1_data.quirk_wndr3700 = 1;
++}
++
++void __init ap94_pci_init(u8 *cal_data0, u8 *mac_addr0,
++ u8 *cal_data1, u8 *mac_addr1)
++{
++ if (cal_data0)
++ memcpy(ap94_wmac0_data.eeprom_data, cal_data0,
++ sizeof(ap94_wmac0_data.eeprom_data));
++
++ if (cal_data1)
++ memcpy(ap94_wmac1_data.eeprom_data, cal_data1,
++ sizeof(ap94_wmac1_data.eeprom_data));
++
++ if (mac_addr0) {
++ memcpy(ap94_wmac0_mac, mac_addr0, sizeof(ap94_wmac0_mac));
++ ap94_wmac0_data.macaddr = ap94_wmac0_mac;
++ }
++
++ if (mac_addr1) {
++ memcpy(ap94_wmac1_mac, mac_addr1, sizeof(ap94_wmac1_mac));
++ ap94_wmac1_data.macaddr = ap94_wmac1_mac;
++ }
++
++ ar71xx_pci_plat_dev_init = ap94_pci_plat_dev_init;
++ ar71xx_pci_init(ARRAY_SIZE(ap94_pci_irqs), ap94_pci_irqs);
++
++ ap94_pci_fixup_enabled = 1;
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-ap94-pci.h linux-2.6.37/arch/mips/ar71xx/dev-ap94-pci.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-ap94-pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-ap94-pci.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,28 @@
++/*
++ * Atheros AP94 reference board PCI initialization
++ *
++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_AP94_PCI_H
++#define _AR71XX_DEV_AP94_PCI_H
++
++#if defined(CONFIG_AR71XX_DEV_AP94_PCI)
++void ap94_pci_init(u8 *cal_data0, u8 *mac_addr0,
++ u8 *cal_data1, u8 *mac_addr1) __init;
++
++void ap94_pci_enable_quirk_wndr3700(void) __init;
++
++#else
++static inline void ap94_pci_init(u8 *cal_data0, u8 *mac_addr0,
++ u8 *cal_data1, u8 *mac_addr1) {}
++
++static inline void ap94_pci_enable_quirk_wndr3700(void) {}
++#endif
++
++#endif /* _AR71XX_DEV_AP94_PCI_H */
++
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-ar913x-wmac.c linux-2.6.37/arch/mips/ar71xx/dev-ar913x-wmac.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-ar913x-wmac.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-ar913x-wmac.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,68 @@
++/*
++ * Atheros AR913x SoC built-in WMAC device support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/etherdevice.h>
++#include <linux/platform_device.h>
++#include <linux/ath9k_platform.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "dev-ar913x-wmac.h"
++
++static struct ath9k_platform_data ar913x_wmac_data;
++static char ar913x_wmac_mac[6];
++
++static struct resource ar913x_wmac_resources[] = {
++ {
++ .start = AR91XX_WMAC_BASE,
++ .end = AR91XX_WMAC_BASE + AR91XX_WMAC_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = AR71XX_CPU_IRQ_IP2,
++ .end = AR71XX_CPU_IRQ_IP2,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device ar913x_wmac_device = {
++ .name = "ath9k",
++ .id = -1,
++ .resource = ar913x_wmac_resources,
++ .num_resources = ARRAY_SIZE(ar913x_wmac_resources),
++ .dev = {
++ .platform_data = &ar913x_wmac_data,
++ },
++};
++
++void __init ar913x_add_device_wmac(u8 *cal_data, u8 *mac_addr)
++{
++ if (cal_data)
++ memcpy(ar913x_wmac_data.eeprom_data, cal_data,
++ sizeof(ar913x_wmac_data.eeprom_data));
++
++ if (mac_addr) {
++ memcpy(ar913x_wmac_mac, mac_addr, sizeof(ar913x_wmac_mac));
++ ar913x_wmac_data.macaddr = ar913x_wmac_mac;
++ }
++
++ ar71xx_device_stop(RESET_MODULE_AMBA2WMAC);
++ mdelay(10);
++
++ ar71xx_device_start(RESET_MODULE_AMBA2WMAC);
++ mdelay(10);
++
++ platform_device_register(&ar913x_wmac_device);
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-ar913x-wmac.h linux-2.6.37/arch/mips/ar71xx/dev-ar913x-wmac.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-ar913x-wmac.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-ar913x-wmac.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,19 @@
++/*
++ * Atheros AR913x SoC built-in WMAC device support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_AR913X_WMAC_H
++#define _AR71XX_DEV_AR913X_WMAC_H
++
++void ar913x_add_device_wmac(u8 *cal_data, u8 *mac_addr) __init;
++
++#endif /* _AR71XX_DEV_AR913X_WMAC_H */
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-dsa.c linux-2.6.37/arch/mips/ar71xx/dev-dsa.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-dsa.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-dsa.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,50 @@
++/*
++ * Atheros AR71xx DSA switch device support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/platform_device.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "devices.h"
++#include "dev-dsa.h"
++
++static struct platform_device ar71xx_dsa_switch_device = {
++ .name = "dsa",
++ .id = 0,
++};
++
++void __init ar71xx_add_device_dsa(unsigned int id,
++ struct dsa_platform_data *d)
++{
++ int i;
++
++ switch (id) {
++ case 0:
++ d->netdev = &ar71xx_eth0_device.dev;
++ break;
++ case 1:
++ d->netdev = &ar71xx_eth1_device.dev;
++ break;
++ default:
++ printk(KERN_ERR
++ "ar71xx: invalid ethernet id %d for DSA switch\n",
++ id);
++ return;
++ }
++
++ for (i = 0; i < d->nr_chips; i++)
++ d->chip[i].mii_bus = &ar71xx_mdio_device.dev;
++
++ ar71xx_dsa_switch_device.dev.platform_data = d;
++
++ platform_device_register(&ar71xx_dsa_switch_device);
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-dsa.h linux-2.6.37/arch/mips/ar71xx/dev-dsa.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-dsa.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-dsa.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,20 @@
++/*
++ * Atheros AR71xx DSA switch device support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_DSA_H
++#define _AR71XX_DEV_DSA_H
++
++#include <net/dsa.h>
++
++void ar71xx_add_device_dsa(unsigned int id,
++ struct dsa_platform_data *d) __init;
++
++#endif /* _AR71XX_DEV_DSA_H */
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-gpio-buttons.c linux-2.6.37/arch/mips/ar71xx/dev-gpio-buttons.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-gpio-buttons.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-gpio-buttons.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,58 @@
++/*
++ * Atheros AR71xx GPIO button support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "linux/init.h"
++#include <linux/platform_device.h>
++
++#include "dev-gpio-buttons.h"
++
++void __init ar71xx_add_device_gpio_buttons(int id,
++ unsigned poll_interval,
++ unsigned nbuttons,
++ struct gpio_button *buttons)
++{
++ struct platform_device *pdev;
++ struct gpio_buttons_platform_data pdata;
++ struct gpio_button *p;
++ int err;
++
++ p = kmalloc(nbuttons * sizeof(*p), GFP_KERNEL);
++ if (!p)
++ return;
++
++ memcpy(p, buttons, nbuttons * sizeof(*p));
++
++ pdev = platform_device_alloc("gpio-buttons", id);
++ if (!pdev)
++ goto err_free_buttons;
++
++ memset(&pdata, 0, sizeof(pdata));
++ pdata.poll_interval = poll_interval;
++ pdata.nbuttons = nbuttons;
++ pdata.buttons = p;
++
++ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
++ if (err)
++ goto err_put_pdev;
++
++
++ err = platform_device_add(pdev);
++ if (err)
++ goto err_put_pdev;
++
++ return;
++
++err_put_pdev:
++ platform_device_put(pdev);
++
++err_free_buttons:
++ kfree(p);
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-gpio-buttons.h linux-2.6.37/arch/mips/ar71xx/dev-gpio-buttons.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-gpio-buttons.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-gpio-buttons.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,25 @@
++/*
++ * Atheros AR71xx GPIO button support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_GPIO_BUTTONS_H
++#define _AR71XX_DEV_GPIO_BUTTONS_H
++
++#include <linux/input.h>
++#include <linux/gpio_buttons.h>
++
++#include <asm/mach-ar71xx/platform.h>
++
++void ar71xx_add_device_gpio_buttons(int id,
++ unsigned poll_interval,
++ unsigned nbuttons,
++ struct gpio_button *buttons) __init;
++
++#endif /* _AR71XX_DEV_GPIO_BUTTONS_H */
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-leds-gpio.c linux-2.6.37/arch/mips/ar71xx/dev-leds-gpio.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-leds-gpio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-leds-gpio.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,57 @@
++/*
++ * Atheros AR71xx GPIO LED device support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include "dev-leds-gpio.h"
++
++void __init ar71xx_add_device_leds_gpio(int id, unsigned num_leds,
++ struct gpio_led *leds)
++{
++ struct platform_device *pdev;
++ struct gpio_led_platform_data pdata;
++ struct gpio_led *p;
++ int err;
++
++ p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL);
++ if (!p)
++ return;
++
++ memcpy(p, leds, num_leds * sizeof(*p));
++
++ pdev = platform_device_alloc("leds-gpio", id);
++ if (!pdev)
++ goto err_free_leds;
++
++ memset(&pdata, 0, sizeof(pdata));
++ pdata.num_leds = num_leds;
++ pdata.leds = p;
++
++ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
++ if (err)
++ goto err_put_pdev;
++
++ err = platform_device_add(pdev);
++ if (err)
++ goto err_put_pdev;
++
++ return;
++
++err_put_pdev:
++ platform_device_put(pdev);
++
++err_free_leds:
++ kfree(p);
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-leds-gpio.h linux-2.6.37/arch/mips/ar71xx/dev-leds-gpio.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-leds-gpio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-leds-gpio.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,21 @@
++/*
++ * Atheros AR71xx GPIO LED device support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_LEDS_GPIO_H
++#define _AR71XX_DEV_LEDS_GPIO_H
++
++#include <linux/leds.h>
++
++void ar71xx_add_device_leds_gpio(int id,
++ unsigned num_leds,
++ struct gpio_led *leds) __init;
++
++#endif /* _AR71XX_DEV_LEDS_GPIO_H */
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-m25p80.c linux-2.6.37/arch/mips/ar71xx/dev-m25p80.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-m25p80.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-m25p80.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++
++#include "devices.h"
++#include "dev-m25p80.h"
++
++static struct spi_board_info ar71xx_spi_info[] = {
++ {
++ .bus_num = 0,
++ .chip_select = 0,
++ .max_speed_hz = 25000000,
++ .modalias = "m25p80",
++ }
++};
++
++void __init ar71xx_add_device_m25p80(struct flash_platform_data *pdata)
++{
++ ar71xx_spi_info[0].platform_data = pdata;
++ ar71xx_add_device_spi(NULL, ar71xx_spi_info,
++ ARRAY_SIZE(ar71xx_spi_info));
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-m25p80.h linux-2.6.37/arch/mips/ar71xx/dev-m25p80.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-m25p80.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-m25p80.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,16 @@
++/*
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_M25P80_H
++#define _AR71XX_DEV_M25P80_H
++
++#include <linux/spi/flash.h>
++
++void ar71xx_add_device_m25p80(struct flash_platform_data *pdata) __init;
++
++#endif /* _AR71XX_DEV_M25P80_H */
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-pb42-pci.c linux-2.6.37/arch/mips/ar71xx/dev-pb42-pci.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-pb42-pci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-pb42-pci.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,40 @@
++/*
++ * Atheros PB42 reference board PCI initialization
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/pci.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#include "dev-pb42-pci.h"
++
++static struct ar71xx_pci_irq pb42_pci_irqs[] __initdata = {
++ {
++ .slot = 0,
++ .pin = 1,
++ .irq = AR71XX_PCI_IRQ_DEV0,
++ }, {
++ .slot = 1,
++ .pin = 1,
++ .irq = AR71XX_PCI_IRQ_DEV1,
++ }, {
++ .slot = 2,
++ .pin = 1,
++ .irq = AR71XX_PCI_IRQ_DEV2,
++ }
++};
++
++void __init pb42_pci_init(void)
++{
++ ar71xx_pci_init(ARRAY_SIZE(pb42_pci_irqs), pb42_pci_irqs);
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-pb42-pci.h linux-2.6.37/arch/mips/ar71xx/dev-pb42-pci.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-pb42-pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-pb42-pci.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,21 @@
++/*
++ * Atheros PB42 reference board PCI initialization
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_PB42_PCI_H
++#define _AR71XX_DEV_PB42_PCI_H
++
++#if defined(CONFIG_AR71XX_DEV_PB42_PCI)
++void pb42_pci_init(void) __init;
++#else
++static inline void pb42_pci_init(void) { }
++#endif
++
++#endif /* _AR71XX_DEV_PB42_PCI_H */
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-pb9x-pci.c linux-2.6.37/arch/mips/ar71xx/dev-pb9x-pci.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-pb9x-pci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-pb9x-pci.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,33 @@
++/*
++ * Atheros PB9x reference board PCI initialization
++ *
++ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/pci.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#include "dev-pb9x-pci.h"
++
++static struct ar71xx_pci_irq pb9x_pci_irqs[] __initdata = {
++ {
++ .slot = 0,
++ .pin = 1,
++ .irq = AR71XX_PCI_IRQ_DEV0,
++ }
++};
++
++void __init pb9x_pci_init(void)
++{
++ ar71xx_pci_init(ARRAY_SIZE(pb9x_pci_irqs), pb9x_pci_irqs);
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-pb9x-pci.h linux-2.6.37/arch/mips/ar71xx/dev-pb9x-pci.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-pb9x-pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-pb9x-pci.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,22 @@
++/*
++ * Atheros PB9x reference board PCI initialization
++ *
++ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_PB9X_PCI_H
++#define _AR71XX_DEV_PB9X_PCI_H
++
++#if defined(CONFIG_AR71XX_DEV_PB9X_PCI)
++void pb9x_pci_init(void) __init;
++#else
++static inline void pb9x_pci_init(void) { }
++#endif
++
++#endif /* _AR71XX_DEV_PB9X_PCI_H */
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-usb.c linux-2.6.37/arch/mips/ar71xx/dev-usb.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-usb.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-usb.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,181 @@
++/*
++ * Atheros AR71xx USB host device support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/platform.h>
++
++#include "dev-usb.h"
++
++/*
++ * OHCI (USB full speed host controller)
++ */
++static struct resource ar71xx_ohci_resources[] = {
++ [0] = {
++ .start = AR71XX_OHCI_BASE,
++ .end = AR71XX_OHCI_BASE + AR71XX_OHCI_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AR71XX_MISC_IRQ_OHCI,
++ .end = AR71XX_MISC_IRQ_OHCI,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct resource ar7240_ohci_resources[] = {
++ [0] = {
++ .start = AR7240_OHCI_BASE,
++ .end = AR7240_OHCI_BASE + AR7240_OHCI_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AR71XX_CPU_IRQ_USB,
++ .end = AR71XX_CPU_IRQ_USB,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static u64 ar71xx_ohci_dmamask = DMA_BIT_MASK(32);
++static struct platform_device ar71xx_ohci_device = {
++ .name = "ar71xx-ohci",
++ .id = -1,
++ .resource = ar71xx_ohci_resources,
++ .num_resources = ARRAY_SIZE(ar71xx_ohci_resources),
++ .dev = {
++ .dma_mask = &ar71xx_ohci_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ },
++};
++
++/*
++ * EHCI (USB full speed host controller)
++ */
++static struct resource ar71xx_ehci_resources[] = {
++ [0] = {
++ .start = AR71XX_EHCI_BASE,
++ .end = AR71XX_EHCI_BASE + AR71XX_EHCI_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AR71XX_CPU_IRQ_USB,
++ .end = AR71XX_CPU_IRQ_USB,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static u64 ar71xx_ehci_dmamask = DMA_BIT_MASK(32);
++static struct ar71xx_ehci_platform_data ar71xx_ehci_data;
++
++static struct platform_device ar71xx_ehci_device = {
++ .name = "ar71xx-ehci",
++ .id = -1,
++ .resource = ar71xx_ehci_resources,
++ .num_resources = ARRAY_SIZE(ar71xx_ehci_resources),
++ .dev = {
++ .dma_mask = &ar71xx_ehci_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &ar71xx_ehci_data,
++ },
++};
++
++#define AR71XX_USB_RESET_MASK \
++ (RESET_MODULE_USB_HOST | RESET_MODULE_USB_PHY \
++ | RESET_MODULE_USB_OHCI_DLL)
++
++#define AR7240_USB_RESET_MASK \
++ (RESET_MODULE_USB_HOST | RESET_MODULE_USB_OHCI_DLL_7240)
++
++static void __init ar71xx_usb_setup(void)
++{
++ ar71xx_device_stop(AR71XX_USB_RESET_MASK);
++ mdelay(1000);
++ ar71xx_device_start(AR71XX_USB_RESET_MASK);
++
++ /* Turning on the Buff and Desc swap bits */
++ ar71xx_usb_ctrl_wr(USB_CTRL_REG_CONFIG, 0xf0000);
++
++ /* WAR for HW bug. Here it adjusts the duration between two SOFS */
++ ar71xx_usb_ctrl_wr(USB_CTRL_REG_FLADJ, 0x20c00);
++
++ mdelay(900);
++
++ platform_device_register(&ar71xx_ohci_device);
++ platform_device_register(&ar71xx_ehci_device);
++}
++
++static void __init ar7240_usb_setup(void)
++{
++ ar71xx_device_stop(AR7240_USB_RESET_MASK);
++ mdelay(1000);
++ ar71xx_device_start(AR7240_USB_RESET_MASK);
++
++ /* WAR for HW bug. Here it adjusts the duration between two SOFS */
++ ar71xx_usb_ctrl_wr(USB_CTRL_REG_FLADJ, 0x3);
++
++ if (ar71xx_soc == AR71XX_SOC_AR7241 || ar71xx_soc == AR71XX_SOC_AR7242) {
++ ar71xx_ehci_data.is_ar91xx = 1;
++ ar71xx_ehci_device.resource = ar7240_ohci_resources;
++ ar71xx_ehci_device.num_resources = ARRAY_SIZE(ar7240_ohci_resources);
++ platform_device_register(&ar71xx_ehci_device);
++ } else {
++ ar71xx_ohci_device.resource = ar7240_ohci_resources;
++ ar71xx_ohci_device.num_resources = ARRAY_SIZE(ar7240_ohci_resources);
++ platform_device_register(&ar71xx_ohci_device);
++ }
++}
++
++static void __init ar91xx_usb_setup(void)
++{
++ ar71xx_device_stop(RESET_MODULE_USBSUS_OVERRIDE);
++ mdelay(10);
++
++ ar71xx_device_start(RESET_MODULE_USB_HOST);
++ mdelay(10);
++
++ ar71xx_device_start(RESET_MODULE_USB_PHY);
++ mdelay(10);
++
++ ar71xx_ehci_data.is_ar91xx = 1;
++ platform_device_register(&ar71xx_ehci_device);
++}
++
++void __init ar71xx_add_device_usb(void)
++{
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ ar7240_usb_setup();
++ break;
++
++ case AR71XX_SOC_AR7130:
++ case AR71XX_SOC_AR7141:
++ case AR71XX_SOC_AR7161:
++ ar71xx_usb_setup();
++ break;
++
++ case AR71XX_SOC_AR9130:
++ case AR71XX_SOC_AR9132:
++ ar91xx_usb_setup();
++ break;
++
++ default:
++ BUG();
++ }
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/dev-usb.h linux-2.6.37/arch/mips/ar71xx/dev-usb.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/dev-usb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/dev-usb.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,17 @@
++/*
++ * Atheros AR71xx USB host device support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_DEV_USB_H
++#define _AR71XX_DEV_USB_H
++
++void ar71xx_add_device_usb(void) __init;
++
++#endif /* _AR71XX_DEV_USB_H */
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/devices.c linux-2.6.37/arch/mips/ar71xx/devices.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/devices.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/devices.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,575 @@
++/*
++ * Atheros AR71xx SoC platform devices
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/etherdevice.h>
++#include <linux/platform_device.h>
++#include <linux/serial_8250.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "devices.h"
++
++static u8 ar71xx_mac_base[ETH_ALEN] __initdata;
++
++static struct resource ar71xx_uart_resources[] = {
++ {
++ .start = AR71XX_UART_BASE,
++ .end = AR71XX_UART_BASE + AR71XX_UART_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++#define AR71XX_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP)
++static struct plat_serial8250_port ar71xx_uart_data[] = {
++ {
++ .mapbase = AR71XX_UART_BASE,
++ .irq = AR71XX_MISC_IRQ_UART,
++ .flags = AR71XX_UART_FLAGS,
++ .iotype = UPIO_MEM32,
++ .regshift = 2,
++ }, {
++ /* terminating entry */
++ }
++};
++
++static struct platform_device ar71xx_uart_device = {
++ .name = "serial8250",
++ .id = PLAT8250_DEV_PLATFORM,
++ .resource = ar71xx_uart_resources,
++ .num_resources = ARRAY_SIZE(ar71xx_uart_resources),
++ .dev = {
++ .platform_data = ar71xx_uart_data
++ },
++};
++
++void __init ar71xx_add_device_uart(void)
++{
++ ar71xx_uart_data[0].uartclk = ar71xx_ahb_freq;
++ platform_device_register(&ar71xx_uart_device);
++}
++
++static struct resource ar71xx_mdio_resources[] = {
++ {
++ .name = "mdio_base",
++ .flags = IORESOURCE_MEM,
++ .start = AR71XX_GE0_BASE,
++ .end = AR71XX_GE0_BASE + 0x200 - 1,
++ }
++};
++
++static struct ag71xx_mdio_platform_data ar71xx_mdio_data;
++
++struct platform_device ar71xx_mdio_device = {
++ .name = "ag71xx-mdio",
++ .id = -1,
++ .resource = ar71xx_mdio_resources,
++ .num_resources = ARRAY_SIZE(ar71xx_mdio_resources),
++ .dev = {
++ .platform_data = &ar71xx_mdio_data,
++ },
++};
++
++void __init ar71xx_add_device_mdio(u32 phy_mask)
++{
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ ar71xx_mdio_data.is_ar7240 = 1;
++ break;
++ default:
++ break;
++ }
++
++ ar71xx_mdio_data.phy_mask = phy_mask;
++
++ platform_device_register(&ar71xx_mdio_device);
++}
++
++static void ar71xx_set_pll(u32 cfg_reg, u32 pll_reg, u32 pll_val, u32 shift)
++{
++ void __iomem *base;
++ u32 t;
++
++ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
++
++ t = __raw_readl(base + cfg_reg);
++ t &= ~(3 << shift);
++ t |= (2 << shift);
++ __raw_writel(t, base + cfg_reg);
++ udelay(100);
++
++ __raw_writel(pll_val, base + pll_reg);
++
++ t |= (3 << shift);
++ __raw_writel(t, base + cfg_reg);
++ udelay(100);
++
++ t &= ~(3 << shift);
++ __raw_writel(t, base + cfg_reg);
++ udelay(100);
++
++ printk(KERN_DEBUG "ar71xx: pll_reg %#x: %#x\n",
++ (unsigned int)(base + pll_reg), __raw_readl(base + pll_reg));
++
++ iounmap(base);
++}
++
++struct ar71xx_eth_pll_data ar71xx_eth0_pll_data;
++struct ar71xx_eth_pll_data ar71xx_eth1_pll_data;
++
++static u32 ar71xx_get_eth_pll(unsigned int mac, int speed)
++{
++ struct ar71xx_eth_pll_data *pll_data;
++ u32 pll_val;
++
++ switch (mac) {
++ case 0:
++ pll_data = &ar71xx_eth0_pll_data;
++ break;
++ case 1:
++ pll_data = &ar71xx_eth1_pll_data;
++ break;
++ default:
++ BUG();
++ }
++
++ switch (speed) {
++ case SPEED_10:
++ pll_val = pll_data->pll_10;
++ break;
++ case SPEED_100:
++ pll_val = pll_data->pll_100;
++ break;
++ case SPEED_1000:
++ pll_val = pll_data->pll_1000;
++ break;
++ default:
++ BUG();
++ }
++
++ return pll_val;
++}
++
++static void ar71xx_set_pll_ge0(int speed)
++{
++ u32 val = ar71xx_get_eth_pll(0, speed);
++
++ ar71xx_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH0_INT_CLOCK,
++ val, AR71XX_ETH0_PLL_SHIFT);
++}
++
++static void ar71xx_set_pll_ge1(int speed)
++{
++ u32 val = ar71xx_get_eth_pll(1, speed);
++
++ ar71xx_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH1_INT_CLOCK,
++ val, AR71XX_ETH1_PLL_SHIFT);
++}
++
++static void ar724x_set_pll_ge0(int speed)
++{
++ /* TODO */
++}
++
++static void ar724x_set_pll_ge1(int speed)
++{
++ /* TODO */
++}
++
++static void ar91xx_set_pll_ge0(int speed)
++{
++ u32 val = ar71xx_get_eth_pll(0, speed);
++
++ ar71xx_set_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH0_INT_CLOCK,
++ val, AR91XX_ETH0_PLL_SHIFT);
++}
++
++static void ar91xx_set_pll_ge1(int speed)
++{
++ u32 val = ar71xx_get_eth_pll(1, speed);
++
++ ar71xx_set_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH1_INT_CLOCK,
++ val, AR91XX_ETH1_PLL_SHIFT);
++}
++
++static void ar71xx_ddr_flush_ge0(void)
++{
++ ar71xx_ddr_flush(AR71XX_DDR_REG_FLUSH_GE0);
++}
++
++static void ar71xx_ddr_flush_ge1(void)
++{
++ ar71xx_ddr_flush(AR71XX_DDR_REG_FLUSH_GE1);
++}
++
++static void ar724x_ddr_flush_ge0(void)
++{
++ ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_GE0);
++}
++
++static void ar724x_ddr_flush_ge1(void)
++{
++ ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_GE1);
++}
++
++static void ar91xx_ddr_flush_ge0(void)
++{
++ ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_GE0);
++}
++
++static void ar91xx_ddr_flush_ge1(void)
++{
++ ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_GE1);
++}
++
++static struct resource ar71xx_eth0_resources[] = {
++ {
++ .name = "mac_base",
++ .flags = IORESOURCE_MEM,
++ .start = AR71XX_GE0_BASE,
++ .end = AR71XX_GE0_BASE + 0x200 - 1,
++ }, {
++ .name = "mii_ctrl",
++ .flags = IORESOURCE_MEM,
++ .start = AR71XX_MII_BASE + MII_REG_MII0_CTRL,
++ .end = AR71XX_MII_BASE + MII_REG_MII0_CTRL + 3,
++ }, {
++ .name = "mac_irq",
++ .flags = IORESOURCE_IRQ,
++ .start = AR71XX_CPU_IRQ_GE0,
++ .end = AR71XX_CPU_IRQ_GE0,
++ },
++};
++
++struct ag71xx_platform_data ar71xx_eth0_data = {
++ .reset_bit = RESET_MODULE_GE0_MAC,
++};
++
++struct platform_device ar71xx_eth0_device = {
++ .name = "ag71xx",
++ .id = 0,
++ .resource = ar71xx_eth0_resources,
++ .num_resources = ARRAY_SIZE(ar71xx_eth0_resources),
++ .dev = {
++ .platform_data = &ar71xx_eth0_data,
++ },
++};
++
++static struct resource ar71xx_eth1_resources[] = {
++ {
++ .name = "mac_base",
++ .flags = IORESOURCE_MEM,
++ .start = AR71XX_GE1_BASE,
++ .end = AR71XX_GE1_BASE + 0x200 - 1,
++ }, {
++ .name = "mii_ctrl",
++ .flags = IORESOURCE_MEM,
++ .start = AR71XX_MII_BASE + MII_REG_MII1_CTRL,
++ .end = AR71XX_MII_BASE + MII_REG_MII1_CTRL + 3,
++ }, {
++ .name = "mac_irq",
++ .flags = IORESOURCE_IRQ,
++ .start = AR71XX_CPU_IRQ_GE1,
++ .end = AR71XX_CPU_IRQ_GE1,
++ },
++};
++
++struct ag71xx_platform_data ar71xx_eth1_data = {
++ .reset_bit = RESET_MODULE_GE1_MAC,
++};
++
++struct platform_device ar71xx_eth1_device = {
++ .name = "ag71xx",
++ .id = 1,
++ .resource = ar71xx_eth1_resources,
++ .num_resources = ARRAY_SIZE(ar71xx_eth1_resources),
++ .dev = {
++ .platform_data = &ar71xx_eth1_data,
++ },
++};
++
++#define AR71XX_PLL_VAL_1000 0x00110000
++#define AR71XX_PLL_VAL_100 0x00001099
++#define AR71XX_PLL_VAL_10 0x00991099
++
++#define AR724X_PLL_VAL_1000 0x00110000
++#define AR724X_PLL_VAL_100 0x00001099
++#define AR724X_PLL_VAL_10 0x00991099
++
++#define AR91XX_PLL_VAL_1000 0x1a000000
++#define AR91XX_PLL_VAL_100 0x13000a44
++#define AR91XX_PLL_VAL_10 0x00441099
++
++static void __init ar71xx_init_eth_pll_data(unsigned int id)
++{
++ struct ar71xx_eth_pll_data *pll_data;
++ u32 pll_10, pll_100, pll_1000;
++
++ switch (id) {
++ case 0:
++ pll_data = &ar71xx_eth0_pll_data;
++ break;
++ case 1:
++ pll_data = &ar71xx_eth1_pll_data;
++ break;
++ default:
++ BUG();
++ }
++
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7130:
++ case AR71XX_SOC_AR7141:
++ case AR71XX_SOC_AR7161:
++ pll_10 = AR71XX_PLL_VAL_10;
++ pll_100 = AR71XX_PLL_VAL_100;
++ pll_1000 = AR71XX_PLL_VAL_1000;
++ break;
++
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ pll_10 = AR724X_PLL_VAL_10;
++ pll_100 = AR724X_PLL_VAL_100;
++ pll_1000 = AR724X_PLL_VAL_1000;
++ break;
++
++ case AR71XX_SOC_AR9130:
++ case AR71XX_SOC_AR9132:
++ pll_10 = AR91XX_PLL_VAL_10;
++ pll_100 = AR91XX_PLL_VAL_100;
++ pll_1000 = AR91XX_PLL_VAL_1000;
++ break;
++ default:
++ BUG();
++ }
++
++ if (!pll_data->pll_10)
++ pll_data->pll_10 = pll_10;
++
++ if (!pll_data->pll_100)
++ pll_data->pll_100 = pll_100;
++
++ if (!pll_data->pll_1000)
++ pll_data->pll_1000 = pll_1000;
++}
++
++static int ar71xx_eth_instance __initdata;
++void __init ar71xx_add_device_eth(unsigned int id)
++{
++ struct platform_device *pdev;
++ struct ag71xx_platform_data *pdata;
++
++ ar71xx_init_eth_pll_data(id);
++
++ switch (id) {
++ case 0:
++ switch (ar71xx_eth0_data.phy_if_mode) {
++ case PHY_INTERFACE_MODE_MII:
++ ar71xx_eth0_data.mii_if = MII0_CTRL_IF_MII;
++ break;
++ case PHY_INTERFACE_MODE_GMII:
++ ar71xx_eth0_data.mii_if = MII0_CTRL_IF_GMII;
++ break;
++ case PHY_INTERFACE_MODE_RGMII:
++ ar71xx_eth0_data.mii_if = MII0_CTRL_IF_RGMII;
++ break;
++ case PHY_INTERFACE_MODE_RMII:
++ ar71xx_eth0_data.mii_if = MII0_CTRL_IF_RMII;
++ break;
++ default:
++ printk(KERN_ERR "ar71xx: invalid PHY interface mode "
++ "for eth0\n");
++ return;
++ }
++ pdev = &ar71xx_eth0_device;
++ break;
++ case 1:
++ switch (ar71xx_eth1_data.phy_if_mode) {
++ case PHY_INTERFACE_MODE_RMII:
++ ar71xx_eth1_data.mii_if = MII1_CTRL_IF_RMII;
++ break;
++ case PHY_INTERFACE_MODE_RGMII:
++ ar71xx_eth1_data.mii_if = MII1_CTRL_IF_RGMII;
++ break;
++ default:
++ printk(KERN_ERR "ar71xx: invalid PHY interface mode "
++ "for eth1\n");
++ return;
++ }
++ pdev = &ar71xx_eth1_device;
++ break;
++ default:
++ printk(KERN_ERR "ar71xx: invalid ethernet id %d\n", id);
++ return;
++ }
++
++ pdata = pdev->dev.platform_data;
++
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7130:
++ pdata->ddr_flush = id ? ar71xx_ddr_flush_ge1
++ : ar71xx_ddr_flush_ge0;
++ pdata->set_pll = id ? ar71xx_set_pll_ge1
++ : ar71xx_set_pll_ge0;
++ break;
++
++ case AR71XX_SOC_AR7141:
++ case AR71XX_SOC_AR7161:
++ pdata->ddr_flush = id ? ar71xx_ddr_flush_ge1
++ : ar71xx_ddr_flush_ge0;
++ pdata->set_pll = id ? ar71xx_set_pll_ge1
++ : ar71xx_set_pll_ge0;
++ pdata->has_gbit = 1;
++ break;
++
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ ar71xx_eth0_data.reset_bit |= AR724X_RESET_GE0_MDIO;
++ ar71xx_eth1_data.reset_bit |= AR724X_RESET_GE1_MDIO;
++ /* fall through */
++ case AR71XX_SOC_AR7240:
++ pdata->ddr_flush = id ? ar724x_ddr_flush_ge1
++ : ar724x_ddr_flush_ge0;
++ pdata->set_pll = id ? ar724x_set_pll_ge1
++ : ar724x_set_pll_ge0;
++ pdata->is_ar724x = 1;
++ break;
++
++ case AR71XX_SOC_AR9130:
++ pdata->ddr_flush = id ? ar91xx_ddr_flush_ge1
++ : ar91xx_ddr_flush_ge0;
++ pdata->set_pll = id ? ar91xx_set_pll_ge1
++ : ar91xx_set_pll_ge0;
++ pdata->is_ar91xx = 1;
++ break;
++
++ case AR71XX_SOC_AR9132:
++ pdata->ddr_flush = id ? ar91xx_ddr_flush_ge1
++ : ar91xx_ddr_flush_ge0;
++ pdata->set_pll = id ? ar91xx_set_pll_ge1
++ : ar91xx_set_pll_ge0;
++ pdata->is_ar91xx = 1;
++ pdata->has_gbit = 1;
++ break;
++
++ default:
++ BUG();
++ }
++
++ switch (pdata->phy_if_mode) {
++ case PHY_INTERFACE_MODE_GMII:
++ case PHY_INTERFACE_MODE_RGMII:
++ if (!pdata->has_gbit) {
++ printk(KERN_ERR "ar71xx: no gbit available on eth%d\n",
++ id);
++ return;
++ }
++ /* fallthrough */
++ default:
++ break;
++ }
++
++ if (is_valid_ether_addr(ar71xx_mac_base)) {
++ memcpy(pdata->mac_addr, ar71xx_mac_base, ETH_ALEN);
++ pdata->mac_addr[5] += ar71xx_eth_instance;
++ } else {
++ random_ether_addr(pdata->mac_addr);
++ printk(KERN_DEBUG
++ "ar71xx: using random MAC address for eth%d\n",
++ ar71xx_eth_instance);
++ }
++
++ if (pdata->mii_bus_dev == NULL)
++ pdata->mii_bus_dev = &ar71xx_mdio_device.dev;
++
++ /* Reset the device */
++ ar71xx_device_stop(pdata->reset_bit);
++ mdelay(100);
++
++ ar71xx_device_start(pdata->reset_bit);
++ mdelay(100);
++
++ platform_device_register(pdev);
++ ar71xx_eth_instance++;
++}
++
++static struct resource ar71xx_spi_resources[] = {
++ [0] = {
++ .start = AR71XX_SPI_BASE,
++ .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++static struct platform_device ar71xx_spi_device = {
++ .name = "ar71xx-spi",
++ .id = -1,
++ .resource = ar71xx_spi_resources,
++ .num_resources = ARRAY_SIZE(ar71xx_spi_resources),
++};
++
++void __init ar71xx_add_device_spi(struct ar71xx_spi_platform_data *pdata,
++ struct spi_board_info const *info,
++ unsigned n)
++{
++ spi_register_board_info(info, n);
++ ar71xx_spi_device.dev.platform_data = pdata;
++ platform_device_register(&ar71xx_spi_device);
++}
++
++void __init ar71xx_add_device_wdt(void)
++{
++ platform_device_register_simple("ar71xx-wdt", -1, NULL, 0);
++}
++
++void __init ar71xx_set_mac_base(unsigned char *mac)
++{
++ memcpy(ar71xx_mac_base, mac, ETH_ALEN);
++}
++
++void __init ar71xx_parse_mac_addr(char *mac_str)
++{
++ u8 tmp[ETH_ALEN];
++ int t;
++
++ t = sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
++ &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]);
++
++ if (t != ETH_ALEN)
++ t = sscanf(mac_str, "%02hhx.%02hhx.%02hhx.%02hhx.%02hhx.%02hhx",
++ &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]);
++
++ if (t == ETH_ALEN)
++ ar71xx_set_mac_base(tmp);
++ else
++ printk(KERN_DEBUG "ar71xx: failed to parse mac address "
++ "\"%s\"\n", mac_str);
++}
++
++static int __init ar71xx_ethaddr_setup(char *str)
++{
++ ar71xx_parse_mac_addr(str);
++ return 1;
++}
++__setup("ethaddr=", ar71xx_ethaddr_setup);
++
++static int __init ar71xx_kmac_setup(char *str)
++{
++ ar71xx_parse_mac_addr(str);
++ return 1;
++}
++__setup("kmac=", ar71xx_kmac_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/devices.h linux-2.6.37/arch/mips/ar71xx/devices.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/devices.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/devices.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,48 @@
++/*
++ * Atheros AR71xx SoC device definitions
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __AR71XX_DEVICES_H
++#define __AR71XX_DEVICES_H
++
++#include <asm/mach-ar71xx/platform.h>
++
++struct platform_device;
++
++void ar71xx_add_device_spi(struct ar71xx_spi_platform_data *pdata,
++ struct spi_board_info const *info,
++ unsigned n) __init;
++
++void ar71xx_set_mac_base(unsigned char *mac) __init;
++void ar71xx_parse_mac_addr(char *mac_str) __init;
++
++struct ar71xx_eth_pll_data {
++ u32 pll_10;
++ u32 pll_100;
++ u32 pll_1000;
++};
++
++extern struct ar71xx_eth_pll_data ar71xx_eth0_pll_data;
++extern struct ar71xx_eth_pll_data ar71xx_eth1_pll_data;
++
++extern struct ag71xx_platform_data ar71xx_eth0_data;
++extern struct ag71xx_platform_data ar71xx_eth1_data;
++extern struct platform_device ar71xx_eth0_device;
++extern struct platform_device ar71xx_eth1_device;
++void ar71xx_add_device_eth(unsigned int id) __init;
++
++extern struct platform_device ar71xx_mdio_device;
++void ar71xx_add_device_mdio(u32 phy_mask) __init;
++
++void ar71xx_add_device_uart(void) __init;
++
++void ar71xx_add_device_wdt(void) __init;
++
++#endif /* __AR71XX_DEVICES_H */
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/early_printk.c linux-2.6.37/arch/mips/ar71xx/early_printk.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/early_printk.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/early_printk.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,30 @@
++/*
++ * Atheros AR71xx SoC early printk support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/io.h>
++#include <linux/serial_reg.h>
++#include <asm/addrspace.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#define UART_READ(r) \
++ __raw_readl((void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4 * (r)))
++
++#define UART_WRITE(r, v) \
++ __raw_writel((v), (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4*(r)))
++
++void prom_putchar(unsigned char ch)
++{
++ while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0);
++ UART_WRITE(UART_TX, ch);
++ while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0);
++}
++
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/gpio.c linux-2.6.37/arch/mips/ar71xx/gpio.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/gpio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/gpio.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,182 @@
++/*
++ * Atheros AR71xx SoC GPIO API support
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/spinlock.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/gpio.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++static DEFINE_SPINLOCK(ar71xx_gpio_lock);
++
++unsigned long ar71xx_gpio_count;
++EXPORT_SYMBOL(ar71xx_gpio_count);
++
++void __ar71xx_gpio_set_value(unsigned gpio, int value)
++{
++ void __iomem *base = ar71xx_gpio_base;
++
++ if (value)
++ __raw_writel(1 << gpio, base + GPIO_REG_SET);
++ else
++ __raw_writel(1 << gpio, base + GPIO_REG_CLEAR);
++}
++EXPORT_SYMBOL(__ar71xx_gpio_set_value);
++
++int __ar71xx_gpio_get_value(unsigned gpio)
++{
++ return (__raw_readl(ar71xx_gpio_base + GPIO_REG_IN) >> gpio) & 1;
++}
++EXPORT_SYMBOL(__ar71xx_gpio_get_value);
++
++static int ar71xx_gpio_get_value(struct gpio_chip *chip, unsigned offset)
++{
++ return __ar71xx_gpio_get_value(offset);
++}
++
++static void ar71xx_gpio_set_value(struct gpio_chip *chip,
++ unsigned offset, int value)
++{
++ __ar71xx_gpio_set_value(offset, value);
++}
++
++static int ar71xx_gpio_direction_input(struct gpio_chip *chip,
++ unsigned offset)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ar71xx_gpio_lock, flags);
++
++ __raw_writel(__raw_readl(base + GPIO_REG_OE) & ~(1 << offset),
++ base + GPIO_REG_OE);
++
++ spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
++
++ return 0;
++}
++
++static int ar71xx_gpio_direction_output(struct gpio_chip *chip,
++ unsigned offset, int value)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ar71xx_gpio_lock, flags);
++
++ if (value)
++ __raw_writel(1 << offset, base + GPIO_REG_SET);
++ else
++ __raw_writel(1 << offset, base + GPIO_REG_CLEAR);
++
++ __raw_writel(__raw_readl(base + GPIO_REG_OE) | (1 << offset),
++ base + GPIO_REG_OE);
++
++ spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
++
++ return 0;
++}
++
++static struct gpio_chip ar71xx_gpio_chip = {
++ .label = "ar71xx",
++ .get = ar71xx_gpio_get_value,
++ .set = ar71xx_gpio_set_value,
++ .direction_input = ar71xx_gpio_direction_input,
++ .direction_output = ar71xx_gpio_direction_output,
++ .base = 0,
++ .ngpio = AR71XX_GPIO_COUNT,
++};
++
++void ar71xx_gpio_function_enable(u32 mask)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ar71xx_gpio_lock, flags);
++
++ __raw_writel(__raw_readl(base + GPIO_REG_FUNC) | mask,
++ base + GPIO_REG_FUNC);
++ /* flush write */
++ (void) __raw_readl(base + GPIO_REG_FUNC);
++
++ spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
++}
++
++void ar71xx_gpio_function_disable(u32 mask)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ar71xx_gpio_lock, flags);
++
++ __raw_writel(__raw_readl(base + GPIO_REG_FUNC) & ~mask,
++ base + GPIO_REG_FUNC);
++ /* flush write */
++ (void) __raw_readl(base + GPIO_REG_FUNC);
++
++ spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
++}
++
++void ar71xx_gpio_function_setup(u32 set, u32 clear)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ar71xx_gpio_lock, flags);
++
++ __raw_writel((__raw_readl(base + GPIO_REG_FUNC) & ~clear) | set,
++ base + GPIO_REG_FUNC);
++ /* flush write */
++ (void) __raw_readl(base + GPIO_REG_FUNC);
++
++ spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
++}
++EXPORT_SYMBOL(ar71xx_gpio_function_setup);
++
++void __init ar71xx_gpio_init(void)
++{
++ int err;
++
++ if (!request_mem_region(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
++ "AR71xx GPIO controller"))
++ panic("cannot allocate AR71xx GPIO registers page");
++
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7130:
++ case AR71XX_SOC_AR7141:
++ case AR71XX_SOC_AR7161:
++ ar71xx_gpio_chip.ngpio = AR71XX_GPIO_COUNT;
++ break;
++
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ ar71xx_gpio_chip.ngpio = AR724X_GPIO_COUNT;
++ break;
++
++ case AR71XX_SOC_AR9130:
++ case AR71XX_SOC_AR9132:
++ ar71xx_gpio_chip.ngpio = AR91XX_GPIO_COUNT;
++ break;
++
++ default:
++ BUG();
++ }
++
++ err = gpiochip_add(&ar71xx_gpio_chip);
++ if (err)
++ panic("cannot add AR71xx GPIO chip, error=%d", err);
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/irq.c linux-2.6.37/arch/mips/ar71xx/irq.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/irq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/irq.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,295 @@
++/*
++ * Atheros AR71xx SoC specific interrupt handling
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++
++#include <asm/irq_cpu.h>
++#include <asm/mipsregs.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++static int ip2_flush_reg;
++
++static void ar71xx_gpio_irq_dispatch(void)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ u32 pending;
++
++ pending = __raw_readl(base + GPIO_REG_INT_PENDING) &
++ __raw_readl(base + GPIO_REG_INT_ENABLE);
++
++ if (pending)
++ do_IRQ(AR71XX_GPIO_IRQ_BASE + fls(pending) - 1);
++ else
++ spurious_interrupt();
++}
++
++static void ar71xx_gpio_irq_unmask(unsigned int irq)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ u32 t;
++
++ irq -= AR71XX_GPIO_IRQ_BASE;
++
++ t = __raw_readl(base + GPIO_REG_INT_ENABLE);
++ __raw_writel(t | (1 << irq), base + GPIO_REG_INT_ENABLE);
++
++ /* flush write */
++ (void) __raw_readl(base + GPIO_REG_INT_ENABLE);
++}
++
++static void ar71xx_gpio_irq_mask(unsigned int irq)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ u32 t;
++
++ irq -= AR71XX_GPIO_IRQ_BASE;
++
++ t = __raw_readl(base + GPIO_REG_INT_ENABLE);
++ __raw_writel(t & ~(1 << irq), base + GPIO_REG_INT_ENABLE);
++
++ /* flush write */
++ (void) __raw_readl(base + GPIO_REG_INT_ENABLE);
++}
++
++#if 0
++static int ar71xx_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
++{
++ /* TODO: implement */
++ return 0;
++}
++#else
++#define ar71xx_gpio_irq_set_type NULL
++#endif
++
++static struct irq_chip ar71xx_gpio_irq_chip = {
++ .name = "AR71XX GPIO",
++ .unmask = ar71xx_gpio_irq_unmask,
++ .mask = ar71xx_gpio_irq_mask,
++ .mask_ack = ar71xx_gpio_irq_mask,
++ .set_type = ar71xx_gpio_irq_set_type,
++};
++
++static struct irqaction ar71xx_gpio_irqaction = {
++ .handler = no_action,
++ .name = "cascade [AR71XX GPIO]",
++};
++
++#define GPIO_IRQ_INIT_STATUS (IRQ_LEVEL | IRQ_TYPE_LEVEL_HIGH | IRQ_DISABLED)
++#define GPIO_INT_ALL 0xffff
++
++static void __init ar71xx_gpio_irq_init(void)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ int i;
++
++ __raw_writel(0, base + GPIO_REG_INT_ENABLE);
++ __raw_writel(0, base + GPIO_REG_INT_PENDING);
++
++ /* setup type of all GPIO interrupts to level sensitive */
++ __raw_writel(GPIO_INT_ALL, base + GPIO_REG_INT_TYPE);
++
++ /* setup polarity of all GPIO interrupts to active high */
++ __raw_writel(GPIO_INT_ALL, base + GPIO_REG_INT_POLARITY);
++
++ for (i = AR71XX_GPIO_IRQ_BASE;
++ i < AR71XX_GPIO_IRQ_BASE + AR71XX_GPIO_IRQ_COUNT; i++) {
++ irq_desc[i].status = GPIO_IRQ_INIT_STATUS;
++ set_irq_chip_and_handler(i, &ar71xx_gpio_irq_chip,
++ handle_level_irq);
++ }
++
++ setup_irq(AR71XX_MISC_IRQ_GPIO, &ar71xx_gpio_irqaction);
++}
++
++static void ar71xx_misc_irq_dispatch(void)
++{
++ u32 pending;
++
++ pending = ar71xx_reset_rr(AR71XX_RESET_REG_MISC_INT_STATUS)
++ & ar71xx_reset_rr(AR71XX_RESET_REG_MISC_INT_ENABLE);
++
++ if (pending & MISC_INT_UART)
++ do_IRQ(AR71XX_MISC_IRQ_UART);
++
++ else if (pending & MISC_INT_DMA)
++ do_IRQ(AR71XX_MISC_IRQ_DMA);
++
++ else if (pending & MISC_INT_PERFC)
++ do_IRQ(AR71XX_MISC_IRQ_PERFC);
++
++ else if (pending & MISC_INT_TIMER)
++ do_IRQ(AR71XX_MISC_IRQ_TIMER);
++
++ else if (pending & MISC_INT_OHCI)
++ do_IRQ(AR71XX_MISC_IRQ_OHCI);
++
++ else if (pending & MISC_INT_ERROR)
++ do_IRQ(AR71XX_MISC_IRQ_ERROR);
++
++ else if (pending & MISC_INT_GPIO)
++ ar71xx_gpio_irq_dispatch();
++
++ else if (pending & MISC_INT_WDOG)
++ do_IRQ(AR71XX_MISC_IRQ_WDOG);
++
++ else
++ spurious_interrupt();
++}
++
++static void ar71xx_misc_irq_unmask(unsigned int irq)
++{
++ void __iomem *base = ar71xx_reset_base;
++ u32 t;
++
++ irq -= AR71XX_MISC_IRQ_BASE;
++
++ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++ __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++
++ /* flush write */
++ (void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++}
++
++static void ar71xx_misc_irq_mask(unsigned int irq)
++{
++ void __iomem *base = ar71xx_reset_base;
++ u32 t;
++
++ irq -= AR71XX_MISC_IRQ_BASE;
++
++ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++ __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++
++ /* flush write */
++ (void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++}
++
++static void ar724x_misc_irq_ack(unsigned int irq)
++{
++ void __iomem *base = ar71xx_reset_base;
++ u32 t;
++
++ irq -= AR71XX_MISC_IRQ_BASE;
++
++ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
++ __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
++
++ /* flush write */
++ (void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
++}
++
++static struct irq_chip ar71xx_misc_irq_chip = {
++ .name = "AR71XX MISC",
++ .unmask = ar71xx_misc_irq_unmask,
++ .mask = ar71xx_misc_irq_mask,
++};
++
++static struct irqaction ar71xx_misc_irqaction = {
++ .handler = no_action,
++ .name = "cascade [AR71XX MISC]",
++};
++
++static void __init ar71xx_misc_irq_init(void)
++{
++ void __iomem *base = ar71xx_reset_base;
++ int i;
++
++ __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
++ __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
++
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ ar71xx_misc_irq_chip.ack = ar724x_misc_irq_ack;
++ break;
++ default:
++ ar71xx_misc_irq_chip.mask_ack = ar71xx_misc_irq_mask;
++ break;
++ }
++
++ for (i = AR71XX_MISC_IRQ_BASE;
++ i < AR71XX_MISC_IRQ_BASE + AR71XX_MISC_IRQ_COUNT; i++) {
++ irq_desc[i].status = IRQ_DISABLED;
++ set_irq_chip_and_handler(i, &ar71xx_misc_irq_chip,
++ handle_level_irq);
++ }
++
++ setup_irq(AR71XX_CPU_IRQ_MISC, &ar71xx_misc_irqaction);
++}
++
++asmlinkage void plat_irq_dispatch(void)
++{
++ unsigned long pending;
++
++ pending = read_c0_status() & read_c0_cause() & ST0_IM;
++
++ if (pending & STATUSF_IP7)
++ do_IRQ(AR71XX_CPU_IRQ_TIMER);
++
++ else if (pending & STATUSF_IP2) {
++ /*
++ * This IRQ is meant for a PCI device. Drivers for PCI devices
++ * typically allocate coherent DMA memory for the descriptor
++ * ring, however the DMA controller may still have some
++ * unsynchronized data in the FIFO.
++ * Issue a flush here to ensure that the driver sees the update.
++ */
++ ar71xx_ddr_flush(ip2_flush_reg);
++ do_IRQ(AR71XX_CPU_IRQ_IP2);
++ }
++
++ else if (pending & STATUSF_IP4)
++ do_IRQ(AR71XX_CPU_IRQ_GE0);
++
++ else if (pending & STATUSF_IP5)
++ do_IRQ(AR71XX_CPU_IRQ_GE1);
++
++ else if (pending & STATUSF_IP3)
++ do_IRQ(AR71XX_CPU_IRQ_USB);
++
++ else if (pending & STATUSF_IP6)
++ ar71xx_misc_irq_dispatch();
++
++ else
++ spurious_interrupt();
++}
++
++void __init arch_init_irq(void)
++{
++ switch(ar71xx_soc) {
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE;
++ break;
++ case AR71XX_SOC_AR9130:
++ case AR71XX_SOC_AR9132:
++ ip2_flush_reg = AR91XX_DDR_REG_FLUSH_WMAC;
++ break;
++ default:
++ ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI;
++ break;
++ }
++ mips_cpu_irq_init();
++
++ ar71xx_misc_irq_init();
++
++ cp0_perfcount_irq = AR71XX_MISC_IRQ_PERFC;
++
++ ar71xx_gpio_irq_init();
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-ap81.c linux-2.6.37/arch/mips/ar71xx/mach-ap81.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-ap81.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-ap81.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,140 @@
++/*
++ * Atheros AP81 board support
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2009 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define AP81_GPIO_LED_STATUS 1
++#define AP81_GPIO_LED_AOSS 3
++#define AP81_GPIO_LED_WLAN 6
++#define AP81_GPIO_LED_POWER 14
++
++#define AP81_GPIO_BTN_SW4 12
++#define AP81_GPIO_BTN_SW1 21
++
++#define AP81_BUTTONS_POLL_INTERVAL 20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition ap81_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x040000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "u-boot-env",
++ .offset = 0x040000,
++ .size = 0x010000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x050000,
++ .size = 0x500000,
++ } , {
++ .name = "uImage",
++ .offset = 0x550000,
++ .size = 0x100000,
++ } , {
++ .name = "ART",
++ .offset = 0x650000,
++ .size = 0x1b0000,
++ .mask_flags = MTD_WRITEABLE,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data ap81_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = ap81_partitions,
++ .nr_parts = ARRAY_SIZE(ap81_partitions),
++#endif
++};
++
++static struct gpio_led ap81_leds_gpio[] __initdata = {
++ {
++ .name = "ap81:green:status",
++ .gpio = AP81_GPIO_LED_STATUS,
++ .active_low = 1,
++ }, {
++ .name = "ap81:amber:aoss",
++ .gpio = AP81_GPIO_LED_AOSS,
++ .active_low = 1,
++ }, {
++ .name = "ap81:green:wlan",
++ .gpio = AP81_GPIO_LED_WLAN,
++ .active_low = 1,
++ }, {
++ .name = "ap81:green:power",
++ .gpio = AP81_GPIO_LED_POWER,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button ap81_gpio_buttons[] __initdata = {
++ {
++ .desc = "sw1",
++ .type = EV_KEY,
++ .code = BTN_0,
++ .threshold = 3,
++ .gpio = AP81_GPIO_BTN_SW1,
++ .active_low = 1,
++ } , {
++ .desc = "sw4",
++ .type = EV_KEY,
++ .code = BTN_1,
++ .threshold = 3,
++ .gpio = AP81_GPIO_BTN_SW4,
++ .active_low = 1,
++ }
++};
++
++static void __init ap81_setup(void)
++{
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++ ar71xx_set_mac_base(eeprom);
++ ar71xx_add_device_mdio(0x0);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++ ar71xx_eth0_data.has_ar8216 = 1;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.phy_mask = 0x10;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_usb();
++
++ ar71xx_add_device_m25p80(&ap81_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ap81_leds_gpio),
++ ap81_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, AP81_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(ap81_gpio_buttons),
++ ap81_gpio_buttons);
++
++ ar913x_add_device_wmac(eeprom, NULL);
++}
++
++MIPS_MACHINE(AR71XX_MACH_AP81, "AP81", "Atheros AP81", ap81_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-ap83.c linux-2.6.37/arch/mips/ar71xx/mach-ap83.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-ap83.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-ap83.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,266 @@
++/*
++ * Atheros AP83 board support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_gpio.h>
++#include <linux/spi/vsc7385.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/ar91xx_flash.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define AP83_GPIO_LED_WLAN 6
++#define AP83_GPIO_LED_POWER 14
++#define AP83_GPIO_LED_JUMPSTART 15
++#define AP83_GPIO_BTN_JUMPSTART 12
++#define AP83_GPIO_BTN_RESET 21
++
++#define AP83_050_GPIO_VSC7385_CS 1
++#define AP83_050_GPIO_VSC7385_MISO 3
++#define AP83_050_GPIO_VSC7385_MOSI 16
++#define AP83_050_GPIO_VSC7385_SCK 17
++
++#define AP83_BUTTONS_POLL_INTERVAL 20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition ap83_flash_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x040000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "u-boot-env",
++ .offset = 0x040000,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "kernel",
++ .offset = 0x060000,
++ .size = 0x140000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x1a0000,
++ .size = 0x650000,
++ } , {
++ .name = "art",
++ .offset = 0x7f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x060000,
++ .size = 0x790000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct ar91xx_flash_platform_data ap83_flash_data = {
++ .width = 2,
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = ap83_flash_partitions,
++ .nr_parts = ARRAY_SIZE(ap83_flash_partitions),
++#endif
++};
++
++static struct resource ap83_flash_resources[] = {
++ [0] = {
++ .start = AR71XX_SPI_BASE,
++ .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++static struct platform_device ap83_flash_device = {
++ .name = "ar91xx-flash",
++ .id = -1,
++ .resource = ap83_flash_resources,
++ .num_resources = ARRAY_SIZE(ap83_flash_resources),
++ .dev = {
++ .platform_data = &ap83_flash_data,
++ }
++};
++
++static struct gpio_led ap83_leds_gpio[] __initdata = {
++ {
++ .name = "ap83:green:jumpstart",
++ .gpio = AP83_GPIO_LED_JUMPSTART,
++ .active_low = 0,
++ }, {
++ .name = "ap83:green:power",
++ .gpio = AP83_GPIO_LED_POWER,
++ .active_low = 0,
++ }, {
++ .name = "ap83:green:wlan",
++ .gpio = AP83_GPIO_LED_WLAN,
++ .active_low = 0,
++ },
++};
++
++static struct gpio_button ap83_gpio_buttons[] __initdata = {
++ {
++ .desc = "soft_reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = AP83_GPIO_BTN_RESET,
++ .active_low = 1,
++ } , {
++ .desc = "jumpstart",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = AP83_GPIO_BTN_JUMPSTART,
++ .active_low = 1,
++ }
++};
++
++static struct resource ap83_040_spi_resources[] = {
++ [0] = {
++ .start = AR71XX_SPI_BASE,
++ .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++static struct platform_device ap83_040_spi_device = {
++ .name = "ap83-spi",
++ .id = 0,
++ .resource = ap83_040_spi_resources,
++ .num_resources = ARRAY_SIZE(ap83_040_spi_resources),
++};
++
++static struct spi_gpio_platform_data ap83_050_spi_data = {
++ .miso = AP83_050_GPIO_VSC7385_MISO,
++ .mosi = AP83_050_GPIO_VSC7385_MOSI,
++ .sck = AP83_050_GPIO_VSC7385_SCK,
++ .num_chipselect = 1,
++};
++
++static struct platform_device ap83_050_spi_device = {
++ .name = "spi_gpio",
++ .id = 0,
++ .dev = {
++ .platform_data = &ap83_050_spi_data,
++ }
++};
++
++static void ap83_vsc7385_reset(void)
++{
++ ar71xx_device_stop(RESET_MODULE_GE1_PHY);
++ udelay(10);
++ ar71xx_device_start(RESET_MODULE_GE1_PHY);
++ mdelay(50);
++}
++
++static struct vsc7385_platform_data ap83_vsc7385_data = {
++ .reset = ap83_vsc7385_reset,
++ .ucode_name = "vsc7385_ucode_ap83.bin",
++ .mac_cfg = {
++ .tx_ipg = 6,
++ .bit2 = 0,
++ .clk_sel = 3,
++ },
++};
++
++static struct spi_board_info ap83_spi_info[] = {
++ {
++ .bus_num = 0,
++ .chip_select = 0,
++ .max_speed_hz = 25000000,
++ .modalias = "spi-vsc7385",
++ .platform_data = &ap83_vsc7385_data,
++ .controller_data = (void *) AP83_050_GPIO_VSC7385_CS,
++ }
++};
++
++static void __init ap83_generic_setup(void)
++{
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++ ar71xx_set_mac_base(eeprom);
++
++ ar71xx_add_device_mdio(0xfffffffe);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth0_data.phy_mask = 0x1;
++
++ ar71xx_add_device_eth(0);
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth1_data.speed = SPEED_1000;
++ ar71xx_eth1_data.duplex = DUPLEX_FULL;
++
++ ar71xx_eth1_pll_data.pll_1000 = 0x1f000000;
++
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ap83_leds_gpio),
++ ap83_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, AP83_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(ap83_gpio_buttons),
++ ap83_gpio_buttons);
++
++ ar71xx_add_device_usb();
++
++ ar913x_add_device_wmac(eeprom, NULL);
++
++ platform_device_register(&ap83_flash_device);
++
++ spi_register_board_info(ap83_spi_info, ARRAY_SIZE(ap83_spi_info));
++}
++
++static void __init ap83_040_setup(void)
++{
++ ap83_flash_data.is_shared=1;
++ ap83_generic_setup();
++ platform_device_register(&ap83_040_spi_device);
++}
++
++static void __init ap83_050_setup(void)
++{
++ ap83_generic_setup();
++ platform_device_register(&ap83_050_spi_device);
++}
++
++static void __init ap83_setup(void)
++{
++ u8 *board_id = (u8 *) KSEG1ADDR(0x1fff1244);
++ unsigned int board_version;
++
++ board_version = (unsigned int)(board_id[0] - '0');
++ board_version += ((unsigned int)(board_id[1] - '0')) * 10;
++
++ switch (board_version) {
++ case 40:
++ ap83_040_setup();
++ break;
++ case 50:
++ ap83_050_setup();
++ break;
++ default:
++ printk(KERN_WARNING "AP83-%03u board is not yet supported\n",
++ board_version);
++ }
++}
++
++MIPS_MACHINE(AR71XX_MACH_AP83, "AP83", "Atheros AP83", ap83_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-aw-nr580.c linux-2.6.37/arch/mips/ar71xx/mach-aw-nr580.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-aw-nr580.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-aw-nr580.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,101 @@
++/*
++ * AzureWave AW-NR580 board support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mips_machine.h>
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-gpio-buttons.h"
++#include "dev-pb42-pci.h"
++#include "dev-leds-gpio.h"
++
++#define AW_NR580_GPIO_LED_READY_RED 0
++#define AW_NR580_GPIO_LED_WLAN 1
++#define AW_NR580_GPIO_LED_READY_GREEN 2
++#define AW_NR580_GPIO_LED_WPS_GREEN 4
++#define AW_NR580_GPIO_LED_WPS_AMBER 5
++
++#define AW_NR580_GPIO_BTN_WPS 3
++#define AW_NR580_GPIO_BTN_RESET 11
++
++#define AW_NR580_BUTTONS_POLL_INTERVAL 20
++
++static struct gpio_led aw_nr580_leds_gpio[] __initdata = {
++ {
++ .name = "aw-nr580:red:ready",
++ .gpio = AW_NR580_GPIO_LED_READY_RED,
++ .active_low = 0,
++ }, {
++ .name = "aw-nr580:green:ready",
++ .gpio = AW_NR580_GPIO_LED_READY_GREEN,
++ .active_low = 0,
++ }, {
++ .name = "aw-nr580:green:wps",
++ .gpio = AW_NR580_GPIO_LED_WPS_GREEN,
++ .active_low = 0,
++ }, {
++ .name = "aw-nr580:amber:wps",
++ .gpio = AW_NR580_GPIO_LED_WPS_AMBER,
++ .active_low = 0,
++ }, {
++ .name = "aw-nr580:green:wlan",
++ .gpio = AW_NR580_GPIO_LED_WLAN,
++ .active_low = 0,
++ }
++};
++
++static struct gpio_button aw_nr580_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = AW_NR580_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "wps",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = AW_NR580_GPIO_BTN_WPS,
++ .active_low = 1,
++ }
++};
++
++static void __init aw_nr580_setup(void)
++{
++ ar71xx_add_device_mdio(0x0);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++ ar71xx_add_device_eth(0);
++
++ pb42_pci_init();
++
++ ar71xx_add_device_m25p80(NULL);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(aw_nr580_leds_gpio),
++ aw_nr580_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, AW_NR580_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(aw_nr580_gpio_buttons),
++ aw_nr580_gpio_buttons);
++}
++
++MIPS_MACHINE(AR71XX_MACH_AW_NR580, "AW-NR580", "AzureWave AW-NR580",
++ aw_nr580_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-dir-600-a1.c linux-2.6.37/arch/mips/ar71xx/mach-dir-600-a1.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-dir-600-a1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-dir-600-a1.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,138 @@
++/*
++ * D-Link DIR-600 rev. A1 board support
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ap91-eth.h"
++#include "dev-ap91-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "nvram.h"
++
++#define DIR_600_A1_GPIO_LED_WPS 0
++#define DIR_600_A1_GPIO_LED_POWER_AMBER 1
++#define DIR_600_A1_GPIO_LED_POWER_GREEN 6
++
++#define DIR_600_A1_GPIO_BTN_RESET 8
++#define DIR_600_A1_GPIO_BTN_WPS 12
++
++#define DIR_600_A1_BUTTONS_POLL_INTERVAL 20
++
++#define DIR_600_A1_NVRAM_ADDR 0x1f030000
++#define DIR_600_A1_NVRAM_SIZE 0x10000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition dir_600_a1_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x030000,
++ .mask_flags = MTD_WRITEABLE,
++ }, {
++ .name = "nvram",
++ .offset = 0x030000,
++ .size = 0x010000,
++ }, {
++ .name = "kernel",
++ .offset = 0x040000,
++ .size = 0x0e0000,
++ }, {
++ .name = "rootfs",
++ .offset = 0x120000,
++ .size = 0x2c0000,
++ }, {
++ .name = "mac",
++ .offset = 0x3e0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ }, {
++ .name = "art",
++ .offset = 0x3f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ }, {
++ .name = "firmware",
++ .offset = 0x040000,
++ .size = 0x3a0000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data dir_600_a1_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = dir_600_a1_partitions,
++ .nr_parts = ARRAY_SIZE(dir_600_a1_partitions),
++#endif
++};
++
++static struct gpio_led dir_600_a1_leds_gpio[] __initdata = {
++ {
++ .name = "dir-600-a1:green:power",
++ .gpio = DIR_600_A1_GPIO_LED_POWER_GREEN,
++ }, {
++ .name = "dir-600-a1:amber:power",
++ .gpio = DIR_600_A1_GPIO_LED_POWER_AMBER,
++ }, {
++ .name = "dir-600-a1:blue:wps",
++ .gpio = DIR_600_A1_GPIO_LED_WPS,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button dir_600_a1_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = DIR_600_A1_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "wps",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = DIR_600_A1_GPIO_BTN_WPS,
++ .active_low = 1,
++ }
++};
++
++static void __init dir_600_a1_setup(void)
++{
++ const char *nvram = (char *) KSEG1ADDR(DIR_600_A1_NVRAM_ADDR);
++ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
++ u8 mac_buff[6];
++ u8 *mac = NULL;
++
++ if (nvram_parse_mac_addr(nvram, DIR_600_A1_NVRAM_SIZE,
++ "lan_mac=", mac_buff) == 0)
++ mac = mac_buff;
++
++ ar71xx_add_device_m25p80(&dir_600_a1_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(dir_600_a1_leds_gpio),
++ dir_600_a1_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, DIR_600_A1_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(dir_600_a1_gpio_buttons),
++ dir_600_a1_gpio_buttons);
++
++ ap91_eth_init(mac, NULL);
++ ap91_pci_init(ee, mac);
++}
++
++MIPS_MACHINE(AR71XX_MACH_DIR_600_A1, "DIR-600-A1", "D-Link DIR-600 rev. A1",
++ dir_600_a1_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-dir-615-c1.c linux-2.6.37/arch/mips/ar71xx/mach-dir-615-c1.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-dir-615-c1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-dir-615-c1.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,173 @@
++/*
++ * D-Link DIR-615 rev C1 board support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "nvram.h"
++
++#define DIR_615C1_GPIO_LED_ORANGE_STATUS 1 /* ORANGE:STATUS:TRICOLOR */
++#define DIR_615C1_GPIO_LED_BLUE_WPS 3 /* BLUE:WPS */
++#define DIR_615C1_GPIO_LED_GREEN_WAN 4 /* GREEN:WAN:TRICOLOR */
++#define DIR_615C1_GPIO_LED_GREEN_WANCPU 5 /* GREEN:WAN:CPU:TRICOLOR */
++#define DIR_615C1_GPIO_LED_GREEN_WLAN 6 /* GREEN:WLAN */
++#define DIR_615C1_GPIO_LED_GREEN_STATUS 14 /* GREEN:STATUS:TRICOLOR */
++#define DIR_615C1_GPIO_LED_ORANGE_WAN 15 /* ORANGE:WAN:TRICOLOR */
++
++/* buttons may need refinement */
++
++#define DIR_615C1_GPIO_BTN_WPS 12
++#define DIR_615C1_GPIO_BTN_RESET 21
++
++#define DIR_615C1_BUTTONS_POLL_INTERVAL 20
++
++#define DIR_615C1_CONFIG_ADDR 0x1f020000
++#define DIR_615C1_CONFIG_SIZE 0x10000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition dir_615c1_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "config",
++ .offset = 0x020000,
++ .size = 0x010000,
++ } , {
++ .name = "kernel",
++ .offset = 0x030000,
++ .size = 0x0d0000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x100000,
++ .size = 0x2f0000,
++ } , {
++ .name = "art",
++ .offset = 0x3f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x030000,
++ .size = 0x3c0000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data dir_615c1_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = dir_615c1_partitions,
++ .nr_parts = ARRAY_SIZE(dir_615c1_partitions),
++#endif
++};
++
++static struct gpio_led dir_615c1_leds_gpio[] __initdata = {
++ {
++ .name = "dir-615c1:orange:status",
++ .gpio = DIR_615C1_GPIO_LED_ORANGE_STATUS,
++ .active_low = 1,
++ }, {
++ .name = "dir-615c1:blue:wps",
++ .gpio = DIR_615C1_GPIO_LED_BLUE_WPS,
++ .active_low = 1,
++ }, {
++ .name = "dir-615c1:green:wan",
++ .gpio = DIR_615C1_GPIO_LED_GREEN_WAN,
++ .active_low = 1,
++ }, {
++ .name = "dir-615c1:green:wancpu",
++ .gpio = DIR_615C1_GPIO_LED_GREEN_WANCPU,
++ .active_low = 1,
++ }, {
++ .name = "dir-615c1:green:wlan",
++ .gpio = DIR_615C1_GPIO_LED_GREEN_WLAN,
++ .active_low = 1,
++ }, {
++ .name = "dir-615c1:green:status",
++ .gpio = DIR_615C1_GPIO_LED_GREEN_STATUS,
++ .active_low = 1,
++ }, {
++ .name = "dir-615c1:orange:wan",
++ .gpio = DIR_615C1_GPIO_LED_ORANGE_WAN,
++ .active_low = 1,
++ }
++
++};
++
++static struct gpio_button dir_615c1_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = DIR_615C1_GPIO_BTN_RESET,
++ }, {
++ .desc = "wps",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = DIR_615C1_GPIO_BTN_WPS,
++ }
++};
++
++#define DIR_615C1_LAN_PHYMASK BIT(0)
++#define DIR_615C1_WAN_PHYMASK BIT(4)
++#define DIR_615C1_MDIO_MASK (~(DIR_615C1_LAN_PHYMASK | \
++ DIR_615C1_WAN_PHYMASK))
++
++static void __init dir_615c1_setup(void)
++{
++ const char *config = (char *) KSEG1ADDR(DIR_615C1_CONFIG_ADDR);
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++ u8 mac[6];
++ u8 *wlan_mac = NULL;
++
++ if (nvram_parse_mac_addr(config, DIR_615C1_CONFIG_SIZE,
++ "lan_mac=", mac) == 0) {
++ ar71xx_set_mac_base(mac);
++ wlan_mac = mac;
++ }
++
++ ar71xx_add_device_mdio(DIR_615C1_MDIO_MASK);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.phy_mask = DIR_615C1_LAN_PHYMASK;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.phy_mask = DIR_615C1_WAN_PHYMASK;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_m25p80(&dir_615c1_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(dir_615c1_leds_gpio),
++ dir_615c1_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, DIR_615C1_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(dir_615c1_gpio_buttons),
++ dir_615c1_gpio_buttons);
++
++ ar913x_add_device_wmac(eeprom, wlan_mac);
++}
++
++MIPS_MACHINE(AR71XX_MACH_DIR_615_C1, "DIR-615-C1", "D-Link DIR-615 rev. C1",
++ dir_615c1_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-dir-825-b1.c linux-2.6.37/arch/mips/ar71xx/mach-dir-825-b1.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-dir-825-b1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-dir-825-b1.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,192 @@
++/*
++ * D-Link DIR-825 rev. B1 board support
++ *
++ * Copyright (C) 2009 Lukas Kuna, Evkanet, s.r.o.
++ *
++ * based on mach-wndr3700.c
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/delay.h>
++#include <linux/rtl8366s.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ap94-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define DIR825B1_GPIO_LED_BLUE_USB 0
++#define DIR825B1_GPIO_LED_ORANGE_POWER 1
++#define DIR825B1_GPIO_LED_BLUE_POWER 2
++#define DIR825B1_GPIO_LED_BLUE_POWERSAVE 4
++#define DIR825B1_GPIO_LED_ORANGE_PLANET 6
++#define DIR825B1_GPIO_LED_BLUE_PLANET 11
++
++#define DIR825B1_GPIO_BTN_RESET 3
++#define DIR825B1_GPIO_BTN_POWERSAVE 8
++
++#define DIR825B1_GPIO_RTL8366_SDA 5
++#define DIR825B1_GPIO_RTL8366_SCK 7
++
++#define DIR825B1_BUTTONS_POLL_INTERVAL 20
++
++#define DIR825B1_CAL_LOCATION_0 0x1f661000
++#define DIR825B1_CAL_LOCATION_1 0x1f665000
++
++#define DIR825B1_MAC_LOCATION_0 0x2ffa81b8
++#define DIR825B1_MAC_LOCATION_1 0x2ffa8370
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition dir825b1_partitions[] = {
++ {
++ .name = "uboot",
++ .offset = 0,
++ .size = 0x040000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "config",
++ .offset = 0x040000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x050000,
++ .size = 0x610000,
++ } , {
++ .name = "caldata",
++ .offset = 0x660000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "unknown",
++ .offset = 0x670000,
++ .size = 0x190000,
++ .mask_flags = MTD_WRITEABLE,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data dir825b1_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = dir825b1_partitions,
++ .nr_parts = ARRAY_SIZE(dir825b1_partitions),
++#endif
++};
++
++static struct gpio_led dir825b1_leds_gpio[] __initdata = {
++ {
++ .name = "dir825b1:blue:usb",
++ .gpio = DIR825B1_GPIO_LED_BLUE_USB,
++ .active_low = 1,
++ }, {
++ .name = "dir825b1:orange:power",
++ .gpio = DIR825B1_GPIO_LED_ORANGE_POWER,
++ .active_low = 1,
++ }, {
++ .name = "dir825b1:blue:power",
++ .gpio = DIR825B1_GPIO_LED_BLUE_POWER,
++ .active_low = 1,
++ }, {
++ .name = "dir825b1:blue:powersave",
++ .gpio = DIR825B1_GPIO_LED_BLUE_POWERSAVE,
++ .active_low = 1,
++ }, {
++ .name = "dir825b1:orange:planet",
++ .gpio = DIR825B1_GPIO_LED_ORANGE_PLANET,
++ .active_low = 1,
++ }, {
++ .name = "dir825b1:blue:planet",
++ .gpio = DIR825B1_GPIO_LED_BLUE_PLANET,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button dir825b1_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = DIR825B1_GPIO_BTN_RESET,
++ .active_low = 1,
++ } , {
++ .desc = "powersave",
++ .type = EV_KEY,
++ .code = BTN_1,
++ .threshold = 3,
++ .gpio = DIR825B1_GPIO_BTN_POWERSAVE,
++ .active_low = 1,
++ }
++};
++
++static struct rtl8366s_platform_data dir825b1_rtl8366s_data = {
++ .gpio_sda = DIR825B1_GPIO_RTL8366_SDA,
++ .gpio_sck = DIR825B1_GPIO_RTL8366_SCK,
++};
++
++static struct platform_device dir825b1_rtl8366s_device = {
++ .name = RTL8366S_DRIVER_NAME,
++ .id = -1,
++ .dev = {
++ .platform_data = &dir825b1_rtl8366s_data,
++ }
++};
++
++static void __init dir825b1_setup(void)
++{
++ u8 mac[6], i;
++
++ memcpy(mac, (u8*)KSEG1ADDR(DIR825B1_MAC_LOCATION_1), 6);
++ for(i = 5; i >= 3; i--)
++ if(++mac[i] != 0x00) break;
++
++ ar71xx_set_mac_base(mac);
++
++ ar71xx_add_device_mdio(0x0);
++
++ ar71xx_eth0_data.mii_bus_dev = &dir825b1_rtl8366s_device.dev;
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth0_data.speed = SPEED_1000;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++ ar71xx_eth0_pll_data.pll_1000 = 0x11110000;
++
++ ar71xx_eth1_data.mii_bus_dev = &dir825b1_rtl8366s_device.dev;
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth1_data.phy_mask = 0x10;
++ ar71xx_eth1_pll_data.pll_1000 = 0x11110000;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_m25p80(&dir825b1_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(dir825b1_leds_gpio),
++ dir825b1_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, DIR825B1_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(dir825b1_gpio_buttons),
++ dir825b1_gpio_buttons);
++
++ ar71xx_add_device_usb();
++
++ platform_device_register(&dir825b1_rtl8366s_device);
++
++ ap94_pci_init((u8 *) KSEG1ADDR(DIR825B1_CAL_LOCATION_0),
++ (u8 *) KSEG1ADDR(DIR825B1_MAC_LOCATION_0),
++ (u8 *) KSEG1ADDR(DIR825B1_CAL_LOCATION_1),
++ (u8 *) KSEG1ADDR(DIR825B1_MAC_LOCATION_1));
++}
++
++MIPS_MACHINE(AR71XX_MACH_DIR_825_B1, "DIR-825-B1", "D-Link DIR-825 rev. B1",
++ dir825b1_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-mzk-w04nu.c linux-2.6.37/arch/mips/ar71xx/mach-mzk-w04nu.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-mzk-w04nu.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-mzk-w04nu.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,165 @@
++/*
++ * Planex MZK-W04NU board support
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-m25p80.h"
++#include "dev-usb.h"
++
++#define MZK_W04NU_GPIO_LED_USB 0
++#define MZK_W04NU_GPIO_LED_STATUS 1
++#define MZK_W04NU_GPIO_LED_WPS 3
++#define MZK_W04NU_GPIO_LED_WLAN 6
++#define MZK_W04NU_GPIO_LED_AP 15
++#define MZK_W04NU_GPIO_LED_ROUTER 16
++
++#define MZK_W04NU_GPIO_BTN_APROUTER 5
++#define MZK_W04NU_GPIO_BTN_WPS 12
++#define MZK_W04NU_GPIO_BTN_RESET 21
++
++#define MZK_W04NU_BUTTONS_POLL_INTERVAL 20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition mzk_w04nu_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x040000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "u-boot-env",
++ .offset = 0x040000,
++ .size = 0x010000,
++ } , {
++ .name = "kernel",
++ .offset = 0x050000,
++ .size = 0x160000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x1b0000,
++ .size = 0x630000,
++ } , {
++ .name = "art",
++ .offset = 0x7e0000,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x050000,
++ .size = 0x790000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data mzk_w04nu_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = mzk_w04nu_partitions,
++ .nr_parts = ARRAY_SIZE(mzk_w04nu_partitions),
++#endif
++};
++
++static struct gpio_led mzk_w04nu_leds_gpio[] __initdata = {
++ {
++ .name = "mzk-w04nu:green:status",
++ .gpio = MZK_W04NU_GPIO_LED_STATUS,
++ .active_low = 1,
++ }, {
++ .name = "mzk-w04nu:blue:wps",
++ .gpio = MZK_W04NU_GPIO_LED_WPS,
++ .active_low = 1,
++ }, {
++ .name = "mzk-w04nu:green:wlan",
++ .gpio = MZK_W04NU_GPIO_LED_WLAN,
++ .active_low = 1,
++ }, {
++ .name = "mzk-w04nu:green:usb",
++ .gpio = MZK_W04NU_GPIO_LED_USB,
++ .active_low = 1,
++ }, {
++ .name = "mzk-w04nu:green:ap",
++ .gpio = MZK_W04NU_GPIO_LED_AP,
++ .active_low = 1,
++ }, {
++ .name = "mzk-w04nu:green:router",
++ .gpio = MZK_W04NU_GPIO_LED_ROUTER,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button mzk_w04nu_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = MZK_W04NU_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "wps",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = MZK_W04NU_GPIO_BTN_WPS,
++ .active_low = 1,
++ }, {
++ .desc = "aprouter",
++ .type = EV_KEY,
++ .code = BTN_2,
++ .threshold = 3,
++ .gpio = MZK_W04NU_GPIO_BTN_APROUTER,
++ .active_low = 0,
++ }
++};
++
++#define MZK_W04NU_WAN_PHYMASK BIT(4)
++#define MZK_W04NU_MDIO_MASK (~MZK_W04NU_WAN_PHYMASK)
++
++static void __init mzk_w04nu_setup(void)
++{
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++ ar71xx_set_mac_base(eeprom);
++
++ ar71xx_add_device_mdio(MZK_W04NU_MDIO_MASK);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++ ar71xx_eth0_data.has_ar8216 = 1;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.phy_mask = MZK_W04NU_WAN_PHYMASK;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_m25p80(&mzk_w04nu_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(mzk_w04nu_leds_gpio),
++ mzk_w04nu_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, MZK_W04NU_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(mzk_w04nu_gpio_buttons),
++ mzk_w04nu_gpio_buttons);
++ ar71xx_add_device_usb();
++
++ ar913x_add_device_wmac(eeprom, NULL);
++}
++
++MIPS_MACHINE(AR71XX_MACH_MZK_W04NU, "MZK-W04NU", "Planex MZK-W04NU",
++ mzk_w04nu_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-mzk-w300nh.c linux-2.6.37/arch/mips/ar71xx/mach-mzk-w300nh.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-mzk-w300nh.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-mzk-w300nh.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,158 @@
++/*
++ * Planex MZK-W300NH board support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++#define MZK_W300NH_GPIO_LED_STATUS 1
++#define MZK_W300NH_GPIO_LED_WPS 3
++#define MZK_W300NH_GPIO_LED_WLAN 6
++#define MZK_W300NH_GPIO_LED_AP 15
++#define MZK_W300NH_GPIO_LED_ROUTER 16
++
++#define MZK_W300NH_GPIO_BTN_APROUTER 5
++#define MZK_W300NH_GPIO_BTN_WPS 12
++#define MZK_W300NH_GPIO_BTN_RESET 21
++
++#define MZK_W04NU_BUTTONS_POLL_INTERVAL 20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition mzk_w300nh_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x040000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "u-boot-env",
++ .offset = 0x040000,
++ .size = 0x010000,
++ } , {
++ .name = "kernel",
++ .offset = 0x050000,
++ .size = 0x160000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x1b0000,
++ .size = 0x630000,
++ } , {
++ .name = "art",
++ .offset = 0x7e0000,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x050000,
++ .size = 0x790000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data mzk_w300nh_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = mzk_w300nh_partitions,
++ .nr_parts = ARRAY_SIZE(mzk_w300nh_partitions),
++#endif
++};
++
++static struct gpio_led mzk_w300nh_leds_gpio[] __initdata = {
++ {
++ .name = "mzk-w300nh:green:status",
++ .gpio = MZK_W300NH_GPIO_LED_STATUS,
++ .active_low = 1,
++ }, {
++ .name = "mzk-w300nh:blue:wps",
++ .gpio = MZK_W300NH_GPIO_LED_WPS,
++ .active_low = 1,
++ }, {
++ .name = "mzk-w300nh:green:wlan",
++ .gpio = MZK_W300NH_GPIO_LED_WLAN,
++ .active_low = 1,
++ }, {
++ .name = "mzk-w300nh:green:ap",
++ .gpio = MZK_W300NH_GPIO_LED_AP,
++ .active_low = 1,
++ }, {
++ .name = "mzk-w300nh:green:router",
++ .gpio = MZK_W300NH_GPIO_LED_ROUTER,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button mzk_w300nh_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = MZK_W300NH_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "wps",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = MZK_W300NH_GPIO_BTN_WPS,
++ .active_low = 1,
++ }, {
++ .desc = "aprouter",
++ .type = EV_KEY,
++ .code = BTN_2,
++ .threshold = 3,
++ .gpio = MZK_W300NH_GPIO_BTN_APROUTER,
++ .active_low = 0,
++ }
++};
++
++#define MZK_W300NH_WAN_PHYMASK BIT(4)
++#define MZK_W300NH_MDIO_MASK (~MZK_W300NH_WAN_PHYMASK)
++
++static void __init mzk_w300nh_setup(void)
++{
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++ ar71xx_set_mac_base(eeprom);
++
++ ar71xx_add_device_mdio(MZK_W300NH_MDIO_MASK);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++ ar71xx_eth0_data.has_ar8216 = 1;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.phy_mask = MZK_W300NH_WAN_PHYMASK;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_m25p80(&mzk_w300nh_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(mzk_w300nh_leds_gpio),
++ mzk_w300nh_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, MZK_W04NU_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(mzk_w300nh_gpio_buttons),
++ mzk_w300nh_gpio_buttons);
++ ar913x_add_device_wmac(eeprom, NULL);
++}
++
++MIPS_MACHINE(AR71XX_MACH_MZK_W300NH, "MZK-W300NH", "Planex MZK-W300NH",
++ mzk_w300nh_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-nbg460n.c linux-2.6.37/arch/mips/ar71xx/mach-nbg460n.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-nbg460n.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-nbg460n.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,222 @@
++/*
++ * Zyxel NBG 460N/550N/550NH board support
++ *
++ * Copyright (C) 2010 Michael Kurz <michi.kurz@googlemail.com>
++ *
++ * based on mach-tl-wr1043nd.c
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/delay.h>
++#include <linux/rtl8366s.h>
++
++#include <linux/i2c.h>
++#include <linux/i2c-algo-bit.h>
++#include <linux/i2c-gpio.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++/* LEDs */
++#define NBG460N_GPIO_LED_WPS 3
++#define NBG460N_GPIO_LED_WAN 6
++#define NBG460N_GPIO_LED_POWER 14
++#define NBG460N_GPIO_LED_WLAN 15
++
++/* Buttons */
++#define NBG460N_GPIO_BTN_WPS 12
++#define NBG460N_GPIO_BTN_RESET 21
++#define NBG460N_BUTTONS_POLL_INTERVAL 20
++
++/* RTC chip PCF8563 I2C interface */
++#define NBG460N_GPIO_PCF8563_SDA 8
++#define NBG460N_GPIO_PCF8563_SCK 7
++
++/* Switch configuration I2C interface */
++#define NBG460N_GPIO_RTL8366_SDA 16
++#define NBG460N_GPIO_RTL8366_SCK 18
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition nbg460n_partitions[] = {
++ {
++ .name = "Bootbase",
++ .offset = 0,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "U-Boot Config",
++ .offset = 0x010000,
++ .size = 0x030000,
++ } , {
++ .name = "U-Boot",
++ .offset = 0x040000,
++ .size = 0x030000,
++ } , {
++ .name = "linux",
++ .offset = 0x070000,
++ .size = 0x0e0000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x150000,
++ .size = 0x2a0000,
++ } , {
++ .name = "CalibData",
++ .offset = 0x3f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x070000,
++ .size = 0x380000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data nbg460n_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = nbg460n_partitions,
++ .nr_parts = ARRAY_SIZE(nbg460n_partitions),
++#endif
++};
++
++static struct gpio_led nbg460n_leds_gpio[] __initdata = {
++ {
++ .name = "nbg460n:green:power",
++ .gpio = NBG460N_GPIO_LED_POWER,
++ .active_low = 0,
++ .default_trigger = "default-on",
++ }, {
++ .name = "nbg460n:green:wps",
++ .gpio = NBG460N_GPIO_LED_WPS,
++ .active_low = 0,
++ }, {
++ .name = "nbg460n:green:wlan",
++ .gpio = NBG460N_GPIO_LED_WLAN,
++ .active_low = 0,
++ }, {
++ /* Not really for controlling the LED,
++ when set low the LED blinks uncontrollable */
++ .name = "nbg460n:green:wan",
++ .gpio = NBG460N_GPIO_LED_WAN,
++ .active_low = 0,
++ }
++};
++
++static struct gpio_button nbg460n_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = NBG460N_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "wps",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = NBG460N_GPIO_BTN_WPS,
++ .active_low = 1,
++ }
++};
++
++static struct i2c_gpio_platform_data nbg460n_i2c_device_platdata = {
++ .sda_pin = NBG460N_GPIO_PCF8563_SDA,
++ .scl_pin = NBG460N_GPIO_PCF8563_SCK,
++ .udelay = 10,
++};
++
++static struct platform_device nbg460n_i2c_device = {
++ .name = "i2c-gpio",
++ .id = -1,
++ .num_resources = 0,
++ .resource = NULL,
++ .dev = {
++ .platform_data = &nbg460n_i2c_device_platdata,
++ },
++};
++
++static struct i2c_board_info nbg460n_i2c_devs[] __initdata = {
++ {
++ I2C_BOARD_INFO("pcf8563", 0x51),
++ },
++};
++
++static void __devinit nbg460n_i2c_init(void)
++{
++ /* The gpio interface */
++ platform_device_register(&nbg460n_i2c_device);
++ /* I2C devices */
++ i2c_register_board_info(0, nbg460n_i2c_devs,
++ ARRAY_SIZE(nbg460n_i2c_devs));
++}
++
++
++static struct rtl8366s_platform_data nbg460n_rtl8366s_data = {
++ .gpio_sda = NBG460N_GPIO_RTL8366_SDA,
++ .gpio_sck = NBG460N_GPIO_RTL8366_SCK,
++};
++
++static struct platform_device nbg460n_rtl8366s_device = {
++ .name = RTL8366S_DRIVER_NAME,
++ .id = -1,
++ .dev = {
++ .platform_data = &nbg460n_rtl8366s_data,
++ }
++};
++
++static void __init nbg460n_setup(void)
++{
++ /* end of bootloader sector contains mac address*/
++ u8 *mac = (u8 *) KSEG1ADDR(0x1fc0fff8);
++ /* last sector contains wlan calib data */
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++ ar71xx_set_mac_base(mac);
++
++ /* LAN Port */
++ ar71xx_eth0_data.mii_bus_dev = &nbg460n_rtl8366s_device.dev;
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth0_data.speed = SPEED_1000;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++ /* WAN Port */
++ ar71xx_eth1_data.mii_bus_dev = &nbg460n_rtl8366s_device.dev;
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth1_data.phy_mask = 0x10;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ /* register the switch phy */
++ platform_device_register(&nbg460n_rtl8366s_device);
++
++ /* register flash */
++ ar71xx_add_device_m25p80(&nbg460n_flash_data);
++
++ ar913x_add_device_wmac(eeprom, mac);
++
++ /* register RTC chip */
++ nbg460n_i2c_init();
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(nbg460n_leds_gpio),
++ nbg460n_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, NBG460N_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(nbg460n_gpio_buttons),
++ nbg460n_gpio_buttons);
++}
++
++MIPS_MACHINE(AR71XX_MACH_NBG460N, "NBG460N", "Zyxel NBG460N/550N/550NH", nbg460n_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-pb42.c linux-2.6.37/arch/mips/ar71xx/mach-pb42.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-pb42.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-pb42.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,71 @@
++/*
++ * Atheros PB42 board support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-gpio-buttons.h"
++#include "dev-pb42-pci.h"
++#include "dev-usb.h"
++
++#define PB42_BUTTONS_POLL_INTERVAL 20
++
++#define PB42_GPIO_BTN_SW4 8
++#define PB42_GPIO_BTN_SW5 3
++
++static struct gpio_button pb42_gpio_buttons[] __initdata = {
++ {
++ .desc = "sw4",
++ .type = EV_KEY,
++ .code = BTN_0,
++ .threshold = 3,
++ .gpio = PB42_GPIO_BTN_SW4,
++ .active_low = 1,
++ } , {
++ .desc = "sw5",
++ .type = EV_KEY,
++ .code = BTN_1,
++ .threshold = 3,
++ .gpio = PB42_GPIO_BTN_SW5,
++ .active_low = 1,
++ }
++};
++
++#define PB42_WAN_PHYMASK BIT(20)
++#define PB42_LAN_PHYMASK (BIT(16) | BIT(17) | BIT(18) | BIT(19))
++#define PB42_MDIO_PHYMASK (PB42_LAN_PHYMASK | PB42_WAN_PHYMASK)
++
++static void __init pb42_init(void)
++{
++ ar71xx_add_device_m25p80(NULL);
++
++ ar71xx_add_device_mdio(~PB42_MDIO_PHYMASK);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ar71xx_eth0_data.phy_mask = PB42_WAN_PHYMASK;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.speed = SPEED_100;
++ ar71xx_eth1_data.duplex = DUPLEX_FULL;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_gpio_buttons(-1, PB42_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(pb42_gpio_buttons),
++ pb42_gpio_buttons);
++
++ pb42_pci_init();
++}
++
++MIPS_MACHINE(AR71XX_MACH_PB42, "PB42", "Atheros PB42", pb42_init);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-pb44.c linux-2.6.37/arch/mips/ar71xx/mach-pb44.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-pb44.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-pb44.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,207 @@
++/*
++ * Atheros PB44 board support
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/bitops.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/spi/vsc7385.h>
++#include <linux/i2c.h>
++#include <linux/i2c-gpio.h>
++#include <linux/i2c/pcf857x.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-pb42-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define PB44_PCF8757_VSC7395_CS 0
++#define PB44_PCF8757_STEREO_CS 1
++#define PB44_PCF8757_SLIC_CS0 2
++#define PB44_PCF8757_SLIC_TEST 3
++#define PB44_PCF8757_SLIC_INT0 4
++#define PB44_PCF8757_SLIC_INT1 5
++#define PB44_PCF8757_SW_RESET 6
++#define PB44_PCF8757_SW_JUMP 8
++#define PB44_PCF8757_LED_JUMP1 9
++#define PB44_PCF8757_LED_JUMP2 10
++#define PB44_PCF8757_TP24 11
++#define PB44_PCF8757_TP25 12
++#define PB44_PCF8757_TP26 13
++#define PB44_PCF8757_TP27 14
++#define PB44_PCF8757_TP28 15
++
++#define PB44_GPIO_I2C_SCL 0
++#define PB44_GPIO_I2C_SDA 1
++
++#define PB44_GPIO_EXP_BASE 16
++#define PB44_GPIO_VSC7395_CS (PB44_GPIO_EXP_BASE + PB44_PCF8757_VSC7395_CS)
++#define PB44_GPIO_SW_RESET (PB44_GPIO_EXP_BASE + PB44_PCF8757_SW_RESET)
++#define PB44_GPIO_SW_JUMP (PB44_GPIO_EXP_BASE + PB44_PCF8757_SW_JUMP)
++#define PB44_GPIO_LED_JUMP1 (PB44_GPIO_EXP_BASE + PB44_PCF8757_LED_JUMP1)
++#define PB44_GPIO_LED_JUMP2 (PB44_GPIO_EXP_BASE + PB44_PCF8757_LED_JUMP2)
++
++static struct i2c_gpio_platform_data pb44_i2c_gpio_data = {
++ .sda_pin = PB44_GPIO_I2C_SDA,
++ .scl_pin = PB44_GPIO_I2C_SCL,
++};
++
++static struct platform_device pb44_i2c_gpio_device = {
++ .name = "i2c-gpio",
++ .id = 0,
++ .dev = {
++ .platform_data = &pb44_i2c_gpio_data,
++ }
++};
++
++static struct pcf857x_platform_data pb44_pcf857x_data = {
++ .gpio_base = PB44_GPIO_EXP_BASE,
++};
++
++static struct i2c_board_info pb44_i2c_board_info[] __initdata = {
++ {
++ I2C_BOARD_INFO("pcf8575", 0x20),
++ .platform_data = &pb44_pcf857x_data,
++ },
++};
++
++static struct gpio_led pb44_leds_gpio[] __initdata = {
++ {
++ .name = "pb44:amber:jump1",
++ .gpio = PB44_GPIO_LED_JUMP1,
++ .active_low = 1,
++ }, {
++ .name = "pb44:green:jump2",
++ .gpio = PB44_GPIO_LED_JUMP2,
++ .active_low = 1,
++ },
++};
++
++static struct gpio_button pb44_gpio_buttons[] __initdata = {
++ {
++ .desc = "soft_reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = PB44_GPIO_SW_RESET,
++ .active_low = 1,
++ } , {
++ .desc = "jumpstart",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = PB44_GPIO_SW_JUMP,
++ .active_low = 1,
++ }
++};
++
++static void pb44_vsc7395_reset(void)
++{
++ ar71xx_device_stop(RESET_MODULE_GE1_PHY);
++ udelay(10);
++ ar71xx_device_start(RESET_MODULE_GE1_PHY);
++ mdelay(50);
++}
++
++static struct vsc7385_platform_data pb44_vsc7395_data = {
++ .reset = pb44_vsc7395_reset,
++ .ucode_name = "vsc7395_ucode_pb44.bin",
++ .mac_cfg = {
++ .tx_ipg = 6,
++ .bit2 = 1,
++ .clk_sel = 0,
++ },
++};
++
++static struct spi_board_info pb44_spi_info[] = {
++ {
++ .bus_num = 0,
++ .chip_select = 0,
++ .max_speed_hz = 25000000,
++ .modalias = "m25p80",
++ }, {
++ .bus_num = 0,
++ .chip_select = 1,
++ .max_speed_hz = 25000000,
++ .modalias = "spi-vsc7385",
++ .platform_data = &pb44_vsc7395_data,
++ .controller_data = (void *) PB44_GPIO_VSC7395_CS,
++ },
++};
++
++static struct resource pb44_spi_resources[] = {
++ [0] = {
++ .start = AR71XX_SPI_BASE,
++ .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++static struct ar71xx_spi_platform_data pb44_spi_data = {
++ .bus_num = 0,
++ .num_chipselect = 2,
++};
++
++static struct platform_device pb44_spi_device = {
++ .name = "pb44-spi",
++ .id = -1,
++ .resource = pb44_spi_resources,
++ .num_resources = ARRAY_SIZE(pb44_spi_resources),
++ .dev = {
++ .platform_data = &pb44_spi_data,
++ },
++};
++
++#define PB44_WAN_PHYMASK BIT(0)
++#define PB44_LAN_PHYMASK 0
++#define PB44_MDIO_PHYMASK (PB44_LAN_PHYMASK | PB44_WAN_PHYMASK)
++
++static void __init pb44_init(void)
++{
++ ar71xx_add_device_mdio(~PB44_MDIO_PHYMASK);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth0_data.phy_mask = PB44_WAN_PHYMASK;
++
++ ar71xx_add_device_eth(0);
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth1_data.speed = SPEED_1000;
++ ar71xx_eth1_data.duplex = DUPLEX_FULL;
++ ar71xx_eth1_pll_data.pll_1000 = 0x110000;
++
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_usb();
++
++ pb42_pci_init();
++
++ i2c_register_board_info(0, pb44_i2c_board_info,
++ ARRAY_SIZE(pb44_i2c_board_info));
++
++ platform_device_register(&pb44_i2c_gpio_device);
++
++ spi_register_board_info(pb44_spi_info, ARRAY_SIZE(pb44_spi_info));
++ platform_device_register(&pb44_spi_device);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(pb44_leds_gpio),
++ pb44_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, 20, ARRAY_SIZE(pb44_gpio_buttons),
++ pb44_gpio_buttons);
++}
++
++MIPS_MACHINE(AR71XX_MACH_PB44, "PB44", "Atheros PB44", pb44_init);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-pb92.c linux-2.6.37/arch/mips/ar71xx/mach-pb92.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-pb92.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-pb92.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,109 @@
++/*
++ * Atheros PB92 board support
++ *
++ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-gpio-buttons.h"
++#include "dev-pb9x-pci.h"
++#include "dev-usb.h"
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition pb92_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x040000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "u-boot-env",
++ .offset = 0x040000,
++ .size = 0x010000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x050000,
++ .size = 0x2b0000,
++ } , {
++ .name = "uImage",
++ .offset = 0x300000,
++ .size = 0x0e0000,
++ } , {
++ .name = "ART",
++ .offset = 0x3e0000,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data pb92_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = pb92_partitions,
++ .nr_parts = ARRAY_SIZE(pb92_partitions),
++#endif
++};
++
++
++#define PB92_BUTTONS_POLL_INTERVAL 20
++
++#define PB92_GPIO_BTN_SW4 8
++#define PB92_GPIO_BTN_SW5 3
++
++static struct gpio_button pb92_gpio_buttons[] __initdata = {
++ {
++ .desc = "sw4",
++ .type = EV_KEY,
++ .code = BTN_0,
++ .threshold = 3,
++ .gpio = PB92_GPIO_BTN_SW4,
++ .active_low = 1,
++ } , {
++ .desc = "sw5",
++ .type = EV_KEY,
++ .code = BTN_1,
++ .threshold = 3,
++ .gpio = PB92_GPIO_BTN_SW5,
++ .active_low = 1,
++ }
++};
++
++static void __init pb92_init(void)
++{
++ u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
++
++ ar71xx_set_mac_base(mac);
++ ar71xx_add_device_m25p80(&pb92_flash_data);
++
++ ar71xx_add_device_mdio(~0);
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.speed = SPEED_1000;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.speed = SPEED_1000;
++ ar71xx_eth1_data.duplex = DUPLEX_FULL;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_gpio_buttons(-1, PB92_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(pb92_gpio_buttons),
++ pb92_gpio_buttons);
++
++ pb9x_pci_init();
++}
++
++MIPS_MACHINE(AR71XX_MACH_PB92, "PB92", "Atheros PB92", pb92_init);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-rb4xx.c linux-2.6.37/arch/mips/ar71xx/mach-rb4xx.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-rb4xx.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-rb4xx.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,290 @@
++/*
++ * MikroTik RouterBOARD 4xx series support
++ *
++ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/irq.h>
++#include <linux/mmc/host.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/spi/mmc_spi.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define RB4XX_GPIO_USER_LED 4
++#define RB4XX_GPIO_RESET_SWITCH 7
++
++#define RB4XX_BUTTONS_POLL_INTERVAL 20
++
++static struct gpio_led rb4xx_leds_gpio[] __initdata = {
++ {
++ .name = "rb4xx:yellow:user",
++ .gpio = RB4XX_GPIO_USER_LED,
++ .active_low = 0,
++ },
++};
++
++static struct gpio_button rb4xx_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset_switch",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = RB4XX_GPIO_RESET_SWITCH,
++ .active_low = 1,
++ }
++};
++
++static struct platform_device rb4xx_nand_device = {
++ .name = "rb4xx-nand",
++ .id = -1,
++};
++
++static struct ar71xx_pci_irq rb4xx_pci_irqs[] __initdata = {
++ {
++ .slot = 0,
++ .pin = 1,
++ .irq = AR71XX_PCI_IRQ_DEV2,
++ }, {
++ .slot = 1,
++ .pin = 1,
++ .irq = AR71XX_PCI_IRQ_DEV0,
++ }, {
++ .slot = 1,
++ .pin = 2,
++ .irq = AR71XX_PCI_IRQ_DEV1,
++ }, {
++ .slot = 2,
++ .pin = 1,
++ .irq = AR71XX_PCI_IRQ_DEV1,
++ }, {
++ .slot = 3,
++ .pin = 1,
++ .irq = AR71XX_PCI_IRQ_DEV2,
++ }
++};
++
++#if 0
++/*
++ * SPI device support is experimental
++ */
++static struct flash_platform_data rb4xx_flash_data = {
++ .type = "pm25lv512",
++};
++
++static struct spi_board_info rb4xx_spi_info[] = {
++ {
++ .bus_num = 0,
++ .chip_select = 0,
++ .max_speed_hz = 25000000,
++ .modalias = "m25p80",
++ .platform_data = &rb4xx_flash_data,
++ }
++};
++
++static struct mmc_spi_platform_data rb433_mmc_data = {
++ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
++};
++
++static struct spi_board_info rb433_spi_info[] = {
++ {
++ .bus_num = 0,
++ .chip_select = 0,
++ .max_speed_hz = 25000000,
++ .modalias = "m25p80",
++ .platform_data = &rb433_flash_data,
++ }, {
++ .bus_num = 0,
++ .chip_select = 2,
++ .max_speed_hz = 25000000,
++ .modalias = "mmc_spi",
++ .platform_data = &rb433_mmc_data,
++ }
++};
++
++static u32 rb433_spi_get_ioc_base(u8 chip_select, int cs_high, int is_on)
++{
++ u32 ret;
++
++ if (is_on == AR71XX_SPI_CS_INACTIVE) {
++ ret = SPI_IOC_CS0 | SPI_IOC_CS1;
++ } else {
++ if (cs_high) {
++ ret = SPI_IOC_CS0 | SPI_IOC_CS1;
++ } else {
++ if ((chip_select ^ 2) == 0)
++ ret = SPI_IOC_CS1 ^ (SPI_IOC_CS0 | SPI_IOC_CS1);
++ else
++ ret = SPI_IOC_CS0 ^ (SPI_IOC_CS0 | SPI_IOC_CS1);
++ }
++ }
++
++ return ret;
++}
++
++struct ar71xx_spi_platform_data rb433_spi_data = {
++ .bus_num = 0,
++ .num_chipselect = 3,
++ .get_ioc_base = rb433_spi_get_ioc_base,
++};
++
++static void rb4xx_add_device_spi(void)
++{
++ ar71xx_add_device_spi(NULL, rb4xx_spi_info, ARRAY_SIZE(rb4xx_spi_info));
++}
++
++static void rb433_add_device_spi(void)
++{
++ ar71xx_add_device_spi(&rb433_spi_data, rb433_spi_info,
++ ARRAY_SIZE(rb433_spi_info));
++}
++#else
++static inline void rb4xx_add_device_spi(void) {}
++static inline void rb433_add_device_spi(void) {}
++#endif
++
++static void __init rb4xx_generic_setup(void)
++{
++ ar71xx_gpio_function_enable(AR71XX_GPIO_FUNC_SPI_CS1_EN |
++ AR71XX_GPIO_FUNC_SPI_CS2_EN);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(rb4xx_leds_gpio),
++ rb4xx_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, RB4XX_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(rb4xx_gpio_buttons),
++ rb4xx_gpio_buttons);
++
++ platform_device_register(&rb4xx_nand_device);
++}
++
++static void __init rb411_setup(void)
++{
++ rb4xx_generic_setup();
++ rb4xx_add_device_spi();
++
++ ar71xx_add_device_mdio(0xfffffffc);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ar71xx_eth0_data.phy_mask = 0x00000003;
++
++ ar71xx_add_device_eth(0);
++
++ ar71xx_pci_init(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_411, "411", "MikroTik RouterBOARD 411/A/AH",
++ rb411_setup);
++
++static void __init rb411u_setup(void)
++{
++ rb411_setup();
++ ar71xx_add_device_usb();
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_411U, "411U", "MikroTik RouterBOARD 411U",
++ rb411u_setup);
++
++static void __init rb433_setup(void)
++{
++ rb4xx_generic_setup();
++ rb433_add_device_spi();
++
++ ar71xx_add_device_mdio(0xffffffe9);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.phy_mask = 0x00000010;
++
++ ar71xx_add_device_eth(1);
++ ar71xx_add_device_eth(0);
++
++ ar71xx_pci_init(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_433, "433", "MikroTik RouterBOARD 433/AH",
++ rb433_setup);
++
++static void __init rb433u_setup(void)
++{
++ rb433_setup();
++ ar71xx_add_device_usb();
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_433U, "433U", "MikroTik RouterBOARD 433UAH",
++ rb433u_setup);
++
++static void __init rb450_generic_setup(int gige)
++{
++ rb4xx_generic_setup();
++ rb4xx_add_device_spi();
++
++ ar71xx_add_device_mdio(0xffffffe0);
++
++ ar71xx_eth0_data.phy_if_mode = (gige) ? PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_MII;
++ ar71xx_eth0_data.phy_mask = (gige) ? (1 << 0) : 0;
++ ar71xx_eth0_data.speed = (gige) ? SPEED_1000 : SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++ ar71xx_eth1_data.phy_if_mode = (gige) ? PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.phy_mask = 0x00000010;
++
++ ar71xx_add_device_eth(1);
++ ar71xx_add_device_eth(0);
++}
++
++static void __init rb450_setup(void)
++{
++ rb450_generic_setup(0);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_450, "450", "MikroTik RouterBOARD 450",
++ rb450_setup);
++
++static void __init rb450g_setup(void)
++{
++ rb450_generic_setup(1);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_450G, "450G", "MikroTik RouterBOARD 450G",
++ rb450g_setup);
++
++static void __init rb493_setup(void)
++{
++ rb4xx_generic_setup();
++ rb4xx_add_device_spi();
++
++ ar71xx_add_device_mdio(0x3fffff00);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.phy_mask = 0x00000001;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_pci_init(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_493, "493", "MikroTik RouterBOARD 493/AH",
++ rb493_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-rb750.c linux-2.6.37/arch/mips/ar71xx/mach-rb750.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-rb750.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-rb750.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,133 @@
++/*
++ * MikroTik RouterBOARD 750 support
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/mach-rb750.h>
++
++#include "machtype.h"
++#include "dev-ap91-eth.h"
++
++static struct rb750_led_data rb750_leds[] = {
++ {
++ .name = "rb750:green:act",
++ .mask = RB750_LED_ACT,
++ .active_low = 1,
++ }, {
++ .name = "rb750:green:port1",
++ .mask = RB750_LED_PORT5,
++ .active_low = 1,
++ }, {
++ .name = "rb750:green:port2",
++ .mask = RB750_LED_PORT4,
++ .active_low = 1,
++ }, {
++ .name = "rb750:green:port3",
++ .mask = RB750_LED_PORT3,
++ .active_low = 1,
++ }, {
++ .name = "rb750:green:port4",
++ .mask = RB750_LED_PORT2,
++ .active_low = 1,
++ }, {
++ .name = "rb750:green:port5",
++ .mask = RB750_LED_PORT1,
++ .active_low = 1,
++ }
++};
++
++static struct rb750_led_platform_data rb750_leds_data = {
++ .num_leds = ARRAY_SIZE(rb750_leds),
++ .leds = rb750_leds,
++};
++
++static struct platform_device rb750_leds_device = {
++ .name = "leds-rb750",
++ .dev = {
++ .platform_data = &rb750_leds_data,
++ }
++};
++
++static const char *rb750_port_names[AP91_ETH_NUM_PORT_NAMES] __initdata = {
++ "port5",
++ "port4",
++ "port3",
++ "port2",
++};
++
++static struct platform_device rb750_nand_device = {
++ .name = "rb750-nand",
++ .id = -1,
++};
++
++int rb750_latch_change(u32 mask_clr, u32 mask_set)
++{
++ static DEFINE_SPINLOCK(lock);
++ static u32 latch_set = RB750_LED_BITS | RB750_LVC573_LE;
++ static u32 latch_oe;
++ static u32 latch_clr;
++ unsigned long flags;
++ u32 t;
++ int ret = 0;
++
++ spin_lock_irqsave(&lock, flags);
++
++ if ((mask_clr & BIT(31)) != 0 &&
++ (latch_set & RB750_LVC573_LE) == 0) {
++ goto unlock;
++ }
++
++ latch_set = (latch_set | mask_set) & ~mask_clr;
++ latch_clr = (latch_clr | mask_clr) & ~mask_set;
++
++ if (latch_oe == 0)
++ latch_oe = __raw_readl(ar71xx_gpio_base + GPIO_REG_OE);
++
++ if (likely(latch_set & RB750_LVC573_LE)) {
++ void __iomem *base = ar71xx_gpio_base;
++
++ t = __raw_readl(base + GPIO_REG_OE);
++ t |= mask_clr | latch_oe | mask_set;
++
++ __raw_writel(t, base + GPIO_REG_OE);
++ __raw_writel(latch_clr, base + GPIO_REG_CLEAR);
++ __raw_writel(latch_set, base + GPIO_REG_SET);
++ } else if (mask_clr & RB750_LVC573_LE) {
++ void __iomem *base = ar71xx_gpio_base;
++
++ latch_oe = __raw_readl(base + GPIO_REG_OE);
++ __raw_writel(RB750_LVC573_LE, base + GPIO_REG_CLEAR);
++ /* flush write */
++ __raw_readl(base + GPIO_REG_CLEAR);
++ }
++
++ ret = 1;
++
++ unlock:
++ spin_unlock_irqrestore(&lock, flags);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(rb750_latch_change);
++
++static void __init rb750_setup(void)
++{
++ ar71xx_gpio_function_disable(AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
++ AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
++ AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
++ AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
++ AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
++
++ ap91_eth_init(NULL, rb750_port_names);
++ platform_device_register(&rb750_leds_device);
++ platform_device_register(&rb750_nand_device);
++}
++
++MIPS_MACHINE(AR71XX_MACH_RB_750, "750i", "MikroTik RouterBOARD 750",
++ rb750_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-tew-632brp.c linux-2.6.37/arch/mips/ar71xx/mach-tew-632brp.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-tew-632brp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-tew-632brp.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,149 @@
++/*
++ * TrendNET TEW-632BRP board support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "nvram.h"
++
++#define TEW_632BRP_GPIO_LED_STATUS 1
++#define TEW_632BRP_GPIO_LED_WPS 3
++#define TEW_632BRP_GPIO_LED_WLAN 6
++#define TEW_632BRP_GPIO_BTN_WPS 12
++#define TEW_632BRP_GPIO_BTN_RESET 21
++
++#define TEW_632BRP_BUTTONS_POLL_INTERVAL 20
++
++#define TEW_632BRP_CONFIG_ADDR 0x1f020000
++#define TEW_632BRP_CONFIG_SIZE 0x10000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition tew_632brp_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "config",
++ .offset = 0x020000,
++ .size = 0x010000,
++ } , {
++ .name = "kernel",
++ .offset = 0x030000,
++ .size = 0x0d0000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x100000,
++ .size = 0x2f0000,
++ } , {
++ .name = "art",
++ .offset = 0x3f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x030000,
++ .size = 0x3c0000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data tew_632brp_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = tew_632brp_partitions,
++ .nr_parts = ARRAY_SIZE(tew_632brp_partitions),
++#endif
++};
++
++static struct gpio_led tew_632brp_leds_gpio[] __initdata = {
++ {
++ .name = "tew-632brp:green:status",
++ .gpio = TEW_632BRP_GPIO_LED_STATUS,
++ .active_low = 1,
++ }, {
++ .name = "tew-632brp:blue:wps",
++ .gpio = TEW_632BRP_GPIO_LED_WPS,
++ .active_low = 1,
++ }, {
++ .name = "tew-632brp:green:wlan",
++ .gpio = TEW_632BRP_GPIO_LED_WLAN,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button tew_632brp_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = TEW_632BRP_GPIO_BTN_RESET,
++ }, {
++ .desc = "wps",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = TEW_632BRP_GPIO_BTN_WPS,
++ }
++};
++
++#define TEW_632BRP_LAN_PHYMASK BIT(0)
++#define TEW_632BRP_WAN_PHYMASK BIT(4)
++#define TEW_632BRP_MDIO_MASK (~(TEW_632BRP_LAN_PHYMASK | \
++ TEW_632BRP_WAN_PHYMASK))
++
++static void __init tew_632brp_setup(void)
++{
++ const char *config = (char *) KSEG1ADDR(TEW_632BRP_CONFIG_ADDR);
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++ u8 mac[6];
++ u8 *wlan_mac = NULL;
++
++ if (nvram_parse_mac_addr(config, TEW_632BRP_CONFIG_SIZE,
++ "lan_mac=", mac) == 0) {
++ ar71xx_set_mac_base(mac);
++ wlan_mac = mac;
++ }
++
++ ar71xx_add_device_mdio(TEW_632BRP_MDIO_MASK);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.phy_mask = TEW_632BRP_LAN_PHYMASK;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.phy_mask = TEW_632BRP_WAN_PHYMASK;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_m25p80(&tew_632brp_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tew_632brp_leds_gpio),
++ tew_632brp_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, TEW_632BRP_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(tew_632brp_gpio_buttons),
++ tew_632brp_gpio_buttons);
++
++ ar913x_add_device_wmac(eeprom, wlan_mac);
++}
++
++MIPS_MACHINE(AR71XX_MACH_TEW_632BRP, "TEW-632BRP", "TRENDnet TEW-632BRP",
++ tew_632brp_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c linux-2.6.37/arch/mips/ar71xx/mach-tl-wr1043nd.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-tl-wr1043nd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-tl-wr1043nd.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,156 @@
++/*
++ * TP-LINK TL-WR1043ND board support
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/platform_device.h>
++#include <linux/rtl8366rb.h>
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define TL_WR1043ND_GPIO_LED_USB 1
++#define TL_WR1043ND_GPIO_LED_SYSTEM 2
++#define TL_WR1043ND_GPIO_LED_QSS 5
++#define TL_WR1043ND_GPIO_LED_WLAN 9
++
++#define TL_WR1043ND_GPIO_BTN_RESET 3
++#define TL_WR1043ND_GPIO_BTN_QSS 7
++
++#define TL_WR1043ND_GPIO_RTL8366_SDA 18
++#define TL_WR1043ND_GPIO_RTL8366_SCK 19
++
++#define TL_WR1043ND_BUTTONS_POLL_INTERVAL 20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition tl_wr1043nd_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "kernel",
++ .offset = 0x020000,
++ .size = 0x140000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x160000,
++ .size = 0x690000,
++ } , {
++ .name = "art",
++ .offset = 0x7f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x020000,
++ .size = 0x7d0000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data tl_wr1043nd_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = tl_wr1043nd_partitions,
++ .nr_parts = ARRAY_SIZE(tl_wr1043nd_partitions),
++#endif
++};
++
++static struct gpio_led tl_wr1043nd_leds_gpio[] __initdata = {
++ {
++ .name = "tl-wr1043nd:green:usb",
++ .gpio = TL_WR1043ND_GPIO_LED_USB,
++ .active_low = 1,
++ }, {
++ .name = "tl-wr1043nd:green:system",
++ .gpio = TL_WR1043ND_GPIO_LED_SYSTEM,
++ .active_low = 1,
++ }, {
++ .name = "tl-wr1043nd:green:qss",
++ .gpio = TL_WR1043ND_GPIO_LED_QSS,
++ .active_low = 0,
++ }, {
++ .name = "tl-wr1043nd:green:wlan",
++ .gpio = TL_WR1043ND_GPIO_LED_WLAN,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button tl_wr1043nd_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = TL_WR1043ND_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "qss",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = TL_WR1043ND_GPIO_BTN_QSS,
++ .active_low = 1,
++ }
++};
++
++static struct rtl8366rb_platform_data tl_wr1043nd_rtl8366rb_data = {
++ .gpio_sda = TL_WR1043ND_GPIO_RTL8366_SDA,
++ .gpio_sck = TL_WR1043ND_GPIO_RTL8366_SCK,
++};
++
++static struct platform_device tl_wr1043nd_rtl8366rb_device = {
++ .name = RTL8366RB_DRIVER_NAME,
++ .id = -1,
++ .dev = {
++ .platform_data = &tl_wr1043nd_rtl8366rb_data,
++ }
++};
++
++static void __init tl_wr1043nd_setup(void)
++{
++ u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++ ar71xx_set_mac_base(mac);
++
++ ar71xx_eth0_data.mii_bus_dev = &tl_wr1043nd_rtl8366rb_device.dev;
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth0_data.speed = SPEED_1000;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++ ar71xx_eth0_pll_data.pll_1000 = 0x1a000000;
++
++ ar71xx_add_device_eth(0);
++
++ ar71xx_add_device_usb();
++
++ ar71xx_add_device_m25p80(&tl_wr1043nd_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr1043nd_leds_gpio),
++ tl_wr1043nd_leds_gpio);
++
++ platform_device_register(&tl_wr1043nd_rtl8366rb_device);
++
++ ar71xx_add_device_gpio_buttons(-1, TL_WR1043ND_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(tl_wr1043nd_gpio_buttons),
++ tl_wr1043nd_gpio_buttons);
++
++ ar913x_add_device_wmac(eeprom, mac);
++}
++
++MIPS_MACHINE(AR71XX_MACH_TL_WR1043ND, "TL-WR1043ND", "TP-LINK TL-WR1043ND",
++ tl_wr1043nd_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-tl-wr741nd.c linux-2.6.37/arch/mips/ar71xx/mach-tl-wr741nd.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-tl-wr741nd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-tl-wr741nd.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,115 @@
++/*
++ * TP-LINK TL-WR741ND board support
++ *
++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ap91-eth.h"
++#include "dev-ap91-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++#define TL_WR741ND_GPIO_LED_QSS 0
++#define TL_WR741ND_GPIO_LED_SYSTEM 1
++
++#define TL_WR741ND_GPIO_BTN_RESET 11
++#define TL_WR741ND_GPIO_BTN_QSS 12
++
++#define TL_WR741ND_BUTTONS_POLL_INTERVAL 20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition tl_wr741nd_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "kernel",
++ .offset = 0x020000,
++ .size = 0x140000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x160000,
++ .size = 0x290000,
++ } , {
++ .name = "art",
++ .offset = 0x3f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x020000,
++ .size = 0x3d0000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data tl_wr741nd_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = tl_wr741nd_partitions,
++ .nr_parts = ARRAY_SIZE(tl_wr741nd_partitions),
++#endif
++};
++
++static struct gpio_led tl_wr741nd_leds_gpio[] __initdata = {
++ {
++ .name = "tl-wr741nd:green:system",
++ .gpio = TL_WR741ND_GPIO_LED_SYSTEM,
++ .active_low = 1,
++ }, {
++ .name = "tl-wr741nd:green:qss",
++ .gpio = TL_WR741ND_GPIO_LED_QSS,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button tl_wr741nd_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = TL_WR741ND_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "qss",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = TL_WR741ND_GPIO_BTN_QSS,
++ .active_low = 1,
++ }
++};
++
++static void __init tl_wr741nd_setup(void)
++{
++ u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
++ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
++
++ ar71xx_add_device_m25p80(&tl_wr741nd_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr741nd_leds_gpio),
++ tl_wr741nd_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, TL_WR741ND_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(tl_wr741nd_gpio_buttons),
++ tl_wr741nd_gpio_buttons);
++
++ ap91_eth_init(mac, NULL);
++ ap91_pci_init(ee, mac);
++}
++MIPS_MACHINE(AR71XX_MACH_TL_WR741ND, "TL-WR741ND", "TP-LINK TL-WR741ND",
++ tl_wr741nd_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-tl-wr841n.c linux-2.6.37/arch/mips/ar71xx/mach-tl-wr841n.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-tl-wr841n.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-tl-wr841n.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,143 @@
++/*
++ * TP-LINK TL-WR841N board support
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-dsa.h"
++#include "dev-m25p80.h"
++#include "dev-gpio-buttons.h"
++#include "dev-pb42-pci.h"
++#include "dev-leds-gpio.h"
++
++#define TL_WR841ND_V1_GPIO_LED_SYSTEM 2
++#define TL_WR841ND_V1_GPIO_LED_QSS_GREEN 4
++#define TL_WR841ND_V1_GPIO_LED_QSS_RED 5
++
++#define TL_WR841ND_V1_GPIO_BTN_RESET 3
++#define TL_WR841ND_V1_GPIO_BTN_QSS 7
++
++#define TL_WR841ND_V1_BUTTONS_POLL_INTERVAL 20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition tl_wr841n_v1_partitions[] = {
++ {
++ .name = "redboot",
++ .offset = 0,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "kernel",
++ .offset = 0x020000,
++ .size = 0x140000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x160000,
++ .size = 0x280000,
++ } , {
++ .name = "config",
++ .offset = 0x3e0000,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x020000,
++ .size = 0x3c0000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data tl_wr841n_v1_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = tl_wr841n_v1_partitions,
++ .nr_parts = ARRAY_SIZE(tl_wr841n_v1_partitions),
++#endif
++};
++
++static struct gpio_led tl_wr841n_v1_leds_gpio[] __initdata = {
++ {
++ .name = "tl-wr841n:green:system",
++ .gpio = TL_WR841ND_V1_GPIO_LED_SYSTEM,
++ .active_low = 1,
++ }, {
++ .name = "tl-wr841n:red:qss",
++ .gpio = TL_WR841ND_V1_GPIO_LED_QSS_RED,
++ }, {
++ .name = "tl-wr841n:green:qss",
++ .gpio = TL_WR841ND_V1_GPIO_LED_QSS_GREEN,
++ }
++};
++
++static struct gpio_button tl_wr841n_v1_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = TL_WR841ND_V1_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "qss",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = TL_WR841ND_V1_GPIO_BTN_QSS,
++ .active_low = 1,
++ }
++};
++
++static struct dsa_chip_data tl_wr841n_v1_dsa_chip = {
++ .port_names[0] = "wan",
++ .port_names[1] = "lan1",
++ .port_names[2] = "lan2",
++ .port_names[3] = "lan3",
++ .port_names[4] = "lan4",
++ .port_names[5] = "cpu",
++};
++
++static struct dsa_platform_data tl_wr841n_v1_dsa_data = {
++ .nr_chips = 1,
++ .chip = &tl_wr841n_v1_dsa_chip,
++};
++
++static void __init tl_wr841n_v1_setup(void)
++{
++ u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
++
++ ar71xx_set_mac_base(mac);
++
++ ar71xx_add_device_mdio(0x0);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++ ar71xx_add_device_eth(0);
++
++ ar71xx_add_device_dsa(0, &tl_wr841n_v1_dsa_data);
++
++ ar71xx_add_device_m25p80(&tl_wr841n_v1_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr841n_v1_leds_gpio),
++ tl_wr841n_v1_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, TL_WR841ND_V1_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(tl_wr841n_v1_gpio_buttons),
++ tl_wr841n_v1_gpio_buttons);
++
++ pb42_pci_init();
++}
++
++MIPS_MACHINE(AR71XX_MACH_TL_WR841N_V1, "TL-WR841N-v1.5", "TP-LINK TL-WR841N v1",
++ tl_wr841n_v1_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-tl-wr941nd.c linux-2.6.37/arch/mips/ar71xx/mach-tl-wr941nd.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-tl-wr941nd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-tl-wr941nd.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,142 @@
++/*
++ * TP-LINK TL-WR941ND board support
++ *
++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-dsa.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++#define TL_WR941ND_GPIO_LED_SYSTEM 2
++#define TL_WR941ND_GPIO_LED_QSS_RED 4
++#define TL_WR941ND_GPIO_LED_QSS_GREEN 5
++
++#define TL_WR941ND_GPIO_BTN_RESET 3
++#define TL_WR941ND_GPIO_BTN_QSS 7
++
++#define TL_WR941ND_BUTTONS_POLL_INTERVAL 20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition tl_wr941nd_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "kernel",
++ .offset = 0x020000,
++ .size = 0x140000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x160000,
++ .size = 0x290000,
++ } , {
++ .name = "art",
++ .offset = 0x3f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x020000,
++ .size = 0x3d0000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data tl_wr941nd_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = tl_wr941nd_partitions,
++ .nr_parts = ARRAY_SIZE(tl_wr941nd_partitions),
++#endif
++};
++
++static struct gpio_led tl_wr941nd_leds_gpio[] __initdata = {
++ {
++ .name = "tl-wr941nd:green:system",
++ .gpio = TL_WR941ND_GPIO_LED_SYSTEM,
++ .active_low = 1,
++ }, {
++ .name = "tl-wr941nd:red:qss",
++ .gpio = TL_WR941ND_GPIO_LED_QSS_RED,
++ }, {
++ .name = "tl-wr941nd:green:qss",
++ .gpio = TL_WR941ND_GPIO_LED_QSS_GREEN,
++ }
++};
++
++static struct gpio_button tl_wr941nd_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = TL_WR941ND_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "qss",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = TL_WR941ND_GPIO_BTN_QSS,
++ .active_low = 1,
++ }
++};
++
++static struct dsa_chip_data tl_wr941nd_dsa_chip = {
++ .port_names[0] = "wan",
++ .port_names[1] = "lan1",
++ .port_names[2] = "lan2",
++ .port_names[3] = "lan3",
++ .port_names[4] = "lan4",
++ .port_names[5] = "cpu",
++};
++
++static struct dsa_platform_data tl_wr941nd_dsa_data = {
++ .nr_chips = 1,
++ .chip = &tl_wr941nd_dsa_chip,
++};
++
++static void __init tl_wr941nd_setup(void)
++{
++ u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++ ar71xx_set_mac_base(mac);
++
++ ar71xx_add_device_mdio(0x0);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_dsa(0, &tl_wr941nd_dsa_data);
++
++ ar71xx_add_device_m25p80(&tl_wr941nd_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(tl_wr941nd_leds_gpio),
++ tl_wr941nd_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, TL_WR941ND_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(tl_wr941nd_gpio_buttons),
++ tl_wr941nd_gpio_buttons);
++ ar913x_add_device_wmac(eeprom, mac);
++}
++
++MIPS_MACHINE(AR71XX_MACH_TL_WR941ND, "TL-WR941ND", "TP-LINK TL-WR941ND",
++ tl_wr941nd_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-ubnt.c linux-2.6.37/arch/mips/ar71xx/mach-ubnt.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-ubnt.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-ubnt.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,281 @@
++/*
++ * Ubiquiti RouterStation support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2008 Ubiquiti <support@ubnt.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ap91-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-pb42-pci.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define UBNT_RS_GPIO_LED_RF 2
++#define UBNT_RS_GPIO_SW4 8
++
++#define UBNT_LS_SR71_GPIO_LED_D25 0
++#define UBNT_LS_SR71_GPIO_LED_D26 1
++#define UBNT_LS_SR71_GPIO_LED_D24 2
++#define UBNT_LS_SR71_GPIO_LED_D23 4
++#define UBNT_LS_SR71_GPIO_LED_D22 5
++#define UBNT_LS_SR71_GPIO_LED_D27 6
++#define UBNT_LS_SR71_GPIO_LED_D28 7
++
++#define UBNT_M_GPIO_LED_L1 0
++#define UBNT_M_GPIO_LED_L2 1
++#define UBNT_M_GPIO_LED_L3 11
++#define UBNT_M_GPIO_LED_L4 7
++#define UBNT_M_GPIO_BTN_RESET 12
++
++#define UBNT_BUTTONS_POLL_INTERVAL 20
++
++static struct gpio_led ubnt_rs_leds_gpio[] __initdata = {
++ {
++ .name = "ubnt:green:rf",
++ .gpio = UBNT_RS_GPIO_LED_RF,
++ .active_low = 0,
++ }
++};
++
++static struct gpio_led ubnt_ls_sr71_leds_gpio[] __initdata = {
++ {
++ .name = "ubnt:green:d22",
++ .gpio = UBNT_LS_SR71_GPIO_LED_D22,
++ .active_low = 0,
++ }, {
++ .name = "ubnt:green:d23",
++ .gpio = UBNT_LS_SR71_GPIO_LED_D23,
++ .active_low = 0,
++ }, {
++ .name = "ubnt:green:d24",
++ .gpio = UBNT_LS_SR71_GPIO_LED_D24,
++ .active_low = 0,
++ }, {
++ .name = "ubnt:red:d25",
++ .gpio = UBNT_LS_SR71_GPIO_LED_D25,
++ .active_low = 0,
++ }, {
++ .name = "ubnt:red:d26",
++ .gpio = UBNT_LS_SR71_GPIO_LED_D26,
++ .active_low = 0,
++ }, {
++ .name = "ubnt:green:d27",
++ .gpio = UBNT_LS_SR71_GPIO_LED_D27,
++ .active_low = 0,
++ }, {
++ .name = "ubnt:green:d28",
++ .gpio = UBNT_LS_SR71_GPIO_LED_D28,
++ .active_low = 0,
++ }
++};
++
++static struct gpio_led ubnt_m_leds_gpio[] __initdata = {
++ {
++ .name = "ubnt:red:link1",
++ .gpio = UBNT_M_GPIO_LED_L1,
++ .active_low = 0,
++ }, {
++ .name = "ubnt:orange:link2",
++ .gpio = UBNT_M_GPIO_LED_L2,
++ .active_low = 0,
++ }, {
++ .name = "ubnt:green:link3",
++ .gpio = UBNT_M_GPIO_LED_L3,
++ .active_low = 0,
++ }, {
++ .name = "ubnt:green:link4",
++ .gpio = UBNT_M_GPIO_LED_L4,
++ .active_low = 0,
++ }
++};
++
++static struct gpio_button ubnt_gpio_buttons[] __initdata = {
++ {
++ .desc = "sw4",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = UBNT_RS_GPIO_SW4,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button ubnt_m_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = UBNT_M_GPIO_BTN_RESET,
++ .active_low = 1,
++ }
++};
++
++static void __init ubnt_generic_setup(void)
++{
++ ar71xx_add_device_m25p80(NULL);
++
++ ar71xx_add_device_gpio_buttons(-1, UBNT_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(ubnt_gpio_buttons),
++ ubnt_gpio_buttons);
++
++ pb42_pci_init();
++}
++
++#define UBNT_RS_WAN_PHYMASK (1 << 20)
++#define UBNT_RS_LAN_PHYMASK ((1 << 16) | (1 << 17) | (1 << 18) | (1 << 19))
++
++static void __init ubnt_rs_setup(void)
++{
++ ubnt_generic_setup();
++
++ ar71xx_add_device_mdio(~(UBNT_RS_WAN_PHYMASK | UBNT_RS_LAN_PHYMASK));
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ar71xx_eth0_data.phy_mask = UBNT_RS_WAN_PHYMASK;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.speed = SPEED_100;
++ ar71xx_eth1_data.duplex = DUPLEX_FULL;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_usb();
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ubnt_rs_leds_gpio),
++ ubnt_rs_leds_gpio);
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_RS, "UBNT-RS", "Ubiquiti RouterStation",
++ ubnt_rs_setup);
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_AR71XX, "Ubiquiti AR71xx-based board",
++ "Ubiquiti RouterStation", ubnt_rs_setup);
++
++#define UBNT_RSPRO_WAN_PHYMASK (1 << 4)
++#define UBNT_RSPRO_LAN_PHYMASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
++
++static void __init ubnt_rspro_setup(void)
++{
++ ubnt_generic_setup();
++
++ ar71xx_add_device_mdio(~(UBNT_RSPRO_WAN_PHYMASK | UBNT_RSPRO_LAN_PHYMASK));
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth0_data.phy_mask = UBNT_RSPRO_WAN_PHYMASK;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth1_data.phy_mask = UBNT_RSPRO_LAN_PHYMASK;
++ ar71xx_eth1_data.speed = SPEED_1000;
++ ar71xx_eth1_data.duplex = DUPLEX_FULL;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_usb();
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ubnt_rs_leds_gpio),
++ ubnt_rs_leds_gpio);
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_RSPRO, "UBNT-RSPRO", "Ubiquiti RouterStation Pro",
++ ubnt_rspro_setup);
++
++static void __init ubnt_lsx_setup(void)
++{
++ ubnt_generic_setup();
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_LSX, "UBNT-LSX", "Ubiquiti LSX", ubnt_lsx_setup);
++
++#define UBNT_LSSR71_PHY_MASK (1 << 1)
++
++static void __init ubnt_lssr71_setup(void)
++{
++ ubnt_generic_setup();
++
++ ar71xx_add_device_mdio(~UBNT_LSSR71_PHY_MASK);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ar71xx_eth0_data.phy_mask = UBNT_LSSR71_PHY_MASK;
++
++ ar71xx_add_device_eth(0);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ubnt_ls_sr71_leds_gpio),
++ ubnt_ls_sr71_leds_gpio);
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_LSSR71, "UBNT-LS-SR71", "Ubiquiti LS-SR71",
++ ubnt_lssr71_setup);
++
++static void __init ubnt_m_setup(void)
++{
++ u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
++ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
++
++ ar71xx_set_mac_base(mac);
++
++ ar71xx_add_device_m25p80(NULL);
++
++ ar71xx_add_device_mdio(~0);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++ ar71xx_eth0_data.fifo_cfg1 = 0x0010ffff;
++ ar71xx_eth0_data.fifo_cfg2 = 0x015500aa;
++ ar71xx_eth0_data.fifo_cfg3 = 0x01f00140;
++
++ ar71xx_add_device_eth(0);
++
++ ap91_pci_init(ee, NULL);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(ubnt_m_leds_gpio),
++ ubnt_m_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, UBNT_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(ubnt_m_gpio_buttons),
++ ubnt_m_gpio_buttons);
++}
++
++static void __init ubnt_rocket_m_setup(void)
++{
++ ubnt_m_setup();
++ ar71xx_add_device_usb();
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_BULLET_M, "UBNT-BM", "Ubiquiti Bullet M",
++ ubnt_m_setup);
++MIPS_MACHINE(AR71XX_MACH_UBNT_ROCKET_M, "UBNT-RM", "Ubiquiti Rocket M",
++ ubnt_rocket_m_setup);
++
++/* TODO detect the second ethernet port and use one
++ init function for all Ubiquiti MIMO series products */
++static void __init ubnt_nano_m_setup(void)
++{
++ ubnt_m_setup();
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.speed = SPEED_1000;
++ ar71xx_eth1_data.duplex = DUPLEX_FULL;
++ ar71xx_eth1_data.fifo_cfg1 = 0x0010ffff;
++ ar71xx_eth1_data.fifo_cfg2 = 0x015500aa;
++ ar71xx_eth1_data.fifo_cfg3 = 0x01f00140;
++
++ ar71xx_add_device_eth(1);
++}
++
++MIPS_MACHINE(AR71XX_MACH_UBNT_NANO_M, "UBNT-NM", "Ubiquiti Nanostation M",
++ ubnt_nano_m_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-wndr3700.c linux-2.6.37/arch/mips/ar71xx/mach-wndr3700.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-wndr3700.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-wndr3700.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,209 @@
++/*
++ * Netgear WNDR3700 board support
++ *
++ * Copyright (C) 2009 Marco Porsch
++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/delay.h>
++#include <linux/rtl8366s.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ap94-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define WNDR3700_GPIO_LED_WPS_ORANGE 0
++#define WNDR3700_GPIO_LED_POWER_ORANGE 1
++#define WNDR3700_GPIO_LED_POWER_GREEN 2
++#define WNDR3700_GPIO_LED_WPS_GREEN 4
++#define WNDR3700_GPIO_LED_WAN_GREEN 6
++
++#define WNDR3700_GPIO_BTN_WPS 3
++#define WNDR3700_GPIO_BTN_RESET 8
++#define WNDR3700_GPIO_BTN_WIFI 11
++
++#define WNDR3700_GPIO_RTL8366_SDA 5
++#define WNDR3700_GPIO_RTL8366_SCK 7
++
++#define WNDR3700_BUTTONS_POLL_INTERVAL 20
++
++#define WNDR3700_WMAC0_MAC_OFFSET 0
++#define WNDR3700_WMAC1_MAC_OFFSET 0xc
++#define WNDR3700_CALDATA0_OFFSET 0x1000
++#define WNDR3700_CALDATA1_OFFSET 0x5000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition wndr3700_partitions[] = {
++ {
++ .name = "uboot",
++ .offset = 0,
++ .size = 0x050000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "env",
++ .offset = 0x050000,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "rootfs",
++ .offset = 0x070000,
++ .size = 0x720000,
++ } , {
++ .name = "config",
++ .offset = 0x790000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "config_bak",
++ .offset = 0x7a0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "pot",
++ .offset = 0x7b0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "traffic_meter",
++ .offset = 0x7c0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "language",
++ .offset = 0x7d0000,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "caldata",
++ .offset = 0x7f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data wndr3700_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = wndr3700_partitions,
++ .nr_parts = ARRAY_SIZE(wndr3700_partitions),
++#endif
++};
++
++static struct gpio_led wndr3700_leds_gpio[] __initdata = {
++ {
++ .name = "wndr3700:green:power",
++ .gpio = WNDR3700_GPIO_LED_POWER_GREEN,
++ .active_low = 1,
++ }, {
++ .name = "wndr3700:orange:power",
++ .gpio = WNDR3700_GPIO_LED_POWER_ORANGE,
++ .active_low = 1,
++ }, {
++ .name = "wndr3700:green:wps",
++ .gpio = WNDR3700_GPIO_LED_WPS_GREEN,
++ .active_low = 1,
++ }, {
++ .name = "wndr3700:orange:wps",
++ .gpio = WNDR3700_GPIO_LED_WPS_ORANGE,
++ .active_low = 1,
++ }, {
++ .name = "wndr3700:green:wan",
++ .gpio = WNDR3700_GPIO_LED_WAN_GREEN,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button wndr3700_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = WNDR3700_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "wps",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = WNDR3700_GPIO_BTN_WPS,
++ .active_low = 1,
++ } , {
++ .desc = "wifi",
++ .type = EV_KEY,
++ .code = BTN_2,
++ .threshold = 3,
++ .gpio = WNDR3700_GPIO_BTN_WIFI,
++ .active_low = 1,
++ }
++};
++
++static struct rtl8366s_platform_data wndr3700_rtl8366s_data = {
++ .gpio_sda = WNDR3700_GPIO_RTL8366_SDA,
++ .gpio_sck = WNDR3700_GPIO_RTL8366_SCK,
++};
++
++static struct platform_device wndr3700_rtl8366s_device = {
++ .name = RTL8366S_DRIVER_NAME,
++ .id = -1,
++ .dev = {
++ .platform_data = &wndr3700_rtl8366s_data,
++ }
++};
++
++static void __init wndr3700_setup(void)
++{
++ u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
++
++ ar71xx_set_mac_base(art);
++
++ ar71xx_eth0_pll_data.pll_1000 = 0x11110000;
++ ar71xx_eth0_data.mii_bus_dev = &wndr3700_rtl8366s_device.dev;
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth0_data.speed = SPEED_1000;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++ ar71xx_eth1_pll_data.pll_1000 = 0x11110000;
++ ar71xx_eth1_data.mii_bus_dev = &wndr3700_rtl8366s_device.dev;
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth1_data.phy_mask = 0x10;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_usb();
++
++ ar71xx_add_device_m25p80(&wndr3700_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wndr3700_leds_gpio),
++ wndr3700_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, WNDR3700_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(wndr3700_gpio_buttons),
++ wndr3700_gpio_buttons);
++
++ platform_device_register(&wndr3700_rtl8366s_device);
++ platform_device_register_simple("wndr3700-led-usb", -1, NULL, 0);
++
++ ap94_pci_enable_quirk_wndr3700();
++ ap94_pci_init(art + WNDR3700_CALDATA0_OFFSET,
++ art + WNDR3700_WMAC0_MAC_OFFSET,
++ art + WNDR3700_CALDATA1_OFFSET,
++ art + WNDR3700_WMAC1_MAC_OFFSET);
++}
++
++MIPS_MACHINE(AR71XX_MACH_WNDR3700, "WNDR3700", "NETGEAR WNDR3700",
++ wndr3700_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-wnr2000.c linux-2.6.37/arch/mips/ar71xx/mach-wnr2000.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-wnr2000.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-wnr2000.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,148 @@
++/*
++ * NETGEAR WNR2000 board support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2008-2009 Andy Boyett <agb@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++#define WNR2000_GPIO_LED_PWR_GREEN 14
++#define WNR2000_GPIO_LED_PWR_AMBER 7
++#define WNR2000_GPIO_LED_WPS 4
++#define WNR2000_GPIO_LED_WLAN 6
++#define WNR2000_GPIO_BTN_RESET 21
++#define WNR2000_GPIO_BTN_WPS 8
++
++#define WNR2000_BUTTONS_POLL_INTERVAL 20
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition wnr2000_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x040000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "u-boot-env",
++ .offset = 0x040000,
++ .size = 0x010000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x050000,
++ .size = 0x240000,
++ } , {
++ .name = "user-config",
++ .offset = 0x290000,
++ .size = 0x010000,
++ } , {
++ .name = "uImage",
++ .offset = 0x2a0000,
++ .size = 0x120000,
++ } , {
++ .name = "language_table",
++ .offset = 0x3c0000,
++ .size = 0x020000,
++ } , {
++ .name = "rootfs_checksum",
++ .offset = 0x3e0000,
++ .size = 0x010000,
++ } , {
++ .name = "art",
++ .offset = 0x3f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data wnr2000_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = wnr2000_partitions,
++ .nr_parts = ARRAY_SIZE(wnr2000_partitions),
++#endif
++};
++
++static struct gpio_led wnr2000_leds_gpio[] __initdata = {
++ {
++ .name = "wnr2000:green:power",
++ .gpio = WNR2000_GPIO_LED_PWR_GREEN,
++ .active_low = 1,
++ }, {
++ .name = "wnr2000:amber:power",
++ .gpio = WNR2000_GPIO_LED_PWR_AMBER,
++ .active_low = 1,
++ }, {
++ .name = "wnr2000:green:wps",
++ .gpio = WNR2000_GPIO_LED_WPS,
++ .active_low = 1,
++ }, {
++ .name = "wnr2000:blue:wlan",
++ .gpio = WNR2000_GPIO_LED_WLAN,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button wnr2000_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = WNR2000_GPIO_BTN_RESET,
++ }, {
++ .desc = "wps",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = WNR2000_GPIO_BTN_WPS,
++ }
++};
++
++static void __init wnr2000_setup(void)
++{
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++ ar71xx_set_mac_base(eeprom);
++ ar71xx_add_device_mdio(0x0);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++ ar71xx_eth0_data.has_ar8216 = 1;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.phy_mask = 0x10;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_m25p80(&wnr2000_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wnr2000_leds_gpio),
++ wnr2000_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, WNR2000_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(wnr2000_gpio_buttons),
++ wnr2000_gpio_buttons);
++
++
++ ar913x_add_device_wmac(eeprom, NULL);
++}
++
++MIPS_MACHINE(AR71XX_MACH_WNR2000, "WNR2000", "NETGEAR WNR2000", wnr2000_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-wp543.c linux-2.6.37/arch/mips/ar71xx/mach-wp543.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-wp543.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-wp543.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,99 @@
++/*
++ * Compex WP543/WPJ543 board support
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-pb42-pci.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define WP543_GPIO_SW6 2
++#define WP543_GPIO_LED_1 3
++#define WP543_GPIO_LED_2 4
++#define WP543_GPIO_LED_WLAN 5
++#define WP543_GPIO_LED_CONN 6
++#define WP543_GPIO_LED_DIAG 7
++#define WP543_GPIO_SW4 8
++
++#define WP543_BUTTONS_POLL_INTERVAL 20
++
++static struct gpio_led wp543_leds_gpio[] __initdata = {
++ {
++ .name = "wp543:green:led1",
++ .gpio = WP543_GPIO_LED_1,
++ .active_low = 1,
++ }, {
++ .name = "wp543:green:led2",
++ .gpio = WP543_GPIO_LED_2,
++ .active_low = 1,
++ }, {
++ .name = "wp543:green:wlan",
++ .gpio = WP543_GPIO_LED_WLAN,
++ .active_low = 1,
++ }, {
++ .name = "wp543:green:conn",
++ .gpio = WP543_GPIO_LED_CONN,
++ .active_low = 1,
++ }, {
++ .name = "wp543:green:diag",
++ .gpio = WP543_GPIO_LED_DIAG,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button wp543_gpio_buttons[] __initdata = {
++ {
++ .desc = "sw6",
++ .type = EV_KEY,
++ .code = BTN_0,
++ .threshold = 3,
++ .gpio = WP543_GPIO_SW6,
++ }, {
++ .desc = "sw4",
++ .type = EV_KEY,
++ .code = BTN_1,
++ .threshold = 3,
++ .gpio = WP543_GPIO_SW4,
++ }
++};
++
++static void __init wp543_setup(void)
++{
++ ar71xx_add_device_m25p80(NULL);
++
++ ar71xx_add_device_mdio(0xfffffff7);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ar71xx_eth0_data.phy_mask = 0x08;
++ ar71xx_eth0_data.reset_bit = RESET_MODULE_GE0_MAC |
++ RESET_MODULE_GE0_PHY;
++ ar71xx_add_device_eth(0);
++
++ ar71xx_add_device_usb();
++
++ pb42_pci_init();
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wp543_leds_gpio),
++ wp543_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, WP543_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(wp543_gpio_buttons),
++ wp543_gpio_buttons);
++}
++
++MIPS_MACHINE(AR71XX_MACH_WP543, "WP543", "Compex WP543", wp543_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-wrt160nl.c linux-2.6.37/arch/mips/ar71xx/mach-wrt160nl.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-wrt160nl.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-wrt160nl.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,158 @@
++/*
++ * Linksys WRT160NL board support
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-m25p80.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++#include "nvram.h"
++
++#define WRT160NL_GPIO_LED_POWER 14
++#define WRT160NL_GPIO_LED_WPS_AMBER 9
++#define WRT160NL_GPIO_LED_WPS_BLUE 8
++#define WRT160NL_GPIO_LED_WLAN 6
++
++#define WRT160NL_GPIO_BTN_WPS 7
++#define WRT160NL_GPIO_BTN_RESET 21
++
++#define WRT160NL_BUTTONS_POLL_INTERVAL 20
++
++#define WRT160NL_NVRAM_ADDR 0x1f7e0000
++#define WRT160NL_NVRAM_SIZE 0x10000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition wrt160nl_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x040000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "kernel",
++ .offset = 0x040000,
++ .size = 0x0e0000,
++ } , {
++ .name = "filesytem",
++ .offset = 0x120000,
++ .size = 0x6c0000,
++ } , {
++ .name = "nvram",
++ .offset = 0x7e0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "ART",
++ .offset = 0x7f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x040000,
++ .size = 0x7a0000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data wrt160nl_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = wrt160nl_partitions,
++ .nr_parts = ARRAY_SIZE(wrt160nl_partitions),
++#endif
++};
++
++static struct gpio_led wrt160nl_leds_gpio[] __initdata = {
++ {
++ .name = "wrt160nl:blue:power",
++ .gpio = WRT160NL_GPIO_LED_POWER,
++ .active_low = 1,
++ .default_trigger = "default-on",
++ }, {
++ .name = "wrt160nl:amber:wps",
++ .gpio = WRT160NL_GPIO_LED_WPS_AMBER,
++ .active_low = 1,
++ }, {
++ .name = "wrt160nl:blue:wps",
++ .gpio = WRT160NL_GPIO_LED_WPS_BLUE,
++ .active_low = 1,
++ }, {
++ .name = "wrt160nl:blue:wlan",
++ .gpio = WRT160NL_GPIO_LED_WLAN,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button wrt160nl_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = WRT160NL_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "wps",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = WRT160NL_GPIO_BTN_WPS,
++ .active_low = 1,
++ }
++};
++
++static void __init wrt160nl_setup(void)
++{
++ const char *nvram = (char *) KSEG1ADDR(WRT160NL_NVRAM_ADDR);
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++ u8 mac[6];
++
++ if (nvram_parse_mac_addr(nvram, WRT160NL_NVRAM_SIZE,
++ "lan_hwaddr=", mac) == 0)
++ ar71xx_set_mac_base(mac);
++
++ ar71xx_add_device_mdio(0x0);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.phy_mask = 0x01;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.phy_mask = 0x10;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_m25p80(&wrt160nl_flash_data);
++
++ ar71xx_add_device_usb();
++
++ if (nvram_parse_mac_addr(nvram, WRT160NL_NVRAM_SIZE,
++ "wl0_hwaddr=", mac) == 0)
++ ar913x_add_device_wmac(eeprom, mac);
++ else
++ ar913x_add_device_wmac(eeprom, NULL);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wrt160nl_leds_gpio),
++ wrt160nl_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, WRT160NL_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(wrt160nl_gpio_buttons),
++ wrt160nl_gpio_buttons);
++
++}
++
++MIPS_MACHINE(AR71XX_MACH_WRT160NL, "WRT160NL", "Linksys WRT160NL",
++ wrt160nl_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-wrt400n.c linux-2.6.37/arch/mips/ar71xx/mach-wrt400n.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-wrt400n.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-wrt400n.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,168 @@
++/*
++ * Linksys WRT400N board support
++ *
++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2009 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-ap94-pci.h"
++#include "dev-m25p80.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++
++#define WRT400N_GPIO_LED_ORANGE 5
++#define WRT400N_GPIO_LED_GREEN 4
++#define WRT400N_GPIO_LED_POWER 1
++#define WRT400N_GPIO_LED_WLAN 0
++
++#define WRT400N_GPIO_BTN_RESET 8
++#define WRT400N_GPIO_BTN_WLSEC 3
++
++#define WRT400N_BUTTONS_POLL_INTERVAL 20
++
++#define WRT400N_MAC_ADDR_OFFSET 0x120c
++#define WRT400N_CALDATA0_OFFSET 0x1000
++#define WRT400N_CALDATA1_OFFSET 0x5000
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition wrt400n_partitions[] = {
++ {
++ .name = "uboot",
++ .offset = 0,
++ .size = 0x030000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "env",
++ .offset = 0x030000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "linux",
++ .offset = 0x040000,
++ .size = 0x140000,
++ } , {
++ .name = "rootfs",
++ .offset = 0x180000,
++ .size = 0x630000,
++ } , {
++ .name = "nvram",
++ .offset = 0x7b0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "factory",
++ .offset = 0x7c0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "language",
++ .offset = 0x7d0000,
++ .size = 0x020000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "caldata",
++ .offset = 0x7f0000,
++ .size = 0x010000,
++ .mask_flags = MTD_WRITEABLE,
++ } , {
++ .name = "firmware",
++ .offset = 0x040000,
++ .size = 0x770000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct flash_platform_data wrt400n_flash_data = {
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = wrt400n_partitions,
++ .nr_parts = ARRAY_SIZE(wrt400n_partitions),
++#endif
++};
++
++static struct gpio_led wrt400n_leds_gpio[] __initdata = {
++ {
++ .name = "wrt400n:green:status",
++ .gpio = WRT400N_GPIO_LED_GREEN,
++ .active_low = 1,
++ }, {
++ .name = "wrt400n:amber:aoss",
++ .gpio = WRT400N_GPIO_LED_ORANGE,
++ .active_low = 1,
++ }, {
++ .name = "wrt400n:green:wlan",
++ .gpio = WRT400N_GPIO_LED_WLAN,
++ .active_low = 1,
++ }, {
++ .name = "wrt400n:green:power",
++ .gpio = WRT400N_GPIO_LED_POWER,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button wrt400n_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = WRT400N_GPIO_BTN_RESET,
++ .active_low = 1,
++ } , {
++ .desc = "wlsec",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = WRT400N_GPIO_BTN_WLSEC,
++ .active_low = 1,
++ }
++};
++
++static void __init wrt400n_setup(void)
++{
++ u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
++ u8 mac[6];
++ int i;
++
++ memcpy(mac, art + WRT400N_MAC_ADDR_OFFSET, 6);
++ for (i = 5; i >= 3; i--)
++ if (++mac[i] != 0x00) break;
++
++ ar71xx_set_mac_base(mac);
++
++ ar71xx_add_device_mdio(0x0);
++
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth0_data.speed = SPEED_100;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ar71xx_eth1_data.phy_mask = 0x10;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_m25p80(&wrt400n_flash_data);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wrt400n_leds_gpio),
++ wrt400n_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, WRT400N_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(wrt400n_gpio_buttons),
++ wrt400n_gpio_buttons);
++
++ ap94_pci_init(art + WRT400N_CALDATA0_OFFSET, NULL,
++ art + WRT400N_CALDATA1_OFFSET, NULL);
++}
++
++MIPS_MACHINE(AR71XX_MACH_WRT400N, "WRT400N", "Linksys WRT400N", wrt400n_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c linux-2.6.37/arch/mips/ar71xx/mach-wzr-hp-g300nh.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/mach-wzr-hp-g300nh.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/mach-wzr-hp-g300nh.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,265 @@
++/*
++ * Buffalo WZR-HP-G300NH board support
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/nxp_74hc153.h>
++#include <linux/rtl8366s.h>
++
++#include <asm/mips_machine.h>
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/ar91xx_flash.h>
++
++#include "machtype.h"
++#include "devices.h"
++#include "dev-ar913x-wmac.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++
++#define WZRHPG300NH_GPIO_LED_USB 0
++#define WZRHPG300NH_GPIO_LED_DIAG 1
++#define WZRHPG300NH_GPIO_LED_WIRELESS 6
++#define WZRHPG300NH_GPIO_LED_SECURITY 17
++#define WZRHPG300NH_GPIO_LED_ROUTER 18
++
++#define WZRHPG300NH_GPIO_RTL8366_SDA 19
++#define WZRHPG300NH_GPIO_RTL8366_SCK 20
++
++#define WZRHPG300NH_GPIO_74HC153_S0 9
++#define WZRHPG300NH_GPIO_74HC153_S1 11
++#define WZRHPG300NH_GPIO_74HC153_1Y 12
++#define WZRHPG300NH_GPIO_74HC153_2Y 14
++
++#define WZRHPG300NH_GPIO_EXP_BASE 32
++#define WZRHPG300NH_GPIO_BTN_AOSS (WZRHPG300NH_GPIO_EXP_BASE + 0)
++#define WZRHPG300NH_GPIO_BTN_RESET (WZRHPG300NH_GPIO_EXP_BASE + 1)
++#define WZRHPG300NH_GPIO_BTN_ROUTER_ON (WZRHPG300NH_GPIO_EXP_BASE + 2)
++#define WZRHPG300NH_GPIO_BTN_QOS_ON (WZRHPG300NH_GPIO_EXP_BASE + 3)
++#define WZRHPG300NH_GPIO_BTN_USB (WZRHPG300NH_GPIO_EXP_BASE + 5)
++#define WZRHPG300NH_GPIO_BTN_ROUTER_AUTO (WZRHPG300NH_GPIO_EXP_BASE + 6)
++#define WZRHPG300NH_GPIO_BTN_QOS_OFF (WZRHPG300NH_GPIO_EXP_BASE + 7)
++
++#define WZRHPG300NH_BUTTONS_POLL_INTERVAL 20
++
++#define WZRHPG300NH_MAC_OFFSET 0x20c
++
++#ifdef CONFIG_MTD_PARTITIONS
++static struct mtd_partition wzrhpg300nh_flash_partitions[] = {
++ {
++ .name = "u-boot",
++ .offset = 0,
++ .size = 0x0040000,
++ .mask_flags = MTD_WRITEABLE,
++ }, {
++ .name = "u-boot-env",
++ .offset = 0x0040000,
++ .size = 0x0020000,
++ .mask_flags = MTD_WRITEABLE,
++ }, {
++ .name = "kernel",
++ .offset = 0x0060000,
++ .size = 0x0100000,
++ }, {
++ .name = "rootfs",
++ .offset = 0x0160000,
++ .size = 0x1e60000,
++ }, {
++ .name = "user_property",
++ .offset = 0x1fc0000,
++ .size = 0x0020000,
++ .mask_flags = MTD_WRITEABLE,
++ }, {
++ .name = "art",
++ .offset = 0x1fe0000,
++ .size = 0x0020000,
++ .mask_flags = MTD_WRITEABLE,
++ }, {
++ .name = "firmware",
++ .offset = 0x0060000,
++ .size = 0x1f60000,
++ }
++};
++#endif /* CONFIG_MTD_PARTITIONS */
++
++static struct ar91xx_flash_platform_data wzrhpg300nh_flash_data = {
++ .width = 2,
++#ifdef CONFIG_MTD_PARTITIONS
++ .parts = wzrhpg300nh_flash_partitions,
++ .nr_parts = ARRAY_SIZE(wzrhpg300nh_flash_partitions),
++#endif
++};
++
++#define WZRHPG300NH_FLASH_BASE 0x1e000000
++#define WZRHPG300NH_FLASH_SIZE (32 * 1024 * 1024)
++
++static struct resource wzrhpg300nh_flash_resources[] = {
++ [0] = {
++ .start = WZRHPG300NH_FLASH_BASE,
++ .end = WZRHPG300NH_FLASH_BASE + WZRHPG300NH_FLASH_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++static struct platform_device wzrhpg300nh_flash_device = {
++ .name = "ar91xx-flash",
++ .id = -1,
++ .resource = wzrhpg300nh_flash_resources,
++ .num_resources = ARRAY_SIZE(wzrhpg300nh_flash_resources),
++ .dev = {
++ .platform_data = &wzrhpg300nh_flash_data,
++ }
++};
++
++static struct gpio_led wzrhpg300nh_leds_gpio[] __initdata = {
++ {
++ .name = "wzr-hp-g300nh:orange:security",
++ .gpio = WZRHPG300NH_GPIO_LED_SECURITY,
++ .active_low = 1,
++ }, {
++ .name = "wzr-hp-g300nh:green:wireless",
++ .gpio = WZRHPG300NH_GPIO_LED_WIRELESS,
++ .active_low = 1,
++ }, {
++ .name = "wzr-hp-g300nh:green:router",
++ .gpio = WZRHPG300NH_GPIO_LED_ROUTER,
++ .active_low = 1,
++ }, {
++ .name = "wzr-hp-g300nh:red:diag",
++ .gpio = WZRHPG300NH_GPIO_LED_DIAG,
++ .active_low = 1,
++ }, {
++ .name = "wzr-hp-g300nh:blue:usb",
++ .gpio = WZRHPG300NH_GPIO_LED_USB,
++ .active_low = 1,
++ }
++};
++
++static struct gpio_button wzrhpg300nh_gpio_buttons[] __initdata = {
++ {
++ .desc = "reset",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .threshold = 3,
++ .gpio = WZRHPG300NH_GPIO_BTN_RESET,
++ .active_low = 1,
++ }, {
++ .desc = "aoss",
++ .type = EV_KEY,
++ .code = KEY_WPS_BUTTON,
++ .threshold = 3,
++ .gpio = WZRHPG300NH_GPIO_BTN_AOSS,
++ .active_low = 1,
++ }, {
++ .desc = "usb",
++ .type = EV_KEY,
++ .code = BTN_2,
++ .threshold = 3,
++ .gpio = WZRHPG300NH_GPIO_BTN_USB,
++ .active_low = 1,
++ }, {
++ .desc = "qos_on",
++ .type = EV_KEY,
++ .code = BTN_3,
++ .threshold = 3,
++ .gpio = WZRHPG300NH_GPIO_BTN_QOS_ON,
++ .active_low = 0,
++ }, {
++ .desc = "qos_off",
++ .type = EV_KEY,
++ .code = BTN_4,
++ .threshold = 3,
++ .gpio = WZRHPG300NH_GPIO_BTN_QOS_OFF,
++ .active_low = 0,
++ }, {
++ .desc = "router_on",
++ .type = EV_KEY,
++ .code = BTN_5,
++ .threshold = 3,
++ .gpio = WZRHPG300NH_GPIO_BTN_ROUTER_ON,
++ .active_low = 0,
++ }, {
++ .desc = "router_auto",
++ .type = EV_KEY,
++ .code = BTN_6,
++ .threshold = 3,
++ .gpio = WZRHPG300NH_GPIO_BTN_ROUTER_AUTO,
++ .active_low = 0,
++ }
++};
++
++static struct nxp_74hc153_platform_data wzrhpg300nh_74hc153_data = {
++ .gpio_base = WZRHPG300NH_GPIO_EXP_BASE,
++ .gpio_pin_s0 = WZRHPG300NH_GPIO_74HC153_S0,
++ .gpio_pin_s1 = WZRHPG300NH_GPIO_74HC153_S1,
++ .gpio_pin_1y = WZRHPG300NH_GPIO_74HC153_1Y,
++ .gpio_pin_2y = WZRHPG300NH_GPIO_74HC153_2Y,
++};
++
++static struct platform_device wzrhpg300nh_74hc153_device = {
++ .name = NXP_74HC153_DRIVER_NAME,
++ .id = -1,
++ .dev = {
++ .platform_data = &wzrhpg300nh_74hc153_data,
++ }
++};
++
++static struct rtl8366s_platform_data wzrhpg300nh_rtl8366s_data = {
++ .gpio_sda = WZRHPG300NH_GPIO_RTL8366_SDA,
++ .gpio_sck = WZRHPG300NH_GPIO_RTL8366_SCK,
++};
++
++static struct platform_device wzrhpg300nh_rtl8366s_device = {
++ .name = RTL8366S_DRIVER_NAME,
++ .id = -1,
++ .dev = {
++ .platform_data = &wzrhpg300nh_rtl8366s_data,
++ }
++};
++
++static void __init wzrhpg300nh_setup(void)
++{
++ u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
++
++ ar71xx_set_mac_base(eeprom + WZRHPG300NH_MAC_OFFSET);
++
++ ar71xx_eth0_pll_data.pll_1000 = 0x1e000100;
++ ar71xx_eth0_data.mii_bus_dev = &wzrhpg300nh_rtl8366s_device.dev;
++ ar71xx_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth0_data.speed = SPEED_1000;
++ ar71xx_eth0_data.duplex = DUPLEX_FULL;
++
++ ar71xx_eth1_pll_data.pll_1000 = 0x1e000100;
++ ar71xx_eth1_data.mii_bus_dev = &wzrhpg300nh_rtl8366s_device.dev;
++ ar71xx_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ar71xx_eth1_data.phy_mask = 0x10;
++
++ ar71xx_add_device_eth(0);
++ ar71xx_add_device_eth(1);
++
++ ar71xx_add_device_usb();
++ ar913x_add_device_wmac(eeprom, NULL);
++
++ platform_device_register(&wzrhpg300nh_74hc153_device);
++ platform_device_register(&wzrhpg300nh_flash_device);
++ platform_device_register(&wzrhpg300nh_rtl8366s_device);
++
++ ar71xx_add_device_leds_gpio(-1, ARRAY_SIZE(wzrhpg300nh_leds_gpio),
++ wzrhpg300nh_leds_gpio);
++
++ ar71xx_add_device_gpio_buttons(-1, WZRHPG300NH_BUTTONS_POLL_INTERVAL,
++ ARRAY_SIZE(wzrhpg300nh_gpio_buttons),
++ wzrhpg300nh_gpio_buttons);
++
++}
++
++MIPS_MACHINE(AR71XX_MACH_WZR_HP_G300NH, "WZR-HP-G300NH",
++ "Buffalo WZR-HP-G300NH", wzrhpg300nh_setup);
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/machtype.h linux-2.6.37/arch/mips/ar71xx/machtype.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/machtype.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/machtype.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,60 @@
++/*
++ * Atheros AR71xx machine type definitions
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_MACHTYPE_H
++#define _AR71XX_MACHTYPE_H
++
++#include <asm/mips_machine.h>
++
++enum ar71xx_mach_type {
++ AR71XX_MACH_GENERIC = 0,
++ AR71XX_MACH_AP81, /* Atheros AP81 */
++ AR71XX_MACH_AP83, /* Atheros AP83 */
++ AR71XX_MACH_AW_NR580, /* AzureWave AW-NR580 */
++ AR71XX_MACH_DIR_600_A1, /* D-Link DIR-600 rev. A1 */
++ AR71XX_MACH_DIR_615_C1, /* D-Link DIR-615 rev. C1 */
++ AR71XX_MACH_DIR_825_B1, /* D-Link DIR-825 rev. B1 */
++ AR71XX_MACH_RB_411, /* MikroTik RouterBOARD 411/411A/411AH */
++ AR71XX_MACH_RB_411U, /* MikroTik RouterBOARD 411U */
++ AR71XX_MACH_RB_433, /* MikroTik RouterBOARD 433/433AH */
++ AR71XX_MACH_RB_433U, /* MikroTik RouterBOARD 433UAH */
++ AR71XX_MACH_RB_450, /* MikroTik RouterBOARD 450 */
++ AR71XX_MACH_RB_450G, /* MikroTik RouterBOARD 450G */
++ AR71XX_MACH_RB_493, /* Mikrotik RouterBOARD 493/493AH */
++ AR71XX_MACH_RB_750, /* MikroTik RouterBOARD 750 */
++ AR71XX_MACH_PB42, /* Atheros PB42 */
++ AR71XX_MACH_PB44, /* Atheros PB44 */
++ AR71XX_MACH_PB92, /* Atheros PB92 */
++ AR71XX_MACH_MZK_W04NU, /* Planex MZK-W04NU */
++ AR71XX_MACH_MZK_W300NH, /* Planex MZK-W300NH */
++ AR71XX_MACH_NBG460N, /* Zyxel NBG460N/550N/550NH */
++ AR71XX_MACH_TEW_632BRP, /* TRENDnet TEW-632BRP */
++ AR71XX_MACH_TL_WR741ND, /* TP-LINK TL-WR741ND */
++ AR71XX_MACH_TL_WR841N_V1, /* TP-LINK TL-WR841N v1 */
++ AR71XX_MACH_TL_WR941ND, /* TP-LINK TL-WR941ND */
++ AR71XX_MACH_TL_WR1043ND, /* TP-LINK TL-WR1041ND */
++ AR71XX_MACH_UBNT_LSSR71, /* Ubiquiti LS-SR71 */
++ AR71XX_MACH_UBNT_LSX, /* Ubiquiti LSX */
++ AR71XX_MACH_UBNT_RS, /* Ubiquiti RouterStation */
++ AR71XX_MACH_UBNT_AR71XX, /* Ubiquiti AR71xx-based board */
++ AR71XX_MACH_UBNT_RSPRO, /* Ubiquiti RouterStation Pro */
++ AR71XX_MACH_UBNT_BULLET_M, /* Ubiquiti Bullet M */
++ AR71XX_MACH_UBNT_ROCKET_M, /* Ubiquiti Rocket M */
++ AR71XX_MACH_UBNT_NANO_M, /* Ubiquiti NanoStation M */
++ AR71XX_MACH_WNDR3700, /* NETGEAR WNDR3700 */
++ AR71XX_MACH_WNR2000, /* NETGEAR WNR2000 */
++ AR71XX_MACH_WP543, /* Compex WP543 */
++ AR71XX_MACH_WRT160NL, /* Linksys WRT160NL */
++ AR71XX_MACH_WRT400N, /* Linksys WRT400N */
++ AR71XX_MACH_WZR_HP_G300NH, /* Buffalo WZR-HP-G300NH */
++};
++
++#endif /* _AR71XX_MACHTYPE_H */
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/nvram.c linux-2.6.37/arch/mips/ar71xx/nvram.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/nvram.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/nvram.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,75 @@
++/*
++ * Atheros AR71xx minimal nvram support
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/vmalloc.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/string.h>
++
++#include "nvram.h"
++
++char *nvram_find_var(const char *name, const char *buf, unsigned buf_len)
++{
++ unsigned len = strlen(name);
++ char *cur, *last;
++
++ if (buf_len == 0 || len == 0)
++ return NULL;
++
++ if (buf_len < len)
++ return NULL;
++
++ if (len == 1)
++ return memchr(buf, (int) *name, buf_len);
++
++ last = (char *) buf + buf_len - len;
++ for (cur = (char *) buf; cur <= last; cur++)
++ if (cur[0] == name[0] && memcmp(cur, name, len) == 0)
++ return cur + len;
++
++ return NULL;
++}
++
++int nvram_parse_mac_addr(const char *nvram, unsigned nvram_len,
++ const char *name, char *mac)
++{
++ char *buf;
++ char *mac_str;
++ int ret;
++ int t;
++
++ buf = vmalloc(nvram_len);
++ if (!buf)
++ return -ENOMEM;
++
++ memcpy(buf, nvram, nvram_len);
++ buf[nvram_len - 1] = '\0';
++
++ mac_str = nvram_find_var(name, buf, nvram_len);
++ if (!mac_str) {
++ ret = -EINVAL;
++ goto free;
++ }
++
++ t = sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
++ &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
++
++ if (t != 6) {
++ ret = -EINVAL;
++ goto free;
++ }
++
++ ret = 0;
++
++ free:
++ vfree(buf);
++ return ret;
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/nvram.h linux-2.6.37/arch/mips/ar71xx/nvram.h
+--- linux-2.6.37.orig/arch/mips/ar71xx/nvram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/nvram.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,19 @@
++/*
++ * Atheros AR71xx minimal nvram support
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _AR71XX_NVRAM_H
++#define _AR71XX_NVRAM_H
++
++char *nvram_find_var(const char *name, const char *buf,
++ unsigned buf_len) __init;
++int nvram_parse_mac_addr(const char *nvram, unsigned nvram_len,
++ const char *name, char *mac) __init;
++
++#endif /* _AR71XX_NVRAM_H */
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/pci.c linux-2.6.37/arch/mips/ar71xx/pci.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/pci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/pci.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,93 @@
++/*
++ * Atheros AR71xx PCI setup code
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++
++#include <asm/traps.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++unsigned ar71xx_pci_nr_irqs __initdata;
++struct ar71xx_pci_irq *ar71xx_pci_irq_map __initdata;
++
++int (*ar71xx_pci_plat_dev_init)(struct pci_dev *dev);
++
++static int ar71xx_be_handler(struct pt_regs *regs, int is_fixup)
++{
++ int err = 0;
++
++ err = ar71xx_pci_be_handler(is_fixup);
++
++ return (is_fixup && !err) ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
++}
++
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++ if (ar71xx_pci_plat_dev_init)
++ return ar71xx_pci_plat_dev_init(dev);
++
++ return 0;
++}
++
++int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
++{
++ int ret = 0;
++
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7130:
++ case AR71XX_SOC_AR7141:
++ case AR71XX_SOC_AR7161:
++ ret = ar71xx_pcibios_map_irq(dev, slot, pin);
++ break;
++
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ ret = ar724x_pcibios_map_irq(dev, slot, pin);
++ break;
++
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++int __init ar71xx_pci_init(unsigned nr_irqs, struct ar71xx_pci_irq *map)
++{
++ int ret = 0;
++
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7130:
++ case AR71XX_SOC_AR7141:
++ case AR71XX_SOC_AR7161:
++ board_be_handler = ar71xx_be_handler;
++ ret = ar71xx_pcibios_init();
++ break;
++
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ ret = ar724x_pcibios_init();
++ break;
++
++ default:
++ return 0;
++ }
++
++ ar71xx_pci_nr_irqs = nr_irqs;
++ ar71xx_pci_irq_map = map;
++
++ return ret;
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/prom.c linux-2.6.37/arch/mips/ar71xx/prom.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/prom.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/prom.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,105 @@
++/*
++ * Atheros AR71xx SoC specific prom routines
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/string.h>
++
++#include <asm/bootinfo.h>
++#include <asm/addrspace.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++static inline int is_valid_ram_addr(void *addr)
++{
++ if (((u32) addr > KSEG0) &&
++ ((u32) addr < (KSEG0 + AR71XX_MEM_SIZE_MAX)))
++ return 1;
++
++ if (((u32) addr > KSEG1) &&
++ ((u32) addr < (KSEG1 + AR71XX_MEM_SIZE_MAX)))
++ return 1;
++
++ return 0;
++}
++
++static void __init ar71xx_prom_append_cmdline(const char *name,
++ const char *value)
++{
++ char buf[COMMAND_LINE_SIZE];
++
++ snprintf(buf, sizeof(buf), " %s=%s", name, value);
++ strlcat(arcs_cmdline, buf, sizeof(arcs_cmdline));
++}
++
++static void __init ar71xx_prom_find_env(char **envp, const char *name)
++{
++ int len = strlen(name);
++ char **p;
++
++ if (!is_valid_ram_addr(envp))
++ return;
++
++ for (p = envp; is_valid_ram_addr(*p); p++) {
++ if (strncmp(name, *p, len) == 0 && (*p)[len] == '=') {
++ ar71xx_prom_append_cmdline(name, *p + len + 1);
++ break;
++ }
++
++ /* RedBoot env comes in pointer pairs - key, value */
++ if (strncmp(name, *p, len) == 0 && (*p)[len] == 0)
++ if (is_valid_ram_addr(*(++p))) {
++ ar71xx_prom_append_cmdline(name, *p);
++ break;
++ }
++ }
++}
++
++static int inline ar71xx_use__image_cmdline(void) { return 0; }
++
++static __init void ar71xx_prom_init_cmdline(int argc, char **argv)
++{
++ int i;
++
++ if (ar71xx_use__image_cmdline())
++ return;
++
++ if (!is_valid_ram_addr(argv))
++ return;
++
++ for (i = 0; i < argc; i++)
++ if (is_valid_ram_addr(argv[i])) {
++ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
++ strlcat(arcs_cmdline, argv[i], sizeof(arcs_cmdline));
++ }
++}
++
++void __init prom_init(void)
++{
++ char **envp;
++
++ printk(KERN_DEBUG "prom: fw_arg0=%08x, fw_arg1=%08x, "
++ "fw_arg2=%08x, fw_arg3=%08x\n",
++ (unsigned int)fw_arg0, (unsigned int)fw_arg1,
++ (unsigned int)fw_arg2, (unsigned int)fw_arg3);
++
++
++ ar71xx_prom_init_cmdline(fw_arg0, (char **)fw_arg1);
++
++ envp = (char **)fw_arg2;
++ ar71xx_prom_find_env(envp, "board");
++}
++
++void __init prom_free_prom_memory(void)
++{
++ /* We do not have to prom memory to free */
++}
+diff -Nur linux-2.6.37.orig/arch/mips/ar71xx/setup.c linux-2.6.37/arch/mips/ar71xx/setup.c
+--- linux-2.6.37.orig/arch/mips/ar71xx/setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/ar71xx/setup.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,310 @@
++/*
++ * Atheros AR71xx SoC specific setup
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/bootmem.h>
++
++#include <asm/bootinfo.h>
++#include <asm/time.h> /* for mips_hpt_frequency */
++#include <asm/reboot.h> /* for _machine_{restart,halt} */
++#include <asm/mips_machine.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#include "machtype.h"
++#include "devices.h"
++
++#define AR71XX_SYS_TYPE_LEN 64
++#define AR71XX_BASE_FREQ 40000000
++#define AR91XX_BASE_FREQ 5000000
++#define AR724X_BASE_FREQ 5000000
++
++u32 ar71xx_cpu_freq;
++EXPORT_SYMBOL_GPL(ar71xx_cpu_freq);
++
++u32 ar71xx_ahb_freq;
++EXPORT_SYMBOL_GPL(ar71xx_ahb_freq);
++
++u32 ar71xx_ddr_freq;
++EXPORT_SYMBOL_GPL(ar71xx_ddr_freq);
++
++enum ar71xx_soc_type ar71xx_soc;
++EXPORT_SYMBOL_GPL(ar71xx_soc);
++
++static char ar71xx_sys_type[AR71XX_SYS_TYPE_LEN];
++
++static void ar71xx_restart(char *command)
++{
++ ar71xx_device_stop(RESET_MODULE_FULL_CHIP);
++ for (;;)
++ if (cpu_wait)
++ cpu_wait();
++}
++
++static void ar71xx_halt(void)
++{
++ while (1)
++ cpu_wait();
++}
++
++static void __init ar71xx_detect_mem_size(void)
++{
++ unsigned long size;
++
++ for (size = AR71XX_MEM_SIZE_MIN; size < AR71XX_MEM_SIZE_MAX;
++ size <<= 1 ) {
++ if (!memcmp(ar71xx_detect_mem_size,
++ ar71xx_detect_mem_size + size, 1024))
++ break;
++ }
++
++ add_memory_region(0, size, BOOT_MEM_RAM);
++}
++
++static void __init ar71xx_detect_sys_type(void)
++{
++ char *chip = "????";
++ u32 id;
++ u32 major;
++ u32 minor;
++ u32 rev = 0;
++
++ id = ar71xx_reset_rr(AR71XX_RESET_REG_REV_ID);
++ major = id & REV_ID_MAJOR_MASK;
++
++ switch (major) {
++ case REV_ID_MAJOR_AR71XX:
++ minor = id & AR71XX_REV_ID_MINOR_MASK;
++ rev = id >> AR71XX_REV_ID_REVISION_SHIFT;
++ rev &= AR71XX_REV_ID_REVISION_MASK;
++ switch (minor) {
++ case AR71XX_REV_ID_MINOR_AR7130:
++ ar71xx_soc = AR71XX_SOC_AR7130;
++ chip = "7130";
++ break;
++
++ case AR71XX_REV_ID_MINOR_AR7141:
++ ar71xx_soc = AR71XX_SOC_AR7141;
++ chip = "7141";
++ break;
++
++ case AR71XX_REV_ID_MINOR_AR7161:
++ ar71xx_soc = AR71XX_SOC_AR7161;
++ chip = "7161";
++ break;
++ }
++ break;
++
++ case REV_ID_MAJOR_AR7240:
++ ar71xx_soc = AR71XX_SOC_AR7240;
++ chip = "7240";
++ rev = (id & AR724X_REV_ID_REVISION_MASK);
++ break;
++
++ case REV_ID_MAJOR_AR7241:
++ ar71xx_soc = AR71XX_SOC_AR7241;
++ chip = "7241";
++ rev = (id & AR724X_REV_ID_REVISION_MASK);
++ break;
++
++ case REV_ID_MAJOR_AR7242:
++ ar71xx_soc = AR71XX_SOC_AR7242;
++ chip = "7242";
++ rev = (id & AR724X_REV_ID_REVISION_MASK);
++ break;
++
++ case REV_ID_MAJOR_AR913X:
++ minor = id & AR91XX_REV_ID_MINOR_MASK;
++ rev = id >> AR91XX_REV_ID_REVISION_SHIFT;
++ rev &= AR91XX_REV_ID_REVISION_MASK;
++ switch (minor) {
++ case AR91XX_REV_ID_MINOR_AR9130:
++ ar71xx_soc = AR71XX_SOC_AR9130;
++ chip = "9130";
++ break;
++
++ case AR91XX_REV_ID_MINOR_AR9132:
++ ar71xx_soc = AR71XX_SOC_AR9132;
++ chip = "9132";
++ break;
++ }
++ break;
++
++ default:
++ panic("ar71xx: unknown chip id:0x%08x\n", id);
++ }
++
++ sprintf(ar71xx_sys_type, "Atheros AR%s rev %u", chip, rev);
++}
++
++static void __init ar91xx_detect_sys_frequency(void)
++{
++ u32 pll;
++ u32 freq;
++ u32 div;
++
++ pll = ar71xx_pll_rr(AR91XX_PLL_REG_CPU_CONFIG);
++
++ div = ((pll >> AR91XX_PLL_DIV_SHIFT) & AR91XX_PLL_DIV_MASK);
++ freq = div * AR91XX_BASE_FREQ;
++
++ ar71xx_cpu_freq = freq;
++
++ div = ((pll >> AR91XX_DDR_DIV_SHIFT) & AR91XX_DDR_DIV_MASK) + 1;
++ ar71xx_ddr_freq = freq / div;
++
++ div = (((pll >> AR91XX_AHB_DIV_SHIFT) & AR91XX_AHB_DIV_MASK) + 1) * 2;
++ ar71xx_ahb_freq = ar71xx_cpu_freq / div;
++}
++
++static void __init ar71xx_detect_sys_frequency(void)
++{
++ u32 pll;
++ u32 freq;
++ u32 div;
++
++ pll = ar71xx_pll_rr(AR71XX_PLL_REG_CPU_CONFIG);
++
++ div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1;
++ freq = div * AR71XX_BASE_FREQ;
++
++ div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
++ ar71xx_cpu_freq = freq / div;
++
++ div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
++ ar71xx_ddr_freq = freq / div;
++
++ div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
++ ar71xx_ahb_freq = ar71xx_cpu_freq / div;
++}
++
++static void __init ar724x_detect_sys_frequency(void)
++{
++ u32 pll;
++ u32 freq;
++ u32 div;
++
++ pll = ar71xx_pll_rr(AR724X_PLL_REG_CPU_CONFIG);
++
++ div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK);
++ freq = div * AR724X_BASE_FREQ;
++
++ div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK);
++ freq *= div;
++
++ ar71xx_cpu_freq = freq;
++
++ div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1;
++ ar71xx_ddr_freq = freq / div;
++
++ div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2;
++ ar71xx_ahb_freq = ar71xx_cpu_freq / div;
++}
++
++static void __init detect_sys_frequency(void)
++{
++ switch (ar71xx_soc) {
++ case AR71XX_SOC_AR7130:
++ case AR71XX_SOC_AR7141:
++ case AR71XX_SOC_AR7161:
++ ar71xx_detect_sys_frequency();
++ break;
++
++ case AR71XX_SOC_AR7240:
++ case AR71XX_SOC_AR7241:
++ case AR71XX_SOC_AR7242:
++ ar724x_detect_sys_frequency();
++ break;
++
++ case AR71XX_SOC_AR9130:
++ case AR71XX_SOC_AR9132:
++ ar91xx_detect_sys_frequency();
++ break;
++
++ default:
++ BUG();
++ }
++}
++
++const char *get_system_type(void)
++{
++ return ar71xx_sys_type;
++}
++
++unsigned int __cpuinit get_c0_compare_irq(void)
++{
++ return CP0_LEGACY_COMPARE_IRQ;
++}
++
++void __init plat_mem_setup(void)
++{
++ set_io_port_base(KSEG1);
++
++ ar71xx_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
++ AR71XX_DDR_CTRL_SIZE);
++
++ ar71xx_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
++ AR71XX_PLL_SIZE);
++
++ ar71xx_reset_base = ioremap_nocache(AR71XX_RESET_BASE,
++ AR71XX_RESET_SIZE);
++
++ ar71xx_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
++
++ ar71xx_usb_ctrl_base = ioremap_nocache(AR71XX_USB_CTRL_BASE,
++ AR71XX_USB_CTRL_SIZE);
++
++ ar71xx_detect_mem_size();
++ ar71xx_detect_sys_type();
++ detect_sys_frequency();
++
++ printk(KERN_INFO
++ "%s, CPU:%u.%03u MHz, AHB:%u.%03u MHz, DDR:%u.%03u MHz\n",
++ ar71xx_sys_type,
++ ar71xx_cpu_freq / 1000000, (ar71xx_cpu_freq / 1000) % 1000,
++ ar71xx_ahb_freq / 1000000, (ar71xx_ahb_freq / 1000) % 1000,
++ ar71xx_ddr_freq / 1000000, (ar71xx_ddr_freq / 1000) % 1000);
++
++ _machine_restart = ar71xx_restart;
++ _machine_halt = ar71xx_halt;
++ pm_power_off = ar71xx_halt;
++}
++
++void __init plat_time_init(void)
++{
++ mips_hpt_frequency = ar71xx_cpu_freq / 2;
++}
++
++__setup("board=", mips_machtype_setup);
++
++static int __init ar71xx_machine_setup(void)
++{
++ ar71xx_gpio_init();
++
++ ar71xx_add_device_uart();
++ ar71xx_add_device_wdt();
++
++ mips_machine_setup();
++ return 0;
++}
++
++arch_initcall(ar71xx_machine_setup);
++
++static void __init ar71xx_generic_init(void)
++{
++ /* Nothing to do */
++}
++
++MIPS_MACHINE(AR71XX_MACH_GENERIC, "Generic", "Generic AR71xx board",
++ ar71xx_generic_init);
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h linux-2.6.37/arch/mips/include/asm/mach-ar71xx/ar71xx.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/ar71xx.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-ar71xx/ar71xx.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,514 @@
++/*
++ * Atheros AR71xx SoC specific definitions
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __ASM_MACH_AR71XX_H
++#define __ASM_MACH_AR71XX_H
++
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/bitops.h>
++
++#ifndef __ASSEMBLER__
++
++#define AR71XX_PCI_MEM_BASE 0x10000000
++#define AR71XX_PCI_MEM_SIZE 0x08000000
++#define AR71XX_APB_BASE 0x18000000
++#define AR71XX_GE0_BASE 0x19000000
++#define AR71XX_GE0_SIZE 0x01000000
++#define AR71XX_GE1_BASE 0x1a000000
++#define AR71XX_GE1_SIZE 0x01000000
++#define AR71XX_EHCI_BASE 0x1b000000
++#define AR71XX_EHCI_SIZE 0x01000000
++#define AR71XX_OHCI_BASE 0x1c000000
++#define AR71XX_OHCI_SIZE 0x01000000
++#define AR7240_OHCI_BASE 0x1b000000
++#define AR7240_OHCI_SIZE 0x01000000
++#define AR71XX_SPI_BASE 0x1f000000
++#define AR71XX_SPI_SIZE 0x01000000
++
++#define AR71XX_DDR_CTRL_BASE (AR71XX_APB_BASE + 0x00000000)
++#define AR71XX_DDR_CTRL_SIZE 0x10000
++#define AR71XX_CPU_BASE (AR71XX_APB_BASE + 0x00010000)
++#define AR71XX_UART_BASE (AR71XX_APB_BASE + 0x00020000)
++#define AR71XX_UART_SIZE 0x10000
++#define AR71XX_USB_CTRL_BASE (AR71XX_APB_BASE + 0x00030000)
++#define AR71XX_USB_CTRL_SIZE 0x10000
++#define AR71XX_GPIO_BASE (AR71XX_APB_BASE + 0x00040000)
++#define AR71XX_GPIO_SIZE 0x10000
++#define AR71XX_PLL_BASE (AR71XX_APB_BASE + 0x00050000)
++#define AR71XX_PLL_SIZE 0x10000
++#define AR71XX_RESET_BASE (AR71XX_APB_BASE + 0x00060000)
++#define AR71XX_RESET_SIZE 0x10000
++#define AR71XX_MII_BASE (AR71XX_APB_BASE + 0x00070000)
++#define AR71XX_MII_SIZE 0x10000
++#define AR71XX_SLIC_BASE (AR71XX_APB_BASE + 0x00090000)
++#define AR71XX_SLIC_SIZE 0x10000
++#define AR71XX_DMA_BASE (AR71XX_APB_BASE + 0x000A0000)
++#define AR71XX_DMA_SIZE 0x10000
++#define AR71XX_STEREO_BASE (AR71XX_APB_BASE + 0x000B0000)
++#define AR71XX_STEREO_SIZE 0x10000
++
++#define AR724X_PCI_CRP_BASE (AR71XX_APB_BASE + 0x000C0000)
++#define AR724X_PCI_CRP_SIZE 0x100
++
++#define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000F0000)
++#define AR724X_PCI_CTRL_SIZE 0x100
++
++#define AR91XX_WMAC_BASE (AR71XX_APB_BASE + 0x000C0000)
++#define AR91XX_WMAC_SIZE 0x30000
++
++#define AR71XX_MEM_SIZE_MIN 0x0200000
++#define AR71XX_MEM_SIZE_MAX 0x10000000
++
++#define AR71XX_CPU_IRQ_BASE 0
++#define AR71XX_MISC_IRQ_BASE 8
++#define AR71XX_MISC_IRQ_COUNT 8
++#define AR71XX_GPIO_IRQ_BASE 16
++#define AR71XX_GPIO_IRQ_COUNT 32
++#define AR71XX_PCI_IRQ_BASE 48
++#define AR71XX_PCI_IRQ_COUNT 8
++
++#define AR71XX_CPU_IRQ_IP2 (AR71XX_CPU_IRQ_BASE + 2)
++#define AR71XX_CPU_IRQ_USB (AR71XX_CPU_IRQ_BASE + 3)
++#define AR71XX_CPU_IRQ_GE0 (AR71XX_CPU_IRQ_BASE + 4)
++#define AR71XX_CPU_IRQ_GE1 (AR71XX_CPU_IRQ_BASE + 5)
++#define AR71XX_CPU_IRQ_MISC (AR71XX_CPU_IRQ_BASE + 6)
++#define AR71XX_CPU_IRQ_TIMER (AR71XX_CPU_IRQ_BASE + 7)
++
++#define AR71XX_MISC_IRQ_TIMER (AR71XX_MISC_IRQ_BASE + 0)
++#define AR71XX_MISC_IRQ_ERROR (AR71XX_MISC_IRQ_BASE + 1)
++#define AR71XX_MISC_IRQ_GPIO (AR71XX_MISC_IRQ_BASE + 2)
++#define AR71XX_MISC_IRQ_UART (AR71XX_MISC_IRQ_BASE + 3)
++#define AR71XX_MISC_IRQ_WDOG (AR71XX_MISC_IRQ_BASE + 4)
++#define AR71XX_MISC_IRQ_PERFC (AR71XX_MISC_IRQ_BASE + 5)
++#define AR71XX_MISC_IRQ_OHCI (AR71XX_MISC_IRQ_BASE + 6)
++#define AR71XX_MISC_IRQ_DMA (AR71XX_MISC_IRQ_BASE + 7)
++
++#define AR71XX_GPIO_IRQ(_x) (AR71XX_GPIO_IRQ_BASE + (_x))
++
++#define AR71XX_PCI_IRQ_DEV0 (AR71XX_PCI_IRQ_BASE + 0)
++#define AR71XX_PCI_IRQ_DEV1 (AR71XX_PCI_IRQ_BASE + 1)
++#define AR71XX_PCI_IRQ_DEV2 (AR71XX_PCI_IRQ_BASE + 2)
++#define AR71XX_PCI_IRQ_CORE (AR71XX_PCI_IRQ_BASE + 4)
++
++extern u32 ar71xx_ahb_freq;
++extern u32 ar71xx_cpu_freq;
++extern u32 ar71xx_ddr_freq;
++
++enum ar71xx_soc_type {
++ AR71XX_SOC_UNKNOWN,
++ AR71XX_SOC_AR7130,
++ AR71XX_SOC_AR7141,
++ AR71XX_SOC_AR7161,
++ AR71XX_SOC_AR7240,
++ AR71XX_SOC_AR7241,
++ AR71XX_SOC_AR7242,
++ AR71XX_SOC_AR9130,
++ AR71XX_SOC_AR9132
++};
++
++extern enum ar71xx_soc_type ar71xx_soc;
++
++/*
++ * PLL block
++ */
++#define AR71XX_PLL_REG_CPU_CONFIG 0x00
++#define AR71XX_PLL_REG_SEC_CONFIG 0x04
++#define AR71XX_PLL_REG_ETH0_INT_CLOCK 0x10
++#define AR71XX_PLL_REG_ETH1_INT_CLOCK 0x14
++
++#define AR71XX_PLL_DIV_SHIFT 3
++#define AR71XX_PLL_DIV_MASK 0x1f
++#define AR71XX_CPU_DIV_SHIFT 16
++#define AR71XX_CPU_DIV_MASK 0x3
++#define AR71XX_DDR_DIV_SHIFT 18
++#define AR71XX_DDR_DIV_MASK 0x3
++#define AR71XX_AHB_DIV_SHIFT 20
++#define AR71XX_AHB_DIV_MASK 0x7
++
++#define AR71XX_ETH0_PLL_SHIFT 17
++#define AR71XX_ETH1_PLL_SHIFT 19
++
++#define AR724X_PLL_REG_CPU_CONFIG 0x00
++#define AR724X_PLL_REG_PCIE_CONFIG 0x18
++
++#define AR724X_PLL_DIV_SHIFT 0
++#define AR724X_PLL_DIV_MASK 0x3ff
++#define AR724X_PLL_REF_DIV_SHIFT 10
++#define AR724X_PLL_REF_DIV_MASK 0xf
++#define AR724X_AHB_DIV_SHIFT 19
++#define AR724X_AHB_DIV_MASK 0x1
++#define AR724X_DDR_DIV_SHIFT 22
++#define AR724X_DDR_DIV_MASK 0x3
++
++#define AR91XX_PLL_REG_CPU_CONFIG 0x00
++#define AR91XX_PLL_REG_ETH_CONFIG 0x04
++#define AR91XX_PLL_REG_ETH0_INT_CLOCK 0x14
++#define AR91XX_PLL_REG_ETH1_INT_CLOCK 0x18
++
++#define AR91XX_PLL_DIV_SHIFT 0
++#define AR91XX_PLL_DIV_MASK 0x3ff
++#define AR91XX_DDR_DIV_SHIFT 22
++#define AR91XX_DDR_DIV_MASK 0x3
++#define AR91XX_AHB_DIV_SHIFT 19
++#define AR91XX_AHB_DIV_MASK 0x1
++
++#define AR91XX_ETH0_PLL_SHIFT 20
++#define AR91XX_ETH1_PLL_SHIFT 22
++
++extern void __iomem *ar71xx_pll_base;
++
++static inline void ar71xx_pll_wr(unsigned reg, u32 val)
++{
++ __raw_writel(val, ar71xx_pll_base + reg);
++}
++
++static inline u32 ar71xx_pll_rr(unsigned reg)
++{
++ return __raw_readl(ar71xx_pll_base + reg);
++}
++
++/*
++ * USB_CONFIG block
++ */
++#define USB_CTRL_REG_FLADJ 0x00
++#define USB_CTRL_REG_CONFIG 0x04
++
++extern void __iomem *ar71xx_usb_ctrl_base;
++
++static inline void ar71xx_usb_ctrl_wr(unsigned reg, u32 val)
++{
++ __raw_writel(val, ar71xx_usb_ctrl_base + reg);
++}
++
++static inline u32 ar71xx_usb_ctrl_rr(unsigned reg)
++{
++ return __raw_readl(ar71xx_usb_ctrl_base + reg);
++}
++
++/*
++ * GPIO block
++ */
++#define GPIO_REG_OE 0x00
++#define GPIO_REG_IN 0x04
++#define GPIO_REG_OUT 0x08
++#define GPIO_REG_SET 0x0c
++#define GPIO_REG_CLEAR 0x10
++#define GPIO_REG_INT_MODE 0x14
++#define GPIO_REG_INT_TYPE 0x18
++#define GPIO_REG_INT_POLARITY 0x1c
++#define GPIO_REG_INT_PENDING 0x20
++#define GPIO_REG_INT_ENABLE 0x24
++#define GPIO_REG_FUNC 0x28
++
++#define AR71XX_GPIO_FUNC_STEREO_EN BIT(17)
++#define AR71XX_GPIO_FUNC_SLIC_EN BIT(16)
++#define AR71XX_GPIO_FUNC_SPI_CS2_EN BIT(13)
++#define AR71XX_GPIO_FUNC_SPI_CS1_EN BIT(12)
++#define AR71XX_GPIO_FUNC_UART_EN BIT(8)
++#define AR71XX_GPIO_FUNC_USB_OC_EN BIT(4)
++#define AR71XX_GPIO_FUNC_USB_CLK_EN BIT(0)
++
++#define AR71XX_GPIO_COUNT 16
++
++#define AR724X_GPIO_FUNC_GE0_MII_CLK_EN BIT(19)
++#define AR724X_GPIO_FUNC_SPI_EN BIT(18)
++#define AR724X_GPIO_FUNC_SPI_CS_EN2 BIT(14)
++#define AR724X_GPIO_FUNC_SPI_CS_EN1 BIT(13)
++#define AR724X_GPIO_FUNC_CLK_OBS5_EN BIT(12)
++#define AR724X_GPIO_FUNC_CLK_OBS4_EN BIT(11)
++#define AR724X_GPIO_FUNC_CLK_OBS3_EN BIT(10)
++#define AR724X_GPIO_FUNC_CLK_OBS2_EN BIT(9)
++#define AR724X_GPIO_FUNC_CLK_OBS1_EN BIT(8)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN BIT(7)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN BIT(6)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN BIT(5)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN BIT(4)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN BIT(3)
++#define AR724X_GPIO_FUNC_UART_RTS_CTS_EN BIT(2)
++#define AR724X_GPIO_FUNC_UART_EN BIT(1)
++#define AR724X_GPIO_FUNC_JTAG_DISABLE BIT(0)
++
++#define AR724X_GPIO_COUNT 18
++
++#define AR91XX_GPIO_FUNC_WMAC_LED_EN BIT(22)
++#define AR91XX_GPIO_FUNC_EXP_PORT_CS_EN BIT(21)
++#define AR91XX_GPIO_FUNC_I2S_REFCLKEN BIT(20)
++#define AR91XX_GPIO_FUNC_I2S_MCKEN BIT(19)
++#define AR91XX_GPIO_FUNC_I2S1_EN BIT(18)
++#define AR91XX_GPIO_FUNC_I2S0_EN BIT(17)
++#define AR91XX_GPIO_FUNC_SLIC_EN BIT(16)
++#define AR91XX_GPIO_FUNC_UART_RTSCTS_EN BIT(9)
++#define AR91XX_GPIO_FUNC_UART_EN BIT(8)
++#define AR91XX_GPIO_FUNC_USB_CLK_EN BIT(4)
++
++#define AR91XX_GPIO_COUNT 22
++
++extern void __iomem *ar71xx_gpio_base;
++
++static inline void ar71xx_gpio_wr(unsigned reg, u32 value)
++{
++ __raw_writel(value, ar71xx_gpio_base + reg);
++}
++
++static inline u32 ar71xx_gpio_rr(unsigned reg)
++{
++ return __raw_readl(ar71xx_gpio_base + reg);
++}
++
++void ar71xx_gpio_init(void) __init;
++void ar71xx_gpio_function_enable(u32 mask);
++void ar71xx_gpio_function_disable(u32 mask);
++void ar71xx_gpio_function_setup(u32 set, u32 clear);
++
++/*
++ * DDR_CTRL block
++ */
++#define AR71XX_DDR_REG_PCI_WIN0 0x7c
++#define AR71XX_DDR_REG_PCI_WIN1 0x80
++#define AR71XX_DDR_REG_PCI_WIN2 0x84
++#define AR71XX_DDR_REG_PCI_WIN3 0x88
++#define AR71XX_DDR_REG_PCI_WIN4 0x8c
++#define AR71XX_DDR_REG_PCI_WIN5 0x90
++#define AR71XX_DDR_REG_PCI_WIN6 0x94
++#define AR71XX_DDR_REG_PCI_WIN7 0x98
++#define AR71XX_DDR_REG_FLUSH_GE0 0x9c
++#define AR71XX_DDR_REG_FLUSH_GE1 0xa0
++#define AR71XX_DDR_REG_FLUSH_USB 0xa4
++#define AR71XX_DDR_REG_FLUSH_PCI 0xa8
++
++#define AR724X_DDR_REG_FLUSH_GE0 0x7c
++#define AR724X_DDR_REG_FLUSH_GE1 0x80
++#define AR724X_DDR_REG_FLUSH_USB 0x84
++#define AR724X_DDR_REG_FLUSH_PCIE 0x88
++
++#define AR91XX_DDR_REG_FLUSH_GE0 0x7c
++#define AR91XX_DDR_REG_FLUSH_GE1 0x80
++#define AR91XX_DDR_REG_FLUSH_USB 0x84
++#define AR91XX_DDR_REG_FLUSH_WMAC 0x88
++
++#define PCI_WIN0_OFFS 0x10000000
++#define PCI_WIN1_OFFS 0x11000000
++#define PCI_WIN2_OFFS 0x12000000
++#define PCI_WIN3_OFFS 0x13000000
++#define PCI_WIN4_OFFS 0x14000000
++#define PCI_WIN5_OFFS 0x15000000
++#define PCI_WIN6_OFFS 0x16000000
++#define PCI_WIN7_OFFS 0x07000000
++
++extern void __iomem *ar71xx_ddr_base;
++
++static inline void ar71xx_ddr_wr(unsigned reg, u32 val)
++{
++ __raw_writel(val, ar71xx_ddr_base + reg);
++}
++
++static inline u32 ar71xx_ddr_rr(unsigned reg)
++{
++ return __raw_readl(ar71xx_ddr_base + reg);
++}
++
++void ar71xx_ddr_flush(u32 reg);
++
++/*
++ * PCI block
++ */
++#define AR71XX_PCI_CFG_BASE (AR71XX_PCI_MEM_BASE + PCI_WIN7_OFFS + 0x10000)
++#define AR71XX_PCI_CFG_SIZE 0x100
++
++#define PCI_REG_CRP_AD_CBE 0x00
++#define PCI_REG_CRP_WRDATA 0x04
++#define PCI_REG_CRP_RDDATA 0x08
++#define PCI_REG_CFG_AD 0x0c
++#define PCI_REG_CFG_CBE 0x10
++#define PCI_REG_CFG_WRDATA 0x14
++#define PCI_REG_CFG_RDDATA 0x18
++#define PCI_REG_PCI_ERR 0x1c
++#define PCI_REG_PCI_ERR_ADDR 0x20
++#define PCI_REG_AHB_ERR 0x24
++#define PCI_REG_AHB_ERR_ADDR 0x28
++
++#define PCI_CRP_CMD_WRITE 0x00010000
++#define PCI_CRP_CMD_READ 0x00000000
++#define PCI_CFG_CMD_READ 0x0000000a
++#define PCI_CFG_CMD_WRITE 0x0000000b
++
++#define PCI_IDSEL_ADL_START 17
++
++#define AR724X_PCI_CFG_BASE (AR71XX_PCI_MEM_BASE + 0x4000000)
++#define AR724X_PCI_CFG_SIZE 0x1000
++
++#define AR724X_PCI_REG_APP 0x00
++#define AR724X_PCI_REG_RESET 0x18
++#define AR724X_PCI_REG_INT_STATUS 0x4c
++#define AR724X_PCI_REG_INT_MASK 0x50
++
++#define AR724X_PCI_APP_LTSSM_ENABLE BIT(0)
++#define AR724X_PCI_RESET_LINK_UP BIT(0)
++
++#define AR724X_PCI_INT_DEV0 BIT(14)
++
++/*
++ * RESET block
++ */
++#define AR71XX_RESET_REG_TIMER 0x00
++#define AR71XX_RESET_REG_TIMER_RELOAD 0x04
++#define AR71XX_RESET_REG_WDOG_CTRL 0x08
++#define AR71XX_RESET_REG_WDOG 0x0c
++#define AR71XX_RESET_REG_MISC_INT_STATUS 0x10
++#define AR71XX_RESET_REG_MISC_INT_ENABLE 0x14
++#define AR71XX_RESET_REG_PCI_INT_STATUS 0x18
++#define AR71XX_RESET_REG_PCI_INT_ENABLE 0x1c
++#define AR71XX_RESET_REG_GLOBAL_INT_STATUS 0x20
++#define AR71XX_RESET_REG_RESET_MODULE 0x24
++#define AR71XX_RESET_REG_PERFC_CTRL 0x2c
++#define AR71XX_RESET_REG_PERFC0 0x30
++#define AR71XX_RESET_REG_PERFC1 0x34
++#define AR71XX_RESET_REG_REV_ID 0x90
++
++#define AR91XX_RESET_REG_GLOBAL_INT_STATUS 0x18
++#define AR91XX_RESET_REG_RESET_MODULE 0x1c
++#define AR91XX_RESET_REG_PERF_CTRL 0x20
++#define AR91XX_RESET_REG_PERFC0 0x24
++#define AR91XX_RESET_REG_PERFC1 0x28
++
++#define AR724X_RESET_REG_RESET_MODULE 0x1c
++
++#define WDOG_CTRL_LAST_RESET BIT(31)
++#define WDOG_CTRL_ACTION_MASK 3
++#define WDOG_CTRL_ACTION_NONE 0 /* no action */
++#define WDOG_CTRL_ACTION_GPI 1 /* general purpose interrupt */
++#define WDOG_CTRL_ACTION_NMI 2 /* NMI */
++#define WDOG_CTRL_ACTION_FCR 3 /* full chip reset */
++
++#define MISC_INT_DMA BIT(7)
++#define MISC_INT_OHCI BIT(6)
++#define MISC_INT_PERFC BIT(5)
++#define MISC_INT_WDOG BIT(4)
++#define MISC_INT_UART BIT(3)
++#define MISC_INT_GPIO BIT(2)
++#define MISC_INT_ERROR BIT(1)
++#define MISC_INT_TIMER BIT(0)
++
++#define PCI_INT_CORE BIT(4)
++#define PCI_INT_DEV2 BIT(2)
++#define PCI_INT_DEV1 BIT(1)
++#define PCI_INT_DEV0 BIT(0)
++
++#define RESET_MODULE_EXTERNAL BIT(28)
++#define RESET_MODULE_FULL_CHIP BIT(24)
++#define RESET_MODULE_AMBA2WMAC BIT(22)
++#define RESET_MODULE_CPU_NMI BIT(21)
++#define RESET_MODULE_CPU_COLD BIT(20)
++#define RESET_MODULE_DMA BIT(19)
++#define RESET_MODULE_SLIC BIT(18)
++#define RESET_MODULE_STEREO BIT(17)
++#define RESET_MODULE_DDR BIT(16)
++#define RESET_MODULE_GE1_MAC BIT(13)
++#define RESET_MODULE_GE1_PHY BIT(12)
++#define RESET_MODULE_USBSUS_OVERRIDE BIT(10)
++#define RESET_MODULE_GE0_MAC BIT(9)
++#define RESET_MODULE_GE0_PHY BIT(8)
++#define RESET_MODULE_USB_OHCI_DLL BIT(6)
++#define RESET_MODULE_USB_HOST BIT(5)
++#define RESET_MODULE_USB_PHY BIT(4)
++#define RESET_MODULE_USB_OHCI_DLL_7240 BIT(3)
++#define RESET_MODULE_PCI_BUS BIT(1)
++#define RESET_MODULE_PCI_CORE BIT(0)
++
++#define AR724X_RESET_GE1_MDIO BIT(23)
++#define AR724X_RESET_GE0_MDIO BIT(22)
++#define AR724X_RESET_PCIE_PHY_SERIAL BIT(10)
++#define AR724X_RESET_PCIE_PHY BIT(7)
++#define AR724X_RESET_PCIE BIT(6)
++
++#define REV_ID_MAJOR_MASK 0xfff0
++#define REV_ID_MAJOR_AR71XX 0x00a0
++#define REV_ID_MAJOR_AR913X 0x00b0
++#define REV_ID_MAJOR_AR7240 0x00c0
++#define REV_ID_MAJOR_AR7241 0x0100
++#define REV_ID_MAJOR_AR7242 0x1100
++
++#define AR71XX_REV_ID_MINOR_MASK 0x3
++#define AR71XX_REV_ID_MINOR_AR7130 0x0
++#define AR71XX_REV_ID_MINOR_AR7141 0x1
++#define AR71XX_REV_ID_MINOR_AR7161 0x2
++#define AR71XX_REV_ID_REVISION_MASK 0x3
++#define AR71XX_REV_ID_REVISION_SHIFT 2
++
++#define AR91XX_REV_ID_MINOR_MASK 0x3
++#define AR91XX_REV_ID_MINOR_AR9130 0x0
++#define AR91XX_REV_ID_MINOR_AR9132 0x1
++#define AR91XX_REV_ID_REVISION_MASK 0x3
++#define AR91XX_REV_ID_REVISION_SHIFT 2
++
++#define AR724X_REV_ID_REVISION_MASK 0x3
++
++extern void __iomem *ar71xx_reset_base;
++
++static inline void ar71xx_reset_wr(unsigned reg, u32 val)
++{
++ __raw_writel(val, ar71xx_reset_base + reg);
++}
++
++static inline u32 ar71xx_reset_rr(unsigned reg)
++{
++ return __raw_readl(ar71xx_reset_base + reg);
++}
++
++void ar71xx_device_stop(u32 mask);
++void ar71xx_device_start(u32 mask);
++int ar71xx_device_stopped(u32 mask);
++
++/*
++ * SPI block
++ */
++#define SPI_REG_FS 0x00 /* Function Select */
++#define SPI_REG_CTRL 0x04 /* SPI Control */
++#define SPI_REG_IOC 0x08 /* SPI I/O Control */
++#define SPI_REG_RDS 0x0c /* Read Data Shift */
++
++#define SPI_FS_GPIO BIT(0) /* Enable GPIO mode */
++
++#define SPI_CTRL_RD BIT(6) /* Remap Disable */
++#define SPI_CTRL_DIV_MASK 0x3f
++
++#define SPI_IOC_DO BIT(0) /* Data Out pin */
++#define SPI_IOC_CLK BIT(8) /* CLK pin */
++#define SPI_IOC_CS(n) BIT(16 + (n))
++#define SPI_IOC_CS0 SPI_IOC_CS(0)
++#define SPI_IOC_CS1 SPI_IOC_CS(1)
++#define SPI_IOC_CS2 SPI_IOC_CS(2)
++#define SPI_IOC_CS_ALL (SPI_IOC_CS0 | SPI_IOC_CS1 | SPI_IOC_CS2)
++
++void ar71xx_flash_acquire(void);
++void ar71xx_flash_release(void);
++
++/*
++ * MII_CTRL block
++ */
++#define MII_REG_MII0_CTRL 0x00
++#define MII_REG_MII1_CTRL 0x04
++
++#define MII0_CTRL_IF_GMII 0
++#define MII0_CTRL_IF_MII 1
++#define MII0_CTRL_IF_RGMII 2
++#define MII0_CTRL_IF_RMII 3
++
++#define MII1_CTRL_IF_RGMII 0
++#define MII1_CTRL_IF_RMII 1
++
++#endif /* __ASSEMBLER__ */
++
++#endif /* __ASM_MACH_AR71XX_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h linux-2.6.37/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-ar71xx/ar91xx_flash.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,26 @@
++/*
++ * AR91xx parallel flash driver platform data definitions
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __AR91XX_FLASH_H
++#define __AR91XX_FLASH_H
++
++struct mtd_partition;
++
++struct ar91xx_flash_platform_data {
++ unsigned int width;
++ u8 is_shared:1;
++#ifdef CONFIG_MTD_PARTITIONS
++ unsigned int nr_parts;
++ struct mtd_partition *parts;
++#endif
++};
++
++#endif /* __AR91XX_FLASH_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h linux-2.6.37/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-ar71xx/cpu-feature-overrides.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,56 @@
++/*
++ * Atheros AR71xx specific CPU feature overrides
++ *
++ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This file was derived from: include/asm-mips/cpu-features.h
++ * Copyright (C) 2003, 2004 Ralf Baechle
++ * Copyright (C) 2004 Maciej W. Rozycki
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ */
++#ifndef __ASM_MACH_AR71XX_CPU_FEATURE_OVERRIDES_H
++#define __ASM_MACH_AR71XX_CPU_FEATURE_OVERRIDES_H
++
++#define cpu_has_tlb 1
++#define cpu_has_4kex 1
++#define cpu_has_3k_cache 0
++#define cpu_has_4k_cache 1
++#define cpu_has_tx39_cache 0
++#define cpu_has_sb1_cache 0
++#define cpu_has_fpu 0
++#define cpu_has_32fpr 0
++#define cpu_has_counter 1
++#define cpu_has_watch 1
++#define cpu_has_divec 1
++
++#define cpu_has_prefetch 1
++#define cpu_has_ejtag 1
++#define cpu_has_llsc 1
++
++#define cpu_has_mips16 1
++#define cpu_has_mdmx 0
++#define cpu_has_mips3d 0
++#define cpu_has_smartmips 0
++
++#define cpu_has_mips32r1 1
++#define cpu_has_mips32r2 1
++#define cpu_has_mips64r1 0
++#define cpu_has_mips64r2 0
++
++#define cpu_has_dsp 0
++#define cpu_has_mipsmt 0
++
++#define cpu_has_64bits 0
++#define cpu_has_64bit_zero_reg 0
++#define cpu_has_64bit_gp_regs 0
++#define cpu_has_64bit_addresses 0
++
++#define cpu_dcache_line_size() 32
++#define cpu_icache_line_size() 32
++
++#endif /* __ASM_MACH_AR71XX_CPU_FEATURE_OVERRIDES_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/gpio.h linux-2.6.37/arch/mips/include/asm/mach-ar71xx/gpio.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/gpio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-ar71xx/gpio.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,53 @@
++/*
++ * Atheros AR71xx GPIO API definitions
++ *
++ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ */
++
++#ifndef __ASM_MACH_AR71XX_GPIO_H
++#define __ASM_MACH_AR71XX_GPIO_H
++
++#define ARCH_NR_GPIOS 64
++#include <asm-generic/gpio.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++extern unsigned long ar71xx_gpio_count;
++extern void __ar71xx_gpio_set_value(unsigned gpio, int value);
++extern int __ar71xx_gpio_get_value(unsigned gpio);
++
++static inline int gpio_to_irq(unsigned gpio)
++{
++ return AR71XX_GPIO_IRQ(gpio);
++}
++
++static inline int irq_to_gpio(unsigned irq)
++{
++ return irq - AR71XX_GPIO_IRQ_BASE;
++}
++
++static inline int gpio_get_value(unsigned gpio)
++{
++ if (gpio < ar71xx_gpio_count)
++ return __ar71xx_gpio_get_value(gpio);
++
++ return __gpio_get_value(gpio);
++}
++
++static inline void gpio_set_value(unsigned gpio, int value)
++{
++ if (gpio < ar71xx_gpio_count)
++ __ar71xx_gpio_set_value(gpio, value);
++ else
++ __gpio_set_value(gpio, value);
++}
++
++#define gpio_cansleep __gpio_cansleep
++
++#endif /* __ASM_MACH_AR71XX_GPIO_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/irq.h linux-2.6.37/arch/mips/include/asm/mach-ar71xx/irq.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/irq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-ar71xx/irq.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,17 @@
++/*
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++#ifndef __ASM_MACH_AR71XX_IRQ_H
++#define __ASM_MACH_AR71XX_IRQ_H
++
++#define MIPS_CPU_IRQ_BASE 0
++#define NR_IRQS 56
++
++#include_next <irq.h>
++
++#endif /* __ASM_MACH_AR71XX_IRQ_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h linux-2.6.37/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-ar71xx/kernel-entry-init.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,32 @@
++/*
++ * Atheros AR71xx specific kernel entry setup
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ */
++#ifndef __ASM_MACH_AR71XX_KERNEL_ENTRY_H
++#define __ASM_MACH_AR71XX_KERNEL_ENTRY_H
++
++ /*
++ * Some bootloaders set the 'Kseg0 coherency algorithm' to
++ * 'Cacheable, noncoherent, write-through, no write allocate'
++ * and this cause performance issues. Let's go and change it to
++ * 'Cacheable, noncoherent, write-back, write allocate'
++ */
++ .macro kernel_entry_setup
++ mfc0 t0, CP0_CONFIG
++ li t1, ~CONF_CM_CMASK
++ and t0, t1
++ ori t0, CONF_CM_CACHABLE_NONCOHERENT
++ mtc0 t0, CP0_CONFIG
++ nop
++ .endm
++
++ .macro smp_slave_setup
++ .endm
++
++#endif /* __ASM_MACH_AR71XX_KERNEL_ENTRY_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/mach-rb750.h linux-2.6.37/arch/mips/include/asm/mach-ar71xx/mach-rb750.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/mach-rb750.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-ar71xx/mach-rb750.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,66 @@
++/*
++ * MikroTik RouterBOARD 750 definitions
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++#ifndef _MACH_RB750_H
++#define _MACH_RB750_H
++
++#include <linux/bitops.h>
++
++#define RB750_GPIO_LVC573_LE 0 /* Latch enable on LVC573 */
++#define RB750_GPIO_NAND_IO0 1 /* NAND I/O 0 */
++#define RB750_GPIO_NAND_IO1 2 /* NAND I/O 1 */
++#define RB750_GPIO_NAND_IO2 3 /* NAND I/O 2 */
++#define RB750_GPIO_NAND_IO3 4 /* NAND I/O 3 */
++#define RB750_GPIO_NAND_IO4 5 /* NAND I/O 4 */
++#define RB750_GPIO_NAND_IO5 6 /* NAND I/O 5 */
++#define RB750_GPIO_NAND_IO6 7 /* NAND I/O 6 */
++#define RB750_GPIO_NAND_IO7 8 /* NAND I/O 7 */
++#define RB750_GPIO_NAND_NCE 11 /* NAND Chip Enable (active low) */
++#define RB750_GPIO_NAND_RDY 12 /* NAND Ready */
++#define RB750_GPIO_NAND_CLE 14 /* NAND Command Latch Enable */
++#define RB750_GPIO_NAND_ALE 15 /* NAND Address Latch Enable */
++#define RB750_GPIO_NAND_NRE 16 /* NAND Read Enable (active low) */
++#define RB750_GPIO_NAND_NWE 17 /* NAND Write Enable (active low) */
++
++#define RB750_GPIO_BTN_RESET 1
++#define RB750_GPIO_SPI_CS0 2
++#define RB750_GPIO_LED_ACT 12
++#define RB750_GPIO_LED_PORT1 13
++#define RB750_GPIO_LED_PORT2 14
++#define RB750_GPIO_LED_PORT3 15
++#define RB750_GPIO_LED_PORT4 16
++#define RB750_GPIO_LED_PORT5 17
++
++#define RB750_LED_ACT BIT(RB750_GPIO_LED_ACT)
++#define RB750_LED_PORT1 BIT(RB750_GPIO_LED_PORT1)
++#define RB750_LED_PORT2 BIT(RB750_GPIO_LED_PORT2)
++#define RB750_LED_PORT3 BIT(RB750_GPIO_LED_PORT3)
++#define RB750_LED_PORT4 BIT(RB750_GPIO_LED_PORT4)
++#define RB750_LED_PORT5 BIT(RB750_GPIO_LED_PORT5)
++
++#define RB750_LVC573_LE BIT(RB750_GPIO_LVC573_LE)
++
++#define RB750_LED_BITS (RB750_LED_PORT1 | RB750_LED_PORT2 | RB750_LED_PORT3 | \
++ RB750_LED_PORT4 | RB750_LED_PORT5 | RB750_LED_ACT)
++
++struct rb750_led_data {
++ char *name;
++ char *default_trigger;
++ u32 mask;
++ int active_low;
++};
++
++struct rb750_led_platform_data {
++ int num_leds;
++ struct rb750_led_data *leds;
++};
++
++int rb750_latch_change(u32 mask_clr, u32 mask_set);
++
++#endif /* _MACH_RB750_H */
+\ No newline at end of file
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/mangle-port.h linux-2.6.37/arch/mips/include/asm/mach-ar71xx/mangle-port.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/mangle-port.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-ar71xx/mangle-port.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This file was derived from: inlude/asm-mips/mach-generic/mangle-port.h
++ * Copyright (C) 2003, 2004 Ralf Baechle
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __ASM_MACH_AR71XX_MANGLE_PORT_H
++#define __ASM_MACH_AR71XX_MANGLE_PORT_H
++
++#define __swizzle_addr_b(port) ((port) ^ 3)
++#define __swizzle_addr_w(port) ((port) ^ 2)
++#define __swizzle_addr_l(port) (port)
++#define __swizzle_addr_q(port) (port)
++
++#if defined(CONFIG_SWAP_IO_SPACE)
++
++# define ioswabb(a, x) (x)
++# define __mem_ioswabb(a, x) (x)
++# define ioswabw(a, x) le16_to_cpu(x)
++# define __mem_ioswabw(a, x) (x)
++# define ioswabl(a, x) le32_to_cpu(x)
++# define __mem_ioswabl(a, x) (x)
++# define ioswabq(a, x) le64_to_cpu(x)
++# define __mem_ioswabq(a, x) (x)
++
++#else
++
++# define ioswabb(a, x) (x)
++# define __mem_ioswabb(a, x) (x)
++# define ioswabw(a, x) (x)
++# define __mem_ioswabw(a, x) cpu_to_le16(x)
++# define ioswabl(a, x) (x)
++# define __mem_ioswabl(a, x) cpu_to_le32(x)
++# define ioswabq(a, x) (x)
++# define __mem_ioswabq(a, x) cpu_to_le64(x)
++
++#endif
++
++#endif /* __ASM_MACH_AR71XX_MANGLE_PORT_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/pci.h linux-2.6.37/arch/mips/include/asm/mach-ar71xx/pci.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-ar71xx/pci.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,39 @@
++/*
++ * Atheros AR71xx SoC specific PCI definitions
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __ASM_MACH_AR71XX_PCI_H
++#define __ASM_MACH_AR71XX_PCI_H
++
++struct pci_dev;
++
++struct ar71xx_pci_irq {
++ int irq;
++ u8 slot;
++ u8 pin;
++};
++
++extern int (*ar71xx_pci_plat_dev_init)(struct pci_dev *dev);
++extern unsigned ar71xx_pci_nr_irqs __initdata;
++extern struct ar71xx_pci_irq *ar71xx_pci_irq_map __initdata;
++
++int ar71xx_pcibios_map_irq(const struct pci_dev *dev,
++ uint8_t slot, uint8_t pin) __init;
++int ar71xx_pcibios_init(void) __init;
++
++int ar71xx_pci_be_handler(int is_fixup);
++
++int ar724x_pcibios_map_irq(const struct pci_dev *dev,
++ uint8_t slot, uint8_t pin) __init;
++int ar724x_pcibios_init(void) __init;
++
++int ar71xx_pci_init(unsigned nr_irqs, struct ar71xx_pci_irq *map) __init;
++
++#endif /* __ASM_MACH_AR71XX_PCI_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/platform.h linux-2.6.37/arch/mips/include/asm/mach-ar71xx/platform.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/platform.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-ar71xx/platform.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,61 @@
++/*
++ * Atheros AR71xx SoC specific platform data definitions
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __ASM_MACH_AR71XX_PLATFORM_H
++#define __ASM_MACH_AR71XX_PLATFORM_H
++
++#include <linux/if_ether.h>
++#include <linux/skbuff.h>
++#include <linux/phy.h>
++#include <linux/spi/spi.h>
++
++struct ag71xx_platform_data {
++ phy_interface_t phy_if_mode;
++ u32 phy_mask;
++ int speed;
++ int duplex;
++ u32 reset_bit;
++ u32 mii_if;
++ u8 mac_addr[ETH_ALEN];
++ struct device *mii_bus_dev;
++
++ u8 has_gbit:1;
++ u8 is_ar91xx:1;
++ u8 is_ar724x:1;
++ u8 has_ar8216:1;
++
++ void (* ddr_flush)(void);
++ void (* set_pll)(int speed);
++
++ u32 fifo_cfg1;
++ u32 fifo_cfg2;
++ u32 fifo_cfg3;
++};
++
++struct ag71xx_mdio_platform_data {
++ u32 phy_mask;
++ int is_ar7240;
++};
++
++struct ar71xx_ehci_platform_data {
++ u8 is_ar91xx;
++};
++
++struct ar71xx_spi_platform_data {
++ unsigned bus_num;
++ unsigned num_chipselect;
++ u32 (*get_ioc_base)(u8 chip_select, int cs_high, int is_on);
++};
++
++#define AR71XX_SPI_CS_INACTIVE 0
++#define AR71XX_SPI_CS_ACTIVE 1
++
++#endif /* __ASM_MACH_AR71XX_PLATFORM_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/war.h linux-2.6.37/arch/mips/include/asm/mach-ar71xx/war.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-ar71xx/war.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-ar71xx/war.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,25 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
++ */
++#ifndef __ASM_MACH_AR71XX_WAR_H
++#define __ASM_MACH_AR71XX_WAR_H
++
++#define R4600_V1_INDEX_ICACHEOP_WAR 0
++#define R4600_V1_HIT_CACHEOP_WAR 0
++#define R4600_V2_HIT_CACHEOP_WAR 0
++#define R5432_CP0_INTERRUPT_WAR 0
++#define BCM1250_M3_WAR 0
++#define SIBYTE_1956_WAR 0
++#define MIPS4K_ICACHE_REFILL_WAR 0
++#define MIPS_CACHE_SYNC_WAR 0
++#define TX49XX_ICACHE_INDEX_INV_WAR 0
++#define RM9000_CDEX_SMP_WAR 0
++#define ICACHE_REFILLS_WORKAROUND_WAR 0
++#define R10000_LLSC_WAR 0
++#define MIPS34K_MISSED_ITLB_WAR 0
++
++#endif /* __ASM_MACH_AR71XX_WAR_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mips_machine.h linux-2.6.37/arch/mips/include/asm/mips_machine.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mips_machine.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mips_machine.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,54 @@
++/*
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ */
++
++#ifndef __ASM_MIPS_MACHINE_H
++#define __ASM_MIPS_MACHINE_H
++
++#include <linux/init.h>
++#include <linux/list.h>
++
++#include <asm/bootinfo.h>
++
++struct mips_machine {
++ unsigned long mach_type;
++ char *mach_id;
++ char *mach_name;
++ void (*mach_setup)(void);
++ struct list_head list;
++};
++
++void mips_machine_register(struct mips_machine *) __init;
++void mips_machine_setup(void) __init;
++int mips_machtype_setup(char *id) __init;
++void mips_machine_set_name(char *name) __init;
++
++extern char *mips_machine_name;
++
++#define MIPS_MACHINE(_type, _id, _name, _setup) \
++static const char machine_name_##_type[] __initconst \
++ __aligned(1) = _name; \
++static const char machine_id_##_type[] __initconst \
++ __aligned(1) = _id; \
++static struct mips_machine machine_##_type __initdata = \
++{ \
++ .mach_type = _type, \
++ .mach_id = (char *) machine_id_##_type, \
++ .mach_name = (char *) machine_name_##_type, \
++ .mach_setup = _setup, \
++}; \
++ \
++static int __init register_machine_##_type(void) \
++{ \
++ mips_machine_register(&machine_##_type); \
++ return 0; \
++} \
++ \
++pure_initcall(register_machine_##_type)
++
++#endif /* __ASM_MIPS_MACHINE_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/time.h linux-2.6.37/arch/mips/include/asm/time.h
+--- linux-2.6.37.orig/arch/mips/include/asm/time.h 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/time.h 2011-01-11 20:25:48.000000000 +0100
+@@ -52,6 +52,7 @@
+ */
+ #ifdef CONFIG_CEVT_R4K_LIB
+ extern unsigned int __weak get_c0_compare_int(void);
++extern unsigned int __weak get_c0_compare_irq(void);
+ extern int r4k_clockevent_init(void);
+ #endif
+
+diff -Nur linux-2.6.37.orig/arch/mips/kernel/Makefile linux-2.6.37/arch/mips/kernel/Makefile
+--- linux-2.6.37.orig/arch/mips/kernel/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/kernel/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -94,6 +94,7 @@
+
+ obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
++obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o
+ obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o
+
+ obj-$(CONFIG_OF) += prom.o
+diff -Nur linux-2.6.37.orig/arch/mips/kernel/mips_machine.c linux-2.6.37/arch/mips/kernel/mips_machine.c
+--- linux-2.6.37.orig/arch/mips/kernel/mips_machine.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/kernel/mips_machine.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,121 @@
++/*
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ */
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++
++#include <asm/mips_machine.h>
++
++static struct list_head mips_machines __initdata =
++ LIST_HEAD_INIT(mips_machines);
++static char *mips_machid __initdata;
++
++char *mips_machine_name = "Unknown";
++
++static struct mips_machine * __init mips_machine_find(unsigned long machtype)
++{
++ struct list_head *this;
++
++ list_for_each(this, &mips_machines) {
++ struct mips_machine *mach;
++
++ mach = list_entry(this, struct mips_machine, list);
++ if (mach->mach_type == machtype)
++ return mach;
++ }
++
++ return NULL;
++}
++
++void __init mips_machine_register(struct mips_machine *mach)
++{
++ list_add_tail(&mach->list, &mips_machines);
++}
++
++void __init mips_machine_set_name(char *name)
++{
++ unsigned int len;
++ char *p;
++
++ if (name == NULL)
++ return;
++
++ len = strlen(name);
++ p = kmalloc(len + 1, GFP_KERNEL);
++ if (p) {
++ strncpy(p, name, len);
++ p[len] = '\0';
++ mips_machine_name = p;
++ } else {
++ printk(KERN_WARNING "MIPS: no memory for machine_name\n");
++ }
++}
++
++void __init mips_machine_setup(void)
++{
++ struct mips_machine *mach;
++
++ mach = mips_machine_find(mips_machtype);
++ if (!mach) {
++ printk(KERN_WARNING "MIPS: no machine registered for "
++ "machtype %lu\n", mips_machtype);
++ return;
++ }
++
++ mips_machine_set_name(mach->mach_name);
++ printk(KERN_NOTICE "MIPS: machine is %s\n", mips_machine_name);
++
++ if (mach->mach_setup)
++ mach->mach_setup();
++}
++
++int __init mips_machtype_setup(char *id)
++{
++ if (mips_machid == NULL)
++ mips_machid = id;
++
++ return 1;
++}
++
++__setup("machtype=", mips_machtype_setup);
++
++static int __init mips_machtype_init(void)
++{
++ struct list_head *this;
++ struct mips_machine *mach;
++
++ if (mips_machid == NULL)
++ return 0;
++
++ list_for_each(this, &mips_machines) {
++ mach = list_entry(this, struct mips_machine, list);
++ if (mach->mach_id == NULL)
++ continue;
++
++ if (strcmp(mach->mach_id, mips_machid) == 0) {
++ mips_machtype = mach->mach_type;
++ return 0;
++ }
++ }
++
++ printk(KERN_WARNING
++ "MIPS: no machine found for id: '%s', registered machines:\n",
++ mips_machid);
++ printk(KERN_WARNING "%32s %s\n", "id", "name");
++
++ list_for_each(this, &mips_machines) {
++ mach = list_entry(this, struct mips_machine, list);
++ printk(KERN_WARNING "%32s %s\n",
++ mach->mach_id ? mach->mach_id : "", mach->mach_name);
++ }
++
++ return 0;
++}
++
++core_initcall(mips_machtype_init);
+diff -Nur linux-2.6.37.orig/arch/mips/kernel/proc.c linux-2.6.37/arch/mips/kernel/proc.c
+--- linux-2.6.37.orig/arch/mips/kernel/proc.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/kernel/proc.c 2011-01-11 20:25:48.000000000 +0100
+@@ -12,6 +12,7 @@
+ #include <asm/cpu-features.h>
+ #include <asm/mipsregs.h>
+ #include <asm/processor.h>
++#include <asm/mips_machine.h>
+
+ unsigned int vced_count, vcei_count;
+
+@@ -31,8 +32,12 @@
+ /*
+ * For the first processor also print the system type
+ */
+- if (n == 0)
++ if (n == 0) {
+ seq_printf(m, "system type\t\t: %s\n", get_system_type());
++#ifdef CONFIG_MIPS_MACHINE
++ seq_printf(m, "machine\t\t\t: %s\n", mips_machine_name);
++#endif
++ }
+
+ seq_printf(m, "processor\t\t: %ld\n", n);
+ sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n",
+diff -Nur linux-2.6.37.orig/arch/mips/kernel/traps.c linux-2.6.37/arch/mips/kernel/traps.c
+--- linux-2.6.37.orig/arch/mips/kernel/traps.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/kernel/traps.c 2011-01-11 20:26:51.000000000 +0100
+@@ -46,6 +46,7 @@
+ #include <asm/ptrace.h>
+ #include <asm/sections.h>
+ #include <asm/system.h>
++#include <asm/time.h>
+ #include <asm/tlbdebug.h>
+ #include <asm/traps.h>
+ #include <asm/uaccess.h>
+@@ -1578,6 +1579,8 @@
+ if (cpu_has_mips_r2) {
+ cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP;
+ cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7;
++ if (get_c0_compare_irq)
++ cp0_compare_irq = get_c0_compare_irq();
+ cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7;
+ if (cp0_perfcount_irq == cp0_compare_irq)
+ cp0_perfcount_irq = -1;
+diff -Nur linux-2.6.37.orig/arch/mips/pci/Makefile linux-2.6.37/arch/mips/pci/Makefile
+--- linux-2.6.37.orig/arch/mips/pci/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/pci/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -18,6 +18,7 @@
+ obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o
+ obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \
+ ops-bcm63xx.o
++obj-$(CONFIG_ATHEROS_AR71XX) += pci-ar71xx.o pci-ar724x.o
+
+ #
+ # These are still pretty much in the old state, watch, go blind.
+diff -Nur linux-2.6.37.orig/arch/mips/pci/pci-ar71xx.c linux-2.6.37/arch/mips/pci/pci-ar71xx.c
+--- linux-2.6.37.orig/arch/mips/pci/pci-ar71xx.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/pci/pci-ar71xx.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,409 @@
++/*
++ * Atheros AR71xx PCI host controller driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/resource.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/pci.h>
++#include <linux/pci_regs.h>
++#include <linux/interrupt.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#undef DEBUG
++#ifdef DEBUG
++#define DBG(fmt, args...) printk(KERN_DEBUG fmt, ## args)
++#else
++#define DBG(fmt, args...)
++#endif
++
++#define AR71XX_PCI_DELAY 100 /* msecs */
++
++#if 0
++#define PCI_IDSEL_BASE PCI_IDSEL_ADL_START
++#else
++#define PCI_IDSEL_BASE 0
++#endif
++
++static void __iomem *ar71xx_pcicfg_base;
++static DEFINE_SPINLOCK(ar71xx_pci_lock);
++static int ar71xx_pci_fixup_enable;
++
++static inline void ar71xx_pci_delay(void)
++{
++ mdelay(AR71XX_PCI_DELAY);
++}
++
++/* Byte lane enable bits */
++static u8 ble_table[4][4] = {
++ {0x0, 0xf, 0xf, 0xf},
++ {0xe, 0xd, 0xb, 0x7},
++ {0xc, 0xf, 0x3, 0xf},
++ {0xf, 0xf, 0xf, 0xf},
++};
++
++static inline u32 ar71xx_pci_get_ble(int where, int size, int local)
++{
++ u32 t;
++
++ t = ble_table[size & 3][where & 3];
++ BUG_ON(t == 0xf);
++ t <<= (local) ? 20 : 4;
++ return t;
++}
++
++static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn,
++ int where)
++{
++ u32 ret;
++
++ if (!bus->number) {
++ /* type 0 */
++ ret = (1 << (PCI_IDSEL_BASE + PCI_SLOT(devfn)))
++ | (PCI_FUNC(devfn) << 8) | (where & ~3);
++ } else {
++ /* type 1 */
++ ret = (bus->number << 16) | (PCI_SLOT(devfn) << 11)
++ | (PCI_FUNC(devfn) << 8) | (where & ~3) | 1;
++ }
++
++ return ret;
++}
++
++int ar71xx_pci_be_handler(int is_fixup)
++{
++ void __iomem *base = ar71xx_pcicfg_base;
++ u32 pci_err;
++ u32 ahb_err;
++
++ pci_err = __raw_readl(base + PCI_REG_PCI_ERR) & 3;
++ if (pci_err) {
++ if (!is_fixup)
++ printk(KERN_ALERT "PCI error %d at PCI addr 0x%x\n",
++ pci_err,
++ __raw_readl(base + PCI_REG_PCI_ERR_ADDR));
++
++ __raw_writel(pci_err, base + PCI_REG_PCI_ERR);
++ }
++
++ ahb_err = __raw_readl(base + PCI_REG_AHB_ERR) & 1;
++ if (ahb_err) {
++ if (!is_fixup)
++ printk(KERN_ALERT "AHB error at AHB address 0x%x\n",
++ __raw_readl(base + PCI_REG_AHB_ERR_ADDR));
++
++ __raw_writel(ahb_err, base + PCI_REG_AHB_ERR);
++ }
++
++ return ((ahb_err | pci_err) ? 1 : 0);
++}
++
++static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus,
++ unsigned int devfn, int where, int size, u32 cmd)
++{
++ void __iomem *base = ar71xx_pcicfg_base;
++ u32 addr;
++
++ addr = ar71xx_pci_bus_addr(bus, devfn, where);
++
++ DBG("PCI: set cfgaddr: %02x:%02x.%01x/%02x:%01d, addr=%08x\n",
++ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
++ where, size, addr);
++
++ __raw_writel(addr, base + PCI_REG_CFG_AD);
++ __raw_writel(cmd | ar71xx_pci_get_ble(where, size, 0),
++ base + PCI_REG_CFG_CBE);
++
++ return ar71xx_pci_be_handler(1);
++}
++
++static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 *value)
++{
++ void __iomem *base = ar71xx_pcicfg_base;
++ static u32 mask[8] = {0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0};
++ unsigned long flags;
++ u32 data;
++ int ret;
++
++ ret = PCIBIOS_SUCCESSFUL;
++
++ DBG("PCI: read config: %02x:%02x.%01x/%02x:%01d\n", bus->number,
++ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size);
++
++ spin_lock_irqsave(&ar71xx_pci_lock, flags);
++
++ if (bus->number == 0 && devfn == 0) {
++ u32 t;
++
++ t = PCI_CRP_CMD_READ | (where & ~3);
++
++ __raw_writel(t, base + PCI_REG_CRP_AD_CBE);
++ data = __raw_readl(base + PCI_REG_CRP_RDDATA);
++
++ DBG("PCI: rd local cfg, ad_cbe:%08x, data:%08x\n", t, data);
++
++ } else {
++ int err;
++
++ err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size,
++ PCI_CFG_CMD_READ);
++
++ if (err == 0) {
++ data = __raw_readl(base + PCI_REG_CFG_RDDATA);
++ } else {
++ ret = PCIBIOS_DEVICE_NOT_FOUND;
++ data = ~0;
++ }
++ }
++
++ spin_unlock_irqrestore(&ar71xx_pci_lock, flags);
++
++ DBG("PCI: read config: data=%08x raw=%08x\n",
++ (data >> (8 * (where & 3))) & mask[size & 7], data);
++
++ *value = (data >> (8 * (where & 3))) & mask[size & 7];
++
++ return ret;
++}
++
++static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 value)
++{
++ void __iomem *base = ar71xx_pcicfg_base;
++ unsigned long flags;
++ int ret;
++
++ DBG("PCI: write config: %02x:%02x.%01x/%02x:%01d value=%08x\n",
++ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
++ where, size, value);
++
++ value = value << (8 * (where & 3));
++ ret = PCIBIOS_SUCCESSFUL;
++
++ spin_lock_irqsave(&ar71xx_pci_lock, flags);
++ if (bus->number == 0 && devfn == 0) {
++ u32 t;
++
++ t = PCI_CRP_CMD_WRITE | (where & ~3);
++ t |= ar71xx_pci_get_ble(where, size, 1);
++
++ DBG("PCI: wr local cfg, ad_cbe:%08x, value:%08x\n", t, value);
++
++ __raw_writel(t, base + PCI_REG_CRP_AD_CBE);
++ __raw_writel(value, base + PCI_REG_CRP_WRDATA);
++ } else {
++ int err;
++
++ err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size,
++ PCI_CFG_CMD_WRITE);
++
++ if (err == 0)
++ __raw_writel(value, base + PCI_REG_CFG_WRDATA);
++ else
++ ret = PCIBIOS_DEVICE_NOT_FOUND;
++ }
++ spin_unlock_irqrestore(&ar71xx_pci_lock, flags);
++
++ return ret;
++}
++
++static void ar71xx_pci_fixup(struct pci_dev *dev)
++{
++ u32 t;
++
++ if (!ar71xx_pci_fixup_enable)
++ return;
++
++ if (dev->bus->number != 0 || dev->devfn != 0)
++ return;
++
++ DBG("PCI: fixup host controller %s (%04x:%04x)\n", pci_name(dev),
++ dev->vendor, dev->device);
++
++ /* setup COMMAND register */
++ t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
++ | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK;
++
++ pci_write_config_word(dev, PCI_COMMAND, t);
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ar71xx_pci_fixup);
++
++int __init ar71xx_pcibios_map_irq(const struct pci_dev *dev, uint8_t slot,
++ uint8_t pin)
++{
++ int irq = -1;
++ int i;
++
++ slot -= PCI_IDSEL_ADL_START - PCI_IDSEL_BASE;
++
++ for (i = 0; i < ar71xx_pci_nr_irqs; i++) {
++ struct ar71xx_pci_irq *entry;
++
++ entry = &ar71xx_pci_irq_map[i];
++ if (entry->slot == slot && entry->pin == pin) {
++ irq = entry->irq;
++ break;
++ }
++ }
++
++ if (irq < 0) {
++ printk(KERN_ALERT "PCI: no irq found for pin%u@%s\n",
++ pin, pci_name((struct pci_dev *)dev));
++ } else {
++ printk(KERN_INFO "PCI: mapping irq %d to pin%u@%s\n",
++ irq, pin, pci_name((struct pci_dev *)dev));
++ }
++
++ return irq;
++}
++
++static struct pci_ops ar71xx_pci_ops = {
++ .read = ar71xx_pci_read_config,
++ .write = ar71xx_pci_write_config,
++};
++
++static struct resource ar71xx_pci_io_resource = {
++ .name = "PCI IO space",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_IO,
++};
++
++static struct resource ar71xx_pci_mem_resource = {
++ .name = "PCI memory space",
++ .start = AR71XX_PCI_MEM_BASE,
++ .end = AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1,
++ .flags = IORESOURCE_MEM
++};
++
++static struct pci_controller ar71xx_pci_controller = {
++ .pci_ops = &ar71xx_pci_ops,
++ .mem_resource = &ar71xx_pci_mem_resource,
++ .io_resource = &ar71xx_pci_io_resource,
++};
++
++static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
++{
++ void __iomem *base = ar71xx_reset_base;
++ u32 pending;
++
++ pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) &
++ __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++
++ if (pending & PCI_INT_DEV0)
++ generic_handle_irq(AR71XX_PCI_IRQ_DEV0);
++
++ else if (pending & PCI_INT_DEV1)
++ generic_handle_irq(AR71XX_PCI_IRQ_DEV1);
++
++ else if (pending & PCI_INT_DEV2)
++ generic_handle_irq(AR71XX_PCI_IRQ_DEV2);
++
++ else if (pending & PCI_INT_CORE)
++ generic_handle_irq(AR71XX_PCI_IRQ_CORE);
++
++ else
++ spurious_interrupt();
++}
++
++static void ar71xx_pci_irq_unmask(unsigned int irq)
++{
++ void __iomem *base = ar71xx_reset_base;
++ u32 t;
++
++ irq -= AR71XX_PCI_IRQ_BASE;
++
++ t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++ __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++
++ /* flush write */
++ (void) __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++}
++
++static void ar71xx_pci_irq_mask(unsigned int irq)
++{
++ void __iomem *base = ar71xx_reset_base;
++ u32 t;
++
++ irq -= AR71XX_PCI_IRQ_BASE;
++
++ t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++ __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++
++ /* flush write */
++ (void) __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++}
++
++static struct irq_chip ar71xx_pci_irq_chip = {
++ .name = "AR71XX PCI ",
++ .mask = ar71xx_pci_irq_mask,
++ .unmask = ar71xx_pci_irq_unmask,
++ .mask_ack = ar71xx_pci_irq_mask,
++};
++
++static void __init ar71xx_pci_irq_init(void)
++{
++ void __iomem *base = ar71xx_reset_base;
++ int i;
++
++ __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++ __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS);
++
++ for (i = AR71XX_PCI_IRQ_BASE;
++ i < AR71XX_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) {
++ irq_desc[i].status = IRQ_DISABLED;
++ set_irq_chip_and_handler(i, &ar71xx_pci_irq_chip,
++ handle_level_irq);
++ }
++
++ set_irq_chained_handler(AR71XX_CPU_IRQ_IP2, ar71xx_pci_irq_handler);
++}
++
++int __init ar71xx_pcibios_init(void)
++{
++ void __iomem *ddr_base = ar71xx_ddr_base;
++
++ ar71xx_device_stop(RESET_MODULE_PCI_BUS | RESET_MODULE_PCI_CORE);
++ ar71xx_pci_delay();
++
++ ar71xx_device_start(RESET_MODULE_PCI_BUS | RESET_MODULE_PCI_CORE);
++ ar71xx_pci_delay();
++
++ ar71xx_pcicfg_base = ioremap_nocache(AR71XX_PCI_CFG_BASE,
++ AR71XX_PCI_CFG_SIZE);
++ if (ar71xx_pcicfg_base == NULL)
++ return -ENOMEM;
++
++ __raw_writel(PCI_WIN0_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN0);
++ __raw_writel(PCI_WIN1_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN1);
++ __raw_writel(PCI_WIN2_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN2);
++ __raw_writel(PCI_WIN3_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN3);
++ __raw_writel(PCI_WIN4_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN4);
++ __raw_writel(PCI_WIN5_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN5);
++ __raw_writel(PCI_WIN6_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN6);
++ __raw_writel(PCI_WIN7_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN7);
++
++ ar71xx_pci_delay();
++
++ /* clear bus errors */
++ (void)ar71xx_pci_be_handler(1);
++
++ ar71xx_pci_fixup_enable = 1;
++ ar71xx_pci_irq_init();
++ register_pci_controller(&ar71xx_pci_controller);
++
++ return 0;
++}
+diff -Nur linux-2.6.37.orig/arch/mips/pci/pci-ar724x.c linux-2.6.37/arch/mips/pci/pci-ar724x.c
+--- linux-2.6.37.orig/arch/mips/pci/pci-ar724x.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/pci/pci-ar724x.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,395 @@
++/*
++ * Atheros AR724x PCI host controller driver
++ *
++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/resource.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/pci.h>
++#include <linux/pci_regs.h>
++#include <linux/interrupt.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/pci.h>
++
++#undef DEBUG
++#ifdef DEBUG
++#define DBG(fmt, args...) printk(KERN_INFO fmt, ## args)
++#else
++#define DBG(fmt, args...)
++#endif
++
++static void __iomem *ar724x_pci_localcfg_base;
++static void __iomem *ar724x_pci_devcfg_base;
++static void __iomem *ar724x_pci_ctrl_base;
++static int ar724x_pci_fixup_enable;
++
++static DEFINE_SPINLOCK(ar724x_pci_lock);
++
++static void ar724x_pci_read(void __iomem *base, int where, int size, u32 *value)
++{
++ unsigned long flags;
++ u32 data;
++
++ spin_lock_irqsave(&ar724x_pci_lock, flags);
++ data = __raw_readl(base + (where & ~3));
++
++ switch (size) {
++ case 1:
++ if (where & 1)
++ data >>= 8;
++ if (where & 2)
++ data >>= 16;
++ data &= 0xFF;
++ break;
++ case 2:
++ if (where & 2)
++ data >>= 16;
++ data &= 0xFFFF;
++ break;
++ }
++
++ *value = data;
++ spin_unlock_irqrestore(&ar724x_pci_lock, flags);
++}
++
++static void ar724x_pci_write(void __iomem *base, int where, int size, u32 value)
++{
++ unsigned long flags;
++ u32 data;
++ int s;
++
++ spin_lock_irqsave(&ar724x_pci_lock, flags);
++ data = __raw_readl(base + (where & ~3));
++
++ switch (size) {
++ case 1:
++ s = ((where & 3) << 3);
++ data &= ~(0xFF << s);
++ data |= ((value & 0xFF) << s);
++ break;
++ case 2:
++ s = ((where & 2) << 3);
++ data &= ~(0xFFFF << s);
++ data |= ((value & 0xFFFF) << s);
++ break;
++ case 4:
++ data = value;
++ break;
++ }
++
++ __raw_writel(data, base + (where & ~3));
++ /* flush write */
++ (void)__raw_readl(base + (where & ~3));
++ spin_unlock_irqrestore(&ar724x_pci_lock, flags);
++}
++
++static int ar724x_pci_read_config(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 *value)
++{
++
++ if (bus->number != 0 || devfn != 0)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++
++ ar724x_pci_read(ar724x_pci_devcfg_base, where, size, value);
++
++ DBG("PCI: read config: %02x:%02x.%01x/%02x:%01d, value=%08x\n",
++ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
++ where, size, *value);
++
++ /*
++ * WAR for BAR issue - We are unable to access the PCI device space
++ * if we set the BAR with proper base address
++ */
++ if ((where == 0x10) && (size == 4)) {
++ if (ar71xx_soc == AR71XX_SOC_AR7240)
++ ar724x_pci_write(ar724x_pci_devcfg_base, where, size, 0xffff);
++ else
++ ar724x_pci_write(ar724x_pci_devcfg_base, where, size, 0x1000ffff);
++ }
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static int ar724x_pci_write_config(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 value)
++{
++ if (bus->number != 0 || devfn != 0)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++
++ DBG("PCI: write config: %02x:%02x.%01x/%02x:%01d, value=%08x\n",
++ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
++ where, size, value);
++
++ ar724x_pci_write(ar724x_pci_devcfg_base, where, size, value);
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static void ar724x_pci_fixup(struct pci_dev *dev)
++{
++ u16 cmd;
++
++ if (!ar724x_pci_fixup_enable)
++ return;
++
++ if (dev->bus->number != 0 || dev->devfn != 0)
++ return;
++
++ /* setup COMMAND register */
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
++ PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR |
++ PCI_COMMAND_FAST_BACK;
++
++ pci_write_config_word(dev, PCI_COMMAND, cmd);
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ar724x_pci_fixup);
++
++int __init ar724x_pcibios_map_irq(const struct pci_dev *dev, uint8_t slot,
++ uint8_t pin)
++{
++ int irq = -1;
++ int i;
++
++ for (i = 0; i < ar71xx_pci_nr_irqs; i++) {
++ struct ar71xx_pci_irq *entry;
++ entry = &ar71xx_pci_irq_map[i];
++
++ if (entry->slot == slot && entry->pin == pin) {
++ irq = entry->irq;
++ break;
++ }
++ }
++
++ if (irq < 0)
++ printk(KERN_ALERT "PCI: no irq found for pin%u@%s\n",
++ pin, pci_name((struct pci_dev *)dev));
++ else
++ printk(KERN_INFO "PCI: mapping irq %d to pin%u@%s\n",
++ irq, pin, pci_name((struct pci_dev *)dev));
++
++ return irq;
++}
++
++static struct pci_ops ar724x_pci_ops = {
++ .read = ar724x_pci_read_config,
++ .write = ar724x_pci_write_config,
++};
++
++static struct resource ar724x_pci_io_resource = {
++ .name = "PCI IO space",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_IO,
++};
++
++static struct resource ar724x_pci_mem_resource = {
++ .name = "PCI memory space",
++ .start = AR71XX_PCI_MEM_BASE,
++ .end = AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1,
++ .flags = IORESOURCE_MEM
++};
++
++static struct pci_controller ar724x_pci_controller = {
++ .pci_ops = &ar724x_pci_ops,
++ .mem_resource = &ar724x_pci_mem_resource,
++ .io_resource = &ar724x_pci_io_resource,
++};
++
++static void __init ar724x_pci_reset(void)
++{
++ ar71xx_device_stop(AR724X_RESET_PCIE);
++ ar71xx_device_stop(AR724X_RESET_PCIE_PHY);
++ ar71xx_device_stop(AR724X_RESET_PCIE_PHY_SERIAL);
++ udelay(100);
++
++ ar71xx_device_start(AR724X_RESET_PCIE_PHY_SERIAL);
++ udelay(100);
++ ar71xx_device_start(AR724X_RESET_PCIE_PHY);
++ ar71xx_device_start(AR724X_RESET_PCIE);
++}
++
++static int __init ar724x_pci_setup(void)
++{
++ void __iomem *base = ar724x_pci_ctrl_base;
++ u32 t;
++
++ /* setup COMMAND register */
++ t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE |
++ PCI_COMMAND_PARITY|PCI_COMMAND_SERR|PCI_COMMAND_FAST_BACK;
++
++ ar724x_pci_write(ar724x_pci_localcfg_base, PCI_COMMAND, 4, t);
++ ar724x_pci_write(ar724x_pci_localcfg_base, 0x20, 4, 0x1ff01000);
++ ar724x_pci_write(ar724x_pci_localcfg_base, 0x24, 4, 0x1ff01000);
++
++ t = __raw_readl(base + AR724X_PCI_REG_RESET);
++ if (t != 0x7) {
++ udelay(100000);
++ __raw_writel(0, base + AR724X_PCI_REG_RESET);
++ udelay(100);
++ __raw_writel(4, base + AR724X_PCI_REG_RESET);
++ udelay(100000);
++ }
++
++ if (ar71xx_soc == AR71XX_SOC_AR7240)
++ t = AR724X_PCI_APP_LTSSM_ENABLE;
++ else
++ t = 0x1ffc1;
++ __raw_writel(t, base + AR724X_PCI_REG_APP);
++ /* flush write */
++ (void) __raw_readl(base + AR724X_PCI_REG_APP);
++ udelay(1000);
++
++ t = __raw_readl(base + AR724X_PCI_REG_RESET);
++ if ((t & AR724X_PCI_RESET_LINK_UP) == 0x0) {
++ printk(KERN_WARNING "PCI: no PCIe module found\n");
++ return -ENODEV;
++ }
++
++ if (ar71xx_soc == AR71XX_SOC_AR7241 || ar71xx_soc == AR71XX_SOC_AR7242) {
++ t = __raw_readl(base + AR724X_PCI_REG_APP);
++ t |= BIT(16);
++ __raw_writel(t, base + AR724X_PCI_REG_APP);
++ }
++
++ return 0;
++}
++
++static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
++{
++ void __iomem *base = ar724x_pci_ctrl_base;
++ u32 pending;
++
++ pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) &
++ __raw_readl(base + AR724X_PCI_REG_INT_MASK);
++
++ if (pending & AR724X_PCI_INT_DEV0)
++ generic_handle_irq(AR71XX_PCI_IRQ_DEV0);
++
++ else
++ spurious_interrupt();
++}
++
++static void ar724x_pci_irq_unmask(unsigned int irq)
++{
++ void __iomem *base = ar724x_pci_ctrl_base;
++ u32 t;
++
++ switch (irq) {
++ case AR71XX_PCI_IRQ_DEV0:
++ irq -= AR71XX_PCI_IRQ_BASE;
++
++ t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
++ __raw_writel(t | AR724X_PCI_INT_DEV0,
++ base + AR724X_PCI_REG_INT_MASK);
++ /* flush write */
++ (void) __raw_readl(base + AR724X_PCI_REG_INT_MASK);
++ }
++}
++
++static void ar724x_pci_irq_mask(unsigned int irq)
++{
++ void __iomem *base = ar724x_pci_ctrl_base;
++ u32 t;
++
++ switch (irq) {
++ case AR71XX_PCI_IRQ_DEV0:
++ irq -= AR71XX_PCI_IRQ_BASE;
++
++ t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
++ __raw_writel(t & ~AR724X_PCI_INT_DEV0,
++ base + AR724X_PCI_REG_INT_MASK);
++
++ /* flush write */
++ (void) __raw_readl(base + AR724X_PCI_REG_INT_MASK);
++
++ t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS);
++ __raw_writel(t | AR724X_PCI_INT_DEV0,
++ base + AR724X_PCI_REG_INT_STATUS);
++
++ /* flush write */
++ (void) __raw_readl(base + AR724X_PCI_REG_INT_STATUS);
++ }
++}
++
++static struct irq_chip ar724x_pci_irq_chip = {
++ .name = "AR724X PCI ",
++ .mask = ar724x_pci_irq_mask,
++ .unmask = ar724x_pci_irq_unmask,
++ .mask_ack = ar724x_pci_irq_mask,
++};
++
++static void __init ar724x_pci_irq_init(void)
++{
++ void __iomem *base = ar724x_pci_ctrl_base;
++ u32 t;
++ int i;
++
++ t = ar71xx_reset_rr(AR724X_RESET_REG_RESET_MODULE);
++ if (t & (AR724X_RESET_PCIE | AR724X_RESET_PCIE_PHY |
++ AR724X_RESET_PCIE_PHY_SERIAL)) {
++ return;
++ }
++
++ __raw_writel(0, base + AR724X_PCI_REG_INT_MASK);
++ __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS);
++
++ for (i = AR71XX_PCI_IRQ_BASE;
++ i < AR71XX_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) {
++ irq_desc[i].status = IRQ_DISABLED;
++ set_irq_chip_and_handler(i, &ar724x_pci_irq_chip,
++ handle_level_irq);
++ }
++
++ set_irq_chained_handler(AR71XX_CPU_IRQ_IP2, ar724x_pci_irq_handler);
++}
++
++int __init ar724x_pcibios_init(void)
++{
++ int ret = -ENOMEM;
++
++ ar724x_pci_localcfg_base = ioremap_nocache(AR724X_PCI_CRP_BASE,
++ AR724X_PCI_CRP_SIZE);
++ if (ar724x_pci_localcfg_base == NULL)
++ goto err;
++
++ ar724x_pci_devcfg_base = ioremap_nocache(AR724X_PCI_CFG_BASE,
++ AR724X_PCI_CFG_SIZE);
++ if (ar724x_pci_devcfg_base == NULL)
++ goto err_unmap_localcfg;
++
++ ar724x_pci_ctrl_base = ioremap_nocache(AR724X_PCI_CTRL_BASE,
++ AR724X_PCI_CTRL_SIZE);
++ if (ar724x_pci_ctrl_base == NULL)
++ goto err_unmap_devcfg;
++
++ ar724x_pci_reset();
++ ret = ar724x_pci_setup();
++ if (ret)
++ goto err_unmap_ctrl;
++
++ ar724x_pci_fixup_enable = 1;
++ ar724x_pci_irq_init();
++ register_pci_controller(&ar724x_pci_controller);
++
++ return 0;
++
++ err_unmap_ctrl:
++ iounmap(ar724x_pci_ctrl_base);
++ err_unmap_devcfg:
++ iounmap(ar724x_pci_devcfg_base);
++ err_unmap_localcfg:
++ iounmap(ar724x_pci_localcfg_base);
++ err:
++ return ret;
++}
+diff -Nur linux-2.6.37.orig/drivers/char/Kconfig linux-2.6.37/drivers/char/Kconfig
+--- linux-2.6.37.orig/drivers/char/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/char/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -1047,6 +1047,14 @@
+
+ If compiled as a module, it will be called cs5535_gpio.
+
++config GPIO_DEVICE
++ tristate "GPIO device support"
++ depends on GENERIC_GPIO
++ help
++ Say Y to enable Linux GPIO device support. This allows control of
++ GPIO pins using a character device
++
++
+ config RAW_DRIVER
+ tristate "RAW driver (/dev/raw/rawN)"
+ depends on BLOCK
+diff -Nur linux-2.6.37.orig/drivers/char/Makefile linux-2.6.37/drivers/char/Makefile
+--- linux-2.6.37.orig/drivers/char/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/char/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -82,6 +82,7 @@
+ obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o
+ obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o
+ obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o
++obj-$(CONFIG_GPIO_DEVICE) += gpio_dev.o
+ obj-$(CONFIG_GPIO_TB0219) += tb0219.o
+ obj-$(CONFIG_TELCLOCK) += tlclk.o
+
+diff -Nur linux-2.6.37.orig/drivers/gpio/nxp_74hc153.c linux-2.6.37/drivers/gpio/nxp_74hc153.c
+--- linux-2.6.37.orig/drivers/gpio/nxp_74hc153.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/gpio/nxp_74hc153.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,246 @@
++/*
++ * NXP 74HC153 - Dual 4-input multiplexer GPIO driver
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/gpio.h>
++#include <linux/platform_device.h>
++#include <linux/nxp_74hc153.h>
++
++#define NXP_74HC153_NUM_GPIOS 8
++#define NXP_74HC153_S0_MASK 0x1
++#define NXP_74HC153_S1_MASK 0x2
++#define NXP_74HC153_BANK_MASK 0x4
++
++struct nxp_74hc153_chip {
++ struct device *parent;
++ struct gpio_chip gpio_chip;
++ struct mutex lock;
++};
++
++static struct nxp_74hc153_chip *gpio_to_nxp(struct gpio_chip *gc)
++{
++ return container_of(gc, struct nxp_74hc153_chip, gpio_chip);
++}
++
++static int nxp_74hc153_direction_input(struct gpio_chip *gc, unsigned offset)
++{
++ return 0;
++}
++
++static int nxp_74hc153_direction_output(struct gpio_chip *gc,
++ unsigned offset, int val)
++{
++ return -EINVAL;
++}
++
++static int nxp_74hc153_get_value(struct gpio_chip *gc, unsigned offset)
++{
++ struct nxp_74hc153_chip *nxp;
++ struct nxp_74hc153_platform_data *pdata;
++ unsigned s0;
++ unsigned s1;
++ unsigned pin;
++ int ret;
++
++ nxp = gpio_to_nxp(gc);
++ pdata = nxp->parent->platform_data;
++
++ s0 = !!(offset & NXP_74HC153_S0_MASK);
++ s1 = !!(offset & NXP_74HC153_S1_MASK);
++ pin = (offset & NXP_74HC153_BANK_MASK) ? pdata->gpio_pin_2y
++ : pdata->gpio_pin_1y;
++
++ mutex_lock(&nxp->lock);
++ gpio_set_value(pdata->gpio_pin_s0, s0);
++ gpio_set_value(pdata->gpio_pin_s1, s1);
++ ret = gpio_get_value(pin);
++ mutex_unlock(&nxp->lock);
++
++ return ret;
++}
++
++static void nxp_74hc153_set_value(struct gpio_chip *gc,
++ unsigned offset, int val)
++{
++ /* not supported */
++}
++
++static int __devinit nxp_74hc153_probe(struct platform_device *pdev)
++{
++ struct nxp_74hc153_platform_data *pdata;
++ struct nxp_74hc153_chip *nxp;
++ struct gpio_chip *gc;
++ int err;
++
++ pdata = pdev->dev.platform_data;
++ if (pdata == NULL) {
++ dev_dbg(&pdev->dev, "no platform data specified\n");
++ return -EINVAL;
++ }
++
++ nxp = kzalloc(sizeof(struct nxp_74hc153_chip), GFP_KERNEL);
++ if (nxp == NULL) {
++ dev_err(&pdev->dev, "no memory for private data\n");
++ return -ENOMEM;
++ }
++
++ err = gpio_request(pdata->gpio_pin_s0, dev_name(&pdev->dev));
++ if (err) {
++ dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
++ pdata->gpio_pin_s0, err);
++ goto err_free_nxp;
++ }
++
++ err = gpio_request(pdata->gpio_pin_s1, dev_name(&pdev->dev));
++ if (err) {
++ dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
++ pdata->gpio_pin_s1, err);
++ goto err_free_s0;
++ }
++
++ err = gpio_request(pdata->gpio_pin_1y, dev_name(&pdev->dev));
++ if (err) {
++ dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
++ pdata->gpio_pin_1y, err);
++ goto err_free_s1;
++ }
++
++ err = gpio_request(pdata->gpio_pin_2y, dev_name(&pdev->dev));
++ if (err) {
++ dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
++ pdata->gpio_pin_2y, err);
++ goto err_free_1y;
++ }
++
++ err = gpio_direction_output(pdata->gpio_pin_s0, 0);
++ if (err) {
++ dev_err(&pdev->dev,
++ "unable to set direction of gpio %u, err=%d\n",
++ pdata->gpio_pin_s0, err);
++ goto err_free_2y;
++ }
++
++ err = gpio_direction_output(pdata->gpio_pin_s1, 0);
++ if (err) {
++ dev_err(&pdev->dev,
++ "unable to set direction of gpio %u, err=%d\n",
++ pdata->gpio_pin_s1, err);
++ goto err_free_2y;
++ }
++
++ err = gpio_direction_input(pdata->gpio_pin_1y);
++ if (err) {
++ dev_err(&pdev->dev,
++ "unable to set direction of gpio %u, err=%d\n",
++ pdata->gpio_pin_1y, err);
++ goto err_free_2y;
++ }
++
++ err = gpio_direction_input(pdata->gpio_pin_2y);
++ if (err) {
++ dev_err(&pdev->dev,
++ "unable to set direction of gpio %u, err=%d\n",
++ pdata->gpio_pin_2y, err);
++ goto err_free_2y;
++ }
++
++ nxp->parent = &pdev->dev;
++ mutex_init(&nxp->lock);
++
++ gc = &nxp->gpio_chip;
++
++ gc->direction_input = nxp_74hc153_direction_input;
++ gc->direction_output = nxp_74hc153_direction_output;
++ gc->get = nxp_74hc153_get_value;
++ gc->set = nxp_74hc153_set_value;
++ gc->can_sleep = 1;
++
++ gc->base = pdata->gpio_base;
++ gc->ngpio = NXP_74HC153_NUM_GPIOS;
++ gc->label = dev_name(nxp->parent);
++ gc->dev = nxp->parent;
++ gc->owner = THIS_MODULE;
++
++ err = gpiochip_add(&nxp->gpio_chip);
++ if (err) {
++ dev_err(&pdev->dev, "unable to add gpio chip, err=%d\n", err);
++ goto err_free_2y;
++ }
++
++ platform_set_drvdata(pdev, nxp);
++ return 0;
++
++ err_free_2y:
++ gpio_free(pdata->gpio_pin_2y);
++ err_free_1y:
++ gpio_free(pdata->gpio_pin_1y);
++ err_free_s1:
++ gpio_free(pdata->gpio_pin_s1);
++ err_free_s0:
++ gpio_free(pdata->gpio_pin_s0);
++ err_free_nxp:
++ kfree(nxp);
++ return err;
++}
++
++static int nxp_74hc153_remove(struct platform_device *pdev)
++{
++ struct nxp_74hc153_chip *nxp = platform_get_drvdata(pdev);
++ struct nxp_74hc153_platform_data *pdata = pdev->dev.platform_data;
++
++ if (nxp) {
++ int err;
++
++ err = gpiochip_remove(&nxp->gpio_chip);
++ if (err) {
++ dev_err(&pdev->dev,
++ "unable to remove gpio chip, err=%d\n",
++ err);
++ return err;
++ }
++
++ gpio_free(pdata->gpio_pin_2y);
++ gpio_free(pdata->gpio_pin_1y);
++ gpio_free(pdata->gpio_pin_s1);
++ gpio_free(pdata->gpio_pin_s0);
++
++ kfree(nxp);
++ platform_set_drvdata(pdev, NULL);
++ }
++
++ return 0;
++}
++
++static struct platform_driver nxp_74hc153_driver = {
++ .probe = nxp_74hc153_probe,
++ .remove = __devexit_p(nxp_74hc153_remove),
++ .driver = {
++ .name = NXP_74HC153_DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init nxp_74hc153_init(void)
++{
++ return platform_driver_register(&nxp_74hc153_driver);
++}
++subsys_initcall(nxp_74hc153_init);
++
++static void __exit nxp_74hc153_exit(void)
++{
++ platform_driver_unregister(&nxp_74hc153_driver);
++}
++module_exit(nxp_74hc153_exit);
++
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_DESCRIPTION("GPIO expander driver for NXP 74HC153");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" NXP_74HC153_DRIVER_NAME);
+diff -Nur linux-2.6.37.orig/drivers/input/misc/Kconfig linux-2.6.37/drivers/input/misc/Kconfig
+--- linux-2.6.37.orig/drivers/input/misc/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/input/misc/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -448,4 +448,20 @@
+ To compile this driver as a module, choose M here: the
+ module will be called adxl34x-spi.
+
++config INPUT_GPIO_BUTTONS
++ tristate "Polled GPIO buttons interface"
++ depends on GENERIC_GPIO
++ select INPUT_POLLDEV
++ help
++ This driver implements support for buttons connected
++ to GPIO pins of various CPUs (and some other chips).
++
++ Say Y here if your device has buttons connected
++ directly to such GPIO pins. Your board-specific
++ setup logic must also provide a platform device,
++ with configuration data saying which GPIOs are used.
++
++ To compile this driver as a module, choose M here: the
++ module will be called gpio-buttons.
++
+ endif
+diff -Nur linux-2.6.37.orig/drivers/input/misc/Makefile linux-2.6.37/drivers/input/misc/Makefile
+--- linux-2.6.37.orig/drivers/input/misc/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/input/misc/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -42,4 +42,5 @@
+ obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
+ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
+ obj-$(CONFIG_INPUT_YEALINK) += yealink.o
++obj-$(CONFIG_INPUT_GPIO_BUTTONS) += gpio_buttons.o
+
+diff -Nur linux-2.6.37.orig/drivers/input/misc/gpio_buttons.c linux-2.6.37/drivers/input/misc/gpio_buttons.c
+--- linux-2.6.37.orig/drivers/input/misc/gpio_buttons.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/input/misc/gpio_buttons.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,216 @@
++/*
++ * Driver for buttons on GPIO lines not capable of generating interrupts
++ *
++ * Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com>
++ *
++ * This file was based on: /drivers/input/misc/cobalt_btns.c
++ * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
++ *
++ * also was based on: /drivers/input/keyboard/gpio_keys.c
++ * Copyright 2005 Phil Blundell
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++
++#include <linux/input.h>
++#include <linux/input-polldev.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++
++#include <linux/gpio_buttons.h>
++
++#include <asm/gpio.h>
++
++#define DRV_NAME "gpio-buttons"
++#define DRV_VERSION "0.1.2"
++#define PFX DRV_NAME ": "
++
++struct gpio_button_data {
++ int last_state;
++ int count;
++};
++
++struct gpio_buttons_dev {
++ struct input_polled_dev *poll_dev;
++ struct gpio_buttons_platform_data *pdata;
++ struct gpio_button_data *data;
++};
++
++static void gpio_buttons_poll(struct input_polled_dev *dev)
++{
++ struct gpio_buttons_dev *bdev = dev->private;
++ struct gpio_buttons_platform_data *pdata = bdev->pdata;
++ struct input_dev *input = dev->input;
++ int i;
++
++ for (i = 0; i < bdev->pdata->nbuttons; i++) {
++ struct gpio_button *button = &pdata->buttons[i];
++ unsigned int type = button->type ?: EV_KEY;
++ int state;
++
++ if (bdev->data[i].count < button->threshold) {
++ bdev->data[i].count++;
++ continue;
++ }
++
++ state = gpio_get_value(button->gpio) ? 1 : 0;
++ if (state != bdev->data[i].last_state) {
++ input_event(input, type, button->code,
++ !!(state ^ button->active_low));
++ input_sync(input);
++ bdev->data[i].count = 0;
++ bdev->data[i].last_state = state;
++ }
++ }
++}
++
++static int __devinit gpio_buttons_probe(struct platform_device *pdev)
++{
++ struct gpio_buttons_platform_data *pdata = pdev->dev.platform_data;
++ struct gpio_buttons_dev *bdev;
++ struct input_polled_dev *poll_dev;
++ struct input_dev *input;
++ int error, i;
++
++ if (!pdata)
++ return -ENXIO;
++
++ bdev = kzalloc(sizeof(struct gpio_buttons_dev) +
++ sizeof(struct gpio_button_data) * pdata->nbuttons,
++ GFP_KERNEL);
++ if (!bdev) {
++ printk(KERN_ERR DRV_NAME "no memory for device\n");
++ return -ENOMEM;
++ }
++
++ bdev->data = (struct gpio_button_data *) &bdev[1];
++
++ poll_dev = input_allocate_polled_device();
++ if (!poll_dev) {
++ printk(KERN_ERR DRV_NAME "no memory for polled device\n");
++ error = -ENOMEM;
++ goto err_free_bdev;
++ }
++
++ poll_dev->private = bdev;
++ poll_dev->poll = gpio_buttons_poll;
++ poll_dev->poll_interval = pdata->poll_interval;
++
++ input = poll_dev->input;
++
++ input->evbit[0] = BIT(EV_KEY);
++ input->name = pdev->name;
++ input->phys = "gpio-buttons/input0";
++ input->dev.parent = &pdev->dev;
++
++ input->id.bustype = BUS_HOST;
++ input->id.vendor = 0x0001;
++ input->id.product = 0x0001;
++ input->id.version = 0x0100;
++
++ for (i = 0; i < pdata->nbuttons; i++) {
++ struct gpio_button *button = &pdata->buttons[i];
++ unsigned int gpio = button->gpio;
++ unsigned int type = button->type ?: EV_KEY;
++
++ error = gpio_request(gpio, button->desc ?
++ button->desc : DRV_NAME);
++ if (error) {
++ printk(KERN_ERR PFX "unable to claim gpio %u, "
++ "error %d\n", gpio, error);
++ goto err_free_gpio;
++ }
++
++ error = gpio_direction_input(gpio);
++ if (error) {
++ printk(KERN_ERR PFX "unable to set direction on "
++ "gpio %u, error %d\n", gpio, error);
++ goto err_free_gpio;
++ }
++
++ input_set_capability(input, type, button->code);
++ bdev->data[i].last_state = gpio_get_value(button->gpio) ? 1 : 0;
++ }
++
++ bdev->poll_dev = poll_dev;
++ bdev->pdata = pdata;
++ platform_set_drvdata(pdev, bdev);
++
++ error = input_register_polled_device(poll_dev);
++ if (error) {
++ printk(KERN_ERR PFX "unable to register polled device, "
++ "error %d\n", error);
++ goto err_free_gpio;
++ }
++
++ return 0;
++
++err_free_gpio:
++ for (i = i - 1; i >= 0; i--)
++ gpio_free(pdata->buttons[i].gpio);
++
++ input_free_polled_device(poll_dev);
++
++err_free_bdev:
++ kfree(bdev);
++
++ platform_set_drvdata(pdev, NULL);
++ return error;
++}
++
++static int __devexit gpio_buttons_remove(struct platform_device *pdev)
++{
++ struct gpio_buttons_dev *bdev = platform_get_drvdata(pdev);
++ struct gpio_buttons_platform_data *pdata = bdev->pdata;
++ int i;
++
++ input_unregister_polled_device(bdev->poll_dev);
++
++ for (i = 0; i < pdata->nbuttons; i++)
++ gpio_free(pdata->buttons[i].gpio);
++
++ input_free_polled_device(bdev->poll_dev);
++
++ kfree(bdev);
++ platform_set_drvdata(pdev, NULL);
++
++ return 0;
++}
++
++static struct platform_driver gpio_buttons_driver = {
++ .probe = gpio_buttons_probe,
++ .remove = __devexit_p(gpio_buttons_remove),
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init gpio_buttons_init(void)
++{
++ printk(KERN_INFO DRV_NAME " driver version " DRV_VERSION "\n");
++ return platform_driver_register(&gpio_buttons_driver);
++}
++
++static void __exit gpio_buttons_exit(void)
++{
++ platform_driver_unregister(&gpio_buttons_driver);
++}
++
++module_init(gpio_buttons_init);
++module_exit(gpio_buttons_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
++MODULE_VERSION(DRV_VERSION);
++MODULE_DESCRIPTION("Polled buttons driver for CPU GPIOs");
++
+diff -Nur linux-2.6.37.orig/drivers/leds/leds-rb750.c linux-2.6.37/drivers/leds/leds-rb750.c
+--- linux-2.6.37.orig/drivers/leds/leds-rb750.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/leds/leds-rb750.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,140 @@
++/*
++ * LED driver for the RouterBOARD 750
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/leds.h>
++
++#include <asm/mach-ar71xx/mach-rb750.h>
++
++#define DRV_NAME "leds-rb750"
++
++struct rb750_led_dev {
++ struct led_classdev cdev;
++ u32 mask;
++ int active_low;
++};
++
++struct rb750_led_drvdata {
++ struct rb750_led_dev *led_devs;
++ int num_leds;
++};
++
++static inline struct rb750_led_dev *to_rbled(struct led_classdev *led_cdev)
++{
++ return (struct rb750_led_dev *)container_of(led_cdev,
++ struct rb750_led_dev, cdev);
++}
++
++static void rb750_led_brightness_set(struct led_classdev *led_cdev,
++ enum led_brightness value)
++{
++ struct rb750_led_dev *rbled = to_rbled(led_cdev);
++ int level;
++
++ level = (value == LED_OFF) ? 0 : 1;
++ level ^= rbled->active_low;
++
++ if (level)
++ rb750_latch_change(0, rbled->mask);
++ else
++ rb750_latch_change(rbled->mask, 0);
++}
++
++static int __devinit rb750_led_probe(struct platform_device *pdev)
++{
++ struct rb750_led_platform_data *pdata;
++ struct rb750_led_drvdata *drvdata;
++ int ret = 0;
++ int i;
++
++ pdata = pdev->dev.platform_data;
++ if (!pdata)
++ return -EINVAL;
++
++ drvdata = kzalloc(sizeof(struct rb750_led_drvdata) +
++ sizeof(struct rb750_led_dev) * pdata->num_leds,
++ GFP_KERNEL);
++ if (!drvdata)
++ return -ENOMEM;
++
++ drvdata->num_leds = pdata->num_leds;
++ drvdata->led_devs = (struct rb750_led_dev *) &drvdata[1];
++
++ for (i = 0; i < drvdata->num_leds; i++) {
++ struct rb750_led_dev *rbled = &drvdata->led_devs[i];
++ struct rb750_led_data *led_data = &pdata->leds[i];
++
++ rbled->cdev.name = led_data->name;
++ rbled->cdev.default_trigger = led_data->default_trigger;
++ rbled->cdev.brightness_set = rb750_led_brightness_set;
++ rbled->cdev.brightness = LED_OFF;
++
++ rbled->mask = led_data->mask;
++ rbled->active_low = !!led_data->active_low;
++
++ ret = led_classdev_register(&pdev->dev, &rbled->cdev);
++ if (ret)
++ goto err;
++ }
++
++ platform_set_drvdata(pdev, drvdata);
++ return 0;
++
++ err:
++ for (i = i - 1; i >= 0; i--)
++ led_classdev_unregister(&drvdata->led_devs[i].cdev);
++
++ kfree(drvdata);
++ return ret;
++}
++
++static int __devexit rb750_led_remove(struct platform_device *pdev)
++{
++ struct rb750_led_drvdata *drvdata;
++ int i;
++
++ drvdata = platform_get_drvdata(pdev);
++ for (i = 0; i < drvdata->num_leds; i++)
++ led_classdev_unregister(&drvdata->led_devs[i].cdev);
++
++ kfree(drvdata);
++ return 0;
++}
++
++static struct platform_driver rb750_led_driver = {
++ .probe = rb750_led_probe,
++ .remove = __devexit_p(rb750_led_remove),
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++MODULE_ALIAS("platform:leds-rb750");
++
++static int __init rb750_led_init(void)
++{
++ return platform_driver_register(&rb750_led_driver);
++}
++
++static void __exit rb750_led_exit(void)
++{
++ platform_driver_unregister(&rb750_led_driver);
++}
++
++module_init(rb750_led_init);
++module_exit(rb750_led_exit);
++
++MODULE_DESCRIPTION(DRV_NAME);
++MODULE_DESCRIPTION("LED driver for the RouterBOARD 750");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.37.orig/drivers/leds/leds-wndr3700-usb.c linux-2.6.37/drivers/leds/leds-wndr3700-usb.c
+--- linux-2.6.37.orig/drivers/leds/leds-wndr3700-usb.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/leds/leds-wndr3700-usb.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,75 @@
++/*
++ * USB LED driver for the NETGEAR WNDR3700
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/leds.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#define DRIVER_NAME "wndr3700-led-usb"
++
++static void wndr3700_usb_led_set(struct led_classdev *cdev,
++ enum led_brightness brightness)
++{
++ if (brightness)
++ ar71xx_device_start(RESET_MODULE_GE1_PHY);
++ else
++ ar71xx_device_stop(RESET_MODULE_GE1_PHY);
++}
++
++static enum led_brightness wndr3700_usb_led_get(struct led_classdev *cdev)
++{
++ return ar71xx_device_stopped(RESET_MODULE_GE1_PHY) ? LED_OFF : LED_FULL;
++}
++
++static struct led_classdev wndr3700_usb_led = {
++ .name = "wndr3700:green:usb",
++ .brightness_set = wndr3700_usb_led_set,
++ .brightness_get = wndr3700_usb_led_get,
++};
++
++static int __devinit wndr3700_usb_led_probe(struct platform_device *pdev)
++{
++ return led_classdev_register(&pdev->dev, &wndr3700_usb_led);
++}
++
++static int __devexit wndr3700_usb_led_remove(struct platform_device *pdev)
++{
++ led_classdev_unregister(&wndr3700_usb_led);
++ return 0;
++}
++
++static struct platform_driver wndr3700_usb_led_driver = {
++ .probe = wndr3700_usb_led_probe,
++ .remove = __devexit_p(wndr3700_usb_led_remove),
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init wndr3700_usb_led_init(void)
++{
++ return platform_driver_register(&wndr3700_usb_led_driver);
++}
++
++static void __exit wndr3700_usb_led_exit(void)
++{
++ platform_driver_unregister(&wndr3700_usb_led_driver);
++}
++
++module_init(wndr3700_usb_led_init);
++module_exit(wndr3700_usb_led_exit);
++
++MODULE_DESCRIPTION("USB LED driver for the NETGEAR WNDR3700");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" DRIVER_NAME);
+diff -Nur linux-2.6.37.orig/drivers/mtd/maps/Kconfig linux-2.6.37/drivers/mtd/maps/Kconfig
+--- linux-2.6.37.orig/drivers/mtd/maps/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/mtd/maps/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -260,6 +260,13 @@
+ Support for parsing CFE image tag and creating MTD partitions on
+ Broadcom BCM63xx boards.
+
++config MTD_AR91XX_FLASH
++ tristate "Atheros AR91xx parallel flash support"
++ depends on ATHEROS_AR71XX
++ select MTD_COMPLEX_MAPPINGS
++ help
++ Parallel flash driver for the Atheros AR91xx based boards.
++
+ config MTD_DILNETPC
+ tristate "CFI Flash device mapped on DIL/Net PC"
+ depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
+diff -Nur linux-2.6.37.orig/drivers/mtd/maps/Makefile linux-2.6.37/drivers/mtd/maps/Makefile
+--- linux-2.6.37.orig/drivers/mtd/maps/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/mtd/maps/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -7,6 +7,7 @@
+ endif
+
+ # Chip mappings
++obj-$(CONFIG_MTD_AR91XX_FLASH) += ar91xx_flash.o
+ obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
+ obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
+ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
+diff -Nur linux-2.6.37.orig/drivers/mtd/maps/ar91xx_flash.c linux-2.6.37/drivers/mtd/maps/ar91xx_flash.c
+--- linux-2.6.37.orig/drivers/mtd/maps/ar91xx_flash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/mtd/maps/ar91xx_flash.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,310 @@
++/*
++ * Parallel flash driver for the Atheros AR91xx SoC
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <linux/io.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/ar91xx_flash.h>
++
++#define DRV_NAME "ar91xx-flash"
++
++struct ar91xx_flash_info {
++ struct mtd_info *mtd;
++ struct map_info map;
++#ifdef CONFIG_MTD_PARTITIONS
++ int nr_parts;
++ struct mtd_partition *parts;
++#endif
++};
++
++static map_word ar91xx_flash_read(struct map_info *map, unsigned long ofs)
++{
++ map_word val;
++
++ if (map_bankwidth_is_1(map))
++ val.x[0] = __raw_readb(map->virt + (ofs ^ 3));
++ else if (map_bankwidth_is_2(map))
++ val.x[0] = __raw_readw(map->virt + (ofs ^ 2));
++ else
++ val = map_word_ff(map);
++
++ return val;
++}
++
++static void ar91xx_flash_write(struct map_info *map, map_word d,
++ unsigned long ofs)
++{
++ if (map_bankwidth_is_1(map))
++ __raw_writeb(d.x[0], map->virt + (ofs ^ 3));
++ else if (map_bankwidth_is_2(map))
++ __raw_writew(d.x[0], map->virt + (ofs ^ 2));
++
++ mb();
++}
++
++static map_word ar91xx_flash_read_lock(struct map_info *map, unsigned long ofs)
++{
++ map_word ret;
++
++ ar71xx_flash_acquire();
++ ret = ar91xx_flash_read(map, ofs);
++ ar71xx_flash_release();
++
++ return ret;
++}
++
++static void ar91xx_flash_write_lock(struct map_info *map, map_word d,
++ unsigned long ofs)
++{
++ ar71xx_flash_acquire();
++ ar91xx_flash_write(map, d, ofs);
++ ar71xx_flash_release();
++}
++
++static void ar91xx_flash_copy_from_lock(struct map_info *map, void *to,
++ unsigned long from, ssize_t len)
++{
++ ar71xx_flash_acquire();
++ inline_map_copy_from(map, to, from, len);
++ ar71xx_flash_release();
++}
++
++static void ar91xx_flash_copy_to_lock(struct map_info *map, unsigned long to,
++ const void *from, ssize_t len)
++{
++ ar71xx_flash_acquire();
++ inline_map_copy_to(map, to, from, len);
++ ar71xx_flash_release();
++}
++
++static int ar91xx_flash_remove(struct platform_device *pdev)
++{
++ struct ar91xx_flash_platform_data *pdata;
++ struct ar91xx_flash_info *info;
++
++ info = platform_get_drvdata(pdev);
++ if (info == NULL)
++ return 0;
++
++ platform_set_drvdata(pdev, NULL);
++
++ if (info->mtd == NULL)
++ return 0;
++
++ pdata = pdev->dev.platform_data;
++#ifdef CONFIG_MTD_PARTITIONS
++ if (info->nr_parts) {
++ del_mtd_partitions(info->mtd);
++ kfree(info->parts);
++ } else if (pdata->nr_parts) {
++ del_mtd_partitions(info->mtd);
++ } else {
++ del_mtd_device(info->mtd);
++ }
++#else
++ del_mtd_device(info->mtd);
++#endif
++ map_destroy(info->mtd);
++
++ return 0;
++}
++
++static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
++#ifdef CONFIG_MTD_PARTITIONS
++static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
++#endif
++
++static int ar91xx_flash_probe(struct platform_device *pdev)
++{
++ struct ar91xx_flash_platform_data *pdata;
++ struct ar91xx_flash_info *info;
++ struct resource *res;
++ struct resource *region;
++ const char **probe_type;
++ int err = 0;
++
++ pdata = pdev->dev.platform_data;
++ if (pdata == NULL)
++ return -EINVAL;
++
++ info = devm_kzalloc(&pdev->dev, sizeof(struct ar91xx_flash_info),
++ GFP_KERNEL);
++ if (info == NULL) {
++ err = -ENOMEM;
++ goto err_out;
++ }
++
++ platform_set_drvdata(pdev, info);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (res == NULL) {
++ err = -ENOENT;
++ goto err_out;
++ }
++
++ dev_info(&pdev->dev, "%.8llx at %.8llx\n",
++ (unsigned long long)(res->end - res->start + 1),
++ (unsigned long long)res->start);
++
++ region = devm_request_mem_region(&pdev->dev,
++ res->start, res->end - res->start + 1,
++ dev_name(&pdev->dev));
++ if (region == NULL) {
++ dev_err(&pdev->dev, "could not reserve memory region\n");
++ err = -ENOMEM;
++ goto err_out;
++ }
++
++ info->map.name = dev_name(&pdev->dev);
++ info->map.phys = res->start;
++ info->map.size = res->end - res->start + 1;
++ info->map.bankwidth = pdata->width;
++
++ info->map.virt = devm_ioremap(&pdev->dev, info->map.phys,
++ info->map.size);
++ if (info->map.virt == NULL) {
++ dev_err(&pdev->dev, "failed to ioremap flash region\n");
++ err = -EIO;
++ goto err_out;
++ }
++
++ simple_map_init(&info->map);
++ if (pdata->is_shared) {
++ info->map.read = ar91xx_flash_read_lock;
++ info->map.write = ar91xx_flash_write_lock;
++ info->map.copy_from = ar91xx_flash_copy_from_lock;
++ info->map.copy_to = ar91xx_flash_copy_to_lock;
++ } else {
++ info->map.read = ar91xx_flash_read;
++ info->map.write = ar91xx_flash_write;
++ }
++
++ probe_type = rom_probe_types;
++ for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
++ info->mtd = do_map_probe(*probe_type, &info->map);
++
++ if (info->mtd == NULL) {
++ dev_err(&pdev->dev, "map_probe failed\n");
++ err = -ENXIO;
++ goto err_out;
++ }
++
++ info->mtd->owner = THIS_MODULE;
++
++#ifdef CONFIG_MTD_PARTITIONS
++ if (pdata->nr_parts) {
++ dev_info(&pdev->dev, "using static partition mapping\n");
++ add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts);
++ return 0;
++ }
++
++ err = parse_mtd_partitions(info->mtd, part_probe_types,
++ &info->parts, 0);
++ if (err > 0) {
++ add_mtd_partitions(info->mtd, info->parts, err);
++ return 0;
++ }
++#endif
++
++ add_mtd_device(info->mtd);
++ return 0;
++
++ err_out:
++ ar91xx_flash_remove(pdev);
++ return err;
++}
++
++#ifdef CONFIG_PM
++static int ar91xx_flash_suspend(struct platform_device *dev, pm_message_t state)
++{
++ struct ar91xx_flash_info *info = platform_get_drvdata(dev);
++ int ret = 0;
++
++ if (info->mtd->suspend)
++ ret = info->mtd->suspend(info->mtd);
++
++ if (ret)
++ goto fail;
++
++ return 0;
++
++ fail:
++ if (info->mtd->suspend) {
++ BUG_ON(!info->mtd->resume);
++ info->mtd->resume(info->mtd);
++ }
++
++ return ret;
++}
++
++static int ar91xx_flash_resume(struct platform_device *pdev)
++{
++ struct ar91xx_flash_info *info = platform_get_drvdata(pdev);
++
++ if (info->mtd->resume)
++ info->mtd->resume(info->mtd);
++
++ return 0;
++}
++
++static void ar91xx_flash_shutdown(struct platform_device *pdev)
++{
++ struct ar91xx_flash_info *info = platform_get_drvdata(pdev);
++
++ if (info->mtd->suspend && info->mtd->resume)
++ if (info->mtd->suspend(info->mtd) == 0)
++ info->mtd->resume(info->mtd);
++}
++#else
++#define ar91xx_flash_suspend NULL
++#define ar91xx_flash_resume NULL
++#define ar91xx_flash_shutdown NULL
++#endif
++
++static struct platform_driver ar91xx_flash_driver = {
++ .probe = ar91xx_flash_probe,
++ .remove = ar91xx_flash_remove,
++ .suspend = ar91xx_flash_suspend,
++ .resume = ar91xx_flash_resume,
++ .shutdown = ar91xx_flash_shutdown,
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init ar91xx_flash_init(void)
++{
++ return platform_driver_register(&ar91xx_flash_driver);
++}
++
++static void __exit ar91xx_flash_exit(void)
++{
++ platform_driver_unregister(&ar91xx_flash_driver);
++}
++
++module_init(ar91xx_flash_init);
++module_exit(ar91xx_flash_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_DESCRIPTION("Parallel flash driver for the Atheros AR91xx SoC");
++MODULE_ALIAS("platform:" DRV_NAME);
+diff -Nur linux-2.6.37.orig/drivers/mtd/nand/Kconfig linux-2.6.37/drivers/mtd/nand/Kconfig
+--- linux-2.6.37.orig/drivers/mtd/nand/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/mtd/nand/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -532,4 +532,8 @@
+ Enables support for NAND Flash chips on the ST Microelectronics
+ Flexible Static Memory Controller (FSMC)
+
++config MTD_NAND_RB4XX
++ tristate "NAND flash driver for RouterBoard 4xx series"
++ depends on MTD_NAND && AR71XX_MACH_RB4XX
++
+ endif # MTD_NAND
+diff -Nur linux-2.6.37.orig/drivers/mtd/nand/Makefile linux-2.6.37/drivers/mtd/nand/Makefile
+--- linux-2.6.37.orig/drivers/mtd/nand/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/mtd/nand/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -33,6 +33,7 @@
+ obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
+ obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
+ obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
++obj-$(CONFIG_MTD_NAND_RB4XX) += rb4xx_nand.o
+ obj-$(CONFIG_MTD_ALAUDA) += alauda.o
+ obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
+ obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
+diff -Nur linux-2.6.37.orig/drivers/mtd/nand/rb4xx_nand.c linux-2.6.37/drivers/mtd/nand/rb4xx_nand.c
+--- linux-2.6.37.orig/drivers/mtd/nand/rb4xx_nand.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/mtd/nand/rb4xx_nand.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,513 @@
++/*
++ * NAND flash driver for the MikroTik RouterBoard 4xx series
++ *
++ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This file was based on the driver for Linux 2.6.22 published by
++ * MikroTik for their RouterBoard 4xx series devices.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++#include <linux/slab.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#define DRV_NAME "rb4xx-nand"
++#define DRV_VERSION "0.1.10"
++#define DRV_DESC "NAND flash driver for RouterBoard 4xx series"
++
++#define USE_FAST_READ 1
++#define USE_FAST_WRITE 1
++#undef RB4XX_NAND_DEBUG
++
++#ifdef RB4XX_NAND_DEBUG
++#define DBG(fmt, arg...) printk(KERN_DEBUG DRV_NAME ": " fmt, ## arg)
++#else
++#define DBG(fmt, arg...) do {} while (0)
++#endif
++
++#define RB4XX_NAND_GPIO_RDY 5
++#define RB4XX_FLASH_HZ 33333334
++#define RB4XX_NAND_HZ 33333334
++
++#define SPI_CTRL_FASTEST 0x40
++#define SPI_CTRL_SAFE 0x43 /* 25 MHz for AHB 200 MHz */
++#define SBIT_IOC_BASE SPI_IOC_CS1
++#define SBIT_IOC_DO_SHIFT 0
++#define SBIT_IOC_DO (1u << SBIT_IOC_DO_SHIFT)
++#define SBIT_IOC_DO2_SHIFT 18
++#define SBIT_IOC_DO2 (1u << SBIT_IOC_DO2_SHIFT)
++
++#define CPLD_CMD_WRITE_MULT 0x08 /* send cmd, n x send data, read data */
++#define CPLD_CMD_WRITE_CFG 0x09 /* send cmd, n x send cfg */
++#define CPLD_CMD_READ_MULT 0x0a /* send cmd, send idle, n x read data */
++#define CPLD_CMD_READ_FAST 0x0b /* send cmd, 4 x idle, n x read data */
++
++#define CFG_BIT_nCE 0x80
++#define CFG_BIT_CLE 0x40
++#define CFG_BIT_ALE 0x20
++#define CFG_BIT_FAN 0x10
++#define CFG_BIT_nLED4 0x08
++#define CFG_BIT_nLED3 0x04
++#define CFG_BIT_nLED2 0x02
++#define CFG_BIT_nLED1 0x01
++
++#define CFG_BIT_nLEDS \
++ (CFG_BIT_nLED1 | CFG_BIT_nLED2 | CFG_BIT_nLED3 | CFG_BIT_nLED4)
++
++struct rb4xx_nand_info {
++ struct nand_chip chip;
++ struct mtd_info mtd;
++};
++
++/*
++ * We need to use the OLD Yaffs-1 OOB layout, otherwise the RB bootloader
++ * will not be able to find the kernel that we load.
++ */
++static struct nand_ecclayout rb4xx_nand_ecclayout = {
++ .eccbytes = 6,
++ .eccpos = { 8, 9, 10, 13, 14, 15 },
++ .oobavail = 9,
++ .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
++};
++
++static struct mtd_partition rb4xx_nand_partitions[] = {
++ {
++ .name = "booter",
++ .offset = 0,
++ .size = (256 * 1024),
++ .mask_flags = MTD_WRITEABLE,
++ },
++ {
++ .name = "kernel",
++ .offset = (256 * 1024),
++ .size = (4 * 1024 * 1024) - (256 * 1024),
++ },
++ {
++ .name = "rootfs",
++ .offset = MTDPART_OFS_NXTBLK,
++ .size = (1024*1024*64) - (1024*256) - (4 * 1024 * 1024)
++ },
++ {
++ .name = "cfgfs",
++ .offset = (1024*1024*64) - (1024*256),
++ .size = (1024*256),
++ },
++};
++
++#if USE_FAST_READ
++#define SPI_NDATA_BASE 0x00800000
++static unsigned spi_ctrl_fread = SPI_CTRL_SAFE;
++static unsigned spi_ctrl_flash = SPI_CTRL_SAFE;
++extern unsigned mips_hpt_frequency;
++#endif
++
++static inline unsigned rb4xx_spi_rreg(unsigned r)
++{
++ return __raw_readl((void * __iomem)(KSEG1ADDR(AR71XX_SPI_BASE) + r));
++}
++
++static inline void rb4xx_spi_wreg(unsigned r, unsigned v)
++{
++ __raw_writel(v, (void * __iomem)(KSEG1ADDR(AR71XX_SPI_BASE) + r));
++}
++
++static inline void do_spi_clk(int bit)
++{
++ unsigned bval = SBIT_IOC_BASE | (bit & 1);
++
++ rb4xx_spi_wreg(SPI_REG_IOC, bval);
++ rb4xx_spi_wreg(SPI_REG_IOC, bval | SPI_IOC_CLK);
++}
++
++static void do_spi_byte(uint8_t byte)
++{
++ do_spi_clk(byte >> 7);
++ do_spi_clk(byte >> 6);
++ do_spi_clk(byte >> 5);
++ do_spi_clk(byte >> 4);
++ do_spi_clk(byte >> 3);
++ do_spi_clk(byte >> 2);
++ do_spi_clk(byte >> 1);
++ do_spi_clk(byte);
++
++ DBG("spi_byte sent 0x%02x got 0x%x\n",
++ byte, rb4xx_spi_rreg(SPI_REG_RDS));
++}
++
++#if USE_FAST_WRITE
++static inline void do_spi_clk_fast(int bit1, int bit2)
++{
++ unsigned bval = (SBIT_IOC_BASE |
++ ((bit1 << SBIT_IOC_DO_SHIFT) & SBIT_IOC_DO) |
++ ((bit2 << SBIT_IOC_DO2_SHIFT) & SBIT_IOC_DO2));
++
++ rb4xx_spi_wreg(SPI_REG_IOC, bval);
++ rb4xx_spi_wreg(SPI_REG_IOC, bval | SPI_IOC_CLK);
++}
++
++static inline void do_spi_byte_fast(uint8_t byte)
++{
++ do_spi_clk_fast(byte >> 7, byte >> 6);
++ do_spi_clk_fast(byte >> 5, byte >> 4);
++ do_spi_clk_fast(byte >> 3, byte >> 2);
++ do_spi_clk_fast(byte >> 1, byte >> 0);
++
++ DBG("spi_byte_fast sent 0x%02x got 0x%x\n",
++ byte, rb4xx_spi_rreg(SPI_REG_RDS));
++}
++#else
++static inline void do_spi_byte_fast(uint8_t byte)
++{
++ do_spi_byte(byte);
++}
++#endif /* USE_FAST_WRITE */
++
++static int do_spi_cmd(unsigned cmd, unsigned sendCnt, const uint8_t *sendData,
++ unsigned recvCnt, uint8_t *recvData,
++ const uint8_t *verifyData, int fastWrite)
++{
++ unsigned i;
++
++ DBG("SPI cmd 0x%x send %u recv %u\n", cmd, sendCnt, recvCnt);
++
++ rb4xx_spi_wreg(SPI_REG_FS, SPI_FS_GPIO);
++ rb4xx_spi_wreg(SPI_REG_CTRL, SPI_CTRL_FASTEST);
++
++ do_spi_byte(cmd);
++#if 0
++ if (cmd == CPLD_CMD_READ_FAST) {
++ do_spi_byte(0x80);
++ do_spi_byte(0);
++ do_spi_byte(0);
++ }
++#endif
++ for (i = 0; i < sendCnt; ++i) {
++ if (fastWrite)
++ do_spi_byte_fast(sendData[i]);
++ else
++ do_spi_byte(sendData[i]);
++ }
++
++ for (i = 0; i < recvCnt; ++i) {
++ if (fastWrite)
++ do_spi_byte_fast(0);
++ else
++ do_spi_byte(0);
++
++ if (recvData) {
++ recvData[i] = rb4xx_spi_rreg(SPI_REG_RDS) & 0xff;
++ } else if (verifyData) {
++ if (verifyData[i] != (rb4xx_spi_rreg(SPI_REG_RDS)
++ & 0xff))
++ break;
++ }
++ }
++
++ rb4xx_spi_wreg(SPI_REG_IOC, SBIT_IOC_BASE | SPI_IOC_CS0);
++ rb4xx_spi_wreg(SPI_REG_CTRL, spi_ctrl_flash);
++ rb4xx_spi_wreg(SPI_REG_FS, 0);
++
++ return i == recvCnt;
++}
++
++static int got_write = 1;
++
++static void rb4xx_nand_write_data(const uint8_t *byte, unsigned cnt)
++{
++ do_spi_cmd(CPLD_CMD_WRITE_MULT, cnt, byte, 1, NULL, NULL, 1);
++ got_write = 1;
++}
++
++static void rb4xx_nand_write_byte(uint8_t byte)
++{
++ rb4xx_nand_write_data(&byte, 1);
++}
++
++#if USE_FAST_READ
++static uint8_t *rb4xx_nand_read_getaddr(unsigned cnt)
++{
++ static unsigned nboffset = 0x100000;
++ unsigned addr;
++
++ if (got_write) {
++ nboffset = (nboffset + 31) & ~31;
++ if (nboffset >= 0x100000) /* 1MB */
++ nboffset = 0;
++
++ got_write = 0;
++ rb4xx_spi_wreg(SPI_REG_FS, SPI_FS_GPIO);
++ rb4xx_spi_wreg(SPI_REG_CTRL, spi_ctrl_fread);
++ rb4xx_spi_wreg(SPI_REG_FS, 0);
++ }
++
++ addr = KSEG1ADDR(AR71XX_SPI_BASE + SPI_NDATA_BASE) + nboffset;
++ DBG("rb4xx_nand_read_getaddr 0x%x cnt 0x%x\n", addr, cnt);
++
++ nboffset += cnt;
++ return (uint8_t *)addr;
++}
++
++static void rb4xx_nand_read_data(uint8_t *buf, unsigned cnt)
++{
++ unsigned size32 = cnt & ~31;
++ unsigned remain = cnt & 31;
++
++ if (size32) {
++ uint8_t *addr = rb4xx_nand_read_getaddr(size32);
++ memcpy(buf, (void *)addr, size32);
++ }
++
++ if (remain) {
++ do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, remain,
++ buf + size32, NULL, 0);
++ }
++}
++
++static int rb4xx_nand_verify_data(const uint8_t *buf, unsigned cnt)
++{
++ unsigned size32 = cnt & ~31;
++ unsigned remain = cnt & 31;
++
++ if (size32) {
++ uint8_t *addr = rb4xx_nand_read_getaddr(size32);
++ if (memcmp(buf, (void *)addr, size32) != 0)
++ return 0;
++ }
++
++ if (remain) {
++ return do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, remain,
++ NULL, buf + size32, 0);
++ }
++ return 1;
++}
++#else /* USE_FAST_READ */
++static void rb4xx_nand_read_data(uint8_t *buf, unsigned cnt)
++{
++ do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, cnt, buf, NULL, 0);
++}
++
++static int rb4xx_nand_verify_data(const uint8_t *buf, unsigned cnt)
++{
++ return do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, cnt, NULL, buf, 0);
++}
++#endif /* USE_FAST_READ */
++
++static void rb4xx_nand_write_cfg(uint8_t byte)
++{
++ do_spi_cmd(CPLD_CMD_WRITE_CFG, 1, &byte, 0, NULL, NULL, 0);
++ got_write = 1;
++}
++
++static int rb4xx_nand_dev_ready(struct mtd_info *mtd)
++{
++ return gpio_get_value(RB4XX_NAND_GPIO_RDY);
++}
++
++static void rb4xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
++ unsigned int ctrl)
++{
++ if (ctrl & NAND_CTRL_CHANGE) {
++ uint8_t cfg = CFG_BIT_nLEDS;
++
++ cfg |= (ctrl & NAND_CLE) ? CFG_BIT_CLE : 0;
++ cfg |= (ctrl & NAND_ALE) ? CFG_BIT_ALE : 0;
++ cfg |= (ctrl & NAND_NCE) ? 0 : CFG_BIT_nCE;
++
++ rb4xx_nand_write_cfg(cfg);
++ }
++
++ if (cmd != NAND_CMD_NONE)
++ rb4xx_nand_write_byte(cmd);
++}
++
++static uint8_t rb4xx_nand_read_byte(struct mtd_info *mtd)
++{
++ uint8_t byte = 0;
++
++ rb4xx_nand_read_data(&byte, 1);
++ return byte;
++}
++
++static void rb4xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
++ int len)
++{
++ rb4xx_nand_write_data(buf, len);
++}
++
++static void rb4xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf,
++ int len)
++{
++ rb4xx_nand_read_data(buf, len);
++}
++
++static int rb4xx_nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf,
++ int len)
++{
++ if (!rb4xx_nand_verify_data(buf, len))
++ return -EFAULT;
++
++ return 0;
++}
++
++static unsigned get_spi_ctrl(unsigned hz_max, const char *name)
++{
++ unsigned div;
++
++ div = (ar71xx_ahb_freq - 1) / (2 * hz_max);
++ /*
++ * CPU has a bug at (div == 0) - first bit read is random
++ */
++ if (div == 0)
++ ++div;
++
++ if (name) {
++ unsigned ahb_khz = (ar71xx_ahb_freq + 500) / 1000;
++ unsigned div_real = 2 * (div + 1);
++ printk(KERN_INFO "%s SPI clock %u kHz (AHB %u kHz / %u)\n",
++ name,
++ ahb_khz / div_real,
++ ahb_khz, div_real);
++ }
++
++ return SPI_CTRL_FASTEST + div;
++}
++
++static int __init rb4xx_nand_probe(struct platform_device *pdev)
++{
++ struct rb4xx_nand_info *info;
++ int ret;
++
++ printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
++
++ ret = gpio_request(RB4XX_NAND_GPIO_RDY, "NAND RDY");
++ if (ret) {
++ printk(KERN_ERR "rb4xx-nand: gpio request failed\n");
++ return ret;
++ }
++
++ ret = gpio_direction_input(RB4XX_NAND_GPIO_RDY);
++ if (ret) {
++ printk(KERN_ERR "rb4xx-nand: unable to set input mode "
++ "on gpio%d\n", RB4XX_NAND_GPIO_RDY);
++ goto err_free_gpio;
++ }
++
++ info = kzalloc(sizeof(*info), GFP_KERNEL);
++ if (!info) {
++ printk(KERN_ERR "rb4xx-nand: no memory for private data\n");
++ ret = -ENOMEM;
++ goto err_free_gpio;
++ }
++
++#if USE_FAST_READ
++ spi_ctrl_fread = get_spi_ctrl(RB4XX_NAND_HZ, "NAND");
++#endif
++ spi_ctrl_flash = get_spi_ctrl(RB4XX_FLASH_HZ, "FLASH");
++
++ rb4xx_nand_write_cfg(CFG_BIT_nLEDS | CFG_BIT_nCE);
++
++ info->chip.priv = &info;
++ info->mtd.priv = &info->chip;
++ info->mtd.owner = THIS_MODULE;
++
++ info->chip.cmd_ctrl = rb4xx_nand_cmd_ctrl;
++ info->chip.dev_ready = rb4xx_nand_dev_ready;
++ info->chip.read_byte = rb4xx_nand_read_byte;
++ info->chip.write_buf = rb4xx_nand_write_buf;
++ info->chip.read_buf = rb4xx_nand_read_buf;
++ info->chip.verify_buf = rb4xx_nand_verify_buf;
++
++ info->chip.chip_delay = 25;
++ info->chip.ecc.mode = NAND_ECC_SOFT;
++ info->chip.options |= NAND_NO_AUTOINCR;
++
++ platform_set_drvdata(pdev, info);
++
++ ret = nand_scan_ident(&info->mtd, 1, NULL);
++ if (ret) {
++ ret = -ENXIO;
++ goto err_free_info;
++ }
++
++ if (info->mtd.writesize == 512)
++ info->chip.ecc.layout = &rb4xx_nand_ecclayout;
++
++ ret = nand_scan_tail(&info->mtd);
++ if (ret) {
++ return -ENXIO;
++ goto err_set_drvdata;
++ }
++
++#ifdef CONFIG_MTD_PARTITIONS
++ ret = add_mtd_partitions(&info->mtd, rb4xx_nand_partitions,
++ ARRAY_SIZE(rb4xx_nand_partitions));
++#else
++ ret = add_mtd_device(&info->mtd);
++#endif
++ if (ret)
++ goto err_release_nand;
++
++ return 0;
++
++err_release_nand:
++ nand_release(&info->mtd);
++err_set_drvdata:
++ platform_set_drvdata(pdev, NULL);
++err_free_info:
++ kfree(info);
++err_free_gpio:
++ gpio_free(RB4XX_NAND_GPIO_RDY);
++ return ret;
++}
++
++static int __devexit rb4xx_nand_remove(struct platform_device *pdev)
++{
++ struct rb4xx_nand_info *info = platform_get_drvdata(pdev);
++
++ nand_release(&info->mtd);
++ platform_set_drvdata(pdev, NULL);
++ kfree(info);
++
++ return 0;
++}
++
++static struct platform_driver rb4xx_nand_driver = {
++ .probe = rb4xx_nand_probe,
++ .remove = __devexit_p(rb4xx_nand_remove),
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init rb4xx_nand_init(void)
++{
++ return platform_driver_register(&rb4xx_nand_driver);
++}
++
++static void __exit rb4xx_nand_exit(void)
++{
++ platform_driver_unregister(&rb4xx_nand_driver);
++}
++
++module_init(rb4xx_nand_init);
++module_exit(rb4xx_nand_exit);
++
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.37.orig/drivers/mtd/nand/rb750_nand.c linux-2.6.37/drivers/mtd/nand/rb750_nand.c
+--- linux-2.6.37.orig/drivers/mtd/nand/rb750_nand.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/mtd/nand/rb750_nand.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,360 @@
++/*
++ * NAND flash driver for the MikroTik RouterBOARD 750
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/mach-rb750.h>
++
++#define DRV_NAME "rb750-nand"
++#define DRV_VERSION "0.1.0"
++#define DRV_DESC "NAND flash driver for the RouterBOARD 750"
++
++#define RB750_NAND_IO0 BIT(RB750_GPIO_NAND_IO0)
++#define RB750_NAND_ALE BIT(RB750_GPIO_NAND_ALE)
++#define RB750_NAND_CLE BIT(RB750_GPIO_NAND_CLE)
++#define RB750_NAND_NRE BIT(RB750_GPIO_NAND_NRE)
++#define RB750_NAND_NWE BIT(RB750_GPIO_NAND_NWE)
++#define RB750_NAND_RDY BIT(RB750_GPIO_NAND_RDY)
++#define RB750_NAND_NCE BIT(RB750_GPIO_NAND_NCE)
++
++#define RB750_NAND_DATA_SHIFT 1
++#define RB750_NAND_DATA_BITS (0xff << RB750_NAND_DATA_SHIFT)
++#define RB750_NAND_INPUT_BITS (RB750_NAND_DATA_BITS | RB750_NAND_RDY)
++#define RB750_NAND_OUTPUT_BITS (RB750_NAND_ALE | RB750_NAND_CLE | \
++ RB750_NAND_NRE | RB750_NAND_NWE | \
++ RB750_NAND_NCE)
++
++struct rb750_nand_info {
++ struct nand_chip chip;
++ struct mtd_info mtd;
++};
++
++/*
++ * We need to use the OLD Yaffs-1 OOB layout, otherwise the RB bootloader
++ * will not be able to find the kernel that we load.
++ */
++static struct nand_ecclayout rb750_nand_ecclayout = {
++ .eccbytes = 6,
++ .eccpos = { 8, 9, 10, 13, 14, 15 },
++ .oobavail = 9,
++ .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
++};
++
++static struct mtd_partition rb750_nand_partitions[] = {
++ {
++ .name = "booter",
++ .offset = 0,
++ .size = (256 * 1024),
++ .mask_flags = MTD_WRITEABLE,
++ }, {
++ .name = "kernel",
++ .offset = (256 * 1024),
++ .size = (4 * 1024 * 1024) - (256 * 1024),
++ }, {
++ .name = "rootfs",
++ .offset = MTDPART_OFS_NXTBLK,
++ .size = MTDPART_SIZ_FULL,
++ },
++};
++
++static void rb750_nand_write(const u8 *buf, unsigned len)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ u32 out;
++ unsigned i;
++
++ /* set data lines to output mode */
++ __raw_writel(__raw_readl(base + GPIO_REG_OE) | RB750_NAND_DATA_BITS,
++ base + GPIO_REG_OE);
++
++ out = __raw_readl(base + GPIO_REG_OUT);
++ out &= ~(RB750_NAND_DATA_BITS | RB750_NAND_NWE);
++ for (i = 0; i != len; i++) {
++ u32 data;
++
++ data = buf[i];
++ data <<= RB750_NAND_DATA_SHIFT;
++ data |= out;
++ __raw_writel(data, base + GPIO_REG_OUT);
++
++ __raw_writel(data | RB750_NAND_NWE, base + GPIO_REG_OUT);
++ /* flush write */
++ __raw_readl(base + GPIO_REG_OUT);
++ }
++
++ /* set data lines to input mode */
++ __raw_writel(__raw_readl(base + GPIO_REG_OE) & ~RB750_NAND_DATA_BITS,
++ base + GPIO_REG_OE);
++ /* flush write */
++ __raw_readl(base + GPIO_REG_OE);
++}
++
++static int rb750_nand_read_verify(u8 *read_buf, unsigned len,
++ const u8 *verify_buf)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ unsigned i;
++
++ for (i = 0; i < len; i++) {
++ u8 data;
++
++ /* activate RE line */
++ __raw_writel(RB750_NAND_NRE, base + GPIO_REG_CLEAR);
++ /* flush write */
++ __raw_readl(base + GPIO_REG_CLEAR);
++
++ /* read input lines */
++ data = __raw_readl(base + GPIO_REG_IN) >> RB750_NAND_DATA_SHIFT;
++
++ /* deactivate RE line */
++ __raw_writel(RB750_NAND_NRE, base + GPIO_REG_SET);
++
++ if (read_buf)
++ read_buf[i] = data;
++ else if (verify_buf && verify_buf[i] != data)
++ return -EFAULT;
++ }
++
++ return 0;
++}
++
++static void rb750_nand_select_chip(struct mtd_info *mtd, int chip)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ u32 func;
++
++ func = __raw_readl(base + GPIO_REG_FUNC);
++ if (chip >= 0) {
++ /* disable latch */
++ rb750_latch_change(RB750_LVC573_LE, 0);
++
++ /* disable alternate functions */
++ ar71xx_gpio_function_setup(AR724X_GPIO_FUNC_JTAG_DISABLE,
++ AR724X_GPIO_FUNC_SPI_EN);
++
++ /* set input mode for data lines */
++ __raw_writel(__raw_readl(base + GPIO_REG_OE) &
++ ~RB750_NAND_INPUT_BITS,
++ base + GPIO_REG_OE);
++
++ /* deactivate RE and WE lines */
++ __raw_writel(RB750_NAND_NRE | RB750_NAND_NWE,
++ base + GPIO_REG_SET);
++ /* flush write */
++ (void) __raw_readl(base + GPIO_REG_SET);
++
++ /* activate CE line */
++ __raw_writel(RB750_NAND_NCE, base + GPIO_REG_CLEAR);
++ } else {
++ /* deactivate CE line */
++ __raw_writel(RB750_NAND_NCE, base + GPIO_REG_SET);
++ /* flush write */
++ (void) __raw_readl(base + GPIO_REG_SET);
++
++ __raw_writel(__raw_readl(base + GPIO_REG_OE) |
++ RB750_NAND_IO0 | RB750_NAND_RDY,
++ base + GPIO_REG_OE);
++
++ /* restore alternate functions */
++ ar71xx_gpio_function_setup(AR724X_GPIO_FUNC_SPI_EN,
++ AR724X_GPIO_FUNC_JTAG_DISABLE);
++
++ /* enable latch */
++ rb750_latch_change(0, RB750_LVC573_LE);
++ }
++}
++
++static int rb750_nand_dev_ready(struct mtd_info *mtd)
++{
++ void __iomem *base = ar71xx_gpio_base;
++
++ return !!(__raw_readl(base + GPIO_REG_IN) & RB750_NAND_RDY);
++}
++
++static void rb750_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
++ unsigned int ctrl)
++{
++ if (ctrl & NAND_CTRL_CHANGE) {
++ void __iomem *base = ar71xx_gpio_base;
++ u32 t;
++
++ t = __raw_readl(base + GPIO_REG_OUT);
++
++ t &= ~(RB750_NAND_CLE | RB750_NAND_ALE);
++ t |= (ctrl & NAND_CLE) ? RB750_NAND_CLE : 0;
++ t |= (ctrl & NAND_ALE) ? RB750_NAND_ALE : 0;
++
++ __raw_writel(t, base + GPIO_REG_OUT);
++ /* flush write */
++ __raw_readl(base + GPIO_REG_OUT);
++ }
++
++ if (cmd != NAND_CMD_NONE) {
++ u8 t = cmd;
++ rb750_nand_write(&t, 1);
++ }
++}
++
++static u8 rb750_nand_read_byte(struct mtd_info *mtd)
++{
++ u8 data = 0;
++ rb750_nand_read_verify(&data, 1, NULL);
++ return data;
++}
++
++static void rb750_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
++{
++ rb750_nand_read_verify(buf, len, NULL);
++}
++
++static void rb750_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
++{
++ rb750_nand_write(buf, len);
++}
++
++static int rb750_nand_verify_buf(struct mtd_info *mtd, const u8 *buf, int len)
++{
++ return rb750_nand_read_verify(NULL, len, buf);
++}
++
++static void __init rb750_nand_gpio_init(void)
++{
++ void __iomem *base = ar71xx_gpio_base;
++ u32 out;
++
++ out = __raw_readl(base + GPIO_REG_OUT);
++
++ /* setup output levels */
++ __raw_writel(RB750_NAND_NCE | RB750_NAND_NRE | RB750_NAND_NWE,
++ base + GPIO_REG_SET);
++
++ __raw_writel(RB750_NAND_ALE | RB750_NAND_CLE,
++ base + GPIO_REG_CLEAR);
++
++ /* setup input lines */
++ __raw_writel(__raw_readl(base + GPIO_REG_OE) & ~(RB750_NAND_INPUT_BITS),
++ base + GPIO_REG_OE);
++
++ /* setup output lines */
++ __raw_writel(__raw_readl(base + GPIO_REG_OE) | RB750_NAND_OUTPUT_BITS,
++ base + GPIO_REG_OE);
++
++ rb750_latch_change(~out & RB750_NAND_IO0, out & RB750_NAND_IO0);
++}
++
++static int __init rb750_nand_probe(struct platform_device *pdev)
++{
++ struct rb750_nand_info *info;
++ int ret;
++
++ printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
++
++ rb750_nand_gpio_init();
++
++ info = kzalloc(sizeof(*info), GFP_KERNEL);
++ if (!info)
++ return -ENOMEM;
++
++ info->chip.priv = &info;
++ info->mtd.priv = &info->chip;
++ info->mtd.owner = THIS_MODULE;
++
++ info->chip.select_chip = rb750_nand_select_chip;
++ info->chip.cmd_ctrl = rb750_nand_cmd_ctrl;
++ info->chip.dev_ready = rb750_nand_dev_ready;
++ info->chip.read_byte = rb750_nand_read_byte;
++ info->chip.write_buf = rb750_nand_write_buf;
++ info->chip.read_buf = rb750_nand_read_buf;
++ info->chip.verify_buf = rb750_nand_verify_buf;
++
++ info->chip.chip_delay = 25;
++ info->chip.ecc.mode = NAND_ECC_SOFT;
++ info->chip.options |= NAND_NO_AUTOINCR;
++
++ platform_set_drvdata(pdev, info);
++
++ ret = nand_scan_ident(&info->mtd, 1);
++ if (ret) {
++ ret = -ENXIO;
++ goto err_free_info;
++ }
++
++ if (info->mtd.writesize == 512)
++ info->chip.ecc.layout = &rb750_nand_ecclayout;
++
++ ret = nand_scan_tail(&info->mtd);
++ if (ret) {
++ return -ENXIO;
++ goto err_set_drvdata;
++ }
++
++#ifdef CONFIG_MTD_PARTITIONS
++ ret = add_mtd_partitions(&info->mtd, rb750_nand_partitions,
++ ARRAY_SIZE(rb750_nand_partitions));
++#else
++ ret = add_mtd_device(&info->mtd);
++#endif
++ if (ret)
++ goto err_release_nand;
++
++ return 0;
++
++ err_release_nand:
++ nand_release(&info->mtd);
++ err_set_drvdata:
++ platform_set_drvdata(pdev, NULL);
++ err_free_info:
++ kfree(info);
++ return ret;
++}
++
++static int __devexit rb750_nand_remove(struct platform_device *pdev)
++{
++ struct rb750_nand_info *info = platform_get_drvdata(pdev);
++
++ nand_release(&info->mtd);
++ platform_set_drvdata(pdev, NULL);
++ kfree(info);
++
++ return 0;
++}
++
++static struct platform_driver rb750_nand_driver = {
++ .probe = rb750_nand_probe,
++ .remove = __devexit_p(rb750_nand_remove),
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init rb750_nand_init(void)
++{
++ return platform_driver_register(&rb750_nand_driver);
++}
++
++static void __exit rb750_nand_exit(void)
++{
++ platform_driver_unregister(&rb750_nand_driver);
++}
++
++module_init(rb750_nand_init);
++module_exit(rb750_nand_exit);
++
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.37.orig/drivers/mtd/wrt160nl_part.c linux-2.6.37/drivers/mtd/wrt160nl_part.c
+--- linux-2.6.37.orig/drivers/mtd/wrt160nl_part.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/mtd/wrt160nl_part.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,181 @@
++/*
++ * Copyright (C) 2009 Christian Daniel <cd@maintech.de>
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * 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
++ *
++ * TRX flash partition table.
++ * Based on ar7 map by Felix Fietkau <nbd@openwrt.org>
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++struct cybertan_header {
++ char magic[4];
++ u8 res1[4];
++ char fw_date[3];
++ char fw_ver[3];
++ char id[4];
++ char hw_ver;
++ char unused;
++ u8 flags[2];
++ u8 res2[10];
++};
++
++#define TRX_PARTS 6
++#define TRX_MAGIC 0x30524448
++#define TRX_MAX_OFFSET 3
++
++struct trx_header {
++ uint32_t magic; /* "HDR0" */
++ uint32_t len; /* Length of file including header */
++ uint32_t crc32; /* 32-bit CRC from flag_version to end of file */
++ uint32_t flag_version; /* 0:15 flags, 16:31 version */
++ uint32_t offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
++};
++
++#define IH_MAGIC 0x27051956 /* Image Magic Number */
++#define IH_NMLEN 32 /* Image Name Length */
++
++struct uimage_header {
++ uint32_t ih_magic; /* Image Header Magic Number */
++ uint32_t ih_hcrc; /* Image Header CRC Checksum */
++ uint32_t ih_time; /* Image Creation Timestamp */
++ uint32_t ih_size; /* Image Data Size */
++ uint32_t ih_load; /* Data» Load Address */
++ uint32_t ih_ep; /* Entry Point Address */
++ uint32_t ih_dcrc; /* Image Data CRC Checksum */
++ uint8_t ih_os; /* Operating System */
++ uint8_t ih_arch; /* CPU architecture */
++ uint8_t ih_type; /* Image Type */
++ uint8_t ih_comp; /* Compression Type */
++ uint8_t ih_name[IH_NMLEN]; /* Image Name */
++};
++
++struct wrt160nl_header {
++ struct cybertan_header cybertan;
++ struct trx_header trx;
++ struct uimage_header uimage;
++} __attribute__ ((packed));
++
++static struct mtd_partition trx_parts[TRX_PARTS];
++
++static int wrt160nl_parse_partitions(struct mtd_info *master,
++ struct mtd_partition **pparts,
++ unsigned long origin)
++{
++ struct wrt160nl_header *header;
++ struct trx_header *theader;
++ struct uimage_header *uheader;
++ size_t retlen;
++ unsigned int kernel_len;
++ int ret;
++
++ header = vmalloc(sizeof(*header));
++ if (!header) {
++ return -ENOMEM;
++ goto out;
++ }
++
++ ret = master->read(master, 4 * master->erasesize, sizeof(*header),
++ &retlen, (void *) header);
++ if (ret)
++ goto free_hdr;
++
++ if (retlen != sizeof(*header)) {
++ ret = -EIO;
++ goto free_hdr;
++ }
++
++ if (strncmp(header->cybertan.magic, "NL16", 4) != 0) {
++ printk(KERN_NOTICE "%s: no WRT160NL signature found\n",
++ master->name);
++ goto free_hdr;
++ }
++
++ theader = &header->trx;
++ if (le32_to_cpu(theader->magic) != TRX_MAGIC) {
++ printk(KERN_NOTICE "%s: no TRX header found\n", master->name);
++ goto free_hdr;
++ }
++
++ uheader = &header->uimage;
++ if (uheader->ih_magic != IH_MAGIC) {
++ printk(KERN_NOTICE "%s: no uImage found\n", master->name);
++ goto free_hdr;
++ }
++
++ kernel_len = le32_to_cpu(theader->offsets[1]) + sizeof(struct cybertan_header);
++
++ trx_parts[0].name = "u-boot";
++ trx_parts[0].offset = 0;
++ trx_parts[0].size = 4 * master->erasesize;
++ trx_parts[0].mask_flags = MTD_WRITEABLE;
++
++ trx_parts[1].name = "kernel";
++ trx_parts[1].offset = trx_parts[0].offset + trx_parts[0].size;
++ trx_parts[1].size = kernel_len;
++ trx_parts[1].mask_flags = 0;
++
++ trx_parts[2].name = "rootfs";
++ trx_parts[2].offset = trx_parts[1].offset + trx_parts[1].size;
++ trx_parts[2].size = master->size - 6 * master->erasesize - trx_parts[1].size;
++ trx_parts[2].mask_flags = 0;
++
++ trx_parts[3].name = "nvram";
++ trx_parts[3].offset = master->size - 2 * master->erasesize;
++ trx_parts[3].size = master->erasesize;
++ trx_parts[3].mask_flags = MTD_WRITEABLE;
++
++ trx_parts[4].name = "art";
++ trx_parts[4].offset = master->size - master->erasesize;
++ trx_parts[4].size = master->erasesize;
++ trx_parts[4].mask_flags = MTD_WRITEABLE;
++
++ trx_parts[5].name = "firmware";
++ trx_parts[5].offset = 4 * master->erasesize;
++ trx_parts[5].size = master->size - 6 * master->erasesize;
++ trx_parts[5].mask_flags = 0;
++
++ *pparts = trx_parts;
++ ret = TRX_PARTS;
++
++ free_hdr:
++ vfree(header);
++ out:
++ return ret;
++}
++
++static struct mtd_part_parser wrt160nl_parser = {
++ .owner = THIS_MODULE,
++ .parse_fn = wrt160nl_parse_partitions,
++ .name = "wrt160nl",
++};
++
++static int __init wrt160nl_parser_init(void)
++{
++ return register_mtd_parser(&wrt160nl_parser);
++}
++
++module_init(wrt160nl_parser_init);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Christian Daniel <cd@maintech.de>");
+diff -Nur linux-2.6.37.orig/drivers/net/Kconfig linux-2.6.37/drivers/net/Kconfig
+--- linux-2.6.37.orig/drivers/net/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/net/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -2068,6 +2068,8 @@
+
+ The safe and default value for this is N.
+
++source drivers/net/ag71xx/Kconfig
++
+ config DL2K
+ tristate "DL2000/TC902x-based Gigabit Ethernet support"
+ depends on PCI
+diff -Nur linux-2.6.37.orig/drivers/net/Makefile linux-2.6.37/drivers/net/Makefile
+--- linux-2.6.37.orig/drivers/net/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/net/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -112,6 +112,7 @@
+ # end link order section
+ #
+
++obj-$(CONFIG_AG71XX) += ag71xx/
+ obj-$(CONFIG_SUNDANCE) += sundance.o
+ obj-$(CONFIG_HAMACHI) += hamachi.o
+ obj-$(CONFIG_NET) += Space.o loopback.o
+diff -Nur linux-2.6.37.orig/drivers/net/ag71xx/Kconfig linux-2.6.37/drivers/net/ag71xx/Kconfig
+--- linux-2.6.37.orig/drivers/net/ag71xx/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/net/ag71xx/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,33 @@
++config AG71XX
++ tristate "Atheros AR71xx built-in ethernet mac support"
++ depends on ATHEROS_AR71XX
++ select PHYLIB
++ help
++ If you wish to compile a kernel for AR71xx/91xx and enable
++ ethernet support, then you should always answer Y to this.
++
++if AG71XX
++
++config AG71XX_DEBUG
++ bool "Atheros AR71xx built-in ethernet driver debugging"
++ default n
++ help
++ Atheros AR71xx built-in ethernet driver debugging messages.
++
++config AG71XX_DEBUG_FS
++ bool "Atheros AR71xx built-in ethernet driver debugfs support"
++ depends on DEBUG_FS
++ default n
++ help
++ Say Y, if you need access to various statistics provided by
++ the ag71xx driver.
++
++config AG71XX_AR8216_SUPPORT
++ bool "special support for the Atheros AR8216 switch"
++ default n
++ default y if AR71XX_MACH_WNR2000 || AR71XX_MACH_MZK_W04NU
++ help
++ Say 'y' here if you want to enable special support for the
++ Atheros AR8216 switch found on some boards.
++
++endif
+diff -Nur linux-2.6.37.orig/drivers/net/ag71xx/Makefile linux-2.6.37/drivers/net/ag71xx/Makefile
+--- linux-2.6.37.orig/drivers/net/ag71xx/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/net/ag71xx/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,14 @@
++#
++# Makefile for the Atheros AR71xx built-in ethernet macs
++#
++
++ag71xx-y += ag71xx_main.o
++ag71xx-y += ag71xx_ethtool.o
++ag71xx-y += ag71xx_phy.o
++ag71xx-y += ag71xx_mdio.o
++
++ag71xx-$(CONFIG_AG71XX_DEBUG_FS) += ag71xx_debugfs.o
++ag71xx-$(CONFIG_AG71XX_AR8216_SUPPORT) += ag71xx_ar8216.o
++
++obj-$(CONFIG_AG71XX) += ag71xx.o
++
+diff -Nur linux-2.6.37.orig/drivers/net/ag71xx/ag71xx.h linux-2.6.37/drivers/net/ag71xx/ag71xx.h
+--- linux-2.6.37.orig/drivers/net/ag71xx/ag71xx.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/net/ag71xx/ag71xx.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,500 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __AG71XX_H
++#define __AG71XX_H
++
++#include <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/random.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/ethtool.h>
++#include <linux/etherdevice.h>
++#include <linux/phy.h>
++#include <linux/skbuff.h>
++#include <linux/dma-mapping.h>
++#include <linux/workqueue.h>
++
++#include <linux/bitops.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/platform.h>
++
++#define ETH_FCS_LEN 4
++
++#define AG71XX_DRV_NAME "ag71xx"
++#define AG71XX_DRV_VERSION "0.5.35"
++
++#define AG71XX_NAPI_WEIGHT 64
++#define AG71XX_OOM_REFILL (1 + HZ/10)
++
++#define AG71XX_INT_ERR (AG71XX_INT_RX_BE | AG71XX_INT_TX_BE)
++#define AG71XX_INT_TX (AG71XX_INT_TX_PS)
++#define AG71XX_INT_RX (AG71XX_INT_RX_PR | AG71XX_INT_RX_OF)
++
++#define AG71XX_INT_POLL (AG71XX_INT_RX | AG71XX_INT_TX)
++#define AG71XX_INT_INIT (AG71XX_INT_ERR | AG71XX_INT_POLL)
++
++#define AG71XX_TX_FIFO_LEN 2048
++#define AG71XX_TX_MTU_LEN 1536
++#define AG71XX_RX_PKT_RESERVE 64
++#define AG71XX_RX_PKT_SIZE \
++ (AG71XX_RX_PKT_RESERVE + ETH_HLEN + ETH_FRAME_LEN + ETH_FCS_LEN)
++
++#define AG71XX_TX_RING_SIZE 64
++#define AG71XX_TX_THRES_STOP (AG71XX_TX_RING_SIZE - 4)
++#define AG71XX_TX_THRES_WAKEUP \
++ (AG71XX_TX_RING_SIZE - (AG71XX_TX_RING_SIZE / 4))
++
++#define AG71XX_RX_RING_SIZE 128
++
++#ifdef CONFIG_AG71XX_DEBUG
++#define DBG(fmt, args...) printk(KERN_DEBUG fmt, ## args)
++#else
++#define DBG(fmt, args...) do {} while (0)
++#endif
++
++#define ag71xx_assert(_cond) \
++do { \
++ if (_cond) \
++ break; \
++ printk("%s,%d: assertion failed\n", __FILE__, __LINE__); \
++ BUG(); \
++} while (0)
++
++struct ag71xx_desc {
++ u32 data;
++ u32 ctrl;
++#define DESC_EMPTY BIT(31)
++#define DESC_MORE BIT(24)
++#define DESC_PKTLEN_M 0xfff
++ u32 next;
++ u32 pad;
++} __attribute__((aligned(4)));
++
++struct ag71xx_buf {
++ struct sk_buff *skb;
++ struct ag71xx_desc *desc;
++ dma_addr_t dma_addr;
++ u32 pad;
++};
++
++struct ag71xx_ring {
++ struct ag71xx_buf *buf;
++ u8 *descs_cpu;
++ dma_addr_t descs_dma;
++ unsigned int desc_size;
++ unsigned int curr;
++ unsigned int dirty;
++ unsigned int size;
++};
++
++struct ag71xx_mdio {
++ struct mii_bus *mii_bus;
++ int mii_irq[PHY_MAX_ADDR];
++ void __iomem *mdio_base;
++ struct ag71xx_mdio_platform_data *pdata;
++};
++
++struct ag71xx_int_stats {
++ unsigned long rx_pr;
++ unsigned long rx_be;
++ unsigned long rx_of;
++ unsigned long tx_ps;
++ unsigned long tx_be;
++ unsigned long tx_ur;
++ unsigned long total;
++};
++
++struct ag71xx_napi_stats {
++ unsigned long napi_calls;
++ unsigned long rx_count;
++ unsigned long rx_packets;
++ unsigned long rx_packets_max;
++ unsigned long tx_count;
++ unsigned long tx_packets;
++ unsigned long tx_packets_max;
++
++ unsigned long rx[AG71XX_NAPI_WEIGHT + 1];
++ unsigned long tx[AG71XX_NAPI_WEIGHT + 1];
++};
++
++struct ag71xx_debug {
++ struct dentry *debugfs_dir;
++ struct dentry *debugfs_int_stats;
++ struct dentry *debugfs_napi_stats;
++
++ struct ag71xx_int_stats int_stats;
++ struct ag71xx_napi_stats napi_stats;
++};
++
++struct ag71xx {
++ void __iomem *mac_base;
++ void __iomem *mii_ctrl;
++
++ spinlock_t lock;
++ struct platform_device *pdev;
++ struct net_device *dev;
++ struct napi_struct napi;
++ u32 msg_enable;
++
++ struct ag71xx_ring rx_ring;
++ struct ag71xx_ring tx_ring;
++
++ struct mii_bus *mii_bus;
++ struct phy_device *phy_dev;
++
++ unsigned int link;
++ unsigned int speed;
++ int duplex;
++
++ struct work_struct restart_work;
++ struct timer_list oom_timer;
++
++#ifdef CONFIG_AG71XX_DEBUG_FS
++ struct ag71xx_debug debug;
++#endif
++};
++
++extern struct ethtool_ops ag71xx_ethtool_ops;
++void ag71xx_link_adjust(struct ag71xx *ag);
++
++int ag71xx_mdio_driver_init(void) __init;
++void ag71xx_mdio_driver_exit(void);
++
++int ag71xx_phy_connect(struct ag71xx *ag);
++void ag71xx_phy_disconnect(struct ag71xx *ag);
++void ag71xx_phy_start(struct ag71xx *ag);
++void ag71xx_phy_stop(struct ag71xx *ag);
++
++static inline struct ag71xx_platform_data *ag71xx_get_pdata(struct ag71xx *ag)
++{
++ return ag->pdev->dev.platform_data;
++}
++
++static inline int ag71xx_desc_empty(struct ag71xx_desc *desc)
++{
++ return ((desc->ctrl & DESC_EMPTY) != 0);
++}
++
++static inline int ag71xx_desc_pktlen(struct ag71xx_desc *desc)
++{
++ return (desc->ctrl & DESC_PKTLEN_M);
++}
++
++/* Register offsets */
++#define AG71XX_REG_MAC_CFG1 0x0000
++#define AG71XX_REG_MAC_CFG2 0x0004
++#define AG71XX_REG_MAC_IPG 0x0008
++#define AG71XX_REG_MAC_HDX 0x000c
++#define AG71XX_REG_MAC_MFL 0x0010
++#define AG71XX_REG_MII_CFG 0x0020
++#define AG71XX_REG_MII_CMD 0x0024
++#define AG71XX_REG_MII_ADDR 0x0028
++#define AG71XX_REG_MII_CTRL 0x002c
++#define AG71XX_REG_MII_STATUS 0x0030
++#define AG71XX_REG_MII_IND 0x0034
++#define AG71XX_REG_MAC_IFCTL 0x0038
++#define AG71XX_REG_MAC_ADDR1 0x0040
++#define AG71XX_REG_MAC_ADDR2 0x0044
++#define AG71XX_REG_FIFO_CFG0 0x0048
++#define AG71XX_REG_FIFO_CFG1 0x004c
++#define AG71XX_REG_FIFO_CFG2 0x0050
++#define AG71XX_REG_FIFO_CFG3 0x0054
++#define AG71XX_REG_FIFO_CFG4 0x0058
++#define AG71XX_REG_FIFO_CFG5 0x005c
++#define AG71XX_REG_FIFO_RAM0 0x0060
++#define AG71XX_REG_FIFO_RAM1 0x0064
++#define AG71XX_REG_FIFO_RAM2 0x0068
++#define AG71XX_REG_FIFO_RAM3 0x006c
++#define AG71XX_REG_FIFO_RAM4 0x0070
++#define AG71XX_REG_FIFO_RAM5 0x0074
++#define AG71XX_REG_FIFO_RAM6 0x0078
++#define AG71XX_REG_FIFO_RAM7 0x007c
++
++#define AG71XX_REG_TX_CTRL 0x0180
++#define AG71XX_REG_TX_DESC 0x0184
++#define AG71XX_REG_TX_STATUS 0x0188
++#define AG71XX_REG_RX_CTRL 0x018c
++#define AG71XX_REG_RX_DESC 0x0190
++#define AG71XX_REG_RX_STATUS 0x0194
++#define AG71XX_REG_INT_ENABLE 0x0198
++#define AG71XX_REG_INT_STATUS 0x019c
++
++#define MAC_CFG1_TXE BIT(0) /* Tx Enable */
++#define MAC_CFG1_STX BIT(1) /* Synchronize Tx Enable */
++#define MAC_CFG1_RXE BIT(2) /* Rx Enable */
++#define MAC_CFG1_SRX BIT(3) /* Synchronize Rx Enable */
++#define MAC_CFG1_TFC BIT(4) /* Tx Flow Control Enable */
++#define MAC_CFG1_RFC BIT(5) /* Rx Flow Control Enable */
++#define MAC_CFG1_LB BIT(8) /* Loopback mode */
++#define MAC_CFG1_SR BIT(31) /* Soft Reset */
++
++#define MAC_CFG2_FDX BIT(0)
++#define MAC_CFG2_CRC_EN BIT(1)
++#define MAC_CFG2_PAD_CRC_EN BIT(2)
++#define MAC_CFG2_LEN_CHECK BIT(4)
++#define MAC_CFG2_HUGE_FRAME_EN BIT(5)
++#define MAC_CFG2_IF_1000 BIT(9)
++#define MAC_CFG2_IF_10_100 BIT(8)
++
++#define FIFO_CFG0_WTM BIT(0) /* Watermark Module */
++#define FIFO_CFG0_RXS BIT(1) /* Rx System Module */
++#define FIFO_CFG0_RXF BIT(2) /* Rx Fabric Module */
++#define FIFO_CFG0_TXS BIT(3) /* Tx System Module */
++#define FIFO_CFG0_TXF BIT(4) /* Tx Fabric Module */
++#define FIFO_CFG0_ALL (FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \
++ | FIFO_CFG0_TXS | FIFO_CFG0_TXF)
++
++#define FIFO_CFG0_ENABLE_SHIFT 8
++
++#define FIFO_CFG4_DE BIT(0) /* Drop Event */
++#define FIFO_CFG4_DV BIT(1) /* RX_DV Event */
++#define FIFO_CFG4_FC BIT(2) /* False Carrier */
++#define FIFO_CFG4_CE BIT(3) /* Code Error */
++#define FIFO_CFG4_CR BIT(4) /* CRC error */
++#define FIFO_CFG4_LM BIT(5) /* Length Mismatch */
++#define FIFO_CFG4_LO BIT(6) /* Length out of range */
++#define FIFO_CFG4_OK BIT(7) /* Packet is OK */
++#define FIFO_CFG4_MC BIT(8) /* Multicast Packet */
++#define FIFO_CFG4_BC BIT(9) /* Broadcast Packet */
++#define FIFO_CFG4_DR BIT(10) /* Dribble */
++#define FIFO_CFG4_LE BIT(11) /* Long Event */
++#define FIFO_CFG4_CF BIT(12) /* Control Frame */
++#define FIFO_CFG4_PF BIT(13) /* Pause Frame */
++#define FIFO_CFG4_UO BIT(14) /* Unsupported Opcode */
++#define FIFO_CFG4_VT BIT(15) /* VLAN tag detected */
++#define FIFO_CFG4_FT BIT(16) /* Frame Truncated */
++#define FIFO_CFG4_UC BIT(17) /* Unicast Packet */
++
++#define FIFO_CFG5_DE BIT(0) /* Drop Event */
++#define FIFO_CFG5_DV BIT(1) /* RX_DV Event */
++#define FIFO_CFG5_FC BIT(2) /* False Carrier */
++#define FIFO_CFG5_CE BIT(3) /* Code Error */
++#define FIFO_CFG5_LM BIT(4) /* Length Mismatch */
++#define FIFO_CFG5_LO BIT(5) /* Length Out of Range */
++#define FIFO_CFG5_OK BIT(6) /* Packet is OK */
++#define FIFO_CFG5_MC BIT(7) /* Multicast Packet */
++#define FIFO_CFG5_BC BIT(8) /* Broadcast Packet */
++#define FIFO_CFG5_DR BIT(9) /* Dribble */
++#define FIFO_CFG5_CF BIT(10) /* Control Frame */
++#define FIFO_CFG5_PF BIT(11) /* Pause Frame */
++#define FIFO_CFG5_UO BIT(12) /* Unsupported Opcode */
++#define FIFO_CFG5_VT BIT(13) /* VLAN tag detected */
++#define FIFO_CFG5_LE BIT(14) /* Long Event */
++#define FIFO_CFG5_FT BIT(15) /* Frame Truncated */
++#define FIFO_CFG5_16 BIT(16) /* unknown */
++#define FIFO_CFG5_17 BIT(17) /* unknown */
++#define FIFO_CFG5_SF BIT(18) /* Short Frame */
++#define FIFO_CFG5_BM BIT(19) /* Byte Mode */
++
++#define AG71XX_INT_TX_PS BIT(0)
++#define AG71XX_INT_TX_UR BIT(1)
++#define AG71XX_INT_TX_BE BIT(3)
++#define AG71XX_INT_RX_PR BIT(4)
++#define AG71XX_INT_RX_OF BIT(6)
++#define AG71XX_INT_RX_BE BIT(7)
++
++#define MAC_IFCTL_SPEED BIT(16)
++
++#define MII_CFG_CLK_DIV_4 0
++#define MII_CFG_CLK_DIV_6 2
++#define MII_CFG_CLK_DIV_8 3
++#define MII_CFG_CLK_DIV_10 4
++#define MII_CFG_CLK_DIV_14 5
++#define MII_CFG_CLK_DIV_20 6
++#define MII_CFG_CLK_DIV_28 7
++#define MII_CFG_RESET BIT(31)
++
++#define MII_CMD_WRITE 0x0
++#define MII_CMD_READ 0x1
++#define MII_ADDR_SHIFT 8
++#define MII_IND_BUSY BIT(0)
++#define MII_IND_INVALID BIT(2)
++
++#define TX_CTRL_TXE BIT(0) /* Tx Enable */
++
++#define TX_STATUS_PS BIT(0) /* Packet Sent */
++#define TX_STATUS_UR BIT(1) /* Tx Underrun */
++#define TX_STATUS_BE BIT(3) /* Bus Error */
++
++#define RX_CTRL_RXE BIT(0) /* Rx Enable */
++
++#define RX_STATUS_PR BIT(0) /* Packet Received */
++#define RX_STATUS_OF BIT(2) /* Rx Overflow */
++#define RX_STATUS_BE BIT(3) /* Bus Error */
++
++#define MII_CTRL_IF_MASK 3
++#define MII_CTRL_SPEED_SHIFT 4
++#define MII_CTRL_SPEED_MASK 3
++#define MII_CTRL_SPEED_10 0
++#define MII_CTRL_SPEED_100 1
++#define MII_CTRL_SPEED_1000 2
++
++static inline void ag71xx_check_reg_offset(struct ag71xx *ag, unsigned reg)
++{
++ switch (reg) {
++ case AG71XX_REG_MAC_CFG1 ... AG71XX_REG_MAC_MFL:
++ case AG71XX_REG_MAC_IFCTL ... AG71XX_REG_INT_STATUS:
++ break;
++
++ default:
++ BUG();
++ }
++}
++
++static inline void ag71xx_wr(struct ag71xx *ag, unsigned reg, u32 value)
++{
++ ag71xx_check_reg_offset(ag, reg);
++
++ __raw_writel(value, ag->mac_base + reg);
++ /* flush write */
++ (void) __raw_readl(ag->mac_base + reg);
++}
++
++static inline u32 ag71xx_rr(struct ag71xx *ag, unsigned reg)
++{
++ ag71xx_check_reg_offset(ag, reg);
++
++ return __raw_readl(ag->mac_base + reg);
++}
++
++static inline void ag71xx_sb(struct ag71xx *ag, unsigned reg, u32 mask)
++{
++ void __iomem *r;
++
++ ag71xx_check_reg_offset(ag, reg);
++
++ r = ag->mac_base + reg;
++ __raw_writel(__raw_readl(r) | mask, r);
++ /* flush write */
++ (void)__raw_readl(r);
++}
++
++static inline void ag71xx_cb(struct ag71xx *ag, unsigned reg, u32 mask)
++{
++ void __iomem *r;
++
++ ag71xx_check_reg_offset(ag, reg);
++
++ r = ag->mac_base + reg;
++ __raw_writel(__raw_readl(r) & ~mask, r);
++ /* flush write */
++ (void) __raw_readl(r);
++}
++
++static inline void ag71xx_int_enable(struct ag71xx *ag, u32 ints)
++{
++ ag71xx_sb(ag, AG71XX_REG_INT_ENABLE, ints);
++}
++
++static inline void ag71xx_int_disable(struct ag71xx *ag, u32 ints)
++{
++ ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints);
++}
++
++static inline void ag71xx_mii_ctrl_wr(struct ag71xx *ag, u32 value)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++ if (pdata->is_ar724x)
++ return;
++
++ __raw_writel(value, ag->mii_ctrl);
++
++ /* flush write */
++ __raw_readl(ag->mii_ctrl);
++}
++
++static inline u32 ag71xx_mii_ctrl_rr(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++ if (pdata->is_ar724x)
++ return 0xffffffff;
++
++ return __raw_readl(ag->mii_ctrl);
++}
++
++static void inline ag71xx_mii_ctrl_set_if(struct ag71xx *ag,
++ unsigned int mii_if)
++{
++ u32 t;
++
++ t = ag71xx_mii_ctrl_rr(ag);
++ t &= ~(MII_CTRL_IF_MASK);
++ t |= (mii_if & MII_CTRL_IF_MASK);
++ ag71xx_mii_ctrl_wr(ag, t);
++}
++
++static void inline ag71xx_mii_ctrl_set_speed(struct ag71xx *ag,
++ unsigned int speed)
++{
++ u32 t;
++
++ t = ag71xx_mii_ctrl_rr(ag);
++ t &= ~(MII_CTRL_SPEED_MASK << MII_CTRL_SPEED_SHIFT);
++ t |= (speed & MII_CTRL_SPEED_MASK) << MII_CTRL_SPEED_SHIFT;
++ ag71xx_mii_ctrl_wr(ag, t);
++}
++
++#ifdef CONFIG_AG71XX_AR8216_SUPPORT
++void ag71xx_add_ar8216_header(struct ag71xx *ag, struct sk_buff *skb);
++int ag71xx_remove_ar8216_header(struct ag71xx *ag, struct sk_buff *skb,
++ int pktlen);
++static inline int ag71xx_has_ar8216(struct ag71xx *ag)
++{
++ return ag71xx_get_pdata(ag)->has_ar8216;
++}
++#else
++static inline void ag71xx_add_ar8216_header(struct ag71xx *ag,
++ struct sk_buff *skb)
++{
++}
++
++static inline int ag71xx_remove_ar8216_header(struct ag71xx *ag,
++ struct sk_buff *skb,
++ int pktlen)
++{
++ return 0;
++}
++static inline int ag71xx_has_ar8216(struct ag71xx *ag)
++{
++ return 0;
++}
++#endif
++
++#ifdef CONFIG_AG71XX_DEBUG_FS
++int ag71xx_debugfs_root_init(void);
++void ag71xx_debugfs_root_exit(void);
++int ag71xx_debugfs_init(struct ag71xx *ag);
++void ag71xx_debugfs_exit(struct ag71xx *ag);
++void ag71xx_debugfs_update_int_stats(struct ag71xx *ag, u32 status);
++void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag, int rx, int tx);
++#else
++static inline int ag71xx_debugfs_root_init(void) { return 0; }
++static inline void ag71xx_debugfs_root_exit(void) {}
++static inline int ag71xx_debugfs_init(struct ag71xx *ag) { return 0; }
++static inline void ag71xx_debugfs_exit(struct ag71xx *ag) {}
++static inline void ag71xx_debugfs_update_int_stats(struct ag71xx *ag,
++ u32 status) {}
++static inline void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag,
++ int rx, int tx) {}
++#endif /* CONFIG_AG71XX_DEBUG_FS */
++
++#endif /* _AG71XX_H */
+diff -Nur linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_ar8216.c linux-2.6.37/drivers/net/ag71xx/ag71xx_ar8216.c
+--- linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_ar8216.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/net/ag71xx/ag71xx_ar8216.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,44 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ * Special support for the Atheros ar8216 switch chip
++ *
++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++#define AR8216_PACKET_TYPE_MASK 0xf
++#define AR8216_PACKET_TYPE_NORMAL 0
++
++#define AR8216_HEADER_LEN 2
++
++void ag71xx_add_ar8216_header(struct ag71xx *ag, struct sk_buff *skb)
++{
++ skb_push(skb, AR8216_HEADER_LEN);
++ skb->data[0] = 0x10;
++ skb->data[1] = 0x80;
++}
++
++int ag71xx_remove_ar8216_header(struct ag71xx *ag, struct sk_buff *skb,
++ int pktlen)
++{
++ u8 type;
++
++ type = skb->data[1] & AR8216_PACKET_TYPE_MASK;
++ switch (type) {
++ case AR8216_PACKET_TYPE_NORMAL:
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ skb_pull(skb, AR8216_HEADER_LEN);
++ return 0;
++}
+diff -Nur linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_debugfs.c linux-2.6.37/drivers/net/ag71xx/ag71xx_debugfs.c
+--- linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_debugfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/net/ag71xx/ag71xx_debugfs.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,197 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/debugfs.h>
++
++#include "ag71xx.h"
++
++static struct dentry *ag71xx_debugfs_root;
++
++static int ag71xx_debugfs_generic_open(struct inode *inode, struct file *file)
++{
++ file->private_data = inode->i_private;
++ return 0;
++}
++
++void ag71xx_debugfs_update_int_stats(struct ag71xx *ag, u32 status)
++{
++ if (status)
++ ag->debug.int_stats.total++;
++ if (status & AG71XX_INT_TX_PS)
++ ag->debug.int_stats.tx_ps++;
++ if (status & AG71XX_INT_TX_UR)
++ ag->debug.int_stats.tx_ur++;
++ if (status & AG71XX_INT_TX_BE)
++ ag->debug.int_stats.tx_be++;
++ if (status & AG71XX_INT_RX_PR)
++ ag->debug.int_stats.rx_pr++;
++ if (status & AG71XX_INT_RX_OF)
++ ag->debug.int_stats.rx_of++;
++ if (status & AG71XX_INT_RX_BE)
++ ag->debug.int_stats.rx_be++;
++}
++
++static ssize_t read_file_int_stats(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++#define PR_INT_STAT(_label, _field) \
++ len += snprintf(buf + len, sizeof(buf) - len, \
++ "%20s: %10lu\n", _label, ag->debug.int_stats._field);
++
++ struct ag71xx *ag = file->private_data;
++ char buf[256];
++ unsigned int len = 0;
++
++ PR_INT_STAT("TX Packet Sent", tx_ps);
++ PR_INT_STAT("TX Underrun", tx_ur);
++ PR_INT_STAT("TX Bus Error", tx_be);
++ PR_INT_STAT("RX Packet Received", rx_pr);
++ PR_INT_STAT("RX Overflow", rx_of);
++ PR_INT_STAT("RX Bus Error", rx_be);
++ len += snprintf(buf + len, sizeof(buf) - len, "\n");
++ PR_INT_STAT("Total", total);
++
++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++#undef PR_INT_STAT
++}
++
++static const struct file_operations ag71xx_fops_int_stats = {
++ .open = ag71xx_debugfs_generic_open,
++ .read = read_file_int_stats,
++ .owner = THIS_MODULE
++};
++
++void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag, int rx, int tx)
++{
++ struct ag71xx_napi_stats *stats = &ag->debug.napi_stats;
++
++ if (rx) {
++ stats->rx_count++;
++ stats->rx_packets += rx;
++ if (rx <= AG71XX_NAPI_WEIGHT)
++ stats->rx[rx]++;
++ if (rx > stats->rx_packets_max)
++ stats->rx_packets_max = rx;
++ }
++
++ if (tx) {
++ stats->tx_count++;
++ stats->tx_packets += tx;
++ if (tx <= AG71XX_NAPI_WEIGHT)
++ stats->tx[tx]++;
++ if (tx > stats->tx_packets_max)
++ stats->tx_packets_max = tx;
++ }
++}
++
++static ssize_t read_file_napi_stats(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ag71xx *ag = file->private_data;
++ struct ag71xx_napi_stats *stats = &ag->debug.napi_stats;
++ char buf[2048];
++ unsigned int len = 0;
++ unsigned long rx_avg = 0;
++ unsigned long tx_avg = 0;
++ int i;
++
++ if (stats->rx_count)
++ rx_avg = stats->rx_packets / stats->rx_count;
++
++ if (stats->tx_count)
++ tx_avg = stats->tx_packets / stats->tx_count;
++
++ len += snprintf(buf + len, sizeof(buf) - len, "%3s %10s %10s\n",
++ "len", "rx", "tx");
++
++ for (i = 1; i <= AG71XX_NAPI_WEIGHT; i++)
++ len += snprintf(buf + len, sizeof(buf) - len,
++ "%3d: %10lu %10lu\n",
++ i, stats->rx[i], stats->tx[i]);
++
++ len += snprintf(buf + len, sizeof(buf) - len, "\n");
++
++ len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n",
++ "sum", stats->rx_count, stats->tx_count);
++ len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n",
++ "avg", rx_avg, tx_avg);
++ len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n",
++ "max", stats->rx_packets_max, stats->tx_packets_max);
++ len += snprintf(buf + len, sizeof(buf) - len, "%3s: %10lu %10lu\n",
++ "pkt", stats->rx_packets, stats->tx_packets);
++
++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static const struct file_operations ag71xx_fops_napi_stats = {
++ .open = ag71xx_debugfs_generic_open,
++ .read = read_file_napi_stats,
++ .owner = THIS_MODULE
++};
++
++void ag71xx_debugfs_exit(struct ag71xx *ag)
++{
++ debugfs_remove(ag->debug.debugfs_napi_stats);
++ debugfs_remove(ag->debug.debugfs_int_stats);
++ debugfs_remove(ag->debug.debugfs_dir);
++}
++
++int ag71xx_debugfs_init(struct ag71xx *ag)
++{
++ ag->debug.debugfs_dir = debugfs_create_dir(ag->dev->name,
++ ag71xx_debugfs_root);
++ if (!ag->debug.debugfs_dir)
++ goto err;
++
++ ag->debug.debugfs_int_stats =
++ debugfs_create_file("int_stats",
++ S_IRUGO,
++ ag->debug.debugfs_dir,
++ ag,
++ &ag71xx_fops_int_stats);
++ if (!ag->debug.debugfs_int_stats)
++ goto err;
++
++ ag->debug.debugfs_napi_stats =
++ debugfs_create_file("napi_stats",
++ S_IRUGO,
++ ag->debug.debugfs_dir,
++ ag,
++ &ag71xx_fops_napi_stats);
++ if (!ag->debug.debugfs_napi_stats)
++ goto err;
++
++ return 0;
++
++ err:
++ ag71xx_debugfs_exit(ag);
++ return -ENOMEM;
++}
++
++int ag71xx_debugfs_root_init(void)
++{
++ if (ag71xx_debugfs_root)
++ return -EBUSY;
++
++ ag71xx_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
++ if (!ag71xx_debugfs_root)
++ return -ENOENT;
++
++ return 0;
++}
++
++void ag71xx_debugfs_root_exit(void)
++{
++ debugfs_remove(ag71xx_debugfs_root);
++ ag71xx_debugfs_root = NULL;
++}
+diff -Nur linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_ethtool.c linux-2.6.37/drivers/net/ag71xx/ag71xx_ethtool.c
+--- linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_ethtool.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/net/ag71xx/ag71xx_ethtool.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,71 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++static int ag71xx_ethtool_get_settings(struct net_device *dev,
++ struct ethtool_cmd *cmd)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ struct phy_device *phydev = ag->phy_dev;
++
++ if (!phydev)
++ return -ENODEV;
++
++ return phy_ethtool_gset(phydev, cmd);
++}
++
++static int ag71xx_ethtool_set_settings(struct net_device *dev,
++ struct ethtool_cmd *cmd)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ struct phy_device *phydev = ag->phy_dev;
++
++ if (!phydev)
++ return -ENODEV;
++
++ return phy_ethtool_sset(phydev, cmd);
++}
++
++static void ag71xx_ethtool_get_drvinfo(struct net_device *dev,
++ struct ethtool_drvinfo *info)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++
++ strcpy(info->driver, ag->pdev->dev.driver->name);
++ strcpy(info->version, AG71XX_DRV_VERSION);
++ strcpy(info->bus_info, dev_name(&ag->pdev->dev));
++}
++
++static u32 ag71xx_ethtool_get_msglevel(struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++
++ return ag->msg_enable;
++}
++
++static void ag71xx_ethtool_set_msglevel(struct net_device *dev, u32 msg_level)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++
++ ag->msg_enable = msg_level;
++}
++
++struct ethtool_ops ag71xx_ethtool_ops = {
++ .set_settings = ag71xx_ethtool_set_settings,
++ .get_settings = ag71xx_ethtool_get_settings,
++ .get_drvinfo = ag71xx_ethtool_get_drvinfo,
++ .get_msglevel = ag71xx_ethtool_get_msglevel,
++ .set_msglevel = ag71xx_ethtool_set_msglevel,
++ .get_link = ethtool_op_get_link,
++};
+diff -Nur linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_main.c linux-2.6.37/drivers/net/ag71xx/ag71xx_main.c
+--- linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_main.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/net/ag71xx/ag71xx_main.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,1184 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++#define AG71XX_DEFAULT_MSG_ENABLE \
++ ( NETIF_MSG_DRV \
++ | NETIF_MSG_PROBE \
++ | NETIF_MSG_LINK \
++ | NETIF_MSG_TIMER \
++ | NETIF_MSG_IFDOWN \
++ | NETIF_MSG_IFUP \
++ | NETIF_MSG_RX_ERR \
++ | NETIF_MSG_TX_ERR )
++
++static int ag71xx_msg_level = -1;
++
++module_param_named(msg_level, ag71xx_msg_level, int, 0);
++MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
++
++static void ag71xx_dump_dma_regs(struct ag71xx *ag)
++{
++ DBG("%s: dma_tx_ctrl=%08x, dma_tx_desc=%08x, dma_tx_status=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_TX_CTRL),
++ ag71xx_rr(ag, AG71XX_REG_TX_DESC),
++ ag71xx_rr(ag, AG71XX_REG_TX_STATUS));
++
++ DBG("%s: dma_rx_ctrl=%08x, dma_rx_desc=%08x, dma_rx_status=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_RX_CTRL),
++ ag71xx_rr(ag, AG71XX_REG_RX_DESC),
++ ag71xx_rr(ag, AG71XX_REG_RX_STATUS));
++}
++
++static void ag71xx_dump_regs(struct ag71xx *ag)
++{
++ DBG("%s: mac_cfg1=%08x, mac_cfg2=%08x, ipg=%08x, hdx=%08x, mfl=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_MAC_CFG1),
++ ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
++ ag71xx_rr(ag, AG71XX_REG_MAC_IPG),
++ ag71xx_rr(ag, AG71XX_REG_MAC_HDX),
++ ag71xx_rr(ag, AG71XX_REG_MAC_MFL));
++ DBG("%s: mac_ifctl=%08x, mac_addr1=%08x, mac_addr2=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL),
++ ag71xx_rr(ag, AG71XX_REG_MAC_ADDR1),
++ ag71xx_rr(ag, AG71XX_REG_MAC_ADDR2));
++ DBG("%s: fifo_cfg0=%08x, fifo_cfg1=%08x, fifo_cfg2=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
++ DBG("%s: fifo_cfg3=%08x, fifo_cfg4=%08x, fifo_cfg5=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
++}
++
++static inline void ag71xx_dump_intr(struct ag71xx *ag, char *label, u32 intr)
++{
++ DBG("%s: %s intr=%08x %s%s%s%s%s%s\n",
++ ag->dev->name, label, intr,
++ (intr & AG71XX_INT_TX_PS) ? "TXPS " : "",
++ (intr & AG71XX_INT_TX_UR) ? "TXUR " : "",
++ (intr & AG71XX_INT_TX_BE) ? "TXBE " : "",
++ (intr & AG71XX_INT_RX_PR) ? "RXPR " : "",
++ (intr & AG71XX_INT_RX_OF) ? "RXOF " : "",
++ (intr & AG71XX_INT_RX_BE) ? "RXBE " : "");
++}
++
++static void ag71xx_ring_free(struct ag71xx_ring *ring)
++{
++ kfree(ring->buf);
++
++ if (ring->descs_cpu)
++ dma_free_coherent(NULL, ring->size * ring->desc_size,
++ ring->descs_cpu, ring->descs_dma);
++}
++
++static int ag71xx_ring_alloc(struct ag71xx_ring *ring, unsigned int size)
++{
++ int err;
++ int i;
++
++ ring->desc_size = sizeof(struct ag71xx_desc);
++ if (ring->desc_size % cache_line_size()) {
++ DBG("ag71xx: ring %p, desc size %u rounded to %u\n",
++ ring, ring->desc_size,
++ roundup(ring->desc_size, cache_line_size()));
++ ring->desc_size = roundup(ring->desc_size, cache_line_size());
++ }
++
++ ring->descs_cpu = dma_alloc_coherent(NULL, size * ring->desc_size,
++ &ring->descs_dma, GFP_ATOMIC);
++ if (!ring->descs_cpu) {
++ err = -ENOMEM;
++ goto err;
++ }
++
++ ring->size = size;
++
++ ring->buf = kzalloc(size * sizeof(*ring->buf), GFP_KERNEL);
++ if (!ring->buf) {
++ err = -ENOMEM;
++ goto err;
++ }
++
++ for (i = 0; i < size; i++) {
++ ring->buf[i].desc = (struct ag71xx_desc *)&ring->descs_cpu[i * ring->desc_size];
++ DBG("ag71xx: ring %p, desc %d at %p\n",
++ ring, i, ring->buf[i].desc);
++ }
++
++ return 0;
++
++ err:
++ return err;
++}
++
++static void ag71xx_ring_tx_clean(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->tx_ring;
++ struct net_device *dev = ag->dev;
++
++ while (ring->curr != ring->dirty) {
++ u32 i = ring->dirty % AG71XX_TX_RING_SIZE;
++
++ if (!ag71xx_desc_empty(ring->buf[i].desc)) {
++ ring->buf[i].desc->ctrl = 0;
++ dev->stats.tx_errors++;
++ }
++
++ if (ring->buf[i].skb)
++ dev_kfree_skb_any(ring->buf[i].skb);
++
++ ring->buf[i].skb = NULL;
++
++ ring->dirty++;
++ }
++
++ /* flush descriptors */
++ wmb();
++
++}
++
++static void ag71xx_ring_tx_init(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->tx_ring;
++ int i;
++
++ for (i = 0; i < AG71XX_TX_RING_SIZE; i++) {
++ ring->buf[i].desc->next = (u32) (ring->descs_dma +
++ ring->desc_size * ((i + 1) % AG71XX_TX_RING_SIZE));
++
++ ring->buf[i].desc->ctrl = DESC_EMPTY;
++ ring->buf[i].skb = NULL;
++ }
++
++ /* flush descriptors */
++ wmb();
++
++ ring->curr = 0;
++ ring->dirty = 0;
++}
++
++static void ag71xx_ring_rx_clean(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->rx_ring;
++ int i;
++
++ if (!ring->buf)
++ return;
++
++ for (i = 0; i < AG71XX_RX_RING_SIZE; i++)
++ if (ring->buf[i].skb) {
++ dma_unmap_single(&ag->dev->dev, ring->buf[i].dma_addr,
++ AG71XX_RX_PKT_SIZE, DMA_FROM_DEVICE);
++ kfree_skb(ring->buf[i].skb);
++ }
++}
++
++static int ag71xx_rx_reserve(struct ag71xx *ag)
++{
++ int reserve = 0;
++
++ if (ag71xx_get_pdata(ag)->is_ar724x) {
++ if (!ag71xx_has_ar8216(ag))
++ reserve = 2;
++
++ if (ag->phy_dev)
++ reserve += 4 - (ag->phy_dev->pkt_align % 4);
++
++ reserve %= 4;
++ }
++
++ return reserve + AG71XX_RX_PKT_RESERVE;
++}
++
++
++static int ag71xx_ring_rx_init(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->rx_ring;
++ unsigned int reserve = ag71xx_rx_reserve(ag);
++ unsigned int i;
++ int ret;
++
++ ret = 0;
++ for (i = 0; i < AG71XX_RX_RING_SIZE; i++) {
++ ring->buf[i].desc->next = (u32) (ring->descs_dma +
++ ring->desc_size * ((i + 1) % AG71XX_RX_RING_SIZE));
++
++ DBG("ag71xx: RX desc at %p, next is %08x\n",
++ ring->buf[i].desc,
++ ring->buf[i].desc->next);
++ }
++
++ for (i = 0; i < AG71XX_RX_RING_SIZE; i++) {
++ struct sk_buff *skb;
++ dma_addr_t dma_addr;
++
++ skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + reserve);
++ if (!skb) {
++ ret = -ENOMEM;
++ break;
++ }
++
++ skb->dev = ag->dev;
++ skb_reserve(skb, reserve);
++
++ dma_addr = dma_map_single(&ag->dev->dev, skb->data,
++ AG71XX_RX_PKT_SIZE,
++ DMA_FROM_DEVICE);
++ ring->buf[i].skb = skb;
++ ring->buf[i].dma_addr = dma_addr;
++ ring->buf[i].desc->data = (u32) dma_addr;
++ ring->buf[i].desc->ctrl = DESC_EMPTY;
++ }
++
++ /* flush descriptors */
++ wmb();
++
++ ring->curr = 0;
++ ring->dirty = 0;
++
++ return ret;
++}
++
++static int ag71xx_ring_rx_refill(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->rx_ring;
++ unsigned int reserve = ag71xx_rx_reserve(ag);
++ unsigned int count;
++
++ count = 0;
++ for (; ring->curr - ring->dirty > 0; ring->dirty++) {
++ unsigned int i;
++
++ i = ring->dirty % AG71XX_RX_RING_SIZE;
++
++ if (ring->buf[i].skb == NULL) {
++ dma_addr_t dma_addr;
++ struct sk_buff *skb;
++
++ skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + reserve);
++ if (skb == NULL)
++ break;
++
++ skb_reserve(skb, reserve);
++ skb->dev = ag->dev;
++
++ dma_addr = dma_map_single(&ag->dev->dev, skb->data,
++ AG71XX_RX_PKT_SIZE,
++ DMA_FROM_DEVICE);
++
++ ring->buf[i].skb = skb;
++ ring->buf[i].dma_addr = dma_addr;
++ ring->buf[i].desc->data = (u32) dma_addr;
++ }
++
++ ring->buf[i].desc->ctrl = DESC_EMPTY;
++ count++;
++ }
++
++ /* flush descriptors */
++ wmb();
++
++ DBG("%s: %u rx descriptors refilled\n", ag->dev->name, count);
++
++ return count;
++}
++
++static int ag71xx_rings_init(struct ag71xx *ag)
++{
++ int ret;
++
++ ret = ag71xx_ring_alloc(&ag->tx_ring, AG71XX_TX_RING_SIZE);
++ if (ret)
++ return ret;
++
++ ag71xx_ring_tx_init(ag);
++
++ ret = ag71xx_ring_alloc(&ag->rx_ring, AG71XX_RX_RING_SIZE);
++ if (ret)
++ return ret;
++
++ ret = ag71xx_ring_rx_init(ag);
++ return ret;
++}
++
++static void ag71xx_rings_cleanup(struct ag71xx *ag)
++{
++ ag71xx_ring_rx_clean(ag);
++ ag71xx_ring_free(&ag->rx_ring);
++
++ ag71xx_ring_tx_clean(ag);
++ ag71xx_ring_free(&ag->tx_ring);
++}
++
++static unsigned char *ag71xx_speed_str(struct ag71xx *ag)
++{
++ switch (ag->speed) {
++ case SPEED_1000:
++ return "1000";
++ case SPEED_100:
++ return "100";
++ case SPEED_10:
++ return "10";
++ }
++
++ return "?";
++}
++
++void ag71xx_link_adjust(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ u32 cfg2;
++ u32 ifctl;
++ u32 fifo5;
++ u32 mii_speed;
++
++ if (!ag->link) {
++ netif_carrier_off(ag->dev);
++ if (netif_msg_link(ag))
++ printk(KERN_INFO "%s: link down\n", ag->dev->name);
++ return;
++ }
++
++ cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2);
++ cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX);
++ cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0;
++
++ ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL);
++ ifctl &= ~(MAC_IFCTL_SPEED);
++
++ fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5);
++ fifo5 &= ~FIFO_CFG5_BM;
++
++ switch (ag->speed) {
++ case SPEED_1000:
++ mii_speed = MII_CTRL_SPEED_1000;
++ cfg2 |= MAC_CFG2_IF_1000;
++ fifo5 |= FIFO_CFG5_BM;
++ break;
++ case SPEED_100:
++ mii_speed = MII_CTRL_SPEED_100;
++ cfg2 |= MAC_CFG2_IF_10_100;
++ ifctl |= MAC_IFCTL_SPEED;
++ break;
++ case SPEED_10:
++ mii_speed = MII_CTRL_SPEED_10;
++ cfg2 |= MAC_CFG2_IF_10_100;
++ break;
++ default:
++ BUG();
++ return;
++ }
++
++ if (pdata->is_ar91xx)
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x00780fff);
++ else if (pdata->is_ar724x)
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, pdata->fifo_cfg3);
++ else
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x008001ff);
++
++ if (pdata->set_pll)
++ pdata->set_pll(ag->speed);
++
++ ag71xx_mii_ctrl_set_speed(ag, mii_speed);
++
++ ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
++ ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
++
++ netif_carrier_on(ag->dev);
++ if (netif_msg_link(ag))
++ printk(KERN_INFO "%s: link up (%sMbps/%s duplex)\n",
++ ag->dev->name,
++ ag71xx_speed_str(ag),
++ (DUPLEX_FULL == ag->duplex) ? "Full" : "Half");
++
++ DBG("%s: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
++
++ DBG("%s: fifo_cfg3=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
++
++ DBG("%s: mac_cfg2=%#x, mac_ifctl=%#x, mii_ctrl=%#x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
++ ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL),
++ ag71xx_mii_ctrl_rr(ag));
++}
++
++static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac)
++{
++ u32 t;
++
++ t = (((u32) mac[5]) << 24) | (((u32) mac[4]) << 16)
++ | (((u32) mac[3]) << 8) | ((u32) mac[2]);
++
++ ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t);
++
++ t = (((u32) mac[1]) << 24) | (((u32) mac[0]) << 16);
++ ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t);
++}
++
++static void ag71xx_dma_reset(struct ag71xx *ag)
++{
++ u32 val;
++ int i;
++
++ ag71xx_dump_dma_regs(ag);
++
++ /* stop RX and TX */
++ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
++ ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
++
++ /* clear descriptor addresses */
++ ag71xx_wr(ag, AG71XX_REG_TX_DESC, 0);
++ ag71xx_wr(ag, AG71XX_REG_RX_DESC, 0);
++
++ /* clear pending RX/TX interrupts */
++ for (i = 0; i < 256; i++) {
++ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
++ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
++ }
++
++ /* clear pending errors */
++ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF);
++ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR);
++
++ val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
++ if (val)
++ printk(KERN_ALERT "%s: unable to clear DMA Rx status: %08x\n",
++ ag->dev->name, val);
++
++ val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
++
++ /* mask out reserved bits */
++ val &= ~0xff000000;
++
++ if (val)
++ printk(KERN_ALERT "%s: unable to clear DMA Tx status: %08x\n",
++ ag->dev->name, val);
++
++ ag71xx_dump_dma_regs(ag);
++}
++
++#define MAC_CFG1_INIT (MAC_CFG1_RXE | MAC_CFG1_TXE | \
++ MAC_CFG1_SRX | MAC_CFG1_STX)
++
++#define FIFO_CFG0_INIT (FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT)
++
++#define FIFO_CFG4_INIT (FIFO_CFG4_DE | FIFO_CFG4_DV | FIFO_CFG4_FC | \
++ FIFO_CFG4_CE | FIFO_CFG4_CR | FIFO_CFG4_LM | \
++ FIFO_CFG4_LO | FIFO_CFG4_OK | FIFO_CFG4_MC | \
++ FIFO_CFG4_BC | FIFO_CFG4_DR | FIFO_CFG4_LE | \
++ FIFO_CFG4_CF | FIFO_CFG4_PF | FIFO_CFG4_UO | \
++ FIFO_CFG4_VT)
++
++#define FIFO_CFG5_INIT (FIFO_CFG5_DE | FIFO_CFG5_DV | FIFO_CFG5_FC | \
++ FIFO_CFG5_CE | FIFO_CFG5_LO | FIFO_CFG5_OK | \
++ FIFO_CFG5_MC | FIFO_CFG5_BC | FIFO_CFG5_DR | \
++ FIFO_CFG5_CF | FIFO_CFG5_PF | FIFO_CFG5_VT | \
++ FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \
++ FIFO_CFG5_17 | FIFO_CFG5_SF)
++
++static void ag71xx_hw_init(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++ ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
++ udelay(20);
++
++ ar71xx_device_stop(pdata->reset_bit);
++ mdelay(100);
++ ar71xx_device_start(pdata->reset_bit);
++ mdelay(100);
++
++ /* setup MAC configuration registers */
++ if (pdata->is_ar724x)
++ ag71xx_wr(ag, AG71XX_REG_MAC_CFG1,
++ MAC_CFG1_INIT | MAC_CFG1_TFC | MAC_CFG1_RFC);
++ else
++ ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT);
++
++ ag71xx_sb(ag, AG71XX_REG_MAC_CFG2,
++ MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK);
++
++ /* setup max frame length */
++ ag71xx_wr(ag, AG71XX_REG_MAC_MFL, AG71XX_TX_MTU_LEN);
++
++ /* setup MII interface type */
++ ag71xx_mii_ctrl_set_if(ag, pdata->mii_if);
++
++ /* setup FIFO configuration registers */
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, FIFO_CFG0_INIT);
++ if (pdata->is_ar724x) {
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, pdata->fifo_cfg1);
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, pdata->fifo_cfg2);
++ } else {
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, 0x0fff0000);
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, 0x00001fff);
++ }
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT);
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT);
++
++ ag71xx_dma_reset(ag);
++}
++
++static void ag71xx_hw_start(struct ag71xx *ag)
++{
++ /* start RX engine */
++ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
++
++ /* enable interrupts */
++ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT);
++}
++
++static void ag71xx_hw_stop(struct ag71xx *ag)
++{
++ /* disable all interrupts */
++ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0);
++
++ ag71xx_dma_reset(ag);
++}
++
++static int ag71xx_open(struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ int ret;
++
++ ret = ag71xx_rings_init(ag);
++ if (ret)
++ goto err;
++
++ napi_enable(&ag->napi);
++
++ netif_carrier_off(dev);
++ ag71xx_phy_start(ag);
++
++ ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
++ ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->rx_ring.descs_dma);
++
++ ag71xx_hw_set_macaddr(ag, dev->dev_addr);
++
++ ag71xx_hw_start(ag);
++
++ netif_start_queue(dev);
++
++ return 0;
++
++ err:
++ ag71xx_rings_cleanup(ag);
++ return ret;
++}
++
++static int ag71xx_stop(struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ unsigned long flags;
++
++ netif_carrier_off(dev);
++ ag71xx_phy_stop(ag);
++
++ spin_lock_irqsave(&ag->lock, flags);
++
++ netif_stop_queue(dev);
++
++ ag71xx_hw_stop(ag);
++
++ napi_disable(&ag->napi);
++ del_timer_sync(&ag->oom_timer);
++
++ spin_unlock_irqrestore(&ag->lock, flags);
++
++ ag71xx_rings_cleanup(ag);
++
++ return 0;
++}
++
++static netdev_tx_t ag71xx_hard_start_xmit(struct sk_buff *skb,
++ struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ struct ag71xx_ring *ring = &ag->tx_ring;
++ struct ag71xx_desc *desc;
++ dma_addr_t dma_addr;
++ int i;
++
++ i = ring->curr % AG71XX_TX_RING_SIZE;
++ desc = ring->buf[i].desc;
++
++ if (!ag71xx_desc_empty(desc))
++ goto err_drop;
++
++ if (ag71xx_has_ar8216(ag))
++ ag71xx_add_ar8216_header(ag, skb);
++
++ if (skb->len <= 0) {
++ DBG("%s: packet len is too small\n", ag->dev->name);
++ goto err_drop;
++ }
++
++ dma_addr = dma_map_single(&dev->dev, skb->data, skb->len,
++ DMA_TO_DEVICE);
++
++ ring->buf[i].skb = skb;
++
++ /* setup descriptor fields */
++ desc->data = (u32) dma_addr;
++ desc->ctrl = (skb->len & DESC_PKTLEN_M);
++
++ /* flush descriptor */
++ wmb();
++
++ ring->curr++;
++ if (ring->curr == (ring->dirty + AG71XX_TX_THRES_STOP)) {
++ DBG("%s: tx queue full\n", ag->dev->name);
++ netif_stop_queue(dev);
++ }
++
++ DBG("%s: packet injected into TX queue\n", ag->dev->name);
++
++ /* enable TX engine */
++ ag71xx_wr(ag, AG71XX_REG_TX_CTRL, TX_CTRL_TXE);
++
++ return NETDEV_TX_OK;
++
++ err_drop:
++ dev->stats.tx_dropped++;
++
++ dev_kfree_skb(skb);
++ return NETDEV_TX_OK;
++}
++
++static int ag71xx_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++ struct mii_ioctl_data *data = (struct mii_ioctl_data *) &ifr->ifr_data;
++ struct ag71xx *ag = netdev_priv(dev);
++ int ret;
++
++ switch (cmd) {
++ case SIOCETHTOOL:
++ if (ag->phy_dev == NULL)
++ break;
++
++ spin_lock_irq(&ag->lock);
++ ret = phy_ethtool_ioctl(ag->phy_dev, (void *) ifr->ifr_data);
++ spin_unlock_irq(&ag->lock);
++ return ret;
++
++ case SIOCSIFHWADDR:
++ if (copy_from_user
++ (dev->dev_addr, ifr->ifr_data, sizeof(dev->dev_addr)))
++ return -EFAULT;
++ return 0;
++
++ case SIOCGIFHWADDR:
++ if (copy_to_user
++ (ifr->ifr_data, dev->dev_addr, sizeof(dev->dev_addr)))
++ return -EFAULT;
++ return 0;
++
++ case SIOCGMIIPHY:
++ case SIOCGMIIREG:
++ case SIOCSMIIREG:
++ if (ag->phy_dev == NULL)
++ break;
++
++ return phy_mii_ioctl(ag->phy_dev, data, cmd);
++
++ default:
++ break;
++ }
++
++ return -EOPNOTSUPP;
++}
++
++static void ag71xx_oom_timer_handler(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *) data;
++ struct ag71xx *ag = netdev_priv(dev);
++
++ napi_schedule(&ag->napi);
++}
++
++static void ag71xx_tx_timeout(struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++
++ if (netif_msg_tx_err(ag))
++ printk(KERN_DEBUG "%s: tx timeout\n", ag->dev->name);
++
++ schedule_work(&ag->restart_work);
++}
++
++static void ag71xx_restart_work_func(struct work_struct *work)
++{
++ struct ag71xx *ag = container_of(work, struct ag71xx, restart_work);
++
++ ag71xx_stop(ag->dev);
++ ag71xx_open(ag->dev);
++}
++
++static int ag71xx_tx_packets(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->tx_ring;
++ int sent;
++
++ DBG("%s: processing TX ring\n", ag->dev->name);
++
++ sent = 0;
++ while (ring->dirty != ring->curr) {
++ unsigned int i = ring->dirty % AG71XX_TX_RING_SIZE;
++ struct ag71xx_desc *desc = ring->buf[i].desc;
++ struct sk_buff *skb = ring->buf[i].skb;
++
++ if (!ag71xx_desc_empty(desc))
++ break;
++
++ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
++
++ ag->dev->stats.tx_bytes += skb->len;
++ ag->dev->stats.tx_packets++;
++
++ dev_kfree_skb_any(skb);
++ ring->buf[i].skb = NULL;
++
++ ring->dirty++;
++ sent++;
++ }
++
++ DBG("%s: %d packets sent out\n", ag->dev->name, sent);
++
++ if ((ring->curr - ring->dirty) < AG71XX_TX_THRES_WAKEUP)
++ netif_wake_queue(ag->dev);
++
++ return sent;
++}
++
++static int ag71xx_rx_packets(struct ag71xx *ag, int limit)
++{
++ struct net_device *dev = ag->dev;
++ struct ag71xx_ring *ring = &ag->rx_ring;
++ int done = 0;
++
++ DBG("%s: rx packets, limit=%d, curr=%u, dirty=%u\n",
++ dev->name, limit, ring->curr, ring->dirty);
++
++ while (done < limit) {
++ unsigned int i = ring->curr % AG71XX_RX_RING_SIZE;
++ struct ag71xx_desc *desc = ring->buf[i].desc;
++ struct sk_buff *skb;
++ int pktlen;
++ int err = 0;
++
++ if (ag71xx_desc_empty(desc))
++ break;
++
++ if ((ring->dirty + AG71XX_RX_RING_SIZE) == ring->curr) {
++ ag71xx_assert(0);
++ break;
++ }
++
++ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
++
++ skb = ring->buf[i].skb;
++ pktlen = ag71xx_desc_pktlen(desc);
++ pktlen -= ETH_FCS_LEN;
++
++ dma_unmap_single(&dev->dev, ring->buf[i].dma_addr,
++ AG71XX_RX_PKT_SIZE, DMA_FROM_DEVICE);
++
++ dev->last_rx = jiffies;
++ dev->stats.rx_packets++;
++ dev->stats.rx_bytes += pktlen;
++
++ skb_put(skb, pktlen);
++ if (ag71xx_has_ar8216(ag))
++ err = ag71xx_remove_ar8216_header(ag, skb, pktlen);
++
++ if (err) {
++ dev->stats.rx_dropped++;
++ kfree_skb(skb);
++ } else {
++ skb->dev = dev;
++ skb->ip_summed = CHECKSUM_NONE;
++ if (ag->phy_dev) {
++ ag->phy_dev->netif_receive_skb(skb);
++ } else {
++ skb->protocol = eth_type_trans(skb, dev);
++ netif_receive_skb(skb);
++ }
++ }
++
++ ring->buf[i].skb = NULL;
++ done++;
++
++ ring->curr++;
++ }
++
++ ag71xx_ring_rx_refill(ag);
++
++ DBG("%s: rx finish, curr=%u, dirty=%u, done=%d\n",
++ dev->name, ring->curr, ring->dirty, done);
++
++ return done;
++}
++
++static int ag71xx_poll(struct napi_struct *napi, int limit)
++{
++ struct ag71xx *ag = container_of(napi, struct ag71xx, napi);
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ struct net_device *dev = ag->dev;
++ struct ag71xx_ring *rx_ring;
++ unsigned long flags;
++ u32 status;
++ int tx_done;
++ int rx_done;
++
++ pdata->ddr_flush();
++ tx_done = ag71xx_tx_packets(ag);
++
++ DBG("%s: processing RX ring\n", dev->name);
++ rx_done = ag71xx_rx_packets(ag, limit);
++
++ ag71xx_debugfs_update_napi_stats(ag, rx_done, tx_done);
++
++ rx_ring = &ag->rx_ring;
++ if (rx_ring->buf[rx_ring->dirty % AG71XX_RX_RING_SIZE].skb == NULL)
++ goto oom;
++
++ status = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
++ if (unlikely(status & RX_STATUS_OF)) {
++ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_OF);
++ dev->stats.rx_fifo_errors++;
++
++ /* restart RX */
++ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
++ }
++
++ if (rx_done < limit) {
++ if (status & RX_STATUS_PR)
++ goto more;
++
++ status = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
++ if (status & TX_STATUS_PS)
++ goto more;
++
++ DBG("%s: disable polling mode, rx=%d, tx=%d,limit=%d\n",
++ dev->name, rx_done, tx_done, limit);
++
++ napi_complete(napi);
++
++ /* enable interrupts */
++ spin_lock_irqsave(&ag->lock, flags);
++ ag71xx_int_enable(ag, AG71XX_INT_POLL);
++ spin_unlock_irqrestore(&ag->lock, flags);
++ return rx_done;
++ }
++
++ more:
++ DBG("%s: stay in polling mode, rx=%d, tx=%d, limit=%d\n",
++ dev->name, rx_done, tx_done, limit);
++ return rx_done;
++
++ oom:
++ if (netif_msg_rx_err(ag))
++ printk(KERN_DEBUG "%s: out of memory\n", dev->name);
++
++ mod_timer(&ag->oom_timer, jiffies + AG71XX_OOM_REFILL);
++ napi_complete(napi);
++ return 0;
++}
++
++static irqreturn_t ag71xx_interrupt(int irq, void *dev_id)
++{
++ struct net_device *dev = dev_id;
++ struct ag71xx *ag = netdev_priv(dev);
++ u32 status;
++
++ status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS);
++ ag71xx_dump_intr(ag, "raw", status);
++
++ if (unlikely(!status))
++ return IRQ_NONE;
++
++ if (unlikely(status & AG71XX_INT_ERR)) {
++ if (status & AG71XX_INT_TX_BE) {
++ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE);
++ dev_err(&dev->dev, "TX BUS error\n");
++ }
++ if (status & AG71XX_INT_RX_BE) {
++ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE);
++ dev_err(&dev->dev, "RX BUS error\n");
++ }
++ }
++
++ if (likely(status & AG71XX_INT_POLL)) {
++ ag71xx_int_disable(ag, AG71XX_INT_POLL);
++ DBG("%s: enable polling mode\n", dev->name);
++ napi_schedule(&ag->napi);
++ }
++
++ ag71xx_debugfs_update_int_stats(ag, status);
++
++ return IRQ_HANDLED;
++}
++
++static void ag71xx_set_multicast_list(struct net_device *dev)
++{
++ /* TODO */
++}
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++/*
++ * Polling 'interrupt' - used by things like netconsole to send skbs
++ * without having to re-enable interrupts. It's not called while
++ * the interrupt routine is executing.
++ */
++static void ag71xx_netpoll(struct net_device *dev)
++{
++ disable_irq(dev->irq);
++ ag71xx_interrupt(dev->irq, dev);
++ enable_irq(dev->irq);
++}
++#endif
++
++static const struct net_device_ops ag71xx_netdev_ops = {
++ .ndo_open = ag71xx_open,
++ .ndo_stop = ag71xx_stop,
++ .ndo_start_xmit = ag71xx_hard_start_xmit,
++ .ndo_set_multicast_list = ag71xx_set_multicast_list,
++ .ndo_do_ioctl = ag71xx_do_ioctl,
++ .ndo_tx_timeout = ag71xx_tx_timeout,
++ .ndo_change_mtu = eth_change_mtu,
++ .ndo_set_mac_address = eth_mac_addr,
++ .ndo_validate_addr = eth_validate_addr,
++#ifdef CONFIG_NET_POLL_CONTROLLER
++ .ndo_poll_controller = ag71xx_netpoll,
++#endif
++};
++
++static int __init ag71xx_probe(struct platform_device *pdev)
++{
++ struct net_device *dev;
++ struct resource *res;
++ struct ag71xx *ag;
++ struct ag71xx_platform_data *pdata;
++ int err;
++
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ dev_err(&pdev->dev, "no platform data specified\n");
++ err = -ENXIO;
++ goto err_out;
++ }
++
++ if (pdata->mii_bus_dev == NULL) {
++ dev_err(&pdev->dev, "no MII bus device specified\n");
++ err = -EINVAL;
++ goto err_out;
++ }
++
++ dev = alloc_etherdev(sizeof(*ag));
++ if (!dev) {
++ dev_err(&pdev->dev, "alloc_etherdev failed\n");
++ err = -ENOMEM;
++ goto err_out;
++ }
++
++ SET_NETDEV_DEV(dev, &pdev->dev);
++
++ ag = netdev_priv(dev);
++ ag->pdev = pdev;
++ ag->dev = dev;
++ ag->msg_enable = netif_msg_init(ag71xx_msg_level,
++ AG71XX_DEFAULT_MSG_ENABLE);
++ spin_lock_init(&ag->lock);
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac_base");
++ if (!res) {
++ dev_err(&pdev->dev, "no mac_base resource found\n");
++ err = -ENXIO;
++ goto err_out;
++ }
++
++ ag->mac_base = ioremap_nocache(res->start, res->end - res->start + 1);
++ if (!ag->mac_base) {
++ dev_err(&pdev->dev, "unable to ioremap mac_base\n");
++ err = -ENOMEM;
++ goto err_free_dev;
++ }
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mii_ctrl");
++ if (!res) {
++ dev_err(&pdev->dev, "no mii_ctrl resource found\n");
++ err = -ENXIO;
++ goto err_unmap_base;
++ }
++
++ ag->mii_ctrl = ioremap_nocache(res->start, res->end - res->start + 1);
++ if (!ag->mii_ctrl) {
++ dev_err(&pdev->dev, "unable to ioremap mii_ctrl\n");
++ err = -ENOMEM;
++ goto err_unmap_base;
++ }
++
++ dev->irq = platform_get_irq(pdev, 0);
++ err = request_irq(dev->irq, ag71xx_interrupt,
++ IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
++ dev->name, dev);
++ if (err) {
++ dev_err(&pdev->dev, "unable to request IRQ %d\n", dev->irq);
++ goto err_unmap_mii_ctrl;
++ }
++
++ dev->base_addr = (unsigned long)ag->mac_base;
++ dev->netdev_ops = &ag71xx_netdev_ops;
++ dev->ethtool_ops = &ag71xx_ethtool_ops;
++
++ INIT_WORK(&ag->restart_work, ag71xx_restart_work_func);
++
++ init_timer(&ag->oom_timer);
++ ag->oom_timer.data = (unsigned long) dev;
++ ag->oom_timer.function = ag71xx_oom_timer_handler;
++
++ memcpy(dev->dev_addr, pdata->mac_addr, ETH_ALEN);
++
++ netif_napi_add(dev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT);
++
++ err = register_netdev(dev);
++ if (err) {
++ dev_err(&pdev->dev, "unable to register net device\n");
++ goto err_free_irq;
++ }
++
++ printk(KERN_INFO "%s: Atheros AG71xx at 0x%08lx, irq %d\n",
++ dev->name, dev->base_addr, dev->irq);
++
++ ag71xx_dump_regs(ag);
++
++ ag71xx_hw_init(ag);
++
++ ag71xx_dump_regs(ag);
++
++ err = ag71xx_phy_connect(ag);
++ if (err)
++ goto err_unregister_netdev;
++
++ err = ag71xx_debugfs_init(ag);
++ if (err)
++ goto err_phy_disconnect;
++
++ platform_set_drvdata(pdev, dev);
++
++ return 0;
++
++ err_phy_disconnect:
++ ag71xx_phy_disconnect(ag);
++ err_unregister_netdev:
++ unregister_netdev(dev);
++ err_free_irq:
++ free_irq(dev->irq, dev);
++ err_unmap_mii_ctrl:
++ iounmap(ag->mii_ctrl);
++ err_unmap_base:
++ iounmap(ag->mac_base);
++ err_free_dev:
++ kfree(dev);
++ err_out:
++ platform_set_drvdata(pdev, NULL);
++ return err;
++}
++
++static int __exit ag71xx_remove(struct platform_device *pdev)
++{
++ struct net_device *dev = platform_get_drvdata(pdev);
++
++ if (dev) {
++ struct ag71xx *ag = netdev_priv(dev);
++
++ ag71xx_debugfs_exit(ag);
++ ag71xx_phy_disconnect(ag);
++ unregister_netdev(dev);
++ free_irq(dev->irq, dev);
++ iounmap(ag->mii_ctrl);
++ iounmap(ag->mac_base);
++ kfree(dev);
++ platform_set_drvdata(pdev, NULL);
++ }
++
++ return 0;
++}
++
++static struct platform_driver ag71xx_driver = {
++ .probe = ag71xx_probe,
++ .remove = __exit_p(ag71xx_remove),
++ .driver = {
++ .name = AG71XX_DRV_NAME,
++ }
++};
++
++static int __init ag71xx_module_init(void)
++{
++ int ret;
++
++ ret = ag71xx_debugfs_root_init();
++ if (ret)
++ goto err_out;
++
++ ret = ag71xx_mdio_driver_init();
++ if (ret)
++ goto err_debugfs_exit;
++
++ ret = platform_driver_register(&ag71xx_driver);
++ if (ret)
++ goto err_mdio_exit;
++
++ return 0;
++
++ err_mdio_exit:
++ ag71xx_mdio_driver_exit();
++ err_debugfs_exit:
++ ag71xx_debugfs_root_exit();
++ err_out:
++ return ret;
++}
++
++static void __exit ag71xx_module_exit(void)
++{
++ platform_driver_unregister(&ag71xx_driver);
++ ag71xx_mdio_driver_exit();
++ ag71xx_debugfs_root_exit();
++}
++
++module_init(ag71xx_module_init);
++module_exit(ag71xx_module_exit);
++
++MODULE_VERSION(AG71XX_DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" AG71XX_DRV_NAME);
+diff -Nur linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_mdio.c linux-2.6.37/drivers/net/ag71xx/ag71xx_mdio.c
+--- linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_mdio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/net/ag71xx/ag71xx_mdio.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,243 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++#define AG71XX_MDIO_RETRY 1000
++#define AG71XX_MDIO_DELAY 5
++
++static inline void ag71xx_mdio_wr(struct ag71xx_mdio *am, unsigned reg,
++ u32 value)
++{
++ void __iomem *r;
++
++ r = am->mdio_base + reg;
++ __raw_writel(value, r);
++
++ /* flush write */
++ (void) __raw_readl(r);
++}
++
++static inline u32 ag71xx_mdio_rr(struct ag71xx_mdio *am, unsigned reg)
++{
++ return __raw_readl(am->mdio_base + reg);
++}
++
++static void ag71xx_mdio_dump_regs(struct ag71xx_mdio *am)
++{
++ DBG("%s: mii_cfg=%08x, mii_cmd=%08x, mii_addr=%08x\n",
++ am->mii_bus->name,
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_CFG),
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_CMD),
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_ADDR));
++ DBG("%s: mii_ctrl=%08x, mii_status=%08x, mii_ind=%08x\n",
++ am->mii_bus->name,
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_CTRL),
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_STATUS),
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_IND));
++}
++
++static int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg)
++{
++ int ret;
++ int i;
++
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_ADDR,
++ ((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_READ);
++
++ i = AG71XX_MDIO_RETRY;
++ while (ag71xx_mdio_rr(am, AG71XX_REG_MII_IND) & MII_IND_BUSY) {
++ if (i-- == 0) {
++ printk(KERN_ERR "%s: mii_read timed out\n",
++ am->mii_bus->name);
++ ret = 0xffff;
++ goto out;
++ }
++ udelay(AG71XX_MDIO_DELAY);
++ }
++
++ ret = ag71xx_mdio_rr(am, AG71XX_REG_MII_STATUS) & 0xffff;
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
++
++ DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr, reg, ret);
++
++ out:
++ return ret;
++}
++
++static void ag71xx_mdio_mii_write(struct ag71xx_mdio *am,
++ int addr, int reg, u16 val)
++{
++ int i;
++
++ DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr, reg, val);
++
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_ADDR,
++ ((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CTRL, val);
++
++ i = AG71XX_MDIO_RETRY;
++ while (ag71xx_mdio_rr(am, AG71XX_REG_MII_IND) & MII_IND_BUSY) {
++ if (i-- == 0) {
++ printk(KERN_ERR "%s: mii_write timed out\n",
++ am->mii_bus->name);
++ break;
++ }
++ udelay(AG71XX_MDIO_DELAY);
++ }
++}
++
++static int ag71xx_mdio_reset(struct mii_bus *bus)
++{
++ struct ag71xx_mdio *am = bus->priv;
++ u32 t;
++
++ if (am->pdata->is_ar7240)
++ t = MII_CFG_CLK_DIV_6;
++ else
++ t = MII_CFG_CLK_DIV_28;
++
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t | MII_CFG_RESET);
++ udelay(100);
++
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t);
++ udelay(100);
++
++ return 0;
++}
++
++static int ag71xx_mdio_read(struct mii_bus *bus, int addr, int reg)
++{
++ struct ag71xx_mdio *am = bus->priv;
++
++ return ag71xx_mdio_mii_read(am, addr, reg);
++}
++
++static int ag71xx_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val)
++{
++ struct ag71xx_mdio *am = bus->priv;
++
++ ag71xx_mdio_mii_write(am, addr, reg, val);
++ return 0;
++}
++
++static int __init ag71xx_mdio_probe(struct platform_device *pdev)
++{
++ struct ag71xx_mdio_platform_data *pdata;
++ struct ag71xx_mdio *am;
++ struct resource *res;
++ int i;
++ int err;
++
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ dev_err(&pdev->dev, "no platform data specified\n");
++ return -EINVAL;
++ }
++
++ am = kzalloc(sizeof(*am), GFP_KERNEL);
++ if (!am) {
++ err = -ENOMEM;
++ goto err_out;
++ }
++
++ am->pdata = pdata;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev, "no iomem resource found\n");
++ err = -ENXIO;
++ goto err_out;
++ }
++
++ am->mdio_base = ioremap_nocache(res->start, res->end - res->start + 1);
++ if (!am->mdio_base) {
++ dev_err(&pdev->dev, "unable to ioremap registers\n");
++ err = -ENOMEM;
++ goto err_free_mdio;
++ }
++
++ am->mii_bus = mdiobus_alloc();
++ if (am->mii_bus == NULL) {
++ err = -ENOMEM;
++ goto err_iounmap;
++ }
++
++ am->mii_bus->name = "ag71xx_mdio";
++ am->mii_bus->read = ag71xx_mdio_read;
++ am->mii_bus->write = ag71xx_mdio_write;
++ am->mii_bus->reset = ag71xx_mdio_reset;
++ am->mii_bus->irq = am->mii_irq;
++ am->mii_bus->priv = am;
++ am->mii_bus->parent = &pdev->dev;
++ snprintf(am->mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(&pdev->dev));
++ am->mii_bus->phy_mask = pdata->phy_mask;
++
++ for (i = 0; i < PHY_MAX_ADDR; i++)
++ am->mii_irq[i] = PHY_POLL;
++
++ ag71xx_mdio_wr(am, AG71XX_REG_MAC_CFG1, 0);
++
++ err = mdiobus_register(am->mii_bus);
++ if (err)
++ goto err_free_bus;
++
++ ag71xx_mdio_dump_regs(am);
++
++ platform_set_drvdata(pdev, am);
++ return 0;
++
++ err_free_bus:
++ mdiobus_free(am->mii_bus);
++ err_iounmap:
++ iounmap(am->mdio_base);
++ err_free_mdio:
++ kfree(am);
++ err_out:
++ return err;
++}
++
++static int __exit ag71xx_mdio_remove(struct platform_device *pdev)
++{
++ struct ag71xx_mdio *am = platform_get_drvdata(pdev);
++
++ if (am) {
++ mdiobus_unregister(am->mii_bus);
++ mdiobus_free(am->mii_bus);
++ iounmap(am->mdio_base);
++ kfree(am);
++ platform_set_drvdata(pdev, NULL);
++ }
++
++ return 0;
++}
++
++static struct platform_driver ag71xx_mdio_driver = {
++ .probe = ag71xx_mdio_probe,
++ .remove = __exit_p(ag71xx_mdio_remove),
++ .driver = {
++ .name = "ag71xx-mdio",
++ }
++};
++
++int ag71xx_mdio_driver_init(void)
++{
++ return platform_driver_register(&ag71xx_mdio_driver);
++}
++
++void ag71xx_mdio_driver_exit(void)
++{
++ platform_driver_unregister(&ag71xx_mdio_driver);
++}
+diff -Nur linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_phy.c linux-2.6.37/drivers/net/ag71xx/ag71xx_phy.c
+--- linux-2.6.37.orig/drivers/net/ag71xx/ag71xx_phy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/net/ag71xx/ag71xx_phy.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,213 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++static void ag71xx_phy_link_adjust(struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ struct phy_device *phydev = ag->phy_dev;
++ unsigned long flags;
++ int status_change = 0;
++
++ spin_lock_irqsave(&ag->lock, flags);
++
++ if (phydev->link) {
++ if (ag->duplex != phydev->duplex
++ || ag->speed != phydev->speed) {
++ status_change = 1;
++ }
++ }
++
++ if (phydev->link != ag->link)
++ status_change = 1;
++
++ ag->link = phydev->link;
++ ag->duplex = phydev->duplex;
++ ag->speed = phydev->speed;
++
++ if (status_change)
++ ag71xx_link_adjust(ag);
++
++ spin_unlock_irqrestore(&ag->lock, flags);
++}
++
++void ag71xx_phy_start(struct ag71xx *ag)
++{
++ if (ag->phy_dev) {
++ phy_start(ag->phy_dev);
++ } else {
++ ag->link = 1;
++ ag71xx_link_adjust(ag);
++ }
++}
++
++void ag71xx_phy_stop(struct ag71xx *ag)
++{
++ if (ag->phy_dev) {
++ phy_stop(ag->phy_dev);
++ } else {
++ ag->link = 0;
++ ag71xx_link_adjust(ag);
++ }
++}
++
++static int ag71xx_phy_connect_fixed(struct ag71xx *ag)
++{
++ struct net_device *dev = ag->dev;
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ int ret = 0;
++
++ /* use fixed settings */
++ switch (pdata->speed) {
++ case SPEED_10:
++ case SPEED_100:
++ case SPEED_1000:
++ break;
++ default:
++ printk(KERN_ERR "%s: invalid speed specified\n", dev->name);
++ ret = -EINVAL;
++ break;
++ }
++
++ printk(KERN_DEBUG "%s: using fixed link parameters\n", dev->name);
++
++ ag->duplex = pdata->duplex;
++ ag->speed = pdata->speed;
++
++ return ret;
++}
++
++static int ag71xx_phy_connect_multi(struct ag71xx *ag)
++{
++ struct net_device *dev = ag->dev;
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ struct phy_device *phydev = NULL;
++ int phy_addr;
++ int ret = 0;
++
++ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
++ if (!(pdata->phy_mask & (1 << phy_addr)))
++ continue;
++
++ if (ag->mii_bus->phy_map[phy_addr] == NULL)
++ continue;
++
++ DBG("%s: PHY found at %s, uid=%08x\n",
++ dev->name,
++ dev_name(&ag->mii_bus->phy_map[phy_addr]->dev),
++ ag->mii_bus->phy_map[phy_addr]->phy_id);
++
++ if (phydev == NULL)
++ phydev = ag->mii_bus->phy_map[phy_addr];
++ }
++
++ if (!phydev) {
++ printk(KERN_ERR "%s: no PHY found with phy_mask=%08x\n",
++ dev->name, pdata->phy_mask);
++ return -ENODEV;
++ }
++
++ ag->phy_dev = phy_connect(dev, dev_name(&phydev->dev),
++ &ag71xx_phy_link_adjust, 0,
++ pdata->phy_if_mode);
++
++ if (IS_ERR(ag->phy_dev)) {
++ printk(KERN_ERR "%s: could not connect to PHY at %s\n",
++ dev->name, dev_name(&phydev->dev));
++ return PTR_ERR(ag->phy_dev);
++ }
++
++ /* mask with MAC supported features */
++ if (pdata->has_gbit)
++ phydev->supported &= PHY_GBIT_FEATURES;
++ else
++ phydev->supported &= PHY_BASIC_FEATURES;
++
++ phydev->advertising = phydev->supported;
++
++ printk(KERN_DEBUG "%s: connected to PHY at %s [uid=%08x, driver=%s]\n",
++ dev->name, dev_name(&phydev->dev),
++ phydev->phy_id, phydev->drv->name);
++
++ ag->link = 0;
++ ag->speed = 0;
++ ag->duplex = -1;
++
++ return ret;
++}
++
++static int dev_is_class(struct device *dev, void *class)
++{
++ if (dev->class != NULL && !strcmp(dev->class->name, class))
++ return 1;
++
++ return 0;
++}
++
++static struct device *dev_find_class(struct device *parent, char *class)
++{
++ if (dev_is_class(parent, class)) {
++ get_device(parent);
++ return parent;
++ }
++
++ return device_find_child(parent, class, dev_is_class);
++}
++
++static struct mii_bus *dev_to_mii_bus(struct device *dev)
++{
++ struct device *d;
++
++ d = dev_find_class(dev, "mdio_bus");
++ if (d != NULL) {
++ struct mii_bus *bus;
++
++ bus = to_mii_bus(d);
++ put_device(d);
++
++ return bus;
++ }
++
++ return NULL;
++}
++
++int ag71xx_phy_connect(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++ ag->mii_bus = dev_to_mii_bus(pdata->mii_bus_dev);
++ if (ag->mii_bus == NULL) {
++ printk(KERN_ERR "%s: unable to find MII bus on device '%s'\n",
++ ag->dev->name, dev_name(pdata->mii_bus_dev));
++ return -ENODEV;
++ }
++
++ /* Reset the mdio bus explicitly */
++ if (ag->mii_bus->reset) {
++ mutex_lock(&ag->mii_bus->mdio_lock);
++ ag->mii_bus->reset(ag->mii_bus);
++ mutex_unlock(&ag->mii_bus->mdio_lock);
++ }
++
++ if (pdata->phy_mask)
++ return ag71xx_phy_connect_multi(ag);
++
++ return ag71xx_phy_connect_fixed(ag);
++}
++
++void ag71xx_phy_disconnect(struct ag71xx *ag)
++{
++ if (ag->phy_dev)
++ phy_disconnect(ag->phy_dev);
++}
+diff -Nur linux-2.6.37.orig/drivers/net/phy/Kconfig linux-2.6.37/drivers/net/phy/Kconfig
+--- linux-2.6.37.orig/drivers/net/phy/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/net/phy/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -92,6 +92,10 @@
+ ---help---
+ Supports the KSZ9021, VSC8201, KS8001 PHYs.
+
++config IP175C_PHY
++ tristate "Driver for IC+ IP175C/IP178C switches"
++ select SWCONFIG
++
+ config FIXED_PHY
+ bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ depends on PHYLIB=y
+diff -Nur linux-2.6.37.orig/drivers/net/phy/phy.c linux-2.6.37/drivers/net/phy/phy.c
+--- linux-2.6.37.orig/drivers/net/phy/phy.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/net/phy/phy.c 2011-01-11 20:25:48.000000000 +0100
+@@ -297,6 +297,50 @@
+ }
+ EXPORT_SYMBOL(phy_ethtool_gset);
+
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr)
++{
++ u32 cmd;
++ int tmp;
++ struct ethtool_cmd ecmd = { ETHTOOL_GSET };
++ struct ethtool_value edata = { ETHTOOL_GLINK };
++
++ if (get_user(cmd, (u32 *) useraddr))
++ return -EFAULT;
++
++ switch (cmd) {
++ case ETHTOOL_GSET:
++ phy_ethtool_gset(phydev, &ecmd);
++ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
++ return -EFAULT;
++ return 0;
++
++ case ETHTOOL_SSET:
++ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
++ return -EFAULT;
++ return phy_ethtool_sset(phydev, &ecmd);
++
++ case ETHTOOL_NWAY_RST:
++ /* if autoneg is off, it's an error */
++ tmp = phy_read(phydev, MII_BMCR);
++ if (tmp & BMCR_ANENABLE) {
++ tmp |= (BMCR_ANRESTART);
++ phy_write(phydev, MII_BMCR, tmp);
++ return 0;
++ }
++ return -EINVAL;
++
++ case ETHTOOL_GLINK:
++ edata.data = (phy_read(phydev,
++ MII_BMSR) & BMSR_LSTATUS) ? 1 : 0;
++ if (copy_to_user(useraddr, &edata, sizeof(edata)))
++ return -EFAULT;
++ return 0;
++ }
++
++ return -EOPNOTSUPP;
++}
++EXPORT_SYMBOL(phy_ethtool_ioctl);
++
+ /**
+ * phy_mii_ioctl - generic PHY MII ioctl interface
+ * @phydev: the phy_device struct
+@@ -351,7 +395,7 @@
+ }
+
+ phy_write(phydev, mii_data->reg_num, val);
+-
++
+ if (mii_data->reg_num == MII_BMCR &&
+ val & BMCR_RESET &&
+ phydev->drv->config_init) {
+@@ -470,7 +514,7 @@
+ int idx;
+
+ idx = phy_find_setting(phydev->speed, phydev->duplex);
+-
++
+ idx++;
+
+ idx = phy_find_valid(idx, phydev->supported);
+diff -Nur linux-2.6.37.orig/drivers/net/phy/phy_device.c linux-2.6.37/drivers/net/phy/phy_device.c
+--- linux-2.6.37.orig/drivers/net/phy/phy_device.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/net/phy/phy_device.c 2011-01-11 20:27:54.000000000 +0100
+@@ -149,6 +149,19 @@
+ }
+ EXPORT_SYMBOL(phy_scan_fixups);
+
++static int generic_receive_skb(struct sk_buff *skb)
++{
++ skb->protocol = eth_type_trans(skb, skb->dev);
++ return netif_receive_skb(skb);
++}
++
++static int generic_rx(struct sk_buff *skb)
++{
++ skb->protocol = eth_type_trans(skb, skb->dev);
++ return netif_rx(skb);
++}
++
++
+ static struct phy_device* phy_device_create(struct mii_bus *bus,
+ int addr, int phy_id)
+ {
+@@ -180,6 +193,8 @@
+ dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr);
+
+ dev->state = PHY_DOWN;
++ dev->netif_receive_skb = &generic_receive_skb;
++ dev->netif_rx = &generic_rx;
+
+ mutex_init(&dev->lock);
+ INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
+diff -Nur linux-2.6.37.orig/drivers/spi/Kconfig linux-2.6.37/drivers/spi/Kconfig
+--- linux-2.6.37.orig/drivers/spi/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/spi/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -53,6 +53,13 @@
+
+ comment "SPI Master Controller Drivers"
+
++config SPI_AR71XX
++ tristate "Atheros AR71xx SPI Controller"
++ depends on SPI_MASTER && ATHEROS_AR71XX
++ select SPI_BITBANG
++ help
++ This is the SPI contoller driver for Atheros AR71xx.
++
+ config SPI_ATMEL
+ tristate "Atmel SPI Controller"
+ depends on (ARCH_AT91 || AVR32)
+diff -Nur linux-2.6.37.orig/drivers/spi/Makefile linux-2.6.37/drivers/spi/Makefile
+--- linux-2.6.37.orig/drivers/spi/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/spi/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -9,6 +9,7 @@
+ obj-$(CONFIG_SPI_MASTER) += spi.o
+
+ # SPI master controller drivers (bus)
++obj-$(CONFIG_SPI_AR71XX) += ar71xx_spi.o
+ obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o
+ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o
+ obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
+diff -Nur linux-2.6.37.orig/drivers/spi/ap83_spi.c linux-2.6.37/drivers/spi/ap83_spi.c
+--- linux-2.6.37.orig/drivers/spi/ap83_spi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/spi/ap83_spi.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,282 @@
++/*
++ * Atheros AP83 board specific SPI Controller driver
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/bitops.h>
++#include <linux/gpio.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/platform.h>
++
++#define DRV_DESC "Atheros AP83 board SPI Controller driver"
++#define DRV_VERSION "0.1.0"
++#define DRV_NAME "ap83-spi"
++
++#define AP83_SPI_CLK_HIGH (1 << 23)
++#define AP83_SPI_CLK_LOW 0
++#define AP83_SPI_MOSI_HIGH (1 << 22)
++#define AP83_SPI_MOSI_LOW 0
++
++#define AP83_SPI_GPIO_CS 1
++#define AP83_SPI_GPIO_MISO 3
++
++struct ap83_spi {
++ struct spi_bitbang bitbang;
++ void __iomem *base;
++ u32 addr;
++
++ struct platform_device *pdev;
++};
++
++static inline u32 ap83_spi_rr(struct ap83_spi *sp, u32 reg)
++{
++ return __raw_readl(sp->base + reg);
++}
++
++static inline struct ap83_spi *spidev_to_sp(struct spi_device *spi)
++{
++ return spi_master_get_devdata(spi->master);
++}
++
++static inline void setsck(struct spi_device *spi, int val)
++{
++ struct ap83_spi *sp = spidev_to_sp(spi);
++
++ if (val)
++ sp->addr |= AP83_SPI_CLK_HIGH;
++ else
++ sp->addr &= ~AP83_SPI_CLK_HIGH;
++
++ dev_dbg(&spi->dev, "addr=%08x, SCK set to %s\n",
++ sp->addr, (val) ? "HIGH" : "LOW");
++
++ ap83_spi_rr(sp, sp->addr);
++}
++
++static inline void setmosi(struct spi_device *spi, int val)
++{
++ struct ap83_spi *sp = spidev_to_sp(spi);
++
++ if (val)
++ sp->addr |= AP83_SPI_MOSI_HIGH;
++ else
++ sp->addr &= ~AP83_SPI_MOSI_HIGH;
++
++ dev_dbg(&spi->dev, "addr=%08x, MOSI set to %s\n",
++ sp->addr, (val) ? "HIGH" : "LOW");
++
++ ap83_spi_rr(sp, sp->addr);
++}
++
++static inline u32 getmiso(struct spi_device *spi)
++{
++ u32 ret;
++
++ ret = gpio_get_value(AP83_SPI_GPIO_MISO) ? 1 : 0;
++ dev_dbg(&spi->dev, "get MISO: %d\n", ret);
++
++ return ret;
++}
++
++static inline void do_spidelay(struct spi_device *spi, unsigned nsecs)
++{
++ ndelay(nsecs);
++}
++
++static void ap83_spi_chipselect(struct spi_device *spi, int on)
++{
++ struct ap83_spi *sp = spidev_to_sp(spi);
++
++ dev_dbg(&spi->dev, "set CS to %d\n", (on) ? 0 : 1);
++
++ if (on) {
++ ar71xx_flash_acquire();
++
++ sp->addr = 0;
++ ap83_spi_rr(sp, sp->addr);
++
++ gpio_set_value(AP83_SPI_GPIO_CS, 0);
++ } else {
++ gpio_set_value(AP83_SPI_GPIO_CS, 1);
++ ar71xx_flash_release();
++ }
++}
++
++#define spidelay(nsecs) \
++ do { \
++ /* Steal the spi_device pointer from our caller. \
++ * The bitbang-API should probably get fixed here... */ \
++ do_spidelay(spi, nsecs); \
++ } while (0)
++
++#define EXPAND_BITBANG_TXRX
++#include <linux/spi/spi_bitbang.h>
++
++static u32 ap83_spi_txrx_mode0(struct spi_device *spi,
++ unsigned nsecs, u32 word, u8 bits)
++{
++ dev_dbg(&spi->dev, "TXRX0 word=%08x, bits=%u\n", word, bits);
++ return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
++}
++
++static u32 ap83_spi_txrx_mode1(struct spi_device *spi,
++ unsigned nsecs, u32 word, u8 bits)
++{
++ dev_dbg(&spi->dev, "TXRX1 word=%08x, bits=%u\n", word, bits);
++ return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
++}
++
++static u32 ap83_spi_txrx_mode2(struct spi_device *spi,
++ unsigned nsecs, u32 word, u8 bits)
++{
++ dev_dbg(&spi->dev, "TXRX2 word=%08x, bits=%u\n", word, bits);
++ return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
++}
++
++static u32 ap83_spi_txrx_mode3(struct spi_device *spi,
++ unsigned nsecs, u32 word, u8 bits)
++{
++ dev_dbg(&spi->dev, "TXRX3 word=%08x, bits=%u\n", word, bits);
++ return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
++}
++
++static int ap83_spi_probe(struct platform_device *pdev)
++{
++ struct spi_master *master;
++ struct ap83_spi *sp;
++ struct ap83_spi_platform_data *pdata;
++ struct resource *r;
++ int ret;
++
++ ret = gpio_request(AP83_SPI_GPIO_MISO, "spi-miso");
++ if (ret) {
++ dev_err(&pdev->dev, "gpio request failed for MISO\n");
++ return ret;
++ }
++
++ ret = gpio_request(AP83_SPI_GPIO_CS, "spi-cs");
++ if (ret) {
++ dev_err(&pdev->dev, "gpio request failed for CS\n");
++ goto err_free_miso;
++ }
++
++ ret = gpio_direction_input(AP83_SPI_GPIO_MISO);
++ if (ret) {
++ dev_err(&pdev->dev, "unable to set direction of MISO\n");
++ goto err_free_cs;
++ }
++
++ ret = gpio_direction_output(AP83_SPI_GPIO_CS, 0);
++ if (ret) {
++ dev_err(&pdev->dev, "unable to set direction of CS\n");
++ goto err_free_cs;
++ }
++
++ master = spi_alloc_master(&pdev->dev, sizeof(*sp));
++ if (master == NULL) {
++ dev_err(&pdev->dev, "failed to allocate spi master\n");
++ return -ENOMEM;
++ }
++
++ sp = spi_master_get_devdata(master);
++ platform_set_drvdata(pdev, sp);
++
++ pdata = pdev->dev.platform_data;
++
++ sp->bitbang.master = spi_master_get(master);
++ sp->bitbang.chipselect = ap83_spi_chipselect;
++ sp->bitbang.txrx_word[SPI_MODE_0] = ap83_spi_txrx_mode0;
++ sp->bitbang.txrx_word[SPI_MODE_1] = ap83_spi_txrx_mode1;
++ sp->bitbang.txrx_word[SPI_MODE_2] = ap83_spi_txrx_mode2;
++ sp->bitbang.txrx_word[SPI_MODE_3] = ap83_spi_txrx_mode3;
++
++ sp->bitbang.master->bus_num = pdev->id;
++ sp->bitbang.master->num_chipselect = 1;
++
++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (r == NULL) {
++ ret = -ENOENT;
++ goto err_spi_put;
++ }
++
++ sp->base = ioremap_nocache(r->start, r->end - r->start + 1);
++ if (!sp->base) {
++ ret = -ENXIO;
++ goto err_spi_put;
++ }
++
++ ret = spi_bitbang_start(&sp->bitbang);
++ if (!ret)
++ goto err_unmap;
++
++ dev_info(&pdev->dev, "AP83 SPI adapter at %08x\n", r->start);
++
++ return 0;
++
++ err_unmap:
++ iounmap(sp->base);
++ err_spi_put:
++ platform_set_drvdata(pdev, NULL);
++ spi_master_put(sp->bitbang.master);
++
++ err_free_cs:
++ gpio_free(AP83_SPI_GPIO_CS);
++ err_free_miso:
++ gpio_free(AP83_SPI_GPIO_MISO);
++ return ret;
++}
++
++static int ap83_spi_remove(struct platform_device *pdev)
++{
++ struct ap83_spi *sp = platform_get_drvdata(pdev);
++
++ spi_bitbang_stop(&sp->bitbang);
++ iounmap(sp->base);
++ platform_set_drvdata(pdev, NULL);
++ spi_master_put(sp->bitbang.master);
++
++ return 0;
++}
++
++static struct platform_driver ap83_spi_drv = {
++ .probe = ap83_spi_probe,
++ .remove = ap83_spi_remove,
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init ap83_spi_init(void)
++{
++ return platform_driver_register(&ap83_spi_drv);
++}
++module_init(ap83_spi_init);
++
++static void __exit ap83_spi_exit(void)
++{
++ platform_driver_unregister(&ap83_spi_drv);
++}
++module_exit(ap83_spi_exit);
++
++MODULE_ALIAS("platform:" DRV_NAME);
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.37.orig/drivers/spi/ar71xx_spi.c linux-2.6.37/drivers/spi/ar71xx_spi.c
+--- linux-2.6.37.orig/drivers/spi/ar71xx_spi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/spi/ar71xx_spi.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,283 @@
++/*
++ * Atheros AR71xx SPI Controller driver
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/bitops.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/platform.h>
++
++#define DRV_DESC "Atheros AR71xx SPI Controller driver"
++#define DRV_VERSION "0.2.4"
++#define DRV_NAME "ar71xx-spi"
++
++#undef PER_BIT_READ
++
++struct ar71xx_spi {
++ struct spi_bitbang bitbang;
++ u32 ioc_base;
++ u32 reg_ctrl;
++
++ void __iomem *base;
++
++ struct platform_device *pdev;
++ u32 (*get_ioc_base)(u8 chip_select, int cs_high,
++ int is_on);
++};
++
++static inline u32 ar71xx_spi_rr(struct ar71xx_spi *sp, unsigned reg)
++{
++ return __raw_readl(sp->base + reg);
++}
++
++static inline void ar71xx_spi_wr(struct ar71xx_spi *sp, unsigned reg, u32 val)
++{
++ __raw_writel(val, sp->base + reg);
++}
++
++static inline struct ar71xx_spi *spidev_to_sp(struct spi_device *spi)
++{
++ return spi_master_get_devdata(spi->master);
++}
++
++static u32 ar71xx_spi_get_ioc_base(u8 chip_select, int cs_high, int is_on)
++{
++ u32 ret;
++
++ if (is_on == AR71XX_SPI_CS_INACTIVE)
++ ret = SPI_IOC_CS_ALL;
++ else
++ ret = SPI_IOC_CS_ALL & ~SPI_IOC_CS(chip_select);
++
++ return ret;
++}
++
++static void ar71xx_spi_chipselect(struct spi_device *spi, int value)
++{
++ struct ar71xx_spi *sp = spidev_to_sp(spi);
++ void __iomem *base = sp->base;
++ u32 ioc_base;
++
++ switch (value) {
++ case BITBANG_CS_INACTIVE:
++ ioc_base = sp->get_ioc_base(spi->chip_select,
++ (spi->mode & SPI_CS_HIGH) != 0,
++ AR71XX_SPI_CS_INACTIVE);
++ __raw_writel(ioc_base, base + SPI_REG_IOC);
++ break;
++
++ case BITBANG_CS_ACTIVE:
++ ioc_base = sp->get_ioc_base(spi->chip_select,
++ (spi->mode & SPI_CS_HIGH) != 0,
++ AR71XX_SPI_CS_ACTIVE);
++
++ __raw_writel(ioc_base, base + SPI_REG_IOC);
++ sp->ioc_base = ioc_base;
++ break;
++ }
++}
++
++static void ar71xx_spi_setup_regs(struct spi_device *spi)
++{
++ struct ar71xx_spi *sp = spidev_to_sp(spi);
++
++ /* enable GPIO mode */
++ ar71xx_spi_wr(sp, SPI_REG_FS, SPI_FS_GPIO);
++
++ /* save CTRL register */
++ sp->reg_ctrl = ar71xx_spi_rr(sp, SPI_REG_CTRL);
++
++ /* TODO: setup speed? */
++ ar71xx_spi_wr(sp, SPI_REG_CTRL, 0x43);
++}
++
++static void ar71xx_spi_restore_regs(struct spi_device *spi)
++{
++ struct ar71xx_spi *sp = spidev_to_sp(spi);
++
++ /* restore CTRL register */
++ ar71xx_spi_wr(sp, SPI_REG_CTRL, sp->reg_ctrl);
++ /* disable GPIO mode */
++ ar71xx_spi_wr(sp, SPI_REG_FS, 0);
++}
++
++static int ar71xx_spi_setup(struct spi_device *spi)
++{
++ int status;
++
++ if (spi->bits_per_word > 32)
++ return -EINVAL;
++
++ if (!spi->controller_state)
++ ar71xx_spi_setup_regs(spi);
++
++ status = spi_bitbang_setup(spi);
++ if (status && !spi->controller_state)
++ ar71xx_spi_restore_regs(spi);
++
++ return status;
++}
++
++static void ar71xx_spi_cleanup(struct spi_device *spi)
++{
++ ar71xx_spi_restore_regs(spi);
++ spi_bitbang_cleanup(spi);
++}
++
++static u32 ar71xx_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
++ u32 word, u8 bits)
++{
++ struct ar71xx_spi *sp = spidev_to_sp(spi);
++ void __iomem *base = sp->base;
++ u32 ioc = sp->ioc_base;
++ u32 ret;
++
++ /* clock starts at inactive polarity */
++ for (word <<= (32 - bits); likely(bits); bits--) {
++ u32 out;
++
++ if (word & (1 << 31))
++ out = ioc | SPI_IOC_DO;
++ else
++ out = ioc & ~SPI_IOC_DO;
++
++ /* setup MSB (to slave) on trailing edge */
++ __raw_writel(out, base + SPI_REG_IOC);
++
++ __raw_writel(out | SPI_IOC_CLK, base + SPI_REG_IOC);
++
++ word <<= 1;
++
++#ifdef PER_BIT_READ
++ /* sample MSB (from slave) on leading edge */
++ ret = __raw_readl(base + SPI_REG_RDS);
++ __raw_writel(out, base + SPI_REG_IOC);
++#endif
++
++ }
++
++#ifndef PER_BIT_READ
++ ret = __raw_readl(base + SPI_REG_RDS);
++#endif
++ return ret;
++}
++
++static int ar71xx_spi_probe(struct platform_device *pdev)
++{
++ struct spi_master *master;
++ struct ar71xx_spi *sp;
++ struct ar71xx_spi_platform_data *pdata;
++ struct resource *r;
++ int ret;
++
++ master = spi_alloc_master(&pdev->dev, sizeof(*sp));
++ if (master == NULL) {
++ dev_err(&pdev->dev, "failed to allocate spi master\n");
++ return -ENOMEM;
++ }
++
++ sp = spi_master_get_devdata(master);
++ platform_set_drvdata(pdev, sp);
++
++ pdata = pdev->dev.platform_data;
++
++ master->setup = ar71xx_spi_setup;
++ master->cleanup = ar71xx_spi_cleanup;
++
++ sp->bitbang.master = spi_master_get(master);
++ sp->bitbang.chipselect = ar71xx_spi_chipselect;
++ sp->bitbang.txrx_word[SPI_MODE_0] = ar71xx_spi_txrx_mode0;
++ sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
++
++ sp->get_ioc_base = ar71xx_spi_get_ioc_base;
++ if (pdata) {
++ sp->bitbang.master->bus_num = pdata->bus_num;
++ sp->bitbang.master->num_chipselect = pdata->num_chipselect;
++ if (pdata->get_ioc_base)
++ sp->get_ioc_base = pdata->get_ioc_base;
++ } else {
++ sp->bitbang.master->bus_num = 0;
++ sp->bitbang.master->num_chipselect = 3;
++ }
++
++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (r == NULL) {
++ ret = -ENOENT;
++ goto err1;
++ }
++
++ sp->base = ioremap_nocache(r->start, r->end - r->start + 1);
++ if (!sp->base) {
++ ret = -ENXIO;
++ goto err1;
++ }
++
++ ret = spi_bitbang_start(&sp->bitbang);
++ if (!ret)
++ return 0;
++
++ iounmap(sp->base);
++ err1:
++ platform_set_drvdata(pdev, NULL);
++ spi_master_put(sp->bitbang.master);
++
++ return ret;
++}
++
++static int ar71xx_spi_remove(struct platform_device *pdev)
++{
++ struct ar71xx_spi *sp = platform_get_drvdata(pdev);
++
++ spi_bitbang_stop(&sp->bitbang);
++ iounmap(sp->base);
++ platform_set_drvdata(pdev, NULL);
++ spi_master_put(sp->bitbang.master);
++
++ return 0;
++}
++
++static struct platform_driver ar71xx_spi_drv = {
++ .probe = ar71xx_spi_probe,
++ .remove = ar71xx_spi_remove,
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init ar71xx_spi_init(void)
++{
++ printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
++ return platform_driver_register(&ar71xx_spi_drv);
++}
++module_init(ar71xx_spi_init);
++
++static void __exit ar71xx_spi_exit(void)
++{
++ platform_driver_unregister(&ar71xx_spi_drv);
++}
++module_exit(ar71xx_spi_exit);
++
++MODULE_ALIAS("platform:" DRV_NAME);
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.37.orig/drivers/spi/pb44_spi.c linux-2.6.37/drivers/spi/pb44_spi.c
+--- linux-2.6.37.orig/drivers/spi/pb44_spi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/spi/pb44_spi.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,299 @@
++/*
++ * Atheros PB44 board SPI controller driver
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/bitops.h>
++#include <linux/gpio.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++#include <asm/mach-ar71xx/platform.h>
++
++#define DRV_DESC "Atheros PB44 SPI Controller driver"
++#define DRV_VERSION "0.1.0"
++#define DRV_NAME "pb44-spi"
++
++#undef PER_BIT_READ
++
++struct ar71xx_spi {
++ struct spi_bitbang bitbang;
++ u32 ioc_base;
++ u32 reg_ctrl;
++
++ void __iomem *base;
++
++ struct platform_device *pdev;
++};
++
++static inline u32 pb44_spi_rr(struct ar71xx_spi *sp, unsigned reg)
++{
++ return __raw_readl(sp->base + reg);
++}
++
++static inline void pb44_spi_wr(struct ar71xx_spi *sp, unsigned reg, u32 val)
++{
++ __raw_writel(val, sp->base + reg);
++}
++
++static inline struct ar71xx_spi *spidev_to_sp(struct spi_device *spi)
++{
++ return spi_master_get_devdata(spi->master);
++}
++
++static void pb44_spi_chipselect(struct spi_device *spi, int is_active)
++{
++ struct ar71xx_spi *sp = spidev_to_sp(spi);
++ int cs_high = (spi->mode & SPI_CS_HIGH) ? is_active : !is_active;
++
++ if (is_active) {
++ /* set initial clock polarity */
++ if (spi->mode & SPI_CPOL)
++ sp->ioc_base |= SPI_IOC_CLK;
++ else
++ sp->ioc_base &= ~SPI_IOC_CLK;
++
++ pb44_spi_wr(sp, SPI_REG_IOC, sp->ioc_base);
++ }
++
++ if (spi->chip_select) {
++ unsigned long gpio = (unsigned long) spi->controller_data;
++
++ /* SPI is normally active-low */
++ gpio_set_value(gpio, cs_high);
++ } else {
++ if (cs_high)
++ sp->ioc_base |= SPI_IOC_CS0;
++ else
++ sp->ioc_base &= ~SPI_IOC_CS0;
++
++ pb44_spi_wr(sp, SPI_REG_IOC, sp->ioc_base);
++ }
++
++}
++
++static int pb44_spi_setup_cs(struct spi_device *spi)
++{
++ struct ar71xx_spi *sp = spidev_to_sp(spi);
++
++ /* enable GPIO mode */
++ pb44_spi_wr(sp, SPI_REG_FS, SPI_FS_GPIO);
++
++ /* save CTRL register */
++ sp->reg_ctrl = pb44_spi_rr(sp, SPI_REG_CTRL);
++ sp->ioc_base = pb44_spi_rr(sp, SPI_REG_IOC);
++
++ /* TODO: setup speed? */
++ pb44_spi_wr(sp, SPI_REG_CTRL, 0x43);
++
++ if (spi->chip_select) {
++ unsigned long gpio = (unsigned long) spi->controller_data;
++ int status = 0;
++
++ status = gpio_request(gpio, dev_name(&spi->dev));
++ if (status)
++ return status;
++
++ status = gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH);
++ if (status) {
++ gpio_free(gpio);
++ return status;
++ }
++ } else {
++ if (spi->mode & SPI_CS_HIGH)
++ sp->ioc_base |= SPI_IOC_CS0;
++ else
++ sp->ioc_base &= ~SPI_IOC_CS0;
++ pb44_spi_wr(sp, SPI_REG_IOC, sp->ioc_base);
++ }
++
++ return 0;
++}
++
++static void pb44_spi_cleanup_cs(struct spi_device *spi)
++{
++ struct ar71xx_spi *sp = spidev_to_sp(spi);
++
++ if (spi->chip_select) {
++ unsigned long gpio = (unsigned long) spi->controller_data;
++ gpio_free(gpio);
++ }
++
++ /* restore CTRL register */
++ pb44_spi_wr(sp, SPI_REG_CTRL, sp->reg_ctrl);
++ /* disable GPIO mode */
++ pb44_spi_wr(sp, SPI_REG_FS, 0);
++}
++
++static int pb44_spi_setup(struct spi_device *spi)
++{
++ int status = 0;
++
++ if (spi->bits_per_word > 32)
++ return -EINVAL;
++
++ if (!spi->controller_state) {
++ status = pb44_spi_setup_cs(spi);
++ if (status)
++ return status;
++ }
++
++ status = spi_bitbang_setup(spi);
++ if (status && !spi->controller_state)
++ pb44_spi_cleanup_cs(spi);
++
++ return status;
++}
++
++static void pb44_spi_cleanup(struct spi_device *spi)
++{
++ pb44_spi_cleanup_cs(spi);
++ spi_bitbang_cleanup(spi);
++}
++
++static u32 pb44_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
++ u32 word, u8 bits)
++{
++ struct ar71xx_spi *sp = spidev_to_sp(spi);
++ u32 ioc = sp->ioc_base;
++ u32 ret;
++
++ /* clock starts at inactive polarity */
++ for (word <<= (32 - bits); likely(bits); bits--) {
++ u32 out;
++
++ if (word & (1 << 31))
++ out = ioc | SPI_IOC_DO;
++ else
++ out = ioc & ~SPI_IOC_DO;
++
++ /* setup MSB (to slave) on trailing edge */
++ pb44_spi_wr(sp, SPI_REG_IOC, out);
++ pb44_spi_wr(sp, SPI_REG_IOC, out | SPI_IOC_CLK);
++
++ word <<= 1;
++
++#ifdef PER_BIT_READ
++ /* sample MSB (from slave) on leading edge */
++ ret = pb44_spi_rr(sp, SPI_REG_RDS);
++ pb44_spi_wr(sp, SPI_REG_IOC, out);
++#endif
++ }
++
++#ifndef PER_BIT_READ
++ ret = pb44_spi_rr(sp, SPI_REG_RDS);
++#endif
++ return ret;
++}
++
++static int pb44_spi_probe(struct platform_device *pdev)
++{
++ struct spi_master *master;
++ struct ar71xx_spi *sp;
++ struct ar71xx_spi_platform_data *pdata;
++ struct resource *r;
++ int ret;
++
++ master = spi_alloc_master(&pdev->dev, sizeof(*sp));
++ if (master == NULL) {
++ dev_err(&pdev->dev, "failed to allocate spi master\n");
++ return -ENOMEM;
++ }
++
++ sp = spi_master_get_devdata(master);
++ platform_set_drvdata(pdev, sp);
++
++ pdata = pdev->dev.platform_data;
++
++ master->setup = pb44_spi_setup;
++ master->cleanup = pb44_spi_cleanup;
++ if (pdata) {
++ master->bus_num = pdata->bus_num;
++ master->num_chipselect = pdata->num_chipselect;
++ } else {
++ master->bus_num = 0;
++ master->num_chipselect = 1;
++ }
++
++ sp->bitbang.master = spi_master_get(master);
++ sp->bitbang.chipselect = pb44_spi_chipselect;
++ sp->bitbang.txrx_word[SPI_MODE_0] = pb44_spi_txrx_mode0;
++ sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
++ sp->bitbang.flags = SPI_CS_HIGH;
++
++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (r == NULL) {
++ ret = -ENOENT;
++ goto err1;
++ }
++
++ sp->base = ioremap_nocache(r->start, r->end - r->start + 1);
++ if (!sp->base) {
++ ret = -ENXIO;
++ goto err1;
++ }
++
++ ret = spi_bitbang_start(&sp->bitbang);
++ if (!ret)
++ return 0;
++
++ iounmap(sp->base);
++ err1:
++ platform_set_drvdata(pdev, NULL);
++ spi_master_put(sp->bitbang.master);
++
++ return ret;
++}
++
++static int pb44_spi_remove(struct platform_device *pdev)
++{
++ struct ar71xx_spi *sp = platform_get_drvdata(pdev);
++
++ spi_bitbang_stop(&sp->bitbang);
++ iounmap(sp->base);
++ platform_set_drvdata(pdev, NULL);
++ spi_master_put(sp->bitbang.master);
++
++ return 0;
++}
++
++static struct platform_driver pb44_spi_drv = {
++ .probe = pb44_spi_probe,
++ .remove = pb44_spi_remove,
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init pb44_spi_init(void)
++{
++ return platform_driver_register(&pb44_spi_drv);
++}
++module_init(pb44_spi_init);
++
++static void __exit pb44_spi_exit(void)
++{
++ platform_driver_unregister(&pb44_spi_drv);
++}
++module_exit(pb44_spi_exit);
++
++MODULE_ALIAS("platform:" DRV_NAME);
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+diff -Nur linux-2.6.37.orig/drivers/spi/spi_vsc7385.c linux-2.6.37/drivers/spi/spi_vsc7385.c
+--- linux-2.6.37.orig/drivers/spi/spi_vsc7385.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/spi/spi_vsc7385.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,620 @@
++/*
++ * SPI driver for the Vitesse VSC7385 ethernet switch
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/bitops.h>
++#include <linux/firmware.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/vsc7385.h>
++
++#define DRV_NAME "spi-vsc7385"
++#define DRV_DESC "Vitesse VSC7385 Gbit ethernet switch driver"
++#define DRV_VERSION "0.1.0"
++
++#define VSC73XX_BLOCK_MAC 0x1
++#define VSC73XX_BLOCK_2 0x2
++#define VSC73XX_BLOCK_MII 0x3
++#define VSC73XX_BLOCK_4 0x4
++#define VSC73XX_BLOCK_5 0x5
++#define VSC73XX_BLOCK_SYSTEM 0x7
++
++#define VSC73XX_SUBBLOCK_PORT_0 0
++#define VSC73XX_SUBBLOCK_PORT_1 1
++#define VSC73XX_SUBBLOCK_PORT_2 2
++#define VSC73XX_SUBBLOCK_PORT_3 3
++#define VSC73XX_SUBBLOCK_PORT_4 4
++#define VSC73XX_SUBBLOCK_PORT_MAC 6
++
++/* MAC Block registers */
++#define VSC73XX_MAC_CFG 0x0
++#define VSC73XX_ADVPORTM 0x19
++#define VSC73XX_RXOCT 0x50
++#define VSC73XX_TXOCT 0x51
++#define VSC73XX_C_RX0 0x52
++#define VSC73XX_C_RX1 0x53
++#define VSC73XX_C_RX2 0x54
++#define VSC73XX_C_TX0 0x55
++#define VSC73XX_C_TX1 0x56
++#define VSC73XX_C_TX2 0x57
++#define VSC73XX_C_CFG 0x58
++
++/* MAC_CFG register bits */
++#define VSC73XX_MAC_CFG_WEXC_DIS (1 << 31)
++#define VSC73XX_MAC_CFG_PORT_RST (1 << 29)
++#define VSC73XX_MAC_CFG_TX_EN (1 << 28)
++#define VSC73XX_MAC_CFG_SEED_LOAD (1 << 27)
++#define VSC73XX_MAC_CFG_FDX (1 << 18)
++#define VSC73XX_MAC_CFG_GIGE (1 << 17)
++#define VSC73XX_MAC_CFG_RX_EN (1 << 16)
++#define VSC73XX_MAC_CFG_VLAN_DBLAWR (1 << 15)
++#define VSC73XX_MAC_CFG_VLAN_AWR (1 << 14)
++#define VSC73XX_MAC_CFG_100_BASE_T (1 << 13)
++#define VSC73XX_MAC_CFG_TX_IPG(x) (((x) & 0x1f) << 6)
++#define VSC73XX_MAC_CFG_MAC_RX_RST (1 << 5)
++#define VSC73XX_MAC_CFG_MAC_TX_RST (1 << 4)
++#define VSC73XX_MAC_CFG_BIT2 (1 << 2)
++#define VSC73XX_MAC_CFG_CLK_SEL(x) ((x) & 0x3)
++
++/* ADVPORTM register bits */
++#define VSC73XX_ADVPORTM_IFG_PPM (1 << 7)
++#define VSC73XX_ADVPORTM_EXC_COL_CONT (1 << 6)
++#define VSC73XX_ADVPORTM_EXT_PORT (1 << 5)
++#define VSC73XX_ADVPORTM_INV_GTX (1 << 4)
++#define VSC73XX_ADVPORTM_ENA_GTX (1 << 3)
++#define VSC73XX_ADVPORTM_DDR_MODE (1 << 2)
++#define VSC73XX_ADVPORTM_IO_LOOPBACK (1 << 1)
++#define VSC73XX_ADVPORTM_HOST_LOOPBACK (1 << 0)
++
++/* MII Block registers */
++#define VSC73XX_MII_STAT 0x0
++#define VSC73XX_MII_CMD 0x1
++#define VSC73XX_MII_DATA 0x2
++
++/* System Block registers */
++#define VSC73XX_ICPU_SIPAD 0x01
++#define VSC73XX_ICPU_CLOCK_DELAY 0x05
++#define VSC73XX_ICPU_CTRL 0x10
++#define VSC73XX_ICPU_ADDR 0x11
++#define VSC73XX_ICPU_SRAM 0x12
++#define VSC73XX_ICPU_MBOX_VAL 0x15
++#define VSC73XX_ICPU_MBOX_SET 0x16
++#define VSC73XX_ICPU_MBOX_CLR 0x17
++#define VSC73XX_ICPU_CHIPID 0x18
++#define VSC73XX_ICPU_GPIO 0x34
++
++#define VSC73XX_ICPU_CTRL_CLK_DIV (1 << 8)
++#define VSC73XX_ICPU_CTRL_SRST_HOLD (1 << 7)
++#define VSC73XX_ICPU_CTRL_BOOT_EN (1 << 3)
++#define VSC73XX_ICPU_CTRL_EXT_ACC_EN (1 << 2)
++#define VSC73XX_ICPU_CTRL_CLK_EN (1 << 1)
++#define VSC73XX_ICPU_CTRL_SRST (1 << 0)
++
++#define VSC73XX_ICPU_CHIPID_ID_SHIFT 12
++#define VSC73XX_ICPU_CHIPID_ID_MASK 0xffff
++#define VSC73XX_ICPU_CHIPID_REV_SHIFT 28
++#define VSC73XX_ICPU_CHIPID_REV_MASK 0xf
++#define VSC73XX_ICPU_CHIPID_ID_7385 0x7385
++#define VSC73XX_ICPU_CHIPID_ID_7395 0x7395
++
++#define VSC73XX_CMD_MODE_READ 0
++#define VSC73XX_CMD_MODE_WRITE 1
++#define VSC73XX_CMD_MODE_SHIFT 4
++#define VSC73XX_CMD_BLOCK_SHIFT 5
++#define VSC73XX_CMD_BLOCK_MASK 0x7
++#define VSC73XX_CMD_SUBBLOCK_MASK 0xf
++
++#define VSC7385_CLOCK_DELAY ((3 << 4) | 3)
++#define VSC7385_CLOCK_DELAY_MASK ((3 << 4) | 3)
++
++#define VSC73XX_ICPU_CTRL_STOP (VSC73XX_ICPU_CTRL_SRST_HOLD | \
++ VSC73XX_ICPU_CTRL_BOOT_EN | \
++ VSC73XX_ICPU_CTRL_EXT_ACC_EN)
++
++#define VSC73XX_ICPU_CTRL_START (VSC73XX_ICPU_CTRL_CLK_DIV | \
++ VSC73XX_ICPU_CTRL_BOOT_EN | \
++ VSC73XX_ICPU_CTRL_CLK_EN | \
++ VSC73XX_ICPU_CTRL_SRST)
++
++#define VSC7385_ADVPORTM_MASK (VSC73XX_ADVPORTM_IFG_PPM | \
++ VSC73XX_ADVPORTM_EXC_COL_CONT | \
++ VSC73XX_ADVPORTM_EXT_PORT | \
++ VSC73XX_ADVPORTM_INV_GTX | \
++ VSC73XX_ADVPORTM_ENA_GTX | \
++ VSC73XX_ADVPORTM_DDR_MODE | \
++ VSC73XX_ADVPORTM_IO_LOOPBACK | \
++ VSC73XX_ADVPORTM_HOST_LOOPBACK)
++
++#define VSC7385_ADVPORTM_INIT (VSC73XX_ADVPORTM_EXT_PORT | \
++ VSC73XX_ADVPORTM_ENA_GTX | \
++ VSC73XX_ADVPORTM_DDR_MODE)
++
++#define VSC7385_MAC_CFG_RESET (VSC73XX_MAC_CFG_PORT_RST | \
++ VSC73XX_MAC_CFG_MAC_RX_RST | \
++ VSC73XX_MAC_CFG_MAC_TX_RST)
++
++#define VSC73XX_MAC_CFG_INIT (VSC73XX_MAC_CFG_TX_EN | \
++ VSC73XX_MAC_CFG_FDX | \
++ VSC73XX_MAC_CFG_GIGE | \
++ VSC73XX_MAC_CFG_RX_EN)
++
++#define VSC73XX_RESET_DELAY 100
++
++struct vsc7385 {
++ struct spi_device *spi;
++ struct mutex lock;
++ struct vsc7385_platform_data *pdata;
++};
++
++static int vsc7385_is_addr_valid(u8 block, u8 subblock)
++{
++ switch (block) {
++ case VSC73XX_BLOCK_MAC:
++ switch (subblock) {
++ case 0 ... 4:
++ case 6:
++ return 1;
++ }
++ break;
++
++ case VSC73XX_BLOCK_2:
++ case VSC73XX_BLOCK_SYSTEM:
++ switch (subblock) {
++ case 0:
++ return 1;
++ }
++ break;
++
++ case VSC73XX_BLOCK_MII:
++ case VSC73XX_BLOCK_4:
++ case VSC73XX_BLOCK_5:
++ switch (subblock) {
++ case 0 ... 1:
++ return 1;
++ }
++ break;
++ }
++
++ return 0;
++}
++
++static inline u8 vsc7385_make_addr(u8 mode, u8 block, u8 subblock)
++{
++ u8 ret;
++
++ ret = (block & VSC73XX_CMD_BLOCK_MASK) << VSC73XX_CMD_BLOCK_SHIFT;
++ ret |= (mode & 1) << VSC73XX_CMD_MODE_SHIFT;
++ ret |= subblock & VSC73XX_CMD_SUBBLOCK_MASK;
++
++ return ret;
++}
++
++static int vsc7385_read(struct vsc7385 *vsc, u8 block, u8 subblock, u8 reg,
++ u32 *value)
++{
++ u8 cmd[4];
++ u8 buf[4];
++ struct spi_transfer t[2];
++ struct spi_message m;
++ int err;
++
++ if (!vsc7385_is_addr_valid(block, subblock))
++ return -EINVAL;
++
++ spi_message_init(&m);
++
++ memset(&t, 0, sizeof(t));
++
++ t[0].tx_buf = cmd;
++ t[0].len = sizeof(cmd);
++ spi_message_add_tail(&t[0], &m);
++
++ t[1].rx_buf = buf;
++ t[1].len = sizeof(buf);
++ spi_message_add_tail(&t[1], &m);
++
++ cmd[0] = vsc7385_make_addr(VSC73XX_CMD_MODE_READ, block, subblock);
++ cmd[1] = reg;
++ cmd[2] = 0;
++ cmd[3] = 0;
++
++ mutex_lock(&vsc->lock);
++ err = spi_sync(vsc->spi, &m);
++ mutex_unlock(&vsc->lock);
++
++ if (err)
++ return err;
++
++ *value = (((u32) buf[0]) << 24) | (((u32) buf[1]) << 16) |
++ (((u32) buf[2]) << 8) | ((u32) buf[3]);
++
++ return 0;
++}
++
++
++static int vsc7385_write(struct vsc7385 *vsc, u8 block, u8 subblock, u8 reg,
++ u32 value)
++{
++ u8 cmd[2];
++ u8 buf[4];
++ struct spi_transfer t[2];
++ struct spi_message m;
++ int err;
++
++ if (!vsc7385_is_addr_valid(block, subblock))
++ return -EINVAL;
++
++ spi_message_init(&m);
++
++ memset(&t, 0, sizeof(t));
++
++ t[0].tx_buf = cmd;
++ t[0].len = sizeof(cmd);
++ spi_message_add_tail(&t[0], &m);
++
++ t[1].tx_buf = buf;
++ t[1].len = sizeof(buf);
++ spi_message_add_tail(&t[1], &m);
++
++ cmd[0] = vsc7385_make_addr(VSC73XX_CMD_MODE_WRITE, block, subblock);
++ cmd[1] = reg;
++
++ buf[0] = (value >> 24) & 0xff;
++ buf[1] = (value >> 16) & 0xff;
++ buf[2] = (value >> 8) & 0xff;
++ buf[3] = value & 0xff;
++
++ mutex_lock(&vsc->lock);
++ err = spi_sync(vsc->spi, &m);
++ mutex_unlock(&vsc->lock);
++
++ return err;
++}
++
++static inline int vsc7385_write_verify(struct vsc7385 *vsc, u8 block,
++ u8 subblock, u8 reg, u32 value,
++ u32 read_mask, u32 read_val)
++{
++ struct spi_device *spi = vsc->spi;
++ u32 t;
++ int err;
++
++ err = vsc7385_write(vsc, block, subblock, reg, value);
++ if (err)
++ return err;
++
++ err = vsc7385_read(vsc, block, subblock, reg, &t);
++ if (err)
++ return err;
++
++ if ((t & read_mask) != read_val) {
++ dev_err(&spi->dev, "register write error\n");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static inline int vsc7385_set_clock_delay(struct vsc7385 *vsc, u32 val)
++{
++ return vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++ VSC73XX_ICPU_CLOCK_DELAY, val);
++}
++
++static inline int vsc7385_get_clock_delay(struct vsc7385 *vsc, u32 *val)
++{
++ return vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++ VSC73XX_ICPU_CLOCK_DELAY, val);
++}
++
++static inline int vsc7385_icpu_stop(struct vsc7385 *vsc)
++{
++ return vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_ICPU_CTRL,
++ VSC73XX_ICPU_CTRL_STOP);
++}
++
++static inline int vsc7385_icpu_start(struct vsc7385 *vsc)
++{
++ return vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_ICPU_CTRL,
++ VSC73XX_ICPU_CTRL_START);
++}
++
++static inline int vsc7385_icpu_reset(struct vsc7385 *vsc)
++{
++ int rc;
++
++ rc = vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_ICPU_ADDR,
++ 0x0000);
++ if (rc)
++ dev_err(&vsc->spi->dev,
++ "could not reset microcode, err=%d\n", rc);
++
++ return rc;
++}
++
++static int vsc7385_upload_ucode(struct vsc7385 *vsc)
++{
++ struct spi_device *spi = vsc->spi;
++ const struct firmware *firmware;
++ char *ucode_name;
++ unsigned char *dp;
++ unsigned int curVal;
++ int i;
++ int diffs;
++ int rc;
++
++ ucode_name = (vsc->pdata->ucode_name) ? vsc->pdata->ucode_name
++ : "vsc7385_ucode.bin";
++ rc = request_firmware(&firmware, ucode_name, &spi->dev);
++ if (rc) {
++ dev_err(&spi->dev, "request_firmware failed, err=%d\n",
++ rc);
++ return rc;
++ }
++
++ rc = vsc7385_icpu_stop(vsc);
++ if (rc)
++ goto out;
++
++ rc = vsc7385_icpu_reset(vsc);
++ if (rc)
++ goto out;
++
++ dev_info(&spi->dev, "uploading microcode...\n");
++
++ dp = (unsigned char *) firmware->data;
++ for (i = 0; i < firmware->size; i++) {
++ rc = vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++ VSC73XX_ICPU_SRAM, *dp++);
++ if (rc) {
++ dev_err(&spi->dev, "could not load microcode, err=%d\n",
++ rc);
++ goto out;
++ }
++ }
++
++ rc = vsc7385_icpu_reset(vsc);
++ if (rc)
++ goto out;
++
++ dev_info(&spi->dev, "verifying microcode...\n");
++
++ dp = (unsigned char *) firmware->data;
++ diffs = 0;
++ for (i = 0; i < firmware->size; i++) {
++ rc = vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++ VSC73XX_ICPU_SRAM, &curVal);
++ if (rc) {
++ dev_err(&spi->dev, "could not read microcode %d\n",rc);
++ goto out;
++ }
++
++ if (curVal > 0xff) {
++ dev_err(&spi->dev, "bad val read: %04x : %02x %02x\n",
++ i, *dp, curVal);
++ rc = -EIO;
++ goto out;
++ }
++
++ if ((curVal & 0xff) != *dp) {
++ diffs++;
++ dev_err(&spi->dev, "verify error: %04x : %02x %02x\n",
++ i, *dp, curVal);
++
++ if (diffs > 4)
++ break;
++ }
++ dp++;
++ }
++
++ if (diffs) {
++ dev_err(&spi->dev, "microcode verification failed\n");
++ rc = -EIO;
++ goto out;
++ }
++
++ dev_info(&spi->dev, "microcode uploaded\n");
++
++ rc = vsc7385_icpu_start(vsc);
++
++ out:
++ release_firmware(firmware);
++ return rc;
++}
++
++static int vsc7385_setup(struct vsc7385 *vsc)
++{
++ struct vsc7385_platform_data *pdata = vsc->pdata;
++ u32 t;
++ int err;
++
++ err = vsc7385_write_verify(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++ VSC73XX_ICPU_CLOCK_DELAY,
++ VSC7385_CLOCK_DELAY,
++ VSC7385_CLOCK_DELAY_MASK,
++ VSC7385_CLOCK_DELAY);
++ if (err)
++ goto err;
++
++ err = vsc7385_write_verify(vsc, VSC73XX_BLOCK_MAC,
++ VSC73XX_SUBBLOCK_PORT_MAC, VSC73XX_ADVPORTM,
++ VSC7385_ADVPORTM_INIT,
++ VSC7385_ADVPORTM_MASK,
++ VSC7385_ADVPORTM_INIT);
++ if (err)
++ goto err;
++
++ err = vsc7385_write(vsc, VSC73XX_BLOCK_MAC, VSC73XX_SUBBLOCK_PORT_MAC,
++ VSC73XX_MAC_CFG, VSC7385_MAC_CFG_RESET);
++ if (err)
++ goto err;
++
++ t = VSC73XX_MAC_CFG_INIT;
++ t |= VSC73XX_MAC_CFG_TX_IPG(pdata->mac_cfg.tx_ipg);
++ t |= VSC73XX_MAC_CFG_CLK_SEL(pdata->mac_cfg.clk_sel);
++ if (pdata->mac_cfg.bit2)
++ t |= VSC73XX_MAC_CFG_BIT2;
++
++ err = vsc7385_write(vsc, VSC73XX_BLOCK_MAC, VSC73XX_SUBBLOCK_PORT_MAC,
++ VSC73XX_MAC_CFG, t);
++ if (err)
++ goto err;
++
++ return 0;
++
++ err:
++ return err;
++}
++
++static int vsc7385_detect(struct vsc7385 *vsc)
++{
++ struct spi_device *spi = vsc->spi;
++ u32 t;
++ u32 id;
++ u32 rev;
++ int err;
++
++ err = vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++ VSC73XX_ICPU_MBOX_VAL, &t);
++ if (err) {
++ dev_err(&spi->dev, "unable to read mailbox, err=%d\n", err);
++ return err;
++ }
++
++ if (t == 0xffffffff) {
++ dev_dbg(&spi->dev, "assert chip reset\n");
++ if (vsc->pdata->reset)
++ vsc->pdata->reset();
++
++ }
++
++ err = vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
++ VSC73XX_ICPU_CHIPID, &t);
++ if (err) {
++ dev_err(&spi->dev, "unable to read chip id, err=%d\n", err);
++ return err;
++ }
++
++ id = (t >> VSC73XX_ICPU_CHIPID_ID_SHIFT) & VSC73XX_ICPU_CHIPID_ID_MASK;
++ switch (id) {
++ case VSC73XX_ICPU_CHIPID_ID_7385:
++ case VSC73XX_ICPU_CHIPID_ID_7395:
++ break;
++ default:
++ dev_err(&spi->dev, "unsupported chip, id=%04x\n", id);
++ return -ENODEV;
++ }
++
++ rev = (t >> VSC73XX_ICPU_CHIPID_REV_SHIFT) &
++ VSC73XX_ICPU_CHIPID_REV_MASK;
++ dev_info(&spi->dev, "VSC%04X (rev. %d) switch found \n", id, rev);
++
++ return 0;
++}
++
++static int __devinit vsc7385_probe(struct spi_device *spi)
++{
++ struct vsc7385 *vsc;
++ struct vsc7385_platform_data *pdata;
++ int err;
++
++ printk(KERN_INFO DRV_DESC " version " DRV_VERSION"\n");
++
++ pdata = spi->dev.platform_data;
++ if (!pdata) {
++ dev_err(&spi->dev, "no platform data specified\n");
++ return-ENODEV;
++ }
++
++ vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);
++ if (!vsc) {
++ dev_err(&spi->dev, "no memory for private data\n");
++ return-ENOMEM;
++ }
++
++ mutex_init(&vsc->lock);
++ vsc->pdata = pdata;
++ vsc->spi = spi_dev_get(spi);
++ dev_set_drvdata(&spi->dev, vsc);
++
++ spi->mode = SPI_MODE_0;
++ spi->bits_per_word = 8;
++ err = spi_setup(spi);
++ if (err) {
++ dev_err(&spi->dev, "spi_setup failed, err=%d \n", err);
++ goto err_drvdata;
++ }
++
++ err = vsc7385_detect(vsc);
++ if (err) {
++ dev_err(&spi->dev, "no chip found, err=%d \n", err);
++ goto err_drvdata;
++ }
++
++ err = vsc7385_upload_ucode(vsc);
++ if (err)
++ goto err_drvdata;
++
++ err = vsc7385_setup(vsc);
++ if (err)
++ goto err_drvdata;
++
++ return 0;
++
++ err_drvdata:
++ dev_set_drvdata(&spi->dev, NULL);
++ kfree(vsc);
++ return err;
++}
++
++static int __devexit vsc7385_remove(struct spi_device *spi)
++{
++ struct vsc7385_data *vsc;
++
++ vsc = dev_get_drvdata(&spi->dev);
++ dev_set_drvdata(&spi->dev, NULL);
++ kfree(vsc);
++
++ return 0;
++}
++
++static struct spi_driver vsc7385_driver = {
++ .driver = {
++ .name = DRV_NAME,
++ .bus = &spi_bus_type,
++ .owner = THIS_MODULE,
++ },
++ .probe = vsc7385_probe,
++ .remove = __devexit_p(vsc7385_remove),
++};
++
++static int __init vsc7385_init(void)
++{
++ return spi_register_driver(&vsc7385_driver);
++}
++module_init(vsc7385_init);
++
++static void __exit vsc7385_exit(void)
++{
++ spi_unregister_driver(&vsc7385_driver);
++}
++module_exit(vsc7385_exit);
++
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
++
+diff -Nur linux-2.6.37.orig/drivers/usb/host/Kconfig linux-2.6.37/drivers/usb/host/Kconfig
+--- linux-2.6.37.orig/drivers/usb/host/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/usb/host/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -118,6 +118,13 @@
+ config USB_FSL_MPH_DR_OF
+ tristate
+
++config USB_EHCI_AR71XX
++ bool "USB EHCI support for AR71xx"
++ depends on USB_EHCI_HCD && ATHEROS_AR71XX
++ default y
++ help
++ Support for Atheros AR71xx built-in EHCI controller
++
+ config USB_EHCI_FSL
+ bool "Support for Freescale on-chip EHCI USB controller"
+ depends on USB_EHCI_HCD && FSL_SOC
+@@ -232,6 +239,13 @@
+ Enables support for the on-chip OHCI controller on
+ OMAP3 and later chips.
+
++config USB_OHCI_AR71XX
++ bool "USB OHCI support for Atheros AR71xx"
++ depends on USB_OHCI_HCD && ATHEROS_AR71XX
++ default y
++ help
++ Support for Atheros AR71xx built-in OHCI controller
++
+ config USB_OHCI_HCD_PPC_SOC
+ bool "OHCI support for on-chip PPC USB controller"
+ depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
+diff -Nur linux-2.6.37.orig/drivers/usb/host/ehci-ar71xx.c linux-2.6.37/drivers/usb/host/ehci-ar71xx.c
+--- linux-2.6.37.orig/drivers/usb/host/ehci-ar71xx.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/usb/host/ehci-ar71xx.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,242 @@
++/*
++ * Bus Glue for Atheros AR71xx built-in EHCI controller.
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ * Copyright (C) 2007 Atheros Communications, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++
++#include <asm/mach-ar71xx/platform.h>
++
++extern int usb_disabled(void);
++
++static int ehci_ar71xx_init(struct usb_hcd *hcd)
++{
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ int ret;
++
++ ehci->caps = hcd->regs;
++ ehci->regs = hcd->regs +
++ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
++ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++ ehci->sbrn = 0x20;
++ ehci->has_synopsys_hc_bug = 1;
++
++ ehci_reset(ehci);
++
++ ret = ehci_init(hcd);
++ if (ret)
++ return ret;
++
++ ehci_port_power(ehci, 0);
++
++ return 0;
++}
++
++static int ehci_ar91xx_init(struct usb_hcd *hcd)
++{
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ int ret;
++
++ ehci->caps = hcd->regs + 0x100;
++ ehci->regs = hcd->regs + 0x100 +
++ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
++ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++ hcd->has_tt = 1;
++ ehci->sbrn = 0x20;
++
++ ehci_reset(ehci);
++
++ ret = ehci_init(hcd);
++ if (ret)
++ return ret;
++
++ ehci_port_power(ehci, 0);
++
++ return 0;
++}
++
++static int ehci_ar71xx_probe(const struct hc_driver *driver,
++ struct usb_hcd **hcd_out,
++ struct platform_device *pdev)
++{
++ struct usb_hcd *hcd;
++ struct resource *res;
++ int irq;
++ int ret;
++
++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!res) {
++ dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
++ dev_name(&pdev->dev));
++ return -ENODEV;
++ }
++ irq = res->start;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_dbg(&pdev->dev, "no base address specified for %s\n",
++ dev_name(&pdev->dev));
++ return -ENODEV;
++ }
++
++ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
++ if (!hcd)
++ return -ENOMEM;
++
++ hcd->rsrc_start = res->start;
++ hcd->rsrc_len = res->end - res->start + 1;
++
++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++ dev_dbg(&pdev->dev, "controller already in use\n");
++ ret = -EBUSY;
++ goto err_put_hcd;
++ }
++
++ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++ if (!hcd->regs) {
++ dev_dbg(&pdev->dev, "error mapping memory\n");
++ ret = -EFAULT;
++ goto err_release_region;
++ }
++
++ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
++ if (ret)
++ goto err_iounmap;
++
++ return 0;
++
++ err_iounmap:
++ iounmap(hcd->regs);
++
++ err_release_region:
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ err_put_hcd:
++ usb_put_hcd(hcd);
++ return ret;
++}
++
++static void ehci_ar71xx_remove(struct usb_hcd *hcd,
++ struct platform_device *pdev)
++{
++ usb_remove_hcd(hcd);
++ iounmap(hcd->regs);
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ usb_put_hcd(hcd);
++}
++
++static const struct hc_driver ehci_ar71xx_hc_driver = {
++ .description = hcd_name,
++ .product_desc = "Atheros AR71xx built-in EHCI controller",
++ .hcd_priv_size = sizeof(struct ehci_hcd),
++
++ .irq = ehci_irq,
++ .flags = HCD_MEMORY | HCD_USB2,
++
++ .reset = ehci_ar71xx_init,
++ .start = ehci_run,
++ .stop = ehci_stop,
++ .shutdown = ehci_shutdown,
++
++ .urb_enqueue = ehci_urb_enqueue,
++ .urb_dequeue = ehci_urb_dequeue,
++ .endpoint_disable = ehci_endpoint_disable,
++ .endpoint_reset = ehci_endpoint_reset,
++
++ .get_frame_number = ehci_get_frame,
++
++ .hub_status_data = ehci_hub_status_data,
++ .hub_control = ehci_hub_control,
++#ifdef CONFIG_PM
++ .hub_suspend = ehci_hub_suspend,
++ .hub_resume = ehci_hub_resume,
++#endif
++ .relinquish_port = ehci_relinquish_port,
++ .port_handed_over = ehci_port_handed_over,
++
++ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
++};
++
++static const struct hc_driver ehci_ar91xx_hc_driver = {
++ .description = hcd_name,
++ .product_desc = "Atheros AR91xx built-in EHCI controller",
++ .hcd_priv_size = sizeof(struct ehci_hcd),
++ .irq = ehci_irq,
++ .flags = HCD_MEMORY | HCD_USB2,
++
++ .reset = ehci_ar91xx_init,
++ .start = ehci_run,
++ .stop = ehci_stop,
++ .shutdown = ehci_shutdown,
++
++ .urb_enqueue = ehci_urb_enqueue,
++ .urb_dequeue = ehci_urb_dequeue,
++ .endpoint_disable = ehci_endpoint_disable,
++ .endpoint_reset = ehci_endpoint_reset,
++
++ .get_frame_number = ehci_get_frame,
++
++ .hub_status_data = ehci_hub_status_data,
++ .hub_control = ehci_hub_control,
++#ifdef CONFIG_PM
++ .hub_suspend = ehci_hub_suspend,
++ .hub_resume = ehci_hub_resume,
++#endif
++ .relinquish_port = ehci_relinquish_port,
++ .port_handed_over = ehci_port_handed_over,
++
++ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
++};
++
++static int ehci_ar71xx_driver_probe(struct platform_device *pdev)
++{
++ struct ar71xx_ehci_platform_data *pdata;
++ struct usb_hcd *hcd = NULL;
++ int ret;
++
++ if (usb_disabled())
++ return -ENODEV;
++
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ dev_err(&pdev->dev, "no platform data specified for %s\n",
++ dev_name(&pdev->dev));
++ return -ENODEV;
++ }
++
++ if (pdata->is_ar91xx)
++ ret = ehci_ar71xx_probe(&ehci_ar91xx_hc_driver, &hcd, pdev);
++ else
++ ret = ehci_ar71xx_probe(&ehci_ar71xx_hc_driver, &hcd, pdev);
++
++ return ret;
++}
++
++static int ehci_ar71xx_driver_remove(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ ehci_ar71xx_remove(hcd, pdev);
++ return 0;
++}
++
++MODULE_ALIAS("platform:ar71xx-ehci");
++
++static struct platform_driver ehci_ar71xx_driver = {
++ .probe = ehci_ar71xx_driver_probe,
++ .remove = ehci_ar71xx_driver_remove,
++ .driver = {
++ .name = "ar71xx-ehci",
++ }
++};
+diff -Nur linux-2.6.37.orig/drivers/usb/host/ehci-hcd.c linux-2.6.37/drivers/usb/host/ehci-hcd.c
+--- linux-2.6.37.orig/drivers/usb/host/ehci-hcd.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/usb/host/ehci-hcd.c 2011-01-11 20:25:48.000000000 +0100
+@@ -1216,6 +1216,11 @@
+ #define PLATFORM_DRIVER ehci_octeon_driver
+ #endif
+
++#ifdef CONFIG_USB_EHCI_AR71XX
++#include "ehci-ar71xx.c"
++#define PLATFORM_DRIVER ehci_ar71xx_driver
++#endif
++
+ #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+ !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
+ !defined(XILINX_OF_PLATFORM_DRIVER)
+diff -Nur linux-2.6.37.orig/drivers/usb/host/ohci-ar71xx.c linux-2.6.37/drivers/usb/host/ohci-ar71xx.c
+--- linux-2.6.37.orig/drivers/usb/host/ohci-ar71xx.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/usb/host/ohci-ar71xx.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,165 @@
++/*
++ * OHCI HCD (Host Controller Driver) for USB.
++ *
++ * Bus Glue for Atheros AR71xx built-in OHCI controller.
++ *
++ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros' 2.6.15 BSP
++ * Copyright (C) 2007 Atheros Communications, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++
++extern int usb_disabled(void);
++
++static int usb_hcd_ar71xx_probe(const struct hc_driver *driver,
++ struct platform_device *pdev)
++{
++ struct usb_hcd *hcd;
++ struct resource *res;
++ int irq;
++ int ret;
++
++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!res) {
++ dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
++ dev_name(&pdev->dev));
++ return -ENODEV;
++ }
++ irq = res->start;
++
++ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
++ if (!hcd)
++ return -ENOMEM;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_dbg(&pdev->dev, "no base address specified for %s\n",
++ dev_name(&pdev->dev));
++ ret = -ENODEV;
++ goto err_put_hcd;
++ }
++ hcd->rsrc_start = res->start;
++ hcd->rsrc_len = res->end - res->start + 1;
++
++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++ dev_dbg(&pdev->dev, "controller already in use\n");
++ ret = -EBUSY;
++ goto err_put_hcd;
++ }
++
++ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++ if (!hcd->regs) {
++ dev_dbg(&pdev->dev, "error mapping memory\n");
++ ret = -EFAULT;
++ goto err_release_region;
++ }
++
++ ohci_hcd_init(hcd_to_ohci(hcd));
++
++ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
++ if (ret)
++ goto err_stop_hcd;
++
++ return 0;
++
++ err_stop_hcd:
++ iounmap(hcd->regs);
++ err_release_region:
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ err_put_hcd:
++ usb_put_hcd(hcd);
++ return ret;
++}
++
++void usb_hcd_ar71xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
++{
++ usb_remove_hcd(hcd);
++ iounmap(hcd->regs);
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ usb_put_hcd(hcd);
++}
++
++static int __devinit ohci_ar71xx_start(struct usb_hcd *hcd)
++{
++ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++ int ret;
++
++ ret = ohci_init(ohci);
++ if (ret < 0)
++ return ret;
++
++ ret = ohci_run(ohci);
++ if (ret < 0)
++ goto err;
++
++ return 0;
++
++ err:
++ ohci_stop(hcd);
++ return ret;
++}
++
++static const struct hc_driver ohci_ar71xx_hc_driver = {
++ .description = hcd_name,
++ .product_desc = "Atheros AR71xx built-in OHCI controller",
++ .hcd_priv_size = sizeof(struct ohci_hcd),
++
++ .irq = ohci_irq,
++ .flags = HCD_USB11 | HCD_MEMORY,
++
++ .start = ohci_ar71xx_start,
++ .stop = ohci_stop,
++ .shutdown = ohci_shutdown,
++
++ .urb_enqueue = ohci_urb_enqueue,
++ .urb_dequeue = ohci_urb_dequeue,
++ .endpoint_disable = ohci_endpoint_disable,
++
++ /*
++ * scheduling support
++ */
++ .get_frame_number = ohci_get_frame,
++
++ /*
++ * root hub support
++ */
++ .hub_status_data = ohci_hub_status_data,
++ .hub_control = ohci_hub_control,
++ .start_port_reset = ohci_start_port_reset,
++};
++
++static int ohci_hcd_ar71xx_drv_probe(struct platform_device *pdev)
++{
++ if (usb_disabled())
++ return -ENODEV;
++
++ return usb_hcd_ar71xx_probe(&ohci_ar71xx_hc_driver, pdev);
++}
++
++static int ohci_hcd_ar71xx_drv_remove(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ usb_hcd_ar71xx_remove(hcd, pdev);
++ return 0;
++}
++
++MODULE_ALIAS("platform:ar71xx-ohci");
++
++static struct platform_driver ohci_hcd_ar71xx_driver = {
++ .probe = ohci_hcd_ar71xx_drv_probe,
++ .remove = ohci_hcd_ar71xx_drv_remove,
++ .shutdown = usb_hcd_platform_shutdown,
++ .driver = {
++ .name = "ar71xx-ohci",
++ .owner = THIS_MODULE,
++ },
++};
+diff -Nur linux-2.6.37.orig/drivers/usb/host/ohci-hcd.c linux-2.6.37/drivers/usb/host/ohci-hcd.c
+--- linux-2.6.37.orig/drivers/usb/host/ohci-hcd.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/usb/host/ohci-hcd.c 2011-01-11 20:25:48.000000000 +0100
+@@ -1111,6 +1111,11 @@
+ #define PLATFORM_DRIVER ohci_octeon_driver
+ #endif
+
++#ifdef CONFIG_USB_OHCI_AR71XX
++#include "ohci-ar71xx.c"
++#define PLATFORM_DRIVER ohci_hcd_ar71xx_driver
++#endif
++
+ #if !defined(PCI_DRIVER) && \
+ !defined(PLATFORM_DRIVER) && \
+ !defined(OMAP1_PLATFORM_DRIVER) && \
+diff -Nur linux-2.6.37.orig/drivers/watchdog/Kconfig linux-2.6.37/drivers/watchdog/Kconfig
+--- linux-2.6.37.orig/drivers/watchdog/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/watchdog/Kconfig 2011-01-11 20:25:48.000000000 +0100
+@@ -930,6 +930,13 @@
+ To compile this driver as a loadable module, choose M here.
+ The module will be called bcm63xx_wdt.
+
++config AR71XX_WDT
++ tristate "Atheros AR71xx Watchdog Timer"
++ depends on ATHEROS_AR71XX
++ help
++ Hardware driver for the built-in watchdog timer on the Atheros
++ AR71xx SoCs.
++
+ # PARISC Architecture
+
+ # POWERPC Architecture
+diff -Nur linux-2.6.37.orig/drivers/watchdog/Makefile linux-2.6.37/drivers/watchdog/Makefile
+--- linux-2.6.37.orig/drivers/watchdog/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/watchdog/Makefile 2011-01-11 20:25:48.000000000 +0100
+@@ -117,6 +117,7 @@
+ obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
+ obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
+ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
++obj-$(CONFIG_AR71XX_WDT) += ar71xx_wdt.o
+ obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
+ octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
+
+diff -Nur linux-2.6.37.orig/drivers/watchdog/ar71xx_wdt.c linux-2.6.37/drivers/watchdog/ar71xx_wdt.c
+--- linux-2.6.37.orig/drivers/watchdog/ar71xx_wdt.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/watchdog/ar71xx_wdt.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,270 @@
++/*
++ * Driver for the Atheros AR71xx SoC's built-in hardware watchdog timer.
++ *
++ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This driver was based on: drivers/watchdog/ixp4xx_wdt.c
++ * Author: Deepak Saxena <dsaxena@plexity.net>
++ * Copyright 2004 (c) MontaVista, Software, Inc.
++ *
++ * which again was based on sa1100 driver,
++ * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ */
++
++#include <linux/bitops.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/types.h>
++#include <linux/watchdog.h>
++
++#include <asm/mach-ar71xx/ar71xx.h>
++
++#define DRV_NAME "ar71xx-wdt"
++#define DRV_DESC "Atheros AR71xx hardware watchdog driver"
++#define DRV_VERSION "0.1.0"
++
++#define WDT_TIMEOUT 15 /* seconds */
++
++static int nowayout = WATCHDOG_NOWAYOUT;
++
++#ifdef CONFIG_WATCHDOG_NOWAYOUT
++module_param(nowayout, int, 0);
++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
++ "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
++#endif
++
++static unsigned long wdt_flags;
++
++#define WDT_FLAGS_BUSY 0
++#define WDT_FLAGS_EXPECT_CLOSE 1
++
++static int wdt_timeout = WDT_TIMEOUT;
++static int boot_status;
++static int max_timeout;
++
++static void inline ar71xx_wdt_keepalive(void)
++{
++ ar71xx_reset_wr(AR71XX_RESET_REG_WDOG, ar71xx_ahb_freq * wdt_timeout);
++}
++
++static void inline ar71xx_wdt_enable(void)
++{
++ printk(KERN_DEBUG DRV_NAME ": enabling watchdog timer\n");
++ ar71xx_wdt_keepalive();
++ ar71xx_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_FCR);
++}
++
++static void inline ar71xx_wdt_disable(void)
++{
++ printk(KERN_DEBUG DRV_NAME ": disabling watchdog timer\n");
++ ar71xx_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_NONE);
++}
++
++static int ar71xx_wdt_set_timeout(int val)
++{
++ if (val < 1 || val > max_timeout)
++ return -EINVAL;
++
++ wdt_timeout = val;
++ ar71xx_wdt_keepalive();
++
++ printk(KERN_DEBUG DRV_NAME ": timeout=%d secs\n", wdt_timeout);
++
++ return 0;
++}
++
++static int ar71xx_wdt_open(struct inode *inode, struct file *file)
++{
++ if (test_and_set_bit(WDT_FLAGS_BUSY, &wdt_flags))
++ return -EBUSY;
++
++ clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
++
++ ar71xx_wdt_enable();
++
++ return nonseekable_open(inode, file);
++}
++
++static int ar71xx_wdt_release(struct inode *inode, struct file *file)
++{
++ if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags)) {
++ ar71xx_wdt_disable();
++ } else {
++ printk(KERN_CRIT DRV_NAME ": device closed unexpectedly, "
++ "watchdog timer will not stop!\n");
++ }
++
++ clear_bit(WDT_FLAGS_BUSY, &wdt_flags);
++ clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
++
++ return 0;
++}
++
++static ssize_t ar71xx_wdt_write(struct file *file, const char *data,
++ size_t len, loff_t *ppos)
++{
++ if (len) {
++ if (!nowayout) {
++ size_t i;
++
++ clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
++
++ for (i = 0; i != len; i++) {
++ char c;
++
++ if (get_user(c, data + i))
++ return -EFAULT;
++
++ if (c == 'V')
++ set_bit(WDT_FLAGS_EXPECT_CLOSE,
++ &wdt_flags);
++ }
++ }
++
++ ar71xx_wdt_keepalive();
++ }
++
++ return len;
++}
++
++static struct watchdog_info ar71xx_wdt_info = {
++ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
++ WDIOF_MAGICCLOSE | WDIOF_CARDRESET,
++ .firmware_version = 0,
++ .identity = "AR71XX watchdog",
++};
++
++static int ar71xx_wdt_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ int t;
++ int ret;
++
++ switch (cmd) {
++ case WDIOC_GETSUPPORT:
++ ret = copy_to_user((struct watchdog_info *)arg,
++ &ar71xx_wdt_info,
++ sizeof(&ar71xx_wdt_info)) ? -EFAULT : 0;
++ break;
++
++ case WDIOC_GETSTATUS:
++ ret = put_user(0, (int *)arg) ? -EFAULT : 0;
++ break;
++
++ case WDIOC_GETBOOTSTATUS:
++ ret = put_user(boot_status, (int *)arg) ? -EFAULT : 0;
++ break;
++
++ case WDIOC_KEEPALIVE:
++ ar71xx_wdt_keepalive();
++ ret = 0;
++ break;
++
++ case WDIOC_SETTIMEOUT:
++ ret = get_user(t, (int *)arg) ? -EFAULT : 0;
++ if (ret)
++ break;
++
++ ret = ar71xx_wdt_set_timeout(t);
++ if (ret)
++ break;
++
++ /* fallthrough */
++ case WDIOC_GETTIMEOUT:
++ ret = put_user(wdt_timeout, (int *)arg) ? -EFAULT : 0;
++ break;
++
++ default:
++ ret = -ENOTTY;
++ break;
++ }
++
++ return ret;
++}
++
++static const struct file_operations ar71xx_wdt_fops = {
++ .owner = THIS_MODULE,
++ .write = ar71xx_wdt_write,
++ .ioctl = ar71xx_wdt_ioctl,
++ .open = ar71xx_wdt_open,
++ .release = ar71xx_wdt_release,
++};
++
++static struct miscdevice ar71xx_wdt_miscdev = {
++ .minor = WATCHDOG_MINOR,
++ .name = "watchdog",
++ .fops = &ar71xx_wdt_fops,
++};
++
++static int __devinit ar71xx_wdt_probe(struct platform_device *pdev)
++{
++ int ret;
++
++ max_timeout = (0xfffffffful / ar71xx_ahb_freq);
++ wdt_timeout = (max_timeout < WDT_TIMEOUT) ? max_timeout : WDT_TIMEOUT;
++
++ boot_status =
++ (ar71xx_reset_rr(AR71XX_RESET_REG_WDOG_CTRL) & WDOG_CTRL_LAST_RESET) ?
++ WDIOF_CARDRESET : 0;
++
++ ret = misc_register(&ar71xx_wdt_miscdev);
++ if (ret)
++ goto err_out;
++
++ printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
++
++ printk(KERN_DEBUG DRV_NAME ": timeout=%d secs (max=%d)\n",
++ wdt_timeout, max_timeout);
++
++ return 0;
++
++err_out:
++ return ret;
++}
++
++static int __devexit ar71xx_wdt_remove(struct platform_device *pdev)
++{
++ misc_deregister(&ar71xx_wdt_miscdev);
++ return 0;
++}
++
++static struct platform_driver ar71xx_wdt_driver = {
++ .probe = ar71xx_wdt_probe,
++ .remove = __devexit_p(ar71xx_wdt_remove),
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init ar71xx_wdt_init(void)
++{
++ return platform_driver_register(&ar71xx_wdt_driver);
++}
++module_init(ar71xx_wdt_init);
++
++static void __exit ar71xx_wdt_exit(void)
++{
++ platform_driver_unregister(&ar71xx_wdt_driver);
++}
++module_exit(ar71xx_wdt_exit);
++
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
++MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" DRV_NAME);
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+diff -Nur linux-2.6.37.orig/include/linux/ath9k_platform.h linux-2.6.37/include/linux/ath9k_platform.h
+--- linux-2.6.37.orig/include/linux/ath9k_platform.h 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/include/linux/ath9k_platform.h 2011-01-11 20:25:48.000000000 +0100
+@@ -1,19 +1,11 @@
+ /*
+- * Copyright (c) 2008 Atheros Communications Inc.
+- * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+- * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
++ * ath9k platform data defines
+ *
+- * Permission to use, copy, modify, and/or distribute this software for any
+- * purpose with or without fee is hereby granted, provided that the above
+- * copyright notice and this permission notice appear in all copies.
++ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
+ */
+
+ #ifndef _LINUX_ATH9K_PLATFORM_H
+@@ -23,6 +15,9 @@
+
+ struct ath9k_platform_data {
+ u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS];
++ u8 *macaddr;
++
++ unsigned long quirk_wndr3700:1;
+ };
+
+ #endif /* _LINUX_ATH9K_PLATFORM_H */
+diff -Nur linux-2.6.37.orig/include/linux/gpio_buttons.h linux-2.6.37/include/linux/gpio_buttons.h
+--- linux-2.6.37.orig/include/linux/gpio_buttons.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/include/linux/gpio_buttons.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,33 @@
++/*
++ * Definitions for the GPIO buttons interface driver
++ *
++ * Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This file was based on: /include/linux/gpio_keys.h
++ * The original gpio_keys.h seems not to have a license.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#ifndef _GPIO_BUTTONS_H_
++#define _GPIO_BUTTONS_H_
++
++struct gpio_button {
++ int gpio; /* GPIO line number */
++ int active_low;
++ char *desc; /* button description */
++ int type; /* input event type (EV_KEY, EV_SW) */
++ int code; /* input event code (KEY_*, SW_*) */
++ int threshold; /* count threshold */
++};
++
++struct gpio_buttons_platform_data {
++ struct gpio_button *buttons;
++ int nbuttons; /* number of buttons */
++ int poll_interval; /* polling interval */
++};
++
++#endif /* _GPIO_BUTTONS_H_ */
+diff -Nur linux-2.6.37.orig/include/linux/gpio_dev.h linux-2.6.37/include/linux/gpio_dev.h
+--- linux-2.6.37.orig/include/linux/gpio_dev.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/include/linux/gpio_dev.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,11 @@
++#ifndef _GPIODEV_H__
++#define _GPIODEV_H__
++
++#define IOC_GPIODEV_MAGIC 'B'
++#define GPIO_GET _IO(IOC_GPIODEV_MAGIC, 10)
++#define GPIO_SET _IO(IOC_GPIODEV_MAGIC, 11)
++#define GPIO_CLEAR _IO(IOC_GPIODEV_MAGIC, 12)
++#define GPIO_DIR_IN _IO(IOC_GPIODEV_MAGIC, 13)
++#define GPIO_DIR_OUT _IO(IOC_GPIODEV_MAGIC, 14)
++
++#endif
+diff -Nur linux-2.6.37.orig/include/linux/netdevice.h linux-2.6.37/include/linux/netdevice.h
+--- linux-2.6.37.orig/include/linux/netdevice.h 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/include/linux/netdevice.h 2011-01-11 20:25:48.000000000 +0100
+@@ -957,6 +957,7 @@
+ void *ax25_ptr; /* AX.25 specific data */
+ struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data,
+ assign before registering */
++ void *phy_ptr; /* PHY device specific data */
+
+ /*
+ * Cache lines mostly used on receive path (including eth_type_trans())
+diff -Nur linux-2.6.37.orig/include/linux/nxp_74hc153.h linux-2.6.37/include/linux/nxp_74hc153.h
+--- linux-2.6.37.orig/include/linux/nxp_74hc153.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/include/linux/nxp_74hc153.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,24 @@
++/*
++ * NXP 74HC153 - Dual 4-input multiplexer defines
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _NXP_74HC153_H
++#define _NXP_74HC153_H
++
++#define NXP_74HC153_DRIVER_NAME "nxp-74hc153"
++
++struct nxp_74hc153_platform_data {
++ unsigned gpio_base;
++ unsigned gpio_pin_s0;
++ unsigned gpio_pin_s1;
++ unsigned gpio_pin_1y;
++ unsigned gpio_pin_2y;
++};
++
++#endif /* _NXP_74HC153_H */
+diff -Nur linux-2.6.37.orig/include/linux/phy.h linux-2.6.37/include/linux/phy.h
+--- linux-2.6.37.orig/include/linux/phy.h 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/include/linux/phy.h 2011-01-11 20:25:48.000000000 +0100
+@@ -332,6 +332,20 @@
+ void (*adjust_link)(struct net_device *dev);
+
+ void (*adjust_state)(struct net_device *dev);
++
++ /*
++ * By default these point to the original functions
++ * with the same name. adding them to the phy_device
++ * allows the phy driver to override them for packet
++ * mangling if the ethernet driver supports it
++ * This is required to support some really horrible
++ * switches such as the Marvell 88E6060
++ */
++ int (*netif_receive_skb)(struct sk_buff *skb);
++ int (*netif_rx)(struct sk_buff *skb);
++
++ /* alignment offset for packets */
++ int pkt_align;
+ };
+ #define to_phy_device(d) container_of(d, struct phy_device, dev)
+
+@@ -508,6 +522,7 @@
+ void phy_stop_machine(struct phy_device *phydev);
+ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr);
+ int phy_mii_ioctl(struct phy_device *phydev,
+ struct ifreq *ifr, int cmd);
+ int phy_start_interrupts(struct phy_device *phydev);
+diff -Nur linux-2.6.37.orig/include/linux/spi/vsc7385.h linux-2.6.37/include/linux/spi/vsc7385.h
+--- linux-2.6.37.orig/include/linux/spi/vsc7385.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/include/linux/spi/vsc7385.h 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,19 @@
++/*
++ * Platform data definition for the Vitesse VSC7385 ethernet switch driver
++ *
++ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++struct vsc7385_platform_data {
++ void (* reset)(void);
++ char *ucode_name;
++ struct {
++ u32 tx_ipg:5;
++ u32 bit2:1;
++ u32 clk_sel:3;
++ } mac_cfg;
++};
+diff -Nur linux-2.6.37.orig/net/dsa/ar7240.c linux-2.6.37/net/dsa/ar7240.c
+--- linux-2.6.37.orig/net/dsa/ar7240.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/net/dsa/ar7240.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,736 @@
++/*
++ * DSA driver for the built-in ethernet switch of the Atheros AR7240 SoC
++ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This file was based on:
++ * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips
++ * Copyright (c) 2008 Marvell Semiconductor
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ */
++
++#include <linux/etherdevice.h>
++#include <linux/list.h>
++#include <linux/netdevice.h>
++#include <linux/phy.h>
++#include <linux/mii.h>
++#include <linux/bitops.h>
++
++#include "dsa_priv.h"
++
++#define BITM(_count) (BIT(_count) - 1)
++
++#define AR7240_REG_MASK_CTRL 0x00
++#define AR7240_MASK_CTRL_REVISION_M BITM(8)
++#define AR7240_MASK_CTRL_VERSION_M BITM(8)
++#define AR7240_MASK_CTRL_VERSION_S 8
++#define AR7240_MASK_CTRL_SOFT_RESET BIT(31)
++
++#define AR7240_REG_MAC_ADDR0 0x20
++#define AR7240_REG_MAC_ADDR1 0x24
++
++#define AR7240_REG_FLOOD_MASK 0x2c
++#define AR7240_FLOOD_MASK_BROAD_TO_CPU BIT(26)
++
++#define AR7240_REG_GLOBAL_CTRL 0x30
++#define AR7240_GLOBAL_CTRL_MTU_M BITM(12)
++
++#define AR7240_REG_AT_CTRL 0x5c
++#define AR7240_AT_CTRL_ARP_EN BIT(20)
++
++#define AR7240_REG_TAG_PRIORITY 0x70
++
++#define AR7240_REG_SERVICE_TAG 0x74
++#define AR7240_SERVICE_TAG_M BITM(16)
++
++#define AR7240_REG_CPU_PORT 0x78
++#define AR7240_MIRROR_PORT_S 4
++#define AR7240_CPU_PORT_EN BIT(8)
++
++#define AR7240_REG_MIB_FUNCTION0 0x80
++#define AR7240_MIB_TIMER_M BITM(16)
++#define AR7240_MIB_AT_HALF_EN BIT(16)
++#define AR7240_MIB_BUSY BIT(17)
++#define AR7240_MIB_FUNC_S 24
++#define AR7240_MIB_FUNC_NO_OP 0x0
++#define AR7240_MIB_FUNC_FLUSH 0x1
++#define AR7240_MIB_FUNC_CAPTURE 0x3
++
++#define AR7240_REG_MDIO_CTRL 0x98
++#define AR7240_MDIO_CTRL_DATA_M BITM(16)
++#define AR7240_MDIO_CTRL_REG_ADDR_S 16
++#define AR7240_MDIO_CTRL_PHY_ADDR_S 21
++#define AR7240_MDIO_CTRL_CMD_WRITE 0
++#define AR7240_MDIO_CTRL_CMD_READ BIT(27)
++#define AR7240_MDIO_CTRL_MASTER_EN BIT(30)
++#define AR7240_MDIO_CTRL_BUSY BIT(31)
++
++#define AR7240_REG_PORT_BASE(_port) (0x100 + (_port) * 0x100)
++
++#define AR7240_REG_PORT_STATUS(_port) (AR7240_REG_PORT_BASE((_port)) + 0x00)
++#define AR7240_PORT_STATUS_SPEED_M BITM(2)
++#define AR7240_PORT_STATUS_SPEED_10 0
++#define AR7240_PORT_STATUS_SPEED_100 1
++#define AR7240_PORT_STATUS_SPEED_1000 2
++#define AR7240_PORT_STATUS_TXMAC BIT(2)
++#define AR7240_PORT_STATUS_RXMAC BIT(3)
++#define AR7240_PORT_STATUS_TXFLOW BIT(4)
++#define AR7240_PORT_STATUS_RXFLOW BIT(5)
++#define AR7240_PORT_STATUS_DUPLEX BIT(6)
++#define AR7240_PORT_STATUS_LINK_UP BIT(8)
++#define AR7240_PORT_STATUS_LINK_AUTO BIT(9)
++#define AR7240_PORT_STATUS_LINK_PAUSE BIT(10)
++
++#define AR7240_REG_PORT_CTRL(_port) (AR7240_REG_PORT_BASE((_port)) + 0x04)
++#define AR7240_PORT_CTRL_STATE_M BITM(3)
++#define AR7240_PORT_CTRL_STATE_DISABLED 0
++#define AR7240_PORT_CTRL_STATE_BLOCK 1
++#define AR7240_PORT_CTRL_STATE_LISTEN 2
++#define AR7240_PORT_CTRL_STATE_LEARN 3
++#define AR7240_PORT_CTRL_STATE_FORWARD 4
++#define AR7240_PORT_CTRL_LEARN_LOCK BIT(7)
++#define AR7240_PORT_CTRL_VLAN_MODE_S 8
++#define AR7240_PORT_CTRL_VLAN_MODE_KEEP 0
++#define AR7240_PORT_CTRL_VLAN_MODE_STRIP 1
++#define AR7240_PORT_CTRL_VLAN_MODE_ADD 2
++#define AR7240_PORT_CTRL_VLAN_MODE_DOUBLE_TAG 3
++#define AR7240_PORT_CTRL_IGMP_SNOOP BIT(10)
++#define AR7240_PORT_CTRL_HEADER BIT(11)
++#define AR7240_PORT_CTRL_MAC_LOOP BIT(12)
++#define AR7240_PORT_CTRL_SINGLE_VLAN BIT(13)
++#define AR7240_PORT_CTRL_LEARN BIT(14)
++#define AR7240_PORT_CTRL_DOUBLE_TAG BIT(15)
++#define AR7240_PORT_CTRL_MIRROR_TX BIT(16)
++#define AR7240_PORT_CTRL_MIRROR_RX BIT(17)
++
++#define AR7240_REG_PORT_VLAN(_port) (AR7240_REG_PORT_BASE((_port)) + 0x08)
++
++#define AR7240_PORT_VLAN_DEFAULT_ID_S 0
++#define AR7240_PORT_VLAN_DEST_PORTS_S 16
++
++#define AR7240_REG_STATS_BASE(_port) (0x20000 + (_port) * 0x100)
++
++#define AR7240_STATS_RXBROAD 0x00
++#define AR7240_STATS_RXPAUSE 0x04
++#define AR7240_STATS_RXMULTI 0x08
++#define AR7240_STATS_RXFCSERR 0x0c
++#define AR7240_STATS_RXALIGNERR 0x10
++#define AR7240_STATS_RXRUNT 0x14
++#define AR7240_STATS_RXFRAGMENT 0x18
++#define AR7240_STATS_RX64BYTE 0x1c
++#define AR7240_STATS_RX128BYTE 0x20
++#define AR7240_STATS_RX256BYTE 0x24
++#define AR7240_STATS_RX512BYTE 0x28
++#define AR7240_STATS_RX1024BYTE 0x2c
++#define AR7240_STATS_RX1518BYTE 0x30
++#define AR7240_STATS_RXMAXBYTE 0x34
++#define AR7240_STATS_RXTOOLONG 0x38
++#define AR7240_STATS_RXGOODBYTE 0x3c
++#define AR7240_STATS_RXBADBYTE 0x44
++#define AR7240_STATS_RXOVERFLOW 0x4c
++#define AR7240_STATS_FILTERED 0x50
++#define AR7240_STATS_TXBROAD 0x54
++#define AR7240_STATS_TXPAUSE 0x58
++#define AR7240_STATS_TXMULTI 0x5c
++#define AR7240_STATS_TXUNDERRUN 0x60
++#define AR7240_STATS_TX64BYTE 0x64
++#define AR7240_STATS_TX128BYTE 0x68
++#define AR7240_STATS_TX256BYTE 0x6c
++#define AR7240_STATS_TX512BYTE 0x70
++#define AR7240_STATS_TX1024BYTE 0x74
++#define AR7240_STATS_TX1518BYTE 0x78
++#define AR7240_STATS_TXMAXBYTE 0x7c
++#define AR7240_STATS_TXOVERSIZE 0x80
++#define AR7240_STATS_TXBYTE 0x84
++#define AR7240_STATS_TXCOLLISION 0x8c
++#define AR7240_STATS_TXABORTCOL 0x90
++#define AR7240_STATS_TXMULTICOL 0x94
++#define AR7240_STATS_TXSINGLECOL 0x98
++#define AR7240_STATS_TXEXCDEFER 0x9c
++#define AR7240_STATS_TXDEFER 0xa0
++#define AR7240_STATS_TXLATECOL 0xa4
++
++#define AR7240_PORT_CPU 0
++#define AR7240_NUM_PORTS 6
++#define AR7240_NUM_PHYS 5
++
++#define AR7240_PHY_ID1 0x004d
++#define AR7240_PHY_ID2 0xd041
++
++#define AR7240_PORT_MASK(_port) BIT((_port))
++#define AR7240_PORT_MASK_ALL BITM(AR7240_NUM_PORTS)
++#define AR7240_PORT_MASK_BUT(_port) (AR7240_PORT_MASK_ALL & ~BIT((_port)))
++
++struct ar7240sw {
++ struct mii_bus *mii_bus;
++ struct mutex reg_mutex;
++ struct mutex stats_mutex;
++};
++
++struct ar7240sw_hw_stat {
++ char string[ETH_GSTRING_LEN];
++ int sizeof_stat;
++ int reg;
++};
++
++static inline struct ar7240sw *dsa_to_ar7240sw(struct dsa_switch *ds)
++{
++ return (struct ar7240sw *)(ds + 1);
++}
++
++static inline void ar7240sw_init(struct ar7240sw *as, struct mii_bus *mii)
++{
++ as->mii_bus = mii;
++ mutex_init(&as->reg_mutex);
++ mutex_init(&as->stats_mutex);
++}
++
++static inline u16 mk_phy_addr(u32 reg)
++{
++ return (0x17 & ((reg >> 4) | 0x10));
++}
++
++static inline u16 mk_phy_reg(u32 reg)
++{
++ return ((reg << 1) & 0x1e);
++}
++
++static inline u16 mk_high_addr(u32 reg)
++{
++ return ((reg >> 7) & 0x1ff);
++}
++
++static u32 __ar7240sw_reg_read(struct ar7240sw *as, u32 reg)
++{
++ struct mii_bus *mii = as->mii_bus;
++ u16 phy_addr;
++ u16 phy_reg;
++ u32 hi, lo;
++
++ reg = (reg & 0xfffffffc) >> 2;
++
++ mdiobus_write(mii, 0x1f, 0x10, mk_high_addr(reg));
++
++ phy_addr = mk_phy_addr(reg);
++ phy_reg = mk_phy_reg(reg);
++
++ lo = (u32) mdiobus_read(mii, phy_addr, phy_reg);
++ hi = (u32) mdiobus_read(mii, phy_addr, phy_reg + 1);
++
++ return ((hi << 16) | lo);
++}
++
++static void __ar7240sw_reg_write(struct ar7240sw *as, u32 reg, u32 val)
++{
++ struct mii_bus *mii = as->mii_bus;
++ u16 phy_addr;
++ u16 phy_reg;
++
++ reg = (reg & 0xfffffffc) >> 2;
++
++ mdiobus_write(mii, 0x1f, 0x10, mk_high_addr(reg));
++
++ phy_addr = mk_phy_addr(reg);
++ phy_reg = mk_phy_reg(reg);
++
++ mdiobus_write(mii, phy_addr, phy_reg + 1, (val >> 16));
++ mdiobus_write(mii, phy_addr, phy_reg, (val & 0xffff));
++}
++
++static u32 ar7240sw_reg_read(struct ar7240sw *as, u32 reg_addr)
++{
++ u32 ret;
++
++ mutex_lock(&as->reg_mutex);
++ ret = __ar7240sw_reg_read(as, reg_addr);
++ mutex_unlock(&as->reg_mutex);
++
++ return ret;
++}
++
++static void ar7240sw_reg_write(struct ar7240sw *as, u32 reg_addr, u32 reg_val)
++{
++ mutex_lock(&as->reg_mutex);
++ __ar7240sw_reg_write(as, reg_addr, reg_val);
++ mutex_unlock(&as->reg_mutex);
++}
++
++static u32 ar7240sw_reg_rmw(struct ar7240sw *as, u32 reg, u32 mask, u32 val)
++{
++ u32 t;
++
++ mutex_lock(&as->reg_mutex);
++ t = __ar7240sw_reg_read(as, reg);
++ t &= ~mask;
++ t |= val;
++ __ar7240sw_reg_write(as, reg, t);
++ mutex_unlock(&as->reg_mutex);
++
++ return t;
++}
++
++static void ar7240sw_reg_set(struct ar7240sw *as, u32 reg, u32 val)
++{
++ u32 t;
++
++ mutex_lock(&as->reg_mutex);
++ t = __ar7240sw_reg_read(as, reg);
++ t |= val;
++ __ar7240sw_reg_write(as, reg, t);
++ mutex_unlock(&as->reg_mutex);
++}
++
++static int ar7240sw_reg_wait(struct ar7240sw *as, u32 reg, u32 mask, u32 val,
++ unsigned timeout)
++{
++ int i;
++
++ for (i = 0; i < timeout; i++) {
++ u32 t;
++
++ t = ar7240sw_reg_read(as, reg);
++ if ((t & mask) == val)
++ return 0;
++
++ msleep(1);
++ }
++
++ return -ETIMEDOUT;
++}
++
++static u16 ar7240sw_phy_read(struct ar7240sw *as, unsigned phy_addr,
++ unsigned reg_addr)
++{
++ u32 t;
++ int err;
++
++ if (phy_addr >= AR7240_NUM_PHYS)
++ return 0xffff;
++
++ t = (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) |
++ (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) |
++ AR7240_MDIO_CTRL_MASTER_EN |
++ AR7240_MDIO_CTRL_BUSY |
++ AR7240_MDIO_CTRL_CMD_READ;
++
++ ar7240sw_reg_write(as, AR7240_REG_MDIO_CTRL, t);
++ err = ar7240sw_reg_wait(as, AR7240_REG_MDIO_CTRL,
++ AR7240_MDIO_CTRL_BUSY, 0, 5);
++ if (err)
++ return 0xffff;
++
++ t = ar7240sw_reg_read(as, AR7240_REG_MDIO_CTRL);
++ return (t & AR7240_MDIO_CTRL_DATA_M);
++}
++
++static int ar7240sw_phy_write(struct ar7240sw *as, unsigned phy_addr,
++ unsigned reg_addr, u16 reg_val)
++{
++ u32 t;
++ int ret;
++
++ if (phy_addr >= AR7240_NUM_PHYS)
++ return -EINVAL;
++
++ t = (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) |
++ (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) |
++ AR7240_MDIO_CTRL_MASTER_EN |
++ AR7240_MDIO_CTRL_BUSY |
++ AR7240_MDIO_CTRL_CMD_WRITE |
++ reg_val;
++
++ ar7240sw_reg_write(as, AR7240_REG_MDIO_CTRL, t);
++ ret = ar7240sw_reg_wait(as, AR7240_REG_MDIO_CTRL,
++ AR7240_MDIO_CTRL_BUSY, 0, 5);
++ return ret;
++}
++
++static int ar7240sw_capture_stats(struct ar7240sw *as)
++{
++ int ret;
++
++ /* Capture the hardware statistics for all ports */
++ ar7240sw_reg_write(as, AR7240_REG_MIB_FUNCTION0,
++ (AR7240_MIB_FUNC_CAPTURE << AR7240_MIB_FUNC_S));
++
++ /* Wait for the capturing to complete. */
++ ret = ar7240sw_reg_wait(as, AR7240_REG_MIB_FUNCTION0,
++ AR7240_MIB_BUSY, 0, 10);
++ return ret;
++}
++
++static void ar7240sw_disable_port(struct ar7240sw *as, unsigned port)
++{
++ ar7240sw_reg_write(as, AR7240_REG_PORT_CTRL(port),
++ AR7240_PORT_CTRL_STATE_DISABLED);
++}
++
++static int ar7240sw_reset(struct ar7240sw *as)
++{
++ int ret;
++ int i;
++
++ /* Set all ports to disabled state. */
++ for (i = 0; i < AR7240_NUM_PORTS; i++)
++ ar7240sw_disable_port(as, i);
++
++ /* Wait for transmit queues to drain. */
++ msleep(2);
++
++ /* Reset the switch. */
++ ar7240sw_reg_write(as, AR7240_REG_MASK_CTRL,
++ AR7240_MASK_CTRL_SOFT_RESET);
++
++ ret = ar7240sw_reg_wait(as, AR7240_REG_MASK_CTRL,
++ AR7240_MASK_CTRL_SOFT_RESET, 0, 1000);
++ return ret;
++}
++
++static void ar7240sw_setup(struct ar7240sw *as)
++{
++ /* Enable CPU port, and disable mirror port */
++ ar7240sw_reg_write(as, AR7240_REG_CPU_PORT,
++ AR7240_CPU_PORT_EN |
++ (15 << AR7240_MIRROR_PORT_S));
++
++ /* Setup TAG priority mapping */
++ ar7240sw_reg_write(as, AR7240_REG_TAG_PRIORITY, 0xfa50);
++
++ /* Enable ARP frame acknowledge */
++ ar7240sw_reg_set(as, AR7240_REG_AT_CTRL, AR7240_AT_CTRL_ARP_EN);
++
++ /* Enable Broadcast frames transmitted to the CPU */
++ ar7240sw_reg_set(as, AR7240_REG_FLOOD_MASK,
++ AR7240_FLOOD_MASK_BROAD_TO_CPU);
++
++ /* setup MTU */
++ ar7240sw_reg_rmw(as, AR7240_REG_GLOBAL_CTRL, AR7240_GLOBAL_CTRL_MTU_M,
++ 1536);
++
++ /* setup Service TAG */
++ ar7240sw_reg_rmw(as, AR7240_REG_SERVICE_TAG, AR7240_SERVICE_TAG_M,
++ ETH_P_QINQ);
++}
++
++static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port)
++{
++ u32 ctrl;
++ u32 dest_ports;
++ u32 vlan;
++
++ ctrl = AR7240_PORT_CTRL_STATE_FORWARD;
++
++ if (port == AR7240_PORT_CPU) {
++ ar7240sw_reg_write(as, AR7240_REG_PORT_STATUS(port),
++ AR7240_PORT_STATUS_SPEED_1000 |
++ AR7240_PORT_STATUS_TXFLOW |
++ AR7240_PORT_STATUS_RXFLOW |
++ AR7240_PORT_STATUS_TXMAC |
++ AR7240_PORT_STATUS_RXMAC |
++ AR7240_PORT_STATUS_DUPLEX);
++
++ /* allow the CPU port to talk to each of the 'real' ports */
++ dest_ports = AR7240_PORT_MASK_BUT(port);
++
++ /* remove service tag from ingress frames */
++ ctrl |= AR7240_PORT_CTRL_DOUBLE_TAG;
++ } else {
++ ar7240sw_reg_write(as, AR7240_REG_PORT_STATUS(port),
++ AR7240_PORT_STATUS_LINK_AUTO);
++
++ /*
++ * allow each of the 'real' ports to only talk to the CPU
++ * port.
++ */
++ dest_ports = AR7240_PORT_MASK(port) |
++ AR7240_PORT_MASK(AR7240_PORT_CPU);
++
++ /* add service tag to egress frames */
++ ctrl |= (AR7240_PORT_CTRL_VLAN_MODE_DOUBLE_TAG <<
++ AR7240_PORT_CTRL_VLAN_MODE_S);
++ }
++
++ /* set default VID and and destination ports for this VLAN */
++ vlan = port;
++ vlan |= (dest_ports << AR7240_PORT_VLAN_DEST_PORTS_S);
++
++ ar7240sw_reg_write(as, AR7240_REG_PORT_CTRL(port), ctrl);
++ ar7240sw_reg_write(as, AR7240_REG_PORT_VLAN(port), vlan);
++}
++
++static char *ar7240_dsa_probe(struct mii_bus *mii, int sw_addr)
++{
++ struct ar7240sw as;
++ u32 ctrl;
++ u16 phy_id1;
++ u16 phy_id2;
++ u8 ver;
++
++ ar7240sw_init(&as, mii);
++
++ ctrl = ar7240sw_reg_read(&as, AR7240_REG_MASK_CTRL);
++
++ ver = (ctrl >> AR7240_MASK_CTRL_VERSION_S) & AR7240_MASK_CTRL_VERSION_M;
++ if (ver != 1) {
++ pr_err("ar7240_dsa: unsupported chip, ctrl=%08x\n", ctrl);
++ return NULL;
++ }
++
++ phy_id1 = ar7240sw_phy_read(&as, 0, MII_PHYSID1);
++ phy_id2 = ar7240sw_phy_read(&as, 0, MII_PHYSID2);
++ if (phy_id1 != AR7240_PHY_ID1 || phy_id2 != AR7240_PHY_ID2) {
++ pr_err("ar7240_dsa: unknown phy id '%04x:%04x'\n",
++ phy_id1, phy_id2);
++ return NULL;
++ }
++
++ return "Atheros AR7240 built-in";
++}
++
++static int ar7240_dsa_setup(struct dsa_switch *ds)
++{
++ struct ar7240sw *as = dsa_to_ar7240sw(ds);
++ int i;
++ int ret;
++
++ ar7240sw_init(as, ds->master_mii_bus);
++
++ ret = ar7240sw_reset(as);
++ if (ret)
++ return ret;
++
++ ar7240sw_setup(as);
++
++ for (i = 0; i < AR7240_NUM_PORTS; i++) {
++ if (dsa_is_cpu_port(ds, i) || (ds->phys_port_mask & (1 << i)))
++ ar7240sw_setup_port(as, i);
++ else
++ ar7240sw_disable_port(as, i);
++ }
++
++ return 0;
++}
++
++static int ar7240_dsa_set_addr(struct dsa_switch *ds, u8 *addr)
++{
++ struct ar7240sw *as = dsa_to_ar7240sw(ds);
++ u32 t;
++
++ t = (addr[4] << 8) | addr[5];
++ ar7240sw_reg_write(as, AR7240_REG_MAC_ADDR0, t);
++
++ t = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
++ ar7240sw_reg_write(as, AR7240_REG_MAC_ADDR1, t);
++
++ return 0;
++}
++
++static int ar7240_iort_to_phy_addr(int port)
++{
++ if (port > 0 && port < AR7240_NUM_PORTS)
++ return port - 1;
++
++ return -EINVAL;
++}
++
++static int ar7240_dsa_phy_read(struct dsa_switch *ds, int port, int regnum)
++{
++ struct ar7240sw *as = dsa_to_ar7240sw(ds);
++ int phy_addr;
++
++ phy_addr = ar7240_iort_to_phy_addr(port);
++ if (phy_addr < 0)
++ return 0xffff;
++
++ return ar7240sw_phy_read(as, phy_addr, regnum);
++}
++
++static int ar7240_dsa_phy_write(struct dsa_switch *ds, int port, int regnum,
++ u16 val)
++{
++ struct ar7240sw *as = dsa_to_ar7240sw(ds);
++ int phy_addr;
++
++ phy_addr = ar7240_iort_to_phy_addr(port);
++ if (phy_addr < 0)
++ return 0xffff;
++
++ return ar7240sw_phy_write(as, phy_addr, regnum, val);
++}
++
++static const char *ar7240sw_speed_str(unsigned speed)
++{
++ switch (speed) {
++ case AR7240_PORT_STATUS_SPEED_10:
++ return "10";
++ case AR7240_PORT_STATUS_SPEED_100:
++ return "100";
++ case AR7240_PORT_STATUS_SPEED_1000:
++ return "1000";
++ }
++
++ return "????";
++}
++
++static void ar7240_dsa_poll_link(struct dsa_switch *ds)
++{
++ struct ar7240sw *as = dsa_to_ar7240sw(ds);
++ int i;
++
++ for (i = 0; i < DSA_MAX_PORTS; i++) {
++ struct net_device *dev;
++ u32 status;
++ int link;
++ unsigned speed;
++ int duplex;
++
++ dev = ds->ports[i];
++ if (dev == NULL)
++ continue;
++
++ link = 0;
++ if (dev->flags & IFF_UP) {
++ status = ar7240sw_reg_read(as,
++ AR7240_REG_PORT_STATUS(i));
++ link = !!(status & AR7240_PORT_STATUS_LINK_UP);
++ }
++
++ if (!link) {
++ if (netif_carrier_ok(dev)) {
++ pr_info("%s: link down\n", dev->name);
++ netif_carrier_off(dev);
++ }
++ continue;
++ }
++
++ speed = (status & AR7240_PORT_STATUS_SPEED_M);
++ duplex = (status & AR7240_PORT_STATUS_DUPLEX) ? 1 : 0;
++ if (!netif_carrier_ok(dev)) {
++ pr_info("%s: link up, %sMb/s, %s duplex",
++ dev->name,
++ ar7240sw_speed_str(speed),
++ duplex ? "full" : "half");
++ netif_carrier_on(dev);
++ }
++ }
++}
++
++static const struct ar7240sw_hw_stat ar7240_hw_stats[] = {
++ { "rx_broadcast" , 4, AR7240_STATS_RXBROAD, },
++ { "rx_pause" , 4, AR7240_STATS_RXPAUSE, },
++ { "rx_multicast" , 4, AR7240_STATS_RXMULTI, },
++ { "rx_fcs_error" , 4, AR7240_STATS_RXFCSERR, },
++ { "rx_align_error" , 4, AR7240_STATS_RXALIGNERR, },
++ { "rx_undersize" , 4, AR7240_STATS_RXRUNT, },
++ { "rx_fragments" , 4, AR7240_STATS_RXFRAGMENT, },
++ { "rx_64bytes" , 4, AR7240_STATS_RX64BYTE, },
++ { "rx_65_127bytes" , 4, AR7240_STATS_RX128BYTE, },
++ { "rx_128_255bytes" , 4, AR7240_STATS_RX256BYTE, },
++ { "rx_256_511bytes" , 4, AR7240_STATS_RX512BYTE, },
++ { "rx_512_1023bytes" , 4, AR7240_STATS_RX1024BYTE, },
++ { "rx_1024_1518bytes" , 4, AR7240_STATS_RX1518BYTE, },
++ { "rx_1519_max_bytes" , 4, AR7240_STATS_RXMAXBYTE, },
++ { "rx_oversize" , 4, AR7240_STATS_RXTOOLONG, },
++ { "rx_good_bytes" , 8, AR7240_STATS_RXGOODBYTE, },
++ { "rx_bad_bytes" , 8, AR7240_STATS_RXBADBYTE, },
++ { "rx_overflow" , 4, AR7240_STATS_RXOVERFLOW, },
++ { "filtered" , 4, AR7240_STATS_FILTERED, },
++ { "tx_broadcast" , 4, AR7240_STATS_TXBROAD, },
++ { "tx_pause" , 4, AR7240_STATS_TXPAUSE, },
++ { "tx_multicast" , 4, AR7240_STATS_TXMULTI, },
++ { "tx_underrun" , 4, AR7240_STATS_TXUNDERRUN, },
++ { "tx_64bytes" , 4, AR7240_STATS_TX64BYTE, },
++ { "tx_65_127bytes" , 4, AR7240_STATS_TX128BYTE, },
++ { "tx_128_255bytes" , 4, AR7240_STATS_TX256BYTE, },
++ { "tx_256_511bytes" , 4, AR7240_STATS_TX512BYTE, },
++ { "tx_512_1023bytes" , 4, AR7240_STATS_TX1024BYTE, },
++ { "tx_1024_1518bytes" , 4, AR7240_STATS_TX1518BYTE, },
++ { "tx_1519_max_bytes" , 4, AR7240_STATS_TXMAXBYTE, },
++ { "tx_oversize" , 4, AR7240_STATS_TXOVERSIZE, },
++ { "tx_bytes" , 8, AR7240_STATS_TXBYTE, },
++ { "tx_collisions" , 4, AR7240_STATS_TXCOLLISION, },
++ { "tx_abort_collisions" , 4, AR7240_STATS_TXABORTCOL, },
++ { "tx_multi_collisions" , 4, AR7240_STATS_TXMULTICOL, },
++ { "tx_single_collisions", 4, AR7240_STATS_TXSINGLECOL, },
++ { "tx_excessive_deferred", 4, AR7240_STATS_TXEXCDEFER, },
++ { "tx_deferred" , 4, AR7240_STATS_TXDEFER, },
++ { "tx_late_collisions" , 4, AR7240_STATS_TXLATECOL, },
++};
++
++static void ar7240_dsa_get_strings(struct dsa_switch *ds, int port,
++ uint8_t *data)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(ar7240_hw_stats); i++) {
++ memcpy(data + i * ETH_GSTRING_LEN,
++ ar7240_hw_stats[i].string, ETH_GSTRING_LEN);
++ }
++}
++
++static void ar7240_dsa_get_ethtool_stats(struct dsa_switch *ds, int port,
++ uint64_t *data)
++{
++ struct ar7240sw *as = dsa_to_ar7240sw(ds);
++ int err;
++ int i;
++
++ mutex_lock(&as->stats_mutex);
++
++ err = ar7240sw_capture_stats(as);
++ if (err)
++ goto unlock;
++
++ for (i = 0; i < ARRAY_SIZE(ar7240_hw_stats); i++) {
++ const struct ar7240sw_hw_stat *s = &ar7240_hw_stats[i];
++ u32 reg = AR7240_REG_STATS_BASE(port);
++ u32 low;
++ u32 high;
++
++ low = ar7240sw_reg_read(as, reg + s->reg);
++ if (s->sizeof_stat == 8)
++ high = ar7240sw_reg_read(as, reg + s->reg);
++ else
++ high = 0;
++
++ data[i] = (((u64) high) << 32) | low;
++ }
++
++ unlock:
++ mutex_unlock(&as->stats_mutex);
++}
++
++static int ar7240_dsa_get_sset_count(struct dsa_switch *ds)
++{
++ return ARRAY_SIZE(ar7240_hw_stats);
++}
++
++static struct dsa_switch_driver ar7240_dsa_driver = {
++ .tag_protocol = htons(ETH_P_QINQ),
++ .priv_size = sizeof(struct ar7240sw),
++ .probe = ar7240_dsa_probe,
++ .setup = ar7240_dsa_setup,
++ .set_addr = ar7240_dsa_set_addr,
++ .phy_read = ar7240_dsa_phy_read,
++ .phy_write = ar7240_dsa_phy_write,
++ .poll_link = ar7240_dsa_poll_link,
++ .get_strings = ar7240_dsa_get_strings,
++ .get_ethtool_stats = ar7240_dsa_get_ethtool_stats,
++ .get_sset_count = ar7240_dsa_get_sset_count,
++};
++
++int __init dsa_ar7240_init(void)
++{
++ register_switch_driver(&ar7240_dsa_driver);
++ return 0;
++}
++module_init(dsa_ar7240_init);
++
++void __exit dsa_ar7240_cleanup(void)
++{
++ unregister_switch_driver(&ar7240_dsa_driver);
++}
++module_exit(dsa_ar7240_cleanup);
+diff -Nur linux-2.6.37.orig/net/dsa/mv88e6063.c linux-2.6.37/net/dsa/mv88e6063.c
+--- linux-2.6.37.orig/net/dsa/mv88e6063.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/net/dsa/mv88e6063.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,294 @@
++/*
++ * net/dsa/mv88e6063.c - Driver for Marvell 88e6063 switch chips
++ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This driver was base on: net/dsa/mv88e6060.c
++ * net/dsa/mv88e6063.c - Driver for Marvell 88e6060 switch chips
++ * Copyright (c) 2008-2009 Marvell Semiconductor
++ *
++ * 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.
++ */
++
++#include <linux/list.h>
++#include <linux/netdevice.h>
++#include <linux/phy.h>
++#include "dsa_priv.h"
++
++#define REG_BASE 0x10
++#define REG_PHY(p) (REG_BASE + (p))
++#define REG_PORT(p) (REG_BASE + 8 + (p))
++#define REG_GLOBAL (REG_BASE + 0x0f)
++#define NUM_PORTS 7
++
++static int reg_read(struct dsa_switch *ds, int addr, int reg)
++{
++ return mdiobus_read(ds->master_mii_bus, addr, reg);
++}
++
++#define REG_READ(addr, reg) \
++ ({ \
++ int __ret; \
++ \
++ __ret = reg_read(ds, addr, reg); \
++ if (__ret < 0) \
++ return __ret; \
++ __ret; \
++ })
++
++
++static int reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
++{
++ return mdiobus_write(ds->master_mii_bus, addr, reg, val);
++}
++
++#define REG_WRITE(addr, reg, val) \
++ ({ \
++ int __ret; \
++ \
++ __ret = reg_write(ds, addr, reg, val); \
++ if (__ret < 0) \
++ return __ret; \
++ })
++
++static char *mv88e6063_probe(struct mii_bus *bus, int sw_addr)
++{
++ int ret;
++
++ ret = mdiobus_read(bus, REG_PORT(0), 0x03);
++ if (ret >= 0) {
++ ret &= 0xfff0;
++ if (ret == 0x1530)
++ return "Marvell 88E6063";
++ }
++
++ return NULL;
++}
++
++static int mv88e6063_switch_reset(struct dsa_switch *ds)
++{
++ int i;
++ int ret;
++
++ /*
++ * Set all ports to the disabled state.
++ */
++ for (i = 0; i < NUM_PORTS; i++) {
++ ret = REG_READ(REG_PORT(i), 0x04);
++ REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
++ }
++
++ /*
++ * Wait for transmit queues to drain.
++ */
++ msleep(2);
++
++ /*
++ * Reset the switch.
++ */
++ REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
++
++ /*
++ * Wait up to one second for reset to complete.
++ */
++ for (i = 0; i < 1000; i++) {
++ ret = REG_READ(REG_GLOBAL, 0x00);
++ if ((ret & 0x8000) == 0x0000)
++ break;
++
++ msleep(1);
++ }
++ if (i == 1000)
++ return -ETIMEDOUT;
++
++ return 0;
++}
++
++static int mv88e6063_setup_global(struct dsa_switch *ds)
++{
++ /*
++ * Disable discarding of frames with excessive collisions,
++ * set the maximum frame size to 1536 bytes, and mask all
++ * interrupt sources.
++ */
++ REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
++
++ /*
++ * Enable automatic address learning, set the address
++ * database size to 1024 entries, and set the default aging
++ * time to 5 minutes.
++ */
++ REG_WRITE(REG_GLOBAL, 0x0a, 0x2130);
++
++ return 0;
++}
++
++static int mv88e6063_setup_port(struct dsa_switch *ds, int p)
++{
++ int addr = REG_PORT(p);
++
++ /*
++ * Do not force flow control, disable Ingress and Egress
++ * Header tagging, disable VLAN tunneling, and set the port
++ * state to Forwarding. Additionally, if this is the CPU
++ * port, enable Ingress and Egress Trailer tagging mode.
++ */
++ REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ? 0x4103 : 0x0003);
++
++ /*
++ * Port based VLAN map: give each port its own address
++ * database, allow the CPU port to talk to each of the 'real'
++ * ports, and allow each of the 'real' ports to only talk to
++ * the CPU port.
++ */
++ REG_WRITE(addr, 0x06,
++ ((p & 0xf) << 12) |
++ (dsa_is_cpu_port(ds, p) ?
++ ds->phys_port_mask :
++ (1 << ds->dst->cpu_port)));
++
++ /*
++ * Port Association Vector: when learning source addresses
++ * of packets, add the address to the address database using
++ * a port bitmap that has only the bit for this port set and
++ * the other bits clear.
++ */
++ REG_WRITE(addr, 0x0b, 1 << p);
++
++ return 0;
++}
++
++static int mv88e6063_setup(struct dsa_switch *ds)
++{
++ int i;
++ int ret;
++
++ ret = mv88e6063_switch_reset(ds);
++ if (ret < 0)
++ return ret;
++
++ /* @@@ initialise atu */
++
++ ret = mv88e6063_setup_global(ds);
++ if (ret < 0)
++ return ret;
++
++ for (i = 0; i < NUM_PORTS; i++) {
++ ret = mv88e6063_setup_port(ds, i);
++ if (ret < 0)
++ return ret;
++ }
++
++ return 0;
++}
++
++static int mv88e6063_set_addr(struct dsa_switch *ds, u8 *addr)
++{
++ REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]);
++ REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]);
++ REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]);
++
++ return 0;
++}
++
++static int mv88e6063_port_to_phy_addr(int port)
++{
++ if (port >= 0 && port <= NUM_PORTS)
++ return REG_PHY(port);
++ return -1;
++}
++
++static int mv88e6063_phy_read(struct dsa_switch *ds, int port, int regnum)
++{
++ int addr;
++
++ addr = mv88e6063_port_to_phy_addr(port);
++ if (addr == -1)
++ return 0xffff;
++
++ return reg_read(ds, addr, regnum);
++}
++
++static int
++mv88e6063_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
++{
++ int addr;
++
++ addr = mv88e6063_port_to_phy_addr(port);
++ if (addr == -1)
++ return 0xffff;
++
++ return reg_write(ds, addr, regnum, val);
++}
++
++static void mv88e6063_poll_link(struct dsa_switch *ds)
++{
++ int i;
++
++ for (i = 0; i < DSA_MAX_PORTS; i++) {
++ struct net_device *dev;
++ int uninitialized_var(port_status);
++ int link;
++ int speed;
++ int duplex;
++ int fc;
++
++ dev = ds->ports[i];
++ if (dev == NULL)
++ continue;
++
++ link = 0;
++ if (dev->flags & IFF_UP) {
++ port_status = reg_read(ds, REG_PORT(i), 0x00);
++ if (port_status < 0)
++ continue;
++
++ link = !!(port_status & 0x1000);
++ }
++
++ if (!link) {
++ if (netif_carrier_ok(dev)) {
++ printk(KERN_INFO "%s: link down\n", dev->name);
++ netif_carrier_off(dev);
++ }
++ continue;
++ }
++
++ speed = (port_status & 0x0100) ? 100 : 10;
++ duplex = (port_status & 0x0200) ? 1 : 0;
++ fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
++
++ if (!netif_carrier_ok(dev)) {
++ printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
++ "flow control %sabled\n", dev->name,
++ speed, duplex ? "full" : "half",
++ fc ? "en" : "dis");
++ netif_carrier_on(dev);
++ }
++ }
++}
++
++static struct dsa_switch_driver mv88e6063_switch_driver = {
++ .tag_protocol = htons(ETH_P_TRAILER),
++ .probe = mv88e6063_probe,
++ .setup = mv88e6063_setup,
++ .set_addr = mv88e6063_set_addr,
++ .phy_read = mv88e6063_phy_read,
++ .phy_write = mv88e6063_phy_write,
++ .poll_link = mv88e6063_poll_link,
++};
++
++static int __init mv88e6063_init(void)
++{
++ register_switch_driver(&mv88e6063_switch_driver);
++ return 0;
++}
++module_init(mv88e6063_init);
++
++static void __exit mv88e6063_cleanup(void)
++{
++ unregister_switch_driver(&mv88e6063_switch_driver);
++}
++module_exit(mv88e6063_cleanup);
+diff -Nur linux-2.6.37.orig/net/dsa/tag_qinq.c linux-2.6.37/net/dsa/tag_qinq.c
+--- linux-2.6.37.orig/net/dsa/tag_qinq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/net/dsa/tag_qinq.c 2011-01-11 20:25:48.000000000 +0100
+@@ -0,0 +1,127 @@
++/*
++ * net/dsa/tag_qinq.c - QinQ tag format handling
++ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This file was based on:
++ * net/dsa/tag_edsa.c - Ethertype DSA tagging
++ * Copyright (c) 2008-2009 Marvell Semiconductor
++ *
++ * 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.
++ */
++
++#include <linux/etherdevice.h>
++#include <linux/list.h>
++#include <linux/netdevice.h>
++#include <linux/if_vlan.h>
++
++#include "dsa_priv.h"
++
++netdev_tx_t qinq_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct dsa_slave_priv *p = netdev_priv(dev);
++ struct vlan_ethhdr *veth;
++ unsigned int len;
++ int ret;
++
++ if (skb_cow_head(skb, VLAN_HLEN) < 0)
++ goto out_free_skb;
++
++ veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
++
++ /* Move the mac addresses to the beginning of the new header. */
++ memmove(skb->data, skb->data + VLAN_HLEN, 2 * VLAN_ETH_ALEN);
++ skb->mac_header -= VLAN_HLEN;
++
++ /* setup VLAN header fields */
++ veth->h_vlan_proto = htons(ETH_P_QINQ);
++ veth->h_vlan_TCI = htons(p->port);
++
++ len = skb->len;
++ skb->protocol = htons(ETH_P_QINQ);
++ skb->dev = p->parent->dst->master_netdev;
++
++ ret = dev_queue_xmit(skb);
++ if (unlikely(ret != NET_XMIT_SUCCESS))
++ goto out_dropped;
++
++ dev->stats.tx_packets++;
++ dev->stats.tx_bytes += len;
++
++ return NETDEV_TX_OK;
++
++ out_free_skb:
++ kfree_skb(skb);
++ out_dropped:
++ dev->stats.tx_dropped++;
++ return NETDEV_TX_OK;
++}
++
++static int qinq_rcv(struct sk_buff *skb, struct net_device *dev,
++ struct packet_type *pt, struct net_device *orig_dev)
++{
++ struct dsa_switch_tree *dst;
++ struct dsa_switch *ds;
++ struct vlan_hdr *vhdr;
++ int source_port;
++
++ dst = dev->dsa_ptr;
++ if (unlikely(dst == NULL))
++ goto out_drop;
++ ds = dst->ds[0];
++
++ skb = skb_unshare(skb, GFP_ATOMIC);
++ if (skb == NULL)
++ goto out;
++
++ if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
++ goto out_drop;
++
++ vhdr = (struct vlan_hdr *)skb->data;
++ source_port = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
++ if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
++ goto out_drop;
++
++ /* Remove the outermost VLAN tag and update checksum. */
++ skb_pull_rcsum(skb, VLAN_HLEN);
++ memmove(skb->data - ETH_HLEN,
++ skb->data - ETH_HLEN - VLAN_HLEN,
++ 2 * ETH_ALEN);
++
++ skb->dev = ds->ports[source_port];
++ skb_push(skb, ETH_HLEN);
++ skb->pkt_type = PACKET_HOST;
++ skb->protocol = eth_type_trans(skb, skb->dev);
++
++ skb->dev->stats.rx_packets++;
++ skb->dev->stats.rx_bytes += skb->len;
++
++ netif_receive_skb(skb);
++
++ return 0;
++
++ out_drop:
++ kfree_skb(skb);
++ out:
++ return 0;
++}
++
++static struct packet_type qinq_packet_type __read_mostly = {
++ .type = cpu_to_be16(ETH_P_QINQ),
++ .func = qinq_rcv,
++};
++
++static int __init qinq_init_module(void)
++{
++ dev_add_pack(&qinq_packet_type);
++ return 0;
++}
++module_init(qinq_init_module);
++
++static void __exit qinq_cleanup_module(void)
++{
++ dev_remove_pack(&qinq_packet_type);
++}
++module_exit(qinq_cleanup_module);
diff --git a/target/linux/patches/2.6.37/aufs2.patch b/target/linux/patches/2.6.37/aufs2.patch
new file mode 100644
index 000000000..7cfe43065
--- /dev/null
+++ b/target/linux/patches/2.6.37/aufs2.patch
@@ -0,0 +1,28523 @@
+diff -Nur linux-2.6.37.orig/fs/Kconfig linux-2.6.37/fs/Kconfig
+--- linux-2.6.37.orig/fs/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/fs/Kconfig 2011-01-11 20:15:11.000000000 +0100
+@@ -191,6 +191,7 @@
+ source "fs/sysv/Kconfig"
+ source "fs/ufs/Kconfig"
+ source "fs/exofs/Kconfig"
++source "fs/aufs/Kconfig"
+
+ endif # MISC_FILESYSTEMS
+
+diff -Nur linux-2.6.37.orig/fs/Makefile linux-2.6.37/fs/Makefile
+--- linux-2.6.37.orig/fs/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/fs/Makefile 2011-01-11 20:15:11.000000000 +0100
+@@ -121,3 +121,4 @@
+ obj-$(CONFIG_GFS2_FS) += gfs2/
+ obj-$(CONFIG_EXOFS_FS) += exofs/
+ obj-$(CONFIG_CEPH_FS) += ceph/
++obj-$(CONFIG_AUFS_FS) += aufs/
+diff -Nur linux-2.6.37.orig/fs/aufs/Kconfig linux-2.6.37/fs/aufs/Kconfig
+--- linux-2.6.37.orig/fs/aufs/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/Kconfig 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,180 @@
++config AUFS_FS
++ tristate "Aufs (Advanced multi layered unification filesystem) support"
++ depends on EXPERIMENTAL
++ help
++ Aufs is a stackable unification filesystem such as Unionfs,
++ which unifies several directories and provides a merged single
++ directory.
++ In the early days, aufs was entirely re-designed and
++ re-implemented Unionfs Version 1.x series. Introducing many
++ original ideas, approaches and improvements, it becomes totally
++ different from Unionfs while keeping the basic features.
++
++if AUFS_FS
++choice
++ prompt "Maximum number of branches"
++ default AUFS_BRANCH_MAX_127
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_127
++ bool "127"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_511
++ bool "511"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_1023
++ bool "1023"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_32767
++ bool "32767"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++endchoice
++
++config AUFS_SBILIST
++ bool
++ depends on AUFS_MAGIC_SYSRQ || PROC_FS
++ default y
++ help
++ Automatic configuration for internal use.
++ When aufs supports Magic SysRq or /proc, enabled automatically.
++
++config AUFS_HNOTIFY
++ bool "Detect direct branch access (bypassing aufs)"
++ help
++ If you want to modify files on branches directly, eg. bypassing aufs,
++ and want aufs to detect the changes of them fully, then enable this
++ option and use 'udba=notify' mount option.
++ Currently there is only one available configuration, "fsnotify".
++ It will have a negative impact to the performance.
++ See detail in aufs.5.
++
++choice
++ prompt "method" if AUFS_HNOTIFY
++ default AUFS_HFSNOTIFY
++config AUFS_HFSNOTIFY
++ bool "fsnotify"
++ select FSNOTIFY
++endchoice
++
++config AUFS_EXPORT
++ bool "NFS-exportable aufs"
++ depends on (AUFS_FS = y && EXPORTFS = y) || (AUFS_FS = m && EXPORTFS)
++ help
++ If you want to export your mounted aufs via NFS, then enable this
++ option. There are several requirements for this configuration.
++ See detail in aufs.5.
++
++config AUFS_INO_T_64
++ bool
++ depends on AUFS_EXPORT
++ depends on 64BIT && !(ALPHA || S390)
++ default y
++ help
++ Automatic configuration for internal use.
++ /* typedef unsigned long/int __kernel_ino_t */
++ /* alpha and s390x are int */
++
++config AUFS_RDU
++ bool "Readdir in userspace"
++ help
++ Aufs has two methods to provide a merged view for a directory,
++ by a user-space library and by kernel-space natively. The latter
++ is always enabled but sometimes large and slow.
++ If you enable this option, install the library in aufs2-util
++ package, and set some environment variables for your readdir(3),
++ then the work will be handled in user-space which generally
++ shows better performance in most cases.
++ See detail in aufs.5.
++
++config AUFS_SP_IATTR
++ bool "Respect the attributes (mtime/ctime mainly) of special files"
++ help
++ When you write something to a special file, some attributes of it
++ (mtime/ctime mainly) may be updated. Generally such updates are
++ less important (actually some device drivers and NFS ignore
++ it). But some applications (such like test program) requires
++ such updates. If you need these updates, then enable this
++ configuration which introduces some overhead.
++ Currently this configuration handles FIFO only.
++
++config AUFS_SHWH
++ bool "Show whiteouts"
++ help
++ If you want to make the whiteouts in aufs visible, then enable
++ this option and specify 'shwh' mount option. Although it may
++ sounds like philosophy or something, but in technically it
++ simply shows the name of whiteout with keeping its behaviour.
++
++config AUFS_BR_RAMFS
++ bool "Ramfs (initramfs/rootfs) as an aufs branch"
++ help
++ If you want to use ramfs as an aufs branch fs, then enable this
++ option. Generally tmpfs is recommended.
++ Aufs prohibited them to be a branch fs by default, because
++ initramfs becomes unusable after switch_root or something
++ generally. If you sets initramfs as an aufs branch and boot your
++ system by switch_root, you will meet a problem easily since the
++ files in initramfs may be inaccessible.
++ Unless you are going to use ramfs as an aufs branch fs without
++ switch_root or something, leave it N.
++
++config AUFS_BR_FUSE
++ bool "Fuse fs as an aufs branch"
++ depends on FUSE_FS
++ select AUFS_POLL
++ help
++ If you want to use fuse-based userspace filesystem as an aufs
++ branch fs, then enable this option.
++ It implements the internal poll(2) operation which is
++ implemented by fuse only (curretnly).
++
++config AUFS_POLL
++ bool
++ help
++ Automatic configuration for internal use.
++
++config AUFS_BR_HFSPLUS
++ bool "Hfsplus as an aufs branch"
++ depends on HFSPLUS_FS
++ default y
++ help
++ If you want to use hfsplus fs as an aufs branch fs, then enable
++ this option. This option introduces a small overhead at
++ copying-up a file on hfsplus.
++
++config AUFS_BDEV_LOOP
++ bool
++ depends on BLK_DEV_LOOP
++ default y
++ help
++ Automatic configuration for internal use.
++ Convert =[ym] into =y.
++
++config AUFS_DEBUG
++ bool "Debug aufs"
++ help
++ Enable this to compile aufs internal debug code.
++ It will have a negative impact to the performance.
++
++config AUFS_MAGIC_SYSRQ
++ bool
++ depends on AUFS_DEBUG && MAGIC_SYSRQ
++ default y
++ help
++ Automatic configuration for internal use.
++ When aufs supports Magic SysRq, enabled automatically.
++endif
+diff -Nur linux-2.6.37.orig/fs/aufs/Makefile linux-2.6.37/fs/aufs/Makefile
+--- linux-2.6.37.orig/fs/aufs/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/Makefile 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,38 @@
++
++include ${src}/magic.mk
++ifeq (${CONFIG_AUFS_FS},m)
++include ${src}/conf.mk
++endif
++-include ${src}/priv_def.mk
++
++# cf. include/linux/kernel.h
++# enable pr_debug
++ccflags-y += -DDEBUG
++# sparse doesn't allow spaces
++ccflags-y += -D'pr_fmt(fmt)=AUFS_NAME"\040%s:%d:%s[%d]:\040"fmt,__func__,__LINE__,current->comm,current->pid'
++
++obj-$(CONFIG_AUFS_FS) += aufs.o
++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \
++ wkq.o vfsub.o dcsub.o \
++ cpup.o whout.o wbr_policy.o \
++ dinfo.o dentry.o \
++ dynop.o \
++ finfo.o file.o f_op.o \
++ dir.o vdir.o \
++ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \
++ ioctl.o
++
++# all are boolean
++aufs-$(CONFIG_PROC_FS) += procfs.o plink.o
++aufs-$(CONFIG_SYSFS) += sysfs.o
++aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o
++aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o
++aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o
++aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o
++aufs-$(CONFIG_AUFS_EXPORT) += export.o
++aufs-$(CONFIG_AUFS_POLL) += poll.o
++aufs-$(CONFIG_AUFS_RDU) += rdu.o
++aufs-$(CONFIG_AUFS_SP_IATTR) += f_op_sp.o
++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o
++aufs-$(CONFIG_AUFS_DEBUG) += debug.o
++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o
+diff -Nur linux-2.6.37.orig/fs/aufs/aufs.h linux-2.6.37/fs/aufs/aufs.h
+--- linux-2.6.37.orig/fs/aufs/aufs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/aufs.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * all header files
++ */
++
++#ifndef __AUFS_H__
++#define __AUFS_H__
++
++#ifdef __KERNEL__
++
++#define AuStub(type, name, body, ...) \
++ static inline type name(__VA_ARGS__) { body; }
++
++#define AuStubVoid(name, ...) \
++ AuStub(void, name, , __VA_ARGS__)
++#define AuStubInt0(name, ...) \
++ AuStub(int, name, return 0, __VA_ARGS__)
++
++#include "debug.h"
++
++#include "branch.h"
++#include "cpup.h"
++#include "dcsub.h"
++#include "dbgaufs.h"
++#include "dentry.h"
++#include "dir.h"
++#include "dynop.h"
++#include "file.h"
++#include "fstype.h"
++#include "inode.h"
++#include "loop.h"
++#include "module.h"
++/* never include ./mtx.h */
++#include "opts.h"
++#include "rwsem.h"
++#include "spl.h"
++#include "super.h"
++#include "sysaufs.h"
++#include "vfsub.h"
++#include "whout.h"
++#include "wkq.h"
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/branch.c linux-2.6.37/fs/aufs/branch.c
+--- linux-2.6.37.orig/fs/aufs/branch.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/branch.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,1071 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * branch management
++ */
++
++#include <linux/file.h>
++#include <linux/statfs.h>
++#include "aufs.h"
++
++/*
++ * free a single branch
++ */
++static void au_br_do_free(struct au_branch *br)
++{
++ int i;
++ struct au_wbr *wbr;
++ struct au_dykey **key;
++
++ au_hnotify_fin_br(br);
++
++ if (br->br_xino.xi_file)
++ fput(br->br_xino.xi_file);
++ mutex_destroy(&br->br_xino.xi_nondir_mtx);
++
++ AuDebugOn(atomic_read(&br->br_count));
++
++ wbr = br->br_wbr;
++ if (wbr) {
++ for (i = 0; i < AuBrWh_Last; i++)
++ dput(wbr->wbr_wh[i]);
++ AuDebugOn(atomic_read(&wbr->wbr_wh_running));
++ AuRwDestroy(&wbr->wbr_wh_rwsem);
++ }
++
++ key = br->br_dykey;
++ for (i = 0; i < AuBrDynOp; i++, key++)
++ if (*key)
++ au_dy_put(*key);
++ else
++ break;
++
++ mntput(br->br_mnt);
++ kfree(wbr);
++ kfree(br);
++}
++
++/*
++ * frees all branches
++ */
++void au_br_free(struct au_sbinfo *sbinfo)
++{
++ aufs_bindex_t bmax;
++ struct au_branch **br;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ bmax = sbinfo->si_bend + 1;
++ br = sbinfo->si_branch;
++ while (bmax--)
++ au_br_do_free(*br++);
++}
++
++/*
++ * find the index of a branch which is specified by @br_id.
++ */
++int au_br_index(struct super_block *sb, aufs_bindex_t br_id)
++{
++ aufs_bindex_t bindex, bend;
++
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++)
++ if (au_sbr_id(sb, bindex) == br_id)
++ return bindex;
++ return -1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * add a branch
++ */
++
++static int test_overlap(struct super_block *sb, struct dentry *h_adding,
++ struct dentry *h_root)
++{
++ if (unlikely(h_adding == h_root
++ || au_test_loopback_overlap(sb, h_adding)))
++ return 1;
++ if (h_adding->d_sb != h_root->d_sb)
++ return 0;
++ return au_test_subdir(h_adding, h_root)
++ || au_test_subdir(h_root, h_adding);
++}
++
++/*
++ * returns a newly allocated branch. @new_nbranch is a number of branches
++ * after adding a branch.
++ */
++static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
++ int perm)
++{
++ struct au_branch *add_branch;
++ struct dentry *root;
++ int err;
++
++ err = -ENOMEM;
++ root = sb->s_root;
++ add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS);
++ if (unlikely(!add_branch))
++ goto out;
++
++ err = au_hnotify_init_br(add_branch, perm);
++ if (unlikely(err))
++ goto out_br;
++
++ add_branch->br_wbr = NULL;
++ if (au_br_writable(perm)) {
++ /* may be freed separately at changing the branch permission */
++ add_branch->br_wbr = kmalloc(sizeof(*add_branch->br_wbr),
++ GFP_NOFS);
++ if (unlikely(!add_branch->br_wbr))
++ goto out_hnotify;
++ }
++
++ err = au_sbr_realloc(au_sbi(sb), new_nbranch);
++ if (!err)
++ err = au_di_realloc(au_di(root), new_nbranch);
++ if (!err)
++ err = au_ii_realloc(au_ii(root->d_inode), new_nbranch);
++ if (!err)
++ return add_branch; /* success */
++
++ kfree(add_branch->br_wbr);
++
++out_hnotify:
++ au_hnotify_fin_br(add_branch);
++out_br:
++ kfree(add_branch);
++out:
++ return ERR_PTR(err);
++}
++
++/*
++ * test if the branch permission is legal or not.
++ */
++static int test_br(struct inode *inode, int brperm, char *path)
++{
++ int err;
++
++ err = (au_br_writable(brperm) && IS_RDONLY(inode));
++ if (!err)
++ goto out;
++
++ err = -EINVAL;
++ pr_err("write permission for readonly mount or inode, %s\n", path);
++
++out:
++ return err;
++}
++
++/*
++ * returns:
++ * 0: success, the caller will add it
++ * plus: success, it is already unified, the caller should ignore it
++ * minus: error
++ */
++static int test_add(struct super_block *sb, struct au_opt_add *add, int remount)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct dentry *root;
++ struct inode *inode, *h_inode;
++
++ root = sb->s_root;
++ bend = au_sbend(sb);
++ if (unlikely(bend >= 0
++ && au_find_dbindex(root, add->path.dentry) >= 0)) {
++ err = 1;
++ if (!remount) {
++ err = -EINVAL;
++ pr_err("%s duplicated\n", add->pathname);
++ }
++ goto out;
++ }
++
++ err = -ENOSPC; /* -E2BIG; */
++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex
++ || AUFS_BRANCH_MAX - 1 <= bend)) {
++ pr_err("number of branches exceeded %s\n", add->pathname);
++ goto out;
++ }
++
++ err = -EDOM;
++ if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) {
++ pr_err("bad index %d\n", add->bindex);
++ goto out;
++ }
++
++ inode = add->path.dentry->d_inode;
++ err = -ENOENT;
++ if (unlikely(!inode->i_nlink)) {
++ pr_err("no existence %s\n", add->pathname);
++ goto out;
++ }
++
++ err = -EINVAL;
++ if (unlikely(inode->i_sb == sb)) {
++ pr_err("%s must be outside\n", add->pathname);
++ goto out;
++ }
++
++ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) {
++ pr_err("unsupported filesystem, %s (%s)\n",
++ add->pathname, au_sbtype(inode->i_sb));
++ goto out;
++ }
++
++ err = test_br(add->path.dentry->d_inode, add->perm, add->pathname);
++ if (unlikely(err))
++ goto out;
++
++ if (bend < 0)
++ return 0; /* success */
++
++ err = -EINVAL;
++ for (bindex = 0; bindex <= bend; bindex++)
++ if (unlikely(test_overlap(sb, add->path.dentry,
++ au_h_dptr(root, bindex)))) {
++ pr_err("%s is overlapped\n", add->pathname);
++ goto out;
++ }
++
++ err = 0;
++ if (au_opt_test(au_mntflags(sb), WARN_PERM)) {
++ h_inode = au_h_dptr(root, 0)->d_inode;
++ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO)
++ || h_inode->i_uid != inode->i_uid
++ || h_inode->i_gid != inode->i_gid)
++ pr_warning("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n",
++ add->pathname,
++ inode->i_uid, inode->i_gid,
++ (inode->i_mode & S_IALLUGO),
++ h_inode->i_uid, h_inode->i_gid,
++ (h_inode->i_mode & S_IALLUGO));
++ }
++
++out:
++ return err;
++}
++
++/*
++ * initialize or clean the whiteouts for an adding branch
++ */
++static int au_br_init_wh(struct super_block *sb, struct au_branch *br,
++ int new_perm, struct dentry *h_root)
++{
++ int err, old_perm;
++ aufs_bindex_t bindex;
++ struct mutex *h_mtx;
++ struct au_wbr *wbr;
++ struct au_hinode *hdir;
++
++ wbr = br->br_wbr;
++ old_perm = br->br_perm;
++ br->br_perm = new_perm;
++ hdir = NULL;
++ h_mtx = NULL;
++ bindex = au_br_index(sb, br->br_id);
++ if (0 <= bindex) {
++ hdir = au_hi(sb->s_root->d_inode, bindex);
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ } else {
++ h_mtx = &h_root->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_PARENT);
++ }
++ if (!wbr)
++ err = au_wh_init(h_root, br, sb);
++ else {
++ wbr_wh_write_lock(wbr);
++ err = au_wh_init(h_root, br, sb);
++ wbr_wh_write_unlock(wbr);
++ }
++ if (hdir)
++ au_hn_imtx_unlock(hdir);
++ else
++ mutex_unlock(h_mtx);
++ br->br_perm = old_perm;
++
++ if (!err && wbr && !au_br_writable(new_perm)) {
++ kfree(wbr);
++ br->br_wbr = NULL;
++ }
++
++ return err;
++}
++
++static int au_wbr_init(struct au_branch *br, struct super_block *sb,
++ int perm, struct path *path)
++{
++ int err;
++ struct kstatfs kst;
++ struct au_wbr *wbr;
++ struct dentry *h_dentry;
++
++ wbr = br->br_wbr;
++ au_rw_init(&wbr->wbr_wh_rwsem);
++ memset(wbr->wbr_wh, 0, sizeof(wbr->wbr_wh));
++ atomic_set(&wbr->wbr_wh_running, 0);
++ wbr->wbr_bytes = 0;
++
++ /*
++ * a limit for rmdir/rename a dir
++ * cf. AUFS_MAX_NAMELEN in include/linux/aufs_type.h
++ */
++ err = vfs_statfs(path, &kst);
++ if (unlikely(err))
++ goto out;
++ err = -EINVAL;
++ h_dentry = path->dentry;
++ if (kst.f_namelen >= NAME_MAX)
++ err = au_br_init_wh(sb, br, perm, h_dentry);
++ else
++ pr_err("%.*s(%s), unsupported namelen %ld\n",
++ AuDLNPair(h_dentry), au_sbtype(h_dentry->d_sb),
++ kst.f_namelen);
++
++out:
++ return err;
++}
++
++/* intialize a new branch */
++static int au_br_init(struct au_branch *br, struct super_block *sb,
++ struct au_opt_add *add)
++{
++ int err;
++
++ err = 0;
++ memset(&br->br_xino, 0, sizeof(br->br_xino));
++ mutex_init(&br->br_xino.xi_nondir_mtx);
++ br->br_perm = add->perm;
++ br->br_mnt = add->path.mnt; /* set first, mntget() later */
++ spin_lock_init(&br->br_dykey_lock);
++ memset(br->br_dykey, 0, sizeof(br->br_dykey));
++ atomic_set(&br->br_count, 0);
++ br->br_xino_upper = AUFS_XINO_TRUNC_INIT;
++ atomic_set(&br->br_xino_running, 0);
++ br->br_id = au_new_br_id(sb);
++ AuDebugOn(br->br_id < 0);
++
++ if (au_br_writable(add->perm)) {
++ err = au_wbr_init(br, sb, add->perm, &add->path);
++ if (unlikely(err))
++ goto out_err;
++ }
++
++ if (au_opt_test(au_mntflags(sb), XINO)) {
++ err = au_xino_br(sb, br, add->path.dentry->d_inode->i_ino,
++ au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1);
++ if (unlikely(err)) {
++ AuDebugOn(br->br_xino.xi_file);
++ goto out_err;
++ }
++ }
++
++ sysaufs_br_init(br);
++ mntget(add->path.mnt);
++ goto out; /* success */
++
++out_err:
++ br->br_mnt = NULL;
++out:
++ return err;
++}
++
++static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex,
++ struct au_branch *br, aufs_bindex_t bend,
++ aufs_bindex_t amount)
++{
++ struct au_branch **brp;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ brp = sbinfo->si_branch + bindex;
++ memmove(brp + 1, brp, sizeof(*brp) * amount);
++ *brp = br;
++ sbinfo->si_bend++;
++ if (unlikely(bend < 0))
++ sbinfo->si_bend = 0;
++}
++
++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex,
++ aufs_bindex_t bend, aufs_bindex_t amount)
++{
++ struct au_hdentry *hdp;
++
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ hdp = dinfo->di_hdentry + bindex;
++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount);
++ au_h_dentry_init(hdp);
++ dinfo->di_bend++;
++ if (unlikely(bend < 0))
++ dinfo->di_bstart = 0;
++}
++
++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex,
++ aufs_bindex_t bend, aufs_bindex_t amount)
++{
++ struct au_hinode *hip;
++
++ AuRwMustWriteLock(&iinfo->ii_rwsem);
++
++ hip = iinfo->ii_hinode + bindex;
++ memmove(hip + 1, hip, sizeof(*hip) * amount);
++ hip->hi_inode = NULL;
++ au_hn_init(hip);
++ iinfo->ii_bend++;
++ if (unlikely(bend < 0))
++ iinfo->ii_bstart = 0;
++}
++
++static void au_br_do_add(struct super_block *sb, struct dentry *h_dentry,
++ struct au_branch *br, aufs_bindex_t bindex)
++{
++ struct dentry *root;
++ struct inode *root_inode;
++ aufs_bindex_t bend, amount;
++
++ root = sb->s_root;
++ root_inode = root->d_inode;
++ bend = au_sbend(sb);
++ amount = bend + 1 - bindex;
++ au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount);
++ au_br_do_add_hdp(au_di(root), bindex, bend, amount);
++ au_br_do_add_hip(au_ii(root_inode), bindex, bend, amount);
++ au_set_h_dptr(root, bindex, dget(h_dentry));
++ au_set_h_iptr(root_inode, bindex, au_igrab(h_dentry->d_inode),
++ /*flags*/0);
++}
++
++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount)
++{
++ int err;
++ aufs_bindex_t bend, add_bindex;
++ struct dentry *root, *h_dentry;
++ struct inode *root_inode;
++ struct au_branch *add_branch;
++
++ root = sb->s_root;
++ root_inode = root->d_inode;
++ IMustLock(root_inode);
++ err = test_add(sb, add, remount);
++ if (unlikely(err < 0))
++ goto out;
++ if (err) {
++ err = 0;
++ goto out; /* success */
++ }
++
++ bend = au_sbend(sb);
++ add_branch = au_br_alloc(sb, bend + 2, add->perm);
++ err = PTR_ERR(add_branch);
++ if (IS_ERR(add_branch))
++ goto out;
++
++ err = au_br_init(add_branch, sb, add);
++ if (unlikely(err)) {
++ au_br_do_free(add_branch);
++ goto out;
++ }
++
++ add_bindex = add->bindex;
++ h_dentry = add->path.dentry;
++ if (!remount)
++ au_br_do_add(sb, h_dentry, add_branch, add_bindex);
++ else {
++ sysaufs_brs_del(sb, add_bindex);
++ au_br_do_add(sb, h_dentry, add_branch, add_bindex);
++ sysaufs_brs_add(sb, add_bindex);
++ }
++
++ if (!add_bindex) {
++ au_cpup_attr_all(root_inode, /*force*/1);
++ sb->s_maxbytes = h_dentry->d_sb->s_maxbytes;
++ } else
++ au_add_nlink(root_inode, h_dentry->d_inode);
++
++ /*
++ * this test/set prevents aufs from handling unnecesary notify events
++ * of xino files, in a case of re-adding a writable branch which was
++ * once detached from aufs.
++ */
++ if (au_xino_brid(sb) < 0
++ && au_br_writable(add_branch->br_perm)
++ && !au_test_fs_bad_xino(h_dentry->d_sb)
++ && add_branch->br_xino.xi_file
++ && add_branch->br_xino.xi_file->f_dentry->d_parent == h_dentry)
++ au_xino_brid_set(sb, add_branch->br_id);
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * delete a branch
++ */
++
++/* to show the line number, do not make it inlined function */
++#define AuVerbose(do_info, fmt, ...) do { \
++ if (do_info) \
++ pr_info(fmt, ##__VA_ARGS__); \
++} while (0)
++
++/*
++ * test if the branch is deletable or not.
++ */
++static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
++ unsigned int sigen, const unsigned int verbose)
++{
++ int err, i, j, ndentry;
++ aufs_bindex_t bstart, bend;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry *d;
++ struct inode *inode;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_dcsub_pages(&dpages, root, NULL, NULL);
++ if (unlikely(err))
++ goto out_dpages;
++
++ for (i = 0; !err && i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ ndentry = dpage->ndentry;
++ for (j = 0; !err && j < ndentry; j++) {
++ d = dpage->dentries[j];
++ AuDebugOn(!atomic_read(&d->d_count));
++ if (!au_digen_test(d, sigen)) {
++ di_read_lock_child(d, AuLock_IR);
++ if (unlikely(au_dbrange_test(d))) {
++ di_read_unlock(d, AuLock_IR);
++ continue;
++ }
++ } else {
++ di_write_lock_child(d);
++ if (unlikely(au_dbrange_test(d))) {
++ di_write_unlock(d);
++ continue;
++ }
++ err = au_reval_dpath(d, sigen);
++ if (!err)
++ di_downgrade_lock(d, AuLock_IR);
++ else {
++ di_write_unlock(d);
++ break;
++ }
++ }
++
++ /* AuDbgDentry(d); */
++ inode = d->d_inode;
++ bstart = au_dbstart(d);
++ bend = au_dbend(d);
++ if (bstart <= bindex
++ && bindex <= bend
++ && au_h_dptr(d, bindex)
++ && ((inode && !S_ISDIR(inode->i_mode))
++ || bstart == bend)) {
++ err = -EBUSY;
++ AuVerbose(verbose, "busy %.*s\n", AuDLNPair(d));
++ AuDbgDentry(d);
++ }
++ di_read_unlock(d, AuLock_IR);
++ }
++ }
++
++out_dpages:
++ au_dpages_free(&dpages);
++out:
++ return err;
++}
++
++static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex,
++ unsigned int sigen, const unsigned int verbose)
++{
++ int err;
++ unsigned long long max, ull;
++ struct inode *i, **array;
++ aufs_bindex_t bstart, bend;
++
++ array = au_iarray_alloc(sb, &max);
++ err = PTR_ERR(array);
++ if (IS_ERR(array))
++ goto out;
++
++ err = 0;
++ AuDbg("b%d\n", bindex);
++ for (ull = 0; !err && ull < max; ull++) {
++ i = array[ull];
++ if (i->i_ino == AUFS_ROOT_INO)
++ continue;
++
++ /* AuDbgInode(i); */
++ if (au_iigen(i) == sigen)
++ ii_read_lock_child(i);
++ else {
++ ii_write_lock_child(i);
++ err = au_refresh_hinode_self(i);
++ au_iigen_dec(i);
++ if (!err)
++ ii_downgrade_lock(i);
++ else {
++ ii_write_unlock(i);
++ break;
++ }
++ }
++
++ bstart = au_ibstart(i);
++ bend = au_ibend(i);
++ if (bstart <= bindex
++ && bindex <= bend
++ && au_h_iptr(i, bindex)
++ && (!S_ISDIR(i->i_mode) || bstart == bend)) {
++ err = -EBUSY;
++ AuVerbose(verbose, "busy i%lu\n", i->i_ino);
++ AuDbgInode(i);
++ }
++ ii_read_unlock(i);
++ }
++ au_iarray_free(array, max);
++
++out:
++ return err;
++}
++
++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex,
++ const unsigned int verbose)
++{
++ int err;
++ unsigned int sigen;
++
++ sigen = au_sigen(root->d_sb);
++ DiMustNoWaiters(root);
++ IiMustNoWaiters(root->d_inode);
++ di_write_unlock(root);
++ err = test_dentry_busy(root, bindex, sigen, verbose);
++ if (!err)
++ err = test_inode_busy(root->d_sb, bindex, sigen, verbose);
++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */
++
++ return err;
++}
++
++static void au_br_do_del_brp(struct au_sbinfo *sbinfo,
++ const aufs_bindex_t bindex,
++ const aufs_bindex_t bend)
++{
++ struct au_branch **brp, **p;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ brp = sbinfo->si_branch + bindex;
++ if (bindex < bend)
++ memmove(brp, brp + 1, sizeof(*brp) * (bend - bindex));
++ sbinfo->si_branch[0 + bend] = NULL;
++ sbinfo->si_bend--;
++
++ p = krealloc(sbinfo->si_branch, sizeof(*p) * bend, GFP_NOFS);
++ if (p)
++ sbinfo->si_branch = p;
++ /* harmless error */
++}
++
++static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex,
++ const aufs_bindex_t bend)
++{
++ struct au_hdentry *hdp, *p;
++
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ hdp = dinfo->di_hdentry;
++ if (bindex < bend)
++ memmove(hdp + bindex, hdp + bindex + 1,
++ sizeof(*hdp) * (bend - bindex));
++ hdp[0 + bend].hd_dentry = NULL;
++ dinfo->di_bend--;
++
++ p = krealloc(hdp, sizeof(*p) * bend, GFP_NOFS);
++ if (p)
++ dinfo->di_hdentry = p;
++ /* harmless error */
++}
++
++static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex,
++ const aufs_bindex_t bend)
++{
++ struct au_hinode *hip, *p;
++
++ AuRwMustWriteLock(&iinfo->ii_rwsem);
++
++ hip = iinfo->ii_hinode + bindex;
++ if (bindex < bend)
++ memmove(hip, hip + 1, sizeof(*hip) * (bend - bindex));
++ iinfo->ii_hinode[0 + bend].hi_inode = NULL;
++ au_hn_init(iinfo->ii_hinode + bend);
++ iinfo->ii_bend--;
++
++ p = krealloc(iinfo->ii_hinode, sizeof(*p) * bend, GFP_NOFS);
++ if (p)
++ iinfo->ii_hinode = p;
++ /* harmless error */
++}
++
++static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex,
++ struct au_branch *br)
++{
++ aufs_bindex_t bend;
++ struct au_sbinfo *sbinfo;
++ struct dentry *root;
++ struct inode *inode;
++
++ SiMustWriteLock(sb);
++
++ root = sb->s_root;
++ inode = root->d_inode;
++ sbinfo = au_sbi(sb);
++ bend = sbinfo->si_bend;
++
++ dput(au_h_dptr(root, bindex));
++ au_hiput(au_hi(inode, bindex));
++ au_br_do_free(br);
++
++ au_br_do_del_brp(sbinfo, bindex, bend);
++ au_br_do_del_hdp(au_di(root), bindex, bend);
++ au_br_do_del_hip(au_ii(inode), bindex, bend);
++}
++
++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
++{
++ int err, rerr, i;
++ unsigned int mnt_flags;
++ aufs_bindex_t bindex, bend, br_id;
++ unsigned char do_wh, verbose;
++ struct au_branch *br;
++ struct au_wbr *wbr;
++
++ err = 0;
++ bindex = au_find_dbindex(sb->s_root, del->h_path.dentry);
++ if (bindex < 0) {
++ if (remount)
++ goto out; /* success */
++ err = -ENOENT;
++ pr_err("%s no such branch\n", del->pathname);
++ goto out;
++ }
++ AuDbg("bindex b%d\n", bindex);
++
++ err = -EBUSY;
++ mnt_flags = au_mntflags(sb);
++ verbose = !!au_opt_test(mnt_flags, VERBOSE);
++ bend = au_sbend(sb);
++ if (unlikely(!bend)) {
++ AuVerbose(verbose, "no more branches left\n");
++ goto out;
++ }
++ br = au_sbr(sb, bindex);
++ i = atomic_read(&br->br_count);
++ if (unlikely(i)) {
++ AuVerbose(verbose, "%d file(s) opened\n", i);
++ goto out;
++ }
++
++ wbr = br->br_wbr;
++ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph);
++ if (do_wh) {
++ /* instead of WbrWhMustWriteLock(wbr) */
++ SiMustWriteLock(sb);
++ for (i = 0; i < AuBrWh_Last; i++) {
++ dput(wbr->wbr_wh[i]);
++ wbr->wbr_wh[i] = NULL;
++ }
++ }
++
++ err = test_children_busy(sb->s_root, bindex, verbose);
++ if (unlikely(err)) {
++ if (do_wh)
++ goto out_wh;
++ goto out;
++ }
++
++ err = 0;
++ br_id = br->br_id;
++ if (!remount)
++ au_br_do_del(sb, bindex, br);
++ else {
++ sysaufs_brs_del(sb, bindex);
++ au_br_do_del(sb, bindex, br);
++ sysaufs_brs_add(sb, bindex);
++ }
++
++ if (!bindex) {
++ au_cpup_attr_all(sb->s_root->d_inode, /*force*/1);
++ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes;
++ } else
++ au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode);
++ if (au_opt_test(mnt_flags, PLINK))
++ au_plink_half_refresh(sb, br_id);
++
++ if (au_xino_brid(sb) == br_id)
++ au_xino_brid_set(sb, -1);
++ goto out; /* success */
++
++out_wh:
++ /* revert */
++ rerr = au_br_init_wh(sb, br, br->br_perm, del->h_path.dentry);
++ if (rerr)
++ pr_warning("failed re-creating base whiteout, %s. (%d)\n",
++ del->pathname, rerr);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * change a branch permission
++ */
++
++static void au_warn_ima(void)
++{
++#ifdef CONFIG_IMA
++ /* since it doesn't support mark_files_ro() */
++ AuWarn1("RW -> RO makes IMA to produce wrong message\n");
++#endif
++}
++
++static int do_need_sigen_inc(int a, int b)
++{
++ return au_br_whable(a) && !au_br_whable(b);
++}
++
++static int need_sigen_inc(int old, int new)
++{
++ return do_need_sigen_inc(old, new)
++ || do_need_sigen_inc(new, old);
++}
++
++static unsigned long long au_farray_cb(void *a,
++ unsigned long long max __maybe_unused,
++ void *arg)
++{
++ unsigned long long n;
++ struct file **p, *f;
++ struct super_block *sb = arg;
++
++ n = 0;
++ p = a;
++ lg_global_lock(files_lglock);
++ do_file_list_for_each_entry(sb, f) {
++ if (au_fi(f)
++ && !special_file(f->f_dentry->d_inode->i_mode)) {
++ get_file(f);
++ *p++ = f;
++ n++;
++ AuDebugOn(n > max);
++ }
++ } while_file_list_for_each_entry;
++ lg_global_unlock(files_lglock);
++
++ return n;
++}
++
++static struct file **au_farray_alloc(struct super_block *sb,
++ unsigned long long *max)
++{
++ *max = atomic_long_read(&au_sbi(sb)->si_nfiles);
++ return au_array_alloc(max, au_farray_cb, sb);
++}
++
++static void au_farray_free(struct file **a, unsigned long long max)
++{
++ unsigned long long ull;
++
++ for (ull = 0; ull < max; ull++)
++ if (a[ull])
++ fput(a[ull]);
++ au_array_free(a);
++}
++
++static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
++{
++ int err, do_warn;
++ unsigned long long ull, max;
++ aufs_bindex_t br_id;
++ struct file *file, *hf, **array;
++ struct inode *inode;
++ struct au_hfile *hfile;
++
++ array = au_farray_alloc(sb, &max);
++ err = PTR_ERR(array);
++ if (IS_ERR(array))
++ goto out;
++
++ do_warn = 0;
++ br_id = au_sbr_id(sb, bindex);
++ for (ull = 0; ull < max; ull++) {
++ file = array[ull];
++
++ /* AuDbg("%.*s\n", AuDLNPair(file->f_dentry)); */
++ fi_read_lock(file);
++ if (unlikely(au_test_mmapped(file))) {
++ err = -EBUSY;
++ AuDbgFile(file);
++ FiMustNoWaiters(file);
++ fi_read_unlock(file);
++ goto out_array;
++ }
++
++ inode = file->f_dentry->d_inode;
++ hfile = &au_fi(file)->fi_htop;
++ hf = hfile->hf_file;
++ if (!S_ISREG(inode->i_mode)
++ || !(file->f_mode & FMODE_WRITE)
++ || hfile->hf_br->br_id != br_id
++ || !(hf->f_mode & FMODE_WRITE))
++ array[ull] = NULL;
++ else {
++ do_warn = 1;
++ get_file(file);
++ }
++
++ FiMustNoWaiters(file);
++ fi_read_unlock(file);
++ fput(file);
++ }
++
++ err = 0;
++ if (do_warn)
++ au_warn_ima();
++
++ for (ull = 0; ull < max; ull++) {
++ file = array[ull];
++ if (!file)
++ continue;
++
++ /* todo: already flushed? */
++ /* cf. fs/super.c:mark_files_ro() */
++ /* fi_read_lock(file); */
++ hfile = &au_fi(file)->fi_htop;
++ hf = hfile->hf_file;
++ /* fi_read_unlock(file); */
++ spin_lock(&hf->f_lock);
++ hf->f_mode &= ~FMODE_WRITE;
++ spin_unlock(&hf->f_lock);
++ if (!file_check_writeable(hf)) {
++ file_release_write(hf);
++ mnt_drop_write(hf->f_vfsmnt);
++ }
++ }
++
++out_array:
++ au_farray_free(array, max);
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount,
++ int *do_refresh)
++{
++ int err, rerr;
++ aufs_bindex_t bindex;
++ struct path path;
++ struct dentry *root;
++ struct au_branch *br;
++
++ root = sb->s_root;
++ bindex = au_find_dbindex(root, mod->h_root);
++ if (bindex < 0) {
++ if (remount)
++ return 0; /* success */
++ err = -ENOENT;
++ pr_err("%s no such branch\n", mod->path);
++ goto out;
++ }
++ AuDbg("bindex b%d\n", bindex);
++
++ err = test_br(mod->h_root->d_inode, mod->perm, mod->path);
++ if (unlikely(err))
++ goto out;
++
++ br = au_sbr(sb, bindex);
++ if (br->br_perm == mod->perm)
++ return 0; /* success */
++
++ if (au_br_writable(br->br_perm)) {
++ /* remove whiteout base */
++ err = au_br_init_wh(sb, br, mod->perm, mod->h_root);
++ if (unlikely(err))
++ goto out;
++
++ if (!au_br_writable(mod->perm)) {
++ /* rw --> ro, file might be mmapped */
++ DiMustNoWaiters(root);
++ IiMustNoWaiters(root->d_inode);
++ di_write_unlock(root);
++ err = au_br_mod_files_ro(sb, bindex);
++ /* aufs_write_lock() calls ..._child() */
++ di_write_lock_child(root);
++
++ if (unlikely(err)) {
++ rerr = -ENOMEM;
++ br->br_wbr = kmalloc(sizeof(*br->br_wbr),
++ GFP_NOFS);
++ if (br->br_wbr) {
++ path.mnt = br->br_mnt;
++ path.dentry = mod->h_root;
++ rerr = au_wbr_init(br, sb, br->br_perm,
++ &path);
++ }
++ if (unlikely(rerr)) {
++ AuIOErr("nested error %d (%d)\n",
++ rerr, err);
++ br->br_perm = mod->perm;
++ }
++ }
++ }
++ } else if (au_br_writable(mod->perm)) {
++ /* ro --> rw */
++ err = -ENOMEM;
++ br->br_wbr = kmalloc(sizeof(*br->br_wbr), GFP_NOFS);
++ if (br->br_wbr) {
++ path.mnt = br->br_mnt;
++ path.dentry = mod->h_root;
++ err = au_wbr_init(br, sb, mod->perm, &path);
++ if (unlikely(err)) {
++ kfree(br->br_wbr);
++ br->br_wbr = NULL;
++ }
++ }
++ }
++
++ if (!err) {
++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm);
++ br->br_perm = mod->perm;
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/branch.h linux-2.6.37/fs/aufs/branch.h
+--- linux-2.6.37.orig/fs/aufs/branch.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/branch.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,229 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * branch filesystems and xino for them
++ */
++
++#ifndef __AUFS_BRANCH_H__
++#define __AUFS_BRANCH_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/mount.h>
++#include <linux/aufs_type.h>
++#include "dynop.h"
++#include "rwsem.h"
++#include "super.h"
++
++/* ---------------------------------------------------------------------- */
++
++/* a xino file */
++struct au_xino_file {
++ struct file *xi_file;
++ struct mutex xi_nondir_mtx;
++
++ /* todo: make xino files an array to support huge inode number */
++
++#ifdef CONFIG_DEBUG_FS
++ struct dentry *xi_dbgaufs;
++#endif
++};
++
++/* members for writable branch only */
++enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last};
++struct au_wbr {
++ struct au_rwsem wbr_wh_rwsem;
++ struct dentry *wbr_wh[AuBrWh_Last];
++ atomic_t wbr_wh_running;
++#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */
++#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */
++#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */
++
++ /* mfs mode */
++ unsigned long long wbr_bytes;
++};
++
++/* ext2 has 3 types of operations at least, ext3 has 4 */
++#define AuBrDynOp (AuDyLast * 4)
++
++/* protected by superblock rwsem */
++struct au_branch {
++ struct au_xino_file br_xino;
++
++ aufs_bindex_t br_id;
++
++ int br_perm;
++ struct vfsmount *br_mnt;
++ spinlock_t br_dykey_lock;
++ struct au_dykey *br_dykey[AuBrDynOp];
++ atomic_t br_count;
++
++ struct au_wbr *br_wbr;
++
++ /* xino truncation */
++ blkcnt_t br_xino_upper; /* watermark in blocks */
++ atomic_t br_xino_running;
++
++#ifdef CONFIG_AUFS_HFSNOTIFY
++ struct fsnotify_group *br_hfsn_group;
++ struct fsnotify_ops br_hfsn_ops;
++#endif
++
++#ifdef CONFIG_SYSFS
++ /* an entry under sysfs per mount-point */
++ char br_name[8];
++ struct attribute br_attr;
++#endif
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* branch permission and attribute */
++enum {
++ AuBrPerm_RW, /* writable, linkable wh */
++ AuBrPerm_RO, /* readonly, no wh */
++ AuBrPerm_RR, /* natively readonly, no wh */
++
++ AuBrPerm_RWNoLinkWH, /* un-linkable whiteouts */
++
++ AuBrPerm_ROWH, /* whiteout-able */
++ AuBrPerm_RRWH, /* whiteout-able */
++
++ AuBrPerm_Last
++};
++
++static inline int au_br_writable(int brperm)
++{
++ return brperm == AuBrPerm_RW || brperm == AuBrPerm_RWNoLinkWH;
++}
++
++static inline int au_br_whable(int brperm)
++{
++ return brperm == AuBrPerm_RW
++ || brperm == AuBrPerm_ROWH
++ || brperm == AuBrPerm_RRWH;
++}
++
++static inline int au_br_rdonly(struct au_branch *br)
++{
++ return ((br->br_mnt->mnt_sb->s_flags & MS_RDONLY)
++ || !au_br_writable(br->br_perm))
++ ? -EROFS : 0;
++}
++
++static inline int au_br_hnotifyable(int brperm __maybe_unused)
++{
++#ifdef CONFIG_AUFS_HNOTIFY
++ return brperm != AuBrPerm_RR && brperm != AuBrPerm_RRWH;
++#else
++ return 0;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* branch.c */
++struct au_sbinfo;
++void au_br_free(struct au_sbinfo *sinfo);
++int au_br_index(struct super_block *sb, aufs_bindex_t br_id);
++struct au_opt_add;
++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount);
++struct au_opt_del;
++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount);
++struct au_opt_mod;
++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount,
++ int *do_refresh);
++
++/* xino.c */
++static const loff_t au_loff_max = LLONG_MAX;
++
++int au_xib_trunc(struct super_block *sb);
++ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size,
++ loff_t *pos);
++ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size,
++ loff_t *pos);
++struct file *au_xino_create2(struct file *base_file, struct file *copy_src);
++struct file *au_xino_create(struct super_block *sb, char *fname, int silent);
++ino_t au_xino_new_ino(struct super_block *sb);
++void au_xino_delete_inode(struct inode *inode, const int unlinked);
++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t ino);
++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t *ino);
++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino,
++ struct file *base_file, int do_test);
++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex);
++
++struct au_opt_xino;
++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount);
++void au_xino_clr(struct super_block *sb);
++struct file *au_xino_def(struct super_block *sb);
++int au_xino_path(struct seq_file *seq, struct file *file);
++
++/* ---------------------------------------------------------------------- */
++
++/* Superblock to branch */
++static inline
++aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr(sb, bindex)->br_id;
++}
++
++static inline
++struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr(sb, bindex)->br_mnt;
++}
++
++static inline
++struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr_mnt(sb, bindex)->mnt_sb;
++}
++
++static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex)
++{
++ atomic_dec(&au_sbr(sb, bindex)->br_count);
++}
++
++static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr(sb, bindex)->br_perm;
++}
++
++static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_br_whable(au_sbr_perm(sb, bindex));
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * wbr_wh_read_lock, wbr_wh_write_lock
++ * wbr_wh_read_unlock, wbr_wh_write_unlock, wbr_wh_downgrade_lock
++ */
++AuSimpleRwsemFuncs(wbr_wh, struct au_wbr *wbr, &wbr->wbr_wh_rwsem);
++
++#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&wbr->wbr_wh_rwsem)
++#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&wbr->wbr_wh_rwsem)
++#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&wbr->wbr_wh_rwsem)
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_BRANCH_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/conf.mk linux-2.6.37/fs/aufs/conf.mk
+--- linux-2.6.37.orig/fs/aufs/conf.mk 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/conf.mk 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,37 @@
++
++AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS}
++
++define AuConf
++ifdef ${1}
++AuConfStr += ${1}=${${1}}
++endif
++endef
++
++AuConfAll = BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \
++ SBILIST \
++ HNOTIFY HFSNOTIFY \
++ EXPORT INO_T_64 \
++ RDU \
++ SP_IATTR \
++ SHWH \
++ BR_RAMFS \
++ BR_FUSE POLL \
++ BR_HFSPLUS \
++ BDEV_LOOP \
++ DEBUG MAGIC_SYSRQ
++$(foreach i, ${AuConfAll}, \
++ $(eval $(call AuConf,CONFIG_AUFS_${i})))
++
++AuConfName = ${obj}/conf.str
++${AuConfName}.tmp: FORCE
++ @echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@
++${AuConfName}: ${AuConfName}.tmp
++ @diff -q $< $@ > /dev/null 2>&1 || { \
++ echo ' GEN ' $@; \
++ cp -p $< $@; \
++ }
++FORCE:
++clean-files += ${AuConfName} ${AuConfName}.tmp
++${obj}/sysfs.o: ${AuConfName}
++
++-include ${srctree}/${src}/conf_priv.mk
+diff -Nur linux-2.6.37.orig/fs/aufs/cpup.c linux-2.6.37/fs/aufs/cpup.c
+--- linux-2.6.37.orig/fs/aufs/cpup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/cpup.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,1063 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * copy-up functions, see wbr_policy.c for copy-down
++ */
++
++#include <linux/file.h>
++#include <linux/fs_stack.h>
++#include <linux/mm.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++void au_cpup_attr_flags(struct inode *dst, struct inode *src)
++{
++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE
++ | S_NOATIME | S_NOCMTIME;
++
++ dst->i_flags |= src->i_flags & ~mask;
++ if (au_test_fs_notime(dst->i_sb))
++ dst->i_flags |= S_NOATIME | S_NOCMTIME;
++}
++
++void au_cpup_attr_timesizes(struct inode *inode)
++{
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ fsstack_copy_attr_times(inode, h_inode);
++ fsstack_copy_inode_size(inode, h_inode);
++}
++
++void au_cpup_attr_nlink(struct inode *inode, int force)
++{
++ struct inode *h_inode;
++ struct super_block *sb;
++ aufs_bindex_t bindex, bend;
++
++ sb = inode->i_sb;
++ bindex = au_ibstart(inode);
++ h_inode = au_h_iptr(inode, bindex);
++ if (!force
++ && !S_ISDIR(h_inode->i_mode)
++ && au_opt_test(au_mntflags(sb), PLINK)
++ && au_plink_test(inode))
++ return;
++
++ inode->i_nlink = h_inode->i_nlink;
++
++ /*
++ * fewer nlink makes find(1) noisy, but larger nlink doesn't.
++ * it may includes whplink directory.
++ */
++ if (S_ISDIR(h_inode->i_mode)) {
++ bend = au_ibend(inode);
++ for (bindex++; bindex <= bend; bindex++) {
++ h_inode = au_h_iptr(inode, bindex);
++ if (h_inode)
++ au_add_nlink(inode, h_inode);
++ }
++ }
++}
++
++void au_cpup_attr_changeable(struct inode *inode)
++{
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ inode->i_mode = h_inode->i_mode;
++ inode->i_uid = h_inode->i_uid;
++ inode->i_gid = h_inode->i_gid;
++ au_cpup_attr_timesizes(inode);
++ au_cpup_attr_flags(inode, h_inode);
++}
++
++void au_cpup_igen(struct inode *inode, struct inode *h_inode)
++{
++ struct au_iinfo *iinfo = au_ii(inode);
++
++ IiMustWriteLock(inode);
++
++ iinfo->ii_higen = h_inode->i_generation;
++ iinfo->ii_hsb1 = h_inode->i_sb;
++}
++
++void au_cpup_attr_all(struct inode *inode, int force)
++{
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ au_cpup_attr_changeable(inode);
++ if (inode->i_nlink > 0)
++ au_cpup_attr_nlink(inode, force);
++ inode->i_rdev = h_inode->i_rdev;
++ inode->i_blkbits = h_inode->i_blkbits;
++ au_cpup_igen(inode, h_inode);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */
++
++/* keep the timestamps of the parent dir when cpup */
++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry,
++ struct path *h_path)
++{
++ struct inode *h_inode;
++
++ dt->dt_dentry = dentry;
++ dt->dt_h_path = *h_path;
++ h_inode = h_path->dentry->d_inode;
++ dt->dt_atime = h_inode->i_atime;
++ dt->dt_mtime = h_inode->i_mtime;
++ /* smp_mb(); */
++}
++
++void au_dtime_revert(struct au_dtime *dt)
++{
++ struct iattr attr;
++ int err;
++
++ attr.ia_atime = dt->dt_atime;
++ attr.ia_mtime = dt->dt_mtime;
++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET
++ | ATTR_ATIME | ATTR_ATIME_SET;
++
++ err = vfsub_notify_change(&dt->dt_h_path, &attr);
++ if (unlikely(err))
++ pr_warning("restoring timestamps failed(%d). ignored\n", err);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static noinline_for_stack
++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src)
++{
++ int err, sbits;
++ struct iattr ia;
++ struct path h_path;
++ struct inode *h_isrc, *h_idst;
++
++ h_path.dentry = au_h_dptr(dst, bindex);
++ h_idst = h_path.dentry->d_inode;
++ h_path.mnt = au_sbr_mnt(dst->d_sb, bindex);
++ h_isrc = h_src->d_inode;
++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID
++ | ATTR_ATIME | ATTR_MTIME
++ | ATTR_ATIME_SET | ATTR_MTIME_SET;
++ ia.ia_uid = h_isrc->i_uid;
++ ia.ia_gid = h_isrc->i_gid;
++ ia.ia_atime = h_isrc->i_atime;
++ ia.ia_mtime = h_isrc->i_mtime;
++ if (h_idst->i_mode != h_isrc->i_mode
++ && !S_ISLNK(h_idst->i_mode)) {
++ ia.ia_valid |= ATTR_MODE;
++ ia.ia_mode = h_isrc->i_mode;
++ }
++ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID));
++ au_cpup_attr_flags(h_idst, h_isrc);
++ err = vfsub_notify_change(&h_path, &ia);
++
++ /* is this nfs only? */
++ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) {
++ ia.ia_valid = ATTR_FORCE | ATTR_MODE;
++ ia.ia_mode = h_isrc->i_mode;
++ err = vfsub_notify_change(&h_path, &ia);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_copy_file(struct file *dst, struct file *src, loff_t len,
++ char *buf, unsigned long blksize)
++{
++ int err;
++ size_t sz, rbytes, wbytes;
++ unsigned char all_zero;
++ char *p, *zp;
++ struct mutex *h_mtx;
++ /* reduce stack usage */
++ struct iattr *ia;
++
++ zp = page_address(ZERO_PAGE(0));
++ if (unlikely(!zp))
++ return -ENOMEM; /* possible? */
++
++ err = 0;
++ all_zero = 0;
++ while (len) {
++ AuDbg("len %lld\n", len);
++ sz = blksize;
++ if (len < blksize)
++ sz = len;
++
++ rbytes = 0;
++ /* todo: signal_pending? */
++ while (!rbytes || err == -EAGAIN || err == -EINTR) {
++ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos);
++ err = rbytes;
++ }
++ if (unlikely(err < 0))
++ break;
++
++ all_zero = 0;
++ if (len >= rbytes && rbytes == blksize)
++ all_zero = !memcmp(buf, zp, rbytes);
++ if (!all_zero) {
++ wbytes = rbytes;
++ p = buf;
++ while (wbytes) {
++ size_t b;
++
++ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos);
++ err = b;
++ /* todo: signal_pending? */
++ if (unlikely(err == -EAGAIN || err == -EINTR))
++ continue;
++ if (unlikely(err < 0))
++ break;
++ wbytes -= b;
++ p += b;
++ }
++ } else {
++ loff_t res;
++
++ AuLabel(hole);
++ res = vfsub_llseek(dst, rbytes, SEEK_CUR);
++ err = res;
++ if (unlikely(res < 0))
++ break;
++ }
++ len -= rbytes;
++ err = 0;
++ }
++
++ /* the last block may be a hole */
++ if (!err && all_zero) {
++ AuLabel(last hole);
++
++ err = 1;
++ if (au_test_nfs(dst->f_dentry->d_sb)) {
++ /* nfs requires this step to make last hole */
++ /* is this only nfs? */
++ do {
++ /* todo: signal_pending? */
++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos);
++ } while (err == -EAGAIN || err == -EINTR);
++ if (err == 1)
++ dst->f_pos--;
++ }
++
++ if (err == 1) {
++ ia = (void *)buf;
++ ia->ia_size = dst->f_pos;
++ ia->ia_valid = ATTR_SIZE | ATTR_FILE;
++ ia->ia_file = dst;
++ h_mtx = &dst->f_dentry->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD2);
++ err = vfsub_notify_change(&dst->f_path, ia);
++ mutex_unlock(h_mtx);
++ }
++ }
++
++ return err;
++}
++
++int au_copy_file(struct file *dst, struct file *src, loff_t len)
++{
++ int err;
++ unsigned long blksize;
++ unsigned char do_kfree;
++ char *buf;
++
++ err = -ENOMEM;
++ blksize = dst->f_dentry->d_sb->s_blocksize;
++ if (!blksize || PAGE_SIZE < blksize)
++ blksize = PAGE_SIZE;
++ AuDbg("blksize %lu\n", blksize);
++ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *));
++ if (do_kfree)
++ buf = kmalloc(blksize, GFP_NOFS);
++ else
++ buf = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!buf))
++ goto out;
++
++ if (len > (1 << 22))
++ AuDbg("copying a large file %lld\n", (long long)len);
++
++ src->f_pos = 0;
++ dst->f_pos = 0;
++ err = au_do_copy_file(dst, src, len, buf, blksize);
++ if (do_kfree)
++ kfree(buf);
++ else
++ free_page((unsigned long)buf);
++
++out:
++ return err;
++}
++
++/*
++ * to support a sparse file which is opened with O_APPEND,
++ * we need to close the file.
++ */
++static int au_cp_regular(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len)
++{
++ int err, i;
++ enum { SRC, DST };
++ struct {
++ aufs_bindex_t bindex;
++ unsigned int flags;
++ struct dentry *dentry;
++ struct file *file;
++ void *label, *label_file;
++ } *f, file[] = {
++ {
++ .bindex = bsrc,
++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE,
++ .file = NULL,
++ .label = &&out,
++ .label_file = &&out_src
++ },
++ {
++ .bindex = bdst,
++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE,
++ .file = NULL,
++ .label = &&out_src,
++ .label_file = &&out_dst
++ }
++ };
++ struct super_block *sb;
++
++ /* bsrc branch can be ro/rw. */
++ sb = dentry->d_sb;
++ f = file;
++ for (i = 0; i < 2; i++, f++) {
++ f->dentry = au_h_dptr(dentry, f->bindex);
++ f->file = au_h_open(dentry, f->bindex, f->flags, /*file*/NULL);
++ err = PTR_ERR(f->file);
++ if (IS_ERR(f->file))
++ goto *f->label;
++ err = -EINVAL;
++ if (unlikely(!f->file->f_op))
++ goto *f->label_file;
++ }
++
++ /* try stopping to update while we copyup */
++ IMustLock(file[SRC].dentry->d_inode);
++ err = au_copy_file(file[DST].file, file[SRC].file, len);
++
++out_dst:
++ fput(file[DST].file);
++ au_sbr_put(sb, file[DST].bindex);
++out_src:
++ fput(file[SRC].file);
++ au_sbr_put(sb, file[SRC].bindex);
++out:
++ return err;
++}
++
++static int au_do_cpup_regular(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len,
++ struct inode *h_dir, struct path *h_path)
++{
++ int err, rerr;
++ loff_t l;
++
++ err = 0;
++ l = i_size_read(au_h_iptr(dentry->d_inode, bsrc));
++ if (len == -1 || l < len)
++ len = l;
++ if (len)
++ err = au_cp_regular(dentry, bdst, bsrc, len);
++ if (!err)
++ goto out; /* success */
++
++ rerr = vfsub_unlink(h_dir, h_path, /*force*/0);
++ if (rerr) {
++ AuIOErr("failed unlinking cpup-ed %.*s(%d, %d)\n",
++ AuDLNPair(h_path->dentry), err, rerr);
++ err = -EIO;
++ }
++
++out:
++ return err;
++}
++
++static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src,
++ struct inode *h_dir)
++{
++ int err, symlen;
++ mm_segment_t old_fs;
++ union {
++ char *k;
++ char __user *u;
++ } sym;
++
++ err = -ENOSYS;
++ if (unlikely(!h_src->d_inode->i_op->readlink))
++ goto out;
++
++ err = -ENOMEM;
++ sym.k = __getname_gfp(GFP_NOFS);
++ if (unlikely(!sym.k))
++ goto out;
++
++ old_fs = get_fs();
++ set_fs(KERNEL_DS);
++ symlen = h_src->d_inode->i_op->readlink(h_src, sym.u, PATH_MAX);
++ err = symlen;
++ set_fs(old_fs);
++
++ if (symlen > 0) {
++ sym.k[symlen] = 0;
++ err = vfsub_symlink(h_dir, h_path, sym.k);
++ }
++ __putname(sym.k);
++
++out:
++ return err;
++}
++
++/* return with the lower dst inode is locked */
++static noinline_for_stack
++int cpup_entry(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent)
++{
++ int err;
++ umode_t mode;
++ unsigned int mnt_flags;
++ unsigned char isdir;
++ const unsigned char do_dt = !!au_ftest_cpup(flags, DTIME);
++ struct au_dtime dt;
++ struct path h_path;
++ struct dentry *h_src, *h_dst, *h_parent;
++ struct inode *h_inode, *h_dir;
++ struct super_block *sb;
++
++ /* bsrc branch can be ro/rw. */
++ h_src = au_h_dptr(dentry, bsrc);
++ h_inode = h_src->d_inode;
++ AuDebugOn(h_inode != au_h_iptr(dentry->d_inode, bsrc));
++
++ /* try stopping to be referenced while we are creating */
++ h_dst = au_h_dptr(dentry, bdst);
++ h_parent = h_dst->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++ AuDebugOn(h_parent != h_dst->d_parent);
++
++ sb = dentry->d_sb;
++ h_path.mnt = au_sbr_mnt(sb, bdst);
++ if (do_dt) {
++ h_path.dentry = h_parent;
++ au_dtime_store(&dt, dst_parent, &h_path);
++ }
++ h_path.dentry = h_dst;
++
++ isdir = 0;
++ mode = h_inode->i_mode;
++ switch (mode & S_IFMT) {
++ case S_IFREG:
++ /* try stopping to update while we are referencing */
++ IMustLock(h_inode);
++ err = vfsub_create(h_dir, &h_path, mode | S_IWUSR);
++ if (!err)
++ err = au_do_cpup_regular
++ (dentry, bdst, bsrc, len,
++ au_h_iptr(dst_parent->d_inode, bdst), &h_path);
++ break;
++ case S_IFDIR:
++ isdir = 1;
++ err = vfsub_mkdir(h_dir, &h_path, mode);
++ if (!err) {
++ /*
++ * strange behaviour from the users view,
++ * particularry setattr case
++ */
++ if (au_ibstart(dst_parent->d_inode) == bdst)
++ au_cpup_attr_nlink(dst_parent->d_inode,
++ /*force*/1);
++ au_cpup_attr_nlink(dentry->d_inode, /*force*/1);
++ }
++ break;
++ case S_IFLNK:
++ err = au_do_cpup_symlink(&h_path, h_src, h_dir);
++ break;
++ case S_IFCHR:
++ case S_IFBLK:
++ AuDebugOn(!capable(CAP_MKNOD));
++ /*FALLTHROUGH*/
++ case S_IFIFO:
++ case S_IFSOCK:
++ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev);
++ break;
++ default:
++ AuIOErr("Unknown inode type 0%o\n", mode);
++ err = -EIO;
++ }
++
++ mnt_flags = au_mntflags(sb);
++ if (!au_opt_test(mnt_flags, UDBA_NONE)
++ && !isdir
++ && au_opt_test(mnt_flags, XINO)
++ && h_inode->i_nlink == 1
++ /* todo: unnecessary? */
++ /* && dentry->d_inode->i_nlink == 1 */
++ && bdst < bsrc
++ && !au_ftest_cpup(flags, KEEPLINO))
++ au_xino_write(sb, bsrc, h_inode->i_ino, /*ino*/0);
++ /* ignore this error */
++
++ if (do_dt)
++ au_dtime_revert(&dt);
++ return err;
++}
++
++/*
++ * copyup the @dentry from @bsrc to @bdst.
++ * the caller must set the both of lower dentries.
++ * @len is for truncating when it is -1 copyup the entire file.
++ * in link/rename cases, @dst_parent may be different from the real one.
++ */
++static int au_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent)
++{
++ int err, rerr;
++ aufs_bindex_t old_ibstart;
++ unsigned char isdir, plink;
++ struct au_dtime dt;
++ struct path h_path;
++ struct dentry *h_src, *h_dst, *h_parent;
++ struct inode *dst_inode, *h_dir, *inode;
++ struct super_block *sb;
++
++ AuDebugOn(bsrc <= bdst);
++
++ sb = dentry->d_sb;
++ h_path.mnt = au_sbr_mnt(sb, bdst);
++ h_dst = au_h_dptr(dentry, bdst);
++ h_parent = h_dst->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++
++ h_src = au_h_dptr(dentry, bsrc);
++ inode = dentry->d_inode;
++
++ if (!dst_parent)
++ dst_parent = dget_parent(dentry);
++ else
++ dget(dst_parent);
++
++ plink = !!au_opt_test(au_mntflags(sb), PLINK);
++ dst_inode = au_h_iptr(inode, bdst);
++ if (dst_inode) {
++ if (unlikely(!plink)) {
++ err = -EIO;
++ AuIOErr("hi%lu(i%lu) exists on b%d "
++ "but plink is disabled\n",
++ dst_inode->i_ino, inode->i_ino, bdst);
++ goto out;
++ }
++
++ if (dst_inode->i_nlink) {
++ const int do_dt = au_ftest_cpup(flags, DTIME);
++
++ h_src = au_plink_lkup(inode, bdst);
++ err = PTR_ERR(h_src);
++ if (IS_ERR(h_src))
++ goto out;
++ if (unlikely(!h_src->d_inode)) {
++ err = -EIO;
++ AuIOErr("i%lu exists on a upper branch "
++ "but not pseudo-linked\n",
++ inode->i_ino);
++ dput(h_src);
++ goto out;
++ }
++
++ if (do_dt) {
++ h_path.dentry = h_parent;
++ au_dtime_store(&dt, dst_parent, &h_path);
++ }
++ h_path.dentry = h_dst;
++ err = vfsub_link(h_src, h_dir, &h_path);
++ if (do_dt)
++ au_dtime_revert(&dt);
++ dput(h_src);
++ goto out;
++ } else
++ /* todo: cpup_wh_file? */
++ /* udba work */
++ au_update_ibrange(inode, /*do_put_zero*/1);
++ }
++
++ old_ibstart = au_ibstart(inode);
++ err = cpup_entry(dentry, bdst, bsrc, len, flags, dst_parent);
++ if (unlikely(err))
++ goto out;
++ dst_inode = h_dst->d_inode;
++ mutex_lock_nested(&dst_inode->i_mutex, AuLsc_I_CHILD2);
++
++ err = cpup_iattr(dentry, bdst, h_src);
++ isdir = S_ISDIR(dst_inode->i_mode);
++ if (!err) {
++ if (bdst < old_ibstart) {
++ if (S_ISREG(inode->i_mode)) {
++ err = au_dy_iaop(inode, bdst, dst_inode);
++ if (unlikely(err))
++ goto out_rev;
++ }
++ au_set_ibstart(inode, bdst);
++ }
++ au_set_h_iptr(inode, bdst, au_igrab(dst_inode),
++ au_hi_flags(inode, isdir));
++ mutex_unlock(&dst_inode->i_mutex);
++ if (!isdir
++ && h_src->d_inode->i_nlink > 1
++ && plink)
++ au_plink_append(inode, bdst, h_dst);
++ goto out; /* success */
++ }
++
++ /* revert */
++out_rev:
++ h_path.dentry = h_parent;
++ mutex_unlock(&dst_inode->i_mutex);
++ au_dtime_store(&dt, dst_parent, &h_path);
++ h_path.dentry = h_dst;
++ if (!isdir)
++ rerr = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ else
++ rerr = vfsub_rmdir(h_dir, &h_path);
++ au_dtime_revert(&dt);
++ if (rerr) {
++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr);
++ err = -EIO;
++ }
++
++out:
++ dput(dst_parent);
++ return err;
++}
++
++struct au_cpup_single_args {
++ int *errp;
++ struct dentry *dentry;
++ aufs_bindex_t bdst, bsrc;
++ loff_t len;
++ unsigned int flags;
++ struct dentry *dst_parent;
++};
++
++static void au_call_cpup_single(void *args)
++{
++ struct au_cpup_single_args *a = args;
++ *a->errp = au_cpup_single(a->dentry, a->bdst, a->bsrc, a->len,
++ a->flags, a->dst_parent);
++}
++
++int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent)
++{
++ int err, wkq_err;
++ umode_t mode;
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bsrc);
++ mode = h_dentry->d_inode->i_mode & S_IFMT;
++ if ((mode != S_IFCHR && mode != S_IFBLK)
++ || capable(CAP_MKNOD))
++ err = au_cpup_single(dentry, bdst, bsrc, len, flags,
++ dst_parent);
++ else {
++ struct au_cpup_single_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .bdst = bdst,
++ .bsrc = bsrc,
++ .len = len,
++ .flags = flags,
++ .dst_parent = dst_parent
++ };
++ wkq_err = au_wkq_wait(au_call_cpup_single, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
++
++/*
++ * copyup the @dentry from the first active lower branch to @bdst,
++ * using au_cpup_single().
++ */
++static int au_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ unsigned int flags)
++{
++ int err;
++ aufs_bindex_t bsrc, bend;
++
++ bend = au_dbend(dentry);
++ for (bsrc = bdst + 1; bsrc <= bend; bsrc++)
++ if (au_h_dptr(dentry, bsrc))
++ break;
++
++ err = au_lkup_neg(dentry, bdst);
++ if (!err) {
++ err = au_cpup_single(dentry, bdst, bsrc, len, flags, NULL);
++ if (!err)
++ return 0; /* success */
++
++ /* revert */
++ au_set_h_dptr(dentry, bdst, NULL);
++ au_set_dbstart(dentry, bsrc);
++ }
++
++ return err;
++}
++
++struct au_cpup_simple_args {
++ int *errp;
++ struct dentry *dentry;
++ aufs_bindex_t bdst;
++ loff_t len;
++ unsigned int flags;
++};
++
++static void au_call_cpup_simple(void *args)
++{
++ struct au_cpup_simple_args *a = args;
++ *a->errp = au_cpup_simple(a->dentry, a->bdst, a->len, a->flags);
++}
++
++int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ unsigned int flags)
++{
++ int err, wkq_err;
++ unsigned char do_sio;
++ struct dentry *parent;
++ struct inode *h_dir;
++
++ parent = dget_parent(dentry);
++ h_dir = au_h_iptr(parent->d_inode, bdst);
++ do_sio = !!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE);
++ if (!do_sio) {
++ /*
++ * testing CAP_MKNOD is for generic fs,
++ * but CAP_FSETID is for xfs only, currently.
++ */
++ umode_t mode = dentry->d_inode->i_mode;
++ do_sio = (((mode & (S_IFCHR | S_IFBLK))
++ && !capable(CAP_MKNOD))
++ || ((mode & (S_ISUID | S_ISGID))
++ && !capable(CAP_FSETID)));
++ }
++ if (!do_sio)
++ err = au_cpup_simple(dentry, bdst, len, flags);
++ else {
++ struct au_cpup_simple_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .bdst = bdst,
++ .len = len,
++ .flags = flags
++ };
++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * copyup the deleted file for writing.
++ */
++static int au_do_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *wh_dentry, struct file *file,
++ loff_t len)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct au_dinfo *dinfo;
++ struct dentry *h_d_dst, *h_d_start;
++ struct au_hdentry *hdp;
++
++ dinfo = au_di(dentry);
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ bstart = dinfo->di_bstart;
++ hdp = dinfo->di_hdentry;
++ h_d_dst = hdp[0 + bdst].hd_dentry;
++ dinfo->di_bstart = bdst;
++ hdp[0 + bdst].hd_dentry = wh_dentry;
++ if (file) {
++ h_d_start = hdp[0 + bstart].hd_dentry;
++ hdp[0 + bstart].hd_dentry = au_hf_top(file)->f_dentry;
++ }
++ err = au_cpup_single(dentry, bdst, bstart, len, !AuCpup_DTIME,
++ /*h_parent*/NULL);
++ if (file) {
++ if (!err)
++ err = au_reopen_nondir(file);
++ hdp[0 + bstart].hd_dentry = h_d_start;
++ }
++ hdp[0 + bdst].hd_dentry = h_d_dst;
++ dinfo->di_bstart = bstart;
++
++ return err;
++}
++
++static int au_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ struct file *file)
++{
++ int err;
++ struct au_dtime dt;
++ struct dentry *parent, *h_parent, *wh_dentry;
++ struct au_branch *br;
++ struct path h_path;
++
++ br = au_sbr(dentry->d_sb, bdst);
++ parent = dget_parent(dentry);
++ h_parent = au_h_dptr(parent, bdst);
++ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out;
++
++ h_path.dentry = h_parent;
++ h_path.mnt = br->br_mnt;
++ au_dtime_store(&dt, parent, &h_path);
++ err = au_do_cpup_wh(dentry, bdst, wh_dentry, file, len);
++ if (unlikely(err))
++ goto out_wh;
++
++ dget(wh_dentry);
++ h_path.dentry = wh_dentry;
++ if (!S_ISDIR(wh_dentry->d_inode->i_mode))
++ err = vfsub_unlink(h_parent->d_inode, &h_path, /*force*/0);
++ else
++ err = vfsub_rmdir(h_parent->d_inode, &h_path);
++ if (unlikely(err)) {
++ AuIOErr("failed remove copied-up tmp file %.*s(%d)\n",
++ AuDLNPair(wh_dentry), err);
++ err = -EIO;
++ }
++ au_dtime_revert(&dt);
++ au_set_hi_wh(dentry->d_inode, bdst, wh_dentry);
++
++out_wh:
++ dput(wh_dentry);
++out:
++ dput(parent);
++ return err;
++}
++
++struct au_cpup_wh_args {
++ int *errp;
++ struct dentry *dentry;
++ aufs_bindex_t bdst;
++ loff_t len;
++ struct file *file;
++};
++
++static void au_call_cpup_wh(void *args)
++{
++ struct au_cpup_wh_args *a = args;
++ *a->errp = au_cpup_wh(a->dentry, a->bdst, a->len, a->file);
++}
++
++int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ struct file *file)
++{
++ int err, wkq_err;
++ struct dentry *parent, *h_orph, *h_parent, *h_dentry;
++ struct inode *dir, *h_dir, *h_tmpdir, *h_inode;
++ struct au_wbr *wbr;
++
++ parent = dget_parent(dentry);
++ dir = parent->d_inode;
++ h_orph = NULL;
++ h_parent = NULL;
++ h_dir = au_igrab(au_h_iptr(dir, bdst));
++ h_tmpdir = h_dir;
++ if (!h_dir->i_nlink) {
++ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr;
++ h_orph = wbr->wbr_orph;
++
++ h_parent = dget(au_h_dptr(parent, bdst));
++ au_set_h_dptr(parent, bdst, dget(h_orph));
++ h_tmpdir = h_orph->d_inode;
++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0);
++
++ /* this temporary unlock is safe */
++ if (file)
++ h_dentry = au_hf_top(file)->f_dentry;
++ else
++ h_dentry = au_h_dptr(dentry, au_dbstart(dentry));
++ h_inode = h_dentry->d_inode;
++ IMustLock(h_inode);
++ mutex_unlock(&h_inode->i_mutex);
++ mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3);
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ /* todo: au_h_open_pre()? */
++ }
++
++ if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE))
++ err = au_cpup_wh(dentry, bdst, len, file);
++ else {
++ struct au_cpup_wh_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .bdst = bdst,
++ .len = len,
++ .file = file
++ };
++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ if (h_orph) {
++ mutex_unlock(&h_tmpdir->i_mutex);
++ /* todo: au_h_open_post()? */
++ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0);
++ au_set_h_dptr(parent, bdst, h_parent);
++ }
++ iput(h_dir);
++ dput(parent);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * generic routine for both of copy-up and copy-down.
++ */
++/* cf. revalidate function in file.c */
++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst,
++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent, void *arg),
++ void *arg)
++{
++ int err;
++ struct au_pin pin;
++ struct dentry *d, *parent, *h_parent, *real_parent;
++
++ err = 0;
++ parent = dget_parent(dentry);
++ if (IS_ROOT(parent))
++ goto out;
++
++ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2,
++ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE);
++
++ /* do not use au_dpage */
++ real_parent = parent;
++ while (1) {
++ dput(parent);
++ parent = dget_parent(dentry);
++ h_parent = au_h_dptr(parent, bdst);
++ if (h_parent)
++ goto out; /* success */
++
++ /* find top dir which is necessary to cpup */
++ do {
++ d = parent;
++ dput(parent);
++ parent = dget_parent(d);
++ di_read_lock_parent3(parent, !AuLock_IR);
++ h_parent = au_h_dptr(parent, bdst);
++ di_read_unlock(parent, !AuLock_IR);
++ } while (!h_parent);
++
++ if (d != real_parent)
++ di_write_lock_child3(d);
++
++ /* somebody else might create while we were sleeping */
++ if (!au_h_dptr(d, bdst) || !au_h_dptr(d, bdst)->d_inode) {
++ if (au_h_dptr(d, bdst))
++ au_update_dbstart(d);
++
++ au_pin_set_dentry(&pin, d);
++ err = au_do_pin(&pin);
++ if (!err) {
++ err = cp(d, bdst, h_parent, arg);
++ au_unpin(&pin);
++ }
++ }
++
++ if (d != real_parent)
++ di_write_unlock(d);
++ if (unlikely(err))
++ break;
++ }
++
++out:
++ dput(parent);
++ return err;
++}
++
++static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent __maybe_unused ,
++ void *arg __maybe_unused)
++{
++ return au_sio_cpup_simple(dentry, bdst, -1, AuCpup_DTIME);
++}
++
++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst)
++{
++ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL);
++}
++
++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst)
++{
++ int err;
++ struct dentry *parent;
++ struct inode *dir;
++
++ parent = dget_parent(dentry);
++ dir = parent->d_inode;
++ err = 0;
++ if (au_h_iptr(dir, bdst))
++ goto out;
++
++ di_read_unlock(parent, AuLock_IR);
++ di_write_lock_parent(parent);
++ /* someone else might change our inode while we were sleeping */
++ if (!au_h_iptr(dir, bdst))
++ err = au_cpup_dirs(dentry, bdst);
++ di_downgrade_lock(parent, AuLock_IR);
++
++out:
++ dput(parent);
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/cpup.h linux-2.6.37/fs/aufs/cpup.h
+--- linux-2.6.37.orig/fs/aufs/cpup.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/cpup.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,83 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * copy-up/down functions
++ */
++
++#ifndef __AUFS_CPUP_H__
++#define __AUFS_CPUP_H__
++
++#ifdef __KERNEL__
++
++#include <linux/path.h>
++#include <linux/time.h>
++#include <linux/aufs_type.h>
++
++struct inode;
++struct file;
++
++void au_cpup_attr_flags(struct inode *dst, struct inode *src);
++void au_cpup_attr_timesizes(struct inode *inode);
++void au_cpup_attr_nlink(struct inode *inode, int force);
++void au_cpup_attr_changeable(struct inode *inode);
++void au_cpup_igen(struct inode *inode, struct inode *h_inode);
++void au_cpup_attr_all(struct inode *inode, int force);
++
++/* ---------------------------------------------------------------------- */
++
++/* cpup flags */
++#define AuCpup_DTIME 1 /* do dtime_store/revert */
++#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino,
++ for link(2) */
++#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name)
++#define au_fset_cpup(flags, name) \
++ do { (flags) |= AuCpup_##name; } while (0)
++#define au_fclr_cpup(flags, name) \
++ do { (flags) &= ~AuCpup_##name; } while (0)
++
++int au_copy_file(struct file *dst, struct file *src, loff_t len);
++int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent);
++int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ unsigned int flags);
++int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ struct file *file);
++
++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst,
++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent, void *arg),
++ void *arg);
++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst);
++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst);
++
++/* ---------------------------------------------------------------------- */
++
++/* keep timestamps when copyup */
++struct au_dtime {
++ struct dentry *dt_dentry;
++ struct path dt_h_path;
++ struct timespec dt_atime, dt_mtime;
++};
++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry,
++ struct path *h_path);
++void au_dtime_revert(struct au_dtime *dt);
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_CPUP_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/dbgaufs.c linux-2.6.37/fs/aufs/dbgaufs.c
+--- linux-2.6.37.orig/fs/aufs/dbgaufs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/dbgaufs.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,334 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * debugfs interface
++ */
++
++#include <linux/debugfs.h>
++#include "aufs.h"
++
++#ifndef CONFIG_SYSFS
++#error DEBUG_FS depends upon SYSFS
++#endif
++
++static struct dentry *dbgaufs;
++static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH;
++
++/* 20 is max digits length of ulong 64 */
++struct dbgaufs_arg {
++ int n;
++ char a[20 * 4];
++};
++
++/*
++ * common function for all XINO files
++ */
++static int dbgaufs_xi_release(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ kfree(file->private_data);
++ return 0;
++}
++
++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt)
++{
++ int err;
++ struct kstat st;
++ struct dbgaufs_arg *p;
++
++ err = -ENOMEM;
++ p = kmalloc(sizeof(*p), GFP_NOFS);
++ if (unlikely(!p))
++ goto out;
++
++ err = 0;
++ p->n = 0;
++ file->private_data = p;
++ if (!xf)
++ goto out;
++
++ err = vfs_getattr(xf->f_vfsmnt, xf->f_dentry, &st);
++ if (!err) {
++ if (do_fcnt)
++ p->n = snprintf
++ (p->a, sizeof(p->a), "%ld, %llux%lu %lld\n",
++ (long)file_count(xf), st.blocks, st.blksize,
++ (long long)st.size);
++ else
++ p->n = snprintf(p->a, sizeof(p->a), "%llux%lu %lld\n",
++ st.blocks, st.blksize,
++ (long long)st.size);
++ AuDebugOn(p->n >= sizeof(p->a));
++ } else {
++ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err);
++ err = 0;
++ }
++
++out:
++ return err;
++
++}
++
++static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct dbgaufs_arg *p;
++
++ p = file->private_data;
++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int dbgaufs_xib_open(struct inode *inode, struct file *file)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++
++ sbinfo = inode->i_private;
++ sb = sbinfo->si_sb;
++ si_noflush_read_lock(sb);
++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0);
++ si_read_unlock(sb);
++ return err;
++}
++
++static const struct file_operations dbgaufs_xib_fop = {
++ .owner = THIS_MODULE,
++ .open = dbgaufs_xib_open,
++ .release = dbgaufs_xi_release,
++ .read = dbgaufs_xi_read
++};
++
++/* ---------------------------------------------------------------------- */
++
++#define DbgaufsXi_PREFIX "xi"
++
++static int dbgaufs_xino_open(struct inode *inode, struct file *file)
++{
++ int err;
++ long l;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++ struct file *xf;
++ struct qstr *name;
++
++ err = -ENOENT;
++ xf = NULL;
++ name = &file->f_dentry->d_name;
++ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX)
++ || memcmp(name->name, DbgaufsXi_PREFIX,
++ sizeof(DbgaufsXi_PREFIX) - 1)))
++ goto out;
++ err = strict_strtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l);
++ if (unlikely(err))
++ goto out;
++
++ sbinfo = inode->i_private;
++ sb = sbinfo->si_sb;
++ si_noflush_read_lock(sb);
++ if (l <= au_sbend(sb)) {
++ xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file;
++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1);
++ } else
++ err = -ENOENT;
++ si_read_unlock(sb);
++
++out:
++ return err;
++}
++
++static const struct file_operations dbgaufs_xino_fop = {
++ .owner = THIS_MODULE,
++ .open = dbgaufs_xino_open,
++ .release = dbgaufs_xi_release,
++ .read = dbgaufs_xi_read
++};
++
++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
++{
++ aufs_bindex_t bend;
++ struct au_branch *br;
++ struct au_xino_file *xi;
++
++ if (!au_sbi(sb)->si_dbgaufs)
++ return;
++
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ xi = &br->br_xino;
++ if (xi->xi_dbgaufs) {
++ debugfs_remove(xi->xi_dbgaufs);
++ xi->xi_dbgaufs = NULL;
++ }
++ }
++}
++
++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
++{
++ struct au_sbinfo *sbinfo;
++ struct dentry *parent;
++ struct au_branch *br;
++ struct au_xino_file *xi;
++ aufs_bindex_t bend;
++ char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */
++
++ sbinfo = au_sbi(sb);
++ parent = sbinfo->si_dbgaufs;
++ if (!parent)
++ return;
++
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex);
++ br = au_sbr(sb, bindex);
++ xi = &br->br_xino;
++ AuDebugOn(xi->xi_dbgaufs);
++ xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent,
++ sbinfo, &dbgaufs_xino_fop);
++ /* ignore an error */
++ if (unlikely(!xi->xi_dbgaufs))
++ AuWarn1("failed %s under debugfs\n", name);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_EXPORT
++static int dbgaufs_xigen_open(struct inode *inode, struct file *file)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++
++ sbinfo = inode->i_private;
++ sb = sbinfo->si_sb;
++ si_noflush_read_lock(sb);
++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0);
++ si_read_unlock(sb);
++ return err;
++}
++
++static const struct file_operations dbgaufs_xigen_fop = {
++ .owner = THIS_MODULE,
++ .open = dbgaufs_xigen_open,
++ .release = dbgaufs_xi_release,
++ .read = dbgaufs_xi_read
++};
++
++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo)
++{
++ int err;
++
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++
++ err = -EIO;
++ sbinfo->si_dbgaufs_xigen = debugfs_create_file
++ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
++ &dbgaufs_xigen_fop);
++ if (sbinfo->si_dbgaufs_xigen)
++ err = 0;
++
++ return err;
++}
++#else
++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo)
++{
++ return 0;
++}
++#endif /* CONFIG_AUFS_EXPORT */
++
++/* ---------------------------------------------------------------------- */
++
++void dbgaufs_si_fin(struct au_sbinfo *sbinfo)
++{
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++
++ debugfs_remove_recursive(sbinfo->si_dbgaufs);
++ sbinfo->si_dbgaufs = NULL;
++ kobject_put(&sbinfo->si_kobj);
++}
++
++int dbgaufs_si_init(struct au_sbinfo *sbinfo)
++{
++ int err;
++ char name[SysaufsSiNameLen];
++
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++
++ err = -ENOENT;
++ if (!dbgaufs) {
++ AuErr1("/debug/aufs is uninitialized\n");
++ goto out;
++ }
++
++ err = -EIO;
++ sysaufs_name(sbinfo, name);
++ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs);
++ if (unlikely(!sbinfo->si_dbgaufs))
++ goto out;
++ kobject_get(&sbinfo->si_kobj);
++
++ sbinfo->si_dbgaufs_xib = debugfs_create_file
++ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
++ &dbgaufs_xib_fop);
++ if (unlikely(!sbinfo->si_dbgaufs_xib))
++ goto out_dir;
++
++ err = dbgaufs_xigen_init(sbinfo);
++ if (!err)
++ goto out; /* success */
++
++out_dir:
++ dbgaufs_si_fin(sbinfo);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void dbgaufs_fin(void)
++{
++ debugfs_remove(dbgaufs);
++}
++
++int __init dbgaufs_init(void)
++{
++ int err;
++
++ err = -EIO;
++ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL);
++ if (dbgaufs)
++ err = 0;
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/dbgaufs.h linux-2.6.37/fs/aufs/dbgaufs.h
+--- linux-2.6.37.orig/fs/aufs/dbgaufs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/dbgaufs.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * debugfs interface
++ */
++
++#ifndef __DBGAUFS_H__
++#define __DBGAUFS_H__
++
++#ifdef __KERNEL__
++
++#include <linux/init.h>
++#include <linux/aufs_type.h>
++
++struct super_block;
++struct au_sbinfo;
++
++#ifdef CONFIG_DEBUG_FS
++/* dbgaufs.c */
++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex);
++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex);
++void dbgaufs_si_fin(struct au_sbinfo *sbinfo);
++int dbgaufs_si_init(struct au_sbinfo *sbinfo);
++void dbgaufs_fin(void);
++int __init dbgaufs_init(void);
++#else
++AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex)
++AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex)
++AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo)
++AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo)
++AuStubVoid(dbgaufs_fin, void)
++AuStubInt0(__init dbgaufs_init, void)
++#endif /* CONFIG_DEBUG_FS */
++
++#endif /* __KERNEL__ */
++#endif /* __DBGAUFS_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/dcsub.c linux-2.6.37/fs/aufs/dcsub.c
+--- linux-2.6.37.orig/fs/aufs/dcsub.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/dcsub.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,210 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sub-routines for dentry cache
++ */
++
++#include "aufs.h"
++
++static void au_dpage_free(struct au_dpage *dpage)
++{
++ int i;
++ struct dentry **p;
++
++ p = dpage->dentries;
++ for (i = 0; i < dpage->ndentry; i++)
++ dput(*p++);
++ free_page((unsigned long)dpage->dentries);
++}
++
++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp)
++{
++ int err;
++ void *p;
++
++ err = -ENOMEM;
++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp);
++ if (unlikely(!dpages->dpages))
++ goto out;
++
++ p = (void *)__get_free_page(gfp);
++ if (unlikely(!p))
++ goto out_dpages;
++
++ dpages->dpages[0].ndentry = 0;
++ dpages->dpages[0].dentries = p;
++ dpages->ndpage = 1;
++ return 0; /* success */
++
++out_dpages:
++ kfree(dpages->dpages);
++out:
++ return err;
++}
++
++void au_dpages_free(struct au_dcsub_pages *dpages)
++{
++ int i;
++ struct au_dpage *p;
++
++ p = dpages->dpages;
++ for (i = 0; i < dpages->ndpage; i++)
++ au_dpage_free(p++);
++ kfree(dpages->dpages);
++}
++
++static int au_dpages_append(struct au_dcsub_pages *dpages,
++ struct dentry *dentry, gfp_t gfp)
++{
++ int err, sz;
++ struct au_dpage *dpage;
++ void *p;
++
++ dpage = dpages->dpages + dpages->ndpage - 1;
++ sz = PAGE_SIZE / sizeof(dentry);
++ if (unlikely(dpage->ndentry >= sz)) {
++ AuLabel(new dpage);
++ err = -ENOMEM;
++ sz = dpages->ndpage * sizeof(*dpages->dpages);
++ p = au_kzrealloc(dpages->dpages, sz,
++ sz + sizeof(*dpages->dpages), gfp);
++ if (unlikely(!p))
++ goto out;
++
++ dpages->dpages = p;
++ dpage = dpages->dpages + dpages->ndpage;
++ p = (void *)__get_free_page(gfp);
++ if (unlikely(!p))
++ goto out;
++
++ dpage->ndentry = 0;
++ dpage->dentries = p;
++ dpages->ndpage++;
++ }
++
++ /* d_count can be zero */
++ dpage->dentries[dpage->ndentry++] = dget_locked(dentry);
++ return 0; /* success */
++
++out:
++ return err;
++}
++
++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
++ au_dpages_test test, void *arg)
++{
++ int err;
++ struct dentry *this_parent = root;
++ struct list_head *next;
++ struct super_block *sb = root->d_sb;
++
++ err = 0;
++ spin_lock(&dcache_lock);
++repeat:
++ next = this_parent->d_subdirs.next;
++resume:
++ if (this_parent->d_sb == sb
++ && !IS_ROOT(this_parent)
++ && au_di(this_parent)
++ && (!test || test(this_parent, arg))) {
++ err = au_dpages_append(dpages, this_parent, GFP_ATOMIC);
++ if (unlikely(err))
++ goto out;
++ }
++
++ while (next != &this_parent->d_subdirs) {
++ struct list_head *tmp = next;
++ struct dentry *dentry = list_entry(tmp, struct dentry,
++ d_u.d_child);
++ next = tmp->next;
++ if (!list_empty(&dentry->d_subdirs)) {
++ this_parent = dentry;
++ goto repeat;
++ }
++ if (dentry->d_sb == sb
++ && au_di(dentry)
++ && (!test || test(dentry, arg))) {
++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
++ if (unlikely(err))
++ goto out;
++ }
++ }
++
++ if (this_parent != root) {
++ next = this_parent->d_u.d_child.next;
++ this_parent = this_parent->d_parent; /* dcache_lock is locked */
++ goto resume;
++ }
++out:
++ spin_unlock(&dcache_lock);
++ return err;
++}
++
++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
++ int do_include, au_dpages_test test, void *arg)
++{
++ int err;
++
++ err = 0;
++ spin_lock(&dcache_lock);
++ if (do_include && (!test || test(dentry, arg))) {
++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
++ if (unlikely(err))
++ goto out;
++ }
++ while (!IS_ROOT(dentry)) {
++ dentry = dentry->d_parent; /* dcache_lock is locked */
++ if (!test || test(dentry, arg)) {
++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
++ if (unlikely(err))
++ break;
++ }
++ }
++
++out:
++ spin_unlock(&dcache_lock);
++
++ return err;
++}
++
++static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg)
++{
++ return au_di(dentry) && dentry->d_sb == arg;
++}
++
++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
++ struct dentry *dentry, int do_include)
++{
++ return au_dcsub_pages_rev(dpages, dentry, do_include,
++ au_dcsub_dpages_aufs, dentry->d_sb);
++}
++
++int au_test_subdir(struct dentry *d1, struct dentry *d2)
++{
++ struct path path[2] = {
++ {
++ .dentry = d1
++ },
++ {
++ .dentry = d2
++ }
++ };
++
++ return path_is_under(path + 0, path + 1);
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/dcsub.h linux-2.6.37/fs/aufs/dcsub.h
+--- linux-2.6.37.orig/fs/aufs/dcsub.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/dcsub.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,100 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sub-routines for dentry cache
++ */
++
++#ifndef __AUFS_DCSUB_H__
++#define __AUFS_DCSUB_H__
++
++#ifdef __KERNEL__
++
++#include <linux/dcache.h>
++#include <linux/fs.h>
++#include <linux/types.h>
++
++struct dentry;
++
++struct au_dpage {
++ int ndentry;
++ struct dentry **dentries;
++};
++
++struct au_dcsub_pages {
++ int ndpage;
++ struct au_dpage *dpages;
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* dcsub.c */
++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp);
++void au_dpages_free(struct au_dcsub_pages *dpages);
++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg);
++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
++ au_dpages_test test, void *arg);
++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
++ int do_include, au_dpages_test test, void *arg);
++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
++ struct dentry *dentry, int do_include);
++int au_test_subdir(struct dentry *d1, struct dentry *d2);
++
++/* ---------------------------------------------------------------------- */
++
++static inline int au_d_removed(struct dentry *d)
++{
++ return !IS_ROOT(d) && d_unhashed(d);
++}
++
++static inline int au_d_hashed_positive(struct dentry *d)
++{
++ int err;
++ struct inode *inode = d->d_inode;
++ err = 0;
++ if (unlikely(d_unhashed(d) || !inode || !inode->i_nlink))
++ err = -ENOENT;
++ return err;
++}
++
++static inline int au_d_alive(struct dentry *d)
++{
++ int err;
++ struct inode *inode;
++ err = 0;
++ if (!IS_ROOT(d))
++ err = au_d_hashed_positive(d);
++ else {
++ inode = d->d_inode;
++ if (unlikely(au_d_removed(d) || !inode || !inode->i_nlink))
++ err = -ENOENT;
++ }
++ return err;
++}
++
++static inline int au_alive_dir(struct dentry *d)
++{
++ int err;
++ err = au_d_alive(d);
++ if (unlikely(err || IS_DEADDIR(d->d_inode)))
++ err = -ENOENT;
++ return err;
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DCSUB_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/debug.c linux-2.6.37/fs/aufs/debug.c
+--- linux-2.6.37.orig/fs/aufs/debug.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/debug.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,468 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * debug print functions
++ */
++
++#include <linux/module.h>
++#include <linux/vt_kern.h>
++#include "aufs.h"
++
++int aufs_debug;
++MODULE_PARM_DESC(debug, "debug print");
++module_param_named(debug, aufs_debug, int, S_IRUGO | S_IWUSR | S_IWGRP);
++
++char *au_plevel = KERN_DEBUG;
++#define dpri(fmt, ...) do { \
++ if ((au_plevel \
++ && strcmp(au_plevel, KERN_DEBUG)) \
++ || au_debug_test()) \
++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \
++} while (0)
++
++/* ---------------------------------------------------------------------- */
++
++void au_dpri_whlist(struct au_nhash *whlist)
++{
++ unsigned long ul, n;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++
++ n = whlist->nh_num;
++ head = whlist->nh_head;
++ for (ul = 0; ul < n; ul++) {
++ hlist_for_each_entry(tpos, pos, head, wh_hash)
++ dpri("b%d, %.*s, %d\n",
++ tpos->wh_bindex,
++ tpos->wh_str.len, tpos->wh_str.name,
++ tpos->wh_str.len);
++ head++;
++ }
++}
++
++void au_dpri_vdir(struct au_vdir *vdir)
++{
++ unsigned long ul;
++ union au_vdir_deblk_p p;
++ unsigned char *o;
++
++ if (!vdir || IS_ERR(vdir)) {
++ dpri("err %ld\n", PTR_ERR(vdir));
++ return;
++ }
++
++ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %lu\n",
++ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk,
++ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version);
++ for (ul = 0; ul < vdir->vd_nblk; ul++) {
++ p.deblk = vdir->vd_deblk[ul];
++ o = p.deblk;
++ dpri("[%lu]: %p\n", ul, o);
++ }
++}
++
++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode,
++ struct dentry *wh)
++{
++ char *n = NULL;
++ int l = 0;
++
++ if (!inode || IS_ERR(inode)) {
++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode));
++ return -1;
++ }
++
++ /* the type of i_blocks depends upon CONFIG_LSF */
++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long)
++ && sizeof(inode->i_blocks) != sizeof(u64));
++ if (wh) {
++ n = (void *)wh->d_name.name;
++ l = wh->d_name.len;
++ }
++
++ dpri("i%d: i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu,"
++ " ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n",
++ bindex,
++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??",
++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode,
++ i_size_read(inode), (unsigned long long)inode->i_blocks,
++ (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff,
++ inode->i_mapping ? inode->i_mapping->nrpages : 0,
++ inode->i_state, inode->i_flags, inode->i_version,
++ inode->i_generation,
++ l ? ", wh " : "", l, n);
++ return 0;
++}
++
++void au_dpri_inode(struct inode *inode)
++{
++ struct au_iinfo *iinfo;
++ aufs_bindex_t bindex;
++ int err;
++
++ err = do_pri_inode(-1, inode, NULL);
++ if (err || !au_test_aufs(inode->i_sb))
++ return;
++
++ iinfo = au_ii(inode);
++ if (!iinfo)
++ return;
++ dpri("i-1: bstart %d, bend %d, gen %d\n",
++ iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode));
++ if (iinfo->ii_bstart < 0)
++ return;
++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++)
++ do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode,
++ iinfo->ii_hinode[0 + bindex].hi_whdentry);
++}
++
++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry)
++{
++ struct dentry *wh = NULL;
++
++ if (!dentry || IS_ERR(dentry)) {
++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry));
++ return -1;
++ }
++ /* do not call dget_parent() here */
++ dpri("d%d: %.*s?/%.*s, %s, cnt %d, flags 0x%x\n",
++ bindex,
++ AuDLNPair(dentry->d_parent), AuDLNPair(dentry),
++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??",
++ atomic_read(&dentry->d_count), dentry->d_flags);
++ if (bindex >= 0 && dentry->d_inode && au_test_aufs(dentry->d_sb)) {
++ struct au_iinfo *iinfo = au_ii(dentry->d_inode);
++ if (iinfo)
++ wh = iinfo->ii_hinode[0 + bindex].hi_whdentry;
++ }
++ do_pri_inode(bindex, dentry->d_inode, wh);
++ return 0;
++}
++
++void au_dpri_dentry(struct dentry *dentry)
++{
++ struct au_dinfo *dinfo;
++ aufs_bindex_t bindex;
++ int err;
++ struct au_hdentry *hdp;
++
++ err = do_pri_dentry(-1, dentry);
++ if (err || !au_test_aufs(dentry->d_sb))
++ return;
++
++ dinfo = au_di(dentry);
++ if (!dinfo)
++ return;
++ dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n",
++ dinfo->di_bstart, dinfo->di_bend,
++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry));
++ if (dinfo->di_bstart < 0)
++ return;
++ hdp = dinfo->di_hdentry;
++ for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++)
++ do_pri_dentry(bindex, hdp[0 + bindex].hd_dentry);
++}
++
++static int do_pri_file(aufs_bindex_t bindex, struct file *file)
++{
++ char a[32];
++
++ if (!file || IS_ERR(file)) {
++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file));
++ return -1;
++ }
++ a[0] = 0;
++ if (bindex < 0
++ && file->f_dentry
++ && au_test_aufs(file->f_dentry->d_sb)
++ && au_fi(file))
++ snprintf(a, sizeof(a), ", gen %d, mmapped %d",
++ au_figen(file), !!au_fi(file)->fi_hvmop);
++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n",
++ bindex, file->f_mode, file->f_flags, (long)file_count(file),
++ file->f_version, file->f_pos, a);
++ if (file->f_dentry)
++ do_pri_dentry(bindex, file->f_dentry);
++ return 0;
++}
++
++void au_dpri_file(struct file *file)
++{
++ struct au_finfo *finfo;
++ struct au_fidir *fidir;
++ struct au_hfile *hfile;
++ aufs_bindex_t bindex;
++ int err;
++
++ err = do_pri_file(-1, file);
++ if (err || !file->f_dentry || !au_test_aufs(file->f_dentry->d_sb))
++ return;
++
++ finfo = au_fi(file);
++ if (!finfo)
++ return;
++ if (finfo->fi_btop < 0)
++ return;
++ fidir = finfo->fi_hdir;
++ if (!fidir)
++ do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file);
++ else
++ for (bindex = finfo->fi_btop;
++ bindex >= 0 && bindex <= fidir->fd_bbot;
++ bindex++) {
++ hfile = fidir->fd_hfile + bindex;
++ do_pri_file(bindex, hfile ? hfile->hf_file : NULL);
++ }
++}
++
++static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br)
++{
++ struct vfsmount *mnt;
++ struct super_block *sb;
++
++ if (!br || IS_ERR(br))
++ goto out;
++ mnt = br->br_mnt;
++ if (!mnt || IS_ERR(mnt))
++ goto out;
++ sb = mnt->mnt_sb;
++ if (!sb || IS_ERR(sb))
++ goto out;
++
++ dpri("s%d: {perm 0x%x, cnt %d, wbr %p}, "
++ "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, "
++ "xino %d\n",
++ bindex, br->br_perm, atomic_read(&br->br_count), br->br_wbr,
++ au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev),
++ sb->s_flags, sb->s_count,
++ atomic_read(&sb->s_active), !!br->br_xino.xi_file);
++ return 0;
++
++out:
++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br));
++ return -1;
++}
++
++void au_dpri_sb(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++ aufs_bindex_t bindex;
++ int err;
++ /* to reuduce stack size */
++ struct {
++ struct vfsmount mnt;
++ struct au_branch fake;
++ } *a;
++
++ /* this function can be called from magic sysrq */
++ a = kzalloc(sizeof(*a), GFP_ATOMIC);
++ if (unlikely(!a)) {
++ dpri("no memory\n");
++ return;
++ }
++
++ a->mnt.mnt_sb = sb;
++ a->fake.br_perm = 0;
++ a->fake.br_mnt = &a->mnt;
++ a->fake.br_xino.xi_file = NULL;
++ atomic_set(&a->fake.br_count, 0);
++ smp_mb(); /* atomic_set */
++ err = do_pri_br(-1, &a->fake);
++ kfree(a);
++ dpri("dev 0x%x\n", sb->s_dev);
++ if (err || !au_test_aufs(sb))
++ return;
++
++ sbinfo = au_sbi(sb);
++ if (!sbinfo)
++ return;
++ dpri("nw %d, gen %u, kobj %d\n",
++ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation,
++ atomic_read(&sbinfo->si_kobj.kref.refcount));
++ for (bindex = 0; bindex <= sbinfo->si_bend; bindex++)
++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]);
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_dbg_sleep_jiffy(int jiffy)
++{
++ while (jiffy)
++ jiffy = schedule_timeout_uninterruptible(jiffy);
++}
++
++void au_dbg_iattr(struct iattr *ia)
++{
++#define AuBit(name) if (ia->ia_valid & ATTR_ ## name) \
++ dpri(#name "\n")
++ AuBit(MODE);
++ AuBit(UID);
++ AuBit(GID);
++ AuBit(SIZE);
++ AuBit(ATIME);
++ AuBit(MTIME);
++ AuBit(CTIME);
++ AuBit(ATIME_SET);
++ AuBit(MTIME_SET);
++ AuBit(FORCE);
++ AuBit(ATTR_FLAG);
++ AuBit(KILL_SUID);
++ AuBit(KILL_SGID);
++ AuBit(FILE);
++ AuBit(KILL_PRIV);
++ AuBit(OPEN);
++ AuBit(TIMES_SET);
++#undef AuBit
++ dpri("ia_file %p\n", ia->ia_file);
++}
++
++/* ---------------------------------------------------------------------- */
++
++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line)
++{
++ struct inode *h_inode, *inode = dentry->d_inode;
++ struct dentry *h_dentry;
++ aufs_bindex_t bindex, bend, bi;
++
++ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */)
++ return;
++
++ bend = au_dbend(dentry);
++ bi = au_ibend(inode);
++ if (bi < bend)
++ bend = bi;
++ bindex = au_dbstart(dentry);
++ bi = au_ibstart(inode);
++ if (bi > bindex)
++ bindex = bi;
++
++ for (; bindex <= bend; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++ h_inode = au_h_iptr(inode, bindex);
++ if (unlikely(h_inode != h_dentry->d_inode)) {
++ int old = au_debug_test();
++ if (!old)
++ au_debug(1);
++ AuDbg("b%d, %s:%d\n", bindex, func, line);
++ AuDbgDentry(dentry);
++ AuDbgInode(inode);
++ if (!old)
++ au_debug(0);
++ BUG();
++ }
++ }
++}
++
++void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen)
++{
++ struct dentry *parent;
++
++ parent = dget_parent(dentry);
++ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode));
++ AuDebugOn(IS_ROOT(dentry));
++ AuDebugOn(au_digen_test(parent, sigen));
++ dput(parent);
++}
++
++void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen)
++{
++ struct dentry *parent;
++ struct inode *inode;
++
++ parent = dget_parent(dentry);
++ inode = dentry->d_inode;
++ AuDebugOn(inode && S_ISDIR(dentry->d_inode->i_mode));
++ AuDebugOn(au_digen_test(parent, sigen));
++ dput(parent);
++}
++
++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen)
++{
++ int err, i, j;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ AuDebugOn(err);
++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1);
++ AuDebugOn(err);
++ for (i = dpages.ndpage - 1; !err && i >= 0; i--) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ for (j = dpage->ndentry - 1; !err && j >= 0; j--)
++ AuDebugOn(au_digen_test(dentries[j], sigen));
++ }
++ au_dpages_free(&dpages);
++}
++
++void au_dbg_verify_kthread(void)
++{
++ if (current->flags & PF_WQ_WORKER) {
++ au_dbg_blocked();
++ WARN_ON(1);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_debug_sbinfo_init(struct au_sbinfo *sbinfo __maybe_unused)
++{
++#ifdef AuForceNoPlink
++ au_opt_clr(sbinfo->si_mntflags, PLINK);
++#endif
++#ifdef AuForceNoXino
++ au_opt_clr(sbinfo->si_mntflags, XINO);
++#endif
++#ifdef AuForceNoRefrof
++ au_opt_clr(sbinfo->si_mntflags, REFROF);
++#endif
++#ifdef AuForceHnotify
++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_HNOTIFY);
++#endif
++#ifdef AuForceRd0
++ sbinfo->si_rdblk = 0;
++ sbinfo->si_rdhash = 0;
++#endif
++}
++
++int __init au_debug_init(void)
++{
++ aufs_bindex_t bindex;
++ struct au_vdir_destr destr;
++
++ bindex = -1;
++ AuDebugOn(bindex >= 0);
++
++ destr.len = -1;
++ AuDebugOn(destr.len < NAME_MAX);
++
++#ifdef CONFIG_4KSTACKS
++ pr_warning("CONFIG_4KSTACKS is defined.\n");
++#endif
++
++#ifdef AuForceNoBrs
++ sysaufs_brs = 0;
++#endif
++
++ return 0;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/debug.h linux-2.6.37/fs/aufs/debug.h
+--- linux-2.6.37.orig/fs/aufs/debug.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/debug.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,245 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * debug print functions
++ */
++
++#ifndef __AUFS_DEBUG_H__
++#define __AUFS_DEBUG_H__
++
++#ifdef __KERNEL__
++
++#include <asm/system.h>
++#include <linux/bug.h>
++/* #include <linux/err.h> */
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kallsyms.h>
++/* #include <linux/kernel.h> */
++#include <linux/delay.h>
++/* #include <linux/kd.h> */
++#include <linux/sysrq.h>
++#include <linux/aufs_type.h>
++
++#include <asm/system.h>
++
++#ifdef CONFIG_AUFS_DEBUG
++#define AuDebugOn(a) BUG_ON(a)
++
++/* module parameter */
++extern int aufs_debug;
++static inline void au_debug(int n)
++{
++ aufs_debug = n;
++ smp_mb();
++}
++
++static inline int au_debug_test(void)
++{
++ return aufs_debug;
++}
++#else
++#define AuDebugOn(a) do {} while (0)
++AuStubVoid(au_debug, int n)
++AuStubInt0(au_debug_test, void)
++#endif /* CONFIG_AUFS_DEBUG */
++
++/* ---------------------------------------------------------------------- */
++
++/* debug print */
++
++#define AuDbg(fmt, ...) do { \
++ if (au_debug_test()) \
++ pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \
++} while (0)
++#define AuLabel(l) AuDbg(#l "\n")
++#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__)
++#define AuWarn1(fmt, ...) do { \
++ static unsigned char _c; \
++ if (!_c++) \
++ pr_warning(fmt, ##__VA_ARGS__); \
++} while (0)
++
++#define AuErr1(fmt, ...) do { \
++ static unsigned char _c; \
++ if (!_c++) \
++ pr_err(fmt, ##__VA_ARGS__); \
++} while (0)
++
++#define AuIOErr1(fmt, ...) do { \
++ static unsigned char _c; \
++ if (!_c++) \
++ AuIOErr(fmt, ##__VA_ARGS__); \
++} while (0)
++
++#define AuUnsupportMsg "This operation is not supported." \
++ " Please report this application to aufs-users ML."
++#define AuUnsupport(fmt, ...) do { \
++ pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \
++ dump_stack(); \
++} while (0)
++
++#define AuTraceErr(e) do { \
++ if (unlikely((e) < 0)) \
++ AuDbg("err %d\n", (int)(e)); \
++} while (0)
++
++#define AuTraceErrPtr(p) do { \
++ if (IS_ERR(p)) \
++ AuDbg("err %ld\n", PTR_ERR(p)); \
++} while (0)
++
++/* dirty macros for debug print, use with "%.*s" and caution */
++#define AuLNPair(qstr) (qstr)->len, (qstr)->name
++#define AuDLNPair(d) AuLNPair(&(d)->d_name)
++
++/* ---------------------------------------------------------------------- */
++
++struct au_sbinfo;
++struct au_finfo;
++struct dentry;
++#ifdef CONFIG_AUFS_DEBUG
++extern char *au_plevel;
++struct au_nhash;
++void au_dpri_whlist(struct au_nhash *whlist);
++struct au_vdir;
++void au_dpri_vdir(struct au_vdir *vdir);
++struct inode;
++void au_dpri_inode(struct inode *inode);
++void au_dpri_dentry(struct dentry *dentry);
++struct file;
++void au_dpri_file(struct file *filp);
++struct super_block;
++void au_dpri_sb(struct super_block *sb);
++
++void au_dbg_sleep_jiffy(int jiffy);
++struct iattr;
++void au_dbg_iattr(struct iattr *ia);
++
++#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__)
++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line);
++void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen);
++void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen);
++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen);
++void au_dbg_verify_kthread(void);
++
++int __init au_debug_init(void);
++void au_debug_sbinfo_init(struct au_sbinfo *sbinfo);
++#define AuDbgWhlist(w) do { \
++ AuDbg(#w "\n"); \
++ au_dpri_whlist(w); \
++} while (0)
++
++#define AuDbgVdir(v) do { \
++ AuDbg(#v "\n"); \
++ au_dpri_vdir(v); \
++} while (0)
++
++#define AuDbgInode(i) do { \
++ AuDbg(#i "\n"); \
++ au_dpri_inode(i); \
++} while (0)
++
++#define AuDbgDentry(d) do { \
++ AuDbg(#d "\n"); \
++ au_dpri_dentry(d); \
++} while (0)
++
++#define AuDbgFile(f) do { \
++ AuDbg(#f "\n"); \
++ au_dpri_file(f); \
++} while (0)
++
++#define AuDbgSb(sb) do { \
++ AuDbg(#sb "\n"); \
++ au_dpri_sb(sb); \
++} while (0)
++
++#define AuDbgSleep(sec) do { \
++ AuDbg("sleep %d sec\n", sec); \
++ ssleep(sec); \
++} while (0)
++
++#define AuDbgSleepJiffy(jiffy) do { \
++ AuDbg("sleep %d jiffies\n", jiffy); \
++ au_dbg_sleep_jiffy(jiffy); \
++} while (0)
++
++#define AuDbgIAttr(ia) do { \
++ AuDbg("ia_valid 0x%x\n", (ia)->ia_valid); \
++ au_dbg_iattr(ia); \
++} while (0)
++
++#define AuDbgSym(addr) do { \
++ char sym[KSYM_SYMBOL_LEN]; \
++ sprint_symbol(sym, (unsigned long)addr); \
++ AuDbg("%s\n", sym); \
++} while (0)
++
++#define AuInfoSym(addr) do { \
++ char sym[KSYM_SYMBOL_LEN]; \
++ sprint_symbol(sym, (unsigned long)addr); \
++ AuInfo("%s\n", sym); \
++} while (0)
++#else
++AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry)
++AuStubVoid(au_dbg_verify_dir_parent, struct dentry *dentry, unsigned int sigen)
++AuStubVoid(au_dbg_verify_nondir_parent, struct dentry *dentry,
++ unsigned int sigen)
++AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen)
++AuStubVoid(au_dbg_verify_kthread, void)
++AuStubInt0(__init au_debug_init, void)
++AuStubVoid(au_debug_sbinfo_init, struct au_sbinfo *sbinfo)
++
++#define AuDbgWhlist(w) do {} while (0)
++#define AuDbgVdir(v) do {} while (0)
++#define AuDbgInode(i) do {} while (0)
++#define AuDbgDentry(d) do {} while (0)
++#define AuDbgFile(f) do {} while (0)
++#define AuDbgSb(sb) do {} while (0)
++#define AuDbgSleep(sec) do {} while (0)
++#define AuDbgSleepJiffy(jiffy) do {} while (0)
++#define AuDbgIAttr(ia) do {} while (0)
++#define AuDbgSym(addr) do {} while (0)
++#define AuInfoSym(addr) do {} while (0)
++#endif /* CONFIG_AUFS_DEBUG */
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_MAGIC_SYSRQ
++int __init au_sysrq_init(void);
++void au_sysrq_fin(void);
++
++#ifdef CONFIG_HW_CONSOLE
++#define au_dbg_blocked() do { \
++ WARN_ON(1); \
++ handle_sysrq('w'); \
++} while (0)
++#else
++AuStubVoid(au_dbg_blocked, void)
++#endif
++
++#else
++AuStubInt0(__init au_sysrq_init, void)
++AuStubVoid(au_sysrq_fin, void)
++AuStubVoid(au_dbg_blocked, void)
++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DEBUG_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/dentry.c linux-2.6.37/fs/aufs/dentry.c
+--- linux-2.6.37.orig/fs/aufs/dentry.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/dentry.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,1131 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * lookup and dentry operations
++ */
++
++#include <linux/namei.h>
++#include "aufs.h"
++
++static void au_h_nd(struct nameidata *h_nd, struct nameidata *nd)
++{
++ if (nd) {
++ *h_nd = *nd;
++
++ /*
++ * gave up supporting LOOKUP_CREATE/OPEN for lower fs,
++ * due to whiteout and branch permission.
++ */
++ h_nd->flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE
++ | LOOKUP_FOLLOW | LOOKUP_EXCL);
++ /* unnecessary? */
++ h_nd->intent.open.file = NULL;
++ } else
++ memset(h_nd, 0, sizeof(*h_nd));
++}
++
++struct au_lkup_one_args {
++ struct dentry **errp;
++ struct qstr *name;
++ struct dentry *h_parent;
++ struct au_branch *br;
++ struct nameidata *nd;
++};
++
++struct dentry *au_lkup_one(struct qstr *name, struct dentry *h_parent,
++ struct au_branch *br, struct nameidata *nd)
++{
++ struct dentry *h_dentry;
++ int err;
++ struct nameidata h_nd;
++
++ if (au_test_fs_null_nd(h_parent->d_sb))
++ return vfsub_lookup_one_len(name->name, h_parent, name->len);
++
++ au_h_nd(&h_nd, nd);
++ h_nd.path.dentry = h_parent;
++ h_nd.path.mnt = br->br_mnt;
++
++ err = __lookup_one_len(name->name, &h_nd.last, NULL, name->len);
++ h_dentry = ERR_PTR(err);
++ if (!err) {
++ path_get(&h_nd.path);
++ h_dentry = vfsub_lookup_hash(&h_nd);
++ path_put(&h_nd.path);
++ }
++
++ AuTraceErrPtr(h_dentry);
++ return h_dentry;
++}
++
++static void au_call_lkup_one(void *args)
++{
++ struct au_lkup_one_args *a = args;
++ *a->errp = au_lkup_one(a->name, a->h_parent, a->br, a->nd);
++}
++
++#define AuLkup_ALLOW_NEG 1
++#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name)
++#define au_fset_lkup(flags, name) \
++ do { (flags) |= AuLkup_##name; } while (0)
++#define au_fclr_lkup(flags, name) \
++ do { (flags) &= ~AuLkup_##name; } while (0)
++
++struct au_do_lookup_args {
++ unsigned int flags;
++ mode_t type;
++ struct nameidata *nd;
++};
++
++/*
++ * returns positive/negative dentry, NULL or an error.
++ * NULL means whiteout-ed or not-found.
++ */
++static struct dentry*
++au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
++ aufs_bindex_t bindex, struct qstr *wh_name,
++ struct au_do_lookup_args *args)
++{
++ struct dentry *h_dentry;
++ struct inode *h_inode, *inode;
++ struct au_branch *br;
++ int wh_found, opq;
++ unsigned char wh_able;
++ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG);
++
++ wh_found = 0;
++ br = au_sbr(dentry->d_sb, bindex);
++ wh_able = !!au_br_whable(br->br_perm);
++ if (wh_able)
++ wh_found = au_wh_test(h_parent, wh_name, br, /*try_sio*/0);
++ h_dentry = ERR_PTR(wh_found);
++ if (!wh_found)
++ goto real_lookup;
++ if (unlikely(wh_found < 0))
++ goto out;
++
++ /* We found a whiteout */
++ /* au_set_dbend(dentry, bindex); */
++ au_set_dbwh(dentry, bindex);
++ if (!allow_neg)
++ return NULL; /* success */
++
++real_lookup:
++ h_dentry = au_lkup_one(&dentry->d_name, h_parent, br, args->nd);
++ if (IS_ERR(h_dentry))
++ goto out;
++
++ h_inode = h_dentry->d_inode;
++ if (!h_inode) {
++ if (!allow_neg)
++ goto out_neg;
++ } else if (wh_found
++ || (args->type && args->type != (h_inode->i_mode & S_IFMT)))
++ goto out_neg;
++
++ if (au_dbend(dentry) <= bindex)
++ au_set_dbend(dentry, bindex);
++ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry))
++ au_set_dbstart(dentry, bindex);
++ au_set_h_dptr(dentry, bindex, h_dentry);
++
++ inode = dentry->d_inode;
++ if (!h_inode || !S_ISDIR(h_inode->i_mode) || !wh_able
++ || (inode && !S_ISDIR(inode->i_mode)))
++ goto out; /* success */
++
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ opq = au_diropq_test(h_dentry, br);
++ mutex_unlock(&h_inode->i_mutex);
++ if (opq > 0)
++ au_set_dbdiropq(dentry, bindex);
++ else if (unlikely(opq < 0)) {
++ au_set_h_dptr(dentry, bindex, NULL);
++ h_dentry = ERR_PTR(opq);
++ }
++ goto out;
++
++out_neg:
++ dput(h_dentry);
++ h_dentry = NULL;
++out:
++ return h_dentry;
++}
++
++static int au_test_shwh(struct super_block *sb, const struct qstr *name)
++{
++ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH)
++ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)))
++ return -EPERM;
++ return 0;
++}
++
++/*
++ * returns the number of lower positive dentries,
++ * otherwise an error.
++ * can be called at unlinking with @type is zero.
++ */
++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type,
++ struct nameidata *nd)
++{
++ int npositive, err;
++ aufs_bindex_t bindex, btail, bdiropq;
++ unsigned char isdir;
++ struct qstr whname;
++ struct au_do_lookup_args args = {
++ .flags = 0,
++ .type = type,
++ .nd = nd
++ };
++ const struct qstr *name = &dentry->d_name;
++ struct dentry *parent;
++ struct inode *inode;
++
++ err = au_test_shwh(dentry->d_sb, name);
++ if (unlikely(err))
++ goto out;
++
++ err = au_wh_name_alloc(&whname, name);
++ if (unlikely(err))
++ goto out;
++
++ inode = dentry->d_inode;
++ isdir = !!(inode && S_ISDIR(inode->i_mode));
++ if (!type)
++ au_fset_lkup(args.flags, ALLOW_NEG);
++
++ npositive = 0;
++ parent = dget_parent(dentry);
++ btail = au_dbtaildir(parent);
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ struct dentry *h_parent, *h_dentry;
++ struct inode *h_inode, *h_dir;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry) {
++ if (h_dentry->d_inode)
++ npositive++;
++ if (type != S_IFDIR)
++ break;
++ continue;
++ }
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent)
++ continue;
++ h_dir = h_parent->d_inode;
++ if (!h_dir || !S_ISDIR(h_dir->i_mode))
++ continue;
++
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname,
++ &args);
++ mutex_unlock(&h_dir->i_mutex);
++ err = PTR_ERR(h_dentry);
++ if (IS_ERR(h_dentry))
++ goto out_parent;
++ au_fclr_lkup(args.flags, ALLOW_NEG);
++
++ if (au_dbwh(dentry) >= 0)
++ break;
++ if (!h_dentry)
++ continue;
++ h_inode = h_dentry->d_inode;
++ if (!h_inode)
++ continue;
++ npositive++;
++ if (!args.type)
++ args.type = h_inode->i_mode & S_IFMT;
++ if (args.type != S_IFDIR)
++ break;
++ else if (isdir) {
++ /* the type of lower may be different */
++ bdiropq = au_dbdiropq(dentry);
++ if (bdiropq >= 0 && bdiropq <= bindex)
++ break;
++ }
++ }
++
++ if (npositive) {
++ AuLabel(positive);
++ au_update_dbstart(dentry);
++ }
++ err = npositive;
++ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE)
++ && au_dbstart(dentry) < 0)) {
++ err = -EIO;
++ AuIOErr("both of real entry and whiteout found, %.*s, err %d\n",
++ AuDLNPair(dentry), err);
++ }
++
++out_parent:
++ dput(parent);
++ kfree(whname.name);
++out:
++ return err;
++}
++
++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent,
++ struct au_branch *br)
++{
++ struct dentry *dentry;
++ int wkq_err;
++
++ if (!au_test_h_perm_sio(parent->d_inode, MAY_EXEC))
++ dentry = au_lkup_one(name, parent, br, /*nd*/NULL);
++ else {
++ struct au_lkup_one_args args = {
++ .errp = &dentry,
++ .name = name,
++ .h_parent = parent,
++ .br = br,
++ .nd = NULL
++ };
++
++ wkq_err = au_wkq_wait(au_call_lkup_one, &args);
++ if (unlikely(wkq_err))
++ dentry = ERR_PTR(wkq_err);
++ }
++
++ return dentry;
++}
++
++/*
++ * lookup @dentry on @bindex which should be negative.
++ */
++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ int err;
++ struct dentry *parent, *h_parent, *h_dentry;
++
++ parent = dget_parent(dentry);
++ h_parent = au_h_dptr(parent, bindex);
++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent,
++ au_sbr(dentry->d_sb, bindex));
++ err = PTR_ERR(h_dentry);
++ if (IS_ERR(h_dentry))
++ goto out;
++ if (unlikely(h_dentry->d_inode)) {
++ err = -EIO;
++ AuIOErr("%.*s should be negative on b%d.\n",
++ AuDLNPair(h_dentry), bindex);
++ dput(h_dentry);
++ goto out;
++ }
++
++ err = 0;
++ if (bindex < au_dbstart(dentry))
++ au_set_dbstart(dentry, bindex);
++ if (au_dbend(dentry) < bindex)
++ au_set_dbend(dentry, bindex);
++ au_set_h_dptr(dentry, bindex, h_dentry);
++
++out:
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* subset of struct inode */
++struct au_iattr {
++ unsigned long i_ino;
++ /* unsigned int i_nlink; */
++ uid_t i_uid;
++ gid_t i_gid;
++ u64 i_version;
++/*
++ loff_t i_size;
++ blkcnt_t i_blocks;
++*/
++ umode_t i_mode;
++};
++
++static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode)
++{
++ ia->i_ino = h_inode->i_ino;
++ /* ia->i_nlink = h_inode->i_nlink; */
++ ia->i_uid = h_inode->i_uid;
++ ia->i_gid = h_inode->i_gid;
++ ia->i_version = h_inode->i_version;
++/*
++ ia->i_size = h_inode->i_size;
++ ia->i_blocks = h_inode->i_blocks;
++*/
++ ia->i_mode = (h_inode->i_mode & S_IFMT);
++}
++
++static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode)
++{
++ return ia->i_ino != h_inode->i_ino
++ /* || ia->i_nlink != h_inode->i_nlink */
++ || ia->i_uid != h_inode->i_uid
++ || ia->i_gid != h_inode->i_gid
++ || ia->i_version != h_inode->i_version
++/*
++ || ia->i_size != h_inode->i_size
++ || ia->i_blocks != h_inode->i_blocks
++*/
++ || ia->i_mode != (h_inode->i_mode & S_IFMT);
++}
++
++static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent,
++ struct au_branch *br)
++{
++ int err;
++ struct au_iattr ia;
++ struct inode *h_inode;
++ struct dentry *h_d;
++ struct super_block *h_sb;
++
++ err = 0;
++ memset(&ia, -1, sizeof(ia));
++ h_sb = h_dentry->d_sb;
++ h_inode = h_dentry->d_inode;
++ if (h_inode)
++ au_iattr_save(&ia, h_inode);
++ else if (au_test_nfs(h_sb) || au_test_fuse(h_sb))
++ /* nfs d_revalidate may return 0 for negative dentry */
++ /* fuse d_revalidate always return 0 for negative dentry */
++ goto out;
++
++ /* main purpose is namei.c:cached_lookup() and d_revalidate */
++ h_d = au_lkup_one(&h_dentry->d_name, h_parent, br, /*nd*/NULL);
++ err = PTR_ERR(h_d);
++ if (IS_ERR(h_d))
++ goto out;
++
++ err = 0;
++ if (unlikely(h_d != h_dentry
++ || h_d->d_inode != h_inode
++ || (h_inode && au_iattr_test(&ia, h_inode))))
++ err = au_busy_or_stale();
++ dput(h_d);
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
++ struct dentry *h_parent, struct au_branch *br)
++{
++ int err;
++
++ err = 0;
++ if (udba == AuOpt_UDBA_REVAL) {
++ IMustLock(h_dir);
++ err = (h_dentry->d_parent->d_inode != h_dir);
++ } else if (udba == AuOpt_UDBA_HNOTIFY)
++ err = au_h_verify_dentry(h_dentry, h_parent, br);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent)
++{
++ int err;
++ aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq;
++ struct au_hdentry tmp, *p, *q;
++ struct au_dinfo *dinfo;
++ struct super_block *sb;
++
++ DiMustWriteLock(dentry);
++
++ sb = dentry->d_sb;
++ dinfo = au_di(dentry);
++ bend = dinfo->di_bend;
++ bwh = dinfo->di_bwh;
++ bdiropq = dinfo->di_bdiropq;
++ p = dinfo->di_hdentry + dinfo->di_bstart;
++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) {
++ if (!p->hd_dentry)
++ continue;
++
++ new_bindex = au_br_index(sb, p->hd_id);
++ if (new_bindex == bindex)
++ continue;
++
++ if (dinfo->di_bwh == bindex)
++ bwh = new_bindex;
++ if (dinfo->di_bdiropq == bindex)
++ bdiropq = new_bindex;
++ if (new_bindex < 0) {
++ au_hdput(p);
++ p->hd_dentry = NULL;
++ continue;
++ }
++
++ /* swap two lower dentries, and loop again */
++ q = dinfo->di_hdentry + new_bindex;
++ tmp = *q;
++ *q = *p;
++ *p = tmp;
++ if (tmp.hd_dentry) {
++ bindex--;
++ p--;
++ }
++ }
++
++ dinfo->di_bwh = -1;
++ if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh))
++ dinfo->di_bwh = bwh;
++
++ dinfo->di_bdiropq = -1;
++ if (bdiropq >= 0
++ && bdiropq <= au_sbend(sb)
++ && au_sbr_whable(sb, bdiropq))
++ dinfo->di_bdiropq = bdiropq;
++
++ err = -EIO;
++ dinfo->di_bstart = -1;
++ dinfo->di_bend = -1;
++ bend = au_dbend(parent);
++ p = dinfo->di_hdentry;
++ for (bindex = 0; bindex <= bend; bindex++, p++)
++ if (p->hd_dentry) {
++ dinfo->di_bstart = bindex;
++ break;
++ }
++
++ if (dinfo->di_bstart >= 0) {
++ p = dinfo->di_hdentry + bend;
++ for (bindex = bend; bindex >= 0; bindex--, p--)
++ if (p->hd_dentry) {
++ dinfo->di_bend = bindex;
++ err = 0;
++ break;
++ }
++ }
++
++ return err;
++}
++
++static void au_do_hide(struct dentry *dentry)
++{
++ struct inode *inode;
++
++ inode = dentry->d_inode;
++ if (inode) {
++ if (!S_ISDIR(inode->i_mode)) {
++ if (inode->i_nlink && !d_unhashed(dentry))
++ drop_nlink(inode);
++ } else {
++ clear_nlink(inode);
++ /* stop next lookup */
++ inode->i_flags |= S_DEAD;
++ }
++ smp_mb(); /* necessary? */
++ }
++ d_drop(dentry);
++}
++
++static int au_hide_children(struct dentry *parent)
++{
++ int err, i, j, ndentry;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry *dentry;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_dcsub_pages(&dpages, parent, NULL, NULL);
++ if (unlikely(err))
++ goto out_dpages;
++
++ /* in reverse order */
++ for (i = dpages.ndpage - 1; i >= 0; i--) {
++ dpage = dpages.dpages + i;
++ ndentry = dpage->ndentry;
++ for (j = ndentry - 1; j >= 0; j--) {
++ dentry = dpage->dentries[j];
++ if (dentry != parent)
++ au_do_hide(dentry);
++ }
++ }
++
++out_dpages:
++ au_dpages_free(&dpages);
++out:
++ return err;
++}
++
++static void au_hide(struct dentry *dentry)
++{
++ int err;
++ struct inode *inode;
++
++ AuDbgDentry(dentry);
++ inode = dentry->d_inode;
++ if (inode && S_ISDIR(inode->i_mode)) {
++ /* shrink_dcache_parent(dentry); */
++ err = au_hide_children(dentry);
++ if (unlikely(err))
++ AuIOErr("%.*s, failed hiding children, ignored %d\n",
++ AuDLNPair(dentry), err);
++ }
++ au_do_hide(dentry);
++}
++
++/*
++ * By adding a dirty branch, a cached dentry may be affected in various ways.
++ *
++ * a dirty branch is added
++ * - on the top of layers
++ * - in the middle of layers
++ * - to the bottom of layers
++ *
++ * on the added branch there exists
++ * - a whiteout
++ * - a diropq
++ * - a same named entry
++ * + exist
++ * * negative --> positive
++ * * positive --> positive
++ * - type is unchanged
++ * - type is changed
++ * + doesn't exist
++ * * negative --> negative
++ * * positive --> negative (rejected by au_br_del() for non-dir case)
++ * - none
++ */
++static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo,
++ struct au_dinfo *tmp)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct {
++ struct dentry *dentry;
++ struct inode *inode;
++ mode_t mode;
++ } orig_h, tmp_h;
++ struct au_hdentry *hd;
++ struct inode *inode, *h_inode;
++ struct dentry *h_dentry;
++
++ err = 0;
++ AuDebugOn(dinfo->di_bstart < 0);
++ orig_h.dentry = dinfo->di_hdentry[dinfo->di_bstart].hd_dentry;
++ orig_h.inode = orig_h.dentry->d_inode;
++ orig_h.mode = 0;
++ if (orig_h.inode)
++ orig_h.mode = orig_h.inode->i_mode & S_IFMT;
++ memset(&tmp_h, 0, sizeof(tmp_h));
++ if (tmp->di_bstart >= 0) {
++ tmp_h.dentry = tmp->di_hdentry[tmp->di_bstart].hd_dentry;
++ tmp_h.inode = tmp_h.dentry->d_inode;
++ if (tmp_h.inode)
++ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT;
++ }
++
++ inode = dentry->d_inode;
++ if (!orig_h.inode) {
++ AuDbg("nagative originally\n");
++ if (inode) {
++ au_hide(dentry);
++ goto out;
++ }
++ AuDebugOn(inode);
++ AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
++ AuDebugOn(dinfo->di_bdiropq != -1);
++
++ if (!tmp_h.inode) {
++ AuDbg("negative --> negative\n");
++ /* should have only one negative lower */
++ if (tmp->di_bstart >= 0
++ && tmp->di_bstart < dinfo->di_bstart) {
++ AuDebugOn(tmp->di_bstart != tmp->di_bend);
++ AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
++ au_set_h_dptr(dentry, dinfo->di_bstart, NULL);
++ au_di_cp(dinfo, tmp);
++ hd = tmp->di_hdentry + tmp->di_bstart;
++ au_set_h_dptr(dentry, tmp->di_bstart,
++ dget(hd->hd_dentry));
++ }
++ au_dbg_verify_dinode(dentry);
++ } else {
++ AuDbg("negative --> positive\n");
++ /*
++ * similar to the behaviour of creating with bypassing
++ * aufs.
++ * unhash it in order to force an error in the
++ * succeeding create operation.
++ * we should not set S_DEAD here.
++ */
++ d_drop(dentry);
++ /* au_di_swap(tmp, dinfo); */
++ au_dbg_verify_dinode(dentry);
++ }
++ } else {
++ AuDbg("positive originally\n");
++ /* inode may be NULL */
++ AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode);
++ if (!tmp_h.inode) {
++ AuDbg("positive --> negative\n");
++ /* or bypassing aufs */
++ au_hide(dentry);
++ if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_bstart)
++ dinfo->di_bwh = tmp->di_bwh;
++ if (inode)
++ err = au_refresh_hinode_self(inode);
++ au_dbg_verify_dinode(dentry);
++ } else if (orig_h.mode == tmp_h.mode) {
++ AuDbg("positive --> positive, same type\n");
++ if (!S_ISDIR(orig_h.mode)
++ && dinfo->di_bstart > tmp->di_bstart) {
++ /*
++ * similar to the behaviour of removing and
++ * creating.
++ */
++ au_hide(dentry);
++ if (inode)
++ err = au_refresh_hinode_self(inode);
++ au_dbg_verify_dinode(dentry);
++ } else {
++ /* fill empty slots */
++ if (dinfo->di_bstart > tmp->di_bstart)
++ dinfo->di_bstart = tmp->di_bstart;
++ if (dinfo->di_bend < tmp->di_bend)
++ dinfo->di_bend = tmp->di_bend;
++ dinfo->di_bwh = tmp->di_bwh;
++ dinfo->di_bdiropq = tmp->di_bdiropq;
++ hd = tmp->di_hdentry;
++ bend = dinfo->di_bend;
++ for (bindex = tmp->di_bstart; bindex <= bend;
++ bindex++) {
++ if (au_h_dptr(dentry, bindex))
++ continue;
++ h_dentry = hd[bindex].hd_dentry;
++ if (!h_dentry)
++ continue;
++ h_inode = h_dentry->d_inode;
++ AuDebugOn(!h_inode);
++ AuDebugOn(orig_h.mode
++ != (h_inode->i_mode
++ & S_IFMT));
++ au_set_h_dptr(dentry, bindex,
++ dget(h_dentry));
++ }
++ err = au_refresh_hinode(inode, dentry);
++ au_dbg_verify_dinode(dentry);
++ }
++ } else {
++ AuDbg("positive --> positive, different type\n");
++ /* similar to the behaviour of removing and creating */
++ au_hide(dentry);
++ if (inode)
++ err = au_refresh_hinode_self(inode);
++ au_dbg_verify_dinode(dentry);
++ }
++ }
++
++out:
++ return err;
++}
++
++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent)
++{
++ int err, ebrange;
++ unsigned int sigen;
++ struct au_dinfo *dinfo, *tmp;
++ struct super_block *sb;
++ struct inode *inode;
++
++ DiMustWriteLock(dentry);
++ AuDebugOn(IS_ROOT(dentry));
++ AuDebugOn(!parent->d_inode);
++
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ sigen = au_sigen(sb);
++ err = au_digen_test(parent, sigen);
++ if (unlikely(err))
++ goto out;
++
++ dinfo = au_di(dentry);
++ err = au_di_realloc(dinfo, au_sbend(sb) + 1);
++ if (unlikely(err))
++ goto out;
++ ebrange = au_dbrange_test(dentry);
++ if (!ebrange)
++ ebrange = au_do_refresh_hdentry(dentry, parent);
++
++ if (d_unhashed(dentry) || ebrange) {
++ AuDebugOn(au_dbstart(dentry) < 0 && au_dbend(dentry) >= 0);
++ if (inode)
++ err = au_refresh_hinode_self(inode);
++ au_dbg_verify_dinode(dentry);
++ if (!err)
++ goto out_dgen; /* success */
++ goto out;
++ }
++
++ /* temporary dinfo */
++ AuDbgDentry(dentry);
++ err = -ENOMEM;
++ tmp = au_di_alloc(sb, AuLsc_DI_TMP);
++ if (unlikely(!tmp))
++ goto out;
++ au_di_swap(tmp, dinfo);
++ /* returns the number of positive dentries */
++ /*
++ * if current working dir is removed, it returns an error.
++ * but the dentry is legal.
++ */
++ err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0, /*nd*/NULL);
++ AuDbgDentry(dentry);
++ au_di_swap(tmp, dinfo);
++ if (err == -ENOENT)
++ err = 0;
++ if (err >= 0) {
++ /* compare/refresh by dinfo */
++ AuDbgDentry(dentry);
++ err = au_refresh_by_dinfo(dentry, dinfo, tmp);
++ au_dbg_verify_dinode(dentry);
++ AuTraceErr(err);
++ }
++ au_rw_write_unlock(&tmp->di_rwsem);
++ au_di_free(tmp);
++ if (unlikely(err))
++ goto out;
++
++out_dgen:
++ au_update_digen(dentry);
++out:
++ if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) {
++ AuIOErr("failed refreshing %.*s, %d\n",
++ AuDLNPair(dentry), err);
++ AuDbgDentry(dentry);
++ }
++ AuTraceErr(err);
++ return err;
++}
++
++static noinline_for_stack
++int au_do_h_d_reval(struct dentry *h_dentry, struct nameidata *nd,
++ struct dentry *dentry, aufs_bindex_t bindex)
++{
++ int err, valid;
++ int (*reval)(struct dentry *, struct nameidata *);
++
++ err = 0;
++ reval = NULL;
++ if (h_dentry->d_op)
++ reval = h_dentry->d_op->d_revalidate;
++ if (!reval)
++ goto out;
++
++ AuDbg("b%d\n", bindex);
++ if (au_test_fs_null_nd(h_dentry->d_sb))
++ /* it may return tri-state */
++ valid = reval(h_dentry, NULL);
++ else {
++ struct nameidata h_nd;
++ int locked;
++ struct dentry *parent;
++
++ au_h_nd(&h_nd, nd);
++ parent = nd->path.dentry;
++ locked = (nd && nd->path.dentry != dentry);
++ if (locked)
++ di_read_lock_parent(parent, AuLock_IR);
++ BUG_ON(bindex > au_dbend(parent));
++ h_nd.path.dentry = au_h_dptr(parent, bindex);
++ BUG_ON(!h_nd.path.dentry);
++ h_nd.path.mnt = au_sbr(parent->d_sb, bindex)->br_mnt;
++ path_get(&h_nd.path);
++ valid = reval(h_dentry, &h_nd);
++ path_put(&h_nd.path);
++ if (locked)
++ di_read_unlock(parent, AuLock_IR);
++ }
++
++ if (unlikely(valid < 0))
++ err = valid;
++ else if (!valid)
++ err = -EINVAL;
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++/* todo: remove this */
++static int h_d_revalidate(struct dentry *dentry, struct inode *inode,
++ struct nameidata *nd, int do_udba)
++{
++ int err;
++ umode_t mode, h_mode;
++ aufs_bindex_t bindex, btail, bstart, ibs, ibe;
++ unsigned char plus, unhashed, is_root, h_plus;
++ struct inode *h_inode, *h_cached_inode;
++ struct dentry *h_dentry;
++ struct qstr *name, *h_name;
++
++ err = 0;
++ plus = 0;
++ mode = 0;
++ ibs = -1;
++ ibe = -1;
++ unhashed = !!d_unhashed(dentry);
++ is_root = !!IS_ROOT(dentry);
++ name = &dentry->d_name;
++
++ /*
++ * Theoretically, REVAL test should be unnecessary in case of
++ * {FS,I}NOTIFY.
++ * But {fs,i}notify doesn't fire some necessary events,
++ * IN_ATTRIB for atime/nlink/pageio
++ * IN_DELETE for NFS dentry
++ * Let's do REVAL test too.
++ */
++ if (do_udba && inode) {
++ mode = (inode->i_mode & S_IFMT);
++ plus = (inode->i_nlink > 0);
++ ibs = au_ibstart(inode);
++ ibe = au_ibend(inode);
++ }
++
++ bstart = au_dbstart(dentry);
++ btail = bstart;
++ if (inode && S_ISDIR(inode->i_mode))
++ btail = au_dbtaildir(dentry);
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++
++ AuDbg("b%d, %.*s\n", bindex, AuDLNPair(h_dentry));
++ h_name = &h_dentry->d_name;
++ if (unlikely(do_udba
++ && !is_root
++ && (unhashed != !!d_unhashed(h_dentry)
++ || name->len != h_name->len
++ || memcmp(name->name, h_name->name, name->len))
++ )) {
++ AuDbg("unhash 0x%x 0x%x, %.*s %.*s\n",
++ unhashed, d_unhashed(h_dentry),
++ AuDLNPair(dentry), AuDLNPair(h_dentry));
++ goto err;
++ }
++
++ err = au_do_h_d_reval(h_dentry, nd, dentry, bindex);
++ if (unlikely(err))
++ /* do not goto err, to keep the errno */
++ break;
++
++ /* todo: plink too? */
++ if (!do_udba)
++ continue;
++
++ /* UDBA tests */
++ h_inode = h_dentry->d_inode;
++ if (unlikely(!!inode != !!h_inode))
++ goto err;
++
++ h_plus = plus;
++ h_mode = mode;
++ h_cached_inode = h_inode;
++ if (h_inode) {
++ h_mode = (h_inode->i_mode & S_IFMT);
++ h_plus = (h_inode->i_nlink > 0);
++ }
++ if (inode && ibs <= bindex && bindex <= ibe)
++ h_cached_inode = au_h_iptr(inode, bindex);
++
++ if (unlikely(plus != h_plus
++ || mode != h_mode
++ || h_cached_inode != h_inode))
++ goto err;
++ continue;
++
++ err:
++ err = -EINVAL;
++ break;
++ }
++
++ return err;
++}
++
++/* todo: consolidate with do_refresh() and au_reval_for_attr() */
++static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen)
++{
++ int err;
++ struct dentry *parent;
++
++ if (!au_digen_test(dentry, sigen))
++ return 0;
++
++ parent = dget_parent(dentry);
++ di_read_lock_parent(parent, AuLock_IR);
++ AuDebugOn(au_digen_test(parent, sigen));
++ au_dbg_verify_gen(parent, sigen);
++ err = au_refresh_dentry(dentry, parent);
++ di_read_unlock(parent, AuLock_IR);
++ dput(parent);
++ AuTraceErr(err);
++ return err;
++}
++
++int au_reval_dpath(struct dentry *dentry, unsigned int sigen)
++{
++ int err;
++ struct dentry *d, *parent;
++ struct inode *inode;
++
++ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR))
++ return simple_reval_dpath(dentry, sigen);
++
++ /* slow loop, keep it simple and stupid */
++ /* cf: au_cpup_dirs() */
++ err = 0;
++ parent = NULL;
++ while (au_digen_test(dentry, sigen)) {
++ d = dentry;
++ while (1) {
++ dput(parent);
++ parent = dget_parent(d);
++ if (!au_digen_test(parent, sigen))
++ break;
++ d = parent;
++ }
++
++ inode = d->d_inode;
++ if (d != dentry)
++ di_write_lock_child2(d);
++
++ /* someone might update our dentry while we were sleeping */
++ if (au_digen_test(d, sigen)) {
++ /*
++ * todo: consolidate with simple_reval_dpath(),
++ * do_refresh() and au_reval_for_attr().
++ */
++ di_read_lock_parent(parent, AuLock_IR);
++ err = au_refresh_dentry(d, parent);
++ di_read_unlock(parent, AuLock_IR);
++ }
++
++ if (d != dentry)
++ di_write_unlock(d);
++ dput(parent);
++ if (unlikely(err))
++ break;
++ }
++
++ return err;
++}
++
++/*
++ * if valid returns 1, otherwise 0.
++ */
++static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
++{
++ int valid, err;
++ unsigned int sigen;
++ unsigned char do_udba;
++ struct super_block *sb;
++ struct inode *inode;
++
++ valid = 0;
++ if (unlikely(!au_di(dentry)))
++ goto out;
++
++ valid = 1;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ /*
++ * todo: very ugly
++ * i_mutex of parent dir may be held,
++ * but we should not return 'invalid' due to busy.
++ */
++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM);
++ if (unlikely(err)) {
++ valid = err;
++ AuTraceErr(err);
++ goto out;
++ }
++ if (unlikely(au_dbrange_test(dentry))) {
++ err = -EINVAL;
++ AuTraceErr(err);
++ goto out_dgrade;
++ }
++
++ sigen = au_sigen(sb);
++ if (au_digen_test(dentry, sigen)) {
++ AuDebugOn(IS_ROOT(dentry));
++ err = au_reval_dpath(dentry, sigen);
++ if (unlikely(err)) {
++ AuTraceErr(err);
++ goto out_dgrade;
++ }
++ }
++ di_downgrade_lock(dentry, AuLock_IR);
++
++ err = -EINVAL;
++ if (inode && (IS_DEADDIR(inode) || !inode->i_nlink))
++ goto out_inval;
++
++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE);
++ if (do_udba && inode) {
++ aufs_bindex_t bstart = au_ibstart(inode);
++ struct inode *h_inode;
++
++ if (bstart >= 0) {
++ h_inode = au_h_iptr(inode, bstart);
++ if (h_inode && au_test_higen(inode, h_inode))
++ goto out_inval;
++ }
++ }
++
++ err = h_d_revalidate(dentry, inode, nd, do_udba);
++ if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) {
++ err = -EIO;
++ AuDbg("both of real entry and whiteout found, %.*s, err %d\n",
++ AuDLNPair(dentry), err);
++ }
++ goto out_inval;
++
++out_dgrade:
++ di_downgrade_lock(dentry, AuLock_IR);
++out_inval:
++ aufs_read_unlock(dentry, AuLock_IR);
++ AuTraceErr(err);
++ valid = !err;
++out:
++ if (!valid) {
++ AuDbg("%.*s invalid, %d\n", AuDLNPair(dentry), valid);
++ d_drop(dentry);
++ }
++ return valid;
++}
++
++static void aufs_d_release(struct dentry *dentry)
++{
++ if (au_di(dentry)) {
++ au_di_fin(dentry);
++ au_hn_di_reinit(dentry);
++ }
++}
++
++const struct dentry_operations aufs_dop = {
++ .d_revalidate = aufs_d_revalidate,
++ .d_release = aufs_d_release
++};
+diff -Nur linux-2.6.37.orig/fs/aufs/dentry.h linux-2.6.37/fs/aufs/dentry.h
+--- linux-2.6.37.orig/fs/aufs/dentry.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/dentry.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,237 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * lookup and dentry operations
++ */
++
++#ifndef __AUFS_DENTRY_H__
++#define __AUFS_DENTRY_H__
++
++#ifdef __KERNEL__
++
++#include <linux/dcache.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++
++struct au_hdentry {
++ struct dentry *hd_dentry;
++ aufs_bindex_t hd_id;
++};
++
++struct au_dinfo {
++ atomic_t di_generation;
++
++ struct au_rwsem di_rwsem;
++ aufs_bindex_t di_bstart, di_bend, di_bwh, di_bdiropq;
++ struct au_hdentry *di_hdentry;
++} ____cacheline_aligned_in_smp;
++
++/* ---------------------------------------------------------------------- */
++
++/* dentry.c */
++extern const struct dentry_operations aufs_dop;
++struct au_branch;
++struct dentry *au_lkup_one(struct qstr *name, struct dentry *h_parent,
++ struct au_branch *br, struct nameidata *nd);
++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent,
++ struct au_branch *br);
++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
++ struct dentry *h_parent, struct au_branch *br);
++
++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type,
++ struct nameidata *nd);
++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex);
++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent);
++int au_reval_dpath(struct dentry *dentry, unsigned int sigen);
++
++/* dinfo.c */
++void au_di_init_once(void *_di);
++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc);
++void au_di_free(struct au_dinfo *dinfo);
++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b);
++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src);
++int au_di_init(struct dentry *dentry);
++void au_di_fin(struct dentry *dentry);
++int au_di_realloc(struct au_dinfo *dinfo, int nbr);
++
++void di_read_lock(struct dentry *d, int flags, unsigned int lsc);
++void di_read_unlock(struct dentry *d, int flags);
++void di_downgrade_lock(struct dentry *d, int flags);
++void di_write_lock(struct dentry *d, unsigned int lsc);
++void di_write_unlock(struct dentry *d);
++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir);
++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir);
++void di_write_unlock2(struct dentry *d1, struct dentry *d2);
++
++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex);
++aufs_bindex_t au_dbtail(struct dentry *dentry);
++aufs_bindex_t au_dbtaildir(struct dentry *dentry);
++
++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_dentry);
++int au_digen_test(struct dentry *dentry, unsigned int sigen);
++int au_dbrange_test(struct dentry *dentry);
++void au_update_digen(struct dentry *dentry);
++void au_update_dbrange(struct dentry *dentry, int do_put_zero);
++void au_update_dbstart(struct dentry *dentry);
++void au_update_dbend(struct dentry *dentry);
++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry);
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_dinfo *au_di(struct dentry *dentry)
++{
++ return dentry->d_fsdata;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* lock subclass for dinfo */
++enum {
++ AuLsc_DI_CHILD, /* child first */
++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */
++ AuLsc_DI_CHILD3, /* copyup dirs */
++ AuLsc_DI_PARENT,
++ AuLsc_DI_PARENT2,
++ AuLsc_DI_PARENT3,
++ AuLsc_DI_TMP /* temp for replacing dinfo */
++};
++
++/*
++ * di_read_lock_child, di_write_lock_child,
++ * di_read_lock_child2, di_write_lock_child2,
++ * di_read_lock_child3, di_write_lock_child3,
++ * di_read_lock_parent, di_write_lock_parent,
++ * di_read_lock_parent2, di_write_lock_parent2,
++ * di_read_lock_parent3, di_write_lock_parent3,
++ */
++#define AuReadLockFunc(name, lsc) \
++static inline void di_read_lock_##name(struct dentry *d, int flags) \
++{ di_read_lock(d, flags, AuLsc_DI_##lsc); }
++
++#define AuWriteLockFunc(name, lsc) \
++static inline void di_write_lock_##name(struct dentry *d) \
++{ di_write_lock(d, AuLsc_DI_##lsc); }
++
++#define AuRWLockFuncs(name, lsc) \
++ AuReadLockFunc(name, lsc) \
++ AuWriteLockFunc(name, lsc)
++
++AuRWLockFuncs(child, CHILD);
++AuRWLockFuncs(child2, CHILD2);
++AuRWLockFuncs(child3, CHILD3);
++AuRWLockFuncs(parent, PARENT);
++AuRWLockFuncs(parent2, PARENT2);
++AuRWLockFuncs(parent3, PARENT3);
++
++#undef AuReadLockFunc
++#undef AuWriteLockFunc
++#undef AuRWLockFuncs
++
++#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem)
++#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem)
++#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem)
++
++/* ---------------------------------------------------------------------- */
++
++/* todo: memory barrier? */
++static inline unsigned int au_digen(struct dentry *d)
++{
++ return atomic_read(&au_di(d)->di_generation);
++}
++
++static inline void au_h_dentry_init(struct au_hdentry *hdentry)
++{
++ hdentry->hd_dentry = NULL;
++}
++
++static inline void au_hdput(struct au_hdentry *hd)
++{
++ if (hd)
++ dput(hd->hd_dentry);
++}
++
++static inline aufs_bindex_t au_dbstart(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bstart;
++}
++
++static inline aufs_bindex_t au_dbend(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bend;
++}
++
++static inline aufs_bindex_t au_dbwh(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bwh;
++}
++
++static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bdiropq;
++}
++
++/* todo: hard/soft set? */
++static inline void au_set_dbstart(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ au_di(dentry)->di_bstart = bindex;
++}
++
++static inline void au_set_dbend(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ au_di(dentry)->di_bend = bindex;
++}
++
++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ /* dbwh can be outside of bstart - bend range */
++ au_di(dentry)->di_bwh = bindex;
++}
++
++static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ au_di(dentry)->di_bdiropq = bindex;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_HNOTIFY
++static inline void au_digen_dec(struct dentry *d)
++{
++ atomic_dec(&au_di(d)->di_generation);
++}
++
++static inline void au_hn_di_reinit(struct dentry *dentry)
++{
++ dentry->d_fsdata = NULL;
++}
++#else
++AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused)
++#endif /* CONFIG_AUFS_HNOTIFY */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DENTRY_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/dinfo.c linux-2.6.37/fs/aufs/dinfo.c
+--- linux-2.6.37.orig/fs/aufs/dinfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/dinfo.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,494 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * dentry private data
++ */
++
++#include "aufs.h"
++
++void au_di_init_once(void *_dinfo)
++{
++ struct au_dinfo *dinfo = _dinfo;
++ static struct lock_class_key aufs_di;
++
++ au_rw_init(&dinfo->di_rwsem);
++ au_rw_class(&dinfo->di_rwsem, &aufs_di);
++}
++
++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc)
++{
++ struct au_dinfo *dinfo;
++ int nbr, i;
++
++ dinfo = au_cache_alloc_dinfo();
++ if (unlikely(!dinfo))
++ goto out;
++
++ nbr = au_sbend(sb) + 1;
++ if (nbr <= 0)
++ nbr = 1;
++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS);
++ if (dinfo->di_hdentry) {
++ au_rw_write_lock_nested(&dinfo->di_rwsem, lsc);
++ dinfo->di_bstart = -1;
++ dinfo->di_bend = -1;
++ dinfo->di_bwh = -1;
++ dinfo->di_bdiropq = -1;
++ for (i = 0; i < nbr; i++)
++ dinfo->di_hdentry[i].hd_id = -1;
++ goto out;
++ }
++
++ au_cache_free_dinfo(dinfo);
++ dinfo = NULL;
++
++out:
++ return dinfo;
++}
++
++void au_di_free(struct au_dinfo *dinfo)
++{
++ struct au_hdentry *p;
++ aufs_bindex_t bend, bindex;
++
++ /* dentry may not be revalidated */
++ bindex = dinfo->di_bstart;
++ if (bindex >= 0) {
++ bend = dinfo->di_bend;
++ p = dinfo->di_hdentry + bindex;
++ while (bindex++ <= bend)
++ au_hdput(p++);
++ }
++ kfree(dinfo->di_hdentry);
++ au_cache_free_dinfo(dinfo);
++}
++
++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b)
++{
++ struct au_hdentry *p;
++ aufs_bindex_t bi;
++
++ AuRwMustWriteLock(&a->di_rwsem);
++ AuRwMustWriteLock(&b->di_rwsem);
++
++#define DiSwap(v, name) \
++ do { \
++ v = a->di_##name; \
++ a->di_##name = b->di_##name; \
++ b->di_##name = v; \
++ } while (0)
++
++ DiSwap(p, hdentry);
++ DiSwap(bi, bstart);
++ DiSwap(bi, bend);
++ DiSwap(bi, bwh);
++ DiSwap(bi, bdiropq);
++ /* smp_mb(); */
++
++#undef DiSwap
++}
++
++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src)
++{
++ AuRwMustWriteLock(&dst->di_rwsem);
++ AuRwMustWriteLock(&src->di_rwsem);
++
++ dst->di_bstart = src->di_bstart;
++ dst->di_bend = src->di_bend;
++ dst->di_bwh = src->di_bwh;
++ dst->di_bdiropq = src->di_bdiropq;
++ /* smp_mb(); */
++}
++
++int au_di_init(struct dentry *dentry)
++{
++ int err;
++ struct super_block *sb;
++ struct au_dinfo *dinfo;
++
++ err = 0;
++ sb = dentry->d_sb;
++ dinfo = au_di_alloc(sb, AuLsc_DI_CHILD);
++ if (dinfo) {
++ atomic_set(&dinfo->di_generation, au_sigen(sb));
++ /* smp_mb(); */ /* atomic_set */
++ dentry->d_op = &aufs_dop;
++ dentry->d_fsdata = dinfo;
++ } else
++ err = -ENOMEM;
++
++ return err;
++}
++
++void au_di_fin(struct dentry *dentry)
++{
++ struct au_dinfo *dinfo;
++
++ dinfo = au_di(dentry);
++ AuRwDestroy(&dinfo->di_rwsem);
++ au_di_free(dinfo);
++}
++
++int au_di_realloc(struct au_dinfo *dinfo, int nbr)
++{
++ int err, sz;
++ struct au_hdentry *hdp;
++
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ err = -ENOMEM;
++ sz = sizeof(*hdp) * (dinfo->di_bend + 1);
++ if (!sz)
++ sz = sizeof(*hdp);
++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS);
++ if (hdp) {
++ dinfo->di_hdentry = hdp;
++ err = 0;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void do_ii_write_lock(struct inode *inode, unsigned int lsc)
++{
++ switch (lsc) {
++ case AuLsc_DI_CHILD:
++ ii_write_lock_child(inode);
++ break;
++ case AuLsc_DI_CHILD2:
++ ii_write_lock_child2(inode);
++ break;
++ case AuLsc_DI_CHILD3:
++ ii_write_lock_child3(inode);
++ break;
++ case AuLsc_DI_PARENT:
++ ii_write_lock_parent(inode);
++ break;
++ case AuLsc_DI_PARENT2:
++ ii_write_lock_parent2(inode);
++ break;
++ case AuLsc_DI_PARENT3:
++ ii_write_lock_parent3(inode);
++ break;
++ default:
++ BUG();
++ }
++}
++
++static void do_ii_read_lock(struct inode *inode, unsigned int lsc)
++{
++ switch (lsc) {
++ case AuLsc_DI_CHILD:
++ ii_read_lock_child(inode);
++ break;
++ case AuLsc_DI_CHILD2:
++ ii_read_lock_child2(inode);
++ break;
++ case AuLsc_DI_CHILD3:
++ ii_read_lock_child3(inode);
++ break;
++ case AuLsc_DI_PARENT:
++ ii_read_lock_parent(inode);
++ break;
++ case AuLsc_DI_PARENT2:
++ ii_read_lock_parent2(inode);
++ break;
++ case AuLsc_DI_PARENT3:
++ ii_read_lock_parent3(inode);
++ break;
++ default:
++ BUG();
++ }
++}
++
++void di_read_lock(struct dentry *d, int flags, unsigned int lsc)
++{
++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc);
++ if (d->d_inode) {
++ if (au_ftest_lock(flags, IW))
++ do_ii_write_lock(d->d_inode, lsc);
++ else if (au_ftest_lock(flags, IR))
++ do_ii_read_lock(d->d_inode, lsc);
++ }
++}
++
++void di_read_unlock(struct dentry *d, int flags)
++{
++ if (d->d_inode) {
++ if (au_ftest_lock(flags, IW)) {
++ au_dbg_verify_dinode(d);
++ ii_write_unlock(d->d_inode);
++ } else if (au_ftest_lock(flags, IR)) {
++ au_dbg_verify_dinode(d);
++ ii_read_unlock(d->d_inode);
++ }
++ }
++ au_rw_read_unlock(&au_di(d)->di_rwsem);
++}
++
++void di_downgrade_lock(struct dentry *d, int flags)
++{
++ if (d->d_inode && au_ftest_lock(flags, IR))
++ ii_downgrade_lock(d->d_inode);
++ au_rw_dgrade_lock(&au_di(d)->di_rwsem);
++}
++
++void di_write_lock(struct dentry *d, unsigned int lsc)
++{
++ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc);
++ if (d->d_inode)
++ do_ii_write_lock(d->d_inode, lsc);
++}
++
++void di_write_unlock(struct dentry *d)
++{
++ au_dbg_verify_dinode(d);
++ if (d->d_inode)
++ ii_write_unlock(d->d_inode);
++ au_rw_write_unlock(&au_di(d)->di_rwsem);
++}
++
++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir)
++{
++ AuDebugOn(d1 == d2
++ || d1->d_inode == d2->d_inode
++ || d1->d_sb != d2->d_sb);
++
++ if (isdir && au_test_subdir(d1, d2)) {
++ di_write_lock_child(d1);
++ di_write_lock_child2(d2);
++ } else {
++ /* there should be no races */
++ di_write_lock_child(d2);
++ di_write_lock_child2(d1);
++ }
++}
++
++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir)
++{
++ AuDebugOn(d1 == d2
++ || d1->d_inode == d2->d_inode
++ || d1->d_sb != d2->d_sb);
++
++ if (isdir && au_test_subdir(d1, d2)) {
++ di_write_lock_parent(d1);
++ di_write_lock_parent2(d2);
++ } else {
++ /* there should be no races */
++ di_write_lock_parent(d2);
++ di_write_lock_parent2(d1);
++ }
++}
++
++void di_write_unlock2(struct dentry *d1, struct dentry *d2)
++{
++ di_write_unlock(d1);
++ if (d1->d_inode == d2->d_inode)
++ au_rw_write_unlock(&au_di(d2)->di_rwsem);
++ else
++ di_write_unlock(d2);
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ struct dentry *d;
++
++ DiMustAnyLock(dentry);
++
++ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry))
++ return NULL;
++ AuDebugOn(bindex < 0);
++ d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry;
++ AuDebugOn(d && (atomic_read(&d->d_count) <= 0));
++ return d;
++}
++
++aufs_bindex_t au_dbtail(struct dentry *dentry)
++{
++ aufs_bindex_t bend, bwh;
++
++ bend = au_dbend(dentry);
++ if (0 <= bend) {
++ bwh = au_dbwh(dentry);
++ if (!bwh)
++ return bwh;
++ if (0 < bwh && bwh < bend)
++ return bwh - 1;
++ }
++ return bend;
++}
++
++aufs_bindex_t au_dbtaildir(struct dentry *dentry)
++{
++ aufs_bindex_t bend, bopq;
++
++ bend = au_dbtail(dentry);
++ if (0 <= bend) {
++ bopq = au_dbdiropq(dentry);
++ if (0 <= bopq && bopq < bend)
++ bend = bopq;
++ }
++ return bend;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_dentry)
++{
++ struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex;
++ struct au_branch *br;
++
++ DiMustWriteLock(dentry);
++
++ au_hdput(hd);
++ hd->hd_dentry = h_dentry;
++ if (h_dentry) {
++ br = au_sbr(dentry->d_sb, bindex);
++ hd->hd_id = br->br_id;
++ }
++}
++
++int au_dbrange_test(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bstart, bend;
++
++ err = 0;
++ bstart = au_dbstart(dentry);
++ bend = au_dbend(dentry);
++ if (bstart >= 0)
++ AuDebugOn(bend < 0 && bstart > bend);
++ else {
++ err = -EIO;
++ AuDebugOn(bend >= 0);
++ }
++
++ return err;
++}
++
++int au_digen_test(struct dentry *dentry, unsigned int sigen)
++{
++ int err;
++
++ err = 0;
++ if (unlikely(au_digen(dentry) != sigen
++ || au_iigen_test(dentry->d_inode, sigen)))
++ err = -EIO;
++
++ return err;
++}
++
++void au_update_digen(struct dentry *dentry)
++{
++ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb));
++ /* smp_mb(); */ /* atomic_set */
++}
++
++void au_update_dbrange(struct dentry *dentry, int do_put_zero)
++{
++ struct au_dinfo *dinfo;
++ struct dentry *h_d;
++ struct au_hdentry *hdp;
++
++ DiMustWriteLock(dentry);
++
++ dinfo = au_di(dentry);
++ if (!dinfo || dinfo->di_bstart < 0)
++ return;
++
++ hdp = dinfo->di_hdentry;
++ if (do_put_zero) {
++ aufs_bindex_t bindex, bend;
++
++ bend = dinfo->di_bend;
++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++) {
++ h_d = hdp[0 + bindex].hd_dentry;
++ if (h_d && !h_d->d_inode)
++ au_set_h_dptr(dentry, bindex, NULL);
++ }
++ }
++
++ dinfo->di_bstart = -1;
++ while (++dinfo->di_bstart <= dinfo->di_bend)
++ if (hdp[0 + dinfo->di_bstart].hd_dentry)
++ break;
++ if (dinfo->di_bstart > dinfo->di_bend) {
++ dinfo->di_bstart = -1;
++ dinfo->di_bend = -1;
++ return;
++ }
++
++ dinfo->di_bend++;
++ while (0 <= --dinfo->di_bend)
++ if (hdp[0 + dinfo->di_bend].hd_dentry)
++ break;
++ AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0);
++}
++
++void au_update_dbstart(struct dentry *dentry)
++{
++ aufs_bindex_t bindex, bend;
++ struct dentry *h_dentry;
++
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++ if (h_dentry->d_inode) {
++ au_set_dbstart(dentry, bindex);
++ return;
++ }
++ au_set_h_dptr(dentry, bindex, NULL);
++ }
++}
++
++void au_update_dbend(struct dentry *dentry)
++{
++ aufs_bindex_t bindex, bstart;
++ struct dentry *h_dentry;
++
++ bstart = au_dbstart(dentry);
++ for (bindex = au_dbend(dentry); bindex >= bstart; bindex--) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++ if (h_dentry->d_inode) {
++ au_set_dbend(dentry, bindex);
++ return;
++ }
++ au_set_h_dptr(dentry, bindex, NULL);
++ }
++}
++
++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry)
++{
++ aufs_bindex_t bindex, bend;
++
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++)
++ if (au_h_dptr(dentry, bindex) == h_dentry)
++ return bindex;
++ return -1;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/dir.c linux-2.6.37/fs/aufs/dir.c
+--- linux-2.6.37.orig/fs/aufs/dir.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/dir.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,648 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * directory operations
++ */
++
++#include <linux/file.h>
++#include <linux/fs_stack.h>
++#include "aufs.h"
++
++void au_add_nlink(struct inode *dir, struct inode *h_dir)
++{
++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode));
++
++ dir->i_nlink += h_dir->i_nlink - 2;
++ if (h_dir->i_nlink < 2)
++ dir->i_nlink += 2;
++}
++
++void au_sub_nlink(struct inode *dir, struct inode *h_dir)
++{
++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode));
++
++ dir->i_nlink -= h_dir->i_nlink - 2;
++ if (h_dir->i_nlink < 2)
++ dir->i_nlink -= 2;
++}
++
++loff_t au_dir_size(struct file *file, struct dentry *dentry)
++{
++ loff_t sz;
++ aufs_bindex_t bindex, bend;
++ struct file *h_file;
++ struct dentry *h_dentry;
++
++ sz = 0;
++ if (file) {
++ AuDebugOn(!file->f_dentry);
++ AuDebugOn(!file->f_dentry->d_inode);
++ AuDebugOn(!S_ISDIR(file->f_dentry->d_inode->i_mode));
++
++ bend = au_fbend_dir(file);
++ for (bindex = au_fbstart(file);
++ bindex <= bend && sz < KMALLOC_MAX_SIZE;
++ bindex++) {
++ h_file = au_hf_dir(file, bindex);
++ if (h_file
++ && h_file->f_dentry
++ && h_file->f_dentry->d_inode)
++ sz += i_size_read(h_file->f_dentry->d_inode);
++ }
++ } else {
++ AuDebugOn(!dentry);
++ AuDebugOn(!dentry->d_inode);
++ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode));
++
++ bend = au_dbtaildir(dentry);
++ for (bindex = au_dbstart(dentry);
++ bindex <= bend && sz < KMALLOC_MAX_SIZE;
++ bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry && h_dentry->d_inode)
++ sz += i_size_read(h_dentry->d_inode);
++ }
++ }
++ if (sz < KMALLOC_MAX_SIZE)
++ sz = roundup_pow_of_two(sz);
++ if (sz > KMALLOC_MAX_SIZE)
++ sz = KMALLOC_MAX_SIZE;
++ else if (sz < NAME_MAX) {
++ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX);
++ sz = AUFS_RDBLK_DEF;
++ }
++ return sz;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int reopen_dir(struct file *file)
++{
++ int err;
++ unsigned int flags;
++ aufs_bindex_t bindex, btail, bstart;
++ struct dentry *dentry, *h_dentry;
++ struct file *h_file;
++
++ /* open all lower dirs */
++ dentry = file->f_dentry;
++ bstart = au_dbstart(dentry);
++ for (bindex = au_fbstart(file); bindex < bstart; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++ au_set_fbstart(file, bstart);
++
++ btail = au_dbtaildir(dentry);
++ for (bindex = au_fbend_dir(file); btail < bindex; bindex--)
++ au_set_h_fptr(file, bindex, NULL);
++ au_set_fbend_dir(file, btail);
++
++ flags = vfsub_file_flags(file);
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++ h_file = au_hf_dir(file, bindex);
++ if (h_file)
++ continue;
++
++ h_file = au_h_open(dentry, bindex, flags, file);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out; /* close all? */
++ au_set_h_fptr(file, bindex, h_file);
++ }
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ err = 0;
++
++out:
++ return err;
++}
++
++static int do_open_dir(struct file *file, int flags)
++{
++ int err;
++ aufs_bindex_t bindex, btail;
++ struct dentry *dentry, *h_dentry;
++ struct file *h_file;
++
++ FiMustWriteLock(file);
++
++ dentry = file->f_dentry;
++ err = au_alive_dir(dentry);
++ if (unlikely(err))
++ goto out;
++
++ file->f_version = dentry->d_inode->i_version;
++ bindex = au_dbstart(dentry);
++ au_set_fbstart(file, bindex);
++ btail = au_dbtaildir(dentry);
++ au_set_fbend_dir(file, btail);
++ for (; !err && bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++
++ h_file = au_h_open(dentry, bindex, flags, file);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ break;
++ }
++ au_set_h_fptr(file, bindex, h_file);
++ }
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ if (!err)
++ return 0; /* success */
++
++ /* close all */
++ for (bindex = au_fbstart(file); bindex <= btail; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++ au_set_fbstart(file, -1);
++ au_set_fbend_dir(file, -1);
++
++out:
++ return err;
++}
++
++static int aufs_open_dir(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ int err;
++ struct super_block *sb;
++ struct au_fidir *fidir;
++
++ err = -ENOMEM;
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ fidir = au_fidir_alloc(sb);
++ if (fidir) {
++ err = au_do_open(file, do_open_dir, fidir);
++ if (unlikely(err))
++ kfree(fidir);
++ }
++ si_read_unlock(sb);
++ return err;
++}
++
++static int aufs_release_dir(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ struct au_vdir *vdir_cache;
++ struct super_block *sb;
++ struct au_finfo *finfo;
++ struct au_fidir *fidir;
++ aufs_bindex_t bindex, bend;
++
++ sb = file->f_dentry->d_sb;
++ finfo = au_fi(file);
++ fidir = finfo->fi_hdir;
++ if (fidir) {
++ /* remove me from sb->s_files */
++ file_sb_list_del(file);
++
++ vdir_cache = fidir->fd_vdir_cache; /* lock-free */
++ if (vdir_cache)
++ au_vdir_free(vdir_cache);
++
++ bindex = finfo->fi_btop;
++ if (bindex >= 0) {
++ /*
++ * calls fput() instead of filp_close(),
++ * since no dnotify or lock for the lower file.
++ */
++ bend = fidir->fd_bbot;
++ for (; bindex <= bend; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++ }
++ kfree(fidir);
++ finfo->fi_hdir = NULL;
++ }
++ au_finfo_fin(file);
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_flush_dir(struct file *file, fl_owner_t id)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct file *h_file;
++
++ err = 0;
++ bend = au_fbend_dir(file);
++ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) {
++ h_file = au_hf_dir(file, bindex);
++ if (h_file)
++ err = vfsub_flush(h_file, id);
++ }
++ return err;
++}
++
++static int aufs_flush_dir(struct file *file, fl_owner_t id)
++{
++ return au_do_flush(file, id, au_do_flush_dir);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct inode *inode;
++ struct super_block *sb;
++
++ err = 0;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ IMustLock(inode);
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); !err && bindex <= bend; bindex++) {
++ struct path h_path;
++ struct inode *h_inode;
++
++ if (au_test_ro(sb, bindex, inode))
++ continue;
++ h_path.dentry = au_h_dptr(dentry, bindex);
++ if (!h_path.dentry)
++ continue;
++ h_inode = h_path.dentry->d_inode;
++ if (!h_inode)
++ continue;
++
++ /* no mnt_want_write() */
++ /* cf. fs/nsfd/vfs.c and fs/nfsd/nfs4recover.c */
++ /* todo: inotiry fired? */
++ h_path.mnt = au_sbr_mnt(sb, bindex);
++ mutex_lock(&h_inode->i_mutex);
++ err = filemap_fdatawrite(h_inode->i_mapping);
++ AuDebugOn(!h_inode->i_fop);
++ if (!err && h_inode->i_fop->fsync)
++ err = h_inode->i_fop->fsync(NULL, datasync);
++ if (!err)
++ err = filemap_fdatawrite(h_inode->i_mapping);
++ if (!err)
++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
++ mutex_unlock(&h_inode->i_mutex);
++ }
++
++ return err;
++}
++
++static int au_do_fsync_dir(struct file *file, int datasync)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct file *h_file;
++ struct super_block *sb;
++ struct inode *inode;
++ struct mutex *h_mtx;
++
++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ sb = file->f_dentry->d_sb;
++ inode = file->f_dentry->d_inode;
++ bend = au_fbend_dir(file);
++ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) {
++ h_file = au_hf_dir(file, bindex);
++ if (!h_file || au_test_ro(sb, bindex, inode))
++ continue;
++
++ err = vfs_fsync(h_file, datasync);
++ if (!err) {
++ h_mtx = &h_file->f_dentry->d_inode->i_mutex;
++ mutex_lock(h_mtx);
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL);
++ /*ignore*/
++ mutex_unlock(h_mtx);
++ }
++ }
++
++out:
++ return err;
++}
++
++/*
++ * @file may be NULL
++ */
++static int aufs_fsync_dir(struct file *file, int datasync)
++{
++ int err;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ IMustLock(dentry->d_inode);
++
++ err = 0;
++ sb = dentry->d_sb;
++ si_noflush_read_lock(sb);
++ if (file)
++ err = au_do_fsync_dir(file, datasync);
++ else {
++ di_write_lock_child(dentry);
++ err = au_do_fsync_dir_no_file(dentry, datasync);
++ }
++ au_cpup_attr_timesizes(dentry->d_inode);
++ di_write_unlock(dentry);
++ if (file)
++ fi_write_unlock(file);
++
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++ int err;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ IMustLock(inode);
++
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++ err = au_alive_dir(dentry);
++ if (!err)
++ err = au_vdir_init(file);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ if (!au_test_nfsd()) {
++ err = au_vdir_fill_de(file, dirent, filldir);
++ fsstack_copy_attr_atime(inode,
++ au_h_iptr(inode, au_ibstart(inode)));
++ } else {
++ /*
++ * nfsd filldir may call lookup_one_len(), vfs_getattr(),
++ * encode_fh() and others.
++ */
++ struct inode *h_inode = au_h_iptr(inode, au_ibstart(inode));
++
++ di_read_unlock(dentry, AuLock_IR);
++ si_read_unlock(sb);
++ err = au_vdir_fill_de(file, dirent, filldir);
++ fsstack_copy_attr_atime(inode, h_inode);
++ fi_write_unlock(file);
++
++ AuTraceErr(err);
++ return err;
++ }
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#define AuTestEmpty_WHONLY 1
++#define AuTestEmpty_CALLED (1 << 1)
++#define AuTestEmpty_SHWH (1 << 2)
++#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name)
++#define au_fset_testempty(flags, name) \
++ do { (flags) |= AuTestEmpty_##name; } while (0)
++#define au_fclr_testempty(flags, name) \
++ do { (flags) &= ~AuTestEmpty_##name; } while (0)
++
++#ifndef CONFIG_AUFS_SHWH
++#undef AuTestEmpty_SHWH
++#define AuTestEmpty_SHWH 0
++#endif
++
++struct test_empty_arg {
++ struct au_nhash *whlist;
++ unsigned int flags;
++ int err;
++ aufs_bindex_t bindex;
++};
++
++static int test_empty_cb(void *__arg, const char *__name, int namelen,
++ loff_t offset __maybe_unused, u64 ino,
++ unsigned int d_type)
++{
++ struct test_empty_arg *arg = __arg;
++ char *name = (void *)__name;
++
++ arg->err = 0;
++ au_fset_testempty(arg->flags, CALLED);
++ /* smp_mb(); */
++ if (name[0] == '.'
++ && (namelen == 1 || (name[1] == '.' && namelen == 2)))
++ goto out; /* success */
++
++ if (namelen <= AUFS_WH_PFX_LEN
++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
++ if (au_ftest_testempty(arg->flags, WHONLY)
++ && !au_nhash_test_known_wh(arg->whlist, name, namelen))
++ arg->err = -ENOTEMPTY;
++ goto out;
++ }
++
++ name += AUFS_WH_PFX_LEN;
++ namelen -= AUFS_WH_PFX_LEN;
++ if (!au_nhash_test_known_wh(arg->whlist, name, namelen))
++ arg->err = au_nhash_append_wh
++ (arg->whlist, name, namelen, ino, d_type, arg->bindex,
++ au_ftest_testempty(arg->flags, SHWH));
++
++out:
++ /* smp_mb(); */
++ AuTraceErr(arg->err);
++ return arg->err;
++}
++
++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg)
++{
++ int err;
++ struct file *h_file;
++
++ h_file = au_h_open(dentry, arg->bindex,
++ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE,
++ /*file*/NULL);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out;
++
++ err = 0;
++ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE)
++ && !h_file->f_dentry->d_inode->i_nlink)
++ goto out_put;
++
++ do {
++ arg->err = 0;
++ au_fclr_testempty(arg->flags, CALLED);
++ /* smp_mb(); */
++ err = vfsub_readdir(h_file, test_empty_cb, arg);
++ if (err >= 0)
++ err = arg->err;
++ } while (!err && au_ftest_testempty(arg->flags, CALLED));
++
++out_put:
++ fput(h_file);
++ au_sbr_put(dentry->d_sb, arg->bindex);
++out:
++ return err;
++}
++
++struct do_test_empty_args {
++ int *errp;
++ struct dentry *dentry;
++ struct test_empty_arg *arg;
++};
++
++static void call_do_test_empty(void *args)
++{
++ struct do_test_empty_args *a = args;
++ *a->errp = do_test_empty(a->dentry, a->arg);
++}
++
++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg)
++{
++ int err, wkq_err;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++
++ h_dentry = au_h_dptr(dentry, arg->bindex);
++ h_inode = h_dentry->d_inode;
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ);
++ mutex_unlock(&h_inode->i_mutex);
++ if (!err)
++ err = do_test_empty(dentry, arg);
++ else {
++ struct do_test_empty_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .arg = arg
++ };
++ unsigned int flags = arg->flags;
++
++ wkq_err = au_wkq_wait(call_do_test_empty, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ arg->flags = flags;
++ }
++
++ return err;
++}
++
++int au_test_empty_lower(struct dentry *dentry)
++{
++ int err;
++ unsigned int rdhash;
++ aufs_bindex_t bindex, bstart, btail;
++ struct au_nhash whlist;
++ struct test_empty_arg arg;
++
++ SiMustAnyLock(dentry->d_sb);
++
++ rdhash = au_sbi(dentry->d_sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry));
++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++
++ arg.flags = 0;
++ arg.whlist = &whlist;
++ bstart = au_dbstart(dentry);
++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH))
++ au_fset_testempty(arg.flags, SHWH);
++ arg.bindex = bstart;
++ err = do_test_empty(dentry, &arg);
++ if (unlikely(err))
++ goto out_whlist;
++
++ au_fset_testempty(arg.flags, WHONLY);
++ btail = au_dbtaildir(dentry);
++ for (bindex = bstart + 1; !err && bindex <= btail; bindex++) {
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry && h_dentry->d_inode) {
++ arg.bindex = bindex;
++ err = do_test_empty(dentry, &arg);
++ }
++ }
++
++out_whlist:
++ au_nhash_wh_free(&whlist);
++out:
++ return err;
++}
++
++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist)
++{
++ int err;
++ struct test_empty_arg arg;
++ aufs_bindex_t bindex, btail;
++
++ err = 0;
++ arg.whlist = whlist;
++ arg.flags = AuTestEmpty_WHONLY;
++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH))
++ au_fset_testempty(arg.flags, SHWH);
++ btail = au_dbtaildir(dentry);
++ for (bindex = au_dbstart(dentry); !err && bindex <= btail; bindex++) {
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry && h_dentry->d_inode) {
++ arg.bindex = bindex;
++ err = sio_test_empty(dentry, &arg);
++ }
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++const struct file_operations aufs_dir_fop = {
++ .owner = THIS_MODULE,
++ .read = generic_read_dir,
++ .readdir = aufs_readdir,
++ .unlocked_ioctl = aufs_ioctl_dir,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = aufs_compat_ioctl_dir,
++#endif
++ .open = aufs_open_dir,
++ .release = aufs_release_dir,
++ .flush = aufs_flush_dir,
++ .fsync = aufs_fsync_dir
++};
+diff -Nur linux-2.6.37.orig/fs/aufs/dir.h linux-2.6.37/fs/aufs/dir.h
+--- linux-2.6.37.orig/fs/aufs/dir.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/dir.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,138 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * directory operations
++ */
++
++#ifndef __AUFS_DIR_H__
++#define __AUFS_DIR_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/aufs_type.h>
++
++/* ---------------------------------------------------------------------- */
++
++/* need to be faster and smaller */
++
++struct au_nhash {
++ unsigned int nh_num;
++ struct hlist_head *nh_head;
++};
++
++struct au_vdir_destr {
++ unsigned char len;
++ unsigned char name[0];
++} __packed;
++
++struct au_vdir_dehstr {
++ struct hlist_node hash;
++ struct au_vdir_destr *str;
++} ____cacheline_aligned_in_smp;
++
++struct au_vdir_de {
++ ino_t de_ino;
++ unsigned char de_type;
++ /* caution: packed */
++ struct au_vdir_destr de_str;
++} __packed;
++
++struct au_vdir_wh {
++ struct hlist_node wh_hash;
++#ifdef CONFIG_AUFS_SHWH
++ ino_t wh_ino;
++ aufs_bindex_t wh_bindex;
++ unsigned char wh_type;
++#else
++ aufs_bindex_t wh_bindex;
++#endif
++ /* caution: packed */
++ struct au_vdir_destr wh_str;
++} __packed;
++
++union au_vdir_deblk_p {
++ unsigned char *deblk;
++ struct au_vdir_de *de;
++};
++
++struct au_vdir {
++ unsigned char **vd_deblk;
++ unsigned long vd_nblk;
++ struct {
++ unsigned long ul;
++ union au_vdir_deblk_p p;
++ } vd_last;
++
++ unsigned long vd_version;
++ unsigned int vd_deblk_sz;
++ unsigned long vd_jiffy;
++} ____cacheline_aligned_in_smp;
++
++/* ---------------------------------------------------------------------- */
++
++/* dir.c */
++extern const struct file_operations aufs_dir_fop;
++void au_add_nlink(struct inode *dir, struct inode *h_dir);
++void au_sub_nlink(struct inode *dir, struct inode *h_dir);
++loff_t au_dir_size(struct file *file, struct dentry *dentry);
++int au_test_empty_lower(struct dentry *dentry);
++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist);
++
++/* vdir.c */
++unsigned int au_rdhash_est(loff_t sz);
++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp);
++void au_nhash_wh_free(struct au_nhash *whlist);
++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
++ int limit);
++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen);
++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino,
++ unsigned int d_type, aufs_bindex_t bindex,
++ unsigned char shwh);
++void au_vdir_free(struct au_vdir *vdir);
++int au_vdir_init(struct file *file);
++int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir);
++
++/* ioctl.c */
++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg);
++
++#ifdef CONFIG_AUFS_RDU
++/* rdu.c */
++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
++#ifdef CONFIG_COMPAT
++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg);
++#endif
++#else
++static inline long au_rdu_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ return -EINVAL;
++}
++#ifdef CONFIG_COMPAT
++static inline long au_rdu_compat_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ return -EINVAL;
++}
++#endif
++#endif
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DIR_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/dynop.c linux-2.6.37/fs/aufs/dynop.c
+--- linux-2.6.37.orig/fs/aufs/dynop.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/dynop.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,425 @@
++/*
++ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * dynamically customizable operations for regular files
++ */
++
++#include "aufs.h"
++
++#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop)
++
++/*
++ * How large will these lists be?
++ * Usually just a few elements, 20-30 at most for each, I guess.
++ */
++static struct au_splhead dynop[AuDyLast];
++
++static struct au_dykey *dy_gfind_get(struct au_splhead *spl, const void *h_op)
++{
++ struct au_dykey *key, *tmp;
++ struct list_head *head;
++
++ key = NULL;
++ head = &spl->head;
++ rcu_read_lock();
++ list_for_each_entry_rcu(tmp, head, dk_list)
++ if (tmp->dk_op.dy_hop == h_op) {
++ key = tmp;
++ kref_get(&key->dk_kref);
++ break;
++ }
++ rcu_read_unlock();
++
++ return key;
++}
++
++static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key)
++{
++ struct au_dykey **k, *found;
++ const void *h_op = key->dk_op.dy_hop;
++ int i;
++
++ found = NULL;
++ k = br->br_dykey;
++ for (i = 0; i < AuBrDynOp; i++)
++ if (k[i]) {
++ if (k[i]->dk_op.dy_hop == h_op) {
++ found = k[i];
++ break;
++ }
++ } else
++ break;
++ if (!found) {
++ spin_lock(&br->br_dykey_lock);
++ for (; i < AuBrDynOp; i++)
++ if (k[i]) {
++ if (k[i]->dk_op.dy_hop == h_op) {
++ found = k[i];
++ break;
++ }
++ } else {
++ k[i] = key;
++ break;
++ }
++ spin_unlock(&br->br_dykey_lock);
++ BUG_ON(i == AuBrDynOp); /* expand the array */
++ }
++
++ return found;
++}
++
++/* kref_get() if @key is already added */
++static struct au_dykey *dy_gadd(struct au_splhead *spl, struct au_dykey *key)
++{
++ struct au_dykey *tmp, *found;
++ struct list_head *head;
++ const void *h_op = key->dk_op.dy_hop;
++
++ found = NULL;
++ head = &spl->head;
++ spin_lock(&spl->spin);
++ list_for_each_entry(tmp, head, dk_list)
++ if (tmp->dk_op.dy_hop == h_op) {
++ kref_get(&tmp->dk_kref);
++ found = tmp;
++ break;
++ }
++ if (!found)
++ list_add_rcu(&key->dk_list, head);
++ spin_unlock(&spl->spin);
++
++ if (!found)
++ DyPrSym(key);
++ return found;
++}
++
++static void dy_free_rcu(struct rcu_head *rcu)
++{
++ struct au_dykey *key;
++
++ key = container_of(rcu, struct au_dykey, dk_rcu);
++ DyPrSym(key);
++ kfree(key);
++}
++
++static void dy_free(struct kref *kref)
++{
++ struct au_dykey *key;
++ struct au_splhead *spl;
++
++ key = container_of(kref, struct au_dykey, dk_kref);
++ spl = dynop + key->dk_op.dy_type;
++ au_spl_del_rcu(&key->dk_list, spl);
++ call_rcu(&key->dk_rcu, dy_free_rcu);
++}
++
++void au_dy_put(struct au_dykey *key)
++{
++ kref_put(&key->dk_kref, dy_free);
++}
++
++/* ---------------------------------------------------------------------- */
++
++#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *))
++
++#ifdef CONFIG_AUFS_DEBUG
++#define DyDbgDeclare(cnt) unsigned int cnt = 0
++#define DyDbgInc(cnt) do { cnt++; } while (0)
++#else
++#define DyDbgDeclare(cnt) do {} while (0)
++#define DyDbgInc(cnt) do {} while (0)
++#endif
++
++#define DySet(func, dst, src, h_op, h_sb) do { \
++ DyDbgInc(cnt); \
++ if (h_op->func) { \
++ if (src.func) \
++ dst.func = src.func; \
++ else \
++ AuDbg("%s %s\n", au_sbtype(h_sb), #func); \
++ } \
++} while (0)
++
++#define DySetForce(func, dst, src) do { \
++ AuDebugOn(!src.func); \
++ DyDbgInc(cnt); \
++ dst.func = src.func; \
++} while (0)
++
++#define DySetAop(func) \
++ DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb)
++#define DySetAopForce(func) \
++ DySetForce(func, dyaop->da_op, aufs_aop)
++
++static void dy_aop(struct au_dykey *key, const void *h_op,
++ struct super_block *h_sb __maybe_unused)
++{
++ struct au_dyaop *dyaop = (void *)key;
++ const struct address_space_operations *h_aop = h_op;
++ DyDbgDeclare(cnt);
++
++ AuDbg("%s\n", au_sbtype(h_sb));
++
++ DySetAop(writepage);
++ DySetAopForce(readpage); /* force */
++ DySetAop(sync_page);
++ DySetAop(writepages);
++ DySetAop(set_page_dirty);
++ DySetAop(readpages);
++ DySetAop(write_begin);
++ DySetAop(write_end);
++ DySetAop(bmap);
++ DySetAop(invalidatepage);
++ DySetAop(releasepage);
++ /* these two will be changed according to an aufs mount option */
++ DySetAop(direct_IO);
++ DySetAop(get_xip_mem);
++ DySetAop(migratepage);
++ DySetAop(launder_page);
++ DySetAop(is_partially_uptodate);
++ DySetAop(error_remove_page);
++
++ DyDbgSize(cnt, *h_aop);
++ dyaop->da_get_xip_mem = h_aop->get_xip_mem;
++}
++
++#define DySetVmop(func) \
++ DySet(func, dyvmop->dv_op, aufs_vm_ops, h_vmop, h_sb)
++#define DySetVmopForce(func) \
++ DySetForce(func, dyvmop->dv_op, aufs_vm_ops)
++
++static void dy_vmop(struct au_dykey *key, const void *h_op,
++ struct super_block *h_sb __maybe_unused)
++{
++ struct au_dyvmop *dyvmop = (void *)key;
++ const struct vm_operations_struct *h_vmop = h_op;
++ DyDbgDeclare(cnt);
++
++ AuDbg("%s\n", au_sbtype(h_sb));
++
++ DySetVmop(open);
++ DySetVmop(close);
++ DySetVmop(fault);
++ DySetVmop(page_mkwrite);
++ DySetVmop(access);
++#ifdef CONFIG_NUMA
++ DySetVmop(set_policy);
++ DySetVmop(get_policy);
++ DySetVmop(migrate);
++#endif
++
++ DyDbgSize(cnt, *h_vmop);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void dy_bug(struct kref *kref)
++{
++ BUG();
++}
++
++static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br)
++{
++ struct au_dykey *key, *old;
++ struct au_splhead *spl;
++ struct op {
++ unsigned int sz;
++ void (*set)(struct au_dykey *key, const void *h_op,
++ struct super_block *h_sb __maybe_unused);
++ };
++ static const struct op a[] = {
++ [AuDy_AOP] = {
++ .sz = sizeof(struct au_dyaop),
++ .set = dy_aop
++ },
++ [AuDy_VMOP] = {
++ .sz = sizeof(struct au_dyvmop),
++ .set = dy_vmop
++ }
++ };
++ const struct op *p;
++
++ spl = dynop + op->dy_type;
++ key = dy_gfind_get(spl, op->dy_hop);
++ if (key)
++ goto out_add; /* success */
++
++ p = a + op->dy_type;
++ key = kzalloc(p->sz, GFP_NOFS);
++ if (unlikely(!key)) {
++ key = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++
++ key->dk_op.dy_hop = op->dy_hop;
++ kref_init(&key->dk_kref);
++ p->set(key, op->dy_hop, br->br_mnt->mnt_sb);
++ old = dy_gadd(spl, key);
++ if (old) {
++ kfree(key);
++ key = old;
++ }
++
++out_add:
++ old = dy_bradd(br, key);
++ if (old)
++ /* its ref-count should never be zero here */
++ kref_put(&key->dk_kref, dy_bug);
++out:
++ return key;
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * Aufs prohibits O_DIRECT by defaut even if the branch supports it.
++ * This behaviour is neccessary to return an error from open(O_DIRECT) instead
++ * of the succeeding I/O. The dio mount option enables O_DIRECT and makes
++ * open(O_DIRECT) always succeed, but the succeeding I/O may return an error.
++ * See the aufs manual in detail.
++ *
++ * To keep this behaviour, aufs has to set NULL to ->get_xip_mem too, and the
++ * performance of fadvise() and madvise() may be affected.
++ */
++static void dy_adx(struct au_dyaop *dyaop, int do_dx)
++{
++ if (!do_dx) {
++ dyaop->da_op.direct_IO = NULL;
++ dyaop->da_op.get_xip_mem = NULL;
++ } else {
++ dyaop->da_op.direct_IO = aufs_aop.direct_IO;
++ dyaop->da_op.get_xip_mem = aufs_aop.get_xip_mem;
++ if (!dyaop->da_get_xip_mem)
++ dyaop->da_op.get_xip_mem = NULL;
++ }
++}
++
++static struct au_dyaop *dy_aget(struct au_branch *br,
++ const struct address_space_operations *h_aop,
++ int do_dx)
++{
++ struct au_dyaop *dyaop;
++ struct au_dynop op;
++
++ op.dy_type = AuDy_AOP;
++ op.dy_haop = h_aop;
++ dyaop = (void *)dy_get(&op, br);
++ if (IS_ERR(dyaop))
++ goto out;
++ dy_adx(dyaop, do_dx);
++
++out:
++ return dyaop;
++}
++
++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex,
++ struct inode *h_inode)
++{
++ int err, do_dx;
++ struct super_block *sb;
++ struct au_branch *br;
++ struct au_dyaop *dyaop;
++
++ AuDebugOn(!S_ISREG(h_inode->i_mode));
++ IiMustWriteLock(inode);
++
++ sb = inode->i_sb;
++ br = au_sbr(sb, bindex);
++ do_dx = !!au_opt_test(au_mntflags(sb), DIO);
++ dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx);
++ err = PTR_ERR(dyaop);
++ if (IS_ERR(dyaop))
++ /* unnecessary to call dy_fput() */
++ goto out;
++
++ err = 0;
++ inode->i_mapping->a_ops = &dyaop->da_op;
++
++out:
++ return err;
++}
++
++/*
++ * Is it safe to replace a_ops during the inode/file is in operation?
++ * Yes, I hope so.
++ */
++int au_dy_irefresh(struct inode *inode)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct inode *h_inode;
++
++ err = 0;
++ if (S_ISREG(inode->i_mode)) {
++ bstart = au_ibstart(inode);
++ h_inode = au_h_iptr(inode, bstart);
++ err = au_dy_iaop(inode, bstart, h_inode);
++ }
++ return err;
++}
++
++void au_dy_arefresh(int do_dx)
++{
++ struct au_splhead *spl;
++ struct list_head *head;
++ struct au_dykey *key;
++
++ spl = dynop + AuDy_AOP;
++ head = &spl->head;
++ spin_lock(&spl->spin);
++ list_for_each_entry(key, head, dk_list)
++ dy_adx((void *)key, do_dx);
++ spin_unlock(&spl->spin);
++}
++
++const struct vm_operations_struct *
++au_dy_vmop(struct file *file, struct au_branch *br,
++ const struct vm_operations_struct *h_vmop)
++{
++ struct au_dyvmop *dyvmop;
++ struct au_dynop op;
++
++ op.dy_type = AuDy_VMOP;
++ op.dy_hvmop = h_vmop;
++ dyvmop = (void *)dy_get(&op, br);
++ if (IS_ERR(dyvmop))
++ return (void *)dyvmop;
++ return &dyvmop->dv_op;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void __init au_dy_init(void)
++{
++ int i;
++
++ /* make sure that 'struct au_dykey *' can be any type */
++ BUILD_BUG_ON(offsetof(struct au_dyaop, da_key));
++ BUILD_BUG_ON(offsetof(struct au_dyvmop, dv_key));
++
++ for (i = 0; i < AuDyLast; i++)
++ au_spl_init(dynop + i);
++}
++
++void au_dy_fin(void)
++{
++ int i;
++
++ for (i = 0; i < AuDyLast; i++)
++ WARN_ON(!list_empty(&dynop[i].head));
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/dynop.h linux-2.6.37/fs/aufs/dynop.h
+--- linux-2.6.37.orig/fs/aufs/dynop.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/dynop.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,89 @@
++/*
++ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * dynamically customizable operations (for regular files only)
++ */
++
++#ifndef __AUFS_DYNOP_H__
++#define __AUFS_DYNOP_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/rcupdate.h>
++#include <linux/aufs_type.h>
++#include "inode.h"
++
++enum {AuDy_AOP, AuDy_VMOP, AuDyLast};
++
++struct au_dynop {
++ int dy_type;
++ union {
++ const void *dy_hop;
++ const struct address_space_operations *dy_haop;
++ const struct vm_operations_struct *dy_hvmop;
++ };
++};
++
++struct au_dykey {
++ union {
++ struct list_head dk_list;
++ struct rcu_head dk_rcu;
++ };
++ struct au_dynop dk_op;
++
++ /*
++ * during I am in the branch local array, kref is gotten. when the
++ * branch is removed, kref is put.
++ */
++ struct kref dk_kref;
++};
++
++/* stop unioning since their sizes are very different from each other */
++struct au_dyaop {
++ struct au_dykey da_key;
++ struct address_space_operations da_op; /* not const */
++ int (*da_get_xip_mem)(struct address_space *, pgoff_t, int,
++ void **, unsigned long *);
++};
++
++struct au_dyvmop {
++ struct au_dykey dv_key;
++ struct vm_operations_struct dv_op; /* not const */
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* dynop.c */
++struct au_branch;
++void au_dy_put(struct au_dykey *key);
++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex,
++ struct inode *h_inode);
++int au_dy_irefresh(struct inode *inode);
++void au_dy_arefresh(int do_dio);
++const struct vm_operations_struct *
++au_dy_vmop(struct file *file, struct au_branch *br,
++ const struct vm_operations_struct *h_vmop);
++
++void __init au_dy_init(void);
++void au_dy_fin(void);
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DYNOP_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/export.c linux-2.6.37/fs/aufs/export.c
+--- linux-2.6.37.orig/fs/aufs/export.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/export.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,798 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * export via nfs
++ */
++
++#include <linux/exportfs.h>
++#include <linux/file.h>
++#include <linux/mnt_namespace.h>
++#include <linux/namei.h>
++#include <linux/nsproxy.h>
++#include <linux/random.h>
++#include <linux/writeback.h>
++#include "aufs.h"
++
++union conv {
++#ifdef CONFIG_AUFS_INO_T_64
++ __u32 a[2];
++#else
++ __u32 a[1];
++#endif
++ ino_t ino;
++};
++
++static ino_t decode_ino(__u32 *a)
++{
++ union conv u;
++
++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a));
++ u.a[0] = a[0];
++#ifdef CONFIG_AUFS_INO_T_64
++ u.a[1] = a[1];
++#endif
++ return u.ino;
++}
++
++static void encode_ino(__u32 *a, ino_t ino)
++{
++ union conv u;
++
++ u.ino = ino;
++ a[0] = u.a[0];
++#ifdef CONFIG_AUFS_INO_T_64
++ a[1] = u.a[1];
++#endif
++}
++
++/* NFS file handle */
++enum {
++ Fh_br_id,
++ Fh_sigen,
++#ifdef CONFIG_AUFS_INO_T_64
++ /* support 64bit inode number */
++ Fh_ino1,
++ Fh_ino2,
++ Fh_dir_ino1,
++ Fh_dir_ino2,
++#else
++ Fh_ino1,
++ Fh_dir_ino1,
++#endif
++ Fh_igen,
++ Fh_h_type,
++ Fh_tail,
++
++ Fh_ino = Fh_ino1,
++ Fh_dir_ino = Fh_dir_ino1
++};
++
++static int au_test_anon(struct dentry *dentry)
++{
++ return !!(dentry->d_flags & DCACHE_DISCONNECTED);
++}
++
++/* ---------------------------------------------------------------------- */
++/* inode generation external table */
++
++void au_xigen_inc(struct inode *inode)
++{
++ loff_t pos;
++ ssize_t sz;
++ __u32 igen;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++ sb = inode->i_sb;
++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO));
++
++ sbinfo = au_sbi(sb);
++ pos = inode->i_ino;
++ pos *= sizeof(igen);
++ igen = inode->i_generation + 1;
++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen,
++ sizeof(igen), &pos);
++ if (sz == sizeof(igen))
++ return; /* success */
++
++ if (unlikely(sz >= 0))
++ AuIOErr("xigen error (%zd)\n", sz);
++}
++
++int au_xigen_new(struct inode *inode)
++{
++ int err;
++ loff_t pos;
++ ssize_t sz;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ err = 0;
++ /* todo: dirty, at mount time */
++ if (inode->i_ino == AUFS_ROOT_INO)
++ goto out;
++ sb = inode->i_sb;
++ SiMustAnyLock(sb);
++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
++ goto out;
++
++ err = -EFBIG;
++ pos = inode->i_ino;
++ if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) {
++ AuIOErr1("too large i%lld\n", pos);
++ goto out;
++ }
++ pos *= sizeof(inode->i_generation);
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ file = sbinfo->si_xigen;
++ BUG_ON(!file);
++
++ if (i_size_read(file->f_dentry->d_inode)
++ < pos + sizeof(inode->i_generation)) {
++ inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next);
++ sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation,
++ sizeof(inode->i_generation), &pos);
++ } else
++ sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation,
++ sizeof(inode->i_generation), &pos);
++ if (sz == sizeof(inode->i_generation))
++ goto out; /* success */
++
++ err = sz;
++ if (unlikely(sz >= 0)) {
++ err = -EIO;
++ AuIOErr("xigen error (%zd)\n", sz);
++ }
++
++out:
++ return err;
++}
++
++int au_xigen_set(struct super_block *sb, struct file *base)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ file = au_xino_create2(base, sbinfo->si_xigen);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ err = 0;
++ if (sbinfo->si_xigen)
++ fput(sbinfo->si_xigen);
++ sbinfo->si_xigen = file;
++
++out:
++ return err;
++}
++
++void au_xigen_clr(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ if (sbinfo->si_xigen) {
++ fput(sbinfo->si_xigen);
++ sbinfo->si_xigen = NULL;
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino,
++ ino_t dir_ino)
++{
++ struct dentry *dentry, *d;
++ struct inode *inode;
++ unsigned int sigen;
++
++ dentry = NULL;
++ inode = ilookup(sb, ino);
++ if (!inode)
++ goto out;
++
++ dentry = ERR_PTR(-ESTALE);
++ sigen = au_sigen(sb);
++ if (unlikely(is_bad_inode(inode)
++ || IS_DEADDIR(inode)
++ || sigen != au_iigen(inode)))
++ goto out_iput;
++
++ dentry = NULL;
++ if (!dir_ino || S_ISDIR(inode->i_mode))
++ dentry = d_find_alias(inode);
++ else {
++ spin_lock(&dcache_lock);
++ list_for_each_entry(d, &inode->i_dentry, d_alias)
++ if (!au_test_anon(d)
++ && d->d_parent->d_inode->i_ino == dir_ino) {
++ dentry = dget_locked(d);
++ break;
++ }
++ spin_unlock(&dcache_lock);
++ }
++ if (unlikely(dentry && au_digen_test(dentry, sigen))) {
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++ }
++
++out_iput:
++ iput(inode);
++out:
++ return dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* todo: dirty? */
++/* if exportfs_decode_fh() passed vfsmount*, we could be happy */
++
++struct au_compare_mnt_args {
++ /* input */
++ struct super_block *sb;
++
++ /* output */
++ struct vfsmount *mnt;
++};
++
++static int au_compare_mnt(struct vfsmount *mnt, void *arg)
++{
++ struct au_compare_mnt_args *a = arg;
++
++ if (mnt->mnt_sb != a->sb)
++ return 0;
++ a->mnt = mntget(mnt);
++ return 1;
++}
++
++static struct vfsmount *au_mnt_get(struct super_block *sb)
++{
++ int err;
++ struct au_compare_mnt_args args = {
++ .sb = sb
++ };
++ struct mnt_namespace *ns;
++
++ br_read_lock(vfsmount_lock);
++ /* no get/put ?? */
++ AuDebugOn(!current->nsproxy);
++ ns = current->nsproxy->mnt_ns;
++ AuDebugOn(!ns);
++ err = iterate_mounts(au_compare_mnt, &args, ns->root);
++ br_read_unlock(vfsmount_lock);
++ AuDebugOn(!err);
++ AuDebugOn(!args.mnt);
++ return args.mnt;
++}
++
++struct au_nfsd_si_lock {
++ unsigned int sigen;
++ aufs_bindex_t bindex, br_id;
++ unsigned char force_lock;
++};
++
++static int si_nfsd_read_lock(struct super_block *sb,
++ struct au_nfsd_si_lock *nsi_lock)
++{
++ int err;
++ aufs_bindex_t bindex;
++
++ si_read_lock(sb, AuLock_FLUSH);
++
++ /* branch id may be wrapped around */
++ err = 0;
++ bindex = au_br_index(sb, nsi_lock->br_id);
++ if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb))
++ goto out; /* success */
++
++ err = -ESTALE;
++ bindex = -1;
++ if (!nsi_lock->force_lock)
++ si_read_unlock(sb);
++
++out:
++ nsi_lock->bindex = bindex;
++ return err;
++}
++
++struct find_name_by_ino {
++ int called, found;
++ ino_t ino;
++ char *name;
++ int namelen;
++};
++
++static int
++find_name_by_ino(void *arg, const char *name, int namelen, loff_t offset,
++ u64 ino, unsigned int d_type)
++{
++ struct find_name_by_ino *a = arg;
++
++ a->called++;
++ if (a->ino != ino)
++ return 0;
++
++ memcpy(a->name, name, namelen);
++ a->namelen = namelen;
++ a->found = 1;
++ return 1;
++}
++
++static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino,
++ struct au_nfsd_si_lock *nsi_lock)
++{
++ struct dentry *dentry, *parent;
++ struct file *file;
++ struct inode *dir;
++ struct find_name_by_ino arg;
++ int err;
++
++ parent = path->dentry;
++ if (nsi_lock)
++ si_read_unlock(parent->d_sb);
++ file = vfsub_dentry_open(path, au_dir_roflags);
++ dentry = (void *)file;
++ if (IS_ERR(file))
++ goto out;
++
++ dentry = ERR_PTR(-ENOMEM);
++ arg.name = __getname_gfp(GFP_NOFS);
++ if (unlikely(!arg.name))
++ goto out_file;
++ arg.ino = ino;
++ arg.found = 0;
++ do {
++ arg.called = 0;
++ /* smp_mb(); */
++ err = vfsub_readdir(file, find_name_by_ino, &arg);
++ } while (!err && !arg.found && arg.called);
++ dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_name;
++ dentry = ERR_PTR(-ENOENT);
++ if (!arg.found)
++ goto out_name;
++
++ /* do not call au_lkup_one() */
++ dir = parent->d_inode;
++ mutex_lock(&dir->i_mutex);
++ dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen);
++ mutex_unlock(&dir->i_mutex);
++ AuTraceErrPtr(dentry);
++ if (IS_ERR(dentry))
++ goto out_name;
++ AuDebugOn(au_test_anon(dentry));
++ if (unlikely(!dentry->d_inode)) {
++ dput(dentry);
++ dentry = ERR_PTR(-ENOENT);
++ }
++
++out_name:
++ __putname(arg.name);
++out_file:
++ fput(file);
++out:
++ if (unlikely(nsi_lock
++ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0))
++ if (!IS_ERR(dentry)) {
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++ }
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino,
++ ino_t dir_ino,
++ struct au_nfsd_si_lock *nsi_lock)
++{
++ struct dentry *dentry;
++ struct path path;
++
++ if (dir_ino != AUFS_ROOT_INO) {
++ path.dentry = decode_by_ino(sb, dir_ino, 0);
++ dentry = path.dentry;
++ if (!path.dentry || IS_ERR(path.dentry))
++ goto out;
++ AuDebugOn(au_test_anon(path.dentry));
++ } else
++ path.dentry = dget(sb->s_root);
++
++ path.mnt = au_mnt_get(sb);
++ dentry = au_lkup_by_ino(&path, ino, nsi_lock);
++ path_put(&path);
++
++out:
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int h_acceptable(void *expv, struct dentry *dentry)
++{
++ return 1;
++}
++
++static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath,
++ char *buf, int len, struct super_block *sb)
++{
++ char *p;
++ int n;
++ struct path path;
++
++ p = d_path(h_rootpath, buf, len);
++ if (IS_ERR(p))
++ goto out;
++ n = strlen(p);
++
++ path.mnt = h_rootpath->mnt;
++ path.dentry = h_parent;
++ p = d_path(&path, buf, len);
++ if (IS_ERR(p))
++ goto out;
++ if (n != 1)
++ p += n;
++
++ path.mnt = au_mnt_get(sb);
++ path.dentry = sb->s_root;
++ p = d_path(&path, buf, len - strlen(p));
++ mntput(path.mnt);
++ if (IS_ERR(p))
++ goto out;
++ if (n != 1)
++ p[strlen(p)] = '/';
++
++out:
++ AuTraceErrPtr(p);
++ return p;
++}
++
++static
++struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh,
++ int fh_len, struct au_nfsd_si_lock *nsi_lock)
++{
++ struct dentry *dentry, *h_parent, *root;
++ struct super_block *h_sb;
++ char *pathname, *p;
++ struct vfsmount *h_mnt;
++ struct au_branch *br;
++ int err;
++ struct path path;
++
++ br = au_sbr(sb, nsi_lock->bindex);
++ h_mnt = br->br_mnt;
++ h_sb = h_mnt->mnt_sb;
++ /* todo: call lower fh_to_dentry()? fh_to_parent()? */
++ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail),
++ fh_len - Fh_tail, fh[Fh_h_type],
++ h_acceptable, /*context*/NULL);
++ dentry = h_parent;
++ if (unlikely(!h_parent || IS_ERR(h_parent))) {
++ AuWarn1("%s decode_fh failed, %ld\n",
++ au_sbtype(h_sb), PTR_ERR(h_parent));
++ goto out;
++ }
++ dentry = NULL;
++ if (unlikely(au_test_anon(h_parent))) {
++ AuWarn1("%s decode_fh returned a disconnected dentry\n",
++ au_sbtype(h_sb));
++ goto out_h_parent;
++ }
++
++ dentry = ERR_PTR(-ENOMEM);
++ pathname = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!pathname))
++ goto out_h_parent;
++
++ root = sb->s_root;
++ path.mnt = h_mnt;
++ di_read_lock_parent(root, !AuLock_IR);
++ path.dentry = au_h_dptr(root, nsi_lock->bindex);
++ di_read_unlock(root, !AuLock_IR);
++ p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb);
++ dentry = (void *)p;
++ if (IS_ERR(p))
++ goto out_pathname;
++
++ si_read_unlock(sb);
++ err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
++ dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_relock;
++
++ dentry = ERR_PTR(-ENOENT);
++ AuDebugOn(au_test_anon(path.dentry));
++ if (unlikely(!path.dentry->d_inode))
++ goto out_path;
++
++ if (ino != path.dentry->d_inode->i_ino)
++ dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL);
++ else
++ dentry = dget(path.dentry);
++
++out_path:
++ path_put(&path);
++out_relock:
++ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0))
++ if (!IS_ERR(dentry)) {
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++ }
++out_pathname:
++ free_page((unsigned long)pathname);
++out_h_parent:
++ dput(h_parent);
++out:
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct dentry *
++aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
++ int fh_type)
++{
++ struct dentry *dentry;
++ __u32 *fh = fid->raw;
++ struct au_branch *br;
++ ino_t ino, dir_ino;
++ struct au_nfsd_si_lock nsi_lock = {
++ .force_lock = 0
++ };
++
++ dentry = ERR_PTR(-ESTALE);
++ /* it should never happen, but the file handle is unreliable */
++ if (unlikely(fh_len < Fh_tail))
++ goto out;
++ nsi_lock.sigen = fh[Fh_sigen];
++ nsi_lock.br_id = fh[Fh_br_id];
++
++ /* branch id may be wrapped around */
++ br = NULL;
++ if (unlikely(si_nfsd_read_lock(sb, &nsi_lock)))
++ goto out;
++ nsi_lock.force_lock = 1;
++
++ /* is this inode still cached? */
++ ino = decode_ino(fh + Fh_ino);
++ /* it should never happen */
++ if (unlikely(ino == AUFS_ROOT_INO))
++ goto out;
++
++ dir_ino = decode_ino(fh + Fh_dir_ino);
++ dentry = decode_by_ino(sb, ino, dir_ino);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++ if (dentry)
++ goto accept;
++
++ /* is the parent dir cached? */
++ br = au_sbr(sb, nsi_lock.bindex);
++ atomic_inc(&br->br_count);
++ dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++ if (dentry)
++ goto accept;
++
++ /* lookup path */
++ dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++ if (unlikely(!dentry))
++ /* todo?: make it ESTALE */
++ goto out_unlock;
++
++accept:
++ if (!au_digen_test(dentry, au_sigen(sb))
++ && dentry->d_inode->i_generation == fh[Fh_igen])
++ goto out_unlock; /* success */
++
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++out_unlock:
++ if (br)
++ atomic_dec(&br->br_count);
++ si_read_unlock(sb);
++out:
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++#if 0 /* reserved for future use */
++/* support subtreecheck option */
++static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid,
++ int fh_len, int fh_type)
++{
++ struct dentry *parent;
++ __u32 *fh = fid->raw;
++ ino_t dir_ino;
++
++ dir_ino = decode_ino(fh + Fh_dir_ino);
++ parent = decode_by_ino(sb, dir_ino, 0);
++ if (IS_ERR(parent))
++ goto out;
++ if (!parent)
++ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]),
++ dir_ino, fh, fh_len);
++
++out:
++ AuTraceErrPtr(parent);
++ return parent;
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
++ int connectable)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct super_block *sb, *h_sb;
++ struct inode *inode;
++ struct dentry *parent, *h_parent;
++ struct au_branch *br;
++
++ AuDebugOn(au_test_anon(dentry));
++
++ parent = NULL;
++ err = -ENOSPC;
++ if (unlikely(*max_len <= Fh_tail)) {
++ AuWarn1("NFSv2 client (max_len %d)?\n", *max_len);
++ goto out;
++ }
++
++ err = FILEID_ROOT;
++ if (IS_ROOT(dentry)) {
++ AuDebugOn(dentry->d_inode->i_ino != AUFS_ROOT_INO);
++ goto out;
++ }
++
++ h_parent = NULL;
++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR | AuLock_GEN);
++ if (unlikely(err))
++ goto out;
++
++ inode = dentry->d_inode;
++ AuDebugOn(!inode);
++ sb = dentry->d_sb;
++#ifdef CONFIG_AUFS_DEBUG
++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
++ AuWarn1("NFS-exporting requires xino\n");
++#endif
++ err = -EIO;
++ parent = dget_parent(dentry);
++ di_read_lock_parent(parent, !AuLock_IR);
++ bend = au_dbtaildir(parent);
++ for (bindex = au_dbstart(parent); bindex <= bend; bindex++) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (h_parent) {
++ dget(h_parent);
++ break;
++ }
++ }
++ if (unlikely(!h_parent))
++ goto out_unlock;
++
++ err = -EPERM;
++ br = au_sbr(sb, bindex);
++ h_sb = br->br_mnt->mnt_sb;
++ if (unlikely(!h_sb->s_export_op)) {
++ AuErr1("%s branch is not exportable\n", au_sbtype(h_sb));
++ goto out_dput;
++ }
++
++ fh[Fh_br_id] = br->br_id;
++ fh[Fh_sigen] = au_sigen(sb);
++ encode_ino(fh + Fh_ino, inode->i_ino);
++ encode_ino(fh + Fh_dir_ino, parent->d_inode->i_ino);
++ fh[Fh_igen] = inode->i_generation;
++
++ *max_len -= Fh_tail;
++ fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail),
++ max_len,
++ /*connectable or subtreecheck*/0);
++ err = fh[Fh_h_type];
++ *max_len += Fh_tail;
++ /* todo: macros? */
++ if (err != 255)
++ err = 99;
++ else
++ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb));
++
++out_dput:
++ dput(h_parent);
++out_unlock:
++ di_read_unlock(parent, !AuLock_IR);
++ dput(parent);
++ aufs_read_unlock(dentry, AuLock_IR);
++out:
++ if (unlikely(err < 0))
++ err = 255;
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_commit_metadata(struct inode *inode)
++{
++ int err;
++ aufs_bindex_t bindex;
++ struct super_block *sb;
++ struct inode *h_inode;
++ int (*f)(struct inode *inode);
++
++ sb = inode->i_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ ii_write_lock_child(inode);
++ bindex = au_ibstart(inode);
++ AuDebugOn(bindex < 0);
++ h_inode = au_h_iptr(inode, bindex);
++
++ f = h_inode->i_sb->s_export_op->commit_metadata;
++ if (f)
++ err = f(h_inode);
++ else {
++ struct writeback_control wbc = {
++ .sync_mode = WB_SYNC_ALL,
++ .nr_to_write = 0 /* metadata only */
++ };
++
++ err = sync_inode(h_inode, &wbc);
++ }
++
++ au_cpup_attr_timesizes(inode);
++ ii_write_unlock(inode);
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct export_operations aufs_export_op = {
++ .fh_to_dentry = aufs_fh_to_dentry,
++ /* .fh_to_parent = aufs_fh_to_parent, */
++ .encode_fh = aufs_encode_fh,
++ .commit_metadata = aufs_commit_metadata
++};
++
++void au_export_init(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++ __u32 u;
++
++ sb->s_export_op = &aufs_export_op;
++ sbinfo = au_sbi(sb);
++ sbinfo->si_xigen = NULL;
++ get_random_bytes(&u, sizeof(u));
++ BUILD_BUG_ON(sizeof(u) != sizeof(int));
++ atomic_set(&sbinfo->si_xigen_next, u);
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/f_op.c linux-2.6.37/fs/aufs/f_op.c
+--- linux-2.6.37.orig/fs/aufs/f_op.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/f_op.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,906 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * file and vm operations
++ */
++
++#include <linux/file.h>
++#include <linux/fs_stack.h>
++#include <linux/mman.h>
++#include <linux/mm.h>
++#include <linux/security.h>
++#include "aufs.h"
++
++int au_do_open_nondir(struct file *file, int flags)
++{
++ int err;
++ aufs_bindex_t bindex;
++ struct file *h_file;
++ struct dentry *dentry;
++ struct au_finfo *finfo;
++
++ FiMustWriteLock(file);
++
++ dentry = file->f_dentry;
++ err = au_d_alive(dentry);
++ if (unlikely(err))
++ goto out;
++
++ finfo = au_fi(file);
++ memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop));
++ finfo->fi_hvmop = NULL;
++ bindex = au_dbstart(dentry);
++ h_file = au_h_open(dentry, bindex, flags, file);
++ if (IS_ERR(h_file))
++ err = PTR_ERR(h_file);
++ else {
++ au_set_fbstart(file, bindex);
++ au_set_h_fptr(file, bindex, h_file);
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ }
++
++out:
++ return err;
++}
++
++static int aufs_open_nondir(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ int err;
++ struct super_block *sb;
++
++ AuDbg("%.*s, f_ flags 0x%x, f_mode 0x%x\n",
++ AuDLNPair(file->f_dentry), vfsub_file_flags(file),
++ file->f_mode);
++
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_do_open(file, au_do_open_nondir, /*fidir*/NULL);
++ si_read_unlock(sb);
++ return err;
++}
++
++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file)
++{
++ struct au_finfo *finfo;
++ aufs_bindex_t bindex;
++
++ finfo = au_fi(file);
++ bindex = finfo->fi_btop;
++ if (bindex >= 0) {
++ /* remove me from sb->s_files */
++ file_sb_list_del(file);
++ au_set_h_fptr(file, bindex, NULL);
++ }
++
++ au_finfo_fin(file);
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_flush_nondir(struct file *file, fl_owner_t id)
++{
++ int err;
++ struct file *h_file;
++
++ err = 0;
++ h_file = au_hf_top(file);
++ if (h_file)
++ err = vfsub_flush(h_file, id);
++ return err;
++}
++
++static int aufs_flush_nondir(struct file *file, fl_owner_t id)
++{
++ return au_do_flush(file, id, au_do_flush_nondir);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static ssize_t aufs_read(struct file *file, char __user *buf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++ struct dentry *dentry;
++ struct file *h_file;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ h_file = au_hf_top(file);
++ err = vfsub_read_u(h_file, buf, count, ppos);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++/*
++ * todo: very ugly
++ * it locks both of i_mutex and si_rwsem for read in safe.
++ * if the plink maintenance mode continues forever (that is the problem),
++ * may loop forever.
++ */
++static void au_mtx_and_read_lock(struct inode *inode)
++{
++ int err;
++ struct super_block *sb = inode->i_sb;
++
++ while (1) {
++ mutex_lock(&inode->i_mutex);
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (!err)
++ break;
++ mutex_unlock(&inode->i_mutex);
++ si_read_lock(sb, AuLock_NOPLMW);
++ si_read_unlock(sb);
++ }
++}
++
++static ssize_t aufs_write(struct file *file, const char __user *ubuf,
++ size_t count, loff_t *ppos)
++{
++ ssize_t err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *h_file;
++ char __user *buf = (char __user *)ubuf;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ au_mtx_and_read_lock(inode);
++
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ h_file = au_hf_top(file);
++ au_unpin(&pin);
++ err = vfsub_write_u(h_file, buf, count, ppos);
++ au_cpup_attr_timesizes(inode);
++ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out:
++ si_read_unlock(inode->i_sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++
++static ssize_t au_do_aio(struct file *h_file, int rw, struct kiocb *kio,
++ const struct iovec *iov, unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ struct file *file;
++ ssize_t (*func)(struct kiocb *, const struct iovec *, unsigned long,
++ loff_t);
++
++ err = security_file_permission(h_file, rw);
++ if (unlikely(err))
++ goto out;
++
++ err = -ENOSYS;
++ func = NULL;
++ if (rw == MAY_READ)
++ func = h_file->f_op->aio_read;
++ else if (rw == MAY_WRITE)
++ func = h_file->f_op->aio_write;
++ if (func) {
++ file = kio->ki_filp;
++ kio->ki_filp = h_file;
++ err = func(kio, iov, nv, pos);
++ kio->ki_filp = file;
++ } else
++ /* currently there is no such fs */
++ WARN_ON_ONCE(1);
++
++out:
++ return err;
++}
++
++static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ struct file *file, *h_file;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ file = kio->ki_filp;
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ h_file = au_hf_top(file);
++ err = au_do_aio(h_file, MAY_READ, kio, iov, nv, pos);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++static ssize_t aufs_aio_write(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *file, *h_file;
++
++ file = kio->ki_filp;
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ au_mtx_and_read_lock(inode);
++
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ au_unpin(&pin);
++ h_file = au_hf_top(file);
++ err = au_do_aio(h_file, MAY_WRITE, kio, iov, nv, pos);
++ au_cpup_attr_timesizes(inode);
++ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out:
++ si_read_unlock(inode->i_sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++
++static ssize_t aufs_splice_read(struct file *file, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ ssize_t err;
++ struct file *h_file;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ err = -EINVAL;
++ h_file = au_hf_top(file);
++ if (au_test_loopback_kthread()) {
++ file->f_mapping = h_file->f_mapping;
++ smp_mb(); /* unnecessary? */
++ }
++ err = vfsub_splice_to(h_file, ppos, pipe, len, flags);
++ /* todo: necessasry? */
++ /* file->f_ra = h_file->f_ra; */
++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++static ssize_t
++aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos,
++ size_t len, unsigned int flags)
++{
++ ssize_t err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *h_file;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ au_mtx_and_read_lock(inode);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ h_file = au_hf_top(file);
++ au_unpin(&pin);
++ err = vfsub_splice_from(pipe, h_file, ppos, len, flags);
++ au_cpup_attr_timesizes(inode);
++ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out:
++ si_read_unlock(inode->i_sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct file *au_safe_file(struct vm_area_struct *vma)
++{
++ struct file *file;
++
++ file = vma->vm_file;
++ if (au_fi(file) && au_test_aufs(file->f_dentry->d_sb))
++ return file;
++ return NULL;
++}
++
++static void au_reset_file(struct vm_area_struct *vma, struct file *file)
++{
++ vma->vm_file = file;
++ /* smp_mb(); */ /* flush vm_file */
++}
++
++static int aufs_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
++{
++ int err;
++ static DECLARE_WAIT_QUEUE_HEAD(wq);
++ struct file *file, *h_file;
++ struct au_finfo *finfo;
++
++ /* todo: non-robr mode, user vm_file as it is? */
++ wait_event(wq, (file = au_safe_file(vma)));
++
++ /* do not revalidate, no si lock */
++ finfo = au_fi(file);
++ AuDebugOn(finfo->fi_hdir);
++ h_file = finfo->fi_htop.hf_file;
++ AuDebugOn(!h_file || !finfo->fi_hvmop);
++
++ mutex_lock(&finfo->fi_vm_mtx);
++ vma->vm_file = h_file;
++ err = finfo->fi_hvmop->fault(vma, vmf);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ au_reset_file(vma, file);
++ mutex_unlock(&finfo->fi_vm_mtx);
++#if 0 /* def CONFIG_SMP */
++ /* wake_up_nr(&wq, online_cpu - 1); */
++ wake_up_all(&wq);
++#else
++ wake_up(&wq);
++#endif
++
++ return err;
++}
++
++static int aufs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
++{
++ int err;
++ static DECLARE_WAIT_QUEUE_HEAD(wq);
++ struct file *file, *h_file;
++ struct au_finfo *finfo;
++
++ wait_event(wq, (file = au_safe_file(vma)));
++
++ finfo = au_fi(file);
++ AuDebugOn(finfo->fi_hdir);
++ h_file = finfo->fi_htop.hf_file;
++ AuDebugOn(!h_file || !finfo->fi_hvmop);
++
++ mutex_lock(&finfo->fi_vm_mtx);
++ vma->vm_file = h_file;
++ err = finfo->fi_hvmop->page_mkwrite(vma, vmf);
++ au_reset_file(vma, file);
++ mutex_unlock(&finfo->fi_vm_mtx);
++ wake_up(&wq);
++
++ return err;
++}
++
++static void aufs_vm_close(struct vm_area_struct *vma)
++{
++ static DECLARE_WAIT_QUEUE_HEAD(wq);
++ struct file *file, *h_file;
++ struct au_finfo *finfo;
++
++ wait_event(wq, (file = au_safe_file(vma)));
++
++ finfo = au_fi(file);
++ AuDebugOn(finfo->fi_hdir);
++ h_file = finfo->fi_htop.hf_file;
++ AuDebugOn(!h_file || !finfo->fi_hvmop);
++
++ mutex_lock(&finfo->fi_vm_mtx);
++ vma->vm_file = h_file;
++ finfo->fi_hvmop->close(vma);
++ au_reset_file(vma, file);
++ mutex_unlock(&finfo->fi_vm_mtx);
++ wake_up(&wq);
++}
++
++const struct vm_operations_struct aufs_vm_ops = {
++ .close = aufs_vm_close,
++ .fault = aufs_fault,
++ .page_mkwrite = aufs_page_mkwrite
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */
++#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b)
++
++static unsigned long au_arch_prot_conv(unsigned long flags)
++{
++ /* currently ppc64 only */
++#ifdef CONFIG_PPC64
++ /* cf. linux/arch/powerpc/include/asm/mman.h */
++ AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO);
++ return AuConv_VM_PROT(flags, SAO);
++#else
++ AuDebugOn(arch_calc_vm_prot_bits(-1));
++ return 0;
++#endif
++}
++
++static unsigned long au_prot_conv(unsigned long flags)
++{
++ return AuConv_VM_PROT(flags, READ)
++ | AuConv_VM_PROT(flags, WRITE)
++ | AuConv_VM_PROT(flags, EXEC)
++ | au_arch_prot_conv(flags);
++}
++
++/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */
++#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b)
++
++static unsigned long au_flag_conv(unsigned long flags)
++{
++ return AuConv_VM_MAP(flags, GROWSDOWN)
++ | AuConv_VM_MAP(flags, DENYWRITE)
++ | AuConv_VM_MAP(flags, EXECUTABLE)
++ | AuConv_VM_MAP(flags, LOCKED);
++}
++
++static struct vm_operations_struct *
++au_hvmop(struct file *h_file, struct vm_area_struct *vma, unsigned long *flags)
++{
++ struct vm_operations_struct *h_vmop;
++ unsigned long prot;
++ int err;
++
++ h_vmop = ERR_PTR(-ENODEV);
++ if (!h_file->f_op || !h_file->f_op->mmap)
++ goto out;
++
++ prot = au_prot_conv(vma->vm_flags);
++ err = security_file_mmap(h_file, /*reqprot*/prot, prot,
++ au_flag_conv(vma->vm_flags), vma->vm_start, 0);
++ h_vmop = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ err = h_file->f_op->mmap(h_file, vma);
++ h_vmop = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ /* oops, it became 'const' */
++ h_vmop = (struct vm_operations_struct *)vma->vm_ops;
++ *flags = vma->vm_flags;
++ err = do_munmap(current->mm, vma->vm_start,
++ vma->vm_end - vma->vm_start);
++ if (unlikely(err)) {
++ AuIOErr("failed internal unmapping %.*s, %d\n",
++ AuDLNPair(h_file->f_dentry), err);
++ h_vmop = ERR_PTR(-EIO);
++ }
++
++out:
++ return h_vmop;
++}
++
++/*
++ * This is another ugly approach to keep the lock order, particularly
++ * mm->mmap_sem and aufs rwsem. The previous approach was reverted and you can
++ * find it in git-log, if you want.
++ *
++ * native readdir: i_mutex, copy_to_user, mmap_sem
++ * aufs readdir: i_mutex, rwsem, nested-i_mutex, copy_to_user, mmap_sem
++ *
++ * Before aufs_mmap() mmap_sem is acquired already, but aufs_mmap() has to
++ * acquire aufs rwsem. It introduces a circular locking dependency.
++ * To address this problem, aufs_mmap() delegates the part which requires aufs
++ * rwsem to its internal workqueue.
++ */
++
++/* very ugly approach */
++#include "mtx.h"
++
++struct au_mmap_pre_args {
++ /* input */
++ struct file *file;
++ struct vm_area_struct *vma;
++
++ /* output */
++ int *errp;
++ struct file *h_file;
++ struct au_branch *br;
++ int mmapped;
++};
++
++static int au_mmap_pre(struct file *file, struct vm_area_struct *vma,
++ struct file **h_file, struct au_branch **br,
++ int *mmapped)
++{
++ int err;
++ aufs_bindex_t bstart;
++ const unsigned char wlock
++ = !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED);
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ *mmapped = !!au_test_mmapped(file);
++ if (wlock) {
++ struct au_pin pin;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_write_unlock(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ au_unpin(&pin);
++ } else
++ di_write_unlock(dentry);
++ bstart = au_fbstart(file);
++ *br = au_sbr(sb, bstart);
++ *h_file = au_hf_top(file);
++ get_file(*h_file);
++ au_fi_mmap_lock(file);
++
++out_unlock:
++ fi_write_unlock(file);
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++static void au_call_mmap_pre(void *args)
++{
++ struct au_mmap_pre_args *a = args;
++ *a->errp = au_mmap_pre(a->file, a->vma, &a->h_file, &a->br,
++ &a->mmapped);
++}
++
++static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ int err, wkq_err;
++ unsigned long h_vmflags;
++ struct au_finfo *finfo;
++ struct dentry *h_dentry;
++ struct vm_operations_struct *h_vmop, *vmop;
++ struct au_mmap_pre_args args = {
++ .file = file,
++ .vma = vma,
++ .errp = &err
++ };
++
++ wkq_err = au_wkq_wait_pre(au_call_mmap_pre, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ if (unlikely(err))
++ goto out;
++ finfo = au_fi(file);
++ mutex_set_owner(&finfo->fi_mmap);
++
++ h_dentry = args.h_file->f_dentry;
++ if (!args.mmapped && au_test_fs_bad_mapping(h_dentry->d_sb)) {
++ /*
++ * by this assignment, f_mapping will differs from aufs inode
++ * i_mapping.
++ * if someone else mixes the use of f_dentry->d_inode and
++ * f_mapping->host, then a problem may arise.
++ */
++ file->f_mapping = args.h_file->f_mapping;
++ }
++
++ /* always try this internal mmap to get vma flags */
++ h_vmflags = 0; /* gcc warning */
++ h_vmop = au_hvmop(args.h_file, vma, &h_vmflags);
++ err = PTR_ERR(h_vmop);
++ if (IS_ERR(h_vmop))
++ goto out_unlock;
++ AuDebugOn(args.mmapped && h_vmop != finfo->fi_hvmop);
++
++ vmop = (void *)au_dy_vmop(file, args.br, h_vmop);
++ err = PTR_ERR(vmop);
++ if (IS_ERR(vmop))
++ goto out_unlock;
++
++ /*
++ * unnecessary to handle MAP_DENYWRITE and deny_write_access()?
++ * currently MAP_DENYWRITE from userspace is ignored, but elf loader
++ * sets it. when FMODE_EXEC is set (by open_exec() or sys_uselib()),
++ * both of the aufs file and the lower file is deny_write_access()-ed.
++ * finally I hope we can skip handlling MAP_DENYWRITE here.
++ */
++ err = generic_file_mmap(file, vma);
++ if (unlikely(err))
++ goto out_unlock;
++
++ vma->vm_ops = vmop;
++ vma->vm_flags = h_vmflags;
++ if (!args.mmapped)
++ finfo->fi_hvmop = h_vmop;
++
++ vfsub_file_accessed(args.h_file);
++ /* update without lock, I don't think it a problem */
++ fsstack_copy_attr_atime(file->f_dentry->d_inode, h_dentry->d_inode);
++
++out_unlock:
++ au_fi_mmap_unlock(file);
++ fput(args.h_file);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_fsync_nondir(struct file *file, int datasync)
++{
++ int err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *h_file;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ IMustLock(file->f_mapping->host);
++ if (inode != file->f_mapping->host) {
++ mutex_unlock(&file->f_mapping->host->i_mutex);
++ mutex_lock(&inode->i_mutex);
++ }
++ IMustLock(inode);
++
++ sb = dentry->d_sb;
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out;
++
++ err = 0; /* -EBADF; */ /* posix? */
++ if (unlikely(!(file->f_mode & FMODE_WRITE)))
++ goto out_si;
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out_si;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++ au_unpin(&pin);
++
++ err = -EINVAL;
++ h_file = au_hf_top(file);
++ if (h_file->f_op && h_file->f_op->fsync) {
++ struct mutex *h_mtx;
++
++ /*
++ * no filemap_fdatawrite() since aufs file has no its own
++ * mapping, but dir.
++ */
++ h_mtx = &h_file->f_dentry->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ err = h_file->f_op->fsync(h_file, datasync);
++ if (!err)
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL);
++ /*ignore*/
++ au_cpup_attr_timesizes(inode);
++ mutex_unlock(h_mtx);
++ }
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out_si:
++ si_read_unlock(sb);
++out:
++ if (inode != file->f_mapping->host) {
++ mutex_unlock(&inode->i_mutex);
++ mutex_lock(&file->f_mapping->host->i_mutex);
++ }
++ return err;
++}
++
++/* no one supports this operation, currently */
++#if 0
++static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync)
++{
++ int err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *file, *h_file;
++
++ file = kio->ki_filp;
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ au_mtx_and_read_lock(inode);
++
++ err = 0; /* -EBADF; */ /* posix? */
++ if (unlikely(!(file->f_mode & FMODE_WRITE)))
++ goto out;
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++ au_unpin(&pin);
++
++ err = -ENOSYS;
++ h_file = au_hf_top(file);
++ if (h_file->f_op && h_file->f_op->aio_fsync) {
++ struct dentry *h_d;
++ struct mutex *h_mtx;
++
++ h_d = h_file->f_dentry;
++ h_mtx = &h_d->d_inode->i_mutex;
++ if (!is_sync_kiocb(kio)) {
++ get_file(h_file);
++ fput(file);
++ }
++ kio->ki_filp = h_file;
++ err = h_file->f_op->aio_fsync(kio, datasync);
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ if (!err)
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL);
++ /*ignore*/
++ au_cpup_attr_timesizes(inode);
++ mutex_unlock(h_mtx);
++ }
++
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++out:
++ si_read_unlock(inode->sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++#endif
++
++static int aufs_fasync(int fd, struct file *file, int flag)
++{
++ int err;
++ struct file *h_file;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ h_file = au_hf_top(file);
++ if (h_file->f_op && h_file->f_op->fasync)
++ err = h_file->f_op->fasync(fd, h_file, flag);
++
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* no one supports this operation, currently */
++#if 0
++static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset,
++ size_t len, loff_t *pos , int more)
++{
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++const struct file_operations aufs_file_fop = {
++ .owner = THIS_MODULE,
++ /*
++ * while generic_file_llseek/_unlocked() don't use BKL,
++ * don't use it since it operates file->f_mapping->host.
++ * in aufs, it may be a real file and may confuse users by UDBA.
++ */
++ /* .llseek = generic_file_llseek, */
++
++ .read = aufs_read,
++ .write = aufs_write,
++ .aio_read = aufs_aio_read,
++ .aio_write = aufs_aio_write,
++#ifdef CONFIG_AUFS_POLL
++ .poll = aufs_poll,
++#endif
++ .unlocked_ioctl = aufs_ioctl_nondir,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = aufs_ioctl_nondir, /* same */
++#endif
++ .mmap = aufs_mmap,
++ .open = aufs_open_nondir,
++ .flush = aufs_flush_nondir,
++ .release = aufs_release_nondir,
++ .fsync = aufs_fsync_nondir,
++ /* .aio_fsync = aufs_aio_fsync_nondir, */
++ .fasync = aufs_fasync,
++ /* .sendpage = aufs_sendpage, */
++ .splice_write = aufs_splice_write,
++ .splice_read = aufs_splice_read,
++#if 0
++ .aio_splice_write = aufs_aio_splice_write,
++ .aio_splice_read = aufs_aio_splice_read
++#endif
++};
+diff -Nur linux-2.6.37.orig/fs/aufs/f_op_sp.c linux-2.6.37/fs/aufs/f_op_sp.c
+--- linux-2.6.37.orig/fs/aufs/f_op_sp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/f_op_sp.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,299 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * file operations for special files.
++ * while they exist in aufs virtually,
++ * their file I/O is handled out of aufs.
++ */
++
++#include <linux/fs_stack.h>
++#include "aufs.h"
++
++static ssize_t aufs_aio_read_sp(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ aufs_bindex_t bstart;
++ unsigned char wbr;
++ struct file *file, *h_file;
++ struct super_block *sb;
++
++ file = kio->ki_filp;
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ fi_read_lock(file);
++ bstart = au_fbstart(file);
++ h_file = au_hf_top(file);
++ fi_read_unlock(file);
++ wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm);
++ si_read_unlock(sb);
++
++ /* do not change the file in kio */
++ AuDebugOn(!h_file->f_op || !h_file->f_op->aio_read);
++ err = h_file->f_op->aio_read(kio, iov, nv, pos);
++ if (err > 0 && wbr)
++ file_accessed(h_file);
++
++ return err;
++}
++
++static ssize_t aufs_aio_write_sp(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ aufs_bindex_t bstart;
++ unsigned char wbr;
++ struct super_block *sb;
++ struct file *file, *h_file;
++
++ file = kio->ki_filp;
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ fi_read_lock(file);
++ bstart = au_fbstart(file);
++ h_file = au_hf_top(file);
++ fi_read_unlock(file);
++ wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm);
++ si_read_unlock(sb);
++
++ /* do not change the file in kio */
++ AuDebugOn(!h_file->f_op || !h_file->f_op->aio_write);
++ err = h_file->f_op->aio_write(kio, iov, nv, pos);
++ if (err > 0 && wbr)
++ file_update_time(h_file);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_release_sp(struct inode *inode, struct file *file)
++{
++ int err;
++ struct file *h_file;
++
++ fi_read_lock(file);
++ h_file = au_hf_top(file);
++ fi_read_unlock(file);
++ /* close this fifo in aufs */
++ err = h_file->f_op->release(inode, file); /* ignore */
++ aufs_release_nondir(inode, file); /* ignore */
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* currently, support only FIFO */
++enum {
++ AuSp_FIFO, AuSp_FIFO_R, AuSp_FIFO_W, AuSp_FIFO_RW,
++ /* AuSp_SOCK, AuSp_CHR, AuSp_BLK, */
++ AuSp_Last
++};
++static int aufs_open_sp(struct inode *inode, struct file *file);
++static struct au_sp_fop {
++ int done;
++ struct file_operations fop; /* not 'const' */
++ spinlock_t spin;
++} au_sp_fop[AuSp_Last] = {
++ [AuSp_FIFO] = {
++ .fop = {
++ .owner = THIS_MODULE,
++ .open = aufs_open_sp
++ }
++ }
++};
++
++static void au_init_fop_sp(struct file *file)
++{
++ struct au_sp_fop *p;
++ int i;
++ struct file *h_file;
++
++ p = au_sp_fop;
++ if (unlikely(!p->done)) {
++ /* initialize first time only */
++ static DEFINE_SPINLOCK(spin);
++
++ spin_lock(&spin);
++ if (!p->done) {
++ BUILD_BUG_ON(sizeof(au_sp_fop)/sizeof(*au_sp_fop)
++ != AuSp_Last);
++ for (i = 0; i < AuSp_Last; i++)
++ spin_lock_init(&p[i].spin);
++ p->done = 1;
++ }
++ spin_unlock(&spin);
++ }
++
++ switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) {
++ case FMODE_READ:
++ i = AuSp_FIFO_R;
++ break;
++ case FMODE_WRITE:
++ i = AuSp_FIFO_W;
++ break;
++ case FMODE_READ | FMODE_WRITE:
++ i = AuSp_FIFO_RW;
++ break;
++ default:
++ BUG();
++ }
++
++ p += i;
++ if (unlikely(!p->done)) {
++ /* initialize first time only */
++ h_file = au_hf_top(file);
++ spin_lock(&p->spin);
++ if (!p->done) {
++ p->fop = *h_file->f_op;
++ p->fop.owner = THIS_MODULE;
++ if (p->fop.aio_read)
++ p->fop.aio_read = aufs_aio_read_sp;
++ if (p->fop.aio_write)
++ p->fop.aio_write = aufs_aio_write_sp;
++ p->fop.release = aufs_release_sp;
++ p->done = 1;
++ }
++ spin_unlock(&p->spin);
++ }
++ file->f_op = &p->fop;
++}
++
++static int au_cpup_sp(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bcpup;
++ struct au_pin pin;
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = 0
++ };
++
++ AuDbg("%.*s\n", AuDLNPair(dentry));
++
++ di_read_unlock(dentry, AuLock_IR);
++ di_write_lock_child(dentry);
++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
++ if (unlikely(err < 0))
++ goto out;
++ bcpup = err;
++ err = 0;
++ if (bcpup == au_dbstart(dentry))
++ goto out; /* success */
++
++ err = au_pin(&pin, dentry, bcpup, au_opt_udba(dentry->d_sb),
++ AuPin_MNT_WRITE);
++ if (!err) {
++ err = au_sio_cpup_simple(dentry, bcpup, -1, AuCpup_DTIME);
++ au_unpin(&pin);
++ }
++
++out:
++ di_downgrade_lock(dentry, AuLock_IR);
++ return err;
++}
++
++static int au_do_open_sp(struct file *file, int flags)
++{
++ int err;
++ struct dentry *dentry;
++ struct super_block *sb;
++ struct file *h_file;
++ struct inode *h_inode;
++
++ dentry = file->f_dentry;
++ AuDbg("%.*s\n", AuDLNPair(dentry));
++
++ /*
++ * try copying-up.
++ * operate on the ro branch is not an error.
++ */
++ au_cpup_sp(dentry); /* ignore */
++
++ /* prepare h_file */
++ err = au_do_open_nondir(file, vfsub_file_flags(file));
++ if (unlikely(err))
++ goto out;
++
++ sb = dentry->d_sb;
++ h_file = au_hf_top(file);
++ h_inode = h_file->f_dentry->d_inode;
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ si_read_unlock(sb);
++ /* open this fifo in aufs */
++ err = h_inode->i_fop->open(file->f_dentry->d_inode, file);
++ si_noflush_read_lock(sb);
++ fi_write_lock(file);
++ di_read_lock_child(dentry, AuLock_IR);
++ if (!err)
++ au_init_fop_sp(file);
++
++out:
++ return err;
++}
++
++static int aufs_open_sp(struct inode *inode, struct file *file)
++{
++ int err;
++ struct super_block *sb;
++
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_do_open(file, au_do_open_sp, /*fidir*/NULL);
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev)
++{
++ init_special_inode(inode, mode, rdev);
++
++ switch (mode & S_IFMT) {
++ case S_IFIFO:
++ inode->i_fop = &au_sp_fop[AuSp_FIFO].fop;
++ /*FALLTHROUGH*/
++ case S_IFCHR:
++ case S_IFBLK:
++ case S_IFSOCK:
++ break;
++ default:
++ AuDebugOn(1);
++ }
++}
++
++int au_special_file(umode_t mode)
++{
++ int ret;
++
++ ret = 0;
++ switch (mode & S_IFMT) {
++ case S_IFIFO:
++#if 0
++ case S_IFCHR:
++ case S_IFBLK:
++ case S_IFSOCK:
++#endif
++ ret = 1;
++ }
++
++ return ret;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/file.c linux-2.6.37/fs/aufs/file.c
+--- linux-2.6.37.orig/fs/aufs/file.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/file.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,676 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * handling file/dir, and address_space operation
++ */
++
++#include <linux/file.h>
++#include <linux/fsnotify.h>
++#include <linux/namei.h>
++#include <linux/pagemap.h>
++#include "aufs.h"
++
++/* drop flags for writing */
++unsigned int au_file_roflags(unsigned int flags)
++{
++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC);
++ flags |= O_RDONLY | O_NOATIME;
++ return flags;
++}
++
++/* common functions to regular file and dir */
++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
++ struct file *file)
++{
++ struct file *h_file;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++ struct super_block *sb;
++ struct au_branch *br;
++ struct path h_path;
++ int err, exec_flag;
++
++ /* a race condition can happen between open and unlink/rmdir */
++ h_file = ERR_PTR(-ENOENT);
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (au_test_nfsd() && !h_dentry)
++ goto out;
++ h_inode = h_dentry->d_inode;
++ if (au_test_nfsd() && !h_inode)
++ goto out;
++ if (unlikely((!d_unhashed(dentry) && au_d_removed(h_dentry))
++ || !h_inode
++ /* || !dentry->d_inode->i_nlink */
++ ))
++ goto out;
++
++ sb = dentry->d_sb;
++ br = au_sbr(sb, bindex);
++ h_file = ERR_PTR(-EACCES);
++ exec_flag = flags & vfsub_fmode_to_uint(FMODE_EXEC);
++ if (exec_flag && (br->br_mnt->mnt_flags & MNT_NOEXEC))
++ goto out;
++
++ /* drop flags for writing */
++ if (au_test_ro(sb, bindex, dentry->d_inode))
++ flags = au_file_roflags(flags);
++ flags &= ~O_CREAT;
++ atomic_inc(&br->br_count);
++ h_path.dentry = h_dentry;
++ h_path.mnt = br->br_mnt;
++ if (!au_special_file(h_inode->i_mode))
++ h_file = vfsub_dentry_open(&h_path, flags);
++ else {
++ /* this block depends upon the configuration */
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ si_read_unlock(sb);
++ h_file = vfsub_dentry_open(&h_path, flags);
++ si_noflush_read_lock(sb);
++ fi_write_lock(file);
++ di_read_lock_child(dentry, AuLock_IR);
++ }
++ if (IS_ERR(h_file))
++ goto out_br;
++
++ if (exec_flag) {
++ err = deny_write_access(h_file);
++ if (unlikely(err)) {
++ fput(h_file);
++ h_file = ERR_PTR(err);
++ goto out_br;
++ }
++ }
++ fsnotify_open(h_file);
++ goto out; /* success */
++
++out_br:
++ atomic_dec(&br->br_count);
++out:
++ return h_file;
++}
++
++int au_do_open(struct file *file, int (*open)(struct file *file, int flags),
++ struct au_fidir *fidir)
++{
++ int err;
++ struct dentry *dentry;
++
++ err = au_finfo_init(file, fidir);
++ if (unlikely(err))
++ goto out;
++
++ dentry = file->f_dentry;
++ di_read_lock_child(dentry, AuLock_IR);
++ err = open(file, vfsub_file_flags(file));
++ di_read_unlock(dentry, AuLock_IR);
++
++ fi_write_unlock(file);
++ if (unlikely(err)) {
++ au_fi(file)->fi_hdir = NULL;
++ au_finfo_fin(file);
++ }
++
++out:
++ return err;
++}
++
++int au_reopen_nondir(struct file *file)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct dentry *dentry;
++ struct file *h_file, *h_file_tmp;
++
++ dentry = file->f_dentry;
++ AuDebugOn(au_special_file(dentry->d_inode->i_mode));
++ bstart = au_dbstart(dentry);
++ h_file_tmp = NULL;
++ if (au_fbstart(file) == bstart) {
++ h_file = au_hf_top(file);
++ if (file->f_mode == h_file->f_mode)
++ return 0; /* success */
++ h_file_tmp = h_file;
++ get_file(h_file_tmp);
++ au_set_h_fptr(file, bstart, NULL);
++ }
++ AuDebugOn(au_fi(file)->fi_hdir);
++ AuDebugOn(au_fbstart(file) < bstart);
++
++ h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC,
++ file);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out; /* todo: close all? */
++
++ err = 0;
++ au_set_fbstart(file, bstart);
++ au_set_h_fptr(file, bstart, h_file);
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++
++out:
++ if (h_file_tmp)
++ fput(h_file_tmp);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_reopen_wh(struct file *file, aufs_bindex_t btgt,
++ struct dentry *hi_wh)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct au_dinfo *dinfo;
++ struct dentry *h_dentry;
++ struct au_hdentry *hdp;
++
++ dinfo = au_di(file->f_dentry);
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ bstart = dinfo->di_bstart;
++ dinfo->di_bstart = btgt;
++ hdp = dinfo->di_hdentry;
++ h_dentry = hdp[0 + btgt].hd_dentry;
++ hdp[0 + btgt].hd_dentry = hi_wh;
++ err = au_reopen_nondir(file);
++ hdp[0 + btgt].hd_dentry = h_dentry;
++ dinfo->di_bstart = bstart;
++
++ return err;
++}
++
++static int au_ready_to_write_wh(struct file *file, loff_t len,
++ aufs_bindex_t bcpup)
++{
++ int err;
++ struct inode *inode, *h_inode;
++ struct dentry *dentry, *h_dentry, *hi_wh;
++
++ dentry = file->f_dentry;
++ au_update_dbstart(dentry);
++ inode = dentry->d_inode;
++ h_inode = NULL;
++ if (au_dbstart(dentry) <= bcpup && au_dbend(dentry) >= bcpup) {
++ h_dentry = au_h_dptr(dentry, bcpup);
++ if (h_dentry)
++ h_inode = h_dentry->d_inode;
++ }
++ hi_wh = au_hi_wh(inode, bcpup);
++ if (!hi_wh && !h_inode)
++ err = au_sio_cpup_wh(dentry, bcpup, len, file);
++ else
++ /* already copied-up after unlink */
++ err = au_reopen_wh(file, bcpup, hi_wh);
++
++ if (!err
++ && inode->i_nlink > 1
++ && au_opt_test(au_mntflags(dentry->d_sb), PLINK))
++ au_plink_append(inode, bcpup, au_h_dptr(dentry, bcpup));
++
++ return err;
++}
++
++/*
++ * prepare the @file for writing.
++ */
++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
++{
++ int err;
++ aufs_bindex_t bstart, bcpup, dbstart;
++ struct dentry *dentry, *parent, *h_dentry;
++ struct inode *h_inode, *inode;
++ struct super_block *sb;
++ struct file *h_file;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ AuDebugOn(au_special_file(inode->i_mode));
++ bstart = au_fbstart(file);
++ err = au_test_ro(sb, bstart, inode);
++ if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) {
++ err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0);
++ goto out;
++ }
++
++ /* need to cpup or reopen */
++ parent = dget_parent(dentry);
++ di_write_lock_parent(parent);
++ err = AuWbrCopyup(au_sbi(sb), dentry);
++ bcpup = err;
++ if (unlikely(err < 0))
++ goto out_dgrade;
++ err = 0;
++
++ if (!d_unhashed(dentry) && !au_h_dptr(parent, bcpup)) {
++ err = au_cpup_dirs(dentry, bcpup);
++ if (unlikely(err))
++ goto out_dgrade;
++ }
++
++ err = au_pin(pin, dentry, bcpup, AuOpt_UDBA_NONE,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (unlikely(err))
++ goto out_dgrade;
++
++ h_dentry = au_hf_top(file)->f_dentry;
++ h_inode = h_dentry->d_inode;
++ dbstart = au_dbstart(dentry);
++ if (dbstart <= bcpup) {
++ h_dentry = au_h_dptr(dentry, bcpup);
++ AuDebugOn(!h_dentry);
++ h_inode = h_dentry->d_inode;
++ AuDebugOn(!h_inode);
++ bstart = bcpup;
++ }
++
++ if (dbstart <= bcpup /* just reopen */
++ || !d_unhashed(dentry) /* copyup and reopen */
++ ) {
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ h_file = au_h_open_pre(dentry, bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else {
++ di_downgrade_lock(parent, AuLock_IR);
++ if (dbstart > bcpup)
++ err = au_sio_cpup_simple(dentry, bcpup, len,
++ AuCpup_DTIME);
++ if (!err)
++ err = au_reopen_nondir(file);
++ }
++ mutex_unlock(&h_inode->i_mutex);
++ au_h_open_post(dentry, bstart, h_file);
++ } else { /* copyup as wh and reopen */
++ /*
++ * since writable hfsplus branch is not supported,
++ * h_open_pre/post() are unnecessary.
++ */
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ err = au_ready_to_write_wh(file, len, bcpup);
++ di_downgrade_lock(parent, AuLock_IR);
++ mutex_unlock(&h_inode->i_mutex);
++ }
++
++ if (!err) {
++ au_pin_set_parent_lflag(pin, /*lflag*/0);
++ goto out_dput; /* success */
++ }
++ au_unpin(pin);
++ goto out_unlock;
++
++out_dgrade:
++ di_downgrade_lock(parent, AuLock_IR);
++out_unlock:
++ di_read_unlock(parent, AuLock_IR);
++out_dput:
++ dput(parent);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_do_flush(struct file *file, fl_owner_t id,
++ int (*flush)(struct file *file, fl_owner_t id))
++{
++ int err;
++ struct dentry *dentry;
++ struct super_block *sb;
++ struct inode *inode;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ si_noflush_read_lock(sb);
++ fi_read_lock(file);
++ ii_read_lock_child(inode);
++
++ err = flush(file, id);
++ au_cpup_attr_timesizes(inode);
++
++ ii_read_unlock(inode);
++ fi_read_unlock(file);
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_file_refresh_by_inode(struct file *file, int *need_reopen)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct au_pin pin;
++ struct au_finfo *finfo;
++ struct dentry *dentry, *parent, *hi_wh;
++ struct inode *inode;
++ struct super_block *sb;
++
++ FiMustWriteLock(file);
++
++ err = 0;
++ finfo = au_fi(file);
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ bstart = au_ibstart(inode);
++ if (bstart == finfo->fi_btop || IS_ROOT(dentry))
++ goto out;
++
++ parent = dget_parent(dentry);
++ if (au_test_ro(sb, bstart, inode)) {
++ di_read_lock_parent(parent, !AuLock_IR);
++ err = AuWbrCopyup(au_sbi(sb), dentry);
++ bstart = err;
++ di_read_unlock(parent, !AuLock_IR);
++ if (unlikely(err < 0))
++ goto out_parent;
++ err = 0;
++ }
++
++ di_read_lock_parent(parent, AuLock_IR);
++ hi_wh = au_hi_wh(inode, bstart);
++ if (!S_ISDIR(inode->i_mode)
++ && au_opt_test(au_mntflags(sb), PLINK)
++ && au_plink_test(inode)
++ && !d_unhashed(dentry)) {
++ err = au_test_and_cpup_dirs(dentry, bstart);
++ if (unlikely(err))
++ goto out_unlock;
++
++ /* always superio. */
++ err = au_pin(&pin, dentry, bstart, AuOpt_UDBA_NONE,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (!err)
++ err = au_sio_cpup_simple(dentry, bstart, -1,
++ AuCpup_DTIME);
++ au_unpin(&pin);
++ } else if (hi_wh) {
++ /* already copied-up after unlink */
++ err = au_reopen_wh(file, bstart, hi_wh);
++ *need_reopen = 0;
++ }
++
++out_unlock:
++ di_read_unlock(parent, AuLock_IR);
++out_parent:
++ dput(parent);
++out:
++ return err;
++}
++
++static void au_do_refresh_dir(struct file *file)
++{
++ aufs_bindex_t bindex, bend, new_bindex, brid;
++ struct au_hfile *p, tmp, *q;
++ struct au_finfo *finfo;
++ struct super_block *sb;
++ struct au_fidir *fidir;
++
++ FiMustWriteLock(file);
++
++ sb = file->f_dentry->d_sb;
++ finfo = au_fi(file);
++ fidir = finfo->fi_hdir;
++ AuDebugOn(!fidir);
++ p = fidir->fd_hfile + finfo->fi_btop;
++ brid = p->hf_br->br_id;
++ bend = fidir->fd_bbot;
++ for (bindex = finfo->fi_btop; bindex <= bend; bindex++, p++) {
++ if (!p->hf_file)
++ continue;
++
++ new_bindex = au_br_index(sb, p->hf_br->br_id);
++ if (new_bindex == bindex)
++ continue;
++ if (new_bindex < 0) {
++ au_set_h_fptr(file, bindex, NULL);
++ continue;
++ }
++
++ /* swap two lower inode, and loop again */
++ q = fidir->fd_hfile + new_bindex;
++ tmp = *q;
++ *q = *p;
++ *p = tmp;
++ if (tmp.hf_file) {
++ bindex--;
++ p--;
++ }
++ }
++
++ p = fidir->fd_hfile;
++ if (!au_test_mmapped(file) && !au_d_removed(file->f_dentry)) {
++ bend = au_sbend(sb);
++ for (finfo->fi_btop = 0; finfo->fi_btop <= bend;
++ finfo->fi_btop++, p++)
++ if (p->hf_file) {
++ if (p->hf_file->f_dentry
++ && p->hf_file->f_dentry->d_inode)
++ break;
++ else
++ au_hfput(p, file);
++ }
++ } else {
++ bend = au_br_index(sb, brid);
++ for (finfo->fi_btop = 0; finfo->fi_btop < bend;
++ finfo->fi_btop++, p++)
++ if (p->hf_file)
++ au_hfput(p, file);
++ bend = au_sbend(sb);
++ }
++
++ p = fidir->fd_hfile + bend;
++ for (fidir->fd_bbot = bend; fidir->fd_bbot >= finfo->fi_btop;
++ fidir->fd_bbot--, p--)
++ if (p->hf_file) {
++ if (p->hf_file->f_dentry
++ && p->hf_file->f_dentry->d_inode)
++ break;
++ else
++ au_hfput(p, file);
++ }
++ AuDebugOn(fidir->fd_bbot < finfo->fi_btop);
++}
++
++/*
++ * after branch manipulating, refresh the file.
++ */
++static int refresh_file(struct file *file, int (*reopen)(struct file *file))
++{
++ int err, need_reopen;
++ aufs_bindex_t bend, bindex;
++ struct dentry *dentry;
++ struct au_finfo *finfo;
++ struct au_hfile *hfile;
++
++ dentry = file->f_dentry;
++ finfo = au_fi(file);
++ if (!finfo->fi_hdir) {
++ hfile = &finfo->fi_htop;
++ AuDebugOn(!hfile->hf_file);
++ bindex = au_br_index(dentry->d_sb, hfile->hf_br->br_id);
++ AuDebugOn(bindex < 0);
++ if (bindex != finfo->fi_btop)
++ au_set_fbstart(file, bindex);
++ } else {
++ err = au_fidir_realloc(finfo, au_sbend(dentry->d_sb) + 1);
++ if (unlikely(err))
++ goto out;
++ au_do_refresh_dir(file);
++ }
++
++ err = 0;
++ need_reopen = 1;
++ if (!au_test_mmapped(file))
++ err = au_file_refresh_by_inode(file, &need_reopen);
++ if (!err && need_reopen && !au_d_removed(dentry))
++ err = reopen(file);
++ if (!err) {
++ au_update_figen(file);
++ goto out; /* success */
++ }
++
++ /* error, close all lower files */
++ if (finfo->fi_hdir) {
++ bend = au_fbend_dir(file);
++ for (bindex = au_fbstart(file); bindex <= bend; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++ }
++
++out:
++ return err;
++}
++
++/* common function to regular file and dir */
++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
++ int wlock)
++{
++ int err;
++ unsigned int sigen, figen;
++ aufs_bindex_t bstart;
++ unsigned char pseudo_link;
++ struct dentry *dentry;
++ struct inode *inode;
++
++ err = 0;
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ AuDebugOn(au_special_file(inode->i_mode));
++ sigen = au_sigen(dentry->d_sb);
++ fi_write_lock(file);
++ figen = au_figen(file);
++ di_write_lock_child(dentry);
++ bstart = au_dbstart(dentry);
++ pseudo_link = (bstart != au_ibstart(inode));
++ if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) {
++ if (!wlock) {
++ di_downgrade_lock(dentry, AuLock_IR);
++ fi_downgrade_lock(file);
++ }
++ goto out; /* success */
++ }
++
++ AuDbg("sigen %d, figen %d\n", sigen, figen);
++ if (au_digen_test(dentry, sigen)) {
++ err = au_reval_dpath(dentry, sigen);
++ AuDebugOn(!err && au_digen_test(dentry, sigen));
++ }
++
++ if (!err)
++ err = refresh_file(file, reopen);
++ if (!err) {
++ if (!wlock) {
++ di_downgrade_lock(dentry, AuLock_IR);
++ fi_downgrade_lock(file);
++ }
++ } else {
++ di_write_unlock(dentry);
++ fi_write_unlock(file);
++ }
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* cf. aufs_nopage() */
++/* for madvise(2) */
++static int aufs_readpage(struct file *file __maybe_unused, struct page *page)
++{
++ unlock_page(page);
++ return 0;
++}
++
++/* it will never be called, but necessary to support O_DIRECT */
++static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb,
++ const struct iovec *iov, loff_t offset,
++ unsigned long nr_segs)
++{ BUG(); return 0; }
++
++/*
++ * it will never be called, but madvise and fadvise behaves differently
++ * when get_xip_mem is defined
++ */
++static int aufs_get_xip_mem(struct address_space *mapping, pgoff_t pgoff,
++ int create, void **kmem, unsigned long *pfn)
++{ BUG(); return 0; }
++
++/* they will never be called. */
++#ifdef CONFIG_AUFS_DEBUG
++static int aufs_write_begin(struct file *file, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned flags,
++ struct page **pagep, void **fsdata)
++{ AuUnsupport(); return 0; }
++static int aufs_write_end(struct file *file, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned copied,
++ struct page *page, void *fsdata)
++{ AuUnsupport(); return 0; }
++static int aufs_writepage(struct page *page, struct writeback_control *wbc)
++{ AuUnsupport(); return 0; }
++static void aufs_sync_page(struct page *page)
++{ AuUnsupport(); }
++
++static int aufs_set_page_dirty(struct page *page)
++{ AuUnsupport(); return 0; }
++static void aufs_invalidatepage(struct page *page, unsigned long offset)
++{ AuUnsupport(); }
++static int aufs_releasepage(struct page *page, gfp_t gfp)
++{ AuUnsupport(); return 0; }
++static int aufs_migratepage(struct address_space *mapping, struct page *newpage,
++ struct page *page)
++{ AuUnsupport(); return 0; }
++static int aufs_launder_page(struct page *page)
++{ AuUnsupport(); return 0; }
++static int aufs_is_partially_uptodate(struct page *page,
++ read_descriptor_t *desc,
++ unsigned long from)
++{ AuUnsupport(); return 0; }
++static int aufs_error_remove_page(struct address_space *mapping,
++ struct page *page)
++{ AuUnsupport(); return 0; }
++#endif /* CONFIG_AUFS_DEBUG */
++
++const struct address_space_operations aufs_aop = {
++ .readpage = aufs_readpage,
++ .direct_IO = aufs_direct_IO,
++ .get_xip_mem = aufs_get_xip_mem,
++#ifdef CONFIG_AUFS_DEBUG
++ .writepage = aufs_writepage,
++ .sync_page = aufs_sync_page,
++ /* no writepages, because of writepage */
++ .set_page_dirty = aufs_set_page_dirty,
++ /* no readpages, because of readpage */
++ .write_begin = aufs_write_begin,
++ .write_end = aufs_write_end,
++ /* no bmap, no block device */
++ .invalidatepage = aufs_invalidatepage,
++ .releasepage = aufs_releasepage,
++ .migratepage = aufs_migratepage,
++ .launder_page = aufs_launder_page,
++ .is_partially_uptodate = aufs_is_partially_uptodate,
++ .error_remove_page = aufs_error_remove_page
++#endif /* CONFIG_AUFS_DEBUG */
++};
+diff -Nur linux-2.6.37.orig/fs/aufs/file.h linux-2.6.37/fs/aufs/file.h
+--- linux-2.6.37.orig/fs/aufs/file.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/file.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,238 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * file operations
++ */
++
++#ifndef __AUFS_FILE_H__
++#define __AUFS_FILE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/poll.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++
++struct au_branch;
++struct au_hfile {
++ struct file *hf_file;
++ struct au_branch *hf_br;
++};
++
++struct au_vdir;
++struct au_fidir {
++ aufs_bindex_t fd_bbot;
++ aufs_bindex_t fd_nent;
++ struct au_vdir *fd_vdir_cache;
++ struct au_hfile fd_hfile[];
++};
++
++static inline int au_fidir_sz(int nent)
++{
++ AuDebugOn(nent < 0);
++ return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent;
++}
++
++struct au_finfo {
++ atomic_t fi_generation;
++
++ struct au_rwsem fi_rwsem;
++ aufs_bindex_t fi_btop;
++
++ /* do not union them */
++ struct { /* for non-dir */
++ struct au_hfile fi_htop;
++ struct vm_operations_struct *fi_hvmop;
++ struct mutex fi_vm_mtx;
++ struct mutex fi_mmap;
++ };
++ struct au_fidir *fi_hdir; /* for dir only */
++} ____cacheline_aligned_in_smp;
++
++/* ---------------------------------------------------------------------- */
++
++/* file.c */
++extern const struct address_space_operations aufs_aop;
++unsigned int au_file_roflags(unsigned int flags);
++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
++ struct file *file);
++int au_do_open(struct file *file, int (*open)(struct file *file, int flags),
++ struct au_fidir *fidir);
++int au_reopen_nondir(struct file *file);
++struct au_pin;
++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin);
++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
++ int wlock);
++int au_do_flush(struct file *file, fl_owner_t id,
++ int (*flush)(struct file *file, fl_owner_t id));
++
++/* poll.c */
++#ifdef CONFIG_AUFS_POLL
++unsigned int aufs_poll(struct file *file, poll_table *wait);
++#endif
++
++#ifdef CONFIG_AUFS_BR_HFSPLUS
++/* hfsplus.c */
++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex);
++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex,
++ struct file *h_file);
++#else
++static inline
++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ return NULL;
++}
++
++AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex,
++ struct file *h_file);
++#endif
++
++/* f_op.c */
++extern const struct file_operations aufs_file_fop;
++extern const struct vm_operations_struct aufs_vm_ops;
++int au_do_open_nondir(struct file *file, int flags);
++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file);
++
++#ifdef CONFIG_AUFS_SP_IATTR
++/* f_op_sp.c */
++int au_special_file(umode_t mode);
++void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev);
++#else
++AuStubInt0(au_special_file, umode_t mode)
++static inline void au_init_special_fop(struct inode *inode, umode_t mode,
++ dev_t rdev)
++{
++ init_special_inode(inode, mode, rdev);
++}
++#endif
++
++/* finfo.c */
++void au_hfput(struct au_hfile *hf, struct file *file);
++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex,
++ struct file *h_file);
++
++void au_update_figen(struct file *file);
++void au_fi_mmap_lock(struct file *file);
++void au_fi_mmap_unlock(struct file *file);
++struct au_fidir *au_fidir_alloc(struct super_block *sb);
++int au_fidir_realloc(struct au_finfo *finfo, int nbr);
++
++void au_fi_init_once(void *_fi);
++void au_finfo_fin(struct file *file);
++int au_finfo_init(struct file *file, struct au_fidir *fidir);
++
++/* ioctl.c */
++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg);
++#ifdef CONFIG_COMPAT
++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
++ unsigned long arg);
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_finfo *au_fi(struct file *file)
++{
++ return file->private_data;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * fi_read_lock, fi_write_lock,
++ * fi_read_unlock, fi_write_unlock, fi_downgrade_lock
++ */
++AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem);
++
++#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem)
++#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem)
++#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem)
++
++/* ---------------------------------------------------------------------- */
++
++/* todo: hard/soft set? */
++static inline aufs_bindex_t au_fbstart(struct file *file)
++{
++ FiMustAnyLock(file);
++ return au_fi(file)->fi_btop;
++}
++
++static inline aufs_bindex_t au_fbend_dir(struct file *file)
++{
++ FiMustAnyLock(file);
++ AuDebugOn(!au_fi(file)->fi_hdir);
++ return au_fi(file)->fi_hdir->fd_bbot;
++}
++
++static inline struct au_vdir *au_fvdir_cache(struct file *file)
++{
++ FiMustAnyLock(file);
++ AuDebugOn(!au_fi(file)->fi_hdir);
++ return au_fi(file)->fi_hdir->fd_vdir_cache;
++}
++
++static inline void au_set_fbstart(struct file *file, aufs_bindex_t bindex)
++{
++ FiMustWriteLock(file);
++ au_fi(file)->fi_btop = bindex;
++}
++
++static inline void au_set_fbend_dir(struct file *file, aufs_bindex_t bindex)
++{
++ FiMustWriteLock(file);
++ AuDebugOn(!au_fi(file)->fi_hdir);
++ au_fi(file)->fi_hdir->fd_bbot = bindex;
++}
++
++static inline void au_set_fvdir_cache(struct file *file,
++ struct au_vdir *vdir_cache)
++{
++ FiMustWriteLock(file);
++ AuDebugOn(!au_fi(file)->fi_hdir);
++ au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache;
++}
++
++static inline struct file *au_hf_top(struct file *file)
++{
++ FiMustAnyLock(file);
++ AuDebugOn(au_fi(file)->fi_hdir);
++ return au_fi(file)->fi_htop.hf_file;
++}
++
++static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex)
++{
++ FiMustAnyLock(file);
++ AuDebugOn(!au_fi(file)->fi_hdir);
++ return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file;
++}
++
++/* todo: memory barrier? */
++static inline unsigned int au_figen(struct file *f)
++{
++ return atomic_read(&au_fi(f)->fi_generation);
++}
++
++static inline int au_test_mmapped(struct file *f)
++{
++ FiMustAnyLock(f);
++ return !!(au_fi(f)->fi_hvmop);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_FILE_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/finfo.c linux-2.6.37/fs/aufs/finfo.c
+--- linux-2.6.37.orig/fs/aufs/finfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/finfo.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,174 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * file private data
++ */
++
++#include <linux/file.h>
++#include "aufs.h"
++
++void au_hfput(struct au_hfile *hf, struct file *file)
++{
++ /* todo: direct access f_flags */
++ if (vfsub_file_flags(file) & vfsub_fmode_to_uint(FMODE_EXEC))
++ allow_write_access(hf->hf_file);
++ fput(hf->hf_file);
++ hf->hf_file = NULL;
++ atomic_dec(&hf->hf_br->br_count);
++ hf->hf_br = NULL;
++}
++
++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val)
++{
++ struct au_finfo *finfo = au_fi(file);
++ struct au_hfile *hf;
++ struct au_fidir *fidir;
++
++ fidir = finfo->fi_hdir;
++ if (!fidir) {
++ AuDebugOn(finfo->fi_btop != bindex);
++ hf = &finfo->fi_htop;
++ } else
++ hf = fidir->fd_hfile + bindex;
++
++ if (hf && hf->hf_file)
++ au_hfput(hf, file);
++ if (val) {
++ FiMustWriteLock(file);
++ hf->hf_file = val;
++ hf->hf_br = au_sbr(file->f_dentry->d_sb, bindex);
++ }
++}
++
++void au_update_figen(struct file *file)
++{
++ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_dentry));
++ /* smp_mb(); */ /* atomic_set */
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_fi_mmap_lock(struct file *file)
++{
++ FiMustWriteLock(file);
++ lockdep_off();
++ mutex_lock(&au_fi(file)->fi_mmap);
++ lockdep_on();
++}
++
++void au_fi_mmap_unlock(struct file *file)
++{
++ lockdep_off();
++ mutex_unlock(&au_fi(file)->fi_mmap);
++ lockdep_on();
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_fidir *au_fidir_alloc(struct super_block *sb)
++{
++ struct au_fidir *fidir;
++ int nbr;
++
++ nbr = au_sbend(sb) + 1;
++ if (nbr < 2)
++ nbr = 2; /* initial allocate for 2 branches */
++ fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS);
++ if (fidir) {
++ fidir->fd_bbot = -1;
++ fidir->fd_nent = nbr;
++ fidir->fd_vdir_cache = NULL;
++ }
++
++ return fidir;
++}
++
++int au_fidir_realloc(struct au_finfo *finfo, int nbr)
++{
++ int err;
++ struct au_fidir *fidir, *p;
++
++ AuRwMustWriteLock(&finfo->fi_rwsem);
++ fidir = finfo->fi_hdir;
++ AuDebugOn(!fidir);
++
++ err = -ENOMEM;
++ p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr),
++ GFP_NOFS);
++ if (p) {
++ p->fd_nent = nbr;
++ finfo->fi_hdir = p;
++ err = 0;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_finfo_fin(struct file *file)
++{
++ struct au_finfo *finfo;
++
++ au_nfiles_dec(file->f_dentry->d_sb);
++
++ finfo = au_fi(file);
++ AuDebugOn(finfo->fi_hdir);
++ AuRwDestroy(&finfo->fi_rwsem);
++ au_cache_free_finfo(finfo);
++}
++
++void au_fi_init_once(void *_finfo)
++{
++ struct au_finfo *finfo = _finfo;
++ static struct lock_class_key aufs_fi, aufs_fi_vm, aufs_fi_mmap;
++
++ au_rw_init(&finfo->fi_rwsem);
++ au_rw_class(&finfo->fi_rwsem, &aufs_fi);
++ mutex_init(&finfo->fi_vm_mtx);
++ lockdep_set_class(&finfo->fi_vm_mtx, &aufs_fi_vm);
++ mutex_init(&finfo->fi_mmap);
++ lockdep_set_class(&finfo->fi_mmap, &aufs_fi_mmap);
++}
++
++int au_finfo_init(struct file *file, struct au_fidir *fidir)
++{
++ int err;
++ struct au_finfo *finfo;
++ struct dentry *dentry;
++
++ err = -ENOMEM;
++ dentry = file->f_dentry;
++ finfo = au_cache_alloc_finfo();
++ if (unlikely(!finfo))
++ goto out;
++
++ err = 0;
++ au_nfiles_inc(dentry->d_sb);
++ au_rw_write_lock(&finfo->fi_rwsem);
++ finfo->fi_btop = -1;
++ finfo->fi_hdir = fidir;
++ atomic_set(&finfo->fi_generation, au_digen(dentry));
++ /* smp_mb(); */ /* atomic_set */
++
++ file->private_data = finfo;
++
++out:
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/fstype.h linux-2.6.37/fs/aufs/fstype.h
+--- linux-2.6.37.orig/fs/aufs/fstype.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/fstype.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,497 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * judging filesystem type
++ */
++
++#ifndef __AUFS_FSTYPE_H__
++#define __AUFS_FSTYPE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/magic.h>
++#include <linux/romfs_fs.h>
++#include <linux/aufs_type.h>
++
++static inline int au_test_aufs(struct super_block *sb)
++{
++ return sb->s_magic == AUFS_SUPER_MAGIC;
++}
++
++static inline const char *au_sbtype(struct super_block *sb)
++{
++ return sb->s_type->name;
++}
++
++static inline int au_test_iso9660(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE)
++ return sb->s_magic == ROMFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_romfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE)
++ return sb->s_magic == ISOFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_cramfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE)
++ return sb->s_magic == CRAMFS_MAGIC;
++#endif
++ return 0;
++}
++
++static inline int au_test_nfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE)
++ return sb->s_magic == NFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_fuse(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE)
++ return sb->s_magic == FUSE_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_xfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_XFS_FS) || defined(CONFIG_XFS_FS_MODULE)
++ return sb->s_magic == XFS_SB_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_tmpfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_TMPFS
++ return sb->s_magic == TMPFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_ECRYPT_FS) || defined(CONFIG_ECRYPT_FS_MODULE)
++ return !strcmp(au_sbtype(sb), "ecryptfs");
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_smbfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_SMB_FS) || defined(CONFIG_SMB_FS_MODULE)
++ return sb->s_magic == SMB_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ocfs2(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_OCFS2_FS) || defined(CONFIG_OCFS2_FS_MODULE)
++ return sb->s_magic == OCFS2_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ocfs2_dlmfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_OCFS2_FS_O2CB) || defined(CONFIG_OCFS2_FS_O2CB_MODULE)
++ return sb->s_magic == DLMFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_coda(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CODA_FS) || defined(CONFIG_CODA_FS_MODULE)
++ return sb->s_magic == CODA_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_v9fs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_9P_FS) || defined(CONFIG_9P_FS_MODULE)
++ return sb->s_magic == V9FS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ext4(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_EXT4DEV_FS) || defined(CONFIG_EXT4DEV_FS_MODULE)
++ return sb->s_magic == EXT4_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_sysv(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_SYSV_FS) || defined(CONFIG_SYSV_FS_MODULE)
++ return !strcmp(au_sbtype(sb), "sysv");
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ramfs(struct super_block *sb)
++{
++ return sb->s_magic == RAMFS_MAGIC;
++}
++
++static inline int au_test_ubifs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_UBIFS_FS) || defined(CONFIG_UBIFS_FS_MODULE)
++ return sb->s_magic == UBIFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_procfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_PROC_FS
++ return sb->s_magic == PROC_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_sysfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_SYSFS
++ return sb->s_magic == SYSFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_configfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CONFIGFS_FS) || defined(CONFIG_CONFIGFS_FS_MODULE)
++ return sb->s_magic == CONFIGFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_minix(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_MINIX_FS) || defined(CONFIG_MINIX_FS_MODULE)
++ return sb->s_magic == MINIX3_SUPER_MAGIC
++ || sb->s_magic == MINIX2_SUPER_MAGIC
++ || sb->s_magic == MINIX2_SUPER_MAGIC2
++ || sb->s_magic == MINIX_SUPER_MAGIC
++ || sb->s_magic == MINIX_SUPER_MAGIC2;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_cifs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CIFS_FS) || defined(CONFIGCIFS_FS_MODULE)
++ return sb->s_magic == CIFS_MAGIC_NUMBER;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_fat(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_FAT_FS) || defined(CONFIG_FAT_FS_MODULE)
++ return sb->s_magic == MSDOS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_msdos(struct super_block *sb)
++{
++ return au_test_fat(sb);
++}
++
++static inline int au_test_vfat(struct super_block *sb)
++{
++ return au_test_fat(sb);
++}
++
++static inline int au_test_securityfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_SECURITYFS
++ return sb->s_magic == SECURITYFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_squashfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_SQUASHFS) || defined(CONFIG_SQUASHFS_MODULE)
++ return sb->s_magic == SQUASHFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_btrfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_BTRFS_FS) || defined(CONFIG_BTRFS_FS_MODULE)
++ return sb->s_magic == BTRFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_xenfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_XENFS) || defined(CONFIG_XENFS_MODULE)
++ return sb->s_magic == XENFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_debugfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_DEBUG_FS
++ return sb->s_magic == DEBUGFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_nilfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_NILFS) || defined(CONFIG_NILFS_MODULE)
++ return sb->s_magic == NILFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_hfsplus(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_HFSPLUS_FS) || defined(CONFIG_HFSPLUS_FS_MODULE)
++ return sb->s_magic == HFSPLUS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * they can't be an aufs branch.
++ */
++static inline int au_test_fs_unsuppoted(struct super_block *sb)
++{
++ return
++#ifndef CONFIG_AUFS_BR_RAMFS
++ au_test_ramfs(sb) ||
++#endif
++ au_test_procfs(sb)
++ || au_test_sysfs(sb)
++ || au_test_configfs(sb)
++ || au_test_debugfs(sb)
++ || au_test_securityfs(sb)
++ || au_test_xenfs(sb)
++ || au_test_ecryptfs(sb)
++ /* || !strcmp(au_sbtype(sb), "unionfs") */
++ || au_test_aufs(sb); /* will be supported in next version */
++}
++
++/*
++ * If the filesystem supports NFS-export, then it has to support NULL as
++ * a nameidata parameter for ->create(), ->lookup() and ->d_revalidate().
++ * We can apply this principle when we handle a lower filesystem.
++ */
++static inline int au_test_fs_null_nd(struct super_block *sb)
++{
++ return !!sb->s_export_op;
++}
++
++static inline int au_test_fs_remote(struct super_block *sb)
++{
++ return !au_test_tmpfs(sb)
++#ifdef CONFIG_AUFS_BR_RAMFS
++ && !au_test_ramfs(sb)
++#endif
++ && !(sb->s_type->fs_flags & FS_REQUIRES_DEV);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * Note: these functions (below) are created after reading ->getattr() in all
++ * filesystems under linux/fs. it means we have to do so in every update...
++ */
++
++/*
++ * some filesystems require getattr to refresh the inode attributes before
++ * referencing.
++ * in most cases, we can rely on the inode attribute in NFS (or every remote fs)
++ * and leave the work for d_revalidate()
++ */
++static inline int au_test_fs_refresh_iattr(struct super_block *sb)
++{
++ return au_test_nfs(sb)
++ || au_test_fuse(sb)
++ /* || au_test_smbfs(sb) */ /* untested */
++ /* || au_test_ocfs2(sb) */ /* untested */
++ /* || au_test_btrfs(sb) */ /* untested */
++ /* || au_test_coda(sb) */ /* untested */
++ /* || au_test_v9fs(sb) */ /* untested */
++ ;
++}
++
++/*
++ * filesystems which don't maintain i_size or i_blocks.
++ */
++static inline int au_test_fs_bad_iattr_size(struct super_block *sb)
++{
++ return au_test_xfs(sb)
++ || au_test_btrfs(sb)
++ || au_test_ubifs(sb)
++ || au_test_hfsplus(sb) /* maintained, but incorrect */
++ /* || au_test_ext4(sb) */ /* untested */
++ /* || au_test_ocfs2(sb) */ /* untested */
++ /* || au_test_ocfs2_dlmfs(sb) */ /* untested */
++ /* || au_test_sysv(sb) */ /* untested */
++ /* || au_test_minix(sb) */ /* untested */
++ ;
++}
++
++/*
++ * filesystems which don't store the correct value in some of their inode
++ * attributes.
++ */
++static inline int au_test_fs_bad_iattr(struct super_block *sb)
++{
++ return au_test_fs_bad_iattr_size(sb)
++ /* || au_test_cifs(sb) */ /* untested */
++ || au_test_fat(sb)
++ || au_test_msdos(sb)
++ || au_test_vfat(sb);
++}
++
++/* they don't check i_nlink in link(2) */
++static inline int au_test_fs_no_limit_nlink(struct super_block *sb)
++{
++ return au_test_tmpfs(sb)
++#ifdef CONFIG_AUFS_BR_RAMFS
++ || au_test_ramfs(sb)
++#endif
++ || au_test_ubifs(sb)
++ || au_test_btrfs(sb)
++ || au_test_hfsplus(sb);
++}
++
++/*
++ * filesystems which sets S_NOATIME and S_NOCMTIME.
++ */
++static inline int au_test_fs_notime(struct super_block *sb)
++{
++ return au_test_nfs(sb)
++ || au_test_fuse(sb)
++ || au_test_ubifs(sb)
++ /* || au_test_cifs(sb) */ /* untested */
++ ;
++}
++
++/*
++ * filesystems which requires replacing i_mapping.
++ */
++static inline int au_test_fs_bad_mapping(struct super_block *sb)
++{
++ return au_test_fuse(sb)
++ || au_test_ubifs(sb);
++}
++
++/* temporary support for i#1 in cramfs */
++static inline int au_test_fs_unique_ino(struct inode *inode)
++{
++ if (au_test_cramfs(inode->i_sb))
++ return inode->i_ino != 1;
++ return 1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * the filesystem where the xino files placed must support i/o after unlink and
++ * maintain i_size and i_blocks.
++ */
++static inline int au_test_fs_bad_xino(struct super_block *sb)
++{
++ return au_test_fs_remote(sb)
++ || au_test_fs_bad_iattr_size(sb)
++#ifdef CONFIG_AUFS_BR_RAMFS
++ || !(au_test_ramfs(sb) || au_test_fs_null_nd(sb))
++#else
++ || !au_test_fs_null_nd(sb) /* to keep xino code simple */
++#endif
++ /* don't want unnecessary work for xino */
++ || au_test_aufs(sb)
++ || au_test_ecryptfs(sb)
++ || au_test_nilfs(sb);
++}
++
++static inline int au_test_fs_trunc_xino(struct super_block *sb)
++{
++ return au_test_tmpfs(sb)
++ || au_test_ramfs(sb);
++}
++
++/*
++ * test if the @sb is real-readonly.
++ */
++static inline int au_test_fs_rr(struct super_block *sb)
++{
++ return au_test_squashfs(sb)
++ || au_test_iso9660(sb)
++ || au_test_cramfs(sb)
++ || au_test_romfs(sb);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_FSTYPE_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/hfsnotify.c linux-2.6.37/fs/aufs/hfsnotify.c
+--- linux-2.6.37.orig/fs/aufs/hfsnotify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/hfsnotify.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,247 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * fsnotify for the lower directories
++ */
++
++#include "aufs.h"
++
++/* FS_IN_IGNORED is unnecessary */
++static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE
++ | FS_CREATE | FS_EVENT_ON_CHILD);
++static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq);
++
++static void au_hfsn_free_mark(struct fsnotify_mark *mark)
++{
++ struct au_hnotify *hn = container_of(mark, struct au_hnotify,
++ hn_mark);
++ AuDbg("here\n");
++ hn->hn_mark_dead = 1;
++ smp_mb();
++ wake_up_all(&au_hfsn_wq);
++}
++
++static int au_hfsn_alloc(struct au_hinode *hinode)
++{
++ struct au_hnotify *hn;
++ struct super_block *sb;
++ struct au_branch *br;
++ struct fsnotify_mark *mark;
++ aufs_bindex_t bindex;
++
++ hn = hinode->hi_notify;
++ sb = hn->hn_aufs_inode->i_sb;
++ bindex = au_br_index(sb, hinode->hi_id);
++ br = au_sbr(sb, bindex);
++ hn->hn_mark_dead = 0;
++ mark = &hn->hn_mark;
++ fsnotify_init_mark(mark, au_hfsn_free_mark);
++ mark->mask = AuHfsnMask;
++ /*
++ * by udba rename or rmdir, aufs assign a new inode to the known
++ * h_inode, so specify 1 to allow dups.
++ */
++ return fsnotify_add_mark(mark, br->br_hfsn_group, hinode->hi_inode,
++ /*mnt*/NULL, /*allow_dups*/1);
++}
++
++static void au_hfsn_free(struct au_hinode *hinode)
++{
++ struct au_hnotify *hn;
++ struct fsnotify_mark *mark;
++
++ hn = hinode->hi_notify;
++ mark = &hn->hn_mark;
++ fsnotify_destroy_mark(mark);
++ fsnotify_put_mark(mark);
++
++ /* TODO: bad approach */
++ wait_event(au_hfsn_wq, hn->hn_mark_dead);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void au_hfsn_ctl(struct au_hinode *hinode, int do_set)
++{
++ struct fsnotify_mark *mark;
++
++ mark = &hinode->hi_notify->hn_mark;
++ spin_lock(&mark->lock);
++ if (do_set) {
++ AuDebugOn(mark->mask & AuHfsnMask);
++ mark->mask |= AuHfsnMask;
++ } else {
++ AuDebugOn(!(mark->mask & AuHfsnMask));
++ mark->mask &= ~AuHfsnMask;
++ }
++ spin_unlock(&mark->lock);
++ /* fsnotify_recalc_inode_mask(hinode->hi_inode); */
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* #define AuDbgHnotify */
++#ifdef AuDbgHnotify
++static char *au_hfsn_name(u32 mask)
++{
++#ifdef CONFIG_AUFS_DEBUG
++#define test_ret(flag) if (mask & flag) \
++ return #flag;
++ test_ret(FS_ACCESS);
++ test_ret(FS_MODIFY);
++ test_ret(FS_ATTRIB);
++ test_ret(FS_CLOSE_WRITE);
++ test_ret(FS_CLOSE_NOWRITE);
++ test_ret(FS_OPEN);
++ test_ret(FS_MOVED_FROM);
++ test_ret(FS_MOVED_TO);
++ test_ret(FS_CREATE);
++ test_ret(FS_DELETE);
++ test_ret(FS_DELETE_SELF);
++ test_ret(FS_MOVE_SELF);
++ test_ret(FS_UNMOUNT);
++ test_ret(FS_Q_OVERFLOW);
++ test_ret(FS_IN_IGNORED);
++ test_ret(FS_IN_ISDIR);
++ test_ret(FS_IN_ONESHOT);
++ test_ret(FS_EVENT_ON_CHILD);
++ return "";
++#undef test_ret
++#else
++ return "??";
++#endif
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static int au_hfsn_handle_event(struct fsnotify_group *group,
++ struct fsnotify_mark *inode_mark,
++ struct fsnotify_mark *vfsmount_mark,
++ struct fsnotify_event *event)
++{
++ int err;
++ struct au_hnotify *hnotify;
++ struct inode *h_dir, *h_inode;
++ __u32 mask;
++ struct qstr h_child_qstr = {
++ .name = event->file_name,
++ .len = event->name_len
++ };
++
++ AuDebugOn(event->data_type != FSNOTIFY_EVENT_INODE);
++
++ err = 0;
++ /* if FS_UNMOUNT happens, there must be another bug */
++ mask = event->mask;
++ AuDebugOn(mask & FS_UNMOUNT);
++ if (mask & (FS_IN_IGNORED | FS_UNMOUNT))
++ goto out;
++
++ h_dir = event->to_tell;
++ h_inode = event->inode;
++#ifdef AuDbgHnotify
++ au_debug(1);
++ if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1
++ || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) {
++ AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n",
++ h_dir->i_ino, mask, au_hfsn_name(mask),
++ AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0);
++ /* WARN_ON(1); */
++ }
++ au_debug(0);
++#endif
++
++ AuDebugOn(!inode_mark);
++ hnotify = container_of(inode_mark, struct au_hnotify, hn_mark);
++ err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode);
++
++out:
++ return err;
++}
++
++/* isn't it waste to ask every registered 'group'? */
++/* copied from linux/fs/notify/inotify/inotify_fsnotiry.c */
++/* it should be exported to modules */
++static bool au_hfsn_should_send_event(struct fsnotify_group *group,
++ struct inode *h_inode,
++ struct fsnotify_mark *inode_mark,
++ struct fsnotify_mark *vfsmount_mark,
++ __u32 mask, void *data, int data_type)
++{
++ mask = (mask & ~FS_EVENT_ON_CHILD);
++ return inode_mark->mask & mask;
++}
++
++static struct fsnotify_ops au_hfsn_ops = {
++ .should_send_event = au_hfsn_should_send_event,
++ .handle_event = au_hfsn_handle_event
++};
++
++/* ---------------------------------------------------------------------- */
++
++static void au_hfsn_fin_br(struct au_branch *br)
++{
++ if (br->br_hfsn_group)
++ fsnotify_put_group(br->br_hfsn_group);
++}
++
++static int au_hfsn_init_br(struct au_branch *br, int perm)
++{
++ br->br_hfsn_group = NULL;
++ br->br_hfsn_ops = au_hfsn_ops;
++ return 0;
++}
++
++static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm)
++{
++ int err;
++
++ err = 0;
++ if (udba != AuOpt_UDBA_HNOTIFY
++ || !au_br_hnotifyable(perm)) {
++ au_hfsn_fin_br(br);
++ br->br_hfsn_group = NULL;
++ goto out;
++ }
++
++ if (br->br_hfsn_group)
++ goto out;
++
++ br->br_hfsn_group = fsnotify_alloc_group(&br->br_hfsn_ops);
++ if (IS_ERR(br->br_hfsn_group)) {
++ err = PTR_ERR(br->br_hfsn_group);
++ pr_err("fsnotify_alloc_group() failed, %d\n", err);
++ br->br_hfsn_group = NULL;
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++const struct au_hnotify_op au_hnotify_op = {
++ .ctl = au_hfsn_ctl,
++ .alloc = au_hfsn_alloc,
++ .free = au_hfsn_free,
++
++ .reset_br = au_hfsn_reset_br,
++ .fin_br = au_hfsn_fin_br,
++ .init_br = au_hfsn_init_br
++};
+diff -Nur linux-2.6.37.orig/fs/aufs/hfsplus.c linux-2.6.37/fs/aufs/hfsplus.c
+--- linux-2.6.37.orig/fs/aufs/hfsplus.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/hfsplus.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,58 @@
++/*
++ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * special support for filesystems which aqucires an inode mutex
++ * at final closing a file, eg, hfsplus.
++ *
++ * This trick is very simple and stupid, just to open the file before really
++ * neceeary open to tell hfsplus that this is not the final closing.
++ * The caller should call au_h_open_pre() after acquiring the inode mutex,
++ * and au_h_open_post() after releasing it.
++ */
++
++#include <linux/file.h>
++#include "aufs.h"
++
++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ struct file *h_file;
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ AuDebugOn(!h_dentry);
++ AuDebugOn(!h_dentry->d_inode);
++ IMustLock(h_dentry->d_inode);
++
++ h_file = NULL;
++ if (au_test_hfsplus(h_dentry->d_sb)
++ && S_ISREG(h_dentry->d_inode->i_mode))
++ h_file = au_h_open(dentry, bindex,
++ O_RDONLY | O_NOATIME | O_LARGEFILE,
++ /*file*/NULL);
++ return h_file;
++}
++
++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex,
++ struct file *h_file)
++{
++ if (h_file) {
++ fput(h_file);
++ au_sbr_put(dentry->d_sb, bindex);
++ }
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/hnotify.c linux-2.6.37/fs/aufs/hnotify.c
+--- linux-2.6.37.orig/fs/aufs/hnotify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/hnotify.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,694 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * abstraction to notify the direct changes on lower directories
++ */
++
++#include "aufs.h"
++
++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode)
++{
++ int err;
++ struct au_hnotify *hn;
++
++ err = -ENOMEM;
++ hn = au_cache_alloc_hnotify();
++ if (hn) {
++ hn->hn_aufs_inode = inode;
++ hinode->hi_notify = hn;
++ err = au_hnotify_op.alloc(hinode);
++ AuTraceErr(err);
++ if (unlikely(err)) {
++ hinode->hi_notify = NULL;
++ au_cache_free_hnotify(hn);
++ /*
++ * The upper dir was removed by udba, but the same named
++ * dir left. In this case, aufs assignes a new inode
++ * number and set the monitor again.
++ * For the lower dir, the old monitnor is still left.
++ */
++ if (err == -EEXIST)
++ err = 0;
++ }
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++void au_hn_free(struct au_hinode *hinode)
++{
++ struct au_hnotify *hn;
++
++ hn = hinode->hi_notify;
++ if (hn) {
++ au_hnotify_op.free(hinode);
++ au_cache_free_hnotify(hn);
++ hinode->hi_notify = NULL;
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_hn_ctl(struct au_hinode *hinode, int do_set)
++{
++ if (hinode->hi_notify)
++ au_hnotify_op.ctl(hinode, do_set);
++}
++
++void au_hn_reset(struct inode *inode, unsigned int flags)
++{
++ aufs_bindex_t bindex, bend;
++ struct inode *hi;
++ struct dentry *iwhdentry;
++
++ bend = au_ibend(inode);
++ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
++ hi = au_h_iptr(inode, bindex);
++ if (!hi)
++ continue;
++
++ /* mutex_lock_nested(&hi->i_mutex, AuLsc_I_CHILD); */
++ iwhdentry = au_hi_wh(inode, bindex);
++ if (iwhdentry)
++ dget(iwhdentry);
++ au_igrab(hi);
++ au_set_h_iptr(inode, bindex, NULL, 0);
++ au_set_h_iptr(inode, bindex, au_igrab(hi),
++ flags & ~AuHi_XINO);
++ iput(hi);
++ dput(iwhdentry);
++ /* mutex_unlock(&hi->i_mutex); */
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int hn_xino(struct inode *inode, struct inode *h_inode)
++{
++ int err;
++ aufs_bindex_t bindex, bend, bfound, bstart;
++ struct inode *h_i;
++
++ err = 0;
++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
++ pr_warning("branch root dir was changed\n");
++ goto out;
++ }
++
++ bfound = -1;
++ bend = au_ibend(inode);
++ bstart = au_ibstart(inode);
++#if 0 /* reserved for future use */
++ if (bindex == bend) {
++ /* keep this ino in rename case */
++ goto out;
++ }
++#endif
++ for (bindex = bstart; bindex <= bend; bindex++)
++ if (au_h_iptr(inode, bindex) == h_inode) {
++ bfound = bindex;
++ break;
++ }
++ if (bfound < 0)
++ goto out;
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ h_i = au_h_iptr(inode, bindex);
++ if (!h_i)
++ continue;
++
++ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0);
++ /* ignore this error */
++ /* bad action? */
++ }
++
++ /* children inode number will be broken */
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int hn_gen_tree(struct dentry *dentry)
++{
++ int err, i, j, ndentry;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_dcsub_pages(&dpages, dentry, NULL, NULL);
++ if (unlikely(err))
++ goto out_dpages;
++
++ for (i = 0; i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ ndentry = dpage->ndentry;
++ for (j = 0; j < ndentry; j++) {
++ struct dentry *d;
++
++ d = dentries[j];
++ if (IS_ROOT(d))
++ continue;
++
++ au_digen_dec(d);
++ if (d->d_inode)
++ /* todo: reset children xino?
++ cached children only? */
++ au_iigen_dec(d->d_inode);
++ }
++ }
++
++out_dpages:
++ au_dpages_free(&dpages);
++
++ /* discard children */
++ dentry_unhash(dentry);
++ dput(dentry);
++out:
++ return err;
++}
++
++/*
++ * return 0 if processed.
++ */
++static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode,
++ const unsigned int isdir)
++{
++ int err;
++ struct dentry *d;
++ struct qstr *dname;
++
++ err = 1;
++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
++ pr_warning("branch root dir was changed\n");
++ err = 0;
++ goto out;
++ }
++
++ if (!isdir) {
++ AuDebugOn(!name);
++ au_iigen_dec(inode);
++ spin_lock(&dcache_lock);
++ list_for_each_entry(d, &inode->i_dentry, d_alias) {
++ dname = &d->d_name;
++ if (dname->len != nlen
++ && memcmp(dname->name, name, nlen))
++ continue;
++ err = 0;
++ au_digen_dec(d);
++ break;
++ }
++ spin_unlock(&dcache_lock);
++ } else {
++ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR);
++ d = d_find_alias(inode);
++ if (!d) {
++ au_iigen_dec(inode);
++ goto out;
++ }
++
++ dname = &d->d_name;
++ if (dname->len == nlen && !memcmp(dname->name, name, nlen))
++ err = hn_gen_tree(d);
++ dput(d);
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir)
++{
++ int err;
++ struct inode *inode;
++
++ inode = dentry->d_inode;
++ if (IS_ROOT(dentry)
++ /* || (inode && inode->i_ino == AUFS_ROOT_INO) */
++ ) {
++ pr_warning("branch root dir was changed\n");
++ return 0;
++ }
++
++ err = 0;
++ if (!isdir) {
++ au_digen_dec(dentry);
++ if (inode)
++ au_iigen_dec(inode);
++ } else {
++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR);
++ if (inode)
++ err = hn_gen_tree(dentry);
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* hnotify job flags */
++#define AuHnJob_XINO0 1
++#define AuHnJob_GEN (1 << 1)
++#define AuHnJob_DIRENT (1 << 2)
++#define AuHnJob_ISDIR (1 << 3)
++#define AuHnJob_TRYXINO0 (1 << 4)
++#define AuHnJob_MNTPNT (1 << 5)
++#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name)
++#define au_fset_hnjob(flags, name) \
++ do { (flags) |= AuHnJob_##name; } while (0)
++#define au_fclr_hnjob(flags, name) \
++ do { (flags) &= ~AuHnJob_##name; } while (0)
++
++enum {
++ AuHn_CHILD,
++ AuHn_PARENT,
++ AuHnLast
++};
++
++struct au_hnotify_args {
++ struct inode *h_dir, *dir, *h_child_inode;
++ u32 mask;
++ unsigned int flags[AuHnLast];
++ unsigned int h_child_nlen;
++ char h_child_name[];
++};
++
++struct hn_job_args {
++ unsigned int flags;
++ struct inode *inode, *h_inode, *dir, *h_dir;
++ struct dentry *dentry;
++ char *h_name;
++ int h_nlen;
++};
++
++static int hn_job(struct hn_job_args *a)
++{
++ const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR);
++
++ /* reset xino */
++ if (au_ftest_hnjob(a->flags, XINO0) && a->inode)
++ hn_xino(a->inode, a->h_inode); /* ignore this error */
++
++ if (au_ftest_hnjob(a->flags, TRYXINO0)
++ && a->inode
++ && a->h_inode) {
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ if (!a->h_inode->i_nlink)
++ hn_xino(a->inode, a->h_inode); /* ignore this error */
++ mutex_unlock(&a->h_inode->i_mutex);
++ }
++
++ /* make the generation obsolete */
++ if (au_ftest_hnjob(a->flags, GEN)) {
++ int err = -1;
++ if (a->inode)
++ err = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode,
++ isdir);
++ if (err && a->dentry)
++ hn_gen_by_name(a->dentry, isdir);
++ /* ignore this error */
++ }
++
++ /* make dir entries obsolete */
++ if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) {
++ struct au_vdir *vdir;
++
++ vdir = au_ivdir(a->inode);
++ if (vdir)
++ vdir->vd_jiffy = 0;
++ /* IMustLock(a->inode); */
++ /* a->inode->i_version++; */
++ }
++
++ /* can do nothing but warn */
++ if (au_ftest_hnjob(a->flags, MNTPNT)
++ && a->dentry
++ && d_mountpoint(a->dentry))
++ pr_warning("mount-point %.*s is removed or renamed\n",
++ AuDLNPair(a->dentry));
++
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen,
++ struct inode *dir)
++{
++ struct dentry *dentry, *d, *parent;
++ struct qstr *dname;
++
++ parent = d_find_alias(dir);
++ if (!parent)
++ return NULL;
++
++ dentry = NULL;
++ spin_lock(&dcache_lock);
++ list_for_each_entry(d, &parent->d_subdirs, d_u.d_child) {
++ /* AuDbg("%.*s\n", AuDLNPair(d)); */
++ dname = &d->d_name;
++ if (dname->len != nlen || memcmp(dname->name, name, nlen))
++ continue;
++ if (au_di(d))
++ au_digen_dec(d);
++ else
++ continue;
++ if (!atomic_read(&d->d_count))
++ continue;
++
++ dentry = dget(d);
++ break;
++ }
++ spin_unlock(&dcache_lock);
++ dput(parent);
++
++ if (dentry)
++ di_write_lock_child(dentry);
++
++ return dentry;
++}
++
++static struct inode *lookup_wlock_by_ino(struct super_block *sb,
++ aufs_bindex_t bindex, ino_t h_ino)
++{
++ struct inode *inode;
++ ino_t ino;
++ int err;
++
++ inode = NULL;
++ err = au_xino_read(sb, bindex, h_ino, &ino);
++ if (!err && ino)
++ inode = ilookup(sb, ino);
++ if (!inode)
++ goto out;
++
++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
++ pr_warning("wrong root branch\n");
++ iput(inode);
++ inode = NULL;
++ goto out;
++ }
++
++ ii_write_lock_child(inode);
++
++out:
++ return inode;
++}
++
++static void au_hn_bh(void *_args)
++{
++ struct au_hnotify_args *a = _args;
++ struct super_block *sb;
++ aufs_bindex_t bindex, bend, bfound;
++ unsigned char xino, try_iput;
++ int err;
++ struct inode *inode;
++ ino_t h_ino;
++ struct hn_job_args args;
++ struct dentry *dentry;
++ struct au_sbinfo *sbinfo;
++
++ AuDebugOn(!_args);
++ AuDebugOn(!a->h_dir);
++ AuDebugOn(!a->dir);
++ AuDebugOn(!a->mask);
++ AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n",
++ a->mask, a->dir->i_ino, a->h_dir->i_ino,
++ a->h_child_inode ? a->h_child_inode->i_ino : 0);
++
++ inode = NULL;
++ dentry = NULL;
++ /*
++ * do not lock a->dir->i_mutex here
++ * because of d_revalidate() may cause a deadlock.
++ */
++ sb = a->dir->i_sb;
++ AuDebugOn(!sb);
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!sbinfo);
++ si_write_lock(sb, AuLock_NOPLMW);
++
++ ii_read_lock_parent(a->dir);
++ bfound = -1;
++ bend = au_ibend(a->dir);
++ for (bindex = au_ibstart(a->dir); bindex <= bend; bindex++)
++ if (au_h_iptr(a->dir, bindex) == a->h_dir) {
++ bfound = bindex;
++ break;
++ }
++ ii_read_unlock(a->dir);
++ if (unlikely(bfound < 0))
++ goto out;
++
++ xino = !!au_opt_test(au_mntflags(sb), XINO);
++ h_ino = 0;
++ if (a->h_child_inode)
++ h_ino = a->h_child_inode->i_ino;
++
++ if (a->h_child_nlen
++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN)
++ || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT)))
++ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen,
++ a->dir);
++ try_iput = 0;
++ if (dentry)
++ inode = dentry->d_inode;
++ if (xino && !inode && h_ino
++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0)
++ || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0)
++ || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) {
++ inode = lookup_wlock_by_ino(sb, bfound, h_ino);
++ try_iput = 1;
++ }
++
++ args.flags = a->flags[AuHn_CHILD];
++ args.dentry = dentry;
++ args.inode = inode;
++ args.h_inode = a->h_child_inode;
++ args.dir = a->dir;
++ args.h_dir = a->h_dir;
++ args.h_name = a->h_child_name;
++ args.h_nlen = a->h_child_nlen;
++ err = hn_job(&args);
++ if (dentry) {
++ if (au_di(dentry))
++ di_write_unlock(dentry);
++ dput(dentry);
++ }
++ if (inode && try_iput) {
++ ii_write_unlock(inode);
++ iput(inode);
++ }
++
++ ii_write_lock_parent(a->dir);
++ args.flags = a->flags[AuHn_PARENT];
++ args.dentry = NULL;
++ args.inode = a->dir;
++ args.h_inode = a->h_dir;
++ args.dir = NULL;
++ args.h_dir = NULL;
++ args.h_name = NULL;
++ args.h_nlen = 0;
++ err = hn_job(&args);
++ ii_write_unlock(a->dir);
++
++out:
++ iput(a->h_child_inode);
++ iput(a->h_dir);
++ iput(a->dir);
++ si_write_unlock(sb);
++ au_nwt_done(&sbinfo->si_nowait);
++ kfree(a);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask,
++ struct qstr *h_child_qstr, struct inode *h_child_inode)
++{
++ int err, len;
++ unsigned int flags[AuHnLast];
++ unsigned char isdir, isroot, wh;
++ struct inode *dir;
++ struct au_hnotify_args *args;
++ char *p, *h_child_name;
++
++ err = 0;
++ AuDebugOn(!hnotify || !hnotify->hn_aufs_inode);
++ dir = igrab(hnotify->hn_aufs_inode);
++ if (!dir)
++ goto out;
++
++ isroot = (dir->i_ino == AUFS_ROOT_INO);
++ wh = 0;
++ h_child_name = (void *)h_child_qstr->name;
++ len = h_child_qstr->len;
++ if (h_child_name) {
++ if (len > AUFS_WH_PFX_LEN
++ && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
++ h_child_name += AUFS_WH_PFX_LEN;
++ len -= AUFS_WH_PFX_LEN;
++ wh = 1;
++ }
++ }
++
++ isdir = 0;
++ if (h_child_inode)
++ isdir = !!S_ISDIR(h_child_inode->i_mode);
++ flags[AuHn_PARENT] = AuHnJob_ISDIR;
++ flags[AuHn_CHILD] = 0;
++ if (isdir)
++ flags[AuHn_CHILD] = AuHnJob_ISDIR;
++ au_fset_hnjob(flags[AuHn_PARENT], DIRENT);
++ au_fset_hnjob(flags[AuHn_CHILD], GEN);
++ switch (mask & FS_EVENTS_POSS_ON_CHILD) {
++ case FS_MOVED_FROM:
++ case FS_MOVED_TO:
++ au_fset_hnjob(flags[AuHn_CHILD], XINO0);
++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT);
++ /*FALLTHROUGH*/
++ case FS_CREATE:
++ AuDebugOn(!h_child_name || !h_child_inode);
++ break;
++
++ case FS_DELETE:
++ /*
++ * aufs never be able to get this child inode.
++ * revalidation should be in d_revalidate()
++ * by checking i_nlink, i_generation or d_unhashed().
++ */
++ AuDebugOn(!h_child_name);
++ au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0);
++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT);
++ break;
++
++ default:
++ AuDebugOn(1);
++ }
++
++ if (wh)
++ h_child_inode = NULL;
++
++ err = -ENOMEM;
++ /* iput() and kfree() will be called in au_hnotify() */
++ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS);
++ if (unlikely(!args)) {
++ AuErr1("no memory\n");
++ iput(dir);
++ goto out;
++ }
++ args->flags[AuHn_PARENT] = flags[AuHn_PARENT];
++ args->flags[AuHn_CHILD] = flags[AuHn_CHILD];
++ args->mask = mask;
++ args->dir = dir;
++ args->h_dir = igrab(h_dir);
++ if (h_child_inode)
++ h_child_inode = igrab(h_child_inode); /* can be NULL */
++ args->h_child_inode = h_child_inode;
++ args->h_child_nlen = len;
++ if (len) {
++ p = (void *)args;
++ p += sizeof(*args);
++ memcpy(p, h_child_name, len);
++ p[len] = 0;
++ }
++
++ err = au_wkq_nowait(au_hn_bh, args, dir->i_sb);
++ if (unlikely(err)) {
++ pr_err("wkq %d\n", err);
++ iput(args->h_child_inode);
++ iput(args->h_dir);
++ iput(args->dir);
++ kfree(args);
++ }
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm)
++{
++ int err;
++
++ AuDebugOn(!(udba & AuOptMask_UDBA));
++
++ err = 0;
++ if (au_hnotify_op.reset_br)
++ err = au_hnotify_op.reset_br(udba, br, perm);
++
++ return err;
++}
++
++int au_hnotify_init_br(struct au_branch *br, int perm)
++{
++ int err;
++
++ err = 0;
++ if (au_hnotify_op.init_br)
++ err = au_hnotify_op.init_br(br, perm);
++
++ return err;
++}
++
++void au_hnotify_fin_br(struct au_branch *br)
++{
++ if (au_hnotify_op.fin_br)
++ au_hnotify_op.fin_br(br);
++}
++
++static void au_hn_destroy_cache(void)
++{
++ kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]);
++ au_cachep[AuCache_HNOTIFY] = NULL;
++}
++
++int __init au_hnotify_init(void)
++{
++ int err;
++
++ err = -ENOMEM;
++ au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify);
++ if (au_cachep[AuCache_HNOTIFY]) {
++ err = 0;
++ if (au_hnotify_op.init)
++ err = au_hnotify_op.init();
++ if (unlikely(err))
++ au_hn_destroy_cache();
++ }
++ AuTraceErr(err);
++ return err;
++}
++
++void au_hnotify_fin(void)
++{
++ if (au_hnotify_op.fin)
++ au_hnotify_op.fin();
++ /* cf. au_cache_fin() */
++ if (au_cachep[AuCache_HNOTIFY])
++ au_hn_destroy_cache();
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/i_op.c linux-2.6.37/fs/aufs/i_op.c
+--- linux-2.6.37.orig/fs/aufs/i_op.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/i_op.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,971 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode operations (except add/del/rename)
++ */
++
++#include <linux/device_cgroup.h>
++#include <linux/fs_stack.h>
++#include <linux/mm.h>
++#include <linux/namei.h>
++#include <linux/security.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++static int h_permission(struct inode *h_inode, int mask,
++ struct vfsmount *h_mnt, int brperm)
++{
++ int err;
++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
++
++ err = -EACCES;
++ if ((write_mask && IS_IMMUTABLE(h_inode))
++ || ((mask & MAY_EXEC)
++ && S_ISREG(h_inode->i_mode)
++ && ((h_mnt->mnt_flags & MNT_NOEXEC)
++ || !(h_inode->i_mode & S_IXUGO))))
++ goto out;
++
++ /*
++ * - skip the lower fs test in the case of write to ro branch.
++ * - nfs dir permission write check is optimized, but a policy for
++ * link/rename requires a real check.
++ */
++ if ((write_mask && !au_br_writable(brperm))
++ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode)
++ && write_mask && !(mask & MAY_READ))
++ || !h_inode->i_op->permission) {
++ /* AuLabel(generic_permission); */
++ err = generic_permission(h_inode, mask,
++ h_inode->i_op->check_acl);
++ } else {
++ /* AuLabel(h_inode->permission); */
++ err = h_inode->i_op->permission(h_inode, mask);
++ AuTraceErr(err);
++ }
++
++ if (!err)
++ err = devcgroup_inode_permission(h_inode, mask);
++ if (!err)
++ err = security_inode_permission(h_inode, mask);
++
++#if 0
++ if (!err) {
++ /* todo: do we need to call ima_path_check()? */
++ struct path h_path = {
++ .dentry =
++ .mnt = h_mnt
++ };
++ err = ima_path_check(&h_path,
++ mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
++ IMA_COUNT_LEAVE);
++ }
++#endif
++
++out:
++ return err;
++}
++
++static int aufs_permission(struct inode *inode, int mask)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ const unsigned char isdir = !!S_ISDIR(inode->i_mode),
++ write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
++ struct inode *h_inode;
++ struct super_block *sb;
++ struct au_branch *br;
++
++ sb = inode->i_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ ii_read_lock_child(inode);
++#if 0
++ err = au_iigen_test(inode, au_sigen(sb));
++ if (unlikely(err))
++ goto out;
++#endif
++
++ if (!isdir || write_mask) {
++ err = au_busy_or_stale();
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ if (unlikely(!h_inode
++ || (h_inode->i_mode & S_IFMT)
++ != (inode->i_mode & S_IFMT)))
++ goto out;
++
++ err = 0;
++ bindex = au_ibstart(inode);
++ br = au_sbr(sb, bindex);
++ err = h_permission(h_inode, mask, br->br_mnt, br->br_perm);
++ if (write_mask
++ && !err
++ && !special_file(h_inode->i_mode)) {
++ /* test whether the upper writable branch exists */
++ err = -EROFS;
++ for (; bindex >= 0; bindex--)
++ if (!au_br_rdonly(au_sbr(sb, bindex))) {
++ err = 0;
++ break;
++ }
++ }
++ goto out;
++ }
++
++ /* non-write to dir */
++ err = 0;
++ bend = au_ibend(inode);
++ for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) {
++ h_inode = au_h_iptr(inode, bindex);
++ if (h_inode) {
++ err = au_busy_or_stale();
++ if (unlikely(!S_ISDIR(h_inode->i_mode)))
++ break;
++
++ br = au_sbr(sb, bindex);
++ err = h_permission(h_inode, mask, br->br_mnt,
++ br->br_perm);
++ }
++ }
++
++out:
++ ii_read_unlock(inode);
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry,
++ struct nameidata *nd)
++{
++ struct dentry *ret, *parent;
++ struct inode *inode;
++ struct super_block *sb;
++ int err, npositive;
++
++ IMustLock(dir);
++
++ sb = dir->i_sb;
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ ret = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ ret = ERR_PTR(-ENAMETOOLONG);
++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
++ goto out_si;
++ err = au_di_init(dentry);
++ ret = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_si;
++
++ npositive = 0; /* suppress a warning */
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_read_lock_parent(parent, AuLock_IR);
++ err = au_alive_dir(parent);
++ if (!err)
++ err = au_digen_test(parent, au_sigen(sb));
++ if (!err) {
++ npositive = au_lkup_dentry(dentry, au_dbstart(parent),
++ /*type*/0, nd);
++ err = npositive;
++ }
++ di_read_unlock(parent, AuLock_IR);
++ ret = ERR_PTR(err);
++ if (unlikely(err < 0))
++ goto out_unlock;
++
++ inode = NULL;
++ if (npositive) {
++ inode = au_new_inode(dentry, /*must_new*/0);
++ ret = (void *)inode;
++ }
++ if (IS_ERR(inode))
++ goto out_unlock;
++
++ ret = d_splice_alias(inode, dentry);
++ if (unlikely(IS_ERR(ret) && inode)) {
++ ii_write_unlock(inode);
++ iput(inode);
++ }
++
++out_unlock:
++ di_write_unlock(dentry);
++out_si:
++ si_read_unlock(sb);
++out:
++ return ret;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent,
++ const unsigned char add_entry, aufs_bindex_t bcpup,
++ aufs_bindex_t bstart)
++{
++ int err;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++
++ if (add_entry)
++ IMustLock(parent->d_inode);
++ else
++ di_write_lock_parent(parent);
++
++ err = 0;
++ if (!au_h_dptr(parent, bcpup)) {
++ if (bstart < bcpup)
++ err = au_cpdown_dirs(dentry, bcpup);
++ else
++ err = au_cpup_dirs(dentry, bcpup);
++ }
++ if (!err && add_entry) {
++ h_parent = au_h_dptr(parent, bcpup);
++ h_dir = h_parent->d_inode;
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
++ err = au_lkup_neg(dentry, bcpup);
++ /* todo: no unlock here */
++ mutex_unlock(&h_dir->i_mutex);
++
++ AuDbg("bcpup %d\n", bcpup);
++ if (!err) {
++ if (!dentry->d_inode)
++ au_set_h_dptr(dentry, bstart, NULL);
++ au_update_dbrange(dentry, /*do_put_zero*/0);
++ }
++ }
++
++ if (!add_entry)
++ di_write_unlock(parent);
++ if (!err)
++ err = bcpup; /* success */
++
++ AuTraceErr(err);
++ return err;
++}
++
++/*
++ * decide the branch and the parent dir where we will create a new entry.
++ * returns new bindex or an error.
++ * copyup the parent dir if needed.
++ */
++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry,
++ struct au_wr_dir_args *args)
++{
++ int err;
++ aufs_bindex_t bcpup, bstart, src_bstart;
++ const unsigned char add_entry = !!au_ftest_wrdir(args->flags,
++ ADD_ENTRY);
++ struct super_block *sb;
++ struct dentry *parent;
++ struct au_sbinfo *sbinfo;
++
++ sb = dentry->d_sb;
++ sbinfo = au_sbi(sb);
++ parent = dget_parent(dentry);
++ bstart = au_dbstart(dentry);
++ bcpup = bstart;
++ if (args->force_btgt < 0) {
++ if (src_dentry) {
++ src_bstart = au_dbstart(src_dentry);
++ if (src_bstart < bstart)
++ bcpup = src_bstart;
++ } else if (add_entry) {
++ err = AuWbrCreate(sbinfo, dentry,
++ au_ftest_wrdir(args->flags, ISDIR));
++ bcpup = err;
++ }
++
++ if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) {
++ if (add_entry)
++ err = AuWbrCopyup(sbinfo, dentry);
++ else {
++ if (!IS_ROOT(dentry)) {
++ di_read_lock_parent(parent, !AuLock_IR);
++ err = AuWbrCopyup(sbinfo, dentry);
++ di_read_unlock(parent, !AuLock_IR);
++ } else
++ err = AuWbrCopyup(sbinfo, dentry);
++ }
++ bcpup = err;
++ if (unlikely(err < 0))
++ goto out;
++ }
++ } else {
++ bcpup = args->force_btgt;
++ AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode));
++ }
++
++ AuDbg("bstart %d, bcpup %d\n", bstart, bcpup);
++ err = bcpup;
++ if (bcpup == bstart)
++ goto out; /* success */
++
++ /* copyup the new parent into the branch we process */
++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart);
++ if (err >= 0) {
++ if (!dentry->d_inode) {
++ au_set_h_dptr(dentry, bstart, NULL);
++ au_set_dbstart(dentry, bcpup);
++ au_set_dbend(dentry, bcpup);
++ }
++ AuDebugOn(add_entry && !au_h_dptr(dentry, bcpup));
++ }
++
++out:
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct dentry *au_pinned_h_parent(struct au_pin *pin)
++{
++ if (pin && pin->parent)
++ return au_h_dptr(pin->parent, pin->bindex);
++ return NULL;
++}
++
++void au_unpin(struct au_pin *p)
++{
++ if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE))
++ mnt_drop_write(p->h_mnt);
++ if (!p->hdir)
++ return;
++
++ au_hn_imtx_unlock(p->hdir);
++ if (!au_ftest_pin(p->flags, DI_LOCKED))
++ di_read_unlock(p->parent, AuLock_IR);
++ iput(p->hdir->hi_inode);
++ dput(p->parent);
++ p->parent = NULL;
++ p->hdir = NULL;
++ p->h_mnt = NULL;
++}
++
++int au_do_pin(struct au_pin *p)
++{
++ int err;
++ struct super_block *sb;
++ struct dentry *h_dentry, *h_parent;
++ struct au_branch *br;
++ struct inode *h_dir;
++
++ err = 0;
++ sb = p->dentry->d_sb;
++ br = au_sbr(sb, p->bindex);
++ if (IS_ROOT(p->dentry)) {
++ if (au_ftest_pin(p->flags, MNT_WRITE)) {
++ p->h_mnt = br->br_mnt;
++ err = mnt_want_write(p->h_mnt);
++ if (unlikely(err)) {
++ au_fclr_pin(p->flags, MNT_WRITE);
++ goto out_err;
++ }
++ }
++ goto out;
++ }
++
++ h_dentry = NULL;
++ if (p->bindex <= au_dbend(p->dentry))
++ h_dentry = au_h_dptr(p->dentry, p->bindex);
++
++ p->parent = dget_parent(p->dentry);
++ if (!au_ftest_pin(p->flags, DI_LOCKED))
++ di_read_lock(p->parent, AuLock_IR, p->lsc_di);
++
++ h_dir = NULL;
++ h_parent = au_h_dptr(p->parent, p->bindex);
++ p->hdir = au_hi(p->parent->d_inode, p->bindex);
++ if (p->hdir)
++ h_dir = p->hdir->hi_inode;
++
++ /*
++ * udba case, or
++ * if DI_LOCKED is not set, then p->parent may be different
++ * and h_parent can be NULL.
++ */
++ if (unlikely(!p->hdir || !h_dir || !h_parent)) {
++ err = -EBUSY;
++ if (!au_ftest_pin(p->flags, DI_LOCKED))
++ di_read_unlock(p->parent, AuLock_IR);
++ dput(p->parent);
++ p->parent = NULL;
++ goto out_err;
++ }
++
++ au_igrab(h_dir);
++ au_hn_imtx_lock_nested(p->hdir, p->lsc_hi);
++
++ if (unlikely(p->hdir->hi_inode != h_parent->d_inode)) {
++ err = -EBUSY;
++ goto out_unpin;
++ }
++ if (h_dentry) {
++ err = au_h_verify(h_dentry, p->udba, h_dir, h_parent, br);
++ if (unlikely(err)) {
++ au_fclr_pin(p->flags, MNT_WRITE);
++ goto out_unpin;
++ }
++ }
++
++ if (au_ftest_pin(p->flags, MNT_WRITE)) {
++ p->h_mnt = br->br_mnt;
++ err = mnt_want_write(p->h_mnt);
++ if (unlikely(err)) {
++ au_fclr_pin(p->flags, MNT_WRITE);
++ goto out_unpin;
++ }
++ }
++ goto out; /* success */
++
++out_unpin:
++ au_unpin(p);
++out_err:
++ pr_err("err %d\n", err);
++ err = au_busy_or_stale();
++out:
++ return err;
++}
++
++void au_pin_init(struct au_pin *p, struct dentry *dentry,
++ aufs_bindex_t bindex, int lsc_di, int lsc_hi,
++ unsigned int udba, unsigned char flags)
++{
++ p->dentry = dentry;
++ p->udba = udba;
++ p->lsc_di = lsc_di;
++ p->lsc_hi = lsc_hi;
++ p->flags = flags;
++ p->bindex = bindex;
++
++ p->parent = NULL;
++ p->hdir = NULL;
++ p->h_mnt = NULL;
++}
++
++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int udba, unsigned char flags)
++{
++ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2,
++ udba, flags);
++ return au_do_pin(pin);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * ->setattr() and ->getattr() are called in various cases.
++ * chmod, stat: dentry is revalidated.
++ * fchmod, fstat: file and dentry are not revalidated, additionally they may be
++ * unhashed.
++ * for ->setattr(), ia->ia_file is passed from ftruncate only.
++ */
++/* todo: consolidate with do_refresh() and simple_reval_dpath() */
++static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen)
++{
++ int err;
++ struct inode *inode;
++ struct dentry *parent;
++
++ err = 0;
++ inode = dentry->d_inode;
++ if (au_digen_test(dentry, sigen)) {
++ parent = dget_parent(dentry);
++ di_read_lock_parent(parent, AuLock_IR);
++ err = au_refresh_dentry(dentry, parent);
++ di_read_unlock(parent, AuLock_IR);
++ dput(parent);
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++#define AuIcpup_DID_CPUP 1
++#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name)
++#define au_fset_icpup(flags, name) \
++ do { (flags) |= AuIcpup_##name; } while (0)
++#define au_fclr_icpup(flags, name) \
++ do { (flags) &= ~AuIcpup_##name; } while (0)
++
++struct au_icpup_args {
++ unsigned char flags;
++ unsigned char pin_flags;
++ aufs_bindex_t btgt;
++ unsigned int udba;
++ struct au_pin pin;
++ struct path h_path;
++ struct inode *h_inode;
++};
++
++static int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia,
++ struct au_icpup_args *a)
++{
++ int err;
++ loff_t sz;
++ aufs_bindex_t bstart, ibstart;
++ struct dentry *hi_wh, *parent;
++ struct inode *inode;
++ struct file *h_file;
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = 0
++ };
++
++ bstart = au_dbstart(dentry);
++ inode = dentry->d_inode;
++ if (S_ISDIR(inode->i_mode))
++ au_fset_wrdir(wr_dir_args.flags, ISDIR);
++ /* plink or hi_wh() case */
++ ibstart = au_ibstart(inode);
++ if (bstart != ibstart && !au_test_ro(inode->i_sb, ibstart, inode))
++ wr_dir_args.force_btgt = ibstart;
++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
++ if (unlikely(err < 0))
++ goto out;
++ a->btgt = err;
++ if (err != bstart)
++ au_fset_icpup(a->flags, DID_CPUP);
++
++ err = 0;
++ a->pin_flags = AuPin_MNT_WRITE;
++ parent = NULL;
++ if (!IS_ROOT(dentry)) {
++ au_fset_pin(a->pin_flags, DI_LOCKED);
++ parent = dget_parent(dentry);
++ di_write_lock_parent(parent);
++ }
++
++ err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags);
++ if (unlikely(err))
++ goto out_parent;
++
++ a->h_path.dentry = au_h_dptr(dentry, bstart);
++ a->h_inode = a->h_path.dentry->d_inode;
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ sz = -1;
++ if ((ia->ia_valid & ATTR_SIZE) && ia->ia_size < i_size_read(a->h_inode))
++ sz = ia->ia_size;
++
++ h_file = NULL;
++ hi_wh = NULL;
++ if (au_ftest_icpup(a->flags, DID_CPUP) && au_d_removed(dentry)) {
++ hi_wh = au_hi_wh(inode, a->btgt);
++ if (!hi_wh) {
++ err = au_sio_cpup_wh(dentry, a->btgt, sz, /*file*/NULL);
++ if (unlikely(err))
++ goto out_unlock;
++ hi_wh = au_hi_wh(inode, a->btgt);
++ /* todo: revalidate hi_wh? */
++ }
++ }
++
++ if (parent) {
++ au_pin_set_parent_lflag(&a->pin, /*lflag*/0);
++ di_downgrade_lock(parent, AuLock_IR);
++ dput(parent);
++ parent = NULL;
++ }
++ if (!au_ftest_icpup(a->flags, DID_CPUP))
++ goto out; /* success */
++
++ if (!d_unhashed(dentry)) {
++ h_file = au_h_open_pre(dentry, bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_simple(dentry, a->btgt, sz,
++ AuCpup_DTIME);
++ if (!err)
++ a->h_path.dentry = au_h_dptr(dentry, a->btgt);
++ } else if (!hi_wh)
++ a->h_path.dentry = au_h_dptr(dentry, a->btgt);
++ else
++ a->h_path.dentry = hi_wh; /* do not dget here */
++
++out_unlock:
++ mutex_unlock(&a->h_inode->i_mutex);
++ au_h_open_post(dentry, bstart, h_file);
++ a->h_inode = a->h_path.dentry->d_inode;
++ if (!err) {
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ goto out; /* success */
++ }
++
++ au_unpin(&a->pin);
++out_parent:
++ if (parent) {
++ di_write_unlock(parent);
++ dput(parent);
++ }
++out:
++ return err;
++}
++
++static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
++{
++ int err;
++ struct inode *inode;
++ struct super_block *sb;
++ struct file *file;
++ struct au_icpup_args *a;
++
++ inode = dentry->d_inode;
++ IMustLock(inode);
++
++ err = -ENOMEM;
++ a = kzalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
++ ia->ia_valid &= ~ATTR_MODE;
++
++ file = NULL;
++ sb = dentry->d_sb;
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out_kfree;
++
++ if (ia->ia_valid & ATTR_FILE) {
++ /* currently ftruncate(2) only */
++ AuDebugOn(!S_ISREG(inode->i_mode));
++ file = ia->ia_file;
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out_si;
++ ia->ia_file = au_hf_top(file);
++ a->udba = AuOpt_UDBA_NONE;
++ } else {
++ /* fchmod() doesn't pass ia_file */
++ a->udba = au_opt_udba(sb);
++ /* no au_d_removed(), to set UDBA_NONE for root */
++ if (d_unhashed(dentry))
++ a->udba = AuOpt_UDBA_NONE;
++ di_write_lock_child(dentry);
++ if (a->udba != AuOpt_UDBA_NONE) {
++ AuDebugOn(IS_ROOT(dentry));
++ err = au_reval_for_attr(dentry, au_sigen(sb));
++ if (unlikely(err))
++ goto out_dentry;
++ }
++ }
++
++ err = au_pin_and_icpup(dentry, ia, a);
++ if (unlikely(err < 0))
++ goto out_dentry;
++ if (au_ftest_icpup(a->flags, DID_CPUP)) {
++ ia->ia_file = NULL;
++ ia->ia_valid &= ~ATTR_FILE;
++ }
++
++ a->h_path.mnt = au_sbr_mnt(sb, a->btgt);
++ if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME))
++ == (ATTR_MODE | ATTR_CTIME)) {
++ err = security_path_chmod(a->h_path.dentry, a->h_path.mnt,
++ ia->ia_mode);
++ if (unlikely(err))
++ goto out_unlock;
++ } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID))
++ && (ia->ia_valid & ATTR_CTIME)) {
++ err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid);
++ if (unlikely(err))
++ goto out_unlock;
++ }
++
++ if (ia->ia_valid & ATTR_SIZE) {
++ struct file *f;
++
++ if (ia->ia_size < i_size_read(inode))
++ /* unmap only */
++ truncate_setsize(inode, ia->ia_size);
++
++ f = NULL;
++ if (ia->ia_valid & ATTR_FILE)
++ f = ia->ia_file;
++ mutex_unlock(&a->h_inode->i_mutex);
++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f);
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ } else
++ err = vfsub_notify_change(&a->h_path, ia);
++ if (!err)
++ au_cpup_attr_changeable(inode);
++
++out_unlock:
++ mutex_unlock(&a->h_inode->i_mutex);
++ au_unpin(&a->pin);
++ if (unlikely(err))
++ au_update_dbstart(dentry);
++out_dentry:
++ di_write_unlock(dentry);
++ if (file) {
++ fi_write_unlock(file);
++ ia->ia_file = file;
++ ia->ia_valid |= ATTR_FILE;
++ }
++out_si:
++ si_read_unlock(sb);
++out_kfree:
++ kfree(a);
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static void au_refresh_iattr(struct inode *inode, struct kstat *st,
++ unsigned int nlink)
++{
++ inode->i_mode = st->mode;
++ inode->i_uid = st->uid;
++ inode->i_gid = st->gid;
++ inode->i_atime = st->atime;
++ inode->i_mtime = st->mtime;
++ inode->i_ctime = st->ctime;
++
++ au_cpup_attr_nlink(inode, /*force*/0);
++ if (S_ISDIR(inode->i_mode)) {
++ inode->i_nlink -= nlink;
++ inode->i_nlink += st->nlink;
++ }
++
++ spin_lock(&inode->i_lock);
++ inode->i_blocks = st->blocks;
++ i_size_write(inode, st->size);
++ spin_unlock(&inode->i_lock);
++}
++
++static int aufs_getattr(struct vfsmount *mnt __maybe_unused,
++ struct dentry *dentry, struct kstat *st)
++{
++ int err;
++ unsigned int mnt_flags;
++ aufs_bindex_t bindex;
++ unsigned char udba_none, positive;
++ struct super_block *sb, *h_sb;
++ struct inode *inode;
++ struct vfsmount *h_mnt;
++ struct dentry *h_dentry;
++
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out;
++ mnt_flags = au_mntflags(sb);
++ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE);
++
++ /* support fstat(2) */
++ if (!au_d_removed(dentry) && !udba_none) {
++ unsigned int sigen = au_sigen(sb);
++ err = au_digen_test(dentry, sigen);
++ if (!err) {
++ di_read_lock_child(dentry, AuLock_IR);
++ err = au_dbrange_test(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ } else {
++ AuDebugOn(IS_ROOT(dentry));
++ di_write_lock_child(dentry);
++ err = au_dbrange_test(dentry);
++ if (!err)
++ err = au_reval_for_attr(dentry, sigen);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++ }
++ } else
++ di_read_lock_child(dentry, AuLock_IR);
++
++ bindex = au_ibstart(inode);
++ h_mnt = au_sbr_mnt(sb, bindex);
++ h_sb = h_mnt->mnt_sb;
++ if (!au_test_fs_bad_iattr(h_sb) && udba_none)
++ goto out_fill; /* success */
++
++ h_dentry = NULL;
++ if (au_dbstart(dentry) == bindex)
++ h_dentry = dget(au_h_dptr(dentry, bindex));
++ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) {
++ h_dentry = au_plink_lkup(inode, bindex);
++ if (IS_ERR(h_dentry))
++ goto out_fill; /* pretending success */
++ }
++ /* illegally overlapped or something */
++ if (unlikely(!h_dentry))
++ goto out_fill; /* pretending success */
++
++ positive = !!h_dentry->d_inode;
++ if (positive)
++ err = vfs_getattr(h_mnt, h_dentry, st);
++ dput(h_dentry);
++ if (!err) {
++ if (positive)
++ au_refresh_iattr(inode, st, h_dentry->d_inode->i_nlink);
++ goto out_fill; /* success */
++ }
++ AuTraceErr(err);
++ goto out_unlock;
++
++out_fill:
++ generic_fillattr(inode, st);
++out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ si_read_unlock(sb);
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int h_readlink(struct dentry *dentry, int bindex, char __user *buf,
++ int bufsiz)
++{
++ int err;
++ struct super_block *sb;
++ struct dentry *h_dentry;
++
++ err = -EINVAL;
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (unlikely(!h_dentry->d_inode->i_op->readlink))
++ goto out;
++
++ err = security_inode_readlink(h_dentry);
++ if (unlikely(err))
++ goto out;
++
++ sb = dentry->d_sb;
++ if (!au_test_ro(sb, bindex, dentry->d_inode)) {
++ vfsub_touch_atime(au_sbr_mnt(sb, bindex), h_dentry);
++ fsstack_copy_attr_atime(dentry->d_inode, h_dentry->d_inode);
++ }
++ err = h_dentry->d_inode->i_op->readlink(h_dentry, buf, bufsiz);
++
++out:
++ return err;
++}
++
++static int aufs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
++{
++ int err;
++
++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN);
++ if (unlikely(err))
++ goto out;
++ err = au_d_hashed_positive(dentry);
++ if (!err)
++ err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz);
++ aufs_read_unlock(dentry, AuLock_IR);
++
++out:
++ return err;
++}
++
++static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ int err;
++ mm_segment_t old_fs;
++ union {
++ char *k;
++ char __user *u;
++ } buf;
++
++ err = -ENOMEM;
++ buf.k = __getname_gfp(GFP_NOFS);
++ if (unlikely(!buf.k))
++ goto out;
++
++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN);
++ if (unlikely(err))
++ goto out_name;
++
++ err = au_d_hashed_positive(dentry);
++ if (!err) {
++ old_fs = get_fs();
++ set_fs(KERNEL_DS);
++ err = h_readlink(dentry, au_dbstart(dentry), buf.u, PATH_MAX);
++ set_fs(old_fs);
++ }
++ aufs_read_unlock(dentry, AuLock_IR);
++
++ if (err >= 0) {
++ buf.k[err] = 0;
++ /* will be freed by put_link */
++ nd_set_link(nd, buf.k);
++ return NULL; /* success */
++ }
++
++out_name:
++ __putname(buf.k);
++out:
++ path_put(&nd->path);
++ AuTraceErr(err);
++ return ERR_PTR(err);
++}
++
++static void aufs_put_link(struct dentry *dentry __maybe_unused,
++ struct nameidata *nd, void *cookie __maybe_unused)
++{
++ __putname(nd_get_link(nd));
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void aufs_truncate_range(struct inode *inode __maybe_unused,
++ loff_t start __maybe_unused,
++ loff_t end __maybe_unused)
++{
++ AuUnsupport();
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct inode_operations aufs_symlink_iop = {
++ .permission = aufs_permission,
++ .setattr = aufs_setattr,
++ .getattr = aufs_getattr,
++ .readlink = aufs_readlink,
++ .follow_link = aufs_follow_link,
++ .put_link = aufs_put_link
++};
++
++struct inode_operations aufs_dir_iop = {
++ .create = aufs_create,
++ .lookup = aufs_lookup,
++ .link = aufs_link,
++ .unlink = aufs_unlink,
++ .symlink = aufs_symlink,
++ .mkdir = aufs_mkdir,
++ .rmdir = aufs_rmdir,
++ .mknod = aufs_mknod,
++ .rename = aufs_rename,
++
++ .permission = aufs_permission,
++ .setattr = aufs_setattr,
++ .getattr = aufs_getattr
++};
++
++struct inode_operations aufs_iop = {
++ .permission = aufs_permission,
++ .setattr = aufs_setattr,
++ .getattr = aufs_getattr,
++ .truncate_range = aufs_truncate_range
++};
+diff -Nur linux-2.6.37.orig/fs/aufs/i_op_add.c linux-2.6.37/fs/aufs/i_op_add.c
+--- linux-2.6.37.orig/fs/aufs/i_op_add.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/i_op_add.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,702 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode operations (add entry)
++ */
++
++#include "aufs.h"
++
++/*
++ * final procedure of adding a new entry, except link(2).
++ * remove whiteout, instantiate, copyup the parent dir's times and size
++ * and update version.
++ * if it failed, re-create the removed whiteout.
++ */
++static int epilog(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct dentry *dentry)
++{
++ int err, rerr;
++ aufs_bindex_t bwh;
++ struct path h_path;
++ struct inode *inode, *h_dir;
++ struct dentry *wh;
++
++ bwh = -1;
++ if (wh_dentry) {
++ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */
++ IMustLock(h_dir);
++ AuDebugOn(au_h_iptr(dir, bindex) != h_dir);
++ bwh = au_dbwh(dentry);
++ h_path.dentry = wh_dentry;
++ h_path.mnt = au_sbr_mnt(dir->i_sb, bindex);
++ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path,
++ dentry);
++ if (unlikely(err))
++ goto out;
++ }
++
++ inode = au_new_inode(dentry, /*must_new*/1);
++ if (!IS_ERR(inode)) {
++ d_instantiate(dentry, inode);
++ dir = dentry->d_parent->d_inode; /* dir inode is locked */
++ IMustLock(dir);
++ if (au_ibstart(dir) == au_dbstart(dentry))
++ au_cpup_attr_timesizes(dir);
++ dir->i_version++;
++ return 0; /* success */
++ }
++
++ err = PTR_ERR(inode);
++ if (!wh_dentry)
++ goto out;
++
++ /* revert */
++ /* dir inode is locked */
++ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent);
++ rerr = PTR_ERR(wh);
++ if (IS_ERR(wh)) {
++ AuIOErr("%.*s reverting whiteout failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ } else
++ dput(wh);
++
++out:
++ return err;
++}
++
++static int au_d_may_add(struct dentry *dentry)
++{
++ int err;
++
++ err = 0;
++ if (unlikely(d_unhashed(dentry)))
++ err = -ENOENT;
++ if (unlikely(dentry->d_inode))
++ err = -EEXIST;
++ return err;
++}
++
++/*
++ * simple tests for the adding inode operations.
++ * following the checks in vfs, plus the parent-child relationship.
++ */
++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir)
++{
++ int err;
++ umode_t h_mode;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++
++ err = -ENAMETOOLONG;
++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
++ goto out;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ h_inode = h_dentry->d_inode;
++ if (!dentry->d_inode) {
++ err = -EEXIST;
++ if (unlikely(h_inode))
++ goto out;
++ } else {
++ /* rename(2) case */
++ err = -EIO;
++ if (unlikely(!h_inode || !h_inode->i_nlink))
++ goto out;
++
++ h_mode = h_inode->i_mode;
++ if (!isdir) {
++ err = -EISDIR;
++ if (unlikely(S_ISDIR(h_mode)))
++ goto out;
++ } else if (unlikely(!S_ISDIR(h_mode))) {
++ err = -ENOTDIR;
++ goto out;
++ }
++ }
++
++ err = 0;
++ /* expected parent dir is locked */
++ if (unlikely(h_parent != h_dentry->d_parent))
++ err = -EIO;
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++/*
++ * initial procedure of adding a new entry.
++ * prepare writable branch and the parent dir, lock it,
++ * and lookup whiteout for the new entry.
++ */
++static struct dentry*
++lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt,
++ struct dentry *src_dentry, struct au_pin *pin,
++ struct au_wr_dir_args *wr_dir_args)
++{
++ struct dentry *wh_dentry, *h_parent;
++ struct super_block *sb;
++ struct au_branch *br;
++ int err;
++ unsigned int udba;
++ aufs_bindex_t bcpup;
++
++ AuDbg("%.*s\n", AuDLNPair(dentry));
++
++ err = au_wr_dir(dentry, src_dentry, wr_dir_args);
++ bcpup = err;
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err < 0))
++ goto out;
++
++ sb = dentry->d_sb;
++ udba = au_opt_udba(sb);
++ err = au_pin(pin, dentry, bcpup, udba,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ h_parent = au_pinned_h_parent(pin);
++ if (udba != AuOpt_UDBA_NONE
++ && au_dbstart(dentry) == bcpup)
++ err = au_may_add(dentry, bcpup, h_parent,
++ au_ftest_wrdir(wr_dir_args->flags, ISDIR));
++ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
++ err = -ENAMETOOLONG;
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_unpin;
++
++ br = au_sbr(sb, bcpup);
++ if (dt) {
++ struct path tmp = {
++ .dentry = h_parent,
++ .mnt = br->br_mnt
++ };
++ au_dtime_store(dt, au_pinned_parent(pin), &tmp);
++ }
++
++ wh_dentry = NULL;
++ if (bcpup != au_dbwh(dentry))
++ goto out; /* success */
++
++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br);
++
++out_unpin:
++ if (IS_ERR(wh_dentry))
++ au_unpin(pin);
++out:
++ return wh_dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++enum { Mknod, Symlink, Creat };
++struct simple_arg {
++ int type;
++ union {
++ struct {
++ int mode;
++ struct nameidata *nd;
++ } c;
++ struct {
++ const char *symname;
++ } s;
++ struct {
++ int mode;
++ dev_t dev;
++ } m;
++ } u;
++};
++
++static int add_simple(struct inode *dir, struct dentry *dentry,
++ struct simple_arg *arg)
++{
++ int err;
++ aufs_bindex_t bstart;
++ unsigned char created;
++ struct au_dtime dt;
++ struct au_pin pin;
++ struct path h_path;
++ struct dentry *wh_dentry, *parent;
++ struct inode *h_dir;
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = AuWrDir_ADD_ENTRY
++ };
++
++ AuDbg("%.*s\n", AuDLNPair(dentry));
++ IMustLock(dir);
++
++ parent = dentry->d_parent; /* dir inode is locked */
++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
++ if (unlikely(err))
++ goto out;
++ err = au_d_may_add(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ di_write_lock_parent(parent);
++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin,
++ &wr_dir_args);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_parent;
++
++ bstart = au_dbstart(dentry);
++ h_path.dentry = au_h_dptr(dentry, bstart);
++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
++ h_dir = au_pinned_h_dir(&pin);
++ switch (arg->type) {
++ case Creat:
++ err = vfsub_create(h_dir, &h_path, arg->u.c.mode);
++ break;
++ case Symlink:
++ err = vfsub_symlink(h_dir, &h_path, arg->u.s.symname);
++ break;
++ case Mknod:
++ err = vfsub_mknod(h_dir, &h_path, arg->u.m.mode, arg->u.m.dev);
++ break;
++ default:
++ BUG();
++ }
++ created = !err;
++ if (!err)
++ err = epilog(dir, bstart, wh_dentry, dentry);
++
++ /* revert */
++ if (unlikely(created && err && h_path.dentry->d_inode)) {
++ int rerr;
++ rerr = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ if (rerr) {
++ AuIOErr("%.*s revert failure(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ }
++ au_dtime_revert(&dt);
++ }
++
++ au_unpin(&pin);
++ dput(wh_dentry);
++
++out_parent:
++ di_write_unlock(parent);
++out_unlock:
++ if (unlikely(err)) {
++ au_update_dbstart(dentry);
++ d_drop(dentry);
++ }
++ aufs_read_unlock(dentry, AuLock_DW);
++out:
++ return err;
++}
++
++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
++{
++ struct simple_arg arg = {
++ .type = Mknod,
++ .u.m = {
++ .mode = mode,
++ .dev = dev
++ }
++ };
++ return add_simple(dir, dentry, &arg);
++}
++
++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
++{
++ struct simple_arg arg = {
++ .type = Symlink,
++ .u.s.symname = symname
++ };
++ return add_simple(dir, dentry, &arg);
++}
++
++int aufs_create(struct inode *dir, struct dentry *dentry, int mode,
++ struct nameidata *nd)
++{
++ struct simple_arg arg = {
++ .type = Creat,
++ .u.c = {
++ .mode = mode,
++ .nd = nd
++ }
++ };
++ return add_simple(dir, dentry, &arg);
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_link_args {
++ aufs_bindex_t bdst, bsrc;
++ struct au_pin pin;
++ struct path h_path;
++ struct dentry *src_parent, *parent;
++};
++
++static int au_cpup_before_link(struct dentry *src_dentry,
++ struct au_link_args *a)
++{
++ int err;
++ struct dentry *h_src_dentry;
++ struct mutex *h_mtx;
++ struct file *h_file;
++
++ di_read_lock_parent(a->src_parent, AuLock_IR);
++ err = au_test_and_cpup_dirs(src_dentry, a->bdst);
++ if (unlikely(err))
++ goto out;
++
++ h_src_dentry = au_h_dptr(src_dentry, a->bsrc);
++ h_mtx = &h_src_dentry->d_inode->i_mutex;
++ err = au_pin(&a->pin, src_dentry, a->bdst,
++ au_opt_udba(src_dentry->d_sb),
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (unlikely(err))
++ goto out;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ h_file = au_h_open_pre(src_dentry, a->bsrc);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_simple(src_dentry, a->bdst, a->bsrc,
++ AuCpup_DTIME /* | AuCpup_KEEPLINO */);
++ mutex_unlock(h_mtx);
++ au_h_open_post(src_dentry, a->bsrc, h_file);
++ au_unpin(&a->pin);
++
++out:
++ di_read_unlock(a->src_parent, AuLock_IR);
++ return err;
++}
++
++static int au_cpup_or_link(struct dentry *src_dentry, struct au_link_args *a)
++{
++ int err;
++ unsigned char plink;
++ struct inode *h_inode, *inode;
++ struct dentry *h_src_dentry;
++ struct super_block *sb;
++ struct file *h_file;
++
++ plink = 0;
++ h_inode = NULL;
++ sb = src_dentry->d_sb;
++ inode = src_dentry->d_inode;
++ if (au_ibstart(inode) <= a->bdst)
++ h_inode = au_h_iptr(inode, a->bdst);
++ if (!h_inode || !h_inode->i_nlink) {
++ /* copyup src_dentry as the name of dentry. */
++ au_set_dbstart(src_dentry, a->bdst);
++ au_set_h_dptr(src_dentry, a->bdst, dget(a->h_path.dentry));
++ h_inode = au_h_dptr(src_dentry, a->bsrc)->d_inode;
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ h_file = au_h_open_pre(src_dentry, a->bsrc);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_single(src_dentry, a->bdst, a->bsrc,
++ -1, AuCpup_KEEPLINO,
++ a->parent);
++ mutex_unlock(&h_inode->i_mutex);
++ au_h_open_post(src_dentry, a->bsrc, h_file);
++ au_set_h_dptr(src_dentry, a->bdst, NULL);
++ au_set_dbstart(src_dentry, a->bsrc);
++ } else {
++ /* the inode of src_dentry already exists on a.bdst branch */
++ h_src_dentry = d_find_alias(h_inode);
++ if (!h_src_dentry && au_plink_test(inode)) {
++ plink = 1;
++ h_src_dentry = au_plink_lkup(inode, a->bdst);
++ err = PTR_ERR(h_src_dentry);
++ if (IS_ERR(h_src_dentry))
++ goto out;
++
++ if (unlikely(!h_src_dentry->d_inode)) {
++ dput(h_src_dentry);
++ h_src_dentry = NULL;
++ }
++
++ }
++ if (h_src_dentry) {
++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
++ &a->h_path);
++ dput(h_src_dentry);
++ } else {
++ AuIOErr("no dentry found for hi%lu on b%d\n",
++ h_inode->i_ino, a->bdst);
++ err = -EIO;
++ }
++ }
++
++ if (!err && !plink)
++ au_plink_append(inode, a->bdst, a->h_path.dentry);
++
++out:
++ return err;
++}
++
++int aufs_link(struct dentry *src_dentry, struct inode *dir,
++ struct dentry *dentry)
++{
++ int err, rerr;
++ struct au_dtime dt;
++ struct au_link_args *a;
++ struct dentry *wh_dentry, *h_src_dentry;
++ struct inode *inode;
++ struct super_block *sb;
++ struct au_wr_dir_args wr_dir_args = {
++ /* .force_btgt = -1, */
++ .flags = AuWrDir_ADD_ENTRY
++ };
++
++ IMustLock(dir);
++ inode = src_dentry->d_inode;
++ IMustLock(inode);
++
++ err = -ENOMEM;
++ a = kzalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ a->parent = dentry->d_parent; /* dir inode is locked */
++ err = aufs_read_and_write_lock2(dentry, src_dentry,
++ AuLock_NOPLM | AuLock_GEN);
++ if (unlikely(err))
++ goto out_kfree;
++ err = au_d_hashed_positive(src_dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ err = au_d_may_add(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++
++ a->src_parent = dget_parent(src_dentry);
++ wr_dir_args.force_btgt = au_dbstart(src_dentry);
++
++ di_write_lock_parent(a->parent);
++ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt);
++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin,
++ &wr_dir_args);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_parent;
++
++ err = 0;
++ sb = dentry->d_sb;
++ a->bdst = au_dbstart(dentry);
++ a->h_path.dentry = au_h_dptr(dentry, a->bdst);
++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst);
++ a->bsrc = au_dbstart(src_dentry);
++ if (au_opt_test(au_mntflags(sb), PLINK)) {
++ if (a->bdst < a->bsrc
++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */)
++ err = au_cpup_or_link(src_dentry, a);
++ else {
++ h_src_dentry = au_h_dptr(src_dentry, a->bdst);
++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
++ &a->h_path);
++ }
++ } else {
++ /*
++ * copyup src_dentry to the branch we process,
++ * and then link(2) to it.
++ */
++ if (a->bdst < a->bsrc
++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) {
++ au_unpin(&a->pin);
++ di_write_unlock(a->parent);
++ err = au_cpup_before_link(src_dentry, a);
++ di_write_lock_parent(a->parent);
++ if (!err)
++ err = au_pin(&a->pin, dentry, a->bdst,
++ au_opt_udba(sb),
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (unlikely(err))
++ goto out_wh;
++ }
++ if (!err) {
++ h_src_dentry = au_h_dptr(src_dentry, a->bdst);
++ err = -ENOENT;
++ if (h_src_dentry && h_src_dentry->d_inode)
++ err = vfsub_link(h_src_dentry,
++ au_pinned_h_dir(&a->pin),
++ &a->h_path);
++ }
++ }
++ if (unlikely(err))
++ goto out_unpin;
++
++ if (wh_dentry) {
++ a->h_path.dentry = wh_dentry;
++ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path,
++ dentry);
++ if (unlikely(err))
++ goto out_revert;
++ }
++
++ dir->i_version++;
++ if (au_ibstart(dir) == au_dbstart(dentry))
++ au_cpup_attr_timesizes(dir);
++ inc_nlink(inode);
++ inode->i_ctime = dir->i_ctime;
++ d_instantiate(dentry, au_igrab(inode));
++ if (d_unhashed(a->h_path.dentry))
++ /* some filesystem calls d_drop() */
++ d_drop(dentry);
++ goto out_unpin; /* success */
++
++out_revert:
++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, /*force*/0);
++ if (unlikely(rerr)) {
++ AuIOErr("%.*s reverting failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ }
++ au_dtime_revert(&dt);
++out_unpin:
++ au_unpin(&a->pin);
++out_wh:
++ dput(wh_dentry);
++out_parent:
++ di_write_unlock(a->parent);
++ dput(a->src_parent);
++out_unlock:
++ if (unlikely(err)) {
++ au_update_dbstart(dentry);
++ d_drop(dentry);
++ }
++ aufs_read_and_write_unlock2(dentry, src_dentry);
++out_kfree:
++ kfree(a);
++out:
++ return err;
++}
++
++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++ int err, rerr;
++ aufs_bindex_t bindex;
++ unsigned char diropq;
++ struct path h_path;
++ struct dentry *wh_dentry, *parent, *opq_dentry;
++ struct mutex *h_mtx;
++ struct super_block *sb;
++ struct {
++ struct au_pin pin;
++ struct au_dtime dt;
++ } *a; /* reduce the stack usage */
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR
++ };
++
++ IMustLock(dir);
++
++ err = -ENOMEM;
++ a = kmalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
++ if (unlikely(err))
++ goto out_free;
++ err = au_d_may_add(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_write_lock_parent(parent);
++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL,
++ &a->pin, &wr_dir_args);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_parent;
++
++ sb = dentry->d_sb;
++ bindex = au_dbstart(dentry);
++ h_path.dentry = au_h_dptr(dentry, bindex);
++ h_path.mnt = au_sbr_mnt(sb, bindex);
++ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode);
++ if (unlikely(err))
++ goto out_unpin;
++
++ /* make the dir opaque */
++ diropq = 0;
++ h_mtx = &h_path.dentry->d_inode->i_mutex;
++ if (wh_dentry
++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) {
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ opq_dentry = au_diropq_create(dentry, bindex);
++ mutex_unlock(h_mtx);
++ err = PTR_ERR(opq_dentry);
++ if (IS_ERR(opq_dentry))
++ goto out_dir;
++ dput(opq_dentry);
++ diropq = 1;
++ }
++
++ err = epilog(dir, bindex, wh_dentry, dentry);
++ if (!err) {
++ inc_nlink(dir);
++ goto out_unpin; /* success */
++ }
++
++ /* revert */
++ if (diropq) {
++ AuLabel(revert opq);
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ rerr = au_diropq_remove(dentry, bindex);
++ mutex_unlock(h_mtx);
++ if (rerr) {
++ AuIOErr("%.*s reverting diropq failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ }
++ }
++
++out_dir:
++ AuLabel(revert dir);
++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path);
++ if (rerr) {
++ AuIOErr("%.*s reverting dir failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ }
++ au_dtime_revert(&a->dt);
++out_unpin:
++ au_unpin(&a->pin);
++ dput(wh_dentry);
++out_parent:
++ di_write_unlock(parent);
++out_unlock:
++ if (unlikely(err)) {
++ au_update_dbstart(dentry);
++ d_drop(dentry);
++ }
++ aufs_read_unlock(dentry, AuLock_DW);
++out_free:
++ kfree(a);
++out:
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/i_op_del.c linux-2.6.37/fs/aufs/i_op_del.c
+--- linux-2.6.37.orig/fs/aufs/i_op_del.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/i_op_del.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,481 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode operations (del entry)
++ */
++
++#include "aufs.h"
++
++/*
++ * decide if a new whiteout for @dentry is necessary or not.
++ * when it is necessary, prepare the parent dir for the upper branch whose
++ * branch index is @bcpup for creation. the actual creation of the whiteout will
++ * be done by caller.
++ * return value:
++ * 0: wh is unnecessary
++ * plus: wh is necessary
++ * minus: error
++ */
++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup)
++{
++ int need_wh, err;
++ aufs_bindex_t bstart;
++ struct super_block *sb;
++
++ sb = dentry->d_sb;
++ bstart = au_dbstart(dentry);
++ if (*bcpup < 0) {
++ *bcpup = bstart;
++ if (au_test_ro(sb, bstart, dentry->d_inode)) {
++ err = AuWbrCopyup(au_sbi(sb), dentry);
++ *bcpup = err;
++ if (unlikely(err < 0))
++ goto out;
++ }
++ } else
++ AuDebugOn(bstart < *bcpup
++ || au_test_ro(sb, *bcpup, dentry->d_inode));
++ AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart);
++
++ if (*bcpup != bstart) {
++ err = au_cpup_dirs(dentry, *bcpup);
++ if (unlikely(err))
++ goto out;
++ need_wh = 1;
++ } else {
++ struct au_dinfo *dinfo, *tmp;
++
++ need_wh = -ENOMEM;
++ dinfo = au_di(dentry);
++ tmp = au_di_alloc(sb, AuLsc_DI_TMP);
++ if (tmp) {
++ au_di_cp(tmp, dinfo);
++ au_di_swap(tmp, dinfo);
++ /* returns the number of positive dentries */
++ need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0,
++ /*nd*/NULL);
++ au_di_swap(tmp, dinfo);
++ au_rw_write_unlock(&tmp->di_rwsem);
++ au_di_free(tmp);
++ }
++ }
++ AuDbg("need_wh %d\n", need_wh);
++ err = need_wh;
++
++out:
++ return err;
++}
++
++/*
++ * simple tests for the del-entry operations.
++ * following the checks in vfs, plus the parent-child relationship.
++ */
++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir)
++{
++ int err;
++ umode_t h_mode;
++ struct dentry *h_dentry, *h_latest;
++ struct inode *h_inode;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ h_inode = h_dentry->d_inode;
++ if (dentry->d_inode) {
++ err = -ENOENT;
++ if (unlikely(!h_inode || !h_inode->i_nlink))
++ goto out;
++
++ h_mode = h_inode->i_mode;
++ if (!isdir) {
++ err = -EISDIR;
++ if (unlikely(S_ISDIR(h_mode)))
++ goto out;
++ } else if (unlikely(!S_ISDIR(h_mode))) {
++ err = -ENOTDIR;
++ goto out;
++ }
++ } else {
++ /* rename(2) case */
++ err = -EIO;
++ if (unlikely(h_inode))
++ goto out;
++ }
++
++ err = -ENOENT;
++ /* expected parent dir is locked */
++ if (unlikely(h_parent != h_dentry->d_parent))
++ goto out;
++ err = 0;
++
++ /*
++ * rmdir a dir may break the consistency on some filesystem.
++ * let's try heavy test.
++ */
++ err = -EACCES;
++ if (unlikely(au_test_h_perm(h_parent->d_inode, MAY_EXEC | MAY_WRITE)))
++ goto out;
++
++ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent,
++ au_sbr(dentry->d_sb, bindex));
++ err = -EIO;
++ if (IS_ERR(h_latest))
++ goto out;
++ if (h_latest == h_dentry)
++ err = 0;
++ dput(h_latest);
++
++out:
++ return err;
++}
++
++/*
++ * decide the branch where we operate for @dentry. the branch index will be set
++ * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent
++ * dir for reverting.
++ * when a new whiteout is necessary, create it.
++ */
++static struct dentry*
++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup,
++ struct au_dtime *dt, struct au_pin *pin)
++{
++ struct dentry *wh_dentry;
++ struct super_block *sb;
++ struct path h_path;
++ int err, need_wh;
++ unsigned int udba;
++ aufs_bindex_t bcpup;
++
++ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup);
++ wh_dentry = ERR_PTR(need_wh);
++ if (unlikely(need_wh < 0))
++ goto out;
++
++ sb = dentry->d_sb;
++ udba = au_opt_udba(sb);
++ bcpup = *rbcpup;
++ err = au_pin(pin, dentry, bcpup, udba,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ h_path.dentry = au_pinned_h_parent(pin);
++ if (udba != AuOpt_UDBA_NONE
++ && au_dbstart(dentry) == bcpup) {
++ err = au_may_del(dentry, bcpup, h_path.dentry, isdir);
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_unpin;
++ }
++
++ h_path.mnt = au_sbr_mnt(sb, bcpup);
++ au_dtime_store(dt, au_pinned_parent(pin), &h_path);
++ wh_dentry = NULL;
++ if (!need_wh)
++ goto out; /* success, no need to create whiteout */
++
++ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_unpin;
++
++ /* returns with the parent is locked and wh_dentry is dget-ed */
++ goto out; /* success */
++
++out_unpin:
++ au_unpin(pin);
++out:
++ return wh_dentry;
++}
++
++/*
++ * when removing a dir, rename it to a unique temporary whiteout-ed name first
++ * in order to be revertible and save time for removing many child whiteouts
++ * under the dir.
++ * returns 1 when there are too many child whiteout and caller should remove
++ * them asynchronously. returns 0 when the number of children is enough small to
++ * remove now or the branch fs is a remote fs.
++ * otherwise return an error.
++ */
++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex,
++ struct au_nhash *whlist, struct inode *dir)
++{
++ int rmdir_later, err, dirwh;
++ struct dentry *h_dentry;
++ struct super_block *sb;
++
++ sb = dentry->d_sb;
++ SiMustAnyLock(sb);
++ h_dentry = au_h_dptr(dentry, bindex);
++ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex));
++ if (unlikely(err))
++ goto out;
++
++ /* stop monitoring */
++ au_hn_free(au_hi(dentry->d_inode, bindex));
++
++ if (!au_test_fs_remote(h_dentry->d_sb)) {
++ dirwh = au_sbi(sb)->si_dirwh;
++ rmdir_later = (dirwh <= 1);
++ if (!rmdir_later)
++ rmdir_later = au_nhash_test_longer_wh(whlist, bindex,
++ dirwh);
++ if (rmdir_later)
++ return rmdir_later;
++ }
++
++ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist);
++ if (unlikely(err)) {
++ AuIOErr("rmdir %.*s, b%d failed, %d. ignored\n",
++ AuDLNPair(h_dentry), bindex, err);
++ err = 0;
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++/*
++ * final procedure for deleting a entry.
++ * maintain dentry and iattr.
++ */
++static void epilog(struct inode *dir, struct dentry *dentry,
++ aufs_bindex_t bindex)
++{
++ struct inode *inode;
++
++ inode = dentry->d_inode;
++ d_drop(dentry);
++ inode->i_ctime = dir->i_ctime;
++
++ if (au_ibstart(dir) == bindex)
++ au_cpup_attr_timesizes(dir);
++ dir->i_version++;
++}
++
++/*
++ * when an error happened, remove the created whiteout and revert everything.
++ */
++static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex,
++ aufs_bindex_t bwh, struct dentry *wh_dentry,
++ struct dentry *dentry, struct au_dtime *dt)
++{
++ int rerr;
++ struct path h_path = {
++ .dentry = wh_dentry,
++ .mnt = au_sbr_mnt(dir->i_sb, bindex)
++ };
++
++ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry);
++ if (!rerr) {
++ au_set_dbwh(dentry, bwh);
++ au_dtime_revert(dt);
++ return 0;
++ }
++
++ AuIOErr("%.*s reverting whiteout failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ return -EIO;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int aufs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bwh, bindex, bstart;
++ struct au_dtime dt;
++ struct au_pin pin;
++ struct path h_path;
++ struct inode *inode, *h_dir;
++ struct dentry *parent, *wh_dentry;
++
++ IMustLock(dir);
++
++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
++ if (unlikely(err))
++ goto out;
++ err = au_d_hashed_positive(dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ inode = dentry->d_inode;
++ IMustLock(inode);
++ err = -EISDIR;
++ if (unlikely(S_ISDIR(inode->i_mode)))
++ goto out_unlock; /* possible? */
++
++ bstart = au_dbstart(dentry);
++ bwh = au_dbwh(dentry);
++ bindex = -1;
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_write_lock_parent(parent);
++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_parent;
++
++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
++ h_path.dentry = au_h_dptr(dentry, bstart);
++ dget(h_path.dentry);
++ if (bindex == bstart) {
++ h_dir = au_pinned_h_dir(&pin);
++ err = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ } else {
++ /* dir inode is locked */
++ h_dir = wh_dentry->d_parent->d_inode;
++ IMustLock(h_dir);
++ err = 0;
++ }
++
++ if (!err) {
++ vfsub_drop_nlink(inode);
++ epilog(dir, dentry, bindex);
++
++ /* update target timestamps */
++ if (bindex == bstart) {
++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
++ inode->i_ctime = h_path.dentry->d_inode->i_ctime;
++ } else
++ /* todo: this timestamp may be reverted later */
++ inode->i_ctime = h_dir->i_ctime;
++ goto out_unpin; /* success */
++ }
++
++ /* revert */
++ if (wh_dentry) {
++ int rerr;
++
++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, &dt);
++ if (rerr)
++ err = rerr;
++ }
++
++out_unpin:
++ au_unpin(&pin);
++ dput(wh_dentry);
++ dput(h_path.dentry);
++out_parent:
++ di_write_unlock(parent);
++out_unlock:
++ aufs_read_unlock(dentry, AuLock_DW);
++out:
++ return err;
++}
++
++int aufs_rmdir(struct inode *dir, struct dentry *dentry)
++{
++ int err, rmdir_later;
++ aufs_bindex_t bwh, bindex, bstart;
++ struct au_dtime dt;
++ struct au_pin pin;
++ struct inode *inode;
++ struct dentry *parent, *wh_dentry, *h_dentry;
++ struct au_whtmp_rmdir *args;
++
++ IMustLock(dir);
++
++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN);
++ if (unlikely(err))
++ goto out;
++
++ /* VFS already unhashes it */
++ inode = dentry->d_inode;
++ err = -ENOENT;
++ if (unlikely(!inode || !inode->i_nlink
++ || IS_DEADDIR(inode)))
++ goto out_unlock;
++ IMustLock(inode);
++ err = -ENOTDIR;
++ if (unlikely(!S_ISDIR(inode->i_mode)))
++ goto out_unlock; /* possible? */
++
++ err = -ENOMEM;
++ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS);
++ if (unlikely(!args))
++ goto out_unlock;
++
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_write_lock_parent(parent);
++ err = au_test_empty(dentry, &args->whlist);
++ if (unlikely(err))
++ goto out_parent;
++
++ bstart = au_dbstart(dentry);
++ bwh = au_dbwh(dentry);
++ bindex = -1;
++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &dt, &pin);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_parent;
++
++ h_dentry = au_h_dptr(dentry, bstart);
++ dget(h_dentry);
++ rmdir_later = 0;
++ if (bindex == bstart) {
++ err = renwh_and_rmdir(dentry, bstart, &args->whlist, dir);
++ if (err > 0) {
++ rmdir_later = err;
++ err = 0;
++ }
++ } else {
++ /* stop monitoring */
++ au_hn_free(au_hi(inode, bstart));
++
++ /* dir inode is locked */
++ IMustLock(wh_dentry->d_parent->d_inode);
++ err = 0;
++ }
++
++ if (!err) {
++ vfsub_dead_dir(inode);
++ au_set_dbdiropq(dentry, -1);
++ epilog(dir, dentry, bindex);
++
++ if (rmdir_later) {
++ au_whtmp_kick_rmdir(dir, bstart, h_dentry, args);
++ args = NULL;
++ }
++
++ goto out_unpin; /* success */
++ }
++
++ /* revert */
++ AuLabel(revert);
++ if (wh_dentry) {
++ int rerr;
++
++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, &dt);
++ if (rerr)
++ err = rerr;
++ }
++
++out_unpin:
++ au_unpin(&pin);
++ dput(wh_dentry);
++ dput(h_dentry);
++out_parent:
++ di_write_unlock(parent);
++ if (args)
++ au_whtmp_rmdir_free(args);
++out_unlock:
++ aufs_read_unlock(dentry, AuLock_DW);
++out:
++ AuTraceErr(err);
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/i_op_ren.c linux-2.6.37/fs/aufs/i_op_ren.c
+--- linux-2.6.37.orig/fs/aufs/i_op_ren.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/i_op_ren.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,1017 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode operation (rename entry)
++ * todo: this is crazy monster
++ */
++
++#include "aufs.h"
++
++enum { AuSRC, AuDST, AuSrcDst };
++enum { AuPARENT, AuCHILD, AuParentChild };
++
++#define AuRen_ISDIR 1
++#define AuRen_ISSAMEDIR (1 << 1)
++#define AuRen_WHSRC (1 << 2)
++#define AuRen_WHDST (1 << 3)
++#define AuRen_MNT_WRITE (1 << 4)
++#define AuRen_DT_DSTDIR (1 << 5)
++#define AuRen_DIROPQ (1 << 6)
++#define AuRen_CPUP (1 << 7)
++#define au_ftest_ren(flags, name) ((flags) & AuRen_##name)
++#define au_fset_ren(flags, name) \
++ do { (flags) |= AuRen_##name; } while (0)
++#define au_fclr_ren(flags, name) \
++ do { (flags) &= ~AuRen_##name; } while (0)
++
++struct au_ren_args {
++ struct {
++ struct dentry *dentry, *h_dentry, *parent, *h_parent,
++ *wh_dentry;
++ struct inode *dir, *inode;
++ struct au_hinode *hdir;
++ struct au_dtime dt[AuParentChild];
++ aufs_bindex_t bstart;
++ } sd[AuSrcDst];
++
++#define src_dentry sd[AuSRC].dentry
++#define src_dir sd[AuSRC].dir
++#define src_inode sd[AuSRC].inode
++#define src_h_dentry sd[AuSRC].h_dentry
++#define src_parent sd[AuSRC].parent
++#define src_h_parent sd[AuSRC].h_parent
++#define src_wh_dentry sd[AuSRC].wh_dentry
++#define src_hdir sd[AuSRC].hdir
++#define src_h_dir sd[AuSRC].hdir->hi_inode
++#define src_dt sd[AuSRC].dt
++#define src_bstart sd[AuSRC].bstart
++
++#define dst_dentry sd[AuDST].dentry
++#define dst_dir sd[AuDST].dir
++#define dst_inode sd[AuDST].inode
++#define dst_h_dentry sd[AuDST].h_dentry
++#define dst_parent sd[AuDST].parent
++#define dst_h_parent sd[AuDST].h_parent
++#define dst_wh_dentry sd[AuDST].wh_dentry
++#define dst_hdir sd[AuDST].hdir
++#define dst_h_dir sd[AuDST].hdir->hi_inode
++#define dst_dt sd[AuDST].dt
++#define dst_bstart sd[AuDST].bstart
++
++ struct dentry *h_trap;
++ struct au_branch *br;
++ struct au_hinode *src_hinode;
++ struct path h_path;
++ struct au_nhash whlist;
++ aufs_bindex_t btgt, src_bwh, src_bdiropq;
++
++ unsigned int flags;
++
++ struct au_whtmp_rmdir *thargs;
++ struct dentry *h_dst;
++};
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * functions for reverting.
++ * when an error happened in a single rename systemcall, we should revert
++ * everything as if nothing happend.
++ * we don't need to revert the copied-up/down the parent dir since they are
++ * harmless.
++ */
++
++#define RevertFailure(fmt, ...) do { \
++ AuIOErr("revert failure: " fmt " (%d, %d)\n", \
++ ##__VA_ARGS__, err, rerr); \
++ err = -EIO; \
++} while (0)
++
++static void au_ren_rev_diropq(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
++ rerr = au_diropq_remove(a->src_dentry, a->btgt);
++ au_hn_imtx_unlock(a->src_hinode);
++ au_set_dbdiropq(a->src_dentry, a->src_bdiropq);
++ if (rerr)
++ RevertFailure("remove diropq %.*s", AuDLNPair(a->src_dentry));
++}
++
++static void au_ren_rev_rename(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = au_lkup_one(&a->src_dentry->d_name, a->src_h_parent,
++ a->br, /*nd*/NULL);
++ rerr = PTR_ERR(a->h_path.dentry);
++ if (IS_ERR(a->h_path.dentry)) {
++ RevertFailure("au_lkup_one %.*s", AuDLNPair(a->src_dentry));
++ return;
++ }
++
++ rerr = vfsub_rename(a->dst_h_dir,
++ au_h_dptr(a->src_dentry, a->btgt),
++ a->src_h_dir, &a->h_path);
++ d_drop(a->h_path.dentry);
++ dput(a->h_path.dentry);
++ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */
++ if (rerr)
++ RevertFailure("rename %.*s", AuDLNPair(a->src_dentry));
++}
++
++static void au_ren_rev_cpup(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = a->dst_h_dentry;
++ rerr = vfsub_unlink(a->dst_h_dir, &a->h_path, /*force*/0);
++ au_set_h_dptr(a->src_dentry, a->btgt, NULL);
++ au_set_dbstart(a->src_dentry, a->src_bstart);
++ if (rerr)
++ RevertFailure("unlink %.*s", AuDLNPair(a->dst_h_dentry));
++}
++
++static void au_ren_rev_whtmp(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = au_lkup_one(&a->dst_dentry->d_name, a->dst_h_parent,
++ a->br, /*nd*/NULL);
++ rerr = PTR_ERR(a->h_path.dentry);
++ if (IS_ERR(a->h_path.dentry)) {
++ RevertFailure("lookup %.*s", AuDLNPair(a->dst_dentry));
++ return;
++ }
++ if (a->h_path.dentry->d_inode) {
++ d_drop(a->h_path.dentry);
++ dput(a->h_path.dentry);
++ return;
++ }
++
++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path);
++ d_drop(a->h_path.dentry);
++ dput(a->h_path.dentry);
++ if (!rerr)
++ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst));
++ else
++ RevertFailure("rename %.*s", AuDLNPair(a->h_dst));
++}
++
++static void au_ren_rev_whsrc(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = a->src_wh_dentry;
++ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry);
++ au_set_dbwh(a->src_dentry, a->src_bwh);
++ if (rerr)
++ RevertFailure("unlink %.*s", AuDLNPair(a->src_wh_dentry));
++}
++#undef RevertFailure
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * when we have to copyup the renaming entry, do it with the rename-target name
++ * in order to minimize the cost (the later actual rename is unnecessary).
++ * otherwise rename it on the target branch.
++ */
++static int au_ren_or_cpup(struct au_ren_args *a)
++{
++ int err;
++ struct dentry *d;
++
++ d = a->src_dentry;
++ if (au_dbstart(d) == a->btgt) {
++ a->h_path.dentry = a->dst_h_dentry;
++ if (au_ftest_ren(a->flags, DIROPQ)
++ && au_dbdiropq(d) == a->btgt)
++ au_fclr_ren(a->flags, DIROPQ);
++ AuDebugOn(au_dbstart(d) != a->btgt);
++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt),
++ a->dst_h_dir, &a->h_path);
++ } else {
++ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex;
++ struct file *h_file;
++
++ au_fset_ren(a->flags, CPUP);
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ au_set_dbstart(d, a->btgt);
++ au_set_h_dptr(d, a->btgt, dget(a->dst_h_dentry));
++ h_file = au_h_open_pre(d, a->src_bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_single(d, a->btgt, a->src_bstart, -1,
++ !AuCpup_DTIME, a->dst_parent);
++ mutex_unlock(h_mtx);
++ au_h_open_post(d, a->src_bstart, h_file);
++ if (!err) {
++ d = a->dst_dentry;
++ au_set_h_dptr(d, a->btgt, NULL);
++ au_update_dbstart(d);
++ } else {
++ au_set_h_dptr(d, a->btgt, NULL);
++ au_set_dbstart(d, a->src_bstart);
++ }
++ }
++ if (!err && a->h_dst)
++ /* it will be set to dinfo later */
++ dget(a->h_dst);
++
++ return err;
++}
++
++/* cf. aufs_rmdir() */
++static int au_ren_del_whtmp(struct au_ren_args *a)
++{
++ int err;
++ struct inode *dir;
++
++ dir = a->dst_dir;
++ SiMustAnyLock(dir->i_sb);
++ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt,
++ au_sbi(dir->i_sb)->si_dirwh)
++ || au_test_fs_remote(a->h_dst->d_sb)) {
++ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist);
++ if (unlikely(err))
++ pr_warning("failed removing whtmp dir %.*s (%d), "
++ "ignored.\n", AuDLNPair(a->h_dst), err);
++ } else {
++ au_nhash_wh_free(&a->thargs->whlist);
++ a->thargs->whlist = a->whlist;
++ a->whlist.nh_num = 0;
++ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs);
++ dput(a->h_dst);
++ a->thargs = NULL;
++ }
++
++ return 0;
++}
++
++/* make it 'opaque' dir. */
++static int au_ren_diropq(struct au_ren_args *a)
++{
++ int err;
++ struct dentry *diropq;
++
++ err = 0;
++ a->src_bdiropq = au_dbdiropq(a->src_dentry);
++ a->src_hinode = au_hi(a->src_inode, a->btgt);
++ au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
++ diropq = au_diropq_create(a->src_dentry, a->btgt);
++ au_hn_imtx_unlock(a->src_hinode);
++ if (IS_ERR(diropq))
++ err = PTR_ERR(diropq);
++ dput(diropq);
++
++ return err;
++}
++
++static int do_rename(struct au_ren_args *a)
++{
++ int err;
++ struct dentry *d, *h_d;
++
++ /* prepare workqueue args for asynchronous rmdir */
++ h_d = a->dst_h_dentry;
++ if (au_ftest_ren(a->flags, ISDIR) && h_d->d_inode) {
++ err = -ENOMEM;
++ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, GFP_NOFS);
++ if (unlikely(!a->thargs))
++ goto out;
++ a->h_dst = dget(h_d);
++ }
++
++ /* create whiteout for src_dentry */
++ if (au_ftest_ren(a->flags, WHSRC)) {
++ a->src_bwh = au_dbwh(a->src_dentry);
++ AuDebugOn(a->src_bwh >= 0);
++ a->src_wh_dentry
++ = au_wh_create(a->src_dentry, a->btgt, a->src_h_parent);
++ err = PTR_ERR(a->src_wh_dentry);
++ if (IS_ERR(a->src_wh_dentry))
++ goto out_thargs;
++ }
++
++ /* lookup whiteout for dentry */
++ if (au_ftest_ren(a->flags, WHDST)) {
++ h_d = au_wh_lkup(a->dst_h_parent, &a->dst_dentry->d_name,
++ a->br);
++ err = PTR_ERR(h_d);
++ if (IS_ERR(h_d))
++ goto out_whsrc;
++ if (!h_d->d_inode)
++ dput(h_d);
++ else
++ a->dst_wh_dentry = h_d;
++ }
++
++ /* rename dentry to tmpwh */
++ if (a->thargs) {
++ err = au_whtmp_ren(a->dst_h_dentry, a->br);
++ if (unlikely(err))
++ goto out_whdst;
++
++ d = a->dst_dentry;
++ au_set_h_dptr(d, a->btgt, NULL);
++ err = au_lkup_neg(d, a->btgt);
++ if (unlikely(err))
++ goto out_whtmp;
++ a->dst_h_dentry = au_h_dptr(d, a->btgt);
++ }
++
++ /* cpup src */
++ if (a->dst_h_dentry->d_inode && a->src_bstart != a->btgt) {
++ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex;
++ struct file *h_file;
++
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ AuDebugOn(au_dbstart(a->src_dentry) != a->src_bstart);
++ h_file = au_h_open_pre(a->src_dentry, a->src_bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_simple(a->src_dentry, a->btgt, -1,
++ !AuCpup_DTIME);
++ mutex_unlock(h_mtx);
++ au_h_open_post(a->src_dentry, a->src_bstart, h_file);
++ if (unlikely(err))
++ goto out_whtmp;
++ }
++
++ /* rename by vfs_rename or cpup */
++ d = a->dst_dentry;
++ if (au_ftest_ren(a->flags, ISDIR)
++ && (a->dst_wh_dentry
++ || au_dbdiropq(d) == a->btgt
++ /* hide the lower to keep xino */
++ || a->btgt < au_dbend(d)
++ || au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ)))
++ au_fset_ren(a->flags, DIROPQ);
++ err = au_ren_or_cpup(a);
++ if (unlikely(err))
++ /* leave the copied-up one */
++ goto out_whtmp;
++
++ /* make dir opaque */
++ if (au_ftest_ren(a->flags, DIROPQ)) {
++ err = au_ren_diropq(a);
++ if (unlikely(err))
++ goto out_rename;
++ }
++
++ /* update target timestamps */
++ AuDebugOn(au_dbstart(a->src_dentry) != a->btgt);
++ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt);
++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/
++ a->src_inode->i_ctime = a->h_path.dentry->d_inode->i_ctime;
++
++ /* remove whiteout for dentry */
++ if (a->dst_wh_dentry) {
++ a->h_path.dentry = a->dst_wh_dentry;
++ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path,
++ a->dst_dentry);
++ if (unlikely(err))
++ goto out_diropq;
++ }
++
++ /* remove whtmp */
++ if (a->thargs)
++ au_ren_del_whtmp(a); /* ignore this error */
++
++ err = 0;
++ goto out_success;
++
++out_diropq:
++ if (au_ftest_ren(a->flags, DIROPQ))
++ au_ren_rev_diropq(err, a);
++out_rename:
++ if (!au_ftest_ren(a->flags, CPUP))
++ au_ren_rev_rename(err, a);
++ else
++ au_ren_rev_cpup(err, a);
++ dput(a->h_dst);
++out_whtmp:
++ if (a->thargs)
++ au_ren_rev_whtmp(err, a);
++out_whdst:
++ dput(a->dst_wh_dentry);
++ a->dst_wh_dentry = NULL;
++out_whsrc:
++ if (a->src_wh_dentry)
++ au_ren_rev_whsrc(err, a);
++out_success:
++ dput(a->src_wh_dentry);
++ dput(a->dst_wh_dentry);
++out_thargs:
++ if (a->thargs) {
++ dput(a->h_dst);
++ au_whtmp_rmdir_free(a->thargs);
++ a->thargs = NULL;
++ }
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * test if @dentry dir can be rename destination or not.
++ * success means, it is a logically empty dir.
++ */
++static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist)
++{
++ return au_test_empty(dentry, whlist);
++}
++
++/*
++ * test if @dentry dir can be rename source or not.
++ * if it can, return 0 and @children is filled.
++ * success means,
++ * - it is a logically empty dir.
++ * - or, it exists on writable branch and has no children including whiteouts
++ * on the lower branch.
++ */
++static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt)
++{
++ int err;
++ unsigned int rdhash;
++ aufs_bindex_t bstart;
++
++ bstart = au_dbstart(dentry);
++ if (bstart != btgt) {
++ struct au_nhash whlist;
++
++ SiMustAnyLock(dentry->d_sb);
++ rdhash = au_sbi(dentry->d_sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL,
++ dentry));
++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_test_empty(dentry, &whlist);
++ au_nhash_wh_free(&whlist);
++ goto out;
++ }
++
++ if (bstart == au_dbtaildir(dentry))
++ return 0; /* success */
++
++ err = au_test_empty_lower(dentry);
++
++out:
++ if (err == -ENOTEMPTY) {
++ AuWarn1("renaming dir who has child(ren) on multiple branches,"
++ " is not supported\n");
++ err = -EXDEV;
++ }
++ return err;
++}
++
++/* side effect: sets whlist and h_dentry */
++static int au_ren_may_dir(struct au_ren_args *a)
++{
++ int err;
++ unsigned int rdhash;
++ struct dentry *d;
++
++ d = a->dst_dentry;
++ SiMustAnyLock(d->d_sb);
++
++ err = 0;
++ if (au_ftest_ren(a->flags, ISDIR) && a->dst_inode) {
++ rdhash = au_sbi(d->d_sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d));
++ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++
++ au_set_dbstart(d, a->dst_bstart);
++ err = may_rename_dstdir(d, &a->whlist);
++ au_set_dbstart(d, a->btgt);
++ }
++ a->dst_h_dentry = au_h_dptr(d, au_dbstart(d));
++ if (unlikely(err))
++ goto out;
++
++ d = a->src_dentry;
++ a->src_h_dentry = au_h_dptr(d, au_dbstart(d));
++ if (au_ftest_ren(a->flags, ISDIR)) {
++ err = may_rename_srcdir(d, a->btgt);
++ if (unlikely(err)) {
++ au_nhash_wh_free(&a->whlist);
++ a->whlist.nh_num = 0;
++ }
++ }
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * simple tests for rename.
++ * following the checks in vfs, plus the parent-child relationship.
++ */
++static int au_may_ren(struct au_ren_args *a)
++{
++ int err, isdir;
++ struct inode *h_inode;
++
++ if (a->src_bstart == a->btgt) {
++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent,
++ au_ftest_ren(a->flags, ISDIR));
++ if (unlikely(err))
++ goto out;
++ err = -EINVAL;
++ if (unlikely(a->src_h_dentry == a->h_trap))
++ goto out;
++ }
++
++ err = 0;
++ if (a->dst_bstart != a->btgt)
++ goto out;
++
++ err = -EIO;
++ h_inode = a->dst_h_dentry->d_inode;
++ isdir = !!au_ftest_ren(a->flags, ISDIR);
++ if (!a->dst_dentry->d_inode) {
++ if (unlikely(h_inode))
++ goto out;
++ err = au_may_add(a->dst_dentry, a->btgt, a->dst_h_parent,
++ isdir);
++ } else {
++ if (unlikely(!h_inode || !h_inode->i_nlink))
++ goto out;
++ err = au_may_del(a->dst_dentry, a->btgt, a->dst_h_parent,
++ isdir);
++ if (unlikely(err))
++ goto out;
++ err = -ENOTEMPTY;
++ if (unlikely(a->dst_h_dentry == a->h_trap))
++ goto out;
++ err = 0;
++ }
++
++out:
++ if (unlikely(err == -ENOENT || err == -EEXIST))
++ err = -EIO;
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * locking order
++ * (VFS)
++ * - src_dir and dir by lock_rename()
++ * - inode if exitsts
++ * (aufs)
++ * - lock all
++ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls,
++ * + si_read_lock
++ * + di_write_lock2_child()
++ * + di_write_lock_child()
++ * + ii_write_lock_child()
++ * + di_write_lock_child2()
++ * + ii_write_lock_child2()
++ * + src_parent and parent
++ * + di_write_lock_parent()
++ * + ii_write_lock_parent()
++ * + di_write_lock_parent2()
++ * + ii_write_lock_parent2()
++ * + lower src_dir and dir by vfsub_lock_rename()
++ * + verify the every relationships between child and parent. if any
++ * of them failed, unlock all and return -EBUSY.
++ */
++static void au_ren_unlock(struct au_ren_args *a)
++{
++ struct super_block *sb;
++
++ sb = a->dst_dentry->d_sb;
++ if (au_ftest_ren(a->flags, MNT_WRITE))
++ mnt_drop_write(a->br->br_mnt);
++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir,
++ a->dst_h_parent, a->dst_hdir);
++}
++
++static int au_ren_lock(struct au_ren_args *a)
++{
++ int err;
++ unsigned int udba;
++
++ err = 0;
++ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt);
++ a->src_hdir = au_hi(a->src_dir, a->btgt);
++ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt);
++ a->dst_hdir = au_hi(a->dst_dir, a->btgt);
++ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir,
++ a->dst_h_parent, a->dst_hdir);
++ udba = au_opt_udba(a->src_dentry->d_sb);
++ if (unlikely(a->src_hdir->hi_inode != a->src_h_parent->d_inode
++ || a->dst_hdir->hi_inode != a->dst_h_parent->d_inode))
++ err = au_busy_or_stale();
++ if (!err && au_dbstart(a->src_dentry) == a->btgt)
++ err = au_h_verify(a->src_h_dentry, udba,
++ a->src_h_parent->d_inode, a->src_h_parent,
++ a->br);
++ if (!err && au_dbstart(a->dst_dentry) == a->btgt)
++ err = au_h_verify(a->dst_h_dentry, udba,
++ a->dst_h_parent->d_inode, a->dst_h_parent,
++ a->br);
++ if (!err) {
++ err = mnt_want_write(a->br->br_mnt);
++ if (unlikely(err))
++ goto out_unlock;
++ au_fset_ren(a->flags, MNT_WRITE);
++ goto out; /* success */
++ }
++
++ err = au_busy_or_stale();
++
++out_unlock:
++ au_ren_unlock(a);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void au_ren_refresh_dir(struct au_ren_args *a)
++{
++ struct inode *dir;
++
++ dir = a->dst_dir;
++ dir->i_version++;
++ if (au_ftest_ren(a->flags, ISDIR)) {
++ /* is this updating defined in POSIX? */
++ au_cpup_attr_timesizes(a->src_inode);
++ au_cpup_attr_nlink(dir, /*force*/1);
++ }
++
++ if (au_ibstart(dir) == a->btgt)
++ au_cpup_attr_timesizes(dir);
++
++ if (au_ftest_ren(a->flags, ISSAMEDIR))
++ return;
++
++ dir = a->src_dir;
++ dir->i_version++;
++ if (au_ftest_ren(a->flags, ISDIR))
++ au_cpup_attr_nlink(dir, /*force*/1);
++ if (au_ibstart(dir) == a->btgt)
++ au_cpup_attr_timesizes(dir);
++}
++
++static void au_ren_refresh(struct au_ren_args *a)
++{
++ aufs_bindex_t bend, bindex;
++ struct dentry *d, *h_d;
++ struct inode *i, *h_i;
++ struct super_block *sb;
++
++ d = a->dst_dentry;
++ d_drop(d);
++ if (a->h_dst)
++ /* already dget-ed by au_ren_or_cpup() */
++ au_set_h_dptr(d, a->btgt, a->h_dst);
++
++ i = a->dst_inode;
++ if (i) {
++ if (!au_ftest_ren(a->flags, ISDIR))
++ vfsub_drop_nlink(i);
++ else {
++ vfsub_dead_dir(i);
++ au_cpup_attr_timesizes(i);
++ }
++ au_update_dbrange(d, /*do_put_zero*/1);
++ } else {
++ bend = a->btgt;
++ for (bindex = au_dbstart(d); bindex < bend; bindex++)
++ au_set_h_dptr(d, bindex, NULL);
++ bend = au_dbend(d);
++ for (bindex = a->btgt + 1; bindex <= bend; bindex++)
++ au_set_h_dptr(d, bindex, NULL);
++ au_update_dbrange(d, /*do_put_zero*/0);
++ }
++
++ d = a->src_dentry;
++ au_set_dbwh(d, -1);
++ bend = au_dbend(d);
++ for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
++ h_d = au_h_dptr(d, bindex);
++ if (h_d)
++ au_set_h_dptr(d, bindex, NULL);
++ }
++ au_set_dbend(d, a->btgt);
++
++ sb = d->d_sb;
++ i = a->src_inode;
++ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i))
++ return; /* success */
++
++ bend = au_ibend(i);
++ for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
++ h_i = au_h_iptr(i, bindex);
++ if (h_i) {
++ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0);
++ /* ignore this error */
++ au_set_h_iptr(i, bindex, NULL, 0);
++ }
++ }
++ au_set_ibend(i, a->btgt);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* mainly for link(2) and rename(2) */
++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt)
++{
++ aufs_bindex_t bdiropq, bwh;
++ struct dentry *parent;
++ struct au_branch *br;
++
++ parent = dentry->d_parent;
++ IMustLock(parent->d_inode); /* dir is locked */
++
++ bdiropq = au_dbdiropq(parent);
++ bwh = au_dbwh(dentry);
++ br = au_sbr(dentry->d_sb, btgt);
++ if (au_br_rdonly(br)
++ || (0 <= bdiropq && bdiropq < btgt)
++ || (0 <= bwh && bwh < btgt))
++ btgt = -1;
++
++ AuDbg("btgt %d\n", btgt);
++ return btgt;
++}
++
++/* sets src_bstart, dst_bstart and btgt */
++static int au_ren_wbr(struct au_ren_args *a)
++{
++ int err;
++ struct au_wr_dir_args wr_dir_args = {
++ /* .force_btgt = -1, */
++ .flags = AuWrDir_ADD_ENTRY
++ };
++
++ a->src_bstart = au_dbstart(a->src_dentry);
++ a->dst_bstart = au_dbstart(a->dst_dentry);
++ if (au_ftest_ren(a->flags, ISDIR))
++ au_fset_wrdir(wr_dir_args.flags, ISDIR);
++ wr_dir_args.force_btgt = a->src_bstart;
++ if (a->dst_inode && a->dst_bstart < a->src_bstart)
++ wr_dir_args.force_btgt = a->dst_bstart;
++ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt);
++ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args);
++ a->btgt = err;
++
++ return err;
++}
++
++static void au_ren_dt(struct au_ren_args *a)
++{
++ a->h_path.dentry = a->src_h_parent;
++ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path);
++ if (!au_ftest_ren(a->flags, ISSAMEDIR)) {
++ a->h_path.dentry = a->dst_h_parent;
++ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path);
++ }
++
++ au_fclr_ren(a->flags, DT_DSTDIR);
++ if (!au_ftest_ren(a->flags, ISDIR))
++ return;
++
++ a->h_path.dentry = a->src_h_dentry;
++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path);
++ if (a->dst_h_dentry->d_inode) {
++ au_fset_ren(a->flags, DT_DSTDIR);
++ a->h_path.dentry = a->dst_h_dentry;
++ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path);
++ }
++}
++
++static void au_ren_rev_dt(int err, struct au_ren_args *a)
++{
++ struct dentry *h_d;
++ struct mutex *h_mtx;
++
++ au_dtime_revert(a->src_dt + AuPARENT);
++ if (!au_ftest_ren(a->flags, ISSAMEDIR))
++ au_dtime_revert(a->dst_dt + AuPARENT);
++
++ if (au_ftest_ren(a->flags, ISDIR) && err != -EIO) {
++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry;
++ h_mtx = &h_d->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ au_dtime_revert(a->src_dt + AuCHILD);
++ mutex_unlock(h_mtx);
++
++ if (au_ftest_ren(a->flags, DT_DSTDIR)) {
++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry;
++ h_mtx = &h_d->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ au_dtime_revert(a->dst_dt + AuCHILD);
++ mutex_unlock(h_mtx);
++ }
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry,
++ struct inode *_dst_dir, struct dentry *_dst_dentry)
++{
++ int err, flags;
++ /* reduce stack space */
++ struct au_ren_args *a;
++
++ AuDbg("%.*s, %.*s\n", AuDLNPair(_src_dentry), AuDLNPair(_dst_dentry));
++ IMustLock(_src_dir);
++ IMustLock(_dst_dir);
++
++ err = -ENOMEM;
++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE);
++ a = kzalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ a->src_dir = _src_dir;
++ a->src_dentry = _src_dentry;
++ a->src_inode = a->src_dentry->d_inode;
++ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */
++ a->dst_dir = _dst_dir;
++ a->dst_dentry = _dst_dentry;
++ a->dst_inode = a->dst_dentry->d_inode;
++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */
++ if (a->dst_inode) {
++ IMustLock(a->dst_inode);
++ au_igrab(a->dst_inode);
++ }
++
++ err = -ENOTDIR;
++ flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN;
++ if (S_ISDIR(a->src_inode->i_mode)) {
++ au_fset_ren(a->flags, ISDIR);
++ if (unlikely(a->dst_inode && !S_ISDIR(a->dst_inode->i_mode)))
++ goto out_free;
++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry,
++ AuLock_DIR | flags);
++ } else
++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry,
++ flags);
++ if (unlikely(err))
++ goto out_free;
++
++ err = au_d_hashed_positive(a->src_dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ err = -ENOENT;
++ if (a->dst_inode) {
++ /*
++ * If it is a dir, VFS unhash dst_dentry before this
++ * function. It means we cannot rely upon d_unhashed().
++ */
++ if (unlikely(!a->dst_inode->i_nlink))
++ goto out_unlock;
++ if (!S_ISDIR(a->dst_inode->i_mode)) {
++ err = au_d_hashed_positive(a->dst_dentry);
++ if (unlikely(err))
++ goto out_unlock;
++ } else if (unlikely(IS_DEADDIR(a->dst_inode)))
++ goto out_unlock;
++ } else if (unlikely(d_unhashed(a->dst_dentry)))
++ goto out_unlock;
++
++ au_fset_ren(a->flags, ISSAMEDIR); /* temporary */
++ di_write_lock_parent(a->dst_parent);
++
++ /* which branch we process */
++ err = au_ren_wbr(a);
++ if (unlikely(err < 0))
++ goto out_parent;
++ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt);
++ a->h_path.mnt = a->br->br_mnt;
++
++ /* are they available to be renamed */
++ err = au_ren_may_dir(a);
++ if (unlikely(err))
++ goto out_children;
++
++ /* prepare the writable parent dir on the same branch */
++ if (a->dst_bstart == a->btgt) {
++ au_fset_ren(a->flags, WHDST);
++ } else {
++ err = au_cpup_dirs(a->dst_dentry, a->btgt);
++ if (unlikely(err))
++ goto out_children;
++ }
++
++ if (a->src_dir != a->dst_dir) {
++ /*
++ * this temporary unlock is safe,
++ * because both dir->i_mutex are locked.
++ */
++ di_write_unlock(a->dst_parent);
++ di_write_lock_parent(a->src_parent);
++ err = au_wr_dir_need_wh(a->src_dentry,
++ au_ftest_ren(a->flags, ISDIR),
++ &a->btgt);
++ di_write_unlock(a->src_parent);
++ di_write_lock2_parent(a->src_parent, a->dst_parent, /*isdir*/1);
++ au_fclr_ren(a->flags, ISSAMEDIR);
++ } else
++ err = au_wr_dir_need_wh(a->src_dentry,
++ au_ftest_ren(a->flags, ISDIR),
++ &a->btgt);
++ if (unlikely(err < 0))
++ goto out_children;
++ if (err)
++ au_fset_ren(a->flags, WHSRC);
++
++ /* lock them all */
++ err = au_ren_lock(a);
++ if (unlikely(err))
++ goto out_children;
++
++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE))
++ err = au_may_ren(a);
++ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN))
++ err = -ENAMETOOLONG;
++ if (unlikely(err))
++ goto out_hdir;
++
++ /* store timestamps to be revertible */
++ au_ren_dt(a);
++
++ /* here we go */
++ err = do_rename(a);
++ if (unlikely(err))
++ goto out_dt;
++
++ /* update dir attributes */
++ au_ren_refresh_dir(a);
++
++ /* dput/iput all lower dentries */
++ au_ren_refresh(a);
++
++ goto out_hdir; /* success */
++
++out_dt:
++ au_ren_rev_dt(err, a);
++out_hdir:
++ au_ren_unlock(a);
++out_children:
++ au_nhash_wh_free(&a->whlist);
++ if (err && a->dst_inode && a->dst_bstart != a->btgt) {
++ AuDbg("bstart %d, btgt %d\n", a->dst_bstart, a->btgt);
++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL);
++ au_set_dbstart(a->dst_dentry, a->dst_bstart);
++ }
++out_parent:
++ if (!err)
++ d_move(a->src_dentry, a->dst_dentry);
++ else {
++ au_update_dbstart(a->dst_dentry);
++ if (!a->dst_inode)
++ d_drop(a->dst_dentry);
++ }
++ if (au_ftest_ren(a->flags, ISSAMEDIR))
++ di_write_unlock(a->dst_parent);
++ else
++ di_write_unlock2(a->src_parent, a->dst_parent);
++out_unlock:
++ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry);
++out_free:
++ iput(a->dst_inode);
++ if (a->thargs)
++ au_whtmp_rmdir_free(a->thargs);
++ kfree(a);
++out:
++ AuTraceErr(err);
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/iinfo.c linux-2.6.37/fs/aufs/iinfo.c
+--- linux-2.6.37.orig/fs/aufs/iinfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/iinfo.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,263 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode private data
++ */
++
++#include "aufs.h"
++
++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex)
++{
++ struct inode *h_inode;
++
++ IiMustAnyLock(inode);
++
++ h_inode = au_ii(inode)->ii_hinode[0 + bindex].hi_inode;
++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0);
++ return h_inode;
++}
++
++/* todo: hard/soft set? */
++void au_hiput(struct au_hinode *hinode)
++{
++ au_hn_free(hinode);
++ dput(hinode->hi_whdentry);
++ iput(hinode->hi_inode);
++}
++
++unsigned int au_hi_flags(struct inode *inode, int isdir)
++{
++ unsigned int flags;
++ const unsigned int mnt_flags = au_mntflags(inode->i_sb);
++
++ flags = 0;
++ if (au_opt_test(mnt_flags, XINO))
++ au_fset_hi(flags, XINO);
++ if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY))
++ au_fset_hi(flags, HNOTIFY);
++ return flags;
++}
++
++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
++ struct inode *h_inode, unsigned int flags)
++{
++ struct au_hinode *hinode;
++ struct inode *hi;
++ struct au_iinfo *iinfo = au_ii(inode);
++
++ IiMustWriteLock(inode);
++
++ hinode = iinfo->ii_hinode + bindex;
++ hi = hinode->hi_inode;
++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0);
++
++ if (hi)
++ au_hiput(hinode);
++ hinode->hi_inode = h_inode;
++ if (h_inode) {
++ int err;
++ struct super_block *sb = inode->i_sb;
++ struct au_branch *br;
++
++ AuDebugOn(inode->i_mode
++ && (h_inode->i_mode & S_IFMT)
++ != (inode->i_mode & S_IFMT));
++ if (bindex == iinfo->ii_bstart)
++ au_cpup_igen(inode, h_inode);
++ br = au_sbr(sb, bindex);
++ hinode->hi_id = br->br_id;
++ if (au_ftest_hi(flags, XINO)) {
++ err = au_xino_write(sb, bindex, h_inode->i_ino,
++ inode->i_ino);
++ if (unlikely(err))
++ AuIOErr1("failed au_xino_write() %d\n", err);
++ }
++
++ if (au_ftest_hi(flags, HNOTIFY)
++ && au_br_hnotifyable(br->br_perm)) {
++ err = au_hn_alloc(hinode, inode);
++ if (unlikely(err))
++ AuIOErr1("au_hn_alloc() %d\n", err);
++ }
++ }
++}
++
++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_wh)
++{
++ struct au_hinode *hinode;
++
++ IiMustWriteLock(inode);
++
++ hinode = au_ii(inode)->ii_hinode + bindex;
++ AuDebugOn(hinode->hi_whdentry);
++ hinode->hi_whdentry = h_wh;
++}
++
++void au_update_iigen(struct inode *inode)
++{
++ atomic_set(&au_ii(inode)->ii_generation, au_sigen(inode->i_sb));
++ /* smp_mb(); */ /* atomic_set */
++}
++
++/* it may be called at remount time, too */
++void au_update_ibrange(struct inode *inode, int do_put_zero)
++{
++ struct au_iinfo *iinfo;
++ aufs_bindex_t bindex, bend;
++
++ iinfo = au_ii(inode);
++ if (!iinfo)
++ return;
++
++ IiMustWriteLock(inode);
++
++ if (do_put_zero && iinfo->ii_bstart >= 0) {
++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
++ bindex++) {
++ struct inode *h_i;
++
++ h_i = iinfo->ii_hinode[0 + bindex].hi_inode;
++ if (h_i && !h_i->i_nlink)
++ au_set_h_iptr(inode, bindex, NULL, 0);
++ }
++ }
++
++ iinfo->ii_bstart = -1;
++ iinfo->ii_bend = -1;
++ bend = au_sbend(inode->i_sb);
++ for (bindex = 0; bindex <= bend; bindex++)
++ if (iinfo->ii_hinode[0 + bindex].hi_inode) {
++ iinfo->ii_bstart = bindex;
++ break;
++ }
++ if (iinfo->ii_bstart >= 0)
++ for (bindex = bend; bindex >= iinfo->ii_bstart; bindex--)
++ if (iinfo->ii_hinode[0 + bindex].hi_inode) {
++ iinfo->ii_bend = bindex;
++ break;
++ }
++ AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend);
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_icntnr_init_once(void *_c)
++{
++ struct au_icntnr *c = _c;
++ struct au_iinfo *iinfo = &c->iinfo;
++ static struct lock_class_key aufs_ii;
++
++ au_rw_init(&iinfo->ii_rwsem);
++ au_rw_class(&iinfo->ii_rwsem, &aufs_ii);
++ inode_init_once(&c->vfs_inode);
++}
++
++int au_iinfo_init(struct inode *inode)
++{
++ struct au_iinfo *iinfo;
++ struct super_block *sb;
++ int nbr, i;
++
++ sb = inode->i_sb;
++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo);
++ nbr = au_sbend(sb) + 1;
++ if (unlikely(nbr <= 0))
++ nbr = 1;
++ iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS);
++ if (iinfo->ii_hinode) {
++ au_ninodes_inc(sb);
++ for (i = 0; i < nbr; i++)
++ iinfo->ii_hinode[i].hi_id = -1;
++
++ atomic_set(&iinfo->ii_generation, au_sigen(sb));
++ /* smp_mb(); */ /* atomic_set */
++ iinfo->ii_bstart = -1;
++ iinfo->ii_bend = -1;
++ iinfo->ii_vdir = NULL;
++ return 0;
++ }
++ return -ENOMEM;
++}
++
++int au_ii_realloc(struct au_iinfo *iinfo, int nbr)
++{
++ int err, sz;
++ struct au_hinode *hip;
++
++ AuRwMustWriteLock(&iinfo->ii_rwsem);
++
++ err = -ENOMEM;
++ sz = sizeof(*hip) * (iinfo->ii_bend + 1);
++ if (!sz)
++ sz = sizeof(*hip);
++ hip = au_kzrealloc(iinfo->ii_hinode, sz, sizeof(*hip) * nbr, GFP_NOFS);
++ if (hip) {
++ iinfo->ii_hinode = hip;
++ err = 0;
++ }
++
++ return err;
++}
++
++void au_iinfo_fin(struct inode *inode)
++{
++ struct au_iinfo *iinfo;
++ struct au_hinode *hi;
++ struct super_block *sb;
++ aufs_bindex_t bindex, bend;
++ const unsigned char unlinked = !inode->i_nlink;
++
++ iinfo = au_ii(inode);
++ /* bad_inode case */
++ if (!iinfo)
++ return;
++
++ sb = inode->i_sb;
++ au_ninodes_dec(sb);
++ if (si_pid_test(sb))
++ au_xino_delete_inode(inode, unlinked);
++ else {
++ /*
++ * it is safe to hide the dependency between sbinfo and
++ * sb->s_umount.
++ */
++ lockdep_off();
++ si_noflush_read_lock(sb);
++ au_xino_delete_inode(inode, unlinked);
++ si_read_unlock(sb);
++ lockdep_on();
++ }
++
++ if (iinfo->ii_vdir)
++ au_vdir_free(iinfo->ii_vdir);
++
++ bindex = iinfo->ii_bstart;
++ if (bindex >= 0) {
++ hi = iinfo->ii_hinode + bindex;
++ bend = iinfo->ii_bend;
++ while (bindex++ <= bend) {
++ if (hi->hi_inode)
++ au_hiput(hi);
++ hi++;
++ }
++ }
++ kfree(iinfo->ii_hinode);
++ AuRwDestroy(&iinfo->ii_rwsem);
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/inode.c linux-2.6.37/fs/aufs/inode.c
+--- linux-2.6.37.orig/fs/aufs/inode.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/inode.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,471 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode functions
++ */
++
++#include "aufs.h"
++
++struct inode *au_igrab(struct inode *inode)
++{
++ if (inode) {
++ AuDebugOn(!atomic_read(&inode->i_count));
++ atomic_inc(&inode->i_count);
++ }
++ return inode;
++}
++
++static void au_refresh_hinode_attr(struct inode *inode, int do_version)
++{
++ au_cpup_attr_all(inode, /*force*/0);
++ au_update_iigen(inode);
++ if (do_version)
++ inode->i_version++;
++}
++
++static int au_ii_refresh(struct inode *inode, int *update)
++{
++ int err, e;
++ umode_t type;
++ aufs_bindex_t bindex, new_bindex;
++ struct super_block *sb;
++ struct au_iinfo *iinfo;
++ struct au_hinode *p, *q, tmp;
++
++ IiMustWriteLock(inode);
++
++ *update = 0;
++ sb = inode->i_sb;
++ type = inode->i_mode & S_IFMT;
++ iinfo = au_ii(inode);
++ err = au_ii_realloc(iinfo, au_sbend(sb) + 1);
++ if (unlikely(err))
++ goto out;
++
++ AuDebugOn(iinfo->ii_bstart < 0);
++ p = iinfo->ii_hinode + iinfo->ii_bstart;
++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
++ bindex++, p++) {
++ if (!p->hi_inode)
++ continue;
++
++ AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT));
++ new_bindex = au_br_index(sb, p->hi_id);
++ if (new_bindex == bindex)
++ continue;
++
++ if (new_bindex < 0) {
++ *update = 1;
++ au_hiput(p);
++ p->hi_inode = NULL;
++ continue;
++ }
++
++ if (new_bindex < iinfo->ii_bstart)
++ iinfo->ii_bstart = new_bindex;
++ if (iinfo->ii_bend < new_bindex)
++ iinfo->ii_bend = new_bindex;
++ /* swap two lower inode, and loop again */
++ q = iinfo->ii_hinode + new_bindex;
++ tmp = *q;
++ *q = *p;
++ *p = tmp;
++ if (tmp.hi_inode) {
++ bindex--;
++ p--;
++ }
++ }
++ au_update_ibrange(inode, /*do_put_zero*/0);
++ e = au_dy_irefresh(inode);
++ if (unlikely(e && !err))
++ err = e;
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++int au_refresh_hinode_self(struct inode *inode)
++{
++ int err, update;
++
++ err = au_ii_refresh(inode, &update);
++ if (!err)
++ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode));
++
++ AuTraceErr(err);
++ return err;
++}
++
++int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
++{
++ int err, e, update;
++ unsigned int flags;
++ umode_t mode;
++ aufs_bindex_t bindex, bend;
++ unsigned char isdir;
++ struct au_hinode *p;
++ struct au_iinfo *iinfo;
++
++ err = au_ii_refresh(inode, &update);
++ if (unlikely(err))
++ goto out;
++
++ update = 0;
++ iinfo = au_ii(inode);
++ p = iinfo->ii_hinode + iinfo->ii_bstart;
++ mode = (inode->i_mode & S_IFMT);
++ isdir = S_ISDIR(mode);
++ flags = au_hi_flags(inode, isdir);
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
++ struct inode *h_i;
++ struct dentry *h_d;
++
++ h_d = au_h_dptr(dentry, bindex);
++ if (!h_d || !h_d->d_inode)
++ continue;
++
++ AuDebugOn(mode != (h_d->d_inode->i_mode & S_IFMT));
++ if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) {
++ h_i = au_h_iptr(inode, bindex);
++ if (h_i) {
++ if (h_i == h_d->d_inode)
++ continue;
++ err = -EIO;
++ break;
++ }
++ }
++ if (bindex < iinfo->ii_bstart)
++ iinfo->ii_bstart = bindex;
++ if (iinfo->ii_bend < bindex)
++ iinfo->ii_bend = bindex;
++ au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags);
++ update = 1;
++ }
++ au_update_ibrange(inode, /*do_put_zero*/0);
++ e = au_dy_irefresh(inode);
++ if (unlikely(e && !err))
++ err = e;
++ if (!err)
++ au_refresh_hinode_attr(inode, update && isdir);
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int set_inode(struct inode *inode, struct dentry *dentry)
++{
++ int err;
++ unsigned int flags;
++ umode_t mode;
++ aufs_bindex_t bindex, bstart, btail;
++ unsigned char isdir;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++ struct au_iinfo *iinfo;
++
++ IiMustWriteLock(inode);
++
++ err = 0;
++ isdir = 0;
++ bstart = au_dbstart(dentry);
++ h_inode = au_h_dptr(dentry, bstart)->d_inode;
++ mode = h_inode->i_mode;
++ switch (mode & S_IFMT) {
++ case S_IFREG:
++ btail = au_dbtail(dentry);
++ inode->i_op = &aufs_iop;
++ inode->i_fop = &aufs_file_fop;
++ err = au_dy_iaop(inode, bstart, h_inode);
++ if (unlikely(err))
++ goto out;
++ break;
++ case S_IFDIR:
++ isdir = 1;
++ btail = au_dbtaildir(dentry);
++ inode->i_op = &aufs_dir_iop;
++ inode->i_fop = &aufs_dir_fop;
++ break;
++ case S_IFLNK:
++ btail = au_dbtail(dentry);
++ inode->i_op = &aufs_symlink_iop;
++ break;
++ case S_IFBLK:
++ case S_IFCHR:
++ case S_IFIFO:
++ case S_IFSOCK:
++ btail = au_dbtail(dentry);
++ inode->i_op = &aufs_iop;
++ au_init_special_fop(inode, mode, h_inode->i_rdev);
++ break;
++ default:
++ AuIOErr("Unknown file type 0%o\n", mode);
++ err = -EIO;
++ goto out;
++ }
++
++ /* do not set hnotify for whiteouted dirs (SHWH mode) */
++ flags = au_hi_flags(inode, isdir);
++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)
++ && au_ftest_hi(flags, HNOTIFY)
++ && dentry->d_name.len > AUFS_WH_PFX_LEN
++ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))
++ au_fclr_hi(flags, HNOTIFY);
++ iinfo = au_ii(inode);
++ iinfo->ii_bstart = bstart;
++ iinfo->ii_bend = btail;
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry)
++ au_set_h_iptr(inode, bindex,
++ au_igrab(h_dentry->d_inode), flags);
++ }
++ au_cpup_attr_all(inode, /*force*/1);
++
++out:
++ return err;
++}
++
++/*
++ * successful returns with iinfo write_locked
++ * minus: errno
++ * zero: success, matched
++ * plus: no error, but unmatched
++ */
++static int reval_inode(struct inode *inode, struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct inode *h_inode, *h_dinode;
++
++ /*
++ * before this function, if aufs got any iinfo lock, it must be only
++ * one, the parent dir.
++ * it can happen by UDBA and the obsoleted inode number.
++ */
++ err = -EIO;
++ if (unlikely(inode->i_ino == parent_ino(dentry)))
++ goto out;
++
++ err = 1;
++ ii_write_lock_new_child(inode);
++ h_dinode = au_h_dptr(dentry, au_dbstart(dentry))->d_inode;
++ bend = au_ibend(inode);
++ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
++ h_inode = au_h_iptr(inode, bindex);
++ if (h_inode && h_inode == h_dinode) {
++ err = 0;
++ if (au_iigen_test(inode, au_digen(dentry)))
++ err = au_refresh_hinode(inode, dentry);
++ break;
++ }
++ }
++
++ if (unlikely(err))
++ ii_write_unlock(inode);
++out:
++ return err;
++}
++
++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ unsigned int d_type, ino_t *ino)
++{
++ int err;
++ struct mutex *mtx;
++
++ /* prevent hardlinked inode number from race condition */
++ mtx = NULL;
++ if (d_type != DT_DIR) {
++ mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx;
++ mutex_lock(mtx);
++ }
++ err = au_xino_read(sb, bindex, h_ino, ino);
++ if (unlikely(err))
++ goto out;
++
++ if (!*ino) {
++ err = -EIO;
++ *ino = au_xino_new_ino(sb);
++ if (unlikely(!*ino))
++ goto out;
++ err = au_xino_write(sb, bindex, h_ino, *ino);
++ if (unlikely(err))
++ goto out;
++ }
++
++out:
++ if (mtx)
++ mutex_unlock(mtx);
++ return err;
++}
++
++/* successful returns with iinfo write_locked */
++/* todo: return with unlocked? */
++struct inode *au_new_inode(struct dentry *dentry, int must_new)
++{
++ struct inode *inode, *h_inode;
++ struct dentry *h_dentry;
++ struct super_block *sb;
++ struct mutex *mtx;
++ ino_t h_ino, ino;
++ int err;
++ aufs_bindex_t bstart;
++
++ sb = dentry->d_sb;
++ bstart = au_dbstart(dentry);
++ h_dentry = au_h_dptr(dentry, bstart);
++ h_inode = h_dentry->d_inode;
++ h_ino = h_inode->i_ino;
++
++ /*
++ * stop 'race'-ing between hardlinks under different
++ * parents.
++ */
++ mtx = NULL;
++ if (!S_ISDIR(h_inode->i_mode))
++ mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx;
++
++new_ino:
++ if (mtx)
++ mutex_lock(mtx);
++ err = au_xino_read(sb, bstart, h_ino, &ino);
++ inode = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ if (!ino) {
++ ino = au_xino_new_ino(sb);
++ if (unlikely(!ino)) {
++ inode = ERR_PTR(-EIO);
++ goto out;
++ }
++ }
++
++ AuDbg("i%lu\n", (unsigned long)ino);
++ inode = au_iget_locked(sb, ino);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out;
++
++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW));
++ if (inode->i_state & I_NEW) {
++ ii_write_lock_new_child(inode);
++ err = set_inode(inode, dentry);
++ if (!err) {
++ unlock_new_inode(inode);
++ goto out; /* success */
++ }
++
++ /*
++ * iget_failed() calls iput(), but we need to call
++ * ii_write_unlock() after iget_failed(). so dirty hack for
++ * i_count.
++ */
++ atomic_inc(&inode->i_count);
++ iget_failed(inode);
++ ii_write_unlock(inode);
++ au_xino_write(sb, bstart, h_ino, /*ino*/0);
++ /* ignore this error */
++ goto out_iput;
++ } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) {
++ /*
++ * horrible race condition between lookup, readdir and copyup
++ * (or something).
++ */
++ if (mtx)
++ mutex_unlock(mtx);
++ err = reval_inode(inode, dentry);
++ if (unlikely(err < 0)) {
++ mtx = NULL;
++ goto out_iput;
++ }
++
++ if (!err) {
++ mtx = NULL;
++ goto out; /* success */
++ } else if (mtx)
++ mutex_lock(mtx);
++ }
++
++ if (unlikely(au_test_fs_unique_ino(h_dentry->d_inode)))
++ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir,"
++ " b%d, %s, %.*s, hi%lu, i%lu.\n",
++ bstart, au_sbtype(h_dentry->d_sb), AuDLNPair(dentry),
++ (unsigned long)h_ino, (unsigned long)ino);
++ ino = 0;
++ err = au_xino_write(sb, bstart, h_ino, /*ino*/0);
++ if (!err) {
++ iput(inode);
++ if (mtx)
++ mutex_unlock(mtx);
++ goto new_ino;
++ }
++
++out_iput:
++ iput(inode);
++ inode = ERR_PTR(err);
++out:
++ if (mtx)
++ mutex_unlock(mtx);
++ return inode;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
++ struct inode *inode)
++{
++ int err;
++
++ err = au_br_rdonly(au_sbr(sb, bindex));
++
++ /* pseudo-link after flushed may happen out of bounds */
++ if (!err
++ && inode
++ && au_ibstart(inode) <= bindex
++ && bindex <= au_ibend(inode)) {
++ /*
++ * permission check is unnecessary since vfsub routine
++ * will be called later
++ */
++ struct inode *hi = au_h_iptr(inode, bindex);
++ if (hi)
++ err = IS_IMMUTABLE(hi) ? -EROFS : 0;
++ }
++
++ return err;
++}
++
++int au_test_h_perm(struct inode *h_inode, int mask)
++{
++ if (!current_fsuid())
++ return 0;
++ return inode_permission(h_inode, mask);
++}
++
++int au_test_h_perm_sio(struct inode *h_inode, int mask)
++{
++ if (au_test_nfs(h_inode->i_sb)
++ && (mask & MAY_WRITE)
++ && S_ISDIR(h_inode->i_mode))
++ mask |= MAY_READ; /* force permission check */
++ return au_test_h_perm(h_inode, mask);
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/inode.h linux-2.6.37/fs/aufs/inode.h
+--- linux-2.6.37.orig/fs/aufs/inode.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/inode.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,546 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * inode operations
++ */
++
++#ifndef __AUFS_INODE_H__
++#define __AUFS_INODE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/fsnotify.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++
++struct vfsmount;
++
++struct au_hnotify {
++#ifdef CONFIG_AUFS_HNOTIFY
++#ifdef CONFIG_AUFS_HFSNOTIFY
++ /* never use fsnotify_add_vfsmount_mark() */
++ struct fsnotify_mark hn_mark;
++ int hn_mark_dead;
++#endif
++ struct inode *hn_aufs_inode; /* no get/put */
++#endif
++} ____cacheline_aligned_in_smp;
++
++struct au_hinode {
++ struct inode *hi_inode;
++ aufs_bindex_t hi_id;
++#ifdef CONFIG_AUFS_HNOTIFY
++ struct au_hnotify *hi_notify;
++#endif
++
++ /* reference to the copied-up whiteout with get/put */
++ struct dentry *hi_whdentry;
++};
++
++struct au_vdir;
++struct au_iinfo {
++ atomic_t ii_generation;
++ struct super_block *ii_hsb1; /* no get/put */
++
++ struct au_rwsem ii_rwsem;
++ aufs_bindex_t ii_bstart, ii_bend;
++ __u32 ii_higen;
++ struct au_hinode *ii_hinode;
++ struct au_vdir *ii_vdir;
++};
++
++struct au_icntnr {
++ struct au_iinfo iinfo;
++ struct inode vfs_inode;
++} ____cacheline_aligned_in_smp;
++
++/* au_pin flags */
++#define AuPin_DI_LOCKED 1
++#define AuPin_MNT_WRITE (1 << 1)
++#define au_ftest_pin(flags, name) ((flags) & AuPin_##name)
++#define au_fset_pin(flags, name) \
++ do { (flags) |= AuPin_##name; } while (0)
++#define au_fclr_pin(flags, name) \
++ do { (flags) &= ~AuPin_##name; } while (0)
++
++struct au_pin {
++ /* input */
++ struct dentry *dentry;
++ unsigned int udba;
++ unsigned char lsc_di, lsc_hi, flags;
++ aufs_bindex_t bindex;
++
++ /* output */
++ struct dentry *parent;
++ struct au_hinode *hdir;
++ struct vfsmount *h_mnt;
++};
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_iinfo *au_ii(struct inode *inode)
++{
++ struct au_iinfo *iinfo;
++
++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo);
++ if (iinfo->ii_hinode)
++ return iinfo;
++ return NULL; /* debugging bad_inode case */
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* inode.c */
++struct inode *au_igrab(struct inode *inode);
++int au_refresh_hinode_self(struct inode *inode);
++int au_refresh_hinode(struct inode *inode, struct dentry *dentry);
++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ unsigned int d_type, ino_t *ino);
++struct inode *au_new_inode(struct dentry *dentry, int must_new);
++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
++ struct inode *inode);
++int au_test_h_perm(struct inode *h_inode, int mask);
++int au_test_h_perm_sio(struct inode *h_inode, int mask);
++
++static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex,
++ ino_t h_ino, unsigned int d_type, ino_t *ino)
++{
++#ifdef CONFIG_AUFS_SHWH
++ return au_ino(sb, bindex, h_ino, d_type, ino);
++#else
++ return 0;
++#endif
++}
++
++/* i_op.c */
++extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop;
++
++/* au_wr_dir flags */
++#define AuWrDir_ADD_ENTRY 1
++#define AuWrDir_ISDIR (1 << 1)
++#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name)
++#define au_fset_wrdir(flags, name) \
++ do { (flags) |= AuWrDir_##name; } while (0)
++#define au_fclr_wrdir(flags, name) \
++ do { (flags) &= ~AuWrDir_##name; } while (0)
++
++struct au_wr_dir_args {
++ aufs_bindex_t force_btgt;
++ unsigned char flags;
++};
++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry,
++ struct au_wr_dir_args *args);
++
++struct dentry *au_pinned_h_parent(struct au_pin *pin);
++void au_pin_init(struct au_pin *pin, struct dentry *dentry,
++ aufs_bindex_t bindex, int lsc_di, int lsc_hi,
++ unsigned int udba, unsigned char flags);
++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int udba, unsigned char flags) __must_check;
++int au_do_pin(struct au_pin *pin) __must_check;
++void au_unpin(struct au_pin *pin);
++
++/* i_op_add.c */
++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir);
++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev);
++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
++int aufs_create(struct inode *dir, struct dentry *dentry, int mode,
++ struct nameidata *nd);
++int aufs_link(struct dentry *src_dentry, struct inode *dir,
++ struct dentry *dentry);
++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
++
++/* i_op_del.c */
++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup);
++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir);
++int aufs_unlink(struct inode *dir, struct dentry *dentry);
++int aufs_rmdir(struct inode *dir, struct dentry *dentry);
++
++/* i_op_ren.c */
++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt);
++int aufs_rename(struct inode *src_dir, struct dentry *src_dentry,
++ struct inode *dir, struct dentry *dentry);
++
++/* iinfo.c */
++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex);
++void au_hiput(struct au_hinode *hinode);
++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_wh);
++unsigned int au_hi_flags(struct inode *inode, int isdir);
++
++/* hinode flags */
++#define AuHi_XINO 1
++#define AuHi_HNOTIFY (1 << 1)
++#define au_ftest_hi(flags, name) ((flags) & AuHi_##name)
++#define au_fset_hi(flags, name) \
++ do { (flags) |= AuHi_##name; } while (0)
++#define au_fclr_hi(flags, name) \
++ do { (flags) &= ~AuHi_##name; } while (0)
++
++#ifndef CONFIG_AUFS_HNOTIFY
++#undef AuHi_HNOTIFY
++#define AuHi_HNOTIFY 0
++#endif
++
++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
++ struct inode *h_inode, unsigned int flags);
++
++void au_update_iigen(struct inode *inode);
++void au_update_ibrange(struct inode *inode, int do_put_zero);
++
++void au_icntnr_init_once(void *_c);
++int au_iinfo_init(struct inode *inode);
++void au_iinfo_fin(struct inode *inode);
++int au_ii_realloc(struct au_iinfo *iinfo, int nbr);
++
++#ifdef CONFIG_PROC_FS
++/* plink.c */
++int au_plink_maint(struct super_block *sb, int flags);
++void au_plink_maint_leave(struct au_sbinfo *sbinfo);
++int au_plink_maint_enter(struct super_block *sb);
++#ifdef CONFIG_AUFS_DEBUG
++void au_plink_list(struct super_block *sb);
++#else
++AuStubVoid(au_plink_list, struct super_block *sb)
++#endif
++int au_plink_test(struct inode *inode);
++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex);
++void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_dentry);
++void au_plink_put(struct super_block *sb, int verbose);
++void au_plink_clean(struct super_block *sb, int verbose);
++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id);
++#else
++AuStubInt0(au_plink_maint, struct super_block *sb, int flags);
++AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo);
++AuStubInt0(au_plink_maint_enter, struct super_block *sb);
++AuStubVoid(au_plink_list, struct super_block *sb);
++AuStubInt0(au_plink_test, struct inode *inode);
++AuStub(struct dentry *, au_plink_lkup, return NULL,
++ struct inode *inode, aufs_bindex_t bindex);
++AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_dentry);
++AuStubVoid(au_plink_put, struct super_block *sb, int verbose);
++AuStubVoid(au_plink_clean, struct super_block *sb, int verbose);
++AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id);
++#endif /* CONFIG_PROC_FS */
++
++/* ---------------------------------------------------------------------- */
++
++/* lock subclass for iinfo */
++enum {
++ AuLsc_II_CHILD, /* child first */
++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */
++ AuLsc_II_CHILD3, /* copyup dirs */
++ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */
++ AuLsc_II_PARENT2,
++ AuLsc_II_PARENT3, /* copyup dirs */
++ AuLsc_II_NEW_CHILD
++};
++
++/*
++ * ii_read_lock_child, ii_write_lock_child,
++ * ii_read_lock_child2, ii_write_lock_child2,
++ * ii_read_lock_child3, ii_write_lock_child3,
++ * ii_read_lock_parent, ii_write_lock_parent,
++ * ii_read_lock_parent2, ii_write_lock_parent2,
++ * ii_read_lock_parent3, ii_write_lock_parent3,
++ * ii_read_lock_new_child, ii_write_lock_new_child,
++ */
++#define AuReadLockFunc(name, lsc) \
++static inline void ii_read_lock_##name(struct inode *i) \
++{ \
++ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \
++}
++
++#define AuWriteLockFunc(name, lsc) \
++static inline void ii_write_lock_##name(struct inode *i) \
++{ \
++ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \
++}
++
++#define AuRWLockFuncs(name, lsc) \
++ AuReadLockFunc(name, lsc) \
++ AuWriteLockFunc(name, lsc)
++
++AuRWLockFuncs(child, CHILD);
++AuRWLockFuncs(child2, CHILD2);
++AuRWLockFuncs(child3, CHILD3);
++AuRWLockFuncs(parent, PARENT);
++AuRWLockFuncs(parent2, PARENT2);
++AuRWLockFuncs(parent3, PARENT3);
++AuRWLockFuncs(new_child, NEW_CHILD);
++
++#undef AuReadLockFunc
++#undef AuWriteLockFunc
++#undef AuRWLockFuncs
++
++/*
++ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock
++ */
++AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem);
++
++#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem)
++#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem)
++#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem)
++
++/* ---------------------------------------------------------------------- */
++
++static inline void au_icntnr_init(struct au_icntnr *c)
++{
++#ifdef CONFIG_AUFS_DEBUG
++ c->vfs_inode.i_mode = 0;
++#endif
++}
++
++static inline unsigned int au_iigen(struct inode *inode)
++{
++ return atomic_read(&au_ii(inode)->ii_generation);
++}
++
++/* tiny test for inode number */
++/* tmpfs generation is too rough */
++static inline int au_test_higen(struct inode *inode, struct inode *h_inode)
++{
++ struct au_iinfo *iinfo;
++
++ iinfo = au_ii(inode);
++ AuRwMustAnyLock(&iinfo->ii_rwsem);
++ return !(iinfo->ii_hsb1 == h_inode->i_sb
++ && iinfo->ii_higen == h_inode->i_generation);
++}
++
++static inline void au_iigen_dec(struct inode *inode)
++{
++ atomic_dec(&au_ii(inode)->ii_generation);
++}
++
++static inline int au_iigen_test(struct inode *inode, unsigned int sigen)
++{
++ int err;
++
++ err = 0;
++ if (unlikely(inode && au_iigen(inode) != sigen))
++ err = -EIO;
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static inline aufs_bindex_t au_ii_br_id(struct inode *inode,
++ aufs_bindex_t bindex)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_hinode[0 + bindex].hi_id;
++}
++
++static inline aufs_bindex_t au_ibstart(struct inode *inode)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_bstart;
++}
++
++static inline aufs_bindex_t au_ibend(struct inode *inode)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_bend;
++}
++
++static inline struct au_vdir *au_ivdir(struct inode *inode)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_vdir;
++}
++
++static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_hinode[0 + bindex].hi_whdentry;
++}
++
++static inline void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex)
++{
++ IiMustWriteLock(inode);
++ au_ii(inode)->ii_bstart = bindex;
++}
++
++static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex)
++{
++ IiMustWriteLock(inode);
++ au_ii(inode)->ii_bend = bindex;
++}
++
++static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir)
++{
++ IiMustWriteLock(inode);
++ au_ii(inode)->ii_vdir = vdir;
++}
++
++static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_hinode + bindex;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct dentry *au_pinned_parent(struct au_pin *pin)
++{
++ if (pin)
++ return pin->parent;
++ return NULL;
++}
++
++static inline struct inode *au_pinned_h_dir(struct au_pin *pin)
++{
++ if (pin && pin->hdir)
++ return pin->hdir->hi_inode;
++ return NULL;
++}
++
++static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin)
++{
++ if (pin)
++ return pin->hdir;
++ return NULL;
++}
++
++static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry)
++{
++ if (pin)
++ pin->dentry = dentry;
++}
++
++static inline void au_pin_set_parent_lflag(struct au_pin *pin,
++ unsigned char lflag)
++{
++ if (pin) {
++ if (lflag)
++ au_fset_pin(pin->flags, DI_LOCKED);
++ else
++ au_fclr_pin(pin->flags, DI_LOCKED);
++ }
++}
++
++static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent)
++{
++ if (pin) {
++ dput(pin->parent);
++ pin->parent = dget(parent);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_branch;
++#ifdef CONFIG_AUFS_HNOTIFY
++struct au_hnotify_op {
++ void (*ctl)(struct au_hinode *hinode, int do_set);
++ int (*alloc)(struct au_hinode *hinode);
++ void (*free)(struct au_hinode *hinode);
++
++ void (*fin)(void);
++ int (*init)(void);
++
++ int (*reset_br)(unsigned int udba, struct au_branch *br, int perm);
++ void (*fin_br)(struct au_branch *br);
++ int (*init_br)(struct au_branch *br, int perm);
++};
++
++/* hnotify.c */
++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode);
++void au_hn_free(struct au_hinode *hinode);
++void au_hn_ctl(struct au_hinode *hinode, int do_set);
++void au_hn_reset(struct inode *inode, unsigned int flags);
++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask,
++ struct qstr *h_child_qstr, struct inode *h_child_inode);
++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm);
++int au_hnotify_init_br(struct au_branch *br, int perm);
++void au_hnotify_fin_br(struct au_branch *br);
++int __init au_hnotify_init(void);
++void au_hnotify_fin(void);
++
++/* hfsnotify.c */
++extern const struct au_hnotify_op au_hnotify_op;
++
++static inline
++void au_hn_init(struct au_hinode *hinode)
++{
++ hinode->hi_notify = NULL;
++}
++
++#else
++static inline
++int au_hn_alloc(struct au_hinode *hinode __maybe_unused,
++ struct inode *inode __maybe_unused)
++{
++ return -EOPNOTSUPP;
++}
++
++AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused)
++AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused,
++ int do_set __maybe_unused)
++AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused,
++ unsigned int flags __maybe_unused)
++AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused,
++ struct au_branch *br __maybe_unused,
++ int perm __maybe_unused)
++AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused,
++ int perm __maybe_unused)
++AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused)
++AuStubInt0(__init au_hnotify_init, void)
++AuStubVoid(au_hnotify_fin, void)
++AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused)
++#endif /* CONFIG_AUFS_HNOTIFY */
++
++static inline void au_hn_suspend(struct au_hinode *hdir)
++{
++ au_hn_ctl(hdir, /*do_set*/0);
++}
++
++static inline void au_hn_resume(struct au_hinode *hdir)
++{
++ au_hn_ctl(hdir, /*do_set*/1);
++}
++
++static inline void au_hn_imtx_lock(struct au_hinode *hdir)
++{
++ mutex_lock(&hdir->hi_inode->i_mutex);
++ au_hn_suspend(hdir);
++}
++
++static inline void au_hn_imtx_lock_nested(struct au_hinode *hdir,
++ unsigned int sc __maybe_unused)
++{
++ mutex_lock_nested(&hdir->hi_inode->i_mutex, sc);
++ au_hn_suspend(hdir);
++}
++
++static inline void au_hn_imtx_unlock(struct au_hinode *hdir)
++{
++ au_hn_resume(hdir);
++ mutex_unlock(&hdir->hi_inode->i_mutex);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_INODE_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/ioctl.c linux-2.6.37/fs/aufs/ioctl.c
+--- linux-2.6.37.orig/fs/aufs/ioctl.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/ioctl.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,150 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * ioctl
++ * plink-management and readdir in userspace.
++ * assist the pathconf(3) wrapper library.
++ */
++
++#include <linux/file.h>
++#include "aufs.h"
++
++static int au_wbr_fd(struct path *path)
++{
++ int err, fd;
++ aufs_bindex_t wbi, bindex, bend;
++ struct file *h_file;
++ struct super_block *sb;
++ struct dentry *root;
++ struct au_branch *wbr;
++
++ err = get_unused_fd();
++ if (unlikely(err < 0))
++ goto out;
++ fd = err;
++
++ wbi = 0;
++ sb = path->dentry->d_sb;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_IR);
++ wbr = au_sbr(sb, wbi);
++ if (!(path->mnt->mnt_flags & MNT_READONLY)
++ && !au_br_writable(wbr->br_perm)) {
++ bend = au_sbend(sb);
++ for (bindex = 1; bindex <= bend; bindex++) {
++ wbr = au_sbr(sb, bindex);
++ if (au_br_writable(wbr->br_perm)) {
++ wbi = bindex;
++ break;
++ }
++ }
++ wbr = au_sbr(sb, wbi);
++ }
++ AuDbg("wbi %d\n", wbi);
++ h_file = au_h_open(root, wbi, O_RDONLY | O_DIRECTORY | O_LARGEFILE,
++ NULL);
++ aufs_read_unlock(root, AuLock_IR);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out_fd;
++
++ atomic_dec(&wbr->br_count); /* cf. au_h_open() */
++ fd_install(fd, h_file);
++ err = fd;
++ goto out; /* success */
++
++out_fd:
++ put_unused_fd(fd);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err;
++
++ switch (cmd) {
++ case AUFS_CTL_RDU:
++ case AUFS_CTL_RDU_INO:
++ err = au_rdu_ioctl(file, cmd, arg);
++ break;
++
++ case AUFS_CTL_WBR_FD:
++ err = au_wbr_fd(&file->f_path);
++ break;
++
++ default:
++ /* do not call the lower */
++ AuDbg("0x%x\n", cmd);
++ err = -ENOTTY;
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err;
++
++ switch (cmd) {
++ case AUFS_CTL_WBR_FD:
++ err = au_wbr_fd(&file->f_path);
++ break;
++
++ default:
++ /* do not call the lower */
++ AuDbg("0x%x\n", cmd);
++ err = -ENOTTY;
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++#ifdef CONFIG_COMPAT
++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ long err;
++
++ switch (cmd) {
++ case AUFS_CTL_RDU:
++ case AUFS_CTL_RDU_INO:
++ err = au_rdu_compat_ioctl(file, cmd, arg);
++ break;
++
++ default:
++ err = aufs_ioctl_dir(file, cmd, arg);
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++#if 0 /* unused yet */
++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg));
++}
++#endif
++#endif
+diff -Nur linux-2.6.37.orig/fs/aufs/loop.c linux-2.6.37/fs/aufs/loop.c
+--- linux-2.6.37.orig/fs/aufs/loop.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/loop.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,63 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * support for loopback block device as a branch
++ */
++
++#include <linux/loop.h>
++#include "aufs.h"
++
++/*
++ * test if two lower dentries have overlapping branches.
++ */
++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding)
++{
++ struct super_block *h_sb;
++ struct loop_device *l;
++
++ h_sb = h_adding->d_sb;
++ if (MAJOR(h_sb->s_dev) != LOOP_MAJOR)
++ return 0;
++
++ l = h_sb->s_bdev->bd_disk->private_data;
++ h_adding = l->lo_backing_file->f_dentry;
++ /*
++ * h_adding can be local NFS.
++ * in this case aufs cannot detect the loop.
++ */
++ if (unlikely(h_adding->d_sb == sb))
++ return 1;
++ return !!au_test_subdir(h_adding, sb->s_root);
++}
++
++/* true if a kernel thread named 'loop[0-9].*' accesses a file */
++int au_test_loopback_kthread(void)
++{
++ int ret;
++ struct task_struct *tsk = current;
++
++ ret = 0;
++ if (tsk->flags & PF_KTHREAD) {
++ const char c = tsk->comm[4];
++ ret = ('0' <= c && c <= '9'
++ && !strncmp(tsk->comm, "loop", 4));
++ }
++
++ return ret;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/loop.h linux-2.6.37/fs/aufs/loop.h
+--- linux-2.6.37.orig/fs/aufs/loop.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/loop.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,42 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * support for loopback mount as a branch
++ */
++
++#ifndef __AUFS_LOOP_H__
++#define __AUFS_LOOP_H__
++
++#ifdef __KERNEL__
++
++struct dentry;
++struct super_block;
++
++#ifdef CONFIG_AUFS_BDEV_LOOP
++/* loop.c */
++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding);
++int au_test_loopback_kthread(void);
++#else
++AuStubInt0(au_test_loopback_overlap, struct super_block *sb,
++ struct dentry *h_adding)
++AuStubInt0(au_test_loopback_kthread, void)
++#endif /* BLK_DEV_LOOP */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_LOOP_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/magic.mk linux-2.6.37/fs/aufs/magic.mk
+--- linux-2.6.37.orig/fs/aufs/magic.mk 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/magic.mk 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,54 @@
++
++# defined in ${srctree}/fs/fuse/inode.c
++# tristate
++ifdef CONFIG_FUSE_FS
++ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546
++endif
++
++# defined in ${srctree}/fs/ocfs2/ocfs2_fs.h
++# tristate
++ifdef CONFIG_OCFS2_FS
++ccflags-y += -DOCFS2_SUPER_MAGIC=0x7461636f
++endif
++
++# defined in ${srctree}/fs/ocfs2/dlm/userdlm.h
++# tristate
++ifdef CONFIG_OCFS2_FS_O2CB
++ccflags-y += -DDLMFS_MAGIC=0x76a9f425
++endif
++
++# defined in ${srctree}/fs/cifs/cifsfs.c
++# tristate
++ifdef CONFIG_CIFS_FS
++ccflags-y += -DCIFS_MAGIC_NUMBER=0xFF534D42
++endif
++
++# defined in ${srctree}/fs/xfs/xfs_sb.h
++# tristate
++ifdef CONFIG_XFS_FS
++ccflags-y += -DXFS_SB_MAGIC=0x58465342
++endif
++
++# defined in ${srctree}/fs/configfs/mount.c
++# tristate
++ifdef CONFIG_CONFIGFS_FS
++ccflags-y += -DCONFIGFS_MAGIC=0x62656570
++endif
++
++# defined in ${srctree}/fs/9p/v9fs.h
++# tristate
++ifdef CONFIG_9P_FS
++ccflags-y += -DV9FS_MAGIC=0x01021997
++endif
++
++# defined in ${srctree}/fs/ubifs/ubifs.h
++# tristate
++ifdef CONFIG_UBIFS_FS
++ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905
++endif
++
++# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h
++# tristate
++ifdef CONFIG_HFSPLUS_FS
++ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b
++endif
+diff -Nur linux-2.6.37.orig/fs/aufs/module.c linux-2.6.37/fs/aufs/module.c
+--- linux-2.6.37.orig/fs/aufs/module.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/module.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,182 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * module global variables and operations
++ */
++
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include "aufs.h"
++
++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp)
++{
++ if (new_sz <= nused)
++ return p;
++
++ p = krealloc(p, new_sz, gfp);
++ if (p)
++ memset(p + nused, 0, new_sz - nused);
++ return p;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * aufs caches
++ */
++struct kmem_cache *au_cachep[AuCache_Last];
++static int __init au_cache_init(void)
++{
++ au_cachep[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once);
++ if (au_cachep[AuCache_DINFO])
++ au_cachep[AuCache_ICNTNR] = AuCacheCtor(au_icntnr,
++ au_icntnr_init_once);
++ if (au_cachep[AuCache_ICNTNR])
++ au_cachep[AuCache_FINFO] = AuCacheCtor(au_finfo,
++ au_fi_init_once);
++ if (au_cachep[AuCache_FINFO])
++ au_cachep[AuCache_VDIR] = AuCache(au_vdir);
++ if (au_cachep[AuCache_VDIR])
++ au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr);
++ if (au_cachep[AuCache_DEHSTR])
++ return 0;
++
++ return -ENOMEM;
++}
++
++static void au_cache_fin(void)
++{
++ int i;
++
++ /* including AuCache_HNOTIFY */
++ for (i = 0; i < AuCache_Last; i++)
++ if (au_cachep[i]) {
++ kmem_cache_destroy(au_cachep[i]);
++ au_cachep[i] = NULL;
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_dir_roflags;
++
++#ifdef CONFIG_AUFS_SBILIST
++struct au_splhead au_sbilist;
++#endif
++
++/*
++ * functions for module interface.
++ */
++MODULE_LICENSE("GPL");
++/* MODULE_LICENSE("GPL v2"); */
++MODULE_AUTHOR("Junjiro R. Okajima <aufs-users@lists.sourceforge.net>");
++MODULE_DESCRIPTION(AUFS_NAME
++ " -- Advanced multi layered unification filesystem");
++MODULE_VERSION(AUFS_VERSION);
++
++/* this module parameter has no meaning when SYSFS is disabled */
++int sysaufs_brs = 1;
++MODULE_PARM_DESC(brs, "use <sysfs>/fs/aufs/si_*/brN");
++module_param_named(brs, sysaufs_brs, int, S_IRUGO);
++
++/* ---------------------------------------------------------------------- */
++
++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */
++
++int au_seq_path(struct seq_file *seq, struct path *path)
++{
++ return seq_path(seq, path, au_esc_chars);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int __init aufs_init(void)
++{
++ int err, i;
++ char *p;
++
++ p = au_esc_chars;
++ for (i = 1; i <= ' '; i++)
++ *p++ = i;
++ *p++ = '\\';
++ *p++ = '\x7f';
++ *p = 0;
++
++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE);
++
++ au_sbilist_init();
++ sysaufs_brs_init();
++ au_debug_init();
++ au_dy_init();
++ err = sysaufs_init();
++ if (unlikely(err))
++ goto out;
++ err = au_procfs_init();
++ if (unlikely(err))
++ goto out_sysaufs;
++ err = au_wkq_init();
++ if (unlikely(err))
++ goto out_procfs;
++ err = au_hnotify_init();
++ if (unlikely(err))
++ goto out_wkq;
++ err = au_sysrq_init();
++ if (unlikely(err))
++ goto out_hin;
++ err = au_cache_init();
++ if (unlikely(err))
++ goto out_sysrq;
++ err = register_filesystem(&aufs_fs_type);
++ if (unlikely(err))
++ goto out_cache;
++ /* since we define pr_fmt, call printk directly */
++ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n");
++ goto out; /* success */
++
++out_cache:
++ au_cache_fin();
++out_sysrq:
++ au_sysrq_fin();
++out_hin:
++ au_hnotify_fin();
++out_wkq:
++ au_wkq_fin();
++out_procfs:
++ au_procfs_fin();
++out_sysaufs:
++ sysaufs_fin();
++ au_dy_fin();
++out:
++ return err;
++}
++
++static void __exit aufs_exit(void)
++{
++ unregister_filesystem(&aufs_fs_type);
++ au_cache_fin();
++ au_sysrq_fin();
++ au_hnotify_fin();
++ au_wkq_fin();
++ au_procfs_fin();
++ sysaufs_fin();
++ au_dy_fin();
++}
++
++module_init(aufs_init);
++module_exit(aufs_exit);
+diff -Nur linux-2.6.37.orig/fs/aufs/module.h linux-2.6.37/fs/aufs/module.h
+--- linux-2.6.37.orig/fs/aufs/module.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/module.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,91 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * module initialization and module-global
++ */
++
++#ifndef __AUFS_MODULE_H__
++#define __AUFS_MODULE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/slab.h>
++
++struct path;
++struct seq_file;
++
++/* module parameters */
++extern int sysaufs_brs;
++
++/* ---------------------------------------------------------------------- */
++
++extern int au_dir_roflags;
++
++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp);
++int au_seq_path(struct seq_file *seq, struct path *path);
++
++#ifdef CONFIG_PROC_FS
++/* procfs.c */
++int __init au_procfs_init(void);
++void au_procfs_fin(void);
++#else
++AuStubInt0(au_procfs_init, void);
++AuStubVoid(au_procfs_fin, void);
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++/* kmem cache */
++enum {
++ AuCache_DINFO,
++ AuCache_ICNTNR,
++ AuCache_FINFO,
++ AuCache_VDIR,
++ AuCache_DEHSTR,
++#ifdef CONFIG_AUFS_HNOTIFY
++ AuCache_HNOTIFY,
++#endif
++ AuCache_Last
++};
++
++#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD)
++#define AuCache(type) KMEM_CACHE(type, AuCacheFlags)
++#define AuCacheCtor(type, ctor) \
++ kmem_cache_create(#type, sizeof(struct type), \
++ __alignof__(struct type), AuCacheFlags, ctor)
++
++extern struct kmem_cache *au_cachep[];
++
++#define AuCacheFuncs(name, index) \
++static inline struct au_##name *au_cache_alloc_##name(void) \
++{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \
++static inline void au_cache_free_##name(struct au_##name *p) \
++{ kmem_cache_free(au_cachep[AuCache_##index], p); }
++
++AuCacheFuncs(dinfo, DINFO);
++AuCacheFuncs(icntnr, ICNTNR);
++AuCacheFuncs(finfo, FINFO);
++AuCacheFuncs(vdir, VDIR);
++AuCacheFuncs(vdir_dehstr, DEHSTR);
++#ifdef CONFIG_AUFS_HNOTIFY
++AuCacheFuncs(hnotify, HNOTIFY);
++#endif
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_MODULE_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/mtx.h linux-2.6.37/fs/aufs/mtx.h
+--- linux-2.6.37.orig/fs/aufs/mtx.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/mtx.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * very ugly approach for aufs_mmap()
++ * never include this file from other than f_op.c.
++ * see f_op.c in detail.
++ */
++
++#ifndef __AUFS_MTX_H__
++#define __AUFS_MTX_H__
++
++#ifdef __KERNEL__
++
++/* copied from ../kernel/mutex{,-debug}.h */
++struct mutex;
++struct thread_info;
++#ifdef CONFIG_DEBUG_MUTEXES
++static inline void mutex_set_owner(struct mutex *lock)
++{
++ lock->owner = current_thread_info();
++}
++#else
++static inline void mutex_set_owner(struct mutex *lock)
++{
++#ifdef CONFIG_SMP
++ lock->owner = current_thread_info();
++#endif
++}
++#endif
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_MTX_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/opts.c linux-2.6.37/fs/aufs/opts.c
+--- linux-2.6.37.orig/fs/aufs/opts.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/opts.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,1595 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * mount options/flags
++ */
++
++#include <linux/file.h>
++#include <linux/jiffies.h>
++#include <linux/namei.h>
++#include <linux/types.h> /* a distribution requires */
++#include <linux/parser.h>
++#include "aufs.h"
++
++/* ---------------------------------------------------------------------- */
++
++enum {
++ Opt_br,
++ Opt_add, Opt_del, Opt_mod, Opt_reorder, Opt_append, Opt_prepend,
++ Opt_idel, Opt_imod, Opt_ireorder,
++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, Opt_rendir,
++ Opt_rdblk_def, Opt_rdhash_def,
++ Opt_xino, Opt_zxino, Opt_noxino,
++ Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino,
++ Opt_trunc_xino_path, Opt_itrunc_xino,
++ Opt_trunc_xib, Opt_notrunc_xib,
++ Opt_shwh, Opt_noshwh,
++ Opt_plink, Opt_noplink, Opt_list_plink,
++ Opt_udba,
++ Opt_dio, Opt_nodio,
++ /* Opt_lock, Opt_unlock, */
++ Opt_cmd, Opt_cmd_args,
++ Opt_diropq_a, Opt_diropq_w,
++ Opt_warn_perm, Opt_nowarn_perm,
++ Opt_wbr_copyup, Opt_wbr_create,
++ Opt_refrof, Opt_norefrof,
++ Opt_verbose, Opt_noverbose,
++ Opt_sum, Opt_nosum, Opt_wsum,
++ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err
++};
++
++static match_table_t options = {
++ {Opt_br, "br=%s"},
++ {Opt_br, "br:%s"},
++
++ {Opt_add, "add=%d:%s"},
++ {Opt_add, "add:%d:%s"},
++ {Opt_add, "ins=%d:%s"},
++ {Opt_add, "ins:%d:%s"},
++ {Opt_append, "append=%s"},
++ {Opt_append, "append:%s"},
++ {Opt_prepend, "prepend=%s"},
++ {Opt_prepend, "prepend:%s"},
++
++ {Opt_del, "del=%s"},
++ {Opt_del, "del:%s"},
++ /* {Opt_idel, "idel:%d"}, */
++ {Opt_mod, "mod=%s"},
++ {Opt_mod, "mod:%s"},
++ /* {Opt_imod, "imod:%d:%s"}, */
++
++ {Opt_dirwh, "dirwh=%d"},
++
++ {Opt_xino, "xino=%s"},
++ {Opt_noxino, "noxino"},
++ {Opt_trunc_xino, "trunc_xino"},
++ {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"},
++ {Opt_notrunc_xino, "notrunc_xino"},
++ {Opt_trunc_xino_path, "trunc_xino=%s"},
++ {Opt_itrunc_xino, "itrunc_xino=%d"},
++ /* {Opt_zxino, "zxino=%s"}, */
++ {Opt_trunc_xib, "trunc_xib"},
++ {Opt_notrunc_xib, "notrunc_xib"},
++
++#ifdef CONFIG_PROC_FS
++ {Opt_plink, "plink"},
++#else
++ {Opt_ignore_silent, "plink"},
++#endif
++
++ {Opt_noplink, "noplink"},
++
++#ifdef CONFIG_AUFS_DEBUG
++ {Opt_list_plink, "list_plink"},
++#endif
++
++ {Opt_udba, "udba=%s"},
++
++ {Opt_dio, "dio"},
++ {Opt_nodio, "nodio"},
++
++ {Opt_diropq_a, "diropq=always"},
++ {Opt_diropq_a, "diropq=a"},
++ {Opt_diropq_w, "diropq=whiteouted"},
++ {Opt_diropq_w, "diropq=w"},
++
++ {Opt_warn_perm, "warn_perm"},
++ {Opt_nowarn_perm, "nowarn_perm"},
++
++ /* keep them temporary */
++ {Opt_ignore_silent, "coo=%s"},
++ {Opt_ignore_silent, "nodlgt"},
++ {Opt_ignore_silent, "nodirperm1"},
++ {Opt_ignore_silent, "clean_plink"},
++
++#ifdef CONFIG_AUFS_SHWH
++ {Opt_shwh, "shwh"},
++#endif
++ {Opt_noshwh, "noshwh"},
++
++ {Opt_rendir, "rendir=%d"},
++
++ {Opt_refrof, "refrof"},
++ {Opt_norefrof, "norefrof"},
++
++ {Opt_verbose, "verbose"},
++ {Opt_verbose, "v"},
++ {Opt_noverbose, "noverbose"},
++ {Opt_noverbose, "quiet"},
++ {Opt_noverbose, "q"},
++ {Opt_noverbose, "silent"},
++
++ {Opt_sum, "sum"},
++ {Opt_nosum, "nosum"},
++ {Opt_wsum, "wsum"},
++
++ {Opt_rdcache, "rdcache=%d"},
++ {Opt_rdblk, "rdblk=%d"},
++ {Opt_rdblk_def, "rdblk=def"},
++ {Opt_rdhash, "rdhash=%d"},
++ {Opt_rdhash_def, "rdhash=def"},
++
++ {Opt_wbr_create, "create=%s"},
++ {Opt_wbr_create, "create_policy=%s"},
++ {Opt_wbr_copyup, "cpup=%s"},
++ {Opt_wbr_copyup, "copyup=%s"},
++ {Opt_wbr_copyup, "copyup_policy=%s"},
++
++ /* internal use for the scripts */
++ {Opt_ignore_silent, "si=%s"},
++
++ {Opt_br, "dirs=%s"},
++ {Opt_ignore, "debug=%d"},
++ {Opt_ignore, "delete=whiteout"},
++ {Opt_ignore, "delete=all"},
++ {Opt_ignore, "imap=%s"},
++
++ /* temporary workaround, due to old mount(8)? */
++ {Opt_ignore_silent, "relatime"},
++
++ {Opt_err, NULL}
++};
++
++/* ---------------------------------------------------------------------- */
++
++static const char *au_parser_pattern(int val, struct match_token *token)
++{
++ while (token->pattern) {
++ if (token->token == val)
++ return token->pattern;
++ token++;
++ }
++ BUG();
++ return "??";
++}
++
++/* ---------------------------------------------------------------------- */
++
++static match_table_t brperms = {
++ {AuBrPerm_RO, AUFS_BRPERM_RO},
++ {AuBrPerm_RR, AUFS_BRPERM_RR},
++ {AuBrPerm_RW, AUFS_BRPERM_RW},
++
++ {AuBrPerm_ROWH, AUFS_BRPERM_ROWH},
++ {AuBrPerm_RRWH, AUFS_BRPERM_RRWH},
++ {AuBrPerm_RWNoLinkWH, AUFS_BRPERM_RWNLWH},
++
++ {AuBrPerm_ROWH, "nfsro"},
++ {AuBrPerm_RO, NULL}
++};
++
++static int noinline_for_stack br_perm_val(char *perm)
++{
++ int val;
++ substring_t args[MAX_OPT_ARGS];
++
++ val = match_token(perm, brperms, args);
++ return val;
++}
++
++const char *au_optstr_br_perm(int brperm)
++{
++ return au_parser_pattern(brperm, (void *)brperms);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static match_table_t udbalevel = {
++ {AuOpt_UDBA_REVAL, "reval"},
++ {AuOpt_UDBA_NONE, "none"},
++#ifdef CONFIG_AUFS_HNOTIFY
++ {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */
++#ifdef CONFIG_AUFS_HFSNOTIFY
++ {AuOpt_UDBA_HNOTIFY, "fsnotify"},
++#endif
++#endif
++ {-1, NULL}
++};
++
++static int noinline_for_stack udba_val(char *str)
++{
++ substring_t args[MAX_OPT_ARGS];
++
++ return match_token(str, udbalevel, args);
++}
++
++const char *au_optstr_udba(int udba)
++{
++ return au_parser_pattern(udba, (void *)udbalevel);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static match_table_t au_wbr_create_policy = {
++ {AuWbrCreate_TDP, "tdp"},
++ {AuWbrCreate_TDP, "top-down-parent"},
++ {AuWbrCreate_RR, "rr"},
++ {AuWbrCreate_RR, "round-robin"},
++ {AuWbrCreate_MFS, "mfs"},
++ {AuWbrCreate_MFS, "most-free-space"},
++ {AuWbrCreate_MFSV, "mfs:%d"},
++ {AuWbrCreate_MFSV, "most-free-space:%d"},
++
++ {AuWbrCreate_MFSRR, "mfsrr:%d"},
++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"},
++ {AuWbrCreate_PMFS, "pmfs"},
++ {AuWbrCreate_PMFSV, "pmfs:%d"},
++
++ {-1, NULL}
++};
++
++/*
++ * cf. linux/lib/parser.c and cmdline.c
++ * gave up calling memparse() since it uses simple_strtoull() instead of
++ * strict_...().
++ */
++static int noinline_for_stack
++au_match_ull(substring_t *s, unsigned long long *result)
++{
++ int err;
++ unsigned int len;
++ char a[32];
++
++ err = -ERANGE;
++ len = s->to - s->from;
++ if (len + 1 <= sizeof(a)) {
++ memcpy(a, s->from, len);
++ a[len] = '\0';
++ err = strict_strtoull(a, 0, result);
++ }
++ return err;
++}
++
++static int au_wbr_mfs_wmark(substring_t *arg, char *str,
++ struct au_opt_wbr_create *create)
++{
++ int err;
++ unsigned long long ull;
++
++ err = 0;
++ if (!au_match_ull(arg, &ull))
++ create->mfsrr_watermark = ull;
++ else {
++ pr_err("bad integer in %s\n", str);
++ err = -EINVAL;
++ }
++
++ return err;
++}
++
++static int au_wbr_mfs_sec(substring_t *arg, char *str,
++ struct au_opt_wbr_create *create)
++{
++ int n, err;
++
++ err = 0;
++ if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC)
++ create->mfs_second = n;
++ else {
++ pr_err("bad integer in %s\n", str);
++ err = -EINVAL;
++ }
++
++ return err;
++}
++
++static int noinline_for_stack
++au_wbr_create_val(char *str, struct au_opt_wbr_create *create)
++{
++ int err, e;
++ substring_t args[MAX_OPT_ARGS];
++
++ err = match_token(str, au_wbr_create_policy, args);
++ create->wbr_create = err;
++ switch (err) {
++ case AuWbrCreate_MFSRRV:
++ e = au_wbr_mfs_wmark(&args[0], str, create);
++ if (!e)
++ e = au_wbr_mfs_sec(&args[1], str, create);
++ if (unlikely(e))
++ err = e;
++ break;
++ case AuWbrCreate_MFSRR:
++ e = au_wbr_mfs_wmark(&args[0], str, create);
++ if (unlikely(e)) {
++ err = e;
++ break;
++ }
++ /*FALLTHROUGH*/
++ case AuWbrCreate_MFS:
++ case AuWbrCreate_PMFS:
++ create->mfs_second = AUFS_MFS_DEF_SEC;
++ break;
++ case AuWbrCreate_MFSV:
++ case AuWbrCreate_PMFSV:
++ e = au_wbr_mfs_sec(&args[0], str, create);
++ if (unlikely(e))
++ err = e;
++ break;
++ }
++
++ return err;
++}
++
++const char *au_optstr_wbr_create(int wbr_create)
++{
++ return au_parser_pattern(wbr_create, (void *)au_wbr_create_policy);
++}
++
++static match_table_t au_wbr_copyup_policy = {
++ {AuWbrCopyup_TDP, "tdp"},
++ {AuWbrCopyup_TDP, "top-down-parent"},
++ {AuWbrCopyup_BUP, "bup"},
++ {AuWbrCopyup_BUP, "bottom-up-parent"},
++ {AuWbrCopyup_BU, "bu"},
++ {AuWbrCopyup_BU, "bottom-up"},
++ {-1, NULL}
++};
++
++static int noinline_for_stack au_wbr_copyup_val(char *str)
++{
++ substring_t args[MAX_OPT_ARGS];
++
++ return match_token(str, au_wbr_copyup_policy, args);
++}
++
++const char *au_optstr_wbr_copyup(int wbr_copyup)
++{
++ return au_parser_pattern(wbr_copyup, (void *)au_wbr_copyup_policy);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
++
++static void dump_opts(struct au_opts *opts)
++{
++#ifdef CONFIG_AUFS_DEBUG
++ /* reduce stack space */
++ union {
++ struct au_opt_add *add;
++ struct au_opt_del *del;
++ struct au_opt_mod *mod;
++ struct au_opt_xino *xino;
++ struct au_opt_xino_itrunc *xino_itrunc;
++ struct au_opt_wbr_create *create;
++ } u;
++ struct au_opt *opt;
++
++ opt = opts->opt;
++ while (opt->type != Opt_tail) {
++ switch (opt->type) {
++ case Opt_add:
++ u.add = &opt->add;
++ AuDbg("add {b%d, %s, 0x%x, %p}\n",
++ u.add->bindex, u.add->pathname, u.add->perm,
++ u.add->path.dentry);
++ break;
++ case Opt_del:
++ case Opt_idel:
++ u.del = &opt->del;
++ AuDbg("del {%s, %p}\n",
++ u.del->pathname, u.del->h_path.dentry);
++ break;
++ case Opt_mod:
++ case Opt_imod:
++ u.mod = &opt->mod;
++ AuDbg("mod {%s, 0x%x, %p}\n",
++ u.mod->path, u.mod->perm, u.mod->h_root);
++ break;
++ case Opt_append:
++ u.add = &opt->add;
++ AuDbg("append {b%d, %s, 0x%x, %p}\n",
++ u.add->bindex, u.add->pathname, u.add->perm,
++ u.add->path.dentry);
++ break;
++ case Opt_prepend:
++ u.add = &opt->add;
++ AuDbg("prepend {b%d, %s, 0x%x, %p}\n",
++ u.add->bindex, u.add->pathname, u.add->perm,
++ u.add->path.dentry);
++ break;
++ case Opt_dirwh:
++ AuDbg("dirwh %d\n", opt->dirwh);
++ break;
++ case Opt_rdcache:
++ AuDbg("rdcache %d\n", opt->rdcache);
++ break;
++ case Opt_rdblk:
++ AuDbg("rdblk %u\n", opt->rdblk);
++ break;
++ case Opt_rdblk_def:
++ AuDbg("rdblk_def\n");
++ break;
++ case Opt_rdhash:
++ AuDbg("rdhash %u\n", opt->rdhash);
++ break;
++ case Opt_rdhash_def:
++ AuDbg("rdhash_def\n");
++ break;
++ case Opt_xino:
++ u.xino = &opt->xino;
++ AuDbg("xino {%s %.*s}\n",
++ u.xino->path,
++ AuDLNPair(u.xino->file->f_dentry));
++ break;
++ case Opt_trunc_xino:
++ AuLabel(trunc_xino);
++ break;
++ case Opt_notrunc_xino:
++ AuLabel(notrunc_xino);
++ break;
++ case Opt_trunc_xino_path:
++ case Opt_itrunc_xino:
++ u.xino_itrunc = &opt->xino_itrunc;
++ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex);
++ break;
++
++ case Opt_noxino:
++ AuLabel(noxino);
++ break;
++ case Opt_trunc_xib:
++ AuLabel(trunc_xib);
++ break;
++ case Opt_notrunc_xib:
++ AuLabel(notrunc_xib);
++ break;
++ case Opt_shwh:
++ AuLabel(shwh);
++ break;
++ case Opt_noshwh:
++ AuLabel(noshwh);
++ break;
++ case Opt_plink:
++ AuLabel(plink);
++ break;
++ case Opt_noplink:
++ AuLabel(noplink);
++ break;
++ case Opt_list_plink:
++ AuLabel(list_plink);
++ break;
++ case Opt_udba:
++ AuDbg("udba %d, %s\n",
++ opt->udba, au_optstr_udba(opt->udba));
++ break;
++ case Opt_dio:
++ AuLabel(dio);
++ break;
++ case Opt_nodio:
++ AuLabel(nodio);
++ break;
++ case Opt_diropq_a:
++ AuLabel(diropq_a);
++ break;
++ case Opt_diropq_w:
++ AuLabel(diropq_w);
++ break;
++ case Opt_warn_perm:
++ AuLabel(warn_perm);
++ break;
++ case Opt_nowarn_perm:
++ AuLabel(nowarn_perm);
++ break;
++ case Opt_refrof:
++ AuLabel(refrof);
++ break;
++ case Opt_norefrof:
++ AuLabel(norefrof);
++ break;
++ case Opt_verbose:
++ AuLabel(verbose);
++ break;
++ case Opt_noverbose:
++ AuLabel(noverbose);
++ break;
++ case Opt_sum:
++ AuLabel(sum);
++ break;
++ case Opt_nosum:
++ AuLabel(nosum);
++ break;
++ case Opt_wsum:
++ AuLabel(wsum);
++ break;
++ case Opt_wbr_create:
++ u.create = &opt->wbr_create;
++ AuDbg("create %d, %s\n", u.create->wbr_create,
++ au_optstr_wbr_create(u.create->wbr_create));
++ switch (u.create->wbr_create) {
++ case AuWbrCreate_MFSV:
++ case AuWbrCreate_PMFSV:
++ AuDbg("%d sec\n", u.create->mfs_second);
++ break;
++ case AuWbrCreate_MFSRR:
++ AuDbg("%llu watermark\n",
++ u.create->mfsrr_watermark);
++ break;
++ case AuWbrCreate_MFSRRV:
++ AuDbg("%llu watermark, %d sec\n",
++ u.create->mfsrr_watermark,
++ u.create->mfs_second);
++ break;
++ }
++ break;
++ case Opt_wbr_copyup:
++ AuDbg("copyup %d, %s\n", opt->wbr_copyup,
++ au_optstr_wbr_copyup(opt->wbr_copyup));
++ break;
++ default:
++ BUG();
++ }
++ opt++;
++ }
++#endif
++}
++
++void au_opts_free(struct au_opts *opts)
++{
++ struct au_opt *opt;
++
++ opt = opts->opt;
++ while (opt->type != Opt_tail) {
++ switch (opt->type) {
++ case Opt_add:
++ case Opt_append:
++ case Opt_prepend:
++ path_put(&opt->add.path);
++ break;
++ case Opt_del:
++ case Opt_idel:
++ path_put(&opt->del.h_path);
++ break;
++ case Opt_mod:
++ case Opt_imod:
++ dput(opt->mod.h_root);
++ break;
++ case Opt_xino:
++ fput(opt->xino.file);
++ break;
++ }
++ opt++;
++ }
++}
++
++static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags,
++ aufs_bindex_t bindex)
++{
++ int err;
++ struct au_opt_add *add = &opt->add;
++ char *p;
++
++ add->bindex = bindex;
++ add->perm = AuBrPerm_Last;
++ add->pathname = opt_str;
++ p = strchr(opt_str, '=');
++ if (p) {
++ *p++ = 0;
++ if (*p)
++ add->perm = br_perm_val(p);
++ }
++
++ err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path);
++ if (!err) {
++ if (!p) {
++ add->perm = AuBrPerm_RO;
++ if (au_test_fs_rr(add->path.dentry->d_sb))
++ add->perm = AuBrPerm_RR;
++ else if (!bindex && !(sb_flags & MS_RDONLY))
++ add->perm = AuBrPerm_RW;
++ }
++ opt->type = Opt_add;
++ goto out;
++ }
++ pr_err("lookup failed %s (%d)\n", add->pathname, err);
++ err = -EINVAL;
++
++out:
++ return err;
++}
++
++static int au_opts_parse_del(struct au_opt_del *del, substring_t args[])
++{
++ int err;
++
++ del->pathname = args[0].from;
++ AuDbg("del path %s\n", del->pathname);
++
++ err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path);
++ if (unlikely(err))
++ pr_err("lookup failed %s (%d)\n", del->pathname, err);
++
++ return err;
++}
++
++#if 0 /* reserved for future use */
++static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex,
++ struct au_opt_del *del, substring_t args[])
++{
++ int err;
++ struct dentry *root;
++
++ err = -EINVAL;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_FLUSH);
++ if (bindex < 0 || au_sbend(sb) < bindex) {
++ pr_err("out of bounds, %d\n", bindex);
++ goto out;
++ }
++
++ err = 0;
++ del->h_path.dentry = dget(au_h_dptr(root, bindex));
++ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex));
++
++out:
++ aufs_read_unlock(root, !AuLock_IR);
++ return err;
++}
++#endif
++
++static int noinline_for_stack
++au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[])
++{
++ int err;
++ struct path path;
++ char *p;
++
++ err = -EINVAL;
++ mod->path = args[0].from;
++ p = strchr(mod->path, '=');
++ if (unlikely(!p)) {
++ pr_err("no permssion %s\n", args[0].from);
++ goto out;
++ }
++
++ *p++ = 0;
++ err = vfsub_kern_path(mod->path, lkup_dirflags, &path);
++ if (unlikely(err)) {
++ pr_err("lookup failed %s (%d)\n", mod->path, err);
++ goto out;
++ }
++
++ mod->perm = br_perm_val(p);
++ AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p);
++ mod->h_root = dget(path.dentry);
++ path_put(&path);
++
++out:
++ return err;
++}
++
++#if 0 /* reserved for future use */
++static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex,
++ struct au_opt_mod *mod, substring_t args[])
++{
++ int err;
++ struct dentry *root;
++
++ err = -EINVAL;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_FLUSH);
++ if (bindex < 0 || au_sbend(sb) < bindex) {
++ pr_err("out of bounds, %d\n", bindex);
++ goto out;
++ }
++
++ err = 0;
++ mod->perm = br_perm_val(args[1].from);
++ AuDbg("mod path %s, perm 0x%x, %s\n",
++ mod->path, mod->perm, args[1].from);
++ mod->h_root = dget(au_h_dptr(root, bindex));
++
++out:
++ aufs_read_unlock(root, !AuLock_IR);
++ return err;
++}
++#endif
++
++static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino,
++ substring_t args[])
++{
++ int err;
++ struct file *file;
++
++ file = au_xino_create(sb, args[0].from, /*silent*/0);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++
++ err = -EINVAL;
++ if (unlikely(file->f_dentry->d_sb == sb)) {
++ fput(file);
++ pr_err("%s must be outside\n", args[0].from);
++ goto out;
++ }
++
++ err = 0;
++ xino->file = file;
++ xino->path = args[0].from;
++
++out:
++ return err;
++}
++
++static int noinline_for_stack
++au_opts_parse_xino_itrunc_path(struct super_block *sb,
++ struct au_opt_xino_itrunc *xino_itrunc,
++ substring_t args[])
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct path path;
++ struct dentry *root;
++
++ err = vfsub_kern_path(args[0].from, lkup_dirflags, &path);
++ if (unlikely(err)) {
++ pr_err("lookup failed %s (%d)\n", args[0].from, err);
++ goto out;
++ }
++
++ xino_itrunc->bindex = -1;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_FLUSH);
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ if (au_h_dptr(root, bindex) == path.dentry) {
++ xino_itrunc->bindex = bindex;
++ break;
++ }
++ }
++ aufs_read_unlock(root, !AuLock_IR);
++ path_put(&path);
++
++ if (unlikely(xino_itrunc->bindex < 0)) {
++ pr_err("no such branch %s\n", args[0].from);
++ err = -EINVAL;
++ }
++
++out:
++ return err;
++}
++
++/* called without aufs lock */
++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
++{
++ int err, n, token;
++ aufs_bindex_t bindex;
++ unsigned char skipped;
++ struct dentry *root;
++ struct au_opt *opt, *opt_tail;
++ char *opt_str;
++ /* reduce the stack space */
++ union {
++ struct au_opt_xino_itrunc *xino_itrunc;
++ struct au_opt_wbr_create *create;
++ } u;
++ struct {
++ substring_t args[MAX_OPT_ARGS];
++ } *a;
++
++ err = -ENOMEM;
++ a = kmalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ root = sb->s_root;
++ err = 0;
++ bindex = 0;
++ opt = opts->opt;
++ opt_tail = opt + opts->max_opt - 1;
++ opt->type = Opt_tail;
++ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) {
++ err = -EINVAL;
++ skipped = 0;
++ token = match_token(opt_str, options, a->args);
++ switch (token) {
++ case Opt_br:
++ err = 0;
++ while (!err && (opt_str = strsep(&a->args[0].from, ":"))
++ && *opt_str) {
++ err = opt_add(opt, opt_str, opts->sb_flags,
++ bindex++);
++ if (unlikely(!err && ++opt > opt_tail)) {
++ err = -E2BIG;
++ break;
++ }
++ opt->type = Opt_tail;
++ skipped = 1;
++ }
++ break;
++ case Opt_add:
++ if (unlikely(match_int(&a->args[0], &n))) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ bindex = n;
++ err = opt_add(opt, a->args[1].from, opts->sb_flags,
++ bindex);
++ if (!err)
++ opt->type = token;
++ break;
++ case Opt_append:
++ err = opt_add(opt, a->args[0].from, opts->sb_flags,
++ /*dummy bindex*/1);
++ if (!err)
++ opt->type = token;
++ break;
++ case Opt_prepend:
++ err = opt_add(opt, a->args[0].from, opts->sb_flags,
++ /*bindex*/0);
++ if (!err)
++ opt->type = token;
++ break;
++ case Opt_del:
++ err = au_opts_parse_del(&opt->del, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#if 0 /* reserved for future use */
++ case Opt_idel:
++ del->pathname = "(indexed)";
++ if (unlikely(match_int(&args[0], &n))) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ err = au_opts_parse_idel(sb, n, &opt->del, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#endif
++ case Opt_mod:
++ err = au_opts_parse_mod(&opt->mod, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#ifdef IMOD /* reserved for future use */
++ case Opt_imod:
++ u.mod->path = "(indexed)";
++ if (unlikely(match_int(&a->args[0], &n))) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ err = au_opts_parse_imod(sb, n, &opt->mod, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#endif
++ case Opt_xino:
++ err = au_opts_parse_xino(sb, &opt->xino, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++
++ case Opt_trunc_xino_path:
++ err = au_opts_parse_xino_itrunc_path
++ (sb, &opt->xino_itrunc, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++
++ case Opt_itrunc_xino:
++ u.xino_itrunc = &opt->xino_itrunc;
++ if (unlikely(match_int(&a->args[0], &n))) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ u.xino_itrunc->bindex = n;
++ aufs_read_lock(root, AuLock_FLUSH);
++ if (n < 0 || au_sbend(sb) < n) {
++ pr_err("out of bounds, %d\n", n);
++ aufs_read_unlock(root, !AuLock_IR);
++ break;
++ }
++ aufs_read_unlock(root, !AuLock_IR);
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_dirwh:
++ if (unlikely(match_int(&a->args[0], &opt->dirwh)))
++ break;
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_rdcache:
++ if (unlikely(match_int(&a->args[0], &n))) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ if (unlikely(n > AUFS_RDCACHE_MAX)) {
++ pr_err("rdcache must be smaller than %d\n",
++ AUFS_RDCACHE_MAX);
++ break;
++ }
++ opt->rdcache = n;
++ err = 0;
++ opt->type = token;
++ break;
++ case Opt_rdblk:
++ if (unlikely(match_int(&a->args[0], &n)
++ || n < 0
++ || n > KMALLOC_MAX_SIZE)) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ if (unlikely(n && n < NAME_MAX)) {
++ pr_err("rdblk must be larger than %d\n",
++ NAME_MAX);
++ break;
++ }
++ opt->rdblk = n;
++ err = 0;
++ opt->type = token;
++ break;
++ case Opt_rdhash:
++ if (unlikely(match_int(&a->args[0], &n)
++ || n < 0
++ || n * sizeof(struct hlist_head)
++ > KMALLOC_MAX_SIZE)) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ opt->rdhash = n;
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_trunc_xino:
++ case Opt_notrunc_xino:
++ case Opt_noxino:
++ case Opt_trunc_xib:
++ case Opt_notrunc_xib:
++ case Opt_shwh:
++ case Opt_noshwh:
++ case Opt_plink:
++ case Opt_noplink:
++ case Opt_list_plink:
++ case Opt_dio:
++ case Opt_nodio:
++ case Opt_diropq_a:
++ case Opt_diropq_w:
++ case Opt_warn_perm:
++ case Opt_nowarn_perm:
++ case Opt_refrof:
++ case Opt_norefrof:
++ case Opt_verbose:
++ case Opt_noverbose:
++ case Opt_sum:
++ case Opt_nosum:
++ case Opt_wsum:
++ case Opt_rdblk_def:
++ case Opt_rdhash_def:
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_udba:
++ opt->udba = udba_val(a->args[0].from);
++ if (opt->udba >= 0) {
++ err = 0;
++ opt->type = token;
++ } else
++ pr_err("wrong value, %s\n", opt_str);
++ break;
++
++ case Opt_wbr_create:
++ u.create = &opt->wbr_create;
++ u.create->wbr_create
++ = au_wbr_create_val(a->args[0].from, u.create);
++ if (u.create->wbr_create >= 0) {
++ err = 0;
++ opt->type = token;
++ } else
++ pr_err("wrong value, %s\n", opt_str);
++ break;
++ case Opt_wbr_copyup:
++ opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from);
++ if (opt->wbr_copyup >= 0) {
++ err = 0;
++ opt->type = token;
++ } else
++ pr_err("wrong value, %s\n", opt_str);
++ break;
++
++ case Opt_ignore:
++ pr_warning("ignored %s\n", opt_str);
++ /*FALLTHROUGH*/
++ case Opt_ignore_silent:
++ skipped = 1;
++ err = 0;
++ break;
++ case Opt_err:
++ pr_err("unknown option %s\n", opt_str);
++ break;
++ }
++
++ if (!err && !skipped) {
++ if (unlikely(++opt > opt_tail)) {
++ err = -E2BIG;
++ opt--;
++ opt->type = Opt_tail;
++ break;
++ }
++ opt->type = Opt_tail;
++ }
++ }
++
++ kfree(a);
++ dump_opts(opts);
++ if (unlikely(err))
++ au_opts_free(opts);
++
++out:
++ return err;
++}
++
++static int au_opt_wbr_create(struct super_block *sb,
++ struct au_opt_wbr_create *create)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ err = 1; /* handled */
++ sbinfo = au_sbi(sb);
++ if (sbinfo->si_wbr_create_ops->fin) {
++ err = sbinfo->si_wbr_create_ops->fin(sb);
++ if (!err)
++ err = 1;
++ }
++
++ sbinfo->si_wbr_create = create->wbr_create;
++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create;
++ switch (create->wbr_create) {
++ case AuWbrCreate_MFSRRV:
++ case AuWbrCreate_MFSRR:
++ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark;
++ /*FALLTHROUGH*/
++ case AuWbrCreate_MFS:
++ case AuWbrCreate_MFSV:
++ case AuWbrCreate_PMFS:
++ case AuWbrCreate_PMFSV:
++ sbinfo->si_wbr_mfs.mfs_expire
++ = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC);
++ break;
++ }
++
++ if (sbinfo->si_wbr_create_ops->init)
++ sbinfo->si_wbr_create_ops->init(sb); /* ignore */
++
++ return err;
++}
++
++/*
++ * returns,
++ * plus: processed without an error
++ * zero: unprocessed
++ */
++static int au_opt_simple(struct super_block *sb, struct au_opt *opt,
++ struct au_opts *opts)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ err = 1; /* handled */
++ sbinfo = au_sbi(sb);
++ switch (opt->type) {
++ case Opt_udba:
++ sbinfo->si_mntflags &= ~AuOptMask_UDBA;
++ sbinfo->si_mntflags |= opt->udba;
++ opts->given_udba |= opt->udba;
++ break;
++
++ case Opt_plink:
++ au_opt_set(sbinfo->si_mntflags, PLINK);
++ break;
++ case Opt_noplink:
++ if (au_opt_test(sbinfo->si_mntflags, PLINK))
++ au_plink_put(sb, /*verbose*/1);
++ au_opt_clr(sbinfo->si_mntflags, PLINK);
++ break;
++ case Opt_list_plink:
++ if (au_opt_test(sbinfo->si_mntflags, PLINK))
++ au_plink_list(sb);
++ break;
++
++ case Opt_dio:
++ au_opt_set(sbinfo->si_mntflags, DIO);
++ au_fset_opts(opts->flags, REFRESH_DYAOP);
++ break;
++ case Opt_nodio:
++ au_opt_clr(sbinfo->si_mntflags, DIO);
++ au_fset_opts(opts->flags, REFRESH_DYAOP);
++ break;
++
++ case Opt_diropq_a:
++ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ);
++ break;
++ case Opt_diropq_w:
++ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ);
++ break;
++
++ case Opt_warn_perm:
++ au_opt_set(sbinfo->si_mntflags, WARN_PERM);
++ break;
++ case Opt_nowarn_perm:
++ au_opt_clr(sbinfo->si_mntflags, WARN_PERM);
++ break;
++
++ case Opt_refrof:
++ au_opt_set(sbinfo->si_mntflags, REFROF);
++ break;
++ case Opt_norefrof:
++ au_opt_clr(sbinfo->si_mntflags, REFROF);
++ break;
++
++ case Opt_verbose:
++ au_opt_set(sbinfo->si_mntflags, VERBOSE);
++ break;
++ case Opt_noverbose:
++ au_opt_clr(sbinfo->si_mntflags, VERBOSE);
++ break;
++
++ case Opt_sum:
++ au_opt_set(sbinfo->si_mntflags, SUM);
++ break;
++ case Opt_wsum:
++ au_opt_clr(sbinfo->si_mntflags, SUM);
++ au_opt_set(sbinfo->si_mntflags, SUM_W);
++ case Opt_nosum:
++ au_opt_clr(sbinfo->si_mntflags, SUM);
++ au_opt_clr(sbinfo->si_mntflags, SUM_W);
++ break;
++
++ case Opt_wbr_create:
++ err = au_opt_wbr_create(sb, &opt->wbr_create);
++ break;
++ case Opt_wbr_copyup:
++ sbinfo->si_wbr_copyup = opt->wbr_copyup;
++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup;
++ break;
++
++ case Opt_dirwh:
++ sbinfo->si_dirwh = opt->dirwh;
++ break;
++
++ case Opt_rdcache:
++ sbinfo->si_rdcache
++ = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC);
++ break;
++ case Opt_rdblk:
++ sbinfo->si_rdblk = opt->rdblk;
++ break;
++ case Opt_rdblk_def:
++ sbinfo->si_rdblk = AUFS_RDBLK_DEF;
++ break;
++ case Opt_rdhash:
++ sbinfo->si_rdhash = opt->rdhash;
++ break;
++ case Opt_rdhash_def:
++ sbinfo->si_rdhash = AUFS_RDHASH_DEF;
++ break;
++
++ case Opt_shwh:
++ au_opt_set(sbinfo->si_mntflags, SHWH);
++ break;
++ case Opt_noshwh:
++ au_opt_clr(sbinfo->si_mntflags, SHWH);
++ break;
++
++ case Opt_trunc_xino:
++ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO);
++ break;
++ case Opt_notrunc_xino:
++ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO);
++ break;
++
++ case Opt_trunc_xino_path:
++ case Opt_itrunc_xino:
++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex);
++ if (!err)
++ err = 1;
++ break;
++
++ case Opt_trunc_xib:
++ au_fset_opts(opts->flags, TRUNC_XIB);
++ break;
++ case Opt_notrunc_xib:
++ au_fclr_opts(opts->flags, TRUNC_XIB);
++ break;
++
++ default:
++ err = 0;
++ break;
++ }
++
++ return err;
++}
++
++/*
++ * returns tri-state.
++ * plus: processed without an error
++ * zero: unprocessed
++ * minus: error
++ */
++static int au_opt_br(struct super_block *sb, struct au_opt *opt,
++ struct au_opts *opts)
++{
++ int err, do_refresh;
++
++ err = 0;
++ switch (opt->type) {
++ case Opt_append:
++ opt->add.bindex = au_sbend(sb) + 1;
++ if (opt->add.bindex < 0)
++ opt->add.bindex = 0;
++ goto add;
++ case Opt_prepend:
++ opt->add.bindex = 0;
++ add:
++ case Opt_add:
++ err = au_br_add(sb, &opt->add,
++ au_ftest_opts(opts->flags, REMOUNT));
++ if (!err) {
++ err = 1;
++ au_fset_opts(opts->flags, REFRESH);
++ }
++ break;
++
++ case Opt_del:
++ case Opt_idel:
++ err = au_br_del(sb, &opt->del,
++ au_ftest_opts(opts->flags, REMOUNT));
++ if (!err) {
++ err = 1;
++ au_fset_opts(opts->flags, TRUNC_XIB);
++ au_fset_opts(opts->flags, REFRESH);
++ }
++ break;
++
++ case Opt_mod:
++ case Opt_imod:
++ err = au_br_mod(sb, &opt->mod,
++ au_ftest_opts(opts->flags, REMOUNT),
++ &do_refresh);
++ if (!err) {
++ err = 1;
++ if (do_refresh)
++ au_fset_opts(opts->flags, REFRESH);
++ }
++ break;
++ }
++
++ return err;
++}
++
++static int au_opt_xino(struct super_block *sb, struct au_opt *opt,
++ struct au_opt_xino **opt_xino,
++ struct au_opts *opts)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct dentry *root, *parent, *h_root;
++
++ err = 0;
++ switch (opt->type) {
++ case Opt_xino:
++ err = au_xino_set(sb, &opt->xino,
++ !!au_ftest_opts(opts->flags, REMOUNT));
++ if (unlikely(err))
++ break;
++
++ *opt_xino = &opt->xino;
++ au_xino_brid_set(sb, -1);
++
++ /* safe d_parent access */
++ parent = opt->xino.file->f_dentry->d_parent;
++ root = sb->s_root;
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ h_root = au_h_dptr(root, bindex);
++ if (h_root == parent) {
++ au_xino_brid_set(sb, au_sbr_id(sb, bindex));
++ break;
++ }
++ }
++ break;
++
++ case Opt_noxino:
++ au_xino_clr(sb);
++ au_xino_brid_set(sb, -1);
++ *opt_xino = (void *)-1;
++ break;
++ }
++
++ return err;
++}
++
++int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
++ unsigned int pending)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ unsigned char do_plink, skip, do_free;
++ struct au_branch *br;
++ struct au_wbr *wbr;
++ struct dentry *root;
++ struct inode *dir, *h_dir;
++ struct au_sbinfo *sbinfo;
++ struct au_hinode *hdir;
++
++ SiMustAnyLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA));
++
++ if (!(sb_flags & MS_RDONLY)) {
++ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0))))
++ pr_warning("first branch should be rw\n");
++ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH)))
++ pr_warning("shwh should be used with ro\n");
++ }
++
++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY)
++ && !au_opt_test(sbinfo->si_mntflags, XINO))
++ pr_warning("udba=*notify requires xino\n");
++
++ err = 0;
++ root = sb->s_root;
++ dir = root->d_inode;
++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK);
++ bend = au_sbend(sb);
++ for (bindex = 0; !err && bindex <= bend; bindex++) {
++ skip = 0;
++ h_dir = au_h_iptr(dir, bindex);
++ br = au_sbr(sb, bindex);
++ do_free = 0;
++
++ wbr = br->br_wbr;
++ if (wbr)
++ wbr_wh_read_lock(wbr);
++
++ switch (br->br_perm) {
++ case AuBrPerm_RO:
++ case AuBrPerm_ROWH:
++ case AuBrPerm_RR:
++ case AuBrPerm_RRWH:
++ do_free = !!wbr;
++ skip = (!wbr
++ || (!wbr->wbr_whbase
++ && !wbr->wbr_plink
++ && !wbr->wbr_orph));
++ break;
++
++ case AuBrPerm_RWNoLinkWH:
++ /* skip = (!br->br_whbase && !br->br_orph); */
++ skip = (!wbr || !wbr->wbr_whbase);
++ if (skip && wbr) {
++ if (do_plink)
++ skip = !!wbr->wbr_plink;
++ else
++ skip = !wbr->wbr_plink;
++ }
++ break;
++
++ case AuBrPerm_RW:
++ /* skip = (br->br_whbase && br->br_ohph); */
++ skip = (wbr && wbr->wbr_whbase);
++ if (skip) {
++ if (do_plink)
++ skip = !!wbr->wbr_plink;
++ else
++ skip = !wbr->wbr_plink;
++ }
++ break;
++
++ default:
++ BUG();
++ }
++ if (wbr)
++ wbr_wh_read_unlock(wbr);
++
++ if (skip)
++ continue;
++
++ hdir = au_hi(dir, bindex);
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ if (wbr)
++ wbr_wh_write_lock(wbr);
++ err = au_wh_init(au_h_dptr(root, bindex), br, sb);
++ if (wbr)
++ wbr_wh_write_unlock(wbr);
++ au_hn_imtx_unlock(hdir);
++
++ if (!err && do_free) {
++ kfree(wbr);
++ br->br_wbr = NULL;
++ }
++ }
++
++ return err;
++}
++
++int au_opts_mount(struct super_block *sb, struct au_opts *opts)
++{
++ int err;
++ unsigned int tmp;
++ aufs_bindex_t bindex, bend;
++ struct au_opt *opt;
++ struct au_opt_xino *opt_xino, xino;
++ struct au_sbinfo *sbinfo;
++ struct au_branch *br;
++
++ SiMustWriteLock(sb);
++
++ err = 0;
++ opt_xino = NULL;
++ opt = opts->opt;
++ while (err >= 0 && opt->type != Opt_tail)
++ err = au_opt_simple(sb, opt++, opts);
++ if (err > 0)
++ err = 0;
++ else if (unlikely(err < 0))
++ goto out;
++
++ /* disable xino and udba temporary */
++ sbinfo = au_sbi(sb);
++ tmp = sbinfo->si_mntflags;
++ au_opt_clr(sbinfo->si_mntflags, XINO);
++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL);
++
++ opt = opts->opt;
++ while (err >= 0 && opt->type != Opt_tail)
++ err = au_opt_br(sb, opt++, opts);
++ if (err > 0)
++ err = 0;
++ else if (unlikely(err < 0))
++ goto out;
++
++ bend = au_sbend(sb);
++ if (unlikely(bend < 0)) {
++ err = -EINVAL;
++ pr_err("no branches\n");
++ goto out;
++ }
++
++ if (au_opt_test(tmp, XINO))
++ au_opt_set(sbinfo->si_mntflags, XINO);
++ opt = opts->opt;
++ while (!err && opt->type != Opt_tail)
++ err = au_opt_xino(sb, opt++, &opt_xino, opts);
++ if (unlikely(err))
++ goto out;
++
++ err = au_opts_verify(sb, sb->s_flags, tmp);
++ if (unlikely(err))
++ goto out;
++
++ /* restore xino */
++ if (au_opt_test(tmp, XINO) && !opt_xino) {
++ xino.file = au_xino_def(sb);
++ err = PTR_ERR(xino.file);
++ if (IS_ERR(xino.file))
++ goto out;
++
++ err = au_xino_set(sb, &xino, /*remount*/0);
++ fput(xino.file);
++ if (unlikely(err))
++ goto out;
++ }
++
++ /* restore udba */
++ tmp &= AuOptMask_UDBA;
++ sbinfo->si_mntflags &= ~AuOptMask_UDBA;
++ sbinfo->si_mntflags |= tmp;
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ err = au_hnotify_reset_br(tmp, br, br->br_perm);
++ if (unlikely(err))
++ AuIOErr("hnotify failed on br %d, %d, ignored\n",
++ bindex, err);
++ /* go on even if err */
++ }
++ if (au_opt_test(tmp, UDBA_HNOTIFY)) {
++ struct inode *dir = sb->s_root->d_inode;
++ au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO);
++ }
++
++out:
++ return err;
++}
++
++int au_opts_remount(struct super_block *sb, struct au_opts *opts)
++{
++ int err, rerr;
++ struct inode *dir;
++ struct au_opt_xino *opt_xino;
++ struct au_opt *opt;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ dir = sb->s_root->d_inode;
++ sbinfo = au_sbi(sb);
++ err = 0;
++ opt_xino = NULL;
++ opt = opts->opt;
++ while (err >= 0 && opt->type != Opt_tail) {
++ err = au_opt_simple(sb, opt, opts);
++ if (!err)
++ err = au_opt_br(sb, opt, opts);
++ if (!err)
++ err = au_opt_xino(sb, opt, &opt_xino, opts);
++ opt++;
++ }
++ if (err > 0)
++ err = 0;
++ AuTraceErr(err);
++ /* go on even err */
++
++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0);
++ if (unlikely(rerr && !err))
++ err = rerr;
++
++ if (au_ftest_opts(opts->flags, TRUNC_XIB)) {
++ rerr = au_xib_trunc(sb);
++ if (unlikely(rerr && !err))
++ err = rerr;
++ }
++
++ /* will be handled by the caller */
++ if (!au_ftest_opts(opts->flags, REFRESH)
++ && (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO)))
++ au_fset_opts(opts->flags, REFRESH);
++
++ AuDbg("status 0x%x\n", opts->flags);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++unsigned int au_opt_udba(struct super_block *sb)
++{
++ return au_mntflags(sb) & AuOptMask_UDBA;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/opts.h linux-2.6.37/fs/aufs/opts.h
+--- linux-2.6.37.orig/fs/aufs/opts.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/opts.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,210 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * mount options/flags
++ */
++
++#ifndef __AUFS_OPTS_H__
++#define __AUFS_OPTS_H__
++
++#ifdef __KERNEL__
++
++#include <linux/path.h>
++#include <linux/aufs_type.h>
++
++struct file;
++struct super_block;
++
++/* ---------------------------------------------------------------------- */
++
++/* mount flags */
++#define AuOpt_XINO 1 /* external inode number bitmap
++ and translation table */
++#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */
++#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */
++#define AuOpt_UDBA_REVAL (1 << 3)
++#define AuOpt_UDBA_HNOTIFY (1 << 4)
++#define AuOpt_SHWH (1 << 5) /* show whiteout */
++#define AuOpt_PLINK (1 << 6) /* pseudo-link */
++#define AuOpt_DIRPERM1 (1 << 7) /* unimplemented */
++#define AuOpt_REFROF (1 << 8) /* unimplemented */
++#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */
++#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */
++#define AuOpt_SUM_W (1 << 11) /* unimplemented */
++#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */
++#define AuOpt_VERBOSE (1 << 13) /* busy inode when del-branch */
++#define AuOpt_DIO (1 << 14) /* direct io */
++
++#ifndef CONFIG_AUFS_HNOTIFY
++#undef AuOpt_UDBA_HNOTIFY
++#define AuOpt_UDBA_HNOTIFY 0
++#endif
++#ifndef CONFIG_AUFS_SHWH
++#undef AuOpt_SHWH
++#define AuOpt_SHWH 0
++#endif
++
++#define AuOpt_Def (AuOpt_XINO \
++ | AuOpt_UDBA_REVAL \
++ | AuOpt_PLINK \
++ /* | AuOpt_DIRPERM1 */ \
++ | AuOpt_WARN_PERM)
++#define AuOptMask_UDBA (AuOpt_UDBA_NONE \
++ | AuOpt_UDBA_REVAL \
++ | AuOpt_UDBA_HNOTIFY)
++
++#define au_opt_test(flags, name) (flags & AuOpt_##name)
++#define au_opt_set(flags, name) do { \
++ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \
++ ((flags) |= AuOpt_##name); \
++} while (0)
++#define au_opt_set_udba(flags, name) do { \
++ (flags) &= ~AuOptMask_UDBA; \
++ ((flags) |= AuOpt_##name); \
++} while (0)
++#define au_opt_clr(flags, name) do { \
++ ((flags) &= ~AuOpt_##name); \
++} while (0)
++
++static inline unsigned int au_opts_plink(unsigned int mntflags)
++{
++#ifdef CONFIG_PROC_FS
++ return mntflags;
++#else
++ return mntflags & ~AuOpt_PLINK;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* policies to select one among multiple writable branches */
++enum {
++ AuWbrCreate_TDP, /* top down parent */
++ AuWbrCreate_RR, /* round robin */
++ AuWbrCreate_MFS, /* most free space */
++ AuWbrCreate_MFSV, /* mfs with seconds */
++ AuWbrCreate_MFSRR, /* mfs then rr */
++ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */
++ AuWbrCreate_PMFS, /* parent and mfs */
++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */
++
++ AuWbrCreate_Def = AuWbrCreate_TDP
++};
++
++enum {
++ AuWbrCopyup_TDP, /* top down parent */
++ AuWbrCopyup_BUP, /* bottom up parent */
++ AuWbrCopyup_BU, /* bottom up */
++
++ AuWbrCopyup_Def = AuWbrCopyup_TDP
++};
++
++/* ---------------------------------------------------------------------- */
++
++struct au_opt_add {
++ aufs_bindex_t bindex;
++ char *pathname;
++ int perm;
++ struct path path;
++};
++
++struct au_opt_del {
++ char *pathname;
++ struct path h_path;
++};
++
++struct au_opt_mod {
++ char *path;
++ int perm;
++ struct dentry *h_root;
++};
++
++struct au_opt_xino {
++ char *path;
++ struct file *file;
++};
++
++struct au_opt_xino_itrunc {
++ aufs_bindex_t bindex;
++};
++
++struct au_opt_wbr_create {
++ int wbr_create;
++ int mfs_second;
++ unsigned long long mfsrr_watermark;
++};
++
++struct au_opt {
++ int type;
++ union {
++ struct au_opt_xino xino;
++ struct au_opt_xino_itrunc xino_itrunc;
++ struct au_opt_add add;
++ struct au_opt_del del;
++ struct au_opt_mod mod;
++ int dirwh;
++ int rdcache;
++ unsigned int rdblk;
++ unsigned int rdhash;
++ int udba;
++ struct au_opt_wbr_create wbr_create;
++ int wbr_copyup;
++ };
++};
++
++/* opts flags */
++#define AuOpts_REMOUNT 1
++#define AuOpts_REFRESH (1 << 1)
++#define AuOpts_TRUNC_XIB (1 << 2)
++#define AuOpts_REFRESH_DYAOP (1 << 3)
++#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name)
++#define au_fset_opts(flags, name) \
++ do { (flags) |= AuOpts_##name; } while (0)
++#define au_fclr_opts(flags, name) \
++ do { (flags) &= ~AuOpts_##name; } while (0)
++
++struct au_opts {
++ struct au_opt *opt;
++ int max_opt;
++
++ unsigned int given_udba;
++ unsigned int flags;
++ unsigned long sb_flags;
++};
++
++/* ---------------------------------------------------------------------- */
++
++const char *au_optstr_br_perm(int brperm);
++const char *au_optstr_udba(int udba);
++const char *au_optstr_wbr_copyup(int wbr_copyup);
++const char *au_optstr_wbr_create(int wbr_create);
++
++void au_opts_free(struct au_opts *opts);
++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts);
++int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
++ unsigned int pending);
++int au_opts_mount(struct super_block *sb, struct au_opts *opts);
++int au_opts_remount(struct super_block *sb, struct au_opts *opts);
++
++unsigned int au_opt_udba(struct super_block *sb);
++
++/* ---------------------------------------------------------------------- */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_OPTS_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/plink.c linux-2.6.37/fs/aufs/plink.c
+--- linux-2.6.37.orig/fs/aufs/plink.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/plink.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,515 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * pseudo-link
++ */
++
++#include "aufs.h"
++
++/*
++ * the pseudo-link maintenance mode.
++ * during a user process maintains the pseudo-links,
++ * prohibit adding a new plink and branch manipulation.
++ *
++ * Flags
++ * NOPLM:
++ * For entry functions which will handle plink, and i_mutex is already held
++ * in VFS.
++ * They cannot wait and should return an error at once.
++ * Callers has to check the error.
++ * NOPLMW:
++ * For entry functions which will handle plink, but i_mutex is not held
++ * in VFS.
++ * They can wait the plink maintenance mode to finish.
++ *
++ * They behave like F_SETLK and F_SETLKW.
++ * If the caller never handle plink, then both flags are unnecessary.
++ */
++
++int au_plink_maint(struct super_block *sb, int flags)
++{
++ int err;
++ pid_t pid, ppid;
++ struct au_sbinfo *sbi;
++
++ SiMustAnyLock(sb);
++
++ err = 0;
++ if (!au_opt_test(au_mntflags(sb), PLINK))
++ goto out;
++
++ sbi = au_sbi(sb);
++ pid = sbi->si_plink_maint_pid;
++ if (!pid || pid == current->pid)
++ goto out;
++
++ /* todo: it highly depends upon /sbin/mount.aufs */
++ rcu_read_lock();
++ ppid = task_pid_vnr(rcu_dereference(current->real_parent));
++ rcu_read_unlock();
++ if (pid == ppid)
++ goto out;
++
++ if (au_ftest_lock(flags, NOPLMW)) {
++ /* if there is no i_mutex lock in VFS, we don't need to wait */
++ /* AuDebugOn(!lockdep_depth(current)); */
++ while (sbi->si_plink_maint_pid) {
++ si_read_unlock(sb);
++ /* gave up wake_up_bit() */
++ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid);
++
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&sbi->si_nowait);
++ si_noflush_read_lock(sb);
++ }
++ } else if (au_ftest_lock(flags, NOPLM)) {
++ AuDbg("ppid %d, pid %d\n", ppid, pid);
++ err = -EAGAIN;
++ }
++
++out:
++ return err;
++}
++
++void au_plink_maint_leave(struct au_sbinfo *sbinfo)
++{
++ spin_lock(&sbinfo->si_plink_maint_lock);
++ sbinfo->si_plink_maint_pid = 0;
++ spin_unlock(&sbinfo->si_plink_maint_lock);
++ wake_up_all(&sbinfo->si_plink_wq);
++}
++
++int au_plink_maint_enter(struct super_block *sb)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ /* make sure i am the only one in this fs */
++ si_write_lock(sb, AuLock_FLUSH);
++ if (au_opt_test(au_mntflags(sb), PLINK)) {
++ spin_lock(&sbinfo->si_plink_maint_lock);
++ if (!sbinfo->si_plink_maint_pid)
++ sbinfo->si_plink_maint_pid = current->pid;
++ else
++ err = -EBUSY;
++ spin_unlock(&sbinfo->si_plink_maint_lock);
++ }
++ si_write_unlock(sb);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct pseudo_link {
++ union {
++ struct list_head list;
++ struct rcu_head rcu;
++ };
++ struct inode *inode;
++};
++
++#ifdef CONFIG_AUFS_DEBUG
++void au_plink_list(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink;
++
++ SiMustAnyLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
++
++ plink_list = &sbinfo->si_plink.head;
++ rcu_read_lock();
++ list_for_each_entry_rcu(plink, plink_list, list)
++ AuDbg("%lu\n", plink->inode->i_ino);
++ rcu_read_unlock();
++}
++#endif
++
++/* is the inode pseudo-linked? */
++int au_plink_test(struct inode *inode)
++{
++ int found;
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink;
++
++ sbinfo = au_sbi(inode->i_sb);
++ AuRwMustAnyLock(&sbinfo->si_rwsem);
++ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK));
++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM));
++
++ found = 0;
++ plink_list = &sbinfo->si_plink.head;
++ rcu_read_lock();
++ list_for_each_entry_rcu(plink, plink_list, list)
++ if (plink->inode == inode) {
++ found = 1;
++ break;
++ }
++ rcu_read_unlock();
++ return found;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * generate a name for plink.
++ * the file will be stored under AUFS_WH_PLINKDIR.
++ */
++/* 20 is max digits length of ulong 64 */
++#define PLINK_NAME_LEN ((20 + 1) * 2)
++
++static int plink_name(char *name, int len, struct inode *inode,
++ aufs_bindex_t bindex)
++{
++ int rlen;
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, bindex);
++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino);
++ return rlen;
++}
++
++struct au_do_plink_lkup_args {
++ struct dentry **errp;
++ struct qstr *tgtname;
++ struct dentry *h_parent;
++ struct au_branch *br;
++};
++
++static struct dentry *au_do_plink_lkup(struct qstr *tgtname,
++ struct dentry *h_parent,
++ struct au_branch *br)
++{
++ struct dentry *h_dentry;
++ struct mutex *h_mtx;
++
++ h_mtx = &h_parent->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD2);
++ h_dentry = au_lkup_one(tgtname, h_parent, br, /*nd*/NULL);
++ mutex_unlock(h_mtx);
++ return h_dentry;
++}
++
++static void au_call_do_plink_lkup(void *args)
++{
++ struct au_do_plink_lkup_args *a = args;
++ *a->errp = au_do_plink_lkup(a->tgtname, a->h_parent, a->br);
++}
++
++/* lookup the plink-ed @inode under the branch at @bindex */
++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex)
++{
++ struct dentry *h_dentry, *h_parent;
++ struct au_branch *br;
++ struct inode *h_dir;
++ int wkq_err;
++ char a[PLINK_NAME_LEN];
++ struct qstr tgtname = {
++ .name = a
++ };
++
++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM));
++
++ br = au_sbr(inode->i_sb, bindex);
++ h_parent = br->br_wbr->wbr_plink;
++ h_dir = h_parent->d_inode;
++ tgtname.len = plink_name(a, sizeof(a), inode, bindex);
++
++ if (current_fsuid()) {
++ struct au_do_plink_lkup_args args = {
++ .errp = &h_dentry,
++ .tgtname = &tgtname,
++ .h_parent = h_parent,
++ .br = br
++ };
++
++ wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args);
++ if (unlikely(wkq_err))
++ h_dentry = ERR_PTR(wkq_err);
++ } else
++ h_dentry = au_do_plink_lkup(&tgtname, h_parent, br);
++
++ return h_dentry;
++}
++
++/* create a pseudo-link */
++static int do_whplink(struct qstr *tgt, struct dentry *h_parent,
++ struct dentry *h_dentry, struct au_branch *br)
++{
++ int err;
++ struct path h_path = {
++ .mnt = br->br_mnt
++ };
++ struct inode *h_dir;
++
++ h_dir = h_parent->d_inode;
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2);
++again:
++ h_path.dentry = au_lkup_one(tgt, h_parent, br, /*nd*/NULL);
++ err = PTR_ERR(h_path.dentry);
++ if (IS_ERR(h_path.dentry))
++ goto out;
++
++ err = 0;
++ /* wh.plink dir is not monitored */
++ /* todo: is it really safe? */
++ if (h_path.dentry->d_inode
++ && h_path.dentry->d_inode != h_dentry->d_inode) {
++ err = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ dput(h_path.dentry);
++ h_path.dentry = NULL;
++ if (!err)
++ goto again;
++ }
++ if (!err && !h_path.dentry->d_inode)
++ err = vfsub_link(h_dentry, h_dir, &h_path);
++ dput(h_path.dentry);
++
++out:
++ mutex_unlock(&h_dir->i_mutex);
++ return err;
++}
++
++struct do_whplink_args {
++ int *errp;
++ struct qstr *tgt;
++ struct dentry *h_parent;
++ struct dentry *h_dentry;
++ struct au_branch *br;
++};
++
++static void call_do_whplink(void *args)
++{
++ struct do_whplink_args *a = args;
++ *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br);
++}
++
++static int whplink(struct dentry *h_dentry, struct inode *inode,
++ aufs_bindex_t bindex, struct au_branch *br)
++{
++ int err, wkq_err;
++ struct au_wbr *wbr;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++ char a[PLINK_NAME_LEN];
++ struct qstr tgtname = {
++ .name = a
++ };
++
++ wbr = au_sbr(inode->i_sb, bindex)->br_wbr;
++ h_parent = wbr->wbr_plink;
++ h_dir = h_parent->d_inode;
++ tgtname.len = plink_name(a, sizeof(a), inode, bindex);
++
++ /* always superio. */
++ if (current_fsuid()) {
++ struct do_whplink_args args = {
++ .errp = &err,
++ .tgt = &tgtname,
++ .h_parent = h_parent,
++ .h_dentry = h_dentry,
++ .br = br
++ };
++ wkq_err = au_wkq_wait(call_do_whplink, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ } else
++ err = do_whplink(&tgtname, h_parent, h_dentry, br);
++
++ return err;
++}
++
++/* free a single plink */
++static void do_put_plink(struct pseudo_link *plink, int do_del)
++{
++ if (do_del)
++ list_del(&plink->list);
++ iput(plink->inode);
++ kfree(plink);
++}
++
++static void do_put_plink_rcu(struct rcu_head *rcu)
++{
++ struct pseudo_link *plink;
++
++ plink = container_of(rcu, struct pseudo_link, rcu);
++ iput(plink->inode);
++ kfree(plink);
++}
++
++/*
++ * create a new pseudo-link for @h_dentry on @bindex.
++ * the linked inode is held in aufs @inode.
++ */
++void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_dentry)
++{
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink, *tmp;
++ int found, err, cnt;
++
++ sb = inode->i_sb;
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
++
++ cnt = 0;
++ found = 0;
++ plink_list = &sbinfo->si_plink.head;
++ rcu_read_lock();
++ list_for_each_entry_rcu(plink, plink_list, list) {
++ cnt++;
++ if (plink->inode == inode) {
++ found = 1;
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (found)
++ return;
++
++ tmp = kmalloc(sizeof(*plink), GFP_NOFS);
++ if (tmp)
++ tmp->inode = au_igrab(inode);
++ else {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ spin_lock(&sbinfo->si_plink.spin);
++ list_for_each_entry(plink, plink_list, list) {
++ if (plink->inode == inode) {
++ found = 1;
++ break;
++ }
++ }
++ if (!found)
++ list_add_rcu(&tmp->list, plink_list);
++ spin_unlock(&sbinfo->si_plink.spin);
++ if (!found) {
++ cnt++;
++ WARN_ONCE(cnt > AUFS_PLINK_WARN,
++ "unexpectedly many pseudo links, %d\n", cnt);
++ err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex));
++ } else {
++ do_put_plink(tmp, 0);
++ return;
++ }
++
++out:
++ if (unlikely(err)) {
++ pr_warning("err %d, damaged pseudo link.\n", err);
++ if (tmp) {
++ au_spl_del_rcu(&tmp->list, &sbinfo->si_plink);
++ call_rcu(&tmp->rcu, do_put_plink_rcu);
++ }
++ }
++}
++
++/* free all plinks */
++void au_plink_put(struct super_block *sb, int verbose)
++{
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink, *tmp;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
++
++ plink_list = &sbinfo->si_plink.head;
++ /* no spin_lock since sbinfo is write-locked */
++ WARN(verbose && !list_empty(plink_list), "pseudo-link is not flushed");
++ list_for_each_entry_safe(plink, tmp, plink_list, list)
++ do_put_plink(plink, 0);
++ INIT_LIST_HEAD(plink_list);
++}
++
++void au_plink_clean(struct super_block *sb, int verbose)
++{
++ struct dentry *root;
++
++ root = sb->s_root;
++ aufs_write_lock(root);
++ if (au_opt_test(au_mntflags(sb), PLINK))
++ au_plink_put(sb, verbose);
++ aufs_write_unlock(root);
++}
++
++/* free the plinks on a branch specified by @br_id */
++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id)
++{
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink, *tmp;
++ struct inode *inode;
++ aufs_bindex_t bstart, bend, bindex;
++ unsigned char do_put;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
++
++ plink_list = &sbinfo->si_plink.head;
++ /* no spin_lock since sbinfo is write-locked */
++ list_for_each_entry_safe(plink, tmp, plink_list, list) {
++ do_put = 0;
++ inode = au_igrab(plink->inode);
++ ii_write_lock_child(inode);
++ bstart = au_ibstart(inode);
++ bend = au_ibend(inode);
++ if (bstart >= 0) {
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ if (!au_h_iptr(inode, bindex)
++ || au_ii_br_id(inode, bindex) != br_id)
++ continue;
++ au_set_h_iptr(inode, bindex, NULL, 0);
++ do_put = 1;
++ break;
++ }
++ } else
++ do_put_plink(plink, 1);
++
++ if (do_put) {
++ for (bindex = bstart; bindex <= bend; bindex++)
++ if (au_h_iptr(inode, bindex)) {
++ do_put = 0;
++ break;
++ }
++ if (do_put)
++ do_put_plink(plink, 1);
++ }
++ ii_write_unlock(inode);
++ iput(inode);
++ }
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/poll.c linux-2.6.37/fs/aufs/poll.c
+--- linux-2.6.37.orig/fs/aufs/poll.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/poll.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,56 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * poll operation
++ * There is only one filesystem which implements ->poll operation, currently.
++ */
++
++#include "aufs.h"
++
++unsigned int aufs_poll(struct file *file, poll_table *wait)
++{
++ unsigned int mask;
++ int err;
++ struct file *h_file;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ /* We should pretend an error happened. */
++ mask = POLLERR /* | POLLIN | POLLOUT */;
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ /* it is not an error if h_file has no operation */
++ mask = DEFAULT_POLLMASK;
++ h_file = au_hf_top(file);
++ if (h_file->f_op && h_file->f_op->poll)
++ mask = h_file->f_op->poll(h_file, wait);
++
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++
++out:
++ si_read_unlock(sb);
++ AuTraceErr((int)mask);
++ return mask;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/procfs.c linux-2.6.37/fs/aufs/procfs.c
+--- linux-2.6.37.orig/fs/aufs/procfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/procfs.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,169 @@
++/*
++ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * procfs interfaces
++ */
++
++#include <linux/proc_fs.h>
++#include "aufs.h"
++
++static int au_procfs_plm_release(struct inode *inode, struct file *file)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = file->private_data;
++ if (sbinfo) {
++ au_plink_maint_leave(sbinfo);
++ kobject_put(&sbinfo->si_kobj);
++ }
++
++ return 0;
++}
++
++static void au_procfs_plm_write_clean(struct file *file)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = file->private_data;
++ if (sbinfo)
++ au_plink_clean(sbinfo->si_sb, /*verbose*/0);
++}
++
++static int au_procfs_plm_write_si(struct file *file, unsigned long id)
++{
++ int err;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++ err = -EBUSY;
++ if (unlikely(file->private_data))
++ goto out;
++
++ sb = NULL;
++ spin_lock(&au_sbilist.spin);
++ list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
++ if (id == sysaufs_si_id(sbinfo)) {
++ kobject_get(&sbinfo->si_kobj);
++ sb = sbinfo->si_sb;
++ break;
++ }
++ spin_unlock(&au_sbilist.spin);
++
++ err = -EINVAL;
++ if (unlikely(!sb))
++ goto out;
++
++ err = au_plink_maint_enter(sb);
++ if (!err)
++ /* keep kobject_get() */
++ file->private_data = sbinfo;
++ else
++ kobject_put(&sbinfo->si_kobj);
++out:
++ return err;
++}
++
++/*
++ * Accept a valid "si=xxxx" only.
++ * Once it is accepted successfully, accept "clean" too.
++ */
++static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf,
++ size_t count, loff_t *ppos)
++{
++ ssize_t err;
++ unsigned long id;
++ /* last newline is allowed */
++ char buf[3 + sizeof(unsigned long) * 2 + 1];
++
++ err = -EACCES;
++ if (unlikely(!capable(CAP_SYS_ADMIN)))
++ goto out;
++
++ err = -EINVAL;
++ if (unlikely(count > sizeof(buf)))
++ goto out;
++
++ err = copy_from_user(buf, ubuf, count);
++ if (unlikely(err)) {
++ err = -EFAULT;
++ goto out;
++ }
++ buf[count] = 0;
++
++ err = -EINVAL;
++ if (!strcmp("clean", buf)) {
++ au_procfs_plm_write_clean(file);
++ goto out_success;
++ } else if (unlikely(strncmp("si=", buf, 3)))
++ goto out;
++
++ err = strict_strtoul(buf + 3, 16, &id);
++ if (unlikely(err))
++ goto out;
++
++ err = au_procfs_plm_write_si(file, id);
++ if (unlikely(err))
++ goto out;
++
++out_success:
++ err = count; /* success */
++out:
++ return err;
++}
++
++static const struct file_operations au_procfs_plm_fop = {
++ .write = au_procfs_plm_write,
++ .release = au_procfs_plm_release,
++ .owner = THIS_MODULE
++};
++
++/* ---------------------------------------------------------------------- */
++
++static struct proc_dir_entry *au_procfs_dir;
++
++void au_procfs_fin(void)
++{
++ remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir);
++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL);
++}
++
++int __init au_procfs_init(void)
++{
++ int err;
++ struct proc_dir_entry *entry;
++
++ err = -ENOMEM;
++ au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL);
++ if (unlikely(!au_procfs_dir))
++ goto out;
++
++ entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | S_IWUSR,
++ au_procfs_dir, &au_procfs_plm_fop);
++ if (unlikely(!entry))
++ goto out_dir;
++
++ err = 0;
++ goto out; /* success */
++
++
++out_dir:
++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL);
++out:
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/rdu.c linux-2.6.37/fs/aufs/rdu.c
+--- linux-2.6.37.orig/fs/aufs/rdu.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/rdu.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,383 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * readdir in userspace.
++ */
++
++#include <linux/compat.h>
++#include <linux/fs_stack.h>
++#include <linux/security.h>
++#include <linux/uaccess.h>
++#include <linux/aufs_type.h>
++#include "aufs.h"
++
++/* bits for struct aufs_rdu.flags */
++#define AuRdu_CALLED 1
++#define AuRdu_CONT (1 << 1)
++#define AuRdu_FULL (1 << 2)
++#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name)
++#define au_fset_rdu(flags, name) \
++ do { (flags) |= AuRdu_##name; } while (0)
++#define au_fclr_rdu(flags, name) \
++ do { (flags) &= ~AuRdu_##name; } while (0)
++
++struct au_rdu_arg {
++ struct aufs_rdu *rdu;
++ union au_rdu_ent_ul ent;
++ unsigned long end;
++
++ struct super_block *sb;
++ int err;
++};
++
++static int au_rdu_fill(void *__arg, const char *name, int nlen,
++ loff_t offset, u64 h_ino, unsigned int d_type)
++{
++ int err, len;
++ struct au_rdu_arg *arg = __arg;
++ struct aufs_rdu *rdu = arg->rdu;
++ struct au_rdu_ent ent;
++
++ err = 0;
++ arg->err = 0;
++ au_fset_rdu(rdu->cookie.flags, CALLED);
++ len = au_rdu_len(nlen);
++ if (arg->ent.ul + len < arg->end) {
++ ent.ino = h_ino;
++ ent.bindex = rdu->cookie.bindex;
++ ent.type = d_type;
++ ent.nlen = nlen;
++ if (unlikely(nlen > AUFS_MAX_NAMELEN))
++ ent.type = DT_UNKNOWN;
++
++ err = -EFAULT;
++ if (copy_to_user(arg->ent.e, &ent, sizeof(ent)))
++ goto out;
++ if (copy_to_user(arg->ent.e->name, name, nlen))
++ goto out;
++ /* the terminating NULL */
++ if (__put_user(0, arg->ent.e->name + nlen))
++ goto out;
++ err = 0;
++ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */
++ arg->ent.ul += len;
++ rdu->rent++;
++ } else {
++ err = -EFAULT;
++ au_fset_rdu(rdu->cookie.flags, FULL);
++ rdu->full = 1;
++ rdu->tail = arg->ent;
++ }
++
++out:
++ /* AuTraceErr(err); */
++ return err;
++}
++
++static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg)
++{
++ int err;
++ loff_t offset;
++ struct au_rdu_cookie *cookie = &arg->rdu->cookie;
++
++ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET);
++ err = offset;
++ if (unlikely(offset != cookie->h_pos))
++ goto out;
++
++ err = 0;
++ do {
++ arg->err = 0;
++ au_fclr_rdu(cookie->flags, CALLED);
++ /* smp_mb(); */
++ err = vfsub_readdir(h_file, au_rdu_fill, arg);
++ if (err >= 0)
++ err = arg->err;
++ } while (!err
++ && au_ftest_rdu(cookie->flags, CALLED)
++ && !au_ftest_rdu(cookie->flags, FULL));
++ cookie->h_pos = h_file->f_pos;
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int au_rdu(struct file *file, struct aufs_rdu *rdu)
++{
++ int err;
++ aufs_bindex_t bend;
++ struct au_rdu_arg arg;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *h_file;
++ struct au_rdu_cookie *cookie = &rdu->cookie;
++
++ err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz);
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ goto out;
++ }
++ rdu->rent = 0;
++ rdu->tail = rdu->ent;
++ rdu->full = 0;
++ arg.rdu = rdu;
++ arg.ent = rdu->ent;
++ arg.end = arg.ent.ul;
++ arg.end += rdu->sz;
++
++ err = -ENOTDIR;
++ if (unlikely(!file->f_op || !file->f_op->readdir))
++ goto out;
++
++ err = security_file_permission(file, MAY_READ);
++ AuTraceErr(err);
++ if (unlikely(err))
++ goto out;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++#if 1
++ mutex_lock(&inode->i_mutex);
++#else
++ err = mutex_lock_killable(&inode->i_mutex);
++ AuTraceErr(err);
++ if (unlikely(err))
++ goto out;
++#endif
++
++ arg.sb = inode->i_sb;
++ err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out_mtx;
++ err = au_alive_dir(dentry);
++ if (unlikely(err))
++ goto out_si;
++ /* todo: reval? */
++ fi_read_lock(file);
++
++ err = -EAGAIN;
++ if (unlikely(au_ftest_rdu(cookie->flags, CONT)
++ && cookie->generation != au_figen(file)))
++ goto out_unlock;
++
++ err = 0;
++ if (!rdu->blk) {
++ rdu->blk = au_sbi(arg.sb)->si_rdblk;
++ if (!rdu->blk)
++ rdu->blk = au_dir_size(file, /*dentry*/NULL);
++ }
++ bend = au_fbstart(file);
++ if (cookie->bindex < bend)
++ cookie->bindex = bend;
++ bend = au_fbend_dir(file);
++ /* AuDbg("b%d, b%d\n", cookie->bindex, bend); */
++ for (; !err && cookie->bindex <= bend;
++ cookie->bindex++, cookie->h_pos = 0) {
++ h_file = au_hf_dir(file, cookie->bindex);
++ if (!h_file)
++ continue;
++
++ au_fclr_rdu(cookie->flags, FULL);
++ err = au_rdu_do(h_file, &arg);
++ AuTraceErr(err);
++ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err))
++ break;
++ }
++ AuDbg("rent %llu\n", rdu->rent);
++
++ if (!err && !au_ftest_rdu(cookie->flags, CONT)) {
++ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH);
++ au_fset_rdu(cookie->flags, CONT);
++ cookie->generation = au_figen(file);
++ }
++
++ ii_read_lock_child(inode);
++ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode)));
++ ii_read_unlock(inode);
++
++out_unlock:
++ fi_read_unlock(file);
++out_si:
++ si_read_unlock(arg.sb);
++out_mtx:
++ mutex_unlock(&inode->i_mutex);
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu)
++{
++ int err;
++ ino_t ino;
++ unsigned long long nent;
++ union au_rdu_ent_ul *u;
++ struct au_rdu_ent ent;
++ struct super_block *sb;
++
++ err = 0;
++ nent = rdu->nent;
++ u = &rdu->ent;
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ while (nent-- > 0) {
++ err = copy_from_user(&ent, u->e, sizeof(ent));
++ if (!err)
++ err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino));
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ break;
++ }
++
++ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */
++ if (!ent.wh)
++ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino);
++ else
++ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type,
++ &ino);
++ if (unlikely(err)) {
++ AuTraceErr(err);
++ break;
++ }
++
++ err = __put_user(ino, &u->e->ino);
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ break;
++ }
++ u->ul += au_rdu_len(ent.nlen);
++ }
++ si_read_unlock(sb);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_rdu_verify(struct aufs_rdu *rdu)
++{
++ AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | "
++ "%llu, b%d, 0x%x, g%u}\n",
++ rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ],
++ rdu->blk,
++ rdu->rent, rdu->shwh, rdu->full,
++ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags,
++ rdu->cookie.generation);
++
++ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu))
++ return 0;
++
++ AuDbg("%u:%u\n",
++ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu));
++ return -EINVAL;
++}
++
++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err, e;
++ struct aufs_rdu rdu;
++ void __user *p = (void __user *)arg;
++
++ err = copy_from_user(&rdu, p, sizeof(rdu));
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ goto out;
++ }
++ err = au_rdu_verify(&rdu);
++ if (unlikely(err))
++ goto out;
++
++ switch (cmd) {
++ case AUFS_CTL_RDU:
++ err = au_rdu(file, &rdu);
++ if (unlikely(err))
++ break;
++
++ e = copy_to_user(p, &rdu, sizeof(rdu));
++ if (unlikely(e)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ }
++ break;
++ case AUFS_CTL_RDU_INO:
++ err = au_rdu_ino(file, &rdu);
++ break;
++
++ default:
++ /* err = -ENOTTY; */
++ err = -EINVAL;
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++#ifdef CONFIG_COMPAT
++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err, e;
++ struct aufs_rdu rdu;
++ void __user *p = compat_ptr(arg);
++
++ /* todo: get_user()? */
++ err = copy_from_user(&rdu, p, sizeof(rdu));
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ goto out;
++ }
++ rdu.ent.e = compat_ptr(rdu.ent.ul);
++ err = au_rdu_verify(&rdu);
++ if (unlikely(err))
++ goto out;
++
++ switch (cmd) {
++ case AUFS_CTL_RDU:
++ err = au_rdu(file, &rdu);
++ if (unlikely(err))
++ break;
++
++ rdu.ent.ul = ptr_to_compat(rdu.ent.e);
++ rdu.tail.ul = ptr_to_compat(rdu.tail.e);
++ e = copy_to_user(p, &rdu, sizeof(rdu));
++ if (unlikely(e)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ }
++ break;
++ case AUFS_CTL_RDU_INO:
++ err = au_rdu_ino(file, &rdu);
++ break;
++
++ default:
++ /* err = -ENOTTY; */
++ err = -EINVAL;
++ }
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++#endif
+diff -Nur linux-2.6.37.orig/fs/aufs/rwsem.h linux-2.6.37/fs/aufs/rwsem.h
+--- linux-2.6.37.orig/fs/aufs/rwsem.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/rwsem.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,189 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * simple read-write semaphore wrappers
++ */
++
++#ifndef __AUFS_RWSEM_H__
++#define __AUFS_RWSEM_H__
++
++#ifdef __KERNEL__
++
++#include <linux/rwsem.h>
++#include "debug.h"
++
++struct au_rwsem {
++ struct rw_semaphore rwsem;
++#ifdef CONFIG_AUFS_DEBUG
++ /* just for debugging, not almighty counter */
++ atomic_t rcnt, wcnt;
++#endif
++};
++
++#ifdef CONFIG_AUFS_DEBUG
++#define AuDbgCntInit(rw) do { \
++ atomic_set(&(rw)->rcnt, 0); \
++ atomic_set(&(rw)->wcnt, 0); \
++ smp_mb(); /* atomic set */ \
++} while (0)
++
++#define AuDbgRcntInc(rw) atomic_inc(&(rw)->rcnt)
++#define AuDbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0)
++#define AuDbgWcntInc(rw) atomic_inc(&(rw)->wcnt)
++#define AuDbgWcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->wcnt) < 0)
++#else
++#define AuDbgCntInit(rw) do {} while (0)
++#define AuDbgRcntInc(rw) do {} while (0)
++#define AuDbgRcntDec(rw) do {} while (0)
++#define AuDbgWcntInc(rw) do {} while (0)
++#define AuDbgWcntDec(rw) do {} while (0)
++#endif /* CONFIG_AUFS_DEBUG */
++
++/* to debug easier, do not make them inlined functions */
++#define AuRwMustNoWaiters(rw) AuDebugOn(!list_empty(&(rw)->rwsem.wait_list))
++/* rwsem_is_locked() is unusable */
++#define AuRwMustReadLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0)
++#define AuRwMustWriteLock(rw) AuDebugOn(atomic_read(&(rw)->wcnt) <= 0)
++#define AuRwMustAnyLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0 \
++ && atomic_read(&(rw)->wcnt) <= 0)
++#define AuRwDestroy(rw) AuDebugOn(atomic_read(&(rw)->rcnt) \
++ || atomic_read(&(rw)->wcnt))
++
++#define au_rw_class(rw, key) lockdep_set_class(&(rw)->rwsem, key)
++
++static inline void au_rw_init(struct au_rwsem *rw)
++{
++ AuDbgCntInit(rw);
++ init_rwsem(&rw->rwsem);
++}
++
++static inline void au_rw_init_wlock(struct au_rwsem *rw)
++{
++ au_rw_init(rw);
++ down_write(&rw->rwsem);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_init_wlock_nested(struct au_rwsem *rw,
++ unsigned int lsc)
++{
++ au_rw_init(rw);
++ down_write_nested(&rw->rwsem, lsc);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_read_lock(struct au_rwsem *rw)
++{
++ down_read(&rw->rwsem);
++ AuDbgRcntInc(rw);
++}
++
++static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc)
++{
++ down_read_nested(&rw->rwsem, lsc);
++ AuDbgRcntInc(rw);
++}
++
++static inline void au_rw_read_unlock(struct au_rwsem *rw)
++{
++ AuRwMustReadLock(rw);
++ AuDbgRcntDec(rw);
++ up_read(&rw->rwsem);
++}
++
++static inline void au_rw_dgrade_lock(struct au_rwsem *rw)
++{
++ AuRwMustWriteLock(rw);
++ AuDbgRcntInc(rw);
++ AuDbgWcntDec(rw);
++ downgrade_write(&rw->rwsem);
++}
++
++static inline void au_rw_write_lock(struct au_rwsem *rw)
++{
++ down_write(&rw->rwsem);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_write_lock_nested(struct au_rwsem *rw,
++ unsigned int lsc)
++{
++ down_write_nested(&rw->rwsem, lsc);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_write_unlock(struct au_rwsem *rw)
++{
++ AuRwMustWriteLock(rw);
++ AuDbgWcntDec(rw);
++ up_write(&rw->rwsem);
++}
++
++/* why is not _nested version defined */
++static inline int au_rw_read_trylock(struct au_rwsem *rw)
++{
++ int ret = down_read_trylock(&rw->rwsem);
++ if (ret)
++ AuDbgRcntInc(rw);
++ return ret;
++}
++
++static inline int au_rw_write_trylock(struct au_rwsem *rw)
++{
++ int ret = down_write_trylock(&rw->rwsem);
++ if (ret)
++ AuDbgWcntInc(rw);
++ return ret;
++}
++
++#undef AuDbgCntInit
++#undef AuDbgRcntInc
++#undef AuDbgRcntDec
++#undef AuDbgWcntInc
++#undef AuDbgWcntDec
++
++#define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \
++static inline void prefix##_read_lock(param) \
++{ au_rw_read_lock(rwsem); } \
++static inline void prefix##_write_lock(param) \
++{ au_rw_write_lock(rwsem); } \
++static inline int prefix##_read_trylock(param) \
++{ return au_rw_read_trylock(rwsem); } \
++static inline int prefix##_write_trylock(param) \
++{ return au_rw_write_trylock(rwsem); }
++/* why is not _nested version defined */
++/* static inline void prefix##_read_trylock_nested(param, lsc)
++{ au_rw_read_trylock_nested(rwsem, lsc)); }
++static inline void prefix##_write_trylock_nestd(param, lsc)
++{ au_rw_write_trylock_nested(rwsem, lsc); } */
++
++#define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \
++static inline void prefix##_read_unlock(param) \
++{ au_rw_read_unlock(rwsem); } \
++static inline void prefix##_write_unlock(param) \
++{ au_rw_write_unlock(rwsem); } \
++static inline void prefix##_downgrade_lock(param) \
++{ au_rw_dgrade_lock(rwsem); }
++
++#define AuSimpleRwsemFuncs(prefix, param, rwsem) \
++ AuSimpleLockRwsemFuncs(prefix, param, rwsem) \
++ AuSimpleUnlockRwsemFuncs(prefix, param, rwsem)
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_RWSEM_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/sbinfo.c linux-2.6.37/fs/aufs/sbinfo.c
+--- linux-2.6.37.orig/fs/aufs/sbinfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/sbinfo.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,345 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * superblock private data
++ */
++
++#include <linux/jiffies.h>
++#include "aufs.h"
++
++/*
++ * they are necessary regardless sysfs is disabled.
++ */
++void au_si_free(struct kobject *kobj)
++{
++ struct au_sbinfo *sbinfo;
++ char *locked __maybe_unused; /* debug only */
++
++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
++ AuDebugOn(!list_empty(&sbinfo->si_plink.head));
++ AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len));
++
++ au_rw_write_lock(&sbinfo->si_rwsem);
++ au_br_free(sbinfo);
++ au_rw_write_unlock(&sbinfo->si_rwsem);
++
++ AuDebugOn(radix_tree_gang_lookup
++ (&sbinfo->au_si_pid.tree, (void **)&locked,
++ /*first_index*/PID_MAX_DEFAULT - 1,
++ /*max_items*/sizeof(locked)/sizeof(*locked)));
++
++ kfree(sbinfo->si_branch);
++ kfree(sbinfo->au_si_pid.bitmap);
++ mutex_destroy(&sbinfo->si_xib_mtx);
++ AuRwDestroy(&sbinfo->si_rwsem);
++
++ kfree(sbinfo);
++}
++
++int au_si_alloc(struct super_block *sb)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ static struct lock_class_key aufs_si;
++
++ err = -ENOMEM;
++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS);
++ if (unlikely(!sbinfo))
++ goto out;
++
++ BUILD_BUG_ON(sizeof(unsigned long) !=
++ sizeof(*sbinfo->au_si_pid.bitmap));
++ sbinfo->au_si_pid.bitmap = kcalloc(BITS_TO_LONGS(PID_MAX_DEFAULT),
++ sizeof(*sbinfo->au_si_pid.bitmap),
++ GFP_NOFS);
++ if (unlikely(!sbinfo->au_si_pid.bitmap))
++ goto out_sbinfo;
++
++ /* will be reallocated separately */
++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS);
++ if (unlikely(!sbinfo->si_branch))
++ goto out_pidmap;
++
++ err = sysaufs_si_init(sbinfo);
++ if (unlikely(err))
++ goto out_br;
++
++ au_nwt_init(&sbinfo->si_nowait);
++ au_rw_init_wlock(&sbinfo->si_rwsem);
++ au_rw_class(&sbinfo->si_rwsem, &aufs_si);
++ spin_lock_init(&sbinfo->au_si_pid.tree_lock);
++ INIT_RADIX_TREE(&sbinfo->au_si_pid.tree, GFP_ATOMIC | __GFP_NOFAIL);
++
++ atomic_long_set(&sbinfo->si_ninodes, 0);
++ atomic_long_set(&sbinfo->si_nfiles, 0);
++
++ sbinfo->si_bend = -1;
++
++ sbinfo->si_wbr_copyup = AuWbrCopyup_Def;
++ sbinfo->si_wbr_create = AuWbrCreate_Def;
++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup;
++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create;
++
++ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def);
++
++ mutex_init(&sbinfo->si_xib_mtx);
++ sbinfo->si_xino_brid = -1;
++ /* leave si_xib_last_pindex and si_xib_next_bit */
++
++ sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC);
++ sbinfo->si_rdblk = AUFS_RDBLK_DEF;
++ sbinfo->si_rdhash = AUFS_RDHASH_DEF;
++ sbinfo->si_dirwh = AUFS_DIRWH_DEF;
++
++ au_spl_init(&sbinfo->si_plink);
++ init_waitqueue_head(&sbinfo->si_plink_wq);
++ spin_lock_init(&sbinfo->si_plink_maint_lock);
++
++ /* leave other members for sysaufs and si_mnt. */
++ sbinfo->si_sb = sb;
++ sb->s_fs_info = sbinfo;
++ si_pid_set(sb);
++ au_debug_sbinfo_init(sbinfo);
++ return 0; /* success */
++
++out_br:
++ kfree(sbinfo->si_branch);
++out_pidmap:
++ kfree(sbinfo->au_si_pid.bitmap);
++out_sbinfo:
++ kfree(sbinfo);
++out:
++ return err;
++}
++
++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr)
++{
++ int err, sz;
++ struct au_branch **brp;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ err = -ENOMEM;
++ sz = sizeof(*brp) * (sbinfo->si_bend + 1);
++ if (unlikely(!sz))
++ sz = sizeof(*brp);
++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS);
++ if (brp) {
++ sbinfo->si_branch = brp;
++ err = 0;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++unsigned int au_sigen_inc(struct super_block *sb)
++{
++ unsigned int gen;
++
++ SiMustWriteLock(sb);
++
++ gen = ++au_sbi(sb)->si_generation;
++ au_update_digen(sb->s_root);
++ au_update_iigen(sb->s_root->d_inode);
++ sb->s_root->d_inode->i_version++;
++ return gen;
++}
++
++aufs_bindex_t au_new_br_id(struct super_block *sb)
++{
++ aufs_bindex_t br_id;
++ int i;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ for (i = 0; i <= AUFS_BRANCH_MAX; i++) {
++ br_id = ++sbinfo->si_last_br_id;
++ AuDebugOn(br_id < 0);
++ if (br_id && au_br_index(sb, br_id) < 0)
++ return br_id;
++ }
++
++ return -1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* it is ok that new 'nwt' tasks are appended while we are sleeping */
++int si_read_lock(struct super_block *sb, int flags)
++{
++ int err;
++
++ err = 0;
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++
++ si_noflush_read_lock(sb);
++ err = au_plink_maint(sb, flags);
++ if (unlikely(err))
++ si_read_unlock(sb);
++
++ return err;
++}
++
++int si_write_lock(struct super_block *sb, int flags)
++{
++ int err;
++
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++
++ si_noflush_write_lock(sb);
++ err = au_plink_maint(sb, flags);
++ if (unlikely(err))
++ si_write_unlock(sb);
++
++ return err;
++}
++
++/* dentry and super_block lock. call at entry point */
++int aufs_read_lock(struct dentry *dentry, int flags)
++{
++ int err;
++ struct super_block *sb;
++
++ sb = dentry->d_sb;
++ err = si_read_lock(sb, flags);
++ if (unlikely(err))
++ goto out;
++
++ if (au_ftest_lock(flags, DW))
++ di_write_lock_child(dentry);
++ else
++ di_read_lock_child(dentry, flags);
++
++ if (au_ftest_lock(flags, GEN)) {
++ err = au_digen_test(dentry, au_sigen(sb));
++ AuDebugOn(!err && au_dbrange_test(dentry));
++ if (unlikely(err))
++ aufs_read_unlock(dentry, flags);
++ }
++
++out:
++ return err;
++}
++
++void aufs_read_unlock(struct dentry *dentry, int flags)
++{
++ if (au_ftest_lock(flags, DW))
++ di_write_unlock(dentry);
++ else
++ di_read_unlock(dentry, flags);
++ si_read_unlock(dentry->d_sb);
++}
++
++void aufs_write_lock(struct dentry *dentry)
++{
++ si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW);
++ di_write_lock_child(dentry);
++}
++
++void aufs_write_unlock(struct dentry *dentry)
++{
++ di_write_unlock(dentry);
++ si_write_unlock(dentry->d_sb);
++}
++
++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags)
++{
++ int err;
++ unsigned int sigen;
++ struct super_block *sb;
++
++ sb = d1->d_sb;
++ err = si_read_lock(sb, flags);
++ if (unlikely(err))
++ goto out;
++
++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR));
++
++ if (au_ftest_lock(flags, GEN)) {
++ sigen = au_sigen(sb);
++ err = au_digen_test(d1, sigen);
++ AuDebugOn(!err && au_dbrange_test(d1));
++ if (!err) {
++ err = au_digen_test(d2, sigen);
++ AuDebugOn(!err && au_dbrange_test(d2));
++ }
++ if (unlikely(err))
++ aufs_read_and_write_unlock2(d1, d2);
++ }
++
++out:
++ return err;
++}
++
++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2)
++{
++ di_write_unlock2(d1, d2);
++ si_read_unlock(d1->d_sb);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int si_pid_test_slow(struct super_block *sb)
++{
++ void *p;
++
++ rcu_read_lock();
++ p = radix_tree_lookup(&au_sbi(sb)->au_si_pid.tree, current->pid);
++ rcu_read_unlock();
++
++ return (long)p;
++}
++
++void si_pid_set_slow(struct super_block *sb)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++
++ AuDebugOn(si_pid_test_slow(sb));
++
++ sbinfo = au_sbi(sb);
++ err = radix_tree_preload(GFP_NOFS | __GFP_NOFAIL);
++ AuDebugOn(err);
++ spin_lock(&sbinfo->au_si_pid.tree_lock);
++ err = radix_tree_insert(&sbinfo->au_si_pid.tree, current->pid,
++ (void *)1);
++ spin_unlock(&sbinfo->au_si_pid.tree_lock);
++ AuDebugOn(err);
++ radix_tree_preload_end();
++}
++
++void si_pid_clr_slow(struct super_block *sb)
++{
++ void *p;
++ struct au_sbinfo *sbinfo;
++
++ AuDebugOn(!si_pid_test_slow(sb));
++
++ sbinfo = au_sbi(sb);
++ spin_lock(&sbinfo->au_si_pid.tree_lock);
++ p = radix_tree_delete(&sbinfo->au_si_pid.tree, current->pid);
++ spin_unlock(&sbinfo->au_si_pid.tree_lock);
++ AuDebugOn(1 != (long)p);
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/spl.h linux-2.6.37/fs/aufs/spl.h
+--- linux-2.6.37.orig/fs/aufs/spl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/spl.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,66 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * simple list protected by a spinlock
++ */
++
++#ifndef __AUFS_SPL_H__
++#define __AUFS_SPL_H__
++
++#ifdef __KERNEL__
++
++#include <linux/spinlock.h>
++#include <linux/list.h>
++#include <linux/rculist.h>
++
++struct au_splhead {
++ spinlock_t spin;
++ struct list_head head;
++};
++
++static inline void au_spl_init(struct au_splhead *spl)
++{
++ spin_lock_init(&spl->spin);
++ INIT_LIST_HEAD(&spl->head);
++}
++
++static inline void au_spl_add(struct list_head *list, struct au_splhead *spl)
++{
++ spin_lock(&spl->spin);
++ list_add(list, &spl->head);
++ spin_unlock(&spl->spin);
++}
++
++static inline void au_spl_del(struct list_head *list, struct au_splhead *spl)
++{
++ spin_lock(&spl->spin);
++ list_del(list);
++ spin_unlock(&spl->spin);
++}
++
++static inline void au_spl_del_rcu(struct list_head *list,
++ struct au_splhead *spl)
++{
++ spin_lock(&spl->spin);
++ list_del_rcu(list);
++ spin_unlock(&spl->spin);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_SPL_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/super.c linux-2.6.37/fs/aufs/super.c
+--- linux-2.6.37.orig/fs/aufs/super.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/super.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,913 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * mount and super_block operations
++ */
++
++#include <linux/buffer_head.h>
++#include <linux/jiffies.h>
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include <linux/statfs.h>
++#include <linux/vmalloc.h>
++#include <linux/writeback.h>
++#include "aufs.h"
++
++/*
++ * super_operations
++ */
++static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused)
++{
++ struct au_icntnr *c;
++
++ c = au_cache_alloc_icntnr();
++ if (c) {
++ au_icntnr_init(c);
++ c->vfs_inode.i_version = 1; /* sigen(sb); */
++ c->iinfo.ii_hinode = NULL;
++ return &c->vfs_inode;
++ }
++ return NULL;
++}
++
++static void aufs_destroy_inode(struct inode *inode)
++{
++ au_iinfo_fin(inode);
++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode));
++}
++
++struct inode *au_iget_locked(struct super_block *sb, ino_t ino)
++{
++ struct inode *inode;
++ int err;
++
++ inode = iget_locked(sb, ino);
++ if (unlikely(!inode)) {
++ inode = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++ if (!(inode->i_state & I_NEW))
++ goto out;
++
++ err = au_xigen_new(inode);
++ if (!err)
++ err = au_iinfo_init(inode);
++ if (!err)
++ inode->i_version++;
++ else {
++ iget_failed(inode);
++ inode = ERR_PTR(err);
++ }
++
++out:
++ /* never return NULL */
++ AuDebugOn(!inode);
++ AuTraceErrPtr(inode);
++ return inode;
++}
++
++/* lock free root dinfo */
++static int au_show_brs(struct seq_file *seq, struct super_block *sb)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct path path;
++ struct au_hdentry *hdp;
++ struct au_branch *br;
++
++ err = 0;
++ bend = au_sbend(sb);
++ hdp = au_di(sb->s_root)->di_hdentry;
++ for (bindex = 0; !err && bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ path.mnt = br->br_mnt;
++ path.dentry = hdp[bindex].hd_dentry;
++ err = au_seq_path(seq, &path);
++ if (err > 0)
++ err = seq_printf(seq, "=%s",
++ au_optstr_br_perm(br->br_perm));
++ if (!err && bindex != bend)
++ err = seq_putc(seq, ':');
++ }
++
++ return err;
++}
++
++static void au_show_wbr_create(struct seq_file *m, int v,
++ struct au_sbinfo *sbinfo)
++{
++ const char *pat;
++
++ AuRwMustAnyLock(&sbinfo->si_rwsem);
++
++ seq_printf(m, ",create=");
++ pat = au_optstr_wbr_create(v);
++ switch (v) {
++ case AuWbrCreate_TDP:
++ case AuWbrCreate_RR:
++ case AuWbrCreate_MFS:
++ case AuWbrCreate_PMFS:
++ seq_printf(m, pat);
++ break;
++ case AuWbrCreate_MFSV:
++ seq_printf(m, /*pat*/"mfs:%lu",
++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
++ / MSEC_PER_SEC);
++ break;
++ case AuWbrCreate_PMFSV:
++ seq_printf(m, /*pat*/"pmfs:%lu",
++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
++ / MSEC_PER_SEC);
++ break;
++ case AuWbrCreate_MFSRR:
++ seq_printf(m, /*pat*/"mfsrr:%llu",
++ sbinfo->si_wbr_mfs.mfsrr_watermark);
++ break;
++ case AuWbrCreate_MFSRRV:
++ seq_printf(m, /*pat*/"mfsrr:%llu:%lu",
++ sbinfo->si_wbr_mfs.mfsrr_watermark,
++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
++ / MSEC_PER_SEC);
++ break;
++ }
++}
++
++static int au_show_xino(struct seq_file *seq, struct vfsmount *mnt)
++{
++#ifdef CONFIG_SYSFS
++ return 0;
++#else
++ int err;
++ const int len = sizeof(AUFS_XINO_FNAME) - 1;
++ aufs_bindex_t bindex, brid;
++ struct super_block *sb;
++ struct qstr *name;
++ struct file *f;
++ struct dentry *d, *h_root;
++ struct au_hdentry *hdp;
++
++ AuRwMustAnyLock(&sbinfo->si_rwsem);
++
++ err = 0;
++ sb = mnt->mnt_sb;
++ f = au_sbi(sb)->si_xib;
++ if (!f)
++ goto out;
++
++ /* stop printing the default xino path on the first writable branch */
++ h_root = NULL;
++ brid = au_xino_brid(sb);
++ if (brid >= 0) {
++ bindex = au_br_index(sb, brid);
++ hdp = au_di(sb->s_root)->di_hdentry;
++ h_root = hdp[0 + bindex].hd_dentry;
++ }
++ d = f->f_dentry;
++ name = &d->d_name;
++ /* safe ->d_parent because the file is unlinked */
++ if (d->d_parent == h_root
++ && name->len == len
++ && !memcmp(name->name, AUFS_XINO_FNAME, len))
++ goto out;
++
++ seq_puts(seq, ",xino=");
++ err = au_xino_path(seq, f);
++
++out:
++ return err;
++#endif
++}
++
++/* seq_file will re-call me in case of too long string */
++static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt)
++{
++ int err;
++ unsigned int mnt_flags, v;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++#define AuBool(name, str) do { \
++ v = au_opt_test(mnt_flags, name); \
++ if (v != au_opt_test(AuOpt_Def, name)) \
++ seq_printf(m, ",%s" #str, v ? "" : "no"); \
++} while (0)
++
++#define AuStr(name, str) do { \
++ v = mnt_flags & AuOptMask_##name; \
++ if (v != (AuOpt_Def & AuOptMask_##name)) \
++ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \
++} while (0)
++
++#define AuUInt(name, str, val) do { \
++ if (val != AUFS_##name##_DEF) \
++ seq_printf(m, "," #str "=%u", val); \
++} while (0)
++
++ /* lock free root dinfo */
++ sb = mnt->mnt_sb;
++ si_noflush_read_lock(sb);
++ sbinfo = au_sbi(sb);
++ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo));
++
++ mnt_flags = au_mntflags(sb);
++ if (au_opt_test(mnt_flags, XINO)) {
++ err = au_show_xino(m, mnt);
++ if (unlikely(err))
++ goto out;
++ } else
++ seq_puts(m, ",noxino");
++
++ AuBool(TRUNC_XINO, trunc_xino);
++ AuStr(UDBA, udba);
++ AuBool(SHWH, shwh);
++ AuBool(PLINK, plink);
++ AuBool(DIO, dio);
++ /* AuBool(DIRPERM1, dirperm1); */
++ /* AuBool(REFROF, refrof); */
++
++ v = sbinfo->si_wbr_create;
++ if (v != AuWbrCreate_Def)
++ au_show_wbr_create(m, v, sbinfo);
++
++ v = sbinfo->si_wbr_copyup;
++ if (v != AuWbrCopyup_Def)
++ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v));
++
++ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ);
++ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ))
++ seq_printf(m, ",diropq=%c", v ? 'a' : 'w');
++
++ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh);
++
++ v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC;
++ AuUInt(RDCACHE, rdcache, v);
++
++ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk);
++ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash);
++
++ AuBool(SUM, sum);
++ /* AuBool(SUM_W, wsum); */
++ AuBool(WARN_PERM, warn_perm);
++ AuBool(VERBOSE, verbose);
++
++out:
++ /* be sure to print "br:" last */
++ if (!sysaufs_brs) {
++ seq_puts(m, ",br:");
++ au_show_brs(m, sb);
++ }
++ si_read_unlock(sb);
++ return 0;
++
++#undef AuBool
++#undef AuStr
++#undef AuUInt
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* sum mode which returns the summation for statfs(2) */
++
++static u64 au_add_till_max(u64 a, u64 b)
++{
++ u64 old;
++
++ old = a;
++ a += b;
++ if (old < a)
++ return a;
++ return ULLONG_MAX;
++}
++
++static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf)
++{
++ int err;
++ u64 blocks, bfree, bavail, files, ffree;
++ aufs_bindex_t bend, bindex, i;
++ unsigned char shared;
++ struct path h_path;
++ struct super_block *h_sb;
++
++ blocks = 0;
++ bfree = 0;
++ bavail = 0;
++ files = 0;
++ ffree = 0;
++
++ err = 0;
++ bend = au_sbend(sb);
++ for (bindex = bend; bindex >= 0; bindex--) {
++ h_path.mnt = au_sbr_mnt(sb, bindex);
++ h_sb = h_path.mnt->mnt_sb;
++ shared = 0;
++ for (i = bindex + 1; !shared && i <= bend; i++)
++ shared = (au_sbr_sb(sb, i) == h_sb);
++ if (shared)
++ continue;
++
++ /* sb->s_root for NFS is unreliable */
++ h_path.dentry = h_path.mnt->mnt_root;
++ err = vfs_statfs(&h_path, buf);
++ if (unlikely(err))
++ goto out;
++
++ blocks = au_add_till_max(blocks, buf->f_blocks);
++ bfree = au_add_till_max(bfree, buf->f_bfree);
++ bavail = au_add_till_max(bavail, buf->f_bavail);
++ files = au_add_till_max(files, buf->f_files);
++ ffree = au_add_till_max(ffree, buf->f_ffree);
++ }
++
++ buf->f_blocks = blocks;
++ buf->f_bfree = bfree;
++ buf->f_bavail = bavail;
++ buf->f_files = files;
++ buf->f_ffree = ffree;
++
++out:
++ return err;
++}
++
++static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ int err;
++ struct path h_path;
++ struct super_block *sb;
++
++ /* lock free root dinfo */
++ sb = dentry->d_sb;
++ si_noflush_read_lock(sb);
++ if (!au_opt_test(au_mntflags(sb), SUM)) {
++ /* sb->s_root for NFS is unreliable */
++ h_path.mnt = au_sbr_mnt(sb, 0);
++ h_path.dentry = h_path.mnt->mnt_root;
++ err = vfs_statfs(&h_path, buf);
++ } else
++ err = au_statfs_sum(sb, buf);
++ si_read_unlock(sb);
++
++ if (!err) {
++ buf->f_type = AUFS_SUPER_MAGIC;
++ buf->f_namelen = AUFS_MAX_NAMELEN;
++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid));
++ }
++ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* final actions when unmounting a file system */
++static void aufs_put_super(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = au_sbi(sb);
++ if (!sbinfo)
++ return;
++
++ dbgaufs_si_fin(sbinfo);
++ kobject_put(&sbinfo->si_kobj);
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_array_free(void *array)
++{
++ if (array) {
++ if (!is_vmalloc_addr(array))
++ kfree(array);
++ else
++ vfree(array);
++ }
++}
++
++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg)
++{
++ void *array;
++ unsigned long long n;
++
++ array = NULL;
++ n = 0;
++ if (!*hint)
++ goto out;
++
++ if (*hint > ULLONG_MAX / sizeof(array)) {
++ array = ERR_PTR(-EMFILE);
++ pr_err("hint %llu\n", *hint);
++ goto out;
++ }
++
++ array = kmalloc(sizeof(array) * *hint, GFP_NOFS);
++ if (unlikely(!array))
++ array = vmalloc(sizeof(array) * *hint);
++ if (unlikely(!array)) {
++ array = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++
++ n = cb(array, *hint, arg);
++ AuDebugOn(n > *hint);
++
++out:
++ *hint = n;
++ return array;
++}
++
++static unsigned long long au_iarray_cb(void *a,
++ unsigned long long max __maybe_unused,
++ void *arg)
++{
++ unsigned long long n;
++ struct inode **p, *inode;
++ struct list_head *head;
++
++ n = 0;
++ p = a;
++ head = arg;
++ spin_lock(&inode_lock);
++ list_for_each_entry(inode, head, i_sb_list) {
++ if (!is_bad_inode(inode)
++ && au_ii(inode)->ii_bstart >= 0) {
++ au_igrab(inode);
++ *p++ = inode;
++ n++;
++ AuDebugOn(n > max);
++ }
++ }
++ spin_unlock(&inode_lock);
++
++ return n;
++}
++
++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max)
++{
++ *max = atomic_long_read(&au_sbi(sb)->si_ninodes);
++ return au_array_alloc(max, au_iarray_cb, &sb->s_inodes);
++}
++
++void au_iarray_free(struct inode **a, unsigned long long max)
++{
++ unsigned long long ull;
++
++ for (ull = 0; ull < max; ull++)
++ iput(a[ull]);
++ au_array_free(a);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * refresh dentry and inode at remount time.
++ */
++/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */
++static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags,
++ struct dentry *parent)
++{
++ int err;
++
++ di_write_lock_child(dentry);
++ di_read_lock_parent(parent, AuLock_IR);
++ err = au_refresh_dentry(dentry, parent);
++ if (!err && dir_flags)
++ au_hn_reset(dentry->d_inode, dir_flags);
++ di_read_unlock(parent, AuLock_IR);
++ di_write_unlock(dentry);
++
++ return err;
++}
++
++static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen,
++ struct au_sbinfo *sbinfo,
++ const unsigned int dir_flags)
++{
++ int err;
++ struct dentry *parent;
++ struct inode *inode;
++
++ err = 0;
++ parent = dget_parent(dentry);
++ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) {
++ inode = dentry->d_inode;
++ if (inode) {
++ if (!S_ISDIR(inode->i_mode))
++ err = au_do_refresh(dentry, /*dir_flags*/0,
++ parent);
++ else {
++ err = au_do_refresh(dentry, dir_flags, parent);
++ if (unlikely(err))
++ au_fset_si(sbinfo, FAILED_REFRESH_DIR);
++ }
++ } else
++ err = au_do_refresh(dentry, /*dir_flags*/0, parent);
++ AuDbgDentry(dentry);
++ }
++ dput(parent);
++
++ AuTraceErr(err);
++ return err;
++}
++
++static int au_refresh_d(struct super_block *sb)
++{
++ int err, i, j, ndentry, e;
++ unsigned int sigen;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries, *d;
++ struct au_sbinfo *sbinfo;
++ struct dentry *root = sb->s_root;
++ const unsigned int dir_flags = au_hi_flags(root->d_inode, /*isdir*/1);
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_dcsub_pages(&dpages, root, NULL, NULL);
++ if (unlikely(err))
++ goto out_dpages;
++
++ sigen = au_sigen(sb);
++ sbinfo = au_sbi(sb);
++ for (i = 0; i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ ndentry = dpage->ndentry;
++ for (j = 0; j < ndentry; j++) {
++ d = dentries[j];
++ e = au_do_refresh_d(d, sigen, sbinfo, dir_flags);
++ if (unlikely(e && !err))
++ err = e;
++ /* go on even err */
++ }
++ }
++
++out_dpages:
++ au_dpages_free(&dpages);
++out:
++ return err;
++}
++
++static int au_refresh_i(struct super_block *sb)
++{
++ int err, e;
++ unsigned int sigen;
++ unsigned long long max, ull;
++ struct inode *inode, **array;
++
++ array = au_iarray_alloc(sb, &max);
++ err = PTR_ERR(array);
++ if (IS_ERR(array))
++ goto out;
++
++ err = 0;
++ sigen = au_sigen(sb);
++ for (ull = 0; ull < max; ull++) {
++ inode = array[ull];
++ if (au_iigen(inode) != sigen) {
++ ii_write_lock_child(inode);
++ e = au_refresh_hinode_self(inode);
++ ii_write_unlock(inode);
++ if (unlikely(e)) {
++ pr_err("error %d, i%lu\n", e, inode->i_ino);
++ if (!err)
++ err = e;
++ /* go on even if err */
++ }
++ }
++ }
++
++ au_iarray_free(array, max);
++
++out:
++ return err;
++}
++
++static void au_remount_refresh(struct super_block *sb)
++{
++ int err, e;
++ unsigned int udba;
++ aufs_bindex_t bindex, bend;
++ struct dentry *root;
++ struct inode *inode;
++ struct au_branch *br;
++
++ au_sigen_inc(sb);
++ au_fclr_si(au_sbi(sb), FAILED_REFRESH_DIR);
++
++ root = sb->s_root;
++ DiMustNoWaiters(root);
++ inode = root->d_inode;
++ IiMustNoWaiters(inode);
++
++ udba = au_opt_udba(sb);
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ err = au_hnotify_reset_br(udba, br, br->br_perm);
++ if (unlikely(err))
++ AuIOErr("hnotify failed on br %d, %d, ignored\n",
++ bindex, err);
++ /* go on even if err */
++ }
++ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1));
++
++ di_write_unlock(root);
++ err = au_refresh_d(sb);
++ e = au_refresh_i(sb);
++ if (unlikely(e && !err))
++ err = e;
++ /* aufs_write_lock() calls ..._child() */
++ di_write_lock_child(root);
++
++ au_cpup_attr_all(inode, /*force*/1);
++
++ if (unlikely(err))
++ AuIOErr("refresh failed, ignored, %d\n", err);
++}
++
++/* stop extra interpretation of errno in mount(8), and strange error messages */
++static int cvt_err(int err)
++{
++ AuTraceErr(err);
++
++ switch (err) {
++ case -ENOENT:
++ case -ENOTDIR:
++ case -EEXIST:
++ case -EIO:
++ err = -EINVAL;
++ }
++ return err;
++}
++
++static int aufs_remount_fs(struct super_block *sb, int *flags, char *data)
++{
++ int err, do_dx;
++ unsigned int mntflags;
++ struct au_opts opts;
++ struct dentry *root;
++ struct inode *inode;
++ struct au_sbinfo *sbinfo;
++
++ err = 0;
++ root = sb->s_root;
++ if (!data || !*data) {
++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (!err) {
++ di_write_lock_child(root);
++ err = au_opts_verify(sb, *flags, /*pending*/0);
++ aufs_write_unlock(root);
++ }
++ goto out;
++ }
++
++ err = -ENOMEM;
++ memset(&opts, 0, sizeof(opts));
++ opts.opt = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!opts.opt))
++ goto out;
++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt);
++ opts.flags = AuOpts_REMOUNT;
++ opts.sb_flags = *flags;
++
++ /* parse it before aufs lock */
++ err = au_opts_parse(sb, data, &opts);
++ if (unlikely(err))
++ goto out_opts;
++
++ sbinfo = au_sbi(sb);
++ inode = root->d_inode;
++ mutex_lock(&inode->i_mutex);
++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out_mtx;
++ di_write_lock_child(root);
++
++ /* au_opts_remount() may return an error */
++ err = au_opts_remount(sb, &opts);
++ au_opts_free(&opts);
++
++ if (au_ftest_opts(opts.flags, REFRESH))
++ au_remount_refresh(sb);
++
++ if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) {
++ mntflags = au_mntflags(sb);
++ do_dx = !!au_opt_test(mntflags, DIO);
++ au_dy_arefresh(do_dx);
++ }
++
++ aufs_write_unlock(root);
++
++out_mtx:
++ mutex_unlock(&inode->i_mutex);
++out_opts:
++ free_page((unsigned long)opts.opt);
++out:
++ err = cvt_err(err);
++ AuTraceErr(err);
++ return err;
++}
++
++static const struct super_operations aufs_sop = {
++ .alloc_inode = aufs_alloc_inode,
++ .destroy_inode = aufs_destroy_inode,
++ /* always deleting, no clearing */
++ .drop_inode = generic_delete_inode,
++ .show_options = aufs_show_options,
++ .statfs = aufs_statfs,
++ .put_super = aufs_put_super,
++ .remount_fs = aufs_remount_fs
++};
++
++/* ---------------------------------------------------------------------- */
++
++static int alloc_root(struct super_block *sb)
++{
++ int err;
++ struct inode *inode;
++ struct dentry *root;
++
++ err = -ENOMEM;
++ inode = au_iget_locked(sb, AUFS_ROOT_INO);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out;
++
++ inode->i_op = &aufs_dir_iop;
++ inode->i_fop = &aufs_dir_fop;
++ inode->i_mode = S_IFDIR;
++ inode->i_nlink = 2;
++ unlock_new_inode(inode);
++
++ root = d_alloc_root(inode);
++ if (unlikely(!root))
++ goto out_iput;
++ err = PTR_ERR(root);
++ if (IS_ERR(root))
++ goto out_iput;
++
++ err = au_di_init(root);
++ if (!err) {
++ sb->s_root = root;
++ return 0; /* success */
++ }
++ dput(root);
++ goto out; /* do not iput */
++
++out_iput:
++ iget_failed(inode);
++out:
++ return err;
++
++}
++
++static int aufs_fill_super(struct super_block *sb, void *raw_data,
++ int silent __maybe_unused)
++{
++ int err;
++ struct au_opts opts;
++ struct dentry *root;
++ struct inode *inode;
++ char *arg = raw_data;
++
++ if (unlikely(!arg || !*arg)) {
++ err = -EINVAL;
++ pr_err("no arg\n");
++ goto out;
++ }
++
++ err = -ENOMEM;
++ memset(&opts, 0, sizeof(opts));
++ opts.opt = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!opts.opt))
++ goto out;
++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt);
++ opts.sb_flags = sb->s_flags;
++
++ err = au_si_alloc(sb);
++ if (unlikely(err))
++ goto out_opts;
++
++ /* all timestamps always follow the ones on the branch */
++ sb->s_flags |= MS_NOATIME | MS_NODIRATIME;
++ sb->s_op = &aufs_sop;
++ sb->s_magic = AUFS_SUPER_MAGIC;
++ sb->s_maxbytes = 0;
++ au_export_init(sb);
++
++ err = alloc_root(sb);
++ if (unlikely(err)) {
++ si_write_unlock(sb);
++ goto out_info;
++ }
++ root = sb->s_root;
++ inode = root->d_inode;
++
++ /*
++ * actually we can parse options regardless aufs lock here.
++ * but at remount time, parsing must be done before aufs lock.
++ * so we follow the same rule.
++ */
++ ii_write_lock_parent(inode);
++ aufs_write_unlock(root);
++ err = au_opts_parse(sb, arg, &opts);
++ if (unlikely(err))
++ goto out_root;
++
++ /* lock vfs_inode first, then aufs. */
++ mutex_lock(&inode->i_mutex);
++ aufs_write_lock(root);
++ err = au_opts_mount(sb, &opts);
++ au_opts_free(&opts);
++ aufs_write_unlock(root);
++ mutex_unlock(&inode->i_mutex);
++ if (!err)
++ goto out_opts; /* success */
++
++out_root:
++ dput(root);
++ sb->s_root = NULL;
++out_info:
++ kobject_put(&au_sbi(sb)->si_kobj);
++ sb->s_fs_info = NULL;
++out_opts:
++ free_page((unsigned long)opts.opt);
++out:
++ AuTraceErr(err);
++ err = cvt_err(err);
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_get_sb(struct file_system_type *fs_type, int flags,
++ const char *dev_name __maybe_unused, void *raw_data,
++ struct vfsmount *mnt)
++{
++ int err;
++ struct super_block *sb;
++
++ /* all timestamps always follow the ones on the branch */
++ /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */
++ err = get_sb_nodev(fs_type, flags, raw_data, aufs_fill_super, mnt);
++ if (!err) {
++ sb = mnt->mnt_sb;
++ si_write_lock(sb, !AuLock_FLUSH);
++ sysaufs_brs_add(sb, 0);
++ si_write_unlock(sb);
++ au_sbilist_add(sb);
++ }
++ return err;
++}
++
++static void aufs_kill_sb(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = au_sbi(sb);
++ if (sbinfo) {
++ au_sbilist_del(sb);
++ aufs_write_lock(sb->s_root);
++ if (sbinfo->si_wbr_create_ops->fin)
++ sbinfo->si_wbr_create_ops->fin(sb);
++ if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) {
++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE);
++ au_remount_refresh(sb);
++ }
++ if (au_opt_test(sbinfo->si_mntflags, PLINK))
++ au_plink_put(sb, /*verbose*/1);
++ au_xino_clr(sb);
++ aufs_write_unlock(sb->s_root);
++ au_nwt_flush(&sbinfo->si_nowait);
++ }
++ generic_shutdown_super(sb);
++}
++
++struct file_system_type aufs_fs_type = {
++ .name = AUFS_FSTYPE,
++ .fs_flags =
++ FS_RENAME_DOES_D_MOVE /* a race between rename and others */
++ | FS_REVAL_DOT, /* for NFS branch and udba */
++ .get_sb = aufs_get_sb,
++ .kill_sb = aufs_kill_sb,
++ /* no need to __module_get() and module_put(). */
++ .owner = THIS_MODULE,
++};
+diff -Nur linux-2.6.37.orig/fs/aufs/super.h linux-2.6.37/fs/aufs/super.h
+--- linux-2.6.37.orig/fs/aufs/super.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/super.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,527 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * super_block operations
++ */
++
++#ifndef __AUFS_SUPER_H__
++#define __AUFS_SUPER_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++#include "spl.h"
++#include "wkq.h"
++
++typedef ssize_t (*au_readf_t)(struct file *, char __user *, size_t, loff_t *);
++typedef ssize_t (*au_writef_t)(struct file *, const char __user *, size_t,
++ loff_t *);
++
++/* policies to select one among multiple writable branches */
++struct au_wbr_copyup_operations {
++ int (*copyup)(struct dentry *dentry);
++};
++
++struct au_wbr_create_operations {
++ int (*create)(struct dentry *dentry, int isdir);
++ int (*init)(struct super_block *sb);
++ int (*fin)(struct super_block *sb);
++};
++
++struct au_wbr_mfs {
++ struct mutex mfs_lock; /* protect this structure */
++ unsigned long mfs_jiffy;
++ unsigned long mfs_expire;
++ aufs_bindex_t mfs_bindex;
++
++ unsigned long long mfsrr_bytes;
++ unsigned long long mfsrr_watermark;
++};
++
++struct au_branch;
++struct au_sbinfo {
++ /* nowait tasks in the system-wide workqueue */
++ struct au_nowait_tasks si_nowait;
++
++ /*
++ * tried sb->s_umount, but failed due to the dependecy between i_mutex.
++ * rwsem for au_sbinfo is necessary.
++ */
++ struct au_rwsem si_rwsem;
++
++ /* prevent recursive locking in deleting inode */
++ struct {
++ unsigned long *bitmap;
++ spinlock_t tree_lock;
++ struct radix_tree_root tree;
++ } au_si_pid;
++
++ /*
++ * dirty approach to protect sb->sb_inodes and ->s_files from remount.
++ */
++ atomic_long_t si_ninodes, si_nfiles;
++
++ /* branch management */
++ unsigned int si_generation;
++
++ /* see above flags */
++ unsigned char au_si_status;
++
++ aufs_bindex_t si_bend;
++
++ /* dirty trick to keep br_id plus */
++ unsigned int si_last_br_id :
++ sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1;
++ struct au_branch **si_branch;
++
++ /* policy to select a writable branch */
++ unsigned char si_wbr_copyup;
++ unsigned char si_wbr_create;
++ struct au_wbr_copyup_operations *si_wbr_copyup_ops;
++ struct au_wbr_create_operations *si_wbr_create_ops;
++
++ /* round robin */
++ atomic_t si_wbr_rr_next;
++
++ /* most free space */
++ struct au_wbr_mfs si_wbr_mfs;
++
++ /* mount flags */
++ /* include/asm-ia64/siginfo.h defines a macro named si_flags */
++ unsigned int si_mntflags;
++
++ /* external inode number (bitmap and translation table) */
++ au_readf_t si_xread;
++ au_writef_t si_xwrite;
++ struct file *si_xib;
++ struct mutex si_xib_mtx; /* protect xib members */
++ unsigned long *si_xib_buf;
++ unsigned long si_xib_last_pindex;
++ int si_xib_next_bit;
++ aufs_bindex_t si_xino_brid;
++ /* reserved for future use */
++ /* unsigned long long si_xib_limit; */ /* Max xib file size */
++
++#ifdef CONFIG_AUFS_EXPORT
++ /* i_generation */
++ struct file *si_xigen;
++ atomic_t si_xigen_next;
++#endif
++
++ /* vdir parameters */
++ unsigned long si_rdcache; /* max cache time in jiffies */
++ unsigned int si_rdblk; /* deblk size */
++ unsigned int si_rdhash; /* hash size */
++
++ /*
++ * If the number of whiteouts are larger than si_dirwh, leave all of
++ * them after au_whtmp_ren to reduce the cost of rmdir(2).
++ * future fsck.aufs or kernel thread will remove them later.
++ * Otherwise, remove all whiteouts and the dir in rmdir(2).
++ */
++ unsigned int si_dirwh;
++
++ /*
++ * rename(2) a directory with all children.
++ */
++ /* reserved for future use */
++ /* int si_rendir; */
++
++ /* pseudo_link list */
++ struct au_splhead si_plink;
++ wait_queue_head_t si_plink_wq;
++ spinlock_t si_plink_maint_lock;
++ pid_t si_plink_maint_pid;
++
++ /*
++ * sysfs and lifetime management.
++ * this is not a small structure and it may be a waste of memory in case
++ * of sysfs is disabled, particulary when many aufs-es are mounted.
++ * but using sysfs is majority.
++ */
++ struct kobject si_kobj;
++#ifdef CONFIG_DEBUG_FS
++ struct dentry *si_dbgaufs, *si_dbgaufs_xib;
++#ifdef CONFIG_AUFS_EXPORT
++ struct dentry *si_dbgaufs_xigen;
++#endif
++#endif
++
++#ifdef CONFIG_AUFS_SBILIST
++ struct list_head si_list;
++#endif
++
++ /* dirty, necessary for unmounting, sysfs and sysrq */
++ struct super_block *si_sb;
++};
++
++/* sbinfo status flags */
++/*
++ * set true when refresh_dirs() failed at remount time.
++ * then try refreshing dirs at access time again.
++ * if it is false, refreshing dirs at access time is unnecesary
++ */
++#define AuSi_FAILED_REFRESH_DIR 1
++static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi,
++ unsigned int flag)
++{
++ AuRwMustAnyLock(&sbi->si_rwsem);
++ return sbi->au_si_status & flag;
++}
++#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name)
++#define au_fset_si(sbinfo, name) do { \
++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \
++ (sbinfo)->au_si_status |= AuSi_##name; \
++} while (0)
++#define au_fclr_si(sbinfo, name) do { \
++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \
++ (sbinfo)->au_si_status &= ~AuSi_##name; \
++} while (0)
++
++/* ---------------------------------------------------------------------- */
++
++/* policy to select one among writable branches */
++#define AuWbrCopyup(sbinfo, ...) \
++ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__))
++#define AuWbrCreate(sbinfo, ...) \
++ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__))
++
++/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */
++#define AuLock_DW 1 /* write-lock dentry */
++#define AuLock_IR (1 << 1) /* read-lock inode */
++#define AuLock_IW (1 << 2) /* write-lock inode */
++#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */
++#define AuLock_DIR (1 << 4) /* target is a dir */
++#define AuLock_NOPLM (1 << 5) /* return err in plm mode */
++#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */
++#define AuLock_GEN (1 << 7) /* test digen/iigen */
++#define au_ftest_lock(flags, name) ((flags) & AuLock_##name)
++#define au_fset_lock(flags, name) \
++ do { (flags) |= AuLock_##name; } while (0)
++#define au_fclr_lock(flags, name) \
++ do { (flags) &= ~AuLock_##name; } while (0)
++
++/* ---------------------------------------------------------------------- */
++
++/* super.c */
++extern struct file_system_type aufs_fs_type;
++struct inode *au_iget_locked(struct super_block *sb, ino_t ino);
++typedef unsigned long long (*au_arraycb_t)(void *array, unsigned long long max,
++ void *arg);
++void au_array_free(void *array);
++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg);
++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max);
++void au_iarray_free(struct inode **a, unsigned long long max);
++
++/* sbinfo.c */
++void au_si_free(struct kobject *kobj);
++int au_si_alloc(struct super_block *sb);
++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr);
++
++unsigned int au_sigen_inc(struct super_block *sb);
++aufs_bindex_t au_new_br_id(struct super_block *sb);
++
++int si_read_lock(struct super_block *sb, int flags);
++int si_write_lock(struct super_block *sb, int flags);
++int aufs_read_lock(struct dentry *dentry, int flags);
++void aufs_read_unlock(struct dentry *dentry, int flags);
++void aufs_write_lock(struct dentry *dentry);
++void aufs_write_unlock(struct dentry *dentry);
++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags);
++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2);
++
++int si_pid_test_slow(struct super_block *sb);
++void si_pid_set_slow(struct super_block *sb);
++void si_pid_clr_slow(struct super_block *sb);
++
++/* wbr_policy.c */
++extern struct au_wbr_copyup_operations au_wbr_copyup_ops[];
++extern struct au_wbr_create_operations au_wbr_create_ops[];
++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst);
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_sbinfo *au_sbi(struct super_block *sb)
++{
++ return sb->s_fs_info;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_EXPORT
++void au_export_init(struct super_block *sb);
++
++static inline int au_test_nfsd(void)
++{
++ struct task_struct *tsk = current;
++
++ return (tsk->flags & PF_KTHREAD)
++ && !strcmp(tsk->comm, "nfsd");
++}
++
++void au_xigen_inc(struct inode *inode);
++int au_xigen_new(struct inode *inode);
++int au_xigen_set(struct super_block *sb, struct file *base);
++void au_xigen_clr(struct super_block *sb);
++
++static inline int au_busy_or_stale(void)
++{
++ if (!au_test_nfsd())
++ return -EBUSY;
++ return -ESTALE;
++}
++#else
++AuStubVoid(au_export_init, struct super_block *sb)
++AuStubInt0(au_test_nfsd, void)
++AuStubVoid(au_xigen_inc, struct inode *inode)
++AuStubInt0(au_xigen_new, struct inode *inode)
++AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base)
++AuStubVoid(au_xigen_clr, struct super_block *sb)
++static inline int au_busy_or_stale(void)
++{
++ return -EBUSY;
++}
++#endif /* CONFIG_AUFS_EXPORT */
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_SBILIST
++/* module.c */
++extern struct au_splhead au_sbilist;
++
++static inline void au_sbilist_init(void)
++{
++ au_spl_init(&au_sbilist);
++}
++
++static inline void au_sbilist_add(struct super_block *sb)
++{
++ au_spl_add(&au_sbi(sb)->si_list, &au_sbilist);
++}
++
++static inline void au_sbilist_del(struct super_block *sb)
++{
++ au_spl_del(&au_sbi(sb)->si_list, &au_sbilist);
++}
++#else
++AuStubVoid(au_sbilist_init, void)
++AuStubVoid(au_sbilist_add, struct super_block*)
++AuStubVoid(au_sbilist_del, struct super_block*)
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo)
++{
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++#ifdef CONFIG_DEBUG_FS
++ sbinfo->si_dbgaufs = NULL;
++ sbinfo->si_dbgaufs_xib = NULL;
++#ifdef CONFIG_AUFS_EXPORT
++ sbinfo->si_dbgaufs_xigen = NULL;
++#endif
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++
++static inline pid_t si_pid_bit(void)
++{
++ /* the origin of pid is 1, but the bitmap's is 0 */
++ return current->pid - 1;
++}
++
++static inline int si_pid_test(struct super_block *sb)
++{
++ pid_t bit = si_pid_bit();
++ if (bit < PID_MAX_DEFAULT)
++ return test_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
++ else
++ return si_pid_test_slow(sb);
++}
++
++static inline void si_pid_set(struct super_block *sb)
++{
++ pid_t bit = si_pid_bit();
++ if (bit < PID_MAX_DEFAULT) {
++ AuDebugOn(test_bit(bit, au_sbi(sb)->au_si_pid.bitmap));
++ set_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
++ /* smp_mb(); */
++ } else
++ si_pid_set_slow(sb);
++}
++
++static inline void si_pid_clr(struct super_block *sb)
++{
++ pid_t bit = si_pid_bit();
++ if (bit < PID_MAX_DEFAULT) {
++ AuDebugOn(!test_bit(bit, au_sbi(sb)->au_si_pid.bitmap));
++ clear_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
++ /* smp_mb(); */
++ } else
++ si_pid_clr_slow(sb);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* lock superblock. mainly for entry point functions */
++/*
++ * __si_read_lock, __si_write_lock,
++ * __si_read_unlock, __si_write_unlock, __si_downgrade_lock
++ */
++AuSimpleRwsemFuncs(__si, struct super_block *sb, &au_sbi(sb)->si_rwsem);
++
++#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem)
++#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem)
++#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem)
++
++static inline void si_noflush_read_lock(struct super_block *sb)
++{
++ __si_read_lock(sb);
++ si_pid_set(sb);
++}
++
++static inline int si_noflush_read_trylock(struct super_block *sb)
++{
++ int locked = __si_read_trylock(sb);
++ if (locked)
++ si_pid_set(sb);
++ return locked;
++}
++
++static inline void si_noflush_write_lock(struct super_block *sb)
++{
++ __si_write_lock(sb);
++ si_pid_set(sb);
++}
++
++static inline int si_noflush_write_trylock(struct super_block *sb)
++{
++ int locked = __si_write_trylock(sb);
++ if (locked)
++ si_pid_set(sb);
++ return locked;
++}
++
++#if 0 /* unused */
++static inline int si_read_trylock(struct super_block *sb, int flags)
++{
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++ return si_noflush_read_trylock(sb);
++}
++#endif
++
++static inline void si_read_unlock(struct super_block *sb)
++{
++ si_pid_clr(sb);
++ __si_read_unlock(sb);
++}
++
++#if 0 /* unused */
++static inline int si_write_trylock(struct super_block *sb, int flags)
++{
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++ return si_noflush_write_trylock(sb);
++}
++#endif
++
++static inline void si_write_unlock(struct super_block *sb)
++{
++ si_pid_clr(sb);
++ __si_write_unlock(sb);
++}
++
++#if 0 /* unused */
++static inline void si_downgrade_lock(struct super_block *sb)
++{
++ __si_downgrade_lock(sb);
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static inline aufs_bindex_t au_sbend(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_bend;
++}
++
++static inline unsigned int au_mntflags(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_mntflags;
++}
++
++static inline unsigned int au_sigen(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_generation;
++}
++
++static inline void au_ninodes_inc(struct super_block *sb)
++{
++ atomic_long_inc(&au_sbi(sb)->si_ninodes);
++}
++
++static inline void au_ninodes_dec(struct super_block *sb)
++{
++ AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_ninodes));
++ atomic_long_dec(&au_sbi(sb)->si_ninodes);
++}
++
++static inline void au_nfiles_inc(struct super_block *sb)
++{
++ atomic_long_inc(&au_sbi(sb)->si_nfiles);
++}
++
++static inline void au_nfiles_dec(struct super_block *sb)
++{
++ AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_nfiles));
++ atomic_long_dec(&au_sbi(sb)->si_nfiles);
++}
++
++static inline struct au_branch *au_sbr(struct super_block *sb,
++ aufs_bindex_t bindex)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_branch[0 + bindex];
++}
++
++static inline void au_xino_brid_set(struct super_block *sb, aufs_bindex_t brid)
++{
++ SiMustWriteLock(sb);
++ au_sbi(sb)->si_xino_brid = brid;
++}
++
++static inline aufs_bindex_t au_xino_brid(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_xino_brid;
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_SUPER_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/sysaufs.c linux-2.6.37/fs/aufs/sysaufs.c
+--- linux-2.6.37.orig/fs/aufs/sysaufs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/sysaufs.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,107 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sysfs interface and lifetime management
++ * they are necessary regardless sysfs is disabled.
++ */
++
++#include <linux/fs.h>
++#include <linux/random.h>
++#include <linux/sysfs.h>
++#include "aufs.h"
++
++unsigned long sysaufs_si_mask;
++struct kset *sysaufs_kset;
++
++#define AuSiAttr(_name) { \
++ .attr = { .name = __stringify(_name), .mode = 0444 }, \
++ .show = sysaufs_si_##_name, \
++}
++
++static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path);
++struct attribute *sysaufs_si_attrs[] = {
++ &sysaufs_si_attr_xi_path.attr,
++ NULL,
++};
++
++static const struct sysfs_ops au_sbi_ops = {
++ .show = sysaufs_si_show
++};
++
++static struct kobj_type au_sbi_ktype = {
++ .release = au_si_free,
++ .sysfs_ops = &au_sbi_ops,
++ .default_attrs = sysaufs_si_attrs
++};
++
++/* ---------------------------------------------------------------------- */
++
++int sysaufs_si_init(struct au_sbinfo *sbinfo)
++{
++ int err;
++
++ sbinfo->si_kobj.kset = sysaufs_kset;
++ /* cf. sysaufs_name() */
++ err = kobject_init_and_add
++ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL,
++ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo));
++
++ dbgaufs_si_null(sbinfo);
++ if (!err) {
++ err = dbgaufs_si_init(sbinfo);
++ if (unlikely(err))
++ kobject_put(&sbinfo->si_kobj);
++ }
++ return err;
++}
++
++void sysaufs_fin(void)
++{
++ dbgaufs_fin();
++ sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group);
++ kset_unregister(sysaufs_kset);
++}
++
++int __init sysaufs_init(void)
++{
++ int err;
++
++ do {
++ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask));
++ } while (!sysaufs_si_mask);
++
++ err = -EINVAL;
++ sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj);
++ if (unlikely(!sysaufs_kset))
++ goto out;
++ err = PTR_ERR(sysaufs_kset);
++ if (IS_ERR(sysaufs_kset))
++ goto out;
++ err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group);
++ if (unlikely(err)) {
++ kset_unregister(sysaufs_kset);
++ goto out;
++ }
++
++ err = dbgaufs_init();
++ if (unlikely(err))
++ sysaufs_fin();
++out:
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/sysaufs.h linux-2.6.37/fs/aufs/sysaufs.h
+--- linux-2.6.37.orig/fs/aufs/sysaufs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/sysaufs.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,105 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sysfs interface and mount lifetime management
++ */
++
++#ifndef __SYSAUFS_H__
++#define __SYSAUFS_H__
++
++#ifdef __KERNEL__
++
++#include <linux/sysfs.h>
++#include <linux/aufs_type.h>
++#include "module.h"
++
++struct super_block;
++struct au_sbinfo;
++
++struct sysaufs_si_attr {
++ struct attribute attr;
++ int (*show)(struct seq_file *seq, struct super_block *sb);
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* sysaufs.c */
++extern unsigned long sysaufs_si_mask;
++extern struct kset *sysaufs_kset;
++extern struct attribute *sysaufs_si_attrs[];
++int sysaufs_si_init(struct au_sbinfo *sbinfo);
++int __init sysaufs_init(void);
++void sysaufs_fin(void);
++
++/* ---------------------------------------------------------------------- */
++
++/* some people doesn't like to show a pointer in kernel */
++static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo)
++{
++ return sysaufs_si_mask ^ (unsigned long)sbinfo;
++}
++
++#define SysaufsSiNamePrefix "si_"
++#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16)
++static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name)
++{
++ snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx",
++ sysaufs_si_id(sbinfo));
++}
++
++struct au_branch;
++#ifdef CONFIG_SYSFS
++/* sysfs.c */
++extern struct attribute_group *sysaufs_attr_group;
++
++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb);
++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
++ char *buf);
++
++void sysaufs_br_init(struct au_branch *br);
++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex);
++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex);
++
++#define sysaufs_brs_init() do {} while (0)
++
++#else
++#define sysaufs_attr_group NULL
++
++AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb)
++
++static inline
++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
++ char *buf)
++{
++ return 0;
++}
++
++AuStubVoid(sysaufs_br_init, struct au_branch *br)
++AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex)
++AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex)
++
++static inline void sysaufs_brs_init(void)
++{
++ sysaufs_brs = 0;
++}
++
++#endif /* CONFIG_SYSFS */
++
++#endif /* __KERNEL__ */
++#endif /* __SYSAUFS_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/sysfs.c linux-2.6.37/fs/aufs/sysfs.c
+--- linux-2.6.37.orig/fs/aufs/sysfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/sysfs.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,250 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sysfs interface
++ */
++
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include <linux/sysfs.h>
++#include "aufs.h"
++
++#ifdef CONFIG_AUFS_FS_MODULE
++/* this entry violates the "one line per file" policy of sysfs */
++static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
++{
++ ssize_t err;
++ static char *conf =
++/* this file is generated at compiling */
++#include "conf.str"
++ ;
++
++ err = snprintf(buf, PAGE_SIZE, conf);
++ if (unlikely(err >= PAGE_SIZE))
++ err = -EFBIG;
++ return err;
++}
++
++static struct kobj_attribute au_config_attr = __ATTR_RO(config);
++#endif
++
++static struct attribute *au_attr[] = {
++#ifdef CONFIG_AUFS_FS_MODULE
++ &au_config_attr.attr,
++#endif
++ NULL, /* need to NULL terminate the list of attributes */
++};
++
++static struct attribute_group sysaufs_attr_group_body = {
++ .attrs = au_attr
++};
++
++struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body;
++
++/* ---------------------------------------------------------------------- */
++
++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb)
++{
++ int err;
++
++ SiMustAnyLock(sb);
++
++ err = 0;
++ if (au_opt_test(au_mntflags(sb), XINO)) {
++ err = au_xino_path(seq, au_sbi(sb)->si_xib);
++ seq_putc(seq, '\n');
++ }
++ return err;
++}
++
++/*
++ * the lifetime of branch is independent from the entry under sysfs.
++ * sysfs handles the lifetime of the entry, and never call ->show() after it is
++ * unlinked.
++ */
++static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb,
++ aufs_bindex_t bindex)
++{
++ struct path path;
++ struct dentry *root;
++ struct au_branch *br;
++
++ AuDbg("b%d\n", bindex);
++
++ root = sb->s_root;
++ di_read_lock_parent(root, !AuLock_IR);
++ br = au_sbr(sb, bindex);
++ path.mnt = br->br_mnt;
++ path.dentry = au_h_dptr(root, bindex);
++ au_seq_path(seq, &path);
++ di_read_unlock(root, !AuLock_IR);
++ seq_printf(seq, "=%s\n", au_optstr_br_perm(br->br_perm));
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct seq_file *au_seq(char *p, ssize_t len)
++{
++ struct seq_file *seq;
++
++ seq = kzalloc(sizeof(*seq), GFP_NOFS);
++ if (seq) {
++ /* mutex_init(&seq.lock); */
++ seq->buf = p;
++ seq->size = len;
++ return seq; /* success */
++ }
++
++ seq = ERR_PTR(-ENOMEM);
++ return seq;
++}
++
++#define SysaufsBr_PREFIX "br"
++
++/* todo: file size may exceed PAGE_SIZE */
++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
++ char *buf)
++{
++ ssize_t err;
++ long l;
++ aufs_bindex_t bend;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++ struct seq_file *seq;
++ char *name;
++ struct attribute **cattr;
++
++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
++ sb = sbinfo->si_sb;
++
++ /*
++ * prevent a race condition between sysfs and aufs.
++ * for instance, sysfs_file_read() calls sysfs_get_active_two() which
++ * prohibits maintaining the sysfs entries.
++ * hew we acquire read lock after sysfs_get_active_two().
++ * on the other hand, the remount process may maintain the sysfs/aufs
++ * entries after acquiring write lock.
++ * it can cause a deadlock.
++ * simply we gave up processing read here.
++ */
++ err = -EBUSY;
++ if (unlikely(!si_noflush_read_trylock(sb)))
++ goto out;
++
++ seq = au_seq(buf, PAGE_SIZE);
++ err = PTR_ERR(seq);
++ if (IS_ERR(seq))
++ goto out_unlock;
++
++ name = (void *)attr->name;
++ cattr = sysaufs_si_attrs;
++ while (*cattr) {
++ if (!strcmp(name, (*cattr)->name)) {
++ err = container_of(*cattr, struct sysaufs_si_attr, attr)
++ ->show(seq, sb);
++ goto out_seq;
++ }
++ cattr++;
++ }
++
++ bend = au_sbend(sb);
++ if (!strncmp(name, SysaufsBr_PREFIX, sizeof(SysaufsBr_PREFIX) - 1)) {
++ name += sizeof(SysaufsBr_PREFIX) - 1;
++ err = strict_strtol(name, 10, &l);
++ if (!err) {
++ if (l <= bend)
++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l);
++ else
++ err = -ENOENT;
++ }
++ goto out_seq;
++ }
++ BUG();
++
++out_seq:
++ if (!err) {
++ err = seq->count;
++ /* sysfs limit */
++ if (unlikely(err == PAGE_SIZE))
++ err = -EFBIG;
++ }
++ kfree(seq);
++out_unlock:
++ si_read_unlock(sb);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void sysaufs_br_init(struct au_branch *br)
++{
++ struct attribute *attr = &br->br_attr;
++
++ sysfs_attr_init(attr);
++ attr->name = br->br_name;
++ attr->mode = S_IRUGO;
++}
++
++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
++{
++ struct au_branch *br;
++ struct kobject *kobj;
++ aufs_bindex_t bend;
++
++ dbgaufs_brs_del(sb, bindex);
++
++ if (!sysaufs_brs)
++ return;
++
++ kobj = &au_sbi(sb)->si_kobj;
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ sysfs_remove_file(kobj, &br->br_attr);
++ }
++}
++
++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
++{
++ int err;
++ aufs_bindex_t bend;
++ struct kobject *kobj;
++ struct au_branch *br;
++
++ dbgaufs_brs_add(sb, bindex);
++
++ if (!sysaufs_brs)
++ return;
++
++ kobj = &au_sbi(sb)->si_kobj;
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ snprintf(br->br_name, sizeof(br->br_name), SysaufsBr_PREFIX
++ "%d", bindex);
++ err = sysfs_create_file(kobj, &br->br_attr);
++ if (unlikely(err))
++ pr_warning("failed %s under sysfs(%d)\n",
++ br->br_name, err);
++ }
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/sysrq.c linux-2.6.37/fs/aufs/sysrq.c
+--- linux-2.6.37.orig/fs/aufs/sysrq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/sysrq.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,148 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * magic sysrq hanlder
++ */
++
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++/* #include <linux/sysrq.h> */
++#include <linux/writeback.h>
++#include "aufs.h"
++
++/* ---------------------------------------------------------------------- */
++
++static void sysrq_sb(struct super_block *sb)
++{
++ char *plevel;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ plevel = au_plevel;
++ au_plevel = KERN_WARNING;
++
++ sbinfo = au_sbi(sb);
++ /* since we define pr_fmt, call printk directly */
++ printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo));
++ printk(KERN_WARNING AUFS_NAME ": superblock\n");
++ au_dpri_sb(sb);
++
++#if 0
++ printk(KERN_WARNING AUFS_NAME ": root dentry\n");
++ au_dpri_dentry(sb->s_root);
++ printk(KERN_WARNING AUFS_NAME ": root inode\n");
++ au_dpri_inode(sb->s_root->d_inode);
++#endif
++
++#if 0
++ do {
++ int err, i, j, ndentry;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++
++ err = au_dpages_init(&dpages, GFP_ATOMIC);
++ if (unlikely(err))
++ break;
++ err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL);
++ if (!err)
++ for (i = 0; i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ ndentry = dpage->ndentry;
++ for (j = 0; j < ndentry; j++)
++ au_dpri_dentry(dpage->dentries[j]);
++ }
++ au_dpages_free(&dpages);
++ } while (0);
++#endif
++
++#if 1
++ {
++ struct inode *i;
++ printk(KERN_WARNING AUFS_NAME ": isolated inode\n");
++ spin_lock(&inode_lock);
++ list_for_each_entry(i, &sb->s_inodes, i_sb_list)
++ if (1 || list_empty(&i->i_dentry))
++ au_dpri_inode(i);
++ spin_unlock(&inode_lock);
++ }
++#endif
++ printk(KERN_WARNING AUFS_NAME ": files\n");
++ lg_global_lock(files_lglock);
++ do_file_list_for_each_entry(sb, file) {
++ umode_t mode;
++ mode = file->f_dentry->d_inode->i_mode;
++ if (!special_file(mode) || au_special_file(mode))
++ au_dpri_file(file);
++ } while_file_list_for_each_entry;
++ lg_global_unlock(files_lglock);
++ printk(KERN_WARNING AUFS_NAME ": done\n");
++
++ au_plevel = plevel;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* module parameter */
++static char *aufs_sysrq_key = "a";
++module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO);
++MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME);
++
++static void au_sysrq(int key __maybe_unused)
++{
++ struct au_sbinfo *sbinfo;
++
++ lockdep_off();
++ spin_lock(&au_sbilist.spin);
++ list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
++ sysrq_sb(sbinfo->si_sb);
++ spin_unlock(&au_sbilist.spin);
++ lockdep_on();
++}
++
++static struct sysrq_key_op au_sysrq_op = {
++ .handler = au_sysrq,
++ .help_msg = "Aufs",
++ .action_msg = "Aufs",
++ .enable_mask = SYSRQ_ENABLE_DUMP
++};
++
++/* ---------------------------------------------------------------------- */
++
++int __init au_sysrq_init(void)
++{
++ int err;
++ char key;
++
++ err = -1;
++ key = *aufs_sysrq_key;
++ if ('a' <= key && key <= 'z')
++ err = register_sysrq_key(key, &au_sysrq_op);
++ if (unlikely(err))
++ pr_err("err %d, sysrq=%c\n", err, key);
++ return err;
++}
++
++void au_sysrq_fin(void)
++{
++ int err;
++ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op);
++ if (unlikely(err))
++ pr_err("err %d (ignored)\n", err);
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/vdir.c linux-2.6.37/fs/aufs/vdir.c
+--- linux-2.6.37.orig/fs/aufs/vdir.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/vdir.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,886 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * virtual or vertical directory
++ */
++
++#include <linux/hash.h>
++#include "aufs.h"
++
++static unsigned int calc_size(int nlen)
++{
++ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t));
++}
++
++static int set_deblk_end(union au_vdir_deblk_p *p,
++ union au_vdir_deblk_p *deblk_end)
++{
++ if (calc_size(0) <= deblk_end->deblk - p->deblk) {
++ p->de->de_str.len = 0;
++ /* smp_mb(); */
++ return 0;
++ }
++ return -1; /* error */
++}
++
++/* returns true or false */
++static int is_deblk_end(union au_vdir_deblk_p *p,
++ union au_vdir_deblk_p *deblk_end)
++{
++ if (calc_size(0) <= deblk_end->deblk - p->deblk)
++ return !p->de->de_str.len;
++ return 1;
++}
++
++static unsigned char *last_deblk(struct au_vdir *vdir)
++{
++ return vdir->vd_deblk[vdir->vd_nblk - 1];
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* estimate the apropriate size for name hash table */
++unsigned int au_rdhash_est(loff_t sz)
++{
++ unsigned int n;
++
++ n = UINT_MAX;
++ sz >>= 10;
++ if (sz < n)
++ n = sz;
++ if (sz < AUFS_RDHASH_DEF)
++ n = AUFS_RDHASH_DEF;
++ /* pr_info("n %u\n", n); */
++ return n;
++}
++
++/*
++ * the allocated memory has to be freed by
++ * au_nhash_wh_free() or au_nhash_de_free().
++ */
++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp)
++{
++ struct hlist_head *head;
++ unsigned int u;
++
++ head = kmalloc(sizeof(*nhash->nh_head) * num_hash, gfp);
++ if (head) {
++ nhash->nh_num = num_hash;
++ nhash->nh_head = head;
++ for (u = 0; u < num_hash; u++)
++ INIT_HLIST_HEAD(head++);
++ return 0; /* success */
++ }
++
++ return -ENOMEM;
++}
++
++static void nhash_count(struct hlist_head *head)
++{
++#if 0
++ unsigned long n;
++ struct hlist_node *pos;
++
++ n = 0;
++ hlist_for_each(pos, head)
++ n++;
++ pr_info("%lu\n", n);
++#endif
++}
++
++static void au_nhash_wh_do_free(struct hlist_head *head)
++{
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos, *node;
++
++ hlist_for_each_entry_safe(tpos, pos, node, head, wh_hash) {
++ /* hlist_del(pos); */
++ kfree(tpos);
++ }
++}
++
++static void au_nhash_de_do_free(struct hlist_head *head)
++{
++ struct au_vdir_dehstr *tpos;
++ struct hlist_node *pos, *node;
++
++ hlist_for_each_entry_safe(tpos, pos, node, head, hash) {
++ /* hlist_del(pos); */
++ au_cache_free_vdir_dehstr(tpos);
++ }
++}
++
++static void au_nhash_do_free(struct au_nhash *nhash,
++ void (*free)(struct hlist_head *head))
++{
++ unsigned int n;
++ struct hlist_head *head;
++
++ n = nhash->nh_num;
++ if (!n)
++ return;
++
++ head = nhash->nh_head;
++ while (n-- > 0) {
++ nhash_count(head);
++ free(head++);
++ }
++ kfree(nhash->nh_head);
++}
++
++void au_nhash_wh_free(struct au_nhash *whlist)
++{
++ au_nhash_do_free(whlist, au_nhash_wh_do_free);
++}
++
++static void au_nhash_de_free(struct au_nhash *delist)
++{
++ au_nhash_do_free(delist, au_nhash_de_do_free);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
++ int limit)
++{
++ int num;
++ unsigned int u, n;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++
++ num = 0;
++ n = whlist->nh_num;
++ head = whlist->nh_head;
++ for (u = 0; u < n; u++, head++)
++ hlist_for_each_entry(tpos, pos, head, wh_hash)
++ if (tpos->wh_bindex == btgt && ++num > limit)
++ return 1;
++ return 0;
++}
++
++static struct hlist_head *au_name_hash(struct au_nhash *nhash,
++ unsigned char *name,
++ unsigned int len)
++{
++ unsigned int v;
++ /* const unsigned int magic_bit = 12; */
++
++ AuDebugOn(!nhash->nh_num || !nhash->nh_head);
++
++ v = 0;
++ while (len--)
++ v += *name++;
++ /* v = hash_long(v, magic_bit); */
++ v %= nhash->nh_num;
++ return nhash->nh_head + v;
++}
++
++static int au_nhash_test_name(struct au_vdir_destr *str, const char *name,
++ int nlen)
++{
++ return str->len == nlen && !memcmp(str->name, name, nlen);
++}
++
++/* returns found or not */
++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen)
++{
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++ struct au_vdir_destr *str;
++
++ head = au_name_hash(whlist, name, nlen);
++ hlist_for_each_entry(tpos, pos, head, wh_hash) {
++ str = &tpos->wh_str;
++ AuDbg("%.*s\n", str->len, str->name);
++ if (au_nhash_test_name(str, name, nlen))
++ return 1;
++ }
++ return 0;
++}
++
++/* returns found(true) or not */
++static int test_known(struct au_nhash *delist, char *name, int nlen)
++{
++ struct hlist_head *head;
++ struct au_vdir_dehstr *tpos;
++ struct hlist_node *pos;
++ struct au_vdir_destr *str;
++
++ head = au_name_hash(delist, name, nlen);
++ hlist_for_each_entry(tpos, pos, head, hash) {
++ str = tpos->str;
++ AuDbg("%.*s\n", str->len, str->name);
++ if (au_nhash_test_name(str, name, nlen))
++ return 1;
++ }
++ return 0;
++}
++
++static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino,
++ unsigned char d_type)
++{
++#ifdef CONFIG_AUFS_SHWH
++ wh->wh_ino = ino;
++ wh->wh_type = d_type;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino,
++ unsigned int d_type, aufs_bindex_t bindex,
++ unsigned char shwh)
++{
++ int err;
++ struct au_vdir_destr *str;
++ struct au_vdir_wh *wh;
++
++ AuDbg("%.*s\n", nlen, name);
++ AuDebugOn(!whlist->nh_num || !whlist->nh_head);
++
++ err = -ENOMEM;
++ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS);
++ if (unlikely(!wh))
++ goto out;
++
++ err = 0;
++ wh->wh_bindex = bindex;
++ if (shwh)
++ au_shwh_init_wh(wh, ino, d_type);
++ str = &wh->wh_str;
++ str->len = nlen;
++ memcpy(str->name, name, nlen);
++ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen));
++ /* smp_mb(); */
++
++out:
++ return err;
++}
++
++static int append_deblk(struct au_vdir *vdir)
++{
++ int err;
++ unsigned long ul;
++ const unsigned int deblk_sz = vdir->vd_deblk_sz;
++ union au_vdir_deblk_p p, deblk_end;
++ unsigned char **o;
++
++ err = -ENOMEM;
++ o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1),
++ GFP_NOFS);
++ if (unlikely(!o))
++ goto out;
++
++ vdir->vd_deblk = o;
++ p.deblk = kmalloc(deblk_sz, GFP_NOFS);
++ if (p.deblk) {
++ ul = vdir->vd_nblk++;
++ vdir->vd_deblk[ul] = p.deblk;
++ vdir->vd_last.ul = ul;
++ vdir->vd_last.p.deblk = p.deblk;
++ deblk_end.deblk = p.deblk + deblk_sz;
++ err = set_deblk_end(&p, &deblk_end);
++ }
++
++out:
++ return err;
++}
++
++static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino,
++ unsigned int d_type, struct au_nhash *delist)
++{
++ int err;
++ unsigned int sz;
++ const unsigned int deblk_sz = vdir->vd_deblk_sz;
++ union au_vdir_deblk_p p, *room, deblk_end;
++ struct au_vdir_dehstr *dehstr;
++
++ p.deblk = last_deblk(vdir);
++ deblk_end.deblk = p.deblk + deblk_sz;
++ room = &vdir->vd_last.p;
++ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk
++ || !is_deblk_end(room, &deblk_end));
++
++ sz = calc_size(nlen);
++ if (unlikely(sz > deblk_end.deblk - room->deblk)) {
++ err = append_deblk(vdir);
++ if (unlikely(err))
++ goto out;
++
++ p.deblk = last_deblk(vdir);
++ deblk_end.deblk = p.deblk + deblk_sz;
++ /* smp_mb(); */
++ AuDebugOn(room->deblk != p.deblk);
++ }
++
++ err = -ENOMEM;
++ dehstr = au_cache_alloc_vdir_dehstr();
++ if (unlikely(!dehstr))
++ goto out;
++
++ dehstr->str = &room->de->de_str;
++ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen));
++ room->de->de_ino = ino;
++ room->de->de_type = d_type;
++ room->de->de_str.len = nlen;
++ memcpy(room->de->de_str.name, name, nlen);
++
++ err = 0;
++ room->deblk += sz;
++ if (unlikely(set_deblk_end(room, &deblk_end)))
++ err = append_deblk(vdir);
++ /* smp_mb(); */
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_vdir_free(struct au_vdir *vdir)
++{
++ unsigned char **deblk;
++
++ deblk = vdir->vd_deblk;
++ while (vdir->vd_nblk--)
++ kfree(*deblk++);
++ kfree(vdir->vd_deblk);
++ au_cache_free_vdir(vdir);
++}
++
++static struct au_vdir *alloc_vdir(struct file *file)
++{
++ struct au_vdir *vdir;
++ struct super_block *sb;
++ int err;
++
++ sb = file->f_dentry->d_sb;
++ SiMustAnyLock(sb);
++
++ err = -ENOMEM;
++ vdir = au_cache_alloc_vdir();
++ if (unlikely(!vdir))
++ goto out;
++
++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS);
++ if (unlikely(!vdir->vd_deblk))
++ goto out_free;
++
++ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk;
++ if (!vdir->vd_deblk_sz) {
++ /* estimate the apropriate size for deblk */
++ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL);
++ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */
++ }
++ vdir->vd_nblk = 0;
++ vdir->vd_version = 0;
++ vdir->vd_jiffy = 0;
++ err = append_deblk(vdir);
++ if (!err)
++ return vdir; /* success */
++
++ kfree(vdir->vd_deblk);
++
++out_free:
++ au_cache_free_vdir(vdir);
++out:
++ vdir = ERR_PTR(err);
++ return vdir;
++}
++
++static int reinit_vdir(struct au_vdir *vdir)
++{
++ int err;
++ union au_vdir_deblk_p p, deblk_end;
++
++ while (vdir->vd_nblk > 1) {
++ kfree(vdir->vd_deblk[vdir->vd_nblk - 1]);
++ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */
++ vdir->vd_nblk--;
++ }
++ p.deblk = vdir->vd_deblk[0];
++ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz;
++ err = set_deblk_end(&p, &deblk_end);
++ /* keep vd_dblk_sz */
++ vdir->vd_last.ul = 0;
++ vdir->vd_last.p.deblk = vdir->vd_deblk[0];
++ vdir->vd_version = 0;
++ vdir->vd_jiffy = 0;
++ /* smp_mb(); */
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#define AuFillVdir_CALLED 1
++#define AuFillVdir_WHABLE (1 << 1)
++#define AuFillVdir_SHWH (1 << 2)
++#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name)
++#define au_fset_fillvdir(flags, name) \
++ do { (flags) |= AuFillVdir_##name; } while (0)
++#define au_fclr_fillvdir(flags, name) \
++ do { (flags) &= ~AuFillVdir_##name; } while (0)
++
++#ifndef CONFIG_AUFS_SHWH
++#undef AuFillVdir_SHWH
++#define AuFillVdir_SHWH 0
++#endif
++
++struct fillvdir_arg {
++ struct file *file;
++ struct au_vdir *vdir;
++ struct au_nhash delist;
++ struct au_nhash whlist;
++ aufs_bindex_t bindex;
++ unsigned int flags;
++ int err;
++};
++
++static int fillvdir(void *__arg, const char *__name, int nlen,
++ loff_t offset __maybe_unused, u64 h_ino,
++ unsigned int d_type)
++{
++ struct fillvdir_arg *arg = __arg;
++ char *name = (void *)__name;
++ struct super_block *sb;
++ ino_t ino;
++ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH);
++
++ arg->err = 0;
++ sb = arg->file->f_dentry->d_sb;
++ au_fset_fillvdir(arg->flags, CALLED);
++ /* smp_mb(); */
++ if (nlen <= AUFS_WH_PFX_LEN
++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
++ if (test_known(&arg->delist, name, nlen)
++ || au_nhash_test_known_wh(&arg->whlist, name, nlen))
++ goto out; /* already exists or whiteouted */
++
++ sb = arg->file->f_dentry->d_sb;
++ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino);
++ if (!arg->err) {
++ if (unlikely(nlen > AUFS_MAX_NAMELEN))
++ d_type = DT_UNKNOWN;
++ arg->err = append_de(arg->vdir, name, nlen, ino,
++ d_type, &arg->delist);
++ }
++ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) {
++ name += AUFS_WH_PFX_LEN;
++ nlen -= AUFS_WH_PFX_LEN;
++ if (au_nhash_test_known_wh(&arg->whlist, name, nlen))
++ goto out; /* already whiteouted */
++
++ if (shwh)
++ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type,
++ &ino);
++ if (!arg->err) {
++ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN)
++ d_type = DT_UNKNOWN;
++ arg->err = au_nhash_append_wh
++ (&arg->whlist, name, nlen, ino, d_type,
++ arg->bindex, shwh);
++ }
++ }
++
++out:
++ if (!arg->err)
++ arg->vdir->vd_jiffy = jiffies;
++ /* smp_mb(); */
++ AuTraceErr(arg->err);
++ return arg->err;
++}
++
++static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir,
++ struct au_nhash *whlist, struct au_nhash *delist)
++{
++#ifdef CONFIG_AUFS_SHWH
++ int err;
++ unsigned int nh, u;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos, *n;
++ char *p, *o;
++ struct au_vdir_destr *destr;
++
++ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH));
++
++ err = -ENOMEM;
++ o = p = __getname_gfp(GFP_NOFS);
++ if (unlikely(!p))
++ goto out;
++
++ err = 0;
++ nh = whlist->nh_num;
++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
++ p += AUFS_WH_PFX_LEN;
++ for (u = 0; u < nh; u++) {
++ head = whlist->nh_head + u;
++ hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) {
++ destr = &tpos->wh_str;
++ memcpy(p, destr->name, destr->len);
++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN,
++ tpos->wh_ino, tpos->wh_type, delist);
++ if (unlikely(err))
++ break;
++ }
++ }
++
++ __putname(o);
++
++out:
++ AuTraceErr(err);
++ return err;
++#else
++ return 0;
++#endif
++}
++
++static int au_do_read_vdir(struct fillvdir_arg *arg)
++{
++ int err;
++ unsigned int rdhash;
++ loff_t offset;
++ aufs_bindex_t bend, bindex, bstart;
++ unsigned char shwh;
++ struct file *hf, *file;
++ struct super_block *sb;
++
++ file = arg->file;
++ sb = file->f_dentry->d_sb;
++ SiMustAnyLock(sb);
++
++ rdhash = au_sbi(sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL));
++ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out_delist;
++
++ err = 0;
++ arg->flags = 0;
++ shwh = 0;
++ if (au_opt_test(au_mntflags(sb), SHWH)) {
++ shwh = 1;
++ au_fset_fillvdir(arg->flags, SHWH);
++ }
++ bstart = au_fbstart(file);
++ bend = au_fbend_dir(file);
++ for (bindex = bstart; !err && bindex <= bend; bindex++) {
++ hf = au_hf_dir(file, bindex);
++ if (!hf)
++ continue;
++
++ offset = vfsub_llseek(hf, 0, SEEK_SET);
++ err = offset;
++ if (unlikely(offset))
++ break;
++
++ arg->bindex = bindex;
++ au_fclr_fillvdir(arg->flags, WHABLE);
++ if (shwh
++ || (bindex != bend
++ && au_br_whable(au_sbr_perm(sb, bindex))))
++ au_fset_fillvdir(arg->flags, WHABLE);
++ do {
++ arg->err = 0;
++ au_fclr_fillvdir(arg->flags, CALLED);
++ /* smp_mb(); */
++ err = vfsub_readdir(hf, fillvdir, arg);
++ if (err >= 0)
++ err = arg->err;
++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED));
++ }
++
++ if (!err && shwh)
++ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist);
++
++ au_nhash_wh_free(&arg->whlist);
++
++out_delist:
++ au_nhash_de_free(&arg->delist);
++out:
++ return err;
++}
++
++static int read_vdir(struct file *file, int may_read)
++{
++ int err;
++ unsigned long expire;
++ unsigned char do_read;
++ struct fillvdir_arg arg;
++ struct inode *inode;
++ struct au_vdir *vdir, *allocated;
++
++ err = 0;
++ inode = file->f_dentry->d_inode;
++ IMustLock(inode);
++ SiMustAnyLock(inode->i_sb);
++
++ allocated = NULL;
++ do_read = 0;
++ expire = au_sbi(inode->i_sb)->si_rdcache;
++ vdir = au_ivdir(inode);
++ if (!vdir) {
++ do_read = 1;
++ vdir = alloc_vdir(file);
++ err = PTR_ERR(vdir);
++ if (IS_ERR(vdir))
++ goto out;
++ err = 0;
++ allocated = vdir;
++ } else if (may_read
++ && (inode->i_version != vdir->vd_version
++ || time_after(jiffies, vdir->vd_jiffy + expire))) {
++ do_read = 1;
++ err = reinit_vdir(vdir);
++ if (unlikely(err))
++ goto out;
++ }
++
++ if (!do_read)
++ return 0; /* success */
++
++ arg.file = file;
++ arg.vdir = vdir;
++ err = au_do_read_vdir(&arg);
++ if (!err) {
++ /* file->f_pos = 0; */
++ vdir->vd_version = inode->i_version;
++ vdir->vd_last.ul = 0;
++ vdir->vd_last.p.deblk = vdir->vd_deblk[0];
++ if (allocated)
++ au_set_ivdir(inode, allocated);
++ } else if (allocated)
++ au_vdir_free(allocated);
++
++out:
++ return err;
++}
++
++static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src)
++{
++ int err, rerr;
++ unsigned long ul, n;
++ const unsigned int deblk_sz = src->vd_deblk_sz;
++
++ AuDebugOn(tgt->vd_nblk != 1);
++
++ err = -ENOMEM;
++ if (tgt->vd_nblk < src->vd_nblk) {
++ unsigned char **p;
++
++ p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk,
++ GFP_NOFS);
++ if (unlikely(!p))
++ goto out;
++ tgt->vd_deblk = p;
++ }
++
++ if (tgt->vd_deblk_sz != deblk_sz) {
++ unsigned char *p;
++
++ tgt->vd_deblk_sz = deblk_sz;
++ p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS);
++ if (unlikely(!p))
++ goto out;
++ tgt->vd_deblk[0] = p;
++ }
++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz);
++ tgt->vd_version = src->vd_version;
++ tgt->vd_jiffy = src->vd_jiffy;
++
++ n = src->vd_nblk;
++ for (ul = 1; ul < n; ul++) {
++ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz,
++ GFP_NOFS);
++ if (unlikely(!tgt->vd_deblk[ul]))
++ goto out;
++ tgt->vd_nblk++;
++ }
++ tgt->vd_nblk = n;
++ tgt->vd_last.ul = tgt->vd_last.ul;
++ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul];
++ tgt->vd_last.p.deblk += src->vd_last.p.deblk
++ - src->vd_deblk[src->vd_last.ul];
++ /* smp_mb(); */
++ return 0; /* success */
++
++out:
++ rerr = reinit_vdir(tgt);
++ BUG_ON(rerr);
++ return err;
++}
++
++int au_vdir_init(struct file *file)
++{
++ int err;
++ struct inode *inode;
++ struct au_vdir *vdir_cache, *allocated;
++
++ err = read_vdir(file, !file->f_pos);
++ if (unlikely(err))
++ goto out;
++
++ allocated = NULL;
++ vdir_cache = au_fvdir_cache(file);
++ if (!vdir_cache) {
++ vdir_cache = alloc_vdir(file);
++ err = PTR_ERR(vdir_cache);
++ if (IS_ERR(vdir_cache))
++ goto out;
++ allocated = vdir_cache;
++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) {
++ err = reinit_vdir(vdir_cache);
++ if (unlikely(err))
++ goto out;
++ } else
++ return 0; /* success */
++
++ inode = file->f_dentry->d_inode;
++ err = copy_vdir(vdir_cache, au_ivdir(inode));
++ if (!err) {
++ file->f_version = inode->i_version;
++ if (allocated)
++ au_set_fvdir_cache(file, allocated);
++ } else if (allocated)
++ au_vdir_free(allocated);
++
++out:
++ return err;
++}
++
++static loff_t calc_offset(struct au_vdir *vdir)
++{
++ loff_t offset;
++ union au_vdir_deblk_p p;
++
++ p.deblk = vdir->vd_deblk[vdir->vd_last.ul];
++ offset = vdir->vd_last.p.deblk - p.deblk;
++ offset += vdir->vd_deblk_sz * vdir->vd_last.ul;
++ return offset;
++}
++
++/* returns true or false */
++static int seek_vdir(struct file *file)
++{
++ int valid;
++ unsigned int deblk_sz;
++ unsigned long ul, n;
++ loff_t offset;
++ union au_vdir_deblk_p p, deblk_end;
++ struct au_vdir *vdir_cache;
++
++ valid = 1;
++ vdir_cache = au_fvdir_cache(file);
++ offset = calc_offset(vdir_cache);
++ AuDbg("offset %lld\n", offset);
++ if (file->f_pos == offset)
++ goto out;
++
++ vdir_cache->vd_last.ul = 0;
++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0];
++ if (!file->f_pos)
++ goto out;
++
++ valid = 0;
++ deblk_sz = vdir_cache->vd_deblk_sz;
++ ul = div64_u64(file->f_pos, deblk_sz);
++ AuDbg("ul %lu\n", ul);
++ if (ul >= vdir_cache->vd_nblk)
++ goto out;
++
++ n = vdir_cache->vd_nblk;
++ for (; ul < n; ul++) {
++ p.deblk = vdir_cache->vd_deblk[ul];
++ deblk_end.deblk = p.deblk + deblk_sz;
++ offset = ul;
++ offset *= deblk_sz;
++ while (!is_deblk_end(&p, &deblk_end) && offset < file->f_pos) {
++ unsigned int l;
++
++ l = calc_size(p.de->de_str.len);
++ offset += l;
++ p.deblk += l;
++ }
++ if (!is_deblk_end(&p, &deblk_end)) {
++ valid = 1;
++ vdir_cache->vd_last.ul = ul;
++ vdir_cache->vd_last.p = p;
++ break;
++ }
++ }
++
++out:
++ /* smp_mb(); */
++ AuTraceErr(!valid);
++ return valid;
++}
++
++int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir)
++{
++ int err;
++ unsigned int l, deblk_sz;
++ union au_vdir_deblk_p deblk_end;
++ struct au_vdir *vdir_cache;
++ struct au_vdir_de *de;
++
++ vdir_cache = au_fvdir_cache(file);
++ if (!seek_vdir(file))
++ return 0;
++
++ deblk_sz = vdir_cache->vd_deblk_sz;
++ while (1) {
++ deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul];
++ deblk_end.deblk += deblk_sz;
++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) {
++ de = vdir_cache->vd_last.p.de;
++ AuDbg("%.*s, off%lld, i%lu, dt%d\n",
++ de->de_str.len, de->de_str.name, file->f_pos,
++ (unsigned long)de->de_ino, de->de_type);
++ err = filldir(dirent, de->de_str.name, de->de_str.len,
++ file->f_pos, de->de_ino, de->de_type);
++ if (unlikely(err)) {
++ AuTraceErr(err);
++ /* todo: ignore the error caused by udba? */
++ /* return err; */
++ return 0;
++ }
++
++ l = calc_size(de->de_str.len);
++ vdir_cache->vd_last.p.deblk += l;
++ file->f_pos += l;
++ }
++ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) {
++ vdir_cache->vd_last.ul++;
++ vdir_cache->vd_last.p.deblk
++ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul];
++ file->f_pos = deblk_sz * vdir_cache->vd_last.ul;
++ continue;
++ }
++ break;
++ }
++
++ /* smp_mb(); */
++ return 0;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/vfsub.c linux-2.6.37/fs/aufs/vfsub.c
+--- linux-2.6.37.orig/fs/aufs/vfsub.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/vfsub.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,790 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sub-routines for VFS
++ */
++
++#include <linux/file.h>
++#include <linux/ima.h>
++#include <linux/namei.h>
++#include <linux/security.h>
++#include <linux/splice.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++int vfsub_update_h_iattr(struct path *h_path, int *did)
++{
++ int err;
++ struct kstat st;
++ struct super_block *h_sb;
++
++ /* for remote fs, leave work for its getattr or d_revalidate */
++ /* for bad i_attr fs, handle them in aufs_getattr() */
++ /* still some fs may acquire i_mutex. we need to skip them */
++ err = 0;
++ if (!did)
++ did = &err;
++ h_sb = h_path->dentry->d_sb;
++ *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb));
++ if (*did)
++ err = vfs_getattr(h_path->mnt, h_path->dentry, &st);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_conv_oflags(int flags)
++{
++ int mask = 0;
++
++#ifdef CONFIG_IMA
++ fmode_t fmode;
++
++ /* mask = MAY_OPEN; */
++ fmode = OPEN_FMODE(flags);
++ if (fmode & FMODE_READ)
++ mask |= MAY_READ;
++ if ((fmode & FMODE_WRITE)
++ || (flags & O_TRUNC))
++ mask |= MAY_WRITE;
++ /*
++ * if (flags & O_APPEND)
++ * mask |= MAY_APPEND;
++ */
++ if (flags & vfsub_fmode_to_uint(FMODE_EXEC))
++ mask |= MAY_EXEC;
++
++ AuDbg("flags 0x%x, mask 0x%x\n", flags, mask);
++#endif
++
++ return mask;
++}
++
++struct file *vfsub_dentry_open(struct path *path, int flags)
++{
++ struct file *file;
++ int err;
++
++ path_get(path);
++ file = dentry_open(path->dentry, path->mnt,
++ flags /* | vfsub_fmode_to_uint(FMODE_NONOTIFY) */,
++ current_cred());
++ if (IS_ERR(file))
++ goto out;
++
++ err = ima_file_check(file, au_conv_oflags(flags));
++ if (unlikely(err)) {
++ fput(file);
++ file = ERR_PTR(err);
++ }
++out:
++ return file;
++}
++
++struct file *vfsub_filp_open(const char *path, int oflags, int mode)
++{
++ struct file *file;
++
++ file = filp_open(path,
++ oflags /* | vfsub_fmode_to_uint(FMODE_NONOTIFY) */,
++ mode);
++ if (IS_ERR(file))
++ goto out;
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++
++out:
++ return file;
++}
++
++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path)
++{
++ int err;
++
++ err = kern_path(name, flags, path);
++ if (!err && path->dentry->d_inode)
++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
++ int len)
++{
++ struct path path = {
++ .mnt = NULL
++ };
++
++ /* VFS checks it too, but by WARN_ON_ONCE() */
++ IMustLock(parent->d_inode);
++
++ path.dentry = lookup_one_len(name, parent, len);
++ if (IS_ERR(path.dentry))
++ goto out;
++ if (path.dentry->d_inode)
++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/
++
++out:
++ AuTraceErrPtr(path.dentry);
++ return path.dentry;
++}
++
++struct dentry *vfsub_lookup_hash(struct nameidata *nd)
++{
++ struct path path = {
++ .mnt = nd->path.mnt
++ };
++
++ IMustLock(nd->path.dentry->d_inode);
++
++ path.dentry = lookup_hash(nd);
++ if (IS_ERR(path.dentry))
++ goto out;
++ if (path.dentry->d_inode)
++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/
++
++out:
++ AuTraceErrPtr(path.dentry);
++ return path.dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2)
++{
++ struct dentry *d;
++
++ d = lock_rename(d1, d2);
++ au_hn_suspend(hdir1);
++ if (hdir1 != hdir2)
++ au_hn_suspend(hdir2);
++
++ return d;
++}
++
++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2)
++{
++ au_hn_resume(hdir1);
++ if (hdir1 != hdir2)
++ au_hn_resume(hdir2);
++ unlock_rename(d1, d2);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int vfsub_create(struct inode *dir, struct path *path, int mode)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_mknod(path, d, mode, 0);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ if (au_test_fs_null_nd(dir->i_sb))
++ err = vfs_create(dir, path->dentry, mode, NULL);
++ else {
++ struct nameidata h_nd;
++
++ memset(&h_nd, 0, sizeof(h_nd));
++ h_nd.flags = LOOKUP_CREATE;
++ h_nd.intent.open.flags = O_CREAT
++ | vfsub_fmode_to_uint(FMODE_READ);
++ h_nd.intent.open.create_mode = mode;
++ h_nd.path.dentry = path->dentry->d_parent;
++ h_nd.path.mnt = path->mnt;
++ path_get(&h_nd.path);
++ err = vfs_create(dir, path->dentry, mode, &h_nd);
++ path_put(&h_nd.path);
++ }
++
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++int vfsub_symlink(struct inode *dir, struct path *path, const char *symname)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_symlink(path, d, symname);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_symlink(dir, path->dentry, symname);
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_mknod(path, d, mode, dev);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_mknod(dir, path->dentry, mode, dev);
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++static int au_test_nlink(struct inode *inode)
++{
++ const unsigned int link_max = UINT_MAX >> 1; /* rough margin */
++
++ if (!au_test_fs_no_limit_nlink(inode->i_sb)
++ || inode->i_nlink < link_max)
++ return 0;
++ return -EMLINK;
++}
++
++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ err = au_test_nlink(src_dentry->d_inode);
++ if (unlikely(err))
++ return err;
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_link(src_dentry, path, d);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_link(src_dentry, dir, path->dentry);
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ /* fuse has different memory inode for the same inumber */
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ tmp.dentry = src_dentry;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry,
++ struct inode *dir, struct path *path)
++{
++ int err;
++ struct path tmp = {
++ .mnt = path->mnt
++ };
++ struct dentry *d;
++
++ IMustLock(dir);
++ IMustLock(src_dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ tmp.dentry = src_dentry->d_parent;
++ err = security_path_rename(&tmp, src_dentry, path, d);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_rename(src_dir, src_dentry, dir, path->dentry);
++ if (!err) {
++ int did;
++
++ tmp.dentry = d->d_parent;
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = src_dentry;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ tmp.dentry = src_dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++int vfsub_mkdir(struct inode *dir, struct path *path, int mode)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_mkdir(path, d, mode);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_mkdir(dir, path->dentry, mode);
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++int vfsub_rmdir(struct inode *dir, struct path *path)
++{
++ int err;
++ struct dentry *d;
++
++ IMustLock(dir);
++
++ d = path->dentry;
++ path->dentry = d->d_parent;
++ err = security_path_rmdir(path, d);
++ path->dentry = d;
++ if (unlikely(err))
++ goto out;
++
++ err = vfs_rmdir(dir, path->dentry);
++ if (!err) {
++ struct path tmp = {
++ .dentry = path->dentry->d_parent,
++ .mnt = path->mnt
++ };
++
++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/
++ }
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++
++ err = vfs_read(file, ubuf, count, ppos);
++ if (err >= 0)
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++/* todo: kernel_read()? */
++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++ union {
++ void *k;
++ char __user *u;
++ } buf;
++
++ buf.k = kbuf;
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ err = vfsub_read_u(file, buf.u, count, ppos);
++ set_fs(oldfs);
++ return err;
++}
++
++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++
++ err = vfs_write(file, ubuf, count, ppos);
++ if (err >= 0)
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++ union {
++ void *k;
++ const char __user *u;
++ } buf;
++
++ buf.k = kbuf;
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ err = vfsub_write_u(file, buf.u, count, ppos);
++ set_fs(oldfs);
++ return err;
++}
++
++int vfsub_flush(struct file *file, fl_owner_t id)
++{
++ int err;
++
++ err = 0;
++ if (file->f_op && file->f_op->flush) {
++ err = file->f_op->flush(file, id);
++ if (!err)
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL);
++ /*ignore*/
++ }
++ return err;
++}
++
++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg)
++{
++ int err;
++
++ err = vfs_readdir(file, filldir, arg);
++ if (err >= 0)
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++long vfsub_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ long err;
++
++ err = do_splice_to(in, ppos, pipe, len, flags);
++ file_accessed(in);
++ if (err >= 0)
++ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
++{
++ long err;
++
++ err = do_splice_from(pipe, out, ppos, len, flags);
++ if (err >= 0)
++ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */
++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
++ struct file *h_file)
++{
++ int err;
++ struct inode *h_inode;
++
++ h_inode = h_path->dentry->d_inode;
++ if (!h_file) {
++ err = mnt_want_write(h_path->mnt);
++ if (err)
++ goto out;
++ err = inode_permission(h_inode, MAY_WRITE);
++ if (err)
++ goto out_mnt;
++ err = get_write_access(h_inode);
++ if (err)
++ goto out_mnt;
++ err = break_lease(h_inode, O_WRONLY);
++ if (err)
++ goto out_inode;
++ }
++
++ err = locks_verify_truncate(h_inode, h_file, length);
++ if (!err)
++ err = security_path_truncate(h_path);
++ if (!err)
++ err = do_truncate(h_path->dentry, length, attr, h_file);
++
++out_inode:
++ if (!h_file)
++ put_write_access(h_inode);
++out_mnt:
++ if (!h_file)
++ mnt_drop_write(h_path->mnt);
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_vfsub_mkdir_args {
++ int *errp;
++ struct inode *dir;
++ struct path *path;
++ int mode;
++};
++
++static void au_call_vfsub_mkdir(void *args)
++{
++ struct au_vfsub_mkdir_args *a = args;
++ *a->errp = vfsub_mkdir(a->dir, a->path, a->mode);
++}
++
++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode)
++{
++ int err, do_sio, wkq_err;
++
++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
++ if (!do_sio)
++ err = vfsub_mkdir(dir, path, mode);
++ else {
++ struct au_vfsub_mkdir_args args = {
++ .errp = &err,
++ .dir = dir,
++ .path = path,
++ .mode = mode
++ };
++ wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
++
++struct au_vfsub_rmdir_args {
++ int *errp;
++ struct inode *dir;
++ struct path *path;
++};
++
++static void au_call_vfsub_rmdir(void *args)
++{
++ struct au_vfsub_rmdir_args *a = args;
++ *a->errp = vfsub_rmdir(a->dir, a->path);
++}
++
++int vfsub_sio_rmdir(struct inode *dir, struct path *path)
++{
++ int err, do_sio, wkq_err;
++
++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
++ if (!do_sio)
++ err = vfsub_rmdir(dir, path);
++ else {
++ struct au_vfsub_rmdir_args args = {
++ .errp = &err,
++ .dir = dir,
++ .path = path
++ };
++ wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct notify_change_args {
++ int *errp;
++ struct path *path;
++ struct iattr *ia;
++};
++
++static void call_notify_change(void *args)
++{
++ struct notify_change_args *a = args;
++ struct inode *h_inode;
++
++ h_inode = a->path->dentry->d_inode;
++ IMustLock(h_inode);
++
++ *a->errp = -EPERM;
++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
++ *a->errp = notify_change(a->path->dentry, a->ia);
++ if (!*a->errp)
++ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/
++ }
++ AuTraceErr(*a->errp);
++}
++
++int vfsub_notify_change(struct path *path, struct iattr *ia)
++{
++ int err;
++ struct notify_change_args args = {
++ .errp = &err,
++ .path = path,
++ .ia = ia
++ };
++
++ call_notify_change(&args);
++
++ return err;
++}
++
++int vfsub_sio_notify_change(struct path *path, struct iattr *ia)
++{
++ int err, wkq_err;
++ struct notify_change_args args = {
++ .errp = &err,
++ .path = path,
++ .ia = ia
++ };
++
++ wkq_err = au_wkq_wait(call_notify_change, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct unlink_args {
++ int *errp;
++ struct inode *dir;
++ struct path *path;
++};
++
++static void call_unlink(void *args)
++{
++ struct unlink_args *a = args;
++ struct dentry *d = a->path->dentry;
++ struct inode *h_inode;
++ const int stop_sillyrename = (au_test_nfs(d->d_sb)
++ && atomic_read(&d->d_count) == 1);
++
++ IMustLock(a->dir);
++
++ a->path->dentry = d->d_parent;
++ *a->errp = security_path_unlink(a->path, d);
++ a->path->dentry = d;
++ if (unlikely(*a->errp))
++ return;
++
++ if (!stop_sillyrename)
++ dget(d);
++ h_inode = d->d_inode;
++ if (h_inode)
++ atomic_inc(&h_inode->i_count);
++
++ *a->errp = vfs_unlink(a->dir, d);
++ if (!*a->errp) {
++ struct path tmp = {
++ .dentry = d->d_parent,
++ .mnt = a->path->mnt
++ };
++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/
++ }
++
++ if (!stop_sillyrename)
++ dput(d);
++ if (h_inode)
++ iput(h_inode);
++
++ AuTraceErr(*a->errp);
++}
++
++/*
++ * @dir: must be locked.
++ * @dentry: target dentry.
++ */
++int vfsub_unlink(struct inode *dir, struct path *path, int force)
++{
++ int err;
++ struct unlink_args args = {
++ .errp = &err,
++ .dir = dir,
++ .path = path
++ };
++
++ if (!force)
++ call_unlink(&args);
++ else {
++ int wkq_err;
++
++ wkq_err = au_wkq_wait(call_unlink, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/vfsub.h linux-2.6.37/fs/aufs/vfsub.h
+--- linux-2.6.37.orig/fs/aufs/vfsub.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/vfsub.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,226 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * sub-routines for VFS
++ */
++
++#ifndef __AUFS_VFSUB_H__
++#define __AUFS_VFSUB_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/lglock.h>
++#include "debug.h"
++
++/* copied from linux/fs/internal.h */
++DECLARE_BRLOCK(vfsmount_lock);
++extern void file_sb_list_del(struct file *f);
++
++/* copied from linux/fs/file_table.c */
++DECLARE_LGLOCK(files_lglock);
++#ifdef CONFIG_SMP
++/*
++ * These macros iterate all files on all CPUs for a given superblock.
++ * files_lglock must be held globally.
++ */
++#define do_file_list_for_each_entry(__sb, __file) \
++{ \
++ int i; \
++ for_each_possible_cpu(i) { \
++ struct list_head *list; \
++ list = per_cpu_ptr((__sb)->s_files, i); \
++ list_for_each_entry((__file), list, f_u.fu_list)
++
++#define while_file_list_for_each_entry \
++ } \
++}
++
++#else
++
++#define do_file_list_for_each_entry(__sb, __file) \
++{ \
++ struct list_head *list; \
++ list = &(sb)->s_files; \
++ list_for_each_entry((__file), list, f_u.fu_list)
++
++#define while_file_list_for_each_entry \
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++/* lock subclass for lower inode */
++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */
++/* reduce? gave up. */
++enum {
++ AuLsc_I_Begin = I_MUTEX_QUOTA, /* 4 */
++ AuLsc_I_PARENT, /* lower inode, parent first */
++ AuLsc_I_PARENT2, /* copyup dirs */
++ AuLsc_I_PARENT3, /* copyup wh */
++ AuLsc_I_CHILD,
++ AuLsc_I_CHILD2,
++ AuLsc_I_End
++};
++
++/* to debug easier, do not make them inlined functions */
++#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx))
++#define IMustLock(i) MtxMustLock(&(i)->i_mutex)
++
++/* ---------------------------------------------------------------------- */
++
++static inline void vfsub_drop_nlink(struct inode *inode)
++{
++ AuDebugOn(!inode->i_nlink);
++ drop_nlink(inode);
++}
++
++static inline void vfsub_dead_dir(struct inode *inode)
++{
++ AuDebugOn(!S_ISDIR(inode->i_mode));
++ inode->i_flags |= S_DEAD;
++ clear_nlink(inode);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int vfsub_update_h_iattr(struct path *h_path, int *did);
++struct file *vfsub_dentry_open(struct path *path, int flags);
++struct file *vfsub_filp_open(const char *path, int oflags, int mode);
++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path);
++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
++ int len);
++struct dentry *vfsub_lookup_hash(struct nameidata *nd);
++
++/* ---------------------------------------------------------------------- */
++
++struct au_hinode;
++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2);
++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2);
++
++int vfsub_create(struct inode *dir, struct path *path, int mode);
++int vfsub_symlink(struct inode *dir, struct path *path,
++ const char *symname);
++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev);
++int vfsub_link(struct dentry *src_dentry, struct inode *dir,
++ struct path *path);
++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry,
++ struct inode *hdir, struct path *path);
++int vfsub_mkdir(struct inode *dir, struct path *path, int mode);
++int vfsub_rmdir(struct inode *dir, struct path *path);
++
++/* ---------------------------------------------------------------------- */
++
++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count,
++ loff_t *ppos);
++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count,
++ loff_t *ppos);
++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count,
++ loff_t *ppos);
++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count,
++ loff_t *ppos);
++int vfsub_flush(struct file *file, fl_owner_t id);
++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg);
++
++static inline unsigned int vfsub_file_flags(struct file *file)
++{
++ unsigned int flags;
++
++ spin_lock(&file->f_lock);
++ flags = file->f_flags;
++ spin_unlock(&file->f_lock);
++
++ return flags;
++}
++
++static inline void vfsub_file_accessed(struct file *h_file)
++{
++ file_accessed(h_file);
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/
++}
++
++static inline void vfsub_touch_atime(struct vfsmount *h_mnt,
++ struct dentry *h_dentry)
++{
++ struct path h_path = {
++ .dentry = h_dentry,
++ .mnt = h_mnt
++ };
++ touch_atime(h_mnt, h_dentry);
++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
++}
++
++long vfsub_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags);
++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags);
++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
++ struct file *h_file);
++
++/* ---------------------------------------------------------------------- */
++
++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin)
++{
++ loff_t err;
++
++ err = vfs_llseek(file, offset, origin);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* dirty workaround for strict type of fmode_t */
++union vfsub_fmu {
++ fmode_t fm;
++ unsigned int ui;
++};
++
++static inline unsigned int vfsub_fmode_to_uint(fmode_t fm)
++{
++ union vfsub_fmu u = {
++ .fm = fm
++ };
++
++ BUILD_BUG_ON(sizeof(u.fm) != sizeof(u.ui));
++
++ return u.ui;
++}
++
++static inline fmode_t vfsub_uint_to_fmode(unsigned int ui)
++{
++ union vfsub_fmu u = {
++ .ui = ui
++ };
++
++ return u.fm;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode);
++int vfsub_sio_rmdir(struct inode *dir, struct path *path);
++int vfsub_sio_notify_change(struct path *path, struct iattr *ia);
++int vfsub_notify_change(struct path *path, struct iattr *ia);
++int vfsub_unlink(struct inode *dir, struct path *path, int force);
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_VFSUB_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/wbr_policy.c linux-2.6.37/fs/aufs/wbr_policy.c
+--- linux-2.6.37.orig/fs/aufs/wbr_policy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/wbr_policy.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,700 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * policies for selecting one among multiple writable branches
++ */
++
++#include <linux/statfs.h>
++#include "aufs.h"
++
++/* subset of cpup_attr() */
++static noinline_for_stack
++int au_cpdown_attr(struct path *h_path, struct dentry *h_src)
++{
++ int err, sbits;
++ struct iattr ia;
++ struct inode *h_isrc;
++
++ h_isrc = h_src->d_inode;
++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID;
++ ia.ia_mode = h_isrc->i_mode;
++ ia.ia_uid = h_isrc->i_uid;
++ ia.ia_gid = h_isrc->i_gid;
++ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID));
++ au_cpup_attr_flags(h_path->dentry->d_inode, h_isrc);
++ err = vfsub_sio_notify_change(h_path, &ia);
++
++ /* is this nfs only? */
++ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) {
++ ia.ia_valid = ATTR_FORCE | ATTR_MODE;
++ ia.ia_mode = h_isrc->i_mode;
++ err = vfsub_sio_notify_change(h_path, &ia);
++ }
++
++ return err;
++}
++
++#define AuCpdown_PARENT_OPQ 1
++#define AuCpdown_WHED (1 << 1)
++#define AuCpdown_MADE_DIR (1 << 2)
++#define AuCpdown_DIROPQ (1 << 3)
++#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name)
++#define au_fset_cpdown(flags, name) \
++ do { (flags) |= AuCpdown_##name; } while (0)
++#define au_fclr_cpdown(flags, name) \
++ do { (flags) &= ~AuCpdown_##name; } while (0)
++
++struct au_cpdown_dir_args {
++ struct dentry *parent;
++ unsigned int flags;
++};
++
++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst,
++ struct au_cpdown_dir_args *a)
++{
++ int err;
++ struct dentry *opq_dentry;
++
++ opq_dentry = au_diropq_create(dentry, bdst);
++ err = PTR_ERR(opq_dentry);
++ if (IS_ERR(opq_dentry))
++ goto out;
++ dput(opq_dentry);
++ au_fset_cpdown(a->flags, DIROPQ);
++
++out:
++ return err;
++}
++
++static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent,
++ struct inode *dir, aufs_bindex_t bdst)
++{
++ int err;
++ struct path h_path;
++ struct au_branch *br;
++
++ br = au_sbr(dentry->d_sb, bdst);
++ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br);
++ err = PTR_ERR(h_path.dentry);
++ if (IS_ERR(h_path.dentry))
++ goto out;
++
++ err = 0;
++ if (h_path.dentry->d_inode) {
++ h_path.mnt = br->br_mnt;
++ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path,
++ dentry);
++ }
++ dput(h_path.dentry);
++
++out:
++ return err;
++}
++
++static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent, void *arg)
++{
++ int err, rerr;
++ aufs_bindex_t bopq, bstart;
++ struct path h_path;
++ struct dentry *parent;
++ struct inode *h_dir, *h_inode, *inode, *dir;
++ struct au_cpdown_dir_args *args = arg;
++
++ bstart = au_dbstart(dentry);
++ /* dentry is di-locked */
++ parent = dget_parent(dentry);
++ dir = parent->d_inode;
++ h_dir = h_parent->d_inode;
++ AuDebugOn(h_dir != au_h_iptr(dir, bdst));
++ IMustLock(h_dir);
++
++ err = au_lkup_neg(dentry, bdst);
++ if (unlikely(err < 0))
++ goto out;
++ h_path.dentry = au_h_dptr(dentry, bdst);
++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst);
++ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path,
++ S_IRWXU | S_IRUGO | S_IXUGO);
++ if (unlikely(err))
++ goto out_put;
++ au_fset_cpdown(args->flags, MADE_DIR);
++
++ bopq = au_dbdiropq(dentry);
++ au_fclr_cpdown(args->flags, WHED);
++ au_fclr_cpdown(args->flags, DIROPQ);
++ if (au_dbwh(dentry) == bdst)
++ au_fset_cpdown(args->flags, WHED);
++ if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst)
++ au_fset_cpdown(args->flags, PARENT_OPQ);
++ h_inode = h_path.dentry->d_inode;
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ if (au_ftest_cpdown(args->flags, WHED)) {
++ err = au_cpdown_dir_opq(dentry, bdst, args);
++ if (unlikely(err)) {
++ mutex_unlock(&h_inode->i_mutex);
++ goto out_dir;
++ }
++ }
++
++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart));
++ mutex_unlock(&h_inode->i_mutex);
++ if (unlikely(err))
++ goto out_opq;
++
++ if (au_ftest_cpdown(args->flags, WHED)) {
++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst);
++ if (unlikely(err))
++ goto out_opq;
++ }
++
++ inode = dentry->d_inode;
++ if (au_ibend(inode) < bdst)
++ au_set_ibend(inode, bdst);
++ au_set_h_iptr(inode, bdst, au_igrab(h_inode),
++ au_hi_flags(inode, /*isdir*/1));
++ goto out; /* success */
++
++ /* revert */
++out_opq:
++ if (au_ftest_cpdown(args->flags, DIROPQ)) {
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ rerr = au_diropq_remove(dentry, bdst);
++ mutex_unlock(&h_inode->i_mutex);
++ if (unlikely(rerr)) {
++ AuIOErr("failed removing diropq for %.*s b%d (%d)\n",
++ AuDLNPair(dentry), bdst, rerr);
++ err = -EIO;
++ goto out;
++ }
++ }
++out_dir:
++ if (au_ftest_cpdown(args->flags, MADE_DIR)) {
++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path);
++ if (unlikely(rerr)) {
++ AuIOErr("failed removing %.*s b%d (%d)\n",
++ AuDLNPair(dentry), bdst, rerr);
++ err = -EIO;
++ }
++ }
++out_put:
++ au_set_h_dptr(dentry, bdst, NULL);
++ if (au_dbend(dentry) == bdst)
++ au_update_dbend(dentry);
++out:
++ dput(parent);
++ return err;
++}
++
++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst)
++{
++ int err;
++ struct au_cpdown_dir_args args = {
++ .parent = dget_parent(dentry),
++ .flags = 0
++ };
++
++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &args);
++ dput(args.parent);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* policies for create */
++
++static int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ int err, i, j, ndentry;
++ aufs_bindex_t bopq;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries, *parent, *d;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ parent = dget_parent(dentry);
++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0);
++ if (unlikely(err))
++ goto out_free;
++
++ err = bindex;
++ for (i = 0; i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ ndentry = dpage->ndentry;
++ for (j = 0; j < ndentry; j++) {
++ d = dentries[j];
++ di_read_lock_parent2(d, !AuLock_IR);
++ bopq = au_dbdiropq(d);
++ di_read_unlock(d, !AuLock_IR);
++ if (bopq >= 0 && bopq < err)
++ err = bopq;
++ }
++ }
++
++out_free:
++ dput(parent);
++ au_dpages_free(&dpages);
++out:
++ return err;
++}
++
++static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex)
++{
++ for (; bindex >= 0; bindex--)
++ if (!au_br_rdonly(au_sbr(sb, bindex)))
++ return bindex;
++ return -EROFS;
++}
++
++/* top down parent */
++static int au_wbr_create_tdp(struct dentry *dentry, int isdir __maybe_unused)
++{
++ int err;
++ aufs_bindex_t bstart, bindex;
++ struct super_block *sb;
++ struct dentry *parent, *h_parent;
++
++ sb = dentry->d_sb;
++ bstart = au_dbstart(dentry);
++ err = bstart;
++ if (!au_br_rdonly(au_sbr(sb, bstart)))
++ goto out;
++
++ err = -EROFS;
++ parent = dget_parent(dentry);
++ for (bindex = au_dbstart(parent); bindex < bstart; bindex++) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent || !h_parent->d_inode)
++ continue;
++
++ if (!au_br_rdonly(au_sbr(sb, bindex))) {
++ err = bindex;
++ break;
++ }
++ }
++ dput(parent);
++
++ /* bottom up here */
++ if (unlikely(err < 0)) {
++ err = au_wbr_bu(sb, bstart - 1);
++ if (err >= 0)
++ err = au_wbr_nonopq(dentry, err);
++ }
++
++out:
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* an exception for the policy other than tdp */
++static int au_wbr_create_exp(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bwh, bdiropq;
++ struct dentry *parent;
++
++ err = -1;
++ bwh = au_dbwh(dentry);
++ parent = dget_parent(dentry);
++ bdiropq = au_dbdiropq(parent);
++ if (bwh >= 0) {
++ if (bdiropq >= 0)
++ err = min(bdiropq, bwh);
++ else
++ err = bwh;
++ AuDbg("%d\n", err);
++ } else if (bdiropq >= 0) {
++ err = bdiropq;
++ AuDbg("%d\n", err);
++ }
++ dput(parent);
++
++ if (err >= 0)
++ err = au_wbr_nonopq(dentry, err);
++
++ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err)))
++ err = -1;
++
++ AuDbg("%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* round robin */
++static int au_wbr_create_init_rr(struct super_block *sb)
++{
++ int err;
++
++ err = au_wbr_bu(sb, au_sbend(sb));
++ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */
++ /* smp_mb(); */
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++static int au_wbr_create_rr(struct dentry *dentry, int isdir)
++{
++ int err, nbr;
++ unsigned int u;
++ aufs_bindex_t bindex, bend;
++ struct super_block *sb;
++ atomic_t *next;
++
++ err = au_wbr_create_exp(dentry);
++ if (err >= 0)
++ goto out;
++
++ sb = dentry->d_sb;
++ next = &au_sbi(sb)->si_wbr_rr_next;
++ bend = au_sbend(sb);
++ nbr = bend + 1;
++ for (bindex = 0; bindex <= bend; bindex++) {
++ if (!isdir) {
++ err = atomic_dec_return(next) + 1;
++ /* modulo for 0 is meaningless */
++ if (unlikely(!err))
++ err = atomic_dec_return(next) + 1;
++ } else
++ err = atomic_read(next);
++ AuDbg("%d\n", err);
++ u = err;
++ err = u % nbr;
++ AuDbg("%d\n", err);
++ if (!au_br_rdonly(au_sbr(sb, err)))
++ break;
++ err = -EROFS;
++ }
++
++ if (err >= 0)
++ err = au_wbr_nonopq(dentry, err);
++
++out:
++ AuDbg("%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* most free space */
++static void au_mfs(struct dentry *dentry)
++{
++ struct super_block *sb;
++ struct au_branch *br;
++ struct au_wbr_mfs *mfs;
++ aufs_bindex_t bindex, bend;
++ int err;
++ unsigned long long b, bavail;
++ struct path h_path;
++ /* reduce the stack usage */
++ struct kstatfs *st;
++
++ st = kmalloc(sizeof(*st), GFP_NOFS);
++ if (unlikely(!st)) {
++ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM);
++ return;
++ }
++
++ bavail = 0;
++ sb = dentry->d_sb;
++ mfs = &au_sbi(sb)->si_wbr_mfs;
++ MtxMustLock(&mfs->mfs_lock);
++ mfs->mfs_bindex = -EROFS;
++ mfs->mfsrr_bytes = 0;
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (au_br_rdonly(br))
++ continue;
++
++ /* sb->s_root for NFS is unreliable */
++ h_path.mnt = br->br_mnt;
++ h_path.dentry = h_path.mnt->mnt_root;
++ err = vfs_statfs(&h_path, st);
++ if (unlikely(err)) {
++ AuWarn1("failed statfs, b%d, %d\n", bindex, err);
++ continue;
++ }
++
++ /* when the available size is equal, select the lower one */
++ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail)
++ || sizeof(b) < sizeof(st->f_bsize));
++ b = st->f_bavail * st->f_bsize;
++ br->br_wbr->wbr_bytes = b;
++ if (b >= bavail) {
++ bavail = b;
++ mfs->mfs_bindex = bindex;
++ mfs->mfs_jiffy = jiffies;
++ }
++ }
++
++ mfs->mfsrr_bytes = bavail;
++ AuDbg("b%d\n", mfs->mfs_bindex);
++ kfree(st);
++}
++
++static int au_wbr_create_mfs(struct dentry *dentry, int isdir __maybe_unused)
++{
++ int err;
++ struct super_block *sb;
++ struct au_wbr_mfs *mfs;
++
++ err = au_wbr_create_exp(dentry);
++ if (err >= 0)
++ goto out;
++
++ sb = dentry->d_sb;
++ mfs = &au_sbi(sb)->si_wbr_mfs;
++ mutex_lock(&mfs->mfs_lock);
++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire)
++ || mfs->mfs_bindex < 0
++ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex)))
++ au_mfs(dentry);
++ mutex_unlock(&mfs->mfs_lock);
++ err = mfs->mfs_bindex;
++
++ if (err >= 0)
++ err = au_wbr_nonopq(dentry, err);
++
++out:
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++static int au_wbr_create_init_mfs(struct super_block *sb)
++{
++ struct au_wbr_mfs *mfs;
++
++ mfs = &au_sbi(sb)->si_wbr_mfs;
++ mutex_init(&mfs->mfs_lock);
++ mfs->mfs_jiffy = 0;
++ mfs->mfs_bindex = -EROFS;
++
++ return 0;
++}
++
++static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused)
++{
++ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock);
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* most free space and then round robin */
++static int au_wbr_create_mfsrr(struct dentry *dentry, int isdir)
++{
++ int err;
++ struct au_wbr_mfs *mfs;
++
++ err = au_wbr_create_mfs(dentry, isdir);
++ if (err >= 0) {
++ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs;
++ mutex_lock(&mfs->mfs_lock);
++ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark)
++ err = au_wbr_create_rr(dentry, isdir);
++ mutex_unlock(&mfs->mfs_lock);
++ }
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++static int au_wbr_create_init_mfsrr(struct super_block *sb)
++{
++ int err;
++
++ au_wbr_create_init_mfs(sb); /* ignore */
++ err = au_wbr_create_init_rr(sb);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* top down parent and most free space */
++static int au_wbr_create_pmfs(struct dentry *dentry, int isdir)
++{
++ int err, e2;
++ unsigned long long b;
++ aufs_bindex_t bindex, bstart, bend;
++ struct super_block *sb;
++ struct dentry *parent, *h_parent;
++ struct au_branch *br;
++
++ err = au_wbr_create_tdp(dentry, isdir);
++ if (unlikely(err < 0))
++ goto out;
++ parent = dget_parent(dentry);
++ bstart = au_dbstart(parent);
++ bend = au_dbtaildir(parent);
++ if (bstart == bend)
++ goto out_parent; /* success */
++
++ e2 = au_wbr_create_mfs(dentry, isdir);
++ if (e2 < 0)
++ goto out_parent; /* success */
++
++ /* when the available size is equal, select upper one */
++ sb = dentry->d_sb;
++ br = au_sbr(sb, err);
++ b = br->br_wbr->wbr_bytes;
++ AuDbg("b%d, %llu\n", err, b);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent || !h_parent->d_inode)
++ continue;
++
++ br = au_sbr(sb, bindex);
++ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) {
++ b = br->br_wbr->wbr_bytes;
++ err = bindex;
++ AuDbg("b%d, %llu\n", err, b);
++ }
++ }
++
++ if (err >= 0)
++ err = au_wbr_nonopq(dentry, err);
++
++out_parent:
++ dput(parent);
++out:
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* policies for copyup */
++
++/* top down parent */
++static int au_wbr_copyup_tdp(struct dentry *dentry)
++{
++ return au_wbr_create_tdp(dentry, /*isdir, anything is ok*/0);
++}
++
++/* bottom up parent */
++static int au_wbr_copyup_bup(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bindex, bstart;
++ struct dentry *parent, *h_parent;
++ struct super_block *sb;
++
++ err = -EROFS;
++ sb = dentry->d_sb;
++ parent = dget_parent(dentry);
++ bstart = au_dbstart(parent);
++ for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent || !h_parent->d_inode)
++ continue;
++
++ if (!au_br_rdonly(au_sbr(sb, bindex))) {
++ err = bindex;
++ break;
++ }
++ }
++ dput(parent);
++
++ /* bottom up here */
++ if (unlikely(err < 0))
++ err = au_wbr_bu(sb, bstart - 1);
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* bottom up */
++static int au_wbr_copyup_bu(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bstart;
++
++ bstart = au_dbstart(dentry);
++ err = au_wbr_bu(dentry->d_sb, bstart);
++ AuDbg("b%d\n", err);
++ if (err > bstart)
++ err = au_wbr_nonopq(dentry, err);
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_wbr_copyup_operations au_wbr_copyup_ops[] = {
++ [AuWbrCopyup_TDP] = {
++ .copyup = au_wbr_copyup_tdp
++ },
++ [AuWbrCopyup_BUP] = {
++ .copyup = au_wbr_copyup_bup
++ },
++ [AuWbrCopyup_BU] = {
++ .copyup = au_wbr_copyup_bu
++ }
++};
++
++struct au_wbr_create_operations au_wbr_create_ops[] = {
++ [AuWbrCreate_TDP] = {
++ .create = au_wbr_create_tdp
++ },
++ [AuWbrCreate_RR] = {
++ .create = au_wbr_create_rr,
++ .init = au_wbr_create_init_rr
++ },
++ [AuWbrCreate_MFS] = {
++ .create = au_wbr_create_mfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_MFSV] = {
++ .create = au_wbr_create_mfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_MFSRR] = {
++ .create = au_wbr_create_mfsrr,
++ .init = au_wbr_create_init_mfsrr,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_MFSRRV] = {
++ .create = au_wbr_create_mfsrr,
++ .init = au_wbr_create_init_mfsrr,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_PMFS] = {
++ .create = au_wbr_create_pmfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_PMFSV] = {
++ .create = au_wbr_create_pmfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ }
++};
+diff -Nur linux-2.6.37.orig/fs/aufs/whout.c linux-2.6.37/fs/aufs/whout.c
+--- linux-2.6.37.orig/fs/aufs/whout.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/whout.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,1062 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * whiteout for logical deletion and opaque directory
++ */
++
++#include <linux/fs.h>
++#include "aufs.h"
++
++#define WH_MASK S_IRUGO
++
++/*
++ * If a directory contains this file, then it is opaque. We start with the
++ * .wh. flag so that it is blocked by lookup.
++ */
++static struct qstr diropq_name = {
++ .name = AUFS_WH_DIROPQ,
++ .len = sizeof(AUFS_WH_DIROPQ) - 1
++};
++
++/*
++ * generate whiteout name, which is NOT terminated by NULL.
++ * @name: original d_name.name
++ * @len: original d_name.len
++ * @wh: whiteout qstr
++ * returns zero when succeeds, otherwise error.
++ * succeeded value as wh->name should be freed by kfree().
++ */
++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name)
++{
++ char *p;
++
++ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN))
++ return -ENAMETOOLONG;
++
++ wh->len = name->len + AUFS_WH_PFX_LEN;
++ p = kmalloc(wh->len, GFP_NOFS);
++ wh->name = p;
++ if (p) {
++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
++ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len);
++ /* smp_mb(); */
++ return 0;
++ }
++ return -ENOMEM;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * test if the @wh_name exists under @h_parent.
++ * @try_sio specifies the necessary of super-io.
++ */
++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name,
++ struct au_branch *br, int try_sio)
++{
++ int err;
++ struct dentry *wh_dentry;
++
++ if (!try_sio)
++ wh_dentry = au_lkup_one(wh_name, h_parent, br, /*nd*/NULL);
++ else
++ wh_dentry = au_sio_lkup_one(wh_name, h_parent, br);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out;
++
++ err = 0;
++ if (!wh_dentry->d_inode)
++ goto out_wh; /* success */
++
++ err = 1;
++ if (S_ISREG(wh_dentry->d_inode->i_mode))
++ goto out_wh; /* success */
++
++ err = -EIO;
++ AuIOErr("%.*s Invalid whiteout entry type 0%o.\n",
++ AuDLNPair(wh_dentry), wh_dentry->d_inode->i_mode);
++
++out_wh:
++ dput(wh_dentry);
++out:
++ return err;
++}
++
++/*
++ * test if the @h_dentry sets opaque or not.
++ */
++int au_diropq_test(struct dentry *h_dentry, struct au_branch *br)
++{
++ int err;
++ struct inode *h_dir;
++
++ h_dir = h_dentry->d_inode;
++ err = au_wh_test(h_dentry, &diropq_name, br,
++ au_test_h_perm_sio(h_dir, MAY_EXEC));
++ return err;
++}
++
++/*
++ * returns a negative dentry whose name is unique and temporary.
++ */
++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
++ struct qstr *prefix)
++{
++ struct dentry *dentry;
++ int i;
++ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN_MIN + 1],
++ *name, *p;
++ /* strict atomic_t is unnecessary here */
++ static unsigned short cnt;
++ struct qstr qs;
++
++ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN);
++
++ name = defname;
++ qs.len = sizeof(defname) - DNAME_INLINE_LEN_MIN + prefix->len - 1;
++ if (unlikely(prefix->len > DNAME_INLINE_LEN_MIN)) {
++ dentry = ERR_PTR(-ENAMETOOLONG);
++ if (unlikely(qs.len > NAME_MAX))
++ goto out;
++ dentry = ERR_PTR(-ENOMEM);
++ name = kmalloc(qs.len + 1, GFP_NOFS);
++ if (unlikely(!name))
++ goto out;
++ }
++
++ /* doubly whiteout-ed */
++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2);
++ p = name + AUFS_WH_PFX_LEN * 2;
++ memcpy(p, prefix->name, prefix->len);
++ p += prefix->len;
++ *p++ = '.';
++ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN);
++
++ qs.name = name;
++ for (i = 0; i < 3; i++) {
++ sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++);
++ dentry = au_sio_lkup_one(&qs, h_parent, br);
++ if (IS_ERR(dentry) || !dentry->d_inode)
++ goto out_name;
++ dput(dentry);
++ }
++ /* pr_warning("could not get random name\n"); */
++ dentry = ERR_PTR(-EEXIST);
++ AuDbg("%.*s\n", AuLNPair(&qs));
++ BUG();
++
++out_name:
++ if (name != defname)
++ kfree(name);
++out:
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++/*
++ * rename the @h_dentry on @br to the whiteouted temporary name.
++ */
++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br)
++{
++ int err;
++ struct path h_path = {
++ .mnt = br->br_mnt
++ };
++ struct inode *h_dir;
++ struct dentry *h_parent;
++
++ h_parent = h_dentry->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++
++ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name);
++ err = PTR_ERR(h_path.dentry);
++ if (IS_ERR(h_path.dentry))
++ goto out;
++
++ /* under the same dir, no need to lock_rename() */
++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path);
++ AuTraceErr(err);
++ dput(h_path.dentry);
++
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * functions for removing a whiteout
++ */
++
++static int do_unlink_wh(struct inode *h_dir, struct path *h_path)
++{
++ int force;
++
++ /*
++ * forces superio when the dir has a sticky bit.
++ * this may be a violation of unix fs semantics.
++ */
++ force = (h_dir->i_mode & S_ISVTX)
++ && h_path->dentry->d_inode->i_uid != current_fsuid();
++ return vfsub_unlink(h_dir, h_path, force);
++}
++
++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path,
++ struct dentry *dentry)
++{
++ int err;
++
++ err = do_unlink_wh(h_dir, h_path);
++ if (!err && dentry)
++ au_set_dbwh(dentry, -1);
++
++ return err;
++}
++
++static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh,
++ struct au_branch *br)
++{
++ int err;
++ struct path h_path = {
++ .mnt = br->br_mnt
++ };
++
++ err = 0;
++ h_path.dentry = au_lkup_one(wh, h_parent, br, /*nd*/NULL);
++ if (IS_ERR(h_path.dentry))
++ err = PTR_ERR(h_path.dentry);
++ else {
++ if (h_path.dentry->d_inode
++ && S_ISREG(h_path.dentry->d_inode->i_mode))
++ err = do_unlink_wh(h_parent->d_inode, &h_path);
++ dput(h_path.dentry);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * initialize/clean whiteout for a branch
++ */
++
++static void au_wh_clean(struct inode *h_dir, struct path *whpath,
++ const int isdir)
++{
++ int err;
++
++ if (!whpath->dentry->d_inode)
++ return;
++
++ err = mnt_want_write(whpath->mnt);
++ if (!err) {
++ if (isdir)
++ err = vfsub_rmdir(h_dir, whpath);
++ else
++ err = vfsub_unlink(h_dir, whpath, /*force*/0);
++ mnt_drop_write(whpath->mnt);
++ }
++ if (unlikely(err))
++ pr_warning("failed removing %.*s (%d), ignored.\n",
++ AuDLNPair(whpath->dentry), err);
++}
++
++static int test_linkable(struct dentry *h_root)
++{
++ struct inode *h_dir = h_root->d_inode;
++
++ if (h_dir->i_op->link)
++ return 0;
++
++ pr_err("%.*s (%s) doesn't support link(2), use noplink and rw+nolwh\n",
++ AuDLNPair(h_root), au_sbtype(h_root->d_sb));
++ return -ENOSYS;
++}
++
++/* todo: should this mkdir be done in /sbin/mount.aufs helper? */
++static int au_whdir(struct inode *h_dir, struct path *path)
++{
++ int err;
++
++ err = -EEXIST;
++ if (!path->dentry->d_inode) {
++ int mode = S_IRWXU;
++
++ if (au_test_nfs(path->dentry->d_sb))
++ mode |= S_IXUGO;
++ err = mnt_want_write(path->mnt);
++ if (!err) {
++ err = vfsub_mkdir(h_dir, path, mode);
++ mnt_drop_write(path->mnt);
++ }
++ } else if (S_ISDIR(path->dentry->d_inode->i_mode))
++ err = 0;
++ else
++ pr_err("unknown %.*s exists\n", AuDLNPair(path->dentry));
++
++ return err;
++}
++
++struct au_wh_base {
++ const struct qstr *name;
++ struct dentry *dentry;
++};
++
++static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[],
++ struct path *h_path)
++{
++ h_path->dentry = base[AuBrWh_BASE].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/0);
++ h_path->dentry = base[AuBrWh_PLINK].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++ h_path->dentry = base[AuBrWh_ORPH].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++}
++
++/*
++ * returns tri-state,
++ * minus: error, caller should print the mesage
++ * zero: succuess
++ * plus: error, caller should NOT print the mesage
++ */
++static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr,
++ int do_plink, struct au_wh_base base[],
++ struct path *h_path)
++{
++ int err;
++ struct inode *h_dir;
++
++ h_dir = h_root->d_inode;
++ h_path->dentry = base[AuBrWh_BASE].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/0);
++ h_path->dentry = base[AuBrWh_PLINK].dentry;
++ if (do_plink) {
++ err = test_linkable(h_root);
++ if (unlikely(err)) {
++ err = 1;
++ goto out;
++ }
++
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry);
++ } else
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++ h_path->dentry = base[AuBrWh_ORPH].dentry;
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry);
++
++out:
++ return err;
++}
++
++/*
++ * for the moment, aufs supports the branch filesystem which does not support
++ * link(2). testing on FAT which does not support i_op->setattr() fully either,
++ * copyup failed. finally, such filesystem will not be used as the writable
++ * branch.
++ *
++ * returns tri-state, see above.
++ */
++static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr,
++ int do_plink, struct au_wh_base base[],
++ struct path *h_path)
++{
++ int err;
++ struct inode *h_dir;
++
++ WbrWhMustWriteLock(wbr);
++
++ err = test_linkable(h_root);
++ if (unlikely(err)) {
++ err = 1;
++ goto out;
++ }
++
++ /*
++ * todo: should this create be done in /sbin/mount.aufs helper?
++ */
++ err = -EEXIST;
++ h_dir = h_root->d_inode;
++ if (!base[AuBrWh_BASE].dentry->d_inode) {
++ err = mnt_want_write(h_path->mnt);
++ if (!err) {
++ h_path->dentry = base[AuBrWh_BASE].dentry;
++ err = vfsub_create(h_dir, h_path, WH_MASK);
++ mnt_drop_write(h_path->mnt);
++ }
++ } else if (S_ISREG(base[AuBrWh_BASE].dentry->d_inode->i_mode))
++ err = 0;
++ else
++ pr_err("unknown %.*s/%.*s exists\n",
++ AuDLNPair(h_root), AuDLNPair(base[AuBrWh_BASE].dentry));
++ if (unlikely(err))
++ goto out;
++
++ h_path->dentry = base[AuBrWh_PLINK].dentry;
++ if (do_plink) {
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry);
++ } else
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry);
++
++ h_path->dentry = base[AuBrWh_ORPH].dentry;
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry);
++
++out:
++ return err;
++}
++
++/*
++ * initialize the whiteout base file/dir for @br.
++ */
++int au_wh_init(struct dentry *h_root, struct au_branch *br,
++ struct super_block *sb)
++{
++ int err, i;
++ const unsigned char do_plink
++ = !!au_opt_test(au_mntflags(sb), PLINK);
++ struct path path = {
++ .mnt = br->br_mnt
++ };
++ struct inode *h_dir;
++ struct au_wbr *wbr = br->br_wbr;
++ static const struct qstr base_name[] = {
++ [AuBrWh_BASE] = {
++ .name = AUFS_BASE_NAME,
++ .len = sizeof(AUFS_BASE_NAME) - 1
++ },
++ [AuBrWh_PLINK] = {
++ .name = AUFS_PLINKDIR_NAME,
++ .len = sizeof(AUFS_PLINKDIR_NAME) - 1
++ },
++ [AuBrWh_ORPH] = {
++ .name = AUFS_ORPHDIR_NAME,
++ .len = sizeof(AUFS_ORPHDIR_NAME) - 1
++ }
++ };
++ struct au_wh_base base[] = {
++ [AuBrWh_BASE] = {
++ .name = base_name + AuBrWh_BASE,
++ .dentry = NULL
++ },
++ [AuBrWh_PLINK] = {
++ .name = base_name + AuBrWh_PLINK,
++ .dentry = NULL
++ },
++ [AuBrWh_ORPH] = {
++ .name = base_name + AuBrWh_ORPH,
++ .dentry = NULL
++ }
++ };
++
++ if (wbr)
++ WbrWhMustWriteLock(wbr);
++
++ for (i = 0; i < AuBrWh_Last; i++) {
++ /* doubly whiteouted */
++ struct dentry *d;
++
++ d = au_wh_lkup(h_root, (void *)base[i].name, br);
++ err = PTR_ERR(d);
++ if (IS_ERR(d))
++ goto out;
++
++ base[i].dentry = d;
++ AuDebugOn(wbr
++ && wbr->wbr_wh[i]
++ && wbr->wbr_wh[i] != base[i].dentry);
++ }
++
++ if (wbr)
++ for (i = 0; i < AuBrWh_Last; i++) {
++ dput(wbr->wbr_wh[i]);
++ wbr->wbr_wh[i] = NULL;
++ }
++
++ err = 0;
++ switch (br->br_perm) {
++ case AuBrPerm_RO:
++ case AuBrPerm_ROWH:
++ case AuBrPerm_RR:
++ case AuBrPerm_RRWH:
++ h_dir = h_root->d_inode;
++ au_wh_init_ro(h_dir, base, &path);
++ break;
++
++ case AuBrPerm_RWNoLinkWH:
++ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path);
++ if (err > 0)
++ goto out;
++ else if (err)
++ goto out_err;
++ break;
++
++ case AuBrPerm_RW:
++ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path);
++ if (err > 0)
++ goto out;
++ else if (err)
++ goto out_err;
++ break;
++
++ default:
++ BUG();
++ }
++ goto out; /* success */
++
++out_err:
++ pr_err("an error(%d) on the writable branch %.*s(%s)\n",
++ err, AuDLNPair(h_root), au_sbtype(h_root->d_sb));
++out:
++ for (i = 0; i < AuBrWh_Last; i++)
++ dput(base[i].dentry);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * whiteouts are all hard-linked usually.
++ * when its link count reaches a ceiling, we create a new whiteout base
++ * asynchronously.
++ */
++
++struct reinit_br_wh {
++ struct super_block *sb;
++ struct au_branch *br;
++};
++
++static void reinit_br_wh(void *arg)
++{
++ int err;
++ aufs_bindex_t bindex;
++ struct path h_path;
++ struct reinit_br_wh *a = arg;
++ struct au_wbr *wbr;
++ struct inode *dir;
++ struct dentry *h_root;
++ struct au_hinode *hdir;
++
++ err = 0;
++ wbr = a->br->br_wbr;
++ /* big aufs lock */
++ si_noflush_write_lock(a->sb);
++ if (!au_br_writable(a->br->br_perm))
++ goto out;
++ bindex = au_br_index(a->sb, a->br->br_id);
++ if (unlikely(bindex < 0))
++ goto out;
++
++ di_read_lock_parent(a->sb->s_root, AuLock_IR);
++ dir = a->sb->s_root->d_inode;
++ hdir = au_hi(dir, bindex);
++ h_root = au_h_dptr(a->sb->s_root, bindex);
++
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ wbr_wh_write_lock(wbr);
++ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode,
++ h_root, a->br);
++ if (!err) {
++ err = mnt_want_write(a->br->br_mnt);
++ if (!err) {
++ h_path.dentry = wbr->wbr_whbase;
++ h_path.mnt = a->br->br_mnt;
++ err = vfsub_unlink(hdir->hi_inode, &h_path, /*force*/0);
++ mnt_drop_write(a->br->br_mnt);
++ }
++ } else {
++ pr_warning("%.*s is moved, ignored\n",
++ AuDLNPair(wbr->wbr_whbase));
++ err = 0;
++ }
++ dput(wbr->wbr_whbase);
++ wbr->wbr_whbase = NULL;
++ if (!err)
++ err = au_wh_init(h_root, a->br, a->sb);
++ wbr_wh_write_unlock(wbr);
++ au_hn_imtx_unlock(hdir);
++ di_read_unlock(a->sb->s_root, AuLock_IR);
++
++out:
++ if (wbr)
++ atomic_dec(&wbr->wbr_wh_running);
++ atomic_dec(&a->br->br_count);
++ si_write_unlock(a->sb);
++ au_nwt_done(&au_sbi(a->sb)->si_nowait);
++ kfree(arg);
++ if (unlikely(err))
++ AuIOErr("err %d\n", err);
++}
++
++static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br)
++{
++ int do_dec, wkq_err;
++ struct reinit_br_wh *arg;
++
++ do_dec = 1;
++ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1)
++ goto out;
++
++ /* ignore ENOMEM */
++ arg = kmalloc(sizeof(*arg), GFP_NOFS);
++ if (arg) {
++ /*
++ * dec(wh_running), kfree(arg) and dec(br_count)
++ * in reinit function
++ */
++ arg->sb = sb;
++ arg->br = br;
++ atomic_inc(&br->br_count);
++ wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb);
++ if (unlikely(wkq_err)) {
++ atomic_dec(&br->br_wbr->wbr_wh_running);
++ atomic_dec(&br->br_count);
++ kfree(arg);
++ }
++ do_dec = 0;
++ }
++
++out:
++ if (do_dec)
++ atomic_dec(&br->br_wbr->wbr_wh_running);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create the whiteout @wh.
++ */
++static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex,
++ struct dentry *wh)
++{
++ int err;
++ struct path h_path = {
++ .dentry = wh
++ };
++ struct au_branch *br;
++ struct au_wbr *wbr;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++
++ h_parent = wh->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++
++ br = au_sbr(sb, bindex);
++ h_path.mnt = br->br_mnt;
++ wbr = br->br_wbr;
++ wbr_wh_read_lock(wbr);
++ if (wbr->wbr_whbase) {
++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path);
++ if (!err || err != -EMLINK)
++ goto out;
++
++ /* link count full. re-initialize br_whbase. */
++ kick_reinit_br_wh(sb, br);
++ }
++
++ /* return this error in this context */
++ err = vfsub_create(h_dir, &h_path, WH_MASK);
++
++out:
++ wbr_wh_read_unlock(wbr);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create or remove the diropq.
++ */
++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int flags)
++{
++ struct dentry *opq_dentry, *h_dentry;
++ struct super_block *sb;
++ struct au_branch *br;
++ int err;
++
++ sb = dentry->d_sb;
++ br = au_sbr(sb, bindex);
++ h_dentry = au_h_dptr(dentry, bindex);
++ opq_dentry = au_lkup_one(&diropq_name, h_dentry, br, /*nd*/NULL);
++ if (IS_ERR(opq_dentry))
++ goto out;
++
++ if (au_ftest_diropq(flags, CREATE)) {
++ err = link_or_create_wh(sb, bindex, opq_dentry);
++ if (!err) {
++ au_set_dbdiropq(dentry, bindex);
++ goto out; /* success */
++ }
++ } else {
++ struct path tmp = {
++ .dentry = opq_dentry,
++ .mnt = br->br_mnt
++ };
++ err = do_unlink_wh(au_h_iptr(dentry->d_inode, bindex), &tmp);
++ if (!err)
++ au_set_dbdiropq(dentry, -1);
++ }
++ dput(opq_dentry);
++ opq_dentry = ERR_PTR(err);
++
++out:
++ return opq_dentry;
++}
++
++struct do_diropq_args {
++ struct dentry **errp;
++ struct dentry *dentry;
++ aufs_bindex_t bindex;
++ unsigned int flags;
++};
++
++static void call_do_diropq(void *args)
++{
++ struct do_diropq_args *a = args;
++ *a->errp = do_diropq(a->dentry, a->bindex, a->flags);
++}
++
++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int flags)
++{
++ struct dentry *diropq, *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!au_test_h_perm_sio(h_dentry->d_inode, MAY_EXEC | MAY_WRITE))
++ diropq = do_diropq(dentry, bindex, flags);
++ else {
++ int wkq_err;
++ struct do_diropq_args args = {
++ .errp = &diropq,
++ .dentry = dentry,
++ .bindex = bindex,
++ .flags = flags
++ };
++
++ wkq_err = au_wkq_wait(call_do_diropq, &args);
++ if (unlikely(wkq_err))
++ diropq = ERR_PTR(wkq_err);
++ }
++
++ return diropq;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * lookup whiteout dentry.
++ * @h_parent: lower parent dentry which must exist and be locked
++ * @base_name: name of dentry which will be whiteouted
++ * returns dentry for whiteout.
++ */
++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name,
++ struct au_branch *br)
++{
++ int err;
++ struct qstr wh_name;
++ struct dentry *wh_dentry;
++
++ err = au_wh_name_alloc(&wh_name, base_name);
++ wh_dentry = ERR_PTR(err);
++ if (!err) {
++ wh_dentry = au_lkup_one(&wh_name, h_parent, br, /*nd*/NULL);
++ kfree(wh_name.name);
++ }
++ return wh_dentry;
++}
++
++/*
++ * link/create a whiteout for @dentry on @bindex.
++ */
++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent)
++{
++ struct dentry *wh_dentry;
++ struct super_block *sb;
++ int err;
++
++ sb = dentry->d_sb;
++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex));
++ if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) {
++ err = link_or_create_wh(sb, bindex, wh_dentry);
++ if (!err)
++ au_set_dbwh(dentry, bindex);
++ else {
++ dput(wh_dentry);
++ wh_dentry = ERR_PTR(err);
++ }
++ }
++
++ return wh_dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* Delete all whiteouts in this directory on branch bindex. */
++static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist,
++ aufs_bindex_t bindex, struct au_branch *br)
++{
++ int err;
++ unsigned long ul, n;
++ struct qstr wh_name;
++ char *p;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++ struct au_vdir_destr *str;
++
++ err = -ENOMEM;
++ p = __getname_gfp(GFP_NOFS);
++ wh_name.name = p;
++ if (unlikely(!wh_name.name))
++ goto out;
++
++ err = 0;
++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
++ p += AUFS_WH_PFX_LEN;
++ n = whlist->nh_num;
++ head = whlist->nh_head;
++ for (ul = 0; !err && ul < n; ul++, head++) {
++ hlist_for_each_entry(tpos, pos, head, wh_hash) {
++ if (tpos->wh_bindex != bindex)
++ continue;
++
++ str = &tpos->wh_str;
++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) {
++ memcpy(p, str->name, str->len);
++ wh_name.len = AUFS_WH_PFX_LEN + str->len;
++ err = unlink_wh_name(h_dentry, &wh_name, br);
++ if (!err)
++ continue;
++ break;
++ }
++ AuIOErr("whiteout name too long %.*s\n",
++ str->len, str->name);
++ err = -EIO;
++ break;
++ }
++ }
++ __putname(wh_name.name);
++
++out:
++ return err;
++}
++
++struct del_wh_children_args {
++ int *errp;
++ struct dentry *h_dentry;
++ struct au_nhash *whlist;
++ aufs_bindex_t bindex;
++ struct au_branch *br;
++};
++
++static void call_del_wh_children(void *args)
++{
++ struct del_wh_children_args *a = args;
++ *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br);
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp)
++{
++ struct au_whtmp_rmdir *whtmp;
++ int err;
++ unsigned int rdhash;
++
++ SiMustAnyLock(sb);
++
++ whtmp = kmalloc(sizeof(*whtmp), gfp);
++ if (unlikely(!whtmp)) {
++ whtmp = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++
++ whtmp->dir = NULL;
++ whtmp->br = NULL;
++ whtmp->wh_dentry = NULL;
++ /* no estimation for dir size */
++ rdhash = au_sbi(sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = AUFS_RDHASH_DEF;
++ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp);
++ if (unlikely(err)) {
++ kfree(whtmp);
++ whtmp = ERR_PTR(err);
++ }
++
++out:
++ return whtmp;
++}
++
++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp)
++{
++ if (whtmp->br)
++ atomic_dec(&whtmp->br->br_count);
++ dput(whtmp->wh_dentry);
++ iput(whtmp->dir);
++ au_nhash_wh_free(&whtmp->whlist);
++ kfree(whtmp);
++}
++
++/*
++ * rmdir the whiteouted temporary named dir @h_dentry.
++ * @whlist: whiteouted children.
++ */
++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_nhash *whlist)
++{
++ int err;
++ struct path h_tmp;
++ struct inode *wh_inode, *h_dir;
++ struct au_branch *br;
++
++ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */
++ IMustLock(h_dir);
++
++ br = au_sbr(dir->i_sb, bindex);
++ wh_inode = wh_dentry->d_inode;
++ mutex_lock_nested(&wh_inode->i_mutex, AuLsc_I_CHILD);
++
++ /*
++ * someone else might change some whiteouts while we were sleeping.
++ * it means this whlist may have an obsoleted entry.
++ */
++ if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE))
++ err = del_wh_children(wh_dentry, whlist, bindex, br);
++ else {
++ int wkq_err;
++ struct del_wh_children_args args = {
++ .errp = &err,
++ .h_dentry = wh_dentry,
++ .whlist = whlist,
++ .bindex = bindex,
++ .br = br
++ };
++
++ wkq_err = au_wkq_wait(call_del_wh_children, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++ mutex_unlock(&wh_inode->i_mutex);
++
++ if (!err) {
++ h_tmp.dentry = wh_dentry;
++ h_tmp.mnt = br->br_mnt;
++ err = vfsub_rmdir(h_dir, &h_tmp);
++ }
++
++ if (!err) {
++ if (au_ibstart(dir) == bindex) {
++ /* todo: dir->i_mutex is necessary */
++ au_cpup_attr_timesizes(dir);
++ vfsub_drop_nlink(dir);
++ }
++ return 0; /* success */
++ }
++
++ pr_warning("failed removing %.*s(%d), ignored\n",
++ AuDLNPair(wh_dentry), err);
++ return err;
++}
++
++static void call_rmdir_whtmp(void *args)
++{
++ int err;
++ aufs_bindex_t bindex;
++ struct au_whtmp_rmdir *a = args;
++ struct super_block *sb;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++ struct au_hinode *hdir;
++
++ /* rmdir by nfsd may cause deadlock with this i_mutex */
++ /* mutex_lock(&a->dir->i_mutex); */
++ err = -EROFS;
++ sb = a->dir->i_sb;
++ si_read_lock(sb, !AuLock_FLUSH);
++ if (!au_br_writable(a->br->br_perm))
++ goto out;
++ bindex = au_br_index(sb, a->br->br_id);
++ if (unlikely(bindex < 0))
++ goto out;
++
++ err = -EIO;
++ ii_write_lock_parent(a->dir);
++ h_parent = dget_parent(a->wh_dentry);
++ h_dir = h_parent->d_inode;
++ hdir = au_hi(a->dir, bindex);
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent,
++ a->br);
++ if (!err) {
++ err = mnt_want_write(a->br->br_mnt);
++ if (!err) {
++ err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry,
++ &a->whlist);
++ mnt_drop_write(a->br->br_mnt);
++ }
++ }
++ au_hn_imtx_unlock(hdir);
++ dput(h_parent);
++ ii_write_unlock(a->dir);
++
++out:
++ /* mutex_unlock(&a->dir->i_mutex); */
++ au_whtmp_rmdir_free(a);
++ si_read_unlock(sb);
++ au_nwt_done(&au_sbi(sb)->si_nowait);
++ if (unlikely(err))
++ AuIOErr("err %d\n", err);
++}
++
++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args)
++{
++ int wkq_err;
++ struct super_block *sb;
++
++ IMustLock(dir);
++
++ /* all post-process will be done in do_rmdir_whtmp(). */
++ sb = dir->i_sb;
++ args->dir = au_igrab(dir);
++ args->br = au_sbr(sb, bindex);
++ atomic_inc(&args->br->br_count);
++ args->wh_dentry = dget(wh_dentry);
++ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb);
++ if (unlikely(wkq_err)) {
++ pr_warning("rmdir error %.*s (%d), ignored\n",
++ AuDLNPair(wh_dentry), wkq_err);
++ au_whtmp_rmdir_free(args);
++ }
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/whout.h linux-2.6.37/fs/aufs/whout.h
+--- linux-2.6.37.orig/fs/aufs/whout.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/whout.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,89 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * whiteout for logical deletion and opaque directory
++ */
++
++#ifndef __AUFS_WHOUT_H__
++#define __AUFS_WHOUT_H__
++
++#ifdef __KERNEL__
++
++#include <linux/aufs_type.h>
++#include "dir.h"
++
++/* whout.c */
++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name);
++struct au_branch;
++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name,
++ struct au_branch *br, int try_sio);
++int au_diropq_test(struct dentry *h_dentry, struct au_branch *br);
++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
++ struct qstr *prefix);
++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br);
++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path,
++ struct dentry *dentry);
++int au_wh_init(struct dentry *h_parent, struct au_branch *br,
++ struct super_block *sb);
++
++/* diropq flags */
++#define AuDiropq_CREATE 1
++#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name)
++#define au_fset_diropq(flags, name) \
++ do { (flags) |= AuDiropq_##name; } while (0)
++#define au_fclr_diropq(flags, name) \
++ do { (flags) &= ~AuDiropq_##name; } while (0)
++
++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int flags);
++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name,
++ struct au_branch *br);
++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent);
++
++/* real rmdir for the whiteout-ed dir */
++struct au_whtmp_rmdir {
++ struct inode *dir;
++ struct au_branch *br;
++ struct dentry *wh_dentry;
++ struct au_nhash whlist;
++};
++
++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp);
++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp);
++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_nhash *whlist);
++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args);
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct dentry *au_diropq_create(struct dentry *dentry,
++ aufs_bindex_t bindex)
++{
++ return au_diropq_sio(dentry, bindex, AuDiropq_CREATE);
++}
++
++static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE));
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_WHOUT_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/wkq.c linux-2.6.37/fs/aufs/wkq.c
+--- linux-2.6.37.orig/fs/aufs/wkq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/wkq.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,236 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * workqueue for asynchronous/super-io operations
++ * todo: try new dredential scheme
++ */
++
++#include <linux/module.h>
++#include "aufs.h"
++
++/* internal workqueue named AUFS_WKQ_NAME and AUFS_WKQ_PRE_NAME */
++enum {
++ AuWkq_INORMAL,
++ AuWkq_IPRE
++};
++
++static struct {
++ char *name;
++ struct workqueue_struct *wkq;
++} au_wkq[] = {
++ [AuWkq_INORMAL] = {
++ .name = AUFS_WKQ_NAME
++ },
++ [AuWkq_IPRE] = {
++ .name = AUFS_WKQ_PRE_NAME
++ }
++};
++
++struct au_wkinfo {
++ struct work_struct wk;
++ struct kobject *kobj;
++
++ unsigned int flags; /* see wkq.h */
++
++ au_wkq_func_t func;
++ void *args;
++
++ struct completion *comp;
++};
++
++/* ---------------------------------------------------------------------- */
++
++static void wkq_func(struct work_struct *wk)
++{
++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk);
++
++ AuDebugOn(current_fsuid());
++ AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY);
++
++ wkinfo->func(wkinfo->args);
++ if (au_ftest_wkq(wkinfo->flags, WAIT))
++ complete(wkinfo->comp);
++ else {
++ kobject_put(wkinfo->kobj);
++ module_put(THIS_MODULE);
++ kfree(wkinfo);
++ }
++}
++
++/*
++ * Since struct completion is large, try allocating it dynamically.
++ */
++#if defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS)
++#define AuWkqCompDeclare(name) struct completion *comp = NULL
++
++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp)
++{
++ *comp = kmalloc(sizeof(**comp), GFP_NOFS);
++ if (*comp) {
++ init_completion(*comp);
++ wkinfo->comp = *comp;
++ return 0;
++ }
++ return -ENOMEM;
++}
++
++static void au_wkq_comp_free(struct completion *comp)
++{
++ kfree(comp);
++}
++
++#else
++
++/* no braces */
++#define AuWkqCompDeclare(name) \
++ DECLARE_COMPLETION_ONSTACK(_ ## name); \
++ struct completion *comp = &_ ## name
++
++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp)
++{
++ wkinfo->comp = *comp;
++ return 0;
++}
++
++static void au_wkq_comp_free(struct completion *comp __maybe_unused)
++{
++ /* empty */
++}
++#endif /* 4KSTACKS */
++
++static void au_wkq_run(struct au_wkinfo *wkinfo, unsigned int flags)
++{
++ struct workqueue_struct *wkq;
++
++ au_dbg_verify_kthread();
++ if (flags & AuWkq_WAIT) {
++ INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func);
++ wkq = au_wkq[AuWkq_INORMAL].wkq;
++ if (flags & AuWkq_PRE)
++ wkq = au_wkq[AuWkq_IPRE].wkq;
++ queue_work(wkq, &wkinfo->wk);
++ } else {
++ INIT_WORK(&wkinfo->wk, wkq_func);
++ schedule_work(&wkinfo->wk);
++ }
++}
++
++/*
++ * Be careful. It is easy to make deadlock happen.
++ * processA: lock, wkq and wait
++ * processB: wkq and wait, lock in wkq
++ * --> deadlock
++ */
++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args)
++{
++ int err;
++ AuWkqCompDeclare(comp);
++ struct au_wkinfo wkinfo = {
++ .flags = flags,
++ .func = func,
++ .args = args
++ };
++
++ err = au_wkq_comp_alloc(&wkinfo, &comp);
++ if (!err) {
++ au_wkq_run(&wkinfo, flags);
++ /* no timeout, no interrupt */
++ wait_for_completion(wkinfo.comp);
++ au_wkq_comp_free(comp);
++ destroy_work_on_stack(&wkinfo.wk);
++ }
++
++ return err;
++
++}
++
++/*
++ * Note: dget/dput() in func for aufs dentries are not supported. It will be a
++ * problem in a concurrent umounting.
++ */
++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb)
++{
++ int err;
++ struct au_wkinfo *wkinfo;
++
++ atomic_inc(&au_sbi(sb)->si_nowait.nw_len);
++
++ /*
++ * wkq_func() must free this wkinfo.
++ * it highly depends upon the implementation of workqueue.
++ */
++ err = 0;
++ wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS);
++ if (wkinfo) {
++ wkinfo->kobj = &au_sbi(sb)->si_kobj;
++ wkinfo->flags = !AuWkq_WAIT;
++ wkinfo->func = func;
++ wkinfo->args = args;
++ wkinfo->comp = NULL;
++ kobject_get(wkinfo->kobj);
++ __module_get(THIS_MODULE);
++
++ au_wkq_run(wkinfo, !AuWkq_WAIT);
++ } else {
++ err = -ENOMEM;
++ au_nwt_done(&au_sbi(sb)->si_nowait);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_nwt_init(struct au_nowait_tasks *nwt)
++{
++ atomic_set(&nwt->nw_len, 0);
++ /* smp_mb(); */ /* atomic_set */
++ init_waitqueue_head(&nwt->nw_wq);
++}
++
++void au_wkq_fin(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(au_wkq); i++)
++ if (au_wkq[i].wkq)
++ destroy_workqueue(au_wkq[i].wkq);
++}
++
++int __init au_wkq_init(void)
++{
++ int err, i;
++
++ err = 0;
++ for (i = 0; !err && i < ARRAY_SIZE(au_wkq); i++) {
++ BUILD_BUG_ON(!WQ_RESCUER);
++ au_wkq[i].wkq = alloc_workqueue(au_wkq[i].name, !WQ_RESCUER,
++ WQ_DFL_ACTIVE);
++ if (IS_ERR(au_wkq[i].wkq))
++ err = PTR_ERR(au_wkq[i].wkq);
++ else if (!au_wkq[i].wkq)
++ err = -ENOMEM;
++ if (unlikely(err))
++ au_wkq[i].wkq = NULL;
++ }
++ if (unlikely(err))
++ au_wkq_fin();
++
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/aufs/wkq.h linux-2.6.37/fs/aufs/wkq.h
+--- linux-2.6.37.orig/fs/aufs/wkq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/wkq.h 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,90 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * workqueue for asynchronous/super-io operations
++ * todo: try new credentials management scheme
++ */
++
++#ifndef __AUFS_WKQ_H__
++#define __AUFS_WKQ_H__
++
++#ifdef __KERNEL__
++
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/aufs_type.h>
++
++struct super_block;
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue
++ */
++struct au_nowait_tasks {
++ atomic_t nw_len;
++ wait_queue_head_t nw_wq;
++};
++
++/* ---------------------------------------------------------------------- */
++
++typedef void (*au_wkq_func_t)(void *args);
++
++/* wkq flags */
++#define AuWkq_WAIT 1
++#define AuWkq_PRE (1 << 1)
++#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name)
++#define au_fset_wkq(flags, name) \
++ do { (flags) |= AuWkq_##name; } while (0)
++#define au_fclr_wkq(flags, name) \
++ do { (flags) &= ~AuWkq_##name; } while (0)
++
++/* wkq.c */
++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args);
++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb);
++void au_nwt_init(struct au_nowait_tasks *nwt);
++int __init au_wkq_init(void);
++void au_wkq_fin(void);
++
++/* ---------------------------------------------------------------------- */
++
++static inline int au_wkq_wait_pre(au_wkq_func_t func, void *args)
++{
++ return au_wkq_do_wait(AuWkq_WAIT | AuWkq_PRE, func, args);
++}
++
++static inline int au_wkq_wait(au_wkq_func_t func, void *args)
++{
++ return au_wkq_do_wait(AuWkq_WAIT, func, args);
++}
++
++static inline void au_nwt_done(struct au_nowait_tasks *nwt)
++{
++ if (atomic_dec_and_test(&nwt->nw_len))
++ wake_up_all(&nwt->nw_wq);
++}
++
++static inline int au_nwt_flush(struct au_nowait_tasks *nwt)
++{
++ wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len));
++ return 0;
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_WKQ_H__ */
+diff -Nur linux-2.6.37.orig/fs/aufs/xino.c linux-2.6.37/fs/aufs/xino.c
+--- linux-2.6.37.orig/fs/aufs/xino.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/fs/aufs/xino.c 2011-01-11 20:15:11.000000000 +0100
+@@ -0,0 +1,1265 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++/*
++ * external inode number translation table and bitmap
++ */
++
++#include <linux/file.h>
++#include <linux/seq_file.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++ssize_t xino_fread(au_readf_t func, struct file *file, void *kbuf, size_t size,
++ loff_t *pos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++ union {
++ void *k;
++ char __user *u;
++ } buf;
++
++ buf.k = kbuf;
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ do {
++ /* todo: signal_pending? */
++ err = func(file, buf.u, size, pos);
++ } while (err == -EAGAIN || err == -EINTR);
++ set_fs(oldfs);
++
++#if 0 /* reserved for future use */
++ if (err > 0)
++ fsnotify_access(file->f_dentry);
++#endif
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static ssize_t do_xino_fwrite(au_writef_t func, struct file *file, void *kbuf,
++ size_t size, loff_t *pos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++ union {
++ void *k;
++ const char __user *u;
++ } buf;
++
++ buf.k = kbuf;
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ do {
++ /* todo: signal_pending? */
++ err = func(file, buf.u, size, pos);
++ } while (err == -EAGAIN || err == -EINTR);
++ set_fs(oldfs);
++
++#if 0 /* reserved for future use */
++ if (err > 0)
++ fsnotify_modify(file->f_dentry);
++#endif
++
++ return err;
++}
++
++struct do_xino_fwrite_args {
++ ssize_t *errp;
++ au_writef_t func;
++ struct file *file;
++ void *buf;
++ size_t size;
++ loff_t *pos;
++};
++
++static void call_do_xino_fwrite(void *args)
++{
++ struct do_xino_fwrite_args *a = args;
++ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos);
++}
++
++ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size,
++ loff_t *pos)
++{
++ ssize_t err;
++
++ /* todo: signal block and no wkq? */
++ if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) {
++ lockdep_off();
++ err = do_xino_fwrite(func, file, buf, size, pos);
++ lockdep_on();
++ } else {
++ /*
++ * it breaks RLIMIT_FSIZE and normal user's limit,
++ * users should care about quota and real 'filesystem full.'
++ */
++ int wkq_err;
++ struct do_xino_fwrite_args args = {
++ .errp = &err,
++ .func = func,
++ .file = file,
++ .buf = buf,
++ .size = size,
++ .pos = pos
++ };
++
++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create a new xinofile at the same place/path as @base_file.
++ */
++struct file *au_xino_create2(struct file *base_file, struct file *copy_src)
++{
++ struct file *file;
++ struct dentry *base, *parent;
++ struct inode *dir;
++ struct qstr *name;
++ struct path path;
++ int err;
++
++ base = base_file->f_dentry;
++ parent = base->d_parent; /* dir inode is locked */
++ dir = parent->d_inode;
++ IMustLock(dir);
++
++ file = ERR_PTR(-EINVAL);
++ name = &base->d_name;
++ path.dentry = vfsub_lookup_one_len(name->name, parent, name->len);
++ if (IS_ERR(path.dentry)) {
++ file = (void *)path.dentry;
++ pr_err("%.*s lookup err %ld\n",
++ AuLNPair(name), PTR_ERR(path.dentry));
++ goto out;
++ }
++
++ /* no need to mnt_want_write() since we call dentry_open() later */
++ err = vfs_create(dir, path.dentry, S_IRUGO | S_IWUGO, NULL);
++ if (unlikely(err)) {
++ file = ERR_PTR(err);
++ pr_err("%.*s create err %d\n", AuLNPair(name), err);
++ goto out_dput;
++ }
++
++ path.mnt = base_file->f_vfsmnt;
++ file = vfsub_dentry_open(&path,
++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE
++ /* | FMODE_NONOTIFY */);
++ if (IS_ERR(file)) {
++ pr_err("%.*s open err %ld\n", AuLNPair(name), PTR_ERR(file));
++ goto out_dput;
++ }
++
++ err = vfsub_unlink(dir, &file->f_path, /*force*/0);
++ if (unlikely(err)) {
++ pr_err("%.*s unlink err %d\n", AuLNPair(name), err);
++ goto out_fput;
++ }
++
++ if (copy_src) {
++ /* no one can touch copy_src xino */
++ err = au_copy_file(file, copy_src,
++ i_size_read(copy_src->f_dentry->d_inode));
++ if (unlikely(err)) {
++ pr_err("%.*s copy err %d\n", AuLNPair(name), err);
++ goto out_fput;
++ }
++ }
++ goto out_dput; /* success */
++
++out_fput:
++ fput(file);
++ file = ERR_PTR(err);
++out_dput:
++ dput(path.dentry);
++out:
++ return file;
++}
++
++struct au_xino_lock_dir {
++ struct au_hinode *hdir;
++ struct dentry *parent;
++ struct mutex *mtx;
++};
++
++static void au_xino_lock_dir(struct super_block *sb, struct file *xino,
++ struct au_xino_lock_dir *ldir)
++{
++ aufs_bindex_t brid, bindex;
++
++ ldir->hdir = NULL;
++ bindex = -1;
++ brid = au_xino_brid(sb);
++ if (brid >= 0)
++ bindex = au_br_index(sb, brid);
++ if (bindex >= 0) {
++ ldir->hdir = au_hi(sb->s_root->d_inode, bindex);
++ au_hn_imtx_lock_nested(ldir->hdir, AuLsc_I_PARENT);
++ } else {
++ ldir->parent = dget_parent(xino->f_dentry);
++ ldir->mtx = &ldir->parent->d_inode->i_mutex;
++ mutex_lock_nested(ldir->mtx, AuLsc_I_PARENT);
++ }
++}
++
++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir)
++{
++ if (ldir->hdir)
++ au_hn_imtx_unlock(ldir->hdir);
++ else {
++ mutex_unlock(ldir->mtx);
++ dput(ldir->parent);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* trucate xino files asynchronously */
++
++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex)
++{
++ int err;
++ aufs_bindex_t bi, bend;
++ struct au_branch *br;
++ struct file *new_xino, *file;
++ struct super_block *h_sb;
++ struct au_xino_lock_dir ldir;
++
++ err = -EINVAL;
++ bend = au_sbend(sb);
++ if (unlikely(bindex < 0 || bend < bindex))
++ goto out;
++ br = au_sbr(sb, bindex);
++ file = br->br_xino.xi_file;
++ if (!file)
++ goto out;
++
++ au_xino_lock_dir(sb, file, &ldir);
++ /* mnt_want_write() is unnecessary here */
++ new_xino = au_xino_create2(file, file);
++ au_xino_unlock_dir(&ldir);
++ err = PTR_ERR(new_xino);
++ if (IS_ERR(new_xino))
++ goto out;
++ err = 0;
++ fput(file);
++ br->br_xino.xi_file = new_xino;
++
++ h_sb = br->br_mnt->mnt_sb;
++ for (bi = 0; bi <= bend; bi++) {
++ if (unlikely(bi == bindex))
++ continue;
++ br = au_sbr(sb, bi);
++ if (br->br_mnt->mnt_sb != h_sb)
++ continue;
++
++ fput(br->br_xino.xi_file);
++ br->br_xino.xi_file = new_xino;
++ get_file(new_xino);
++ }
++
++out:
++ return err;
++}
++
++struct xino_do_trunc_args {
++ struct super_block *sb;
++ struct au_branch *br;
++};
++
++static void xino_do_trunc(void *_args)
++{
++ struct xino_do_trunc_args *args = _args;
++ struct super_block *sb;
++ struct au_branch *br;
++ struct inode *dir;
++ int err;
++ aufs_bindex_t bindex;
++
++ err = 0;
++ sb = args->sb;
++ dir = sb->s_root->d_inode;
++ br = args->br;
++
++ si_noflush_write_lock(sb);
++ ii_read_lock_parent(dir);
++ bindex = au_br_index(sb, br->br_id);
++ err = au_xino_trunc(sb, bindex);
++ if (!err
++ && br->br_xino.xi_file->f_dentry->d_inode->i_blocks
++ >= br->br_xino_upper)
++ br->br_xino_upper += AUFS_XINO_TRUNC_STEP;
++
++ ii_read_unlock(dir);
++ if (unlikely(err))
++ pr_warning("err b%d, (%d)\n", bindex, err);
++ atomic_dec(&br->br_xino_running);
++ atomic_dec(&br->br_count);
++ si_write_unlock(sb);
++ au_nwt_done(&au_sbi(sb)->si_nowait);
++ kfree(args);
++}
++
++static void xino_try_trunc(struct super_block *sb, struct au_branch *br)
++{
++ struct xino_do_trunc_args *args;
++ int wkq_err;
++
++ if (br->br_xino.xi_file->f_dentry->d_inode->i_blocks
++ < br->br_xino_upper)
++ return;
++
++ if (atomic_inc_return(&br->br_xino_running) > 1)
++ goto out;
++
++ /* lock and kfree() will be called in trunc_xino() */
++ args = kmalloc(sizeof(*args), GFP_NOFS);
++ if (unlikely(!args)) {
++ AuErr1("no memory\n");
++ goto out_args;
++ }
++
++ atomic_inc(&br->br_count);
++ args->sb = sb;
++ args->br = br;
++ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb);
++ if (!wkq_err)
++ return; /* success */
++
++ pr_err("wkq %d\n", wkq_err);
++ atomic_dec(&br->br_count);
++
++out_args:
++ kfree(args);
++out:
++ atomic_dec(&br->br_xino_running);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_xino_do_write(au_writef_t write, struct file *file,
++ ino_t h_ino, ino_t ino)
++{
++ loff_t pos;
++ ssize_t sz;
++
++ pos = h_ino;
++ if (unlikely(au_loff_max / sizeof(ino) - 1 < pos)) {
++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino);
++ return -EFBIG;
++ }
++ pos *= sizeof(ino);
++ sz = xino_fwrite(write, file, &ino, sizeof(ino), &pos);
++ if (sz == sizeof(ino))
++ return 0; /* success */
++
++ AuIOErr("write failed (%zd)\n", sz);
++ return -EIO;
++}
++
++/*
++ * write @ino to the xinofile for the specified branch{@sb, @bindex}
++ * at the position of @h_ino.
++ * even if @ino is zero, it is written to the xinofile and means no entry.
++ * if the size of the xino file on a specific filesystem exceeds the watermark,
++ * try truncating it.
++ */
++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t ino)
++{
++ int err;
++ unsigned int mnt_flags;
++ struct au_branch *br;
++
++ BUILD_BUG_ON(sizeof(long long) != sizeof(au_loff_max)
++ || ((loff_t)-1) > 0);
++ SiMustAnyLock(sb);
++
++ mnt_flags = au_mntflags(sb);
++ if (!au_opt_test(mnt_flags, XINO))
++ return 0;
++
++ br = au_sbr(sb, bindex);
++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file,
++ h_ino, ino);
++ if (!err) {
++ if (au_opt_test(mnt_flags, TRUNC_XINO)
++ && au_test_fs_trunc_xino(br->br_mnt->mnt_sb))
++ xino_try_trunc(sb, br);
++ return 0; /* success */
++ }
++
++ AuIOErr("write failed (%d)\n", err);
++ return -EIO;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* aufs inode number bitmap */
++
++static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE;
++static ino_t xib_calc_ino(unsigned long pindex, int bit)
++{
++ ino_t ino;
++
++ AuDebugOn(bit < 0 || page_bits <= bit);
++ ino = AUFS_FIRST_INO + pindex * page_bits + bit;
++ return ino;
++}
++
++static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit)
++{
++ AuDebugOn(ino < AUFS_FIRST_INO);
++ ino -= AUFS_FIRST_INO;
++ *pindex = ino / page_bits;
++ *bit = ino % page_bits;
++}
++
++static int xib_pindex(struct super_block *sb, unsigned long pindex)
++{
++ int err;
++ loff_t pos;
++ ssize_t sz;
++ struct au_sbinfo *sbinfo;
++ struct file *xib;
++ unsigned long *p;
++
++ sbinfo = au_sbi(sb);
++ MtxMustLock(&sbinfo->si_xib_mtx);
++ AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE
++ || !au_opt_test(sbinfo->si_mntflags, XINO));
++
++ if (pindex == sbinfo->si_xib_last_pindex)
++ return 0;
++
++ xib = sbinfo->si_xib;
++ p = sbinfo->si_xib_buf;
++ pos = sbinfo->si_xib_last_pindex;
++ pos *= PAGE_SIZE;
++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos);
++ if (unlikely(sz != PAGE_SIZE))
++ goto out;
++
++ pos = pindex;
++ pos *= PAGE_SIZE;
++ if (i_size_read(xib->f_dentry->d_inode) >= pos + PAGE_SIZE)
++ sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos);
++ else {
++ memset(p, 0, PAGE_SIZE);
++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos);
++ }
++ if (sz == PAGE_SIZE) {
++ sbinfo->si_xib_last_pindex = pindex;
++ return 0; /* success */
++ }
++
++out:
++ AuIOErr1("write failed (%zd)\n", sz);
++ err = sz;
++ if (sz >= 0)
++ err = -EIO;
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void au_xib_clear_bit(struct inode *inode)
++{
++ int err, bit;
++ unsigned long pindex;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++ AuDebugOn(inode->i_nlink);
++
++ sb = inode->i_sb;
++ xib_calc_bit(inode->i_ino, &pindex, &bit);
++ AuDebugOn(page_bits <= bit);
++ sbinfo = au_sbi(sb);
++ mutex_lock(&sbinfo->si_xib_mtx);
++ err = xib_pindex(sb, pindex);
++ if (!err) {
++ clear_bit(bit, sbinfo->si_xib_buf);
++ sbinfo->si_xib_next_bit = bit;
++ }
++ mutex_unlock(&sbinfo->si_xib_mtx);
++}
++
++/* for s_op->delete_inode() */
++void au_xino_delete_inode(struct inode *inode, const int unlinked)
++{
++ int err;
++ unsigned int mnt_flags;
++ aufs_bindex_t bindex, bend, bi;
++ unsigned char try_trunc;
++ struct au_iinfo *iinfo;
++ struct super_block *sb;
++ struct au_hinode *hi;
++ struct inode *h_inode;
++ struct au_branch *br;
++ au_writef_t xwrite;
++
++ sb = inode->i_sb;
++ mnt_flags = au_mntflags(sb);
++ if (!au_opt_test(mnt_flags, XINO)
++ || inode->i_ino == AUFS_ROOT_INO)
++ return;
++
++ if (unlinked) {
++ au_xigen_inc(inode);
++ au_xib_clear_bit(inode);
++ }
++
++ iinfo = au_ii(inode);
++ if (!iinfo)
++ return;
++
++ bindex = iinfo->ii_bstart;
++ if (bindex < 0)
++ return;
++
++ xwrite = au_sbi(sb)->si_xwrite;
++ try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO);
++ hi = iinfo->ii_hinode + bindex;
++ bend = iinfo->ii_bend;
++ for (; bindex <= bend; bindex++, hi++) {
++ h_inode = hi->hi_inode;
++ if (!h_inode
++ || (!unlinked && h_inode->i_nlink))
++ continue;
++
++ /* inode may not be revalidated */
++ bi = au_br_index(sb, hi->hi_id);
++ if (bi < 0)
++ continue;
++
++ br = au_sbr(sb, bi);
++ err = au_xino_do_write(xwrite, br->br_xino.xi_file,
++ h_inode->i_ino, /*ino*/0);
++ if (!err && try_trunc
++ && au_test_fs_trunc_xino(br->br_mnt->mnt_sb))
++ xino_try_trunc(sb, br);
++ }
++}
++
++/* get an unused inode number from bitmap */
++ino_t au_xino_new_ino(struct super_block *sb)
++{
++ ino_t ino;
++ unsigned long *p, pindex, ul, pend;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++ int free_bit, err;
++
++ if (!au_opt_test(au_mntflags(sb), XINO))
++ return iunique(sb, AUFS_FIRST_INO);
++
++ sbinfo = au_sbi(sb);
++ mutex_lock(&sbinfo->si_xib_mtx);
++ p = sbinfo->si_xib_buf;
++ free_bit = sbinfo->si_xib_next_bit;
++ if (free_bit < page_bits && !test_bit(free_bit, p))
++ goto out; /* success */
++ free_bit = find_first_zero_bit(p, page_bits);
++ if (free_bit < page_bits)
++ goto out; /* success */
++
++ pindex = sbinfo->si_xib_last_pindex;
++ for (ul = pindex - 1; ul < ULONG_MAX; ul--) {
++ err = xib_pindex(sb, ul);
++ if (unlikely(err))
++ goto out_err;
++ free_bit = find_first_zero_bit(p, page_bits);
++ if (free_bit < page_bits)
++ goto out; /* success */
++ }
++
++ file = sbinfo->si_xib;
++ pend = i_size_read(file->f_dentry->d_inode) / PAGE_SIZE;
++ for (ul = pindex + 1; ul <= pend; ul++) {
++ err = xib_pindex(sb, ul);
++ if (unlikely(err))
++ goto out_err;
++ free_bit = find_first_zero_bit(p, page_bits);
++ if (free_bit < page_bits)
++ goto out; /* success */
++ }
++ BUG();
++
++out:
++ set_bit(free_bit, p);
++ sbinfo->si_xib_next_bit = free_bit + 1;
++ pindex = sbinfo->si_xib_last_pindex;
++ mutex_unlock(&sbinfo->si_xib_mtx);
++ ino = xib_calc_ino(pindex, free_bit);
++ AuDbg("i%lu\n", (unsigned long)ino);
++ return ino;
++out_err:
++ mutex_unlock(&sbinfo->si_xib_mtx);
++ AuDbg("i0\n");
++ return 0;
++}
++
++/*
++ * read @ino from xinofile for the specified branch{@sb, @bindex}
++ * at the position of @h_ino.
++ * if @ino does not exist and @do_new is true, get new one.
++ */
++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t *ino)
++{
++ int err;
++ ssize_t sz;
++ loff_t pos;
++ struct file *file;
++ struct au_sbinfo *sbinfo;
++
++ *ino = 0;
++ if (!au_opt_test(au_mntflags(sb), XINO))
++ return 0; /* no xino */
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ pos = h_ino;
++ if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) {
++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino);
++ return -EFBIG;
++ }
++ pos *= sizeof(*ino);
++
++ file = au_sbr(sb, bindex)->br_xino.xi_file;
++ if (i_size_read(file->f_dentry->d_inode) < pos + sizeof(*ino))
++ return 0; /* no ino */
++
++ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos);
++ if (sz == sizeof(*ino))
++ return 0; /* success */
++
++ err = sz;
++ if (unlikely(sz >= 0)) {
++ err = -EIO;
++ AuIOErr("xino read error (%zd)\n", sz);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* create and set a new xino file */
++
++struct file *au_xino_create(struct super_block *sb, char *fname, int silent)
++{
++ struct file *file;
++ struct dentry *h_parent, *d;
++ struct inode *h_dir;
++ int err;
++
++ /*
++ * at mount-time, and the xino file is the default path,
++ * hnotify is disabled so we have no notify events to ignore.
++ * when a user specified the xino, we cannot get au_hdir to be ignored.
++ */
++ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE
++ /* | FMODE_NONOTIFY */,
++ S_IRUGO | S_IWUGO);
++ if (IS_ERR(file)) {
++ if (!silent)
++ pr_err("open %s(%ld)\n", fname, PTR_ERR(file));
++ return file;
++ }
++
++ /* keep file count */
++ h_parent = dget_parent(file->f_dentry);
++ h_dir = h_parent->d_inode;
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
++ /* mnt_want_write() is unnecessary here */
++ err = vfsub_unlink(h_dir, &file->f_path, /*force*/0);
++ mutex_unlock(&h_dir->i_mutex);
++ dput(h_parent);
++ if (unlikely(err)) {
++ if (!silent)
++ pr_err("unlink %s(%d)\n", fname, err);
++ goto out;
++ }
++
++ err = -EINVAL;
++ d = file->f_dentry;
++ if (unlikely(sb == d->d_sb)) {
++ if (!silent)
++ pr_err("%s must be outside\n", fname);
++ goto out;
++ }
++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) {
++ if (!silent)
++ pr_err("xino doesn't support %s(%s)\n",
++ fname, au_sbtype(d->d_sb));
++ goto out;
++ }
++ return file; /* success */
++
++out:
++ fput(file);
++ file = ERR_PTR(err);
++ return file;
++}
++
++/*
++ * find another branch who is on the same filesystem of the specified
++ * branch{@btgt}. search until @bend.
++ */
++static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt,
++ aufs_bindex_t bend)
++{
++ aufs_bindex_t bindex;
++ struct super_block *tgt_sb = au_sbr_sb(sb, btgt);
++
++ for (bindex = 0; bindex < btgt; bindex++)
++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex)))
++ return bindex;
++ for (bindex++; bindex <= bend; bindex++)
++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex)))
++ return bindex;
++ return -1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * initialize the xinofile for the specified branch @br
++ * at the place/path where @base_file indicates.
++ * test whether another branch is on the same filesystem or not,
++ * if @do_test is true.
++ */
++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino,
++ struct file *base_file, int do_test)
++{
++ int err;
++ ino_t ino;
++ aufs_bindex_t bend, bindex;
++ struct au_branch *shared_br, *b;
++ struct file *file;
++ struct super_block *tgt_sb;
++
++ shared_br = NULL;
++ bend = au_sbend(sb);
++ if (do_test) {
++ tgt_sb = br->br_mnt->mnt_sb;
++ for (bindex = 0; bindex <= bend; bindex++) {
++ b = au_sbr(sb, bindex);
++ if (tgt_sb == b->br_mnt->mnt_sb) {
++ shared_br = b;
++ break;
++ }
++ }
++ }
++
++ if (!shared_br || !shared_br->br_xino.xi_file) {
++ struct au_xino_lock_dir ldir;
++
++ au_xino_lock_dir(sb, base_file, &ldir);
++ /* mnt_want_write() is unnecessary here */
++ file = au_xino_create2(base_file, NULL);
++ au_xino_unlock_dir(&ldir);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ br->br_xino.xi_file = file;
++ } else {
++ br->br_xino.xi_file = shared_br->br_xino.xi_file;
++ get_file(br->br_xino.xi_file);
++ }
++
++ ino = AUFS_ROOT_INO;
++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file,
++ h_ino, ino);
++ if (unlikely(err)) {
++ fput(br->br_xino.xi_file);
++ br->br_xino.xi_file = NULL;
++ }
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* trucate a xino bitmap file */
++
++/* todo: slow */
++static int do_xib_restore(struct super_block *sb, struct file *file, void *page)
++{
++ int err, bit;
++ ssize_t sz;
++ unsigned long pindex;
++ loff_t pos, pend;
++ struct au_sbinfo *sbinfo;
++ au_readf_t func;
++ ino_t *ino;
++ unsigned long *p;
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ MtxMustLock(&sbinfo->si_xib_mtx);
++ p = sbinfo->si_xib_buf;
++ func = sbinfo->si_xread;
++ pend = i_size_read(file->f_dentry->d_inode);
++ pos = 0;
++ while (pos < pend) {
++ sz = xino_fread(func, file, page, PAGE_SIZE, &pos);
++ err = sz;
++ if (unlikely(sz <= 0))
++ goto out;
++
++ err = 0;
++ for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) {
++ if (unlikely(*ino < AUFS_FIRST_INO))
++ continue;
++
++ xib_calc_bit(*ino, &pindex, &bit);
++ AuDebugOn(page_bits <= bit);
++ err = xib_pindex(sb, pindex);
++ if (!err)
++ set_bit(bit, p);
++ else
++ goto out;
++ }
++ }
++
++out:
++ return err;
++}
++
++static int xib_restore(struct super_block *sb)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ void *page;
++
++ err = -ENOMEM;
++ page = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!page))
++ goto out;
++
++ err = 0;
++ bend = au_sbend(sb);
++ for (bindex = 0; !err && bindex <= bend; bindex++)
++ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0)
++ err = do_xib_restore
++ (sb, au_sbr(sb, bindex)->br_xino.xi_file, page);
++ else
++ AuDbg("b%d\n", bindex);
++ free_page((unsigned long)page);
++
++out:
++ return err;
++}
++
++int au_xib_trunc(struct super_block *sb)
++{
++ int err;
++ ssize_t sz;
++ loff_t pos;
++ struct au_xino_lock_dir ldir;
++ struct au_sbinfo *sbinfo;
++ unsigned long *p;
++ struct file *file;
++
++ SiMustWriteLock(sb);
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ if (!au_opt_test(sbinfo->si_mntflags, XINO))
++ goto out;
++
++ file = sbinfo->si_xib;
++ if (i_size_read(file->f_dentry->d_inode) <= PAGE_SIZE)
++ goto out;
++
++ au_xino_lock_dir(sb, file, &ldir);
++ /* mnt_want_write() is unnecessary here */
++ file = au_xino_create2(sbinfo->si_xib, NULL);
++ au_xino_unlock_dir(&ldir);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = file;
++
++ p = sbinfo->si_xib_buf;
++ memset(p, 0, PAGE_SIZE);
++ pos = 0;
++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos);
++ if (unlikely(sz != PAGE_SIZE)) {
++ err = sz;
++ AuIOErr("err %d\n", err);
++ if (sz >= 0)
++ err = -EIO;
++ goto out;
++ }
++
++ mutex_lock(&sbinfo->si_xib_mtx);
++ /* mnt_want_write() is unnecessary here */
++ err = xib_restore(sb);
++ mutex_unlock(&sbinfo->si_xib_mtx);
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * xino mount option handlers
++ */
++static au_readf_t find_readf(struct file *h_file)
++{
++ const struct file_operations *fop = h_file->f_op;
++
++ if (fop) {
++ if (fop->read)
++ return fop->read;
++ if (fop->aio_read)
++ return do_sync_read;
++ }
++ return ERR_PTR(-ENOSYS);
++}
++
++static au_writef_t find_writef(struct file *h_file)
++{
++ const struct file_operations *fop = h_file->f_op;
++
++ if (fop) {
++ if (fop->write)
++ return fop->write;
++ if (fop->aio_write)
++ return do_sync_write;
++ }
++ return ERR_PTR(-ENOSYS);
++}
++
++/* xino bitmap */
++static void xino_clear_xib(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ sbinfo->si_xread = NULL;
++ sbinfo->si_xwrite = NULL;
++ if (sbinfo->si_xib)
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = NULL;
++ free_page((unsigned long)sbinfo->si_xib_buf);
++ sbinfo->si_xib_buf = NULL;
++}
++
++static int au_xino_set_xib(struct super_block *sb, struct file *base)
++{
++ int err;
++ loff_t pos;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ file = au_xino_create2(base, sbinfo->si_xib);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ if (sbinfo->si_xib)
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = file;
++ sbinfo->si_xread = find_readf(file);
++ sbinfo->si_xwrite = find_writef(file);
++
++ err = -ENOMEM;
++ if (!sbinfo->si_xib_buf)
++ sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS);
++ if (unlikely(!sbinfo->si_xib_buf))
++ goto out_unset;
++
++ sbinfo->si_xib_last_pindex = 0;
++ sbinfo->si_xib_next_bit = 0;
++ if (i_size_read(file->f_dentry->d_inode) < PAGE_SIZE) {
++ pos = 0;
++ err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf,
++ PAGE_SIZE, &pos);
++ if (unlikely(err != PAGE_SIZE))
++ goto out_free;
++ }
++ err = 0;
++ goto out; /* success */
++
++out_free:
++ free_page((unsigned long)sbinfo->si_xib_buf);
++ sbinfo->si_xib_buf = NULL;
++ if (err >= 0)
++ err = -EIO;
++out_unset:
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = NULL;
++ sbinfo->si_xread = NULL;
++ sbinfo->si_xwrite = NULL;
++out:
++ return err;
++}
++
++/* xino for each branch */
++static void xino_clear_br(struct super_block *sb)
++{
++ aufs_bindex_t bindex, bend;
++ struct au_branch *br;
++
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (!br || !br->br_xino.xi_file)
++ continue;
++
++ fput(br->br_xino.xi_file);
++ br->br_xino.xi_file = NULL;
++ }
++}
++
++static int au_xino_set_br(struct super_block *sb, struct file *base)
++{
++ int err;
++ ino_t ino;
++ aufs_bindex_t bindex, bend, bshared;
++ struct {
++ struct file *old, *new;
++ } *fpair, *p;
++ struct au_branch *br;
++ struct inode *inode;
++ au_writef_t writef;
++
++ SiMustWriteLock(sb);
++
++ err = -ENOMEM;
++ bend = au_sbend(sb);
++ fpair = kcalloc(bend + 1, sizeof(*fpair), GFP_NOFS);
++ if (unlikely(!fpair))
++ goto out;
++
++ inode = sb->s_root->d_inode;
++ ino = AUFS_ROOT_INO;
++ writef = au_sbi(sb)->si_xwrite;
++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) {
++ br = au_sbr(sb, bindex);
++ bshared = is_sb_shared(sb, bindex, bindex - 1);
++ if (bshared >= 0) {
++ /* shared xino */
++ *p = fpair[bshared];
++ get_file(p->new);
++ }
++
++ if (!p->new) {
++ /* new xino */
++ p->old = br->br_xino.xi_file;
++ p->new = au_xino_create2(base, br->br_xino.xi_file);
++ err = PTR_ERR(p->new);
++ if (IS_ERR(p->new)) {
++ p->new = NULL;
++ goto out_pair;
++ }
++ }
++
++ err = au_xino_do_write(writef, p->new,
++ au_h_iptr(inode, bindex)->i_ino, ino);
++ if (unlikely(err))
++ goto out_pair;
++ }
++
++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) {
++ br = au_sbr(sb, bindex);
++ if (br->br_xino.xi_file)
++ fput(br->br_xino.xi_file);
++ get_file(p->new);
++ br->br_xino.xi_file = p->new;
++ }
++
++out_pair:
++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++)
++ if (p->new)
++ fput(p->new);
++ else
++ break;
++ kfree(fpair);
++out:
++ return err;
++}
++
++void au_xino_clr(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ au_xigen_clr(sb);
++ xino_clear_xib(sb);
++ xino_clear_br(sb);
++ sbinfo = au_sbi(sb);
++ /* lvalue, do not call au_mntflags() */
++ au_opt_clr(sbinfo->si_mntflags, XINO);
++}
++
++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount)
++{
++ int err, skip;
++ struct dentry *parent, *cur_parent;
++ struct qstr *dname, *cur_name;
++ struct file *cur_xino;
++ struct inode *dir;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ parent = dget_parent(xino->file->f_dentry);
++ if (remount) {
++ skip = 0;
++ dname = &xino->file->f_dentry->d_name;
++ cur_xino = sbinfo->si_xib;
++ if (cur_xino) {
++ cur_parent = dget_parent(cur_xino->f_dentry);
++ cur_name = &cur_xino->f_dentry->d_name;
++ skip = (cur_parent == parent
++ && dname->len == cur_name->len
++ && !memcmp(dname->name, cur_name->name,
++ dname->len));
++ dput(cur_parent);
++ }
++ if (skip)
++ goto out;
++ }
++
++ au_opt_set(sbinfo->si_mntflags, XINO);
++ dir = parent->d_inode;
++ mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT);
++ /* mnt_want_write() is unnecessary here */
++ err = au_xino_set_xib(sb, xino->file);
++ if (!err)
++ err = au_xigen_set(sb, xino->file);
++ if (!err)
++ err = au_xino_set_br(sb, xino->file);
++ mutex_unlock(&dir->i_mutex);
++ if (!err)
++ goto out; /* success */
++
++ /* reset all */
++ AuIOErr("failed creating xino(%d).\n", err);
++
++out:
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create a xinofile at the default place/path.
++ */
++struct file *au_xino_def(struct super_block *sb)
++{
++ struct file *file;
++ char *page, *p;
++ struct au_branch *br;
++ struct super_block *h_sb;
++ struct path path;
++ aufs_bindex_t bend, bindex, bwr;
++
++ br = NULL;
++ bend = au_sbend(sb);
++ bwr = -1;
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (au_br_writable(br->br_perm)
++ && !au_test_fs_bad_xino(br->br_mnt->mnt_sb)) {
++ bwr = bindex;
++ break;
++ }
++ }
++
++ if (bwr >= 0) {
++ file = ERR_PTR(-ENOMEM);
++ page = __getname_gfp(GFP_NOFS);
++ if (unlikely(!page))
++ goto out;
++ path.mnt = br->br_mnt;
++ path.dentry = au_h_dptr(sb->s_root, bwr);
++ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME));
++ file = (void *)p;
++ if (!IS_ERR(p)) {
++ strcat(p, "/" AUFS_XINO_FNAME);
++ AuDbg("%s\n", p);
++ file = au_xino_create(sb, p, /*silent*/0);
++ if (!IS_ERR(file))
++ au_xino_brid_set(sb, br->br_id);
++ }
++ __putname(page);
++ } else {
++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0);
++ if (IS_ERR(file))
++ goto out;
++ h_sb = file->f_dentry->d_sb;
++ if (unlikely(au_test_fs_bad_xino(h_sb))) {
++ pr_err("xino doesn't support %s(%s)\n",
++ AUFS_XINO_DEFPATH, au_sbtype(h_sb));
++ fput(file);
++ file = ERR_PTR(-EINVAL);
++ }
++ if (!IS_ERR(file))
++ au_xino_brid_set(sb, -1);
++ }
++
++out:
++ return file;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_xino_path(struct seq_file *seq, struct file *file)
++{
++ int err;
++
++ err = au_seq_path(seq, &file->f_path);
++ if (unlikely(err < 0))
++ goto out;
++
++ err = 0;
++#define Deleted "\\040(deleted)"
++ seq->count -= sizeof(Deleted) - 1;
++ AuDebugOn(memcmp(seq->buf + seq->count, Deleted,
++ sizeof(Deleted) - 1));
++#undef Deleted
++
++out:
++ return err;
++}
+diff -Nur linux-2.6.37.orig/fs/file_table.c linux-2.6.37/fs/file_table.c
+--- linux-2.6.37.orig/fs/file_table.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/fs/file_table.c 2011-01-11 20:15:11.000000000 +0100
+@@ -393,6 +393,8 @@
+ }
+ }
+
++EXPORT_SYMBOL(file_sb_list_del);
++
+ #ifdef CONFIG_SMP
+
+ /*
+diff -Nur linux-2.6.37.orig/fs/inode.c linux-2.6.37/fs/inode.c
+--- linux-2.6.37.orig/fs/inode.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/fs/inode.c 2011-01-11 20:15:11.000000000 +0100
+@@ -82,6 +82,7 @@
+ * the i_state of an inode while it is in use..
+ */
+ DEFINE_SPINLOCK(inode_lock);
++EXPORT_SYMBOL(inode_lock);
+
+ /*
+ * iprune_sem provides exclusion between the kswapd or try_to_free_pages
+diff -Nur linux-2.6.37.orig/fs/namei.c linux-2.6.37/fs/namei.c
+--- linux-2.6.37.orig/fs/namei.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/fs/namei.c 2011-01-11 20:15:11.000000000 +0100
+@@ -347,6 +347,7 @@
+
+ return 0;
+ }
++EXPORT_SYMBOL(deny_write_access);
+
+ /**
+ * path_get - get a reference to a path
+@@ -1161,12 +1162,13 @@
+ * needs parent already locked. Doesn't follow mounts.
+ * SMP-safe.
+ */
+-static struct dentry *lookup_hash(struct nameidata *nd)
++struct dentry *lookup_hash(struct nameidata *nd)
+ {
+ return __lookup_hash(&nd->last, nd->path.dentry, nd);
+ }
++EXPORT_SYMBOL(lookup_hash);
+
+-static int __lookup_one_len(const char *name, struct qstr *this,
++int __lookup_one_len(const char *name, struct qstr *this,
+ struct dentry *base, int len)
+ {
+ unsigned long hash;
+@@ -1187,6 +1189,7 @@
+ this->hash = end_name_hash(hash);
+ return 0;
+ }
++EXPORT_SYMBOL(__lookup_one_len);
+
+ /**
+ * lookup_one_len - filesystem helper to lookup single pathname component
+diff -Nur linux-2.6.37.orig/fs/namespace.c linux-2.6.37/fs/namespace.c
+--- linux-2.6.37.orig/fs/namespace.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/fs/namespace.c 2011-01-11 20:15:13.000000000 +0100
+@@ -1321,6 +1321,7 @@
+ }
+ return 0;
+ }
++EXPORT_SYMBOL(iterate_mounts);
+
+ static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end)
+ {
+diff -Nur linux-2.6.37.orig/fs/notify/group.c linux-2.6.37/fs/notify/group.c
+--- linux-2.6.37.orig/fs/notify/group.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/fs/notify/group.c 2011-01-11 20:15:13.000000000 +0100
+@@ -22,6 +22,7 @@
+ #include <linux/srcu.h>
+ #include <linux/rculist.h>
+ #include <linux/wait.h>
++#include <linux/module.h>
+
+ #include <linux/fsnotify_backend.h>
+ #include "fsnotify.h"
+@@ -70,6 +71,7 @@
+ if (atomic_dec_and_test(&group->refcnt))
+ fsnotify_destroy_group(group);
+ }
++EXPORT_SYMBOL(fsnotify_put_group);
+
+ /*
+ * Create a new fsnotify_group and hold a reference for the group returned.
+@@ -102,3 +104,4 @@
+
+ return group;
+ }
++EXPORT_SYMBOL(fsnotify_alloc_group);
+diff -Nur linux-2.6.37.orig/fs/notify/mark.c linux-2.6.37/fs/notify/mark.c
+--- linux-2.6.37.orig/fs/notify/mark.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/fs/notify/mark.c 2011-01-11 20:15:13.000000000 +0100
+@@ -113,6 +113,7 @@
+ if (atomic_dec_and_test(&mark->refcnt))
+ mark->free_mark(mark);
+ }
++EXPORT_SYMBOL(fsnotify_put_mark);
+
+ /*
+ * Any time a mark is getting freed we end up here.
+@@ -190,6 +191,7 @@
+ if (unlikely(atomic_dec_and_test(&group->num_marks)))
+ fsnotify_final_destroy_group(group);
+ }
++EXPORT_SYMBOL(fsnotify_destroy_mark);
+
+ void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask)
+ {
+@@ -277,6 +279,7 @@
+
+ return ret;
+ }
++EXPORT_SYMBOL(fsnotify_add_mark);
+
+ /*
+ * clear any marks in a group in which mark->flags & flags is true
+@@ -332,6 +335,7 @@
+ atomic_set(&mark->refcnt, 1);
+ mark->free_mark = free_mark;
+ }
++EXPORT_SYMBOL(fsnotify_init_mark);
+
+ static int fsnotify_mark_destroy(void *ignored)
+ {
+diff -Nur linux-2.6.37.orig/fs/open.c linux-2.6.37/fs/open.c
+--- linux-2.6.37.orig/fs/open.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/fs/open.c 2011-01-11 20:15:13.000000000 +0100
+@@ -60,6 +60,7 @@
+ mutex_unlock(&dentry->d_inode->i_mutex);
+ return ret;
+ }
++EXPORT_SYMBOL(do_truncate);
+
+ static long do_sys_truncate(const char __user *pathname, loff_t length)
+ {
+diff -Nur linux-2.6.37.orig/fs/splice.c linux-2.6.37/fs/splice.c
+--- linux-2.6.37.orig/fs/splice.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/fs/splice.c 2011-01-11 20:15:13.000000000 +0100
+@@ -1092,8 +1092,8 @@
+ /*
+ * Attempt to initiate a splice from pipe to file.
+ */
+-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+- loff_t *ppos, size_t len, unsigned int flags)
++long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
+ {
+ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
+ loff_t *, size_t, unsigned int);
+@@ -1116,13 +1116,14 @@
+
+ return splice_write(pipe, out, ppos, len, flags);
+ }
++EXPORT_SYMBOL(do_splice_from);
+
+ /*
+ * Attempt to initiate a splice from a file to a pipe.
+ */
+-static long do_splice_to(struct file *in, loff_t *ppos,
+- struct pipe_inode_info *pipe, size_t len,
+- unsigned int flags)
++long do_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
+ {
+ ssize_t (*splice_read)(struct file *, loff_t *,
+ struct pipe_inode_info *, size_t, unsigned int);
+@@ -1142,6 +1143,7 @@
+
+ return splice_read(in, ppos, pipe, len, flags);
+ }
++EXPORT_SYMBOL(do_splice_to);
+
+ /**
+ * splice_direct_to_actor - splices data directly between two non-pipes
+diff -Nur linux-2.6.37.orig/security/commoncap.c linux-2.6.37/security/commoncap.c
+--- linux-2.6.37.orig/security/commoncap.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/security/commoncap.c 2011-01-11 20:15:13.000000000 +0100
+@@ -929,3 +929,4 @@
+ }
+ return ret;
+ }
++EXPORT_SYMBOL(cap_file_mmap);
+diff -Nur linux-2.6.37.orig/security/device_cgroup.c linux-2.6.37/security/device_cgroup.c
+--- linux-2.6.37.orig/security/device_cgroup.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/security/device_cgroup.c 2011-01-11 20:15:13.000000000 +0100
+@@ -515,6 +515,7 @@
+
+ return -EPERM;
+ }
++EXPORT_SYMBOL(devcgroup_inode_permission);
+
+ int devcgroup_inode_mknod(int mode, dev_t dev)
+ {
+diff -Nur linux-2.6.37.orig/security/security.c linux-2.6.37/security/security.c
+--- linux-2.6.37.orig/security/security.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/security/security.c 2011-01-11 20:15:13.000000000 +0100
+@@ -360,6 +360,7 @@
+ return 0;
+ return security_ops->path_mkdir(dir, dentry, mode);
+ }
++EXPORT_SYMBOL(security_path_mkdir);
+
+ int security_path_rmdir(struct path *dir, struct dentry *dentry)
+ {
+@@ -367,6 +368,7 @@
+ return 0;
+ return security_ops->path_rmdir(dir, dentry);
+ }
++EXPORT_SYMBOL(security_path_rmdir);
+
+ int security_path_unlink(struct path *dir, struct dentry *dentry)
+ {
+@@ -374,6 +376,7 @@
+ return 0;
+ return security_ops->path_unlink(dir, dentry);
+ }
++EXPORT_SYMBOL(security_path_unlink);
+
+ int security_path_symlink(struct path *dir, struct dentry *dentry,
+ const char *old_name)
+@@ -382,6 +385,7 @@
+ return 0;
+ return security_ops->path_symlink(dir, dentry, old_name);
+ }
++EXPORT_SYMBOL(security_path_symlink);
+
+ int security_path_link(struct dentry *old_dentry, struct path *new_dir,
+ struct dentry *new_dentry)
+@@ -390,6 +394,7 @@
+ return 0;
+ return security_ops->path_link(old_dentry, new_dir, new_dentry);
+ }
++EXPORT_SYMBOL(security_path_link);
+
+ int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
+ struct path *new_dir, struct dentry *new_dentry)
+@@ -400,6 +405,7 @@
+ return security_ops->path_rename(old_dir, old_dentry, new_dir,
+ new_dentry);
+ }
++EXPORT_SYMBOL(security_path_rename);
+
+ int security_path_truncate(struct path *path)
+ {
+@@ -407,6 +413,7 @@
+ return 0;
+ return security_ops->path_truncate(path);
+ }
++EXPORT_SYMBOL(security_path_truncate);
+
+ int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+ mode_t mode)
+@@ -415,6 +422,7 @@
+ return 0;
+ return security_ops->path_chmod(dentry, mnt, mode);
+ }
++EXPORT_SYMBOL(security_path_chmod);
+
+ int security_path_chown(struct path *path, uid_t uid, gid_t gid)
+ {
+@@ -422,6 +430,7 @@
+ return 0;
+ return security_ops->path_chown(path, uid, gid);
+ }
++EXPORT_SYMBOL(security_path_chown);
+
+ int security_path_chroot(struct path *path)
+ {
+@@ -498,6 +507,7 @@
+ return 0;
+ return security_ops->inode_readlink(dentry);
+ }
++EXPORT_SYMBOL(security_inode_readlink);
+
+ int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
+ {
+@@ -512,6 +522,7 @@
+ return 0;
+ return security_ops->inode_permission(inode, mask);
+ }
++EXPORT_SYMBOL(security_inode_permission);
+
+ int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
+ {
+@@ -611,6 +622,7 @@
+
+ return fsnotify_perm(file, mask);
+ }
++EXPORT_SYMBOL(security_file_permission);
+
+ int security_file_alloc(struct file *file)
+ {
+@@ -638,6 +650,7 @@
+ return ret;
+ return ima_file_mmap(file, prot);
+ }
++EXPORT_SYMBOL(security_file_mmap);
+
+ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
+ unsigned long prot)
diff --git a/target/linux/patches/2.6.37/brcm.patch b/target/linux/patches/2.6.37/brcm.patch
new file mode 100644
index 000000000..10a9a4947
--- /dev/null
+++ b/target/linux/patches/2.6.37/brcm.patch
@@ -0,0 +1,169 @@
+--- linux-2.6.36.orig/arch/mips/bcm47xx/Makefile 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/mips/bcm47xx/Makefile 2010-12-22 16:39:15.000000000 +0100
+@@ -3,4 +3,4 @@
+ # under Linux.
+ #
+
+-obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
++obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o platform.o
+--- /dev/null Fri Jan 7 17:21:57 2011
++++ linux-2.6.36/arch/mips/bcm47xx/platform.c Fri Jan 7 17:21:42 2011
+@@ -0,0 +1,147 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2010, 2011 Waldemar Brodkorb <wbx@openadk.org>
++ * Copyright © 2007, 2011 Thorsten Glaser <tg@freewrt.org>
++ */
++
++#include <linux/platform_device.h>
++#include <linux/module.h>
++#include <linux/mtd/physmap.h>
++#include <linux/ssb/ssb.h>
++
++#include <asm/mach-bcm47xx/bcm47xx.h>
++#include <asm/mach-bcm47xx/nvram.h>
++
++#define NVRAM_FLASH_SIZE 0x10000
++#define CFGFS_FLASH_SIZE (64 * 1024)
++
++static struct mtd_partition bcm47xx_partitions[] = {
++#define SLOT_CFE 0
++ {
++ .name = "cfe",
++ .offset = 0,
++ .size = 0x40000, /* 256k */
++ .mask_flags = MTD_WRITEABLE /* force read-only */
++ },
++#define SLOT_LINUX 1
++ {
++ .name = "linux",
++ .offset = 0,
++ .size = 0,
++ },
++#define SLOT_ROOTFS 2
++ {
++ .name = "rootfs",
++ .offset = 0,
++ .size = 0,
++ },
++#define SLOT_CFGFS 3
++ {
++ .name = "cfgfs",
++ .offset = 0,
++ .size = 0,
++ },
++#define SLOT_NVRAM 4
++ {
++ .name = "nvram",
++ .offset = 0,
++ .size = 0,
++ },
++};
++
++static struct physmap_flash_data bcm47xx_flash_data = {
++ .parts = bcm47xx_partitions,
++ .nr_parts = ARRAY_SIZE(bcm47xx_partitions)
++};
++
++static struct resource bcm47xx_flash_resource = {
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device bcm47xx_flash = {
++ .name = "physmap-flash",
++ .id = 0,
++ .dev = { .platform_data = &bcm47xx_flash_data, },
++ .resource = &bcm47xx_flash_resource,
++ .num_resources = 1,
++};
++
++static struct platform_device *bcm47xx_devices[] __initdata = {
++ &bcm47xx_flash,
++};
++
++struct bcm47xx_trx_header {
++#define BCM47XX_TRX_MAGIC 0x30524448
++ u32 magic;
++ u32 len;
++ u32 crc32;
++ u32 flag_version;
++ u32 offsets[3];
++};
++
++#define UPTODOWN(slot, psize) do { \
++ posn -= psize; left -= psize; \
++ bcm47xx_partitions[slot].offset = posn; \
++ bcm47xx_partitions[slot].size = psize; \
++} while (/* CONSTCOND */ 0)
++
++static int __init bcm47xx_register_devices(void)
++{
++ u32 flash_size;
++ size_t left, posn;
++ struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
++ struct bcm47xx_trx_header *trx_hdr;
++
++ trx_hdr = (void *)KSEG1ADDR(mcore->flash_window + 0x40000);
++
++ /* devices might have 2, 4 or 8 MB flash size */
++#ifdef BCM47XX_OVERRIDE_FLASHSIZE
++ flash_size = BCM47XX_OVERRIDE_FLASHSIZE;
++ mcore->flash_window_size = flash_size;
++#define BCM47XX_OVERRODE_FLASHSIZE " (overridden)"
++#else
++ flash_size = mcore->flash_window_size;
++#define BCM47XX_OVERRODE_FLASHSIZE ""
++#endif
++ printk(KERN_INFO "FLASH SIZE%s: %x\n", BCM47XX_OVERRODE_FLASHSIZE,
++ flash_size);
++
++ left = flash_size - 0x40000;
++ posn = flash_size;
++ UPTODOWN(SLOT_NVRAM, NVRAM_FLASH_SIZE);
++ UPTODOWN(SLOT_CFGFS, CFGFS_FLASH_SIZE);
++ bcm47xx_partitions[SLOT_LINUX].offset = 0x40000;
++ bcm47xx_partitions[SLOT_LINUX].size = left;
++
++ if (trx_hdr->magic == BCM47XX_TRX_MAGIC) {
++ bcm47xx_partitions[SLOT_ROOTFS].offset =
++ bcm47xx_partitions[SLOT_LINUX].offset +
++ trx_hdr->offsets[1];
++ bcm47xx_partitions[SLOT_ROOTFS].size =
++ bcm47xx_partitions[SLOT_LINUX].size -
++ trx_hdr->offsets[1];
++ } else
++ printk("bcm47xx/platform: no TRX header found\n");
++
++ printk(KERN_INFO "=== Flash map dump ===\n");
++ for (posn = 0; posn < bcm47xx_flash_data.nr_parts; ++posn)
++ printk(KERN_INFO " #%u %08X @%08X '%s'\n",
++ (unsigned int)posn,
++ (unsigned int)bcm47xx_partitions[posn].size,
++ (unsigned int)bcm47xx_partitions[posn].offset,
++ bcm47xx_partitions[posn].name);
++ printk(KERN_INFO "=== Hope this works, have a nice day\n");
++
++ bcm47xx_flash_data.width = mcore->flash_buswidth;
++ bcm47xx_flash_resource.start = mcore->flash_window;
++ bcm47xx_flash_resource.end = mcore->flash_window
++ + mcore->flash_window_size
++ - 1;
++ return platform_add_devices(bcm47xx_devices,
++ ARRAY_SIZE(bcm47xx_devices));
++}
++
++device_initcall(bcm47xx_register_devices);
+--- linux-2.6.36.orig/drivers/ssb/driver_mipscore.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/ssb/driver_mipscore.c 2010-12-22 16:38:53.000000000 +0100
+@@ -193,7 +193,7 @@
+ mcore->flash_buswidth = 2;
+ if (bus->chipco.dev) {
+ mcore->flash_window = 0x1c000000;
+- mcore->flash_window_size = 0x02000000;
++ mcore->flash_window_size = 0x00800000;
+ if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
+ & SSB_CHIPCO_CFG_DS16) == 0)
+ mcore->flash_buswidth = 1;
diff --git a/target/linux/patches/2.6.37/bsd-compatibility.patch b/target/linux/patches/2.6.37/bsd-compatibility.patch
new file mode 100644
index 000000000..9e91a62de
--- /dev/null
+++ b/target/linux/patches/2.6.37/bsd-compatibility.patch
@@ -0,0 +1,2512 @@
+diff -Nur linux-2.6.36.orig/scripts/Makefile.lib linux-2.6.36/scripts/Makefile.lib
+--- linux-2.6.36.orig/scripts/Makefile.lib 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/scripts/Makefile.lib 2010-11-28 18:34:22.000000000 +0100
+@@ -216,7 +216,12 @@
+ size_append = printf $(shell \
+ dec_size=0; \
+ for F in $1; do \
+- fsize=$$(stat -c "%s" $$F); \
++ if stat -qs .>/dev/null 2>&1; then \
++ statcmd='stat -f %z'; \
++ else \
++ statcmd='stat -c %s'; \
++ fi; \
++ fsize=$$($$statcmd $$F); \
+ dec_size=$$(expr $$dec_size + $$fsize); \
+ done; \
+ printf "%08x\n" $$dec_size | \
+diff -Nur linux-2.6.36.orig/scripts/mod/mk_elfconfig.c linux-2.6.36/scripts/mod/mk_elfconfig.c
+--- linux-2.6.36.orig/scripts/mod/mk_elfconfig.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/scripts/mod/mk_elfconfig.c 2010-11-28 18:33:24.000000000 +0100
+@@ -1,7 +1,18 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+-#include <elf.h>
++
++#define EI_NIDENT (16)
++#define ELFMAG "\177ELF"
++
++#define SELFMAG 4
++#define EI_CLASS 4
++#define ELFCLASS32 1 /* 32-bit objects */
++#define ELFCLASS64 2 /* 64-bit objects */
++
++#define EI_DATA 5 /* Data encoding byte index */
++#define ELFDATA2LSB 1 /* 2's complement, little endian */
++#define ELFDATA2MSB 2 /* 2's complement, big endian */
+
+ int
+ main(int argc, char **argv)
+diff -Nur linux-2.6.36.orig/scripts/mod/modpost.h linux-2.6.36/scripts/mod/modpost.h
+--- linux-2.6.36.orig/scripts/mod/modpost.h 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/scripts/mod/modpost.h 2010-11-28 18:33:24.000000000 +0100
+@@ -7,7 +7,2453 @@
+ #include <sys/mman.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+-#include <elf.h>
++
++
++/* This file defines standard ELF types, structures, and macros.
++ Copyright (C) 1995-1999,2000,2001,2002,2003 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _ELF_H
++#define _ELF_H 1
++
++__BEGIN_DECLS
++
++/* Standard ELF types. */
++
++#include <stdint.h>
++
++/* Type for a 16-bit quantity. */
++typedef uint16_t Elf32_Half;
++typedef uint16_t Elf64_Half;
++
++/* Types for signed and unsigned 32-bit quantities. */
++typedef uint32_t Elf32_Word;
++typedef int32_t Elf32_Sword;
++typedef uint32_t Elf64_Word;
++typedef int32_t Elf64_Sword;
++
++/* Types for signed and unsigned 64-bit quantities. */
++typedef uint64_t Elf32_Xword;
++typedef int64_t Elf32_Sxword;
++typedef uint64_t Elf64_Xword;
++typedef int64_t Elf64_Sxword;
++
++/* Type of addresses. */
++typedef uint32_t Elf32_Addr;
++typedef uint64_t Elf64_Addr;
++
++/* Type of file offsets. */
++typedef uint32_t Elf32_Off;
++typedef uint64_t Elf64_Off;
++
++/* Type for section indices, which are 16-bit quantities. */
++typedef uint16_t Elf32_Section;
++typedef uint16_t Elf64_Section;
++
++/* Type for version symbol information. */
++typedef Elf32_Half Elf32_Versym;
++typedef Elf64_Half Elf64_Versym;
++
++
++/* The ELF file header. This appears at the start of every ELF file. */
++
++#define EI_NIDENT (16)
++
++typedef struct
++{
++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
++ Elf32_Half e_type; /* Object file type */
++ Elf32_Half e_machine; /* Architecture */
++ Elf32_Word e_version; /* Object file version */
++ Elf32_Addr e_entry; /* Entry point virtual address */
++ Elf32_Off e_phoff; /* Program header table file offset */
++ Elf32_Off e_shoff; /* Section header table file offset */
++ Elf32_Word e_flags; /* Processor-specific flags */
++ Elf32_Half e_ehsize; /* ELF header size in bytes */
++ Elf32_Half e_phentsize; /* Program header table entry size */
++ Elf32_Half e_phnum; /* Program header table entry count */
++ Elf32_Half e_shentsize; /* Section header table entry size */
++ Elf32_Half e_shnum; /* Section header table entry count */
++ Elf32_Half e_shstrndx; /* Section header string table index */
++} Elf32_Ehdr;
++
++typedef struct
++{
++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
++ Elf64_Half e_type; /* Object file type */
++ Elf64_Half e_machine; /* Architecture */
++ Elf64_Word e_version; /* Object file version */
++ Elf64_Addr e_entry; /* Entry point virtual address */
++ Elf64_Off e_phoff; /* Program header table file offset */
++ Elf64_Off e_shoff; /* Section header table file offset */
++ Elf64_Word e_flags; /* Processor-specific flags */
++ Elf64_Half e_ehsize; /* ELF header size in bytes */
++ Elf64_Half e_phentsize; /* Program header table entry size */
++ Elf64_Half e_phnum; /* Program header table entry count */
++ Elf64_Half e_shentsize; /* Section header table entry size */
++ Elf64_Half e_shnum; /* Section header table entry count */
++ Elf64_Half e_shstrndx; /* Section header string table index */
++} Elf64_Ehdr;
++
++/* Fields in the e_ident array. The EI_* macros are indices into the
++ array. The macros under each EI_* macro are the values the byte
++ may have. */
++
++#define EI_MAG0 0 /* File identification byte 0 index */
++#define ELFMAG0 0x7f /* Magic number byte 0 */
++
++#define EI_MAG1 1 /* File identification byte 1 index */
++#define ELFMAG1 'E' /* Magic number byte 1 */
++
++#define EI_MAG2 2 /* File identification byte 2 index */
++#define ELFMAG2 'L' /* Magic number byte 2 */
++
++#define EI_MAG3 3 /* File identification byte 3 index */
++#define ELFMAG3 'F' /* Magic number byte 3 */
++
++/* Conglomeration of the identification bytes, for easy testing as a word. */
++#define ELFMAG "\177ELF"
++#define SELFMAG 4
++
++#define EI_CLASS 4 /* File class byte index */
++#define ELFCLASSNONE 0 /* Invalid class */
++#define ELFCLASS32 1 /* 32-bit objects */
++#define ELFCLASS64 2 /* 64-bit objects */
++#define ELFCLASSNUM 3
++
++#define EI_DATA 5 /* Data encoding byte index */
++#define ELFDATANONE 0 /* Invalid data encoding */
++#define ELFDATA2LSB 1 /* 2's complement, little endian */
++#define ELFDATA2MSB 2 /* 2's complement, big endian */
++#define ELFDATANUM 3
++
++#define EI_VERSION 6 /* File version byte index */
++ /* Value must be EV_CURRENT */
++
++#define EI_OSABI 7 /* OS ABI identification */
++#define ELFOSABI_NONE 0 /* UNIX System V ABI */
++#define ELFOSABI_SYSV 0 /* Alias. */
++#define ELFOSABI_HPUX 1 /* HP-UX */
++#define ELFOSABI_NETBSD 2 /* NetBSD. */
++#define ELFOSABI_LINUX 3 /* Linux. */
++#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */
++#define ELFOSABI_AIX 7 /* IBM AIX. */
++#define ELFOSABI_IRIX 8 /* SGI Irix. */
++#define ELFOSABI_FREEBSD 9 /* FreeBSD. */
++#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */
++#define ELFOSABI_MODESTO 11 /* Novell Modesto. */
++#define ELFOSABI_OPENBSD 12 /* OpenBSD. */
++#define ELFOSABI_ARM 97 /* ARM */
++#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
++
++#define EI_ABIVERSION 8 /* ABI version */
++
++#define EI_PAD 9 /* Byte index of padding bytes */
++
++/* Legal values for e_type (object file type). */
++
++#define ET_NONE 0 /* No file type */
++#define ET_REL 1 /* Relocatable file */
++#define ET_EXEC 2 /* Executable file */
++#define ET_DYN 3 /* Shared object file */
++#define ET_CORE 4 /* Core file */
++#define ET_NUM 5 /* Number of defined types */
++#define ET_LOOS 0xfe00 /* OS-specific range start */
++#define ET_HIOS 0xfeff /* OS-specific range end */
++#define ET_LOPROC 0xff00 /* Processor-specific range start */
++#define ET_HIPROC 0xffff /* Processor-specific range end */
++
++/* Legal values for e_machine (architecture). */
++
++#define EM_NONE 0 /* No machine */
++#define EM_M32 1 /* AT&T WE 32100 */
++#define EM_SPARC 2 /* SUN SPARC */
++#define EM_386 3 /* Intel 80386 */
++#define EM_68K 4 /* Motorola m68k family */
++#define EM_88K 5 /* Motorola m88k family */
++#define EM_860 7 /* Intel 80860 */
++#define EM_MIPS 8 /* MIPS R3000 big-endian */
++#define EM_S370 9 /* IBM System/370 */
++#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
++
++#define EM_PARISC 15 /* HPPA */
++#define EM_VPP500 17 /* Fujitsu VPP500 */
++#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
++#define EM_960 19 /* Intel 80960 */
++#define EM_PPC 20 /* PowerPC */
++#define EM_PPC64 21 /* PowerPC 64-bit */
++#define EM_S390 22 /* IBM S390 */
++
++#define EM_V800 36 /* NEC V800 series */
++#define EM_FR20 37 /* Fujitsu FR20 */
++#define EM_RH32 38 /* TRW RH-32 */
++#define EM_RCE 39 /* Motorola RCE */
++#define EM_ARM 40 /* ARM */
++#define EM_FAKE_ALPHA 41 /* Digital Alpha */
++#define EM_SH 42 /* Hitachi SH */
++#define EM_SPARCV9 43 /* SPARC v9 64-bit */
++#define EM_TRICORE 44 /* Siemens Tricore */
++#define EM_ARC 45 /* Argonaut RISC Core */
++#define EM_H8_300 46 /* Hitachi H8/300 */
++#define EM_H8_300H 47 /* Hitachi H8/300H */
++#define EM_H8S 48 /* Hitachi H8S */
++#define EM_H8_500 49 /* Hitachi H8/500 */
++#define EM_IA_64 50 /* Intel Merced */
++#define EM_MIPS_X 51 /* Stanford MIPS-X */
++#define EM_COLDFIRE 52 /* Motorola Coldfire */
++#define EM_68HC12 53 /* Motorola M68HC12 */
++#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/
++#define EM_PCP 55 /* Siemens PCP */
++#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
++#define EM_NDR1 57 /* Denso NDR1 microprocessor */
++#define EM_STARCORE 58 /* Motorola Start*Core processor */
++#define EM_ME16 59 /* Toyota ME16 processor */
++#define EM_ST100 60 /* STMicroelectronic ST100 processor */
++#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/
++#define EM_X86_64 62 /* AMD x86-64 architecture */
++#define EM_PDSP 63 /* Sony DSP Processor */
++
++#define EM_FX66 66 /* Siemens FX66 microcontroller */
++#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
++#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
++#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
++#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
++#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
++#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
++#define EM_SVX 73 /* Silicon Graphics SVx */
++#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */
++#define EM_VAX 75 /* Digital VAX */
++#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
++#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */
++#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
++#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
++#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */
++#define EM_HUANY 81 /* Harvard University machine-independent object files */
++#define EM_PRISM 82 /* SiTera Prism */
++#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
++#define EM_FR30 84 /* Fujitsu FR30 */
++#define EM_D10V 85 /* Mitsubishi D10V */
++#define EM_D30V 86 /* Mitsubishi D30V */
++#define EM_V850 87 /* NEC v850 */
++#define EM_M32R 88 /* Mitsubishi M32R */
++#define EM_MN10300 89 /* Matsushita MN10300 */
++#define EM_MN10200 90 /* Matsushita MN10200 */
++#define EM_PJ 91 /* picoJava */
++#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
++#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */
++#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
++#define EM_NUM 95
++
++/* If it is necessary to assign new unofficial EM_* values, please
++ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
++ chances of collision with official or non-GNU unofficial values. */
++
++#define EM_ALPHA 0x9026
++
++/* Legal values for e_version (version). */
++
++#define EV_NONE 0 /* Invalid ELF version */
++#define EV_CURRENT 1 /* Current version */
++#define EV_NUM 2
++
++/* Section header. */
++
++typedef struct
++{
++ Elf32_Word sh_name; /* Section name (string tbl index) */
++ Elf32_Word sh_type; /* Section type */
++ Elf32_Word sh_flags; /* Section flags */
++ Elf32_Addr sh_addr; /* Section virtual addr at execution */
++ Elf32_Off sh_offset; /* Section file offset */
++ Elf32_Word sh_size; /* Section size in bytes */
++ Elf32_Word sh_link; /* Link to another section */
++ Elf32_Word sh_info; /* Additional section information */
++ Elf32_Word sh_addralign; /* Section alignment */
++ Elf32_Word sh_entsize; /* Entry size if section holds table */
++} Elf32_Shdr;
++
++typedef struct
++{
++ Elf64_Word sh_name; /* Section name (string tbl index) */
++ Elf64_Word sh_type; /* Section type */
++ Elf64_Xword sh_flags; /* Section flags */
++ Elf64_Addr sh_addr; /* Section virtual addr at execution */
++ Elf64_Off sh_offset; /* Section file offset */
++ Elf64_Xword sh_size; /* Section size in bytes */
++ Elf64_Word sh_link; /* Link to another section */
++ Elf64_Word sh_info; /* Additional section information */
++ Elf64_Xword sh_addralign; /* Section alignment */
++ Elf64_Xword sh_entsize; /* Entry size if section holds table */
++} Elf64_Shdr;
++
++/* Special section indices. */
++
++#define SHN_UNDEF 0 /* Undefined section */
++#define SHN_LORESERVE 0xff00 /* Start of reserved indices */
++#define SHN_LOPROC 0xff00 /* Start of processor-specific */
++#define SHN_HIPROC 0xff1f /* End of processor-specific */
++#define SHN_LOOS 0xff20 /* Start of OS-specific */
++#define SHN_HIOS 0xff3f /* End of OS-specific */
++#define SHN_ABS 0xfff1 /* Associated symbol is absolute */
++#define SHN_COMMON 0xfff2 /* Associated symbol is common */
++#define SHN_XINDEX 0xffff /* Index is in extra table. */
++#define SHN_HIRESERVE 0xffff /* End of reserved indices */
++
++/* Legal values for sh_type (section type). */
++
++#define SHT_NULL 0 /* Section header table entry unused */
++#define SHT_PROGBITS 1 /* Program data */
++#define SHT_SYMTAB 2 /* Symbol table */
++#define SHT_STRTAB 3 /* String table */
++#define SHT_RELA 4 /* Relocation entries with addends */
++#define SHT_HASH 5 /* Symbol hash table */
++#define SHT_DYNAMIC 6 /* Dynamic linking information */
++#define SHT_NOTE 7 /* Notes */
++#define SHT_NOBITS 8 /* Program space with no data (bss) */
++#define SHT_REL 9 /* Relocation entries, no addends */
++#define SHT_SHLIB 10 /* Reserved */
++#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
++#define SHT_INIT_ARRAY 14 /* Array of constructors */
++#define SHT_FINI_ARRAY 15 /* Array of destructors */
++#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
++#define SHT_GROUP 17 /* Section group */
++#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
++#define SHT_NUM 19 /* Number of defined types. */
++#define SHT_LOOS 0x60000000 /* Start OS-specific */
++#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
++#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
++#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
++#define SHT_SUNW_move 0x6ffffffa
++#define SHT_SUNW_COMDAT 0x6ffffffb
++#define SHT_SUNW_syminfo 0x6ffffffc
++#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */
++#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */
++#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */
++#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */
++#define SHT_HIOS 0x6fffffff /* End OS-specific type */
++#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
++#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
++#define SHT_LOUSER 0x80000000 /* Start of application-specific */
++#define SHT_HIUSER 0x8fffffff /* End of application-specific */
++
++/* Legal values for sh_flags (section flags). */
++
++#define SHF_WRITE (1 << 0) /* Writable */
++#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
++#define SHF_EXECINSTR (1 << 2) /* Executable */
++#define SHF_MERGE (1 << 4) /* Might be merged */
++#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
++#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */
++#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */
++#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling
++ required */
++#define SHF_GROUP (1 << 9) /* Section is member of a group. */
++#define SHF_TLS (1 << 10) /* Section hold thread-local data. */
++#define SHF_MASKOS 0x0ff00000 /* OS-specific. */
++#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
++
++/* Section group handling. */
++#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */
++
++/* Symbol table entry. */
++
++typedef struct
++{
++ Elf32_Word st_name; /* Symbol name (string tbl index) */
++ Elf32_Addr st_value; /* Symbol value */
++ Elf32_Word st_size; /* Symbol size */
++ unsigned char st_info; /* Symbol type and binding */
++ unsigned char st_other; /* Symbol visibility */
++ Elf32_Section st_shndx; /* Section index */
++} Elf32_Sym;
++
++typedef struct
++{
++ Elf64_Word st_name; /* Symbol name (string tbl index) */
++ unsigned char st_info; /* Symbol type and binding */
++ unsigned char st_other; /* Symbol visibility */
++ Elf64_Section st_shndx; /* Section index */
++ Elf64_Addr st_value; /* Symbol value */
++ Elf64_Xword st_size; /* Symbol size */
++} Elf64_Sym;
++
++/* The syminfo section if available contains additional information about
++ every dynamic symbol. */
++
++typedef struct
++{
++ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */
++ Elf32_Half si_flags; /* Per symbol flags */
++} Elf32_Syminfo;
++
++typedef struct
++{
++ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */
++ Elf64_Half si_flags; /* Per symbol flags */
++} Elf64_Syminfo;
++
++/* Possible values for si_boundto. */
++#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */
++#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */
++#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */
++
++/* Possible bitmasks for si_flags. */
++#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */
++#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */
++#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */
++#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy
++ loaded */
++/* Syminfo version values. */
++#define SYMINFO_NONE 0
++#define SYMINFO_CURRENT 1
++#define SYMINFO_NUM 2
++
++
++/* How to extract and insert information held in the st_info field. */
++
++#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4)
++#define ELF32_ST_TYPE(val) ((val) & 0xf)
++#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
++
++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */
++#define ELF64_ST_BIND(val) ELF32_ST_BIND (val)
++#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val)
++#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type))
++
++/* Legal values for ST_BIND subfield of st_info (symbol binding). */
++
++#define STB_LOCAL 0 /* Local symbol */
++#define STB_GLOBAL 1 /* Global symbol */
++#define STB_WEAK 2 /* Weak symbol */
++#define STB_NUM 3 /* Number of defined types. */
++#define STB_LOOS 10 /* Start of OS-specific */
++#define STB_HIOS 12 /* End of OS-specific */
++#define STB_LOPROC 13 /* Start of processor-specific */
++#define STB_HIPROC 15 /* End of processor-specific */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type). */
++
++#define STT_NOTYPE 0 /* Symbol type is unspecified */
++#define STT_OBJECT 1 /* Symbol is a data object */
++#define STT_FUNC 2 /* Symbol is a code object */
++#define STT_SECTION 3 /* Symbol associated with a section */
++#define STT_FILE 4 /* Symbol's name is file name */
++#define STT_COMMON 5 /* Symbol is a common data object */
++#define STT_TLS 6 /* Symbol is thread-local data object*/
++#define STT_NUM 7 /* Number of defined types. */
++#define STT_LOOS 10 /* Start of OS-specific */
++#define STT_HIOS 12 /* End of OS-specific */
++#define STT_LOPROC 13 /* Start of processor-specific */
++#define STT_HIPROC 15 /* End of processor-specific */
++
++
++/* Symbol table indices are found in the hash buckets and chain table
++ of a symbol hash table section. This special index value indicates
++ the end of a chain, meaning no further symbols are found in that bucket. */
++
++#define STN_UNDEF 0 /* End of a chain. */
++
++
++/* How to extract and insert information held in the st_other field. */
++
++#define ELF32_ST_VISIBILITY(o) ((o) & 0x03)
++
++/* For ELF64 the definitions are the same. */
++#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o)
++
++/* Symbol visibility specification encoded in the st_other field. */
++#define STV_DEFAULT 0 /* Default symbol visibility rules */
++#define STV_INTERNAL 1 /* Processor specific hidden class */
++#define STV_HIDDEN 2 /* Sym unavailable in other modules */
++#define STV_PROTECTED 3 /* Not preemptible, not exported */
++
++
++/* Relocation table entry without addend (in section of type SHT_REL). */
++
++typedef struct
++{
++ Elf32_Addr r_offset; /* Address */
++ Elf32_Word r_info; /* Relocation type and symbol index */
++} Elf32_Rel;
++
++/* I have seen two different definitions of the Elf64_Rel and
++ Elf64_Rela structures, so we'll leave them out until Novell (or
++ whoever) gets their act together. */
++/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */
++
++typedef struct
++{
++ Elf64_Addr r_offset; /* Address */
++ Elf64_Xword r_info; /* Relocation type and symbol index */
++} Elf64_Rel;
++
++/* Relocation table entry with addend (in section of type SHT_RELA). */
++
++typedef struct
++{
++ Elf32_Addr r_offset; /* Address */
++ Elf32_Word r_info; /* Relocation type and symbol index */
++ Elf32_Sword r_addend; /* Addend */
++} Elf32_Rela;
++
++typedef struct
++{
++ Elf64_Addr r_offset; /* Address */
++ Elf64_Xword r_info; /* Relocation type and symbol index */
++ Elf64_Sxword r_addend; /* Addend */
++} Elf64_Rela;
++
++/* How to extract and insert information held in the r_info field. */
++
++#define ELF32_R_SYM(val) ((val) >> 8)
++#define ELF32_R_TYPE(val) ((val) & 0xff)
++#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
++
++#define ELF64_R_SYM(i) ((i) >> 32)
++#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
++#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type))
++
++/* Program segment header. */
++
++typedef struct
++{
++ Elf32_Word p_type; /* Segment type */
++ Elf32_Off p_offset; /* Segment file offset */
++ Elf32_Addr p_vaddr; /* Segment virtual address */
++ Elf32_Addr p_paddr; /* Segment physical address */
++ Elf32_Word p_filesz; /* Segment size in file */
++ Elf32_Word p_memsz; /* Segment size in memory */
++ Elf32_Word p_flags; /* Segment flags */
++ Elf32_Word p_align; /* Segment alignment */
++} Elf32_Phdr;
++
++typedef struct
++{
++ Elf64_Word p_type; /* Segment type */
++ Elf64_Word p_flags; /* Segment flags */
++ Elf64_Off p_offset; /* Segment file offset */
++ Elf64_Addr p_vaddr; /* Segment virtual address */
++ Elf64_Addr p_paddr; /* Segment physical address */
++ Elf64_Xword p_filesz; /* Segment size in file */
++ Elf64_Xword p_memsz; /* Segment size in memory */
++ Elf64_Xword p_align; /* Segment alignment */
++} Elf64_Phdr;
++
++/* Legal values for p_type (segment type). */
++
++#define PT_NULL 0 /* Program header table entry unused */
++#define PT_LOAD 1 /* Loadable program segment */
++#define PT_DYNAMIC 2 /* Dynamic linking information */
++#define PT_INTERP 3 /* Program interpreter */
++#define PT_NOTE 4 /* Auxiliary information */
++#define PT_SHLIB 5 /* Reserved */
++#define PT_PHDR 6 /* Entry for header table itself */
++#define PT_TLS 7 /* Thread-local storage segment */
++#define PT_NUM 8 /* Number of defined types */
++#define PT_LOOS 0x60000000 /* Start of OS-specific */
++#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
++#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
++#define PT_LOSUNW 0x6ffffffa
++#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
++#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */
++#define PT_HISUNW 0x6fffffff
++#define PT_HIOS 0x6fffffff /* End of OS-specific */
++#define PT_LOPROC 0x70000000 /* Start of processor-specific */
++#define PT_HIPROC 0x7fffffff /* End of processor-specific */
++
++/* Legal values for p_flags (segment flags). */
++
++#define PF_X (1 << 0) /* Segment is executable */
++#define PF_W (1 << 1) /* Segment is writable */
++#define PF_R (1 << 2) /* Segment is readable */
++#define PF_MASKOS 0x0ff00000 /* OS-specific */
++#define PF_MASKPROC 0xf0000000 /* Processor-specific */
++
++/* Legal values for note segment descriptor types for core files. */
++
++#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
++#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
++#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
++#define NT_PRXREG 4 /* Contains copy of prxregset struct */
++#define NT_TASKSTRUCT 4 /* Contains copy of task structure */
++#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */
++#define NT_AUXV 6 /* Contains copy of auxv array */
++#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */
++#define NT_ASRS 8 /* Contains copy of asrset struct */
++#define NT_PSTATUS 10 /* Contains copy of pstatus struct */
++#define NT_PSINFO 13 /* Contains copy of psinfo struct */
++#define NT_PRCRED 14 /* Contains copy of prcred struct */
++#define NT_UTSNAME 15 /* Contains copy of utsname struct */
++#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */
++#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */
++#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct*/
++
++/* Legal values for the note segment descriptor types for object files. */
++
++#define NT_VERSION 1 /* Contains a version string. */
++
++
++/* Dynamic section entry. */
++
++typedef struct
++{
++ Elf32_Sword d_tag; /* Dynamic entry type */
++ union
++ {
++ Elf32_Word d_val; /* Integer value */
++ Elf32_Addr d_ptr; /* Address value */
++ } d_un;
++} Elf32_Dyn;
++
++typedef struct
++{
++ Elf64_Sxword d_tag; /* Dynamic entry type */
++ union
++ {
++ Elf64_Xword d_val; /* Integer value */
++ Elf64_Addr d_ptr; /* Address value */
++ } d_un;
++} Elf64_Dyn;
++
++/* Legal values for d_tag (dynamic entry type). */
++
++#define DT_NULL 0 /* Marks end of dynamic section */
++#define DT_NEEDED 1 /* Name of needed library */
++#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */
++#define DT_PLTGOT 3 /* Processor defined value */
++#define DT_HASH 4 /* Address of symbol hash table */
++#define DT_STRTAB 5 /* Address of string table */
++#define DT_SYMTAB 6 /* Address of symbol table */
++#define DT_RELA 7 /* Address of Rela relocs */
++#define DT_RELASZ 8 /* Total size of Rela relocs */
++#define DT_RELAENT 9 /* Size of one Rela reloc */
++#define DT_STRSZ 10 /* Size of string table */
++#define DT_SYMENT 11 /* Size of one symbol table entry */
++#define DT_INIT 12 /* Address of init function */
++#define DT_FINI 13 /* Address of termination function */
++#define DT_SONAME 14 /* Name of shared object */
++#define DT_RPATH 15 /* Library search path (deprecated) */
++#define DT_SYMBOLIC 16 /* Start symbol search here */
++#define DT_REL 17 /* Address of Rel relocs */
++#define DT_RELSZ 18 /* Total size of Rel relocs */
++#define DT_RELENT 19 /* Size of one Rel reloc */
++#define DT_PLTREL 20 /* Type of reloc in PLT */
++#define DT_DEBUG 21 /* For debugging; unspecified */
++#define DT_TEXTREL 22 /* Reloc might modify .text */
++#define DT_JMPREL 23 /* Address of PLT relocs */
++#define DT_BIND_NOW 24 /* Process relocations of object */
++#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
++#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
++#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
++#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
++#define DT_RUNPATH 29 /* Library search path */
++#define DT_FLAGS 30 /* Flags for the object being loaded */
++#define DT_ENCODING 32 /* Start of encoded range */
++#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
++#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
++#define DT_NUM 34 /* Number used */
++#define DT_LOOS 0x6000000d /* Start of OS-specific */
++#define DT_HIOS 0x6ffff000 /* End of OS-specific */
++#define DT_LOPROC 0x70000000 /* Start of processor-specific */
++#define DT_HIPROC 0x7fffffff /* End of processor-specific */
++#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */
++
++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
++ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's
++ approach. */
++#define DT_VALRNGLO 0x6ffffd00
++#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */
++#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */
++#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */
++#define DT_CHECKSUM 0x6ffffdf8
++#define DT_PLTPADSZ 0x6ffffdf9
++#define DT_MOVEENT 0x6ffffdfa
++#define DT_MOVESZ 0x6ffffdfb
++#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */
++#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting
++ the following DT_* entry. */
++#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */
++#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */
++#define DT_VALRNGHI 0x6ffffdff
++#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */
++#define DT_VALNUM 12
++
++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
++ Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
++
++ If any adjustment is made to the ELF object after it has been
++ built these entries will need to be adjusted. */
++#define DT_ADDRRNGLO 0x6ffffe00
++#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */
++#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */
++#define DT_CONFIG 0x6ffffefa /* Configuration information. */
++#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */
++#define DT_AUDIT 0x6ffffefc /* Object auditing. */
++#define DT_PLTPAD 0x6ffffefd /* PLT padding. */
++#define DT_MOVETAB 0x6ffffefe /* Move table. */
++#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */
++#define DT_ADDRRNGHI 0x6ffffeff
++#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */
++#define DT_ADDRNUM 10
++
++/* The versioning entry types. The next are defined as part of the
++ GNU extension. */
++#define DT_VERSYM 0x6ffffff0
++
++#define DT_RELACOUNT 0x6ffffff9
++#define DT_RELCOUNT 0x6ffffffa
++
++/* These were chosen by Sun. */
++#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */
++#define DT_VERDEF 0x6ffffffc /* Address of version definition
++ table */
++#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */
++#define DT_VERNEED 0x6ffffffe /* Address of table with needed
++ versions */
++#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */
++#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
++#define DT_VERSIONTAGNUM 16
++
++/* Sun added these machine-independent extensions in the "processor-specific"
++ range. Be compatible. */
++#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */
++#define DT_FILTER 0x7fffffff /* Shared object to get values from */
++#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
++#define DT_EXTRANUM 3
++
++/* Values of `d_un.d_val' in the DT_FLAGS entry. */
++#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */
++#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */
++#define DF_TEXTREL 0x00000004 /* Object contains text relocations */
++#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */
++#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */
++
++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
++ entry in the dynamic section. */
++#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */
++#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */
++#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */
++#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/
++#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/
++#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/
++#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */
++#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */
++#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */
++#define DF_1_TRANS 0x00000200
++#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */
++#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */
++#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */
++#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/
++#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */
++#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */
++#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */
++
++/* Flags for the feature selection in DT_FEATURE_1. */
++#define DTF_1_PARINIT 0x00000001
++#define DTF_1_CONFEXP 0x00000002
++
++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */
++#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */
++#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not
++ generally available. */
++
++/* Version definition sections. */
++
++typedef struct
++{
++ Elf32_Half vd_version; /* Version revision */
++ Elf32_Half vd_flags; /* Version information */
++ Elf32_Half vd_ndx; /* Version Index */
++ Elf32_Half vd_cnt; /* Number of associated aux entries */
++ Elf32_Word vd_hash; /* Version name hash value */
++ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */
++ Elf32_Word vd_next; /* Offset in bytes to next verdef
++ entry */
++} Elf32_Verdef;
++
++typedef struct
++{
++ Elf64_Half vd_version; /* Version revision */
++ Elf64_Half vd_flags; /* Version information */
++ Elf64_Half vd_ndx; /* Version Index */
++ Elf64_Half vd_cnt; /* Number of associated aux entries */
++ Elf64_Word vd_hash; /* Version name hash value */
++ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */
++ Elf64_Word vd_next; /* Offset in bytes to next verdef
++ entry */
++} Elf64_Verdef;
++
++
++/* Legal values for vd_version (version revision). */
++#define VER_DEF_NONE 0 /* No version */
++#define VER_DEF_CURRENT 1 /* Current version */
++#define VER_DEF_NUM 2 /* Given version number */
++
++/* Legal values for vd_flags (version information flags). */
++#define VER_FLG_BASE 0x1 /* Version definition of file itself */
++#define VER_FLG_WEAK 0x2 /* Weak version identifier */
++
++/* Versym symbol index values. */
++#define VER_NDX_LOCAL 0 /* Symbol is local. */
++#define VER_NDX_GLOBAL 1 /* Symbol is global. */
++#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */
++#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */
++
++/* Auxialiary version information. */
++
++typedef struct
++{
++ Elf32_Word vda_name; /* Version or dependency names */
++ Elf32_Word vda_next; /* Offset in bytes to next verdaux
++ entry */
++} Elf32_Verdaux;
++
++typedef struct
++{
++ Elf64_Word vda_name; /* Version or dependency names */
++ Elf64_Word vda_next; /* Offset in bytes to next verdaux
++ entry */
++} Elf64_Verdaux;
++
++
++/* Version dependency section. */
++
++typedef struct
++{
++ Elf32_Half vn_version; /* Version of structure */
++ Elf32_Half vn_cnt; /* Number of associated aux entries */
++ Elf32_Word vn_file; /* Offset of filename for this
++ dependency */
++ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */
++ Elf32_Word vn_next; /* Offset in bytes to next verneed
++ entry */
++} Elf32_Verneed;
++
++typedef struct
++{
++ Elf64_Half vn_version; /* Version of structure */
++ Elf64_Half vn_cnt; /* Number of associated aux entries */
++ Elf64_Word vn_file; /* Offset of filename for this
++ dependency */
++ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */
++ Elf64_Word vn_next; /* Offset in bytes to next verneed
++ entry */
++} Elf64_Verneed;
++
++
++/* Legal values for vn_version (version revision). */
++#define VER_NEED_NONE 0 /* No version */
++#define VER_NEED_CURRENT 1 /* Current version */
++#define VER_NEED_NUM 2 /* Given version number */
++
++/* Auxiliary needed version information. */
++
++typedef struct
++{
++ Elf32_Word vna_hash; /* Hash value of dependency name */
++ Elf32_Half vna_flags; /* Dependency specific information */
++ Elf32_Half vna_other; /* Unused */
++ Elf32_Word vna_name; /* Dependency name string offset */
++ Elf32_Word vna_next; /* Offset in bytes to next vernaux
++ entry */
++} Elf32_Vernaux;
++
++typedef struct
++{
++ Elf64_Word vna_hash; /* Hash value of dependency name */
++ Elf64_Half vna_flags; /* Dependency specific information */
++ Elf64_Half vna_other; /* Unused */
++ Elf64_Word vna_name; /* Dependency name string offset */
++ Elf64_Word vna_next; /* Offset in bytes to next vernaux
++ entry */
++} Elf64_Vernaux;
++
++
++/* Legal values for vna_flags. */
++#define VER_FLG_WEAK 0x2 /* Weak version identifier */
++
++
++/* Auxiliary vector. */
++
++/* This vector is normally only used by the program interpreter. The
++ usual definition in an ABI supplement uses the name auxv_t. The
++ vector is not usually defined in a standard <elf.h> file, but it
++ can't hurt. We rename it to avoid conflicts. The sizes of these
++ types are an arrangement between the exec server and the program
++ interpreter, so we don't fully specify them here. */
++
++typedef struct
++{
++ int a_type; /* Entry type */
++ union
++ {
++ long int a_val; /* Integer value */
++ void *a_ptr; /* Pointer value */
++ void (*a_fcn) (void); /* Function pointer value */
++ } a_un;
++} Elf32_auxv_t;
++
++typedef struct
++{
++ long int a_type; /* Entry type */
++ union
++ {
++ long int a_val; /* Integer value */
++ void *a_ptr; /* Pointer value */
++ void (*a_fcn) (void); /* Function pointer value */
++ } a_un;
++} Elf64_auxv_t;
++
++/* Legal values for a_type (entry type). */
++
++#define AT_NULL 0 /* End of vector */
++#define AT_IGNORE 1 /* Entry should be ignored */
++#define AT_EXECFD 2 /* File descriptor of program */
++#define AT_PHDR 3 /* Program headers for program */
++#define AT_PHENT 4 /* Size of program header entry */
++#define AT_PHNUM 5 /* Number of program headers */
++#define AT_PAGESZ 6 /* System page size */
++#define AT_BASE 7 /* Base address of interpreter */
++#define AT_FLAGS 8 /* Flags */
++#define AT_ENTRY 9 /* Entry point of program */
++#define AT_NOTELF 10 /* Program is not ELF */
++#define AT_UID 11 /* Real uid */
++#define AT_EUID 12 /* Effective uid */
++#define AT_GID 13 /* Real gid */
++#define AT_EGID 14 /* Effective gid */
++#define AT_CLKTCK 17 /* Frequency of times() */
++
++/* Some more special a_type values describing the hardware. */
++#define AT_PLATFORM 15 /* String identifying platform. */
++#define AT_HWCAP 16 /* Machine dependent hints about
++ processor capabilities. */
++
++/* This entry gives some information about the FPU initialization
++ performed by the kernel. */
++#define AT_FPUCW 18 /* Used FPU control word. */
++
++/* Cache block sizes. */
++#define AT_DCACHEBSIZE 19 /* Data cache block size. */
++#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */
++#define AT_UCACHEBSIZE 21 /* Unified cache block size. */
++
++/* A special ignored value for PPC, used by the kernel to control the
++ interpretation of the AUXV. Must be > 16. */
++#define AT_IGNOREPPC 22 /* Entry should be ignored. */
++
++#define AT_SECURE 23 /* Boolean, was exec setuid-like? */
++
++/* Pointer to the global system page used for system calls and other
++ nice things. */
++#define AT_SYSINFO 32
++#define AT_SYSINFO_EHDR 33
++
++
++/* Note section contents. Each entry in the note section begins with
++ a header of a fixed form. */
++
++typedef struct
++{
++ Elf32_Word n_namesz; /* Length of the note's name. */
++ Elf32_Word n_descsz; /* Length of the note's descriptor. */
++ Elf32_Word n_type; /* Type of the note. */
++} Elf32_Nhdr;
++
++typedef struct
++{
++ Elf64_Word n_namesz; /* Length of the note's name. */
++ Elf64_Word n_descsz; /* Length of the note's descriptor. */
++ Elf64_Word n_type; /* Type of the note. */
++} Elf64_Nhdr;
++
++/* Known names of notes. */
++
++/* Solaris entries in the note section have this name. */
++#define ELF_NOTE_SOLARIS "SUNW Solaris"
++
++/* Note entries for GNU systems have this name. */
++#define ELF_NOTE_GNU "GNU"
++
++
++/* Defined types of notes for Solaris. */
++
++/* Value of descriptor (one word) is desired pagesize for the binary. */
++#define ELF_NOTE_PAGESIZE_HINT 1
++
++
++/* Defined note types for GNU systems. */
++
++/* ABI information. The descriptor consists of words:
++ word 0: OS descriptor
++ word 1: major version of the ABI
++ word 2: minor version of the ABI
++ word 3: subminor version of the ABI
++*/
++#define ELF_NOTE_ABI 1
++
++/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI
++ note section entry. */
++#define ELF_NOTE_OS_LINUX 0
++#define ELF_NOTE_OS_GNU 1
++#define ELF_NOTE_OS_SOLARIS2 2
++#define ELF_NOTE_OS_FREEBSD 3
++
++
++/* Move records. */
++typedef struct
++{
++ Elf32_Xword m_value; /* Symbol value. */
++ Elf32_Word m_info; /* Size and index. */
++ Elf32_Word m_poffset; /* Symbol offset. */
++ Elf32_Half m_repeat; /* Repeat count. */
++ Elf32_Half m_stride; /* Stride info. */
++} Elf32_Move;
++
++typedef struct
++{
++ Elf64_Xword m_value; /* Symbol value. */
++ Elf64_Xword m_info; /* Size and index. */
++ Elf64_Xword m_poffset; /* Symbol offset. */
++ Elf64_Half m_repeat; /* Repeat count. */
++ Elf64_Half m_stride; /* Stride info. */
++} Elf64_Move;
++
++/* Macro to construct move records. */
++#define ELF32_M_SYM(info) ((info) >> 8)
++#define ELF32_M_SIZE(info) ((unsigned char) (info))
++#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size))
++
++#define ELF64_M_SYM(info) ELF32_M_SYM (info)
++#define ELF64_M_SIZE(info) ELF32_M_SIZE (info)
++#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size)
++
++
++/* Motorola 68k specific definitions. */
++
++/* Values for Elf32_Ehdr.e_flags. */
++#define EF_CPU32 0x00810000
++
++/* m68k relocs. */
++
++#define R_68K_NONE 0 /* No reloc */
++#define R_68K_32 1 /* Direct 32 bit */
++#define R_68K_16 2 /* Direct 16 bit */
++#define R_68K_8 3 /* Direct 8 bit */
++#define R_68K_PC32 4 /* PC relative 32 bit */
++#define R_68K_PC16 5 /* PC relative 16 bit */
++#define R_68K_PC8 6 /* PC relative 8 bit */
++#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */
++#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */
++#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */
++#define R_68K_GOT32O 10 /* 32 bit GOT offset */
++#define R_68K_GOT16O 11 /* 16 bit GOT offset */
++#define R_68K_GOT8O 12 /* 8 bit GOT offset */
++#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */
++#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */
++#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */
++#define R_68K_PLT32O 16 /* 32 bit PLT offset */
++#define R_68K_PLT16O 17 /* 16 bit PLT offset */
++#define R_68K_PLT8O 18 /* 8 bit PLT offset */
++#define R_68K_COPY 19 /* Copy symbol at runtime */
++#define R_68K_GLOB_DAT 20 /* Create GOT entry */
++#define R_68K_JMP_SLOT 21 /* Create PLT entry */
++#define R_68K_RELATIVE 22 /* Adjust by program base */
++/* Keep this the last entry. */
++#define R_68K_NUM 23
++
++/* Intel 80386 specific definitions. */
++
++/* i386 relocs. */
++
++#define R_386_NONE 0 /* No reloc */
++#define R_386_32 1 /* Direct 32 bit */
++#define R_386_PC32 2 /* PC relative 32 bit */
++#define R_386_GOT32 3 /* 32 bit GOT entry */
++#define R_386_PLT32 4 /* 32 bit PLT address */
++#define R_386_COPY 5 /* Copy symbol at runtime */
++#define R_386_GLOB_DAT 6 /* Create GOT entry */
++#define R_386_JMP_SLOT 7 /* Create PLT entry */
++#define R_386_RELATIVE 8 /* Adjust by program base */
++#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
++#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */
++#define R_386_32PLT 11
++#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */
++#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS
++ block offset */
++#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block
++ offset */
++#define R_386_TLS_LE 17 /* Offset relative to static TLS
++ block */
++#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of
++ general dynamic thread local data */
++#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of
++ local dynamic thread local data
++ in LE code */
++#define R_386_16 20
++#define R_386_PC16 21
++#define R_386_8 22
++#define R_386_PC8 23
++#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic
++ thread local data */
++#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */
++#define R_386_TLS_GD_CALL 26 /* Relocation for call to
++ __tls_get_addr() */
++#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */
++#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic
++ thread local data in LE code */
++#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */
++#define R_386_TLS_LDM_CALL 30 /* Relocation for call to
++ __tls_get_addr() in LDM code */
++#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */
++#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */
++#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS
++ block offset */
++#define R_386_TLS_LE_32 34 /* Negated offset relative to static
++ TLS block */
++#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */
++#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */
++#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */
++/* Keep this the last entry. */
++#define R_386_NUM 38
++
++/* SUN SPARC specific definitions. */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type). */
++
++#define STT_REGISTER 13 /* Global register reserved to app. */
++
++/* Values for Elf64_Ehdr.e_flags. */
++
++#define EF_SPARCV9_MM 3
++#define EF_SPARCV9_TSO 0
++#define EF_SPARCV9_PSO 1
++#define EF_SPARCV9_RMO 2
++#define EF_SPARC_LEDATA 0x800000 /* little endian data */
++#define EF_SPARC_EXT_MASK 0xFFFF00
++#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */
++#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */
++#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */
++#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */
++
++/* SPARC relocs. */
++
++#define R_SPARC_NONE 0 /* No reloc */
++#define R_SPARC_8 1 /* Direct 8 bit */
++#define R_SPARC_16 2 /* Direct 16 bit */
++#define R_SPARC_32 3 /* Direct 32 bit */
++#define R_SPARC_DISP8 4 /* PC relative 8 bit */
++#define R_SPARC_DISP16 5 /* PC relative 16 bit */
++#define R_SPARC_DISP32 6 /* PC relative 32 bit */
++#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */
++#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */
++#define R_SPARC_HI22 9 /* High 22 bit */
++#define R_SPARC_22 10 /* Direct 22 bit */
++#define R_SPARC_13 11 /* Direct 13 bit */
++#define R_SPARC_LO10 12 /* Truncated 10 bit */
++#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */
++#define R_SPARC_GOT13 14 /* 13 bit GOT entry */
++#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */
++#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */
++#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */
++#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */
++#define R_SPARC_COPY 19 /* Copy symbol at runtime */
++#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */
++#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */
++#define R_SPARC_RELATIVE 22 /* Adjust by program base */
++#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */
++
++/* Additional Sparc64 relocs. */
++
++#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */
++#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */
++#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */
++#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */
++#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */
++#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */
++#define R_SPARC_10 30 /* Direct 10 bit */
++#define R_SPARC_11 31 /* Direct 11 bit */
++#define R_SPARC_64 32 /* Direct 64 bit */
++#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */
++#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */
++#define R_SPARC_HM10 35 /* High middle 10 bits of ... */
++#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */
++#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */
++#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */
++#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */
++#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */
++#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */
++#define R_SPARC_7 43 /* Direct 7 bit */
++#define R_SPARC_5 44 /* Direct 5 bit */
++#define R_SPARC_6 45 /* Direct 6 bit */
++#define R_SPARC_DISP64 46 /* PC relative 64 bit */
++#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */
++#define R_SPARC_HIX22 48 /* High 22 bit complemented */
++#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */
++#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */
++#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */
++#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */
++#define R_SPARC_REGISTER 53 /* Global register usage */
++#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */
++#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */
++#define R_SPARC_TLS_GD_HI22 56
++#define R_SPARC_TLS_GD_LO10 57
++#define R_SPARC_TLS_GD_ADD 58
++#define R_SPARC_TLS_GD_CALL 59
++#define R_SPARC_TLS_LDM_HI22 60
++#define R_SPARC_TLS_LDM_LO10 61
++#define R_SPARC_TLS_LDM_ADD 62
++#define R_SPARC_TLS_LDM_CALL 63
++#define R_SPARC_TLS_LDO_HIX22 64
++#define R_SPARC_TLS_LDO_LOX10 65
++#define R_SPARC_TLS_LDO_ADD 66
++#define R_SPARC_TLS_IE_HI22 67
++#define R_SPARC_TLS_IE_LO10 68
++#define R_SPARC_TLS_IE_LD 69
++#define R_SPARC_TLS_IE_LDX 70
++#define R_SPARC_TLS_IE_ADD 71
++#define R_SPARC_TLS_LE_HIX22 72
++#define R_SPARC_TLS_LE_LOX10 73
++#define R_SPARC_TLS_DTPMOD32 74
++#define R_SPARC_TLS_DTPMOD64 75
++#define R_SPARC_TLS_DTPOFF32 76
++#define R_SPARC_TLS_DTPOFF64 77
++#define R_SPARC_TLS_TPOFF32 78
++#define R_SPARC_TLS_TPOFF64 79
++/* Keep this the last entry. */
++#define R_SPARC_NUM 80
++
++/* For Sparc64, legal values for d_tag of Elf64_Dyn. */
++
++#define DT_SPARC_REGISTER 0x70000001
++#define DT_SPARC_NUM 2
++
++/* Bits present in AT_HWCAP, primarily for Sparc32. */
++
++#define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */
++#define HWCAP_SPARC_STBAR 2
++#define HWCAP_SPARC_SWAP 4
++#define HWCAP_SPARC_MULDIV 8
++#define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */
++#define HWCAP_SPARC_ULTRA3 32
++
++/* MIPS R3000 specific definitions. */
++
++/* Legal values for e_flags field of Elf32_Ehdr. */
++
++#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */
++#define EF_MIPS_PIC 2 /* Contains PIC code */
++#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */
++#define EF_MIPS_XGOT 8
++#define EF_MIPS_64BIT_WHIRL 16
++#define EF_MIPS_ABI2 32
++#define EF_MIPS_ABI_ON32 64
++#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */
++
++/* Legal values for MIPS architecture level. */
++
++#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
++#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
++#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
++#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
++#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
++#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */
++#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */
++
++/* The following are non-official names and should not be used. */
++
++#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
++#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
++#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
++#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
++#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
++#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */
++#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */
++
++/* Special section indices. */
++
++#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */
++#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */
++#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */
++#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */
++#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */
++
++/* Legal values for sh_type field of Elf32_Shdr. */
++
++#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */
++#define SHT_MIPS_MSYM 0x70000001
++#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */
++#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */
++#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */
++#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/
++#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */
++#define SHT_MIPS_PACKAGE 0x70000007
++#define SHT_MIPS_PACKSYM 0x70000008
++#define SHT_MIPS_RELD 0x70000009
++#define SHT_MIPS_IFACE 0x7000000b
++#define SHT_MIPS_CONTENT 0x7000000c
++#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */
++#define SHT_MIPS_SHDR 0x70000010
++#define SHT_MIPS_FDESC 0x70000011
++#define SHT_MIPS_EXTSYM 0x70000012
++#define SHT_MIPS_DENSE 0x70000013
++#define SHT_MIPS_PDESC 0x70000014
++#define SHT_MIPS_LOCSYM 0x70000015
++#define SHT_MIPS_AUXSYM 0x70000016
++#define SHT_MIPS_OPTSYM 0x70000017
++#define SHT_MIPS_LOCSTR 0x70000018
++#define SHT_MIPS_LINE 0x70000019
++#define SHT_MIPS_RFDESC 0x7000001a
++#define SHT_MIPS_DELTASYM 0x7000001b
++#define SHT_MIPS_DELTAINST 0x7000001c
++#define SHT_MIPS_DELTACLASS 0x7000001d
++#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */
++#define SHT_MIPS_DELTADECL 0x7000001f
++#define SHT_MIPS_SYMBOL_LIB 0x70000020
++#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */
++#define SHT_MIPS_TRANSLATE 0x70000022
++#define SHT_MIPS_PIXIE 0x70000023
++#define SHT_MIPS_XLATE 0x70000024
++#define SHT_MIPS_XLATE_DEBUG 0x70000025
++#define SHT_MIPS_WHIRL 0x70000026
++#define SHT_MIPS_EH_REGION 0x70000027
++#define SHT_MIPS_XLATE_OLD 0x70000028
++#define SHT_MIPS_PDR_EXCEPTION 0x70000029
++
++/* Legal values for sh_flags field of Elf32_Shdr. */
++
++#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */
++#define SHF_MIPS_MERGE 0x20000000
++#define SHF_MIPS_ADDR 0x40000000
++#define SHF_MIPS_STRINGS 0x80000000
++#define SHF_MIPS_NOSTRIP 0x08000000
++#define SHF_MIPS_LOCAL 0x04000000
++#define SHF_MIPS_NAMES 0x02000000
++#define SHF_MIPS_NODUPE 0x01000000
++
++
++/* Symbol tables. */
++
++/* MIPS specific values for `st_other'. */
++#define STO_MIPS_DEFAULT 0x0
++#define STO_MIPS_INTERNAL 0x1
++#define STO_MIPS_HIDDEN 0x2
++#define STO_MIPS_PROTECTED 0x3
++#define STO_MIPS_SC_ALIGN_UNUSED 0xff
++
++/* MIPS specific values for `st_info'. */
++#define STB_MIPS_SPLIT_COMMON 13
++
++/* Entries found in sections of type SHT_MIPS_GPTAB. */
++
++typedef union
++{
++ struct
++ {
++ Elf32_Word gt_current_g_value; /* -G value used for compilation */
++ Elf32_Word gt_unused; /* Not used */
++ } gt_header; /* First entry in section */
++ struct
++ {
++ Elf32_Word gt_g_value; /* If this value were used for -G */
++ Elf32_Word gt_bytes; /* This many bytes would be used */
++ } gt_entry; /* Subsequent entries in section */
++} Elf32_gptab;
++
++/* Entry found in sections of type SHT_MIPS_REGINFO. */
++
++typedef struct
++{
++ Elf32_Word ri_gprmask; /* General registers used */
++ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */
++ Elf32_Sword ri_gp_value; /* $gp register value */
++} Elf32_RegInfo;
++
++/* Entries found in sections of type SHT_MIPS_OPTIONS. */
++
++typedef struct
++{
++ unsigned char kind; /* Determines interpretation of the
++ variable part of descriptor. */
++ unsigned char size; /* Size of descriptor, including header. */
++ Elf32_Section section; /* Section header index of section affected,
++ 0 for global options. */
++ Elf32_Word info; /* Kind-specific information. */
++} Elf_Options;
++
++/* Values for `kind' field in Elf_Options. */
++
++#define ODK_NULL 0 /* Undefined. */
++#define ODK_REGINFO 1 /* Register usage information. */
++#define ODK_EXCEPTIONS 2 /* Exception processing options. */
++#define ODK_PAD 3 /* Section padding options. */
++#define ODK_HWPATCH 4 /* Hardware workarounds performed */
++#define ODK_FILL 5 /* record the fill value used by the linker. */
++#define ODK_TAGS 6 /* reserve space for desktop tools to write. */
++#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */
++#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */
++
++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */
++
++#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */
++#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */
++#define OEX_PAGE0 0x10000 /* page zero must be mapped. */
++#define OEX_SMM 0x20000 /* Force sequential memory mode? */
++#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */
++#define OEX_PRECISEFP OEX_FPDBUG
++#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */
++
++#define OEX_FPU_INVAL 0x10
++#define OEX_FPU_DIV0 0x08
++#define OEX_FPU_OFLO 0x04
++#define OEX_FPU_UFLO 0x02
++#define OEX_FPU_INEX 0x01
++
++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */
++
++#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */
++#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */
++#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */
++#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */
++
++#define OPAD_PREFIX 0x1
++#define OPAD_POSTFIX 0x2
++#define OPAD_SYMBOL 0x4
++
++/* Entry found in `.options' section. */
++
++typedef struct
++{
++ Elf32_Word hwp_flags1; /* Extra flags. */
++ Elf32_Word hwp_flags2; /* Extra flags. */
++} Elf_Options_Hw;
++
++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */
++
++#define OHWA0_R4KEOP_CHECKED 0x00000001
++#define OHWA1_R4KEOP_CLEAN 0x00000002
++
++/* MIPS relocs. */
++
++#define R_MIPS_NONE 0 /* No reloc */
++#define R_MIPS_16 1 /* Direct 16 bit */
++#define R_MIPS_32 2 /* Direct 32 bit */
++#define R_MIPS_REL32 3 /* PC relative 32 bit */
++#define R_MIPS_26 4 /* Direct 26 bit shifted */
++#define R_MIPS_HI16 5 /* High 16 bit */
++#define R_MIPS_LO16 6 /* Low 16 bit */
++#define R_MIPS_GPREL16 7 /* GP relative 16 bit */
++#define R_MIPS_LITERAL 8 /* 16 bit literal entry */
++#define R_MIPS_GOT16 9 /* 16 bit GOT entry */
++#define R_MIPS_PC16 10 /* PC relative 16 bit */
++#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */
++#define R_MIPS_GPREL32 12 /* GP relative 32 bit */
++
++#define R_MIPS_SHIFT5 16
++#define R_MIPS_SHIFT6 17
++#define R_MIPS_64 18
++#define R_MIPS_GOT_DISP 19
++#define R_MIPS_GOT_PAGE 20
++#define R_MIPS_GOT_OFST 21
++#define R_MIPS_GOT_HI16 22
++#define R_MIPS_GOT_LO16 23
++#define R_MIPS_SUB 24
++#define R_MIPS_INSERT_A 25
++#define R_MIPS_INSERT_B 26
++#define R_MIPS_DELETE 27
++#define R_MIPS_HIGHER 28
++#define R_MIPS_HIGHEST 29
++#define R_MIPS_CALL_HI16 30
++#define R_MIPS_CALL_LO16 31
++#define R_MIPS_SCN_DISP 32
++#define R_MIPS_REL16 33
++#define R_MIPS_ADD_IMMEDIATE 34
++#define R_MIPS_PJUMP 35
++#define R_MIPS_RELGOT 36
++#define R_MIPS_JALR 37
++/* Keep this the last entry. */
++#define R_MIPS_NUM 38
++
++/* Legal values for p_type field of Elf32_Phdr. */
++
++#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */
++#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
++#define PT_MIPS_OPTIONS 0x70000002
++
++/* Special program header types. */
++
++#define PF_MIPS_LOCAL 0x10000000
++
++/* Legal values for d_tag field of Elf32_Dyn. */
++
++#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */
++#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */
++#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */
++#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */
++#define DT_MIPS_FLAGS 0x70000005 /* Flags */
++#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */
++#define DT_MIPS_MSYM 0x70000007
++#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */
++#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */
++#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */
++#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */
++#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */
++#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */
++#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */
++#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */
++#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */
++#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */
++#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */
++#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in
++ DT_MIPS_DELTA_CLASS. */
++#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */
++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
++ DT_MIPS_DELTA_INSTANCE. */
++#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */
++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
++ DT_MIPS_DELTA_RELOC. */
++#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta
++ relocations refer to. */
++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
++ DT_MIPS_DELTA_SYM. */
++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
++ class declaration. */
++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
++ DT_MIPS_DELTA_CLASSSYM. */
++#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */
++#define DT_MIPS_PIXIE_INIT 0x70000023
++#define DT_MIPS_SYMBOL_LIB 0x70000024
++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
++#define DT_MIPS_LOCAL_GOTIDX 0x70000026
++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
++#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */
++#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */
++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
++ function stored in GOT. */
++#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added
++ by rld on dlopen() calls. */
++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
++#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */
++#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */
++#define DT_MIPS_NUM 0x32
++
++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */
++
++#define RHF_NONE 0 /* No flags */
++#define RHF_QUICKSTART (1 << 0) /* Use quickstart */
++#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */
++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */
++#define RHF_NO_MOVE (1 << 3)
++#define RHF_SGI_ONLY (1 << 4)
++#define RHF_GUARANTEE_INIT (1 << 5)
++#define RHF_DELTA_C_PLUS_PLUS (1 << 6)
++#define RHF_GUARANTEE_START_INIT (1 << 7)
++#define RHF_PIXIE (1 << 8)
++#define RHF_DEFAULT_DELAY_LOAD (1 << 9)
++#define RHF_REQUICKSTART (1 << 10)
++#define RHF_REQUICKSTARTED (1 << 11)
++#define RHF_CORD (1 << 12)
++#define RHF_NO_UNRES_UNDEF (1 << 13)
++#define RHF_RLD_ORDER_SAFE (1 << 14)
++
++/* Entries found in sections of type SHT_MIPS_LIBLIST. */
++
++typedef struct
++{
++ Elf32_Word l_name; /* Name (string table index) */
++ Elf32_Word l_time_stamp; /* Timestamp */
++ Elf32_Word l_checksum; /* Checksum */
++ Elf32_Word l_version; /* Interface version */
++ Elf32_Word l_flags; /* Flags */
++} Elf32_Lib;
++
++typedef struct
++{
++ Elf64_Word l_name; /* Name (string table index) */
++ Elf64_Word l_time_stamp; /* Timestamp */
++ Elf64_Word l_checksum; /* Checksum */
++ Elf64_Word l_version; /* Interface version */
++ Elf64_Word l_flags; /* Flags */
++} Elf64_Lib;
++
++
++/* Legal values for l_flags. */
++
++#define LL_NONE 0
++#define LL_EXACT_MATCH (1 << 0) /* Require exact match */
++#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */
++#define LL_REQUIRE_MINOR (1 << 2)
++#define LL_EXPORTS (1 << 3)
++#define LL_DELAY_LOAD (1 << 4)
++#define LL_DELTA (1 << 5)
++
++/* Entries found in sections of type SHT_MIPS_CONFLICT. */
++
++typedef Elf32_Addr Elf32_Conflict;
++
++
++/* HPPA specific definitions. */
++
++/* Legal values for e_flags field of Elf32_Ehdr. */
++
++#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */
++#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */
++#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */
++#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */
++#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch
++ prediction. */
++#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */
++#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */
++
++/* Defined values for `e_flags & EF_PARISC_ARCH' are: */
++
++#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */
++#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */
++#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */
++
++/* Additional section indeces. */
++
++#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared
++ symbols in ANSI C. */
++#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */
++
++/* Legal values for sh_type field of Elf32_Shdr. */
++
++#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */
++#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */
++#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */
++
++/* Legal values for sh_flags field of Elf32_Shdr. */
++
++#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */
++#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */
++#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type). */
++
++#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */
++
++#define STT_HP_OPAQUE (STT_LOOS + 0x1)
++#define STT_HP_STUB (STT_LOOS + 0x2)
++
++/* HPPA relocs. */
++
++#define R_PARISC_NONE 0 /* No reloc. */
++#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */
++#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */
++#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */
++#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */
++#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */
++#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */
++#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */
++#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */
++#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */
++#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */
++#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */
++#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */
++#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */
++#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */
++#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */
++#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */
++#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */
++#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */
++#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */
++#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */
++#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */
++#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */
++#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */
++#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */
++#define R_PARISC_FPTR64 64 /* 64 bits function address. */
++#define R_PARISC_PLABEL32 65 /* 32 bits function address. */
++#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */
++#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */
++#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */
++#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */
++#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */
++#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */
++#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */
++#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */
++#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */
++#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */
++#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */
++#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */
++#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */
++#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */
++#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */
++#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */
++#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */
++#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */
++#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */
++#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */
++#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */
++#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */
++#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */
++#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */
++#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */
++#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */
++#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */
++#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */
++#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */
++#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */
++#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */
++#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */
++#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */
++#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */
++#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */
++#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */
++#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */
++#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */
++#define R_PARISC_LORESERVE 128
++#define R_PARISC_COPY 128 /* Copy relocation. */
++#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */
++#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */
++#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */
++#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */
++#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */
++#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */
++#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */
++#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */
++#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */
++#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */
++#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */
++#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */
++#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */
++#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */
++#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */
++#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */
++#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */
++#define R_PARISC_HIRESERVE 255
++
++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */
++
++#define PT_HP_TLS (PT_LOOS + 0x0)
++#define PT_HP_CORE_NONE (PT_LOOS + 0x1)
++#define PT_HP_CORE_VERSION (PT_LOOS + 0x2)
++#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3)
++#define PT_HP_CORE_COMM (PT_LOOS + 0x4)
++#define PT_HP_CORE_PROC (PT_LOOS + 0x5)
++#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6)
++#define PT_HP_CORE_STACK (PT_LOOS + 0x7)
++#define PT_HP_CORE_SHM (PT_LOOS + 0x8)
++#define PT_HP_CORE_MMF (PT_LOOS + 0x9)
++#define PT_HP_PARALLEL (PT_LOOS + 0x10)
++#define PT_HP_FASTBIND (PT_LOOS + 0x11)
++#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12)
++#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13)
++#define PT_HP_STACK (PT_LOOS + 0x14)
++
++#define PT_PARISC_ARCHEXT 0x70000000
++#define PT_PARISC_UNWIND 0x70000001
++
++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */
++
++#define PF_PARISC_SBP 0x08000000
++
++#define PF_HP_PAGE_SIZE 0x00100000
++#define PF_HP_FAR_SHARED 0x00200000
++#define PF_HP_NEAR_SHARED 0x00400000
++#define PF_HP_CODE 0x01000000
++#define PF_HP_MODIFY 0x02000000
++#define PF_HP_LAZYSWAP 0x04000000
++#define PF_HP_SBP 0x08000000
++
++
++/* Alpha specific definitions. */
++
++/* Legal values for e_flags field of Elf64_Ehdr. */
++
++#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */
++#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */
++
++/* Legal values for sh_type field of Elf64_Shdr. */
++
++/* These two are primerily concerned with ECOFF debugging info. */
++#define SHT_ALPHA_DEBUG 0x70000001
++#define SHT_ALPHA_REGINFO 0x70000002
++
++/* Legal values for sh_flags field of Elf64_Shdr. */
++
++#define SHF_ALPHA_GPREL 0x10000000
++
++/* Legal values for st_other field of Elf64_Sym. */
++#define STO_ALPHA_NOPV 0x80 /* No PV required. */
++#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */
++
++/* Alpha relocs. */
++
++#define R_ALPHA_NONE 0 /* No reloc */
++#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
++#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
++#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
++#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
++#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
++#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
++#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
++#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
++#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
++#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
++#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
++#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */
++#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */
++#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */
++#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
++#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
++#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
++#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
++#define R_ALPHA_TLS_GD_HI 28
++#define R_ALPHA_TLSGD 29
++#define R_ALPHA_TLS_LDM 30
++#define R_ALPHA_DTPMOD64 31
++#define R_ALPHA_GOTDTPREL 32
++#define R_ALPHA_DTPREL64 33
++#define R_ALPHA_DTPRELHI 34
++#define R_ALPHA_DTPRELLO 35
++#define R_ALPHA_DTPREL16 36
++#define R_ALPHA_GOTTPREL 37
++#define R_ALPHA_TPREL64 38
++#define R_ALPHA_TPRELHI 39
++#define R_ALPHA_TPRELLO 40
++#define R_ALPHA_TPREL16 41
++/* Keep this the last entry. */
++#define R_ALPHA_NUM 46
++
++/* Magic values of the LITUSE relocation addend. */
++#define LITUSE_ALPHA_ADDR 0
++#define LITUSE_ALPHA_BASE 1
++#define LITUSE_ALPHA_BYTOFF 2
++#define LITUSE_ALPHA_JSR 3
++#define LITUSE_ALPHA_TLS_GD 4
++#define LITUSE_ALPHA_TLS_LDM 5
++
++
++/* PowerPC specific declarations */
++
++/* Values for Elf32/64_Ehdr.e_flags. */
++#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */
++
++/* Cygnus local bits below */
++#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/
++#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib
++ flag */
++
++/* PowerPC relocations defined by the ABIs */
++#define R_PPC_NONE 0
++#define R_PPC_ADDR32 1 /* 32bit absolute address */
++#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */
++#define R_PPC_ADDR16 3 /* 16bit absolute address */
++#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */
++#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */
++#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */
++#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */
++#define R_PPC_ADDR14_BRTAKEN 8
++#define R_PPC_ADDR14_BRNTAKEN 9
++#define R_PPC_REL24 10 /* PC relative 26 bit */
++#define R_PPC_REL14 11 /* PC relative 16 bit */
++#define R_PPC_REL14_BRTAKEN 12
++#define R_PPC_REL14_BRNTAKEN 13
++#define R_PPC_GOT16 14
++#define R_PPC_GOT16_LO 15
++#define R_PPC_GOT16_HI 16
++#define R_PPC_GOT16_HA 17
++#define R_PPC_PLTREL24 18
++#define R_PPC_COPY 19
++#define R_PPC_GLOB_DAT 20
++#define R_PPC_JMP_SLOT 21
++#define R_PPC_RELATIVE 22
++#define R_PPC_LOCAL24PC 23
++#define R_PPC_UADDR32 24
++#define R_PPC_UADDR16 25
++#define R_PPC_REL32 26
++#define R_PPC_PLT32 27
++#define R_PPC_PLTREL32 28
++#define R_PPC_PLT16_LO 29
++#define R_PPC_PLT16_HI 30
++#define R_PPC_PLT16_HA 31
++#define R_PPC_SDAREL16 32
++#define R_PPC_SECTOFF 33
++#define R_PPC_SECTOFF_LO 34
++#define R_PPC_SECTOFF_HI 35
++#define R_PPC_SECTOFF_HA 36
++
++/* PowerPC relocations defined for the TLS access ABI. */
++#define R_PPC_TLS 67 /* none (sym+add)@tls */
++#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */
++#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */
++#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
++#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
++#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
++#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */
++#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */
++#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
++#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
++#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
++#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */
++#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
++#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
++#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
++#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
++#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
++#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
++#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
++#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
++#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */
++#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */
++#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
++#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
++#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */
++#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */
++#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */
++#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */
++
++/* Keep this the last entry. */
++#define R_PPC_NUM 95
++
++/* The remaining relocs are from the Embedded ELF ABI, and are not
++ in the SVR4 ELF ABI. */
++#define R_PPC_EMB_NADDR32 101
++#define R_PPC_EMB_NADDR16 102
++#define R_PPC_EMB_NADDR16_LO 103
++#define R_PPC_EMB_NADDR16_HI 104
++#define R_PPC_EMB_NADDR16_HA 105
++#define R_PPC_EMB_SDAI16 106
++#define R_PPC_EMB_SDA2I16 107
++#define R_PPC_EMB_SDA2REL 108
++#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */
++#define R_PPC_EMB_MRKREF 110
++#define R_PPC_EMB_RELSEC16 111
++#define R_PPC_EMB_RELST_LO 112
++#define R_PPC_EMB_RELST_HI 113
++#define R_PPC_EMB_RELST_HA 114
++#define R_PPC_EMB_BIT_FLD 115
++#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */
++
++/* Diab tool relocations. */
++#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */
++#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */
++#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */
++#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */
++#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */
++#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */
++
++/* This is a phony reloc to handle any old fashioned TOC16 references
++ that may still be in object files. */
++#define R_PPC_TOC16 255
++
++
++/* PowerPC64 relocations defined by the ABIs */
++#define R_PPC64_NONE R_PPC_NONE
++#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */
++#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */
++#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */
++#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */
++#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */
++#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */
++#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */
++#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN
++#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN
++#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
++#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */
++#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN
++#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN
++#define R_PPC64_GOT16 R_PPC_GOT16
++#define R_PPC64_GOT16_LO R_PPC_GOT16_LO
++#define R_PPC64_GOT16_HI R_PPC_GOT16_HI
++#define R_PPC64_GOT16_HA R_PPC_GOT16_HA
++
++#define R_PPC64_COPY R_PPC_COPY
++#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT
++#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT
++#define R_PPC64_RELATIVE R_PPC_RELATIVE
++
++#define R_PPC64_UADDR32 R_PPC_UADDR32
++#define R_PPC64_UADDR16 R_PPC_UADDR16
++#define R_PPC64_REL32 R_PPC_REL32
++#define R_PPC64_PLT32 R_PPC_PLT32
++#define R_PPC64_PLTREL32 R_PPC_PLTREL32
++#define R_PPC64_PLT16_LO R_PPC_PLT16_LO
++#define R_PPC64_PLT16_HI R_PPC_PLT16_HI
++#define R_PPC64_PLT16_HA R_PPC_PLT16_HA
++
++#define R_PPC64_SECTOFF R_PPC_SECTOFF
++#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO
++#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI
++#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA
++#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */
++#define R_PPC64_ADDR64 38 /* doubleword64 S + A */
++#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */
++#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */
++#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */
++#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */
++#define R_PPC64_UADDR64 43 /* doubleword64 S + A */
++#define R_PPC64_REL64 44 /* doubleword64 S + A - P */
++#define R_PPC64_PLT64 45 /* doubleword64 L + A */
++#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */
++#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */
++#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */
++#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */
++#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */
++#define R_PPC64_TOC 51 /* doubleword64 .TOC */
++#define R_PPC64_PLTGOT16 52 /* half16* M + A */
++#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */
++#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */
++#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */
++
++#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */
++#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */
++#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */
++#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */
++#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */
++#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */
++#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */
++#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */
++#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */
++#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */
++#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */
++
++/* PowerPC64 relocations defined for the TLS access ABI. */
++#define R_PPC64_TLS 67 /* none (sym+add)@tls */
++#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */
++#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */
++#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
++#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
++#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
++#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */
++#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */
++#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
++#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
++#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
++#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */
++#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
++#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
++#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
++#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
++#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
++#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
++#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
++#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
++#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */
++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
++#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
++#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
++#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */
++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
++#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */
++#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */
++#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */
++#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */
++#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */
++#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */
++#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */
++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */
++#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */
++#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */
++#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */
++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */
++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */
++
++/* Keep this the last entry. */
++#define R_PPC64_NUM 107
++
++/* PowerPC64 specific values for the Dyn d_tag field. */
++#define DT_PPC64_GLINK (DT_LOPROC + 0)
++#define DT_PPC64_NUM 1
++
++
++/* ARM specific declarations */
++
++/* Processor specific flags for the ELF header e_flags field. */
++#define EF_ARM_RELEXEC 0x01
++#define EF_ARM_HASENTRY 0x02
++#define EF_ARM_INTERWORK 0x04
++#define EF_ARM_APCS_26 0x08
++#define EF_ARM_APCS_FLOAT 0x10
++#define EF_ARM_PIC 0x20
++#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */
++#define EF_ARM_NEW_ABI 0x80
++#define EF_ARM_OLD_ABI 0x100
++
++/* Other constants defined in the ARM ELF spec. version B-01. */
++/* NB. These conflict with values defined above. */
++#define EF_ARM_SYMSARESORTED 0x04
++#define EF_ARM_DYNSYMSUSESEGIDX 0x08
++#define EF_ARM_MAPSYMSFIRST 0x10
++#define EF_ARM_EABIMASK 0XFF000000
++
++#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)
++#define EF_ARM_EABI_UNKNOWN 0x00000000
++#define EF_ARM_EABI_VER1 0x01000000
++#define EF_ARM_EABI_VER2 0x02000000
++
++/* Additional symbol types for Thumb */
++#define STT_ARM_TFUNC 0xd
++
++/* ARM-specific values for sh_flags */
++#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */
++#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined
++ in the input to a link step */
++
++/* ARM-specific program header flags */
++#define PF_ARM_SB 0x10000000 /* Segment contains the location
++ addressed by the static base */
++
++/* ARM relocs. */
++#define R_ARM_NONE 0 /* No reloc */
++#define R_ARM_PC24 1 /* PC relative 26 bit branch */
++#define R_ARM_ABS32 2 /* Direct 32 bit */
++#define R_ARM_REL32 3 /* PC relative 32 bit */
++#define R_ARM_PC13 4
++#define R_ARM_ABS16 5 /* Direct 16 bit */
++#define R_ARM_ABS12 6 /* Direct 12 bit */
++#define R_ARM_THM_ABS5 7
++#define R_ARM_ABS8 8 /* Direct 8 bit */
++#define R_ARM_SBREL32 9
++#define R_ARM_THM_PC22 10
++#define R_ARM_THM_PC8 11
++#define R_ARM_AMP_VCALL9 12
++#define R_ARM_SWI24 13
++#define R_ARM_THM_SWI8 14
++#define R_ARM_XPC25 15
++#define R_ARM_THM_XPC22 16
++#define R_ARM_COPY 20 /* Copy symbol at runtime */
++#define R_ARM_GLOB_DAT 21 /* Create GOT entry */
++#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */
++#define R_ARM_RELATIVE 23 /* Adjust by program base */
++#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */
++#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */
++#define R_ARM_GOT32 26 /* 32 bit GOT entry */
++#define R_ARM_PLT32 27 /* 32 bit PLT address */
++#define R_ARM_ALU_PCREL_7_0 32
++#define R_ARM_ALU_PCREL_15_8 33
++#define R_ARM_ALU_PCREL_23_15 34
++#define R_ARM_LDR_SBREL_11_0 35
++#define R_ARM_ALU_SBREL_19_12 36
++#define R_ARM_ALU_SBREL_27_20 37
++#define R_ARM_GNU_VTENTRY 100
++#define R_ARM_GNU_VTINHERIT 101
++#define R_ARM_THM_PC11 102 /* thumb unconditional branch */
++#define R_ARM_THM_PC9 103 /* thumb conditional branch */
++#define R_ARM_RXPC25 249
++#define R_ARM_RSBREL32 250
++#define R_ARM_THM_RPC22 251
++#define R_ARM_RREL32 252
++#define R_ARM_RABS22 253
++#define R_ARM_RPC24 254
++#define R_ARM_RBASE 255
++/* Keep this the last entry. */
++#define R_ARM_NUM 256
++
++/* IA-64 specific declarations. */
++
++/* Processor specific flags for the Ehdr e_flags field. */
++#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */
++#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */
++#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */
++
++/* Processor specific values for the Phdr p_type field. */
++#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */
++#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */
++
++/* Processor specific flags for the Phdr p_flags field. */
++#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */
++
++/* Processor specific values for the Shdr sh_type field. */
++#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */
++#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */
++
++/* Processor specific flags for the Shdr sh_flags field. */
++#define SHF_IA_64_SHORT 0x10000000 /* section near gp */
++#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */
++
++/* Processor specific values for the Dyn d_tag field. */
++#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0)
++#define DT_IA_64_NUM 1
++
++/* IA-64 relocations. */
++#define R_IA64_NONE 0x00 /* none */
++#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */
++#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */
++#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */
++#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */
++#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */
++#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */
++#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */
++#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */
++#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */
++#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */
++#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */
++#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */
++#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */
++#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */
++#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */
++#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */
++#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */
++#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */
++#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */
++#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */
++#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */
++#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */
++#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */
++#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */
++#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */
++#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */
++#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */
++#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */
++#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */
++#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */
++#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */
++#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */
++#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */
++#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */
++#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */
++#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */
++#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */
++#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */
++#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */
++#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */
++#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */
++#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */
++#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */
++#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */
++#define R_IA64_REL32MSB 0x6c /* data 4 + REL */
++#define R_IA64_REL32LSB 0x6d /* data 4 + REL */
++#define R_IA64_REL64MSB 0x6e /* data 8 + REL */
++#define R_IA64_REL64LSB 0x6f /* data 8 + REL */
++#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */
++#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */
++#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */
++#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */
++#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */
++#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */
++#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */
++#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */
++#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */
++#define R_IA64_COPY 0x84 /* copy relocation */
++#define R_IA64_SUB 0x85 /* Addend and symbol difference */
++#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */
++#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */
++#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */
++#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */
++#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */
++#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */
++#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */
++#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */
++#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */
++#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */
++#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */
++#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */
++#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */
++#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */
++#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */
++#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */
++#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */
++
++/* SH specific declarations */
++
++/* SH relocs. */
++#define R_SH_NONE 0
++#define R_SH_DIR32 1
++#define R_SH_REL32 2
++#define R_SH_DIR8WPN 3
++#define R_SH_IND12W 4
++#define R_SH_DIR8WPL 5
++#define R_SH_DIR8WPZ 6
++#define R_SH_DIR8BP 7
++#define R_SH_DIR8W 8
++#define R_SH_DIR8L 9
++#define R_SH_SWITCH16 25
++#define R_SH_SWITCH32 26
++#define R_SH_USES 27
++#define R_SH_COUNT 28
++#define R_SH_ALIGN 29
++#define R_SH_CODE 30
++#define R_SH_DATA 31
++#define R_SH_LABEL 32
++#define R_SH_SWITCH8 33
++#define R_SH_GNU_VTINHERIT 34
++#define R_SH_GNU_VTENTRY 35
++#define R_SH_TLS_GD_32 144
++#define R_SH_TLS_LD_32 145
++#define R_SH_TLS_LDO_32 146
++#define R_SH_TLS_IE_32 147
++#define R_SH_TLS_LE_32 148
++#define R_SH_TLS_DTPMOD32 149
++#define R_SH_TLS_DTPOFF32 150
++#define R_SH_TLS_TPOFF32 151
++#define R_SH_GOT32 160
++#define R_SH_PLT32 161
++#define R_SH_COPY 162
++#define R_SH_GLOB_DAT 163
++#define R_SH_JMP_SLOT 164
++#define R_SH_RELATIVE 165
++#define R_SH_GOTOFF 166
++#define R_SH_GOTPC 167
++/* Keep this the last entry. */
++#define R_SH_NUM 256
++
++/* Additional s390 relocs */
++
++#define R_390_NONE 0 /* No reloc. */
++#define R_390_8 1 /* Direct 8 bit. */
++#define R_390_12 2 /* Direct 12 bit. */
++#define R_390_16 3 /* Direct 16 bit. */
++#define R_390_32 4 /* Direct 32 bit. */
++#define R_390_PC32 5 /* PC relative 32 bit. */
++#define R_390_GOT12 6 /* 12 bit GOT offset. */
++#define R_390_GOT32 7 /* 32 bit GOT offset. */
++#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */
++#define R_390_COPY 9 /* Copy symbol at runtime. */
++#define R_390_GLOB_DAT 10 /* Create GOT entry. */
++#define R_390_JMP_SLOT 11 /* Create PLT entry. */
++#define R_390_RELATIVE 12 /* Adjust by program base. */
++#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */
++#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */
++#define R_390_GOT16 15 /* 16 bit GOT offset. */
++#define R_390_PC16 16 /* PC relative 16 bit. */
++#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */
++#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */
++#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */
++#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */
++#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */
++#define R_390_64 22 /* Direct 64 bit. */
++#define R_390_PC64 23 /* PC relative 64 bit. */
++#define R_390_GOT64 24 /* 64 bit GOT offset. */
++#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */
++#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */
++#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */
++#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */
++#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */
++#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */
++#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */
++#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */
++#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */
++#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */
++#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */
++#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */
++#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */
++#define R_390_TLS_GDCALL 38 /* Tag for function call in general
++ dynamic TLS code. */
++#define R_390_TLS_LDCALL 39 /* Tag for function call in local
++ dynamic TLS code. */
++#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic
++ thread local data. */
++#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic
++ thread local data. */
++#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS
++ block offset. */
++#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS
++ block offset. */
++#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS
++ block offset. */
++#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic
++ thread local data in LE code. */
++#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic
++ thread local data in LE code. */
++#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for
++ negated static TLS block offset. */
++#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for
++ negated static TLS block offset. */
++#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for
++ negated static TLS block offset. */
++#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to
++ static TLS block. */
++#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to
++ static TLS block. */
++#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS
++ block. */
++#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS
++ block. */
++#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */
++#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */
++#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS
++ block. */
++
++/* Keep this the last entry. */
++#define R_390_NUM 57
++
++/* CRIS relocations. */
++#define R_CRIS_NONE 0
++#define R_CRIS_8 1
++#define R_CRIS_16 2
++#define R_CRIS_32 3
++#define R_CRIS_8_PCREL 4
++#define R_CRIS_16_PCREL 5
++#define R_CRIS_32_PCREL 6
++#define R_CRIS_GNU_VTINHERIT 7
++#define R_CRIS_GNU_VTENTRY 8
++#define R_CRIS_COPY 9
++#define R_CRIS_GLOB_DAT 10
++#define R_CRIS_JUMP_SLOT 11
++#define R_CRIS_RELATIVE 12
++#define R_CRIS_16_GOT 13
++#define R_CRIS_32_GOT 14
++#define R_CRIS_16_GOTPLT 15
++#define R_CRIS_32_GOTPLT 16
++#define R_CRIS_32_GOTREL 17
++#define R_CRIS_32_PLT_GOTREL 18
++#define R_CRIS_32_PLT_PCREL 19
++
++#define R_CRIS_NUM 20
++
++/* AMD x86-64 relocations. */
++#define R_X86_64_NONE 0 /* No reloc */
++#define R_X86_64_64 1 /* Direct 64 bit */
++#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
++#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
++#define R_X86_64_PLT32 4 /* 32 bit PLT address */
++#define R_X86_64_COPY 5 /* Copy symbol at runtime */
++#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
++#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
++#define R_X86_64_RELATIVE 8 /* Adjust by program base */
++#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative
++ offset to GOT */
++#define R_X86_64_32 10 /* Direct 32 bit zero extended */
++#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
++#define R_X86_64_16 12 /* Direct 16 bit zero extended */
++#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
++#define R_X86_64_8 14 /* Direct 8 bit sign extended */
++#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
++#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
++#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */
++#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */
++#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset
++ to two GOT entries for GD symbol */
++#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset
++ to two GOT entries for LD symbol */
++#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
++#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset
++ to GOT entry for IE symbol */
++#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */
++
++#define R_X86_64_NUM 24
++
++__END_DECLS
++
++#endif /* elf.h */
+
+ #include "elfconfig.h"
+
+@@ -195,3 +2641,4 @@
+ void fatal(const char *fmt, ...);
+ void warn(const char *fmt, ...);
+ void merror(const char *fmt, ...);
++
+diff -Nur linux-2.6.36.orig/scripts/mod/sumversion.c linux-2.6.36/scripts/mod/sumversion.c
+--- linux-2.6.36.orig/scripts/mod/sumversion.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/scripts/mod/sumversion.c 2010-11-28 18:33:24.000000000 +0100
+@@ -1,4 +1,4 @@
+-#include <netinet/in.h>
++/* #include <netinet/in.h> */
+ #ifdef __sun__
+ #include <inttypes.h>
+ #else
diff --git a/target/linux/patches/2.6.37/cc-abstract.patch b/target/linux/patches/2.6.37/cc-abstract.patch
new file mode 100644
index 000000000..dc5d87f0d
--- /dev/null
+++ b/target/linux/patches/2.6.37/cc-abstract.patch
@@ -0,0 +1,14 @@
+diff -Nur linux-2.6.32.orig/Makefile linux-2.6.32/Makefile
+--- linux-2.6.32.orig/Makefile Thu Dec 3 04:50:57 2009
++++ linux-2.6.32/Makefile Fri Dec 18 20:53:57 2009
+@@ -219,8 +219,8 @@
+ else if [ -x /bin/bash ]; then echo /bin/bash; \
+ else echo sh; fi ; fi)
+
+-HOSTCC = gcc
+-HOSTCXX = g++
++HOSTCC ?= gcc
++HOSTCXX ?= g++
+ HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer
+ HOSTCXXFLAGS = -O2
+
diff --git a/target/linux/patches/2.6.37/cris.patch b/target/linux/patches/2.6.37/cris.patch
new file mode 100644
index 000000000..6be88fc18
--- /dev/null
+++ b/target/linux/patches/2.6.37/cris.patch
@@ -0,0 +1,5736 @@
+diff -Nur linux-2.6.36.orig/arch/cris/Kconfig linux-2.6.36/arch/cris/Kconfig
+--- linux-2.6.36.orig/arch/cris/Kconfig 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/Kconfig 2010-12-28 20:35:16.000000000 +0100
+@@ -177,6 +177,12 @@
+ help
+ Size of DRAM (decimal in MB) typically 2, 8 or 16.
+
++config ETRAX_MTD_SIZE
++ hex "MTD size (hex)"
++ default "0x00800000"
++ help
++ Size of MTD device typically 4 or 8 MB.
++
+ config ETRAX_VMEM_SIZE
+ int "Video memory size (dec, in MB)"
+ depends on ETRAX_ARCH_V32 && !ETRAXFS
+@@ -282,7 +288,7 @@
+ select MTD_CFI_AMDSTD
+ select MTD_JEDECPROBE if ETRAX_ARCH_V32
+ select MTD_CHAR
+- select MTD_BLOCK
++ select MTD_BLOCK_RO
+ select MTD_PARTITIONS
+ select MTD_CONCAT
+ select MTD_COMPLEX_MAPPINGS
+@@ -671,6 +677,11 @@
+
+ source "drivers/ide/Kconfig"
+
++#mysteriously part of this standard linux driver was removed from cris build! - info@crisos.org
++source "drivers/scsi/Kconfig"
++
++source "drivers/media/Kconfig"
++
+ source "drivers/net/Kconfig"
+
+ source "drivers/i2c/Kconfig"
+@@ -686,6 +697,8 @@
+
+ source "fs/Kconfig"
+
++source "sound/Kconfig"
++
+ source "drivers/usb/Kconfig"
+
+ source "drivers/uwb/Kconfig"
+diff -Nur linux-2.6.36.orig/arch/cris/Makefile linux-2.6.36/arch/cris/Makefile
+--- linux-2.6.36.orig/arch/cris/Makefile 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/Makefile 2010-12-28 20:35:00.000000000 +0100
+@@ -40,10 +40,10 @@
+
+ LD = $(CROSS_COMPILE)ld -mcrislinux
+
+-OBJCOPYFLAGS := -O binary -R .note -R .comment -S
++OBJCOPYFLAGS := -O binary -R .bss -R .note -R .note.gnu.build-id -R .comment -S
+
+ KBUILD_AFLAGS += -mlinux -march=$(arch-y) $(inc)
+-KBUILD_CFLAGS += -mlinux -march=$(arch-y) -pipe $(inc)
++KBUILD_CFLAGS += -mlinux -march=$(arch-y) -pipe -fno-peephole2 $(inc)
+ KBUILD_CPPFLAGS += $(inc)
+
+ ifdef CONFIG_FRAME_POINTER
+diff -Nur linux-2.6.36.orig/arch/cris/arch-v10/drivers/axisflashmap.c linux-2.6.36/arch/cris/arch-v10/drivers/axisflashmap.c
+--- linux-2.6.36.orig/arch/cris/arch-v10/drivers/axisflashmap.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/arch-v10/drivers/axisflashmap.c 2010-12-28 20:35:00.000000000 +0100
+@@ -113,7 +113,7 @@
+
+ /* If no partition-table was found, we use this default-set. */
+ #define MAX_PARTITIONS 7
+-#define NUM_DEFAULT_PARTITIONS 3
++#define NUM_DEFAULT_PARTITIONS 4
+
+ /*
+ * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
+@@ -122,19 +122,24 @@
+ */
+ static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = {
+ {
+- .name = "boot firmware",
+- .size = CONFIG_ETRAX_PTABLE_SECTOR,
++ .name = "kernel",
++ .size = 0x00,
+ .offset = 0
+ },
+ {
+- .name = "kernel",
+- .size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR),
+- .offset = CONFIG_ETRAX_PTABLE_SECTOR
++ .name = "rootfs",
++ .size = 0x200000 ,
++ .offset = 0x200000
+ },
+ {
+- .name = "filesystem",
+- .size = 5 * CONFIG_ETRAX_PTABLE_SECTOR,
+- .offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR)
++ .name = "cfgfs",
++ .size = 0x20000 ,
++ .offset = CONFIG_ETRAX_MTD_SIZE - 0x20000
++ },
++ {
++ .name = "linux",
++ .size = CONFIG_ETRAX_MTD_SIZE - 0x20000,
++ .offset = 0
+ }
+ };
+
+@@ -281,6 +286,11 @@
+ struct partitiontable_entry *ptable;
+ int use_default_ptable = 1; /* Until proven otherwise. */
+ const char pmsg[] = " /dev/flash%d at 0x%08x, size 0x%08x\n";
++ unsigned int kernel_part_size = 0;
++ unsigned char *flash_mem = (unsigned char*)(FLASH_CACHED_ADDR);
++ unsigned int flash_scan_count = 0;
++ const char *part_magic = "ACME_PART_MAGIC";
++ unsigned int magic_len = strlen(part_magic);
+
+ if (!(mymtd = flash_probe())) {
+ /* There's no reason to use this module if no flash chip can
+@@ -292,6 +302,31 @@
+ mymtd->name, mymtd->size);
+ axisflash_mtd = mymtd;
+ }
++ /* scan flash to findout where out partition starts */
++
++ printk(KERN_INFO "Scanning flash for end of kernel magic\n");
++ for(flash_scan_count = 0; flash_scan_count < 100000; flash_scan_count++){
++ if(strncmp(&flash_mem[flash_scan_count], part_magic, magic_len - 1) == 0)
++ {
++ kernel_part_size = flash_mem[flash_scan_count + magic_len ];
++ kernel_part_size <<= 8;
++ kernel_part_size += flash_mem[flash_scan_count + magic_len + 2];
++ kernel_part_size <<= 8;
++ kernel_part_size += flash_mem[flash_scan_count + magic_len + 1];
++ kernel_part_size <<= 8;
++ kernel_part_size += flash_mem[flash_scan_count + magic_len + 3];
++ printk(KERN_INFO "Kernel ends at 0x%.08X\n", kernel_part_size);
++ flash_scan_count = 1100000;
++ }
++ }
++
++
++ if(kernel_part_size){
++ kernel_part_size = (kernel_part_size & 0xffff0000);
++ axis_default_partitions[0].size = kernel_part_size;
++ axis_default_partitions[1].size = mymtd->size - axis_default_partitions[0].size - axis_default_partitions[2].size;
++ axis_default_partitions[1].offset = axis_default_partitions[0].size;
++ }
+
+ if (mymtd) {
+ mymtd->owner = THIS_MODULE;
+@@ -360,21 +395,6 @@
+ use_default_ptable = !ptable_ok;
+ }
+
+- if (romfs_in_flash) {
+- /* Add an overlapping device for the root partition (romfs). */
+-
+- axis_partitions[pidx].name = "romfs";
+- axis_partitions[pidx].size = romfs_length;
+- axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
+- axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
+-
+- printk(KERN_INFO
+- " Adding readonly flash partition for romfs image:\n");
+- printk(pmsg, pidx, axis_partitions[pidx].offset,
+- axis_partitions[pidx].size);
+- pidx++;
+- }
+-
+ #ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
+ if (mymtd) {
+ main_partition.size = mymtd->size;
+@@ -397,36 +417,6 @@
+ if (err)
+ panic("axisflashmap could not add MTD partitions!\n");
+ }
+-
+- if (!romfs_in_flash) {
+- /* Create an RAM device for the root partition (romfs). */
+-
+-#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
+- /* No use trying to boot this kernel from RAM. Panic! */
+- printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
+- "device due to kernel (mis)configuration!\n");
+- panic("This kernel cannot boot from RAM!\n");
+-#else
+- struct mtd_info *mtd_ram;
+-
+- mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+- if (!mtd_ram)
+- panic("axisflashmap couldn't allocate memory for "
+- "mtd_info!\n");
+-
+- printk(KERN_INFO " Adding RAM partition for romfs image:\n");
+- printk(pmsg, pidx, (unsigned)romfs_start,
+- (unsigned)romfs_length);
+-
+- err = mtdram_init_device(mtd_ram,
+- (void *)romfs_start,
+- romfs_length,
+- "romfs");
+- if (err)
+- panic("axisflashmap could not initialize MTD RAM "
+- "device!\n");
+-#endif
+- }
+ return err;
+ }
+
+diff -Nur linux-2.6.36.orig/arch/cris/arch-v10/drivers/ds1302.c linux-2.6.36/arch/cris/arch-v10/drivers/ds1302.c
+--- linux-2.6.36.orig/arch/cris/arch-v10/drivers/ds1302.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/arch-v10/drivers/ds1302.c 2010-12-28 20:35:00.000000000 +0100
+@@ -22,6 +22,7 @@
+ #include <linux/smp_lock.h>
+ #include <linux/bcd.h>
+ #include <linux/capability.h>
++#include <linux/device.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+@@ -499,6 +500,10 @@
+ return 0;
+ }
+
++#ifdef CONFIG_SYSFS
++static struct class *rtc_class;
++#endif
++
+ static int __init ds1302_register(void)
+ {
+ ds1302_init();
+@@ -507,6 +512,12 @@
+ ds1302_name, RTC_MAJOR_NR);
+ return -1;
+ }
++ #ifdef CONFIG_SYSFS
++ rtc_class = class_create(THIS_MODULE, "rtc");
++ class_device_create(rtc_class, NULL, MKDEV(RTC_MAJOR_NR, 0),
++ NULL, "rtc");
++ #endif
++
+ return 0;
+
+ }
+diff -Nur linux-2.6.36.orig/arch/cris/arch-v10/drivers/gpio.c linux-2.6.36/arch/cris/arch-v10/drivers/gpio.c
+--- linux-2.6.36.orig/arch/cris/arch-v10/drivers/gpio.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/arch-v10/drivers/gpio.c 2010-12-28 20:35:00.000000000 +0100
+@@ -20,6 +20,7 @@
+ #include <linux/poll.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
++#include <linux/device.h>
+
+ #include <asm/etraxgpio.h>
+ #include <arch/svinto.h>
+@@ -797,6 +798,10 @@
+
+ /* main driver initialization routine, called from mem.c */
+
++#ifdef CONFIG_SYSFS
++static struct class *gpio_class;
++#endif
++
+ static int __init gpio_init(void)
+ {
+ int res;
+@@ -810,6 +815,13 @@
+ return res;
+ }
+
++#ifdef CONFIG_SYSFS
++ gpio_class = class_create(THIS_MODULE, "gpio");
++ device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, 0), NULL, "gpioa");
++ device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, 1), NULL, "gpiob");
++ device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, 2), NULL, "leds");
++ device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, 3), NULL, "gpiog");
++#endif
+ /* Clear all leds */
+ #if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS)
+ CRIS_LED_NETWORK_SET(0);
+diff -Nur linux-2.6.36.orig/arch/cris/arch-v10/lib/hw_settings.S linux-2.6.36/arch/cris/arch-v10/lib/hw_settings.S
+--- linux-2.6.36.orig/arch/cris/arch-v10/lib/hw_settings.S 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/arch-v10/lib/hw_settings.S 2010-12-28 20:35:00.000000000 +0100
+@@ -58,3 +58,5 @@
+ .dword R_PORT_PB_SET
+ .dword PB_SET_VALUE
+ .dword 0 ; No more register values
++ .ascii "ACME_PART_MAGIC"
++ .dword 0xdeadc0de
+diff -Nur linux-2.6.36.orig/arch/cris/arch-v10/mm/init.c linux-2.6.36/arch/cris/arch-v10/mm/init.c
+--- linux-2.6.36.orig/arch/cris/arch-v10/mm/init.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/arch-v10/mm/init.c 2010-12-28 20:35:00.000000000 +0100
+@@ -184,6 +184,9 @@
+
+ free_area_init_node(0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0);
+ }
++void free_initrd_mem(unsigned long start, unsigned long end)
++{
++}
+
+ /* Initialize remaps of some I/O-ports. It is important that this
+ * is called before any driver is initialized.
+diff -Nur linux-2.6.36.orig/arch/cris/boot/Makefile linux-2.6.36/arch/cris/boot/Makefile
+--- linux-2.6.36.orig/arch/cris/boot/Makefile 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/boot/Makefile 2010-12-28 20:35:00.000000000 +0100
+@@ -5,7 +5,7 @@
+ objcopyflags-$(CONFIG_ETRAX_ARCH_V10) += -R .note -R .comment
+ objcopyflags-$(CONFIG_ETRAX_ARCH_V32) += --remove-section=.bss --remove-section=.note.gnu.build-id
+
+-OBJCOPYFLAGS = -O binary $(objcopyflags-y)
++#OBJCOPYFLAGS = -O binary $(objcopyflags-y)
+
+
+ subdir- := compressed rescue
+@@ -17,7 +17,6 @@
+
+ $(obj)/compressed/vmlinux: $(obj)/Image FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/compressed $@
+- $(Q)$(MAKE) $(build)=$(obj)/rescue $(obj)/rescue/rescue.bin
+
+ $(obj)/zImage: $(obj)/compressed/vmlinux
+ @cp $< $@
+diff -Nur linux-2.6.36.orig/arch/cris/boot/compressed/Makefile linux-2.6.36/arch/cris/boot/compressed/Makefile
+--- linux-2.6.36.orig/arch/cris/boot/compressed/Makefile 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/boot/compressed/Makefile 2010-12-28 20:35:00.000000000 +0100
+@@ -18,7 +18,7 @@
+ OBJECTS-$(CONFIG_ETRAX_ARCH_V32) = $(obj)/head_v32.o
+ OBJECTS-$(CONFIG_ETRAX_ARCH_V10) = $(obj)/head_v10.o
+ OBJECTS= $(OBJECTS-y) $(obj)/misc.o
+-OBJCOPYFLAGS = -O binary --remove-section=.bss
++#OBJCOPYFLAGS = -O binary --remove-section=.bss
+
+ quiet_cmd_image = BUILD $@
+ cmd_image = cat $(obj)/decompress.bin $(obj)/piggy.gz > $@
+diff -Nur linux-2.6.36.orig/arch/cris/mm/init.c linux-2.6.36/arch/cris/mm/init.c
+--- linux-2.6.36.orig/arch/cris/mm/init.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/mm/init.c 2010-12-28 20:35:11.000000000 +0100
+@@ -81,3 +81,10 @@
+ printk (KERN_INFO "Freeing unused kernel memory: %luk freed\n",
+ (unsigned long)((&__init_end - &__init_begin) >> 10));
+ }
++
++#ifdef CONFIG_BLK_DEV_INITRD
++void free_initrd_mem(unsigned long start, unsigned long end)
++{
++ return 0;
++}
++#endif
+diff -Nur linux-2.6.36.orig/drivers/net/cris/eth_v10.c linux-2.6.36/drivers/net/cris/eth_v10.c
+--- linux-2.6.36.orig/drivers/net/cris/eth_v10.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/net/cris/eth_v10.c 2010-12-28 20:35:00.000000000 +0100
+@@ -1718,7 +1718,7 @@
+ static void
+ e100_netpoll(struct net_device* netdev)
+ {
+- e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev, NULL);
++ e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev);
+ }
+ #endif
+
+diff -Nur linux-2.6.36.orig/drivers/serial/crisv10.c linux-2.6.36/drivers/serial/crisv10.c
+--- linux-2.6.36.orig/drivers/serial/crisv10.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/serial/crisv10.c 2010-12-28 20:35:00.000000000 +0100
+@@ -13,6 +13,7 @@
+ #include <linux/errno.h>
+ #include <linux/signal.h>
+ #include <linux/sched.h>
++#include <linux/smp_lock.h>
+ #include <linux/timer.h>
+ #include <linux/interrupt.h>
+ #include <linux/tty.h>
+@@ -27,6 +28,7 @@
+ #include <linux/kernel.h>
+ #include <linux/mutex.h>
+ #include <linux/bitops.h>
++#include <linux/device.h>
+ #include <linux/seq_file.h>
+ #include <linux/delay.h>
+ #include <linux/module.h>
+@@ -4426,6 +4428,7 @@
+ #endif
+ };
+
++static struct class *rs_class;
+ static int __init rs_init(void)
+ {
+ int i;
+@@ -4559,6 +4562,24 @@
+ #endif
+ #endif /* CONFIG_SVINTO_SIM */
+
++ rs_class = class_create(THIS_MODULE, "rs_tty");
++#ifdef CONFIG_ETRAX_SERIAL_PORT0
++ device_create(rs_class, NULL,
++ MKDEV(TTY_MAJOR, 64), NULL, "ttyS0");
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT1
++ device_create(rs_class, NULL,
++ MKDEV(TTY_MAJOR, 65), NULL, "ttyS1");
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT2
++ device_create(rs_class, NULL,
++ MKDEV(TTY_MAJOR, 66), NULL, "ttyS2");
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT3
++ device_create(rs_class, NULL,
++ MKDEV(TTY_MAJOR, 67), NULL, "ttyS3");
++#endif
++
+ return 0;
+ }
+
+diff -Nur linux-2.6.36.orig/drivers/usb/Makefile linux-2.6.36/drivers/usb/Makefile
+--- linux-2.6.36.orig/drivers/usb/Makefile 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/usb/Makefile 2010-12-28 20:35:00.000000000 +0100
+@@ -21,6 +21,7 @@
+ obj-$(CONFIG_USB_R8A66597_HCD) += host/
+ obj-$(CONFIG_USB_HWA_HCD) += host/
+ obj-$(CONFIG_USB_ISP1760_HCD) += host/
++obj-$(CONFIG_ETRAX_USB_HOST) += host/
+ obj-$(CONFIG_USB_IMX21_HCD) += host/
+
+ obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
+diff -Nur linux-2.6.36.orig/drivers/usb/host/Makefile linux-2.6.36/drivers/usb/host/Makefile
+--- linux-2.6.36.orig/drivers/usb/host/Makefile 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/usb/host/Makefile 2010-12-28 20:35:00.000000000 +0100
+@@ -32,5 +32,6 @@
+ obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
+ obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
+ obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
++obj-$(CONFIG_ETRAX_USB_HOST) += hc-crisv10.o
+ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
+
+diff -Nur linux-2.6.36.orig/drivers/usb/host/hc-cris-dbg.h linux-2.6.36/drivers/usb/host/hc-cris-dbg.h
+--- linux-2.6.36.orig/drivers/usb/host/hc-cris-dbg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/drivers/usb/host/hc-cris-dbg.h 2010-12-28 20:35:00.000000000 +0100
+@@ -0,0 +1,146 @@
++
++/* macros for debug output */
++
++#define warn(fmt, args...) \
++ printk(KERN_INFO "crisv10 warn: ");printk(fmt, ## args)
++
++#define hcd_dbg(hcd, fmt, args...) \
++ dev_info(hcd->self.controller, fmt, ## args)
++#define hcd_err(hcd, fmt, args...) \
++ dev_err(hcd->self.controller, fmt, ## args)
++#define hcd_info(hcd, fmt, args...) \
++ dev_info(hcd->self.controller, fmt, ## args)
++#define hcd_warn(hcd, fmt, args...) \
++ dev_warn(hcd->self.controller, fmt, ## args)
++
++/*
++#define devdrv_dbg(fmt, args...) \
++ printk(KERN_INFO "usb_devdrv dbg: ");printk(fmt, ## args)
++*/
++#define devdrv_dbg(fmt, args...) {}
++
++#define devdrv_err(fmt, args...) \
++ printk(KERN_ERR "usb_devdrv error: ");printk(fmt, ## args)
++#define devdrv_info(fmt, args...) \
++ printk(KERN_INFO "usb_devdrv: ");printk(fmt, ## args)
++
++#define irq_dbg(fmt, args...) \
++ printk(KERN_INFO "crisv10_irq dbg: ");printk(fmt, ## args)
++#define irq_err(fmt, args...) \
++ printk(KERN_ERR "crisv10_irq error: ");printk(fmt, ## args)
++#define irq_warn(fmt, args...) \
++ printk(KERN_INFO "crisv10_irq warn: ");printk(fmt, ## args)
++#define irq_info(fmt, args...) \
++ printk(KERN_INFO "crisv10_hcd: ");printk(fmt, ## args)
++
++/*
++#define rh_dbg(fmt, args...) \
++ printk(KERN_DEBUG "crisv10_rh dbg: ");printk(fmt, ## args)
++*/
++#define rh_dbg(fmt, args...) {}
++
++#define rh_err(fmt, args...) \
++ printk(KERN_ERR "crisv10_rh error: ");printk(fmt, ## args)
++#define rh_warn(fmt, args...) \
++ printk(KERN_INFO "crisv10_rh warning: ");printk(fmt, ## args)
++#define rh_info(fmt, args...) \
++ printk(KERN_INFO "crisv10_rh: ");printk(fmt, ## args)
++
++/*
++#define tc_dbg(fmt, args...) \
++ printk(KERN_INFO "crisv10_tc dbg: ");printk(fmt, ## args)
++*/
++#define tc_dbg(fmt, args...) {while(0){}}
++
++#define tc_err(fmt, args...) \
++ printk(KERN_ERR "crisv10_tc error: ");printk(fmt, ## args)
++/*
++#define tc_warn(fmt, args...) \
++ printk(KERN_INFO "crisv10_tc warning: ");printk(fmt, ## args)
++*/
++#define tc_warn(fmt, args...) {while(0){}}
++
++#define tc_info(fmt, args...) \
++ printk(KERN_INFO "crisv10_tc: ");printk(fmt, ## args)
++
++
++/* Debug print-outs for various traffic types */
++
++#define intr_warn(fmt, args...) \
++ printk(KERN_INFO "crisv10_intr warning: ");printk(fmt, ## args)
++
++#define intr_dbg(fmt, args...) \
++ printk(KERN_DEBUG "crisv10_intr dbg: ");printk(fmt, ## args)
++/*
++#define intr_dbg(fmt, args...) {while(0){}}
++*/
++
++
++#define isoc_err(fmt, args...) \
++ printk(KERN_ERR "crisv10_isoc error: ");printk(fmt, ## args)
++/*
++#define isoc_warn(fmt, args...) \
++ printk(KERN_INFO "crisv10_isoc warning: ");printk(fmt, ## args)
++*/
++#define isoc_warn(fmt, args...) {while(0){}}
++
++/*
++#define isoc_dbg(fmt, args...) \
++ printk(KERN_INFO "crisv10_isoc dbg: ");printk(fmt, ## args)
++*/
++#define isoc_dbg(fmt, args...) {while(0){}}
++
++/*
++#define timer_warn(fmt, args...) \
++ printk(KERN_INFO "crisv10_timer warning: ");printk(fmt, ## args)
++*/
++#define timer_warn(fmt, args...) {while(0){}}
++
++/*
++#define timer_dbg(fmt, args...) \
++ printk(KERN_INFO "crisv10_timer dbg: ");printk(fmt, ## args)
++*/
++#define timer_dbg(fmt, args...) {while(0){}}
++
++
++/* Debug printouts for events related to late finishing of URBs */
++
++#define late_dbg(fmt, args...) \
++ printk(KERN_INFO "crisv10_late dbg: ");printk(fmt, ## args)
++/*
++#define late_dbg(fmt, args...) {while(0){}}
++*/
++
++#define late_warn(fmt, args...) \
++ printk(KERN_INFO "crisv10_late warning: ");printk(fmt, ## args)
++/*
++#define errno_dbg(fmt, args...) \
++ printk(KERN_INFO "crisv10_errno dbg: ");printk(fmt, ## args)
++*/
++#define errno_dbg(fmt, args...) {while(0){}}
++
++
++#define dma_dbg(fmt, args...) \
++ printk(KERN_INFO "crisv10_dma dbg: ");printk(fmt, ## args)
++#define dma_err(fmt, args...) \
++ printk(KERN_ERR "crisv10_dma error: ");printk(fmt, ## args)
++#define dma_warn(fmt, args...) \
++ printk(KERN_INFO "crisv10_dma warning: ");printk(fmt, ## args)
++#define dma_info(fmt, args...) \
++ printk(KERN_INFO "crisv10_dma: ");printk(fmt, ## args)
++
++
++
++#define str_dir(pipe) \
++ (usb_pipeout(pipe) ? "out" : "in")
++#define str_type(pipe) \
++ ({ \
++ char *s = "?"; \
++ switch (usb_pipetype(pipe)) { \
++ case PIPE_ISOCHRONOUS: s = "iso"; break; \
++ case PIPE_INTERRUPT: s = "intr"; break; \
++ case PIPE_CONTROL: s = "ctrl"; break; \
++ case PIPE_BULK: s = "bulk"; break; \
++ }; \
++ s; \
++ })
+diff -Nur linux-2.6.36.orig/drivers/usb/host/hc-crisv10.c linux-2.6.36/drivers/usb/host/hc-crisv10.c
+--- linux-2.6.36.orig/drivers/usb/host/hc-crisv10.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/drivers/usb/host/hc-crisv10.c 2010-12-28 20:35:00.000000000 +0100
+@@ -0,0 +1,4801 @@
++/*
++ *
++ * ETRAX 100LX USB Host Controller Driver
++ *
++ * Copyright (C) 2005, 2006 Axis Communications AB
++ *
++ * Author: Konrad Eriksson <konrad.eriksson@axis.se>
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/moduleparam.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/usb.h>
++#include <linux/platform_device.h>
++#include <linux/usb/hcd.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <arch/dma.h>
++#include <arch/io_interface_mux.h>
++
++#include "hc-crisv10.h"
++#include "hc-cris-dbg.h"
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* Host Controller settings */
++/***************************************************************************/
++/***************************************************************************/
++
++#define VERSION "1.00 hinko.4"
++#define COPYRIGHT "(c) 2005, 2006 Axis Communications AB"
++#define DESCRIPTION "ETRAX 100LX USB Host Controller"
++
++#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR
++#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR
++#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR
++
++/* Number of physical ports in Etrax 100LX */
++#define USB_ROOT_HUB_PORTS 2
++
++const char hc_name[] = "hc-crisv10";
++const char product_desc[] = DESCRIPTION;
++
++/* The number of epids is, among other things, used for pre-allocating
++ ctrl, bulk and isoc EP descriptors (one for each epid).
++ Assumed to be > 1 when initiating the DMA lists. */
++#define NBR_OF_EPIDS 32
++
++/* Support interrupt traffic intervals up to 128 ms. */
++#define MAX_INTR_INTERVAL 128
++
++/* If periodic traffic (intr or isoc) is to be used, then one entry in the EP
++ table must be "invalid". By this we mean that we shouldn't care about epid
++ attentions for this epid, or at least handle them differently from epid
++ attentions for "valid" epids. This define determines which one to use
++ (don't change it). */
++#define INVALID_EPID 31
++/* A special epid for the bulk dummys. */
++#define DUMMY_EPID 30
++
++/* Module settings */
++
++MODULE_DESCRIPTION(DESCRIPTION);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Konrad Eriksson <konrad.eriksson@axis.se>");
++
++
++/* Module parameters */
++
++/* 0 = No ports enabled
++ 1 = Only port 1 enabled (on board ethernet on devboard)
++ 2 = Only port 2 enabled (external connector on devboard)
++ 3 = Both ports enabled
++*/
++static unsigned int ports = 3;
++module_param(ports, uint, S_IRUGO);
++MODULE_PARM_DESC(ports, "Bitmask indicating USB ports to use");
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* Shared global variables for this module */
++/***************************************************************************/
++/***************************************************************************/
++
++/* EP descriptor lists for non period transfers. Must be 32-bit aligned. */
++static volatile struct USB_EP_Desc TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++
++static volatile struct USB_EP_Desc TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++
++/* EP descriptor lists for period transfers. Must be 32-bit aligned. */
++static volatile struct USB_EP_Desc TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
++static volatile struct USB_SB_Desc TxIntrSB_zout __attribute__ ((aligned (4)));
++
++static volatile struct USB_EP_Desc TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++static volatile struct USB_SB_Desc TxIsocSB_zout __attribute__ ((aligned (4)));
++
++//static volatile struct USB_SB_Desc TxIsocSBList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++
++/* After each enabled bulk EP IN we put two disabled EP descriptors with the eol flag set,
++ causing the DMA to stop the DMA channel. The first of these two has the intr flag set, which
++ gives us a dma8_sub0_descr interrupt. When we receive this, we advance the DMA one step in the
++ EP list and then restart the bulk channel, thus forcing a switch between bulk EP descriptors
++ in each frame. */
++static volatile struct USB_EP_Desc TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4)));
++
++/* List of URB pointers, where each points to the active URB for a epid.
++ For Bulk, Ctrl and Intr this means which URB that currently is added to
++ DMA lists (Isoc URBs are all directly added to DMA lists). As soon as
++ URB has completed is the queue examined and the first URB in queue is
++ removed and moved to the activeUrbList while its state change to STARTED and
++ its transfer(s) gets added to DMA list (exception Isoc where URBs enter
++ state STARTED directly and added transfers added to DMA lists). */
++static struct urb *activeUrbList[NBR_OF_EPIDS];
++
++/* Additional software state info for each epid */
++static struct etrax_epid epid_state[NBR_OF_EPIDS];
++
++/* Timer handles for bulk traffic timer used to avoid DMA bug where DMA stops
++ even if there is new data waiting to be processed */
++static struct timer_list bulk_start_timer = TIMER_INITIALIZER(NULL, 0, 0);
++static struct timer_list bulk_eot_timer = TIMER_INITIALIZER(NULL, 0, 0);
++
++/* We want the start timer to expire before the eot timer, because the former
++ might start traffic, thus making it unnecessary for the latter to time
++ out. */
++#define BULK_START_TIMER_INTERVAL (HZ/50) /* 20 ms */
++#define BULK_EOT_TIMER_INTERVAL (HZ/16) /* 60 ms */
++
++/* Delay before a URB completion happen when it's scheduled to be delayed */
++#define LATER_TIMER_DELAY (HZ/50) /* 20 ms */
++
++/* Simplifying macros for checking software state info of a epid */
++/* ----------------------------------------------------------------------- */
++#define epid_inuse(epid) epid_state[epid].inuse
++#define epid_out_traffic(epid) epid_state[epid].out_traffic
++#define epid_isoc(epid) (epid_state[epid].type == PIPE_ISOCHRONOUS ? 1 : 0)
++#define epid_intr(epid) (epid_state[epid].type == PIPE_INTERRUPT ? 1 : 0)
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* DEBUG FUNCTIONS */
++/***************************************************************************/
++/***************************************************************************/
++/* Note that these functions are always available in their "__" variants,
++ for use in error situations. The "__" missing variants are controlled by
++ the USB_DEBUG_DESC/USB_DEBUG_URB macros. */
++static void __dump_urb(struct urb* purb)
++{
++ struct crisv10_urb_priv *urb_priv = purb->hcpriv;
++ int urb_num = -1;
++ if(urb_priv) {
++ urb_num = urb_priv->urb_num;
++ }
++ printk("\nURB:0x%x[%d]\n", (unsigned int)purb, urb_num);
++ printk("dev :0x%08lx\n", (unsigned long)purb->dev);
++ printk("pipe :0x%08x\n", purb->pipe);
++ printk("status :%d\n", purb->status);
++ printk("transfer_flags :0x%08x\n", purb->transfer_flags);
++ printk("transfer_buffer :0x%08lx\n", (unsigned long)purb->transfer_buffer);
++ printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
++ printk("actual_length :%d\n", purb->actual_length);
++ printk("setup_packet :0x%08lx\n", (unsigned long)purb->setup_packet);
++ printk("start_frame :%d\n", purb->start_frame);
++ printk("number_of_packets :%d\n", purb->number_of_packets);
++ printk("interval :%d\n", purb->interval);
++ printk("error_count :%d\n", purb->error_count);
++ printk("context :0x%08lx\n", (unsigned long)purb->context);
++ printk("complete :0x%08lx\n\n", (unsigned long)purb->complete);
++}
++
++static void __dump_in_desc(volatile struct USB_IN_Desc *in)
++{
++ printk("\nUSB_IN_Desc at 0x%08lx\n", (unsigned long)in);
++ printk(" sw_len : 0x%04x (%d)\n", in->sw_len, in->sw_len);
++ printk(" command : 0x%04x\n", in->command);
++ printk(" next : 0x%08lx\n", in->next);
++ printk(" buf : 0x%08lx\n", in->buf);
++ printk(" hw_len : 0x%04x (%d)\n", in->hw_len, in->hw_len);
++ printk(" status : 0x%04x\n\n", in->status);
++}
++
++static void __dump_sb_desc(volatile struct USB_SB_Desc *sb)
++{
++ char tt = (sb->command & 0x30) >> 4;
++ char *tt_string;
++
++ switch (tt) {
++ case 0:
++ tt_string = "zout";
++ break;
++ case 1:
++ tt_string = "in";
++ break;
++ case 2:
++ tt_string = "out";
++ break;
++ case 3:
++ tt_string = "setup";
++ break;
++ default:
++ tt_string = "unknown (weird)";
++ }
++
++ printk(" USB_SB_Desc at 0x%08lx ", (unsigned long)sb);
++ printk(" command:0x%04x (", sb->command);
++ printk("rem:%d ", (sb->command & 0x3f00) >> 8);
++ printk("full:%d ", (sb->command & 0x40) >> 6);
++ printk("tt:%d(%s) ", tt, tt_string);
++ printk("intr:%d ", (sb->command & 0x8) >> 3);
++ printk("eot:%d ", (sb->command & 0x2) >> 1);
++ printk("eol:%d)", sb->command & 0x1);
++ printk(" sw_len:0x%04x(%d)", sb->sw_len, sb->sw_len);
++ printk(" next:0x%08lx", sb->next);
++ printk(" buf:0x%08lx\n", sb->buf);
++}
++
++
++static void __dump_ep_desc(volatile struct USB_EP_Desc *ep)
++{
++ printk("USB_EP_Desc at 0x%08lx ", (unsigned long)ep);
++ printk(" command:0x%04x (", ep->command);
++ printk("ep_id:%d ", (ep->command & 0x1f00) >> 8);
++ printk("enable:%d ", (ep->command & 0x10) >> 4);
++ printk("intr:%d ", (ep->command & 0x8) >> 3);
++ printk("eof:%d ", (ep->command & 0x2) >> 1);
++ printk("eol:%d)", ep->command & 0x1);
++ printk(" hw_len:0x%04x(%d)", ep->hw_len, ep->hw_len);
++ printk(" next:0x%08lx", ep->next);
++ printk(" sub:0x%08lx\n", ep->sub);
++}
++
++static inline void __dump_ep_list(int pipe_type)
++{
++ volatile struct USB_EP_Desc *ep;
++ volatile struct USB_EP_Desc *first_ep;
++ volatile struct USB_SB_Desc *sb;
++
++ switch (pipe_type)
++ {
++ case PIPE_BULK:
++ first_ep = &TxBulkEPList[0];
++ break;
++ case PIPE_CONTROL:
++ first_ep = &TxCtrlEPList[0];
++ break;
++ case PIPE_INTERRUPT:
++ first_ep = &TxIntrEPList[0];
++ break;
++ case PIPE_ISOCHRONOUS:
++ first_ep = &TxIsocEPList[0];
++ break;
++ default:
++ warn("Cannot dump unknown traffic type");
++ return;
++ }
++ ep = first_ep;
++
++ printk("\n\nDumping EP list...\n\n");
++
++ do {
++ __dump_ep_desc(ep);
++ /* Cannot phys_to_virt on 0 as it turns into 80000000, which is != 0. */
++ sb = ep->sub ? phys_to_virt(ep->sub) : 0;
++ while (sb) {
++ __dump_sb_desc(sb);
++ sb = sb->next ? phys_to_virt(sb->next) : 0;
++ }
++ ep = (volatile struct USB_EP_Desc *)(phys_to_virt(ep->next));
++
++ } while (ep != first_ep);
++}
++
++static inline void __dump_ept_data(int epid)
++{
++ unsigned long flags;
++ __u32 r_usb_ept_data;
++
++ if (epid < 0 || epid > 31) {
++ printk("Cannot dump ept data for invalid epid %d\n", epid);
++ return;
++ }
++
++ local_irq_save(flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
++ nop();
++ r_usb_ept_data = *R_USB_EPT_DATA;
++ local_irq_restore(flags);
++
++ printk(" R_USB_EPT_DATA = 0x%x for epid %d :\n", r_usb_ept_data, epid);
++ if (r_usb_ept_data == 0) {
++ /* No need for more detailed printing. */
++ return;
++ }
++ printk(" valid : %d\n", (r_usb_ept_data & 0x80000000) >> 31);
++ printk(" hold : %d\n", (r_usb_ept_data & 0x40000000) >> 30);
++ printk(" error_count_in : %d\n", (r_usb_ept_data & 0x30000000) >> 28);
++ printk(" t_in : %d\n", (r_usb_ept_data & 0x08000000) >> 27);
++ printk(" low_speed : %d\n", (r_usb_ept_data & 0x04000000) >> 26);
++ printk(" port : %d\n", (r_usb_ept_data & 0x03000000) >> 24);
++ printk(" error_code : %d\n", (r_usb_ept_data & 0x00c00000) >> 22);
++ printk(" t_out : %d\n", (r_usb_ept_data & 0x00200000) >> 21);
++ printk(" error_count_out : %d\n", (r_usb_ept_data & 0x00180000) >> 19);
++ printk(" max_len : %d\n", (r_usb_ept_data & 0x0003f800) >> 11);
++ printk(" ep : %d\n", (r_usb_ept_data & 0x00000780) >> 7);
++ printk(" dev : %d\n", (r_usb_ept_data & 0x0000003f));
++}
++
++static inline void __dump_ept_data_iso(int epid)
++{
++ unsigned long flags;
++ __u32 ept_data;
++
++ if (epid < 0 || epid > 31) {
++ printk("Cannot dump ept data for invalid epid %d\n", epid);
++ return;
++ }
++
++ local_irq_save(flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
++ nop();
++ ept_data = *R_USB_EPT_DATA_ISO;
++ local_irq_restore(flags);
++
++ printk(" R_USB_EPT_DATA = 0x%x for epid %d :\n", ept_data, epid);
++ if (ept_data == 0) {
++ /* No need for more detailed printing. */
++ return;
++ }
++ printk(" valid : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, valid,
++ ept_data));
++ printk(" port : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, port,
++ ept_data));
++ printk(" error_code : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code,
++ ept_data));
++ printk(" max_len : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len,
++ ept_data));
++ printk(" ep : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, ep,
++ ept_data));
++ printk(" dev : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, dev,
++ ept_data));
++}
++
++static inline void __dump_ept_data_list(void)
++{
++ int i;
++
++ printk("Dumping the whole R_USB_EPT_DATA list\n");
++
++ for (i = 0; i < 32; i++) {
++ __dump_ept_data(i);
++ }
++}
++
++static void debug_epid(int epid) {
++ int i;
++
++ if(epid_isoc(epid)) {
++ __dump_ept_data_iso(epid);
++ } else {
++ __dump_ept_data(epid);
++ }
++
++ printk("Bulk:\n");
++ for(i = 0; i < 32; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxBulkEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxBulkEPList[i]));
++ }
++ }
++
++ printk("Ctrl:\n");
++ for(i = 0; i < 32; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxCtrlEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxCtrlEPList[i]));
++ }
++ }
++
++ printk("Intr:\n");
++ for(i = 0; i < MAX_INTR_INTERVAL; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxIntrEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxIntrEPList[i]));
++ }
++ }
++
++ printk("Isoc:\n");
++ for(i = 0; i < 32; i++) {
++ if(IO_EXTRACT(USB_EP_command, epid, TxIsocEPList[i].command) ==
++ epid) {
++ printk("%d: ", i); __dump_ep_desc(&(TxIsocEPList[i]));
++ }
++ }
++
++ __dump_ept_data_list();
++ __dump_ep_list(PIPE_INTERRUPT);
++ printk("\n\n");
++}
++
++
++
++char* hcd_status_to_str(__u8 bUsbStatus) {
++ static char hcd_status_str[128];
++ hcd_status_str[0] = '\0';
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, ourun, yes)) {
++ strcat(hcd_status_str, "ourun ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, perror, yes)) {
++ strcat(hcd_status_str, "perror ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, device_mode, yes)) {
++ strcat(hcd_status_str, "device_mode ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, host_mode, yes)) {
++ strcat(hcd_status_str, "host_mode ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, started, yes)) {
++ strcat(hcd_status_str, "started ");
++ }
++ if(bUsbStatus & IO_STATE(R_USB_STATUS, running, yes)) {
++ strcat(hcd_status_str, "running ");
++ }
++ return hcd_status_str;
++}
++
++
++char* sblist_to_str(struct USB_SB_Desc* sb_desc) {
++ static char sblist_to_str_buff[128];
++ char tmp[32], tmp2[32];
++ sblist_to_str_buff[0] = '\0';
++ while(sb_desc != NULL) {
++ switch(IO_EXTRACT(USB_SB_command, tt, sb_desc->command)) {
++ case 0: sprintf(tmp, "zout"); break;
++ case 1: sprintf(tmp, "in"); break;
++ case 2: sprintf(tmp, "out"); break;
++ case 3: sprintf(tmp, "setup"); break;
++ }
++ sprintf(tmp2, "(%s %d)", tmp, sb_desc->sw_len);
++ strcat(sblist_to_str_buff, tmp2);
++ if(sb_desc->next != 0) {
++ sb_desc = phys_to_virt(sb_desc->next);
++ } else {
++ sb_desc = NULL;
++ }
++ }
++ return sblist_to_str_buff;
++}
++
++char* port_status_to_str(__u16 wPortStatus) {
++ static char port_status_str[128];
++ port_status_str[0] = '\0';
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) {
++ strcat(port_status_str, "connected ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)) {
++ strcat(port_status_str, "enabled ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, suspended, yes)) {
++ strcat(port_status_str, "suspended ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, reset, yes)) {
++ strcat(port_status_str, "reset ");
++ }
++ if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, speed, full)) {
++ strcat(port_status_str, "full-speed ");
++ } else {
++ strcat(port_status_str, "low-speed ");
++ }
++ return port_status_str;
++}
++
++
++char* endpoint_to_str(struct usb_endpoint_descriptor *ed) {
++ static char endpoint_to_str_buff[128];
++ char tmp[32];
++ int epnum = ed->bEndpointAddress & 0x0F;
++ int dir = ed->bEndpointAddress & 0x80;
++ int type = ed->bmAttributes & 0x03;
++ endpoint_to_str_buff[0] = '\0';
++ sprintf(endpoint_to_str_buff, "ep:%d ", epnum);
++ switch(type) {
++ case 0:
++ sprintf(tmp, " ctrl");
++ break;
++ case 1:
++ sprintf(tmp, " isoc");
++ break;
++ case 2:
++ sprintf(tmp, " bulk");
++ break;
++ case 3:
++ sprintf(tmp, " intr");
++ break;
++ }
++ strcat(endpoint_to_str_buff, tmp);
++ if(dir) {
++ sprintf(tmp, " in");
++ } else {
++ sprintf(tmp, " out");
++ }
++ strcat(endpoint_to_str_buff, tmp);
++
++ return endpoint_to_str_buff;
++}
++
++/* Debug helper functions for Transfer Controller */
++char* pipe_to_str(unsigned int pipe) {
++ static char pipe_to_str_buff[128];
++ char tmp[64];
++ sprintf(pipe_to_str_buff, "dir:%s", str_dir(pipe));
++ sprintf(tmp, " type:%s", str_type(pipe));
++ strcat(pipe_to_str_buff, tmp);
++
++ sprintf(tmp, " dev:%d", usb_pipedevice(pipe));
++ strcat(pipe_to_str_buff, tmp);
++ sprintf(tmp, " ep:%d", usb_pipeendpoint(pipe));
++ strcat(pipe_to_str_buff, tmp);
++ return pipe_to_str_buff;
++}
++
++
++#define USB_DEBUG_DESC 1
++
++#ifdef USB_DEBUG_DESC
++#define dump_in_desc(x) __dump_in_desc(x)
++#define dump_sb_desc(...) __dump_sb_desc(...)
++#define dump_ep_desc(x) __dump_ep_desc(x)
++#define dump_ept_data(x) __dump_ept_data(x)
++#else
++#define dump_in_desc(...) do {} while (0)
++#define dump_sb_desc(...) do {} while (0)
++#define dump_ep_desc(...) do {} while (0)
++#endif
++
++
++/* Uncomment this to enable massive function call trace
++ #define USB_DEBUG_TRACE */
++//#define USB_DEBUG_TRACE 1
++
++#ifdef USB_DEBUG_TRACE
++#define DBFENTER (printk(": Entering: %s\n", __FUNCTION__))
++#define DBFEXIT (printk(": Exiting: %s\n", __FUNCTION__))
++#else
++#define DBFENTER do {} while (0)
++#define DBFEXIT do {} while (0)
++#endif
++
++#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \
++{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);}
++
++/* Most helpful debugging aid */
++#define ASSERT(expr) ((void) ((expr) ? 0 : (err("assert failed at: %s %d",__FUNCTION__, __LINE__))))
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* Forward declarations */
++/***************************************************************************/
++/***************************************************************************/
++void crisv10_hcd_epid_attn_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_port_status_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_ctl_status_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_isoc_eof_irq(struct crisv10_irq_reg *reg);
++
++void rh_port_status_change(__u16[]);
++int rh_clear_port_feature(__u8, __u16);
++int rh_set_port_feature(__u8, __u16);
++static void rh_disable_port(unsigned int port);
++
++static void check_finished_bulk_tx_epids(struct usb_hcd *hcd,
++ int timer);
++
++//static int tc_setup_epid(struct usb_host_endpoint *ep, struct urb *urb,
++// int mem_flags);
++static int tc_setup_epid(struct urb *urb, int mem_flags);
++static void tc_free_epid(struct usb_host_endpoint *ep);
++static int tc_allocate_epid(void);
++static void tc_finish_urb(struct usb_hcd *hcd, struct urb *urb, int status);
++static void tc_finish_urb_later(struct usb_hcd *hcd, struct urb *urb,
++ int status);
++
++static int urb_priv_create(struct usb_hcd *hcd, struct urb *urb, int epid,
++ int mem_flags);
++static void urb_priv_free(struct usb_hcd *hcd, struct urb *urb);
++
++static inline struct urb *urb_list_first(int epid);
++static inline void urb_list_add(struct urb *urb, int epid,
++ int mem_flags);
++static inline urb_entry_t *urb_list_entry(struct urb *urb, int epid);
++static inline void urb_list_del(struct urb *urb, int epid);
++static inline void urb_list_move_last(struct urb *urb, int epid);
++static inline struct urb *urb_list_next(struct urb *urb, int epid);
++
++int create_sb_for_urb(struct urb *urb, int mem_flags);
++int init_intr_urb(struct urb *urb, int mem_flags);
++
++static inline void etrax_epid_set(__u8 index, __u32 data);
++static inline void etrax_epid_clear_error(__u8 index);
++static inline void etrax_epid_set_toggle(__u8 index, __u8 dirout,
++ __u8 toggle);
++static inline __u8 etrax_epid_get_toggle(__u8 index, __u8 dirout);
++static inline __u32 etrax_epid_get(__u8 index);
++
++/* We're accessing the same register position in Etrax so
++ when we do full access the internal difference doesn't matter */
++#define etrax_epid_iso_set(index, data) etrax_epid_set(index, data)
++#define etrax_epid_iso_get(index) etrax_epid_get(index)
++
++
++//static void tc_dma_process_isoc_urb(struct urb *urb);
++static void tc_dma_process_queue(int epid);
++static void tc_dma_unlink_intr_urb(struct urb *urb);
++static irqreturn_t tc_dma_tx_interrupt(int irq, void *vhc);
++static irqreturn_t tc_dma_rx_interrupt(int irq, void *vhc);
++
++static void tc_bulk_start_timer_func(unsigned long dummy);
++static void tc_bulk_eot_timer_func(unsigned long dummy);
++
++
++/*************************************************************/
++/*************************************************************/
++/* Host Controler Driver block */
++/*************************************************************/
++/*************************************************************/
++
++/* HCD operations */
++static irqreturn_t crisv10_hcd_top_irq(int irq, void*);
++static int crisv10_hcd_reset(struct usb_hcd *);
++static int crisv10_hcd_start(struct usb_hcd *);
++static void crisv10_hcd_stop(struct usb_hcd *);
++#ifdef CONFIG_PM
++static int crisv10_hcd_suspend(struct device *, u32, u32);
++static int crisv10_hcd_resume(struct device *, u32);
++#endif /* CONFIG_PM */
++static int crisv10_hcd_get_frame(struct usb_hcd *);
++
++//static int tc_urb_enqueue(struct usb_hcd *, struct usb_host_endpoint *ep, struct urb *, gfp_t mem_flags);
++static int tc_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
++//static int tc_urb_dequeue(struct usb_hcd *, struct urb *);
++static int tc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
++static void tc_endpoint_disable(struct usb_hcd *, struct usb_host_endpoint *ep);
++
++static int rh_status_data_request(struct usb_hcd *, char *);
++static int rh_control_request(struct usb_hcd *, u16, u16, u16, char*, u16);
++
++#ifdef CONFIG_PM
++static int crisv10_hcd_hub_suspend(struct usb_hcd *);
++static int crisv10_hcd_hub_resume(struct usb_hcd *);
++#endif /* CONFIG_PM */
++#ifdef CONFIG_USB_OTG
++static int crisv10_hcd_start_port_reset(struct usb_hcd *, unsigned);
++#endif /* CONFIG_USB_OTG */
++
++/* host controller driver interface */
++static const struct hc_driver crisv10_hc_driver =
++ {
++ .description = hc_name,
++ .product_desc = product_desc,
++ .hcd_priv_size = sizeof(struct crisv10_hcd),
++
++ /* Attaching IRQ handler manualy in probe() */
++ /* .irq = crisv10_hcd_irq, */
++
++ .flags = HCD_USB11,
++
++ /* called to init HCD and root hub */
++ .reset = crisv10_hcd_reset,
++ .start = crisv10_hcd_start,
++
++ /* cleanly make HCD stop writing memory and doing I/O */
++ .stop = crisv10_hcd_stop,
++
++ /* return current frame number */
++ .get_frame_number = crisv10_hcd_get_frame,
++
++
++ /* Manage i/o requests via the Transfer Controller */
++ .urb_enqueue = tc_urb_enqueue,
++ .urb_dequeue = tc_urb_dequeue,
++
++ /* hw synch, freeing endpoint resources that urb_dequeue can't */
++ .endpoint_disable = tc_endpoint_disable,
++
++
++ /* Root Hub support */
++ .hub_status_data = rh_status_data_request,
++ .hub_control = rh_control_request,
++#ifdef CONFIG_PM
++ .hub_suspend = rh_suspend_request,
++ .hub_resume = rh_resume_request,
++#endif /* CONFIG_PM */
++#ifdef CONFIG_USB_OTG
++ .start_port_reset = crisv10_hcd_start_port_reset,
++#endif /* CONFIG_USB_OTG */
++ };
++
++
++/*
++ * conversion between pointers to a hcd and the corresponding
++ * crisv10_hcd
++ */
++
++static inline struct crisv10_hcd *hcd_to_crisv10_hcd(struct usb_hcd *hcd)
++{
++ return (struct crisv10_hcd *) hcd->hcd_priv;
++}
++
++static inline struct usb_hcd *crisv10_hcd_to_hcd(struct crisv10_hcd *hcd)
++{
++ return container_of((void *) hcd, struct usb_hcd, hcd_priv);
++}
++
++/* check if specified port is in use */
++static inline int port_in_use(unsigned int port)
++{
++ return ports & (1 << port);
++}
++
++/* number of ports in use */
++static inline unsigned int num_ports(void)
++{
++ unsigned int i, num = 0;
++ for (i = 0; i < USB_ROOT_HUB_PORTS; i++)
++ if (port_in_use(i))
++ num++;
++ return num;
++}
++
++/* map hub port number to the port number used internally by the HC */
++static inline unsigned int map_port(unsigned int port)
++{
++ unsigned int i, num = 0;
++ for (i = 0; i < USB_ROOT_HUB_PORTS; i++)
++ if (port_in_use(i))
++ if (++num == port)
++ return i;
++ return -1;
++}
++
++/* size of descriptors in slab cache */
++#ifndef MAX
++#define MAX(x, y) ((x) > (y) ? (x) : (y))
++#endif
++
++
++/******************************************************************/
++/* Hardware Interrupt functions */
++/******************************************************************/
++
++/* Fast interrupt handler for HC */
++static irqreturn_t crisv10_hcd_top_irq(int irq, void *vcd)
++{
++ struct usb_hcd *hcd = vcd;
++ struct crisv10_irq_reg reg;
++ __u32 irq_mask;
++ unsigned long flags;
++
++ DBFENTER;
++
++ ASSERT(hcd != NULL);
++ reg.hcd = hcd;
++
++ /* Turn of other interrupts while handling these sensitive cases */
++ local_irq_save(flags);
++
++ /* Read out which interrupts that are flaged */
++ irq_mask = *R_USB_IRQ_MASK_READ;
++ reg.r_usb_irq_mask_read = irq_mask;
++
++ /* Reading R_USB_STATUS clears the ctl_status interrupt. Note that
++ R_USB_STATUS must be read before R_USB_EPID_ATTN since reading the latter
++ clears the ourun and perror fields of R_USB_STATUS. */
++ reg.r_usb_status = *R_USB_STATUS;
++
++ /* Reading R_USB_EPID_ATTN clears the iso_eof, bulk_eot and epid_attn
++ interrupts. */
++ reg.r_usb_epid_attn = *R_USB_EPID_ATTN;
++
++ /* Reading R_USB_RH_PORT_STATUS_1 and R_USB_RH_PORT_STATUS_2 clears the
++ port_status interrupt. */
++ reg.r_usb_rh_port_status_1 = *R_USB_RH_PORT_STATUS_1;
++ reg.r_usb_rh_port_status_2 = *R_USB_RH_PORT_STATUS_2;
++
++ /* Reading R_USB_FM_NUMBER clears the sof interrupt. */
++ /* Note: the lower 11 bits contain the actual frame number, sent with each
++ sof. */
++ reg.r_usb_fm_number = *R_USB_FM_NUMBER;
++
++ /* Interrupts are handled in order of priority. */
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) {
++ crisv10_hcd_port_status_irq(&reg);
++ }
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, epid_attn)) {
++ crisv10_hcd_epid_attn_irq(&reg);
++ }
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, ctl_status)) {
++ crisv10_hcd_ctl_status_irq(&reg);
++ }
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, iso_eof)) {
++ crisv10_hcd_isoc_eof_irq(&reg);
++ }
++ if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, bulk_eot)) {
++ /* Update/restart the bulk start timer since obviously the channel is
++ running. */
++ mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
++ /* Update/restart the bulk eot timer since we just received an bulk eot
++ interrupt. */
++ mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
++
++ /* Check for finished bulk transfers on epids */
++ check_finished_bulk_tx_epids(hcd, 0);
++ }
++ local_irq_restore(flags);
++
++ DBFEXIT;
++ return IRQ_HANDLED;
++}
++
++
++void crisv10_hcd_epid_attn_irq(struct crisv10_irq_reg *reg) {
++ struct usb_hcd *hcd = reg->hcd;
++ struct crisv10_urb_priv *urb_priv;
++ int epid;
++ DBFENTER;
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if (test_bit(epid, (void *)&reg->r_usb_epid_attn)) {
++ struct urb *urb;
++ __u32 ept_data;
++ int error_code;
++
++ if (epid == DUMMY_EPID || epid == INVALID_EPID) {
++ /* We definitely don't care about these ones. Besides, they are
++ always disabled, so any possible disabling caused by the
++ epid attention interrupt is irrelevant. */
++ warn("Got epid_attn for INVALID_EPID or DUMMY_EPID (%d).", epid);
++ continue;
++ }
++
++ if(!epid_inuse(epid)) {
++ irq_err("Epid attention on epid:%d that isn't in use\n", epid);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ debug_epid(epid);
++ continue;
++ }
++
++ /* Note that although there are separate R_USB_EPT_DATA and
++ R_USB_EPT_DATA_ISO registers, they are located at the same address and
++ are of the same size. In other words, this read should be ok for isoc
++ also. */
++ ept_data = etrax_epid_get(epid);
++ error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, ept_data);
++
++ /* Get the active URB for this epid. We blatantly assume
++ that only this URB could have caused the epid attention. */
++ urb = activeUrbList[epid];
++ if (urb == NULL) {
++ irq_err("Attention on epid:%d error:%d with no active URB.\n",
++ epid, error_code);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ debug_epid(epid);
++ continue;
++ }
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ /* Using IO_STATE_VALUE on R_USB_EPT_DATA should be ok for isoc also. */
++ if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
++
++ /* Isoc traffic doesn't have error_count_in/error_count_out. */
++ if ((usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) &&
++ (IO_EXTRACT(R_USB_EPT_DATA, error_count_in, ept_data) == 3 ||
++ IO_EXTRACT(R_USB_EPT_DATA, error_count_out, ept_data) == 3)) {
++ /* Check if URB allready is marked for late-finish, we can get
++ several 3rd error for Intr traffic when a device is unplugged */
++ if(urb_priv->later_data == NULL) {
++ /* 3rd error. */
++ irq_warn("3rd error for epid:%d (%s %s) URB:0x%x[%d]\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe),
++ (unsigned int)urb, urb_priv->urb_num);
++
++ tc_finish_urb_later(hcd, urb, -EPROTO);
++ }
++
++ } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
++ irq_warn("Perror for epid:%d\n", epid);
++ printk("FM_NUMBER: %d\n", reg->r_usb_fm_number & 0x7ff);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ __dump_urb(urb);
++ debug_epid(epid);
++
++ if (!(ept_data & IO_MASK(R_USB_EPT_DATA, valid))) {
++ /* invalid ep_id */
++ panic("Perror because of invalid epid."
++ " Deconfigured too early?");
++ } else {
++ /* past eof1, near eof, zout transfer, setup transfer */
++ /* Dump the urb and the relevant EP descriptor. */
++ panic("Something wrong with DMA descriptor contents."
++ " Too much traffic inserted?");
++ }
++ } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
++ /* buffer ourun */
++ printk("FM_NUMBER: %d\n", reg->r_usb_fm_number & 0x7ff);
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ __dump_urb(urb);
++ debug_epid(epid);
++
++ panic("Buffer overrun/underrun for epid:%d. DMA too busy?", epid);
++ } else {
++ irq_warn("Attention on epid:%d (%s %s) with no error code\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe));
++ printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++ __dump_urb(urb);
++ debug_epid(epid);
++ }
++
++ } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code,
++ stall)) {
++ /* Not really a protocol error, just says that the endpoint gave
++ a stall response. Note that error_code cannot be stall for isoc. */
++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++ panic("Isoc traffic cannot stall");
++ }
++
++ tc_dbg("Stall for epid:%d (%s %s) URB:0x%x\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe), (unsigned int)urb);
++ tc_finish_urb(hcd, urb, -EPIPE);
++
++ } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code,
++ bus_error)) {
++ /* Two devices responded to a transaction request. Must be resolved
++ by software. FIXME: Reset ports? */
++ panic("Bus error for epid %d."
++ " Two devices responded to transaction request\n",
++ epid);
++
++ } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code,
++ buffer_error)) {
++ /* DMA overrun or underrun. */
++ irq_warn("Buffer overrun/underrun for epid:%d (%s %s)\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe));
++
++ /* It seems that error_code = buffer_error in
++ R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
++ are the same error. */
++ tc_finish_urb(hcd, urb, -EPROTO);
++ } else {
++ irq_warn("Unknown attention on epid:%d (%s %s)\n", epid,
++ str_dir(urb->pipe), str_type(urb->pipe));
++ dump_ept_data(epid);
++ }
++ }
++ }
++ DBFEXIT;
++}
++
++void crisv10_hcd_port_status_irq(struct crisv10_irq_reg *reg)
++{
++ __u16 port_reg[USB_ROOT_HUB_PORTS];
++ DBFENTER;
++ port_reg[0] = reg->r_usb_rh_port_status_1;
++ port_reg[1] = reg->r_usb_rh_port_status_2;
++ rh_port_status_change(port_reg);
++ DBFEXIT;
++}
++
++void crisv10_hcd_isoc_eof_irq(struct crisv10_irq_reg *reg)
++{
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv *urb_priv;
++
++ DBFENTER;
++
++ for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
++
++ /* Only check epids that are in use, is valid and has SB list */
++ if (!epid_inuse(epid) || epid == INVALID_EPID ||
++ TxIsocEPList[epid].sub == 0 || epid == DUMMY_EPID) {
++ /* Nothing here to see. */
++ continue;
++ }
++ ASSERT(epid_isoc(epid));
++
++ /* Get the active URB for this epid (if any). */
++ urb = activeUrbList[epid];
++ if (urb == 0) {
++ isoc_warn("Ignoring NULL urb for epid:%d\n", epid);
++ continue;
++ }
++ if(!epid_out_traffic(epid)) {
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ if (urb_priv->urb_state == NOT_STARTED) {
++ /* If ASAP is not set and urb->start_frame is the current frame,
++ start the transfer. */
++ if (!(urb->transfer_flags & URB_ISO_ASAP) &&
++ (urb->start_frame == (*R_USB_FM_NUMBER & 0x7ff))) {
++ /* EP should not be enabled if we're waiting for start_frame */
++ ASSERT((TxIsocEPList[epid].command &
++ IO_STATE(USB_EP_command, enable, yes)) == 0);
++
++ isoc_warn("Enabling isoc IN EP descr for epid %d\n", epid);
++ TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++ /* This urb is now active. */
++ urb_priv->urb_state = STARTED;
++ continue;
++ }
++ }
++ }
++ }
++
++ DBFEXIT;
++}
++
++void crisv10_hcd_ctl_status_irq(struct crisv10_irq_reg *reg)
++{
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(reg->hcd);
++
++ DBFENTER;
++ ASSERT(crisv10_hcd);
++
++ irq_dbg("ctr_status_irq, controller status: %s\n",
++ hcd_status_to_str(reg->r_usb_status));
++
++ /* FIXME: What should we do if we get ourun or perror? Dump the EP and SB
++ list for the corresponding epid? */
++ if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
++ panic("USB controller got ourun.");
++ }
++ if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
++
++ /* Before, etrax_usb_do_intr_recover was called on this epid if it was
++ an interrupt pipe. I don't see how re-enabling all EP descriptors
++ will help if there was a programming error. */
++ panic("USB controller got perror.");
++ }
++
++ /* Keep track of USB Controller, if it's running or not */
++ if(reg->r_usb_status & IO_STATE(R_USB_STATUS, running, yes)) {
++ crisv10_hcd->running = 1;
++ } else {
++ crisv10_hcd->running = 0;
++ }
++
++ if (reg->r_usb_status & IO_MASK(R_USB_STATUS, device_mode)) {
++ /* We should never operate in device mode. */
++ panic("USB controller in device mode.");
++ }
++
++ /* Set the flag to avoid getting "Unlink after no-IRQ? Controller is probably
++ using the wrong IRQ" from hcd_unlink_urb() in drivers/usb/core/hcd.c */
++ set_bit(HCD_FLAG_SAW_IRQ, &reg->hcd->flags);
++
++ DBFEXIT;
++}
++
++
++/******************************************************************/
++/* Host Controller interface functions */
++/******************************************************************/
++
++static inline void crisv10_ready_wait(void) {
++ volatile int timeout = 10000;
++ /* Check the busy bit of USB controller in Etrax */
++ while((*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for USB controller to be idle\n");
++ }
++}
++
++/* reset host controller */
++static int crisv10_hcd_reset(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ hcd_dbg(hcd, "reset\n");
++
++
++ /* Reset the USB interface. */
++ /*
++ *R_USB_COMMAND =
++ IO_STATE(R_USB_COMMAND, port_sel, nop) |
++ IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++ IO_STATE(R_USB_COMMAND, ctrl_cmd, reset);
++ nop();
++ */
++ DBFEXIT;
++ return 0;
++}
++
++/* start host controller */
++static int crisv10_hcd_start(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ hcd_dbg(hcd, "start\n");
++
++ crisv10_ready_wait();
++
++ /* Start processing of USB traffic. */
++ *R_USB_COMMAND =
++ IO_STATE(R_USB_COMMAND, port_sel, nop) |
++ IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++ IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
++
++ nop();
++
++ hcd->state = HC_STATE_RUNNING;
++
++ DBFEXIT;
++ return 0;
++}
++
++/* stop host controller */
++static void crisv10_hcd_stop(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ hcd_dbg(hcd, "stop\n");
++ crisv10_hcd_reset(hcd);
++ DBFEXIT;
++}
++
++/* return the current frame number */
++static int crisv10_hcd_get_frame(struct usb_hcd *hcd)
++{
++ DBFENTER;
++ DBFEXIT;
++ return (*R_USB_FM_NUMBER & 0x7ff);
++}
++
++#ifdef CONFIG_USB_OTG
++
++static int crisv10_hcd_start_port_reset(struct usb_hcd *hcd, unsigned port)
++{
++ return 0; /* no-op for now */
++}
++
++#endif /* CONFIG_USB_OTG */
++
++
++/******************************************************************/
++/* Root Hub functions */
++/******************************************************************/
++
++/* root hub status */
++static const struct usb_hub_status rh_hub_status =
++ {
++ .wHubStatus = 0,
++ .wHubChange = 0,
++ };
++
++/* root hub descriptor */
++static const u8 rh_hub_descr[] =
++ {
++ 0x09, /* bDescLength */
++ 0x29, /* bDescriptorType */
++ USB_ROOT_HUB_PORTS, /* bNbrPorts */
++ 0x00, /* wHubCharacteristics */
++ 0x00,
++ 0x01, /* bPwrOn2pwrGood */
++ 0x00, /* bHubContrCurrent */
++ 0x00, /* DeviceRemovable */
++ 0xff /* PortPwrCtrlMask */
++ };
++
++/* Actual holder of root hub status*/
++struct crisv10_rh rh;
++
++/* Initialize root hub data structures (called from dvdrv_hcd_probe()) */
++int rh_init(void) {
++ int i;
++ /* Reset port status flags */
++ for (i = 0; i < USB_ROOT_HUB_PORTS; i++) {
++ rh.wPortChange[i] = 0;
++ rh.wPortStatusPrev[i] = 0;
++ }
++ return 0;
++}
++
++#define RH_FEAT_MASK ((1<<USB_PORT_FEAT_CONNECTION)|\
++ (1<<USB_PORT_FEAT_ENABLE)|\
++ (1<<USB_PORT_FEAT_SUSPEND)|\
++ (1<<USB_PORT_FEAT_RESET))
++
++/* Handle port status change interrupt (called from bottom part interrupt) */
++void rh_port_status_change(__u16 port_reg[]) {
++ int i;
++ __u16 wChange;
++
++ for(i = 0; i < USB_ROOT_HUB_PORTS; i++) {
++ /* Xor out changes since last read, masked for important flags */
++ wChange = (port_reg[i] & RH_FEAT_MASK) ^ rh.wPortStatusPrev[i];
++ /* Or changes together with (if any) saved changes */
++ rh.wPortChange[i] |= wChange;
++ /* Save new status */
++ rh.wPortStatusPrev[i] = port_reg[i];
++
++ if(wChange) {
++ rh_dbg("Interrupt port_status change port%d: %s Current-status:%s\n", i+1,
++ port_status_to_str(wChange),
++ port_status_to_str(port_reg[i]));
++ }
++ }
++}
++
++/* Construct port status change bitmap for the root hub */
++static int rh_status_data_request(struct usb_hcd *hcd, char *buf)
++{
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ unsigned int i;
++
++// DBFENTER;
++
++ /*
++ * corresponds to hub status change EP (USB 2.0 spec section 11.13.4)
++ * return bitmap indicating ports with status change
++ */
++ *buf = 0;
++ spin_lock(&crisv10_hcd->lock);
++ for (i = 1; i <= crisv10_hcd->num_ports; i++) {
++ if (rh.wPortChange[map_port(i)]) {
++ *buf |= (1 << i);
++ rh_dbg("rh_status_data_request, change on port %d: %s Current Status: %s\n", i,
++ port_status_to_str(rh.wPortChange[map_port(i)]),
++ port_status_to_str(rh.wPortStatusPrev[map_port(i)]));
++ }
++ }
++ spin_unlock(&crisv10_hcd->lock);
++
++// DBFEXIT;
++
++ return *buf == 0 ? 0 : 1;
++}
++
++/* Handle a control request for the root hub (called from hcd_driver) */
++static int rh_control_request(struct usb_hcd *hcd,
++ u16 typeReq,
++ u16 wValue,
++ u16 wIndex,
++ char *buf,
++ u16 wLength) {
++
++ struct crisv10_hcd *crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ int retval = 0;
++ int len;
++ DBFENTER;
++
++ switch (typeReq) {
++ case GetHubDescriptor:
++ rh_dbg("GetHubDescriptor\n");
++ len = min_t(unsigned int, sizeof rh_hub_descr, wLength);
++ memcpy(buf, rh_hub_descr, len);
++ buf[2] = crisv10_hcd->num_ports;
++ break;
++ case GetHubStatus:
++ rh_dbg("GetHubStatus\n");
++ len = min_t(unsigned int, sizeof rh_hub_status, wLength);
++ memcpy(buf, &rh_hub_status, len);
++ break;
++ case GetPortStatus:
++ if (!wIndex || wIndex > crisv10_hcd->num_ports)
++ goto error;
++ rh_dbg("GetportStatus, port:%d change:%s status:%s\n", wIndex,
++ port_status_to_str(rh.wPortChange[map_port(wIndex)]),
++ port_status_to_str(rh.wPortStatusPrev[map_port(wIndex)]));
++ *(u16 *) buf = cpu_to_le16(rh.wPortStatusPrev[map_port(wIndex)]);
++ *(u16 *) (buf + 2) = cpu_to_le16(rh.wPortChange[map_port(wIndex)]);
++ break;
++ case SetHubFeature:
++ rh_dbg("SetHubFeature\n");
++ case ClearHubFeature:
++ rh_dbg("ClearHubFeature\n");
++ switch (wValue) {
++ case C_HUB_OVER_CURRENT:
++ case C_HUB_LOCAL_POWER:
++ rh_warn("Not implemented hub request:%d \n", typeReq);
++ /* not implemented */
++ break;
++ default:
++ goto error;
++ }
++ break;
++ case SetPortFeature:
++ if (!wIndex || wIndex > crisv10_hcd->num_ports)
++ goto error;
++ if(rh_set_port_feature(map_port(wIndex), wValue))
++ goto error;
++ break;
++ case ClearPortFeature:
++ if (!wIndex || wIndex > crisv10_hcd->num_ports)
++ goto error;
++ if(rh_clear_port_feature(map_port(wIndex), wValue))
++ goto error;
++ break;
++ default:
++ rh_warn("Unknown hub request: %d\n", typeReq);
++ error:
++ retval = -EPIPE;
++ }
++ DBFEXIT;
++ return retval;
++}
++
++int rh_set_port_feature(__u8 bPort, __u16 wFeature) {
++ __u8 bUsbCommand = 0;
++ switch(wFeature) {
++ case USB_PORT_FEAT_RESET:
++ rh_dbg("SetPortFeature: reset\n");
++ bUsbCommand |= IO_STATE(R_USB_COMMAND, port_cmd, reset);
++ goto set;
++ break;
++ case USB_PORT_FEAT_SUSPEND:
++ rh_dbg("SetPortFeature: suspend\n");
++ bUsbCommand |= IO_STATE(R_USB_COMMAND, port_cmd, suspend);
++ goto set;
++ break;
++ case USB_PORT_FEAT_POWER:
++ rh_dbg("SetPortFeature: power\n");
++ break;
++ case USB_PORT_FEAT_C_CONNECTION:
++ rh_dbg("SetPortFeature: c_connection\n");
++ break;
++ case USB_PORT_FEAT_C_RESET:
++ rh_dbg("SetPortFeature: c_reset\n");
++ break;
++ case USB_PORT_FEAT_C_OVER_CURRENT:
++ rh_dbg("SetPortFeature: c_over_current\n");
++ break;
++
++ set:
++ /* Select which port via the port_sel field */
++ bUsbCommand |= IO_FIELD(R_USB_COMMAND, port_sel, bPort+1);
++
++ /* Make sure the controller isn't busy. */
++ crisv10_ready_wait();
++ /* Send out the actual command to the USB controller */
++ *R_USB_COMMAND = bUsbCommand;
++
++ /* If port reset then also bring USB controller into running state */
++ if(wFeature == USB_PORT_FEAT_RESET) {
++ /* Wait a while for controller to first become started after port reset */
++ udelay(12000); /* 12ms blocking wait */
++
++ /* Make sure the controller isn't busy. */
++ crisv10_ready_wait();
++
++ /* If all enabled ports were disabled the host controller goes down into
++ started mode, so we need to bring it back into the running state.
++ (This is safe even if it's already in the running state.) */
++ *R_USB_COMMAND =
++ IO_STATE(R_USB_COMMAND, port_sel, nop) |
++ IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++ IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
++ }
++
++ break;
++ default:
++ rh_dbg("SetPortFeature: unknown feature\n");
++ return -1;
++ }
++ return 0;
++}
++
++int rh_clear_port_feature(__u8 bPort, __u16 wFeature) {
++ switch(wFeature) {
++ case USB_PORT_FEAT_ENABLE:
++ rh_dbg("ClearPortFeature: enable\n");
++ rh_disable_port(bPort);
++ break;
++ case USB_PORT_FEAT_SUSPEND:
++ rh_dbg("ClearPortFeature: suspend\n");
++ break;
++ case USB_PORT_FEAT_POWER:
++ rh_dbg("ClearPortFeature: power\n");
++ break;
++
++ case USB_PORT_FEAT_C_ENABLE:
++ rh_dbg("ClearPortFeature: c_enable\n");
++ goto clear;
++ case USB_PORT_FEAT_C_SUSPEND:
++ rh_dbg("ClearPortFeature: c_suspend\n");
++ goto clear;
++ case USB_PORT_FEAT_C_CONNECTION:
++ rh_dbg("ClearPortFeature: c_connection\n");
++ goto clear;
++ case USB_PORT_FEAT_C_OVER_CURRENT:
++ rh_dbg("ClearPortFeature: c_over_current\n");
++ goto clear;
++ case USB_PORT_FEAT_C_RESET:
++ rh_dbg("ClearPortFeature: c_reset\n");
++ goto clear;
++ clear:
++ rh.wPortChange[bPort] &= ~(1 << (wFeature - 16));
++ break;
++ default:
++ rh_dbg("ClearPortFeature: unknown feature\n");
++ return -1;
++ }
++ return 0;
++}
++
++
++#ifdef CONFIG_PM
++/* Handle a suspend request for the root hub (called from hcd_driver) */
++static int rh_suspend_request(struct usb_hcd *hcd)
++{
++ return 0; /* no-op for now */
++}
++
++/* Handle a resume request for the root hub (called from hcd_driver) */
++static int rh_resume_request(struct usb_hcd *hcd)
++{
++ return 0; /* no-op for now */
++}
++#endif /* CONFIG_PM */
++
++
++
++/* Wrapper function for workaround port disable registers in USB controller */
++static void rh_disable_port(unsigned int port) {
++ volatile int timeout = 10000;
++ volatile char* usb_portx_disable;
++ switch(port) {
++ case 0:
++ usb_portx_disable = R_USB_PORT1_DISABLE;
++ break;
++ case 1:
++ usb_portx_disable = R_USB_PORT2_DISABLE;
++ break;
++ default:
++ /* Invalid port index */
++ return;
++ }
++ /* Set disable flag in special register */
++ *usb_portx_disable = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
++ /* Wait until not enabled anymore */
++ while((rh.wPortStatusPrev[port] &
++ IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for port %d to become disabled\n", port);
++ }
++ /* clear disable flag in special register */
++ *usb_portx_disable = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
++ rh_info("Physical port %d disabled\n", port+1);
++}
++
++
++/******************************************************************/
++/* Transfer Controller (TC) functions */
++/******************************************************************/
++
++/* FIXME: Should RX_BUF_SIZE be a config option, or maybe we should adjust it
++ dynamically?
++ To adjust it dynamically we would have to get an interrupt when we reach
++ the end of the rx descriptor list, or when we get close to the end, and
++ then allocate more descriptors. */
++#define NBR_OF_RX_DESC 512
++#define RX_DESC_BUF_SIZE 1024
++#define RX_BUF_SIZE (NBR_OF_RX_DESC * RX_DESC_BUF_SIZE)
++
++
++/* Local variables for Transfer Controller */
++/* --------------------------------------- */
++
++/* This is a circular (double-linked) list of the active urbs for each epid.
++ The head is never removed, and new urbs are linked onto the list as
++ urb_entry_t elements. Don't reference urb_list directly; use the wrapper
++ functions instead (which includes spin_locks) */
++static struct list_head urb_list[NBR_OF_EPIDS];
++
++/* Read about the need and usage of this lock in submit_ctrl_urb. */
++/* Lock for URB lists for each EPID */
++static spinlock_t urb_list_lock;
++
++/* Lock for EPID array register (R_USB_EPT_x) in Etrax */
++static spinlock_t etrax_epid_lock;
++
++/* Lock for dma8 sub0 handling */
++static spinlock_t etrax_dma8_sub0_lock;
++
++/* DMA IN cache bug. Align the DMA IN buffers to 32 bytes, i.e. a cache line.
++ Since RX_DESC_BUF_SIZE is 1024 is a multiple of 32, all rx buffers will be
++ cache aligned. */
++static volatile unsigned char RxBuf[RX_BUF_SIZE] __attribute__ ((aligned (32)));
++static volatile struct USB_IN_Desc RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));
++
++/* Pointers into RxDescList. */
++static volatile struct USB_IN_Desc *myNextRxDesc;
++static volatile struct USB_IN_Desc *myLastRxDesc;
++
++/* A zout transfer makes a memory access at the address of its buf pointer,
++ which means that setting this buf pointer to 0 will cause an access to the
++ flash. In addition to this, setting sw_len to 0 results in a 16/32 bytes
++ (depending on DMA burst size) transfer.
++ Instead, we set it to 1, and point it to this buffer. */
++static int zout_buffer[4] __attribute__ ((aligned (4)));
++
++/* Cache for allocating new EP and SB descriptors. */
++//static kmem_cache_t *usb_desc_cache;
++static struct kmem_cache *usb_desc_cache;
++
++/* Cache for the data allocated in the isoc descr top half. */
++//static kmem_cache_t *isoc_compl_cache;
++static struct kmem_cache *isoc_compl_cache;
++
++/* Cache for the data allocated when delayed finishing of URBs */
++//static kmem_cache_t *later_data_cache;
++static struct kmem_cache *later_data_cache;
++
++/* Counter to keep track of how many Isoc EP we have sat up. Used to enable
++ and disable iso_eof interrupt. We only need these interrupts when we have
++ Isoc data endpoints (consumes CPU cycles).
++ FIXME: This could be more fine granular, so this interrupt is only enabled
++ when we have a In Isoc URB not URB_ISO_ASAP flaged queued. */
++static int isoc_epid_counter;
++
++/* Protecting wrapper functions for R_USB_EPT_x */
++/* -------------------------------------------- */
++static inline void etrax_epid_set(__u8 index, __u32 data) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ *R_USB_EPT_DATA = data;
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline void etrax_epid_clear_error(__u8 index) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ *R_USB_EPT_DATA &=
++ ~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
++ IO_MASK(R_USB_EPT_DATA, error_count_out) |
++ IO_MASK(R_USB_EPT_DATA, error_code));
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline void etrax_epid_set_toggle(__u8 index, __u8 dirout,
++ __u8 toggle) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ if(dirout) {
++ *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out);
++ *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle);
++ } else {
++ *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in);
++ *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle);
++ }
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline __u8 etrax_epid_get_toggle(__u8 index, __u8 dirout) {
++ unsigned long flags;
++ __u8 toggle;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ if (dirout) {
++ toggle = IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA);
++ } else {
++ toggle = IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA);
++ }
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++ return toggle;
++}
++
++
++static inline __u32 etrax_epid_get(__u8 index) {
++ unsigned long flags;
++ __u32 data;
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++ nop();
++ data = *R_USB_EPT_DATA;
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++ return data;
++}
++
++
++
++
++/* Main functions for Transfer Controller */
++/* -------------------------------------- */
++
++/* Init structs, memories and lists used by Transfer Controller */
++int tc_init(struct usb_hcd *hcd) {
++ int i;
++ /* Clear software state info for all epids */
++ memset(epid_state, 0, sizeof(struct etrax_epid) * NBR_OF_EPIDS);
++
++ /* Set Invalid and Dummy as being in use and disabled */
++ epid_state[INVALID_EPID].inuse = 1;
++ epid_state[DUMMY_EPID].inuse = 1;
++ epid_state[INVALID_EPID].disabled = 1;
++ epid_state[DUMMY_EPID].disabled = 1;
++
++ /* Clear counter for how many Isoc epids we have sat up */
++ isoc_epid_counter = 0;
++
++ /* Initialize the urb list by initiating a head for each list.
++ Also reset list hodling active URB for each epid */
++ for (i = 0; i < NBR_OF_EPIDS; i++) {
++ INIT_LIST_HEAD(&urb_list[i]);
++ activeUrbList[i] = NULL;
++ }
++
++ /* Init lock for URB lists */
++ spin_lock_init(&urb_list_lock);
++ /* Init lock for Etrax R_USB_EPT register */
++ spin_lock_init(&etrax_epid_lock);
++ /* Init lock for Etrax dma8 sub0 handling */
++ spin_lock_init(&etrax_dma8_sub0_lock);
++
++ /* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */
++
++ /* Note that we specify sizeof(struct USB_EP_Desc) as the size, but also
++ allocate SB descriptors from this cache. This is ok since
++ sizeof(struct USB_EP_Desc) == sizeof(struct USB_SB_Desc). */
++// usb_desc_cache = kmem_cache_create("usb_desc_cache",
++// sizeof(struct USB_EP_Desc), 0,
++// SLAB_HWCACHE_ALIGN, 0, 0);
++ usb_desc_cache = kmem_cache_create(
++ "usb_desc_cache",
++ sizeof(struct USB_EP_Desc),
++ 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL);
++ if(usb_desc_cache == NULL) {
++ return -ENOMEM;
++ }
++
++ /* Create slab cache for speedy allocation of memory for isoc bottom-half
++ interrupt handling */
++// isoc_compl_cache =
++// kmem_cache_create("isoc_compl_cache",
++// sizeof(struct crisv10_isoc_complete_data),
++// 0, SLAB_HWCACHE_ALIGN, 0, 0);
++ isoc_compl_cache = kmem_cache_create(
++ "isoc_compl_cache",
++ sizeof(struct crisv10_isoc_complete_data),
++ 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL
++ );
++
++ if(isoc_compl_cache == NULL) {
++ return -ENOMEM;
++ }
++
++ /* Create slab cache for speedy allocation of memory for later URB finish
++ struct */
++// later_data_cache =
++// kmem_cache_create("later_data_cache",
++// sizeof(struct urb_later_data),
++// 0, SLAB_HWCACHE_ALIGN, 0, 0);
++
++ later_data_cache = kmem_cache_create(
++ "later_data_cache",
++ sizeof(struct urb_later_data),
++ 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL
++ );
++
++ if(later_data_cache == NULL) {
++ return -ENOMEM;
++ }
++
++
++ /* Initiate the bulk start timer. */
++ init_timer(&bulk_start_timer);
++ bulk_start_timer.expires = jiffies + BULK_START_TIMER_INTERVAL;
++ bulk_start_timer.function = tc_bulk_start_timer_func;
++ add_timer(&bulk_start_timer);
++
++
++ /* Initiate the bulk eot timer. */
++ init_timer(&bulk_eot_timer);
++ bulk_eot_timer.expires = jiffies + BULK_EOT_TIMER_INTERVAL;
++ bulk_eot_timer.function = tc_bulk_eot_timer_func;
++ bulk_eot_timer.data = (unsigned long)hcd;
++ add_timer(&bulk_eot_timer);
++
++ return 0;
++}
++
++/* Uninitialize all resources used by Transfer Controller */
++void tc_destroy(void) {
++
++ /* Destroy all slab cache */
++ kmem_cache_destroy(usb_desc_cache);
++ kmem_cache_destroy(isoc_compl_cache);
++ kmem_cache_destroy(later_data_cache);
++
++ /* Remove timers */
++ del_timer(&bulk_start_timer);
++ del_timer(&bulk_eot_timer);
++}
++
++static void restart_dma8_sub0(void) {
++ unsigned long flags;
++ spin_lock_irqsave(&etrax_dma8_sub0_lock, flags);
++ /* Verify that the dma is not running */
++ if ((*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd)) == 0) {
++ struct USB_EP_Desc *ep = (struct USB_EP_Desc *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
++ while (DUMMY_EPID == IO_EXTRACT(USB_EP_command, epid, ep->command)) {
++ ep = (struct USB_EP_Desc *)phys_to_virt(ep->next);
++ }
++ /* Advance the DMA to the next EP descriptor that is not a DUMMY_EPID.
++ * ep->next is already a physical address. virt_to_phys is needed, see
++ * http://mhonarc.axis.se/dev-etrax/msg08630.html
++ */
++ //*R_DMA_CH8_SUB0_EP = ep->next;
++ *R_DMA_CH8_SUB0_EP = virt_to_phys(ep);
++ /* Restart the DMA */
++ *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
++ }
++ spin_unlock_irqrestore(&etrax_dma8_sub0_lock, flags);
++}
++
++/* queue an URB with the transfer controller (called from hcd_driver) */
++//static int tc_urb_enqueue(struct usb_hcd *hcd,
++// struct usb_host_endpoint *ep,
++// struct urb *urb,
++// gfp_t mem_flags) {
++static int tc_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
++{
++ int epid;
++ int retval;
++// int bustime = 0;
++ int maxpacket;
++ unsigned long flags;
++ struct crisv10_urb_priv *urb_priv;
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ DBFENTER;
++
++ if(!(crisv10_hcd->running)) {
++ /* The USB Controller is not running, probably because no device is
++ attached. No idea to enqueue URBs then */
++ tc_warn("Rejected enqueueing of URB:0x%x because no dev attached\n",
++ (unsigned int)urb);
++ return -ENOENT;
++ }
++
++ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
++
++ /* hinko ignore usb_pipeisoc */
++#if 0
++ /* Special case check for In Isoc transfers. Specification states that each
++ In Isoc transfer consists of one packet and therefore it should fit into
++ the transfer-buffer of an URB.
++ We do the check here to be sure (an invalid scenario can be produced with
++ parameters to the usbtest suite) */
++ if(usb_pipeisoc(urb->pipe) && usb_pipein(urb->pipe) &&
++ (urb->transfer_buffer_length < maxpacket)) {
++ tc_err("Submit In Isoc URB with buffer length:%d to pipe with maxpacketlen: %d\n", urb->transfer_buffer_length, maxpacket);
++ return -EMSGSIZE;
++ }
++
++ /* Check if there is enough bandwidth for periodic transfer */
++ if(usb_pipeint(urb->pipe) || usb_pipeisoc(urb->pipe)) {
++ /* only check (and later claim) if not already claimed */
++ if (urb->bandwidth == 0) {
++ bustime = usb_check_bandwidth(urb->dev, urb);
++ if (bustime < 0) {
++ tc_err("Not enough periodic bandwidth\n");
++ return -ENOSPC;
++ }
++ }
++ }
++#endif
++
++ /* Check if there is a epid for URBs destination, if not this function
++ set up one. */
++ //epid = tc_setup_epid(ep, urb, mem_flags);
++ epid = tc_setup_epid(urb, mem_flags);
++ if (epid < 0) {
++ tc_err("Failed setup epid:%d for URB:0x%x\n", epid, (unsigned int)urb);
++ DBFEXIT;
++ return -ENOMEM;
++ }
++
++ if(urb == activeUrbList[epid]) {
++ tc_err("Resubmition of allready active URB:0x%x\n", (unsigned int)urb);
++ return -ENXIO;
++ }
++
++ if(urb_list_entry(urb, epid)) {
++ tc_err("Resubmition of allready queued URB:0x%x\n", (unsigned int)urb);
++ return -ENXIO;
++ }
++
++ /* If we actively have flaged endpoint as disabled then refuse submition */
++ if(epid_state[epid].disabled) {
++ return -ENOENT;
++ }
++
++ /* Allocate and init HC-private data for URB */
++ if(urb_priv_create(hcd, urb, epid, mem_flags) != 0) {
++ DBFEXIT;
++ return -ENOMEM;
++ }
++ urb_priv = urb->hcpriv;
++
++ tc_dbg("Enqueue URB:0x%x[%d] epid:%d (%s) bufflen:%d\n",
++ (unsigned int)urb, urb_priv->urb_num, epid,
++ pipe_to_str(urb->pipe), urb->transfer_buffer_length);
++
++ /* Create and link SBs required for this URB */
++ retval = create_sb_for_urb(urb, mem_flags);
++ if(retval != 0) {
++ tc_err("Failed to create SBs for URB:0x%x[%d]\n", (unsigned int)urb,
++ urb_priv->urb_num);
++ urb_priv_free(hcd, urb);
++ DBFEXIT;
++ return retval;
++ }
++
++ /* Init intr EP pool if this URB is a INTR transfer. This pool is later
++ used when inserting EPs in the TxIntrEPList. We do the alloc here
++ so we can't run out of memory later */
++ if(usb_pipeint(urb->pipe)) {
++ retval = init_intr_urb(urb, mem_flags);
++ if(retval != 0) {
++ tc_warn("Failed to init Intr URB\n");
++ urb_priv_free(hcd, urb);
++ DBFEXIT;
++ return retval;
++ }
++ }
++
++ /* Disable other access when inserting USB */
++
++ /* BUG on sleeping inside int disabled if using local_irq_save/local_irq_restore
++ * her - because urb_list_add() and tc_dma_process_queue() save irqs again !??!
++ */
++// local_irq_save(flags);
++
++ /* hinko ignore usb_pipeisoc */
++#if 0
++ /* Claim bandwidth, if needed */
++ if(bustime) {
++ usb_claim_bandwidth(urb->dev, urb, bustime, 0);
++ }
++
++ /* Add URB to EP queue */
++ urb_list_add(urb, epid, mem_flags);
++
++ if(usb_pipeisoc(urb->pipe)) {
++ /* Special processing of Isoc URBs. */
++ tc_dma_process_isoc_urb(urb);
++ } else {
++ /* Process EP queue for rest of the URB types (Bulk, Ctrl, Intr) */
++ tc_dma_process_queue(epid);
++ }
++#endif
++ /* Add URB to EP queue */
++ urb_list_add(urb, epid, mem_flags);
++
++ /*hinko link/unlink urb -> ep */
++ spin_lock_irqsave(&crisv10_hcd->lock, flags);
++ //spin_lock(&crisv10_hcd->lock);
++ retval = usb_hcd_link_urb_to_ep(hcd, urb);
++ if (retval) {
++ spin_unlock_irqrestore(&crisv10_hcd->lock, flags);
++ tc_warn("Failed to link urb to ep\n");
++ urb_priv_free(hcd, urb);
++ DBFEXIT;
++ return retval;
++ }
++ spin_unlock_irqrestore(&crisv10_hcd->lock, flags);
++ //spin_unlock(&crisv10_hcd->lock);
++
++ /* Process EP queue for rest of the URB types (Bulk, Ctrl, Intr) */
++ tc_dma_process_queue(epid);
++
++// local_irq_restore(flags);
++
++ DBFEXIT;
++ return 0;
++}
++
++/* remove an URB from the transfer controller queues (called from hcd_driver)*/
++//static int tc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
++static int tc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
++{
++ struct crisv10_urb_priv *urb_priv;
++ unsigned long flags;
++ int epid;
++
++ DBFENTER;
++ /* Disable interrupts here since a descriptor interrupt for the isoc epid
++ will modify the sb list. This could possibly be done more granular, but
++ urb_dequeue should not be used frequently anyway.
++ */
++ local_irq_save(flags);
++
++ urb_priv = urb->hcpriv;
++
++ if (!urb_priv) {
++ /* This happens if a device driver calls unlink on an urb that
++ was never submitted (lazy driver) or if the urb was completed
++ while dequeue was being called. */
++ tc_warn("Dequeing of not enqueued URB:0x%x\n", (unsigned int)urb);
++ local_irq_restore(flags);
++ return 0;
++ }
++ epid = urb_priv->epid;
++
++ tc_warn("Dequeing %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++ (urb == activeUrbList[epid]) ? "active" : "queued",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), epid, urb->status,
++ (urb_priv->later_data) ? "later-sched" : "");
++
++ /* For Bulk, Ctrl and Intr are only one URB active at a time. So any URB
++ that isn't active can be dequeued by just removing it from the queue */
++ if(usb_pipebulk(urb->pipe) || usb_pipecontrol(urb->pipe) ||
++ usb_pipeint(urb->pipe)) {
++
++ /* Check if URB haven't gone further than the queue */
++ if(urb != activeUrbList[epid]) {
++ ASSERT(urb_priv->later_data == NULL);
++ tc_warn("Dequeing URB:0x%x[%d] (%s %s epid:%d) from queue"
++ " (not active)\n", (unsigned int)urb, urb_priv->urb_num,
++ str_dir(urb->pipe), str_type(urb->pipe), epid);
++
++ /* Finish the URB with error status from USB core */
++ tc_finish_urb(hcd, urb, urb->status);
++ local_irq_restore(flags);
++ return 0;
++ }
++ }
++
++ /* Set URB status to Unlink for handling when interrupt comes. */
++ urb_priv->urb_state = UNLINK;
++
++ /* Differentiate dequeing of Bulk and Ctrl from Isoc and Intr */
++ switch(usb_pipetype(urb->pipe)) {
++ case PIPE_BULK:
++ /* Check if EP still is enabled */
++ if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ /* Kicking dummy list out of the party. */
++ TxBulkEPList[epid].next = virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
++ break;
++ case PIPE_CONTROL:
++ /* Check if EP still is enabled */
++ if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ break;
++ case PIPE_ISOCHRONOUS:
++ /* Disabling, busy-wait and unlinking of Isoc SBs will be done in
++ finish_isoc_urb(). Because there might the case when URB is dequeued
++ but there are other valid URBs waiting */
++
++ /* Check if In Isoc EP still is enabled */
++ if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ break;
++ case PIPE_INTERRUPT:
++ /* Special care is taken for interrupt URBs. EPs are unlinked in
++ tc_finish_urb */
++ break;
++ default:
++ break;
++ }
++
++ /* Asynchronous unlink, finish the URB later from scheduled or other
++ event (data finished, error) */
++ tc_finish_urb_later(hcd, urb, urb->status);
++
++ local_irq_restore(flags);
++ DBFEXIT;
++ return 0;
++}
++
++
++static void tc_sync_finish_epid(struct usb_hcd *hcd, int epid) {
++ volatile int timeout = 10000;
++ struct urb* urb;
++ struct crisv10_urb_priv* urb_priv;
++ unsigned long flags;
++
++ volatile struct USB_EP_Desc *first_ep; /* First EP in the list. */
++ volatile struct USB_EP_Desc *curr_ep; /* Current EP, the iterator. */
++ volatile struct USB_EP_Desc *next_ep; /* The EP after current. */
++
++ int type = epid_state[epid].type;
++
++ /* Setting this flag will cause enqueue() to return -ENOENT for new
++ submitions on this endpoint and finish_urb() wont process queue further */
++ epid_state[epid].disabled = 1;
++
++ switch(type) {
++ case PIPE_BULK:
++ /* Check if EP still is enabled */
++ if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ tc_warn("sync_finish: Disabling EP for epid:%d\n", epid);
++
++ /* Do busy-wait until DMA not using this EP descriptor anymore */
++ while((*R_DMA_CH8_SUB0_EP ==
++ virt_to_phys(&TxBulkEPList[epid])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Bulk to leave EP for"
++ " epid:%d\n", epid);
++ }
++ }
++ break;
++
++ case PIPE_CONTROL:
++ /* Check if EP still is enabled */
++ if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ /* The EP was enabled, disable it. */
++ TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++ tc_warn("sync_finish: Disabling EP for epid:%d\n", epid);
++
++ /* Do busy-wait until DMA not using this EP descriptor anymore */
++ while((*R_DMA_CH8_SUB1_EP ==
++ virt_to_phys(&TxCtrlEPList[epid])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Ctrl to leave EP for"
++ " epid:%d\n", epid);
++ }
++ }
++ break;
++
++ case PIPE_INTERRUPT:
++ local_irq_save(flags);
++ /* Disable all Intr EPs belonging to epid */
++ first_ep = &TxIntrEPList[0];
++ curr_ep = first_ep;
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
++ /* Disable EP */
++ next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != first_ep);
++
++ local_irq_restore(flags);
++ break;
++
++ case PIPE_ISOCHRONOUS:
++ /* Check if EP still is enabled */
++ if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ tc_warn("sync_finish: Disabling Isoc EP for epid:%d\n", epid);
++ /* The EP was enabled, disable it. */
++ TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++
++ while((*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Isoc to leave EP for"
++ " epid:%d\n", epid);
++ }
++ }
++ break;
++ }
++
++ local_irq_save(flags);
++
++ /* Finish if there is active URB for this endpoint */
++ if(activeUrbList[epid] != NULL) {
++ urb = activeUrbList[epid];
++ urb_priv = urb->hcpriv;
++ ASSERT(urb_priv);
++ tc_warn("Sync finish %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++ (urb == activeUrbList[epid]) ? "active" : "queued",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), epid, urb->status,
++ (urb_priv->later_data) ? "later-sched" : "");
++
++ tc_finish_urb(hcd, activeUrbList[epid], -ENOENT);
++ ASSERT(activeUrbList[epid] == NULL);
++ }
++
++ /* Finish any queued URBs for this endpoint. There won't be any resubmitions
++ because epid_disabled causes enqueue() to fail for this endpoint */
++ while((urb = urb_list_first(epid)) != NULL) {
++ urb_priv = urb->hcpriv;
++ ASSERT(urb_priv);
++
++ tc_warn("Sync finish %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++ (urb == activeUrbList[epid]) ? "active" : "queued",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), epid, urb->status,
++ (urb_priv->later_data) ? "later-sched" : "");
++
++ tc_finish_urb(hcd, urb, -ENOENT);
++ }
++ epid_state[epid].disabled = 0;
++ local_irq_restore(flags);
++}
++
++/* free resources associated with an endpoint (called from hcd_driver) */
++static void tc_endpoint_disable(struct usb_hcd *hcd,
++ struct usb_host_endpoint *ep) {
++ DBFENTER;
++ /* Only free epid if it has been allocated. We get two endpoint_disable
++ requests for ctrl endpoints so ignore the second one */
++ if(ep->hcpriv != NULL) {
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++ int epid = ep_priv->epid;
++ tc_warn("endpoint_disable ep:0x%x ep-priv:0x%x (%s) (epid:%d freed)\n",
++ (unsigned int)ep, (unsigned int)ep->hcpriv,
++ endpoint_to_str(&(ep->desc)), epid);
++
++ tc_sync_finish_epid(hcd, epid);
++
++ ASSERT(activeUrbList[epid] == NULL);
++ ASSERT(list_empty(&urb_list[epid]));
++
++ tc_free_epid(ep);
++ } else {
++ tc_dbg("endpoint_disable ep:0x%x ep-priv:0x%x (%s)\n", (unsigned int)ep,
++ (unsigned int)ep->hcpriv, endpoint_to_str(&(ep->desc)));
++ }
++ DBFEXIT;
++}
++
++//static void tc_finish_urb_later_proc(void *data) {
++static void tc_finish_urb_later_proc(struct work_struct *work) {
++ unsigned long flags;
++ //struct urb_later_data* uld = (struct urb_later_data*)data;
++ struct urb_later_data* uld = container_of(work, struct urb_later_data, ws.work);
++ local_irq_save(flags);
++ if(uld->urb == NULL) {
++ late_dbg("Later finish of URB = NULL (allready finished)\n");
++ } else {
++ struct crisv10_urb_priv* urb_priv = uld->urb->hcpriv;
++ ASSERT(urb_priv);
++ if(urb_priv->urb_num == uld->urb_num) {
++ late_dbg("Later finish of URB:0x%x[%d]\n", (unsigned int)(uld->urb),
++ urb_priv->urb_num);
++ if(uld->status != uld->urb->status) {
++ errno_dbg("Later-finish URB with status:%d, later-status:%d\n",
++ uld->urb->status, uld->status);
++ }
++ if(uld != urb_priv->later_data) {
++ panic("Scheduled uld not same as URBs uld\n");
++ }
++ tc_finish_urb(uld->hcd, uld->urb, uld->status);
++ } else {
++ late_warn("Ignoring later finish of URB:0x%x[%d]"
++ ", urb_num doesn't match current URB:0x%x[%d]",
++ (unsigned int)(uld->urb), uld->urb_num,
++ (unsigned int)(uld->urb), urb_priv->urb_num);
++ }
++ }
++ local_irq_restore(flags);
++ kmem_cache_free(later_data_cache, uld);
++}
++
++static void tc_finish_urb_later(struct usb_hcd *hcd, struct urb *urb,
++ int status) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ struct urb_later_data* uld;
++
++ ASSERT(urb_priv);
++
++ if(urb_priv->later_data != NULL) {
++ /* Later-finish allready scheduled for this URB, just update status to
++ return when finishing later */
++ errno_dbg("Later-finish schedule change URB status:%d with new"
++ " status:%d\n", urb_priv->later_data->status, status);
++
++ urb_priv->later_data->status = status;
++ return;
++ }
++
++ uld = kmem_cache_alloc(later_data_cache, GFP_ATOMIC);
++ ASSERT(uld);
++
++ uld->hcd = hcd;
++ uld->urb = urb;
++ uld->urb_num = urb_priv->urb_num;
++ uld->status = status;
++
++ //INIT_WORK(&uld->ws, tc_finish_urb_later_proc, uld);
++ INIT_DELAYED_WORK(&uld->ws, tc_finish_urb_later_proc);
++ urb_priv->later_data = uld;
++
++ /* Schedule the finishing of the URB to happen later */
++ schedule_delayed_work(&uld->ws, LATER_TIMER_DELAY);
++}
++
++ /* hinko ignore usb_pipeisoc */
++#if 0
++static void tc_finish_isoc_urb(struct usb_hcd *hcd, struct urb *urb,
++ int status);
++#endif
++
++static void tc_finish_urb(struct usb_hcd *hcd, struct urb *urb, int status) {
++ struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ int epid;
++ char toggle;
++ int urb_num;
++ unsigned long flags;
++
++ DBFENTER;
++ ASSERT(urb_priv != NULL);
++ epid = urb_priv->epid;
++ urb_num = urb_priv->urb_num;
++
++ if(urb != activeUrbList[epid]) {
++ if(urb_list_entry(urb, epid)) {
++ /* Remove this URB from the list. Only happens when URB are finished
++ before having been processed (dequeing) */
++ urb_list_del(urb, epid);
++ } else {
++ tc_warn("Finishing of URB:0x%x[%d] neither active or in queue for"
++ " epid:%d\n", (unsigned int)urb, urb_num, epid);
++ }
++ }
++
++ /* Cancel any pending later-finish of this URB */
++ if(urb_priv->later_data) {
++ urb_priv->later_data->urb = NULL;
++ }
++
++ /* For an IN pipe, we always set the actual length, regardless of whether
++ there was an error or not (which means the device driver can use the data
++ if it wants to). */
++ if(usb_pipein(urb->pipe)) {
++ urb->actual_length = urb_priv->rx_offset;
++ } else {
++ /* Set actual_length for OUT urbs also; the USB mass storage driver seems
++ to want that. */
++ if (status == 0 && urb->status == -EINPROGRESS) {
++ urb->actual_length = urb->transfer_buffer_length;
++ } else {
++ /* We wouldn't know of any partial writes if there was an error. */
++ urb->actual_length = 0;
++ }
++ }
++
++
++ /* URB status mangling */
++ if(urb->status == -EINPROGRESS) {
++ /* The USB core hasn't changed the status, let's set our finish status */
++ urb->status = status;
++
++ if ((status == 0) && (urb->transfer_flags & URB_SHORT_NOT_OK) &&
++ usb_pipein(urb->pipe) &&
++ (urb->actual_length != urb->transfer_buffer_length)) {
++ /* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's
++ max length) is to be treated as an error. */
++ errno_dbg("Finishing URB:0x%x[%d] with SHORT_NOT_OK flag and short"
++ " data:%d\n", (unsigned int)urb, urb_num,
++ urb->actual_length);
++ urb->status = -EREMOTEIO;
++ }
++
++ if(urb_priv->urb_state == UNLINK) {
++ /* URB has been requested to be unlinked asynchronously */
++ urb->status = -ECONNRESET;
++ errno_dbg("Fixing unlink status of URB:0x%x[%d] to:%d\n",
++ (unsigned int)urb, urb_num, urb->status);
++ }
++ } else {
++ /* The USB Core wants to signal some error via the URB, pass it through */
++ }
++
++ /* hinko ignore usb_pipeisoc */
++#if 0
++ /* use completely different finish function for Isoc URBs */
++ if(usb_pipeisoc(urb->pipe)) {
++ tc_finish_isoc_urb(hcd, urb, status);
++ return;
++ }
++#endif
++
++ /* Do special unlinking of EPs for Intr traffic */
++ if(usb_pipeint(urb->pipe)) {
++ tc_dma_unlink_intr_urb(urb);
++ }
++
++ /* hinko ignore usb_pipeisoc */
++#if 0
++ /* Release allocated bandwidth for periodic transfers */
++ if(usb_pipeint(urb->pipe) || usb_pipeisoc(urb->pipe))
++ usb_release_bandwidth(urb->dev, urb, 0);
++#endif
++
++ /* This URB is active on EP */
++ if(urb == activeUrbList[epid]) {
++ /* We need to fiddle with the toggle bits because the hardware doesn't do
++ it for us. */
++ toggle = etrax_epid_get_toggle(epid, usb_pipeout(urb->pipe));
++ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++ usb_pipeout(urb->pipe), toggle);
++
++ /* Checks for Ctrl and Bulk EPs */
++ switch(usb_pipetype(urb->pipe)) {
++ case PIPE_BULK:
++ /* Check so Bulk EP realy is disabled before finishing active URB */
++ ASSERT((TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) ==
++ IO_STATE(USB_EP_command, enable, no));
++ /* Disable sub-pointer for EP to avoid next tx_interrupt() to
++ process Bulk EP. */
++ TxBulkEPList[epid].sub = 0;
++ /* No need to wait for the DMA before changing the next pointer.
++ The modulo NBR_OF_EPIDS isn't actually necessary, since we will never use
++ the last one (INVALID_EPID) for actual traffic. */
++ TxBulkEPList[epid].next =
++ virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
++ break;
++ case PIPE_CONTROL:
++ /* Check so Ctrl EP realy is disabled before finishing active URB */
++ ASSERT((TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) ==
++ IO_STATE(USB_EP_command, enable, no));
++ /* Disable sub-pointer for EP to avoid next tx_interrupt() to
++ process Ctrl EP. */
++ TxCtrlEPList[epid].sub = 0;
++ break;
++ }
++ }
++
++ /* Free HC-private URB data*/
++ urb_priv_free(hcd, urb);
++
++ if(urb->status) {
++ errno_dbg("finish_urb (URB:0x%x[%d] %s %s) (data:%d) status:%d\n",
++ (unsigned int)urb, urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb->actual_length, urb->status);
++ } else {
++ tc_dbg("finish_urb (URB:0x%x[%d] %s %s) (data:%d) status:%d\n",
++ (unsigned int)urb, urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb->actual_length, urb->status);
++ }
++
++ /* If we just finished an active URB, clear active pointer. */
++ if (urb == activeUrbList[epid]) {
++ /* Make URB not active on EP anymore */
++ activeUrbList[epid] = NULL;
++
++ if(urb->status == 0) {
++ /* URB finished sucessfully, process queue to see if there are any more
++ URBs waiting before we call completion function.*/
++ if(crisv10_hcd->running) {
++ /* Only process queue if USB controller is running */
++ tc_dma_process_queue(epid);
++ } else {
++ tc_warn("No processing of queue for epid:%d, USB Controller not"
++ " running\n", epid);
++ }
++ }
++ }
++
++ /* Hand the URB from HCD to its USB device driver, using its completion
++ functions */
++// usb_hcd_giveback_urb (hcd, urb);
++ /**
++ * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
++ * @hcd: host controller to which @urb was submitted
++ * @urb: URB being unlinked
++ *
++ * Host controller drivers should call this routine before calling
++ * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and
++ * interrupts must be disabled. The actions carried out here are required
++ * for URB completion.
++ */
++
++ /*hinko link/unlink urb -> ep */
++ //spin_lock(&crisv10_hcd->lock);
++ spin_lock_irqsave(&crisv10_hcd->lock, flags);
++ usb_hcd_unlink_urb_from_ep(hcd, urb);
++ usb_hcd_giveback_urb(hcd, urb, status);
++ //spin_unlock(&crisv10_hcd->lock);
++ spin_unlock_irqrestore(&crisv10_hcd->lock, flags);
++
++ /* Check the queue once more if the URB returned with error, because we
++ didn't do it before the completion function because the specification
++ states that the queue should not restart until all it's unlinked
++ URBs have been fully retired, with the completion functions run */
++ if(crisv10_hcd->running) {
++ /* Only process queue if USB controller is running */
++ tc_dma_process_queue(epid);
++ } else {
++ tc_warn("No processing of queue for epid:%d, USB Controller not running\n",
++ epid);
++ }
++
++ DBFEXIT;
++}
++
++ /* hinko ignore usb_pipeisoc */
++#if 0
++static void tc_finish_isoc_urb(struct usb_hcd *hcd, struct urb *urb,
++ int status) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ int epid, i;
++ volatile int timeout = 10000;
++
++ ASSERT(urb_priv);
++ epid = urb_priv->epid;
++
++ ASSERT(usb_pipeisoc(urb->pipe));
++
++ /* Set that all isoc packets have status and length set before
++ completing the urb. */
++ for (i = urb_priv->isoc_packet_counter; i < urb->number_of_packets; i++){
++ urb->iso_frame_desc[i].actual_length = 0;
++ urb->iso_frame_desc[i].status = -EPROTO;
++ }
++
++ /* Check if the URB is currently active (done or error) */
++ if(urb == activeUrbList[epid]) {
++ /* Check if there are another In Isoc URB queued for this epid */
++ if (!list_empty(&urb_list[epid])&& !epid_state[epid].disabled) {
++ /* Move it from queue to active and mark it started so Isoc transfers
++ won't be interrupted.
++ All Isoc URBs data transfers are already added to DMA lists so we
++ don't have to insert anything in DMA lists here. */
++ activeUrbList[epid] = urb_list_first(epid);
++ ((struct crisv10_urb_priv *)(activeUrbList[epid]->hcpriv))->urb_state =
++ STARTED;
++ urb_list_del(activeUrbList[epid], epid);
++
++ if(urb->status) {
++ errno_dbg("finish_isoc_urb (URB:0x%x[%d] %s %s) (%d of %d packets)"
++ " status:%d, new waiting URB:0x%x[%d]\n",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb_priv->isoc_packet_counter,
++ urb->number_of_packets, urb->status,
++ (unsigned int)activeUrbList[epid],
++ ((struct crisv10_urb_priv *)(activeUrbList[epid]->hcpriv))->urb_num);
++ }
++
++ } else { /* No other URB queued for this epid */
++ if(urb->status) {
++ errno_dbg("finish_isoc_urb (URB:0x%x[%d] %s %s) (%d of %d packets)"
++ " status:%d, no new URB waiting\n",
++ (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++ str_type(urb->pipe), urb_priv->isoc_packet_counter,
++ urb->number_of_packets, urb->status);
++ }
++
++ /* Check if EP is still enabled, then shut it down. */
++ if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ isoc_dbg("Isoc EP enabled for epid:%d, disabling it\n", epid);
++
++ /* Should only occur for In Isoc EPs where SB isn't consumed. */
++ ASSERT(usb_pipein(urb->pipe));
++
++ /* Disable it and wait for it to stop */
++ TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++
++ /* Ah, the luxury of busy-wait. */
++ while((*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid])) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Isoc to leave EP for epid:%d\n", epid);
++ }
++ }
++
++ /* Unlink SB to say that epid is finished. */
++ TxIsocEPList[epid].sub = 0;
++ TxIsocEPList[epid].hw_len = 0;
++
++ /* No URB active for EP anymore */
++ activeUrbList[epid] = NULL;
++ }
++ } else { /* Finishing of not active URB (queued up with SBs thought) */
++ isoc_warn("finish_isoc_urb (URB:0x%x %s) (%d of %d packets) status:%d,"
++ " SB queued but not active\n",
++ (unsigned int)urb, str_dir(urb->pipe),
++ urb_priv->isoc_packet_counter, urb->number_of_packets,
++ urb->status);
++ if(usb_pipeout(urb->pipe)) {
++ /* Finishing of not yet active Out Isoc URB needs unlinking of SBs. */
++ struct USB_SB_Desc *iter_sb, *prev_sb, *next_sb;
++
++ iter_sb = TxIsocEPList[epid].sub ?
++ phys_to_virt(TxIsocEPList[epid].sub) : 0;
++ prev_sb = 0;
++
++ /* SB that is linked before this URBs first SB */
++ while (iter_sb && (iter_sb != urb_priv->first_sb)) {
++ prev_sb = iter_sb;
++ iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
++ }
++
++ if (iter_sb == 0) {
++ /* Unlink of the URB currently being transmitted. */
++ prev_sb = 0;
++ iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
++ }
++
++ while (iter_sb && (iter_sb != urb_priv->last_sb)) {
++ iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
++ }
++
++ if (iter_sb) {
++ next_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
++ } else {
++ /* This should only happen if the DMA has completed
++ processing the SB list for this EP while interrupts
++ are disabled. */
++ isoc_dbg("Isoc urb not found, already sent?\n");
++ next_sb = 0;
++ }
++ if (prev_sb) {
++ prev_sb->next = next_sb ? virt_to_phys(next_sb) : 0;
++ } else {
++ TxIsocEPList[epid].sub = next_sb ? virt_to_phys(next_sb) : 0;
++ }
++ }
++ }
++
++ /* Free HC-private URB data*/
++ urb_priv_free(hcd, urb);
++
++ usb_release_bandwidth(urb->dev, urb, 0);
++
++ /* Hand the URB from HCD to its USB device driver, using its completion
++ functions */
++ usb_hcd_giveback_urb (hcd, urb);
++}
++#endif
++
++static __u32 urb_num = 0;
++
++/* allocate and initialize URB private data */
++static int urb_priv_create(struct usb_hcd *hcd, struct urb *urb, int epid,
++ int mem_flags) {
++ struct crisv10_urb_priv *urb_priv;
++
++ urb_priv = kmalloc(sizeof *urb_priv, mem_flags);
++ if (!urb_priv)
++ return -ENOMEM;
++ memset(urb_priv, 0, sizeof *urb_priv);
++
++ urb_priv->epid = epid;
++ urb_priv->urb_state = NOT_STARTED;
++
++ urb->hcpriv = urb_priv;
++ /* Assign URB a sequence number, and increment counter */
++ urb_priv->urb_num = urb_num;
++ urb_num++;
++ return 0;
++}
++
++/* free URB private data */
++static void urb_priv_free(struct usb_hcd *hcd, struct urb *urb) {
++ int i;
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ ASSERT(urb_priv != 0);
++
++ /* Check it has any SBs linked that needs to be freed*/
++ if(urb_priv->first_sb != NULL) {
++ struct USB_SB_Desc *next_sb, *first_sb, *last_sb;
++ int i = 0;
++ first_sb = urb_priv->first_sb;
++ last_sb = urb_priv->last_sb;
++ ASSERT(last_sb);
++ while(first_sb != last_sb) {
++ next_sb = (struct USB_SB_Desc *)phys_to_virt(first_sb->next);
++ kmem_cache_free(usb_desc_cache, first_sb);
++ first_sb = next_sb;
++ i++;
++ }
++ kmem_cache_free(usb_desc_cache, last_sb);
++ i++;
++ }
++
++ /* Check if it has any EPs in its Intr pool that also needs to be freed */
++ if(urb_priv->intr_ep_pool_length > 0) {
++ for(i = 0; i < urb_priv->intr_ep_pool_length; i++) {
++ kfree(urb_priv->intr_ep_pool[i]);
++ }
++ /*
++ tc_dbg("Freed %d EPs from URB:0x%x EP pool\n",
++ urb_priv->intr_ep_pool_length, (unsigned int)urb);
++ */
++ }
++
++ kfree(urb_priv);
++ urb->hcpriv = NULL;
++}
++
++static int ep_priv_create(struct usb_host_endpoint *ep, int mem_flags) {
++ struct crisv10_ep_priv *ep_priv;
++
++ ep_priv = kmalloc(sizeof *ep_priv, mem_flags);
++ if (!ep_priv)
++ return -ENOMEM;
++ memset(ep_priv, 0, sizeof *ep_priv);
++
++ ep->hcpriv = ep_priv;
++ return 0;
++}
++
++static void ep_priv_free(struct usb_host_endpoint *ep) {
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++ ASSERT(ep_priv);
++ kfree(ep_priv);
++ ep->hcpriv = NULL;
++}
++
++/* EPID handling functions, managing EP-list in Etrax through wrappers */
++/* ------------------------------------------------------------------- */
++
++/* Sets up a new EPID for an endpoint or returns existing if found */
++//static int tc_setup_epid(struct usb_host_endpoint *ep, struct urb *urb,
++// int mem_flags) {
++static int tc_setup_epid(struct urb *urb, int mem_flags)
++{
++ int epid;
++ char devnum, endpoint, out_traffic, slow;
++ int maxlen;
++ __u32 epid_data;
++ struct usb_host_endpoint *ep = urb->ep;
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++
++ DBFENTER;
++
++ /* Check if a valid epid already is setup for this endpoint */
++ if(ep_priv != NULL) {
++ return ep_priv->epid;
++ }
++
++ /* We must find and initiate a new epid for this urb. */
++ epid = tc_allocate_epid();
++
++ if (epid == -1) {
++ /* Failed to allocate a new epid. */
++ DBFEXIT;
++ return epid;
++ }
++
++ /* We now have a new epid to use. Claim it. */
++ epid_state[epid].inuse = 1;
++
++ /* Init private data for new endpoint */
++ if(ep_priv_create(ep, mem_flags) != 0) {
++ return -ENOMEM;
++ }
++ ep_priv = ep->hcpriv;
++ ep_priv->epid = epid;
++
++ devnum = usb_pipedevice(urb->pipe);
++ endpoint = usb_pipeendpoint(urb->pipe);
++ slow = (urb->dev->speed == USB_SPEED_LOW);
++ maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
++
++ if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
++ /* We want both IN and OUT control traffic to be put on the same
++ EP/SB list. */
++ out_traffic = 1;
++ } else {
++ out_traffic = usb_pipeout(urb->pipe);
++ }
++
++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++ epid_data = IO_STATE(R_USB_EPT_DATA_ISO, valid, yes) |
++ /* FIXME: Change any to the actual port? */
++ IO_STATE(R_USB_EPT_DATA_ISO, port, any) |
++ IO_FIELD(R_USB_EPT_DATA_ISO, max_len, maxlen) |
++ IO_FIELD(R_USB_EPT_DATA_ISO, ep, endpoint) |
++ IO_FIELD(R_USB_EPT_DATA_ISO, dev, devnum);
++ etrax_epid_iso_set(epid, epid_data);
++ } else {
++ epid_data = IO_STATE(R_USB_EPT_DATA, valid, yes) |
++ IO_FIELD(R_USB_EPT_DATA, low_speed, slow) |
++ /* FIXME: Change any to the actual port? */
++ IO_STATE(R_USB_EPT_DATA, port, any) |
++ IO_FIELD(R_USB_EPT_DATA, max_len, maxlen) |
++ IO_FIELD(R_USB_EPT_DATA, ep, endpoint) |
++ IO_FIELD(R_USB_EPT_DATA, dev, devnum);
++ etrax_epid_set(epid, epid_data);
++ }
++
++ epid_state[epid].out_traffic = out_traffic;
++ epid_state[epid].type = usb_pipetype(urb->pipe);
++
++ tc_warn("Setting up ep:0x%x epid:%d (addr:%d endp:%d max_len:%d %s %s %s)\n",
++ (unsigned int)ep, epid, devnum, endpoint, maxlen,
++ str_type(urb->pipe), out_traffic ? "out" : "in",
++ slow ? "low" : "full");
++
++ /* Enable Isoc eof interrupt if we set up the first Isoc epid */
++ if(usb_pipeisoc(urb->pipe)) {
++ isoc_epid_counter++;
++ if(isoc_epid_counter == 1) {
++ isoc_warn("Enabled Isoc eof interrupt\n");
++ *R_USB_IRQ_MASK_SET |= IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set);
++ }
++ }
++
++ DBFEXIT;
++ return epid;
++}
++
++static void tc_free_epid(struct usb_host_endpoint *ep) {
++ unsigned long flags;
++ struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++ int epid;
++ volatile int timeout = 10000;
++
++ DBFENTER;
++
++ if (ep_priv == NULL) {
++ tc_warn("Trying to free unused epid on ep:0x%x\n", (unsigned int)ep);
++ DBFEXIT;
++ return;
++ }
++
++ epid = ep_priv->epid;
++
++ /* Disable Isoc eof interrupt if we free the last Isoc epid */
++ if(epid_isoc(epid)) {
++ ASSERT(isoc_epid_counter > 0);
++ isoc_epid_counter--;
++ if(isoc_epid_counter == 0) {
++ *R_USB_IRQ_MASK_SET &= ~IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set);
++ isoc_warn("Disabled Isoc eof interrupt\n");
++ }
++ }
++
++ /* Take lock manualy instead of in epid_x_x wrappers,
++ because we need to be polling here */
++ spin_lock_irqsave(&etrax_epid_lock, flags);
++
++ *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
++ nop();
++ while((*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for epid:%d to drop hold\n", epid);
++ }
++ /* This will, among other things, set the valid field to 0. */
++ *R_USB_EPT_DATA = 0;
++ spin_unlock_irqrestore(&etrax_epid_lock, flags);
++
++ /* Free resource in software state info list */
++ epid_state[epid].inuse = 0;
++
++ /* Free private endpoint data */
++ ep_priv_free(ep);
++
++ DBFEXIT;
++}
++
++static int tc_allocate_epid(void) {
++ int i;
++ DBFENTER;
++ for (i = 0; i < NBR_OF_EPIDS; i++) {
++ if (!epid_inuse(i)) {
++ DBFEXIT;
++ return i;
++ }
++ }
++
++ tc_warn("Found no free epids\n");
++ DBFEXIT;
++ return -1;
++}
++
++
++/* Wrappers around the list functions (include/linux/list.h). */
++/* ---------------------------------------------------------- */
++static inline int __urb_list_empty(int epid) {
++ int retval;
++ retval = list_empty(&urb_list[epid]);
++ return retval;
++}
++
++/* Returns first urb for this epid, or NULL if list is empty. */
++static inline struct urb *urb_list_first(int epid) {
++ unsigned long flags;
++ struct urb *first_urb = 0;
++ spin_lock_irqsave(&urb_list_lock, flags);
++ if (!__urb_list_empty(epid)) {
++ /* Get the first urb (i.e. head->next). */
++ urb_entry_t *urb_entry = list_entry((&urb_list[epid])->next, urb_entry_t, list);
++ first_urb = urb_entry->urb;
++ }
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ return first_urb;
++}
++
++/* Adds an urb_entry last in the list for this epid. */
++static inline void urb_list_add(struct urb *urb, int epid, int mem_flags) {
++ unsigned long flags;
++ urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), mem_flags);
++ ASSERT(urb_entry);
++
++ urb_entry->urb = urb;
++ spin_lock_irqsave(&urb_list_lock, flags);
++ list_add_tail(&urb_entry->list, &urb_list[epid]);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++}
++
++/* Search through the list for an element that contains this urb. (The list
++ is expected to be short and the one we are about to delete will often be
++ the first in the list.)
++ Should be protected by spin_locks in calling function */
++static inline urb_entry_t *__urb_list_entry(struct urb *urb, int epid) {
++ struct list_head *entry;
++ struct list_head *tmp;
++ urb_entry_t *urb_entry;
++
++ list_for_each_safe(entry, tmp, &urb_list[epid]) {
++ urb_entry = list_entry(entry, urb_entry_t, list);
++ ASSERT(urb_entry);
++ ASSERT(urb_entry->urb);
++
++ if (urb_entry->urb == urb) {
++ return urb_entry;
++ }
++ }
++ return 0;
++}
++
++/* Same function as above but for global use. Protects list by spinlock */
++static inline urb_entry_t *urb_list_entry(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++ spin_lock_irqsave(&urb_list_lock, flags);
++ urb_entry = __urb_list_entry(urb, epid);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ return (urb_entry);
++}
++
++/* Delete an urb from the list. */
++static inline void urb_list_del(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++
++ /* Delete entry and free. */
++ spin_lock_irqsave(&urb_list_lock, flags);
++ urb_entry = __urb_list_entry(urb, epid);
++ ASSERT(urb_entry);
++
++ list_del(&urb_entry->list);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ kfree(urb_entry);
++}
++
++/* Move an urb to the end of the list. */
++static inline void urb_list_move_last(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++
++ spin_lock_irqsave(&urb_list_lock, flags);
++ urb_entry = __urb_list_entry(urb, epid);
++ ASSERT(urb_entry);
++
++ list_del(&urb_entry->list);
++ list_add_tail(&urb_entry->list, &urb_list[epid]);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++}
++
++/* Get the next urb in the list. */
++static inline struct urb *urb_list_next(struct urb *urb, int epid) {
++ unsigned long flags;
++ urb_entry_t *urb_entry;
++
++ spin_lock_irqsave(&urb_list_lock, flags);
++ urb_entry = __urb_list_entry(urb, epid);
++ ASSERT(urb_entry);
++
++ if (urb_entry->list.next != &urb_list[epid]) {
++ struct list_head *elem = urb_entry->list.next;
++ urb_entry = list_entry(elem, urb_entry_t, list);
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ return urb_entry->urb;
++ } else {
++ spin_unlock_irqrestore(&urb_list_lock, flags);
++ return NULL;
++ }
++}
++
++struct USB_EP_Desc* create_ep(int epid, struct USB_SB_Desc* sb_desc,
++ int mem_flags) {
++ struct USB_EP_Desc *ep_desc;
++ ep_desc = (struct USB_EP_Desc *) kmem_cache_alloc(usb_desc_cache, mem_flags);
++ if(ep_desc == NULL)
++ return NULL;
++ memset(ep_desc, 0, sizeof(struct USB_EP_Desc));
++
++ ep_desc->hw_len = 0;
++ ep_desc->command = (IO_FIELD(USB_EP_command, epid, epid) |
++ IO_STATE(USB_EP_command, enable, yes));
++ if(sb_desc == NULL) {
++ ep_desc->sub = 0;
++ } else {
++ ep_desc->sub = virt_to_phys(sb_desc);
++ }
++ return ep_desc;
++}
++
++#define TT_ZOUT 0
++#define TT_IN 1
++#define TT_OUT 2
++#define TT_SETUP 3
++
++#define CMD_EOL IO_STATE(USB_SB_command, eol, yes)
++#define CMD_INTR IO_STATE(USB_SB_command, intr, yes)
++#define CMD_FULL IO_STATE(USB_SB_command, full, yes)
++
++/* Allocation and setup of a generic SB. Used to create SETUP, OUT and ZOUT
++ SBs. Also used by create_sb_in() to avoid same allocation procedure at two
++ places */
++struct USB_SB_Desc* create_sb(struct USB_SB_Desc* sb_prev, int tt, void* data,
++ int datalen, int mem_flags) {
++ struct USB_SB_Desc *sb_desc;
++ sb_desc = (struct USB_SB_Desc*)kmem_cache_alloc(usb_desc_cache, mem_flags);
++ if(sb_desc == NULL)
++ return NULL;
++ memset(sb_desc, 0, sizeof(struct USB_SB_Desc));
++
++ sb_desc->command = IO_FIELD(USB_SB_command, tt, tt) |
++ IO_STATE(USB_SB_command, eot, yes);
++
++ sb_desc->sw_len = datalen;
++ if(data != NULL) {
++ sb_desc->buf = virt_to_phys(data);
++ } else {
++ sb_desc->buf = 0;
++ }
++ if(sb_prev != NULL) {
++ sb_prev->next = virt_to_phys(sb_desc);
++ }
++ return sb_desc;
++}
++
++/* Creates a copy of an existing SB by allocation space for it and copy
++ settings */
++struct USB_SB_Desc* create_sb_copy(struct USB_SB_Desc* sb_orig, int mem_flags) {
++ struct USB_SB_Desc *sb_desc;
++ sb_desc = (struct USB_SB_Desc*)kmem_cache_alloc(usb_desc_cache, mem_flags);
++ if(sb_desc == NULL)
++ return NULL;
++
++ memcpy(sb_desc, sb_orig, sizeof(struct USB_SB_Desc));
++ return sb_desc;
++}
++
++/* A specific create_sb function for creation of in SBs. This is due to
++ that datalen in In SBs shows how many packets we are expecting. It also
++ sets up the rem field to show if how many bytes we expect in last packet
++ if it's not a full one */
++struct USB_SB_Desc* create_sb_in(struct USB_SB_Desc* sb_prev, int datalen,
++ int maxlen, int mem_flags) {
++ struct USB_SB_Desc *sb_desc;
++ sb_desc = create_sb(sb_prev, TT_IN, NULL,
++ datalen ? (datalen - 1) / maxlen + 1 : 0, mem_flags);
++ if(sb_desc == NULL)
++ return NULL;
++ sb_desc->command |= IO_FIELD(USB_SB_command, rem, datalen % maxlen);
++ return sb_desc;
++}
++
++void set_sb_cmds(struct USB_SB_Desc *sb_desc, __u16 flags) {
++ sb_desc->command |= flags;
++}
++
++int create_sb_for_urb(struct urb *urb, int mem_flags) {
++ int is_out = !usb_pipein(urb->pipe);
++ int type = usb_pipetype(urb->pipe);
++ int maxlen = usb_maxpacket(urb->dev, urb->pipe, is_out);
++ int buf_len = urb->transfer_buffer_length;
++ void *buf = buf_len > 0 ? urb->transfer_buffer : NULL;
++ struct USB_SB_Desc *sb_desc = NULL;
++
++ struct crisv10_urb_priv *urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv != NULL);
++
++ switch(type) {
++ case PIPE_CONTROL:
++ /* Setup stage */
++ sb_desc = create_sb(NULL, TT_SETUP, urb->setup_packet, 8, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ set_sb_cmds(sb_desc, CMD_FULL);
++
++ /* Attach first SB to URB */
++ urb_priv->first_sb = sb_desc;
++
++ if (is_out) { /* Out Control URB */
++ /* If this Control OUT transfer has an optional data stage we add
++ an OUT token before the mandatory IN (status) token */
++ if ((buf_len > 0) && buf) {
++ sb_desc = create_sb(sb_desc, TT_OUT, buf, buf_len, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++
++ /* Status stage */
++ /* The data length has to be exactly 1. This is due to a requirement
++ of the USB specification that a host must be prepared to receive
++ data in the status phase */
++ sb_desc = create_sb(sb_desc, TT_IN, NULL, 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ } else { /* In control URB */
++ /* Data stage */
++ sb_desc = create_sb_in(sb_desc, buf_len, maxlen, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++
++ /* Status stage */
++ /* Read comment at zout_buffer declaration for an explanation to this. */
++ sb_desc = create_sb(sb_desc, TT_ZOUT, &zout_buffer[0], 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ /* Set descriptor interrupt flag for in URBs so we can finish URB after
++ zout-packet has been sent */
++ set_sb_cmds(sb_desc, CMD_INTR | CMD_FULL);
++ }
++ /* Set end-of-list flag in last SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++ /* Attach last SB to URB */
++ urb_priv->last_sb = sb_desc;
++ break;
++
++ case PIPE_BULK:
++ if (is_out) { /* Out Bulk URB */
++ sb_desc = create_sb(NULL, TT_OUT, buf, buf_len, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ /* The full field is set to yes, even if we don't actually check that
++ this is a full-length transfer (i.e., that transfer_buffer_length %
++ maxlen = 0).
++ Setting full prevents the USB controller from sending an empty packet
++ in that case. However, if URB_ZERO_PACKET was set we want that. */
++ if (!(urb->transfer_flags & URB_ZERO_PACKET)) {
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++ } else { /* In Bulk URB */
++ sb_desc = create_sb_in(NULL, buf_len, maxlen, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ }
++ /* Set end-of-list flag for last SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++
++ /* Attach SB to URB */
++ urb_priv->first_sb = sb_desc;
++ urb_priv->last_sb = sb_desc;
++ break;
++
++ case PIPE_INTERRUPT:
++ if(is_out) { /* Out Intr URB */
++ sb_desc = create_sb(NULL, TT_OUT, buf, buf_len, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++
++ /* The full field is set to yes, even if we don't actually check that
++ this is a full-length transfer (i.e., that transfer_buffer_length %
++ maxlen = 0).
++ Setting full prevents the USB controller from sending an empty packet
++ in that case. However, if URB_ZERO_PACKET was set we want that. */
++ if (!(urb->transfer_flags & URB_ZERO_PACKET)) {
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++ /* Only generate TX interrupt if it's a Out URB*/
++ set_sb_cmds(sb_desc, CMD_INTR);
++
++ } else { /* In Intr URB */
++ sb_desc = create_sb_in(NULL, buf_len, maxlen, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ }
++ /* Set end-of-list flag for last SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++
++ /* Attach SB to URB */
++ urb_priv->first_sb = sb_desc;
++ urb_priv->last_sb = sb_desc;
++
++ break;
++ case PIPE_ISOCHRONOUS:
++ if(is_out) { /* Out Isoc URB */
++ int i;
++ if(urb->number_of_packets == 0) {
++ tc_err("Can't create SBs for Isoc URB with zero packets\n");
++ return -EPIPE;
++ }
++ /* Create one SB descriptor for each packet and link them together. */
++ for(i = 0; i < urb->number_of_packets; i++) {
++ if (urb->iso_frame_desc[i].length > 0) {
++
++ sb_desc = create_sb(sb_desc, TT_OUT, urb->transfer_buffer +
++ urb->iso_frame_desc[i].offset,
++ urb->iso_frame_desc[i].length, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++
++ /* Check if it's a full length packet */
++ if (urb->iso_frame_desc[i].length ==
++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++
++ } else { /* zero length packet */
++ sb_desc = create_sb(sb_desc, TT_ZOUT, &zout_buffer[0], 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ set_sb_cmds(sb_desc, CMD_FULL);
++ }
++ /* Attach first SB descriptor to URB */
++ if (i == 0) {
++ urb_priv->first_sb = sb_desc;
++ }
++ }
++ /* Set interrupt and end-of-list flags in last SB */
++ set_sb_cmds(sb_desc, CMD_INTR | CMD_EOL);
++ /* Attach last SB descriptor to URB */
++ urb_priv->last_sb = sb_desc;
++ tc_dbg("Created %d out SBs for Isoc URB:0x%x\n",
++ urb->number_of_packets, (unsigned int)urb);
++ } else { /* In Isoc URB */
++ /* Actual number of packets is not relevant for periodic in traffic as
++ long as it is more than zero. Set to 1 always. */
++ sb_desc = create_sb(sb_desc, TT_IN, NULL, 1, mem_flags);
++ if(sb_desc == NULL)
++ return -ENOMEM;
++ /* Set end-of-list flags for SB */
++ set_sb_cmds(sb_desc, CMD_EOL);
++
++ /* Attach SB to URB */
++ urb_priv->first_sb = sb_desc;
++ urb_priv->last_sb = sb_desc;
++ }
++ break;
++ default:
++ tc_err("Unknown pipe-type\n");
++ return -EPIPE;
++ break;
++ }
++ return 0;
++}
++
++int init_intr_urb(struct urb *urb, int mem_flags) {
++ struct crisv10_urb_priv *urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ struct USB_EP_Desc* ep_desc;
++ int interval;
++ int i;
++ int ep_count;
++
++ ASSERT(urb_priv != NULL);
++ ASSERT(usb_pipeint(urb->pipe));
++ /* We can't support interval longer than amount of eof descriptors in
++ TxIntrEPList */
++ if(urb->interval > MAX_INTR_INTERVAL) {
++ tc_err("Interrupt interval %dms too big (max: %dms)\n", urb->interval,
++ MAX_INTR_INTERVAL);
++ return -EINVAL;
++ }
++
++ /* We assume that the SB descriptors already have been setup */
++ ASSERT(urb_priv->first_sb != NULL);
++
++ /* Round of the interval to 2^n, it is obvious that this code favours
++ smaller numbers, but that is actually a good thing */
++ /* FIXME: The "rounding error" for larger intervals will be quite
++ large. For in traffic this shouldn't be a problem since it will only
++ mean that we "poll" more often. */
++ interval = urb->interval;
++ for (i = 0; interval; i++) {
++ interval = interval >> 1;
++ }
++ urb_priv->interval = 1 << (i - 1);
++
++ /* We can only have max interval for Out Interrupt due to that we can only
++ handle one linked in EP for a certain epid in the Intr descr array at the
++ time. The USB Controller in the Etrax 100LX continues to process Intr EPs
++ so we have no way of knowing which one that caused the actual transfer if
++ we have several linked in. */
++ if(usb_pipeout(urb->pipe)) {
++ urb_priv->interval = MAX_INTR_INTERVAL;
++ }
++
++ /* Calculate amount of EPs needed */
++ ep_count = MAX_INTR_INTERVAL / urb_priv->interval;
++
++ for(i = 0; i < ep_count; i++) {
++ ep_desc = create_ep(urb_priv->epid, urb_priv->first_sb, mem_flags);
++ if(ep_desc == NULL) {
++ /* Free any descriptors that we may have allocated before failure */
++ while(i > 0) {
++ i--;
++ kfree(urb_priv->intr_ep_pool[i]);
++ }
++ return -ENOMEM;
++ }
++ urb_priv->intr_ep_pool[i] = ep_desc;
++ }
++ urb_priv->intr_ep_pool_length = ep_count;
++ return 0;
++}
++
++/* DMA RX/TX functions */
++/* ----------------------- */
++
++static void tc_dma_init_rx_list(void) {
++ int i;
++
++ /* Setup descriptor list except last one */
++ for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
++ RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
++ RxDescList[i].command = 0;
++ RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]);
++ RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
++ RxDescList[i].hw_len = 0;
++ RxDescList[i].status = 0;
++
++ /* DMA IN cache bug. (struct etrax_dma_descr has the same layout as
++ USB_IN_Desc for the relevant fields.) */
++ prepare_rx_descriptor((struct etrax_dma_descr*)&RxDescList[i]);
++
++ }
++ /* Special handling of last descriptor */
++ RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
++ RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes);
++ RxDescList[i].next = virt_to_phys(&RxDescList[0]);
++ RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
++ RxDescList[i].hw_len = 0;
++ RxDescList[i].status = 0;
++
++ /* Setup list pointers that show progress in list */
++ myNextRxDesc = &RxDescList[0];
++ myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
++
++ flush_etrax_cache();
++ /* Point DMA to first descriptor in list and start it */
++ *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc);
++ *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start);
++}
++
++
++static void tc_dma_init_tx_bulk_list(void) {
++ int i;
++ volatile struct USB_EP_Desc *epDescr;
++
++ for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
++ epDescr = &(TxBulkEPList[i]);
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->next = virt_to_phys(&TxBulkEPList[i + 1]);
++
++ /* Initiate two EPs, disabled and with the eol flag set. No need for any
++ preserved epid. */
++
++ /* The first one has the intr flag set so we get an interrupt when the DMA
++ channel is about to become disabled. */
++ CHECK_ALIGN(&TxBulkDummyEPList[i][0]);
++ TxBulkDummyEPList[i][0].hw_len = 0;
++ TxBulkDummyEPList[i][0].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
++ IO_STATE(USB_EP_command, eol, yes) |
++ IO_STATE(USB_EP_command, intr, yes));
++ TxBulkDummyEPList[i][0].sub = 0;
++ TxBulkDummyEPList[i][0].next = virt_to_phys(&TxBulkDummyEPList[i][1]);
++
++ /* The second one. */
++ CHECK_ALIGN(&TxBulkDummyEPList[i][1]);
++ TxBulkDummyEPList[i][1].hw_len = 0;
++ TxBulkDummyEPList[i][1].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
++ IO_STATE(USB_EP_command, eol, yes));
++ TxBulkDummyEPList[i][1].sub = 0;
++ /* The last dummy's next pointer is the same as the current EP's next pointer. */
++ TxBulkDummyEPList[i][1].next = virt_to_phys(&TxBulkEPList[i + 1]);
++ }
++
++ /* Special handling of last descr in list, make list circular */
++ epDescr = &TxBulkEPList[i];
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_STATE(USB_EP_command, eol, yes) |
++ IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->next = virt_to_phys(&TxBulkEPList[0]);
++
++ /* Init DMA sub-channel pointers to last item in each list */
++ *R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[i]);
++ /* No point in starting the bulk channel yet.
++ *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
++}
++
++static void tc_dma_init_tx_ctrl_list(void) {
++ int i;
++ volatile struct USB_EP_Desc *epDescr;
++
++ for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
++ epDescr = &(TxCtrlEPList[i]);
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->next = virt_to_phys(&TxCtrlEPList[i + 1]);
++ }
++ /* Special handling of last descr in list, make list circular */
++ epDescr = &TxCtrlEPList[i];
++ CHECK_ALIGN(epDescr);
++ epDescr->hw_len = 0;
++ epDescr->command = IO_STATE(USB_EP_command, eol, yes) |
++ IO_FIELD(USB_EP_command, epid, i);
++ epDescr->sub = 0;
++ epDescr->next = virt_to_phys(&TxCtrlEPList[0]);
++
++ /* Init DMA sub-channel pointers to last item in each list */
++ *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[i]);
++ /* No point in starting the ctrl channel yet.
++ *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
++}
++
++
++static void tc_dma_init_tx_intr_list(void) {
++ int i;
++
++ TxIntrSB_zout.sw_len = 1;
++ TxIntrSB_zout.next = 0;
++ TxIntrSB_zout.buf = virt_to_phys(&zout_buffer[0]);
++ TxIntrSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
++ IO_STATE(USB_SB_command, tt, zout) |
++ IO_STATE(USB_SB_command, full, yes) |
++ IO_STATE(USB_SB_command, eot, yes) |
++ IO_STATE(USB_SB_command, eol, yes));
++
++ for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) {
++ CHECK_ALIGN(&TxIntrEPList[i]);
++ TxIntrEPList[i].hw_len = 0;
++ TxIntrEPList[i].command =
++ (IO_STATE(USB_EP_command, eof, yes) |
++ IO_STATE(USB_EP_command, enable, yes) |
++ IO_FIELD(USB_EP_command, epid, INVALID_EPID));
++ TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
++ TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[i + 1]);
++ }
++
++ /* Special handling of last descr in list, make list circular */
++ CHECK_ALIGN(&TxIntrEPList[i]);
++ TxIntrEPList[i].hw_len = 0;
++ TxIntrEPList[i].command =
++ (IO_STATE(USB_EP_command, eof, yes) |
++ IO_STATE(USB_EP_command, eol, yes) |
++ IO_STATE(USB_EP_command, enable, yes) |
++ IO_FIELD(USB_EP_command, epid, INVALID_EPID));
++ TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
++ TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[0]);
++
++ intr_dbg("Initiated Intr EP descriptor list\n");
++
++
++ /* Connect DMA 8 sub-channel 2 to first in list */
++ *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
++}
++
++static void tc_dma_init_tx_isoc_list(void) {
++ int i;
++
++ DBFENTER;
++
++ /* Read comment at zout_buffer declaration for an explanation to this. */
++ TxIsocSB_zout.sw_len = 1;
++ TxIsocSB_zout.next = 0;
++ TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]);
++ TxIsocSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
++ IO_STATE(USB_SB_command, tt, zout) |
++ IO_STATE(USB_SB_command, full, yes) |
++ IO_STATE(USB_SB_command, eot, yes) |
++ IO_STATE(USB_SB_command, eol, yes));
++
++ /* The last isochronous EP descriptor is a dummy. */
++ for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
++ CHECK_ALIGN(&TxIsocEPList[i]);
++ TxIsocEPList[i].hw_len = 0;
++ TxIsocEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
++ TxIsocEPList[i].sub = 0;
++ TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[i + 1]);
++ }
++
++ CHECK_ALIGN(&TxIsocEPList[i]);
++ TxIsocEPList[i].hw_len = 0;
++
++ /* Must enable the last EP descr to get eof interrupt. */
++ TxIsocEPList[i].command = (IO_STATE(USB_EP_command, enable, yes) |
++ IO_STATE(USB_EP_command, eof, yes) |
++ IO_STATE(USB_EP_command, eol, yes) |
++ IO_FIELD(USB_EP_command, epid, INVALID_EPID));
++ TxIsocEPList[i].sub = virt_to_phys(&TxIsocSB_zout);
++ TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[0]);
++
++ *R_DMA_CH8_SUB3_EP = virt_to_phys(&TxIsocEPList[0]);
++ *R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
++}
++
++static int tc_dma_init(struct usb_hcd *hcd) {
++ tc_dma_init_rx_list();
++ tc_dma_init_tx_bulk_list();
++ tc_dma_init_tx_ctrl_list();
++ tc_dma_init_tx_intr_list();
++ tc_dma_init_tx_isoc_list();
++
++ if (cris_request_dma(USB_TX_DMA_NBR,
++ "ETRAX 100LX built-in USB (Tx)",
++ DMA_VERBOSE_ON_ERROR,
++ dma_usb)) {
++ err("Could not allocate DMA ch 8 for USB");
++ return -EBUSY;
++ }
++
++ if (cris_request_dma(USB_RX_DMA_NBR,
++ "ETRAX 100LX built-in USB (Rx)",
++ DMA_VERBOSE_ON_ERROR,
++ dma_usb)) {
++ err("Could not allocate DMA ch 9 for USB");
++ return -EBUSY;
++ }
++
++ *R_IRQ_MASK2_SET =
++ /* Note that these interrupts are not used. */
++ IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) |
++ /* Sub channel 1 (ctrl) descr. interrupts are used. */
++ IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) |
++ IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) |
++ /* Sub channel 3 (isoc) descr. interrupts are used. */
++ IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set);
++
++ /* Note that the dma9_descr interrupt is not used. */
++ *R_IRQ_MASK2_SET =
++ IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) |
++ IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
++
++ if (request_irq(ETRAX_USB_RX_IRQ, tc_dma_rx_interrupt, 0,
++ "ETRAX 100LX built-in USB (Rx)", hcd)) {
++ err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ);
++ return -EBUSY;
++ }
++
++ if (request_irq(ETRAX_USB_TX_IRQ, tc_dma_tx_interrupt, 0,
++ "ETRAX 100LX built-in USB (Tx)", hcd)) {
++ err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ);
++ return -EBUSY;
++ }
++
++ return 0;
++}
++
++static void tc_dma_destroy(void) {
++ free_irq(ETRAX_USB_RX_IRQ, NULL);
++ free_irq(ETRAX_USB_TX_IRQ, NULL);
++
++ cris_free_dma(USB_TX_DMA_NBR, "ETRAX 100LX built-in USB (Tx)");
++ cris_free_dma(USB_RX_DMA_NBR, "ETRAX 100LX built-in USB (Rx)");
++
++}
++
++static void tc_dma_link_intr_urb(struct urb *urb);
++
++/* Handle processing of Bulk, Ctrl and Intr queues */
++static void tc_dma_process_queue(int epid) {
++ struct urb *urb;
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ unsigned long flags;
++ char toggle;
++
++ if(epid_state[epid].disabled) {
++ /* Don't process any URBs on a disabled endpoint */
++ return;
++ }
++
++ /* Do not disturb us while fiddling with EPs and epids */
++ local_irq_save(flags);
++
++ /* For bulk, Ctrl and Intr can we only have one URB active at a time for
++ a specific EP. */
++ if(activeUrbList[epid] != NULL) {
++ /* An URB is already active on EP, skip checking queue */
++ local_irq_restore(flags);
++ return;
++ }
++
++ urb = urb_list_first(epid);
++ if(urb == NULL) {
++ /* No URB waiting in EP queue. Nothing do to */
++ local_irq_restore(flags);
++ return;
++ }
++
++ urb_priv = urb->hcpriv;
++ ASSERT(urb_priv != NULL);
++ ASSERT(urb_priv->urb_state == NOT_STARTED);
++ ASSERT(!usb_pipeisoc(urb->pipe));
++
++ /* Remove this URB from the queue and move it to active */
++ activeUrbList[epid] = urb;
++ urb_list_del(urb, epid);
++
++ urb_priv->urb_state = STARTED;
++
++ /* Reset error counters (regardless of which direction this traffic is). */
++ etrax_epid_clear_error(epid);
++
++ /* Special handling of Intr EP lists */
++ if(usb_pipeint(urb->pipe)) {
++ tc_dma_link_intr_urb(urb);
++ local_irq_restore(flags);
++ return;
++ }
++
++ /* Software must preset the toggle bits for Bulk and Ctrl */
++ if(usb_pipecontrol(urb->pipe)) {
++ /* Toggle bits are initialized only during setup transaction in a
++ CTRL transfer */
++ etrax_epid_set_toggle(epid, 0, 0);
++ etrax_epid_set_toggle(epid, 1, 0);
++ } else {
++ toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++ usb_pipeout(urb->pipe));
++ etrax_epid_set_toggle(epid, usb_pipeout(urb->pipe), toggle);
++ }
++
++ tc_dbg("Added SBs from (URB:0x%x %s %s) to epid %d: %s\n",
++ (unsigned int)urb, str_dir(urb->pipe), str_type(urb->pipe), epid,
++ sblist_to_str(urb_priv->first_sb));
++
++ /* We start the DMA sub channel without checking if it's running or not,
++ because:
++ 1) If it's already running, issuing the start command is a nop.
++ 2) We avoid a test-and-set race condition. */
++ switch(usb_pipetype(urb->pipe)) {
++ case PIPE_BULK:
++ /* Assert that the EP descriptor is disabled. */
++ ASSERT(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
++
++ /* Set up and enable the EP descriptor. */
++ TxBulkEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++ TxBulkEPList[epid].hw_len = 0;
++ TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++ /* Check if the dummy list is already with us (if several urbs were queued). */
++ if (usb_pipein(urb->pipe) && (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0]))) {
++ tc_dbg("Inviting dummy list to the party for urb 0x%lx, epid %d",
++ (unsigned long)urb, epid);
++
++ /* We don't need to check if the DMA is at this EP or not before changing the
++ next pointer, since we will do it in one 32-bit write (EP descriptors are
++ 32-bit aligned). */
++ TxBulkEPList[epid].next = virt_to_phys(&TxBulkDummyEPList[epid][0]);
++ }
++
++ restart_dma8_sub0();
++
++ /* Update/restart the bulk start timer since we just started the channel.*/
++ mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
++ /* Update/restart the bulk eot timer since we just inserted traffic. */
++ mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
++ break;
++ case PIPE_CONTROL:
++ /* Assert that the EP descriptor is disabled. */
++ ASSERT(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
++
++ /* Set up and enable the EP descriptor. */
++ TxCtrlEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++ TxCtrlEPList[epid].hw_len = 0;
++ TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++ *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
++ break;
++ }
++ local_irq_restore(flags);
++}
++
++static void tc_dma_link_intr_urb(struct urb *urb) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ volatile struct USB_EP_Desc *tmp_ep;
++ struct USB_EP_Desc *ep_desc;
++ int i = 0, epid;
++ int pool_idx = 0;
++
++ ASSERT(urb_priv != NULL);
++ epid = urb_priv->epid;
++ ASSERT(urb_priv->interval > 0);
++ ASSERT(urb_priv->intr_ep_pool_length > 0);
++
++ tmp_ep = &TxIntrEPList[0];
++
++ /* Only insert one EP descriptor in list for Out Intr URBs.
++ We can only handle Out Intr with interval of 128ms because
++ it's not possible to insert several Out Intr EPs because they
++ are not consumed by the DMA. */
++ if(usb_pipeout(urb->pipe)) {
++ ep_desc = urb_priv->intr_ep_pool[0];
++ ASSERT(ep_desc);
++ ep_desc->next = tmp_ep->next;
++ tmp_ep->next = virt_to_phys(ep_desc);
++ i++;
++ } else {
++ /* Loop through Intr EP descriptor list and insert EP for URB at
++ specified interval */
++ do {
++ /* Each EP descriptor with eof flag sat signals a new frame */
++ if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) {
++ /* Insert a EP from URBs EP pool at correct interval */
++ if ((i % urb_priv->interval) == 0) {
++ ep_desc = urb_priv->intr_ep_pool[pool_idx];
++ ASSERT(ep_desc);
++ ep_desc->next = tmp_ep->next;
++ tmp_ep->next = virt_to_phys(ep_desc);
++ pool_idx++;
++ ASSERT(pool_idx <= urb_priv->intr_ep_pool_length);
++ }
++ i++;
++ }
++ tmp_ep = (struct USB_EP_Desc *)phys_to_virt(tmp_ep->next);
++ } while(tmp_ep != &TxIntrEPList[0]);
++ }
++
++ intr_dbg("Added SBs to intr epid %d: %s interval:%d (%d EP)\n", epid,
++ sblist_to_str(urb_priv->first_sb), urb_priv->interval, pool_idx);
++
++ /* We start the DMA sub channel without checking if it's running or not,
++ because:
++ 1) If it's already running, issuing the start command is a nop.
++ 2) We avoid a test-and-set race condition. */
++ *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
++}
++
++ /* hinko ignore usb_pipeisoc */
++#if 0
++static void tc_dma_process_isoc_urb(struct urb *urb) {
++ unsigned long flags;
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ int epid;
++
++ /* Do not disturb us while fiddling with EPs and epids */
++ local_irq_save(flags);
++
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->first_sb);
++ epid = urb_priv->epid;
++
++ if(activeUrbList[epid] == NULL) {
++ /* EP is idle, so make this URB active */
++ activeUrbList[epid] = urb;
++ urb_list_del(urb, epid);
++ ASSERT(TxIsocEPList[epid].sub == 0);
++ ASSERT(!(TxIsocEPList[epid].command &
++ IO_STATE(USB_EP_command, enable, yes)));
++
++ /* Differentiate between In and Out Isoc. Because In SBs are not consumed*/
++ if(usb_pipein(urb->pipe)) {
++ /* Each EP for In Isoc will have only one SB descriptor, setup when
++ submitting the first active urb. We do it here by copying from URBs
++ pre-allocated SB. */
++ memcpy((void *)&(TxIsocSBList[epid]), urb_priv->first_sb,
++ sizeof(TxIsocSBList[epid]));
++ TxIsocEPList[epid].hw_len = 0;
++ TxIsocEPList[epid].sub = virt_to_phys(&(TxIsocSBList[epid]));
++ } else {
++ /* For Out Isoc we attach the pre-allocated list of SBs for the URB */
++ TxIsocEPList[epid].hw_len = 0;
++ TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++
++ isoc_dbg("Attached first URB:0x%x[%d] to epid:%d first_sb:0x%x"
++ " last_sb::0x%x\n",
++ (unsigned int)urb, urb_priv->urb_num, epid,
++ (unsigned int)(urb_priv->first_sb),
++ (unsigned int)(urb_priv->last_sb));
++ }
++
++ if (urb->transfer_flags & URB_ISO_ASAP) {
++ /* The isoc transfer should be started as soon as possible. The
++ start_frame field is a return value if URB_ISO_ASAP was set. Comparing
++ R_USB_FM_NUMBER with a USB Chief trace shows that the first isoc IN
++ token is sent 2 frames later. I'm not sure how this affects usage of
++ the start_frame field by the device driver, or how it affects things
++ when USB_ISO_ASAP is not set, so therefore there's no compensation for
++ the 2 frame "lag" here. */
++ urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff);
++ TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++ urb_priv->urb_state = STARTED;
++ isoc_dbg("URB_ISO_ASAP set, urb->start_frame set to %d\n",
++ urb->start_frame);
++ } else {
++ /* Not started yet. */
++ urb_priv->urb_state = NOT_STARTED;
++ isoc_warn("urb_priv->urb_state set to NOT_STARTED for URB:0x%x\n",
++ (unsigned int)urb);
++ }
++
++ } else {
++ /* An URB is already active on the EP. Leave URB in queue and let
++ finish_isoc_urb process it after current active URB */
++ ASSERT(TxIsocEPList[epid].sub != 0);
++
++ if(usb_pipein(urb->pipe)) {
++ /* Because there already is a active In URB on this epid we do nothing
++ and the finish_isoc_urb() function will handle switching to next URB*/
++
++ } else { /* For Out Isoc, insert new URBs traffic last in SB-list. */
++ struct USB_SB_Desc *temp_sb_desc;
++
++ /* Set state STARTED to all Out Isoc URBs added to SB list because we
++ don't know how many of them that are finished before descr interrupt*/
++ urb_priv->urb_state = STARTED;
++
++ /* Find end of current SB list by looking for SB with eol flag sat */
++ temp_sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
++ while ((temp_sb_desc->command & IO_MASK(USB_SB_command, eol)) !=
++ IO_STATE(USB_SB_command, eol, yes)) {
++ ASSERT(temp_sb_desc->next);
++ temp_sb_desc = phys_to_virt(temp_sb_desc->next);
++ }
++
++ isoc_dbg("Appended URB:0x%x[%d] (first:0x%x last:0x%x) to epid:%d"
++ " sub:0x%x eol:0x%x\n",
++ (unsigned int)urb, urb_priv->urb_num,
++ (unsigned int)(urb_priv->first_sb),
++ (unsigned int)(urb_priv->last_sb), epid,
++ (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++ (unsigned int)temp_sb_desc);
++
++ /* Next pointer must be set before eol is removed. */
++ temp_sb_desc->next = virt_to_phys(urb_priv->first_sb);
++ /* Clear the previous end of list flag since there is a new in the
++ added SB descriptor list. */
++ temp_sb_desc->command &= ~IO_MASK(USB_SB_command, eol);
++
++ if (!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
++ __u32 epid_data;
++ /* 8.8.5 in Designer's Reference says we should check for and correct
++ any errors in the EP here. That should not be necessary if
++ epid_attn is handled correctly, so we assume all is ok. */
++ epid_data = etrax_epid_iso_get(epid);
++ if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data) !=
++ IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
++ isoc_err("Disabled Isoc EP with error:%d on epid:%d when appending"
++ " URB:0x%x[%d]\n",
++ IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data), epid,
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++
++ /* The SB list was exhausted. */
++ if (virt_to_phys(urb_priv->last_sb) != TxIsocEPList[epid].sub) {
++ /* The new sublist did not get processed before the EP was
++ disabled. Setup the EP again. */
++
++ if(virt_to_phys(temp_sb_desc) == TxIsocEPList[epid].sub) {
++ isoc_dbg("EP for epid:%d stoped at SB:0x%x before newly inserted"
++ ", restarting from this URBs SB:0x%x\n",
++ epid, (unsigned int)temp_sb_desc,
++ (unsigned int)(urb_priv->first_sb));
++ TxIsocEPList[epid].hw_len = 0;
++ TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++ urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff);
++ /* Enable the EP again so data gets processed this time */
++ TxIsocEPList[epid].command |=
++ IO_STATE(USB_EP_command, enable, yes);
++
++ } else {
++ /* The EP has been disabled but not at end this URB (god knows
++ where). This should generate an epid_attn so we should not be
++ here */
++ isoc_warn("EP was disabled on sb:0x%x before SB list for"
++ " URB:0x%x[%d] got processed\n",
++ (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++ } else {
++ /* This might happend if we are slow on this function and isn't
++ an error. */
++ isoc_dbg("EP was disabled and finished with SBs from appended"
++ " URB:0x%x[%d]\n", (unsigned int)urb, urb_priv->urb_num);
++ }
++ }
++ }
++ }
++
++ /* Start the DMA sub channel */
++ *R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
++
++ local_irq_restore(flags);
++}
++#endif
++
++static void tc_dma_unlink_intr_urb(struct urb *urb) {
++ struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++ volatile struct USB_EP_Desc *first_ep; /* First EP in the list. */
++ volatile struct USB_EP_Desc *curr_ep; /* Current EP, the iterator. */
++ volatile struct USB_EP_Desc *next_ep; /* The EP after current. */
++ volatile struct USB_EP_Desc *unlink_ep; /* The one we should remove from
++ the list. */
++ int count = 0;
++ volatile int timeout = 10000;
++ int epid;
++
++ /* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the
++ List". */
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->intr_ep_pool_length > 0);
++ epid = urb_priv->epid;
++
++ /* First disable all Intr EPs belonging to epid for this URB */
++ first_ep = &TxIntrEPList[0];
++ curr_ep = first_ep;
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
++ /* Disable EP */
++ next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != first_ep);
++
++
++ /* Now unlink all EPs belonging to this epid from Descr list */
++ first_ep = &TxIntrEPList[0];
++ curr_ep = first_ep;
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
++ /* This is the one we should unlink. */
++ unlink_ep = next_ep;
++
++ /* Actually unlink the EP from the DMA list. */
++ curr_ep->next = unlink_ep->next;
++
++ /* Wait until the DMA is no longer at this descriptor. */
++ while((*R_DMA_CH8_SUB2_EP == virt_to_phys(unlink_ep)) &&
++ (timeout-- > 0));
++ if(timeout == 0) {
++ warn("Timeout while waiting for DMA-TX-Intr to leave unlink EP\n");
++ }
++
++ count++;
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != first_ep);
++
++ if(count != urb_priv->intr_ep_pool_length) {
++ intr_warn("Unlinked %d of %d Intr EPs for URB:0x%x[%d]\n", count,
++ urb_priv->intr_ep_pool_length, (unsigned int)urb,
++ urb_priv->urb_num);
++ } else {
++ intr_dbg("Unlinked %d of %d interrupt EPs for URB:0x%x\n", count,
++ urb_priv->intr_ep_pool_length, (unsigned int)urb);
++ }
++}
++
++static void check_finished_bulk_tx_epids(struct usb_hcd *hcd,
++ int timer) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ __u32 epid_data;
++
++ /* Protect TxEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ /* A finished EP descriptor is disabled and has a valid sub pointer */
++ if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
++ (TxBulkEPList[epid].sub != 0)) {
++
++ /* Get the active URB for this epid */
++ urb = activeUrbList[epid];
++ /* Sanity checks */
++ ASSERT(urb);
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ /* Only handle finished out Bulk EPs here,
++ and let RX interrupt take care of the rest */
++ if(!epid_out_traffic(epid)) {
++ continue;
++ }
++
++ if(timer) {
++ tc_warn("Found finished %s Bulk epid:%d URB:0x%x[%d] from timeout\n",
++ epid_out_traffic(epid) ? "Out" : "In", epid, (unsigned int)urb,
++ urb_priv->urb_num);
++ } else {
++ tc_dbg("Found finished %s Bulk epid:%d URB:0x%x[%d] from interrupt\n",
++ epid_out_traffic(epid) ? "Out" : "In", epid, (unsigned int)urb,
++ urb_priv->urb_num);
++ }
++
++ if(urb_priv->urb_state == UNLINK) {
++ /* This Bulk URB is requested to be unlinked, that means that the EP
++ has been disabled and we might not have sent all data */
++ tc_finish_urb(hcd, urb, urb->status);
++ continue;
++ }
++
++ ASSERT(urb_priv->urb_state == STARTED);
++ if (phys_to_virt(TxBulkEPList[epid].sub) != urb_priv->last_sb) {
++ tc_err("Endpoint got disabled before reaching last sb\n");
++ }
++
++ epid_data = etrax_epid_get(epid);
++ if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data) ==
++ IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
++ /* This means that the endpoint has no error, is disabled
++ and had inserted traffic, i.e. transfer successfully completed. */
++ tc_finish_urb(hcd, urb, 0);
++ } else {
++ /* Shouldn't happen. We expect errors to be caught by epid
++ attention. */
++ tc_err("Found disabled bulk EP desc (epid:%d error:%d)\n",
++ epid, IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data));
++ }
++ } else {
++ tc_dbg("Ignoring In Bulk epid:%d, let RX interrupt handle it\n", epid);
++ }
++ }
++
++ local_irq_restore(flags);
++}
++
++static void check_finished_ctrl_tx_epids(struct usb_hcd *hcd) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ __u32 epid_data;
++
++ /* Protect TxEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if(epid == DUMMY_EPID)
++ continue;
++
++ /* A finished EP descriptor is disabled and has a valid sub pointer */
++ if (!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
++ (TxCtrlEPList[epid].sub != 0)) {
++
++ /* Get the active URB for this epid */
++ urb = activeUrbList[epid];
++
++ if(urb == NULL) {
++ tc_warn("Found finished Ctrl epid:%d with no active URB\n", epid);
++ continue;
++ }
++
++ /* Sanity checks */
++ ASSERT(usb_pipein(urb->pipe));
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++ if (phys_to_virt(TxCtrlEPList[epid].sub) != urb_priv->last_sb) {
++ tc_err("Endpoint got disabled before reaching last sb\n");
++ }
++
++ epid_data = etrax_epid_get(epid);
++ if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data) ==
++ IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
++ /* This means that the endpoint has no error, is disabled
++ and had inserted traffic, i.e. transfer successfully completed. */
++
++ /* Check if RX-interrupt for In Ctrl has been processed before
++ finishing the URB */
++ if(urb_priv->ctrl_rx_done) {
++ tc_dbg("Finishing In Ctrl URB:0x%x[%d] in tx_interrupt\n",
++ (unsigned int)urb, urb_priv->urb_num);
++ tc_finish_urb(hcd, urb, 0);
++ } else {
++ /* If we get zout descriptor interrupt before RX was done for a
++ In Ctrl transfer, then we flag that and it will be finished
++ in the RX-Interrupt */
++ urb_priv->ctrl_zout_done = 1;
++ tc_dbg("Got zout descr interrupt before RX interrupt\n");
++ }
++ } else {
++ /* Shouldn't happen. We expect errors to be caught by epid
++ attention. */
++ tc_err("Found disabled Ctrl EP desc (epid:%d URB:0x%x[%d]) error_code:%d\n", epid, (unsigned int)urb, urb_priv->urb_num, IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data));
++ __dump_ep_desc(&(TxCtrlEPList[epid]));
++ __dump_ept_data(epid);
++ }
++ }
++ }
++ local_irq_restore(flags);
++}
++
++ /* hinko ignore usb_pipeisoc */
++#if 0
++/* This function goes through all epids that are setup for Out Isoc transfers
++ and marks (isoc_out_done) all queued URBs that the DMA has finished
++ transfer for.
++ No URB completetion is done here to make interrupt routine return quickly.
++ URBs are completed later with help of complete_isoc_bottom_half() that
++ becomes schedules when this functions is finished. */
++static void check_finished_isoc_tx_epids(void) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ struct USB_SB_Desc* sb_desc;
++ int epid_done;
++
++ /* Protect TxIsocEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if (TxIsocEPList[epid].sub == 0 || epid == INVALID_EPID ||
++ !epid_out_traffic(epid)) {
++ /* Nothing here to see. */
++ continue;
++ }
++ ASSERT(epid_inuse(epid));
++ ASSERT(epid_isoc(epid));
++
++ sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
++ /* Find the last descriptor of the currently active URB for this ep.
++ This is the first descriptor in the sub list marked for a descriptor
++ interrupt. */
++ while (sb_desc && !IO_EXTRACT(USB_SB_command, intr, sb_desc->command)) {
++ sb_desc = sb_desc->next ? phys_to_virt(sb_desc->next) : 0;
++ }
++ ASSERT(sb_desc);
++
++ isoc_dbg("Descr IRQ checking epid:%d sub:0x%x intr:0x%x\n",
++ epid, (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++ (unsigned int)sb_desc);
++
++ urb = activeUrbList[epid];
++ if(urb == NULL) {
++ isoc_err("Isoc Descr irq on epid:%d with no active URB\n", epid);
++ continue;
++ }
++
++ epid_done = 0;
++ while(urb && !epid_done) {
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++ ASSERT(usb_pipeout(urb->pipe));
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->urb_state == STARTED ||
++ urb_priv->urb_state == UNLINK);
++
++ if (sb_desc != urb_priv->last_sb) {
++ /* This urb has been sent. */
++ urb_priv->isoc_out_done = 1;
++
++ } else { /* Found URB that has last_sb as the interrupt reason */
++
++ /* Check if EP has been disabled, meaning that all transfers are done*/
++ if(!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
++ ASSERT((sb_desc->command & IO_MASK(USB_SB_command, eol)) ==
++ IO_STATE(USB_SB_command, eol, yes));
++ ASSERT(sb_desc->next == 0);
++ urb_priv->isoc_out_done = 1;
++ } else {
++ isoc_dbg("Skipping URB:0x%x[%d] because EP not disabled yet\n",
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++ /* Stop looking any further in queue */
++ epid_done = 1;
++ }
++
++ if (!epid_done) {
++ if(urb == activeUrbList[epid]) {
++ urb = urb_list_first(epid);
++ } else {
++ urb = urb_list_next(urb, epid);
++ }
++ }
++ } /* END: while(urb && !epid_done) */
++ }
++
++ local_irq_restore(flags);
++}
++
++
++/* This is where the Out Isoc URBs are realy completed. This function is
++ scheduled from tc_dma_tx_interrupt() when one or more Out Isoc transfers
++ are done. This functions completes all URBs earlier marked with
++ isoc_out_done by fast interrupt routine check_finished_isoc_tx_epids() */
++
++static void complete_isoc_bottom_half(void *data) {
++ struct crisv10_isoc_complete_data *comp_data;
++ struct usb_iso_packet_descriptor *packet;
++ struct crisv10_urb_priv * urb_priv;
++ unsigned long flags;
++ struct urb* urb;
++ int epid_done;
++ int epid;
++ int i;
++
++ comp_data = (struct crisv10_isoc_complete_data*)data;
++
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
++ if(!epid_inuse(epid) || !epid_isoc(epid) || !epid_out_traffic(epid) || epid == DUMMY_EPID) {
++ /* Only check valid Out Isoc epids */
++ continue;
++ }
++
++ isoc_dbg("Isoc bottom-half checking epid:%d, sub:0x%x\n", epid,
++ (unsigned int)phys_to_virt(TxIsocEPList[epid].sub));
++
++ /* The descriptor interrupt handler has marked all transmitted Out Isoc
++ URBs with isoc_out_done. Now we traverse all epids and for all that
++ have out Isoc traffic we traverse its URB list and complete the
++ transmitted URBs. */
++ epid_done = 0;
++ while (!epid_done) {
++
++ /* Get the active urb (if any) */
++ urb = activeUrbList[epid];
++ if (urb == 0) {
++ isoc_dbg("No active URB on epid:%d anymore\n", epid);
++ epid_done = 1;
++ continue;
++ }
++
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++ ASSERT(usb_pipeout(urb->pipe));
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ if (!(urb_priv->isoc_out_done)) {
++ /* We have reached URB that isn't flaged done yet, stop traversing. */
++ isoc_dbg("Stoped traversing Out Isoc URBs on epid:%d"
++ " before not yet flaged URB:0x%x[%d]\n",
++ epid, (unsigned int)urb, urb_priv->urb_num);
++ epid_done = 1;
++ continue;
++ }
++
++ /* This urb has been sent. */
++ isoc_dbg("Found URB:0x%x[%d] that is flaged isoc_out_done\n",
++ (unsigned int)urb, urb_priv->urb_num);
++
++ /* Set ok on transfered packets for this URB and finish it */
++ for (i = 0; i < urb->number_of_packets; i++) {
++ packet = &urb->iso_frame_desc[i];
++ packet->status = 0;
++ packet->actual_length = packet->length;
++ }
++ urb_priv->isoc_packet_counter = urb->number_of_packets;
++ tc_finish_urb(comp_data->hcd, urb, 0);
++
++ } /* END: while(!epid_done) */
++ } /* END: for(epid...) */
++
++ local_irq_restore(flags);
++ kmem_cache_free(isoc_compl_cache, comp_data);
++}
++#endif
++
++static void check_finished_intr_tx_epids(struct usb_hcd *hcd) {
++ unsigned long flags;
++ int epid;
++ struct urb *urb;
++ struct crisv10_urb_priv * urb_priv;
++ volatile struct USB_EP_Desc *curr_ep; /* Current EP, the iterator. */
++ volatile struct USB_EP_Desc *next_ep; /* The EP after current. */
++
++ /* Protect TxintrEPList */
++ local_irq_save(flags);
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if(!epid_inuse(epid) || !epid_intr(epid) || !epid_out_traffic(epid)) {
++ /* Nothing to see on this epid. Only check valid Out Intr epids */
++ continue;
++ }
++
++ urb = activeUrbList[epid];
++ if(urb == 0) {
++ intr_warn("Found Out Intr epid:%d with no active URB\n", epid);
++ continue;
++ }
++
++ /* Sanity check. */
++ ASSERT(usb_pipetype(urb->pipe) == PIPE_INTERRUPT);
++ ASSERT(usb_pipeout(urb->pipe));
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++
++ /* Go through EPs between first and second sof-EP. It's here Out Intr EPs
++ are inserted.*/
++ curr_ep = &TxIntrEPList[0];
++ do {
++ next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++ if(next_ep == urb_priv->intr_ep_pool[0]) {
++ /* We found the Out Intr EP for this epid */
++
++ /* Disable it so it doesn't get processed again */
++ next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++
++ /* Finish the active Out Intr URB with status OK */
++ tc_finish_urb(hcd, urb, 0);
++ }
++ curr_ep = phys_to_virt(curr_ep->next);
++ } while (curr_ep != &TxIntrEPList[1]);
++
++ }
++ local_irq_restore(flags);
++}
++
++/* Interrupt handler for DMA8/IRQ24 with subchannels (called from hardware intr) */
++static irqreturn_t tc_dma_tx_interrupt(int irq, void *vhc) {
++ struct usb_hcd *hcd = (struct usb_hcd*)vhc;
++ ASSERT(hcd);
++
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);
++ restart_dma8_sub0();
++ }
++
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);
++ check_finished_ctrl_tx_epids(hcd);
++ }
++
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);
++ check_finished_intr_tx_epids(hcd);
++ }
++
++ /* hinko ignore usb_pipeisoc */
++#if 0
++ if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {
++ struct crisv10_isoc_complete_data* comp_data;
++
++ /* Flag done Out Isoc for later completion */
++ check_finished_isoc_tx_epids();
++
++ /* Clear this interrupt */
++ *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);
++ /* Schedule bottom half of Out Isoc completion function. This function
++ finishes the URBs marked with isoc_out_done */
++ comp_data = (struct crisv10_isoc_complete_data*)
++ kmem_cache_alloc(isoc_compl_cache, GFP_ATOMIC);
++ ASSERT(comp_data != NULL);
++ comp_data ->hcd = hcd;
++
++ //INIT_WORK(&comp_data->usb_bh, complete_isoc_bottom_half, comp_data);
++ INIT_WORK(&comp_data->usb_bh, complete_isoc_bottom_half);
++ schedule_work(&comp_data->usb_bh);
++ }
++#endif
++
++ return IRQ_HANDLED;
++}
++
++/* Interrupt handler for DMA9/IRQ25 (called from hardware intr) */
++static irqreturn_t tc_dma_rx_interrupt(int irq, void *vhc) {
++ unsigned long flags;
++ struct urb *urb;
++ struct usb_hcd *hcd = (struct usb_hcd*)vhc;
++ struct crisv10_urb_priv *urb_priv;
++ int epid = 0;
++ int real_error;
++
++ ASSERT(hcd);
++
++ /* Clear this interrupt. */
++ *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
++
++ /* Custom clear interrupt for this interrupt */
++ /* The reason we cli here is that we call the driver's callback functions. */
++ local_irq_save(flags);
++
++ /* Note that this while loop assumes that all packets span only
++ one rx descriptor. */
++ while(myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {
++ epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);
++ /* Get the active URB for this epid */
++ urb = activeUrbList[epid];
++
++ ASSERT(epid_inuse(epid));
++ if (!urb) {
++ dma_err("No urb for epid %d in rx interrupt\n", epid);
++ goto skip_out;
++ }
++
++ /* Check if any errors on epid */
++ real_error = 0;
++ if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {
++ __u32 r_usb_ept_data;
++
++ if (usb_pipeisoc(urb->pipe)) {
++ r_usb_ept_data = etrax_epid_iso_get(epid);
++ if((r_usb_ept_data & IO_MASK(R_USB_EPT_DATA_ISO, valid)) &&
++ (IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data) == 0) &&
++ (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata))) {
++ /* Not an error, just a failure to receive an expected iso
++ in packet in this frame. This is not documented
++ in the designers reference. Continue processing.
++ */
++ } else real_error = 1;
++ } else real_error = 1;
++ }
++
++ if(real_error) {
++ dma_err("Error in RX descr on epid:%d for URB 0x%x",
++ epid, (unsigned int)urb);
++ dump_ept_data(epid);
++ dump_in_desc(myNextRxDesc);
++ goto skip_out;
++ }
++
++ urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++ ASSERT(urb_priv);
++ ASSERT(urb_priv->urb_state == STARTED ||
++ urb_priv->urb_state == UNLINK);
++
++ if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||
++ (usb_pipetype(urb->pipe) == PIPE_CONTROL) ||
++ (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
++
++ /* We get nodata for empty data transactions, and the rx descriptor's
++ hw_len field is not valid in that case. No data to copy in other
++ words. */
++ if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
++ /* No data to copy */
++ } else {
++ /*
++ dma_dbg("Processing RX for URB:0x%x epid:%d (data:%d ofs:%d)\n",
++ (unsigned int)urb, epid, myNextRxDesc->hw_len,
++ urb_priv->rx_offset);
++ */
++ /* Only copy data if URB isn't flaged to be unlinked*/
++ if(urb_priv->urb_state != UNLINK) {
++ /* Make sure the data fits in the buffer. */
++ if(urb_priv->rx_offset + myNextRxDesc->hw_len
++ <= urb->transfer_buffer_length) {
++
++ /* Copy the data to URBs buffer */
++ memcpy(urb->transfer_buffer + urb_priv->rx_offset,
++ phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);
++ urb_priv->rx_offset += myNextRxDesc->hw_len;
++ } else {
++ /* Signal overflow when returning URB */
++ urb->status = -EOVERFLOW;
++ tc_finish_urb_later(hcd, urb, urb->status);
++ }
++ }
++ }
++
++ /* Check if it was the last packet in the transfer */
++ if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {
++ /* Special handling for In Ctrl URBs. */
++ if(usb_pipecontrol(urb->pipe) && usb_pipein(urb->pipe) &&
++ !(urb_priv->ctrl_zout_done)) {
++ /* Flag that RX part of Ctrl transfer is done. Because zout descr
++ interrupt hasn't happend yet will the URB be finished in the
++ TX-Interrupt. */
++ urb_priv->ctrl_rx_done = 1;
++ tc_dbg("Not finishing In Ctrl URB:0x%x from rx_interrupt, waiting"
++ " for zout\n", (unsigned int)urb);
++ } else {
++ tc_finish_urb(hcd, urb, 0);
++ }
++ }
++ } else { /* ISOC RX */
++ /*
++ isoc_dbg("Processing RX for epid:%d (URB:0x%x) ISOC pipe\n",
++ epid, (unsigned int)urb);
++ */
++
++ struct usb_iso_packet_descriptor *packet;
++
++ if (urb_priv->urb_state == UNLINK) {
++ isoc_warn("Ignoring Isoc Rx data for urb being unlinked.\n");
++ goto skip_out;
++ } else if (urb_priv->urb_state == NOT_STARTED) {
++ isoc_err("What? Got Rx data for Isoc urb that isn't started?\n");
++ goto skip_out;
++ }
++
++ packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];
++ ASSERT(packet);
++ packet->status = 0;
++
++ if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
++ /* We get nodata for empty data transactions, and the rx descriptor's
++ hw_len field is not valid in that case. We copy 0 bytes however to
++ stay in synch. */
++ packet->actual_length = 0;
++ } else {
++ packet->actual_length = myNextRxDesc->hw_len;
++ /* Make sure the data fits in the buffer. */
++ ASSERT(packet->actual_length <= packet->length);
++ memcpy(urb->transfer_buffer + packet->offset,
++ phys_to_virt(myNextRxDesc->buf), packet->actual_length);
++ if(packet->actual_length > 0)
++ isoc_dbg("Copied %d bytes, packet %d for URB:0x%x[%d]\n",
++ packet->actual_length, urb_priv->isoc_packet_counter,
++ (unsigned int)urb, urb_priv->urb_num);
++ }
++
++ /* Increment the packet counter. */
++ urb_priv->isoc_packet_counter++;
++
++ /* Note that we don't care about the eot field in the rx descriptor's
++ status. It will always be set for isoc traffic. */
++ if (urb->number_of_packets == urb_priv->isoc_packet_counter) {
++ /* Complete the urb with status OK. */
++ tc_finish_urb(hcd, urb, 0);
++ }
++ }
++
++ skip_out:
++ myNextRxDesc->status = 0;
++ myNextRxDesc->command |= IO_MASK(USB_IN_command, eol);
++ myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);
++ myLastRxDesc = myNextRxDesc;
++ myNextRxDesc = phys_to_virt(myNextRxDesc->next);
++ flush_etrax_cache();
++ *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, restart);
++ }
++
++ local_irq_restore(flags);
++
++ return IRQ_HANDLED;
++}
++
++static void tc_bulk_start_timer_func(unsigned long dummy) {
++ /* We might enable an EP descriptor behind the current DMA position when
++ it's about to decide that there are no more bulk traffic and it should
++ stop the bulk channel.
++ Therefore we periodically check if the bulk channel is stopped and there
++ is an enabled bulk EP descriptor, in which case we start the bulk
++ channel. */
++
++ if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
++ int epid;
++
++ timer_dbg("bulk_start_timer: Bulk DMA channel not running.\n");
++
++ for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++ if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++ timer_warn("Found enabled EP for epid %d, starting bulk channel.\n",
++ epid);
++ restart_dma8_sub0();
++
++ /* Restart the bulk eot timer since we just started the bulk channel.*/
++ mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
++
++ /* No need to search any further. */
++ break;
++ }
++ }
++ } else {
++ timer_dbg("bulk_start_timer: Bulk DMA channel running.\n");
++ }
++}
++
++static void tc_bulk_eot_timer_func(unsigned long dummy) {
++ struct usb_hcd *hcd = (struct usb_hcd*)dummy;
++ ASSERT(hcd);
++ /* Because of a race condition in the top half, we might miss a bulk eot.
++ This timer "simulates" a bulk eot if we don't get one for a while,
++ hopefully correcting the situation. */
++ timer_dbg("bulk_eot_timer timed out.\n");
++ check_finished_bulk_tx_epids(hcd, 1);
++}
++
++
++/*************************************************************/
++/*************************************************************/
++/* Device driver block */
++/*************************************************************/
++/*************************************************************/
++
++/* Forward declarations for device driver functions */
++static int devdrv_hcd_probe(struct device *);
++static int devdrv_hcd_remove(struct device *);
++#ifdef CONFIG_PM
++static int devdrv_hcd_suspend(struct device *, u32, u32);
++static int devdrv_hcd_resume(struct device *, u32);
++#endif /* CONFIG_PM */
++
++/* the device */
++static struct platform_device *devdrv_hc_platform_device;
++
++/* device driver interface */
++static struct device_driver devdrv_hc_device_driver = {
++ .name = (char *) hc_name,
++ .bus = &platform_bus_type,
++
++ .probe = devdrv_hcd_probe,
++ .remove = devdrv_hcd_remove,
++
++#ifdef CONFIG_PM
++ .suspend = devdrv_hcd_suspend,
++ .resume = devdrv_hcd_resume,
++#endif /* CONFIG_PM */
++};
++
++/* initialize the host controller and driver */
++static int __init_or_module devdrv_hcd_probe(struct device *dev)
++{
++ struct usb_hcd *hcd;
++ struct crisv10_hcd *crisv10_hcd;
++ int retval;
++ int rev_maj, rev_min;
++
++ /* Check DMA burst length */
++ if(IO_EXTRACT(R_BUS_CONFIG, dma_burst, *R_BUS_CONFIG) !=
++ IO_STATE(R_BUS_CONFIG, dma_burst, burst32)) {
++ devdrv_err("Invalid DMA burst length in Etrax 100LX,"
++ " needs to be 32\n");
++ return -EPERM;
++ }
++
++ hcd = usb_create_hcd(&crisv10_hc_driver, dev, dev_name(dev));
++ if (!hcd)
++ return -ENOMEM;
++
++ crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++ spin_lock_init(&crisv10_hcd->lock);
++ crisv10_hcd->num_ports = num_ports();
++ crisv10_hcd->running = 0;
++
++ dev_set_drvdata(dev, crisv10_hcd);
++
++ devdrv_dbg("ETRAX USB IRQs HC:%d RX:%d TX:%d\n", ETRAX_USB_HC_IRQ,
++ ETRAX_USB_RX_IRQ, ETRAX_USB_TX_IRQ);
++
++ /* Print out chip version read from registers */
++ rev_maj = *R_USB_REVISION & IO_MASK(R_USB_REVISION, major);
++ rev_min = *R_USB_REVISION & IO_MASK(R_USB_REVISION, minor);
++ if(rev_min == 0) {
++ devdrv_info("Etrax 100LX USB Revision %d v1,2\n", rev_maj);
++ } else {
++ devdrv_info("Etrax 100LX USB Revision %d v%d\n", rev_maj, rev_min);
++ }
++
++ devdrv_info("Bulk timer interval, start:%d eot:%d\n",
++ BULK_START_TIMER_INTERVAL,
++ BULK_EOT_TIMER_INTERVAL);
++
++
++ /* Init root hub data structures */
++ if(rh_init()) {
++ devdrv_err("Failed init data for Root Hub\n");
++ retval = -ENOMEM;
++ }
++
++ if(port_in_use(0)) {
++ if (cris_request_io_interface(if_usb_1, "ETRAX100LX USB-HCD")) {
++ printk(KERN_CRIT "usb-host: request IO interface usb1 failed");
++ retval = -EBUSY;
++ goto out;
++ }
++ devdrv_info("Claimed interface for USB physical port 1\n");
++ }
++ if(port_in_use(1)) {
++ if (cris_request_io_interface(if_usb_2, "ETRAX100LX USB-HCD")) {
++ /* Free first interface if second failed to be claimed */
++ if(port_in_use(0)) {
++ cris_free_io_interface(if_usb_1);
++ }
++ printk(KERN_CRIT "usb-host: request IO interface usb2 failed");
++ retval = -EBUSY;
++ goto out;
++ }
++ devdrv_info("Claimed interface for USB physical port 2\n");
++ }
++
++ /* Init transfer controller structs and locks */
++ if((retval = tc_init(hcd)) != 0) {
++ goto out;
++ }
++
++ /* Attach interrupt functions for DMA and init DMA controller */
++ if((retval = tc_dma_init(hcd)) != 0) {
++ goto out;
++ }
++
++ /* Attach the top IRQ handler for USB controller interrupts */
++ if (request_irq(ETRAX_USB_HC_IRQ, crisv10_hcd_top_irq, 0,
++ "ETRAX 100LX built-in USB (HC)", hcd)) {
++ err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ);
++ retval = -EBUSY;
++ goto out;
++ }
++
++ /* iso_eof is only enabled when isoc traffic is running. */
++ *R_USB_IRQ_MASK_SET =
++ /* IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set) | */
++ IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) |
++ IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) |
++ IO_STATE(R_USB_IRQ_MASK_SET, port_status, set) |
++ IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set);
++
++
++ crisv10_ready_wait();
++ /* Reset the USB interface. */
++ *R_USB_COMMAND =
++ IO_STATE(R_USB_COMMAND, port_sel, nop) |
++ IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++ IO_STATE(R_USB_COMMAND, ctrl_cmd, reset);
++
++ /* Designer's Reference, p. 8 - 10 says we should Initate R_USB_FM_PSTART to
++ 0x2A30 (10800), to guarantee that control traffic gets 10% of the
++ bandwidth, and periodic transfer may allocate the rest (90%).
++ This doesn't work though.
++ The value 11960 is chosen to be just after the SOF token, with a couple
++ of bit times extra for possible bit stuffing. */
++ *R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 11960);
++
++ crisv10_ready_wait();
++ /* Configure the USB interface as a host controller. */
++ *R_USB_COMMAND =
++ IO_STATE(R_USB_COMMAND, port_sel, nop) |
++ IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++ IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config);
++
++
++ /* Check so controller not busy before enabling ports */
++ crisv10_ready_wait();
++
++ /* Enable selected USB ports */
++ if(port_in_use(0)) {
++ *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
++ } else {
++ *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
++ }
++ if(port_in_use(1)) {
++ *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
++ } else {
++ *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes);
++ }
++
++ crisv10_ready_wait();
++ /* Start processing of USB traffic. */
++ *R_USB_COMMAND =
++ IO_STATE(R_USB_COMMAND, port_sel, nop) |
++ IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++ IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
++
++ /* Do not continue probing initialization before USB interface is done */
++ crisv10_ready_wait();
++
++ /* Register our Host Controller to USB Core
++ * Finish the remaining parts of generic HCD initialization: allocate the
++ * buffers of consistent memory, register the bus
++ * and call the driver's reset() and start() routines. */
++ retval = usb_add_hcd(hcd, ETRAX_USB_HC_IRQ, IRQF_DISABLED);
++ if (retval != 0) {
++ devdrv_err("Failed registering HCD driver\n");
++ goto out;
++ }
++
++ return 0;
++
++ out:
++ devdrv_hcd_remove(dev);
++ return retval;
++}
++
++
++/* cleanup after the host controller and driver */
++static int __init_or_module devdrv_hcd_remove(struct device *dev)
++{
++ struct crisv10_hcd *crisv10_hcd = dev_get_drvdata(dev);
++ struct usb_hcd *hcd;
++
++ if (!crisv10_hcd)
++ return 0;
++ hcd = crisv10_hcd_to_hcd(crisv10_hcd);
++
++
++ /* Stop USB Controller in Etrax 100LX */
++ crisv10_hcd_reset(hcd);
++
++ usb_remove_hcd(hcd);
++ devdrv_dbg("Removed HCD from USB Core\n");
++
++ /* Free USB Controller IRQ */
++ free_irq(ETRAX_USB_HC_IRQ, NULL);
++
++ /* Free resources */
++ tc_dma_destroy();
++ tc_destroy();
++
++
++ if(port_in_use(0)) {
++ cris_free_io_interface(if_usb_1);
++ }
++ if(port_in_use(1)) {
++ cris_free_io_interface(if_usb_2);
++ }
++
++ devdrv_dbg("Freed all claimed resources\n");
++
++ return 0;
++}
++
++
++#ifdef CONFIG_PM
++
++static int devdrv_hcd_suspend(struct usb_hcd *hcd, u32 state, u32 level)
++{
++ return 0; /* no-op for now */
++}
++
++static int devdrv_hcd_resume(struct usb_hcd *hcd, u32 level)
++{
++ return 0; /* no-op for now */
++}
++
++#endif /* CONFIG_PM */
++
++
++
++/*************************************************************/
++/*************************************************************/
++/* Module block */
++/*************************************************************/
++/*************************************************************/
++
++/* register driver */
++static int __init module_hcd_init(void)
++{
++
++ if (usb_disabled())
++ return -ENODEV;
++
++ /* Here we select enabled ports by following defines created from
++ menuconfig */
++#ifndef CONFIG_ETRAX_USB_HOST_PORT1
++ ports &= ~(1<<0);
++#endif
++#ifndef CONFIG_ETRAX_USB_HOST_PORT2
++ ports &= ~(1<<1);
++#endif
++
++ printk(KERN_INFO "%s version "VERSION" "COPYRIGHT"\n", product_desc);
++
++ devdrv_hc_platform_device =
++ platform_device_register_simple((char *) hc_name, 0, NULL, 0);
++
++ if (IS_ERR(devdrv_hc_platform_device))
++ return PTR_ERR(devdrv_hc_platform_device);
++ return driver_register(&devdrv_hc_device_driver);
++ /*
++ * Note that we do not set the DMA mask for the device,
++ * i.e. we pretend that we will use PIO, since no specific
++ * allocation routines are needed for DMA buffers. This will
++ * cause the HCD buffer allocation routines to fall back to
++ * kmalloc().
++ */
++}
++
++/* unregister driver */
++static void __exit module_hcd_exit(void)
++{
++ driver_unregister(&devdrv_hc_device_driver);
++}
++
++
++/* Module hooks */
++module_init(module_hcd_init);
++module_exit(module_hcd_exit);
+diff -Nur linux-2.6.36.orig/drivers/usb/host/hc-crisv10.h linux-2.6.36/drivers/usb/host/hc-crisv10.h
+--- linux-2.6.36.orig/drivers/usb/host/hc-crisv10.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/drivers/usb/host/hc-crisv10.h 2010-12-28 20:35:00.000000000 +0100
+@@ -0,0 +1,331 @@
++#ifndef __LINUX_ETRAX_USB_H
++#define __LINUX_ETRAX_USB_H
++
++#include <linux/types.h>
++#include <linux/list.h>
++
++struct USB_IN_Desc {
++ volatile __u16 sw_len;
++ volatile __u16 command;
++ volatile unsigned long next;
++ volatile unsigned long buf;
++ volatile __u16 hw_len;
++ volatile __u16 status;
++};
++
++struct USB_SB_Desc {
++ volatile __u16 sw_len;
++ volatile __u16 command;
++ volatile unsigned long next;
++ volatile unsigned long buf;
++};
++
++struct USB_EP_Desc {
++ volatile __u16 hw_len;
++ volatile __u16 command;
++ volatile unsigned long sub;
++ volatile unsigned long next;
++};
++
++
++/* Root Hub port status struct */
++struct crisv10_rh {
++ volatile __u16 wPortChange[2];
++ volatile __u16 wPortStatusPrev[2];
++};
++
++/* HCD description */
++struct crisv10_hcd {
++ spinlock_t lock;
++ __u8 num_ports;
++ __u8 running;
++};
++
++
++/* Endpoint HC private data description */
++struct crisv10_ep_priv {
++ int epid;
++};
++
++/* Additional software state info for a USB Controller epid */
++struct etrax_epid {
++ __u8 inuse; /* !0 = setup in Etrax and used for a endpoint */
++ __u8 disabled; /* !0 = Temporarly disabled to avoid resubmission */
++ __u8 type; /* Setup as: PIPE_BULK, PIPE_CONTROL ... */
++ __u8 out_traffic; /* !0 = This epid is for out traffic */
++};
++
++/* Struct to hold information of scheduled later URB completion */
++struct urb_later_data {
++// struct work_struct ws;
++ struct delayed_work ws;
++ struct usb_hcd *hcd;
++ struct urb *urb;
++ int urb_num;
++ int status;
++};
++
++
++typedef enum {
++ STARTED,
++ NOT_STARTED,
++ UNLINK,
++} crisv10_urb_state_t;
++
++
++struct crisv10_urb_priv {
++ /* Sequence number for this URB. Every new submited URB gets this from
++ a incrementing counter. Used when a URB is scheduled for later finish to
++ be sure that the intended URB hasn't already been completed (device
++ drivers has a tendency to reuse URBs once they are completed, causing us
++ to not be able to single old ones out only based on the URB pointer.) */
++ __u32 urb_num;
++
++ /* The first_sb field is used for freeing all SB descriptors belonging
++ to an urb. The corresponding ep descriptor's sub pointer cannot be
++ used for this since the DMA advances the sub pointer as it processes
++ the sb list. */
++ struct USB_SB_Desc *first_sb;
++
++ /* The last_sb field referes to the last SB descriptor that belongs to
++ this urb. This is important to know so we can free the SB descriptors
++ that ranges between first_sb and last_sb. */
++ struct USB_SB_Desc *last_sb;
++
++ /* The rx_offset field is used in ctrl and bulk traffic to keep track
++ of the offset in the urb's transfer_buffer where incoming data should be
++ copied to. */
++ __u32 rx_offset;
++
++ /* Counter used in isochronous transfers to keep track of the
++ number of packets received/transmitted. */
++ __u32 isoc_packet_counter;
++
++ /* Flag that marks if this Isoc Out URB has finished it's transfer. Used
++ because several URBs can be finished before list is processed */
++ __u8 isoc_out_done;
++
++ /* This field is used to pass information about the urb's current state
++ between the various interrupt handlers (thus marked volatile). */
++ volatile crisv10_urb_state_t urb_state;
++
++ /* In Ctrl transfers consist of (at least) 3 packets: SETUP, IN and ZOUT.
++ When DMA8 sub-channel 2 has processed the SB list for this sequence we
++ get a interrupt. We also get a interrupt for In transfers and which
++ one of these interrupts that comes first depends of data size and device.
++ To be sure that we have got both interrupts before we complete the URB
++ we have these to flags that shows which part that has completed.
++ We can then check when we get one of the interrupts that if the other has
++ occured it's safe for us to complete the URB, otherwise we set appropriate
++ flag and do the completion when we get the other interrupt. */
++ volatile unsigned char ctrl_zout_done;
++ volatile unsigned char ctrl_rx_done;
++
++ /* Connection between the submitted urb and ETRAX epid number */
++ __u8 epid;
++
++ /* The rx_data_list field is used for periodic traffic, to hold
++ received data for later processing in the the complete_urb functions,
++ where the data us copied to the urb's transfer_buffer. Basically, we
++ use this intermediate storage because we don't know when it's safe to
++ reuse the transfer_buffer (FIXME?). */
++ struct list_head rx_data_list;
++
++
++ /* The interval time rounded up to closest 2^N */
++ int interval;
++
++ /* Pool of EP descriptors needed if it's a INTR transfer.
++ Amount of EPs in pool correspons to how many INTR that should
++ be inserted in TxIntrEPList (max 128, defined by MAX_INTR_INTERVAL) */
++ struct USB_EP_Desc* intr_ep_pool[128];
++
++ /* The mount of EPs allocated for this INTR URB */
++ int intr_ep_pool_length;
++
++ /* Pointer to info struct if URB is scheduled to be finished later */
++ struct urb_later_data* later_data;
++};
++
++
++/* This struct is for passing data from the top half to the bottom half irq
++ handlers */
++struct crisv10_irq_reg {
++ struct usb_hcd* hcd;
++ __u32 r_usb_epid_attn;
++ __u8 r_usb_status;
++ __u16 r_usb_rh_port_status_1;
++ __u16 r_usb_rh_port_status_2;
++ __u32 r_usb_irq_mask_read;
++ __u32 r_usb_fm_number;
++ struct work_struct usb_bh;
++};
++
++
++/* This struct is for passing data from the isoc top half to the isoc bottom
++ half. */
++struct crisv10_isoc_complete_data {
++ struct usb_hcd *hcd;
++ struct urb *urb;
++ struct work_struct usb_bh;
++};
++
++/* Entry item for URB lists for each endpint */
++typedef struct urb_entry
++{
++ struct urb *urb;
++ struct list_head list;
++} urb_entry_t;
++
++/* ---------------------------------------------------------------------------
++ Virtual Root HUB
++ ------------------------------------------------------------------------- */
++/* destination of request */
++#define RH_INTERFACE 0x01
++#define RH_ENDPOINT 0x02
++#define RH_OTHER 0x03
++
++#define RH_CLASS 0x20
++#define RH_VENDOR 0x40
++
++/* Requests: bRequest << 8 | bmRequestType */
++#define RH_GET_STATUS 0x0080
++#define RH_CLEAR_FEATURE 0x0100
++#define RH_SET_FEATURE 0x0300
++#define RH_SET_ADDRESS 0x0500
++#define RH_GET_DESCRIPTOR 0x0680
++#define RH_SET_DESCRIPTOR 0x0700
++#define RH_GET_CONFIGURATION 0x0880
++#define RH_SET_CONFIGURATION 0x0900
++#define RH_GET_STATE 0x0280
++#define RH_GET_INTERFACE 0x0A80
++#define RH_SET_INTERFACE 0x0B00
++#define RH_SYNC_FRAME 0x0C80
++/* Our Vendor Specific Request */
++#define RH_SET_EP 0x2000
++
++
++/* Hub port features */
++#define RH_PORT_CONNECTION 0x00
++#define RH_PORT_ENABLE 0x01
++#define RH_PORT_SUSPEND 0x02
++#define RH_PORT_OVER_CURRENT 0x03
++#define RH_PORT_RESET 0x04
++#define RH_PORT_POWER 0x08
++#define RH_PORT_LOW_SPEED 0x09
++#define RH_C_PORT_CONNECTION 0x10
++#define RH_C_PORT_ENABLE 0x11
++#define RH_C_PORT_SUSPEND 0x12
++#define RH_C_PORT_OVER_CURRENT 0x13
++#define RH_C_PORT_RESET 0x14
++
++/* Hub features */
++#define RH_C_HUB_LOCAL_POWER 0x00
++#define RH_C_HUB_OVER_CURRENT 0x01
++
++#define RH_DEVICE_REMOTE_WAKEUP 0x00
++#define RH_ENDPOINT_STALL 0x01
++
++/* Our Vendor Specific feature */
++#define RH_REMOVE_EP 0x00
++
++
++#define RH_ACK 0x01
++#define RH_REQ_ERR -1
++#define RH_NACK 0x00
++
++/* Field definitions for */
++
++#define USB_IN_command__eol__BITNR 0 /* command macros */
++#define USB_IN_command__eol__WIDTH 1
++#define USB_IN_command__eol__no 0
++#define USB_IN_command__eol__yes 1
++
++#define USB_IN_command__intr__BITNR 3
++#define USB_IN_command__intr__WIDTH 1
++#define USB_IN_command__intr__no 0
++#define USB_IN_command__intr__yes 1
++
++#define USB_IN_status__eop__BITNR 1 /* status macros. */
++#define USB_IN_status__eop__WIDTH 1
++#define USB_IN_status__eop__no 0
++#define USB_IN_status__eop__yes 1
++
++#define USB_IN_status__eot__BITNR 5
++#define USB_IN_status__eot__WIDTH 1
++#define USB_IN_status__eot__no 0
++#define USB_IN_status__eot__yes 1
++
++#define USB_IN_status__error__BITNR 6
++#define USB_IN_status__error__WIDTH 1
++#define USB_IN_status__error__no 0
++#define USB_IN_status__error__yes 1
++
++#define USB_IN_status__nodata__BITNR 7
++#define USB_IN_status__nodata__WIDTH 1
++#define USB_IN_status__nodata__no 0
++#define USB_IN_status__nodata__yes 1
++
++#define USB_IN_status__epid__BITNR 8
++#define USB_IN_status__epid__WIDTH 5
++
++#define USB_EP_command__eol__BITNR 0
++#define USB_EP_command__eol__WIDTH 1
++#define USB_EP_command__eol__no 0
++#define USB_EP_command__eol__yes 1
++
++#define USB_EP_command__eof__BITNR 1
++#define USB_EP_command__eof__WIDTH 1
++#define USB_EP_command__eof__no 0
++#define USB_EP_command__eof__yes 1
++
++#define USB_EP_command__intr__BITNR 3
++#define USB_EP_command__intr__WIDTH 1
++#define USB_EP_command__intr__no 0
++#define USB_EP_command__intr__yes 1
++
++#define USB_EP_command__enable__BITNR 4
++#define USB_EP_command__enable__WIDTH 1
++#define USB_EP_command__enable__no 0
++#define USB_EP_command__enable__yes 1
++
++#define USB_EP_command__hw_valid__BITNR 5
++#define USB_EP_command__hw_valid__WIDTH 1
++#define USB_EP_command__hw_valid__no 0
++#define USB_EP_command__hw_valid__yes 1
++
++#define USB_EP_command__epid__BITNR 8
++#define USB_EP_command__epid__WIDTH 5
++
++#define USB_SB_command__eol__BITNR 0 /* command macros. */
++#define USB_SB_command__eol__WIDTH 1
++#define USB_SB_command__eol__no 0
++#define USB_SB_command__eol__yes 1
++
++#define USB_SB_command__eot__BITNR 1
++#define USB_SB_command__eot__WIDTH 1
++#define USB_SB_command__eot__no 0
++#define USB_SB_command__eot__yes 1
++
++#define USB_SB_command__intr__BITNR 3
++#define USB_SB_command__intr__WIDTH 1
++#define USB_SB_command__intr__no 0
++#define USB_SB_command__intr__yes 1
++
++#define USB_SB_command__tt__BITNR 4
++#define USB_SB_command__tt__WIDTH 2
++#define USB_SB_command__tt__zout 0
++#define USB_SB_command__tt__in 1
++#define USB_SB_command__tt__out 2
++#define USB_SB_command__tt__setup 3
++
++
++#define USB_SB_command__rem__BITNR 8
++#define USB_SB_command__rem__WIDTH 6
++
++#define USB_SB_command__full__BITNR 6
++#define USB_SB_command__full__WIDTH 1
++#define USB_SB_command__full__no 0
++#define USB_SB_command__full__yes 1
++
++#endif
+diff -Nur linux-2.6.36.orig/lib/klist.c linux-2.6.36/lib/klist.c
+--- linux-2.6.36.orig/lib/klist.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/lib/klist.c 2010-12-28 20:35:00.000000000 +0100
+@@ -60,7 +60,7 @@
+ {
+ knode->n_klist = klist;
+ /* no knode deserves to start its life dead */
+- WARN_ON(knode_dead(knode));
++ //WARN_ON(knode_dead(knode));
+ }
+
+ static void knode_kill(struct klist_node *knode)
diff --git a/target/linux/patches/2.6.37/cygwin-compat.patch b/target/linux/patches/2.6.37/cygwin-compat.patch
new file mode 100644
index 000000000..17258e565
--- /dev/null
+++ b/target/linux/patches/2.6.37/cygwin-compat.patch
@@ -0,0 +1,14 @@
+diff -Nur linux-2.6.30.orig/scripts/mod/file2alias.c linux-2.6.30/scripts/mod/file2alias.c
+--- linux-2.6.30.orig/scripts/mod/file2alias.c 2009-06-10 05:05:27.000000000 +0200
++++ linux-2.6.30/scripts/mod/file2alias.c 2009-06-11 09:17:10.000000000 +0200
+@@ -29,7 +29,11 @@
+
+ #include <ctype.h>
+
++#ifdef __CYGWIN__
++typedef __uint32_t __u32;
++#else
+ typedef uint32_t __u32;
++#endif
+ typedef uint16_t __u16;
+ typedef unsigned char __u8;
diff --git a/target/linux/patches/2.6.37/drm-kconfig.patch b/target/linux/patches/2.6.37/drm-kconfig.patch
new file mode 100644
index 000000000..cfeb599f8
--- /dev/null
+++ b/target/linux/patches/2.6.37/drm-kconfig.patch
@@ -0,0 +1,36 @@
+diff -Nur linux-2.6.37.orig/drivers/gpu/drm/Kconfig linux-2.6.37/drivers/gpu/drm/Kconfig
+--- linux-2.6.37.orig/drivers/gpu/drm/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/gpu/drm/Kconfig 2011-01-11 20:20:26.000000000 +0100
+@@ -80,23 +80,6 @@
+ selected, the module will be called i810. AGP support is required
+ for this driver to work.
+
+-choice
+- prompt "Intel 830M, 845G, 852GM, 855GM, 865G"
+- depends on DRM && AGP && AGP_INTEL
+- optional
+-
+-config DRM_I830
+- tristate "i830 driver"
+- # BKL usage in order to avoid AB-BA deadlocks, i830 may get removed
+- depends on BKL
+- help
+- Choose this option if you have a system that has Intel 830M, 845G,
+- 852GM, 855GM or 865G integrated graphics. If M is selected, the
+- module will be called i830. AGP support is required for this driver
+- to work. This driver is used by the older X releases X.org 6.7 and
+- XFree86 4.3. If unsure, build this and i915 as modules and the X server
+- will load the correct one.
+-
+ config DRM_I915
+ tristate "i915 driver"
+ depends on AGP_INTEL
+@@ -130,8 +113,6 @@
+ the driver to bind to PCI devices, which precludes loading things
+ like intelfb.
+
+-endchoice
+-
+ config DRM_MGA
+ tristate "Matrox g200/g400"
+ depends on DRM && PCI
diff --git a/target/linux/patches/2.6.37/exmap.patch b/target/linux/patches/2.6.37/exmap.patch
new file mode 100644
index 000000000..012e4794e
--- /dev/null
+++ b/target/linux/patches/2.6.37/exmap.patch
@@ -0,0 +1,11 @@
+diff -Nur linux-2.6.32.orig/kernel/pid.c linux-2.6.32/kernel/pid.c
+--- linux-2.6.32.orig/kernel/pid.c 2009-12-03 04:51:21.000000000 +0100
++++ linux-2.6.32/kernel/pid.c 2009-12-06 01:04:41.000000000 +0100
+@@ -387,6 +387,7 @@
+ {
+ return find_task_by_pid_ns(vnr, current->nsproxy->pid_ns);
+ }
++EXPORT_SYMBOL(find_task_by_vpid);
+
+ struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
+ {
diff --git a/target/linux/patches/2.6.37/foxg20.patch b/target/linux/patches/2.6.37/foxg20.patch
new file mode 100644
index 000000000..9a7d7afa0
--- /dev/null
+++ b/target/linux/patches/2.6.37/foxg20.patch
@@ -0,0 +1,522 @@
+diff -Nur linux-2.6.36.orig/arch/arm/Kconfig linux-2.6.36/arch/arm/Kconfig
+--- linux-2.6.36.orig/arch/arm/Kconfig 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/arm/Kconfig 2010-12-25 17:49:20.000000000 +0100
+@@ -21,6 +21,8 @@
+ select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
+ select HAVE_GENERIC_DMA_COHERENT
+ select HAVE_KERNEL_GZIP
++ select HAVE_KERNEL_BZIP2
++ select HAVE_KERNEL_LZMA
+ select HAVE_KERNEL_LZO
+ select HAVE_KERNEL_LZMA
+ select HAVE_PERF_EVENTS
+diff -Nur linux-2.6.36.orig/arch/arm/include/asm/setup.h linux-2.6.36/arch/arm/include/asm/setup.h
+--- linux-2.6.36.orig/arch/arm/include/asm/setup.h 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/arm/include/asm/setup.h 2010-12-25 17:49:20.000000000 +0100
+@@ -18,6 +18,8 @@
+
+ #define COMMAND_LINE_SIZE 1024
+
++const char *get_system_type(void);
++
+ /* The list ends with an ATAG_NONE node. */
+ #define ATAG_NONE 0x00000000
+
+diff -Nur linux-2.6.36.orig/arch/arm/kernel/setup.c linux-2.6.36/arch/arm/kernel/setup.c
+--- linux-2.6.36.orig/arch/arm/kernel/setup.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/arm/kernel/setup.c 2010-12-25 17:49:20.000000000 +0100
+@@ -899,8 +899,12 @@
+
+ static int c_show(struct seq_file *m, void *v)
+ {
++ unsigned long n = (unsigned long) v - 1;
+ int i;
+
++ if (n == 0)
++ seq_printf(m, "system type\t\t: %s\n", get_system_type());
++
+ seq_printf(m, "Processor\t: %s rev %d (%s)\n",
+ cpu_name, read_cpuid_id() & 15, elf_platform);
+
+diff -Nur linux-2.6.36.orig/arch/arm/mach-at91/Kconfig linux-2.6.36/arch/arm/mach-at91/Kconfig
+--- linux-2.6.36.orig/arch/arm/mach-at91/Kconfig 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/arm/mach-at91/Kconfig 2010-12-25 17:49:20.000000000 +0100
+@@ -364,6 +364,15 @@
+ evaluation board.
+ <http://www.taskit.de/en/>
+
++config MACH_FOXG20
++ bool "Acme Systems FOX G20"
++ select HAVE_AT91_DATAFLASH_CARD
++ select HAVE_NAND_ATMEL_BUSWIDTH_16
++ depends on ARCH_AT91SAM9G20
++ help
++ Select this if you are using Acme Systems
++ FOX Board G20 <http://netus.acmesystems.it>
++
+ endif
+
+ if (ARCH_AT91SAM9260 || ARCH_AT91SAM9G20)
+diff -Nur linux-2.6.36.orig/arch/arm/mach-at91/Makefile linux-2.6.36/arch/arm/mach-at91/Makefile
+--- linux-2.6.36.orig/arch/arm/mach-at91/Makefile 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/arm/mach-at91/Makefile 2010-12-25 17:49:20.000000000 +0100
+@@ -72,6 +72,9 @@
+ # AT91SAM9G45 board-specific support
+ obj-$(CONFIG_MACH_AT91SAM9G45EKES) += board-sam9m10g45ek.o
+
++# FOXG20 board-specific support
++obj-$(CONFIG_MACH_FOXG20) += board-foxg20.o
++
+ # AT91CAP9 board-specific support
+ obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o
+
+diff -Nur linux-2.6.36.orig/arch/arm/mach-at91/at91sam9260_devices.c linux-2.6.36/arch/arm/mach-at91/at91sam9260_devices.c
+--- linux-2.6.36.orig/arch/arm/mach-at91/at91sam9260_devices.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/arm/mach-at91/at91sam9260_devices.c 2010-12-25 17:49:20.000000000 +0100
+@@ -454,7 +454,15 @@
+ .sda_is_open_drain = 1,
+ .scl_pin = AT91_PIN_PA24,
+ .scl_is_open_drain = 1,
++#if defined(CONFIG_MACH_FOXG20)
++ /* Some I2C devices are limited to 100 kHz and i2c-gpio.h
++ * says "frequency is (500 / udelay) kHz" so 5 is best (and is
++ * used in i2c-gpio.c)
++ */
++ .udelay = 5, /* ~100 kHz */
++#else
+ .udelay = 2, /* ~100 kHz */
++#endif
+ };
+
+ static struct platform_device at91sam9260_twi_device = {
+diff -Nur linux-2.6.36.orig/arch/arm/mach-at91/board-foxg20.c linux-2.6.36/arch/arm/mach-at91/board-foxg20.c
+--- linux-2.6.36.orig/arch/arm/mach-at91/board-foxg20.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/arch/arm/mach-at91/board-foxg20.c 2010-12-25 17:49:20.000000000 +0100
+@@ -0,0 +1,376 @@
++/*
++ * Copyright (C) 2005 SAN People
++ * Copyright (C) 2008 Atmel
++ * Copyright (C) 2010 Lee McLoughlin - lee@lmmrtech.com
++ *
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/at73c213.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
++#include <linux/clk.h>
++#include <linux/w1-gpio.h>
++
++#include <mach/hardware.h>
++#include <asm/setup.h>
++#include <asm/mach-types.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <mach/board.h>
++#include <mach/gpio.h>
++#include <mach/at91sam9_smc.h>
++
++#include "sam9_smc.h"
++#include "generic.h"
++
++/*
++ * The FOX hardware comes as the "Netus" board with just the cpu, ram,
++ * dataflash and two header connectors. This is plugged into the Fox board
++ * which provides the ethernet, usb, rtc, leds, switch, ...
++ * Other version of the Fox board are planned which could contain
++ * both NAND and sound (WM8731).
++ *
++ * By default USART4 and USART5 are not enabled (freeing up those pins
++ * for general use)
++ *
++ * Note: Enabling the NAND without a NAND device present doesn't cause
++ * any issues as on boot the probe will fail.
++ */
++/* #define FOXG20_NAND */
++/* #define FOXG20_WM8731 */
++/* #define FOX_USART4 */
++/* #define FOX_USART5 */
++
++const char *get_system_type(void)
++{
++ return "FoxBoard FOXG20";
++}
++
++static void __init foxg20_map_io(void)
++{
++ /* Initialize processor: 18.432 MHz crystal */
++ at91sam9260_initialize(18432000);
++
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
++
++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
++
++ /* USART2 on ttyS3. (Rx & Tx only) */
++ at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
++
++ /* USART3 on ttyS4. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_CTS | ATMEL_UART_RTS);
++
++#if defined(FOX_USART4)
++ /* USART4 on ttyS5. (Rx & Tx only) */
++ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
++#endif
++
++#if defined(FOX_USART5)
++ /* USART5 on ttyS6. (Rx & Tx only) */
++ at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
++#endif
++
++ /* set serial console to ttyS0 (ie, DBGU) */
++ at91_set_serial_console(0);
++}
++
++static void __init foxg20_init_irq(void)
++{
++ at91sam9260_init_interrupts(NULL);
++}
++
++
++/*
++ * USB Host port
++ */
++static struct at91_usbh_data __initdata foxg20_usbh_data = {
++ .ports = 2,
++};
++
++/*
++ * USB Device port
++ */
++static struct at91_udc_data __initdata foxg20_udc_data = {
++ .vbus_pin = AT91_PIN_PC6,
++ .pullup_pin = 0, /* pull-up driven by UDC */
++};
++
++
++/*
++ * SPI devices.
++ */
++static struct spi_board_info foxg20_spi_devices[] = {
++#if !defined(CONFIG_MMC_AT91)
++ {
++ .modalias = "mtd_dataflash",
++ .chip_select = 1,
++ .max_speed_hz = 15 * 1000 * 1000,
++ .bus_num = 0,
++ },
++#endif
++};
++
++
++/*
++ * MACB Ethernet device
++ */
++static struct at91_eth_data __initdata foxg20_macb_data = {
++ .phy_irq_pin = AT91_PIN_PA7,
++ .is_rmii = 1,
++};
++
++
++#ifdef FOXG20_NAND
++/* The Fox doesn't have NAND memory */
++/*
++ * NAND flash
++ */
++static struct mtd_partition __initdata foxg20_nand_partition[] = {
++ {
++ .name = "Bootstrap",
++ .offset = 0,
++ .size = 4 * SZ_1M,
++ },
++ {
++ .name = "Partition 1",
++ .offset = MTDPART_OFS_NXTBLK,
++ .size = 60 * SZ_1M,
++ },
++ {
++ .name = "Partition 2",
++ .offset = MTDPART_OFS_NXTBLK,
++ .size = MTDPART_SIZ_FULL,
++ },
++};
++
++static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
++{
++ *num_partitions = ARRAY_SIZE(foxg20_nand_partition);
++ return foxg20_nand_partition;
++}
++
++/* det_pin is not connected */
++static struct atmel_nand_data __initdata foxg20_nand_data = {
++ .ale = 21,
++ .cle = 22,
++ .rdy_pin = AT91_PIN_PC13,
++ .enable_pin = AT91_PIN_PC14,
++ .partition_info = nand_partitions,
++#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
++ .bus_width_16 = 1,
++#else
++ .bus_width_16 = 0,
++#endif
++};
++
++static struct sam9_smc_config __initdata foxg20_nand_smc_config = {
++ .ncs_read_setup = 0,
++ .nrd_setup = 2,
++ .ncs_write_setup = 0,
++ .nwe_setup = 2,
++
++ .ncs_read_pulse = 4,
++ .nrd_pulse = 4,
++ .ncs_write_pulse = 4,
++ .nwe_pulse = 4,
++
++ .read_cycle = 7,
++ .write_cycle = 7,
++
++ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
++ .tdf_cycles = 3,
++};
++
++static void __init foxg20_add_device_nand(void)
++{
++ /* setup bus-width (8 or 16) */
++ if (foxg20_nand_data.bus_width_16)
++ foxg20_nand_smc_config.mode |= AT91_SMC_DBW_16;
++ else
++ foxg20_nand_smc_config.mode |= AT91_SMC_DBW_8;
++
++ /* configure chip-select 3 (NAND) */
++ sam9_smc_configure(3, &foxg20_nand_smc_config);
++
++ at91_add_device_nand(&foxg20_nand_data);
++}
++#endif
++
++
++/*
++ * MCI (SD/MMC)
++ * det_pin, wp_pin and vcc_pin are not connected
++ */
++static struct at91_mmc_data __initdata foxg20_mmc_data = {
++ .slot_b = 1,
++ .wire4 = 1,
++};
++
++
++/*
++ * LEDs
++ */
++static struct gpio_led foxg20_leds[] = {
++ { /* user led, red */
++ .name = "user_led",
++ .gpio = AT91_PIN_PC7,
++ .active_low = 0,
++ .default_trigger = "heartbeat",
++ },
++};
++
++
++/*
++ * GPIO Buttons
++ */
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++static struct gpio_keys_button foxg20_buttons[] = {
++ {
++ .gpio = AT91_PIN_PC4,
++ .code = BTN_1,
++ .desc = "Button 1",
++ .active_low = 1,
++ .wakeup = 1,
++ },
++};
++
++static struct gpio_keys_platform_data foxg20_button_data = {
++ .buttons = foxg20_buttons,
++ .nbuttons = ARRAY_SIZE(foxg20_buttons),
++};
++
++static struct platform_device foxg20_button_device = {
++ .name = "gpio-keys",
++ .id = -1,
++ .num_resources = 0,
++ .dev = {
++ .platform_data = &foxg20_button_data,
++ }
++};
++
++static void __init foxg20_add_device_buttons(void)
++{
++ at91_set_gpio_input(AT91_PIN_PC4, 1); /* btn1 */
++ at91_set_deglitch(AT91_PIN_PC4, 1);
++
++ platform_device_register(&foxg20_button_device);
++}
++#else
++static void __init foxg20_add_device_buttons(void) {}
++#endif
++
++
++#if !defined(FOXG20_WM8731)
++#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
++static struct w1_gpio_platform_data w1_gpio_pdata = {
++ /* If you choose to use a pin other than PB16 it needs to be 3.3V */
++ .pin = AT91_PIN_PB16,
++ .is_open_drain = 1,
++};
++
++static struct platform_device w1_device = {
++ .name = "w1-gpio",
++ .id = -1,
++ .dev.platform_data = &w1_gpio_pdata,
++};
++
++static void __init at91_add_device_w1(void)
++{
++ at91_set_GPIO_periph(w1_gpio_pdata.pin, 1);
++ at91_set_multi_drive(w1_gpio_pdata.pin, 1);
++ platform_device_register(&w1_device);
++}
++
++#endif
++#endif
++
++
++static struct i2c_board_info __initdata foxg20_i2c_devices[] = {
++ {
++ I2C_BOARD_INFO("24c512", 0x50),
++#ifdef FOXG20_WM8731
++ I2C_BOARD_INFO("wm8731", 0x1b),
++#endif
++ },
++};
++
++
++static void __init foxg20_board_init(void)
++{
++ /* Serial */
++ at91_add_device_serial();
++ /* USB Host */
++ at91_add_device_usbh(&foxg20_usbh_data);
++ /* USB Device */
++ at91_add_device_udc(&foxg20_udc_data);
++ /* SPI */
++ at91_add_device_spi(foxg20_spi_devices, ARRAY_SIZE(foxg20_spi_devices));
++#ifdef FOXG20_NAND
++ /* The Fox doesn't have NAND memory */
++ /* NAND */
++ foxg20_add_device_nand();
++#endif
++ /* Ethernet */
++ at91_add_device_eth(&foxg20_macb_data);
++ /* MMC */
++ at91_add_device_mmc(0, &foxg20_mmc_data);
++ /* I2C */
++ at91_add_device_i2c(foxg20_i2c_devices, ARRAY_SIZE(foxg20_i2c_devices));
++ /* LEDs */
++ at91_gpio_leds(foxg20_leds, ARRAY_SIZE(foxg20_leds));
++ /* Push Buttons */
++ foxg20_add_device_buttons();
++#ifdef FOXG20_WM8731
++ /* The Fox doesn't have this sound chip */
++ /* PCK0 provides MCLK to the WM8731 */
++ at91_set_B_periph(AT91_PIN_PC1, 0);
++ /* SSC (for WM8731) */
++ at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
++#else
++#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
++ at91_add_device_w1();
++#endif
++#endif
++}
++
++MACHINE_START(AT91SAM9G20EK, "Acme Systems FOXG20")
++ /* Maintainer: Lee McLoughlin */
++ .phys_io = AT91_BASE_SYS,
++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
++ .boot_params = AT91_SDRAM_BASE + 0x100,
++ .timer = &at91sam926x_timer,
++ .map_io = foxg20_map_io,
++ .init_irq = foxg20_init_irq,
++ .init_machine = foxg20_board_init,
++MACHINE_END
+diff -Nur linux-2.6.36.orig/drivers/mmc/host/Kconfig linux-2.6.36/drivers/mmc/host/Kconfig
+--- linux-2.6.36.orig/drivers/mmc/host/Kconfig 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/mmc/host/Kconfig 2010-12-25 19:15:17.000000000 +0100
+@@ -208,12 +208,12 @@
+
+ If unsure, say N.
+
+-choice
+- prompt "Atmel SD/MMC Driver"
+- depends on AVR32 || ARCH_AT91
+- default MMC_ATMELMCI if AVR32
+- help
+- Choose which driver to use for the Atmel MCI Silicon
++#choice
++# prompt "Atmel SD/MMC Driver"
++# depends on AVR32 || ARCH_AT91
++# default MMC_ATMELMCI if AVR32
++# help
++# Choose which driver to use for the Atmel MCI Silicon
+
+ config MMC_AT91
+ tristate "AT91 SD/MMC Card Interface support"
+@@ -223,17 +223,17 @@
+
+ If unsure, say N.
+
+-config MMC_ATMELMCI
+- tristate "Atmel Multimedia Card Interface support"
+- depends on AVR32 || ARCH_AT91
+- help
+- This selects the Atmel Multimedia Card Interface driver. If
+- you have an AT32 (AVR32) or AT91 platform with a Multimedia
+- Card slot, say Y or M here.
+-
+- If unsure, say N.
+-
+-endchoice
++#config MMC_ATMELMCI
++# tristate "Atmel Multimedia Card Interface support"
++# depends on AVR32 || ARCH_AT91
++# help
++# This selects the Atmel Multimedia Card Interface driver. If
++# you have an AT32 (AVR32) or AT91 platform with a Multimedia
++# Card slot, say Y or M here.
++#
++# If unsure, say N.
++#
++#endchoice
+
+ config MMC_ATMELMCI_DMA
+ bool "Atmel MCI DMA support (EXPERIMENTAL)"
diff --git a/target/linux/patches/2.6.37/freebsd-compat.patch b/target/linux/patches/2.6.37/freebsd-compat.patch
new file mode 100644
index 000000000..051fdc63e
--- /dev/null
+++ b/target/linux/patches/2.6.37/freebsd-compat.patch
@@ -0,0 +1,11 @@
+diff -Nur linux-2.6.30.orig/arch/x86/boot/tools/build.c linux-2.6.30/arch/x86/boot/tools/build.c
+--- linux-2.6.30.orig/arch/x86/boot/tools/build.c 2009-06-10 05:05:27.000000000 +0200
++++ linux-2.6.30/arch/x86/boot/tools/build.c 2009-06-11 09:18:50.000000000 +0200
+@@ -29,7 +29,6 @@
+ #include <stdarg.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+-#include <sys/sysmacros.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <sys/mman.h>
diff --git a/target/linux/patches/2.6.37/gemalto.patch b/target/linux/patches/2.6.37/gemalto.patch
new file mode 100644
index 000000000..9461d0317
--- /dev/null
+++ b/target/linux/patches/2.6.37/gemalto.patch
@@ -0,0 +1,11 @@
+diff -Nur linux-2.6.36.orig/drivers/serial/serial_cs.c linux-2.6.36/drivers/serial/serial_cs.c
+--- linux-2.6.36.orig/drivers/serial/serial_cs.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/serial/serial_cs.c 2010-12-13 23:03:40.000000000 +0100
+@@ -794,6 +794,7 @@
+ PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
+ PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
+ PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
++ PCMCIA_DEVICE_MANF_CARD(0x0157, 0x0100), /* Gemalto SCR */
+ PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */
+ PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */
+ PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
diff --git a/target/linux/patches/2.6.37/lemote.patch b/target/linux/patches/2.6.37/lemote.patch
new file mode 100644
index 000000000..513292e96
--- /dev/null
+++ b/target/linux/patches/2.6.37/lemote.patch
@@ -0,0 +1,4271 @@
+diff -Nur linux-2.6.37.orig/arch/mips/Kconfig linux-2.6.37/arch/mips/Kconfig
+--- linux-2.6.37.orig/arch/mips/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/Kconfig 2011-01-11 20:44:43.000000000 +0100
+@@ -210,7 +210,7 @@
+
+ config MACH_LOONGSON
+ bool "Loongson family of machines"
+- select SYS_SUPPORTS_ZBOOT
++ select SYS_SUPPORTS_ZBOOT_UART16550
+ help
+ This enables the support of Loongson family of machines.
+
+@@ -1101,6 +1101,8 @@
+ bool "Loongson 2E"
+ depends on SYS_HAS_CPU_LOONGSON2E
+ select CPU_LOONGSON2
++ select GENERIC_GPIO
++ select ARCH_REQUIRE_GPIOLIB
+ help
+ The Loongson 2E processor implements the MIPS III instruction set
+ with many extensions.
+@@ -2099,6 +2101,18 @@
+ source "kernel/time/Kconfig"
+
+ #
++# High Resolution sched_clock() Configuration
++#
++
++config CPU_HAS_FIXED_C0_COUNT
++ bool
++
++config CPU_SUPPORTS_HR_SCHED_CLOCK
++ bool
++ depends on CPU_HAS_FIXED_C0_COUNT || !CPU_FREQ
++ default y
++
++#
+ # Timer Interrupt Frequency Configuration
+ #
+
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/dma-mapping.h linux-2.6.37/arch/mips/include/asm/dma-mapping.h
+--- linux-2.6.37.orig/arch/mips/include/asm/dma-mapping.h 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/dma-mapping.h 2011-01-11 20:44:43.000000000 +0100
+@@ -85,4 +85,8 @@
+ void dma_free_noncoherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
+
++#define ARCH_HAS_DMA_MMAP_COHERENT
++extern int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
++ void *cpu_addr, dma_addr_t handle, size_t size);
++
+ #endif /* _ASM_DMA_MAPPING_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h linux-2.6.37/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h 2011-01-11 20:44:43.000000000 +0100
+@@ -255,21 +255,12 @@
+ * IDE STANDARD
+ */
+ #define IDE_CAP 0x00
+-#define IDE_CONFIG 0x01
+-#define IDE_SMI 0x02
+-#define IDE_ERROR 0x03
+-#define IDE_PM 0x04
+-#define IDE_DIAG 0x05
+-
+-/*
+- * IDE SPEC.
+- */
+ #define IDE_IO_BAR 0x08
+ #define IDE_CFG 0x10
+ #define IDE_DTC 0x12
+ #define IDE_CAST 0x13
+ #define IDE_ETC 0x14
+-#define IDE_INTERNAL_PM 0x15
++#define IDE_PM 0x15
+
+ /*
+ * ACC STANDARD
+@@ -301,5 +292,40 @@
+ /* GPIO : I/O SPACE; REG : 32BITS */
+ #define GPIOL_OUT_VAL 0x00
+ #define GPIOL_OUT_EN 0x04
++#define GPIOL_OUT_AUX1_SEL 0x10
++/* SMB : I/O SPACE, REG : 8BITS WIDTH */
++#define SMB_SDA 0x00
++#define SMB_STS 0x01
++#define SMB_STS_SLVSTP (1 << 7)
++#define SMB_STS_SDAST (1 << 6)
++#define SMB_STS_BER (1 << 5)
++#define SMB_STS_NEGACK (1 << 4)
++#define SMB_STS_STASTR (1 << 3)
++#define SMB_STS_NMATCH (1 << 2)
++#define SMB_STS_MASTER (1 << 1)
++#define SMB_STS_XMIT (1 << 0)
++#define SMB_CTRL_STS 0x02
++#define SMB_CSTS_TGSTL (1 << 5)
++#define SMB_CSTS_TSDA (1 << 4)
++#define SMB_CSTS_GCMTCH (1 << 3)
++#define SMB_CSTS_MATCH (1 << 2)
++#define SMB_CSTS_BB (1 << 1)
++#define SMB_CSTS_BUSY (1 << 0)
++#define SMB_CTRL1 0x03
++#define SMB_CTRL1_STASTRE (1 << 7)
++#define SMB_CTRL1_NMINTE (1 << 6)
++#define SMB_CTRL1_GCMEN (1 << 5)
++#define SMB_CTRL1_ACK (1 << 4)
++#define SMB_CTRL1_RSVD (1 << 3)
++#define SMB_CTRL1_INTEN (1 << 2)
++#define SMB_CTRL1_STOP (1 << 1)
++#define SMB_CTRL1_START (1 << 0)
++#define SMB_ADDR 0x04
++#define SMB_ADDR_SAEN (1 << 7)
++#define SMB_CONTROLLER_ADDR (0xef << 0)
++#define SMB_CTRL2 0x05
++#define SMB_FREQ (0x20 << 1)
++#define SMB_ENABLE (0x01 << 0)
++#define SMB_CTRL3 0x06
+
+ #endif /* _CS5536_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h linux-2.6.37/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h 2011-01-11 20:44:43.000000000 +0100
+@@ -32,4 +32,9 @@
+ #define MFGPT0_CNT (MFGPT_BASE + 4)
+ #define MFGPT0_SETUP (MFGPT_BASE + 6)
+
++#define MFGPT2_CMP1 (MFGPT_BASE + 0x10)
++#define MFGPT2_CMP2 (MFGPT_BASE + 0x12)
++#define MFGPT2_CNT (MFGPT_BASE + 0x14)
++#define MFGPT2_SETUP (MFGPT_BASE + 0x16)
++
+ #endif /*!_CS5536_MFGPT_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-loongson/ec_kb3310b.h linux-2.6.37/arch/mips/include/asm/mach-loongson/ec_kb3310b.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-loongson/ec_kb3310b.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-loongson/ec_kb3310b.h 2011-01-11 20:44:43.000000000 +0100
+@@ -0,0 +1,191 @@
++/*
++ * KB3310B Embedded Controller
++ *
++ * Copyright (C) 2008 Lemote Inc.
++ * Author: liujl <liujl@lemote.com>, 2008-03-14
++ * Copyright (C) 2009 Lemote Inc.
++ * Author: Wu Zhangjin <wuzhangjin@gmail.com>
++ *
++ * 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.
++ */
++
++#ifndef _EC_KB3310B_H
++#define _EC_KB3310B_H
++
++extern unsigned char ec_read(unsigned short addr);
++extern void ec_write(unsigned short addr, unsigned char val);
++extern int ec_query_seq(unsigned char cmd);
++extern int ec_query_event_num(void);
++extern int ec_get_event_num(void);
++
++typedef int (*sci_handler) (int status);
++extern sci_handler yeeloong_report_lid_status;
++
++#define SCI_IRQ_NUM 0x0A
++
++/*
++ * The following registers are determined by the EC index configuration.
++ * 1, fill the PORT_HIGH as EC register high part.
++ * 2, fill the PORT_LOW as EC register low part.
++ * 3, fill the PORT_DATA as EC register write data or get the data from it.
++ */
++#define EC_IO_PORT_HIGH 0x0381
++#define EC_IO_PORT_LOW 0x0382
++#define EC_IO_PORT_DATA 0x0383
++
++/*
++ * EC delay time is 500us for register and status access
++ */
++#define EC_REG_DELAY 500 /* unit : us */
++#define EC_CMD_TIMEOUT 0x1000
++
++/*
++ * EC access port for SCI communication
++ */
++#define EC_CMD_PORT 0x66
++#define EC_STS_PORT 0x66
++#define EC_DAT_PORT 0x62
++#define CMD_INIT_IDLE_MODE 0xdd
++#define CMD_EXIT_IDLE_MODE 0xdf
++#define CMD_INIT_RESET_MODE 0xd8
++#define CMD_REBOOT_SYSTEM 0x8c
++#define CMD_GET_EVENT_NUM 0x84
++#define CMD_PROGRAM_PIECE 0xda
++
++/* Temperature & Fan registers */
++#define REG_TEMPERATURE_VALUE 0xF458
++#define REG_FAN_AUTO_MAN_SWITCH 0xF459
++#define BIT_FAN_AUTO 0
++#define BIT_FAN_MANUAL 1
++#define REG_FAN_CONTROL 0xF4D2
++#define BIT_FAN_CONTROL_ON (1 << 0)
++#define BIT_FAN_CONTROL_OFF (0 << 0)
++#define REG_FAN_STATUS 0xF4DA
++#define BIT_FAN_STATUS_ON (1 << 0)
++#define BIT_FAN_STATUS_OFF (0 << 0)
++#define REG_FAN_SPEED_HIGH 0xFE22
++#define REG_FAN_SPEED_LOW 0xFE23
++#define REG_FAN_SPEED_LEVEL 0xF4CC
++/* Fan speed divider */
++#define FAN_SPEED_DIVIDER 480000 /* (60*1000*1000/62.5/2)*/
++
++/* Battery registers */
++#define REG_BAT_DESIGN_CAP_HIGH 0xF77D
++#define REG_BAT_DESIGN_CAP_LOW 0xF77E
++#define REG_BAT_FULLCHG_CAP_HIGH 0xF780
++#define REG_BAT_FULLCHG_CAP_LOW 0xF781
++#define REG_BAT_DESIGN_VOL_HIGH 0xF782
++#define REG_BAT_DESIGN_VOL_LOW 0xF783
++#define REG_BAT_CURRENT_HIGH 0xF784
++#define REG_BAT_CURRENT_LOW 0xF785
++#define REG_BAT_VOLTAGE_HIGH 0xF786
++#define REG_BAT_VOLTAGE_LOW 0xF787
++#define REG_BAT_TEMPERATURE_HIGH 0xF788
++#define REG_BAT_TEMPERATURE_LOW 0xF789
++#define REG_BAT_RELATIVE_CAP_HIGH 0xF492
++#define REG_BAT_RELATIVE_CAP_LOW 0xF493
++#define REG_BAT_VENDOR 0xF4C4
++#define FLAG_BAT_VENDOR_SANYO 0x01
++#define FLAG_BAT_VENDOR_SIMPLO 0x02
++#define REG_BAT_CELL_COUNT 0xF4C6
++#define FLAG_BAT_CELL_3S1P 0x03
++#define FLAG_BAT_CELL_3S2P 0x06
++#define REG_BAT_CHARGE 0xF4A2
++#define FLAG_BAT_CHARGE_DISCHARGE 0x01
++#define FLAG_BAT_CHARGE_CHARGE 0x02
++#define FLAG_BAT_CHARGE_ACPOWER 0x00
++#define REG_BAT_STATUS 0xF4B0
++#define BIT_BAT_STATUS_LOW (1 << 5)
++#define BIT_BAT_STATUS_DESTROY (1 << 2)
++#define BIT_BAT_STATUS_FULL (1 << 1)
++#define BIT_BAT_STATUS_IN (1 << 0)
++#define REG_BAT_CHARGE_STATUS 0xF4B1
++#define BIT_BAT_CHARGE_STATUS_OVERTEMP (1 << 2)
++#define BIT_BAT_CHARGE_STATUS_PRECHG (1 << 1)
++#define REG_BAT_STATE 0xF482
++#define BIT_BAT_STATE_CHARGING (1 << 1)
++#define BIT_BAT_STATE_DISCHARGING (1 << 0)
++#define REG_BAT_POWER 0xF440
++#define BIT_BAT_POWER_S3 (1 << 2)
++#define BIT_BAT_POWER_ON (1 << 1)
++#define BIT_BAT_POWER_ACIN (1 << 0)
++
++/* Audio: rd/wr */
++#define REG_AUDIO_VOLUME 0xF46C
++#define REG_AUDIO_MUTE 0xF4E7
++#define REG_AUDIO_BEEP 0xF4D0
++/* USB port power or not: rd/wr */
++#define REG_USB0_FLAG 0xF461
++#define REG_USB1_FLAG 0xF462
++#define REG_USB2_FLAG 0xF463
++#define BIT_USB_FLAG_ON 1
++#define BIT_USB_FLAG_OFF 0
++/* LID */
++#define REG_LID_DETECT 0xF4BD
++#define BIT_LID_DETECT_ON 1
++#define BIT_LID_DETECT_OFF 0
++/* CRT */
++#define REG_CRT_DETECT 0xF4AD
++#define BIT_CRT_DETECT_PLUG 1
++#define BIT_CRT_DETECT_UNPLUG 0
++/* LCD backlight brightness adjust: 9 levels */
++#define REG_DISPLAY_BRIGHTNESS 0xF4F5
++/* Black screen Status */
++#define BIT_DISPLAY_LCD_ON 1
++#define BIT_DISPLAY_LCD_OFF 0
++/* LCD backlight control: off/restore */
++#define REG_BACKLIGHT_CTRL 0xF7BD
++#define BIT_BACKLIGHT_ON 1
++#define BIT_BACKLIGHT_OFF 0
++/* Reset the machine auto-clear: rd/wr */
++#define REG_RESET 0xF4EC
++#define BIT_RESET_ON 1
++/* Light the led: rd/wr */
++#define REG_LED 0xF4C8
++#define BIT_LED_RED_POWER (1 << 0)
++#define BIT_LED_ORANGE_POWER (1 << 1)
++#define BIT_LED_GREEN_CHARGE (1 << 2)
++#define BIT_LED_RED_CHARGE (1 << 3)
++#define BIT_LED_NUMLOCK (1 << 4)
++/* Test led mode, all led on/off */
++#define REG_LED_TEST 0xF4C2
++#define BIT_LED_TEST_IN 1
++#define BIT_LED_TEST_OUT 0
++/* Camera on/off */
++#define REG_CAMERA_STATUS 0xF46A
++#define BIT_CAMERA_STATUS_ON 1
++#define BIT_CAMERA_STATUS_OFF 0
++#define REG_CAMERA_CONTROL 0xF7B7
++#define BIT_CAMERA_CONTROL_OFF 0
++#define BIT_CAMERA_CONTROL_ON 1
++/* Wlan Status */
++#define REG_WLAN 0xF4FA
++#define BIT_WLAN_ON 1
++#define BIT_WLAN_OFF 0
++#define REG_DISPLAY_LCD 0xF79F
++
++/* SCI Event Number from EC */
++enum {
++ EVENT_LID = 0x23, /* Turn on/off LID */
++ EVENT_SWITCHVIDEOMODE, /* Fn+F3 for display switch */
++ EVENT_SLEEP, /* Fn+F1 for entering sleep mode */
++ EVENT_OVERTEMP, /* Over-temperature happened */
++ EVENT_CRT_DETECT, /* CRT is connected */
++ EVENT_CAMERA, /* Camera on/off */
++ EVENT_USB_OC2, /* USB2 Over Current occurred */
++ EVENT_USB_OC0, /* USB0 Over Current occurred */
++ EVENT_DISPLAYTOGGLE, /* Fn+F2, Turn on/off backlight */
++ EVENT_AUDIO_MUTE, /* Fn+F4, Mute on/off */
++ EVENT_DISPLAY_BRIGHTNESS,/* Fn+^/V, LCD backlight brightness adjust */
++ EVENT_AC_BAT, /* AC & Battery relative issue */
++ EVENT_AUDIO_VOLUME, /* Fn+<|>, Volume adjust */
++ EVENT_WLAN, /* Wlan on/off */
++};
++
++#define EVENT_START EVENT_LID
++#define EVENT_END EVENT_WLAN
++
++#endif /* !_EC_KB3310B_H */
+diff -Nur linux-2.6.37.orig/arch/mips/include/asm/mach-loongson/loongson.h linux-2.6.37/arch/mips/include/asm/mach-loongson/loongson.h
+--- linux-2.6.37.orig/arch/mips/include/asm/mach-loongson/loongson.h 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/include/asm/mach-loongson/loongson.h 2011-01-11 20:44:43.000000000 +0100
+@@ -43,6 +43,12 @@
+ #endif
+ }
+
++/*
++ * Copy kernel command line from arcs_cmdline
++ */
++#include <asm/setup.h>
++extern char loongson_cmdline[COMMAND_LINE_SIZE];
++
+ /* irq operation functions */
+ extern void bonito_irqdispatch(void);
+ extern void __init bonito_irq_init(void);
+diff -Nur linux-2.6.37.orig/arch/mips/kernel/csrc-r4k.c linux-2.6.37/arch/mips/kernel/csrc-r4k.c
+--- linux-2.6.37.orig/arch/mips/kernel/csrc-r4k.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/kernel/csrc-r4k.c 2011-01-11 20:44:43.000000000 +0100
+@@ -6,10 +6,66 @@
+ * Copyright (C) 2007 by Ralf Baechle
+ */
+ #include <linux/clocksource.h>
++#include <linux/cnt32_to_63.h>
+ #include <linux/init.h>
++#include <linux/timer.h>
+
+ #include <asm/time.h>
+
++#ifdef CONFIG_CPU_SUPPORTS_HR_SCHED_CLOCK
++/*
++ * MIPS sched_clock implementation.
++ *
++ * Because the hardware timer period is quite short and because cnt32_to_63()
++ * needs to be called at least once per half period to work properly, a kernel
++ * timer is set up to ensure this requirement is always met.
++ *
++ * Please refer to include/linux/cnt32_to_63.h and arch/arm/plat-orion/time.c
++ */
++#define CLOCK2NS_SCALE_FACTOR 8
++
++static unsigned long clock2ns_scale __read_mostly;
++
++unsigned long long notrace sched_clock(void)
++{
++ unsigned long long v = cnt32_to_63(read_c0_count());
++ return (v * clock2ns_scale) >> CLOCK2NS_SCALE_FACTOR;
++}
++
++static struct timer_list cnt32_to_63_keepwarm_timer;
++
++static void cnt32_to_63_keepwarm(unsigned long data)
++{
++ mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data));
++ sched_clock();
++}
++#endif
++
++static inline void setup_hres_sched_clock(unsigned long clock)
++{
++#ifdef CONFIG_CPU_SUPPORTS_HR_SCHED_CLOCK
++ unsigned long long v;
++ unsigned long data;
++
++ v = NSEC_PER_SEC;
++ v <<= CLOCK2NS_SCALE_FACTOR;
++ v += clock/2;
++ do_div(v, clock);
++ /*
++ * We want an even value to automatically clear the top bit
++ * returned by cnt32_to_63() without an additional run time
++ * instruction. So if the LSB is 1 then round it up.
++ */
++ if (v & 1)
++ v++;
++ clock2ns_scale = v;
++
++ data = 0x80000000UL / clock * HZ;
++ setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, data);
++ mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data));
++#endif
++}
++
+ static cycle_t c0_hpt_read(struct clocksource *cs)
+ {
+ return read_c0_count();
+@@ -27,6 +83,8 @@
+ if (!cpu_has_counter || !mips_hpt_frequency)
+ return -ENXIO;
+
++ setup_hres_sched_clock(mips_hpt_frequency);
++
+ /* Calculate a somewhat reasonable rating value */
+ clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
+
+diff -Nur linux-2.6.37.orig/arch/mips/kernel/time.c linux-2.6.37/arch/mips/kernel/time.c
+--- linux-2.6.37.orig/arch/mips/kernel/time.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/kernel/time.c 2011-01-11 20:44:43.000000000 +0100
+@@ -119,6 +119,11 @@
+
+ void __init time_init(void)
+ {
++#ifdef CONFIG_HR_SCHED_CLOCK
++ if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug())
++ write_c0_count(0);
++#endif
++
+ plat_time_init();
+
+ if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug())
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/common/cmdline.c linux-2.6.37/arch/mips/loongson/common/cmdline.c
+--- linux-2.6.37.orig/arch/mips/loongson/common/cmdline.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/common/cmdline.c 2011-01-11 20:44:43.000000000 +0100
+@@ -17,10 +17,15 @@
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
++#include <linux/module.h>
+ #include <asm/bootinfo.h>
+
+ #include <loongson.h>
+
++/* the kernel command line copied from arcs_cmdline */
++char loongson_cmdline[COMMAND_LINE_SIZE];
++EXPORT_SYMBOL(loongson_cmdline);
++
+ void __init prom_init_cmdline(void)
+ {
+ int prom_argc;
+@@ -50,4 +55,26 @@
+ strcat(arcs_cmdline, " root=/dev/hda1");
+
+ prom_init_machtype();
++
++ /* append machine specific command line */
++ switch (mips_machtype) {
++ case MACH_LEMOTE_LL2F:
++ if ((strstr(arcs_cmdline, "video=")) == NULL)
++ strcat(arcs_cmdline, " video=sisfb:1360x768-16@60");
++ break;
++ case MACH_LEMOTE_FL2F:
++ if ((strstr(arcs_cmdline, "ide_core.ignore_cable=")) == NULL)
++ strcat(arcs_cmdline, " ide_core.ignore_cable=0");
++ break;
++ case MACH_LEMOTE_ML2F7:
++ /* Mengloong-2F has a 800x480 screen */
++ if ((strstr(arcs_cmdline, "vga=")) == NULL)
++ strcat(arcs_cmdline, " vga=0x313");
++ break;
++ default:
++ break;
++ }
++
++ /* copy arcs_cmdline into loongson_cmdline */
++ strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE);
+ }
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/common/cs5536/cs5536_acc.c linux-2.6.37/arch/mips/loongson/common/cs5536/cs5536_acc.c
+--- linux-2.6.37.orig/arch/mips/loongson/common/cs5536/cs5536_acc.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/common/cs5536/cs5536_acc.c 2011-01-11 20:44:43.000000000 +0100
+@@ -18,7 +18,7 @@
+
+ void pci_acc_write_reg(int reg, u32 value)
+ {
+- u32 hi = 0, lo = value;
++ u32 hi, lo;
+
+ switch (reg) {
+ case PCI_COMMAND:
+@@ -66,75 +66,73 @@
+ u32 pci_acc_read_reg(int reg)
+ {
+ u32 hi, lo;
+- u32 conf_data = 0;
++ u32 cfg = 0;
+
+ switch (reg) {
+ case PCI_VENDOR_ID:
+- conf_data =
+- CFG_PCI_VENDOR_ID(CS5536_ACC_DEVICE_ID, CS5536_VENDOR_ID);
++ cfg = CFG_PCI_VENDOR_ID(CS5536_ACC_DEVICE_ID,
++ CS5536_VENDOR_ID);
+ break;
+ case PCI_COMMAND:
+ _rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
+ if (((lo & 0xfff00000) || (hi & 0x000000ff))
+ && ((hi & 0xf0000000) == 0xa0000000))
+- conf_data |= PCI_COMMAND_IO;
++ cfg |= PCI_COMMAND_IO;
+ _rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
+ if ((lo & 0x300) == 0x300)
+- conf_data |= PCI_COMMAND_MASTER;
++ cfg |= PCI_COMMAND_MASTER;
+ break;
+ case PCI_STATUS:
+- conf_data |= PCI_STATUS_66MHZ;
+- conf_data |= PCI_STATUS_FAST_BACK;
++ cfg |= PCI_STATUS_66MHZ;
++ cfg |= PCI_STATUS_FAST_BACK;
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG)
+- conf_data |= PCI_STATUS_PARITY;
+- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
++ cfg |= PCI_STATUS_PARITY;
++ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
+ break;
+ case PCI_CLASS_REVISION:
+ _rdmsr(ACC_MSR_REG(ACC_CAP), &hi, &lo);
+- conf_data = lo & 0x000000ff;
+- conf_data |= (CS5536_ACC_CLASS_CODE << 8);
++ cfg = lo & 0x000000ff;
++ cfg |= (CS5536_ACC_CLASS_CODE << 8);
+ break;
+ case PCI_CACHE_LINE_SIZE:
+- conf_data =
+- CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+- PCI_NORMAL_LATENCY_TIMER);
++ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
++ PCI_NORMAL_LATENCY_TIMER);
+ break;
+ case PCI_BAR0_REG:
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ if (lo & SOFT_BAR_ACC_FLAG) {
+- conf_data = CS5536_ACC_RANGE |
++ cfg = CS5536_ACC_RANGE |
+ PCI_BASE_ADDRESS_SPACE_IO;
+ lo &= ~SOFT_BAR_ACC_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else {
+ _rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
+- conf_data = (hi & 0x000000ff) << 12;
+- conf_data |= (lo & 0xfff00000) >> 20;
+- conf_data |= 0x01;
+- conf_data &= ~0x02;
++ cfg = (hi & 0x000000ff) << 12;
++ cfg |= (lo & 0xfff00000) >> 20;
++ cfg |= 0x01;
++ cfg &= ~0x02;
+ }
+ break;
+ case PCI_CARDBUS_CIS:
+- conf_data = PCI_CARDBUS_CIS_POINTER;
++ cfg = PCI_CARDBUS_CIS_POINTER;
+ break;
+ case PCI_SUBSYSTEM_VENDOR_ID:
+- conf_data =
+- CFG_PCI_VENDOR_ID(CS5536_ACC_SUB_ID, CS5536_SUB_VENDOR_ID);
++ cfg = CFG_PCI_VENDOR_ID(CS5536_ACC_SUB_ID,
++ CS5536_SUB_VENDOR_ID);
+ break;
+ case PCI_ROM_ADDRESS:
+- conf_data = PCI_EXPANSION_ROM_BAR;
++ cfg = PCI_EXPANSION_ROM_BAR;
+ break;
+ case PCI_CAPABILITY_LIST:
+- conf_data = PCI_CAPLIST_USB_POINTER;
++ cfg = PCI_CAPLIST_USB_POINTER;
+ break;
+ case PCI_INTERRUPT_LINE:
+- conf_data =
+- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_ACC_INTR);
++ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_ACC_INTR);
+ break;
+ default:
+ break;
+ }
+
+- return conf_data;
++ return cfg;
+ }
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/common/cs5536/cs5536_ehci.c linux-2.6.37/arch/mips/loongson/common/cs5536/cs5536_ehci.c
+--- linux-2.6.37.orig/arch/mips/loongson/common/cs5536/cs5536_ehci.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/common/cs5536/cs5536_ehci.c 2011-01-11 20:44:43.000000000 +0100
+@@ -18,7 +18,7 @@
+
+ void pci_ehci_write_reg(int reg, u32 value)
+ {
+- u32 hi = 0, lo = value;
++ u32 hi, lo;
+
+ switch (reg) {
+ case PCI_COMMAND:
+@@ -78,83 +78,81 @@
+
+ u32 pci_ehci_read_reg(int reg)
+ {
+- u32 conf_data = 0;
++ u32 cfg = 0;
+ u32 hi, lo;
+
+ switch (reg) {
+ case PCI_VENDOR_ID:
+- conf_data =
+- CFG_PCI_VENDOR_ID(CS5536_EHCI_DEVICE_ID, CS5536_VENDOR_ID);
++ cfg = CFG_PCI_VENDOR_ID(CS5536_EHCI_DEVICE_ID,
++ CS5536_VENDOR_ID);
+ break;
+ case PCI_COMMAND:
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+ if (hi & PCI_COMMAND_MASTER)
+- conf_data |= PCI_COMMAND_MASTER;
++ cfg |= PCI_COMMAND_MASTER;
+ if (hi & PCI_COMMAND_MEMORY)
+- conf_data |= PCI_COMMAND_MEMORY;
++ cfg |= PCI_COMMAND_MEMORY;
+ break;
+ case PCI_STATUS:
+- conf_data |= PCI_STATUS_66MHZ;
+- conf_data |= PCI_STATUS_FAST_BACK;
++ cfg |= PCI_STATUS_66MHZ;
++ cfg |= PCI_STATUS_FAST_BACK;
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG)
+- conf_data |= PCI_STATUS_PARITY;
+- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
++ cfg |= PCI_STATUS_PARITY;
++ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
+ break;
+ case PCI_CLASS_REVISION:
+ _rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
+- conf_data = lo & 0x000000ff;
+- conf_data |= (CS5536_EHCI_CLASS_CODE << 8);
++ cfg = lo & 0x000000ff;
++ cfg |= (CS5536_EHCI_CLASS_CODE << 8);
+ break;
+ case PCI_CACHE_LINE_SIZE:
+- conf_data =
+- CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+- PCI_NORMAL_LATENCY_TIMER);
++ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
++ PCI_NORMAL_LATENCY_TIMER);
+ break;
+ case PCI_BAR0_REG:
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ if (lo & SOFT_BAR_EHCI_FLAG) {
+- conf_data = CS5536_EHCI_RANGE |
++ cfg = CS5536_EHCI_RANGE |
+ PCI_BASE_ADDRESS_SPACE_MEMORY;
+ lo &= ~SOFT_BAR_EHCI_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else {
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+- conf_data = lo & 0xfffff000;
++ cfg = lo & 0xfffff000;
+ }
+ break;
+ case PCI_CARDBUS_CIS:
+- conf_data = PCI_CARDBUS_CIS_POINTER;
++ cfg = PCI_CARDBUS_CIS_POINTER;
+ break;
+ case PCI_SUBSYSTEM_VENDOR_ID:
+- conf_data =
+- CFG_PCI_VENDOR_ID(CS5536_EHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
++ cfg = CFG_PCI_VENDOR_ID(CS5536_EHCI_SUB_ID,
++ CS5536_SUB_VENDOR_ID);
+ break;
+ case PCI_ROM_ADDRESS:
+- conf_data = PCI_EXPANSION_ROM_BAR;
++ cfg = PCI_EXPANSION_ROM_BAR;
+ break;
+ case PCI_CAPABILITY_LIST:
+- conf_data = PCI_CAPLIST_USB_POINTER;
++ cfg = PCI_CAPLIST_USB_POINTER;
+ break;
+ case PCI_INTERRUPT_LINE:
+- conf_data =
+- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
++ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
+ break;
+ case PCI_EHCI_LEGSMIEN_REG:
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+- conf_data = (hi & 0x003f0000) >> 16;
++ cfg = (hi & 0x003f0000) >> 16;
+ break;
+ case PCI_EHCI_LEGSMISTS_REG:
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+- conf_data = (hi & 0x3f000000) >> 24;
++ cfg = (hi & 0x3f000000) >> 24;
+ break;
+ case PCI_EHCI_FLADJ_REG:
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+- conf_data = hi & 0x00003f00;
++ cfg = hi & 0x00003f00;
+ break;
+ default:
+ break;
+ }
+
+- return conf_data;
++ return cfg;
+ }
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/common/cs5536/cs5536_ide.c linux-2.6.37/arch/mips/loongson/common/cs5536/cs5536_ide.c
+--- linux-2.6.37.orig/arch/mips/loongson/common/cs5536/cs5536_ide.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/common/cs5536/cs5536_ide.c 2011-01-11 20:44:43.000000000 +0100
+@@ -18,7 +18,7 @@
+
+ void pci_ide_write_reg(int reg, u32 value)
+ {
+- u32 hi = 0, lo = value;
++ u32 hi, lo;
+
+ switch (reg) {
+ case PCI_COMMAND:
+@@ -72,26 +72,16 @@
+ _wrmsr(IDE_MSR_REG(IDE_CFG), hi, lo);
+ }
+ break;
+- case PCI_IDE_DTC_REG:
+- _rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
+- lo = value;
+- _wrmsr(IDE_MSR_REG(IDE_DTC), hi, lo);
+- break;
+- case PCI_IDE_CAST_REG:
+- _rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
+- lo = value;
+- _wrmsr(IDE_MSR_REG(IDE_CAST), hi, lo);
+- break;
+- case PCI_IDE_ETC_REG:
+- _rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
+- lo = value;
+- _wrmsr(IDE_MSR_REG(IDE_ETC), hi, lo);
+- break;
+- case PCI_IDE_PM_REG:
+- _rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
+- lo = value;
+- _wrmsr(IDE_MSR_REG(IDE_INTERNAL_PM), hi, lo);
+- break;
++#define SET_PCI_IDE_REG(r) \
++ case PCI_IDE_##r##_REG: \
++ _rdmsr(IDE_MSR_REG(IDE_##r), &hi, &lo); \
++ lo = value; \
++ _wrmsr(IDE_MSR_REG(IDE_##r), hi, lo); \
++ break;
++ SET_PCI_IDE_REG(DTC)
++ SET_PCI_IDE_REG(CAST)
++ SET_PCI_IDE_REG(ETC)
++ SET_PCI_IDE_REG(PM)
+ default:
+ break;
+ }
+@@ -99,94 +89,82 @@
+
+ u32 pci_ide_read_reg(int reg)
+ {
+- u32 conf_data = 0;
++ u32 cfg = 0;
+ u32 hi, lo;
+
+ switch (reg) {
+ case PCI_VENDOR_ID:
+- conf_data =
+- CFG_PCI_VENDOR_ID(CS5536_IDE_DEVICE_ID, CS5536_VENDOR_ID);
++ cfg = CFG_PCI_VENDOR_ID(CS5536_IDE_DEVICE_ID,
++ CS5536_VENDOR_ID);
+ break;
+ case PCI_COMMAND:
+ _rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
+ if (lo & 0xfffffff0)
+- conf_data |= PCI_COMMAND_IO;
++ cfg |= PCI_COMMAND_IO;
+ _rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
+ if ((lo & 0x30) == 0x30)
+- conf_data |= PCI_COMMAND_MASTER;
++ cfg |= PCI_COMMAND_MASTER;
+ break;
+ case PCI_STATUS:
+- conf_data |= PCI_STATUS_66MHZ;
+- conf_data |= PCI_STATUS_FAST_BACK;
++ cfg |= PCI_STATUS_66MHZ;
++ cfg |= PCI_STATUS_FAST_BACK;
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG)
+- conf_data |= PCI_STATUS_PARITY;
+- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
++ cfg |= PCI_STATUS_PARITY;
++ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
+ break;
+ case PCI_CLASS_REVISION:
+ _rdmsr(IDE_MSR_REG(IDE_CAP), &hi, &lo);
+- conf_data = lo & 0x000000ff;
+- conf_data |= (CS5536_IDE_CLASS_CODE << 8);
++ cfg = lo & 0x000000ff;
++ cfg |= (CS5536_IDE_CLASS_CODE << 8);
+ break;
+ case PCI_CACHE_LINE_SIZE:
+ _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
+ hi &= 0x000000f8;
+- conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, hi);
++ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, hi);
+ break;
+ case PCI_BAR4_REG:
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ if (lo & SOFT_BAR_IDE_FLAG) {
+- conf_data = CS5536_IDE_RANGE |
++ cfg = CS5536_IDE_RANGE |
+ PCI_BASE_ADDRESS_SPACE_IO;
+ lo &= ~SOFT_BAR_IDE_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else {
+ _rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
+- conf_data = lo & 0xfffffff0;
+- conf_data |= 0x01;
+- conf_data &= ~0x02;
++ cfg = lo & 0xfffffff0;
++ cfg |= 0x01;
++ cfg &= ~0x02;
+ }
+ break;
+ case PCI_CARDBUS_CIS:
+- conf_data = PCI_CARDBUS_CIS_POINTER;
++ cfg = PCI_CARDBUS_CIS_POINTER;
+ break;
+ case PCI_SUBSYSTEM_VENDOR_ID:
+- conf_data =
+- CFG_PCI_VENDOR_ID(CS5536_IDE_SUB_ID, CS5536_SUB_VENDOR_ID);
++ cfg = CFG_PCI_VENDOR_ID(CS5536_IDE_SUB_ID,
++ CS5536_SUB_VENDOR_ID);
+ break;
+ case PCI_ROM_ADDRESS:
+- conf_data = PCI_EXPANSION_ROM_BAR;
++ cfg = PCI_EXPANSION_ROM_BAR;
+ break;
+ case PCI_CAPABILITY_LIST:
+- conf_data = PCI_CAPLIST_POINTER;
++ cfg = PCI_CAPLIST_POINTER;
+ break;
+ case PCI_INTERRUPT_LINE:
+- conf_data =
+- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_IDE_INTR);
+- break;
+- case PCI_IDE_CFG_REG:
+- _rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
+- conf_data = lo;
+- break;
+- case PCI_IDE_DTC_REG:
+- _rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
+- conf_data = lo;
+- break;
+- case PCI_IDE_CAST_REG:
+- _rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
+- conf_data = lo;
+- break;
+- case PCI_IDE_ETC_REG:
+- _rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
+- conf_data = lo;
+- break;
+- case PCI_IDE_PM_REG:
+- _rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
+- conf_data = lo;
++ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_IDE_INTR);
+ break;
++#define GET_PCI_IDE_REG(r) \
++ case PCI_IDE_##r##_REG: \
++ _rdmsr(IDE_MSR_REG(IDE_##r), &hi, &cfg); \
++ break;
++ GET_PCI_IDE_REG(CFG)
++ GET_PCI_IDE_REG(DTC)
++ GET_PCI_IDE_REG(CAST)
++ GET_PCI_IDE_REG(ETC)
++ GET_PCI_IDE_REG(PM)
+ default:
+ break;
+ }
+
+- return conf_data;
++ return cfg;
+ }
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/common/cs5536/cs5536_ohci.c linux-2.6.37/arch/mips/loongson/common/cs5536/cs5536_ohci.c
+--- linux-2.6.37.orig/arch/mips/loongson/common/cs5536/cs5536_ohci.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/common/cs5536/cs5536_ohci.c 2011-01-11 20:44:43.000000000 +0100
+@@ -18,7 +18,7 @@
+
+ void pci_ohci_write_reg(int reg, u32 value)
+ {
+- u32 hi = 0, lo = value;
++ u32 hi, lo;
+
+ switch (reg) {
+ case PCI_COMMAND:
+@@ -73,77 +73,75 @@
+
+ u32 pci_ohci_read_reg(int reg)
+ {
+- u32 conf_data = 0;
++ u32 cfg = 0;
+ u32 hi, lo;
+
+ switch (reg) {
+ case PCI_VENDOR_ID:
+- conf_data =
+- CFG_PCI_VENDOR_ID(CS5536_OHCI_DEVICE_ID, CS5536_VENDOR_ID);
++ cfg = CFG_PCI_VENDOR_ID(CS5536_OHCI_DEVICE_ID,
++ CS5536_VENDOR_ID);
+ break;
+ case PCI_COMMAND:
+ _rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
+ if (hi & PCI_COMMAND_MASTER)
+- conf_data |= PCI_COMMAND_MASTER;
++ cfg |= PCI_COMMAND_MASTER;
+ if (hi & PCI_COMMAND_MEMORY)
+- conf_data |= PCI_COMMAND_MEMORY;
++ cfg |= PCI_COMMAND_MEMORY;
+ break;
+ case PCI_STATUS:
+- conf_data |= PCI_STATUS_66MHZ;
+- conf_data |= PCI_STATUS_FAST_BACK;
++ cfg |= PCI_STATUS_66MHZ;
++ cfg |= PCI_STATUS_FAST_BACK;
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG)
+- conf_data |= PCI_STATUS_PARITY;
+- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
++ cfg |= PCI_STATUS_PARITY;
++ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
+ break;
+ case PCI_CLASS_REVISION:
+ _rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
+- conf_data = lo & 0x000000ff;
+- conf_data |= (CS5536_OHCI_CLASS_CODE << 8);
++ cfg = lo & 0x000000ff;
++ cfg |= (CS5536_OHCI_CLASS_CODE << 8);
+ break;
+ case PCI_CACHE_LINE_SIZE:
+- conf_data =
+- CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+- PCI_NORMAL_LATENCY_TIMER);
++ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
++ PCI_NORMAL_LATENCY_TIMER);
+ break;
+ case PCI_BAR0_REG:
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ if (lo & SOFT_BAR_OHCI_FLAG) {
+- conf_data = CS5536_OHCI_RANGE |
++ cfg = CS5536_OHCI_RANGE |
+ PCI_BASE_ADDRESS_SPACE_MEMORY;
+ lo &= ~SOFT_BAR_OHCI_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else {
+ _rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
+- conf_data = lo & 0xffffff00;
+- conf_data &= ~0x0000000f; /* 32bit mem */
++ cfg = lo & 0xffffff00;
++ cfg &= ~0x0000000f; /* 32bit mem */
+ }
+ break;
+ case PCI_CARDBUS_CIS:
+- conf_data = PCI_CARDBUS_CIS_POINTER;
++ cfg = PCI_CARDBUS_CIS_POINTER;
+ break;
+ case PCI_SUBSYSTEM_VENDOR_ID:
+- conf_data =
+- CFG_PCI_VENDOR_ID(CS5536_OHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
++ cfg = CFG_PCI_VENDOR_ID(CS5536_OHCI_SUB_ID,
++ CS5536_SUB_VENDOR_ID);
+ break;
+ case PCI_ROM_ADDRESS:
+- conf_data = PCI_EXPANSION_ROM_BAR;
++ cfg = PCI_EXPANSION_ROM_BAR;
+ break;
+ case PCI_CAPABILITY_LIST:
+- conf_data = PCI_CAPLIST_USB_POINTER;
++ cfg = PCI_CAPLIST_USB_POINTER;
+ break;
+ case PCI_INTERRUPT_LINE:
+- conf_data =
+- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
++ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
+ break;
+ case PCI_OHCI_INT_REG:
+ _rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
+ if ((lo & 0x00000f00) == CS5536_USB_INTR)
+- conf_data = 1;
++ cfg = 1;
+ break;
+ default:
+ break;
+ }
+
+- return conf_data;
++ return cfg;
+ }
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/common/mtd.c linux-2.6.37/arch/mips/loongson/common/mtd.c
+--- linux-2.6.37.orig/arch/mips/loongson/common/mtd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/common/mtd.c 2011-01-11 20:44:43.000000000 +0100
+@@ -0,0 +1,91 @@
++/*
++ * Driver for flushing/dumping ROM of PMON on loongson family machines
++ *
++ * Copyright (C) 2008-2009 Lemote Inc.
++ * Author: Yan Hua <yanh@lemote.com>
++ *
++ * 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.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/io.h>
++
++#include <loongson.h>
++
++#define FLASH_PHYS_ADDR LOONGSON_BOOT_BASE
++#define FLASH_SIZE 0x080000
++
++#define FLASH_PARTITION0_ADDR 0x00000000
++#define FLASH_PARTITION0_SIZE 0x00080000
++
++struct map_info flash_map = {
++ .name = "flash device",
++ .size = FLASH_SIZE,
++ .bankwidth = 1,
++};
++
++struct mtd_partition flash_parts[] = {
++ {
++ .name = "Bootloader",
++ .offset = FLASH_PARTITION0_ADDR,
++ .size = FLASH_PARTITION0_SIZE},
++};
++
++#define PARTITION_COUNT ARRAY_SIZE(flash_parts)
++
++static struct mtd_info *mymtd;
++
++int __init init_flash(void)
++{
++ printk(KERN_NOTICE "flash device: %x at %x\n",
++ FLASH_SIZE, FLASH_PHYS_ADDR);
++
++ flash_map.phys = FLASH_PHYS_ADDR;
++ flash_map.virt = ioremap(FLASH_PHYS_ADDR, FLASH_SIZE);
++
++ if (!flash_map.virt) {
++ printk(KERN_NOTICE "Failed to ioremap\n");
++ return -EIO;
++ }
++
++ simple_map_init(&flash_map);
++
++ mymtd = do_map_probe("cfi_probe", &flash_map);
++ if (mymtd) {
++ add_mtd_partitions(mymtd, flash_parts, PARTITION_COUNT);
++ printk(KERN_NOTICE "pmon flash device initialized\n");
++ return 0;
++ }
++
++ iounmap((void *)flash_map.virt);
++ return -ENXIO;
++}
++
++static void __exit cleanup_flash(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ }
++ if (flash_map.virt) {
++ iounmap((void *)flash_map.virt);
++ flash_map.virt = 0;
++ }
++}
++
++module_init(init_flash);
++module_exit(cleanup_flash);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Yanhua <yanh@lemote.com>");
++MODULE_DESCRIPTION("MTD driver for pmon flushing/dumping");
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/lemote-2f/Makefile linux-2.6.37/arch/mips/loongson/lemote-2f/Makefile
+--- linux-2.6.37.orig/arch/mips/loongson/lemote-2f/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/lemote-2f/Makefile 2011-01-11 20:44:43.000000000 +0100
+@@ -2,7 +2,7 @@
+ # Makefile for lemote loongson2f family machines
+ #
+
+-obj-y += machtype.o irq.o reset.o ec_kb3310b.o
++obj-y += machtype.o irq.o reset.o ec_kb3310b.o platform.o
+
+ #
+ # Suspend Support
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/lemote-2f/ec_kb3310b.c linux-2.6.37/arch/mips/loongson/lemote-2f/ec_kb3310b.c
+--- linux-2.6.37.orig/arch/mips/loongson/lemote-2f/ec_kb3310b.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/lemote-2f/ec_kb3310b.c 2011-01-11 20:44:43.000000000 +0100
+@@ -14,7 +14,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/delay.h>
+
+-#include "ec_kb3310b.h"
++#include <ec_kb3310b.h>
+
+ static DEFINE_SPINLOCK(index_access_lock);
+ static DEFINE_SPINLOCK(port_access_lock);
+@@ -78,12 +78,9 @@
+ spin_unlock_irqrestore(&port_access_lock, flags);
+
+ if (timeout <= 0) {
+- printk(KERN_ERR "%s: deadable error : timeout...\n", __func__);
++ pr_err("%s: deadable error : timeout...\n", __func__);
+ ret = -EINVAL;
+- } else
+- printk(KERN_INFO
+- "(%x/%d)ec issued command %d status : 0x%x\n",
+- timeout, EC_CMD_TIMEOUT - timeout, cmd, status);
++ }
+
+ return ret;
+ }
+@@ -118,8 +115,7 @@
+ udelay(EC_REG_DELAY);
+ }
+ if (timeout <= 0) {
+- pr_info("%s: get event number timeout.\n", __func__);
+-
++ pr_err("%s: get event number timeout.\n", __func__);
+ return -EINVAL;
+ }
+ value = inb(EC_DAT_PORT);
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/lemote-2f/ec_kb3310b.h linux-2.6.37/arch/mips/loongson/lemote-2f/ec_kb3310b.h
+--- linux-2.6.37.orig/arch/mips/loongson/lemote-2f/ec_kb3310b.h 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/lemote-2f/ec_kb3310b.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,188 +0,0 @@
+-/*
+- * KB3310B Embedded Controller
+- *
+- * Copyright (C) 2008 Lemote Inc.
+- * Author: liujl <liujl@lemote.com>, 2008-03-14
+- *
+- * 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.
+- */
+-
+-#ifndef _EC_KB3310B_H
+-#define _EC_KB3310B_H
+-
+-extern unsigned char ec_read(unsigned short addr);
+-extern void ec_write(unsigned short addr, unsigned char val);
+-extern int ec_query_seq(unsigned char cmd);
+-extern int ec_query_event_num(void);
+-extern int ec_get_event_num(void);
+-
+-typedef int (*sci_handler) (int status);
+-extern sci_handler yeeloong_report_lid_status;
+-
+-#define SCI_IRQ_NUM 0x0A
+-
+-/*
+- * The following registers are determined by the EC index configuration.
+- * 1, fill the PORT_HIGH as EC register high part.
+- * 2, fill the PORT_LOW as EC register low part.
+- * 3, fill the PORT_DATA as EC register write data or get the data from it.
+- */
+-#define EC_IO_PORT_HIGH 0x0381
+-#define EC_IO_PORT_LOW 0x0382
+-#define EC_IO_PORT_DATA 0x0383
+-
+-/*
+- * EC delay time is 500us for register and status access
+- */
+-#define EC_REG_DELAY 500 /* unit : us */
+-#define EC_CMD_TIMEOUT 0x1000
+-
+-/*
+- * EC access port for SCI communication
+- */
+-#define EC_CMD_PORT 0x66
+-#define EC_STS_PORT 0x66
+-#define EC_DAT_PORT 0x62
+-#define CMD_INIT_IDLE_MODE 0xdd
+-#define CMD_EXIT_IDLE_MODE 0xdf
+-#define CMD_INIT_RESET_MODE 0xd8
+-#define CMD_REBOOT_SYSTEM 0x8c
+-#define CMD_GET_EVENT_NUM 0x84
+-#define CMD_PROGRAM_PIECE 0xda
+-
+-/* temperature & fan registers */
+-#define REG_TEMPERATURE_VALUE 0xF458
+-#define REG_FAN_AUTO_MAN_SWITCH 0xF459
+-#define BIT_FAN_AUTO 0
+-#define BIT_FAN_MANUAL 1
+-#define REG_FAN_CONTROL 0xF4D2
+-#define BIT_FAN_CONTROL_ON (1 << 0)
+-#define BIT_FAN_CONTROL_OFF (0 << 0)
+-#define REG_FAN_STATUS 0xF4DA
+-#define BIT_FAN_STATUS_ON (1 << 0)
+-#define BIT_FAN_STATUS_OFF (0 << 0)
+-#define REG_FAN_SPEED_HIGH 0xFE22
+-#define REG_FAN_SPEED_LOW 0xFE23
+-#define REG_FAN_SPEED_LEVEL 0xF4CC
+-/* fan speed divider */
+-#define FAN_SPEED_DIVIDER 480000 /* (60*1000*1000/62.5/2)*/
+-
+-/* battery registers */
+-#define REG_BAT_DESIGN_CAP_HIGH 0xF77D
+-#define REG_BAT_DESIGN_CAP_LOW 0xF77E
+-#define REG_BAT_FULLCHG_CAP_HIGH 0xF780
+-#define REG_BAT_FULLCHG_CAP_LOW 0xF781
+-#define REG_BAT_DESIGN_VOL_HIGH 0xF782
+-#define REG_BAT_DESIGN_VOL_LOW 0xF783
+-#define REG_BAT_CURRENT_HIGH 0xF784
+-#define REG_BAT_CURRENT_LOW 0xF785
+-#define REG_BAT_VOLTAGE_HIGH 0xF786
+-#define REG_BAT_VOLTAGE_LOW 0xF787
+-#define REG_BAT_TEMPERATURE_HIGH 0xF788
+-#define REG_BAT_TEMPERATURE_LOW 0xF789
+-#define REG_BAT_RELATIVE_CAP_HIGH 0xF492
+-#define REG_BAT_RELATIVE_CAP_LOW 0xF493
+-#define REG_BAT_VENDOR 0xF4C4
+-#define FLAG_BAT_VENDOR_SANYO 0x01
+-#define FLAG_BAT_VENDOR_SIMPLO 0x02
+-#define REG_BAT_CELL_COUNT 0xF4C6
+-#define FLAG_BAT_CELL_3S1P 0x03
+-#define FLAG_BAT_CELL_3S2P 0x06
+-#define REG_BAT_CHARGE 0xF4A2
+-#define FLAG_BAT_CHARGE_DISCHARGE 0x01
+-#define FLAG_BAT_CHARGE_CHARGE 0x02
+-#define FLAG_BAT_CHARGE_ACPOWER 0x00
+-#define REG_BAT_STATUS 0xF4B0
+-#define BIT_BAT_STATUS_LOW (1 << 5)
+-#define BIT_BAT_STATUS_DESTROY (1 << 2)
+-#define BIT_BAT_STATUS_FULL (1 << 1)
+-#define BIT_BAT_STATUS_IN (1 << 0)
+-#define REG_BAT_CHARGE_STATUS 0xF4B1
+-#define BIT_BAT_CHARGE_STATUS_OVERTEMP (1 << 2)
+-#define BIT_BAT_CHARGE_STATUS_PRECHG (1 << 1)
+-#define REG_BAT_STATE 0xF482
+-#define BIT_BAT_STATE_CHARGING (1 << 1)
+-#define BIT_BAT_STATE_DISCHARGING (1 << 0)
+-#define REG_BAT_POWER 0xF440
+-#define BIT_BAT_POWER_S3 (1 << 2)
+-#define BIT_BAT_POWER_ON (1 << 1)
+-#define BIT_BAT_POWER_ACIN (1 << 0)
+-
+-/* other registers */
+-/* Audio: rd/wr */
+-#define REG_AUDIO_VOLUME 0xF46C
+-#define REG_AUDIO_MUTE 0xF4E7
+-#define REG_AUDIO_BEEP 0xF4D0
+-/* USB port power or not: rd/wr */
+-#define REG_USB0_FLAG 0xF461
+-#define REG_USB1_FLAG 0xF462
+-#define REG_USB2_FLAG 0xF463
+-#define BIT_USB_FLAG_ON 1
+-#define BIT_USB_FLAG_OFF 0
+-/* LID */
+-#define REG_LID_DETECT 0xF4BD
+-#define BIT_LID_DETECT_ON 1
+-#define BIT_LID_DETECT_OFF 0
+-/* CRT */
+-#define REG_CRT_DETECT 0xF4AD
+-#define BIT_CRT_DETECT_PLUG 1
+-#define BIT_CRT_DETECT_UNPLUG 0
+-/* LCD backlight brightness adjust: 9 levels */
+-#define REG_DISPLAY_BRIGHTNESS 0xF4F5
+-/* Black screen Status */
+-#define BIT_DISPLAY_LCD_ON 1
+-#define BIT_DISPLAY_LCD_OFF 0
+-/* LCD backlight control: off/restore */
+-#define REG_BACKLIGHT_CTRL 0xF7BD
+-#define BIT_BACKLIGHT_ON 1
+-#define BIT_BACKLIGHT_OFF 0
+-/* Reset the machine auto-clear: rd/wr */
+-#define REG_RESET 0xF4EC
+-#define BIT_RESET_ON 1
+-/* Light the led: rd/wr */
+-#define REG_LED 0xF4C8
+-#define BIT_LED_RED_POWER (1 << 0)
+-#define BIT_LED_ORANGE_POWER (1 << 1)
+-#define BIT_LED_GREEN_CHARGE (1 << 2)
+-#define BIT_LED_RED_CHARGE (1 << 3)
+-#define BIT_LED_NUMLOCK (1 << 4)
+-/* Test led mode, all led on/off */
+-#define REG_LED_TEST 0xF4C2
+-#define BIT_LED_TEST_IN 1
+-#define BIT_LED_TEST_OUT 0
+-/* Camera on/off */
+-#define REG_CAMERA_STATUS 0xF46A
+-#define BIT_CAMERA_STATUS_ON 1
+-#define BIT_CAMERA_STATUS_OFF 0
+-#define REG_CAMERA_CONTROL 0xF7B7
+-#define BIT_CAMERA_CONTROL_OFF 0
+-#define BIT_CAMERA_CONTROL_ON 1
+-/* Wlan Status */
+-#define REG_WLAN 0xF4FA
+-#define BIT_WLAN_ON 1
+-#define BIT_WLAN_OFF 0
+-#define REG_DISPLAY_LCD 0xF79F
+-
+-/* SCI Event Number from EC */
+-enum {
+- EVENT_LID = 0x23, /* LID open/close */
+- EVENT_DISPLAY_TOGGLE, /* Fn+F3 for display switch */
+- EVENT_SLEEP, /* Fn+F1 for entering sleep mode */
+- EVENT_OVERTEMP, /* Over-temperature happened */
+- EVENT_CRT_DETECT, /* CRT is connected */
+- EVENT_CAMERA, /* Camera on/off */
+- EVENT_USB_OC2, /* USB2 Over Current occurred */
+- EVENT_USB_OC0, /* USB0 Over Current occurred */
+- EVENT_BLACK_SCREEN, /* Turn on/off backlight */
+- EVENT_AUDIO_MUTE, /* Mute on/off */
+- EVENT_DISPLAY_BRIGHTNESS,/* LCD backlight brightness adjust */
+- EVENT_AC_BAT, /* AC & Battery relative issue */
+- EVENT_AUDIO_VOLUME, /* Volume adjust */
+- EVENT_WLAN, /* Wlan on/off */
+- EVENT_END
+-};
+-
+-#endif /* !_EC_KB3310B_H */
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/lemote-2f/platform.c linux-2.6.37/arch/mips/loongson/lemote-2f/platform.c
+--- linux-2.6.37.orig/arch/mips/loongson/lemote-2f/platform.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/lemote-2f/platform.c 2011-01-11 20:44:43.000000000 +0100
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2009 Lemote Inc.
++ * Author: Wu Zhangjin, wuzhangjin@gmail.com
++ *
++ * 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.
++ */
++
++#include <linux/err.h>
++#include <linux/platform_device.h>
++
++#include <asm/bootinfo.h>
++
++static struct platform_device yeeloong_pdev = {
++ .name = "yeeloong_laptop",
++ .id = -1,
++};
++
++static struct platform_device lynloong_pdev = {
++ .name = "lynloong_pc",
++ .id = -1,
++};
++
++static int __init lemote2f_platform_init(void)
++{
++ struct platform_device *pdev = NULL;
++
++ switch (mips_machtype) {
++ case MACH_LEMOTE_YL2F89:
++ pdev = &yeeloong_pdev;
++ break;
++ case MACH_LEMOTE_LL2F:
++ pdev = &lynloong_pdev;
++ break;
++ default:
++ break;
++
++ }
++
++ if (pdev != NULL)
++ return platform_device_register(pdev);
++
++ return -ENODEV;
++}
++
++arch_initcall(lemote2f_platform_init);
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/lemote-2f/pm.c linux-2.6.37/arch/mips/loongson/lemote-2f/pm.c
+--- linux-2.6.37.orig/arch/mips/loongson/lemote-2f/pm.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/lemote-2f/pm.c 2011-01-11 20:44:43.000000000 +0100
+@@ -23,7 +23,7 @@
+ #include <loongson.h>
+
+ #include <cs5536/cs5536_mfgpt.h>
+-#include "ec_kb3310b.h"
++#include <ec_kb3310b.h>
+
+ #define I8042_KBD_IRQ 1
+ #define I8042_CTR_KBDINT 0x01
+@@ -100,7 +100,7 @@
+ if (irq < 0)
+ return 0;
+
+- printk(KERN_INFO "%s: irq = %d\n", __func__, irq);
++ pr_info("%s: irq = %d\n", __func__, irq);
+
+ if (irq == I8042_KBD_IRQ)
+ return 1;
+diff -Nur linux-2.6.37.orig/arch/mips/loongson/lemote-2f/reset.c linux-2.6.37/arch/mips/loongson/lemote-2f/reset.c
+--- linux-2.6.37.orig/arch/mips/loongson/lemote-2f/reset.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/loongson/lemote-2f/reset.c 2011-01-11 20:44:43.000000000 +0100
+@@ -20,7 +20,7 @@
+ #include <loongson.h>
+
+ #include <cs5536/cs5536.h>
+-#include "ec_kb3310b.h"
++#include <ec_kb3310b.h>
+
+ static void reset_cpu(void)
+ {
+diff -Nur linux-2.6.37.orig/arch/mips/mm/dma-default.c linux-2.6.37/arch/mips/mm/dma-default.c
+--- linux-2.6.37.orig/arch/mips/mm/dma-default.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/arch/mips/mm/dma-default.c 2011-01-11 20:46:19.000000000 +0100
+@@ -300,6 +300,20 @@
+
+ EXPORT_SYMBOL(dma_cache_sync);
+
++int __weak dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
++ void *cpu_addr, dma_addr_t handle, size_t size)
++{
++ struct page *pg;
++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++ cpu_addr = (void *)dma_addr_to_virt(dev, handle);
++ pg = virt_to_page(cpu_addr);
++ return remap_pfn_range(vma, vma->vm_start,
++ page_to_pfn(pg) + vma->vm_pgoff,
++ size, vma->vm_page_prot);
++}
++EXPORT_SYMBOL(dma_mmap_coherent);
++
++
+ static struct dma_map_ops mips_default_dma_map_ops = {
+ .alloc_coherent = mips_dma_alloc_coherent,
+ .free_coherent = mips_dma_free_coherent,
+diff -Nur linux-2.6.37.orig/drivers/ide/ide-iops.c linux-2.6.37/drivers/ide/ide-iops.c
+--- linux-2.6.37.orig/drivers/ide/ide-iops.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/ide/ide-iops.c 2011-01-11 20:44:43.000000000 +0100
+@@ -27,6 +27,8 @@
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+
++#include <asm/bootinfo.h>
++
+ void SELECT_MASK(ide_drive_t *drive, int mask)
+ {
+ const struct ide_port_ops *port_ops = drive->hwif->port_ops;
+@@ -300,6 +302,9 @@
+ {
+ const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
+
++ if (mips_machtype != MACH_LEMOTE_YL2F89)
++ return;
++
+ for (list = nien_quirk_list; *list != NULL; list++)
+ if (strstr(m, *list) != NULL) {
+ drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK;
+diff -Nur linux-2.6.37.orig/drivers/platform/Kconfig linux-2.6.37/drivers/platform/Kconfig
+--- linux-2.6.37.orig/drivers/platform/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/platform/Kconfig 2011-01-11 20:44:43.000000000 +0100
+@@ -1,3 +1,7 @@
+ if X86
+ source "drivers/platform/x86/Kconfig"
+ endif
++
++if MIPS
++source "drivers/platform/mips/Kconfig"
++endif
+diff -Nur linux-2.6.37.orig/drivers/platform/Makefile linux-2.6.37/drivers/platform/Makefile
+--- linux-2.6.37.orig/drivers/platform/Makefile 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/platform/Makefile 2011-01-11 20:44:43.000000000 +0100
+@@ -3,3 +3,4 @@
+ #
+
+ obj-$(CONFIG_X86) += x86/
++obj-$(CONFIG_MIPS) += mips/
+diff -Nur linux-2.6.37.orig/drivers/platform/mips/Kconfig linux-2.6.37/drivers/platform/mips/Kconfig
+--- linux-2.6.37.orig/drivers/platform/mips/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/platform/mips/Kconfig 2011-01-11 20:44:43.000000000 +0100
+@@ -0,0 +1,43 @@
++#
++# MIPS Platform Specific Drivers
++#
++
++menuconfig MIPS_PLATFORM_DEVICES
++ bool "MIPS Platform Specific Device Drivers"
++ default y
++ help
++ Say Y here to get to see options for device drivers of various
++ MIPS platforms, including vendor-specific netbook/laptop/pc extension
++ drivers. This option alone does not add any kernel code.
++
++ If you say N, all options in this submenu will be skipped and disabled.
++
++if MIPS_PLATFORM_DEVICES
++
++config LEMOTE_YEELOONG2F
++ tristate "Lemote YeeLoong Laptop"
++ depends on LEMOTE_MACH2F
++ select BACKLIGHT_CLASS_DEVICE
++ select POWER_SUPPLY
++ select HWMON
++ select VIDEO_OUTPUT_CONTROL
++ select INPUT_SPARSEKMAP
++ depends on INPUT
++ help
++ YeeLoong netbook is a mini laptop made by Lemote, which is basically
++ compatible to FuLoong2F mini PC, but it has an extra Embedded
++ Controller(kb3310b) for battery, hotkey, backlight, temperature and
++ fan management.
++
++config LEMOTE_LYNLOONG2F
++ tristate "Lemote LynLoong PC"
++ depends on LEMOTE_MACH2F
++ select BACKLIGHT_CLASS_DEVICE
++ select VIDEO_OUTPUT_CONTROL
++ help
++ LynLoong PC is an AllINONE machine made by Lemote, which is basically
++ compatible to FuLoong2F Mini PC, the only difference is that it has a
++ size-fixed screen: 1360x768 with sisfb video driver. and also, it has
++ its own specific suspend support.
++
++endif # MIPS_PLATFORM_DEVICES
+diff -Nur linux-2.6.37.orig/drivers/platform/mips/Makefile linux-2.6.37/drivers/platform/mips/Makefile
+--- linux-2.6.37.orig/drivers/platform/mips/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/platform/mips/Makefile 2011-01-11 20:44:43.000000000 +0100
+@@ -0,0 +1,7 @@
++#
++# Makefile for MIPS Platform-Specific Drivers
++#
++
++obj-$(CONFIG_LEMOTE_YEELOONG2F) += yeeloong_laptop.o
++
++obj-$(CONFIG_LEMOTE_LYNLOONG2F) += lynloong_pc.o
+diff -Nur linux-2.6.37.orig/drivers/platform/mips/lynloong_pc.c linux-2.6.37/drivers/platform/mips/lynloong_pc.c
+--- linux-2.6.37.orig/drivers/platform/mips/lynloong_pc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/platform/mips/lynloong_pc.c 2011-01-11 20:44:43.000000000 +0100
+@@ -0,0 +1,513 @@
++/*
++ * Driver for LynLoong PC extras
++ *
++ * Copyright (C) 2009 Lemote Inc.
++ * Author: Wu Zhangjin <wuzhangjin@gmail.com>, Xiang Yu <xiangy@lemote.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/backlight.h> /* for backlight subdriver */
++#include <linux/fb.h>
++#include <linux/video_output.h> /* for video output subdriver */
++#include <linux/delay.h> /* for suspend support */
++
++#include <cs5536/cs5536.h>
++#include <cs5536/cs5536_mfgpt.h>
++
++#include <loongson.h>
++
++static u32 gpio_base, mfgpt_base;
++
++static void set_gpio_reg_high(int gpio, int reg)
++{
++ u32 val;
++
++ val = inl(gpio_base + reg);
++ val |= (1 << gpio);
++ val &= ~(1 << (16 + gpio));
++ outl(val, gpio_base + reg);
++ mmiowb();
++}
++
++static void set_gpio_reg_low(int gpio, int reg)
++{
++ u32 val;
++
++ val = inl(gpio_base + reg);
++ val |= (1 << (16 + gpio));
++ val &= ~(1 << gpio);
++ outl(val, gpio_base + reg);
++ mmiowb();
++}
++
++static void set_gpio_output_low(int gpio)
++{
++ set_gpio_reg_high(gpio, GPIOL_OUT_EN);
++ set_gpio_reg_low(gpio, GPIOL_OUT_VAL);
++}
++
++static void set_gpio_output_high(int gpio)
++{
++ set_gpio_reg_high(gpio, GPIOL_OUT_EN);
++ set_gpio_reg_high(gpio, GPIOL_OUT_VAL);
++}
++
++/* backlight subdriver */
++
++#define MAX_BRIGHTNESS 100
++#define DEFAULT_BRIGHTNESS 50
++#define MIN_BRIGHTNESS 0
++static unsigned int level;
++
++DEFINE_SPINLOCK(backlight_lock);
++/* Tune the brightness */
++static void setup_mfgpt2(void)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&backlight_lock, flags);
++
++ /* Set MFGPT2 comparator 1,2 */
++ outw(MAX_BRIGHTNESS-level, MFGPT2_CMP1);
++ outw(MAX_BRIGHTNESS, MFGPT2_CMP2);
++ /* Clear MFGPT2 UP COUNTER */
++ outw(0, MFGPT2_CNT);
++ /* Enable counter, compare mode, 32k */
++ outw(0x8280, MFGPT2_SETUP);
++
++ spin_unlock_irqrestore(&backlight_lock, flags);
++}
++
++static int lynloong_set_brightness(struct backlight_device *bd)
++{
++ level = (bd->props.fb_blank == FB_BLANK_UNBLANK &&
++ bd->props.power == FB_BLANK_UNBLANK) ?
++ bd->props.brightness : 0;
++
++ if (level > MAX_BRIGHTNESS)
++ level = MAX_BRIGHTNESS;
++ else if (level < MIN_BRIGHTNESS)
++ level = MIN_BRIGHTNESS;
++
++ setup_mfgpt2();
++
++ return 0;
++}
++
++static int lynloong_get_brightness(struct backlight_device *bd)
++{
++ return level;
++}
++
++static struct backlight_ops backlight_ops = {
++ .get_brightness = lynloong_get_brightness,
++ .update_status = lynloong_set_brightness,
++};
++
++static struct backlight_device *lynloong_backlight_dev;
++
++static int lynloong_backlight_init(void)
++{
++ int ret;
++ u32 hi;
++ struct backlight_properties props;
++
++ /* Get gpio_base */
++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base);
++ /* Get mfgpt_base */
++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &hi, &mfgpt_base);
++ /* Get gpio_base */
++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base);
++
++ /* Select for mfgpt */
++ set_gpio_reg_high(7, GPIOL_OUT_AUX1_SEL);
++ /* Enable brightness controlling */
++ set_gpio_output_high(7);
++
++ memset(&props, 0, sizeof(struct backlight_properties));
++ props.max_brightness = MAX_BRIGHTNESS;
++ lynloong_backlight_dev = backlight_device_register("backlight0", NULL,
++ NULL, &backlight_ops, &props);
++
++ if (IS_ERR(lynloong_backlight_dev)) {
++ ret = PTR_ERR(lynloong_backlight_dev);
++ return ret;
++ }
++
++ lynloong_backlight_dev->props.brightness = DEFAULT_BRIGHTNESS;
++ backlight_update_status(lynloong_backlight_dev);
++
++ return 0;
++}
++
++static void lynloong_backlight_exit(void)
++{
++ if (lynloong_backlight_dev) {
++ backlight_device_unregister(lynloong_backlight_dev);
++ lynloong_backlight_dev = NULL;
++ }
++ /* Disable brightness controlling */
++ set_gpio_output_low(7);
++}
++
++/* video output driver */
++static int vo_status = 1;
++
++static int lcd_video_output_get(struct output_device *od)
++{
++ return vo_status;
++}
++
++static int lcd_video_output_set(struct output_device *od)
++{
++ int i;
++ unsigned long status;
++
++ status = !!od->request_state;
++
++ if (status == 0) {
++ /* Set the current status as off */
++ vo_status = 0;
++ /* Turn off the backlight */
++ set_gpio_output_low(11);
++ for (i = 0; i < 0x500; i++)
++ delay();
++ /* Turn off the LCD */
++ set_gpio_output_high(8);
++ } else {
++ /* Turn on the LCD */
++ set_gpio_output_low(8);
++ for (i = 0; i < 0x500; i++)
++ delay();
++ /* Turn on the backlight */
++ set_gpio_output_high(11);
++ /* Set the current status as on */
++ vo_status = 1;
++ }
++
++ return 0;
++}
++
++static struct output_properties lcd_output_properties = {
++ .set_state = lcd_video_output_set,
++ .get_status = lcd_video_output_get,
++};
++
++static struct output_device *lcd_output_dev;
++
++static void lynloong_lcd_vo_set(int status)
++{
++ lcd_output_dev->request_state = status;
++ lcd_video_output_set(lcd_output_dev);
++}
++
++static int lynloong_vo_init(void)
++{
++ int ret;
++
++ /* Register video output device: lcd */
++ lcd_output_dev = video_output_register("LCD", NULL, NULL,
++ &lcd_output_properties);
++
++ if (IS_ERR(lcd_output_dev)) {
++ ret = PTR_ERR(lcd_output_dev);
++ lcd_output_dev = NULL;
++ return ret;
++ }
++ /* Ensure LCD is on by default */
++ lynloong_lcd_vo_set(1);
++
++ return 0;
++}
++
++static void lynloong_vo_exit(void)
++{
++ if (lcd_output_dev) {
++ video_output_unregister(lcd_output_dev);
++ lcd_output_dev = NULL;
++ }
++}
++
++/* suspend support */
++
++#ifdef CONFIG_PM
++
++static u32 smb_base;
++
++/* I2C operations */
++
++static int i2c_wait(void)
++{
++ char c;
++ int i;
++
++ udelay(1000);
++ for (i = 0; i < 20; i++) {
++ c = inb(smb_base | SMB_STS);
++ if (c & (SMB_STS_BER | SMB_STS_NEGACK))
++ return -1;
++ if (c & SMB_STS_SDAST)
++ return 0;
++ udelay(100);
++ }
++ return -2;
++}
++
++static void i2c_read_single(int addr, int regNo, char *value)
++{
++ unsigned char c;
++
++ /* Start condition */
++ c = inb(smb_base | SMB_CTRL1);
++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
++ i2c_wait();
++
++ /* Send slave address */
++ outb(addr & 0xfe, smb_base | SMB_SDA);
++ i2c_wait();
++
++ /* Acknowledge smbus */
++ c = inb(smb_base | SMB_CTRL1);
++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
++
++ /* Send register index */
++ outb(regNo, smb_base | SMB_SDA);
++ i2c_wait();
++
++ /* Acknowledge smbus */
++ c = inb(smb_base | SMB_CTRL1);
++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
++
++ /* Start condition again */
++ c = inb(smb_base | SMB_CTRL1);
++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
++ i2c_wait();
++
++ /* Send salve address again */
++ outb(1 | addr, smb_base | SMB_SDA);
++ i2c_wait();
++
++ /* Acknowledge smbus */
++ c = inb(smb_base | SMB_CTRL1);
++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
++
++ /* Read data */
++ *value = inb(smb_base | SMB_SDA);
++
++ /* Stop condition */
++ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1);
++ i2c_wait();
++}
++
++static void i2c_write_single(int addr, int regNo, char value)
++{
++ unsigned char c;
++
++ /* Start condition */
++ c = inb(smb_base | SMB_CTRL1);
++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
++ i2c_wait();
++ /* Send slave address */
++ outb(addr & 0xfe, smb_base | SMB_SDA);
++ i2c_wait();;
++
++ /* Send register index */
++ outb(regNo, smb_base | SMB_SDA);
++ i2c_wait();
++
++ /* Write data */
++ outb(value, smb_base | SMB_SDA);
++ i2c_wait();
++ /* Stop condition */
++ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1);
++ i2c_wait();
++}
++
++static void stop_clock(int clk_reg, int clk_sel)
++{
++ u8 value;
++
++ i2c_read_single(0xd3, clk_reg, &value);
++ value &= ~(1 << clk_sel);
++ i2c_write_single(0xd2, clk_reg, value);
++}
++
++static void enable_clock(int clk_reg, int clk_sel)
++{
++ u8 value;
++
++ i2c_read_single(0xd3, clk_reg, &value);
++ value |= (1 << clk_sel);
++ i2c_write_single(0xd2, clk_reg, value);
++}
++
++static char cached_clk_freq;
++static char cached_pci_fixed_freq;
++
++static void decrease_clk_freq(void)
++{
++ char value;
++
++ i2c_read_single(0xd3, 1, &value);
++ cached_clk_freq = value;
++
++ /* Select frequency by software */
++ value |= (1 << 1);
++ /* CPU, 3V66, PCI : 100, 66, 33(1) */
++ value |= (1 << 2);
++ i2c_write_single(0xd2, 1, value);
++
++ /* Cache the pci frequency */
++ i2c_read_single(0xd3, 14, &value);
++ cached_pci_fixed_freq = value;
++
++ /* Enable PCI fix mode */
++ value |= (1 << 5);
++ /* 3V66, PCI : 64MHz, 32MHz */
++ value |= (1 << 3);
++ i2c_write_single(0xd2, 14, value);
++
++}
++
++static void resume_clk_freq(void)
++{
++ i2c_write_single(0xd2, 1, cached_clk_freq);
++ i2c_write_single(0xd2, 14, cached_pci_fixed_freq);
++}
++
++static void stop_clocks(void)
++{
++ /* CPU Clock Register */
++ stop_clock(2, 5); /* not used */
++ stop_clock(2, 6); /* not used */
++ stop_clock(2, 7); /* not used */
++
++ /* PCI Clock Register */
++ stop_clock(3, 1); /* 8100 */
++ stop_clock(3, 5); /* SIS */
++ stop_clock(3, 0); /* not used */
++ stop_clock(3, 6); /* not used */
++
++ /* PCI 48M Clock Register */
++ stop_clock(4, 6); /* USB grounding */
++ stop_clock(4, 5); /* REF(5536_14M) */
++
++ /* 3V66 Control Register */
++ stop_clock(5, 0); /* VCH_CLK..., grounding */
++}
++
++static void enable_clocks(void)
++{
++ enable_clock(3, 1); /* 8100 */
++ enable_clock(3, 5); /* SIS */
++
++ enable_clock(4, 6);
++ enable_clock(4, 5); /* REF(5536_14M) */
++
++ enable_clock(5, 0); /* VCH_CLOCK, grounding */
++}
++
++static int lynloong_suspend(struct device *dev)
++{
++ /* Disable AMP */
++ set_gpio_output_high(6);
++ /* Turn off LCD */
++ lynloong_lcd_vo_set(0);
++
++ /* Stop the clocks of some devices */
++ stop_clocks();
++
++ /* Decrease the external clock frequency */
++ decrease_clk_freq();
++
++ return 0;
++}
++
++static int lynloong_resume(struct device *dev)
++{
++ /* Turn on the LCD */
++ lynloong_lcd_vo_set(1);
++
++ /* Resume clock frequency, enable the relative clocks */
++ resume_clk_freq();
++ enable_clocks();
++
++ /* Enable AMP */
++ set_gpio_output_low(6);
++
++ return 0;
++}
++
++static const SIMPLE_DEV_PM_OPS(lynloong_pm_ops, lynloong_suspend,
++ lynloong_resume);
++#endif /* !CONFIG_PM */
++
++static struct platform_device_id platform_device_ids[] = {
++ {
++ .name = "lynloong_pc",
++ },
++ {}
++};
++
++MODULE_DEVICE_TABLE(platform, platform_device_ids);
++
++static struct platform_driver platform_driver = {
++ .driver = {
++ .name = "lynloong_pc",
++ .owner = THIS_MODULE,
++#ifdef CONFIG_PM
++ .pm = &lynloong_pm_ops,
++#endif
++ },
++ .id_table = platform_device_ids,
++};
++
++static int __init lynloong_init(void)
++{
++ int ret;
++
++ pr_info("Load LynLoong Platform Specific Driver.\n");
++
++ /* Register platform stuff */
++ ret = platform_driver_register(&platform_driver);
++ if (ret) {
++ pr_err("Fail to register lynloong platform driver.\n");
++ return ret;
++ }
++
++ ret = lynloong_backlight_init();
++ if (ret) {
++ pr_err("Fail to register lynloong backlight driver.\n");
++ return ret;
++ }
++
++ ret = lynloong_vo_init();
++ if (ret) {
++ pr_err("Fail to register lynloong backlight driver.\n");
++ lynloong_vo_exit();
++ return ret;
++ }
++
++ return 0;
++}
++
++static void __exit lynloong_exit(void)
++{
++ lynloong_vo_exit();
++ lynloong_backlight_exit();
++ platform_driver_unregister(&platform_driver);
++
++ pr_info("Unload LynLoong Platform Specific Driver.\n");
++}
++
++module_init(lynloong_init);
++module_exit(lynloong_exit);
++
++MODULE_AUTHOR("Wu Zhangjin <wuzhangjin@gmail.com>; Xiang Yu <xiangy@lemote.com>");
++MODULE_DESCRIPTION("LynLoong PC driver");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.6.37.orig/drivers/platform/mips/yeeloong_ecrom.c linux-2.6.37/drivers/platform/mips/yeeloong_ecrom.c
+--- linux-2.6.37.orig/drivers/platform/mips/yeeloong_ecrom.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/platform/mips/yeeloong_ecrom.c 2011-01-11 20:44:43.000000000 +0100
+@@ -0,0 +1,943 @@
++/*
++ * Driver for flushing/dumping ROM of EC on YeeLoong laptop
++ *
++ * Copyright (C) 2009 Lemote Inc.
++ * Author: liujl <liujl@lemote.com>
++ *
++ * NOTE :
++ * The EC resources accessing and programming are supported.
++ */
++
++#include <linux/proc_fs.h>
++#include <linux/miscdevice.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <ec_kb3310b.h>
++
++#define EC_MISC_DEV "ec_misc"
++#define EC_IOC_MAGIC 'E'
++
++/* ec registers range */
++#define EC_MAX_REGADDR 0xFFFF
++#define EC_MIN_REGADDR 0xF000
++#define EC_RAM_ADDR 0xF800
++
++/* version burned address */
++#define VER_ADDR 0xf7a1
++#define VER_MAX_SIZE 7
++#define EC_ROM_MAX_SIZE 0x10000
++
++/* ec internal register */
++#define REG_POWER_MODE 0xF710
++#define FLAG_NORMAL_MODE 0x00
++#define FLAG_IDLE_MODE 0x01
++#define FLAG_RESET_MODE 0x02
++
++/* ec update program flag */
++#define PROGRAM_FLAG_NONE 0x00
++#define PROGRAM_FLAG_IE 0x01
++#define PROGRAM_FLAG_ROM 0x02
++
++/* XBI relative registers */
++#define REG_XBISEG0 0xFEA0
++#define REG_XBISEG1 0xFEA1
++#define REG_XBIRSV2 0xFEA2
++#define REG_XBIRSV3 0xFEA3
++#define REG_XBIRSV4 0xFEA4
++#define REG_XBICFG 0xFEA5
++#define REG_XBICS 0xFEA6
++#define REG_XBIWE 0xFEA7
++#define REG_XBISPIA0 0xFEA8
++#define REG_XBISPIA1 0xFEA9
++#define REG_XBISPIA2 0xFEAA
++#define REG_XBISPIDAT 0xFEAB
++#define REG_XBISPICMD 0xFEAC
++#define REG_XBISPICFG 0xFEAD
++#define REG_XBISPIDATR 0xFEAE
++#define REG_XBISPICFG2 0xFEAF
++
++/* commands definition for REG_XBISPICMD */
++#define SPICMD_WRITE_STATUS 0x01
++#define SPICMD_BYTE_PROGRAM 0x02
++#define SPICMD_READ_BYTE 0x03
++#define SPICMD_WRITE_DISABLE 0x04
++#define SPICMD_READ_STATUS 0x05
++#define SPICMD_WRITE_ENABLE 0x06
++#define SPICMD_HIGH_SPEED_READ 0x0B
++#define SPICMD_POWER_DOWN 0xB9
++#define SPICMD_SST_EWSR 0x50
++#define SPICMD_SST_SEC_ERASE 0x20
++#define SPICMD_SST_BLK_ERASE 0x52
++#define SPICMD_SST_CHIP_ERASE 0x60
++#define SPICMD_FRDO 0x3B
++#define SPICMD_SEC_ERASE 0xD7
++#define SPICMD_BLK_ERASE 0xD8
++#define SPICMD_CHIP_ERASE 0xC7
++
++/* bits definition for REG_XBISPICFG */
++#define SPICFG_AUTO_CHECK 0x01
++#define SPICFG_SPI_BUSY 0x02
++#define SPICFG_DUMMY_READ 0x04
++#define SPICFG_EN_SPICMD 0x08
++#define SPICFG_LOW_SPICS 0x10
++#define SPICFG_EN_SHORT_READ 0x20
++#define SPICFG_EN_OFFSET_READ 0x40
++#define SPICFG_EN_FAST_READ 0x80
++
++/* watchdog timer registers */
++#define REG_WDTCFG 0xfe80
++#define REG_WDTPF 0xfe81
++#define REG_WDT 0xfe82
++
++/* lpc configure register */
++#define REG_LPCCFG 0xfe95
++
++/* 8051 reg */
++#define REG_PXCFG 0xff14
++
++/* Fan register in KB3310 */
++#define REG_ECFAN_SPEED_LEVEL 0xf4e4
++#define REG_ECFAN_SWITCH 0xf4d2
++
++/* the ec flash rom id number */
++#define EC_ROM_PRODUCT_ID_SPANSION 0x01
++#define EC_ROM_PRODUCT_ID_MXIC 0xC2
++#define EC_ROM_PRODUCT_ID_AMIC 0x37
++#define EC_ROM_PRODUCT_ID_EONIC 0x1C
++
++/* misc ioctl operations */
++#define IOCTL_RDREG _IOR(EC_IOC_MAGIC, 1, int)
++#define IOCTL_WRREG _IOW(EC_IOC_MAGIC, 2, int)
++#define IOCTL_READ_EC _IOR(EC_IOC_MAGIC, 3, int)
++#define IOCTL_PROGRAM_IE _IOW(EC_IOC_MAGIC, 4, int)
++#define IOCTL_PROGRAM_EC _IOW(EC_IOC_MAGIC, 5, int)
++
++/* start address for programming of EC content or IE */
++/* ec running code start address */
++#define EC_START_ADDR 0x00000000
++/* ec information element storing address */
++#define IE_START_ADDR 0x00020000
++
++/* EC state */
++#define EC_STATE_IDLE 0x00 /* ec in idle state */
++#define EC_STATE_BUSY 0x01 /* ec in busy state */
++
++/* timeout value for programming */
++#define EC_FLASH_TIMEOUT 0x1000 /* ec program timeout */
++/* command checkout timeout including cmd to port or state flag check */
++#define EC_CMD_TIMEOUT 0x1000
++#define EC_SPICMD_STANDARD_TIMEOUT (4 * 1000) /* unit : us */
++#define EC_MAX_DELAY_UNIT (10) /* every time for polling */
++#define SPI_FINISH_WAIT_TIME 10
++/* EC content max size */
++#define EC_CONTENT_MAX_SIZE (64 * 1024)
++#define IE_CONTENT_MAX_SIZE (0x100000 - IE_START_ADDR)
++
++/* the register operation access struct */
++struct ec_reg {
++ u32 addr; /* the address of kb3310 registers */
++ u8 val; /* the register value */
++};
++
++struct ec_info {
++ u32 start_addr;
++ u32 size;
++ u8 *buf;
++};
++
++/* open for using rom protection action */
++#define EC_ROM_PROTECTION
++
++/* enable the chip reset mode */
++static int ec_init_reset_mode(void)
++{
++ int timeout;
++ unsigned char status = 0;
++ int ret = 0;
++
++ /* make chip goto reset mode */
++ ret = ec_query_seq(CMD_INIT_RESET_MODE);
++ if (ret < 0) {
++ printk(KERN_ERR "ec init reset mode failed.\n");
++ goto out;
++ }
++
++ /* make the action take active */
++ timeout = EC_CMD_TIMEOUT;
++ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE;
++ while (timeout--) {
++ if (status) {
++ udelay(EC_REG_DELAY);
++ break;
++ }
++ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE;
++ udelay(EC_REG_DELAY);
++ }
++ if (timeout <= 0) {
++ printk(KERN_ERR "ec rom fixup : can't check reset status.\n");
++ ret = -EINVAL;
++ } else
++ printk(KERN_INFO "(%d/%d)reset 0xf710 : 0x%x\n", timeout,
++ EC_CMD_TIMEOUT - timeout, status);
++
++ /* set MCU to reset mode */
++ udelay(EC_REG_DELAY);
++ status = ec_read(REG_PXCFG);
++ status |= (1 << 0);
++ ec_write(REG_PXCFG, status);
++ udelay(EC_REG_DELAY);
++
++ /* disable FWH/LPC */
++ udelay(EC_REG_DELAY);
++ status = ec_read(REG_LPCCFG);
++ status &= ~(1 << 7);
++ ec_write(REG_LPCCFG, status);
++ udelay(EC_REG_DELAY);
++
++ printk(KERN_INFO "entering reset mode ok..............\n");
++
++ out:
++ return ret;
++}
++
++/* make ec exit from reset mode */
++static void ec_exit_reset_mode(void)
++{
++ unsigned char regval;
++
++ udelay(EC_REG_DELAY);
++ regval = ec_read(REG_LPCCFG);
++ regval |= (1 << 7);
++ ec_write(REG_LPCCFG, regval);
++ regval = ec_read(REG_PXCFG);
++ regval &= ~(1 << 0);
++ ec_write(REG_PXCFG, regval);
++ printk(KERN_INFO "exit reset mode ok..................\n");
++
++ return;
++}
++
++/* make ec disable WDD */
++static void ec_disable_WDD(void)
++{
++ unsigned char status;
++
++ udelay(EC_REG_DELAY);
++ status = ec_read(REG_WDTCFG);
++ ec_write(REG_WDTPF, 0x03);
++ ec_write(REG_WDTCFG, (status & 0x80) | 0x48);
++ printk(KERN_INFO "Disable WDD ok..................\n");
++
++ return;
++}
++
++/* make ec enable WDD */
++static void ec_enable_WDD(void)
++{
++ unsigned char status;
++
++ udelay(EC_REG_DELAY);
++ status = ec_read(REG_WDTCFG);
++ ec_write(REG_WDT, 0x28); /* set WDT 5sec(0x28) */
++ ec_write(REG_WDTCFG, (status & 0x80) | 0x03);
++ printk(KERN_INFO "Enable WDD ok..................\n");
++
++ return;
++}
++
++/* make ec goto idle mode */
++static int ec_init_idle_mode(void)
++{
++ int timeout;
++ unsigned char status = 0;
++ int ret = 0;
++
++ ec_query_seq(CMD_INIT_IDLE_MODE);
++
++ /* make the action take active */
++ timeout = EC_CMD_TIMEOUT;
++ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE;
++ while (timeout--) {
++ if (status) {
++ udelay(EC_REG_DELAY);
++ break;
++ }
++ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE;
++ udelay(EC_REG_DELAY);
++ }
++ if (timeout <= 0) {
++ printk(KERN_ERR "ec rom fixup : can't check out the status.\n");
++ ret = -EINVAL;
++ } else
++ printk(KERN_INFO "(%d/%d)0xf710 : 0x%x\n", timeout,
++ EC_CMD_TIMEOUT - timeout, ec_read(REG_POWER_MODE));
++
++ printk(KERN_INFO "entering idle mode ok...................\n");
++
++ return ret;
++}
++
++/* make ec exit from idle mode */
++static int ec_exit_idle_mode(void)
++{
++
++ ec_query_seq(CMD_EXIT_IDLE_MODE);
++
++ printk(KERN_INFO "exit idle mode ok...................\n");
++
++ return 0;
++}
++
++static int ec_instruction_cycle(void)
++{
++ unsigned long timeout;
++ int ret = 0;
++
++ timeout = EC_FLASH_TIMEOUT;
++ while (timeout-- >= 0) {
++ if (!(ec_read(REG_XBISPICFG) & SPICFG_SPI_BUSY))
++ break;
++ }
++ if (timeout <= 0) {
++ printk(KERN_ERR
++ "EC_INSTRUCTION_CYCLE : timeout for check flag.\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ out:
++ return ret;
++}
++
++/* To see if the ec is in busy state or not. */
++static inline int ec_flash_busy(unsigned long timeout)
++{
++ /* assurance the first command be going to rom */
++ if (ec_instruction_cycle() < 0)
++ return EC_STATE_BUSY;
++#if 1
++ timeout = timeout / EC_MAX_DELAY_UNIT;
++ while (timeout-- > 0) {
++ /* check the rom's status of busy flag */
++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
++ if (ec_instruction_cycle() < 0)
++ return EC_STATE_BUSY;
++ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00)
++ return EC_STATE_IDLE;
++ udelay(EC_MAX_DELAY_UNIT);
++ }
++ if (timeout <= 0) {
++ printk(KERN_ERR
++ "EC_FLASH_BUSY : timeout for check rom flag.\n");
++ return EC_STATE_BUSY;
++ }
++#else
++ /* check the rom's status of busy flag */
++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
++ if (ec_instruction_cycle() < 0)
++ return EC_STATE_BUSY;
++
++ timeout = timeout / EC_MAX_DELAY_UNIT;
++ while (timeout-- > 0) {
++ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00)
++ return EC_STATE_IDLE;
++ udelay(EC_MAX_DELAY_UNIT);
++ }
++ if (timeout <= 0) {
++ printk(KERN_ERR
++ "EC_FLASH_BUSY : timeout for check rom flag.\n");
++ return EC_STATE_BUSY;
++ }
++#endif
++
++ return EC_STATE_IDLE;
++}
++
++static int rom_instruction_cycle(unsigned char cmd)
++{
++ unsigned long timeout = 0;
++
++ switch (cmd) {
++ case SPICMD_READ_STATUS:
++ case SPICMD_WRITE_ENABLE:
++ case SPICMD_WRITE_DISABLE:
++ case SPICMD_READ_BYTE:
++ case SPICMD_HIGH_SPEED_READ:
++ timeout = 0;
++ break;
++ case SPICMD_WRITE_STATUS:
++ timeout = 300 * 1000;
++ break;
++ case SPICMD_BYTE_PROGRAM:
++ timeout = 5 * 1000;
++ break;
++ case SPICMD_SST_SEC_ERASE:
++ case SPICMD_SEC_ERASE:
++ timeout = 1000 * 1000;
++ break;
++ case SPICMD_SST_BLK_ERASE:
++ case SPICMD_BLK_ERASE:
++ timeout = 3 * 1000 * 1000;
++ break;
++ case SPICMD_SST_CHIP_ERASE:
++ case SPICMD_CHIP_ERASE:
++ timeout = 20 * 1000 * 1000;
++ break;
++ default:
++ timeout = EC_SPICMD_STANDARD_TIMEOUT;
++ }
++ if (timeout == 0)
++ return ec_instruction_cycle();
++ if (timeout < EC_SPICMD_STANDARD_TIMEOUT)
++ timeout = EC_SPICMD_STANDARD_TIMEOUT;
++
++ return ec_flash_busy(timeout);
++}
++
++/* delay for start/stop action */
++static void delay_spi(int n)
++{
++ while (n--)
++ inb(EC_IO_PORT_HIGH);
++}
++
++/* start the action to spi rom function */
++static void ec_start_spi(void)
++{
++ unsigned char val;
++
++ delay_spi(SPI_FINISH_WAIT_TIME);
++ val = ec_read(REG_XBISPICFG) | SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK;
++ ec_write(REG_XBISPICFG, val);
++ delay_spi(SPI_FINISH_WAIT_TIME);
++}
++
++/* stop the action to spi rom function */
++static void ec_stop_spi(void)
++{
++ unsigned char val;
++
++ delay_spi(SPI_FINISH_WAIT_TIME);
++ val =
++ ec_read(REG_XBISPICFG) & (~(SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK));
++ ec_write(REG_XBISPICFG, val);
++ delay_spi(SPI_FINISH_WAIT_TIME);
++}
++
++/* read one byte from xbi interface */
++static int ec_read_byte(unsigned int addr, unsigned char *byte)
++{
++ int ret = 0;
++
++ /* enable spicmd writing. */
++ ec_start_spi();
++
++ /* enable write spi flash */
++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
++ printk(KERN_ERR "EC_READ_BYTE : SPICMD_WRITE_ENABLE failed.\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ /* write the address */
++ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16);
++ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8);
++ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0);
++ /* start action */
++ ec_write(REG_XBISPICMD, SPICMD_HIGH_SPEED_READ);
++ if (rom_instruction_cycle(SPICMD_HIGH_SPEED_READ) == EC_STATE_BUSY) {
++ printk(KERN_ERR
++ "EC_READ_BYTE : SPICMD_HIGH_SPEED_READ failed.\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ *byte = ec_read(REG_XBISPIDAT);
++
++ out:
++ /* disable spicmd writing. */
++ ec_stop_spi();
++
++ return ret;
++}
++
++/* write one byte to ec rom */
++static int ec_write_byte(unsigned int addr, unsigned char byte)
++{
++ int ret = 0;
++
++ /* enable spicmd writing. */
++ ec_start_spi();
++
++ /* enable write spi flash */
++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
++ printk(KERN_ERR
++ "EC_WRITE_BYTE : SPICMD_WRITE_ENABLE failed.\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ /* write the address */
++ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16);
++ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8);
++ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0);
++ ec_write(REG_XBISPIDAT, byte);
++ /* start action */
++ ec_write(REG_XBISPICMD, SPICMD_BYTE_PROGRAM);
++ if (rom_instruction_cycle(SPICMD_BYTE_PROGRAM) == EC_STATE_BUSY) {
++ printk(KERN_ERR
++ "EC_WRITE_BYTE : SPICMD_BYTE_PROGRAM failed.\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ out:
++ /* disable spicmd writing. */
++ ec_stop_spi();
++
++ return ret;
++}
++
++/* unprotect SPI ROM */
++/* EC_ROM_unprotect function code */
++static int EC_ROM_unprotect(void)
++{
++ unsigned char status;
++
++ /* enable write spi flash */
++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
++ printk(KERN_ERR
++ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n");
++ return 1;
++ }
++
++ /* unprotect the status register of rom */
++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
++ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) {
++ printk(KERN_ERR "EC_UNIT_ERASE : SPICMD_READ_STATUS failed.\n");
++ return 1;
++ }
++ status = ec_read(REG_XBISPIDAT);
++ ec_write(REG_XBISPIDAT, status & 0x02);
++ if (ec_instruction_cycle() < 0) {
++ printk(KERN_ERR "EC_UNIT_ERASE : write status value failed.\n");
++ return 1;
++ }
++
++ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS);
++ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) {
++ printk(KERN_ERR
++ "EC_UNIT_ERASE : SPICMD_WRITE_STATUS failed.\n");
++ return 1;
++ }
++
++ /* enable write spi flash */
++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
++ printk(KERN_ERR
++ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n");
++ return 1;
++ }
++
++ return 0;
++}
++
++/* erase one block or chip or sector as needed */
++static int ec_unit_erase(unsigned char erase_cmd, unsigned int addr)
++{
++ unsigned char status;
++ int ret = 0, i = 0;
++ int unprotect_count = 3;
++ int check_flag = 0;
++
++ /* enable spicmd writing. */
++ ec_start_spi();
++
++#ifdef EC_ROM_PROTECTION
++ /* added for re-check SPICMD_READ_STATUS */
++ while (unprotect_count-- > 0) {
++ if (EC_ROM_unprotect()) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ /* first time:500ms --> 5.5sec -->10.5sec */
++ for (i = 0; i < ((2 - unprotect_count) * 100 + 10); i++)
++ udelay(50000);
++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
++ if (rom_instruction_cycle(SPICMD_READ_STATUS)
++ == EC_STATE_BUSY) {
++ printk(KERN_ERR
++ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n");
++ } else {
++ status = ec_read(REG_XBISPIDAT);
++ printk(KERN_INFO "Read unprotect status : 0x%x\n",
++ status);
++ if ((status & 0x1C) == 0x00) {
++ printk(KERN_INFO
++ "Read unprotect status OK1 : 0x%x\n",
++ status & 0x1C);
++ check_flag = 1;
++ break;
++ }
++ }
++ }
++
++ if (!check_flag) {
++ printk(KERN_INFO "SPI ROM unprotect fail.\n");
++ return 1;
++ }
++#endif
++
++ /* block address fill */
++ if (erase_cmd == SPICMD_BLK_ERASE) {
++ ec_write(REG_XBISPIA2, (addr & 0x00ff0000) >> 16);
++ ec_write(REG_XBISPIA1, (addr & 0x0000ff00) >> 8);
++ ec_write(REG_XBISPIA0, (addr & 0x000000ff) >> 0);
++ }
++
++ /* erase the whole chip first */
++ ec_write(REG_XBISPICMD, erase_cmd);
++ if (rom_instruction_cycle(erase_cmd) == EC_STATE_BUSY) {
++ printk(KERN_ERR "EC_UNIT_ERASE : erase failed.\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ out:
++ /* disable spicmd writing. */
++ ec_stop_spi();
++
++ return ret;
++}
++
++/* update the whole rom content with H/W mode
++ * PLEASE USING ec_unit_erase() FIRSTLY
++ */
++static int ec_program_rom(struct ec_info *info, int flag)
++{
++ unsigned int addr = 0;
++ unsigned long size = 0;
++ unsigned char *ptr = NULL;
++ unsigned char data;
++ unsigned char val = 0;
++ int ret = 0;
++ int i, j;
++ unsigned char status;
++
++ /* modify for program serial No.
++ * set IE_START_ADDR & use idle mode,
++ * disable WDD
++ */
++ if (flag == PROGRAM_FLAG_ROM) {
++ ret = ec_init_reset_mode();
++ addr = info->start_addr + EC_START_ADDR;
++ printk(KERN_INFO "PROGRAM_FLAG_ROM..............\n");
++ } else if (flag == PROGRAM_FLAG_IE) {
++ ret = ec_init_idle_mode();
++ ec_disable_WDD();
++ addr = info->start_addr + IE_START_ADDR;
++ printk(KERN_INFO "PROGRAM_FLAG_IE..............\n");
++ } else {
++ return 0;
++ }
++
++ if (ret < 0) {
++ if (flag == PROGRAM_FLAG_IE)
++ ec_enable_WDD();
++ return ret;
++ }
++
++ size = info->size;
++ ptr = info->buf;
++ printk(KERN_INFO "starting update ec ROM..............\n");
++
++ ret = ec_unit_erase(SPICMD_BLK_ERASE, addr);
++ if (ret) {
++ printk(KERN_ERR "program ec : erase block failed.\n");
++ goto out;
++ }
++ printk(KERN_ERR "program ec : erase block OK.\n");
++
++ i = 0;
++ while (i < size) {
++ data = *(ptr + i);
++ ec_write_byte(addr, data);
++ ec_read_byte(addr, &val);
++ if (val != data) {
++ ec_write_byte(addr, data);
++ ec_read_byte(addr, &val);
++ if (val != data) {
++ printk(KERN_INFO
++ "EC : Second flash program failed at:\t");
++ printk(KERN_INFO
++ "addr : 0x%x, source : 0x%x, dest: 0x%x\n",
++ addr, data, val);
++ printk(KERN_INFO "This should not happen... STOP\n");
++ break;
++ }
++ }
++ i++;
++ addr++;
++ }
++
++#ifdef EC_ROM_PROTECTION
++ /* we should start spi access firstly */
++ ec_start_spi();
++
++ /* enable write spi flash */
++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
++ printk(KERN_ERR
++ "EC_PROGRAM_ROM : SPICMD_WRITE_ENABLE failed.\n");
++ goto out1;
++ }
++
++ /* protect the status register of rom */
++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
++ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) {
++ printk(KERN_ERR
++ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n");
++ goto out1;
++ }
++ status = ec_read(REG_XBISPIDAT);
++
++ ec_write(REG_XBISPIDAT, status | 0x1C);
++ if (ec_instruction_cycle() < 0) {
++ printk(KERN_ERR
++ "EC_PROGRAM_ROM : write status value failed.\n");
++ goto out1;
++ }
++
++ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS);
++ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) {
++ printk(KERN_ERR
++ "EC_PROGRAM_ROM : SPICMD_WRITE_STATUS failed.\n");
++ goto out1;
++ }
++#endif
++
++ /* disable the write action to spi rom */
++ ec_write(REG_XBISPICMD, SPICMD_WRITE_DISABLE);
++ if (rom_instruction_cycle(SPICMD_WRITE_DISABLE) == EC_STATE_BUSY) {
++ printk(KERN_ERR
++ "EC_PROGRAM_ROM : SPICMD_WRITE_DISABLE failed.\n");
++ goto out1;
++ }
++
++ out1:
++ /* we should stop spi access firstly */
++ ec_stop_spi();
++ out:
++ /* for security */
++ for (j = 0; j < 2000; j++)
++ udelay(1000);
++
++ /* modify for program serial No.
++ * after program No exit idle mode
++ * and enable WDD
++ */
++ if (flag == PROGRAM_FLAG_ROM) {
++ /* exit from the reset mode */
++ ec_exit_reset_mode();
++ } else {
++ /* ec exit from idle mode */
++ ret = ec_exit_idle_mode();
++ ec_enable_WDD();
++ if (ret < 0)
++ return ret;
++ }
++
++ return 0;
++}
++
++/* ioctl */
++static int misc_ioctl(struct inode *inode, struct file *filp, u_int cmd,
++ u_long arg)
++{
++ struct ec_info ecinfo;
++ void __user *ptr = (void __user *)arg;
++ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data);
++ int ret = 0;
++
++ switch (cmd) {
++ case IOCTL_RDREG:
++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg));
++ if (ret) {
++ printk(KERN_ERR "reg read : copy from user error.\n");
++ return -EFAULT;
++ }
++ if ((ecreg->addr > EC_MAX_REGADDR)
++ || (ecreg->addr < EC_MIN_REGADDR)) {
++ printk(KERN_ERR
++ "reg read : out of register address range.\n");
++ return -EINVAL;
++ }
++ ecreg->val = ec_read(ecreg->addr);
++ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg));
++ if (ret) {
++ printk(KERN_ERR "reg read : copy to user error.\n");
++ return -EFAULT;
++ }
++ break;
++ case IOCTL_WRREG:
++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg));
++ if (ret) {
++ printk(KERN_ERR "reg write : copy from user error.\n");
++ return -EFAULT;
++ }
++ if ((ecreg->addr > EC_MAX_REGADDR)
++ || (ecreg->addr < EC_MIN_REGADDR)) {
++ printk(KERN_ERR
++ "reg write : out of register address range.\n");
++ return -EINVAL;
++ }
++ ec_write(ecreg->addr, ecreg->val);
++ break;
++ case IOCTL_READ_EC:
++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg));
++ if (ret) {
++ printk(KERN_ERR "spi read : copy from user error.\n");
++ return -EFAULT;
++ }
++ if ((ecreg->addr > EC_RAM_ADDR)
++ && (ecreg->addr < EC_MAX_REGADDR)) {
++ printk(KERN_ERR
++ "spi read : out of register address range.\n");
++ return -EINVAL;
++ }
++ ec_read_byte(ecreg->addr, &(ecreg->val));
++ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg));
++ if (ret) {
++ printk(KERN_ERR "spi read : copy to user error.\n");
++ return -EFAULT;
++ }
++ break;
++ case IOCTL_PROGRAM_IE:
++ ecinfo.start_addr = EC_START_ADDR;
++ ecinfo.size = EC_CONTENT_MAX_SIZE;
++ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL);
++ if (ecinfo.buf == NULL) {
++ printk(KERN_ERR "program ie : kmalloc failed.\n");
++ return -ENOMEM;
++ }
++ ret = copy_from_user(ecinfo.buf, (u8 *) ptr, ecinfo.size);
++ if (ret) {
++ printk(KERN_ERR "program ie : copy from user error.\n");
++ kfree(ecinfo.buf);
++ ecinfo.buf = NULL;
++ return -EFAULT;
++ }
++
++ /* use ec_program_rom to write serial No */
++ ec_program_rom(&ecinfo, PROGRAM_FLAG_IE);
++
++ kfree(ecinfo.buf);
++ ecinfo.buf = NULL;
++ break;
++ case IOCTL_PROGRAM_EC:
++ ecinfo.start_addr = EC_START_ADDR;
++ if (get_user((ecinfo.size), (u32 *) ptr)) {
++ printk(KERN_ERR "program ec : get user error.\n");
++ return -EFAULT;
++ }
++ if ((ecinfo.size) > EC_CONTENT_MAX_SIZE) {
++ printk(KERN_ERR "program ec : size out of limited.\n");
++ return -EINVAL;
++ }
++ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL);
++ if (ecinfo.buf == NULL) {
++ printk(KERN_ERR "program ec : kmalloc failed.\n");
++ return -ENOMEM;
++ }
++ ret = copy_from_user(ecinfo.buf, ((u8 *) ptr + 4), ecinfo.size);
++ if (ret) {
++ printk(KERN_ERR "program ec : copy from user error.\n");
++ kfree(ecinfo.buf);
++ ecinfo.buf = NULL;
++ return -EFAULT;
++ }
++
++ ec_program_rom(&ecinfo, PROGRAM_FLAG_ROM);
++
++ kfree(ecinfo.buf);
++ ecinfo.buf = NULL;
++ break;
++
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++static long misc_compat_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ return misc_ioctl(file->f_dentry->d_inode, file, cmd, arg);
++}
++
++static int misc_open(struct inode *inode, struct file *filp)
++{
++ struct ec_reg *ecreg = NULL;
++ ecreg = kmalloc(sizeof(struct ec_reg), GFP_KERNEL);
++ if (ecreg)
++ filp->private_data = ecreg;
++
++ return ecreg ? 0 : -ENOMEM;
++}
++
++static int misc_release(struct inode *inode, struct file *filp)
++{
++ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data);
++
++ filp->private_data = NULL;
++ kfree(ecreg);
++
++ return 0;
++}
++
++static const struct file_operations ecmisc_fops = {
++ .open = misc_open,
++ .release = misc_release,
++ .read = NULL,
++ .write = NULL,
++#ifdef CONFIG_64BIT
++ .compat_ioctl = misc_compat_ioctl,
++#else
++ .ioctl = misc_ioctl,
++#endif
++};
++
++static struct miscdevice ecmisc_device = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = EC_MISC_DEV,
++ .fops = &ecmisc_fops
++};
++
++static int __init ecmisc_init(void)
++{
++ int ret;
++
++ printk(KERN_INFO "EC misc device init.\n");
++ ret = misc_register(&ecmisc_device);
++
++ return ret;
++}
++
++static void __exit ecmisc_exit(void)
++{
++ printk(KERN_INFO "EC misc device exit.\n");
++ misc_deregister(&ecmisc_device);
++}
++
++module_init(ecmisc_init);
++module_exit(ecmisc_exit);
++
++MODULE_AUTHOR("liujl <liujl@lemote.com>");
++MODULE_DESCRIPTION("Driver for flushing/dumping ROM of EC on YeeLoong laptop");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.6.37.orig/drivers/platform/mips/yeeloong_laptop.c linux-2.6.37/drivers/platform/mips/yeeloong_laptop.c
+--- linux-2.6.37.orig/drivers/platform/mips/yeeloong_laptop.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.37/drivers/platform/mips/yeeloong_laptop.c 2011-01-11 20:44:43.000000000 +0100
+@@ -0,0 +1,1200 @@
++/*
++ * Driver for YeeLoong laptop extras
++ *
++ * Copyright (C) 2009 Lemote Inc.
++ * Author: Wu Zhangjin <wuzhangjin@gmail.com>, Liu Junliang <liujl@lemote.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/backlight.h> /* for backlight subdriver */
++#include <linux/fb.h>
++#include <linux/hwmon.h> /* for hwmon subdriver */
++#include <linux/hwmon-sysfs.h>
++#include <linux/video_output.h> /* for video output subdriver */
++#include <linux/input.h> /* for hotkey subdriver */
++#include <linux/input/sparse-keymap.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/power_supply.h> /* for AC & Battery subdriver */
++
++#include <cs5536/cs5536.h>
++
++#include <loongson.h> /* for loongson_cmdline */
++#include <ec_kb3310b.h>
++
++/* common function */
++#define EC_VER_LEN 64
++
++static int ec_version_before(char *version)
++{
++ char *p, ec_ver[EC_VER_LEN];
++
++ p = strstr(loongson_cmdline, "EC_VER=");
++ if (!p)
++ memset(ec_ver, 0, EC_VER_LEN);
++ else {
++ strncpy(ec_ver, p, EC_VER_LEN);
++ p = strstr(ec_ver, " ");
++ if (p)
++ *p = '\0';
++ }
++
++ return (strncasecmp(ec_ver, version, 64) < 0);
++}
++
++/* backlight subdriver */
++#define MAX_BRIGHTNESS 8
++
++static int yeeloong_set_brightness(struct backlight_device *bd)
++{
++ unsigned int level, current_level;
++ static unsigned int old_level;
++
++ level = (bd->props.fb_blank == FB_BLANK_UNBLANK &&
++ bd->props.power == FB_BLANK_UNBLANK) ?
++ bd->props.brightness : 0;
++
++ level = SENSORS_LIMIT(level, 0, MAX_BRIGHTNESS);
++
++ /* Avoid to modify the brightness when EC is tuning it */
++ if (old_level != level) {
++ current_level = ec_read(REG_DISPLAY_BRIGHTNESS);
++ if (old_level == current_level)
++ ec_write(REG_DISPLAY_BRIGHTNESS, level);
++ old_level = level;
++ }
++
++ return 0;
++}
++
++static int yeeloong_get_brightness(struct backlight_device *bd)
++{
++ return ec_read(REG_DISPLAY_BRIGHTNESS);
++}
++
++static struct backlight_ops backlight_ops = {
++ .get_brightness = yeeloong_get_brightness,
++ .update_status = yeeloong_set_brightness,
++};
++
++static struct backlight_device *yeeloong_backlight_dev;
++
++static int yeeloong_backlight_init(void)
++{
++ int ret;
++ struct backlight_properties props;
++
++ memset(&props, 0, sizeof(struct backlight_properties));
++ props.max_brightness = MAX_BRIGHTNESS;
++ yeeloong_backlight_dev = backlight_device_register("backlight0", NULL,
++ NULL, &backlight_ops, &props);
++
++ if (IS_ERR(yeeloong_backlight_dev)) {
++ ret = PTR_ERR(yeeloong_backlight_dev);
++ yeeloong_backlight_dev = NULL;
++ return ret;
++ }
++
++ yeeloong_backlight_dev->props.brightness =
++ yeeloong_get_brightness(yeeloong_backlight_dev);
++ backlight_update_status(yeeloong_backlight_dev);
++
++ return 0;
++}
++
++static void yeeloong_backlight_exit(void)
++{
++ if (yeeloong_backlight_dev) {
++ backlight_device_unregister(yeeloong_backlight_dev);
++ yeeloong_backlight_dev = NULL;
++ }
++}
++
++/* AC & Battery subdriver */
++
++static struct power_supply yeeloong_ac, yeeloong_bat;
++
++#define AC_OFFLINE 0
++#define AC_ONLINE 1
++
++static int yeeloong_get_ac_props(struct power_supply *psy,
++ enum power_supply_property psp,
++ union power_supply_propval *val)
++{
++ switch (psp) {
++ case POWER_SUPPLY_PROP_ONLINE:
++ val->intval = ((ec_read(REG_BAT_POWER)) & BIT_BAT_POWER_ACIN) ?
++ AC_ONLINE : AC_OFFLINE;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static enum power_supply_property yeeloong_ac_props[] = {
++ POWER_SUPPLY_PROP_ONLINE,
++};
++
++static struct power_supply yeeloong_ac = {
++ .name = "yeeloong-ac",
++ .type = POWER_SUPPLY_TYPE_MAINS,
++ .properties = yeeloong_ac_props,
++ .num_properties = ARRAY_SIZE(yeeloong_ac_props),
++ .get_property = yeeloong_get_ac_props,
++};
++
++#define BAT_CAP_CRITICAL 5
++#define BAT_CAP_HIGH 99
++
++#define get_bat_info(type) \
++ ((ec_read(REG_BAT_##type##_HIGH) << 8) | \
++ (ec_read(REG_BAT_##type##_LOW)))
++
++static int yeeloong_bat_get_ex_property(enum power_supply_property psp,
++ union power_supply_propval *val)
++{
++ int bat_in, curr_cap, cap_level, status, charge, health;
++
++ status = ec_read(REG_BAT_STATUS);
++ bat_in = status & BIT_BAT_STATUS_IN;
++ curr_cap = get_bat_info(RELATIVE_CAP);
++ if (status & BIT_BAT_STATUS_FULL)
++ curr_cap = 100;
++
++ switch (psp) {
++ case POWER_SUPPLY_PROP_PRESENT:
++ val->intval = bat_in;
++ break;
++ case POWER_SUPPLY_PROP_CAPACITY:
++ val->intval = curr_cap;
++ break;
++ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
++ cap_level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
++ if (status & BIT_BAT_STATUS_LOW) {
++ cap_level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
++ if (curr_cap <= BAT_CAP_CRITICAL)
++ cap_level =
++ POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
++ } else if (status & BIT_BAT_STATUS_FULL) {
++ cap_level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
++ if (curr_cap >= BAT_CAP_HIGH)
++ cap_level = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
++ } else if (status & BIT_BAT_STATUS_DESTROY)
++ cap_level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
++ val->intval = cap_level;
++ break;
++ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
++ /* seconds */
++ val->intval = bat_in ? (curr_cap - 3) * 54 + 142 : 0;
++ break;
++ case POWER_SUPPLY_PROP_STATUS:
++ if (!bat_in)
++ charge = POWER_SUPPLY_STATUS_UNKNOWN;
++ else {
++ if (status & BIT_BAT_STATUS_FULL) {
++ val->intval = POWER_SUPPLY_STATUS_FULL;
++ break;
++ }
++
++ charge = ec_read(REG_BAT_CHARGE);
++ if (charge & FLAG_BAT_CHARGE_DISCHARGE)
++ charge = POWER_SUPPLY_STATUS_DISCHARGING;
++ else if (charge & FLAG_BAT_CHARGE_CHARGE)
++ charge = POWER_SUPPLY_STATUS_CHARGING;
++ else
++ charge = POWER_SUPPLY_STATUS_NOT_CHARGING;
++ }
++ val->intval = charge;
++ break;
++ case POWER_SUPPLY_PROP_HEALTH:
++ if (!bat_in) /* no battery present */
++ health = POWER_SUPPLY_HEALTH_UNKNOWN;
++ else { /* Assume it is good */
++ health = POWER_SUPPLY_HEALTH_GOOD;
++ if (status &
++ (BIT_BAT_STATUS_DESTROY | BIT_BAT_STATUS_LOW))
++ health = POWER_SUPPLY_HEALTH_DEAD;
++ if (ec_read(REG_BAT_CHARGE_STATUS) &
++ BIT_BAT_CHARGE_STATUS_OVERTEMP)
++ health = POWER_SUPPLY_HEALTH_OVERHEAT;
++ }
++ val->intval = health;
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_NOW: /* 1/100(%)*1000 µAh */
++ val->intval = curr_cap * get_bat_info(FULLCHG_CAP) * 10;
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int get_battery_temp(void)
++{
++ int value;
++
++ value = get_bat_info(TEMPERATURE);
++
++ return value * 1000;
++}
++
++static int get_battery_current(void)
++{
++ s16 value;
++
++ value = get_bat_info(CURRENT);
++
++ return -value;
++}
++
++static int get_battery_voltage(void)
++{
++ int value;
++
++ value = get_bat_info(VOLTAGE);
++
++ return value;
++}
++
++static int yeeloong_get_bat_props(struct power_supply *psy,
++ enum power_supply_property psp,
++ union power_supply_propval *val)
++{
++ switch (psp) {
++ /* Fixed information */
++ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
++ val->intval = get_bat_info(DESIGN_VOL) * 1000; /* mV -> µV */
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
++ val->intval = get_bat_info(DESIGN_CAP) * 1000; /* mAh->µAh */
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_FULL:
++ val->intval = get_bat_info(FULLCHG_CAP) * 1000; /* µAh */
++ break;
++ case POWER_SUPPLY_PROP_MANUFACTURER:
++ val->strval = (ec_read(REG_BAT_VENDOR) ==
++ FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO";
++ break;
++ /* Dynamic information */
++ case POWER_SUPPLY_PROP_CURRENT_NOW:
++ val->intval = get_battery_current() * 1000; /* mA -> µA */
++ break;
++ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
++ val->intval = get_battery_voltage() * 1000; /* mV -> µV */
++ break;
++ case POWER_SUPPLY_PROP_TEMP:
++ val->intval = get_battery_temp(); /* Celcius */
++ break;
++ /* Dynamic but related information */
++ default:
++ return yeeloong_bat_get_ex_property(psp, val);
++ }
++
++ return 0;
++}
++
++static enum power_supply_property yeeloong_bat_props[] = {
++ POWER_SUPPLY_PROP_STATUS,
++ POWER_SUPPLY_PROP_PRESENT,
++ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
++ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
++ POWER_SUPPLY_PROP_CHARGE_FULL,
++ POWER_SUPPLY_PROP_CHARGE_NOW,
++ POWER_SUPPLY_PROP_CURRENT_NOW,
++ POWER_SUPPLY_PROP_VOLTAGE_NOW,
++ POWER_SUPPLY_PROP_HEALTH,
++ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
++ POWER_SUPPLY_PROP_CAPACITY,
++ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
++ POWER_SUPPLY_PROP_TEMP,
++ POWER_SUPPLY_PROP_MANUFACTURER,
++};
++
++static struct power_supply yeeloong_bat = {
++ .name = "yeeloong-bat",
++ .type = POWER_SUPPLY_TYPE_BATTERY,
++ .properties = yeeloong_bat_props,
++ .num_properties = ARRAY_SIZE(yeeloong_bat_props),
++ .get_property = yeeloong_get_bat_props,
++};
++
++static int ac_bat_initialized;
++
++static int yeeloong_bat_init(void)
++{
++ int ret;
++
++ ret = power_supply_register(NULL, &yeeloong_ac);
++ if (ret)
++ return ret;
++ ret = power_supply_register(NULL, &yeeloong_bat);
++ if (ret) {
++ power_supply_unregister(&yeeloong_ac);
++ return ret;
++ }
++ ac_bat_initialized = 1;
++
++ return 0;
++}
++
++static void yeeloong_bat_exit(void)
++{
++ ac_bat_initialized = 0;
++
++ power_supply_unregister(&yeeloong_ac);
++ power_supply_unregister(&yeeloong_bat);
++}
++/* hwmon subdriver */
++
++#define MIN_FAN_SPEED 0
++#define MAX_FAN_SPEED 3
++
++static int get_fan_pwm_enable(void)
++{
++ int level, mode;
++
++ level = ec_read(REG_FAN_SPEED_LEVEL);
++ mode = ec_read(REG_FAN_AUTO_MAN_SWITCH);
++
++ if (level == MAX_FAN_SPEED && mode == BIT_FAN_MANUAL)
++ mode = 0;
++ else if (mode == BIT_FAN_MANUAL)
++ mode = 1;
++ else
++ mode = 2;
++
++ return mode;
++}
++
++static void set_fan_pwm_enable(int mode)
++{
++ switch (mode) {
++ case 0:
++ /* fullspeed */
++ ec_write(REG_FAN_AUTO_MAN_SWITCH, BIT_FAN_MANUAL);
++ ec_write(REG_FAN_SPEED_LEVEL, MAX_FAN_SPEED);
++ break;
++ case 1:
++ ec_write(REG_FAN_AUTO_MAN_SWITCH, BIT_FAN_MANUAL);
++ break;
++ case 2:
++ ec_write(REG_FAN_AUTO_MAN_SWITCH, BIT_FAN_AUTO);
++ break;
++ default:
++ break;
++ }
++}
++
++static int get_fan_pwm(void)
++{
++ return ec_read(REG_FAN_SPEED_LEVEL);
++}
++
++static void set_fan_pwm(int value)
++{
++ int mode;
++
++ mode = ec_read(REG_FAN_AUTO_MAN_SWITCH);
++ if (mode != BIT_FAN_MANUAL)
++ return;
++
++ value = SENSORS_LIMIT(value, 0, 3);
++
++ /* We must ensure the fan is on */
++ if (value > 0)
++ ec_write(REG_FAN_CONTROL, BIT_FAN_CONTROL_ON);
++
++ ec_write(REG_FAN_SPEED_LEVEL, value);
++}
++
++static int get_fan_rpm(void)
++{
++ int value;
++
++ value = FAN_SPEED_DIVIDER /
++ (((ec_read(REG_FAN_SPEED_HIGH) & 0x0f) << 8) |
++ ec_read(REG_FAN_SPEED_LOW));
++
++ return value;
++}
++
++static int get_cpu_temp(void)
++{
++ s8 value;
++
++ value = ec_read(REG_TEMPERATURE_VALUE);
++
++ return value * 1000;
++}
++
++static int get_cpu_temp_max(void)
++{
++ return 60 * 1000;
++}
++
++static int get_battery_temp_alarm(void)
++{
++ int status;
++
++ status = (ec_read(REG_BAT_CHARGE_STATUS) &
++ BIT_BAT_CHARGE_STATUS_OVERTEMP);
++
++ return !!status;
++}
++
++static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count)
++{
++ int ret;
++ unsigned long value;
++
++ if (!count)
++ return 0;
++
++ ret = strict_strtoul(buf, 10, &value);
++ if (ret)
++ return ret;
++
++ set(value);
++
++ return count;
++}
++
++static ssize_t show_sys_hwmon(int (*get) (void), char *buf)
++{
++ return sprintf(buf, "%d\n", get());
++}
++
++#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
++ static ssize_t show_##_name(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++ { \
++ return show_sys_hwmon(_set, buf); \
++ } \
++ static ssize_t store_##_name(struct device *dev, \
++ struct device_attribute *attr, \
++ const char *buf, size_t count) \
++ { \
++ return store_sys_hwmon(_get, buf, count); \
++ } \
++ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
++
++CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL);
++CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm);
++CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable,
++ set_fan_pwm_enable);
++CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL);
++CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL);
++CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_battery_temp, NULL);
++CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_battery_temp_alarm, NULL);
++CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_battery_current, NULL);
++CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_battery_voltage, NULL);
++
++static ssize_t
++show_name(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return sprintf(buf, "yeeloong\n");
++}
++
++static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
++
++static struct attribute *hwmon_attributes[] = {
++ &sensor_dev_attr_pwm1.dev_attr.attr,
++ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
++ &sensor_dev_attr_fan1_input.dev_attr.attr,
++ &sensor_dev_attr_temp1_input.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_temp2_input.dev_attr.attr,
++ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
++ &sensor_dev_attr_curr1_input.dev_attr.attr,
++ &sensor_dev_attr_in1_input.dev_attr.attr,
++ &sensor_dev_attr_name.dev_attr.attr,
++ NULL
++};
++
++static struct attribute_group hwmon_attribute_group = {
++ .attrs = hwmon_attributes
++};
++
++static struct device *yeeloong_hwmon_dev;
++
++static int yeeloong_hwmon_init(void)
++{
++ int ret;
++
++ yeeloong_hwmon_dev = hwmon_device_register(NULL);
++ if (IS_ERR(yeeloong_hwmon_dev)) {
++ pr_err("Fail to register yeeloong hwmon device\n");
++ yeeloong_hwmon_dev = NULL;
++ return PTR_ERR(yeeloong_hwmon_dev);
++ }
++ ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj,
++ &hwmon_attribute_group);
++ if (ret) {
++ hwmon_device_unregister(yeeloong_hwmon_dev);
++ yeeloong_hwmon_dev = NULL;
++ return ret;
++ }
++ /* ensure fan is set to auto mode */
++ set_fan_pwm_enable(2);
++
++ return 0;
++}
++
++static void yeeloong_hwmon_exit(void)
++{
++ if (yeeloong_hwmon_dev) {
++ sysfs_remove_group(&yeeloong_hwmon_dev->kobj,
++ &hwmon_attribute_group);
++ hwmon_device_unregister(yeeloong_hwmon_dev);
++ yeeloong_hwmon_dev = NULL;
++ }
++}
++
++/* video output subdriver */
++
++static int lcd_video_output_get(struct output_device *od)
++{
++ return ec_read(REG_DISPLAY_LCD);
++}
++
++#define LCD 0
++#define CRT 1
++
++static void display_vo_set(int display, int on)
++{
++ int addr;
++ unsigned long value;
++
++ addr = (display == LCD) ? 0x31 : 0x21;
++
++ outb(addr, 0x3c4);
++ value = inb(0x3c5);
++
++ if (display == LCD)
++ value |= (on ? 0x03 : 0x02);
++ else {
++ if (on)
++ clear_bit(7, &value);
++ else
++ set_bit(7, &value);
++ }
++
++ outb(addr, 0x3c4);
++ outb(value, 0x3c5);
++}
++
++static int lcd_video_output_set(struct output_device *od)
++{
++ unsigned long status;
++
++ status = !!od->request_state;
++
++ display_vo_set(LCD, status);
++ ec_write(REG_BACKLIGHT_CTRL, status);
++
++ return 0;
++}
++
++static struct output_properties lcd_output_properties = {
++ .set_state = lcd_video_output_set,
++ .get_status = lcd_video_output_get,
++};
++
++static int crt_video_output_get(struct output_device *od)
++{
++ return ec_read(REG_CRT_DETECT);
++}
++
++static int crt_video_output_set(struct output_device *od)
++{
++ unsigned long status;
++
++ status = !!od->request_state;
++
++ if (ec_read(REG_CRT_DETECT) == BIT_CRT_DETECT_PLUG)
++ display_vo_set(CRT, status);
++
++ return 0;
++}
++
++static struct output_properties crt_output_properties = {
++ .set_state = crt_video_output_set,
++ .get_status = crt_video_output_get,
++};
++
++static struct output_device *lcd_output_dev, *crt_output_dev;
++
++static void yeeloong_lcd_vo_set(int status)
++{
++ lcd_output_dev->request_state = status;
++ lcd_video_output_set(lcd_output_dev);
++}
++
++static void yeeloong_crt_vo_set(int status)
++{
++ crt_output_dev->request_state = status;
++ crt_video_output_set(crt_output_dev);
++}
++
++static int yeeloong_vo_init(void)
++{
++ int ret;
++
++ /* Register video output device: lcd, crt */
++ lcd_output_dev = video_output_register("LCD", NULL, NULL,
++ &lcd_output_properties);
++
++ if (IS_ERR(lcd_output_dev)) {
++ ret = PTR_ERR(lcd_output_dev);
++ lcd_output_dev = NULL;
++ return ret;
++ }
++ /* Ensure LCD is on by default */
++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
++
++ crt_output_dev = video_output_register("CRT", NULL, NULL,
++ &crt_output_properties);
++
++ if (IS_ERR(crt_output_dev)) {
++ ret = PTR_ERR(crt_output_dev);
++ crt_output_dev = NULL;
++ return ret;
++ }
++
++ /* Turn off CRT by default, and will be enabled when the CRT
++ * connectting event reported by SCI */
++ yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
++
++ return 0;
++}
++
++static void yeeloong_vo_exit(void)
++{
++ if (lcd_output_dev) {
++ video_output_unregister(lcd_output_dev);
++ lcd_output_dev = NULL;
++ }
++ if (crt_output_dev) {
++ video_output_unregister(crt_output_dev);
++ crt_output_dev = NULL;
++ }
++}
++
++/* hotkey subdriver */
++
++static struct input_dev *yeeloong_hotkey_dev;
++
++static const struct key_entry yeeloong_keymap[] = {
++ {KE_SW, EVENT_LID, { SW_LID } },
++ {KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */
++ {KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */
++ {KE_KEY, EVENT_DISPLAYTOGGLE, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */
++ {KE_KEY, EVENT_SWITCHVIDEOMODE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */
++ {KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */
++ {KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */
++ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */
++ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + down */
++ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */
++ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEDOWN } }, /* Fn + left */
++ {KE_END, 0}
++};
++
++static struct key_entry *get_event_key_entry(int event, int status)
++{
++ struct key_entry *ke;
++ static int old_brightness_status = -1;
++ static int old_volume_status = -1;
++
++ ke = sparse_keymap_entry_from_scancode(yeeloong_hotkey_dev, event);
++ if (!ke)
++ return NULL;
++
++ switch (event) {
++ case EVENT_DISPLAY_BRIGHTNESS:
++ /* current status > old one, means up */
++ if ((status < old_brightness_status) || (0 == status))
++ ke++;
++ old_brightness_status = status;
++ break;
++ case EVENT_AUDIO_VOLUME:
++ if ((status < old_volume_status) || (0 == status))
++ ke++;
++ old_volume_status = status;
++ break;
++ default:
++ break;
++ }
++
++ return ke;
++}
++
++static int report_lid_switch(int status)
++{
++ input_report_switch(yeeloong_hotkey_dev, SW_LID, !status);
++ input_sync(yeeloong_hotkey_dev);
++
++ return status;
++}
++
++static int crt_detect_handler(int status)
++{
++ if (status) {
++ yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG);
++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF);
++ } else {
++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
++ yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
++ }
++ return status;
++}
++
++static int displaytoggle_handler(int status)
++{
++ /* EC(>=PQ1D26) does this job for us, we can not do it again,
++ * otherwise, the brightness will not resume to the normal level! */
++ if (ec_version_before("EC_VER=PQ1D26"))
++ yeeloong_lcd_vo_set(status);
++
++ return status;
++}
++
++static int switchvideomode_handler(int status)
++{
++ static int video_output_status;
++
++ /* Only enable switch video output button
++ * when CRT is connected */
++ if (ec_read(REG_CRT_DETECT) == BIT_CRT_DETECT_UNPLUG)
++ return 0;
++ /* 0. no CRT connected: LCD on, CRT off
++ * 1. BOTH on
++ * 2. LCD off, CRT on
++ * 3. BOTH off
++ * 4. LCD on, CRT off
++ */
++ video_output_status++;
++ if (video_output_status > 4)
++ video_output_status = 1;
++
++ switch (video_output_status) {
++ case 1:
++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
++ yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG);
++ break;
++ case 2:
++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF);
++ yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG);
++ break;
++ case 3:
++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF);
++ yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
++ break;
++ case 4:
++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
++ yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
++ break;
++ default:
++ /* Ensure LCD is on */
++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
++ break;
++ }
++ return video_output_status;
++}
++
++static int camera_handler(int status)
++{
++ int value;
++
++ value = ec_read(REG_CAMERA_CONTROL);
++ ec_write(REG_CAMERA_CONTROL, value | (1 << 1));
++
++ return status;
++}
++
++static int usb2_handler(int status)
++{
++ pr_emerg("USB2 Over Current occurred\n");
++
++ return status;
++}
++
++static int usb0_handler(int status)
++{
++ pr_emerg("USB0 Over Current occurred\n");
++
++ return status;
++}
++
++static int ac_bat_handler(int status)
++{
++ if (ac_bat_initialized) {
++ power_supply_changed(&yeeloong_ac);
++ power_supply_changed(&yeeloong_bat);
++ }
++ return status;
++}
++
++static void do_event_action(int event)
++{
++ sci_handler handler;
++ int reg, status;
++ struct key_entry *ke;
++
++ reg = 0;
++ handler = NULL;
++
++ switch (event) {
++ case EVENT_LID:
++ reg = REG_LID_DETECT;
++ break;
++ case EVENT_SWITCHVIDEOMODE:
++ handler = switchvideomode_handler;
++ break;
++ case EVENT_CRT_DETECT:
++ reg = REG_CRT_DETECT;
++ handler = crt_detect_handler;
++ break;
++ case EVENT_CAMERA:
++ reg = REG_CAMERA_STATUS;
++ handler = camera_handler;
++ break;
++ case EVENT_USB_OC2:
++ reg = REG_USB2_FLAG;
++ handler = usb2_handler;
++ break;
++ case EVENT_USB_OC0:
++ reg = REG_USB0_FLAG;
++ handler = usb0_handler;
++ break;
++ case EVENT_DISPLAYTOGGLE:
++ reg = REG_DISPLAY_LCD;
++ handler = displaytoggle_handler;
++ break;
++ case EVENT_AUDIO_MUTE:
++ reg = REG_AUDIO_MUTE;
++ break;
++ case EVENT_DISPLAY_BRIGHTNESS:
++ reg = REG_DISPLAY_BRIGHTNESS;
++ break;
++ case EVENT_AUDIO_VOLUME:
++ reg = REG_AUDIO_VOLUME;
++ break;
++ case EVENT_AC_BAT:
++ handler = ac_bat_handler;
++ break;
++ default:
++ break;
++ }
++
++ if (reg != 0)
++ status = ec_read(reg);
++
++ if (handler != NULL)
++ status = handler(status);
++
++ pr_info("%s: event: %d status: %d\n", __func__, event, status);
++
++ /* Report current key to user-space */
++ ke = get_event_key_entry(event, status);
++ if (ke) {
++ if (ke->keycode == SW_LID)
++ report_lid_switch(status);
++ else
++ sparse_keymap_report_entry(yeeloong_hotkey_dev, ke, 1,
++ true);
++ }
++}
++
++/*
++ * SCI(system control interrupt) main interrupt routine
++ *
++ * We will do the query and get event number together so the interrupt routine
++ * should be longer than 120us now at least 3ms elpase for it.
++ */
++static irqreturn_t sci_irq_handler(int irq, void *dev_id)
++{
++ int ret, event;
++
++ if (SCI_IRQ_NUM != irq)
++ return IRQ_NONE;
++
++ /* Query the event number */
++ ret = ec_query_event_num();
++ if (ret < 0)
++ return IRQ_NONE;
++
++ event = ec_get_event_num();
++ if (event < EVENT_START || event > EVENT_END)
++ return IRQ_NONE;
++
++ /* Execute corresponding actions */
++ do_event_action(event);
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * Config and init some msr and gpio register properly.
++ */
++static int sci_irq_init(void)
++{
++ u32 hi, lo;
++ u32 gpio_base;
++ unsigned long flags;
++ int ret;
++
++ /* Get gpio base */
++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo);
++ gpio_base = lo & 0xff00;
++
++ /* Filter the former kb3310 interrupt for security */
++ ret = ec_query_event_num();
++ if (ret)
++ return ret;
++
++ /* For filtering next number interrupt */
++ udelay(10000);
++
++ /* Set gpio native registers and msrs for GPIO27 SCI EVENT PIN
++ * gpio :
++ * input, pull-up, no-invert, event-count and value 0,
++ * no-filter, no edge mode
++ * gpio27 map to Virtual gpio0
++ * msr :
++ * no primary and lpc
++ * Unrestricted Z input to IG10 from Virtual gpio 0.
++ */
++ local_irq_save(flags);
++ _rdmsr(0x80000024, &hi, &lo);
++ lo &= ~(1 << 10);
++ _wrmsr(0x80000024, hi, lo);
++ _rdmsr(0x80000025, &hi, &lo);
++ lo &= ~(1 << 10);
++ _wrmsr(0x80000025, hi, lo);
++ _rdmsr(0x80000023, &hi, &lo);
++ lo |= (0x0a << 0);
++ _wrmsr(0x80000023, hi, lo);
++ local_irq_restore(flags);
++
++ /* Set gpio27 as sci interrupt
++ *
++ * input, pull-up, no-fliter, no-negedge, invert
++ * the sci event is just about 120us
++ */
++ asm(".set noreorder\n");
++ /* input enable */
++ outl(0x00000800, (gpio_base | 0xA0));
++ /* revert the input */
++ outl(0x00000800, (gpio_base | 0xA4));
++ /* event-int enable */
++ outl(0x00000800, (gpio_base | 0xB8));
++ asm(".set reorder\n");
++
++ return 0;
++}
++
++static struct irqaction sci_irqaction = {
++ .handler = sci_irq_handler,
++ .name = "sci",
++ .flags = IRQF_SHARED,
++};
++
++static int yeeloong_hotkey_init(void)
++{
++ int ret;
++
++ ret = sci_irq_init();
++ if (ret)
++ return -EFAULT;
++
++ ret = setup_irq(SCI_IRQ_NUM, &sci_irqaction);
++ if (ret)
++ return -EFAULT;
++
++ yeeloong_hotkey_dev = input_allocate_device();
++
++ if (!yeeloong_hotkey_dev) {
++ remove_irq(SCI_IRQ_NUM, &sci_irqaction);
++ return -ENOMEM;
++ }
++
++ yeeloong_hotkey_dev->name = "HotKeys";
++ yeeloong_hotkey_dev->phys = "button/input0";
++ yeeloong_hotkey_dev->id.bustype = BUS_HOST;
++ yeeloong_hotkey_dev->dev.parent = NULL;
++
++ ret = sparse_keymap_setup(yeeloong_hotkey_dev, yeeloong_keymap, NULL);
++ if (ret) {
++ pr_err("Fail to setup input device keymap\n");
++ input_free_device(yeeloong_hotkey_dev);
++ return ret;
++ }
++
++ ret = input_register_device(yeeloong_hotkey_dev);
++ if (ret) {
++ sparse_keymap_free(yeeloong_hotkey_dev);
++ input_free_device(yeeloong_hotkey_dev);
++ return ret;
++ }
++
++ /* Update the current status of LID */
++ report_lid_switch(BIT_LID_DETECT_ON);
++
++#ifdef CONFIG_LOONGSON_SUSPEND
++ /* Install the real yeeloong_report_lid_status for pm.c */
++ yeeloong_report_lid_status = report_lid_switch;
++#endif
++
++ return 0;
++}
++
++static void yeeloong_hotkey_exit(void)
++{
++ /* Free irq */
++ remove_irq(SCI_IRQ_NUM, &sci_irqaction);
++
++#ifdef CONFIG_LOONGSON_SUSPEND
++ /* Uninstall yeeloong_report_lid_status for pm.c */
++ if (yeeloong_report_lid_status == report_lid_switch)
++ yeeloong_report_lid_status = NULL;
++#endif
++
++ if (yeeloong_hotkey_dev) {
++ sparse_keymap_free(yeeloong_hotkey_dev);
++ input_unregister_device(yeeloong_hotkey_dev);
++ yeeloong_hotkey_dev = NULL;
++ }
++}
++
++#ifdef CONFIG_PM
++static void usb_ports_set(int status)
++{
++ status = !!status;
++
++ ec_write(REG_USB0_FLAG, status);
++ ec_write(REG_USB1_FLAG, status);
++ ec_write(REG_USB2_FLAG, status);
++}
++
++static int yeeloong_suspend(struct device *dev)
++
++{
++ if (ec_version_before("EC_VER=PQ1D27"))
++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF);
++ yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
++ usb_ports_set(BIT_USB_FLAG_OFF);
++
++ return 0;
++}
++
++static int yeeloong_resume(struct device *dev)
++{
++ if (ec_version_before("EC_VER=PQ1D27"))
++ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
++ yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG);
++ usb_ports_set(BIT_USB_FLAG_ON);
++
++ return 0;
++}
++
++static const SIMPLE_DEV_PM_OPS(yeeloong_pm_ops, yeeloong_suspend,
++ yeeloong_resume);
++#endif
++
++static struct platform_device_id platform_device_ids[] = {
++ {
++ .name = "yeeloong_laptop",
++ },
++ {}
++};
++
++MODULE_DEVICE_TABLE(platform, platform_device_ids);
++
++static struct platform_driver platform_driver = {
++ .driver = {
++ .name = "yeeloong_laptop",
++ .owner = THIS_MODULE,
++#ifdef CONFIG_PM
++ .pm = &yeeloong_pm_ops,
++#endif
++ },
++ .id_table = platform_device_ids,
++};
++
++static int __init yeeloong_init(void)
++{
++ int ret;
++
++ pr_info("Load YeeLoong Laptop Platform Specific Driver.\n");
++
++ /* Register platform stuff */
++ ret = platform_driver_register(&platform_driver);
++ if (ret) {
++ pr_err("Fail to register yeeloong platform driver.\n");
++ return ret;
++ }
++
++ ret = yeeloong_backlight_init();
++ if (ret) {
++ pr_err("Fail to register yeeloong backlight driver.\n");
++ yeeloong_backlight_exit();
++ return ret;
++ }
++
++ ret = yeeloong_bat_init();
++ if (ret) {
++ pr_err("Fail to register yeeloong battery driver.\n");
++ yeeloong_bat_exit();
++ return ret;
++ }
++
++ ret = yeeloong_hwmon_init();
++ if (ret) {
++ pr_err("Fail to register yeeloong hwmon driver.\n");
++ yeeloong_hwmon_exit();
++ return ret;
++ }
++
++ ret = yeeloong_vo_init();
++ if (ret) {
++ pr_err("Fail to register yeeloong video output driver.\n");
++ yeeloong_vo_exit();
++ return ret;
++ }
++
++ ret = yeeloong_hotkey_init();
++ if (ret) {
++ pr_err("Fail to register yeeloong hotkey driver.\n");
++ yeeloong_hotkey_exit();
++ return ret;
++ }
++
++ return 0;
++}
++
++static void __exit yeeloong_exit(void)
++{
++ yeeloong_hotkey_exit();
++ yeeloong_vo_exit();
++ yeeloong_hwmon_exit();
++ yeeloong_bat_exit();
++ yeeloong_backlight_exit();
++ platform_driver_unregister(&platform_driver);
++
++ pr_info("Unload YeeLoong Platform Specific Driver.\n");
++}
++
++module_init(yeeloong_init);
++module_exit(yeeloong_exit);
++
++MODULE_AUTHOR("Wu Zhangjin <wuzhangjin@gmail.com>; Liu Junliang <liujl@lemote.com>");
++MODULE_DESCRIPTION("YeeLoong laptop driver");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.6.37.orig/drivers/staging/sm7xx/smtcfb.c linux-2.6.37/drivers/staging/sm7xx/smtcfb.c
+--- linux-2.6.37.orig/drivers/staging/sm7xx/smtcfb.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/staging/sm7xx/smtcfb.c 2011-01-11 20:44:43.000000000 +0100
+@@ -12,6 +12,8 @@
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
++ * - Remove the buggy 2D support for Lynx, 2010/01/06, Wu Zhangjin
++ *
+ * Version 0.10.26192.21.01
+ * - Add PowerPC/Big endian support
+ * - Add 2D support for Lynx
+@@ -107,6 +109,7 @@
+ {"0x307", 1280, 1024, 8},
+
+ {"0x311", 640, 480, 16},
++ {"0x313", 800, 480, 16},
+ {"0x314", 800, 600, 16},
+ {"0x317", 1024, 768, 16},
+ {"0x31A", 1280, 1024, 16},
+diff -Nur linux-2.6.37.orig/drivers/usb/host/ohci-hcd.c linux-2.6.37/drivers/usb/host/ohci-hcd.c
+--- linux-2.6.37.orig/drivers/usb/host/ohci-hcd.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/usb/host/ohci-hcd.c 2011-01-11 20:44:43.000000000 +0100
+@@ -838,9 +838,13 @@
+ }
+
+ if (ints & OHCI_INTR_WDH) {
+- spin_lock (&ohci->lock);
+- dl_done_list (ohci);
+- spin_unlock (&ohci->lock);
++ if (ohci->hcca->done_head == 0) {
++ ints &= ~OHCI_INTR_WDH;
++ } else {
++ spin_lock (&ohci->lock);
++ dl_done_list (ohci);
++ spin_unlock (&ohci->lock);
++ }
+ }
+
+ if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
+diff -Nur linux-2.6.37.orig/net/rfkill/core.c linux-2.6.37/net/rfkill/core.c
+--- linux-2.6.37.orig/net/rfkill/core.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/net/rfkill/core.c 2011-01-11 20:44:43.000000000 +0100
+@@ -112,7 +112,7 @@
+ static DEFINE_MUTEX(rfkill_global_mutex);
+ static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */
+
+-static unsigned int rfkill_default_state = 1;
++static unsigned int rfkill_default_state; /* default: 0 = radio off */
+ module_param_named(default_state, rfkill_default_state, uint, 0444);
+ MODULE_PARM_DESC(default_state,
+ "Default initial state for all radio types, 0 = radio off");
diff --git a/target/linux/patches/2.6.37/mtd-root.patch b/target/linux/patches/2.6.37/mtd-root.patch
new file mode 100644
index 000000000..ecb9a696b
--- /dev/null
+++ b/target/linux/patches/2.6.37/mtd-root.patch
@@ -0,0 +1,64 @@
+diff -Nur linux-2.6.37.orig/drivers/mtd/Kconfig linux-2.6.37/drivers/mtd/Kconfig
+--- linux-2.6.37.orig/drivers/mtd/Kconfig 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/mtd/Kconfig 2011-01-11 20:32:21.000000000 +0100
+@@ -53,6 +53,11 @@
+ devices. Partitioning on NFTL 'devices' is a different - that's the
+ 'normal' form of partitioning used on a block device.
+
++config MTD_ROOTFS_ROOT_DEV
++ bool "Automatically set 'rootfs' partition to be root filesystem"
++ depends on MTD_PARTITIONS
++ default y
++
+ config MTD_REDBOOT_PARTS
+ tristate "RedBoot partition table parsing"
+ depends on MTD_PARTITIONS
+diff -Nur linux-2.6.37.orig/drivers/mtd/mtdpart.c linux-2.6.37/drivers/mtd/mtdpart.c
+--- linux-2.6.37.orig/drivers/mtd/mtdpart.c 2011-01-05 01:50:19.000000000 +0100
++++ linux-2.6.37/drivers/mtd/mtdpart.c 2011-01-11 20:40:29.000000000 +0100
+@@ -30,6 +30,7 @@
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/err.h>
++#include <linux/root_dev.h>
+
+ /* Our partition linked list */
+ static LIST_HEAD(mtd_partitions);
+@@ -48,7 +49,7 @@
+ * the pointer to that structure with this macro.
+ */
+ #define PART(x) ((struct mtd_part *)(x))
+-
++#define IS_PART(mtd) (mtd->read == part_read)
+
+ /*
+ * MTD methods which simply translate the effective address and pass through
+@@ -633,15 +634,24 @@
+ {
+ struct mtd_part *slave;
+ uint64_t cur_offset = 0;
+- int i;
++ int i, j;
+
+ printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
+
+- for (i = 0; i < nbparts; i++) {
+- slave = allocate_partition(master, parts + i, i, cur_offset);
+- if (IS_ERR(slave))
++ for (i = 0, j = 0; i < nbparts; i++) {
++ slave = add_one_partition(master, parts + i, j++, cur_offset);
++ if (!(slave))
+ return PTR_ERR(slave);
+
++
++ if (!strcmp(parts[i].name, "rootfs")) {
++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
++ if (ROOT_DEV == 0) {
++ printk(KERN_NOTICE "mtd: partition \"rootfs\" "
++ "set to be root filesystem\n");
++ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index);
++ }
++#endif
+ mutex_lock(&mtd_partitions_mutex);
+ list_add(&slave->list, &mtd_partitions);
+ mutex_unlock(&mtd_partitions_mutex);
diff --git a/target/linux/patches/2.6.37/ocf-20100325.patch b/target/linux/patches/2.6.37/ocf-20100325.patch
new file mode 100644
index 000000000..bb4e537d5
--- /dev/null
+++ b/target/linux/patches/2.6.37/ocf-20100325.patch
@@ -0,0 +1,87545 @@
+diff -Nur linux-2.6.36.orig/crypto/Kconfig linux-2.6.36/crypto/Kconfig
+--- linux-2.6.36.orig/crypto/Kconfig 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/crypto/Kconfig 2010-11-09 20:28:04.004996902 +0100
+@@ -845,3 +845,6 @@
+ source "drivers/crypto/Kconfig"
+
+ endif # if CRYPTO
++
++source "crypto/ocf/Kconfig"
++
+diff -Nur linux-2.6.36.orig/crypto/Makefile linux-2.6.36/crypto/Makefile
+--- linux-2.6.36.orig/crypto/Makefile 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/crypto/Makefile 2010-11-09 20:28:04.014995662 +0100
+@@ -86,6 +86,8 @@
+ obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
+ obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o
+
++obj-$(CONFIG_OCF_OCF) += ocf/
++
+ #
+ # generic algorithms and the async_tx api
+ #
+diff -Nur linux-2.6.36.orig/crypto/ocf/c7108/aes-7108.c linux-2.6.36/crypto/ocf/c7108/aes-7108.c
+--- linux-2.6.36.orig/crypto/ocf/c7108/aes-7108.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/c7108/aes-7108.c 2010-11-09 20:28:04.061247304 +0100
+@@ -0,0 +1,839 @@
++/*
++ * Copyright (C) 2006 Micronas USA
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++ */
++
++//#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/crypto.h>
++#include <linux/mm.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++#include <asm/io.h>
++#include <asm/delay.h>
++//#include <asm/scatterlist.h>
++#include <linux/scatterlist.h>
++#include <linux/dma-mapping.h>
++#include <linux/highmem.h>
++#include <cryptodev.h>
++#include <uio.h>
++#include <aes-7108.h>
++
++/* Runtime mode */
++static int c7108_crypto_mode = C7108_AES_CTRL_MODE_CTR;
++//static int c7108_crypto_mode = C7108_AES_CTRL_MODE_CBC;
++
++static int32_t c7108_id = -1;
++static struct cipher_7108 **c7108_sessions = NULL;
++static u_int32_t c7108_sesnum = 0;
++static unsigned long iobar;
++
++/* Crypto entry points */
++static int c7108_process(void *, struct cryptop *, int);
++static int c7108_newsession(void *, u_int32_t *, struct cryptoini *);
++static int c7108_freesession(void *, u_int64_t);
++
++/* Globals */
++static int debug = 0;
++static spinlock_t csr_mutex;
++
++/* Generic controller-based lock */
++#define AES_LOCK()\
++ spin_lock(&csr_mutex)
++#define AES_UNLOCK()\
++ spin_unlock(&csr_mutex)
++
++/* 7108 AES register access */
++#define c7108_reg_wr8(a,d) iowrite8(d, (void*)(iobar+(a)))
++#define c7108_reg_wr16(a,d) iowrite16(d, (void*)(iobar+(a)))
++#define c7108_reg_wr32(a,d) iowrite32(d, (void*)(iobar+(a)))
++#define c7108_reg_rd8(a) ioread8((void*)(iobar+(a)))
++#define c7108_reg_rd16(a) ioread16((void*)(iobar+(a)))
++#define c7108_reg_rd32(a) ioread32((void*)(iobar+(a)))
++
++static int
++c7108_xlate_key(int klen, u8* k8ptr, u32* k32ptr)
++{
++ int i, nw=0;
++ nw = ((klen >= 256) ? 8 : (klen >= 192) ? 6 : 4);
++ for ( i = 0; i < nw; i++) {
++ k32ptr[i] = (k8ptr[i+3] << 24) | (k8ptr[i+2] << 16) |
++ (k8ptr[i+1] << 8) | k8ptr[i];
++
++ }
++ return 0;
++}
++
++static int
++c7108_cache_key(int klen, u32* k32ptr, u8* k8ptr)
++{
++ int i, nb=0;
++ u8* ptr = (u8*)k32ptr;
++ nb = ((klen >= 256) ? 32 : (klen >= 192) ? 24 : 16);
++ for ( i = 0; i < nb; i++)
++ k8ptr[i] = ptr[i];
++ return 0;
++}
++
++static int
++c7108_aes_setup_dma(u32 src, u32 dst, u32 len)
++{
++ if (len < 16) {
++ printk("len < 16\n");
++ return -10;
++ }
++ if (len % 16) {
++ printk("len not multiple of 16\n");
++ return -11;
++ }
++ c7108_reg_wr16(C7108_AES_DMA_SRC0_LO, (u16) src);
++ c7108_reg_wr16(C7108_AES_DMA_SRC0_HI, (u16)((src & 0xffff0000) >> 16));
++ c7108_reg_wr16(C7108_AES_DMA_DST0_LO, (u16) dst);
++ c7108_reg_wr16(C7108_AES_DMA_DST0_HI, (u16)((dst & 0xffff0000) >> 16));
++ c7108_reg_wr16(C7108_AES_DMA_LEN, (u16) ((len / 16) - 1));
++
++ return 0;
++}
++
++static int
++c7108_aes_set_hw_iv(u8 iv[16])
++{
++ c7108_reg_wr16(C7108_AES_IV0_LO, (u16) ((iv[1] << 8) | iv[0]));
++ c7108_reg_wr16(C7108_AES_IV0_HI, (u16) ((iv[3] << 8) | iv[2]));
++ c7108_reg_wr16(C7108_AES_IV1_LO, (u16) ((iv[5] << 8) | iv[4]));
++ c7108_reg_wr16(C7108_AES_IV1_HI, (u16) ((iv[7] << 8) | iv[6]));
++ c7108_reg_wr16(C7108_AES_IV2_LO, (u16) ((iv[9] << 8) | iv[8]));
++ c7108_reg_wr16(C7108_AES_IV2_HI, (u16) ((iv[11] << 8) | iv[10]));
++ c7108_reg_wr16(C7108_AES_IV3_LO, (u16) ((iv[13] << 8) | iv[12]));
++ c7108_reg_wr16(C7108_AES_IV3_HI, (u16) ((iv[15] << 8) | iv[14]));
++
++ return 0;
++}
++
++static void
++c7108_aes_read_dkey(u32 * dkey)
++{
++ dkey[0] = (c7108_reg_rd16(C7108_AES_EKEY0_HI) << 16) |
++ c7108_reg_rd16(C7108_AES_EKEY0_LO);
++ dkey[1] = (c7108_reg_rd16(C7108_AES_EKEY1_HI) << 16) |
++ c7108_reg_rd16(C7108_AES_EKEY1_LO);
++ dkey[2] = (c7108_reg_rd16(C7108_AES_EKEY2_HI) << 16) |
++ c7108_reg_rd16(C7108_AES_EKEY2_LO);
++ dkey[3] = (c7108_reg_rd16(C7108_AES_EKEY3_HI) << 16) |
++ c7108_reg_rd16(C7108_AES_EKEY3_LO);
++ dkey[4] = (c7108_reg_rd16(C7108_AES_EKEY4_HI) << 16) |
++ c7108_reg_rd16(C7108_AES_EKEY4_LO);
++ dkey[5] = (c7108_reg_rd16(C7108_AES_EKEY5_HI) << 16) |
++ c7108_reg_rd16(C7108_AES_EKEY5_LO);
++ dkey[6] = (c7108_reg_rd16(C7108_AES_EKEY6_HI) << 16) |
++ c7108_reg_rd16(C7108_AES_EKEY6_LO);
++ dkey[7] = (c7108_reg_rd16(C7108_AES_EKEY7_HI) << 16) |
++ c7108_reg_rd16(C7108_AES_EKEY7_LO);
++}
++
++static int
++c7108_aes_cipher(int op,
++ u32 dst,
++ u32 src,
++ u32 len,
++ int klen,
++ u16 mode,
++ u32 key[8],
++ u8 iv[16])
++{
++ int rv = 0, cnt=0;
++ u16 ctrl = 0, stat = 0;
++
++ AES_LOCK();
++
++ /* Setup key length */
++ if (klen == 128) {
++ ctrl |= C7108_AES_KEY_LEN_128;
++ } else if (klen == 192) {
++ ctrl |= C7108_AES_KEY_LEN_192;
++ } else if (klen == 256) {
++ ctrl |= C7108_AES_KEY_LEN_256;
++ } else {
++ AES_UNLOCK();
++ return -3;
++ }
++
++ /* Check opcode */
++ if (C7108_AES_ENCRYPT == op) {
++ ctrl |= C7108_AES_ENCRYPT;
++ } else if (C7108_AES_DECRYPT == op) {
++ ctrl |= C7108_AES_DECRYPT;
++ } else {
++ AES_UNLOCK();
++ return -4;
++ }
++
++ /* check mode */
++ if ( (mode != C7108_AES_CTRL_MODE_CBC) &&
++ (mode != C7108_AES_CTRL_MODE_CFB) &&
++ (mode != C7108_AES_CTRL_MODE_OFB) &&
++ (mode != C7108_AES_CTRL_MODE_CTR) &&
++ (mode != C7108_AES_CTRL_MODE_ECB) ) {
++ AES_UNLOCK();
++ return -5;
++ }
++
++ /* Now set mode */
++ ctrl |= mode;
++
++ /* For CFB, OFB, and CTR, neither backward key
++ * expansion nor key inversion is required.
++ */
++ if ( (C7108_AES_DECRYPT == op) &&
++ (C7108_AES_CTRL_MODE_CBC == mode ||
++ C7108_AES_CTRL_MODE_ECB == mode ) ){
++
++ /* Program Key */
++ c7108_reg_wr16(C7108_AES_KEY0_LO, (u16) key[4]);
++ c7108_reg_wr16(C7108_AES_KEY0_HI, (u16) (key[4] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY1_LO, (u16) key[5]);
++ c7108_reg_wr16(C7108_AES_KEY1_HI, (u16) (key[5] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY2_LO, (u16) key[6]);
++ c7108_reg_wr16(C7108_AES_KEY2_HI, (u16) (key[6] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY3_LO, (u16) key[7]);
++ c7108_reg_wr16(C7108_AES_KEY3_HI, (u16) (key[7] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY6_LO, (u16) key[2]);
++ c7108_reg_wr16(C7108_AES_KEY6_HI, (u16) (key[2] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY7_LO, (u16) key[3]);
++ c7108_reg_wr16(C7108_AES_KEY7_HI, (u16) (key[3] >> 16));
++
++
++ if (192 == klen) {
++ c7108_reg_wr16(C7108_AES_KEY4_LO, (u16) key[7]);
++ c7108_reg_wr16(C7108_AES_KEY4_HI, (u16) (key[7] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY5_LO, (u16) key[7]);
++ c7108_reg_wr16(C7108_AES_KEY5_HI, (u16) (key[7] >> 16));
++
++ } else if (256 == klen) {
++ /* 256 */
++ c7108_reg_wr16(C7108_AES_KEY4_LO, (u16) key[0]);
++ c7108_reg_wr16(C7108_AES_KEY4_HI, (u16) (key[0] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY5_LO, (u16) key[1]);
++ c7108_reg_wr16(C7108_AES_KEY5_HI, (u16) (key[1] >> 16));
++
++ }
++
++ } else {
++ /* Program Key */
++ c7108_reg_wr16(C7108_AES_KEY0_LO, (u16) key[0]);
++ c7108_reg_wr16(C7108_AES_KEY0_HI, (u16) (key[0] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY1_LO, (u16) key[1]);
++ c7108_reg_wr16(C7108_AES_KEY1_HI, (u16) (key[1] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY2_LO, (u16) key[2]);
++ c7108_reg_wr16(C7108_AES_KEY2_HI, (u16) (key[2] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY3_LO, (u16) key[3]);
++ c7108_reg_wr16(C7108_AES_KEY3_HI, (u16) (key[3] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY4_LO, (u16) key[4]);
++ c7108_reg_wr16(C7108_AES_KEY4_HI, (u16) (key[4] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY5_LO, (u16) key[5]);
++ c7108_reg_wr16(C7108_AES_KEY5_HI, (u16) (key[5] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY6_LO, (u16) key[6]);
++ c7108_reg_wr16(C7108_AES_KEY6_HI, (u16) (key[6] >> 16));
++ c7108_reg_wr16(C7108_AES_KEY7_LO, (u16) key[7]);
++ c7108_reg_wr16(C7108_AES_KEY7_HI, (u16) (key[7] >> 16));
++
++ }
++
++ /* Set IV always */
++ c7108_aes_set_hw_iv(iv);
++
++ /* Program DMA addresses */
++ if ((rv = c7108_aes_setup_dma(src, dst, len)) < 0) {
++ AES_UNLOCK();
++ return rv;
++ }
++
++
++ /* Start AES cipher */
++ c7108_reg_wr16(C7108_AES_CTRL, ctrl | C7108_AES_GO);
++
++ //printk("Ctrl: 0x%x\n", ctrl | C7108_AES_GO);
++ do {
++ /* TODO: interrupt mode */
++ // printk("aes_stat=0x%x\n", stat);
++ //udelay(100);
++ } while ((cnt++ < 1000000) &&
++ !((stat=c7108_reg_rd16(C7108_AES_CTRL))&C7108_AES_OP_DONE));
++
++
++ if ((mode == C7108_AES_CTRL_MODE_ECB)||
++ (mode == C7108_AES_CTRL_MODE_CBC)) {
++ /* Save out key when the lock is held ... */
++ c7108_aes_read_dkey(key);
++ }
++
++ AES_UNLOCK();
++ return 0;
++
++}
++
++/*
++ * Generate a new crypto device session.
++ */
++static int
++c7108_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri)
++{
++ struct cipher_7108 **swd;
++ u_int32_t i;
++ char *algo;
++ int mode, xfm_type;
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (sid == NULL || cri == NULL) {
++ dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ if (c7108_sessions) {
++ for (i = 1; i < c7108_sesnum; i++)
++ if (c7108_sessions[i] == NULL)
++ break;
++ } else
++ i = 1; /* NB: to silence compiler warning */
++
++ if (c7108_sessions == NULL || i == c7108_sesnum) {
++ if (c7108_sessions == NULL) {
++ i = 1; /* We leave c7108_sessions[0] empty */
++ c7108_sesnum = CRYPTO_SW_SESSIONS;
++ } else
++ c7108_sesnum *= 2;
++
++ swd = kmalloc(c7108_sesnum * sizeof(struct cipher_7108 *),
++ GFP_ATOMIC);
++ if (swd == NULL) {
++ /* Reset session number */
++ if (c7108_sesnum == CRYPTO_SW_SESSIONS)
++ c7108_sesnum = 0;
++ else
++ c7108_sesnum /= 2;
++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++ return ENOBUFS;
++ }
++ memset(swd, 0, c7108_sesnum * sizeof(struct cipher_7108 *));
++
++ /* Copy existing sessions */
++ if (c7108_sessions) {
++ memcpy(swd, c7108_sessions,
++ (c7108_sesnum / 2) * sizeof(struct cipher_7108 *));
++ kfree(c7108_sessions);
++ }
++
++ c7108_sessions = swd;
++
++ }
++
++ swd = &c7108_sessions[i];
++ *sid = i;
++
++ while (cri) {
++ *swd = (struct cipher_7108 *)
++ kmalloc(sizeof(struct cipher_7108), GFP_ATOMIC);
++ if (*swd == NULL) {
++ c7108_freesession(NULL, i);
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return ENOBUFS;
++ }
++ memset(*swd, 0, sizeof(struct cipher_7108));
++
++ algo = NULL;
++ mode = 0;
++ xfm_type = HW_TYPE_CIPHER;
++
++ switch (cri->cri_alg) {
++
++ case CRYPTO_AES_CBC:
++ algo = "aes";
++ mode = CRYPTO_TFM_MODE_CBC;
++ c7108_crypto_mode = C7108_AES_CTRL_MODE_CBC;
++ break;
++#if 0
++ case CRYPTO_AES_CTR:
++ algo = "aes_ctr";
++ mode = CRYPTO_TFM_MODE_CBC;
++ c7108_crypto_mode = C7108_AES_CTRL_MODE_CTR;
++ break;
++ case CRYPTO_AES_ECB:
++ algo = "aes_ecb";
++ mode = CRYPTO_TFM_MODE_CBC;
++ c7108_crypto_mode = C7108_AES_CTRL_MODE_ECB;
++ break;
++ case CRYPTO_AES_OFB:
++ algo = "aes_ofb";
++ mode = CRYPTO_TFM_MODE_CBC;
++ c7108_crypto_mode = C7108_AES_CTRL_MODE_OFB;
++ break;
++ case CRYPTO_AES_CFB:
++ algo = "aes_cfb";
++ mode = CRYPTO_TFM_MODE_CBC;
++ c7108_crypto_mode = C7108_AES_CTRL_MODE_CFB;
++ break;
++#endif
++ default:
++ printk("unsupported crypto algorithm: %d\n",
++ cri->cri_alg);
++ return -EINVAL;
++ break;
++ }
++
++
++ if (!algo || !*algo) {
++ printk("cypher_7108_crypto: Unknown algo 0x%x\n",
++ cri->cri_alg);
++ c7108_freesession(NULL, i);
++ return EINVAL;
++ }
++
++ if (xfm_type == HW_TYPE_CIPHER) {
++ if (debug) {
++ dprintk("%s key:", __FUNCTION__);
++ for (i = 0; i < (cri->cri_klen + 7) / 8; i++)
++ dprintk("%s0x%02x", (i % 8) ? " " : "\n ",
++ cri->cri_key[i]);
++ dprintk("\n");
++ }
++
++ } else if (xfm_type == SW_TYPE_HMAC ||
++ xfm_type == SW_TYPE_HASH) {
++ printk("cypher_7108_crypto: HMAC unsupported!\n");
++ return -EINVAL;
++ c7108_freesession(NULL, i);
++ } else {
++ printk("cypher_7108_crypto: "
++ "Unhandled xfm_type %d\n", xfm_type);
++ c7108_freesession(NULL, i);
++ return EINVAL;
++ }
++
++ (*swd)->cri_alg = cri->cri_alg;
++ (*swd)->xfm_type = xfm_type;
++
++ cri = cri->cri_next;
++ swd = &((*swd)->next);
++ }
++ return 0;
++}
++
++/*
++ * Free a session.
++ */
++static int
++c7108_freesession(void *arg, u_int64_t tid)
++{
++ struct cipher_7108 *swd;
++ u_int32_t sid = CRYPTO_SESID2LID(tid);
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (sid > c7108_sesnum || c7108_sessions == NULL ||
++ c7108_sessions[sid] == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return(EINVAL);
++ }
++
++ /* Silently accept and return */
++ if (sid == 0)
++ return(0);
++
++ while ((swd = c7108_sessions[sid]) != NULL) {
++ c7108_sessions[sid] = swd->next;
++ kfree(swd);
++ }
++ return 0;
++}
++
++/*
++ * Process a hardware request.
++ */
++static int
++c7108_process(void *arg, struct cryptop *crp, int hint)
++{
++ struct cryptodesc *crd;
++ struct cipher_7108 *sw;
++ u_int32_t lid;
++ int type;
++ u32 hwkey[8];
++
++#define SCATTERLIST_MAX 16
++ struct scatterlist sg[SCATTERLIST_MAX];
++ int sg_num, sg_len, skip;
++ struct sk_buff *skb = NULL;
++ struct uio *uiop = NULL;
++
++ dprintk("%s()\n", __FUNCTION__);
++ /* Sanity check */
++ if (crp == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ crp->crp_etype = 0;
++
++ if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ crp->crp_etype = EINVAL;
++ goto done;
++ }
++
++ lid = crp->crp_sid & 0xffffffff;
++ if (lid >= c7108_sesnum || lid == 0 || c7108_sessions == NULL ||
++ c7108_sessions[lid] == NULL) {
++ crp->crp_etype = ENOENT;
++ dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);
++ goto done;
++ }
++
++ /*
++ * do some error checking outside of the loop for SKB and IOV
++ * processing this leaves us with valid skb or uiop pointers
++ * for later
++ */
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ skb = (struct sk_buff *) crp->crp_buf;
++ if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) {
++ printk("%s,%d: %d nr_frags > SCATTERLIST_MAX",
++ __FILE__, __LINE__,
++ skb_shinfo(skb)->nr_frags);
++ goto done;
++ }
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ uiop = (struct uio *) crp->crp_buf;
++ if (uiop->uio_iovcnt > SCATTERLIST_MAX) {
++ printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX",
++ __FILE__, __LINE__,
++ uiop->uio_iovcnt);
++ goto done;
++ }
++ }
++
++ /* Go through crypto descriptors, processing as we go */
++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
++ /*
++ * Find the crypto context.
++ *
++ * XXX Note that the logic here prevents us from having
++ * XXX the same algorithm multiple times in a session
++ * XXX (or rather, we can but it won't give us the right
++ * XXX results). To do that, we'd need some way of differentiating
++ * XXX between the various instances of an algorithm (so we can
++ * XXX locate the correct crypto context).
++ */
++ for (sw = c7108_sessions[lid];
++ sw && sw->cri_alg != crd->crd_alg;
++ sw = sw->next)
++ ;
++
++ /* No such context ? */
++ if (sw == NULL) {
++ crp->crp_etype = EINVAL;
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ goto done;
++ }
++
++ skip = crd->crd_skip;
++
++ /*
++ * setup the SG list skip from the start of the buffer
++ */
++ memset(sg, 0, sizeof(sg));
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ int i, len;
++ type = CRYPTO_BUF_SKBUF;
++
++ sg_num = 0;
++ sg_len = 0;
++
++ if (skip < skb_headlen(skb)) {
++ //sg[sg_num].page = virt_to_page(skb->data + skip);
++ //sg[sg_num].offset = offset_in_page(skb->data + skip);
++ len = skb_headlen(skb) - skip;
++ if (len + sg_len > crd->crd_len)
++ len = crd->crd_len - sg_len;
++ //sg[sg_num].length = len;
++ sg_set_page(&sg[sg_num], virt_to_page(skb->data + skip), len, offset_in_page(skb->data + skip));
++ sg_len += sg[sg_num].length;
++ sg_num++;
++ skip = 0;
++ } else
++ skip -= skb_headlen(skb);
++
++ for (i = 0; sg_len < crd->crd_len &&
++ i < skb_shinfo(skb)->nr_frags &&
++ sg_num < SCATTERLIST_MAX; i++) {
++ if (skip < skb_shinfo(skb)->frags[i].size) {
++ //sg[sg_num].page = skb_shinfo(skb)->frags[i].page;
++ //sg[sg_num].offset = skb_shinfo(skb)->frags[i].page_offset + skip;
++ len = skb_shinfo(skb)->frags[i].size - skip;
++ if (len + sg_len > crd->crd_len)
++ len = crd->crd_len - sg_len;
++ //sg[sg_num].length = len;
++ sg_set_page(&sg[sg_num], skb_shinfo(skb)->frags[i].page, len, skb_shinfo(skb)->frags[i].page_offset + skip);
++ sg_len += sg[sg_num].length;
++ sg_num++;
++ skip = 0;
++ } else
++ skip -= skb_shinfo(skb)->frags[i].size;
++ }
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ int len;
++ type = CRYPTO_BUF_IOV;
++ sg_len = 0;
++ for (sg_num = 0; sg_len < crd->crd_len &&
++ sg_num < uiop->uio_iovcnt &&
++ sg_num < SCATTERLIST_MAX; sg_num++) {
++ if (skip < uiop->uio_iov[sg_num].iov_len) {
++ //sg[sg_num].page = virt_to_page(uiop->uio_iov[sg_num].iov_base+skip);
++ //sg[sg_num].offset = offset_in_page(uiop->uio_iov[sg_num].iov_base+skip);
++ len = uiop->uio_iov[sg_num].iov_len - skip;
++ if (len + sg_len > crd->crd_len)
++ len = crd->crd_len - sg_len;
++ //sg[sg_num].length = len;
++ sg_set_page(&sg[sg_num], virt_to_page(uiop->uio_iov[sg_num].iov_base+skip), len, offset_in_page(uiop->uio_iov[sg_num].iov_base+skip));
++ sg_len += sg[sg_num].length;
++ skip = 0;
++ } else
++ skip -= uiop->uio_iov[sg_num].iov_len;
++ }
++ } else {
++ type = CRYPTO_BUF_CONTIG;
++ //sg[0].page = virt_to_page(crp->crp_buf + skip);
++ //sg[0].offset = offset_in_page(crp->crp_buf + skip);
++ sg_len = (crp->crp_ilen - skip);
++ if (sg_len > crd->crd_len)
++ sg_len = crd->crd_len;
++ //sg[0].length = sg_len;
++ sg_set_page(&sg[0], virt_to_page(crp->crp_buf + skip), sg_len, offset_in_page(crp->crp_buf + skip));
++ sg_num = 1;
++ }
++
++
++ switch (sw->xfm_type) {
++
++ case HW_TYPE_CIPHER: {
++
++ unsigned char iv[64];
++ unsigned char *ivp = iv;
++ int i;
++ int ivsize = 16; /* fixed for AES */
++ int blocksize = 16; /* fixed for AES */
++
++ if (sg_len < blocksize) {
++ crp->crp_etype = EINVAL;
++ dprintk("%s,%d: EINVAL len %d < %d\n",
++ __FILE__, __LINE__,
++ sg_len,
++ blocksize);
++ goto done;
++ }
++
++ if (ivsize > sizeof(iv)) {
++ crp->crp_etype = EINVAL;
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ goto done;
++ }
++
++ if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
++
++ if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
++ ivp = crd->crd_iv;
++ } else {
++ get_random_bytes(ivp, ivsize);
++ }
++ /*
++ * do we have to copy the IV back to the buffer ?
++ */
++ if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++ crypto_copyback(crp->crp_buf,
++ crd->crd_inject,
++ ivsize,
++ (caddr_t)ivp);
++ }
++
++ c7108_xlate_key(crd->crd_klen,
++ (u8*)crd->crd_key, (u32*)hwkey);
++
++ /* Encrypt SG list */
++ for (i = 0; i < sg_num; i++) {
++ sg[i].dma_address =
++ dma_map_single(NULL,
++ kmap(sg_page(&sg[i])) + sg[i].offset, sg_len, DMA_BIDIRECTIONAL);
++#if 0
++ printk("sg[%d]:0x%08x, off 0x%08x "
++ "kmap 0x%08x phys 0x%08x\n",
++ i, sg[i].page, sg[i].offset,
++ kmap(sg[i].page) + sg[i].offset,
++ sg[i].dma_address);
++#endif
++ c7108_aes_cipher(C7108_AES_ENCRYPT,
++ sg[i].dma_address,
++ sg[i].dma_address,
++ sg_len,
++ crd->crd_klen,
++ c7108_crypto_mode,
++ hwkey,
++ ivp);
++
++ if ((c7108_crypto_mode == C7108_AES_CTRL_MODE_CBC)||
++ (c7108_crypto_mode == C7108_AES_CTRL_MODE_ECB)) {
++ /* Read back expanded key and cache it in key
++ * context.
++ * NOTE: for ECB/CBC modes only (not CTR, CFB, OFB)
++ * where you set the key once.
++ */
++ c7108_cache_key(crd->crd_klen,
++ (u32*)hwkey, (u8*)crd->crd_key);
++#if 0
++ printk("%s expanded key:", __FUNCTION__);
++ for (i = 0; i < (crd->crd_klen + 7) / 8; i++)
++ printk("%s0x%02x", (i % 8) ? " " : "\n ",
++ crd->crd_key[i]);
++ printk("\n");
++#endif
++ }
++ }
++ }
++ else { /*decrypt */
++
++ if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
++ ivp = crd->crd_iv;
++ } else {
++ crypto_copydata(crp->crp_buf, crd->crd_inject,
++ ivsize, (caddr_t)ivp);
++ }
++
++ c7108_xlate_key(crd->crd_klen,
++ (u8*)crd->crd_key, (u32*)hwkey);
++
++ /* Decrypt SG list */
++ for (i = 0; i < sg_num; i++) {
++ sg[i].dma_address =
++ dma_map_single(NULL,
++ kmap(sg_page(&sg[i])) + sg[i].offset,
++ sg_len, DMA_BIDIRECTIONAL);
++
++#if 0
++ printk("sg[%d]:0x%08x, off 0x%08x "
++ "kmap 0x%08x phys 0x%08x\n",
++ i, sg[i].page, sg[i].offset,
++ kmap(sg[i].page) + sg[i].offset,
++ sg[i].dma_address);
++#endif
++ c7108_aes_cipher(C7108_AES_DECRYPT,
++ sg[i].dma_address,
++ sg[i].dma_address,
++ sg_len,
++ crd->crd_klen,
++ c7108_crypto_mode,
++ hwkey,
++ ivp);
++ }
++ }
++ } break;
++ case SW_TYPE_HMAC:
++ case SW_TYPE_HASH:
++ crp->crp_etype = EINVAL;
++ goto done;
++ break;
++
++ case SW_TYPE_COMP:
++ crp->crp_etype = EINVAL;
++ goto done;
++ break;
++
++ default:
++ /* Unknown/unsupported algorithm */
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ crp->crp_etype = EINVAL;
++ goto done;
++ }
++ }
++
++done:
++ crypto_done(crp);
++ return 0;
++}
++
++static struct {
++ softc_device_decl sc_dev;
++} a7108dev;
++
++static device_method_t a7108_methods = {
++/* crypto device methods */
++ DEVMETHOD(cryptodev_newsession, c7108_newsession),
++ DEVMETHOD(cryptodev_freesession, c7108_freesession),
++ DEVMETHOD(cryptodev_process, c7108_process),
++ DEVMETHOD(cryptodev_kprocess, NULL)
++};
++
++static int
++cypher_7108_crypto_init(void)
++{
++ dprintk("%s(%p)\n", __FUNCTION__, cypher_7108_crypto_init);
++
++ iobar = (unsigned long)ioremap(CCU_AES_REG_BASE, 0x4000);
++ printk("7108: AES @ 0x%08x (0x%08x phys) %s mode\n",
++ iobar, CCU_AES_REG_BASE,
++ c7108_crypto_mode & C7108_AES_CTRL_MODE_CBC ? "CBC" :
++ c7108_crypto_mode & C7108_AES_CTRL_MODE_ECB ? "ECB" :
++ c7108_crypto_mode & C7108_AES_CTRL_MODE_CTR ? "CTR" :
++ c7108_crypto_mode & C7108_AES_CTRL_MODE_CFB ? "CFB" :
++ c7108_crypto_mode & C7108_AES_CTRL_MODE_OFB ? "OFB" : "???");
++ csr_mutex = SPIN_LOCK_UNLOCKED;
++
++ memset(&a7108dev, 0, sizeof(a7108dev));
++ softc_device_init(&a7108dev, "aes7108", 0, a7108_methods);
++
++ c7108_id = crypto_get_driverid(softc_get_device(&a7108dev), CRYPTOCAP_F_HARDWARE);
++ if (c7108_id < 0)
++ panic("7108: crypto device cannot initialize!");
++
++// crypto_register(c7108_id, CRYPTO_AES_CBC, 0, 0, c7108_newsession, c7108_freesession, c7108_process, NULL);
++ crypto_register(c7108_id, CRYPTO_AES_CBC, 0, 0);
++
++ return(0);
++}
++
++static void
++cypher_7108_crypto_exit(void)
++{
++ dprintk("%s()\n", __FUNCTION__);
++ crypto_unregister_all(c7108_id);
++ c7108_id = -1;
++}
++
++module_init(cypher_7108_crypto_init);
++module_exit(cypher_7108_crypto_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("Cypher 7108 Crypto (OCF module for kernel crypto)");
+diff -Nur linux-2.6.36.orig/crypto/ocf/c7108/aes-7108.h linux-2.6.36/crypto/ocf/c7108/aes-7108.h
+--- linux-2.6.36.orig/crypto/ocf/c7108/aes-7108.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/c7108/aes-7108.h 2010-11-09 20:28:04.102495305 +0100
+@@ -0,0 +1,134 @@
++/*
++ * Copyright (C) 2006 Micronas USA
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++ */
++
++#ifndef __AES_7108_H__
++#define __AES_7108_H__
++
++/* Cypher 7108 AES Controller Hardware */
++#define CCU_REG_BASE 0x1b500000
++#define CCU_AES_REG_BASE (CCU_REG_BASE + 0x100)
++#define C7108_AES_KEY0_LO (0x0000)
++#define C7108_AES_KEY0_HI (0x0004)
++#define C7108_AES_KEY1_LO (0x0008)
++#define C7108_AES_KEY1_HI (0x000c)
++#define C7108_AES_KEY2_LO (0x0010)
++#define C7108_AES_KEY2_HI (0x0014)
++#define C7108_AES_KEY3_LO (0x0018)
++#define C7108_AES_KEY3_HI (0x001c)
++#define C7108_AES_KEY4_LO (0x0020)
++#define C7108_AES_KEY4_HI (0x0024)
++#define C7108_AES_KEY5_LO (0x0028)
++#define C7108_AES_KEY5_HI (0x002c)
++#define C7108_AES_KEY6_LO (0x0030)
++#define C7108_AES_KEY6_HI (0x0034)
++#define C7108_AES_KEY7_LO (0x0038)
++#define C7108_AES_KEY7_HI (0x003c)
++#define C7108_AES_IV0_LO (0x0040)
++#define C7108_AES_IV0_HI (0x0044)
++#define C7108_AES_IV1_LO (0x0048)
++#define C7108_AES_IV1_HI (0x004c)
++#define C7108_AES_IV2_LO (0x0050)
++#define C7108_AES_IV2_HI (0x0054)
++#define C7108_AES_IV3_LO (0x0058)
++#define C7108_AES_IV3_HI (0x005c)
++
++#define C7108_AES_DMA_SRC0_LO (0x0068) /* Bits 0:15 */
++#define C7108_AES_DMA_SRC0_HI (0x006c) /* Bits 27:16 */
++#define C7108_AES_DMA_DST0_LO (0x0070) /* Bits 0:15 */
++#define C7108_AES_DMA_DST0_HI (0x0074) /* Bits 27:16 */
++#define C7108_AES_DMA_LEN (0x0078) /*Bytes:(Count+1)x16 */
++
++/* AES/Copy engine control register */
++#define C7108_AES_CTRL (0x007c) /* AES control */
++#define C7108_AES_CTRL_RS (1<<0) /* Which set of src/dst to use */
++
++/* AES Cipher mode, controlled by setting Bits 2:0 */
++#define C7108_AES_CTRL_MODE_CBC 0
++#define C7108_AES_CTRL_MODE_CFB (1<<0)
++#define C7108_AES_CTRL_MODE_OFB (1<<1)
++#define C7108_AES_CTRL_MODE_CTR ((1<<0)|(1<<1))
++#define C7108_AES_CTRL_MODE_ECB (1<<2)
++
++/* AES Key length , Bits 5:4 */
++#define C7108_AES_KEY_LEN_128 0 /* 00 */
++#define C7108_AES_KEY_LEN_192 (1<<4) /* 01 */
++#define C7108_AES_KEY_LEN_256 (1<<5) /* 10 */
++
++/* AES Operation (crypt/decrypt), Bit 3 */
++#define C7108_AES_DECRYPT (1<<3) /* Clear for encrypt */
++#define C7108_AES_ENCRYPT 0
++#define C7108_AES_INTR (1<<13) /* Set on done trans from 0->1*/
++#define C7108_AES_GO (1<<14) /* Run */
++#define C7108_AES_OP_DONE (1<<15) /* Set when complete */
++
++
++/* Expanded key registers */
++#define C7108_AES_EKEY0_LO (0x0080)
++#define C7108_AES_EKEY0_HI (0x0084)
++#define C7108_AES_EKEY1_LO (0x0088)
++#define C7108_AES_EKEY1_HI (0x008c)
++#define C7108_AES_EKEY2_LO (0x0090)
++#define C7108_AES_EKEY2_HI (0x0094)
++#define C7108_AES_EKEY3_LO (0x0098)
++#define C7108_AES_EKEY3_HI (0x009c)
++#define C7108_AES_EKEY4_LO (0x00a0)
++#define C7108_AES_EKEY4_HI (0x00a4)
++#define C7108_AES_EKEY5_LO (0x00a8)
++#define C7108_AES_EKEY5_HI (0x00ac)
++#define C7108_AES_EKEY6_LO (0x00b0)
++#define C7108_AES_EKEY6_HI (0x00b4)
++#define C7108_AES_EKEY7_LO (0x00b8)
++#define C7108_AES_EKEY7_HI (0x00bc)
++#define C7108_AES_OK (0x00fc) /* Reset: "OK" */
++
++#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
++
++/* Software session entry */
++
++#define HW_TYPE_CIPHER 0
++#define SW_TYPE_HMAC 1
++#define SW_TYPE_AUTH2 2
++#define SW_TYPE_HASH 3
++#define SW_TYPE_COMP 4
++
++struct cipher_7108 {
++ int xfm_type;
++ int cri_alg;
++ union {
++ struct {
++ char sw_key[HMAC_BLOCK_LEN];
++ int sw_klen;
++ int sw_authlen;
++ } hmac;
++ } u;
++ struct cipher_7108 *next;
++};
++
++
++
++#endif /* __C7108_AES_7108_H__ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/c7108/Makefile linux-2.6.36/crypto/ocf/c7108/Makefile
+--- linux-2.6.36.orig/crypto/ocf/c7108/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/c7108/Makefile 2010-11-09 20:28:04.152495478 +0100
+@@ -0,0 +1,12 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_C7108) += aes-7108.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/Config.in linux-2.6.36/crypto/ocf/Config.in
+--- linux-2.6.36.orig/crypto/ocf/Config.in 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/Config.in 2010-11-09 20:28:04.191247583 +0100
+@@ -0,0 +1,36 @@
++#############################################################################
++
++mainmenu_option next_comment
++comment 'OCF Configuration'
++tristate 'OCF (Open Cryptograhic Framework)' CONFIG_OCF_OCF
++dep_mbool ' enable fips RNG checks (fips check on RNG data before use)' \
++ CONFIG_OCF_FIPS $CONFIG_OCF_OCF
++dep_mbool ' enable harvesting entropy for /dev/random' \
++ CONFIG_OCF_RANDOMHARVEST $CONFIG_OCF_OCF
++dep_tristate ' cryptodev (user space support)' \
++ CONFIG_OCF_CRYPTODEV $CONFIG_OCF_OCF
++dep_tristate ' cryptosoft (software crypto engine)' \
++ CONFIG_OCF_CRYPTOSOFT $CONFIG_OCF_OCF
++dep_tristate ' safenet (HW crypto engine)' \
++ CONFIG_OCF_SAFE $CONFIG_OCF_OCF
++dep_tristate ' IXP4xx (HW crypto engine)' \
++ CONFIG_OCF_IXP4XX $CONFIG_OCF_OCF
++dep_mbool ' Enable IXP4xx HW to perform SHA1 and MD5 hashing (very slow)' \
++ CONFIG_OCF_IXP4XX_SHA1_MD5 $CONFIG_OCF_IXP4XX
++dep_tristate ' hifn (HW crypto engine)' \
++ CONFIG_OCF_HIFN $CONFIG_OCF_OCF
++dep_tristate ' talitos (HW crypto engine)' \
++ CONFIG_OCF_TALITOS $CONFIG_OCF_OCF
++dep_tristate ' pasemi (HW crypto engine)' \
++ CONFIG_OCF_PASEMI $CONFIG_OCF_OCF
++dep_tristate ' ep80579 (HW crypto engine)' \
++ CONFIG_OCF_EP80579 $CONFIG_OCF_OCF
++dep_tristate ' Micronas c7108 (HW crypto engine)' \
++ CONFIG_OCF_C7108 $CONFIG_OCF_OCF
++dep_tristate ' ocfnull (does no crypto)' \
++ CONFIG_OCF_OCFNULL $CONFIG_OCF_OCF
++dep_tristate ' ocf-bench (HW crypto in-kernel benchmark)' \
++ CONFIG_OCF_BENCH $CONFIG_OCF_OCF
++endmenu
++
++#############################################################################
+diff -Nur linux-2.6.36.orig/crypto/ocf/criov.c linux-2.6.36/crypto/ocf/criov.c
+--- linux-2.6.36.orig/crypto/ocf/criov.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/criov.c 2010-11-09 20:28:04.232050075 +0100
+@@ -0,0 +1,215 @@
++/* $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $ */
++
++/*
++ * Linux port done by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 1999 Theo de Raadt
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++__FBSDID("$FreeBSD: src/sys/opencrypto/criov.c,v 1.5 2006/06/04 22:15:13 pjd Exp $");
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/uio.h>
++#include <linux/skbuff.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <asm/io.h>
++
++#include <uio.h>
++#include <cryptodev.h>
++
++/*
++ * This macro is only for avoiding code duplication, as we need to skip
++ * given number of bytes in the same way in three functions below.
++ */
++#define CUIO_SKIP() do { \
++ KASSERT(off >= 0, ("%s: off %d < 0", __func__, off)); \
++ KASSERT(len >= 0, ("%s: len %d < 0", __func__, len)); \
++ while (off > 0) { \
++ KASSERT(iol >= 0, ("%s: empty in skip", __func__)); \
++ if (off < iov->iov_len) \
++ break; \
++ off -= iov->iov_len; \
++ iol--; \
++ iov++; \
++ } \
++} while (0)
++
++void
++cuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
++{
++ struct iovec *iov = uio->uio_iov;
++ int iol = uio->uio_iovcnt;
++ unsigned count;
++
++ CUIO_SKIP();
++ while (len > 0) {
++ KASSERT(iol >= 0, ("%s: empty", __func__));
++ count = min((int)(iov->iov_len - off), len);
++ memcpy(cp, ((caddr_t)iov->iov_base) + off, count);
++ len -= count;
++ cp += count;
++ off = 0;
++ iol--;
++ iov++;
++ }
++}
++
++void
++cuio_copyback(struct uio* uio, int off, int len, caddr_t cp)
++{
++ struct iovec *iov = uio->uio_iov;
++ int iol = uio->uio_iovcnt;
++ unsigned count;
++
++ CUIO_SKIP();
++ while (len > 0) {
++ KASSERT(iol >= 0, ("%s: empty", __func__));
++ count = min((int)(iov->iov_len - off), len);
++ memcpy(((caddr_t)iov->iov_base) + off, cp, count);
++ len -= count;
++ cp += count;
++ off = 0;
++ iol--;
++ iov++;
++ }
++}
++
++/*
++ * Return a pointer to iov/offset of location in iovec list.
++ */
++struct iovec *
++cuio_getptr(struct uio *uio, int loc, int *off)
++{
++ struct iovec *iov = uio->uio_iov;
++ int iol = uio->uio_iovcnt;
++
++ while (loc >= 0) {
++ /* Normal end of search */
++ if (loc < iov->iov_len) {
++ *off = loc;
++ return (iov);
++ }
++
++ loc -= iov->iov_len;
++ if (iol == 0) {
++ if (loc == 0) {
++ /* Point at the end of valid data */
++ *off = iov->iov_len;
++ return (iov);
++ } else
++ return (NULL);
++ } else {
++ iov++, iol--;
++ }
++ }
++
++ return (NULL);
++}
++
++EXPORT_SYMBOL(cuio_copyback);
++EXPORT_SYMBOL(cuio_copydata);
++EXPORT_SYMBOL(cuio_getptr);
++
++
++static void
++skb_copy_bits_back(struct sk_buff *skb, int offset, caddr_t cp, int len)
++{
++ int i;
++ if (offset < skb_headlen(skb)) {
++ memcpy(skb->data + offset, cp, min_t(int, skb_headlen(skb), len));
++ len -= skb_headlen(skb);
++ cp += skb_headlen(skb);
++ }
++ offset -= skb_headlen(skb);
++ for (i = 0; len > 0 && i < skb_shinfo(skb)->nr_frags; i++) {
++ if (offset < skb_shinfo(skb)->frags[i].size) {
++ memcpy(page_address(skb_shinfo(skb)->frags[i].page) +
++ skb_shinfo(skb)->frags[i].page_offset,
++ cp, min_t(int, skb_shinfo(skb)->frags[i].size, len));
++ len -= skb_shinfo(skb)->frags[i].size;
++ cp += skb_shinfo(skb)->frags[i].size;
++ }
++ offset -= skb_shinfo(skb)->frags[i].size;
++ }
++}
++
++void
++crypto_copyback(int flags, caddr_t buf, int off, int size, caddr_t in)
++{
++
++ if ((flags & CRYPTO_F_SKBUF) != 0)
++ skb_copy_bits_back((struct sk_buff *)buf, off, in, size);
++ else if ((flags & CRYPTO_F_IOV) != 0)
++ cuio_copyback((struct uio *)buf, off, size, in);
++ else
++ bcopy(in, buf + off, size);
++}
++
++void
++crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out)
++{
++
++ if ((flags & CRYPTO_F_SKBUF) != 0)
++ skb_copy_bits((struct sk_buff *)buf, off, out, size);
++ else if ((flags & CRYPTO_F_IOV) != 0)
++ cuio_copydata((struct uio *)buf, off, size, out);
++ else
++ bcopy(buf + off, out, size);
++}
++
++int
++crypto_apply(int flags, caddr_t buf, int off, int len,
++ int (*f)(void *, void *, u_int), void *arg)
++{
++#if 0
++ int error;
++
++ if ((flags & CRYPTO_F_SKBUF) != 0)
++ error = XXXXXX((struct mbuf *)buf, off, len, f, arg);
++ else if ((flags & CRYPTO_F_IOV) != 0)
++ error = cuio_apply((struct uio *)buf, off, len, f, arg);
++ else
++ error = (*f)(arg, buf + off, len);
++ return (error);
++#else
++ KASSERT(0, ("crypto_apply not implemented!\n"));
++#endif
++ return 0;
++}
++
++EXPORT_SYMBOL(crypto_copyback);
++EXPORT_SYMBOL(crypto_copydata);
++EXPORT_SYMBOL(crypto_apply);
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/crypto.c linux-2.6.36/crypto/ocf/crypto.c
+--- linux-2.6.36.orig/crypto/ocf/crypto.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/crypto.c 2010-11-09 20:28:04.272495385 +0100
+@@ -0,0 +1,1784 @@
++/*-
++ * Linux port done by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * Copyright (c) 2002-2006 Sam Leffler. All rights reserved.
++ *
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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 0
++#include <sys/cdefs.h>
++__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.27 2007/03/21 03:42:51 sam Exp $");
++#endif
++
++/*
++ * Cryptographic Subsystem.
++ *
++ * This code is derived from the Openbsd Cryptographic Framework (OCF)
++ * that has the copyright shown below. Very little of the original
++ * code remains.
++ */
++/*-
++ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
++ *
++ * This code was written by Angelos D. Keromytis in Athens, Greece, in
++ * February 2000. Network Security Technologies Inc. (NSTI) kindly
++ * supported the development of this code.
++ *
++ * Copyright (c) 2000, 2001 Angelos D. Keromytis
++ *
++ * Permission to use, copy, and modify this software with or without fee
++ * is hereby granted, provided that this entire notice is included in
++ * all source code copies of any software which is or includes a copy or
++ * modification of this software.
++ *
++ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
++ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
++ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
++ * PURPOSE.
++ *
++__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.16 2005/01/07 02:29:16 imp Exp $");
++ */
++
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/version.h>
++#include <cryptodev.h>
++
++/*
++ * keep track of whether or not we have been initialised, a big
++ * issue if we are linked into the kernel and a driver gets started before
++ * us
++ */
++static int crypto_initted = 0;
++
++/*
++ * Crypto drivers register themselves by allocating a slot in the
++ * crypto_drivers table with crypto_get_driverid() and then registering
++ * each algorithm they support with crypto_register() and crypto_kregister().
++ */
++
++/*
++ * lock on driver table
++ * we track its state as spin_is_locked does not do anything on non-SMP boxes
++ */
++static spinlock_t crypto_drivers_lock;
++static int crypto_drivers_locked; /* for non-SMP boxes */
++
++#define CRYPTO_DRIVER_LOCK() \
++ ({ \
++ spin_lock_irqsave(&crypto_drivers_lock, d_flags); \
++ crypto_drivers_locked = 1; \
++ dprintk("%s,%d: DRIVER_LOCK()\n", __FILE__, __LINE__); \
++ })
++#define CRYPTO_DRIVER_UNLOCK() \
++ ({ \
++ dprintk("%s,%d: DRIVER_UNLOCK()\n", __FILE__, __LINE__); \
++ crypto_drivers_locked = 0; \
++ spin_unlock_irqrestore(&crypto_drivers_lock, d_flags); \
++ })
++#define CRYPTO_DRIVER_ASSERT() \
++ ({ \
++ if (!crypto_drivers_locked) { \
++ dprintk("%s,%d: DRIVER_ASSERT!\n", __FILE__, __LINE__); \
++ } \
++ })
++
++/*
++ * Crypto device/driver capabilities structure.
++ *
++ * Synchronization:
++ * (d) - protected by CRYPTO_DRIVER_LOCK()
++ * (q) - protected by CRYPTO_Q_LOCK()
++ * Not tagged fields are read-only.
++ */
++struct cryptocap {
++ device_t cc_dev; /* (d) device/driver */
++ u_int32_t cc_sessions; /* (d) # of sessions */
++ u_int32_t cc_koperations; /* (d) # os asym operations */
++ /*
++ * Largest possible operator length (in bits) for each type of
++ * encryption algorithm. XXX not used
++ */
++ u_int16_t cc_max_op_len[CRYPTO_ALGORITHM_MAX + 1];
++ u_int8_t cc_alg[CRYPTO_ALGORITHM_MAX + 1];
++ u_int8_t cc_kalg[CRK_ALGORITHM_MAX + 1];
++
++ int cc_flags; /* (d) flags */
++#define CRYPTOCAP_F_CLEANUP 0x80000000 /* needs resource cleanup */
++ int cc_qblocked; /* (q) symmetric q blocked */
++ int cc_kqblocked; /* (q) asymmetric q blocked */
++
++ int cc_unqblocked; /* (q) symmetric q blocked */
++ int cc_unkqblocked; /* (q) asymmetric q blocked */
++};
++static struct cryptocap *crypto_drivers = NULL;
++static int crypto_drivers_num = 0;
++
++/*
++ * There are two queues for crypto requests; one for symmetric (e.g.
++ * cipher) operations and one for asymmetric (e.g. MOD)operations.
++ * A single mutex is used to lock access to both queues. We could
++ * have one per-queue but having one simplifies handling of block/unblock
++ * operations.
++ */
++static int crp_sleep = 0;
++static LIST_HEAD(crp_q); /* request queues */
++static LIST_HEAD(crp_kq);
++
++static spinlock_t crypto_q_lock;
++
++int crypto_all_qblocked = 0; /* protect with Q_LOCK */
++module_param(crypto_all_qblocked, int, 0444);
++MODULE_PARM_DESC(crypto_all_qblocked, "Are all crypto queues blocked");
++
++int crypto_all_kqblocked = 0; /* protect with Q_LOCK */
++module_param(crypto_all_kqblocked, int, 0444);
++MODULE_PARM_DESC(crypto_all_kqblocked, "Are all asym crypto queues blocked");
++
++#define CRYPTO_Q_LOCK() \
++ ({ \
++ spin_lock_irqsave(&crypto_q_lock, q_flags); \
++ dprintk("%s,%d: Q_LOCK()\n", __FILE__, __LINE__); \
++ })
++#define CRYPTO_Q_UNLOCK() \
++ ({ \
++ dprintk("%s,%d: Q_UNLOCK()\n", __FILE__, __LINE__); \
++ spin_unlock_irqrestore(&crypto_q_lock, q_flags); \
++ })
++
++/*
++ * There are two queues for processing completed crypto requests; one
++ * for the symmetric and one for the asymmetric ops. We only need one
++ * but have two to avoid type futzing (cryptop vs. cryptkop). A single
++ * mutex is used to lock access to both queues. Note that this lock
++ * must be separate from the lock on request queues to insure driver
++ * callbacks don't generate lock order reversals.
++ */
++static LIST_HEAD(crp_ret_q); /* callback queues */
++static LIST_HEAD(crp_ret_kq);
++
++static spinlock_t crypto_ret_q_lock;
++#define CRYPTO_RETQ_LOCK() \
++ ({ \
++ spin_lock_irqsave(&crypto_ret_q_lock, r_flags); \
++ dprintk("%s,%d: RETQ_LOCK\n", __FILE__, __LINE__); \
++ })
++#define CRYPTO_RETQ_UNLOCK() \
++ ({ \
++ dprintk("%s,%d: RETQ_UNLOCK\n", __FILE__, __LINE__); \
++ spin_unlock_irqrestore(&crypto_ret_q_lock, r_flags); \
++ })
++#define CRYPTO_RETQ_EMPTY() (list_empty(&crp_ret_q) && list_empty(&crp_ret_kq))
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++static kmem_cache_t *cryptop_zone;
++static kmem_cache_t *cryptodesc_zone;
++#else
++static struct kmem_cache *cryptop_zone;
++static struct kmem_cache *cryptodesc_zone;
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
++#include <linux/sched.h>
++#define kill_proc(p,s,v) send_sig(s,find_task_by_vpid(p),0)
++#endif
++
++#define debug crypto_debug
++int crypto_debug = 0;
++module_param(crypto_debug, int, 0644);
++MODULE_PARM_DESC(crypto_debug, "Enable debug");
++EXPORT_SYMBOL(crypto_debug);
++
++/*
++ * Maximum number of outstanding crypto requests before we start
++ * failing requests. We need this to prevent DOS when too many
++ * requests are arriving for us to keep up. Otherwise we will
++ * run the system out of memory. Since crypto is slow, we are
++ * usually the bottleneck that needs to say, enough is enough.
++ *
++ * We cannot print errors when this condition occurs, we are already too
++ * slow, printing anything will just kill us
++ */
++
++static int crypto_q_cnt = 0;
++module_param(crypto_q_cnt, int, 0444);
++MODULE_PARM_DESC(crypto_q_cnt,
++ "Current number of outstanding crypto requests");
++
++static int crypto_q_max = 1000;
++module_param(crypto_q_max, int, 0644);
++MODULE_PARM_DESC(crypto_q_max,
++ "Maximum number of outstanding crypto requests");
++
++#define bootverbose crypto_verbose
++static int crypto_verbose = 0;
++module_param(crypto_verbose, int, 0644);
++MODULE_PARM_DESC(crypto_verbose,
++ "Enable verbose crypto startup");
++
++int crypto_usercrypto = 1; /* userland may do crypto reqs */
++module_param(crypto_usercrypto, int, 0644);
++MODULE_PARM_DESC(crypto_usercrypto,
++ "Enable/disable user-mode access to crypto support");
++
++int crypto_userasymcrypto = 1; /* userland may do asym crypto reqs */
++module_param(crypto_userasymcrypto, int, 0644);
++MODULE_PARM_DESC(crypto_userasymcrypto,
++ "Enable/disable user-mode access to asymmetric crypto support");
++
++int crypto_devallowsoft = 0; /* only use hardware crypto */
++module_param(crypto_devallowsoft, int, 0644);
++MODULE_PARM_DESC(crypto_devallowsoft,
++ "Enable/disable use of software crypto support");
++
++/*
++ * This parameter controls the maximum number of crypto operations to
++ * do consecutively in the crypto kernel thread before scheduling to allow
++ * other processes to run. Without it, it is possible to get into a
++ * situation where the crypto thread never allows any other processes to run.
++ * Default to 1000 which should be less than one second.
++ */
++static int crypto_max_loopcount = 1000;
++module_param(crypto_max_loopcount, int, 0644);
++MODULE_PARM_DESC(crypto_max_loopcount,
++ "Maximum number of crypto ops to do before yielding to other processes");
++
++static pid_t cryptoproc = (pid_t) -1;
++static struct completion cryptoproc_exited;
++static DECLARE_WAIT_QUEUE_HEAD(cryptoproc_wait);
++static pid_t cryptoretproc = (pid_t) -1;
++static struct completion cryptoretproc_exited;
++static DECLARE_WAIT_QUEUE_HEAD(cryptoretproc_wait);
++
++static int crypto_proc(void *arg);
++static int crypto_ret_proc(void *arg);
++static int crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint);
++static int crypto_kinvoke(struct cryptkop *krp, int flags);
++static void crypto_exit(void);
++static int crypto_init(void);
++
++static struct cryptostats cryptostats;
++
++static struct cryptocap *
++crypto_checkdriver(u_int32_t hid)
++{
++ if (crypto_drivers == NULL)
++ return NULL;
++ return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]);
++}
++
++/*
++ * Compare a driver's list of supported algorithms against another
++ * list; return non-zero if all algorithms are supported.
++ */
++static int
++driver_suitable(const struct cryptocap *cap, const struct cryptoini *cri)
++{
++ const struct cryptoini *cr;
++
++ /* See if all the algorithms are supported. */
++ for (cr = cri; cr; cr = cr->cri_next)
++ if (cap->cc_alg[cr->cri_alg] == 0)
++ return 0;
++ return 1;
++}
++
++/*
++ * Select a driver for a new session that supports the specified
++ * algorithms and, optionally, is constrained according to the flags.
++ * The algorithm we use here is pretty stupid; just use the
++ * first driver that supports all the algorithms we need. If there
++ * are multiple drivers we choose the driver with the fewest active
++ * sessions. We prefer hardware-backed drivers to software ones.
++ *
++ * XXX We need more smarts here (in real life too, but that's
++ * XXX another story altogether).
++ */
++static struct cryptocap *
++crypto_select_driver(const struct cryptoini *cri, int flags)
++{
++ struct cryptocap *cap, *best;
++ int match, hid;
++
++ CRYPTO_DRIVER_ASSERT();
++
++ /*
++ * Look first for hardware crypto devices if permitted.
++ */
++ if (flags & CRYPTOCAP_F_HARDWARE)
++ match = CRYPTOCAP_F_HARDWARE;
++ else
++ match = CRYPTOCAP_F_SOFTWARE;
++ best = NULL;
++again:
++ for (hid = 0; hid < crypto_drivers_num; hid++) {
++ cap = &crypto_drivers[hid];
++ /*
++ * If it's not initialized, is in the process of
++ * going away, or is not appropriate (hardware
++ * or software based on match), then skip.
++ */
++ if (cap->cc_dev == NULL ||
++ (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ||
++ (cap->cc_flags & match) == 0)
++ continue;
++
++ /* verify all the algorithms are supported. */
++ if (driver_suitable(cap, cri)) {
++ if (best == NULL ||
++ cap->cc_sessions < best->cc_sessions)
++ best = cap;
++ }
++ }
++ if (best != NULL)
++ return best;
++ if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) {
++ /* sort of an Algol 68-style for loop */
++ match = CRYPTOCAP_F_SOFTWARE;
++ goto again;
++ }
++ return best;
++}
++
++/*
++ * Create a new session. The crid argument specifies a crypto
++ * driver to use or constraints on a driver to select (hardware
++ * only, software only, either). Whatever driver is selected
++ * must be capable of the requested crypto algorithms.
++ */
++int
++crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int crid)
++{
++ struct cryptocap *cap;
++ u_int32_t hid, lid;
++ int err;
++ unsigned long d_flags;
++
++ CRYPTO_DRIVER_LOCK();
++ if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
++ /*
++ * Use specified driver; verify it is capable.
++ */
++ cap = crypto_checkdriver(crid);
++ if (cap != NULL && !driver_suitable(cap, cri))
++ cap = NULL;
++ } else {
++ /*
++ * No requested driver; select based on crid flags.
++ */
++ cap = crypto_select_driver(cri, crid);
++ /*
++ * if NULL then can't do everything in one session.
++ * XXX Fix this. We need to inject a "virtual" session
++ * XXX layer right about here.
++ */
++ }
++ if (cap != NULL) {
++ /* Call the driver initialization routine. */
++ hid = cap - crypto_drivers;
++ lid = hid; /* Pass the driver ID. */
++ cap->cc_sessions++;
++ CRYPTO_DRIVER_UNLOCK();
++ err = CRYPTODEV_NEWSESSION(cap->cc_dev, &lid, cri);
++ CRYPTO_DRIVER_LOCK();
++ if (err == 0) {
++ (*sid) = (cap->cc_flags & 0xff000000)
++ | (hid & 0x00ffffff);
++ (*sid) <<= 32;
++ (*sid) |= (lid & 0xffffffff);
++ } else
++ cap->cc_sessions--;
++ } else
++ err = EINVAL;
++ CRYPTO_DRIVER_UNLOCK();
++ return err;
++}
++
++static void
++crypto_remove(struct cryptocap *cap)
++{
++ CRYPTO_DRIVER_ASSERT();
++ if (cap->cc_sessions == 0 && cap->cc_koperations == 0)
++ bzero(cap, sizeof(*cap));
++}
++
++/*
++ * Delete an existing session (or a reserved session on an unregistered
++ * driver).
++ */
++int
++crypto_freesession(u_int64_t sid)
++{
++ struct cryptocap *cap;
++ u_int32_t hid;
++ int err = 0;
++ unsigned long d_flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++ CRYPTO_DRIVER_LOCK();
++
++ if (crypto_drivers == NULL) {
++ err = EINVAL;
++ goto done;
++ }
++
++ /* Determine two IDs. */
++ hid = CRYPTO_SESID2HID(sid);
++
++ if (hid >= crypto_drivers_num) {
++ dprintk("%s - INVALID DRIVER NUM %d\n", __FUNCTION__, hid);
++ err = ENOENT;
++ goto done;
++ }
++ cap = &crypto_drivers[hid];
++
++ if (cap->cc_dev) {
++ CRYPTO_DRIVER_UNLOCK();
++ /* Call the driver cleanup routine, if available, unlocked. */
++ err = CRYPTODEV_FREESESSION(cap->cc_dev, sid);
++ CRYPTO_DRIVER_LOCK();
++ }
++
++ if (cap->cc_sessions)
++ cap->cc_sessions--;
++
++ if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
++ crypto_remove(cap);
++
++done:
++ CRYPTO_DRIVER_UNLOCK();
++ return err;
++}
++
++/*
++ * Return an unused driver id. Used by drivers prior to registering
++ * support for the algorithms they handle.
++ */
++int32_t
++crypto_get_driverid(device_t dev, int flags)
++{
++ struct cryptocap *newdrv;
++ int i;
++ unsigned long d_flags;
++
++ if ((flags & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
++ printf("%s: no flags specified when registering driver\n",
++ device_get_nameunit(dev));
++ return -1;
++ }
++
++ CRYPTO_DRIVER_LOCK();
++
++ for (i = 0; i < crypto_drivers_num; i++) {
++ if (crypto_drivers[i].cc_dev == NULL &&
++ (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0) {
++ break;
++ }
++ }
++
++ /* Out of entries, allocate some more. */
++ if (i == crypto_drivers_num) {
++ /* Be careful about wrap-around. */
++ if (2 * crypto_drivers_num <= crypto_drivers_num) {
++ CRYPTO_DRIVER_UNLOCK();
++ printk("crypto: driver count wraparound!\n");
++ return -1;
++ }
++
++ newdrv = kmalloc(2 * crypto_drivers_num * sizeof(struct cryptocap),
++ GFP_KERNEL);
++ if (newdrv == NULL) {
++ CRYPTO_DRIVER_UNLOCK();
++ printk("crypto: no space to expand driver table!\n");
++ return -1;
++ }
++
++ memcpy(newdrv, crypto_drivers,
++ crypto_drivers_num * sizeof(struct cryptocap));
++ memset(&newdrv[crypto_drivers_num], 0,
++ crypto_drivers_num * sizeof(struct cryptocap));
++
++ crypto_drivers_num *= 2;
++
++ kfree(crypto_drivers);
++ crypto_drivers = newdrv;
++ }
++
++ /* NB: state is zero'd on free */
++ crypto_drivers[i].cc_sessions = 1; /* Mark */
++ crypto_drivers[i].cc_dev = dev;
++ crypto_drivers[i].cc_flags = flags;
++ if (bootverbose)
++ printf("crypto: assign %s driver id %u, flags %u\n",
++ device_get_nameunit(dev), i, flags);
++
++ CRYPTO_DRIVER_UNLOCK();
++
++ return i;
++}
++
++/*
++ * Lookup a driver by name. We match against the full device
++ * name and unit, and against just the name. The latter gives
++ * us a simple widlcarding by device name. On success return the
++ * driver/hardware identifier; otherwise return -1.
++ */
++int
++crypto_find_driver(const char *match)
++{
++ int i, len = strlen(match);
++ unsigned long d_flags;
++
++ CRYPTO_DRIVER_LOCK();
++ for (i = 0; i < crypto_drivers_num; i++) {
++ device_t dev = crypto_drivers[i].cc_dev;
++ if (dev == NULL ||
++ (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP))
++ continue;
++ if (strncmp(match, device_get_nameunit(dev), len) == 0 ||
++ strncmp(match, device_get_name(dev), len) == 0)
++ break;
++ }
++ CRYPTO_DRIVER_UNLOCK();
++ return i < crypto_drivers_num ? i : -1;
++}
++
++/*
++ * Return the device_t for the specified driver or NULL
++ * if the driver identifier is invalid.
++ */
++device_t
++crypto_find_device_byhid(int hid)
++{
++ struct cryptocap *cap = crypto_checkdriver(hid);
++ return cap != NULL ? cap->cc_dev : NULL;
++}
++
++/*
++ * Return the device/driver capabilities.
++ */
++int
++crypto_getcaps(int hid)
++{
++ struct cryptocap *cap = crypto_checkdriver(hid);
++ return cap != NULL ? cap->cc_flags : 0;
++}
++
++/*
++ * Register support for a key-related algorithm. This routine
++ * is called once for each algorithm supported a driver.
++ */
++int
++crypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags)
++{
++ struct cryptocap *cap;
++ int err;
++ unsigned long d_flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++ CRYPTO_DRIVER_LOCK();
++
++ cap = crypto_checkdriver(driverid);
++ if (cap != NULL &&
++ (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) {
++ /*
++ * XXX Do some performance testing to determine placing.
++ * XXX We probably need an auxiliary data structure that
++ * XXX describes relative performances.
++ */
++
++ cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
++ if (bootverbose)
++ printf("crypto: %s registers key alg %u flags %u\n"
++ , device_get_nameunit(cap->cc_dev)
++ , kalg
++ , flags
++ );
++ err = 0;
++ } else
++ err = EINVAL;
++
++ CRYPTO_DRIVER_UNLOCK();
++ return err;
++}
++
++/*
++ * Register support for a non-key-related algorithm. This routine
++ * is called once for each such algorithm supported by a driver.
++ */
++int
++crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
++ u_int32_t flags)
++{
++ struct cryptocap *cap;
++ int err;
++ unsigned long d_flags;
++
++ dprintk("%s(id=0x%x, alg=%d, maxoplen=%d, flags=0x%x)\n", __FUNCTION__,
++ driverid, alg, maxoplen, flags);
++
++ CRYPTO_DRIVER_LOCK();
++
++ cap = crypto_checkdriver(driverid);
++ /* NB: algorithms are in the range [1..max] */
++ if (cap != NULL &&
++ (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) {
++ /*
++ * XXX Do some performance testing to determine placing.
++ * XXX We probably need an auxiliary data structure that
++ * XXX describes relative performances.
++ */
++
++ cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
++ cap->cc_max_op_len[alg] = maxoplen;
++ if (bootverbose)
++ printf("crypto: %s registers alg %u flags %u maxoplen %u\n"
++ , device_get_nameunit(cap->cc_dev)
++ , alg
++ , flags
++ , maxoplen
++ );
++ cap->cc_sessions = 0; /* Unmark */
++ err = 0;
++ } else
++ err = EINVAL;
++
++ CRYPTO_DRIVER_UNLOCK();
++ return err;
++}
++
++static void
++driver_finis(struct cryptocap *cap)
++{
++ u_int32_t ses, kops;
++
++ CRYPTO_DRIVER_ASSERT();
++
++ ses = cap->cc_sessions;
++ kops = cap->cc_koperations;
++ bzero(cap, sizeof(*cap));
++ if (ses != 0 || kops != 0) {
++ /*
++ * If there are pending sessions,
++ * just mark as invalid.
++ */
++ cap->cc_flags |= CRYPTOCAP_F_CLEANUP;
++ cap->cc_sessions = ses;
++ cap->cc_koperations = kops;
++ }
++}
++
++/*
++ * Unregister a crypto driver. If there are pending sessions using it,
++ * leave enough information around so that subsequent calls using those
++ * sessions will correctly detect the driver has been unregistered and
++ * reroute requests.
++ */
++int
++crypto_unregister(u_int32_t driverid, int alg)
++{
++ struct cryptocap *cap;
++ int i, err;
++ unsigned long d_flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++ CRYPTO_DRIVER_LOCK();
++
++ cap = crypto_checkdriver(driverid);
++ if (cap != NULL &&
++ (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) &&
++ cap->cc_alg[alg] != 0) {
++ cap->cc_alg[alg] = 0;
++ cap->cc_max_op_len[alg] = 0;
++
++ /* Was this the last algorithm ? */
++ for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
++ if (cap->cc_alg[i] != 0)
++ break;
++
++ if (i == CRYPTO_ALGORITHM_MAX + 1)
++ driver_finis(cap);
++ err = 0;
++ } else
++ err = EINVAL;
++ CRYPTO_DRIVER_UNLOCK();
++ return err;
++}
++
++/*
++ * Unregister all algorithms associated with a crypto driver.
++ * If there are pending sessions using it, leave enough information
++ * around so that subsequent calls using those sessions will
++ * correctly detect the driver has been unregistered and reroute
++ * requests.
++ */
++int
++crypto_unregister_all(u_int32_t driverid)
++{
++ struct cryptocap *cap;
++ int err;
++ unsigned long d_flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++ CRYPTO_DRIVER_LOCK();
++ cap = crypto_checkdriver(driverid);
++ if (cap != NULL) {
++ driver_finis(cap);
++ err = 0;
++ } else
++ err = EINVAL;
++ CRYPTO_DRIVER_UNLOCK();
++
++ return err;
++}
++
++/*
++ * Clear blockage on a driver. The what parameter indicates whether
++ * the driver is now ready for cryptop's and/or cryptokop's.
++ */
++int
++crypto_unblock(u_int32_t driverid, int what)
++{
++ struct cryptocap *cap;
++ int err;
++ unsigned long q_flags;
++
++ CRYPTO_Q_LOCK();
++ cap = crypto_checkdriver(driverid);
++ if (cap != NULL) {
++ if (what & CRYPTO_SYMQ) {
++ cap->cc_qblocked = 0;
++ cap->cc_unqblocked = 0;
++ crypto_all_qblocked = 0;
++ }
++ if (what & CRYPTO_ASYMQ) {
++ cap->cc_kqblocked = 0;
++ cap->cc_unkqblocked = 0;
++ crypto_all_kqblocked = 0;
++ }
++ if (crp_sleep)
++ wake_up_interruptible(&cryptoproc_wait);
++ err = 0;
++ } else
++ err = EINVAL;
++ CRYPTO_Q_UNLOCK(); //DAVIDM should this be a driver lock
++
++ return err;
++}
++
++/*
++ * Add a crypto request to a queue, to be processed by the kernel thread.
++ */
++int
++crypto_dispatch(struct cryptop *crp)
++{
++ struct cryptocap *cap;
++ int result = -1;
++ unsigned long q_flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ cryptostats.cs_ops++;
++
++ CRYPTO_Q_LOCK();
++ if (crypto_q_cnt >= crypto_q_max) {
++ CRYPTO_Q_UNLOCK();
++ cryptostats.cs_drops++;
++ return ENOMEM;
++ }
++ crypto_q_cnt++;
++
++ /* make sure we are starting a fresh run on this crp. */
++ crp->crp_flags &= ~CRYPTO_F_DONE;
++ crp->crp_etype = 0;
++
++ /*
++ * Caller marked the request to be processed immediately; dispatch
++ * it directly to the driver unless the driver is currently blocked.
++ */
++ if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) {
++ int hid = CRYPTO_SESID2HID(crp->crp_sid);
++ cap = crypto_checkdriver(hid);
++ /* Driver cannot disappear when there is an active session. */
++ KASSERT(cap != NULL, ("%s: Driver disappeared.", __func__));
++ if (!cap->cc_qblocked) {
++ crypto_all_qblocked = 0;
++ crypto_drivers[hid].cc_unqblocked = 1;
++ CRYPTO_Q_UNLOCK();
++ result = crypto_invoke(cap, crp, 0);
++ CRYPTO_Q_LOCK();
++ if (result == ERESTART)
++ if (crypto_drivers[hid].cc_unqblocked)
++ crypto_drivers[hid].cc_qblocked = 1;
++ crypto_drivers[hid].cc_unqblocked = 0;
++ }
++ }
++ if (result == ERESTART) {
++ /*
++ * The driver ran out of resources, mark the
++ * driver ``blocked'' for cryptop's and put
++ * the request back in the queue. It would
++ * best to put the request back where we got
++ * it but that's hard so for now we put it
++ * at the front. This should be ok; putting
++ * it at the end does not work.
++ */
++ list_add(&crp->crp_next, &crp_q);
++ cryptostats.cs_blocks++;
++ result = 0;
++ } else if (result == -1) {
++ TAILQ_INSERT_TAIL(&crp_q, crp, crp_next);
++ result = 0;
++ }
++ if (crp_sleep)
++ wake_up_interruptible(&cryptoproc_wait);
++ CRYPTO_Q_UNLOCK();
++ return result;
++}
++
++/*
++ * Add an asymetric crypto request to a queue,
++ * to be processed by the kernel thread.
++ */
++int
++crypto_kdispatch(struct cryptkop *krp)
++{
++ int error;
++ unsigned long q_flags;
++
++ cryptostats.cs_kops++;
++
++ error = crypto_kinvoke(krp, krp->krp_crid);
++ if (error == ERESTART) {
++ CRYPTO_Q_LOCK();
++ TAILQ_INSERT_TAIL(&crp_kq, krp, krp_next);
++ if (crp_sleep)
++ wake_up_interruptible(&cryptoproc_wait);
++ CRYPTO_Q_UNLOCK();
++ error = 0;
++ }
++ return error;
++}
++
++/*
++ * Verify a driver is suitable for the specified operation.
++ */
++static __inline int
++kdriver_suitable(const struct cryptocap *cap, const struct cryptkop *krp)
++{
++ return (cap->cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED) != 0;
++}
++
++/*
++ * Select a driver for an asym operation. The driver must
++ * support the necessary algorithm. The caller can constrain
++ * which device is selected with the flags parameter. The
++ * algorithm we use here is pretty stupid; just use the first
++ * driver that supports the algorithms we need. If there are
++ * multiple suitable drivers we choose the driver with the
++ * fewest active operations. We prefer hardware-backed
++ * drivers to software ones when either may be used.
++ */
++static struct cryptocap *
++crypto_select_kdriver(const struct cryptkop *krp, int flags)
++{
++ struct cryptocap *cap, *best, *blocked;
++ int match, hid;
++
++ CRYPTO_DRIVER_ASSERT();
++
++ /*
++ * Look first for hardware crypto devices if permitted.
++ */
++ if (flags & CRYPTOCAP_F_HARDWARE)
++ match = CRYPTOCAP_F_HARDWARE;
++ else
++ match = CRYPTOCAP_F_SOFTWARE;
++ best = NULL;
++ blocked = NULL;
++again:
++ for (hid = 0; hid < crypto_drivers_num; hid++) {
++ cap = &crypto_drivers[hid];
++ /*
++ * If it's not initialized, is in the process of
++ * going away, or is not appropriate (hardware
++ * or software based on match), then skip.
++ */
++ if (cap->cc_dev == NULL ||
++ (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ||
++ (cap->cc_flags & match) == 0)
++ continue;
++
++ /* verify all the algorithms are supported. */
++ if (kdriver_suitable(cap, krp)) {
++ if (best == NULL ||
++ cap->cc_koperations < best->cc_koperations)
++ best = cap;
++ }
++ }
++ if (best != NULL)
++ return best;
++ if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) {
++ /* sort of an Algol 68-style for loop */
++ match = CRYPTOCAP_F_SOFTWARE;
++ goto again;
++ }
++ return best;
++}
++
++/*
++ * Dispatch an assymetric crypto request.
++ */
++static int
++crypto_kinvoke(struct cryptkop *krp, int crid)
++{
++ struct cryptocap *cap = NULL;
++ int error;
++ unsigned long d_flags;
++
++ KASSERT(krp != NULL, ("%s: krp == NULL", __func__));
++ KASSERT(krp->krp_callback != NULL,
++ ("%s: krp->crp_callback == NULL", __func__));
++
++ CRYPTO_DRIVER_LOCK();
++ if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
++ cap = crypto_checkdriver(crid);
++ if (cap != NULL) {
++ /*
++ * Driver present, it must support the necessary
++ * algorithm and, if s/w drivers are excluded,
++ * it must be registered as hardware-backed.
++ */
++ if (!kdriver_suitable(cap, krp) ||
++ (!crypto_devallowsoft &&
++ (cap->cc_flags & CRYPTOCAP_F_HARDWARE) == 0))
++ cap = NULL;
++ }
++ } else {
++ /*
++ * No requested driver; select based on crid flags.
++ */
++ if (!crypto_devallowsoft) /* NB: disallow s/w drivers */
++ crid &= ~CRYPTOCAP_F_SOFTWARE;
++ cap = crypto_select_kdriver(krp, crid);
++ }
++ if (cap != NULL && !cap->cc_kqblocked) {
++ krp->krp_hid = cap - crypto_drivers;
++ cap->cc_koperations++;
++ CRYPTO_DRIVER_UNLOCK();
++ error = CRYPTODEV_KPROCESS(cap->cc_dev, krp, 0);
++ CRYPTO_DRIVER_LOCK();
++ if (error == ERESTART) {
++ cap->cc_koperations--;
++ CRYPTO_DRIVER_UNLOCK();
++ return (error);
++ }
++ /* return the actual device used */
++ krp->krp_crid = krp->krp_hid;
++ } else {
++ /*
++ * NB: cap is !NULL if device is blocked; in
++ * that case return ERESTART so the operation
++ * is resubmitted if possible.
++ */
++ error = (cap == NULL) ? ENODEV : ERESTART;
++ }
++ CRYPTO_DRIVER_UNLOCK();
++
++ if (error) {
++ krp->krp_status = error;
++ crypto_kdone(krp);
++ }
++ return 0;
++}
++
++
++/*
++ * Dispatch a crypto request to the appropriate crypto devices.
++ */
++static int
++crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint)
++{
++ KASSERT(crp != NULL, ("%s: crp == NULL", __func__));
++ KASSERT(crp->crp_callback != NULL,
++ ("%s: crp->crp_callback == NULL", __func__));
++ KASSERT(crp->crp_desc != NULL, ("%s: crp->crp_desc == NULL", __func__));
++
++ dprintk("%s()\n", __FUNCTION__);
++
++#ifdef CRYPTO_TIMING
++ if (crypto_timing)
++ crypto_tstat(&cryptostats.cs_invoke, &crp->crp_tstamp);
++#endif
++ if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) {
++ struct cryptodesc *crd;
++ u_int64_t nid;
++
++ /*
++ * Driver has unregistered; migrate the session and return
++ * an error to the caller so they'll resubmit the op.
++ *
++ * XXX: What if there are more already queued requests for this
++ * session?
++ */
++ crypto_freesession(crp->crp_sid);
++
++ for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
++ crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
++
++ /* XXX propagate flags from initial session? */
++ if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI),
++ CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE) == 0)
++ crp->crp_sid = nid;
++
++ crp->crp_etype = EAGAIN;
++ crypto_done(crp);
++ return 0;
++ } else {
++ /*
++ * Invoke the driver to process the request.
++ */
++ return CRYPTODEV_PROCESS(cap->cc_dev, crp, hint);
++ }
++}
++
++/*
++ * Release a set of crypto descriptors.
++ */
++void
++crypto_freereq(struct cryptop *crp)
++{
++ struct cryptodesc *crd;
++
++ if (crp == NULL)
++ return;
++
++#ifdef DIAGNOSTIC
++ {
++ struct cryptop *crp2;
++ unsigned long q_flags;
++
++ CRYPTO_Q_LOCK();
++ TAILQ_FOREACH(crp2, &crp_q, crp_next) {
++ KASSERT(crp2 != crp,
++ ("Freeing cryptop from the crypto queue (%p).",
++ crp));
++ }
++ CRYPTO_Q_UNLOCK();
++ CRYPTO_RETQ_LOCK();
++ TAILQ_FOREACH(crp2, &crp_ret_q, crp_next) {
++ KASSERT(crp2 != crp,
++ ("Freeing cryptop from the return queue (%p).",
++ crp));
++ }
++ CRYPTO_RETQ_UNLOCK();
++ }
++#endif
++
++ while ((crd = crp->crp_desc) != NULL) {
++ crp->crp_desc = crd->crd_next;
++ kmem_cache_free(cryptodesc_zone, crd);
++ }
++ kmem_cache_free(cryptop_zone, crp);
++}
++
++/*
++ * Acquire a set of crypto descriptors.
++ */
++struct cryptop *
++crypto_getreq(int num)
++{
++ struct cryptodesc *crd;
++ struct cryptop *crp;
++
++ crp = kmem_cache_alloc(cryptop_zone, SLAB_ATOMIC);
++ if (crp != NULL) {
++ memset(crp, 0, sizeof(*crp));
++ INIT_LIST_HEAD(&crp->crp_next);
++ init_waitqueue_head(&crp->crp_waitq);
++ while (num--) {
++ crd = kmem_cache_alloc(cryptodesc_zone, SLAB_ATOMIC);
++ if (crd == NULL) {
++ crypto_freereq(crp);
++ return NULL;
++ }
++ memset(crd, 0, sizeof(*crd));
++ crd->crd_next = crp->crp_desc;
++ crp->crp_desc = crd;
++ }
++ }
++ return crp;
++}
++
++/*
++ * Invoke the callback on behalf of the driver.
++ */
++void
++crypto_done(struct cryptop *crp)
++{
++ unsigned long q_flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++ if ((crp->crp_flags & CRYPTO_F_DONE) == 0) {
++ crp->crp_flags |= CRYPTO_F_DONE;
++ CRYPTO_Q_LOCK();
++ crypto_q_cnt--;
++ CRYPTO_Q_UNLOCK();
++ } else
++ printk("crypto: crypto_done op already done, flags 0x%x",
++ crp->crp_flags);
++ if (crp->crp_etype != 0)
++ cryptostats.cs_errs++;
++ /*
++ * CBIMM means unconditionally do the callback immediately;
++ * CBIFSYNC means do the callback immediately only if the
++ * operation was done synchronously. Both are used to avoid
++ * doing extraneous context switches; the latter is mostly
++ * used with the software crypto driver.
++ */
++ if ((crp->crp_flags & CRYPTO_F_CBIMM) ||
++ ((crp->crp_flags & CRYPTO_F_CBIFSYNC) &&
++ (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) {
++ /*
++ * Do the callback directly. This is ok when the
++ * callback routine does very little (e.g. the
++ * /dev/crypto callback method just does a wakeup).
++ */
++ crp->crp_callback(crp);
++ } else {
++ unsigned long r_flags;
++ /*
++ * Normal case; queue the callback for the thread.
++ */
++ CRYPTO_RETQ_LOCK();
++ if (CRYPTO_RETQ_EMPTY())
++ wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */
++ TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next);
++ CRYPTO_RETQ_UNLOCK();
++ }
++}
++
++/*
++ * Invoke the callback on behalf of the driver.
++ */
++void
++crypto_kdone(struct cryptkop *krp)
++{
++ struct cryptocap *cap;
++ unsigned long d_flags;
++
++ if ((krp->krp_flags & CRYPTO_KF_DONE) != 0)
++ printk("crypto: crypto_kdone op already done, flags 0x%x",
++ krp->krp_flags);
++ krp->krp_flags |= CRYPTO_KF_DONE;
++ if (krp->krp_status != 0)
++ cryptostats.cs_kerrs++;
++
++ CRYPTO_DRIVER_LOCK();
++ /* XXX: What if driver is loaded in the meantime? */
++ if (krp->krp_hid < crypto_drivers_num) {
++ cap = &crypto_drivers[krp->krp_hid];
++ cap->cc_koperations--;
++ KASSERT(cap->cc_koperations >= 0, ("cc_koperations < 0"));
++ if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
++ crypto_remove(cap);
++ }
++ CRYPTO_DRIVER_UNLOCK();
++
++ /*
++ * CBIMM means unconditionally do the callback immediately;
++ * This is used to avoid doing extraneous context switches
++ */
++ if ((krp->krp_flags & CRYPTO_KF_CBIMM)) {
++ /*
++ * Do the callback directly. This is ok when the
++ * callback routine does very little (e.g. the
++ * /dev/crypto callback method just does a wakeup).
++ */
++ krp->krp_callback(krp);
++ } else {
++ unsigned long r_flags;
++ /*
++ * Normal case; queue the callback for the thread.
++ */
++ CRYPTO_RETQ_LOCK();
++ if (CRYPTO_RETQ_EMPTY())
++ wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */
++ TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next);
++ CRYPTO_RETQ_UNLOCK();
++ }
++}
++
++int
++crypto_getfeat(int *featp)
++{
++ int hid, kalg, feat = 0;
++ unsigned long d_flags;
++
++ CRYPTO_DRIVER_LOCK();
++ for (hid = 0; hid < crypto_drivers_num; hid++) {
++ const struct cryptocap *cap = &crypto_drivers[hid];
++
++ if ((cap->cc_flags & CRYPTOCAP_F_SOFTWARE) &&
++ !crypto_devallowsoft) {
++ continue;
++ }
++ for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++)
++ if (cap->cc_kalg[kalg] & CRYPTO_ALG_FLAG_SUPPORTED)
++ feat |= 1 << kalg;
++ }
++ CRYPTO_DRIVER_UNLOCK();
++ *featp = feat;
++ return (0);
++}
++
++/*
++ * Crypto thread, dispatches crypto requests.
++ */
++static int
++crypto_proc(void *arg)
++{
++ struct cryptop *crp, *submit;
++ struct cryptkop *krp, *krpp;
++ struct cryptocap *cap;
++ u_int32_t hid;
++ int result, hint;
++ unsigned long q_flags;
++ int loopcount = 0;
++
++ ocf_daemonize("crypto");
++
++ CRYPTO_Q_LOCK();
++ for (;;) {
++ /*
++ * we need to make sure we don't get into a busy loop with nothing
++ * to do, the two crypto_all_*blocked vars help us find out when
++ * we are all full and can do nothing on any driver or Q. If so we
++ * wait for an unblock.
++ */
++ crypto_all_qblocked = !list_empty(&crp_q);
++
++ /*
++ * Find the first element in the queue that can be
++ * processed and look-ahead to see if multiple ops
++ * are ready for the same driver.
++ */
++ submit = NULL;
++ hint = 0;
++ list_for_each_entry(crp, &crp_q, crp_next) {
++ hid = CRYPTO_SESID2HID(crp->crp_sid);
++ cap = crypto_checkdriver(hid);
++ /*
++ * Driver cannot disappear when there is an active
++ * session.
++ */
++ KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
++ __func__, __LINE__));
++ if (cap == NULL || cap->cc_dev == NULL) {
++ /* Op needs to be migrated, process it. */
++ if (submit == NULL)
++ submit = crp;
++ break;
++ }
++ if (!cap->cc_qblocked) {
++ if (submit != NULL) {
++ /*
++ * We stop on finding another op,
++ * regardless whether its for the same
++ * driver or not. We could keep
++ * searching the queue but it might be
++ * better to just use a per-driver
++ * queue instead.
++ */
++ if (CRYPTO_SESID2HID(submit->crp_sid) == hid)
++ hint = CRYPTO_HINT_MORE;
++ break;
++ } else {
++ submit = crp;
++ if ((submit->crp_flags & CRYPTO_F_BATCH) == 0)
++ break;
++ /* keep scanning for more are q'd */
++ }
++ }
++ }
++ if (submit != NULL) {
++ hid = CRYPTO_SESID2HID(submit->crp_sid);
++ crypto_all_qblocked = 0;
++ list_del(&submit->crp_next);
++ crypto_drivers[hid].cc_unqblocked = 1;
++ cap = crypto_checkdriver(hid);
++ CRYPTO_Q_UNLOCK();
++ KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
++ __func__, __LINE__));
++ result = crypto_invoke(cap, submit, hint);
++ CRYPTO_Q_LOCK();
++ if (result == ERESTART) {
++ /*
++ * The driver ran out of resources, mark the
++ * driver ``blocked'' for cryptop's and put
++ * the request back in the queue. It would
++ * best to put the request back where we got
++ * it but that's hard so for now we put it
++ * at the front. This should be ok; putting
++ * it at the end does not work.
++ */
++ /* XXX validate sid again? */
++ list_add(&submit->crp_next, &crp_q);
++ cryptostats.cs_blocks++;
++ if (crypto_drivers[hid].cc_unqblocked)
++ crypto_drivers[hid].cc_qblocked=0;
++ crypto_drivers[hid].cc_unqblocked=0;
++ }
++ crypto_drivers[hid].cc_unqblocked = 0;
++ }
++
++ crypto_all_kqblocked = !list_empty(&crp_kq);
++
++ /* As above, but for key ops */
++ krp = NULL;
++ list_for_each_entry(krpp, &crp_kq, krp_next) {
++ cap = crypto_checkdriver(krpp->krp_hid);
++ if (cap == NULL || cap->cc_dev == NULL) {
++ /*
++ * Operation needs to be migrated, invalidate
++ * the assigned device so it will reselect a
++ * new one below. Propagate the original
++ * crid selection flags if supplied.
++ */
++ krp->krp_hid = krp->krp_crid &
++ (CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE);
++ if (krp->krp_hid == 0)
++ krp->krp_hid =
++ CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE;
++ break;
++ }
++ if (!cap->cc_kqblocked) {
++ krp = krpp;
++ break;
++ }
++ }
++ if (krp != NULL) {
++ crypto_all_kqblocked = 0;
++ list_del(&krp->krp_next);
++ crypto_drivers[krp->krp_hid].cc_kqblocked = 1;
++ CRYPTO_Q_UNLOCK();
++ result = crypto_kinvoke(krp, krp->krp_hid);
++ CRYPTO_Q_LOCK();
++ if (result == ERESTART) {
++ /*
++ * The driver ran out of resources, mark the
++ * driver ``blocked'' for cryptkop's and put
++ * the request back in the queue. It would
++ * best to put the request back where we got
++ * it but that's hard so for now we put it
++ * at the front. This should be ok; putting
++ * it at the end does not work.
++ */
++ /* XXX validate sid again? */
++ list_add(&krp->krp_next, &crp_kq);
++ cryptostats.cs_kblocks++;
++ } else
++ crypto_drivers[krp->krp_hid].cc_kqblocked = 0;
++ }
++
++ if (submit == NULL && krp == NULL) {
++ /*
++ * Nothing more to be processed. Sleep until we're
++ * woken because there are more ops to process.
++ * This happens either by submission or by a driver
++ * becoming unblocked and notifying us through
++ * crypto_unblock. Note that when we wakeup we
++ * start processing each queue again from the
++ * front. It's not clear that it's important to
++ * preserve this ordering since ops may finish
++ * out of order if dispatched to different devices
++ * and some become blocked while others do not.
++ */
++ dprintk("%s - sleeping (qe=%d qb=%d kqe=%d kqb=%d)\n",
++ __FUNCTION__,
++ list_empty(&crp_q), crypto_all_qblocked,
++ list_empty(&crp_kq), crypto_all_kqblocked);
++ loopcount = 0;
++ CRYPTO_Q_UNLOCK();
++ crp_sleep = 1;
++ wait_event_interruptible(cryptoproc_wait,
++ !(list_empty(&crp_q) || crypto_all_qblocked) ||
++ !(list_empty(&crp_kq) || crypto_all_kqblocked) ||
++ cryptoproc == (pid_t) -1);
++ crp_sleep = 0;
++ if (signal_pending (current)) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ spin_lock_irq(&current->sigmask_lock);
++#endif
++ flush_signals(current);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ spin_unlock_irq(&current->sigmask_lock);
++#endif
++ }
++ CRYPTO_Q_LOCK();
++ dprintk("%s - awake\n", __FUNCTION__);
++ if (cryptoproc == (pid_t) -1)
++ break;
++ cryptostats.cs_intrs++;
++ } else if (loopcount > crypto_max_loopcount) {
++ /*
++ * Give other processes a chance to run if we've
++ * been using the CPU exclusively for a while.
++ */
++ loopcount = 0;
++ schedule();
++ }
++ loopcount++;
++ }
++ CRYPTO_Q_UNLOCK();
++ complete_and_exit(&cryptoproc_exited, 0);
++}
++
++/*
++ * Crypto returns thread, does callbacks for processed crypto requests.
++ * Callbacks are done here, rather than in the crypto drivers, because
++ * callbacks typically are expensive and would slow interrupt handling.
++ */
++static int
++crypto_ret_proc(void *arg)
++{
++ struct cryptop *crpt;
++ struct cryptkop *krpt;
++ unsigned long r_flags;
++
++ ocf_daemonize("crypto_ret");
++
++ CRYPTO_RETQ_LOCK();
++ for (;;) {
++ /* Harvest return q's for completed ops */
++ crpt = NULL;
++ if (!list_empty(&crp_ret_q))
++ crpt = list_entry(crp_ret_q.next, typeof(*crpt), crp_next);
++ if (crpt != NULL)
++ list_del(&crpt->crp_next);
++
++ krpt = NULL;
++ if (!list_empty(&crp_ret_kq))
++ krpt = list_entry(crp_ret_kq.next, typeof(*krpt), krp_next);
++ if (krpt != NULL)
++ list_del(&krpt->krp_next);
++
++ if (crpt != NULL || krpt != NULL) {
++ CRYPTO_RETQ_UNLOCK();
++ /*
++ * Run callbacks unlocked.
++ */
++ if (crpt != NULL)
++ crpt->crp_callback(crpt);
++ if (krpt != NULL)
++ krpt->krp_callback(krpt);
++ CRYPTO_RETQ_LOCK();
++ } else {
++ /*
++ * Nothing more to be processed. Sleep until we're
++ * woken because there are more returns to process.
++ */
++ dprintk("%s - sleeping\n", __FUNCTION__);
++ CRYPTO_RETQ_UNLOCK();
++ wait_event_interruptible(cryptoretproc_wait,
++ cryptoretproc == (pid_t) -1 ||
++ !list_empty(&crp_ret_q) ||
++ !list_empty(&crp_ret_kq));
++ if (signal_pending (current)) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ spin_lock_irq(&current->sigmask_lock);
++#endif
++ flush_signals(current);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ spin_unlock_irq(&current->sigmask_lock);
++#endif
++ }
++ CRYPTO_RETQ_LOCK();
++ dprintk("%s - awake\n", __FUNCTION__);
++ if (cryptoretproc == (pid_t) -1) {
++ dprintk("%s - EXITING!\n", __FUNCTION__);
++ break;
++ }
++ cryptostats.cs_rets++;
++ }
++ }
++ CRYPTO_RETQ_UNLOCK();
++ complete_and_exit(&cryptoretproc_exited, 0);
++}
++
++
++#if 0 /* should put this into /proc or something */
++static void
++db_show_drivers(void)
++{
++ int hid;
++
++ db_printf("%12s %4s %4s %8s %2s %2s\n"
++ , "Device"
++ , "Ses"
++ , "Kops"
++ , "Flags"
++ , "QB"
++ , "KB"
++ );
++ for (hid = 0; hid < crypto_drivers_num; hid++) {
++ const struct cryptocap *cap = &crypto_drivers[hid];
++ if (cap->cc_dev == NULL)
++ continue;
++ db_printf("%-12s %4u %4u %08x %2u %2u\n"
++ , device_get_nameunit(cap->cc_dev)
++ , cap->cc_sessions
++ , cap->cc_koperations
++ , cap->cc_flags
++ , cap->cc_qblocked
++ , cap->cc_kqblocked
++ );
++ }
++}
++
++DB_SHOW_COMMAND(crypto, db_show_crypto)
++{
++ struct cryptop *crp;
++
++ db_show_drivers();
++ db_printf("\n");
++
++ db_printf("%4s %8s %4s %4s %4s %4s %8s %8s\n",
++ "HID", "Caps", "Ilen", "Olen", "Etype", "Flags",
++ "Desc", "Callback");
++ TAILQ_FOREACH(crp, &crp_q, crp_next) {
++ db_printf("%4u %08x %4u %4u %4u %04x %8p %8p\n"
++ , (int) CRYPTO_SESID2HID(crp->crp_sid)
++ , (int) CRYPTO_SESID2CAPS(crp->crp_sid)
++ , crp->crp_ilen, crp->crp_olen
++ , crp->crp_etype
++ , crp->crp_flags
++ , crp->crp_desc
++ , crp->crp_callback
++ );
++ }
++ if (!TAILQ_EMPTY(&crp_ret_q)) {
++ db_printf("\n%4s %4s %4s %8s\n",
++ "HID", "Etype", "Flags", "Callback");
++ TAILQ_FOREACH(crp, &crp_ret_q, crp_next) {
++ db_printf("%4u %4u %04x %8p\n"
++ , (int) CRYPTO_SESID2HID(crp->crp_sid)
++ , crp->crp_etype
++ , crp->crp_flags
++ , crp->crp_callback
++ );
++ }
++ }
++}
++
++DB_SHOW_COMMAND(kcrypto, db_show_kcrypto)
++{
++ struct cryptkop *krp;
++
++ db_show_drivers();
++ db_printf("\n");
++
++ db_printf("%4s %5s %4s %4s %8s %4s %8s\n",
++ "Op", "Status", "#IP", "#OP", "CRID", "HID", "Callback");
++ TAILQ_FOREACH(krp, &crp_kq, krp_next) {
++ db_printf("%4u %5u %4u %4u %08x %4u %8p\n"
++ , krp->krp_op
++ , krp->krp_status
++ , krp->krp_iparams, krp->krp_oparams
++ , krp->krp_crid, krp->krp_hid
++ , krp->krp_callback
++ );
++ }
++ if (!TAILQ_EMPTY(&crp_ret_q)) {
++ db_printf("%4s %5s %8s %4s %8s\n",
++ "Op", "Status", "CRID", "HID", "Callback");
++ TAILQ_FOREACH(krp, &crp_ret_kq, krp_next) {
++ db_printf("%4u %5u %08x %4u %8p\n"
++ , krp->krp_op
++ , krp->krp_status
++ , krp->krp_crid, krp->krp_hid
++ , krp->krp_callback
++ );
++ }
++ }
++}
++#endif
++
++
++static int
++crypto_init(void)
++{
++ int error;
++
++ dprintk("%s(%p)\n", __FUNCTION__, (void *) crypto_init);
++
++ if (crypto_initted)
++ return 0;
++ crypto_initted = 1;
++
++ spin_lock_init(&crypto_drivers_lock);
++ spin_lock_init(&crypto_q_lock);
++ spin_lock_init(&crypto_ret_q_lock);
++
++ cryptop_zone = kmem_cache_create("cryptop", sizeof(struct cryptop),
++ 0, SLAB_HWCACHE_ALIGN, NULL
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++ , NULL
++#endif
++ );
++
++ cryptodesc_zone = kmem_cache_create("cryptodesc", sizeof(struct cryptodesc),
++ 0, SLAB_HWCACHE_ALIGN, NULL
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++ , NULL
++#endif
++ );
++
++ if (cryptodesc_zone == NULL || cryptop_zone == NULL) {
++ printk("crypto: crypto_init cannot setup crypto zones\n");
++ error = ENOMEM;
++ goto bad;
++ }
++
++ crypto_drivers_num = CRYPTO_DRIVERS_INITIAL;
++ crypto_drivers = kmalloc(crypto_drivers_num * sizeof(struct cryptocap),
++ GFP_KERNEL);
++ if (crypto_drivers == NULL) {
++ printk("crypto: crypto_init cannot setup crypto drivers\n");
++ error = ENOMEM;
++ goto bad;
++ }
++
++ memset(crypto_drivers, 0, crypto_drivers_num * sizeof(struct cryptocap));
++
++ init_completion(&cryptoproc_exited);
++ init_completion(&cryptoretproc_exited);
++
++ cryptoproc = 0; /* to avoid race condition where proc runs first */
++ cryptoproc = kernel_thread(crypto_proc, NULL, CLONE_FS|CLONE_FILES);
++ if (cryptoproc < 0) {
++ error = cryptoproc;
++ printk("crypto: crypto_init cannot start crypto thread; error %d",
++ error);
++ goto bad;
++ }
++
++ cryptoretproc = 0; /* to avoid race condition where proc runs first */
++ cryptoretproc = kernel_thread(crypto_ret_proc, NULL, CLONE_FS|CLONE_FILES);
++ if (cryptoretproc < 0) {
++ error = cryptoretproc;
++ printk("crypto: crypto_init cannot start cryptoret thread; error %d",
++ error);
++ goto bad;
++ }
++
++ return 0;
++bad:
++ crypto_exit();
++ return error;
++}
++
++
++static void
++crypto_exit(void)
++{
++ pid_t p;
++ unsigned long d_flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ /*
++ * Terminate any crypto threads.
++ */
++
++ CRYPTO_DRIVER_LOCK();
++ p = cryptoproc;
++ cryptoproc = (pid_t) -1;
++ kill_proc(p, SIGTERM, 1);
++ wake_up_interruptible(&cryptoproc_wait);
++ CRYPTO_DRIVER_UNLOCK();
++
++ wait_for_completion(&cryptoproc_exited);
++
++ CRYPTO_DRIVER_LOCK();
++ p = cryptoretproc;
++ cryptoretproc = (pid_t) -1;
++ kill_proc(p, SIGTERM, 1);
++ wake_up_interruptible(&cryptoretproc_wait);
++ CRYPTO_DRIVER_UNLOCK();
++
++ wait_for_completion(&cryptoretproc_exited);
++
++ /* XXX flush queues??? */
++
++ /*
++ * Reclaim dynamically allocated resources.
++ */
++ if (crypto_drivers != NULL)
++ kfree(crypto_drivers);
++
++ if (cryptodesc_zone != NULL)
++ kmem_cache_destroy(cryptodesc_zone);
++ if (cryptop_zone != NULL)
++ kmem_cache_destroy(cryptop_zone);
++}
++
++
++EXPORT_SYMBOL(crypto_newsession);
++EXPORT_SYMBOL(crypto_freesession);
++EXPORT_SYMBOL(crypto_get_driverid);
++EXPORT_SYMBOL(crypto_kregister);
++EXPORT_SYMBOL(crypto_register);
++EXPORT_SYMBOL(crypto_unregister);
++EXPORT_SYMBOL(crypto_unregister_all);
++EXPORT_SYMBOL(crypto_unblock);
++EXPORT_SYMBOL(crypto_dispatch);
++EXPORT_SYMBOL(crypto_kdispatch);
++EXPORT_SYMBOL(crypto_freereq);
++EXPORT_SYMBOL(crypto_getreq);
++EXPORT_SYMBOL(crypto_done);
++EXPORT_SYMBOL(crypto_kdone);
++EXPORT_SYMBOL(crypto_getfeat);
++EXPORT_SYMBOL(crypto_userasymcrypto);
++EXPORT_SYMBOL(crypto_getcaps);
++EXPORT_SYMBOL(crypto_find_driver);
++EXPORT_SYMBOL(crypto_find_device_byhid);
++
++module_init(crypto_init);
++module_exit(crypto_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
++MODULE_DESCRIPTION("OCF (OpenBSD Cryptographic Framework)");
+diff -Nur linux-2.6.36.orig/crypto/ocf/cryptocteon/cavium_crypto.c linux-2.6.36/crypto/ocf/cryptocteon/cavium_crypto.c
+--- linux-2.6.36.orig/crypto/ocf/cryptocteon/cavium_crypto.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/cryptocteon/cavium_crypto.c 2010-11-09 20:28:04.311245450 +0100
+@@ -0,0 +1,2283 @@
++/*
++ * Copyright (c) 2009 David McCullough <david.mccullough@securecomputing.com>
++ *
++ * Copyright (c) 2003-2007 Cavium Networks (support@cavium.com). All rights
++ * reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * 1. Redistributions of source code must retain the above copyright notice,
++ * this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. All advertising materials mentioning features or use of this software
++ * must display the following acknowledgement:
++ * This product includes software developed by Cavium Networks
++ * 4. Cavium Networks' name may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * This Software, including technical data, may be subject to U.S. export
++ * control laws, including the U.S. Export Administration Act and its
++ * associated regulations, and may be subject to export or import regulations
++ * in other countries. You warrant that You will comply strictly in all
++ * respects with all such regulations and acknowledge that you have the
++ * responsibility to obtain licenses to export, re-export or import the
++ * Software.
++ *
++ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" AND
++ * WITH ALL FAULTS AND CAVIUM MAKES NO PROMISES, REPRESENTATIONS OR WARRANTIES,
++ * EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE
++ * SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
++ * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
++ * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
++ * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
++ * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
++ * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR
++ * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
++*/
++/****************************************************************************/
++
++#include <linux/scatterlist.h>
++#include <asm/octeon/octeon.h>
++#include "octeon-asm.h"
++
++/****************************************************************************/
++
++extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *);
++extern void octeon_crypto_disable(struct octeon_cop2_state *, unsigned long);
++
++#define SG_INIT(s, p, i, l) \
++ { \
++ (i) = 0; \
++ (l) = (s)[0].length; \
++ (p) = (typeof(p)) sg_virt((s)); \
++ CVMX_PREFETCH0((p)); \
++ }
++
++#define SG_CONSUME(s, p, i, l) \
++ { \
++ (p)++; \
++ (l) -= sizeof(*(p)); \
++ if ((l) < 0) { \
++ dprintk("%s, %d: l = %d\n", __FILE__, __LINE__, l); \
++ } else if ((l) == 0) { \
++ (i)++; \
++ (l) = (s)[0].length; \
++ (p) = (typeof(p)) sg_virt(s); \
++ CVMX_PREFETCH0((p)); \
++ } \
++ }
++
++#define ESP_HEADER_LENGTH 8
++#define DES_CBC_IV_LENGTH 8
++#define AES_CBC_IV_LENGTH 16
++#define ESP_HMAC_LEN 12
++
++#define ESP_HEADER_LENGTH 8
++#define DES_CBC_IV_LENGTH 8
++
++/****************************************************************************/
++
++#define CVM_LOAD_SHA_UNIT(dat, next) { \
++ if (next == 0) { \
++ next = 1; \
++ CVMX_MT_HSH_DAT (dat, 0); \
++ } else if (next == 1) { \
++ next = 2; \
++ CVMX_MT_HSH_DAT (dat, 1); \
++ } else if (next == 2) { \
++ next = 3; \
++ CVMX_MT_HSH_DAT (dat, 2); \
++ } else if (next == 3) { \
++ next = 4; \
++ CVMX_MT_HSH_DAT (dat, 3); \
++ } else if (next == 4) { \
++ next = 5; \
++ CVMX_MT_HSH_DAT (dat, 4); \
++ } else if (next == 5) { \
++ next = 6; \
++ CVMX_MT_HSH_DAT (dat, 5); \
++ } else if (next == 6) { \
++ next = 7; \
++ CVMX_MT_HSH_DAT (dat, 6); \
++ } else { \
++ CVMX_MT_HSH_STARTSHA (dat); \
++ next = 0; \
++ } \
++}
++
++#define CVM_LOAD2_SHA_UNIT(dat1, dat2, next) { \
++ if (next == 0) { \
++ CVMX_MT_HSH_DAT (dat1, 0); \
++ CVMX_MT_HSH_DAT (dat2, 1); \
++ next = 2; \
++ } else if (next == 1) { \
++ CVMX_MT_HSH_DAT (dat1, 1); \
++ CVMX_MT_HSH_DAT (dat2, 2); \
++ next = 3; \
++ } else if (next == 2) { \
++ CVMX_MT_HSH_DAT (dat1, 2); \
++ CVMX_MT_HSH_DAT (dat2, 3); \
++ next = 4; \
++ } else if (next == 3) { \
++ CVMX_MT_HSH_DAT (dat1, 3); \
++ CVMX_MT_HSH_DAT (dat2, 4); \
++ next = 5; \
++ } else if (next == 4) { \
++ CVMX_MT_HSH_DAT (dat1, 4); \
++ CVMX_MT_HSH_DAT (dat2, 5); \
++ next = 6; \
++ } else if (next == 5) { \
++ CVMX_MT_HSH_DAT (dat1, 5); \
++ CVMX_MT_HSH_DAT (dat2, 6); \
++ next = 7; \
++ } else if (next == 6) { \
++ CVMX_MT_HSH_DAT (dat1, 6); \
++ CVMX_MT_HSH_STARTSHA (dat2); \
++ next = 0; \
++ } else { \
++ CVMX_MT_HSH_STARTSHA (dat1); \
++ CVMX_MT_HSH_DAT (dat2, 0); \
++ next = 1; \
++ } \
++}
++
++/****************************************************************************/
++
++#define CVM_LOAD_MD5_UNIT(dat, next) { \
++ if (next == 0) { \
++ next = 1; \
++ CVMX_MT_HSH_DAT (dat, 0); \
++ } else if (next == 1) { \
++ next = 2; \
++ CVMX_MT_HSH_DAT (dat, 1); \
++ } else if (next == 2) { \
++ next = 3; \
++ CVMX_MT_HSH_DAT (dat, 2); \
++ } else if (next == 3) { \
++ next = 4; \
++ CVMX_MT_HSH_DAT (dat, 3); \
++ } else if (next == 4) { \
++ next = 5; \
++ CVMX_MT_HSH_DAT (dat, 4); \
++ } else if (next == 5) { \
++ next = 6; \
++ CVMX_MT_HSH_DAT (dat, 5); \
++ } else if (next == 6) { \
++ next = 7; \
++ CVMX_MT_HSH_DAT (dat, 6); \
++ } else { \
++ CVMX_MT_HSH_STARTMD5 (dat); \
++ next = 0; \
++ } \
++}
++
++#define CVM_LOAD2_MD5_UNIT(dat1, dat2, next) { \
++ if (next == 0) { \
++ CVMX_MT_HSH_DAT (dat1, 0); \
++ CVMX_MT_HSH_DAT (dat2, 1); \
++ next = 2; \
++ } else if (next == 1) { \
++ CVMX_MT_HSH_DAT (dat1, 1); \
++ CVMX_MT_HSH_DAT (dat2, 2); \
++ next = 3; \
++ } else if (next == 2) { \
++ CVMX_MT_HSH_DAT (dat1, 2); \
++ CVMX_MT_HSH_DAT (dat2, 3); \
++ next = 4; \
++ } else if (next == 3) { \
++ CVMX_MT_HSH_DAT (dat1, 3); \
++ CVMX_MT_HSH_DAT (dat2, 4); \
++ next = 5; \
++ } else if (next == 4) { \
++ CVMX_MT_HSH_DAT (dat1, 4); \
++ CVMX_MT_HSH_DAT (dat2, 5); \
++ next = 6; \
++ } else if (next == 5) { \
++ CVMX_MT_HSH_DAT (dat1, 5); \
++ CVMX_MT_HSH_DAT (dat2, 6); \
++ next = 7; \
++ } else if (next == 6) { \
++ CVMX_MT_HSH_DAT (dat1, 6); \
++ CVMX_MT_HSH_STARTMD5 (dat2); \
++ next = 0; \
++ } else { \
++ CVMX_MT_HSH_STARTMD5 (dat1); \
++ CVMX_MT_HSH_DAT (dat2, 0); \
++ next = 1; \
++ } \
++}
++
++/****************************************************************************/
++
++static inline uint64_t
++swap64(uint64_t a)
++{
++ return ((a >> 56) |
++ (((a >> 48) & 0xfful) << 8) |
++ (((a >> 40) & 0xfful) << 16) |
++ (((a >> 32) & 0xfful) << 24) |
++ (((a >> 24) & 0xfful) << 32) |
++ (((a >> 16) & 0xfful) << 40) |
++ (((a >> 8) & 0xfful) << 48) | (((a >> 0) & 0xfful) << 56));
++}
++
++/****************************************************************************/
++
++void
++octo_calc_hash(__u8 auth, unsigned char *key, uint64_t *inner, uint64_t *outer)
++{
++ uint8_t hash_key[64];
++ uint64_t *key1;
++ register uint64_t xor1 = 0x3636363636363636ULL;
++ register uint64_t xor2 = 0x5c5c5c5c5c5c5c5cULL;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ memset(hash_key, 0, sizeof(hash_key));
++ memcpy(hash_key, (uint8_t *) key, (auth ? 20 : 16));
++ key1 = (uint64_t *) hash_key;
++ flags = octeon_crypto_enable(&state);
++ if (auth) {
++ CVMX_MT_HSH_IV(0x67452301EFCDAB89ULL, 0);
++ CVMX_MT_HSH_IV(0x98BADCFE10325476ULL, 1);
++ CVMX_MT_HSH_IV(0xC3D2E1F000000000ULL, 2);
++ } else {
++ CVMX_MT_HSH_IV(0x0123456789ABCDEFULL, 0);
++ CVMX_MT_HSH_IV(0xFEDCBA9876543210ULL, 1);
++ }
++
++ CVMX_MT_HSH_DAT((*key1 ^ xor1), 0);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor1), 1);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor1), 2);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor1), 3);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor1), 4);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor1), 5);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor1), 6);
++ key1++;
++ if (auth)
++ CVMX_MT_HSH_STARTSHA((*key1 ^ xor1));
++ else
++ CVMX_MT_HSH_STARTMD5((*key1 ^ xor1));
++
++ CVMX_MF_HSH_IV(inner[0], 0);
++ CVMX_MF_HSH_IV(inner[1], 1);
++ if (auth) {
++ inner[2] = 0;
++ CVMX_MF_HSH_IV(((uint64_t *) inner)[2], 2);
++ }
++
++ memset(hash_key, 0, sizeof(hash_key));
++ memcpy(hash_key, (uint8_t *) key, (auth ? 20 : 16));
++ key1 = (uint64_t *) hash_key;
++ if (auth) {
++ CVMX_MT_HSH_IV(0x67452301EFCDAB89ULL, 0);
++ CVMX_MT_HSH_IV(0x98BADCFE10325476ULL, 1);
++ CVMX_MT_HSH_IV(0xC3D2E1F000000000ULL, 2);
++ } else {
++ CVMX_MT_HSH_IV(0x0123456789ABCDEFULL, 0);
++ CVMX_MT_HSH_IV(0xFEDCBA9876543210ULL, 1);
++ }
++
++ CVMX_MT_HSH_DAT((*key1 ^ xor2), 0);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor2), 1);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor2), 2);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor2), 3);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor2), 4);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor2), 5);
++ key1++;
++ CVMX_MT_HSH_DAT((*key1 ^ xor2), 6);
++ key1++;
++ if (auth)
++ CVMX_MT_HSH_STARTSHA((*key1 ^ xor2));
++ else
++ CVMX_MT_HSH_STARTMD5((*key1 ^ xor2));
++
++ CVMX_MF_HSH_IV(outer[0], 0);
++ CVMX_MF_HSH_IV(outer[1], 1);
++ if (auth) {
++ outer[2] = 0;
++ CVMX_MF_HSH_IV(outer[2], 2);
++ }
++ octeon_crypto_disable(&state, flags);
++ return;
++}
++
++/****************************************************************************/
++/* DES functions */
++
++int
++octo_des_cbc_encrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ uint64_t *data;
++ int data_i, data_l;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x7) || (crypt_off + crypt_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load 3DES Key */
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ if (od->octo_encklen == 24) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ } else if (od->octo_encklen == 8) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++
++ CVMX_MT_3DES_IV(* (uint64_t *) ivp);
++
++ while (crypt_off > 0) {
++ SG_CONSUME(sg, data, data_i, data_l);
++ crypt_off -= 8;
++ }
++
++ while (crypt_len > 0) {
++ CVMX_MT_3DES_ENC_CBC(*data);
++ CVMX_MF_3DES_RESULT(*data);
++ SG_CONSUME(sg, data, data_i, data_l);
++ crypt_len -= 8;
++ }
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++
++int
++octo_des_cbc_decrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ uint64_t *data;
++ int data_i, data_l;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x7) || (crypt_off + crypt_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load 3DES Key */
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ if (od->octo_encklen == 24) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ } else if (od->octo_encklen == 8) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++
++ CVMX_MT_3DES_IV(* (uint64_t *) ivp);
++
++ while (crypt_off > 0) {
++ SG_CONSUME(sg, data, data_i, data_l);
++ crypt_off -= 8;
++ }
++
++ while (crypt_len > 0) {
++ CVMX_MT_3DES_DEC_CBC(*data);
++ CVMX_MF_3DES_RESULT(*data);
++ SG_CONSUME(sg, data, data_i, data_l);
++ crypt_len -= 8;
++ }
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++/****************************************************************************/
++/* AES functions */
++
++int
++octo_aes_cbc_encrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ uint64_t *data, *pdata;
++ int data_i, data_l;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x7) || (crypt_off + crypt_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load AES Key */
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++
++ if (od->octo_encklen == 16) {
++ CVMX_MT_AES_KEY(0x0, 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 24) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 32) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++ CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1);
++
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0);
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1);
++
++ while (crypt_off > 0) {
++ SG_CONSUME(sg, data, data_i, data_l);
++ crypt_off -= 8;
++ }
++
++ while (crypt_len > 0) {
++ pdata = data;
++ CVMX_MT_AES_ENC_CBC0(*data);
++ SG_CONSUME(sg, data, data_i, data_l);
++ CVMX_MT_AES_ENC_CBC1(*data);
++ CVMX_MF_AES_RESULT(*pdata, 0);
++ CVMX_MF_AES_RESULT(*data, 1);
++ SG_CONSUME(sg, data, data_i, data_l);
++ crypt_len -= 16;
++ }
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++
++int
++octo_aes_cbc_decrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ uint64_t *data, *pdata;
++ int data_i, data_l;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x7) || (crypt_off + crypt_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load AES Key */
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++
++ if (od->octo_encklen == 16) {
++ CVMX_MT_AES_KEY(0x0, 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 24) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 32) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++ CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1);
++
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0);
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1);
++
++ while (crypt_off > 0) {
++ SG_CONSUME(sg, data, data_i, data_l);
++ crypt_off -= 8;
++ }
++
++ while (crypt_len > 0) {
++ pdata = data;
++ CVMX_MT_AES_DEC_CBC0(*data);
++ SG_CONSUME(sg, data, data_i, data_l);
++ CVMX_MT_AES_DEC_CBC1(*data);
++ CVMX_MF_AES_RESULT(*pdata, 0);
++ CVMX_MF_AES_RESULT(*data, 1);
++ SG_CONSUME(sg, data, data_i, data_l);
++ crypt_len -= 16;
++ }
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++/****************************************************************************/
++/* MD5 */
++
++int
++octo_null_md5_encrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ register int next = 0;
++ uint64_t *data;
++ uint64_t tmp1, tmp2;
++ int data_i, data_l, alen = auth_len;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 ||
++ (auth_off & 0x7) || (auth_off + auth_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data, data_i, data_l);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* Load MD5 IV */
++ CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
++
++ while (auth_off > 0) {
++ SG_CONSUME(sg, data, data_i, data_l);
++ auth_off -= 8;
++ }
++
++ while (auth_len > 0) {
++ CVM_LOAD_MD5_UNIT(*data, next);
++ auth_len -= 8;
++ SG_CONSUME(sg, data, data_i, data_l);
++ }
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_MD5_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* Finish Inner hash */
++ while (next != 7) {
++ CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next);
++ }
++ CVMX_ES64(tmp1, ((alen + 64) << 3));
++ CVM_LOAD_MD5_UNIT(tmp1, next);
++
++ /* Get the inner hash of HMAC */
++ CVMX_MF_HSH_IV(tmp1, 0);
++ CVMX_MF_HSH_IV(tmp2, 1);
++
++ /* Initialize hash unit */
++ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hmouter[1], 1);
++
++ CVMX_MT_HSH_DAT(tmp1, 0);
++ CVMX_MT_HSH_DAT(tmp2, 1);
++ CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2);
++ CVMX_MT_HSH_DATZ(3);
++ CVMX_MT_HSH_DATZ(4);
++ CVMX_MT_HSH_DATZ(5);
++ CVMX_MT_HSH_DATZ(6);
++ CVMX_ES64(tmp1, ((64 + 16) << 3));
++ CVMX_MT_HSH_STARTMD5(tmp1);
++
++ /* save the HMAC */
++ SG_INIT(sg, data, data_i, data_l);
++ while (icv_off > 0) {
++ SG_CONSUME(sg, data, data_i, data_l);
++ icv_off -= 8;
++ }
++ CVMX_MF_HSH_IV(*data, 0);
++ SG_CONSUME(sg, data, data_i, data_l);
++ CVMX_MF_HSH_IV(tmp1, 1);
++ *(uint32_t *)data = (uint32_t) (tmp1 >> 32);
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++/****************************************************************************/
++/* SHA1 */
++
++int
++octo_null_sha1_encrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ register int next = 0;
++ uint64_t *data;
++ uint64_t tmp1, tmp2, tmp3;
++ int data_i, data_l, alen = auth_len;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 ||
++ (auth_off & 0x7) || (auth_off + auth_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data, data_i, data_l);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* Load SHA1 IV */
++ CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
++ CVMX_MT_HSH_IV(od->octo_hminner[2], 2);
++
++ while (auth_off > 0) {
++ SG_CONSUME(sg, data, data_i, data_l);
++ auth_off -= 8;
++ }
++
++ while (auth_len > 0) {
++ CVM_LOAD_SHA_UNIT(*data, next);
++ auth_len -= 8;
++ SG_CONSUME(sg, data, data_i, data_l);
++ }
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_MD5_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* Finish Inner hash */
++ while (next != 7) {
++ CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next);
++ }
++ CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next);
++
++ /* Get the inner hash of HMAC */
++ CVMX_MF_HSH_IV(tmp1, 0);
++ CVMX_MF_HSH_IV(tmp2, 1);
++ tmp3 = 0;
++ CVMX_MF_HSH_IV(tmp3, 2);
++
++ /* Initialize hash unit */
++ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hmouter[1], 1);
++ CVMX_MT_HSH_IV(od->octo_hmouter[2], 2);
++
++ CVMX_MT_HSH_DAT(tmp1, 0);
++ CVMX_MT_HSH_DAT(tmp2, 1);
++ tmp3 |= 0x0000000080000000;
++ CVMX_MT_HSH_DAT(tmp3, 2);
++ CVMX_MT_HSH_DATZ(3);
++ CVMX_MT_HSH_DATZ(4);
++ CVMX_MT_HSH_DATZ(5);
++ CVMX_MT_HSH_DATZ(6);
++ CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3));
++
++ /* save the HMAC */
++ SG_INIT(sg, data, data_i, data_l);
++ while (icv_off > 0) {
++ SG_CONSUME(sg, data, data_i, data_l);
++ icv_off -= 8;
++ }
++ CVMX_MF_HSH_IV(*data, 0);
++ SG_CONSUME(sg, data, data_i, data_l);
++ CVMX_MF_HSH_IV(tmp1, 1);
++ *(uint32_t *)data = (uint32_t) (tmp1 >> 32);
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++/****************************************************************************/
++/* DES MD5 */
++
++int
++octo_des_cbc_md5_encrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ register int next = 0;
++ union {
++ uint32_t data32[2];
++ uint64_t data64[1];
++ } mydata;
++ uint64_t *data = &mydata.data64[0];
++ uint32_t *data32;
++ uint64_t tmp1, tmp2;
++ int data_i, data_l, alen = auth_len;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) ||
++ (crypt_len & 0x7) ||
++ (auth_len & 0x7) ||
++ (auth_off & 0x3) || (auth_off + auth_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data32, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load 3DES Key */
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ if (od->octo_encklen == 24) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ } else if (od->octo_encklen == 8) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++
++ CVMX_MT_3DES_IV(* (uint64_t *) ivp);
++
++ /* Load MD5 IV */
++ CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
++
++ while (crypt_off > 0 && auth_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ crypt_off -= 4;
++ auth_off -= 4;
++ }
++
++ while (crypt_len > 0 || auth_len > 0) {
++ uint32_t *first = data32;
++ mydata.data32[0] = *first;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata.data32[1] = *data32;
++ if (crypt_off <= 0) {
++ if (crypt_len > 0) {
++ CVMX_MT_3DES_ENC_CBC(*data);
++ CVMX_MF_3DES_RESULT(*data);
++ crypt_len -= 8;
++ }
++ } else
++ crypt_off -= 8;
++ if (auth_off <= 0) {
++ if (auth_len > 0) {
++ CVM_LOAD_MD5_UNIT(*data, next);
++ auth_len -= 8;
++ }
++ } else
++ auth_off -= 8;
++ *first = mydata.data32[0];
++ *data32 = mydata.data32[1];
++ SG_CONSUME(sg, data32, data_i, data_l);
++ }
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_MD5_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* Finish Inner hash */
++ while (next != 7) {
++ CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next);
++ }
++ CVMX_ES64(tmp1, ((alen + 64) << 3));
++ CVM_LOAD_MD5_UNIT(tmp1, next);
++
++ /* Get the inner hash of HMAC */
++ CVMX_MF_HSH_IV(tmp1, 0);
++ CVMX_MF_HSH_IV(tmp2, 1);
++
++ /* Initialize hash unit */
++ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hmouter[1], 1);
++
++ CVMX_MT_HSH_DAT(tmp1, 0);
++ CVMX_MT_HSH_DAT(tmp2, 1);
++ CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2);
++ CVMX_MT_HSH_DATZ(3);
++ CVMX_MT_HSH_DATZ(4);
++ CVMX_MT_HSH_DATZ(5);
++ CVMX_MT_HSH_DATZ(6);
++ CVMX_ES64(tmp1, ((64 + 16) << 3));
++ CVMX_MT_HSH_STARTMD5(tmp1);
++
++ /* save the HMAC */
++ SG_INIT(sg, data32, data_i, data_l);
++ while (icv_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ icv_off -= 4;
++ }
++ CVMX_MF_HSH_IV(tmp1, 0);
++ *data32 = (uint32_t) (tmp1 >> 32);
++ SG_CONSUME(sg, data32, data_i, data_l);
++ *data32 = (uint32_t) tmp1;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVMX_MF_HSH_IV(tmp1, 1);
++ *data32 = (uint32_t) (tmp1 >> 32);
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++int
++octo_des_cbc_md5_decrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ register int next = 0;
++ union {
++ uint32_t data32[2];
++ uint64_t data64[1];
++ } mydata;
++ uint64_t *data = &mydata.data64[0];
++ uint32_t *data32;
++ uint64_t tmp1, tmp2;
++ int data_i, data_l, alen = auth_len;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) ||
++ (crypt_len & 0x7) ||
++ (auth_len & 0x7) ||
++ (auth_off & 0x3) || (auth_off + auth_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data32, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load 3DES Key */
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ if (od->octo_encklen == 24) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ } else if (od->octo_encklen == 8) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++
++ CVMX_MT_3DES_IV(* (uint64_t *) ivp);
++
++ /* Load MD5 IV */
++ CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
++
++ while (crypt_off > 0 && auth_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ crypt_off -= 4;
++ auth_off -= 4;
++ }
++
++ while (crypt_len > 0 || auth_len > 0) {
++ uint32_t *first = data32;
++ mydata.data32[0] = *first;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata.data32[1] = *data32;
++ if (auth_off <= 0) {
++ if (auth_len > 0) {
++ CVM_LOAD_MD5_UNIT(*data, next);
++ auth_len -= 8;
++ }
++ } else
++ auth_off -= 8;
++ if (crypt_off <= 0) {
++ if (crypt_len > 0) {
++ CVMX_MT_3DES_DEC_CBC(*data);
++ CVMX_MF_3DES_RESULT(*data);
++ crypt_len -= 8;
++ }
++ } else
++ crypt_off -= 8;
++ *first = mydata.data32[0];
++ *data32 = mydata.data32[1];
++ SG_CONSUME(sg, data32, data_i, data_l);
++ }
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_MD5_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* Finish Inner hash */
++ while (next != 7) {
++ CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next);
++ }
++ CVMX_ES64(tmp1, ((alen + 64) << 3));
++ CVM_LOAD_MD5_UNIT(tmp1, next);
++
++ /* Get the inner hash of HMAC */
++ CVMX_MF_HSH_IV(tmp1, 0);
++ CVMX_MF_HSH_IV(tmp2, 1);
++
++ /* Initialize hash unit */
++ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hmouter[1], 1);
++
++ CVMX_MT_HSH_DAT(tmp1, 0);
++ CVMX_MT_HSH_DAT(tmp2, 1);
++ CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2);
++ CVMX_MT_HSH_DATZ(3);
++ CVMX_MT_HSH_DATZ(4);
++ CVMX_MT_HSH_DATZ(5);
++ CVMX_MT_HSH_DATZ(6);
++ CVMX_ES64(tmp1, ((64 + 16) << 3));
++ CVMX_MT_HSH_STARTMD5(tmp1);
++
++ /* save the HMAC */
++ SG_INIT(sg, data32, data_i, data_l);
++ while (icv_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ icv_off -= 4;
++ }
++ CVMX_MF_HSH_IV(tmp1, 0);
++ *data32 = (uint32_t) (tmp1 >> 32);
++ SG_CONSUME(sg, data32, data_i, data_l);
++ *data32 = (uint32_t) tmp1;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVMX_MF_HSH_IV(tmp1, 1);
++ *data32 = (uint32_t) (tmp1 >> 32);
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++/****************************************************************************/
++/* DES SHA */
++
++int
++octo_des_cbc_sha1_encrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ register int next = 0;
++ union {
++ uint32_t data32[2];
++ uint64_t data64[1];
++ } mydata;
++ uint64_t *data = &mydata.data64[0];
++ uint32_t *data32;
++ uint64_t tmp1, tmp2, tmp3;
++ int data_i, data_l, alen = auth_len;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) ||
++ (crypt_len & 0x7) ||
++ (auth_len & 0x7) ||
++ (auth_off & 0x3) || (auth_off + auth_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data32, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load 3DES Key */
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ if (od->octo_encklen == 24) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ } else if (od->octo_encklen == 8) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++
++ CVMX_MT_3DES_IV(* (uint64_t *) ivp);
++
++ /* Load SHA1 IV */
++ CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
++ CVMX_MT_HSH_IV(od->octo_hminner[2], 2);
++
++ while (crypt_off > 0 && auth_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ crypt_off -= 4;
++ auth_off -= 4;
++ }
++
++ while (crypt_len > 0 || auth_len > 0) {
++ uint32_t *first = data32;
++ mydata.data32[0] = *first;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata.data32[1] = *data32;
++ if (crypt_off <= 0) {
++ if (crypt_len > 0) {
++ CVMX_MT_3DES_ENC_CBC(*data);
++ CVMX_MF_3DES_RESULT(*data);
++ crypt_len -= 8;
++ }
++ } else
++ crypt_off -= 8;
++ if (auth_off <= 0) {
++ if (auth_len > 0) {
++ CVM_LOAD_SHA_UNIT(*data, next);
++ auth_len -= 8;
++ }
++ } else
++ auth_off -= 8;
++ *first = mydata.data32[0];
++ *data32 = mydata.data32[1];
++ SG_CONSUME(sg, data32, data_i, data_l);
++ }
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_SHA_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* Finish Inner hash */
++ while (next != 7) {
++ CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next);
++ }
++ CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next);
++
++ /* Get the inner hash of HMAC */
++ CVMX_MF_HSH_IV(tmp1, 0);
++ CVMX_MF_HSH_IV(tmp2, 1);
++ tmp3 = 0;
++ CVMX_MF_HSH_IV(tmp3, 2);
++
++ /* Initialize hash unit */
++ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hmouter[1], 1);
++ CVMX_MT_HSH_IV(od->octo_hmouter[2], 2);
++
++ CVMX_MT_HSH_DAT(tmp1, 0);
++ CVMX_MT_HSH_DAT(tmp2, 1);
++ tmp3 |= 0x0000000080000000;
++ CVMX_MT_HSH_DAT(tmp3, 2);
++ CVMX_MT_HSH_DATZ(3);
++ CVMX_MT_HSH_DATZ(4);
++ CVMX_MT_HSH_DATZ(5);
++ CVMX_MT_HSH_DATZ(6);
++ CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3));
++
++ /* save the HMAC */
++ SG_INIT(sg, data32, data_i, data_l);
++ while (icv_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ icv_off -= 4;
++ }
++ CVMX_MF_HSH_IV(tmp1, 0);
++ *data32 = (uint32_t) (tmp1 >> 32);
++ SG_CONSUME(sg, data32, data_i, data_l);
++ *data32 = (uint32_t) tmp1;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVMX_MF_HSH_IV(tmp1, 1);
++ *data32 = (uint32_t) (tmp1 >> 32);
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++int
++octo_des_cbc_sha1_decrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ register int next = 0;
++ union {
++ uint32_t data32[2];
++ uint64_t data64[1];
++ } mydata;
++ uint64_t *data = &mydata.data64[0];
++ uint32_t *data32;
++ uint64_t tmp1, tmp2, tmp3;
++ int data_i, data_l, alen = auth_len;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) ||
++ (crypt_len & 0x7) ||
++ (auth_len & 0x7) ||
++ (auth_off & 0x3) || (auth_off + auth_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data32, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load 3DES Key */
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ if (od->octo_encklen == 24) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ } else if (od->octo_encklen == 8) {
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1);
++ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++
++ CVMX_MT_3DES_IV(* (uint64_t *) ivp);
++
++ /* Load SHA1 IV */
++ CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
++ CVMX_MT_HSH_IV(od->octo_hminner[2], 2);
++
++ while (crypt_off > 0 && auth_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ crypt_off -= 4;
++ auth_off -= 4;
++ }
++
++ while (crypt_len > 0 || auth_len > 0) {
++ uint32_t *first = data32;
++ mydata.data32[0] = *first;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata.data32[1] = *data32;
++ if (auth_off <= 0) {
++ if (auth_len > 0) {
++ CVM_LOAD_SHA_UNIT(*data, next);
++ auth_len -= 8;
++ }
++ } else
++ auth_off -= 8;
++ if (crypt_off <= 0) {
++ if (crypt_len > 0) {
++ CVMX_MT_3DES_DEC_CBC(*data);
++ CVMX_MF_3DES_RESULT(*data);
++ crypt_len -= 8;
++ }
++ } else
++ crypt_off -= 8;
++ *first = mydata.data32[0];
++ *data32 = mydata.data32[1];
++ SG_CONSUME(sg, data32, data_i, data_l);
++ }
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_SHA_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* Finish Inner hash */
++ while (next != 7) {
++ CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next);
++ }
++ CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next);
++
++ /* Get the inner hash of HMAC */
++ CVMX_MF_HSH_IV(tmp1, 0);
++ CVMX_MF_HSH_IV(tmp2, 1);
++ tmp3 = 0;
++ CVMX_MF_HSH_IV(tmp3, 2);
++
++ /* Initialize hash unit */
++ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hmouter[1], 1);
++ CVMX_MT_HSH_IV(od->octo_hmouter[2], 2);
++
++ CVMX_MT_HSH_DAT(tmp1, 0);
++ CVMX_MT_HSH_DAT(tmp2, 1);
++ tmp3 |= 0x0000000080000000;
++ CVMX_MT_HSH_DAT(tmp3, 2);
++ CVMX_MT_HSH_DATZ(3);
++ CVMX_MT_HSH_DATZ(4);
++ CVMX_MT_HSH_DATZ(5);
++ CVMX_MT_HSH_DATZ(6);
++ CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3));
++ /* save the HMAC */
++ SG_INIT(sg, data32, data_i, data_l);
++ while (icv_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ icv_off -= 4;
++ }
++ CVMX_MF_HSH_IV(tmp1, 0);
++ *data32 = (uint32_t) (tmp1 >> 32);
++ SG_CONSUME(sg, data32, data_i, data_l);
++ *data32 = (uint32_t) tmp1;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVMX_MF_HSH_IV(tmp1, 1);
++ *data32 = (uint32_t) (tmp1 >> 32);
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++/****************************************************************************/
++/* AES MD5 */
++
++int
++octo_aes_cbc_md5_encrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ register int next = 0;
++ union {
++ uint32_t data32[2];
++ uint64_t data64[1];
++ } mydata[2];
++ uint64_t *pdata = &mydata[0].data64[0];
++ uint64_t *data = &mydata[1].data64[0];
++ uint32_t *data32;
++ uint64_t tmp1, tmp2;
++ int data_i, data_l, alen = auth_len;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) ||
++ (crypt_len & 0x7) ||
++ (auth_len & 0x7) ||
++ (auth_off & 0x3) || (auth_off + auth_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data32, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load AES Key */
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++
++ if (od->octo_encklen == 16) {
++ CVMX_MT_AES_KEY(0x0, 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 24) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 32) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++ CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1);
++
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0);
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1);
++
++ /* Load MD5 IV */
++ CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
++
++ while (crypt_off > 0 && auth_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ crypt_off -= 4;
++ auth_off -= 4;
++ }
++
++ /* align auth and crypt */
++ while (crypt_off > 0 && auth_len > 0) {
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVM_LOAD_MD5_UNIT(*pdata, next);
++ crypt_off -= 8;
++ auth_len -= 8;
++ }
++
++ while (crypt_len > 0) {
++ uint32_t *pdata32[3];
++
++ pdata32[0] = data32;
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++
++ pdata32[1] = data32;
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++
++ pdata32[2] = data32;
++ mydata[1].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++
++ mydata[1].data32[1] = *data32;
++
++ CVMX_MT_AES_ENC_CBC0(*pdata);
++ CVMX_MT_AES_ENC_CBC1(*data);
++ CVMX_MF_AES_RESULT(*pdata, 0);
++ CVMX_MF_AES_RESULT(*data, 1);
++ crypt_len -= 16;
++
++ if (auth_len > 0) {
++ CVM_LOAD_MD5_UNIT(*pdata, next);
++ auth_len -= 8;
++ }
++ if (auth_len > 0) {
++ CVM_LOAD_MD5_UNIT(*data, next);
++ auth_len -= 8;
++ }
++
++ *pdata32[0] = mydata[0].data32[0];
++ *pdata32[1] = mydata[0].data32[1];
++ *pdata32[2] = mydata[1].data32[0];
++ *data32 = mydata[1].data32[1];
++
++ SG_CONSUME(sg, data32, data_i, data_l);
++ }
++
++ /* finish any left over hashing */
++ while (auth_len > 0) {
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVM_LOAD_MD5_UNIT(*pdata, next);
++ auth_len -= 8;
++ }
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_MD5_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* Finish Inner hash */
++ while (next != 7) {
++ CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next);
++ }
++ CVMX_ES64(tmp1, ((alen + 64) << 3));
++ CVM_LOAD_MD5_UNIT(tmp1, next);
++
++ /* Get the inner hash of HMAC */
++ CVMX_MF_HSH_IV(tmp1, 0);
++ CVMX_MF_HSH_IV(tmp2, 1);
++
++ /* Initialize hash unit */
++ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hmouter[1], 1);
++
++ CVMX_MT_HSH_DAT(tmp1, 0);
++ CVMX_MT_HSH_DAT(tmp2, 1);
++ CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2);
++ CVMX_MT_HSH_DATZ(3);
++ CVMX_MT_HSH_DATZ(4);
++ CVMX_MT_HSH_DATZ(5);
++ CVMX_MT_HSH_DATZ(6);
++ CVMX_ES64(tmp1, ((64 + 16) << 3));
++ CVMX_MT_HSH_STARTMD5(tmp1);
++
++ /* save the HMAC */
++ SG_INIT(sg, data32, data_i, data_l);
++ while (icv_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ icv_off -= 4;
++ }
++ CVMX_MF_HSH_IV(tmp1, 0);
++ *data32 = (uint32_t) (tmp1 >> 32);
++ SG_CONSUME(sg, data32, data_i, data_l);
++ *data32 = (uint32_t) tmp1;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVMX_MF_HSH_IV(tmp1, 1);
++ *data32 = (uint32_t) (tmp1 >> 32);
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++int
++octo_aes_cbc_md5_decrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ register int next = 0;
++ union {
++ uint32_t data32[2];
++ uint64_t data64[1];
++ } mydata[2];
++ uint64_t *pdata = &mydata[0].data64[0];
++ uint64_t *data = &mydata[1].data64[0];
++ uint32_t *data32;
++ uint64_t tmp1, tmp2;
++ int data_i, data_l, alen = auth_len;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) ||
++ (crypt_len & 0x7) ||
++ (auth_len & 0x7) ||
++ (auth_off & 0x3) || (auth_off + auth_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data32, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load AES Key */
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++
++ if (od->octo_encklen == 16) {
++ CVMX_MT_AES_KEY(0x0, 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 24) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 32) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++ CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1);
++
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0);
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1);
++
++ /* Load MD5 IV */
++ CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
++
++ while (crypt_off > 0 && auth_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ crypt_off -= 4;
++ auth_off -= 4;
++ }
++
++ /* align auth and crypt */
++ while (crypt_off > 0 && auth_len > 0) {
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVM_LOAD_MD5_UNIT(*pdata, next);
++ crypt_off -= 8;
++ auth_len -= 8;
++ }
++
++ while (crypt_len > 0) {
++ uint32_t *pdata32[3];
++
++ pdata32[0] = data32;
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ pdata32[1] = data32;
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ pdata32[2] = data32;
++ mydata[1].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata[1].data32[1] = *data32;
++
++ if (auth_len > 0) {
++ CVM_LOAD_MD5_UNIT(*pdata, next);
++ auth_len -= 8;
++ }
++
++ if (auth_len > 0) {
++ CVM_LOAD_MD5_UNIT(*data, next);
++ auth_len -= 8;
++ }
++
++ CVMX_MT_AES_DEC_CBC0(*pdata);
++ CVMX_MT_AES_DEC_CBC1(*data);
++ CVMX_MF_AES_RESULT(*pdata, 0);
++ CVMX_MF_AES_RESULT(*data, 1);
++ crypt_len -= 16;
++
++ *pdata32[0] = mydata[0].data32[0];
++ *pdata32[1] = mydata[0].data32[1];
++ *pdata32[2] = mydata[1].data32[0];
++ *data32 = mydata[1].data32[1];
++
++ SG_CONSUME(sg, data32, data_i, data_l);
++ }
++
++ /* finish left over hash if any */
++ while (auth_len > 0) {
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVM_LOAD_MD5_UNIT(*pdata, next);
++ auth_len -= 8;
++ }
++
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_MD5_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* Finish Inner hash */
++ while (next != 7) {
++ CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next);
++ }
++ CVMX_ES64(tmp1, ((alen + 64) << 3));
++ CVM_LOAD_MD5_UNIT(tmp1, next);
++
++ /* Get the inner hash of HMAC */
++ CVMX_MF_HSH_IV(tmp1, 0);
++ CVMX_MF_HSH_IV(tmp2, 1);
++
++ /* Initialize hash unit */
++ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hmouter[1], 1);
++
++ CVMX_MT_HSH_DAT(tmp1, 0);
++ CVMX_MT_HSH_DAT(tmp2, 1);
++ CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2);
++ CVMX_MT_HSH_DATZ(3);
++ CVMX_MT_HSH_DATZ(4);
++ CVMX_MT_HSH_DATZ(5);
++ CVMX_MT_HSH_DATZ(6);
++ CVMX_ES64(tmp1, ((64 + 16) << 3));
++ CVMX_MT_HSH_STARTMD5(tmp1);
++
++ /* save the HMAC */
++ SG_INIT(sg, data32, data_i, data_l);
++ while (icv_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ icv_off -= 4;
++ }
++ CVMX_MF_HSH_IV(tmp1, 0);
++ *data32 = (uint32_t) (tmp1 >> 32);
++ SG_CONSUME(sg, data32, data_i, data_l);
++ *data32 = (uint32_t) tmp1;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVMX_MF_HSH_IV(tmp1, 1);
++ *data32 = (uint32_t) (tmp1 >> 32);
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++/****************************************************************************/
++/* AES SHA1 */
++
++int
++octo_aes_cbc_sha1_encrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ register int next = 0;
++ union {
++ uint32_t data32[2];
++ uint64_t data64[1];
++ } mydata[2];
++ uint64_t *pdata = &mydata[0].data64[0];
++ uint64_t *data = &mydata[1].data64[0];
++ uint32_t *data32;
++ uint64_t tmp1, tmp2, tmp3;
++ int data_i, data_l, alen = auth_len;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s(a_off=%d a_len=%d c_off=%d c_len=%d icv_off=%d)\n",
++ __FUNCTION__, auth_off, auth_len, crypt_off, crypt_len, icv_off);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) ||
++ (crypt_len & 0x7) ||
++ (auth_len & 0x7) ||
++ (auth_off & 0x3) || (auth_off + auth_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data32, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load AES Key */
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++
++ if (od->octo_encklen == 16) {
++ CVMX_MT_AES_KEY(0x0, 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 24) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 32) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++ CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1);
++
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0);
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1);
++
++ /* Load SHA IV */
++ CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
++ CVMX_MT_HSH_IV(od->octo_hminner[2], 2);
++
++ while (crypt_off > 0 && auth_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ crypt_off -= 4;
++ auth_off -= 4;
++ }
++
++ /* align auth and crypt */
++ while (crypt_off > 0 && auth_len > 0) {
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVM_LOAD_SHA_UNIT(*pdata, next);
++ crypt_off -= 8;
++ auth_len -= 8;
++ }
++
++ while (crypt_len > 0) {
++ uint32_t *pdata32[3];
++
++ pdata32[0] = data32;
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ pdata32[1] = data32;
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ pdata32[2] = data32;
++ mydata[1].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata[1].data32[1] = *data32;
++
++ CVMX_MT_AES_ENC_CBC0(*pdata);
++ CVMX_MT_AES_ENC_CBC1(*data);
++ CVMX_MF_AES_RESULT(*pdata, 0);
++ CVMX_MF_AES_RESULT(*data, 1);
++ crypt_len -= 16;
++
++ if (auth_len > 0) {
++ CVM_LOAD_SHA_UNIT(*pdata, next);
++ auth_len -= 8;
++ }
++ if (auth_len > 0) {
++ CVM_LOAD_SHA_UNIT(*data, next);
++ auth_len -= 8;
++ }
++
++ *pdata32[0] = mydata[0].data32[0];
++ *pdata32[1] = mydata[0].data32[1];
++ *pdata32[2] = mydata[1].data32[0];
++ *data32 = mydata[1].data32[1];
++
++ SG_CONSUME(sg, data32, data_i, data_l);
++ }
++
++ /* finish and hashing */
++ while (auth_len > 0) {
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVM_LOAD_SHA_UNIT(*pdata, next);
++ auth_len -= 8;
++ }
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_SHA_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* Finish Inner hash */
++ while (next != 7) {
++ CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next);
++ }
++ CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next);
++
++ /* Get the inner hash of HMAC */
++ CVMX_MF_HSH_IV(tmp1, 0);
++ CVMX_MF_HSH_IV(tmp2, 1);
++ tmp3 = 0;
++ CVMX_MF_HSH_IV(tmp3, 2);
++
++ /* Initialize hash unit */
++ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hmouter[1], 1);
++ CVMX_MT_HSH_IV(od->octo_hmouter[2], 2);
++
++ CVMX_MT_HSH_DAT(tmp1, 0);
++ CVMX_MT_HSH_DAT(tmp2, 1);
++ tmp3 |= 0x0000000080000000;
++ CVMX_MT_HSH_DAT(tmp3, 2);
++ CVMX_MT_HSH_DATZ(3);
++ CVMX_MT_HSH_DATZ(4);
++ CVMX_MT_HSH_DATZ(5);
++ CVMX_MT_HSH_DATZ(6);
++ CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3));
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_MD5_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* save the HMAC */
++ SG_INIT(sg, data32, data_i, data_l);
++ while (icv_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ icv_off -= 4;
++ }
++ CVMX_MF_HSH_IV(tmp1, 0);
++ *data32 = (uint32_t) (tmp1 >> 32);
++ SG_CONSUME(sg, data32, data_i, data_l);
++ *data32 = (uint32_t) tmp1;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVMX_MF_HSH_IV(tmp1, 1);
++ *data32 = (uint32_t) (tmp1 >> 32);
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++int
++octo_aes_cbc_sha1_decrypt(
++ struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp)
++{
++ register int next = 0;
++ union {
++ uint32_t data32[2];
++ uint64_t data64[1];
++ } mydata[2];
++ uint64_t *pdata = &mydata[0].data64[0];
++ uint64_t *data = &mydata[1].data64[0];
++ uint32_t *data32;
++ uint64_t tmp1, tmp2, tmp3;
++ int data_i, data_l, alen = auth_len;
++ struct octeon_cop2_state state;
++ unsigned long flags;
++
++ dprintk("%s(a_off=%d a_len=%d c_off=%d c_len=%d icv_off=%d)\n",
++ __FUNCTION__, auth_off, auth_len, crypt_off, crypt_len, icv_off);
++
++ if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL ||
++ (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) ||
++ (crypt_len & 0x7) ||
++ (auth_len & 0x7) ||
++ (auth_off & 0x3) || (auth_off + auth_len > sg_len))) {
++ dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d "
++ "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d "
++ "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ return -EINVAL;
++ }
++
++ SG_INIT(sg, data32, data_i, data_l);
++
++ CVMX_PREFETCH0(ivp);
++ CVMX_PREFETCH0(od->octo_enckey);
++
++ flags = octeon_crypto_enable(&state);
++
++ /* load AES Key */
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1);
++
++ if (od->octo_encklen == 16) {
++ CVMX_MT_AES_KEY(0x0, 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 24) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(0x0, 3);
++ } else if (od->octo_encklen == 32) {
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2);
++ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3);
++ } else {
++ octeon_crypto_disable(&state, flags);
++ dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen);
++ return -EINVAL;
++ }
++ CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1);
++
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0);
++ CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1);
++
++ /* Load SHA1 IV */
++ CVMX_MT_HSH_IV(od->octo_hminner[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hminner[1], 1);
++ CVMX_MT_HSH_IV(od->octo_hminner[2], 2);
++
++ while (crypt_off > 0 && auth_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ crypt_off -= 4;
++ auth_off -= 4;
++ }
++
++ /* align auth and crypt */
++ while (crypt_off > 0 && auth_len > 0) {
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVM_LOAD_SHA_UNIT(*pdata, next);
++ crypt_off -= 8;
++ auth_len -= 8;
++ }
++
++ while (crypt_len > 0) {
++ uint32_t *pdata32[3];
++
++ pdata32[0] = data32;
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ pdata32[1] = data32;
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ pdata32[2] = data32;
++ mydata[1].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata[1].data32[1] = *data32;
++
++ if (auth_len > 0) {
++ CVM_LOAD_SHA_UNIT(*pdata, next);
++ auth_len -= 8;
++ }
++ if (auth_len > 0) {
++ CVM_LOAD_SHA_UNIT(*data, next);
++ auth_len -= 8;
++ }
++
++ CVMX_MT_AES_DEC_CBC0(*pdata);
++ CVMX_MT_AES_DEC_CBC1(*data);
++ CVMX_MF_AES_RESULT(*pdata, 0);
++ CVMX_MF_AES_RESULT(*data, 1);
++ crypt_len -= 16;
++
++ *pdata32[0] = mydata[0].data32[0];
++ *pdata32[1] = mydata[0].data32[1];
++ *pdata32[2] = mydata[1].data32[0];
++ *data32 = mydata[1].data32[1];
++
++ SG_CONSUME(sg, data32, data_i, data_l);
++ }
++
++ /* finish and leftover hashing */
++ while (auth_len > 0) {
++ mydata[0].data32[0] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ mydata[0].data32[1] = *data32;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVM_LOAD_SHA_UNIT(*pdata, next);
++ auth_len -= 8;
++ }
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_SHA_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* Finish Inner hash */
++ while (next != 7) {
++ CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next);
++ }
++ CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next);
++
++ /* Get the inner hash of HMAC */
++ CVMX_MF_HSH_IV(tmp1, 0);
++ CVMX_MF_HSH_IV(tmp2, 1);
++ tmp3 = 0;
++ CVMX_MF_HSH_IV(tmp3, 2);
++
++ /* Initialize hash unit */
++ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0);
++ CVMX_MT_HSH_IV(od->octo_hmouter[1], 1);
++ CVMX_MT_HSH_IV(od->octo_hmouter[2], 2);
++
++ CVMX_MT_HSH_DAT(tmp1, 0);
++ CVMX_MT_HSH_DAT(tmp2, 1);
++ tmp3 |= 0x0000000080000000;
++ CVMX_MT_HSH_DAT(tmp3, 2);
++ CVMX_MT_HSH_DATZ(3);
++ CVMX_MT_HSH_DATZ(4);
++ CVMX_MT_HSH_DATZ(5);
++ CVMX_MT_HSH_DATZ(6);
++ CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3));
++
++ /* finish the hash */
++ CVMX_PREFETCH0(od->octo_hmouter);
++#if 0
++ if (unlikely(inplen)) {
++ uint64_t tmp = 0;
++ uint8_t *p = (uint8_t *) & tmp;
++ p[inplen] = 0x80;
++ do {
++ inplen--;
++ p[inplen] = ((uint8_t *) data)[inplen];
++ } while (inplen);
++ CVM_LOAD_MD5_UNIT(tmp, next);
++ } else {
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++ }
++#else
++ CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next);
++#endif
++
++ /* save the HMAC */
++ SG_INIT(sg, data32, data_i, data_l);
++ while (icv_off > 0) {
++ SG_CONSUME(sg, data32, data_i, data_l);
++ icv_off -= 4;
++ }
++ CVMX_MF_HSH_IV(tmp1, 0);
++ *data32 = (uint32_t) (tmp1 >> 32);
++ SG_CONSUME(sg, data32, data_i, data_l);
++ *data32 = (uint32_t) tmp1;
++ SG_CONSUME(sg, data32, data_i, data_l);
++ CVMX_MF_HSH_IV(tmp1, 1);
++ *data32 = (uint32_t) (tmp1 >> 32);
++
++ octeon_crypto_disable(&state, flags);
++ return 0;
++}
++
++/****************************************************************************/
+diff -Nur linux-2.6.36.orig/crypto/ocf/cryptocteon/cryptocteon.c linux-2.6.36/crypto/ocf/cryptocteon/cryptocteon.c
+--- linux-2.6.36.orig/crypto/ocf/cryptocteon/cryptocteon.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/cryptocteon/cryptocteon.c 2010-11-09 20:28:04.371247488 +0100
+@@ -0,0 +1,574 @@
++/*
++ * Octeon Crypto for OCF
++ *
++ * Written by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2009-2010 David McCullough
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ * 1. distributions of this source code include the above copyright
++ * notice, this list of conditions and the following disclaimer;
++ *
++ * 2. distributions in binary form include the above copyright
++ * notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other associated materials;
++ *
++ * 3. the copyright holder's name is not used to endorse products
++ * built using this software without specific written permission.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ * ---------------------------------------------------------------------------
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/crypto.h>
++#include <linux/mm.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++#include <linux/scatterlist.h>
++
++#include <cryptodev.h>
++#include <uio.h>
++
++struct {
++ softc_device_decl sc_dev;
++} octo_softc;
++
++#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
++
++struct octo_sess {
++ int octo_encalg;
++ #define MAX_CIPHER_KEYLEN 64
++ char octo_enckey[MAX_CIPHER_KEYLEN];
++ int octo_encklen;
++
++ int octo_macalg;
++ #define MAX_HASH_KEYLEN 64
++ char octo_mackey[MAX_HASH_KEYLEN];
++ int octo_macklen;
++ int octo_mackey_set;
++
++ int octo_mlen;
++ int octo_ivsize;
++
++#if 0
++ int (*octo_decrypt)(struct scatterlist *sg, int sg_len,
++ uint8_t *key, int key_len, uint8_t * iv,
++ uint64_t *hminner, uint64_t *hmouter);
++
++ int (*octo_encrypt)(struct scatterlist *sg, int sg_len,
++ uint8_t *key, int key_len, uint8_t * iv,
++ uint64_t *hminner, uint64_t *hmouter);
++#else
++ int (*octo_encrypt)(struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp);
++ int (*octo_decrypt)(struct octo_sess *od,
++ struct scatterlist *sg, int sg_len,
++ int auth_off, int auth_len,
++ int crypt_off, int crypt_len,
++ int icv_off, uint8_t *ivp);
++#endif
++
++ uint64_t octo_hminner[3];
++ uint64_t octo_hmouter[3];
++};
++
++int32_t octo_id = -1;
++module_param(octo_id, int, 0444);
++MODULE_PARM_DESC(octo_id, "Read-Only OCF ID for cryptocteon driver");
++
++static struct octo_sess **octo_sessions = NULL;
++static u_int32_t octo_sesnum = 0;
++
++static int octo_process(device_t, struct cryptop *, int);
++static int octo_newsession(device_t, u_int32_t *, struct cryptoini *);
++static int octo_freesession(device_t, u_int64_t);
++
++static device_method_t octo_methods = {
++ /* crypto device methods */
++ DEVMETHOD(cryptodev_newsession, octo_newsession),
++ DEVMETHOD(cryptodev_freesession,octo_freesession),
++ DEVMETHOD(cryptodev_process, octo_process),
++};
++
++#define debug octo_debug
++int octo_debug = 0;
++module_param(octo_debug, int, 0644);
++MODULE_PARM_DESC(octo_debug, "Enable debug");
++
++
++#include "cavium_crypto.c"
++
++
++/*
++ * Generate a new octo session. We artifically limit it to a single
++ * hash/cipher or hash-cipher combo just to make it easier, most callers
++ * do not expect more than this anyway.
++ */
++static int
++octo_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
++{
++ struct cryptoini *c, *encini = NULL, *macini = NULL;
++ struct octo_sess **ocd;
++ int i;
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (sid == NULL || cri == NULL) {
++ dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ /*
++ * To keep it simple, we only handle hash, cipher or hash/cipher in a
++ * session, you cannot currently do multiple ciphers/hashes in one
++ * session even though it would be possibel to code this driver to
++ * handle it.
++ */
++ for (i = 0, c = cri; c && i < 2; i++) {
++ if (c->cri_alg == CRYPTO_MD5_HMAC ||
++ c->cri_alg == CRYPTO_SHA1_HMAC ||
++ c->cri_alg == CRYPTO_NULL_HMAC) {
++ if (macini) {
++ break;
++ }
++ macini = c;
++ }
++ if (c->cri_alg == CRYPTO_DES_CBC ||
++ c->cri_alg == CRYPTO_3DES_CBC ||
++ c->cri_alg == CRYPTO_AES_CBC ||
++ c->cri_alg == CRYPTO_NULL_CBC) {
++ if (encini) {
++ break;
++ }
++ encini = c;
++ }
++ c = c->cri_next;
++ }
++ if (!macini && !encini) {
++ dprintk("%s,%d - EINVAL bad cipher/hash or combination\n",
++ __FILE__, __LINE__);
++ return EINVAL;
++ }
++ if (c) {
++ dprintk("%s,%d - EINVAL cannot handle chained cipher/hash combos\n",
++ __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ /*
++ * So we have something we can do, lets setup the session
++ */
++
++ if (octo_sessions) {
++ for (i = 1; i < octo_sesnum; i++)
++ if (octo_sessions[i] == NULL)
++ break;
++ } else
++ i = 1; /* NB: to silence compiler warning */
++
++ if (octo_sessions == NULL || i == octo_sesnum) {
++ if (octo_sessions == NULL) {
++ i = 1; /* We leave octo_sessions[0] empty */
++ octo_sesnum = CRYPTO_SW_SESSIONS;
++ } else
++ octo_sesnum *= 2;
++
++ ocd = kmalloc(octo_sesnum * sizeof(struct octo_sess *), SLAB_ATOMIC);
++ if (ocd == NULL) {
++ /* Reset session number */
++ if (octo_sesnum == CRYPTO_SW_SESSIONS)
++ octo_sesnum = 0;
++ else
++ octo_sesnum /= 2;
++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++ return ENOBUFS;
++ }
++ memset(ocd, 0, octo_sesnum * sizeof(struct octo_sess *));
++
++ /* Copy existing sessions */
++ if (octo_sessions) {
++ memcpy(ocd, octo_sessions,
++ (octo_sesnum / 2) * sizeof(struct octo_sess *));
++ kfree(octo_sessions);
++ }
++
++ octo_sessions = ocd;
++ }
++
++ ocd = &octo_sessions[i];
++ *sid = i;
++
++
++ *ocd = (struct octo_sess *) kmalloc(sizeof(struct octo_sess), SLAB_ATOMIC);
++ if (*ocd == NULL) {
++ octo_freesession(NULL, i);
++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++ return ENOBUFS;
++ }
++ memset(*ocd, 0, sizeof(struct octo_sess));
++
++ if (encini && encini->cri_key) {
++ (*ocd)->octo_encklen = (encini->cri_klen + 7) / 8;
++ memcpy((*ocd)->octo_enckey, encini->cri_key, (*ocd)->octo_encklen);
++ }
++
++ if (macini && macini->cri_key) {
++ (*ocd)->octo_macklen = (macini->cri_klen + 7) / 8;
++ memcpy((*ocd)->octo_mackey, macini->cri_key, (*ocd)->octo_macklen);
++ }
++
++ (*ocd)->octo_mlen = 0;
++ if (encini && encini->cri_mlen)
++ (*ocd)->octo_mlen = encini->cri_mlen;
++ else if (macini && macini->cri_mlen)
++ (*ocd)->octo_mlen = macini->cri_mlen;
++ else
++ (*ocd)->octo_mlen = 12;
++
++ /*
++ * point c at the enc if it exists, otherwise the mac
++ */
++ c = encini ? encini : macini;
++
++ switch (c->cri_alg) {
++ case CRYPTO_DES_CBC:
++ case CRYPTO_3DES_CBC:
++ (*ocd)->octo_ivsize = 8;
++ switch (macini ? macini->cri_alg : -1) {
++ case CRYPTO_MD5_HMAC:
++ (*ocd)->octo_encrypt = octo_des_cbc_md5_encrypt;
++ (*ocd)->octo_decrypt = octo_des_cbc_md5_decrypt;
++ octo_calc_hash(0, macini->cri_key, (*ocd)->octo_hminner,
++ (*ocd)->octo_hmouter);
++ break;
++ case CRYPTO_SHA1_HMAC:
++ (*ocd)->octo_encrypt = octo_des_cbc_sha1_encrypt;
++ (*ocd)->octo_decrypt = octo_des_cbc_sha1_encrypt;
++ octo_calc_hash(1, macini->cri_key, (*ocd)->octo_hminner,
++ (*ocd)->octo_hmouter);
++ break;
++ case -1:
++ (*ocd)->octo_encrypt = octo_des_cbc_encrypt;
++ (*ocd)->octo_decrypt = octo_des_cbc_decrypt;
++ break;
++ default:
++ octo_freesession(NULL, i);
++ dprintk("%s,%d: EINVALn", __FILE__, __LINE__);
++ return EINVAL;
++ }
++ break;
++ case CRYPTO_AES_CBC:
++ (*ocd)->octo_ivsize = 16;
++ switch (macini ? macini->cri_alg : -1) {
++ case CRYPTO_MD5_HMAC:
++ (*ocd)->octo_encrypt = octo_aes_cbc_md5_encrypt;
++ (*ocd)->octo_decrypt = octo_aes_cbc_md5_decrypt;
++ octo_calc_hash(0, macini->cri_key, (*ocd)->octo_hminner,
++ (*ocd)->octo_hmouter);
++ break;
++ case CRYPTO_SHA1_HMAC:
++ (*ocd)->octo_encrypt = octo_aes_cbc_sha1_encrypt;
++ (*ocd)->octo_decrypt = octo_aes_cbc_sha1_decrypt;
++ octo_calc_hash(1, macini->cri_key, (*ocd)->octo_hminner,
++ (*ocd)->octo_hmouter);
++ break;
++ case -1:
++ (*ocd)->octo_encrypt = octo_aes_cbc_encrypt;
++ (*ocd)->octo_decrypt = octo_aes_cbc_decrypt;
++ break;
++ default:
++ octo_freesession(NULL, i);
++ dprintk("%s,%d: EINVALn", __FILE__, __LINE__);
++ return EINVAL;
++ }
++ break;
++ case CRYPTO_MD5_HMAC:
++ (*ocd)->octo_encrypt = octo_null_md5_encrypt;
++ (*ocd)->octo_decrypt = octo_null_md5_encrypt;
++ octo_calc_hash(0, macini->cri_key, (*ocd)->octo_hminner,
++ (*ocd)->octo_hmouter);
++ break;
++ case CRYPTO_SHA1_HMAC:
++ (*ocd)->octo_encrypt = octo_null_sha1_encrypt;
++ (*ocd)->octo_decrypt = octo_null_sha1_encrypt;
++ octo_calc_hash(1, macini->cri_key, (*ocd)->octo_hminner,
++ (*ocd)->octo_hmouter);
++ break;
++ default:
++ octo_freesession(NULL, i);
++ dprintk("%s,%d: EINVALn", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ (*ocd)->octo_encalg = encini ? encini->cri_alg : -1;
++ (*ocd)->octo_macalg = macini ? macini->cri_alg : -1;
++
++ return 0;
++}
++
++/*
++ * Free a session.
++ */
++static int
++octo_freesession(device_t dev, u_int64_t tid)
++{
++ u_int32_t sid = CRYPTO_SESID2LID(tid);
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (sid > octo_sesnum || octo_sessions == NULL ||
++ octo_sessions[sid] == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return(EINVAL);
++ }
++
++ /* Silently accept and return */
++ if (sid == 0)
++ return(0);
++
++ if (octo_sessions[sid])
++ kfree(octo_sessions[sid]);
++ octo_sessions[sid] = NULL;
++ return 0;
++}
++
++/*
++ * Process a request.
++ */
++static int
++octo_process(device_t dev, struct cryptop *crp, int hint)
++{
++ struct cryptodesc *crd;
++ struct octo_sess *od;
++ u_int32_t lid;
++#define SCATTERLIST_MAX 16
++ struct scatterlist sg[SCATTERLIST_MAX];
++ int sg_num, sg_len;
++ struct sk_buff *skb = NULL;
++ struct uio *uiop = NULL;
++ struct cryptodesc *enccrd = NULL, *maccrd = NULL;
++ unsigned char *ivp = NULL;
++ unsigned char iv_data[HASH_MAX_LEN];
++ int auth_off = 0, auth_len = 0, crypt_off = 0, crypt_len = 0, icv_off = 0;
++
++ dprintk("%s()\n", __FUNCTION__);
++ /* Sanity check */
++ if (crp == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ crp->crp_etype = 0;
++
++ if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ crp->crp_etype = EINVAL;
++ goto done;
++ }
++
++ lid = crp->crp_sid & 0xffffffff;
++ if (lid >= octo_sesnum || lid == 0 || octo_sessions == NULL ||
++ octo_sessions[lid] == NULL) {
++ crp->crp_etype = ENOENT;
++ dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);
++ goto done;
++ }
++ od = octo_sessions[lid];
++
++ /*
++ * do some error checking outside of the loop for SKB and IOV processing
++ * this leaves us with valid skb or uiop pointers for later
++ */
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ skb = (struct sk_buff *) crp->crp_buf;
++ if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) {
++ printk("%s,%d: %d nr_frags > SCATTERLIST_MAX", __FILE__, __LINE__,
++ skb_shinfo(skb)->nr_frags);
++ goto done;
++ }
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ uiop = (struct uio *) crp->crp_buf;
++ if (uiop->uio_iovcnt > SCATTERLIST_MAX) {
++ printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX", __FILE__, __LINE__,
++ uiop->uio_iovcnt);
++ goto done;
++ }
++ }
++
++ /* point our enccrd and maccrd appropriately */
++ crd = crp->crp_desc;
++ if (crd->crd_alg == od->octo_encalg) enccrd = crd;
++ if (crd->crd_alg == od->octo_macalg) maccrd = crd;
++ crd = crd->crd_next;
++ if (crd) {
++ if (crd->crd_alg == od->octo_encalg) enccrd = crd;
++ if (crd->crd_alg == od->octo_macalg) maccrd = crd;
++ crd = crd->crd_next;
++ }
++ if (crd) {
++ crp->crp_etype = EINVAL;
++ dprintk("%s,%d: ENOENT - descriptors do not match session\n",
++ __FILE__, __LINE__);
++ goto done;
++ }
++
++ if (enccrd) {
++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) {
++ ivp = enccrd->crd_iv;
++ } else {
++ ivp = iv_data;
++ crypto_copydata(crp->crp_flags, crp->crp_buf,
++ enccrd->crd_inject, od->octo_ivsize, (caddr_t) ivp);
++ }
++
++ if (maccrd) {
++ auth_off = maccrd->crd_skip;
++ auth_len = maccrd->crd_len;
++ icv_off = maccrd->crd_inject;
++ }
++
++ crypt_off = enccrd->crd_skip;
++ crypt_len = enccrd->crd_len;
++ } else { /* if (maccrd) */
++ auth_off = maccrd->crd_skip;
++ auth_len = maccrd->crd_len;
++ icv_off = maccrd->crd_inject;
++ }
++
++
++ /*
++ * setup the SG list to cover the buffer
++ */
++ memset(sg, 0, sizeof(sg));
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ int i, len;
++
++ sg_num = 0;
++ sg_len = 0;
++
++ len = skb_headlen(skb);
++ sg_set_page(&sg[sg_num], virt_to_page(skb->data), len,
++ offset_in_page(skb->data));
++ sg_len += len;
++ sg_num++;
++
++ for (i = 0; i < skb_shinfo(skb)->nr_frags && sg_num < SCATTERLIST_MAX;
++ i++) {
++ len = skb_shinfo(skb)->frags[i].size;
++ sg_set_page(&sg[sg_num], skb_shinfo(skb)->frags[i].page,
++ len, skb_shinfo(skb)->frags[i].page_offset);
++ sg_len += len;
++ sg_num++;
++ }
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ int len;
++
++ sg_len = 0;
++ for (sg_num = 0; sg_len < crp->crp_ilen &&
++ sg_num < uiop->uio_iovcnt &&
++ sg_num < SCATTERLIST_MAX; sg_num++) {
++ len = uiop->uio_iov[sg_num].iov_len;
++ sg_set_page(&sg[sg_num],
++ virt_to_page(uiop->uio_iov[sg_num].iov_base), len,
++ offset_in_page(uiop->uio_iov[sg_num].iov_base));
++ sg_len += len;
++ }
++ } else {
++ sg_len = crp->crp_ilen;
++ sg_set_page(&sg[0], virt_to_page(crp->crp_buf), sg_len,
++ offset_in_page(crp->crp_buf));
++ sg_num = 1;
++ }
++
++
++ /*
++ * setup a new explicit key
++ */
++ if (enccrd) {
++ if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
++ od->octo_encklen = (enccrd->crd_klen + 7) / 8;
++ memcpy(od->octo_enckey, enccrd->crd_key, od->octo_encklen);
++ }
++ }
++ if (maccrd) {
++ if (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
++ od->octo_macklen = (maccrd->crd_klen + 7) / 8;
++ memcpy(od->octo_mackey, maccrd->crd_key, od->octo_macklen);
++ od->octo_mackey_set = 0;
++ }
++ if (!od->octo_mackey_set) {
++ octo_calc_hash(maccrd->crd_alg == CRYPTO_MD5_HMAC ? 0 : 1,
++ maccrd->crd_key, od->octo_hminner, od->octo_hmouter);
++ od->octo_mackey_set = 1;
++ }
++ }
++
++
++ if (!enccrd || (enccrd->crd_flags & CRD_F_ENCRYPT))
++ (*od->octo_encrypt)(od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++ else
++ (*od->octo_decrypt)(od, sg, sg_len,
++ auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
++
++done:
++ crypto_done(crp);
++ return 0;
++}
++
++static int
++cryptocteon_init(void)
++{
++ dprintk("%s(%p)\n", __FUNCTION__, cryptocteon_init);
++
++ softc_device_init(&octo_softc, "cryptocteon", 0, octo_methods);
++
++ octo_id = crypto_get_driverid(softc_get_device(&octo_softc),
++ CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SYNC);
++ if (octo_id < 0) {
++ printk("Cryptocteon device cannot initialize!");
++ return -ENODEV;
++ }
++
++ crypto_register(octo_id, CRYPTO_MD5_HMAC, 0,0);
++ crypto_register(octo_id, CRYPTO_SHA1_HMAC, 0,0);
++ //crypto_register(octo_id, CRYPTO_MD5, 0,0);
++ //crypto_register(octo_id, CRYPTO_SHA1, 0,0);
++ crypto_register(octo_id, CRYPTO_DES_CBC, 0,0);
++ crypto_register(octo_id, CRYPTO_3DES_CBC, 0,0);
++ crypto_register(octo_id, CRYPTO_AES_CBC, 0,0);
++
++ return(0);
++}
++
++static void
++cryptocteon_exit(void)
++{
++ dprintk("%s()\n", __FUNCTION__);
++ crypto_unregister_all(octo_id);
++ octo_id = -1;
++}
++
++module_init(cryptocteon_init);
++module_exit(cryptocteon_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
++MODULE_DESCRIPTION("Cryptocteon (OCF module for Cavium OCTEON crypto)");
+diff -Nur linux-2.6.36.orig/crypto/ocf/cryptocteon/Makefile linux-2.6.36/crypto/ocf/cryptocteon/Makefile
+--- linux-2.6.36.orig/crypto/ocf/cryptocteon/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/cryptocteon/Makefile 2010-11-09 20:28:04.411246358 +0100
+@@ -0,0 +1,17 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_CRYPTOCTEON) += cryptocteon.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/
++
++ifdef CONFIG_OCF_CRYPTOCTEON
++# you need the cavium crypto component installed
++EXTRA_CFLAGS += -I$(ROOTDIR)/prop/include
++endif
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/cryptodev.c linux-2.6.36/crypto/ocf/cryptodev.c
+--- linux-2.6.36.orig/crypto/ocf/cryptodev.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/cryptodev.c 2010-11-09 20:29:09.284996310 +0100
+@@ -0,0 +1,1060 @@
++/* $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $ */
++
++/*-
++ * Linux port done by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 2001 Theo de Raadt
++ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++__FBSDID("$FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.34 2007/05/09 19:37:02 gnn Exp $");
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/types.h>
++#include <linux/time.h>
++#include <linux/delay.h>
++#include <linux/list.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/unistd.h>
++#include <linux/module.h>
++#include <linux/wait.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/dcache.h>
++#include <linux/file.h>
++#include <linux/mount.h>
++#include <linux/miscdevice.h>
++#include <linux/version.h>
++#include <asm/uaccess.h>
++
++#include <cryptodev.h>
++#include <uio.h>
++
++extern asmlinkage long sys_dup(unsigned int fildes);
++
++#define debug cryptodev_debug
++int cryptodev_debug = 0;
++module_param(cryptodev_debug, int, 0644);
++MODULE_PARM_DESC(cryptodev_debug, "Enable cryptodev debug");
++
++struct csession_info {
++ u_int16_t blocksize;
++ u_int16_t minkey, maxkey;
++
++ u_int16_t keysize;
++ /* u_int16_t hashsize; */
++ u_int16_t authsize;
++ u_int16_t authkey;
++ /* u_int16_t ctxsize; */
++};
++
++struct csession {
++ struct list_head list;
++ u_int64_t sid;
++ u_int32_t ses;
++
++ wait_queue_head_t waitq;
++
++ u_int32_t cipher;
++
++ u_int32_t mac;
++
++ caddr_t key;
++ int keylen;
++ u_char tmp_iv[EALG_MAX_BLOCK_LEN];
++
++ caddr_t mackey;
++ int mackeylen;
++
++ struct csession_info info;
++
++ struct iovec iovec;
++ struct uio uio;
++ int error;
++};
++
++struct fcrypt {
++ struct list_head csessions;
++ int sesn;
++};
++
++static struct csession *csefind(struct fcrypt *, u_int);
++static int csedelete(struct fcrypt *, struct csession *);
++static struct csession *cseadd(struct fcrypt *, struct csession *);
++static struct csession *csecreate(struct fcrypt *, u_int64_t,
++ struct cryptoini *crie, struct cryptoini *cria, struct csession_info *);
++static int csefree(struct csession *);
++
++static int cryptodev_op(struct csession *, struct crypt_op *);
++static int cryptodev_key(struct crypt_kop *);
++static int cryptodev_find(struct crypt_find_op *);
++
++static int cryptodev_cb(void *);
++static int cryptodev_open(struct inode *inode, struct file *filp);
++
++/*
++ * Check a crypto identifier to see if it requested
++ * a valid crid and it's capabilities match.
++ */
++static int
++checkcrid(int crid)
++{
++ int hid = crid & ~(CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE);
++ int typ = crid & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE);
++ int caps = 0;
++
++ /* if the user hasn't selected a driver, then just call newsession */
++ if (hid == 0 && typ != 0)
++ return 0;
++
++ caps = crypto_getcaps(hid);
++
++ /* didn't find anything with capabilities */
++ if (caps == 0) {
++ dprintk("%s: hid=%x typ=%x not matched\n", __FUNCTION__, hid, typ);
++ return EINVAL;
++ }
++
++ /* the user didn't specify SW or HW, so the driver is ok */
++ if (typ == 0)
++ return 0;
++
++ /* if the type specified didn't match */
++ if (typ != (caps & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE))) {
++ dprintk("%s: hid=%x typ=%x caps=%x not matched\n", __FUNCTION__,
++ hid, typ, caps);
++ return EINVAL;
++ }
++
++ return 0;
++}
++
++static int
++cryptodev_op(struct csession *cse, struct crypt_op *cop)
++{
++ struct cryptop *crp = NULL;
++ struct cryptodesc *crde = NULL, *crda = NULL;
++ int error = 0;
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (cop->len > CRYPTO_MAX_DATA_LEN) {
++ dprintk("%s: %d > %d\n", __FUNCTION__, cop->len, CRYPTO_MAX_DATA_LEN);
++ return (E2BIG);
++ }
++
++ if (cse->info.blocksize && (cop->len % cse->info.blocksize) != 0) {
++ dprintk("%s: blocksize=%d len=%d\n", __FUNCTION__, cse->info.blocksize,
++ cop->len);
++ return (EINVAL);
++ }
++
++ cse->uio.uio_iov = &cse->iovec;
++ cse->uio.uio_iovcnt = 1;
++ cse->uio.uio_offset = 0;
++#if 0
++ cse->uio.uio_resid = cop->len;
++ cse->uio.uio_segflg = UIO_SYSSPACE;
++ cse->uio.uio_rw = UIO_WRITE;
++ cse->uio.uio_td = td;
++#endif
++ cse->uio.uio_iov[0].iov_len = cop->len;
++ if (cse->info.authsize)
++ cse->uio.uio_iov[0].iov_len += cse->info.authsize;
++ cse->uio.uio_iov[0].iov_base = kmalloc(cse->uio.uio_iov[0].iov_len,
++ GFP_KERNEL);
++
++ if (cse->uio.uio_iov[0].iov_base == NULL) {
++ dprintk("%s: iov_base kmalloc(%d) failed\n", __FUNCTION__,
++ (int)cse->uio.uio_iov[0].iov_len);
++ return (ENOMEM);
++ }
++
++ crp = crypto_getreq((cse->info.blocksize != 0) + (cse->info.authsize != 0));
++ if (crp == NULL) {
++ dprintk("%s: ENOMEM\n", __FUNCTION__);
++ error = ENOMEM;
++ goto bail;
++ }
++
++ if (cse->info.authsize && cse->info.blocksize) {
++ if (cop->op == COP_ENCRYPT) {
++ crde = crp->crp_desc;
++ crda = crde->crd_next;
++ } else {
++ crda = crp->crp_desc;
++ crde = crda->crd_next;
++ }
++ } else if (cse->info.authsize) {
++ crda = crp->crp_desc;
++ } else if (cse->info.blocksize) {
++ crde = crp->crp_desc;
++ } else {
++ dprintk("%s: bad request\n", __FUNCTION__);
++ error = EINVAL;
++ goto bail;
++ }
++
++ if ((error = copy_from_user(cse->uio.uio_iov[0].iov_base, cop->src,
++ cop->len))) {
++ dprintk("%s: bad copy\n", __FUNCTION__);
++ goto bail;
++ }
++
++ if (crda) {
++ crda->crd_skip = 0;
++ crda->crd_len = cop->len;
++ crda->crd_inject = cop->len;
++
++ crda->crd_alg = cse->mac;
++ crda->crd_key = cse->mackey;
++ crda->crd_klen = cse->mackeylen * 8;
++ }
++
++ if (crde) {
++ if (cop->op == COP_ENCRYPT)
++ crde->crd_flags |= CRD_F_ENCRYPT;
++ else
++ crde->crd_flags &= ~CRD_F_ENCRYPT;
++ crde->crd_len = cop->len;
++ crde->crd_inject = 0;
++
++ crde->crd_alg = cse->cipher;
++ crde->crd_key = cse->key;
++ crde->crd_klen = cse->keylen * 8;
++ }
++
++ crp->crp_ilen = cse->uio.uio_iov[0].iov_len;
++ crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM
++ | (cop->flags & COP_F_BATCH);
++ crp->crp_buf = (caddr_t)&cse->uio;
++ crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb;
++ crp->crp_sid = cse->sid;
++ crp->crp_opaque = (void *)cse;
++
++ if (cop->iv) {
++ if (crde == NULL) {
++ error = EINVAL;
++ dprintk("%s no crde\n", __FUNCTION__);
++ goto bail;
++ }
++ if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
++ error = EINVAL;
++ dprintk("%s arc4 with IV\n", __FUNCTION__);
++ goto bail;
++ }
++ if ((error = copy_from_user(cse->tmp_iv, cop->iv,
++ cse->info.blocksize))) {
++ dprintk("%s bad iv copy\n", __FUNCTION__);
++ goto bail;
++ }
++ memcpy(crde->crd_iv, cse->tmp_iv, cse->info.blocksize);
++ crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
++ crde->crd_skip = 0;
++ } else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
++ crde->crd_skip = 0;
++ } else if (crde) {
++ crde->crd_flags |= CRD_F_IV_PRESENT;
++ crde->crd_skip = cse->info.blocksize;
++ crde->crd_len -= cse->info.blocksize;
++ }
++
++ if (cop->mac && crda == NULL) {
++ error = EINVAL;
++ dprintk("%s no crda\n", __FUNCTION__);
++ goto bail;
++ }
++
++ /*
++ * Let the dispatch run unlocked, then, interlock against the
++ * callback before checking if the operation completed and going
++ * to sleep. This insures drivers don't inherit our lock which
++ * results in a lock order reversal between crypto_dispatch forced
++ * entry and the crypto_done callback into us.
++ */
++ error = crypto_dispatch(crp);
++ if (error) {
++ dprintk("%s error in crypto_dispatch\n", __FUNCTION__);
++ goto bail;
++ }
++
++ dprintk("%s about to WAIT\n", __FUNCTION__);
++ /*
++ * we really need to wait for driver to complete to maintain
++ * state, luckily interrupts will be remembered
++ */
++ do {
++ error = wait_event_interruptible(crp->crp_waitq,
++ ((crp->crp_flags & CRYPTO_F_DONE) != 0));
++ /*
++ * we can't break out of this loop or we will leave behind
++ * a huge mess, however, staying here means if your driver
++ * is broken user applications can hang and not be killed.
++ * The solution, fix your driver :-)
++ */
++ if (error) {
++ schedule();
++ error = 0;
++ }
++ } while ((crp->crp_flags & CRYPTO_F_DONE) == 0);
++ dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error);
++
++ if (crp->crp_etype != 0) {
++ error = crp->crp_etype;
++ dprintk("%s error in crp processing\n", __FUNCTION__);
++ goto bail;
++ }
++
++ if (cse->error) {
++ error = cse->error;
++ dprintk("%s error in cse processing\n", __FUNCTION__);
++ goto bail;
++ }
++
++ if (cop->dst && (error = copy_to_user(cop->dst,
++ cse->uio.uio_iov[0].iov_base, cop->len))) {
++ dprintk("%s bad dst copy\n", __FUNCTION__);
++ goto bail;
++ }
++
++ if (cop->mac &&
++ (error=copy_to_user(cop->mac,
++ (caddr_t)cse->uio.uio_iov[0].iov_base + cop->len,
++ cse->info.authsize))) {
++ dprintk("%s bad mac copy\n", __FUNCTION__);
++ goto bail;
++ }
++
++bail:
++ if (crp)
++ crypto_freereq(crp);
++ if (cse->uio.uio_iov[0].iov_base)
++ kfree(cse->uio.uio_iov[0].iov_base);
++
++ return (error);
++}
++
++static int
++cryptodev_cb(void *op)
++{
++ struct cryptop *crp = (struct cryptop *) op;
++ struct csession *cse = (struct csession *)crp->crp_opaque;
++ int error;
++
++ dprintk("%s()\n", __FUNCTION__);
++ error = crp->crp_etype;
++ if (error == EAGAIN) {
++ crp->crp_flags &= ~CRYPTO_F_DONE;
++#ifdef NOTYET
++ /*
++ * DAVIDM I am fairly sure that we should turn this into a batch
++ * request to stop bad karma/lockup, revisit
++ */
++ crp->crp_flags |= CRYPTO_F_BATCH;
++#endif
++ return crypto_dispatch(crp);
++ }
++ if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) {
++ cse->error = error;
++ wake_up_interruptible(&crp->crp_waitq);
++ }
++ return (0);
++}
++
++static int
++cryptodevkey_cb(void *op)
++{
++ struct cryptkop *krp = (struct cryptkop *) op;
++ dprintk("%s()\n", __FUNCTION__);
++ wake_up_interruptible(&krp->krp_waitq);
++ return (0);
++}
++
++static int
++cryptodev_key(struct crypt_kop *kop)
++{
++ struct cryptkop *krp = NULL;
++ int error = EINVAL;
++ int in, out, size, i;
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) {
++ dprintk("%s params too big\n", __FUNCTION__);
++ return (EFBIG);
++ }
++
++ in = kop->crk_iparams;
++ out = kop->crk_oparams;
++ switch (kop->crk_op) {
++ case CRK_MOD_EXP:
++ if (in == 3 && out == 1)
++ break;
++ return (EINVAL);
++ case CRK_MOD_EXP_CRT:
++ if (in == 6 && out == 1)
++ break;
++ return (EINVAL);
++ case CRK_DSA_SIGN:
++ if (in == 5 && out == 2)
++ break;
++ return (EINVAL);
++ case CRK_DSA_VERIFY:
++ if (in == 7 && out == 0)
++ break;
++ return (EINVAL);
++ case CRK_DH_COMPUTE_KEY:
++ if (in == 3 && out == 1)
++ break;
++ return (EINVAL);
++ default:
++ return (EINVAL);
++ }
++
++ krp = (struct cryptkop *)kmalloc(sizeof *krp, GFP_KERNEL);
++ if (!krp)
++ return (ENOMEM);
++ bzero(krp, sizeof *krp);
++ krp->krp_op = kop->crk_op;
++ krp->krp_status = kop->crk_status;
++ krp->krp_iparams = kop->crk_iparams;
++ krp->krp_oparams = kop->crk_oparams;
++ krp->krp_crid = kop->crk_crid;
++ krp->krp_status = 0;
++ krp->krp_flags = CRYPTO_KF_CBIMM;
++ krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb;
++ init_waitqueue_head(&krp->krp_waitq);
++
++ for (i = 0; i < CRK_MAXPARAM; i++)
++ krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits;
++ for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) {
++ size = (krp->krp_param[i].crp_nbits + 7) / 8;
++ if (size == 0)
++ continue;
++ krp->krp_param[i].crp_p = (caddr_t) kmalloc(size, GFP_KERNEL);
++ if (i >= krp->krp_iparams)
++ continue;
++ error = copy_from_user(krp->krp_param[i].crp_p,
++ kop->crk_param[i].crp_p, size);
++ if (error)
++ goto fail;
++ }
++
++ error = crypto_kdispatch(krp);
++ if (error)
++ goto fail;
++
++ do {
++ error = wait_event_interruptible(krp->krp_waitq,
++ ((krp->krp_flags & CRYPTO_KF_DONE) != 0));
++ /*
++ * we can't break out of this loop or we will leave behind
++ * a huge mess, however, staying here means if your driver
++ * is broken user applications can hang and not be killed.
++ * The solution, fix your driver :-)
++ */
++ if (error) {
++ schedule();
++ error = 0;
++ }
++ } while ((krp->krp_flags & CRYPTO_KF_DONE) == 0);
++
++ dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error);
++
++ kop->crk_crid = krp->krp_crid; /* device that did the work */
++ if (krp->krp_status != 0) {
++ error = krp->krp_status;
++ goto fail;
++ }
++
++ for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) {
++ size = (krp->krp_param[i].crp_nbits + 7) / 8;
++ if (size == 0)
++ continue;
++ error = copy_to_user(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p,
++ size);
++ if (error)
++ goto fail;
++ }
++
++fail:
++ if (krp) {
++ kop->crk_status = krp->krp_status;
++ for (i = 0; i < CRK_MAXPARAM; i++) {
++ if (krp->krp_param[i].crp_p)
++ kfree(krp->krp_param[i].crp_p);
++ }
++ kfree(krp);
++ }
++ return (error);
++}
++
++static int
++cryptodev_find(struct crypt_find_op *find)
++{
++ device_t dev;
++
++ if (find->crid != -1) {
++ dev = crypto_find_device_byhid(find->crid);
++ if (dev == NULL)
++ return (ENOENT);
++ strlcpy(find->name, device_get_nameunit(dev),
++ sizeof(find->name));
++ } else {
++ find->crid = crypto_find_driver(find->name);
++ if (find->crid == -1)
++ return (ENOENT);
++ }
++ return (0);
++}
++
++static struct csession *
++csefind(struct fcrypt *fcr, u_int ses)
++{
++ struct csession *cse;
++
++ dprintk("%s()\n", __FUNCTION__);
++ list_for_each_entry(cse, &fcr->csessions, list)
++ if (cse->ses == ses)
++ return (cse);
++ return (NULL);
++}
++
++static int
++csedelete(struct fcrypt *fcr, struct csession *cse_del)
++{
++ struct csession *cse;
++
++ dprintk("%s()\n", __FUNCTION__);
++ list_for_each_entry(cse, &fcr->csessions, list) {
++ if (cse == cse_del) {
++ list_del(&cse->list);
++ return (1);
++ }
++ }
++ return (0);
++}
++
++static struct csession *
++cseadd(struct fcrypt *fcr, struct csession *cse)
++{
++ dprintk("%s()\n", __FUNCTION__);
++ list_add_tail(&cse->list, &fcr->csessions);
++ cse->ses = fcr->sesn++;
++ return (cse);
++}
++
++static struct csession *
++csecreate(struct fcrypt *fcr, u_int64_t sid, struct cryptoini *crie,
++ struct cryptoini *cria, struct csession_info *info)
++{
++ struct csession *cse;
++
++ dprintk("%s()\n", __FUNCTION__);
++ cse = (struct csession *) kmalloc(sizeof(struct csession), GFP_KERNEL);
++ if (cse == NULL)
++ return NULL;
++ memset(cse, 0, sizeof(struct csession));
++
++ INIT_LIST_HEAD(&cse->list);
++ init_waitqueue_head(&cse->waitq);
++
++ cse->key = crie->cri_key;
++ cse->keylen = crie->cri_klen/8;
++ cse->mackey = cria->cri_key;
++ cse->mackeylen = cria->cri_klen/8;
++ cse->sid = sid;
++ cse->cipher = crie->cri_alg;
++ cse->mac = cria->cri_alg;
++ cse->info = *info;
++ cseadd(fcr, cse);
++ return (cse);
++}
++
++static int
++csefree(struct csession *cse)
++{
++ int error;
++
++ dprintk("%s()\n", __FUNCTION__);
++ error = crypto_freesession(cse->sid);
++ if (cse->key)
++ kfree(cse->key);
++ if (cse->mackey)
++ kfree(cse->mackey);
++ kfree(cse);
++ return(error);
++}
++
++static int
++cryptodev_ioctl(
++ struct inode *inode,
++ struct file *filp,
++ unsigned int cmd,
++ unsigned long arg)
++{
++ struct cryptoini cria, crie;
++ struct fcrypt *fcr = filp->private_data;
++ struct csession *cse;
++ struct csession_info info;
++ struct session2_op sop;
++ struct crypt_op cop;
++ struct crypt_kop kop;
++ struct crypt_find_op fop;
++ u_int64_t sid;
++ u_int32_t ses = 0;
++ int feat, fd, error = 0, crid;
++ mm_segment_t fs;
++
++ dprintk("%s(cmd=%x arg=%lx)\n", __FUNCTION__, cmd, arg);
++
++ switch (cmd) {
++
++ case CRIOGET: {
++ dprintk("%s(CRIOGET)\n", __FUNCTION__);
++ fs = get_fs();
++ set_fs(get_ds());
++ for (fd = 0; fd < files_fdtable(current->files)->max_fds; fd++)
++ if (files_fdtable(current->files)->fd[fd] == filp)
++ break;
++ fd = sys_dup(fd);
++ set_fs(fs);
++ put_user(fd, (int *) arg);
++ return IS_ERR_VALUE(fd) ? fd : 0;
++ }
++
++#define CIOCGSESSSTR (cmd == CIOCGSESSION ? "CIOCGSESSION" : "CIOCGSESSION2")
++ case CIOCGSESSION:
++ case CIOCGSESSION2:
++ dprintk("%s(%s)\n", __FUNCTION__, CIOCGSESSSTR);
++ memset(&crie, 0, sizeof(crie));
++ memset(&cria, 0, sizeof(cria));
++ memset(&info, 0, sizeof(info));
++ memset(&sop, 0, sizeof(sop));
++
++ if (copy_from_user(&sop, (void*)arg, (cmd == CIOCGSESSION) ?
++ sizeof(struct session_op) : sizeof(sop))) {
++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++ error = EFAULT;
++ goto bail;
++ }
++
++ switch (sop.cipher) {
++ case 0:
++ dprintk("%s(%s) - no cipher\n", __FUNCTION__, CIOCGSESSSTR);
++ break;
++ case CRYPTO_NULL_CBC:
++ info.blocksize = NULL_BLOCK_LEN;
++ info.minkey = NULL_MIN_KEY_LEN;
++ info.maxkey = NULL_MAX_KEY_LEN;
++ break;
++ case CRYPTO_DES_CBC:
++ info.blocksize = DES_BLOCK_LEN;
++ info.minkey = DES_MIN_KEY_LEN;
++ info.maxkey = DES_MAX_KEY_LEN;
++ break;
++ case CRYPTO_3DES_CBC:
++ info.blocksize = DES3_BLOCK_LEN;
++ info.minkey = DES3_MIN_KEY_LEN;
++ info.maxkey = DES3_MAX_KEY_LEN;
++ break;
++ case CRYPTO_BLF_CBC:
++ info.blocksize = BLOWFISH_BLOCK_LEN;
++ info.minkey = BLOWFISH_MIN_KEY_LEN;
++ info.maxkey = BLOWFISH_MAX_KEY_LEN;
++ break;
++ case CRYPTO_CAST_CBC:
++ info.blocksize = CAST128_BLOCK_LEN;
++ info.minkey = CAST128_MIN_KEY_LEN;
++ info.maxkey = CAST128_MAX_KEY_LEN;
++ break;
++ case CRYPTO_SKIPJACK_CBC:
++ info.blocksize = SKIPJACK_BLOCK_LEN;
++ info.minkey = SKIPJACK_MIN_KEY_LEN;
++ info.maxkey = SKIPJACK_MAX_KEY_LEN;
++ break;
++ case CRYPTO_AES_CBC:
++ info.blocksize = AES_BLOCK_LEN;
++ info.minkey = AES_MIN_KEY_LEN;
++ info.maxkey = AES_MAX_KEY_LEN;
++ break;
++ case CRYPTO_ARC4:
++ info.blocksize = ARC4_BLOCK_LEN;
++ info.minkey = ARC4_MIN_KEY_LEN;
++ info.maxkey = ARC4_MAX_KEY_LEN;
++ break;
++ case CRYPTO_CAMELLIA_CBC:
++ info.blocksize = CAMELLIA_BLOCK_LEN;
++ info.minkey = CAMELLIA_MIN_KEY_LEN;
++ info.maxkey = CAMELLIA_MAX_KEY_LEN;
++ break;
++ default:
++ dprintk("%s(%s) - bad cipher\n", __FUNCTION__, CIOCGSESSSTR);
++ error = EINVAL;
++ goto bail;
++ }
++
++ switch (sop.mac) {
++ case 0:
++ dprintk("%s(%s) - no mac\n", __FUNCTION__, CIOCGSESSSTR);
++ break;
++ case CRYPTO_NULL_HMAC:
++ info.authsize = NULL_HASH_LEN;
++ break;
++ case CRYPTO_MD5:
++ info.authsize = MD5_HASH_LEN;
++ break;
++ case CRYPTO_SHA1:
++ info.authsize = SHA1_HASH_LEN;
++ break;
++ case CRYPTO_SHA2_256:
++ info.authsize = SHA2_256_HASH_LEN;
++ break;
++ case CRYPTO_SHA2_384:
++ info.authsize = SHA2_384_HASH_LEN;
++ break;
++ case CRYPTO_SHA2_512:
++ info.authsize = SHA2_512_HASH_LEN;
++ break;
++ case CRYPTO_RIPEMD160:
++ info.authsize = RIPEMD160_HASH_LEN;
++ break;
++ case CRYPTO_MD5_HMAC:
++ info.authsize = MD5_HASH_LEN;
++ info.authkey = 16;
++ break;
++ case CRYPTO_SHA1_HMAC:
++ info.authsize = SHA1_HASH_LEN;
++ info.authkey = 20;
++ break;
++ case CRYPTO_SHA2_256_HMAC:
++ info.authsize = SHA2_256_HASH_LEN;
++ info.authkey = 32;
++ break;
++ case CRYPTO_SHA2_384_HMAC:
++ info.authsize = SHA2_384_HASH_LEN;
++ info.authkey = 48;
++ break;
++ case CRYPTO_SHA2_512_HMAC:
++ info.authsize = SHA2_512_HASH_LEN;
++ info.authkey = 64;
++ break;
++ case CRYPTO_RIPEMD160_HMAC:
++ info.authsize = RIPEMD160_HASH_LEN;
++ info.authkey = 20;
++ break;
++ default:
++ dprintk("%s(%s) - bad mac\n", __FUNCTION__, CIOCGSESSSTR);
++ error = EINVAL;
++ goto bail;
++ }
++
++ if (info.blocksize) {
++ crie.cri_alg = sop.cipher;
++ crie.cri_klen = sop.keylen * 8;
++ if ((info.maxkey && sop.keylen > info.maxkey) ||
++ sop.keylen < info.minkey) {
++ dprintk("%s(%s) - bad key\n", __FUNCTION__, CIOCGSESSSTR);
++ error = EINVAL;
++ goto bail;
++ }
++
++ crie.cri_key = (u_int8_t *) kmalloc(crie.cri_klen/8+1, GFP_KERNEL);
++ if (copy_from_user(crie.cri_key, sop.key,
++ crie.cri_klen/8)) {
++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++ error = EFAULT;
++ goto bail;
++ }
++ if (info.authsize)
++ crie.cri_next = &cria;
++ }
++
++ if (info.authsize) {
++ cria.cri_alg = sop.mac;
++ cria.cri_klen = sop.mackeylen * 8;
++ if (info.authkey && sop.mackeylen != info.authkey) {
++ dprintk("%s(%s) - mackeylen %d != %d\n", __FUNCTION__,
++ CIOCGSESSSTR, sop.mackeylen, info.authkey);
++ error = EINVAL;
++ goto bail;
++ }
++
++ if (cria.cri_klen) {
++ cria.cri_key = (u_int8_t *) kmalloc(cria.cri_klen/8,GFP_KERNEL);
++ if (copy_from_user(cria.cri_key, sop.mackey,
++ cria.cri_klen / 8)) {
++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++ error = EFAULT;
++ goto bail;
++ }
++ }
++ }
++
++ /* NB: CIOGSESSION2 has the crid */
++ if (cmd == CIOCGSESSION2) {
++ crid = sop.crid;
++ error = checkcrid(crid);
++ if (error) {
++ dprintk("%s(%s) - checkcrid %x\n", __FUNCTION__,
++ CIOCGSESSSTR, error);
++ goto bail;
++ }
++ } else {
++ /* allow either HW or SW to be used */
++ crid = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
++ }
++ error = crypto_newsession(&sid, (info.blocksize ? &crie : &cria), crid);
++ if (error) {
++ dprintk("%s(%s) - newsession %d\n",__FUNCTION__,CIOCGSESSSTR,error);
++ goto bail;
++ }
++
++ cse = csecreate(fcr, sid, &crie, &cria, &info);
++ if (cse == NULL) {
++ crypto_freesession(sid);
++ error = EINVAL;
++ dprintk("%s(%s) - csecreate failed\n", __FUNCTION__, CIOCGSESSSTR);
++ goto bail;
++ }
++ sop.ses = cse->ses;
++
++ if (cmd == CIOCGSESSION2) {
++ /* return hardware/driver id */
++ sop.crid = CRYPTO_SESID2HID(cse->sid);
++ }
++
++ if (copy_to_user((void*)arg, &sop, (cmd == CIOCGSESSION) ?
++ sizeof(struct session_op) : sizeof(sop))) {
++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++ error = EFAULT;
++ }
++bail:
++ if (error) {
++ dprintk("%s(%s) - bail %d\n", __FUNCTION__, CIOCGSESSSTR, error);
++ if (crie.cri_key)
++ kfree(crie.cri_key);
++ if (cria.cri_key)
++ kfree(cria.cri_key);
++ }
++ break;
++ case CIOCFSESSION:
++ dprintk("%s(CIOCFSESSION)\n", __FUNCTION__);
++ get_user(ses, (uint32_t*)arg);
++ cse = csefind(fcr, ses);
++ if (cse == NULL) {
++ error = EINVAL;
++ dprintk("%s(CIOCFSESSION) - Fail %d\n", __FUNCTION__, error);
++ break;
++ }
++ csedelete(fcr, cse);
++ error = csefree(cse);
++ break;
++ case CIOCCRYPT:
++ dprintk("%s(CIOCCRYPT)\n", __FUNCTION__);
++ if(copy_from_user(&cop, (void*)arg, sizeof(cop))) {
++ dprintk("%s(CIOCCRYPT) - bad copy\n", __FUNCTION__);
++ error = EFAULT;
++ goto bail;
++ }
++ cse = csefind(fcr, cop.ses);
++ if (cse == NULL) {
++ error = EINVAL;
++ dprintk("%s(CIOCCRYPT) - Fail %d\n", __FUNCTION__, error);
++ break;
++ }
++ error = cryptodev_op(cse, &cop);
++ if(copy_to_user((void*)arg, &cop, sizeof(cop))) {
++ dprintk("%s(CIOCCRYPT) - bad return copy\n", __FUNCTION__);
++ error = EFAULT;
++ goto bail;
++ }
++ break;
++ case CIOCKEY:
++ case CIOCKEY2:
++ dprintk("%s(CIOCKEY)\n", __FUNCTION__);
++ if (!crypto_userasymcrypto)
++ return (EPERM); /* XXX compat? */
++ if(copy_from_user(&kop, (void*)arg, sizeof(kop))) {
++ dprintk("%s(CIOCKEY) - bad copy\n", __FUNCTION__);
++ error = EFAULT;
++ goto bail;
++ }
++ if (cmd == CIOCKEY) {
++ /* NB: crypto core enforces s/w driver use */
++ kop.crk_crid =
++ CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
++ }
++ error = cryptodev_key(&kop);
++ if(copy_to_user((void*)arg, &kop, sizeof(kop))) {
++ dprintk("%s(CIOCGKEY) - bad return copy\n", __FUNCTION__);
++ error = EFAULT;
++ goto bail;
++ }
++ break;
++ case CIOCASYMFEAT:
++ dprintk("%s(CIOCASYMFEAT)\n", __FUNCTION__);
++ if (!crypto_userasymcrypto) {
++ /*
++ * NB: if user asym crypto operations are
++ * not permitted return "no algorithms"
++ * so well-behaved applications will just
++ * fallback to doing them in software.
++ */
++ feat = 0;
++ } else
++ error = crypto_getfeat(&feat);
++ if (!error) {
++ error = copy_to_user((void*)arg, &feat, sizeof(feat));
++ }
++ break;
++ case CIOCFINDDEV:
++ if (copy_from_user(&fop, (void*)arg, sizeof(fop))) {
++ dprintk("%s(CIOCFINDDEV) - bad copy\n", __FUNCTION__);
++ error = EFAULT;
++ goto bail;
++ }
++ error = cryptodev_find(&fop);
++ if (copy_to_user((void*)arg, &fop, sizeof(fop))) {
++ dprintk("%s(CIOCFINDDEV) - bad return copy\n", __FUNCTION__);
++ error = EFAULT;
++ goto bail;
++ }
++ break;
++ default:
++ dprintk("%s(unknown ioctl 0x%x)\n", __FUNCTION__, cmd);
++ error = EINVAL;
++ break;
++ }
++ return(-error);
++}
++
++#ifdef HAVE_UNLOCKED_IOCTL
++static long
++cryptodev_unlocked_ioctl(
++ struct file *filp,
++ unsigned int cmd,
++ unsigned long arg)
++{
++ return cryptodev_ioctl(NULL, filp, cmd, arg);
++}
++#endif
++
++static int
++cryptodev_open(struct inode *inode, struct file *filp)
++{
++ struct fcrypt *fcr;
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (filp->private_data) {
++ printk("cryptodev: Private data already exists !\n");
++ return(0);
++ }
++
++ fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
++ if (!fcr) {
++ dprintk("%s() - malloc failed\n", __FUNCTION__);
++ return(-ENOMEM);
++ }
++ memset(fcr, 0, sizeof(*fcr));
++
++ INIT_LIST_HEAD(&fcr->csessions);
++ filp->private_data = fcr;
++ return(0);
++}
++
++static int
++cryptodev_release(struct inode *inode, struct file *filp)
++{
++ struct fcrypt *fcr = filp->private_data;
++ struct csession *cse, *tmp;
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (!filp) {
++ printk("cryptodev: No private data on release\n");
++ return(0);
++ }
++
++ list_for_each_entry_safe(cse, tmp, &fcr->csessions, list) {
++ list_del(&cse->list);
++ (void)csefree(cse);
++ }
++ filp->private_data = NULL;
++ kfree(fcr);
++ return(0);
++}
++
++static struct file_operations cryptodev_fops = {
++ .owner = THIS_MODULE,
++ .open = cryptodev_open,
++ .release = cryptodev_release,
++#ifdef HAVE_UNLOCKED_IOCTL
++ .unlocked_ioctl = cryptodev_unlocked_ioctl,
++#endif
++};
++
++static struct miscdevice cryptodev = {
++ .minor = CRYPTODEV_MINOR,
++ .name = "crypto",
++ .fops = &cryptodev_fops,
++};
++
++static int __init
++cryptodev_init(void)
++{
++ int rc;
++
++ dprintk("%s(%p)\n", __FUNCTION__, cryptodev_init);
++ rc = misc_register(&cryptodev);
++ if (rc) {
++ printk(KERN_ERR "cryptodev: registration of /dev/crypto failed\n");
++ return(rc);
++ }
++
++ return(0);
++}
++
++static void __exit
++cryptodev_exit(void)
++{
++ dprintk("%s()\n", __FUNCTION__);
++ misc_deregister(&cryptodev);
++}
++
++module_init(cryptodev_init);
++module_exit(cryptodev_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
++MODULE_DESCRIPTION("Cryptodev (user interface to OCF)");
+diff -Nur linux-2.6.36.orig/crypto/ocf/cryptodev.h linux-2.6.36/crypto/ocf/cryptodev.h
+--- linux-2.6.36.orig/crypto/ocf/cryptodev.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/cryptodev.h 2010-11-09 20:28:04.492495480 +0100
+@@ -0,0 +1,479 @@
++/* $FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.25 2007/05/09 19:37:02 gnn Exp $ */
++/* $OpenBSD: cryptodev.h,v 1.31 2002/06/11 11:14:29 beck Exp $ */
++
++/*-
++ * Linux port done by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
++ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
++ *
++ * This code was written by Angelos D. Keromytis in Athens, Greece, in
++ * February 2000. Network Security Technologies Inc. (NSTI) kindly
++ * supported the development of this code.
++ *
++ * Copyright (c) 2000 Angelos D. Keromytis
++ *
++ * Permission to use, copy, and modify this software with or without fee
++ * is hereby granted, provided that this entire notice is included in
++ * all source code copies of any software which is or includes a copy or
++ * modification of this software.
++ *
++ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
++ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
++ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
++ * PURPOSE.
++ *
++ * Copyright (c) 2001 Theo de Raadt
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++ */
++
++#ifndef _CRYPTO_CRYPTO_H_
++#define _CRYPTO_CRYPTO_H_
++
++/* Some initial values */
++#define CRYPTO_DRIVERS_INITIAL 4
++#define CRYPTO_SW_SESSIONS 32
++
++/* Hash values */
++#define NULL_HASH_LEN 0
++#define MD5_HASH_LEN 16
++#define SHA1_HASH_LEN 20
++#define RIPEMD160_HASH_LEN 20
++#define SHA2_256_HASH_LEN 32
++#define SHA2_384_HASH_LEN 48
++#define SHA2_512_HASH_LEN 64
++#define MD5_KPDK_HASH_LEN 16
++#define SHA1_KPDK_HASH_LEN 20
++/* Maximum hash algorithm result length */
++#define HASH_MAX_LEN SHA2_512_HASH_LEN /* Keep this updated */
++
++/* HMAC values */
++#define NULL_HMAC_BLOCK_LEN 1
++#define MD5_HMAC_BLOCK_LEN 64
++#define SHA1_HMAC_BLOCK_LEN 64
++#define RIPEMD160_HMAC_BLOCK_LEN 64
++#define SHA2_256_HMAC_BLOCK_LEN 64
++#define SHA2_384_HMAC_BLOCK_LEN 128
++#define SHA2_512_HMAC_BLOCK_LEN 128
++/* Maximum HMAC block length */
++#define HMAC_MAX_BLOCK_LEN SHA2_512_HMAC_BLOCK_LEN /* Keep this updated */
++#define HMAC_IPAD_VAL 0x36
++#define HMAC_OPAD_VAL 0x5C
++
++/* Encryption algorithm block sizes */
++#define NULL_BLOCK_LEN 1
++#define DES_BLOCK_LEN 8
++#define DES3_BLOCK_LEN 8
++#define BLOWFISH_BLOCK_LEN 8
++#define SKIPJACK_BLOCK_LEN 8
++#define CAST128_BLOCK_LEN 8
++#define RIJNDAEL128_BLOCK_LEN 16
++#define AES_BLOCK_LEN RIJNDAEL128_BLOCK_LEN
++#define CAMELLIA_BLOCK_LEN 16
++#define ARC4_BLOCK_LEN 1
++#define EALG_MAX_BLOCK_LEN AES_BLOCK_LEN /* Keep this updated */
++
++/* Encryption algorithm min and max key sizes */
++#define NULL_MIN_KEY_LEN 0
++#define NULL_MAX_KEY_LEN 0
++#define DES_MIN_KEY_LEN 8
++#define DES_MAX_KEY_LEN 8
++#define DES3_MIN_KEY_LEN 24
++#define DES3_MAX_KEY_LEN 24
++#define BLOWFISH_MIN_KEY_LEN 4
++#define BLOWFISH_MAX_KEY_LEN 56
++#define SKIPJACK_MIN_KEY_LEN 10
++#define SKIPJACK_MAX_KEY_LEN 10
++#define CAST128_MIN_KEY_LEN 5
++#define CAST128_MAX_KEY_LEN 16
++#define RIJNDAEL128_MIN_KEY_LEN 16
++#define RIJNDAEL128_MAX_KEY_LEN 32
++#define AES_MIN_KEY_LEN RIJNDAEL128_MIN_KEY_LEN
++#define AES_MAX_KEY_LEN RIJNDAEL128_MAX_KEY_LEN
++#define CAMELLIA_MIN_KEY_LEN 16
++#define CAMELLIA_MAX_KEY_LEN 32
++#define ARC4_MIN_KEY_LEN 1
++#define ARC4_MAX_KEY_LEN 256
++
++/* Max size of data that can be processed */
++#define CRYPTO_MAX_DATA_LEN 64*1024 - 1
++
++#define CRYPTO_ALGORITHM_MIN 1
++#define CRYPTO_DES_CBC 1
++#define CRYPTO_3DES_CBC 2
++#define CRYPTO_BLF_CBC 3
++#define CRYPTO_CAST_CBC 4
++#define CRYPTO_SKIPJACK_CBC 5
++#define CRYPTO_MD5_HMAC 6
++#define CRYPTO_SHA1_HMAC 7
++#define CRYPTO_RIPEMD160_HMAC 8
++#define CRYPTO_MD5_KPDK 9
++#define CRYPTO_SHA1_KPDK 10
++#define CRYPTO_RIJNDAEL128_CBC 11 /* 128 bit blocksize */
++#define CRYPTO_AES_CBC 11 /* 128 bit blocksize -- the same as above */
++#define CRYPTO_ARC4 12
++#define CRYPTO_MD5 13
++#define CRYPTO_SHA1 14
++#define CRYPTO_NULL_HMAC 15
++#define CRYPTO_NULL_CBC 16
++#define CRYPTO_DEFLATE_COMP 17 /* Deflate compression algorithm */
++#define CRYPTO_SHA2_256_HMAC 18
++#define CRYPTO_SHA2_384_HMAC 19
++#define CRYPTO_SHA2_512_HMAC 20
++#define CRYPTO_CAMELLIA_CBC 21
++#define CRYPTO_SHA2_256 22
++#define CRYPTO_SHA2_384 23
++#define CRYPTO_SHA2_512 24
++#define CRYPTO_RIPEMD160 25
++#define CRYPTO_ALGORITHM_MAX 25 /* Keep updated - see below */
++
++/* Algorithm flags */
++#define CRYPTO_ALG_FLAG_SUPPORTED 0x01 /* Algorithm is supported */
++#define CRYPTO_ALG_FLAG_RNG_ENABLE 0x02 /* Has HW RNG for DH/DSA */
++#define CRYPTO_ALG_FLAG_DSA_SHA 0x04 /* Can do SHA on msg */
++
++/*
++ * Crypto driver/device flags. They can set in the crid
++ * parameter when creating a session or submitting a key
++ * op to affect the device/driver assigned. If neither
++ * of these are specified then the crid is assumed to hold
++ * the driver id of an existing (and suitable) device that
++ * must be used to satisfy the request.
++ */
++#define CRYPTO_FLAG_HARDWARE 0x01000000 /* hardware accelerated */
++#define CRYPTO_FLAG_SOFTWARE 0x02000000 /* software implementation */
++
++/* NB: deprecated */
++struct session_op {
++ u_int32_t cipher; /* ie. CRYPTO_DES_CBC */
++ u_int32_t mac; /* ie. CRYPTO_MD5_HMAC */
++
++ u_int32_t keylen; /* cipher key */
++ caddr_t key;
++ int mackeylen; /* mac key */
++ caddr_t mackey;
++
++ u_int32_t ses; /* returns: session # */
++};
++
++struct session2_op {
++ u_int32_t cipher; /* ie. CRYPTO_DES_CBC */
++ u_int32_t mac; /* ie. CRYPTO_MD5_HMAC */
++
++ u_int32_t keylen; /* cipher key */
++ caddr_t key;
++ int mackeylen; /* mac key */
++ caddr_t mackey;
++
++ u_int32_t ses; /* returns: session # */
++ int crid; /* driver id + flags (rw) */
++ int pad[4]; /* for future expansion */
++};
++
++struct crypt_op {
++ u_int32_t ses;
++ u_int16_t op; /* i.e. COP_ENCRYPT */
++#define COP_NONE 0
++#define COP_ENCRYPT 1
++#define COP_DECRYPT 2
++ u_int16_t flags;
++#define COP_F_BATCH 0x0008 /* Batch op if possible */
++ u_int len;
++ caddr_t src, dst; /* become iov[] inside kernel */
++ caddr_t mac; /* must be big enough for chosen MAC */
++ caddr_t iv;
++};
++
++/*
++ * Parameters for looking up a crypto driver/device by
++ * device name or by id. The latter are returned for
++ * created sessions (crid) and completed key operations.
++ */
++struct crypt_find_op {
++ int crid; /* driver id + flags */
++ char name[32]; /* device/driver name */
++};
++
++/* bignum parameter, in packed bytes, ... */
++struct crparam {
++ caddr_t crp_p;
++ u_int crp_nbits;
++};
++
++#define CRK_MAXPARAM 8
++
++struct crypt_kop {
++ u_int crk_op; /* ie. CRK_MOD_EXP or other */
++ u_int crk_status; /* return status */
++ u_short crk_iparams; /* # of input parameters */
++ u_short crk_oparams; /* # of output parameters */
++ u_int crk_crid; /* NB: only used by CIOCKEY2 (rw) */
++ struct crparam crk_param[CRK_MAXPARAM];
++};
++#define CRK_ALGORITM_MIN 0
++#define CRK_MOD_EXP 0
++#define CRK_MOD_EXP_CRT 1
++#define CRK_DSA_SIGN 2
++#define CRK_DSA_VERIFY 3
++#define CRK_DH_COMPUTE_KEY 4
++#define CRK_ALGORITHM_MAX 4 /* Keep updated - see below */
++
++#define CRF_MOD_EXP (1 << CRK_MOD_EXP)
++#define CRF_MOD_EXP_CRT (1 << CRK_MOD_EXP_CRT)
++#define CRF_DSA_SIGN (1 << CRK_DSA_SIGN)
++#define CRF_DSA_VERIFY (1 << CRK_DSA_VERIFY)
++#define CRF_DH_COMPUTE_KEY (1 << CRK_DH_COMPUTE_KEY)
++
++/*
++ * done against open of /dev/crypto, to get a cloned descriptor.
++ * Please use F_SETFD against the cloned descriptor.
++ */
++#define CRIOGET _IOWR('c', 100, u_int32_t)
++#define CRIOASYMFEAT CIOCASYMFEAT
++#define CRIOFINDDEV CIOCFINDDEV
++
++/* the following are done against the cloned descriptor */
++#define CIOCGSESSION _IOWR('c', 101, struct session_op)
++#define CIOCFSESSION _IOW('c', 102, u_int32_t)
++#define CIOCCRYPT _IOWR('c', 103, struct crypt_op)
++#define CIOCKEY _IOWR('c', 104, struct crypt_kop)
++#define CIOCASYMFEAT _IOR('c', 105, u_int32_t)
++#define CIOCGSESSION2 _IOWR('c', 106, struct session2_op)
++#define CIOCKEY2 _IOWR('c', 107, struct crypt_kop)
++#define CIOCFINDDEV _IOWR('c', 108, struct crypt_find_op)
++
++struct cryptotstat {
++ struct timespec acc; /* total accumulated time */
++ struct timespec min; /* min time */
++ struct timespec max; /* max time */
++ u_int32_t count; /* number of observations */
++};
++
++struct cryptostats {
++ u_int32_t cs_ops; /* symmetric crypto ops submitted */
++ u_int32_t cs_errs; /* symmetric crypto ops that failed */
++ u_int32_t cs_kops; /* asymetric/key ops submitted */
++ u_int32_t cs_kerrs; /* asymetric/key ops that failed */
++ u_int32_t cs_intrs; /* crypto swi thread activations */
++ u_int32_t cs_rets; /* crypto return thread activations */
++ u_int32_t cs_blocks; /* symmetric op driver block */
++ u_int32_t cs_kblocks; /* symmetric op driver block */
++ /*
++ * When CRYPTO_TIMING is defined at compile time and the
++ * sysctl debug.crypto is set to 1, the crypto system will
++ * accumulate statistics about how long it takes to process
++ * crypto requests at various points during processing.
++ */
++ struct cryptotstat cs_invoke; /* crypto_dipsatch -> crypto_invoke */
++ struct cryptotstat cs_done; /* crypto_invoke -> crypto_done */
++ struct cryptotstat cs_cb; /* crypto_done -> callback */
++ struct cryptotstat cs_finis; /* callback -> callback return */
++
++ u_int32_t cs_drops; /* crypto ops dropped due to congestion */
++};
++
++#ifdef __KERNEL__
++
++/* Standard initialization structure beginning */
++struct cryptoini {
++ int cri_alg; /* Algorithm to use */
++ int cri_klen; /* Key length, in bits */
++ int cri_mlen; /* Number of bytes we want from the
++ entire hash. 0 means all. */
++ caddr_t cri_key; /* key to use */
++ u_int8_t cri_iv[EALG_MAX_BLOCK_LEN]; /* IV to use */
++ struct cryptoini *cri_next;
++};
++
++/* Describe boundaries of a single crypto operation */
++struct cryptodesc {
++ int crd_skip; /* How many bytes to ignore from start */
++ int crd_len; /* How many bytes to process */
++ int crd_inject; /* Where to inject results, if applicable */
++ int crd_flags;
++
++#define CRD_F_ENCRYPT 0x01 /* Set when doing encryption */
++#define CRD_F_IV_PRESENT 0x02 /* When encrypting, IV is already in
++ place, so don't copy. */
++#define CRD_F_IV_EXPLICIT 0x04 /* IV explicitly provided */
++#define CRD_F_DSA_SHA_NEEDED 0x08 /* Compute SHA-1 of buffer for DSA */
++#define CRD_F_KEY_EXPLICIT 0x10 /* Key explicitly provided */
++#define CRD_F_COMP 0x0f /* Set when doing compression */
++
++ struct cryptoini CRD_INI; /* Initialization/context data */
++#define crd_iv CRD_INI.cri_iv
++#define crd_key CRD_INI.cri_key
++#define crd_alg CRD_INI.cri_alg
++#define crd_klen CRD_INI.cri_klen
++#define crd_mlen CRD_INI.cri_mlen
++
++ struct cryptodesc *crd_next;
++};
++
++/* Structure describing complete operation */
++struct cryptop {
++ struct list_head crp_next;
++ wait_queue_head_t crp_waitq;
++
++ u_int64_t crp_sid; /* Session ID */
++ int crp_ilen; /* Input data total length */
++ int crp_olen; /* Result total length */
++
++ int crp_etype; /*
++ * Error type (zero means no error).
++ * All error codes except EAGAIN
++ * indicate possible data corruption (as in,
++ * the data have been touched). On all
++ * errors, the crp_sid may have changed
++ * (reset to a new one), so the caller
++ * should always check and use the new
++ * value on future requests.
++ */
++ int crp_flags;
++
++#define CRYPTO_F_SKBUF 0x0001 /* Input/output are skbuf chains */
++#define CRYPTO_F_IOV 0x0002 /* Input/output are uio */
++#define CRYPTO_F_REL 0x0004 /* Must return data in same place */
++#define CRYPTO_F_BATCH 0x0008 /* Batch op if possible */
++#define CRYPTO_F_CBIMM 0x0010 /* Do callback immediately */
++#define CRYPTO_F_DONE 0x0020 /* Operation completed */
++#define CRYPTO_F_CBIFSYNC 0x0040 /* Do CBIMM if op is synchronous */
++
++ caddr_t crp_buf; /* Data to be processed */
++ caddr_t crp_opaque; /* Opaque pointer, passed along */
++ struct cryptodesc *crp_desc; /* Linked list of processing descriptors */
++
++ int (*crp_callback)(struct cryptop *); /* Callback function */
++};
++
++#define CRYPTO_BUF_CONTIG 0x0
++#define CRYPTO_BUF_IOV 0x1
++#define CRYPTO_BUF_SKBUF 0x2
++
++#define CRYPTO_OP_DECRYPT 0x0
++#define CRYPTO_OP_ENCRYPT 0x1
++
++/*
++ * Hints passed to process methods.
++ */
++#define CRYPTO_HINT_MORE 0x1 /* more ops coming shortly */
++
++struct cryptkop {
++ struct list_head krp_next;
++ wait_queue_head_t krp_waitq;
++
++ int krp_flags;
++#define CRYPTO_KF_DONE 0x0001 /* Operation completed */
++#define CRYPTO_KF_CBIMM 0x0002 /* Do callback immediately */
++
++ u_int krp_op; /* ie. CRK_MOD_EXP or other */
++ u_int krp_status; /* return status */
++ u_short krp_iparams; /* # of input parameters */
++ u_short krp_oparams; /* # of output parameters */
++ u_int krp_crid; /* desired device, etc. */
++ u_int32_t krp_hid;
++ struct crparam krp_param[CRK_MAXPARAM]; /* kvm */
++ int (*krp_callback)(struct cryptkop *);
++};
++
++#include <ocf-compat.h>
++
++/*
++ * Session ids are 64 bits. The lower 32 bits contain a "local id" which
++ * is a driver-private session identifier. The upper 32 bits contain a
++ * "hardware id" used by the core crypto code to identify the driver and
++ * a copy of the driver's capabilities that can be used by client code to
++ * optimize operation.
++ */
++#define CRYPTO_SESID2HID(_sid) (((_sid) >> 32) & 0x00ffffff)
++#define CRYPTO_SESID2CAPS(_sid) (((_sid) >> 32) & 0xff000000)
++#define CRYPTO_SESID2LID(_sid) (((u_int32_t) (_sid)) & 0xffffffff)
++
++extern int crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard);
++extern int crypto_freesession(u_int64_t sid);
++#define CRYPTOCAP_F_HARDWARE CRYPTO_FLAG_HARDWARE
++#define CRYPTOCAP_F_SOFTWARE CRYPTO_FLAG_SOFTWARE
++#define CRYPTOCAP_F_SYNC 0x04000000 /* operates synchronously */
++extern int32_t crypto_get_driverid(device_t dev, int flags);
++extern int crypto_find_driver(const char *);
++extern device_t crypto_find_device_byhid(int hid);
++extern int crypto_getcaps(int hid);
++extern int crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
++ u_int32_t flags);
++extern int crypto_kregister(u_int32_t, int, u_int32_t);
++extern int crypto_unregister(u_int32_t driverid, int alg);
++extern int crypto_unregister_all(u_int32_t driverid);
++extern int crypto_dispatch(struct cryptop *crp);
++extern int crypto_kdispatch(struct cryptkop *);
++#define CRYPTO_SYMQ 0x1
++#define CRYPTO_ASYMQ 0x2
++extern int crypto_unblock(u_int32_t, int);
++extern void crypto_done(struct cryptop *crp);
++extern void crypto_kdone(struct cryptkop *);
++extern int crypto_getfeat(int *);
++
++extern void crypto_freereq(struct cryptop *crp);
++extern struct cryptop *crypto_getreq(int num);
++
++extern int crypto_usercrypto; /* userland may do crypto requests */
++extern int crypto_userasymcrypto; /* userland may do asym crypto reqs */
++extern int crypto_devallowsoft; /* only use hardware crypto */
++
++/*
++ * random number support, crypto_unregister_all will unregister
++ */
++extern int crypto_rregister(u_int32_t driverid,
++ int (*read_random)(void *arg, u_int32_t *buf, int len), void *arg);
++extern int crypto_runregister_all(u_int32_t driverid);
++
++/*
++ * Crypto-related utility routines used mainly by drivers.
++ *
++ * XXX these don't really belong here; but for now they're
++ * kept apart from the rest of the system.
++ */
++struct uio;
++extern void cuio_copydata(struct uio* uio, int off, int len, caddr_t cp);
++extern void cuio_copyback(struct uio* uio, int off, int len, caddr_t cp);
++extern struct iovec *cuio_getptr(struct uio *uio, int loc, int *off);
++
++extern void crypto_copyback(int flags, caddr_t buf, int off, int size,
++ caddr_t in);
++extern void crypto_copydata(int flags, caddr_t buf, int off, int size,
++ caddr_t out);
++extern int crypto_apply(int flags, caddr_t buf, int off, int len,
++ int (*f)(void *, void *, u_int), void *arg);
++
++#endif /* __KERNEL__ */
++#endif /* _CRYPTO_CRYPTO_H_ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/cryptosoft.c linux-2.6.36/crypto/ocf/cryptosoft.c
+--- linux-2.6.36.orig/crypto/ocf/cryptosoft.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/cryptosoft.c 2010-11-09 20:28:04.532495450 +0100
+@@ -0,0 +1,1210 @@
++/*
++ * An OCF module that uses the linux kernel cryptoapi, based on the
++ * original cryptosoft for BSD by Angelos D. Keromytis (angelos@cis.upenn.edu)
++ * but is mostly unrecognisable,
++ *
++ * Written by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2004-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ * 1. distributions of this source code include the above copyright
++ * notice, this list of conditions and the following disclaimer;
++ *
++ * 2. distributions in binary form include the above copyright
++ * notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other associated materials;
++ *
++ * 3. the copyright holder's name is not used to endorse products
++ * built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ * ---------------------------------------------------------------------------
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/crypto.h>
++#include <linux/mm.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
++#include <linux/scatterlist.h>
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
++#include <crypto/hash.h>
++#endif
++
++#include <cryptodev.h>
++#include <uio.h>
++
++struct {
++ softc_device_decl sc_dev;
++} swcr_softc;
++
++#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
++
++#define SW_TYPE_CIPHER 0x01
++#define SW_TYPE_HMAC 0x02
++#define SW_TYPE_HASH 0x04
++#define SW_TYPE_COMP 0x08
++#define SW_TYPE_BLKCIPHER 0x10
++#define SW_TYPE_ALG_MASK 0x1f
++
++#define SW_TYPE_ASYNC 0x8000
++
++/* We change some of the above if we have an async interface */
++
++#define SW_TYPE_ALG_AMASK (SW_TYPE_ALG_MASK | SW_TYPE_ASYNC)
++
++#define SW_TYPE_ABLKCIPHER (SW_TYPE_BLKCIPHER | SW_TYPE_ASYNC)
++#define SW_TYPE_AHASH (SW_TYPE_HASH | SW_TYPE_ASYNC)
++#define SW_TYPE_AHMAC (SW_TYPE_HMAC | SW_TYPE_ASYNC)
++
++#define SCATTERLIST_MAX 16
++
++struct swcr_data {
++ int sw_type;
++ int sw_alg;
++ struct crypto_tfm *sw_tfm;
++ union {
++ struct {
++ char *sw_key;
++ int sw_klen;
++ int sw_mlen;
++ } hmac;
++ void *sw_comp_buf;
++ } u;
++ struct swcr_data *sw_next;
++};
++
++struct swcr_req {
++ struct swcr_data *sw_head;
++ struct swcr_data *sw;
++ struct cryptop *crp;
++ struct cryptodesc *crd;
++ struct scatterlist sg[SCATTERLIST_MAX];
++ unsigned char iv[EALG_MAX_BLOCK_LEN];
++ char result[HASH_MAX_LEN];
++ void *crypto_req;
++};
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++static kmem_cache_t *swcr_req_cache;
++#else
++static struct kmem_cache *swcr_req_cache;
++#endif
++
++#ifndef CRYPTO_TFM_MODE_CBC
++/*
++ * As of linux-2.6.21 this is no longer defined, and presumably no longer
++ * needed to be passed into the crypto core code.
++ */
++#define CRYPTO_TFM_MODE_CBC 0
++#define CRYPTO_TFM_MODE_ECB 0
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ /*
++ * Linux 2.6.19 introduced a new Crypto API, setup macro's to convert new
++ * API into old API.
++ */
++
++ /* Symmetric/Block Cipher */
++ struct blkcipher_desc
++ {
++ struct crypto_tfm *tfm;
++ void *info;
++ };
++ #define ecb(X) #X , CRYPTO_TFM_MODE_ECB
++ #define cbc(X) #X , CRYPTO_TFM_MODE_CBC
++ #define crypto_has_blkcipher(X, Y, Z) crypto_alg_available(X, 0)
++ #define crypto_blkcipher_cast(X) X
++ #define crypto_blkcipher_tfm(X) X
++ #define crypto_alloc_blkcipher(X, Y, Z) crypto_alloc_tfm(X, mode)
++ #define crypto_blkcipher_ivsize(X) crypto_tfm_alg_ivsize(X)
++ #define crypto_blkcipher_blocksize(X) crypto_tfm_alg_blocksize(X)
++ #define crypto_blkcipher_setkey(X, Y, Z) crypto_cipher_setkey(X, Y, Z)
++ #define crypto_blkcipher_encrypt_iv(W, X, Y, Z) \
++ crypto_cipher_encrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
++ #define crypto_blkcipher_decrypt_iv(W, X, Y, Z) \
++ crypto_cipher_decrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
++ #define crypto_blkcipher_set_flags(x, y) /* nop */
++
++ /* Hash/HMAC/Digest */
++ struct hash_desc
++ {
++ struct crypto_tfm *tfm;
++ };
++ #define hmac(X) #X , 0
++ #define crypto_has_hash(X, Y, Z) crypto_alg_available(X, 0)
++ #define crypto_hash_cast(X) X
++ #define crypto_hash_tfm(X) X
++ #define crypto_alloc_hash(X, Y, Z) crypto_alloc_tfm(X, mode)
++ #define crypto_hash_digestsize(X) crypto_tfm_alg_digestsize(X)
++ #define crypto_hash_digest(W, X, Y, Z) \
++ crypto_digest_digest((W)->tfm, X, sg_num, Z)
++
++ /* Asymmetric Cipher */
++ #define crypto_has_cipher(X, Y, Z) crypto_alg_available(X, 0)
++
++ /* Compression */
++ #define crypto_has_comp(X, Y, Z) crypto_alg_available(X, 0)
++ #define crypto_comp_tfm(X) X
++ #define crypto_comp_cast(X) X
++ #define crypto_alloc_comp(X, Y, Z) crypto_alloc_tfm(X, mode)
++ #define plain(X) #X , 0
++#else
++ #define ecb(X) "ecb(" #X ")" , 0
++ #define cbc(X) "cbc(" #X ")" , 0
++ #define hmac(X) "hmac(" #X ")" , 0
++ #define plain(X) #X , 0
++#endif /* if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
++/* no ablkcipher in older kernels */
++#define crypto_alloc_ablkcipher(a,b,c) (NULL)
++#define crypto_ablkcipher_tfm(x) ((struct crypto_tfm *)(x))
++#define crypto_ablkcipher_set_flags(a, b) /* nop */
++#define crypto_ablkcipher_setkey(x, y, z) (-EINVAL)
++#define crypto_has_ablkcipher(a,b,c) (0)
++#else
++#define HAVE_ABLKCIPHER
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
++/* no ahash in older kernels */
++#define crypto_ahash_tfm(x) ((struct crypto_tfm *)(x))
++#define crypto_alloc_ahash(a,b,c) (NULL)
++#define crypto_ahash_digestsize(x) 0
++#else
++#define HAVE_AHASH
++#endif
++
++struct crypto_details {
++ char *alg_name;
++ int mode;
++ int sw_type;
++};
++
++static struct crypto_details crypto_details[] = {
++ [CRYPTO_DES_CBC] = { cbc(des), SW_TYPE_BLKCIPHER, },
++ [CRYPTO_3DES_CBC] = { cbc(des3_ede), SW_TYPE_BLKCIPHER, },
++ [CRYPTO_BLF_CBC] = { cbc(blowfish), SW_TYPE_BLKCIPHER, },
++ [CRYPTO_CAST_CBC] = { cbc(cast5), SW_TYPE_BLKCIPHER, },
++ [CRYPTO_SKIPJACK_CBC] = { cbc(skipjack), SW_TYPE_BLKCIPHER, },
++ [CRYPTO_MD5_HMAC] = { hmac(md5), SW_TYPE_HMAC, },
++ [CRYPTO_SHA1_HMAC] = { hmac(sha1), SW_TYPE_HMAC, },
++ [CRYPTO_RIPEMD160_HMAC] = { hmac(ripemd160), SW_TYPE_HMAC, },
++ [CRYPTO_MD5_KPDK] = { plain(md5-kpdk), SW_TYPE_HASH, },
++ [CRYPTO_SHA1_KPDK] = { plain(sha1-kpdk), SW_TYPE_HASH, },
++ [CRYPTO_AES_CBC] = { cbc(aes), SW_TYPE_BLKCIPHER, },
++ [CRYPTO_ARC4] = { ecb(arc4), SW_TYPE_BLKCIPHER, },
++ [CRYPTO_MD5] = { plain(md5), SW_TYPE_HASH, },
++ [CRYPTO_SHA1] = { plain(sha1), SW_TYPE_HASH, },
++ [CRYPTO_NULL_HMAC] = { hmac(digest_null), SW_TYPE_HMAC, },
++ [CRYPTO_NULL_CBC] = { cbc(cipher_null), SW_TYPE_BLKCIPHER, },
++ [CRYPTO_DEFLATE_COMP] = { plain(deflate), SW_TYPE_COMP, },
++ [CRYPTO_SHA2_256_HMAC] = { hmac(sha256), SW_TYPE_HMAC, },
++ [CRYPTO_SHA2_384_HMAC] = { hmac(sha384), SW_TYPE_HMAC, },
++ [CRYPTO_SHA2_512_HMAC] = { hmac(sha512), SW_TYPE_HMAC, },
++ [CRYPTO_CAMELLIA_CBC] = { cbc(camellia), SW_TYPE_BLKCIPHER, },
++ [CRYPTO_SHA2_256] = { plain(sha256), SW_TYPE_HASH, },
++ [CRYPTO_SHA2_384] = { plain(sha384), SW_TYPE_HASH, },
++ [CRYPTO_SHA2_512] = { plain(sha512), SW_TYPE_HASH, },
++ [CRYPTO_RIPEMD160] = { plain(ripemd160), SW_TYPE_HASH, },
++};
++
++int32_t swcr_id = -1;
++module_param(swcr_id, int, 0444);
++MODULE_PARM_DESC(swcr_id, "Read-Only OCF ID for cryptosoft driver");
++
++int swcr_fail_if_compression_grows = 1;
++module_param(swcr_fail_if_compression_grows, int, 0644);
++MODULE_PARM_DESC(swcr_fail_if_compression_grows,
++ "Treat compression that results in more data as a failure");
++
++int swcr_no_ahash = 0;
++module_param(swcr_no_ahash, int, 0644);
++MODULE_PARM_DESC(swcr_no_ahash,
++ "Do not use async hash/hmac even if available");
++
++int swcr_no_ablk = 0;
++module_param(swcr_no_ablk, int, 0644);
++MODULE_PARM_DESC(swcr_no_ablk,
++ "Do not use async blk ciphers even if available");
++
++static struct swcr_data **swcr_sessions = NULL;
++static u_int32_t swcr_sesnum = 0;
++
++static int swcr_process(device_t, struct cryptop *, int);
++static int swcr_newsession(device_t, u_int32_t *, struct cryptoini *);
++static int swcr_freesession(device_t, u_int64_t);
++
++static device_method_t swcr_methods = {
++ /* crypto device methods */
++ DEVMETHOD(cryptodev_newsession, swcr_newsession),
++ DEVMETHOD(cryptodev_freesession,swcr_freesession),
++ DEVMETHOD(cryptodev_process, swcr_process),
++};
++
++#define debug swcr_debug
++int swcr_debug = 0;
++module_param(swcr_debug, int, 0644);
++MODULE_PARM_DESC(swcr_debug, "Enable debug");
++
++static void swcr_process_req(struct swcr_req *req);
++
++/*
++ * Generate a new software session.
++ */
++static int
++swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
++{
++ struct swcr_data **swd;
++ u_int32_t i;
++ int error;
++ char *algo;
++ int mode;
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (sid == NULL || cri == NULL) {
++ dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ if (swcr_sessions) {
++ for (i = 1; i < swcr_sesnum; i++)
++ if (swcr_sessions[i] == NULL)
++ break;
++ } else
++ i = 1; /* NB: to silence compiler warning */
++
++ if (swcr_sessions == NULL || i == swcr_sesnum) {
++ if (swcr_sessions == NULL) {
++ i = 1; /* We leave swcr_sessions[0] empty */
++ swcr_sesnum = CRYPTO_SW_SESSIONS;
++ } else
++ swcr_sesnum *= 2;
++
++ swd = kmalloc(swcr_sesnum * sizeof(struct swcr_data *), SLAB_ATOMIC);
++ if (swd == NULL) {
++ /* Reset session number */
++ if (swcr_sesnum == CRYPTO_SW_SESSIONS)
++ swcr_sesnum = 0;
++ else
++ swcr_sesnum /= 2;
++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++ return ENOBUFS;
++ }
++ memset(swd, 0, swcr_sesnum * sizeof(struct swcr_data *));
++
++ /* Copy existing sessions */
++ if (swcr_sessions) {
++ memcpy(swd, swcr_sessions,
++ (swcr_sesnum / 2) * sizeof(struct swcr_data *));
++ kfree(swcr_sessions);
++ }
++
++ swcr_sessions = swd;
++ }
++
++ swd = &swcr_sessions[i];
++ *sid = i;
++
++ while (cri) {
++ *swd = (struct swcr_data *) kmalloc(sizeof(struct swcr_data),
++ SLAB_ATOMIC);
++ if (*swd == NULL) {
++ swcr_freesession(NULL, i);
++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++ return ENOBUFS;
++ }
++ memset(*swd, 0, sizeof(struct swcr_data));
++
++ if (cri->cri_alg < 0 ||
++ cri->cri_alg>=sizeof(crypto_details)/sizeof(crypto_details[0])){
++ printk("cryptosoft: Unknown algorithm 0x%x\n", cri->cri_alg);
++ swcr_freesession(NULL, i);
++ return EINVAL;
++ }
++
++ algo = crypto_details[cri->cri_alg].alg_name;
++ if (!algo || !*algo) {
++ printk("cryptosoft: Unsupported algorithm 0x%x\n", cri->cri_alg);
++ swcr_freesession(NULL, i);
++ return EINVAL;
++ }
++
++ mode = crypto_details[cri->cri_alg].mode;
++ (*swd)->sw_type = crypto_details[cri->cri_alg].sw_type;
++ (*swd)->sw_alg = cri->cri_alg;
++
++ /* Algorithm specific configuration */
++ switch (cri->cri_alg) {
++ case CRYPTO_NULL_CBC:
++ cri->cri_klen = 0; /* make it work with crypto API */
++ break;
++ default:
++ break;
++ }
++
++ if ((*swd)->sw_type & SW_TYPE_BLKCIPHER) {
++ dprintk("%s crypto_alloc_*blkcipher(%s, 0x%x)\n", __FUNCTION__,
++ algo, mode);
++
++ /* try async first */
++ (*swd)->sw_tfm = swcr_no_ablk ? NULL :
++ crypto_ablkcipher_tfm(crypto_alloc_ablkcipher(algo, 0, 0));
++ if ((*swd)->sw_tfm) {
++ dprintk("%s %s cipher is async\n", __FUNCTION__, algo);
++ (*swd)->sw_type |= SW_TYPE_ASYNC;
++ } else {
++ dprintk("%s %s cipher is sync\n", __FUNCTION__, algo);
++ (*swd)->sw_tfm = crypto_blkcipher_tfm(
++ crypto_alloc_blkcipher(algo, 0, CRYPTO_ALG_ASYNC));
++ }
++ if (!(*swd)->sw_tfm) {
++ dprintk("cryptosoft: crypto_alloc_blkcipher failed(%s, 0x%x)\n",
++ algo,mode);
++ swcr_freesession(NULL, i);
++ return EINVAL;
++ }
++
++ if (debug) {
++ dprintk("%s key:cri->cri_klen=%d,(cri->cri_klen + 7)/8=%d",
++ __FUNCTION__, cri->cri_klen, (cri->cri_klen + 7) / 8);
++ for (i = 0; i < (cri->cri_klen + 7) / 8; i++)
++ dprintk("%s0x%x", (i % 8) ? " " : "\n ",
++ cri->cri_key[i] & 0xff);
++ dprintk("\n");
++ }
++ if ((*swd)->sw_type & SW_TYPE_ASYNC) {
++ /* OCF doesn't enforce keys */
++ crypto_ablkcipher_set_flags(
++ __crypto_ablkcipher_cast((*swd)->sw_tfm),
++ CRYPTO_TFM_REQ_WEAK_KEY);
++ error = crypto_ablkcipher_setkey(
++ __crypto_ablkcipher_cast((*swd)->sw_tfm),
++ cri->cri_key, (cri->cri_klen + 7) / 8);
++ } else {
++ /* OCF doesn't enforce keys */
++ crypto_blkcipher_set_flags(
++ crypto_blkcipher_cast((*swd)->sw_tfm),
++ CRYPTO_TFM_REQ_WEAK_KEY);
++ error = crypto_blkcipher_setkey(
++ crypto_blkcipher_cast((*swd)->sw_tfm),
++ cri->cri_key, (cri->cri_klen + 7) / 8);
++ }
++ if (error) {
++ printk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", error,
++ (*swd)->sw_tfm->crt_flags);
++ swcr_freesession(NULL, i);
++ return error;
++ }
++ } else if ((*swd)->sw_type & (SW_TYPE_HMAC | SW_TYPE_HASH)) {
++ dprintk("%s crypto_alloc_*hash(%s, 0x%x)\n", __FUNCTION__,
++ algo, mode);
++
++ /* try async first */
++ (*swd)->sw_tfm = swcr_no_ahash ? NULL :
++ crypto_ahash_tfm(crypto_alloc_ahash(algo, 0, 0));
++ if ((*swd)->sw_tfm) {
++ dprintk("%s %s hash is async\n", __FUNCTION__, algo);
++ (*swd)->sw_type |= SW_TYPE_ASYNC;
++ } else {
++ dprintk("%s %s hash is sync\n", __FUNCTION__, algo);
++ (*swd)->sw_tfm = crypto_hash_tfm(
++ crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC));
++ }
++
++ if (!(*swd)->sw_tfm) {
++ dprintk("cryptosoft: crypto_alloc_hash failed(%s,0x%x)\n",
++ algo, mode);
++ swcr_freesession(NULL, i);
++ return EINVAL;
++ }
++
++ (*swd)->u.hmac.sw_klen = (cri->cri_klen + 7) / 8;
++ (*swd)->u.hmac.sw_key = (char *)kmalloc((*swd)->u.hmac.sw_klen,
++ SLAB_ATOMIC);
++ if ((*swd)->u.hmac.sw_key == NULL) {
++ swcr_freesession(NULL, i);
++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++ return ENOBUFS;
++ }
++ memcpy((*swd)->u.hmac.sw_key, cri->cri_key, (*swd)->u.hmac.sw_klen);
++ if (cri->cri_mlen) {
++ (*swd)->u.hmac.sw_mlen = cri->cri_mlen;
++ } else if ((*swd)->sw_type & SW_TYPE_ASYNC) {
++ (*swd)->u.hmac.sw_mlen = crypto_ahash_digestsize(
++ __crypto_ahash_cast((*swd)->sw_tfm));
++ } else {
++ (*swd)->u.hmac.sw_mlen = crypto_hash_digestsize(
++ crypto_hash_cast((*swd)->sw_tfm));
++ }
++ } else if ((*swd)->sw_type & SW_TYPE_COMP) {
++ (*swd)->sw_tfm = crypto_comp_tfm(
++ crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC));
++ if (!(*swd)->sw_tfm) {
++ dprintk("cryptosoft: crypto_alloc_comp failed(%s,0x%x)\n",
++ algo, mode);
++ swcr_freesession(NULL, i);
++ return EINVAL;
++ }
++ (*swd)->u.sw_comp_buf = kmalloc(CRYPTO_MAX_DATA_LEN, SLAB_ATOMIC);
++ if ((*swd)->u.sw_comp_buf == NULL) {
++ swcr_freesession(NULL, i);
++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++ return ENOBUFS;
++ }
++ } else {
++ printk("cryptosoft: Unhandled sw_type %d\n", (*swd)->sw_type);
++ swcr_freesession(NULL, i);
++ return EINVAL;
++ }
++
++ cri = cri->cri_next;
++ swd = &((*swd)->sw_next);
++ }
++ return 0;
++}
++
++/*
++ * Free a session.
++ */
++static int
++swcr_freesession(device_t dev, u_int64_t tid)
++{
++ struct swcr_data *swd;
++ u_int32_t sid = CRYPTO_SESID2LID(tid);
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (sid > swcr_sesnum || swcr_sessions == NULL ||
++ swcr_sessions[sid] == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return(EINVAL);
++ }
++
++ /* Silently accept and return */
++ if (sid == 0)
++ return(0);
++
++ while ((swd = swcr_sessions[sid]) != NULL) {
++ swcr_sessions[sid] = swd->sw_next;
++ if (swd->sw_tfm) {
++ switch (swd->sw_type & SW_TYPE_ALG_AMASK) {
++#ifdef HAVE_AHASH
++ case SW_TYPE_AHMAC:
++ case SW_TYPE_AHASH:
++ crypto_free_ahash(__crypto_ahash_cast(swd->sw_tfm));
++ break;
++#endif
++#ifdef HAVE_ABLKCIPHER
++ case SW_TYPE_ABLKCIPHER:
++ crypto_free_ablkcipher(__crypto_ablkcipher_cast(swd->sw_tfm));
++ break;
++#endif
++ case SW_TYPE_BLKCIPHER:
++ crypto_free_blkcipher(crypto_blkcipher_cast(swd->sw_tfm));
++ break;
++ case SW_TYPE_HMAC:
++ case SW_TYPE_HASH:
++ crypto_free_hash(crypto_hash_cast(swd->sw_tfm));
++ break;
++ case SW_TYPE_COMP:
++ crypto_free_comp(crypto_comp_cast(swd->sw_tfm));
++ default:
++ crypto_free_tfm(swd->sw_tfm);
++ break;
++ }
++ swd->sw_tfm = NULL;
++ }
++ if (swd->sw_type & SW_TYPE_COMP) {
++ if (swd->u.sw_comp_buf)
++ kfree(swd->u.sw_comp_buf);
++ } else {
++ if (swd->u.hmac.sw_key)
++ kfree(swd->u.hmac.sw_key);
++ }
++ kfree(swd);
++ }
++ return 0;
++}
++
++#if defined(HAVE_ABLKCIPHER) || defined(HAVE_AHASH)
++/* older kernels had no async interface */
++
++static void swcr_process_callback(struct crypto_async_request *creq, int err)
++{
++ struct swcr_req *req = creq->data;
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (err) {
++ if (err == -EINPROGRESS)
++ return;
++ dprintk("%s() fail %d\n", __FUNCTION__, -err);
++ req->crp->crp_etype = -err;
++ goto done;
++ }
++
++ switch (req->sw->sw_type & SW_TYPE_ALG_AMASK) {
++ case SW_TYPE_AHMAC:
++ case SW_TYPE_AHASH:
++ crypto_copyback(req->crp->crp_flags, req->crp->crp_buf,
++ req->crd->crd_inject, req->sw->u.hmac.sw_mlen, req->result);
++ ahash_request_free(req->crypto_req);
++ break;
++ case SW_TYPE_ABLKCIPHER:
++ ablkcipher_request_free(req->crypto_req);
++ break;
++ default:
++ req->crp->crp_etype = EINVAL;
++ goto done;
++ }
++
++ req->crd = req->crd->crd_next;
++ if (req->crd) {
++ swcr_process_req(req);
++ return;
++ }
++
++done:
++ dprintk("%s crypto_done %p\n", __FUNCTION__, req);
++ crypto_done(req->crp);
++ kmem_cache_free(swcr_req_cache, req);
++}
++#endif /* defined(HAVE_ABLKCIPHER) || defined(HAVE_AHASH) */
++
++
++static void swcr_process_req(struct swcr_req *req)
++{
++ struct swcr_data *sw;
++ struct cryptop *crp = req->crp;
++ struct cryptodesc *crd = req->crd;
++ struct sk_buff *skb = (struct sk_buff *) crp->crp_buf;
++ struct uio *uiop = (struct uio *) crp->crp_buf;
++ int sg_num, sg_len, skip;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ /*
++ * Find the crypto context.
++ *
++ * XXX Note that the logic here prevents us from having
++ * XXX the same algorithm multiple times in a session
++ * XXX (or rather, we can but it won't give us the right
++ * XXX results). To do that, we'd need some way of differentiating
++ * XXX between the various instances of an algorithm (so we can
++ * XXX locate the correct crypto context).
++ */
++ for (sw = req->sw_head; sw && sw->sw_alg != crd->crd_alg; sw = sw->sw_next)
++ ;
++
++ /* No such context ? */
++ if (sw == NULL) {
++ crp->crp_etype = EINVAL;
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ goto done;
++ }
++
++ req->sw = sw;
++ skip = crd->crd_skip;
++
++ /*
++ * setup the SG list skip from the start of the buffer
++ */
++ memset(req->sg, 0, sizeof(req->sg));
++ sg_init_table(req->sg, SCATTERLIST_MAX);
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ int i, len;
++
++ sg_num = 0;
++ sg_len = 0;
++
++ if (skip < skb_headlen(skb)) {
++ len = skb_headlen(skb) - skip;
++ if (len + sg_len > crd->crd_len)
++ len = crd->crd_len - sg_len;
++ sg_set_page(&req->sg[sg_num],
++ virt_to_page(skb->data + skip), len,
++ offset_in_page(skb->data + skip));
++ sg_len += len;
++ sg_num++;
++ skip = 0;
++ } else
++ skip -= skb_headlen(skb);
++
++ for (i = 0; sg_len < crd->crd_len &&
++ i < skb_shinfo(skb)->nr_frags &&
++ sg_num < SCATTERLIST_MAX; i++) {
++ if (skip < skb_shinfo(skb)->frags[i].size) {
++ len = skb_shinfo(skb)->frags[i].size - skip;
++ if (len + sg_len > crd->crd_len)
++ len = crd->crd_len - sg_len;
++ sg_set_page(&req->sg[sg_num],
++ skb_shinfo(skb)->frags[i].page,
++ len,
++ skb_shinfo(skb)->frags[i].page_offset + skip);
++ sg_len += len;
++ sg_num++;
++ skip = 0;
++ } else
++ skip -= skb_shinfo(skb)->frags[i].size;
++ }
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ int len;
++
++ sg_len = 0;
++ for (sg_num = 0; sg_len < crd->crd_len &&
++ sg_num < uiop->uio_iovcnt &&
++ sg_num < SCATTERLIST_MAX; sg_num++) {
++ if (skip <= uiop->uio_iov[sg_num].iov_len) {
++ len = uiop->uio_iov[sg_num].iov_len - skip;
++ if (len + sg_len > crd->crd_len)
++ len = crd->crd_len - sg_len;
++ sg_set_page(&req->sg[sg_num],
++ virt_to_page(uiop->uio_iov[sg_num].iov_base+skip),
++ len,
++ offset_in_page(uiop->uio_iov[sg_num].iov_base+skip));
++ sg_len += len;
++ skip = 0;
++ } else
++ skip -= uiop->uio_iov[sg_num].iov_len;
++ }
++ } else {
++ sg_len = (crp->crp_ilen - skip);
++ if (sg_len > crd->crd_len)
++ sg_len = crd->crd_len;
++ sg_set_page(&req->sg[0], virt_to_page(crp->crp_buf + skip),
++ sg_len, offset_in_page(crp->crp_buf + skip));
++ sg_num = 1;
++ }
++
++ switch (sw->sw_type & SW_TYPE_ALG_AMASK) {
++
++#ifdef HAVE_AHASH
++ case SW_TYPE_AHMAC:
++ case SW_TYPE_AHASH:
++ {
++ int ret;
++
++ /* check we have room for the result */
++ if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) {
++ dprintk("cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d "
++ "digestsize=%d\n", crp->crp_ilen, crd->crd_skip + sg_len,
++ crd->crd_inject, sw->u.hmac.sw_mlen);
++ crp->crp_etype = EINVAL;
++ goto done;
++ }
++
++ req->crypto_req =
++ ahash_request_alloc(__crypto_ahash_cast(sw->sw_tfm),GFP_KERNEL);
++ if (!req->crypto_req) {
++ crp->crp_etype = ENOMEM;
++ dprintk("%s,%d: ENOMEM ahash_request_alloc", __FILE__, __LINE__);
++ goto done;
++ }
++
++ ahash_request_set_callback(req->crypto_req,
++ CRYPTO_TFM_REQ_MAY_BACKLOG, swcr_process_callback, req);
++
++ memset(req->result, 0, sizeof(req->result));
++
++ if (sw->sw_type & SW_TYPE_AHMAC)
++ crypto_ahash_setkey(__crypto_ahash_cast(sw->sw_tfm),
++ sw->u.hmac.sw_key, sw->u.hmac.sw_klen);
++ ahash_request_set_crypt(req->crypto_req, req->sg, req->result, sg_len);
++ ret = crypto_ahash_digest(req->crypto_req);
++ switch (ret) {
++ case -EINPROGRESS:
++ case -EBUSY:
++ return;
++ default:
++ case 0:
++ dprintk("hash OP %s %d\n", ret ? "failed" : "success", ret);
++ crp->crp_etype = ret;
++ ahash_request_free(req->crypto_req);
++ goto done;
++ }
++ } break;
++#endif /* HAVE_AHASH */
++
++#ifdef HAVE_ABLKCIPHER
++ case SW_TYPE_ABLKCIPHER: {
++ int ret;
++ unsigned char *ivp = req->iv;
++ int ivsize =
++ crypto_ablkcipher_ivsize(__crypto_ablkcipher_cast(sw->sw_tfm));
++
++ if (sg_len < crypto_ablkcipher_blocksize(
++ __crypto_ablkcipher_cast(sw->sw_tfm))) {
++ crp->crp_etype = EINVAL;
++ dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__,
++ sg_len, crypto_ablkcipher_blocksize(
++ __crypto_ablkcipher_cast(sw->sw_tfm)));
++ goto done;
++ }
++
++ if (ivsize > sizeof(req->iv)) {
++ crp->crp_etype = EINVAL;
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ goto done;
++ }
++
++ req->crypto_req = ablkcipher_request_alloc(
++ __crypto_ablkcipher_cast(sw->sw_tfm), GFP_KERNEL);
++ if (!req->crypto_req) {
++ crp->crp_etype = ENOMEM;
++ dprintk("%s,%d: ENOMEM ablkcipher_request_alloc",
++ __FILE__, __LINE__);
++ goto done;
++ }
++
++ ablkcipher_request_set_callback(req->crypto_req,
++ CRYPTO_TFM_REQ_MAY_BACKLOG, swcr_process_callback, req);
++
++ if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
++ int i, error;
++
++ if (debug) {
++ dprintk("%s key:", __FUNCTION__);
++ for (i = 0; i < (crd->crd_klen + 7) / 8; i++)
++ dprintk("%s0x%x", (i % 8) ? " " : "\n ",
++ crd->crd_key[i] & 0xff);
++ dprintk("\n");
++ }
++ /* OCF doesn't enforce keys */
++ crypto_ablkcipher_set_flags(__crypto_ablkcipher_cast(sw->sw_tfm),
++ CRYPTO_TFM_REQ_WEAK_KEY);
++ error = crypto_ablkcipher_setkey(
++ __crypto_ablkcipher_cast(sw->sw_tfm), crd->crd_key,
++ (crd->crd_klen + 7) / 8);
++ if (error) {
++ dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n",
++ error, sw->sw_tfm->crt_flags);
++ crp->crp_etype = -error;
++ }
++ }
++
++ if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
++
++ if (crd->crd_flags & CRD_F_IV_EXPLICIT)
++ ivp = crd->crd_iv;
++ else
++ get_random_bytes(ivp, ivsize);
++ /*
++ * do we have to copy the IV back to the buffer ?
++ */
++ if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++ crypto_copyback(crp->crp_flags, crp->crp_buf,
++ crd->crd_inject, ivsize, (caddr_t)ivp);
++ }
++ ablkcipher_request_set_crypt(req->crypto_req, req->sg, req->sg,
++ sg_len, ivp);
++ ret = crypto_ablkcipher_encrypt(req->crypto_req);
++
++ } else { /*decrypt */
++
++ if (crd->crd_flags & CRD_F_IV_EXPLICIT)
++ ivp = crd->crd_iv;
++ else
++ crypto_copydata(crp->crp_flags, crp->crp_buf,
++ crd->crd_inject, ivsize, (caddr_t)ivp);
++ ablkcipher_request_set_crypt(req->crypto_req, req->sg, req->sg,
++ sg_len, ivp);
++ ret = crypto_ablkcipher_decrypt(req->crypto_req);
++ }
++
++ switch (ret) {
++ case -EINPROGRESS:
++ case -EBUSY:
++ return;
++ default:
++ case 0:
++ dprintk("crypto OP %s %d\n", ret ? "failed" : "success", ret);
++ crp->crp_etype = ret;
++ goto done;
++ }
++ } break;
++#endif /* HAVE_ABLKCIPHER */
++
++ case SW_TYPE_BLKCIPHER: {
++ unsigned char iv[EALG_MAX_BLOCK_LEN];
++ unsigned char *ivp = iv;
++ struct blkcipher_desc desc;
++ int ivsize = crypto_blkcipher_ivsize(crypto_blkcipher_cast(sw->sw_tfm));
++
++ if (sg_len < crypto_blkcipher_blocksize(
++ crypto_blkcipher_cast(sw->sw_tfm))) {
++ crp->crp_etype = EINVAL;
++ dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__,
++ sg_len, crypto_blkcipher_blocksize(
++ crypto_blkcipher_cast(sw->sw_tfm)));
++ goto done;
++ }
++
++ if (ivsize > sizeof(iv)) {
++ crp->crp_etype = EINVAL;
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ goto done;
++ }
++
++ if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
++ int i, error;
++
++ if (debug) {
++ dprintk("%s key:", __FUNCTION__);
++ for (i = 0; i < (crd->crd_klen + 7) / 8; i++)
++ dprintk("%s0x%x", (i % 8) ? " " : "\n ",
++ crd->crd_key[i] & 0xff);
++ dprintk("\n");
++ }
++ /* OCF doesn't enforce keys */
++ crypto_blkcipher_set_flags(crypto_blkcipher_cast(sw->sw_tfm),
++ CRYPTO_TFM_REQ_WEAK_KEY);
++ error = crypto_blkcipher_setkey(
++ crypto_blkcipher_cast(sw->sw_tfm), crd->crd_key,
++ (crd->crd_klen + 7) / 8);
++ if (error) {
++ dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n",
++ error, sw->sw_tfm->crt_flags);
++ crp->crp_etype = -error;
++ }
++ }
++
++ memset(&desc, 0, sizeof(desc));
++ desc.tfm = crypto_blkcipher_cast(sw->sw_tfm);
++
++ if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
++
++ if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
++ ivp = crd->crd_iv;
++ } else {
++ get_random_bytes(ivp, ivsize);
++ }
++ /*
++ * do we have to copy the IV back to the buffer ?
++ */
++ if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++ crypto_copyback(crp->crp_flags, crp->crp_buf,
++ crd->crd_inject, ivsize, (caddr_t)ivp);
++ }
++ desc.info = ivp;
++ crypto_blkcipher_encrypt_iv(&desc, req->sg, req->sg, sg_len);
++
++ } else { /*decrypt */
++
++ if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
++ ivp = crd->crd_iv;
++ } else {
++ crypto_copydata(crp->crp_flags, crp->crp_buf,
++ crd->crd_inject, ivsize, (caddr_t)ivp);
++ }
++ desc.info = ivp;
++ crypto_blkcipher_decrypt_iv(&desc, req->sg, req->sg, sg_len);
++ }
++ } break;
++
++ case SW_TYPE_HMAC:
++ case SW_TYPE_HASH:
++ {
++ char result[HASH_MAX_LEN];
++ struct hash_desc desc;
++
++ /* check we have room for the result */
++ if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) {
++ dprintk("cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d "
++ "digestsize=%d\n", crp->crp_ilen, crd->crd_skip + sg_len,
++ crd->crd_inject, sw->u.hmac.sw_mlen);
++ crp->crp_etype = EINVAL;
++ goto done;
++ }
++
++ memset(&desc, 0, sizeof(desc));
++ desc.tfm = crypto_hash_cast(sw->sw_tfm);
++
++ memset(result, 0, sizeof(result));
++
++ if (sw->sw_type & SW_TYPE_HMAC) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ crypto_hmac(sw->sw_tfm, sw->u.hmac.sw_key, &sw->u.hmac.sw_klen,
++ req->sg, sg_num, result);
++#else
++ crypto_hash_setkey(desc.tfm, sw->u.hmac.sw_key,
++ sw->u.hmac.sw_klen);
++ crypto_hash_digest(&desc, req->sg, sg_len, result);
++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
++
++ } else { /* SW_TYPE_HASH */
++ crypto_hash_digest(&desc, req->sg, sg_len, result);
++ }
++
++ crypto_copyback(crp->crp_flags, crp->crp_buf,
++ crd->crd_inject, sw->u.hmac.sw_mlen, result);
++ }
++ break;
++
++ case SW_TYPE_COMP: {
++ void *ibuf = NULL;
++ void *obuf = sw->u.sw_comp_buf;
++ int ilen = sg_len, olen = CRYPTO_MAX_DATA_LEN;
++ int ret = 0;
++
++ /*
++ * we need to use an additional copy if there is more than one
++ * input chunk since the kernel comp routines do not handle
++ * SG yet. Otherwise we just use the input buffer as is.
++ * Rather than allocate another buffer we just split the tmp
++ * buffer we already have.
++ * Perhaps we should just use zlib directly ?
++ */
++ if (sg_num > 1) {
++ int blk;
++
++ ibuf = obuf;
++ for (blk = 0; blk < sg_num; blk++) {
++ memcpy(obuf, sg_virt(&req->sg[blk]),
++ req->sg[blk].length);
++ obuf += req->sg[blk].length;
++ }
++ olen -= sg_len;
++ } else
++ ibuf = sg_virt(&req->sg[0]);
++
++ if (crd->crd_flags & CRD_F_ENCRYPT) { /* compress */
++ ret = crypto_comp_compress(crypto_comp_cast(sw->sw_tfm),
++ ibuf, ilen, obuf, &olen);
++ if (!ret && olen > crd->crd_len) {
++ dprintk("cryptosoft: ERANGE compress %d into %d\n",
++ crd->crd_len, olen);
++ if (swcr_fail_if_compression_grows)
++ ret = ERANGE;
++ }
++ } else { /* decompress */
++ ret = crypto_comp_decompress(crypto_comp_cast(sw->sw_tfm),
++ ibuf, ilen, obuf, &olen);
++ if (!ret && (olen + crd->crd_inject) > crp->crp_olen) {
++ dprintk("cryptosoft: ETOOSMALL decompress %d into %d, "
++ "space for %d,at offset %d\n",
++ crd->crd_len, olen, crp->crp_olen, crd->crd_inject);
++ ret = ETOOSMALL;
++ }
++ }
++ if (ret)
++ dprintk("%s,%d: ret = %d\n", __FILE__, __LINE__, ret);
++
++ /*
++ * on success copy result back,
++ * linux crpyto API returns -errno, we need to fix that
++ */
++ crp->crp_etype = ret < 0 ? -ret : ret;
++ if (ret == 0) {
++ /* copy back the result and return it's size */
++ crypto_copyback(crp->crp_flags, crp->crp_buf,
++ crd->crd_inject, olen, obuf);
++ crp->crp_olen = olen;
++ }
++
++
++ } break;
++
++ default:
++ /* Unknown/unsupported algorithm */
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ crp->crp_etype = EINVAL;
++ goto done;
++ }
++
++done:
++ crypto_done(crp);
++ kmem_cache_free(swcr_req_cache, req);
++}
++
++
++/*
++ * Process a crypto request.
++ */
++static int
++swcr_process(device_t dev, struct cryptop *crp, int hint)
++{
++ struct swcr_req *req = NULL;
++ u_int32_t lid;
++
++ dprintk("%s()\n", __FUNCTION__);
++ /* Sanity check */
++ if (crp == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ crp->crp_etype = 0;
++
++ if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ crp->crp_etype = EINVAL;
++ goto done;
++ }
++
++ lid = crp->crp_sid & 0xffffffff;
++ if (lid >= swcr_sesnum || lid == 0 || swcr_sessions == NULL ||
++ swcr_sessions[lid] == NULL) {
++ crp->crp_etype = ENOENT;
++ dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);
++ goto done;
++ }
++
++ /*
++ * do some error checking outside of the loop for SKB and IOV processing
++ * this leaves us with valid skb or uiop pointers for later
++ */
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ struct sk_buff *skb = (struct sk_buff *) crp->crp_buf;
++ if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) {
++ printk("%s,%d: %d nr_frags > SCATTERLIST_MAX", __FILE__, __LINE__,
++ skb_shinfo(skb)->nr_frags);
++ goto done;
++ }
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ struct uio *uiop = (struct uio *) crp->crp_buf;
++ if (uiop->uio_iovcnt > SCATTERLIST_MAX) {
++ printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX", __FILE__, __LINE__,
++ uiop->uio_iovcnt);
++ goto done;
++ }
++ }
++
++ /*
++ * setup a new request ready for queuing
++ */
++ req = kmem_cache_alloc(swcr_req_cache, SLAB_ATOMIC);
++ if (req == NULL) {
++ dprintk("%s,%d: ENOMEM\n", __FILE__, __LINE__);
++ crp->crp_etype = ENOMEM;
++ goto done;
++ }
++ memset(req, 0, sizeof(*req));
++
++ req->sw_head = swcr_sessions[lid];
++ req->crp = crp;
++ req->crd = crp->crp_desc;
++
++ swcr_process_req(req);
++ return 0;
++
++done:
++ crypto_done(crp);
++ if (req)
++ kmem_cache_free(swcr_req_cache, req);
++ return 0;
++}
++
++
++static int
++cryptosoft_init(void)
++{
++ int i, sw_type, mode;
++ char *algo;
++
++ dprintk("%s(%p)\n", __FUNCTION__, cryptosoft_init);
++
++ swcr_req_cache = kmem_cache_create("cryptosoft_req",
++ sizeof(struct swcr_req), 0, SLAB_HWCACHE_ALIGN, NULL
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++ , NULL
++#endif
++ );
++ if (!swcr_req_cache) {
++ printk("cryptosoft: failed to create request cache\n");
++ return -ENOENT;
++ }
++
++ softc_device_init(&swcr_softc, "cryptosoft", 0, swcr_methods);
++
++ swcr_id = crypto_get_driverid(softc_get_device(&swcr_softc),
++ CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC);
++ if (swcr_id < 0) {
++ printk("cryptosoft: Software crypto device cannot initialize!");
++ return -ENODEV;
++ }
++
++#define REGISTER(alg) \
++ crypto_register(swcr_id, alg, 0,0)
++
++ for (i = 0; i < sizeof(crypto_details)/sizeof(crypto_details[0]); i++) {
++ int found;
++
++ algo = crypto_details[i].alg_name;
++ if (!algo || !*algo) {
++ dprintk("%s:Algorithm %d not supported\n", __FUNCTION__, i);
++ continue;
++ }
++
++ mode = crypto_details[i].mode;
++ sw_type = crypto_details[i].sw_type;
++
++ found = 0;
++ switch (sw_type & SW_TYPE_ALG_MASK) {
++ case SW_TYPE_CIPHER:
++ found = crypto_has_cipher(algo, 0, CRYPTO_ALG_ASYNC);
++ break;
++ case SW_TYPE_HMAC:
++ found = crypto_has_hash(algo, 0, swcr_no_ahash?CRYPTO_ALG_ASYNC:0);
++ break;
++ case SW_TYPE_HASH:
++ found = crypto_has_hash(algo, 0, swcr_no_ahash?CRYPTO_ALG_ASYNC:0);
++ break;
++ case SW_TYPE_COMP:
++ found = crypto_has_comp(algo, 0, CRYPTO_ALG_ASYNC);
++ break;
++ case SW_TYPE_BLKCIPHER:
++ found = crypto_has_blkcipher(algo, 0, CRYPTO_ALG_ASYNC);
++ if (!found && !swcr_no_ablk)
++ found = crypto_has_ablkcipher(algo, 0, 0);
++ break;
++ }
++ if (found) {
++ REGISTER(i);
++ } else {
++ dprintk("%s:Algorithm Type %d not supported (algorithm %d:'%s')\n",
++ __FUNCTION__, sw_type, i, algo);
++ }
++ }
++ return 0;
++}
++
++static void
++cryptosoft_exit(void)
++{
++ dprintk("%s()\n", __FUNCTION__);
++ crypto_unregister_all(swcr_id);
++ swcr_id = -1;
++ kmem_cache_destroy(swcr_req_cache);
++}
++
++late_initcall(cryptosoft_init);
++module_exit(cryptosoft_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("David McCullough <david_mccullough@securecomputing.com>");
++MODULE_DESCRIPTION("Cryptosoft (OCF module for kernel crypto)");
+diff -Nur linux-2.6.36.orig/crypto/ocf/ep80579/icp_asym.c linux-2.6.36/crypto/ocf/ep80579/icp_asym.c
+--- linux-2.6.36.orig/crypto/ocf/ep80579/icp_asym.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/ep80579/icp_asym.c 2010-11-09 20:28:04.572486503 +0100
+@@ -0,0 +1,1334 @@
++/***************************************************************************
++ *
++ * This file is provided under a dual BSD/GPLv2 license. When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * GPL LICENSE SUMMARY
++ *
++ * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ * The full GNU General Public License is included in this distribution
++ * in the file called LICENSE.GPL.
++ *
++ * Contact Information:
++ * Intel Corporation
++ *
++ * BSD LICENSE
++ *
++ * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
++ * 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 Intel Corporation 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE 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.
++ *
++ *
++ * version: Security.L.1.0.2-229
++ *
++ ***************************************************************************/
++
++#include "icp_ocf.h"
++
++/*The following define values (containing the word 'INDEX') are used to find
++the index of each input buffer of the crypto_kop struct (see OCF cryptodev.h).
++These values were found through analysis of the OCF OpenSSL patch. If the
++calling program uses different input buffer positions, these defines will have
++to be changed.*/
++
++/*DIFFIE HELLMAN buffer index values*/
++#define ICP_DH_KRP_PARAM_PRIME_INDEX (0)
++#define ICP_DH_KRP_PARAM_BASE_INDEX (1)
++#define ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX (2)
++#define ICP_DH_KRP_PARAM_RESULT_INDEX (3)
++
++/*MOD EXP buffer index values*/
++#define ICP_MOD_EXP_KRP_PARAM_BASE_INDEX (0)
++#define ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX (1)
++#define ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX (2)
++#define ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX (3)
++
++/*MOD EXP CRT buffer index values*/
++#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX (0)
++#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX (1)
++#define ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX (2)
++#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX (3)
++#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX (4)
++#define ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX (5)
++#define ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX (6)
++
++/*DSA sign buffer index values*/
++#define ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX (0)
++#define ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX (1)
++#define ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX (2)
++#define ICP_DSA_SIGN_KRP_PARAM_G_INDEX (3)
++#define ICP_DSA_SIGN_KRP_PARAM_X_INDEX (4)
++#define ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX (5)
++#define ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX (6)
++
++/*DSA verify buffer index values*/
++#define ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX (0)
++#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX (1)
++#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX (2)
++#define ICP_DSA_VERIFY_KRP_PARAM_G_INDEX (3)
++#define ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX (4)
++#define ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX (5)
++#define ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX (6)
++
++/*DSA sign prime Q vs random number K size check values*/
++#define DONT_RUN_LESS_THAN_CHECK (0)
++#define FAIL_A_IS_GREATER_THAN_B (1)
++#define FAIL_A_IS_EQUAL_TO_B (1)
++#define SUCCESS_A_IS_LESS_THAN_B (0)
++#define DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS (500)
++
++/* We need to set a cryptokp success value just in case it is set or allocated
++ and not set to zero outside of this module */
++#define CRYPTO_OP_SUCCESS (0)
++
++/*Function to compute Diffie Hellman (DH) phase 1 or phase 2 key values*/
++static int icp_ocfDrvDHComputeKey(struct cryptkop *krp);
++
++/*Function to compute a Modular Exponentiation (Mod Exp)*/
++static int icp_ocfDrvModExp(struct cryptkop *krp);
++
++/*Function to compute a Mod Exp using the Chinease Remainder Theorem*/
++static int icp_ocfDrvModExpCRT(struct cryptkop *krp);
++
++/*Helper function to compute whether the first big number argument is less than
++ the second big number argument */
++static int
++icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck);
++
++/*Function to sign an input with DSA R and S keys*/
++static int icp_ocfDrvDsaSign(struct cryptkop *krp);
++
++/*Function to Verify a DSA buffer signature*/
++static int icp_ocfDrvDsaVerify(struct cryptkop *krp);
++
++/*Callback function for DH operation*/
++static void
++icp_ocfDrvDhP1CallBack(void *callbackTag,
++ CpaStatus status,
++ void *pOpData, CpaFlatBuffer * pLocalOctetStringPV);
++
++/*Callback function for ME operation*/
++static void
++icp_ocfDrvModExpCallBack(void *callbackTag,
++ CpaStatus status,
++ void *pOpData, CpaFlatBuffer * pResult);
++
++/*Callback function for ME CRT operation*/
++static void
++icp_ocfDrvModExpCRTCallBack(void *callbackTag,
++ CpaStatus status,
++ void *pOpData, CpaFlatBuffer * pOutputData);
++
++/*Callback function for DSA sign operation*/
++static void
++icp_ocfDrvDsaRSSignCallBack(void *callbackTag,
++ CpaStatus status,
++ void *pOpData,
++ CpaBoolean protocolStatus,
++ CpaFlatBuffer * pR, CpaFlatBuffer * pS);
++
++/*Callback function for DSA Verify operation*/
++static void
++icp_ocfDrvDsaVerifyCallBack(void *callbackTag,
++ CpaStatus status,
++ void *pOpData, CpaBoolean verifyStatus);
++
++/* Name : icp_ocfDrvPkeProcess
++ *
++ * Description : This function will choose which PKE process to follow
++ * based on the input arguments
++ */
++int icp_ocfDrvPkeProcess(icp_device_t dev, struct cryptkop *krp, int hint)
++{
++ CpaStatus lacStatus = CPA_STATUS_SUCCESS;
++
++ if (NULL == krp) {
++ DPRINTK("%s(): Invalid input parameters, cryptkop = %p\n",
++ __FUNCTION__, krp);
++ return EINVAL;
++ }
++
++ if (CPA_TRUE == icp_atomic_read(&icp_ocfDrvIsExiting)) {
++ krp->krp_status = ECANCELED;
++ return ECANCELED;
++ }
++
++ switch (krp->krp_op) {
++ case CRK_DH_COMPUTE_KEY:
++ DPRINTK("%s() doing DH_COMPUTE_KEY\n", __FUNCTION__);
++ lacStatus = icp_ocfDrvDHComputeKey(krp);
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): icp_ocfDrvDHComputeKey failed "
++ "(%d).\n", __FUNCTION__, lacStatus);
++ krp->krp_status = ECANCELED;
++ return ECANCELED;
++ }
++
++ break;
++
++ case CRK_MOD_EXP:
++ DPRINTK("%s() doing MOD_EXP \n", __FUNCTION__);
++ lacStatus = icp_ocfDrvModExp(krp);
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): icp_ocfDrvModExp failed (%d).\n",
++ __FUNCTION__, lacStatus);
++ krp->krp_status = ECANCELED;
++ return ECANCELED;
++ }
++
++ break;
++
++ case CRK_MOD_EXP_CRT:
++ DPRINTK("%s() doing MOD_EXP_CRT \n", __FUNCTION__);
++ lacStatus = icp_ocfDrvModExpCRT(krp);
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): icp_ocfDrvModExpCRT "
++ "failed (%d).\n", __FUNCTION__, lacStatus);
++ krp->krp_status = ECANCELED;
++ return ECANCELED;
++ }
++
++ break;
++
++ case CRK_DSA_SIGN:
++ DPRINTK("%s() doing DSA_SIGN \n", __FUNCTION__);
++ lacStatus = icp_ocfDrvDsaSign(krp);
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): icp_ocfDrvDsaSign "
++ "failed (%d).\n", __FUNCTION__, lacStatus);
++ krp->krp_status = ECANCELED;
++ return ECANCELED;
++ }
++
++ break;
++
++ case CRK_DSA_VERIFY:
++ DPRINTK("%s() doing DSA_VERIFY \n", __FUNCTION__);
++ lacStatus = icp_ocfDrvDsaVerify(krp);
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): icp_ocfDrvDsaVerify "
++ "failed (%d).\n", __FUNCTION__, lacStatus);
++ krp->krp_status = ECANCELED;
++ return ECANCELED;
++ }
++
++ break;
++
++ default:
++ EPRINTK("%s(): Asymettric function not "
++ "supported (%d).\n", __FUNCTION__, krp->krp_op);
++ krp->krp_status = EOPNOTSUPP;
++ return EOPNOTSUPP;
++ }
++
++ return ICP_OCF_DRV_STATUS_SUCCESS;
++}
++
++/* Name : icp_ocfDrvSwapBytes
++ *
++ * Description : This function is used to swap the byte order of a buffer.
++ * It has been seen that in general we are passed little endian byte order
++ * buffers, but LAC only accepts big endian byte order buffers.
++ */
++static void inline icp_ocfDrvSwapBytes(u_int8_t * num, u_int32_t buff_len_bytes)
++{
++
++ int i;
++ u_int8_t *end_ptr;
++ u_int8_t hold_val;
++
++ end_ptr = num + (buff_len_bytes - 1);
++ buff_len_bytes = buff_len_bytes >> 1;
++ for (i = 0; i < buff_len_bytes; i++) {
++ hold_val = *num;
++ *num = *end_ptr;
++ num++;
++ *end_ptr = hold_val;
++ end_ptr--;
++ }
++}
++
++/* Name : icp_ocfDrvDHComputeKey
++ *
++ * Description : This function will map Diffie Hellman calls from OCF
++ * to the LAC API. OCF uses this function for Diffie Hellman Phase1 and
++ * Phase2. LAC has a separate Diffie Hellman Phase2 call, however both phases
++ * break down to a modular exponentiation.
++ */
++static int icp_ocfDrvDHComputeKey(struct cryptkop *krp)
++{
++ CpaStatus lacStatus = CPA_STATUS_SUCCESS;
++ void *callbackTag = NULL;
++ CpaCyDhPhase1KeyGenOpData *pPhase1OpData = NULL;
++ CpaFlatBuffer *pLocalOctetStringPV = NULL;
++ uint32_t dh_prime_len_bytes = 0, dh_prime_len_bits = 0;
++
++ /* Input checks - check prime is a multiple of 8 bits to allow for
++ allocation later */
++ dh_prime_len_bits =
++ (krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_nbits);
++
++ /* LAC can reject prime lengths based on prime key sizes, we just
++ need to make sure we can allocate space for the base and
++ exponent buffers correctly */
++ if ((dh_prime_len_bits % NUM_BITS_IN_BYTE) != 0) {
++ APRINTK("%s(): Warning Prime number buffer size is not a "
++ "multiple of 8 bits\n", __FUNCTION__);
++ }
++
++ /* Result storage space should be the same size as the prime as this
++ value can take up the same amount of storage space */
++ if (dh_prime_len_bits !=
++ krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits) {
++ DPRINTK("%s(): Return Buffer must be the same size "
++ "as the Prime buffer\n", __FUNCTION__);
++ krp->krp_status = EINVAL;
++ return EINVAL;
++ }
++ /* Switch to size in bytes */
++ BITS_TO_BYTES(dh_prime_len_bytes, dh_prime_len_bits);
++
++ callbackTag = krp;
++
++/*All allocations are set to ICP_M_NOWAIT due to the possibility of getting
++called in interrupt context*/
++ pPhase1OpData = icp_kmem_cache_zalloc(drvDH_zone, ICP_M_NOWAIT);
++ if (NULL == pPhase1OpData) {
++ APRINTK("%s():Failed to get memory for key gen data\n",
++ __FUNCTION__);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ pLocalOctetStringPV =
++ icp_kmem_cache_zalloc(drvFlatBuffer_zone, ICP_M_NOWAIT);
++ if (NULL == pLocalOctetStringPV) {
++ APRINTK("%s():Failed to get memory for pLocalOctetStringPV\n",
++ __FUNCTION__);
++ ICP_CACHE_FREE(drvDH_zone, pPhase1OpData);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ /* Link parameters */
++ pPhase1OpData->primeP.pData =
++ krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_p;
++
++ pPhase1OpData->primeP.dataLenInBytes = dh_prime_len_bytes;
++
++ icp_ocfDrvSwapBytes(pPhase1OpData->primeP.pData, dh_prime_len_bytes);
++
++ pPhase1OpData->baseG.pData =
++ krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_p;
++
++ BITS_TO_BYTES(pPhase1OpData->baseG.dataLenInBytes,
++ krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_nbits);
++
++ icp_ocfDrvSwapBytes(pPhase1OpData->baseG.pData,
++ pPhase1OpData->baseG.dataLenInBytes);
++
++ pPhase1OpData->privateValueX.pData =
++ krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX].crp_p;
++
++ BITS_TO_BYTES(pPhase1OpData->privateValueX.dataLenInBytes,
++ krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX].
++ crp_nbits);
++
++ icp_ocfDrvSwapBytes(pPhase1OpData->privateValueX.pData,
++ pPhase1OpData->privateValueX.dataLenInBytes);
++
++ /* Output parameters */
++ pLocalOctetStringPV->pData =
++ krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_p;
++
++ BITS_TO_BYTES(pLocalOctetStringPV->dataLenInBytes,
++ krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits);
++
++ lacStatus = cpaCyDhKeyGenPhase1(CPA_INSTANCE_HANDLE_SINGLE,
++ icp_ocfDrvDhP1CallBack,
++ callbackTag, pPhase1OpData,
++ pLocalOctetStringPV);
++
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): DH Phase 1 Key Gen failed (%d).\n",
++ __FUNCTION__, lacStatus);
++ icp_ocfDrvFreeFlatBuffer(pLocalOctetStringPV);
++ ICP_CACHE_FREE(drvDH_zone, pPhase1OpData);
++ }
++
++ return lacStatus;
++}
++
++/* Name : icp_ocfDrvModExp
++ *
++ * Description : This function will map ordinary Modular Exponentiation calls
++ * from OCF to the LAC API.
++ *
++ */
++static int icp_ocfDrvModExp(struct cryptkop *krp)
++{
++ CpaStatus lacStatus = CPA_STATUS_SUCCESS;
++ void *callbackTag = NULL;
++ CpaCyLnModExpOpData *pModExpOpData = NULL;
++ CpaFlatBuffer *pResult = NULL;
++
++ if ((krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits %
++ NUM_BITS_IN_BYTE) != 0) {
++ DPRINTK("%s(): Warning - modulus buffer size (%d) is not a "
++ "multiple of 8 bits\n", __FUNCTION__,
++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].
++ crp_nbits);
++ }
++
++ /* Result storage space should be the same size as the prime as this
++ value can take up the same amount of storage space */
++ if (krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits >
++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_nbits) {
++ APRINTK("%s(): Return Buffer size must be the same or"
++ " greater than the Modulus buffer\n", __FUNCTION__);
++ krp->krp_status = EINVAL;
++ return EINVAL;
++ }
++
++ callbackTag = krp;
++
++ pModExpOpData = icp_kmem_cache_zalloc(drvLnModExp_zone, ICP_M_NOWAIT);
++ if (NULL == pModExpOpData) {
++ APRINTK("%s():Failed to get memory for key gen data\n",
++ __FUNCTION__);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ pResult = icp_kmem_cache_zalloc(drvFlatBuffer_zone, ICP_M_NOWAIT);
++ if (NULL == pResult) {
++ APRINTK("%s():Failed to get memory for ModExp result\n",
++ __FUNCTION__);
++ ICP_CACHE_FREE(drvLnModExp_zone, pModExpOpData);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ /* Link parameters */
++ pModExpOpData->modulus.pData =
++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_p;
++ BITS_TO_BYTES(pModExpOpData->modulus.dataLenInBytes,
++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].
++ crp_nbits);
++
++ icp_ocfDrvSwapBytes(pModExpOpData->modulus.pData,
++ pModExpOpData->modulus.dataLenInBytes);
++
++ DPRINTK("%s : base (%d)\n", __FUNCTION__, krp->
++ krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits);
++ pModExpOpData->base.pData =
++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_p;
++ BITS_TO_BYTES(pModExpOpData->base.dataLenInBytes,
++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].
++ crp_nbits);
++ icp_ocfDrvSwapBytes(pModExpOpData->base.pData,
++ pModExpOpData->base.dataLenInBytes);
++
++ pModExpOpData->exponent.pData =
++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX].crp_p;
++ BITS_TO_BYTES(pModExpOpData->exponent.dataLenInBytes,
++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX].
++ crp_nbits);
++
++ icp_ocfDrvSwapBytes(pModExpOpData->exponent.pData,
++ pModExpOpData->exponent.dataLenInBytes);
++ /* Output parameters */
++ pResult->pData =
++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_p,
++ BITS_TO_BYTES(pResult->dataLenInBytes,
++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].
++ crp_nbits);
++
++ lacStatus = cpaCyLnModExp(CPA_INSTANCE_HANDLE_SINGLE,
++ icp_ocfDrvModExpCallBack,
++ callbackTag, pModExpOpData, pResult);
++
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): Mod Exp Operation failed (%d).\n",
++ __FUNCTION__, lacStatus);
++ krp->krp_status = ECANCELED;
++ icp_ocfDrvFreeFlatBuffer(pResult);
++ ICP_CACHE_FREE(drvLnModExp_zone, pModExpOpData);
++ }
++
++ return lacStatus;
++}
++
++/* Name : icp_ocfDrvModExpCRT
++ *
++ * Description : This function will map ordinary Modular Exponentiation Chinese
++ * Remainder Theorem implementaion calls from OCF to the LAC API.
++ *
++ * Note : Mod Exp CRT for this driver is accelerated through LAC RSA type 2
++ * decrypt operation. Therefore P and Q input values must always be prime
++ * numbers. Although basic primality checks are done in LAC, it is up to the
++ * user to do any correct prime number checking before passing the inputs.
++ */
++static int icp_ocfDrvModExpCRT(struct cryptkop *krp)
++{
++ CpaStatus lacStatus = CPA_STATUS_SUCCESS;
++ CpaCyRsaDecryptOpData *rsaDecryptOpData = NULL;
++ void *callbackTag = NULL;
++ CpaFlatBuffer *pOutputData = NULL;
++
++ /*Parameter input checks are all done by LAC, no need to repeat
++ them here. */
++ callbackTag = krp;
++
++ rsaDecryptOpData =
++ icp_kmem_cache_zalloc(drvRSADecrypt_zone, ICP_M_NOWAIT);
++ if (NULL == rsaDecryptOpData) {
++ APRINTK("%s():Failed to get memory"
++ " for MOD EXP CRT Op data struct\n", __FUNCTION__);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ rsaDecryptOpData->pRecipientPrivateKey
++ = icp_kmem_cache_zalloc(drvRSAPrivateKey_zone, ICP_M_NOWAIT);
++ if (NULL == rsaDecryptOpData->pRecipientPrivateKey) {
++ APRINTK("%s():Failed to get memory for MOD EXP CRT"
++ " private key values struct\n", __FUNCTION__);
++ ICP_CACHE_FREE(drvRSADecrypt_zone, rsaDecryptOpData);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ rsaDecryptOpData->pRecipientPrivateKey->
++ version = CPA_CY_RSA_VERSION_TWO_PRIME;
++ rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2;
++
++ pOutputData = icp_kmem_cache_zalloc(drvFlatBuffer_zone, ICP_M_NOWAIT);
++ if (NULL == pOutputData) {
++ APRINTK("%s():Failed to get memory"
++ " for MOD EXP CRT output data\n", __FUNCTION__);
++ ICP_CACHE_FREE(drvRSAPrivateKey_zone,
++ rsaDecryptOpData->pRecipientPrivateKey);
++ ICP_CACHE_FREE(drvRSADecrypt_zone, rsaDecryptOpData);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ rsaDecryptOpData->pRecipientPrivateKey->
++ version = CPA_CY_RSA_VERSION_TWO_PRIME;
++ rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2;
++
++ /* Link parameters */
++ rsaDecryptOpData->inputData.pData =
++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX].crp_p;
++ BITS_TO_BYTES(rsaDecryptOpData->inputData.dataLenInBytes,
++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX].
++ crp_nbits);
++
++ icp_ocfDrvSwapBytes(rsaDecryptOpData->inputData.pData,
++ rsaDecryptOpData->inputData.dataLenInBytes);
++
++ rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime1P.pData =
++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX].crp_p;
++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.
++ prime1P.dataLenInBytes,
++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX].
++ crp_nbits);
++
++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.prime1P.pData,
++ rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.prime1P.dataLenInBytes);
++
++ rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime2Q.pData =
++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX].crp_p;
++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.
++ prime2Q.dataLenInBytes,
++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX].
++ crp_nbits);
++
++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.prime2Q.pData,
++ rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.prime2Q.dataLenInBytes);
++
++ rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.exponent1Dp.pData =
++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX].crp_p;
++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.
++ exponent1Dp.dataLenInBytes,
++ krp->
++ krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX].
++ crp_nbits);
++
++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.exponent1Dp.pData,
++ rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.exponent1Dp.dataLenInBytes);
++
++ rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.exponent2Dq.pData =
++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX].crp_p;
++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.exponent2Dq.dataLenInBytes,
++ krp->
++ krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX].
++ crp_nbits);
++
++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.exponent2Dq.pData,
++ rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.exponent2Dq.dataLenInBytes);
++
++ rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.coefficientQInv.pData =
++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX].crp_p;
++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.coefficientQInv.dataLenInBytes,
++ krp->
++ krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX].
++ crp_nbits);
++
++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.coefficientQInv.pData,
++ rsaDecryptOpData->pRecipientPrivateKey->
++ privateKeyRep2.coefficientQInv.dataLenInBytes);
++
++ /* Output Parameter */
++ pOutputData->pData =
++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX].crp_p;
++ BITS_TO_BYTES(pOutputData->dataLenInBytes,
++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX].
++ crp_nbits);
++
++ lacStatus = cpaCyRsaDecrypt(CPA_INSTANCE_HANDLE_SINGLE,
++ icp_ocfDrvModExpCRTCallBack,
++ callbackTag, rsaDecryptOpData, pOutputData);
++
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): Mod Exp CRT Operation failed (%d).\n",
++ __FUNCTION__, lacStatus);
++ krp->krp_status = ECANCELED;
++ icp_ocfDrvFreeFlatBuffer(pOutputData);
++ ICP_CACHE_FREE(drvRSAPrivateKey_zone,
++ rsaDecryptOpData->pRecipientPrivateKey);
++ ICP_CACHE_FREE(drvRSADecrypt_zone, rsaDecryptOpData);
++ }
++
++ return lacStatus;
++}
++
++/* Name : icp_ocfDrvCheckALessThanB
++ *
++ * Description : This function will check whether the first argument is less
++ * than the second. It is used to check whether the DSA RS sign Random K
++ * value is less than the Prime Q value (as defined in the specification)
++ *
++ */
++static int
++icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck)
++{
++
++ uint8_t *MSB_K = pK->pData;
++ uint8_t *MSB_Q = pQ->pData;
++ uint32_t buffer_lengths_in_bytes = pQ->dataLenInBytes;
++
++ if (DONT_RUN_LESS_THAN_CHECK == *doCheck) {
++ return FAIL_A_IS_GREATER_THAN_B;
++ }
++
++/*Check MSBs
++if A == B, check next MSB
++if A > B, return A_IS_GREATER_THAN_B
++if A < B, return A_IS_LESS_THAN_B (success)
++*/
++ while (*MSB_K == *MSB_Q) {
++ MSB_K++;
++ MSB_Q++;
++
++ buffer_lengths_in_bytes--;
++ if (0 == buffer_lengths_in_bytes) {
++ DPRINTK("%s() Buffers have equal value!!\n",
++ __FUNCTION__);
++ return FAIL_A_IS_EQUAL_TO_B;
++ }
++
++ }
++
++ if (*MSB_K < *MSB_Q) {
++ return SUCCESS_A_IS_LESS_THAN_B;
++ } else {
++ return FAIL_A_IS_GREATER_THAN_B;
++ }
++
++}
++
++/* Name : icp_ocfDrvDsaSign
++ *
++ * Description : This function will map DSA RS Sign from OCF to the LAC API.
++ *
++ * NOTE: From looking at OCF patch to OpenSSL and even the number of input
++ * parameters, OCF expects us to generate the random seed value. This value
++ * is generated and passed to LAC, however the number is discared in the
++ * callback and not returned to the user.
++ */
++static int icp_ocfDrvDsaSign(struct cryptkop *krp)
++{
++ CpaStatus lacStatus = CPA_STATUS_SUCCESS;
++ CpaCyDsaRSSignOpData *dsaRsSignOpData = NULL;
++ void *callbackTag = NULL;
++ CpaCyRandGenOpData randGenOpData;
++ int primeQSizeInBytes = 0;
++ int doCheck = 0;
++ CpaFlatBuffer randData;
++ CpaBoolean protocolStatus = CPA_FALSE;
++ CpaFlatBuffer *pR = NULL;
++ CpaFlatBuffer *pS = NULL;
++
++ callbackTag = krp;
++
++ BITS_TO_BYTES(primeQSizeInBytes,
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX].
++ crp_nbits);
++
++ if (DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES != primeQSizeInBytes) {
++ APRINTK("%s(): DSA PRIME Q size not equal to the "
++ "FIPS defined 20bytes, = %d\n",
++ __FUNCTION__, primeQSizeInBytes);
++ krp->krp_status = EDOM;
++ return EDOM;
++ }
++
++ dsaRsSignOpData =
++ icp_kmem_cache_zalloc(drvDSARSSign_zone, ICP_M_NOWAIT);
++ if (NULL == dsaRsSignOpData) {
++ APRINTK("%s():Failed to get memory"
++ " for DSA RS Sign Op data struct\n", __FUNCTION__);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ dsaRsSignOpData->K.pData =
++ icp_kmem_cache_alloc(drvDSARSSignKValue_zone, ICP_M_NOWAIT);
++
++ if (NULL == dsaRsSignOpData->K.pData) {
++ APRINTK("%s():Failed to get memory"
++ " for DSA RS Sign Op Random value\n", __FUNCTION__);
++ ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ pR = icp_kmem_cache_zalloc(drvFlatBuffer_zone, ICP_M_NOWAIT);
++ if (NULL == pR) {
++ APRINTK("%s():Failed to get memory"
++ " for DSA signature R\n", __FUNCTION__);
++ ICP_CACHE_FREE(drvDSARSSignKValue_zone,
++ dsaRsSignOpData->K.pData);
++ ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ pS = icp_kmem_cache_zalloc(drvFlatBuffer_zone, ICP_M_NOWAIT);
++ if (NULL == pS) {
++ APRINTK("%s():Failed to get memory"
++ " for DSA signature S\n", __FUNCTION__);
++ icp_ocfDrvFreeFlatBuffer(pR);
++ ICP_CACHE_FREE(drvDSARSSignKValue_zone,
++ dsaRsSignOpData->K.pData);
++ ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ /*link prime number parameter for ease of processing */
++ dsaRsSignOpData->P.pData =
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX].crp_p;
++ BITS_TO_BYTES(dsaRsSignOpData->P.dataLenInBytes,
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX].
++ crp_nbits);
++
++ icp_ocfDrvSwapBytes(dsaRsSignOpData->P.pData,
++ dsaRsSignOpData->P.dataLenInBytes);
++
++ dsaRsSignOpData->Q.pData =
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX].crp_p;
++ BITS_TO_BYTES(dsaRsSignOpData->Q.dataLenInBytes,
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX].
++ crp_nbits);
++
++ icp_ocfDrvSwapBytes(dsaRsSignOpData->Q.pData,
++ dsaRsSignOpData->Q.dataLenInBytes);
++
++ /*generate random number with equal buffer size to Prime value Q,
++ but value less than Q */
++ dsaRsSignOpData->K.dataLenInBytes = dsaRsSignOpData->Q.dataLenInBytes;
++
++ randGenOpData.generateBits = CPA_TRUE;
++ randGenOpData.lenInBytes = dsaRsSignOpData->K.dataLenInBytes;
++
++ icp_ocfDrvPtrAndLenToFlatBuffer(dsaRsSignOpData->K.pData,
++ dsaRsSignOpData->K.dataLenInBytes,
++ &randData);
++
++ doCheck = 0;
++ while (icp_ocfDrvCheckALessThanB(&(dsaRsSignOpData->K),
++ &(dsaRsSignOpData->Q), &doCheck)) {
++
++ if (CPA_STATUS_SUCCESS
++ != cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE,
++ NULL, NULL, &randGenOpData, &randData)) {
++ APRINTK("%s(): ERROR - Failed to generate DSA RS Sign K"
++ "value\n", __FUNCTION__);
++ icp_ocfDrvFreeFlatBuffer(pS);
++ icp_ocfDrvFreeFlatBuffer(pR);
++ ICP_CACHE_FREE(drvDSARSSignKValue_zone,
++ dsaRsSignOpData->K.pData);
++ ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData);
++ krp->krp_status = EAGAIN;
++ return EAGAIN;
++ }
++
++ doCheck++;
++ if (DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS == doCheck) {
++ APRINTK("%s(): ERROR - Failed to find DSA RS Sign K "
++ "value less than Q value\n", __FUNCTION__);
++ icp_ocfDrvFreeFlatBuffer(pS);
++ icp_ocfDrvFreeFlatBuffer(pR);
++ ICP_CACHE_FREE(drvDSARSSignKValue_zone,
++ dsaRsSignOpData->K.pData);
++ ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData);
++ krp->krp_status = EAGAIN;
++ return EAGAIN;
++ }
++
++ }
++ /*Rand Data - no need to swap bytes for pK */
++
++ /* Link parameters */
++ dsaRsSignOpData->G.pData =
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_p;
++ BITS_TO_BYTES(dsaRsSignOpData->G.dataLenInBytes,
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_nbits);
++
++ icp_ocfDrvSwapBytes(dsaRsSignOpData->G.pData,
++ dsaRsSignOpData->G.dataLenInBytes);
++
++ dsaRsSignOpData->X.pData =
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_p;
++ BITS_TO_BYTES(dsaRsSignOpData->X.dataLenInBytes,
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_nbits);
++ icp_ocfDrvSwapBytes(dsaRsSignOpData->X.pData,
++ dsaRsSignOpData->X.dataLenInBytes);
++
++ /*OpenSSL dgst parameter is left in big endian byte order,
++ therefore no byte swap is required */
++ dsaRsSignOpData->M.pData =
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX].crp_p;
++ BITS_TO_BYTES(dsaRsSignOpData->M.dataLenInBytes,
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX].
++ crp_nbits);
++
++ /* Output Parameters */
++ pS->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX].crp_p;
++ BITS_TO_BYTES(pS->dataLenInBytes,
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX].
++ crp_nbits);
++
++ pR->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX].crp_p;
++ BITS_TO_BYTES(pR->dataLenInBytes,
++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX].
++ crp_nbits);
++
++ lacStatus = cpaCyDsaSignRS(CPA_INSTANCE_HANDLE_SINGLE,
++ icp_ocfDrvDsaRSSignCallBack,
++ callbackTag, dsaRsSignOpData,
++ &protocolStatus, pR, pS);
++
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): DSA RS Sign Operation failed (%d).\n",
++ __FUNCTION__, lacStatus);
++ krp->krp_status = ECANCELED;
++ icp_ocfDrvFreeFlatBuffer(pS);
++ icp_ocfDrvFreeFlatBuffer(pR);
++ ICP_CACHE_FREE(drvDSARSSignKValue_zone,
++ dsaRsSignOpData->K.pData);
++ ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData);
++ }
++
++ return lacStatus;
++}
++
++/* Name : icp_ocfDrvDsaVerify
++ *
++ * Description : This function will map DSA RS Verify from OCF to the LAC API.
++ *
++ */
++static int icp_ocfDrvDsaVerify(struct cryptkop *krp)
++{
++ CpaStatus lacStatus = CPA_STATUS_SUCCESS;
++ CpaCyDsaVerifyOpData *dsaVerifyOpData = NULL;
++ void *callbackTag = NULL;
++ CpaBoolean verifyStatus = CPA_FALSE;
++
++ callbackTag = krp;
++
++ dsaVerifyOpData =
++ icp_kmem_cache_zalloc(drvDSAVerify_zone, ICP_M_NOWAIT);
++ if (NULL == dsaVerifyOpData) {
++ APRINTK("%s():Failed to get memory"
++ " for DSA Verify Op data struct\n", __FUNCTION__);
++ krp->krp_status = ENOMEM;
++ return ENOMEM;
++ }
++
++ /* Link parameters */
++ dsaVerifyOpData->P.pData =
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX].crp_p;
++ BITS_TO_BYTES(dsaVerifyOpData->P.dataLenInBytes,
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX].
++ crp_nbits);
++ icp_ocfDrvSwapBytes(dsaVerifyOpData->P.pData,
++ dsaVerifyOpData->P.dataLenInBytes);
++
++ dsaVerifyOpData->Q.pData =
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX].crp_p;
++ BITS_TO_BYTES(dsaVerifyOpData->Q.dataLenInBytes,
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX].
++ crp_nbits);
++ icp_ocfDrvSwapBytes(dsaVerifyOpData->Q.pData,
++ dsaVerifyOpData->Q.dataLenInBytes);
++
++ dsaVerifyOpData->G.pData =
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX].crp_p;
++ BITS_TO_BYTES(dsaVerifyOpData->G.dataLenInBytes,
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX].
++ crp_nbits);
++ icp_ocfDrvSwapBytes(dsaVerifyOpData->G.pData,
++ dsaVerifyOpData->G.dataLenInBytes);
++
++ dsaVerifyOpData->Y.pData =
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX].crp_p;
++ BITS_TO_BYTES(dsaVerifyOpData->Y.dataLenInBytes,
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX].
++ crp_nbits);
++ icp_ocfDrvSwapBytes(dsaVerifyOpData->Y.pData,
++ dsaVerifyOpData->Y.dataLenInBytes);
++
++ /*OpenSSL dgst parameter is left in big endian byte order,
++ therefore no byte swap is required */
++ dsaVerifyOpData->M.pData =
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX].crp_p;
++ BITS_TO_BYTES(dsaVerifyOpData->M.dataLenInBytes,
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX].
++ crp_nbits);
++
++ dsaVerifyOpData->R.pData =
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX].crp_p;
++ BITS_TO_BYTES(dsaVerifyOpData->R.dataLenInBytes,
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX].
++ crp_nbits);
++ icp_ocfDrvSwapBytes(dsaVerifyOpData->R.pData,
++ dsaVerifyOpData->R.dataLenInBytes);
++
++ dsaVerifyOpData->S.pData =
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX].crp_p;
++ BITS_TO_BYTES(dsaVerifyOpData->S.dataLenInBytes,
++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX].
++ crp_nbits);
++ icp_ocfDrvSwapBytes(dsaVerifyOpData->S.pData,
++ dsaVerifyOpData->S.dataLenInBytes);
++
++ lacStatus = cpaCyDsaVerify(CPA_INSTANCE_HANDLE_SINGLE,
++ icp_ocfDrvDsaVerifyCallBack,
++ callbackTag, dsaVerifyOpData, &verifyStatus);
++
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): DSA Verify Operation failed (%d).\n",
++ __FUNCTION__, lacStatus);
++ ICP_CACHE_FREE(drvDSAVerify_zone, dsaVerifyOpData);
++ krp->krp_status = ECANCELED;
++ }
++
++ return lacStatus;
++}
++
++/* Name : icp_ocfDrvDhP1Callback
++ *
++ * Description : When this function returns it signifies that the LAC
++ * component has completed the DH operation.
++ */
++static void
++icp_ocfDrvDhP1CallBack(void *callbackTag,
++ CpaStatus status,
++ void *pOpData, CpaFlatBuffer * pLocalOctetStringPV)
++{
++ struct cryptkop *krp = NULL;
++ CpaCyDhPhase1KeyGenOpData *pPhase1OpData = NULL;
++
++ if (NULL == callbackTag) {
++ DPRINTK("%s(): Invalid input parameters - "
++ "callbackTag data is NULL\n", __FUNCTION__);
++ return;
++ }
++ krp = (struct cryptkop *)callbackTag;
++
++ if (NULL == pOpData) {
++ DPRINTK("%s(): Invalid input parameters - "
++ "Operation Data is NULL\n", __FUNCTION__);
++ krp->krp_status = ECANCELED;
++ crypto_kdone(krp);
++ return;
++ }
++ pPhase1OpData = (CpaCyDhPhase1KeyGenOpData *) pOpData;
++
++ if (NULL == pLocalOctetStringPV) {
++ DPRINTK("%s(): Invalid input parameters - "
++ "pLocalOctetStringPV Data is NULL\n", __FUNCTION__);
++ memset(pPhase1OpData, 0, sizeof(CpaCyDhPhase1KeyGenOpData));
++ ICP_CACHE_FREE(drvDH_zone, pPhase1OpData);
++ krp->krp_status = ECANCELED;
++ crypto_kdone(krp);
++ return;
++ }
++
++ if (CPA_STATUS_SUCCESS == status) {
++ krp->krp_status = CRYPTO_OP_SUCCESS;
++ } else {
++ APRINTK("%s(): Diffie Hellman Phase1 Key Gen failed - "
++ "Operation Status = %d\n", __FUNCTION__, status);
++ krp->krp_status = ECANCELED;
++ }
++
++ icp_ocfDrvSwapBytes(pLocalOctetStringPV->pData,
++ pLocalOctetStringPV->dataLenInBytes);
++
++ icp_ocfDrvFreeFlatBuffer(pLocalOctetStringPV);
++ memset(pPhase1OpData, 0, sizeof(CpaCyDhPhase1KeyGenOpData));
++ ICP_CACHE_FREE(drvDH_zone, pPhase1OpData);
++
++ crypto_kdone(krp);
++
++ return;
++}
++
++/* Name : icp_ocfDrvModExpCallBack
++ *
++ * Description : When this function returns it signifies that the LAC
++ * component has completed the Mod Exp operation.
++ */
++static void
++icp_ocfDrvModExpCallBack(void *callbackTag,
++ CpaStatus status,
++ void *pOpdata, CpaFlatBuffer * pResult)
++{
++ struct cryptkop *krp = NULL;
++ CpaCyLnModExpOpData *pLnModExpOpData = NULL;
++
++ if (NULL == callbackTag) {
++ DPRINTK("%s(): Invalid input parameters - "
++ "callbackTag data is NULL\n", __FUNCTION__);
++ return;
++ }
++ krp = (struct cryptkop *)callbackTag;
++
++ if (NULL == pOpdata) {
++ DPRINTK("%s(): Invalid Mod Exp input parameters - "
++ "Operation Data is NULL\n", __FUNCTION__);
++ krp->krp_status = ECANCELED;
++ crypto_kdone(krp);
++ return;
++ }
++ pLnModExpOpData = (CpaCyLnModExpOpData *) pOpdata;
++
++ if (NULL == pResult) {
++ DPRINTK("%s(): Invalid input parameters - "
++ "pResult data is NULL\n", __FUNCTION__);
++ krp->krp_status = ECANCELED;
++ memset(pLnModExpOpData, 0, sizeof(CpaCyLnModExpOpData));
++ ICP_CACHE_FREE(drvLnModExp_zone, pLnModExpOpData);
++ crypto_kdone(krp);
++ return;
++ }
++
++ if (CPA_STATUS_SUCCESS == status) {
++ krp->krp_status = CRYPTO_OP_SUCCESS;
++ } else {
++ APRINTK("%s(): LAC Mod Exp Operation failed - "
++ "Operation Status = %d\n", __FUNCTION__, status);
++ krp->krp_status = ECANCELED;
++ }
++
++ icp_ocfDrvSwapBytes(pResult->pData, pResult->dataLenInBytes);
++
++ /*switch base size value back to original */
++ if (pLnModExpOpData->base.pData ==
++ (uint8_t *) & (krp->
++ krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].
++ crp_nbits)) {
++ *((uint32_t *) pLnModExpOpData->base.pData) =
++ ntohl(*((uint32_t *) pLnModExpOpData->base.pData));
++ }
++ icp_ocfDrvFreeFlatBuffer(pResult);
++ memset(pLnModExpOpData, 0, sizeof(CpaCyLnModExpOpData));
++ ICP_CACHE_FREE(drvLnModExp_zone, pLnModExpOpData);
++
++ crypto_kdone(krp);
++
++ return;
++
++}
++
++/* Name : icp_ocfDrvModExpCRTCallBack
++ *
++ * Description : When this function returns it signifies that the LAC
++ * component has completed the Mod Exp CRT operation.
++ */
++static void
++icp_ocfDrvModExpCRTCallBack(void *callbackTag,
++ CpaStatus status,
++ void *pOpData, CpaFlatBuffer * pOutputData)
++{
++ struct cryptkop *krp = NULL;
++ CpaCyRsaDecryptOpData *pDecryptData = NULL;
++
++ if (NULL == callbackTag) {
++ DPRINTK("%s(): Invalid input parameters - "
++ "callbackTag data is NULL\n", __FUNCTION__);
++ return;
++ }
++
++ krp = (struct cryptkop *)callbackTag;
++
++ if (NULL == pOpData) {
++ DPRINTK("%s(): Invalid input parameters - "
++ "Operation Data is NULL\n", __FUNCTION__);
++ krp->krp_status = ECANCELED;
++ crypto_kdone(krp);
++ return;
++ }
++ pDecryptData = (CpaCyRsaDecryptOpData *) pOpData;
++
++ if (NULL == pOutputData) {
++ DPRINTK("%s(): Invalid input parameter - "
++ "pOutputData is NULL\n", __FUNCTION__);
++ memset(pDecryptData->pRecipientPrivateKey, 0,
++ sizeof(CpaCyRsaPrivateKey));
++ ICP_CACHE_FREE(drvRSAPrivateKey_zone,
++ pDecryptData->pRecipientPrivateKey);
++ memset(pDecryptData, 0, sizeof(CpaCyRsaDecryptOpData));
++ ICP_CACHE_FREE(drvRSADecrypt_zone, pDecryptData);
++ krp->krp_status = ECANCELED;
++ crypto_kdone(krp);
++ return;
++ }
++
++ if (CPA_STATUS_SUCCESS == status) {
++ krp->krp_status = CRYPTO_OP_SUCCESS;
++ } else {
++ APRINTK("%s(): LAC Mod Exp CRT operation failed - "
++ "Operation Status = %d\n", __FUNCTION__, status);
++ krp->krp_status = ECANCELED;
++ }
++
++ icp_ocfDrvSwapBytes(pOutputData->pData, pOutputData->dataLenInBytes);
++
++ icp_ocfDrvFreeFlatBuffer(pOutputData);
++ memset(pDecryptData->pRecipientPrivateKey, 0,
++ sizeof(CpaCyRsaPrivateKey));
++ ICP_CACHE_FREE(drvRSAPrivateKey_zone,
++ pDecryptData->pRecipientPrivateKey);
++ memset(pDecryptData, 0, sizeof(CpaCyRsaDecryptOpData));
++ ICP_CACHE_FREE(drvRSADecrypt_zone, pDecryptData);
++
++ crypto_kdone(krp);
++
++ return;
++}
++
++/* Name : icp_ocfDrvDsaRSSignCallBack
++ *
++ * Description : When this function returns it signifies that the LAC
++ * component has completed the DSA RS sign operation.
++ */
++static void
++icp_ocfDrvDsaRSSignCallBack(void *callbackTag,
++ CpaStatus status,
++ void *pOpData,
++ CpaBoolean protocolStatus,
++ CpaFlatBuffer * pR, CpaFlatBuffer * pS)
++{
++ struct cryptkop *krp = NULL;
++ CpaCyDsaRSSignOpData *pSignData = NULL;
++
++ if (NULL == callbackTag) {
++ DPRINTK("%s(): Invalid input parameters - "
++ "callbackTag data is NULL\n", __FUNCTION__);
++ return;
++ }
++
++ krp = (struct cryptkop *)callbackTag;
++
++ if (NULL == pOpData) {
++ DPRINTK("%s(): Invalid input parameters - "
++ "Operation Data is NULL\n", __FUNCTION__);
++ krp->krp_status = ECANCELED;
++ crypto_kdone(krp);
++ return;
++ }
++ pSignData = (CpaCyDsaRSSignOpData *) pOpData;
++
++ if (NULL == pR) {
++ DPRINTK("%s(): Invalid input parameter - "
++ "pR sign is NULL\n", __FUNCTION__);
++ icp_ocfDrvFreeFlatBuffer(pS);
++ ICP_CACHE_FREE(drvDSARSSign_zone, pSignData);
++ krp->krp_status = ECANCELED;
++ crypto_kdone(krp);
++ return;
++ }
++
++ if (NULL == pS) {
++ DPRINTK("%s(): Invalid input parameter - "
++ "pS sign is NULL\n", __FUNCTION__);
++ icp_ocfDrvFreeFlatBuffer(pR);
++ ICP_CACHE_FREE(drvDSARSSign_zone, pSignData);
++ krp->krp_status = ECANCELED;
++ crypto_kdone(krp);
++ return;
++ }
++
++ if (CPA_STATUS_SUCCESS != status) {
++ APRINTK("%s(): LAC DSA RS Sign operation failed - "
++ "Operation Status = %d\n", __FUNCTION__, status);
++ krp->krp_status = ECANCELED;
++ } else {
++ krp->krp_status = CRYPTO_OP_SUCCESS;
++
++ if (CPA_TRUE != protocolStatus) {
++ DPRINTK("%s(): LAC DSA RS Sign operation failed due "
++ "to protocol error\n", __FUNCTION__);
++ krp->krp_status = EIO;
++ }
++ }
++
++ /* Swap bytes only when the callback status is successful and
++ protocolStatus is set to true */
++ if (CPA_STATUS_SUCCESS == status && CPA_TRUE == protocolStatus) {
++ icp_ocfDrvSwapBytes(pR->pData, pR->dataLenInBytes);
++ icp_ocfDrvSwapBytes(pS->pData, pS->dataLenInBytes);
++ }
++
++ icp_ocfDrvFreeFlatBuffer(pR);
++ icp_ocfDrvFreeFlatBuffer(pS);
++ memset(pSignData->K.pData, 0, pSignData->K.dataLenInBytes);
++ ICP_CACHE_FREE(drvDSARSSignKValue_zone, pSignData->K.pData);
++ memset(pSignData, 0, sizeof(CpaCyDsaRSSignOpData));
++ ICP_CACHE_FREE(drvDSARSSign_zone, pSignData);
++ crypto_kdone(krp);
++
++ return;
++}
++
++/* Name : icp_ocfDrvDsaVerifyCallback
++ *
++ * Description : When this function returns it signifies that the LAC
++ * component has completed the DSA Verify operation.
++ */
++static void
++icp_ocfDrvDsaVerifyCallBack(void *callbackTag,
++ CpaStatus status,
++ void *pOpData, CpaBoolean verifyStatus)
++{
++
++ struct cryptkop *krp = NULL;
++ CpaCyDsaVerifyOpData *pVerData = NULL;
++
++ if (NULL == callbackTag) {
++ DPRINTK("%s(): Invalid input parameters - "
++ "callbackTag data is NULL\n", __FUNCTION__);
++ return;
++ }
++
++ krp = (struct cryptkop *)callbackTag;
++
++ if (NULL == pOpData) {
++ DPRINTK("%s(): Invalid input parameters - "
++ "Operation Data is NULL\n", __FUNCTION__);
++ krp->krp_status = ECANCELED;
++ crypto_kdone(krp);
++ return;
++ }
++ pVerData = (CpaCyDsaVerifyOpData *) pOpData;
++
++ if (CPA_STATUS_SUCCESS != status) {
++ APRINTK("%s(): LAC DSA Verify operation failed - "
++ "Operation Status = %d\n", __FUNCTION__, status);
++ krp->krp_status = ECANCELED;
++ } else {
++ krp->krp_status = CRYPTO_OP_SUCCESS;
++
++ if (CPA_TRUE != verifyStatus) {
++ DPRINTK("%s(): DSA signature invalid\n", __FUNCTION__);
++ krp->krp_status = EIO;
++ }
++ }
++
++ /* Swap bytes only when the callback status is successful and
++ verifyStatus is set to true */
++ /*Just swapping back the key values for now. Possibly all
++ swapped buffers need to be reverted */
++ if (CPA_STATUS_SUCCESS == status && CPA_TRUE == verifyStatus) {
++ icp_ocfDrvSwapBytes(pVerData->R.pData,
++ pVerData->R.dataLenInBytes);
++ icp_ocfDrvSwapBytes(pVerData->S.pData,
++ pVerData->S.dataLenInBytes);
++ }
++
++ memset(pVerData, 0, sizeof(CpaCyDsaVerifyOpData));
++ ICP_CACHE_FREE(drvDSAVerify_zone, pVerData);
++ crypto_kdone(krp);
++
++ return;
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/ep80579/icp_common.c linux-2.6.36/crypto/ocf/ep80579/icp_common.c
+--- linux-2.6.36.orig/crypto/ocf/ep80579/icp_common.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/ep80579/icp_common.c 2010-11-09 20:28:04.612495446 +0100
+@@ -0,0 +1,773 @@
++/*************************************************************************
++ *
++ * This file is provided under a dual BSD/GPLv2 license. When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * GPL LICENSE SUMMARY
++ *
++ * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ * The full GNU General Public License is included in this distribution
++ * in the file called LICENSE.GPL.
++ *
++ * Contact Information:
++ * Intel Corporation
++ *
++ * BSD LICENSE
++ *
++ * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
++ * 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 Intel Corporation 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE 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.
++ *
++ *
++ * version: Security.L.1.0.2-229
++ *
++ ***************************************************************************/
++
++/*
++ * An OCF module that uses Intel® QuickAssist Integrated Accelerator to do the
++ * crypto.
++ *
++ * This driver requires the ICP Access Library that is available from Intel in
++ * order to operate.
++ */
++
++#include "icp_ocf.h"
++
++#define ICP_OCF_COMP_NAME "ICP_OCF"
++#define ICP_OCF_VER_MAIN (2)
++#define ICP_OCF_VER_MJR (1)
++#define ICP_OCF_VER_MNR (0)
++
++#define MAX_DEREG_RETRIES (100)
++#define DEFAULT_DEREG_RETRIES (10)
++#define DEFAULT_DEREG_DELAY_IN_JIFFIES (10)
++
++/* This defines the maximum number of sessions possible between OCF
++ and the OCF EP80579 Driver. If set to zero, there is no limit. */
++#define DEFAULT_OCF_TO_DRV_MAX_SESSION_COUNT (0)
++#define NUM_SUPPORTED_CAPABILITIES (21)
++
++/*Slab zone names*/
++#define ICP_SESSION_DATA_NAME "icp_ocf.SesDat"
++#define ICP_OP_DATA_NAME "icp_ocf.OpDat"
++#define ICP_DH_NAME "icp_ocf.DH"
++#define ICP_MODEXP_NAME "icp_ocf.ModExp"
++#define ICP_RSA_DECRYPT_NAME "icp_ocf.RSAdec"
++#define ICP_RSA_PKEY_NAME "icp_ocf.RSApk"
++#define ICP_DSA_SIGN_NAME "icp_ocf.DSAsg"
++#define ICP_DSA_VER_NAME "icp_ocf.DSAver"
++#define ICP_RAND_VAL_NAME "icp_ocf.DSArnd"
++#define ICP_FLAT_BUFF_NAME "icp_ocf.FB"
++
++/*Slabs zones*/
++icp_kmem_cache drvSessionData_zone = NULL;
++icp_kmem_cache drvOpData_zone = NULL;
++icp_kmem_cache drvDH_zone = NULL;
++icp_kmem_cache drvLnModExp_zone = NULL;
++icp_kmem_cache drvRSADecrypt_zone = NULL;
++icp_kmem_cache drvRSAPrivateKey_zone = NULL;
++icp_kmem_cache drvDSARSSign_zone = NULL;
++icp_kmem_cache drvDSARSSignKValue_zone = NULL;
++icp_kmem_cache drvDSAVerify_zone = NULL;
++
++/*Slab zones for flatbuffers and bufferlist*/
++icp_kmem_cache drvFlatBuffer_zone = NULL;
++
++static inline int icp_cache_null_check(void)
++{
++ return (drvSessionData_zone && drvOpData_zone
++ && drvDH_zone && drvLnModExp_zone && drvRSADecrypt_zone
++ && drvRSAPrivateKey_zone && drvDSARSSign_zone
++ && drvDSARSSign_zone && drvDSARSSignKValue_zone
++ && drvDSAVerify_zone && drvFlatBuffer_zone);
++}
++
++/*Function to free all allocated slab caches before exiting the module*/
++static void icp_ocfDrvFreeCaches(void);
++
++int32_t icp_ocfDrvDriverId = INVALID_DRIVER_ID;
++
++/* Module parameter - gives the number of times LAC deregistration shall be
++ re-tried */
++int num_dereg_retries = DEFAULT_DEREG_RETRIES;
++
++/* Module parameter - gives the delay time in jiffies before a LAC session
++ shall be attempted to be deregistered again */
++int dereg_retry_delay_in_jiffies = DEFAULT_DEREG_DELAY_IN_JIFFIES;
++
++/* Module parameter - gives the maximum number of sessions possible between
++ OCF and the OCF EP80579 Driver. If set to zero, there is no limit.*/
++int max_sessions = DEFAULT_OCF_TO_DRV_MAX_SESSION_COUNT;
++
++/* This is set when the module is removed from the system, no further
++ processing can take place if this is set */
++icp_atomic_t icp_ocfDrvIsExiting = ICP_ATOMIC_INIT(0);
++
++/* This is used to show how many lac sessions were not deregistered*/
++icp_atomic_t lac_session_failed_dereg_count = ICP_ATOMIC_INIT(0);
++
++/* This is used to track the number of registered sessions between OCF and
++ * and the OCF EP80579 driver, when max_session is set to value other than
++ * zero. This ensures that the max_session set for the OCF and the driver
++ * is equal to the LAC registered sessions */
++icp_atomic_t num_ocf_to_drv_registered_sessions = ICP_ATOMIC_INIT(0);
++
++/* Head of linked list used to store session data */
++icp_drvSessionListHead_t icp_ocfDrvGlobalSymListHead;
++icp_drvSessionListHead_t icp_ocfDrvGlobalSymListHead_FreeMemList;
++
++icp_spinlock_t icp_ocfDrvSymSessInfoListSpinlock;
++
++/*Below pointer is only used in linux, FreeBSD uses the name to
++create its own variable name*/
++icp_workqueue *icp_ocfDrvFreeLacSessionWorkQ = NULL;
++ICP_WORKQUEUE_DEFINE_THREAD(icp_ocfDrvFreeLacSessionWorkQ);
++
++struct icp_drvBuffListInfo defBuffListInfo;
++
++/* Name : icp_ocfDrvInit
++ *
++ * Description : This function will register all the symmetric and asymmetric
++ * functionality that will be accelerated by the hardware. It will also
++ * get a unique driver ID from the OCF and initialise all slab caches
++ */
++ICP_MODULE_INIT_FUNC(icp_ocfDrvInit)
++{
++ int ocfStatus = 0;
++
++ IPRINTK("=== %s ver %d.%d.%d ===\n", ICP_OCF_COMP_NAME,
++ ICP_OCF_VER_MAIN, ICP_OCF_VER_MJR, ICP_OCF_VER_MNR);
++
++ if (MAX_DEREG_RETRIES < num_dereg_retries) {
++ EPRINTK("Session deregistration retry count set to greater "
++ "than %d", MAX_DEREG_RETRIES);
++ icp_module_return_code(EINVAL);
++ }
++
++ /* Initialize and Start the Cryptographic component */
++ if (CPA_STATUS_SUCCESS !=
++ cpaCyStartInstance(CPA_INSTANCE_HANDLE_SINGLE)) {
++ EPRINTK("Failed to initialize and start the instance "
++ "of the Cryptographic component.\n");
++ return icp_module_return_code(EINVAL);
++ }
++
++ icp_spin_lock_init(&icp_ocfDrvSymSessInfoListSpinlock);
++
++ /* Set the default size of BufferList to allocate */
++ memset(&defBuffListInfo, 0, sizeof(struct icp_drvBuffListInfo));
++ if (ICP_OCF_DRV_STATUS_SUCCESS !=
++ icp_ocfDrvBufferListMemInfo(ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS,
++ &defBuffListInfo)) {
++ EPRINTK("Failed to get bufferlist memory info.\n");
++ return icp_module_return_code(ENOMEM);
++ }
++
++ /*Register OCF EP80579 Driver with OCF */
++ icp_ocfDrvDriverId = ICP_CRYPTO_GET_DRIVERID();
++
++ if (icp_ocfDrvDriverId < 0) {
++ EPRINTK("%s : ICP driver failed to register with OCF!\n",
++ __FUNCTION__);
++ return icp_module_return_code(ENODEV);
++ }
++
++ /*Create all the slab caches used by the OCF EP80579 Driver */
++ drvSessionData_zone =
++ ICP_CACHE_CREATE(ICP_SESSION_DATA_NAME, struct icp_drvSessionData);
++
++ /*
++ * Allocation of the OpData includes the allocation space for meta data.
++ * The memory after the opData structure is reserved for this meta data.
++ */
++ drvOpData_zone =
++ icp_kmem_cache_create(ICP_OP_DATA_NAME,
++ sizeof(struct icp_drvOpData) +
++ defBuffListInfo.metaSize,
++ ICP_KERNEL_CACHE_ALIGN,
++ ICP_KERNEL_CACHE_NOINIT);
++
++ drvDH_zone = ICP_CACHE_CREATE(ICP_DH_NAME, CpaCyDhPhase1KeyGenOpData);
++
++ drvLnModExp_zone =
++ ICP_CACHE_CREATE(ICP_MODEXP_NAME, CpaCyLnModExpOpData);
++
++ drvRSADecrypt_zone =
++ ICP_CACHE_CREATE(ICP_RSA_DECRYPT_NAME, CpaCyRsaDecryptOpData);
++
++ drvRSAPrivateKey_zone =
++ ICP_CACHE_CREATE(ICP_RSA_PKEY_NAME, CpaCyRsaPrivateKey);
++
++ drvDSARSSign_zone =
++ ICP_CACHE_CREATE(ICP_DSA_SIGN_NAME, CpaCyDsaRSSignOpData);
++
++ /*too awkward to use a macro here */
++ drvDSARSSignKValue_zone =
++ ICP_CACHE_CREATE(ICP_RAND_VAL_NAME,
++ DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES);
++
++ drvDSAVerify_zone =
++ ICP_CACHE_CREATE(ICP_DSA_VER_NAME, CpaCyDsaVerifyOpData);
++
++ drvFlatBuffer_zone =
++ ICP_CACHE_CREATE(ICP_FLAT_BUFF_NAME, CpaFlatBuffer);
++
++ if (0 == icp_cache_null_check()) {
++ icp_ocfDrvFreeCaches();
++ EPRINTK("%s() line %d: Not enough memory!\n",
++ __FUNCTION__, __LINE__);
++ return ENOMEM;
++ }
++
++ /* Register the ICP symmetric crypto support. */
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_NULL_CBC, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_DES_CBC, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_3DES_CBC, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_AES_CBC, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_ARC4, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_MD5, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_MD5_HMAC, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA1, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA1_HMAC, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_256, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_256_HMAC,
++ ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_384, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_384_HMAC,
++ ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_512, ocfStatus);
++ ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_512_HMAC,
++ ocfStatus);
++
++ /* Register the ICP asymmetric algorithm support */
++ ICP_REG_ASYM_WITH_OCF(icp_ocfDrvDriverId, CRK_DH_COMPUTE_KEY,
++ ocfStatus);
++ ICP_REG_ASYM_WITH_OCF(icp_ocfDrvDriverId, CRK_MOD_EXP, ocfStatus);
++ ICP_REG_ASYM_WITH_OCF(icp_ocfDrvDriverId, CRK_MOD_EXP_CRT, ocfStatus);
++ ICP_REG_ASYM_WITH_OCF(icp_ocfDrvDriverId, CRK_DSA_SIGN, ocfStatus);
++ ICP_REG_ASYM_WITH_OCF(icp_ocfDrvDriverId, CRK_DSA_VERIFY, ocfStatus);
++
++ /* Register the ICP random number generator support */
++ ICP_REG_RAND_WITH_OCF(icp_ocfDrvDriverId,
++ icp_ocfDrvReadRandom, NULL, ocfStatus);
++
++ if (OCF_ZERO_FUNCTIONALITY_REGISTERED == ocfStatus) {
++ DPRINTK("%s: Failed to register any device capabilities\n",
++ __FUNCTION__);
++ icp_ocfDrvFreeCaches();
++ icp_ocfDrvDriverId = INVALID_DRIVER_ID;
++ return icp_module_return_code(ECANCELED);
++ }
++
++ DPRINTK("%s: Registered %d of %d device capabilities\n",
++ __FUNCTION__, ocfStatus, NUM_SUPPORTED_CAPABILITIES);
++
++ /*Session data linked list used during module exit */
++ ICP_INIT_LIST_HEAD(&icp_ocfDrvGlobalSymListHead);
++ ICP_INIT_LIST_HEAD(&icp_ocfDrvGlobalSymListHead_FreeMemList);
++
++ ICP_WORKQUEUE_CREATE(icp_ocfDrvFreeLacSessionWorkQ, "icpwq");
++ if (ICP_WORKQUEUE_NULL_CHECK(icp_ocfDrvFreeLacSessionWorkQ)) {
++ EPRINTK("%s: Failed to create single "
++ "thread workqueue\n", __FUNCTION__);
++ icp_ocfDrvFreeCaches();
++ icp_ocfDrvDriverId = INVALID_DRIVER_ID;
++ return icp_module_return_code(ENOMEM);
++ }
++
++ return icp_module_return_code(0);
++}
++
++/* Name : icp_ocfDrvExit
++ *
++ * Description : This function will deregister all the symmetric sessions
++ * registered with the LAC component. It will also deregister all symmetric
++ * and asymmetric functionality that can be accelerated by the hardware via OCF
++ * and random number generation if it is enabled.
++ */
++ICP_MODULE_EXIT_FUNC(icp_ocfDrvExit)
++{
++ CpaStatus lacStatus = CPA_STATUS_SUCCESS;
++ struct icp_drvSessionData *sessionData = NULL;
++ struct icp_drvSessionData *tempSessionData = NULL;
++ int i, remaining_delay_time_in_jiffies = 0;
++
++ /* For FreeBSD the invariant macro below makes function to return */
++ /* with EBUSY value in the case of any session which has been regi- */
++ /* stered with LAC not being deregistered. */
++ /* The Linux implementation is empty since it is purely to compensate */
++ /* for a limitation of the FreeBSD 7.1 Opencrypto framework. */
++
++ ICP_MODULE_EXIT_INV();
++
++ /* There is a possibility of a process or new session command being */
++ /* sent before this variable is incremented. The aim of this variable */
++ /* is to stop a loop of calls creating a deadlock situation which */
++ /* would prevent the driver from exiting. */
++ icp_atomic_set(&icp_ocfDrvIsExiting, 1);
++
++ /*Existing sessions will be routed to another driver after these calls */
++ crypto_unregister_all(icp_ocfDrvDriverId);
++ crypto_runregister_all(icp_ocfDrvDriverId);
++
++ if (ICP_WORKQUEUE_NULL_CHECK(icp_ocfDrvFreeLacSessionWorkQ)) {
++ DPRINTK("%s: workqueue already "
++ "destroyed, therefore module exit "
++ " function already called. Exiting.\n", __FUNCTION__);
++ return ICP_MODULE_EXIT_FUNC_RETURN_VAL;
++ }
++ /*If any sessions are waiting to be deregistered, do that. This also
++ flushes the work queue */
++ ICP_WORKQUEUE_DESTROY(icp_ocfDrvFreeLacSessionWorkQ);
++
++ /*ENTER CRITICAL SECTION */
++ icp_spin_lockbh_lock(&icp_ocfDrvSymSessInfoListSpinlock);
++
++ ICP_LIST_FOR_EACH_ENTRY_SAFE(tempSessionData, sessionData,
++ &icp_ocfDrvGlobalSymListHead, listNode) {
++ for (i = 0; i < num_dereg_retries; i++) {
++ /*No harm if bad input - LAC will handle error cases */
++ if (ICP_SESSION_RUNNING == tempSessionData->inUse) {
++ lacStatus =
++ cpaCySymRemoveSession
++ (CPA_INSTANCE_HANDLE_SINGLE,
++ tempSessionData->sessHandle);
++ if (CPA_STATUS_SUCCESS == lacStatus) {
++ /* Succesfully deregistered */
++ break;
++ } else if (CPA_STATUS_RETRY != lacStatus) {
++ icp_atomic_inc
++ (&lac_session_failed_dereg_count);
++ break;
++ }
++
++ /*schedule_timout returns the time left for completion if
++ * this task is set to TASK_INTERRUPTIBLE */
++ remaining_delay_time_in_jiffies =
++ dereg_retry_delay_in_jiffies;
++ while (0 > remaining_delay_time_in_jiffies) {
++ remaining_delay_time_in_jiffies =
++ icp_schedule_timeout
++ (&icp_ocfDrvSymSessInfoListSpinlock,
++ remaining_delay_time_in_jiffies);
++ }
++
++ DPRINTK
++ ("%s(): Retry %d to deregistrate the session\n",
++ __FUNCTION__, i);
++ }
++ }
++
++ /*remove from current list */
++ ICP_LIST_DEL(tempSessionData, listNode);
++ /*add to free mem linked list */
++ ICP_LIST_ADD(tempSessionData,
++ &icp_ocfDrvGlobalSymListHead_FreeMemList,
++ listNode);
++
++ }
++
++ /*EXIT CRITICAL SECTION */
++ icp_spin_lockbh_unlock(&icp_ocfDrvSymSessInfoListSpinlock);
++
++ /*set back to initial values */
++ sessionData = NULL;
++ /*still have a reference in our list! */
++ tempSessionData = NULL;
++ /*free memory */
++
++ ICP_LIST_FOR_EACH_ENTRY_SAFE(tempSessionData, sessionData,
++ &icp_ocfDrvGlobalSymListHead_FreeMemList,
++ listNode) {
++
++ ICP_LIST_DEL(tempSessionData, listNode);
++ /* Free allocated CpaCySymSessionCtx */
++ if (NULL != tempSessionData->sessHandle) {
++ icp_kfree(tempSessionData->sessHandle);
++ }
++ memset(tempSessionData, 0, sizeof(struct icp_drvSessionData));
++ ICP_CACHE_FREE(drvSessionData_zone, tempSessionData);
++ }
++
++ if (0 != icp_atomic_read(&lac_session_failed_dereg_count)) {
++ DPRINTK("%s(): %d LAC sessions were not deregistered "
++ "correctly. This is not a clean exit! \n",
++ __FUNCTION__,
++ icp_atomic_read(&lac_session_failed_dereg_count));
++ }
++
++ icp_ocfDrvFreeCaches();
++ icp_ocfDrvDriverId = INVALID_DRIVER_ID;
++
++ icp_spin_lock_destroy(&icp_ocfDrvSymSessInfoListSpinlock);
++
++ /* Shutdown the Cryptographic component */
++ lacStatus = cpaCyStopInstance(CPA_INSTANCE_HANDLE_SINGLE);
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ DPRINTK("%s(): Failed to stop instance of the "
++ "Cryptographic component.(status == %d)\n",
++ __FUNCTION__, lacStatus);
++ }
++
++ return ICP_MODULE_EXIT_FUNC_RETURN_VAL;
++}
++
++/* Name : icp_ocfDrvFreeCaches
++ *
++ * Description : This function deregisters all slab caches
++ */
++static void icp_ocfDrvFreeCaches(void)
++{
++ icp_atomic_set(&icp_ocfDrvIsExiting, 1);
++
++ /*Sym Zones */
++ ICP_CACHE_DESTROY(drvSessionData_zone);
++ ICP_CACHE_DESTROY(drvOpData_zone);
++
++ /*Asym zones */
++ ICP_CACHE_DESTROY(drvDH_zone);
++ ICP_CACHE_DESTROY(drvLnModExp_zone);
++ ICP_CACHE_DESTROY(drvRSADecrypt_zone);
++ ICP_CACHE_DESTROY(drvRSAPrivateKey_zone);
++ ICP_CACHE_DESTROY(drvDSARSSignKValue_zone);
++ ICP_CACHE_DESTROY(drvDSARSSign_zone);
++ ICP_CACHE_DESTROY(drvDSAVerify_zone);
++
++ /*FlatBuffer and BufferList Zones */
++ ICP_CACHE_DESTROY(drvFlatBuffer_zone);
++
++}
++
++/* Name : icp_ocfDrvDeregRetry
++ *
++ * Description : This function will try to farm the session deregistration
++ * off to a work queue. If it fails, nothing more can be done and it
++ * returns an error
++ */
++int icp_ocfDrvDeregRetry(CpaCySymSessionCtx sessionToDeregister)
++{
++ struct icp_ocfDrvFreeLacSession *workstore = NULL;
++
++ DPRINTK("%s(): Retry - Deregistering session (%p)\n",
++ __FUNCTION__, sessionToDeregister);
++
++ /*make sure the session is not available to be allocated during this
++ process */
++ icp_atomic_inc(&lac_session_failed_dereg_count);
++
++ /*Farm off to work queue */
++ workstore =
++ icp_kmalloc(sizeof(struct icp_ocfDrvFreeLacSession), ICP_M_NOWAIT);
++ if (NULL == workstore) {
++ DPRINTK("%s(): unable to free session - no memory available "
++ "for work queue\n", __FUNCTION__);
++ return ENOMEM;
++ }
++
++ workstore->sessionToDeregister = sessionToDeregister;
++
++ icp_init_work(&(workstore->work),
++ icp_ocfDrvDeferedFreeLacSessionTaskFn, workstore);
++
++ ICP_WORKQUEUE_ENQUEUE(icp_ocfDrvFreeLacSessionWorkQ,
++ &(workstore->work));
++
++ return ICP_OCF_DRV_STATUS_SUCCESS;
++
++}
++
++/* Name : icp_ocfDrvDeferedFreeLacSessionProcess
++ *
++ * Description : This function will retry (module input parameter)
++ * 'num_dereg_retries' times to deregister any symmetric session that recieves a
++ * CPA_STATUS_RETRY message from the LAC component. This function is run in
++ * Thread context because it is called from a worker thread
++ */
++void icp_ocfDrvDeferedFreeLacSessionProcess(void *arg)
++{
++ struct icp_ocfDrvFreeLacSession *workstore = NULL;
++ CpaCySymSessionCtx sessionToDeregister = NULL;
++ int i = 0;
++ int remaining_delay_time_in_jiffies = 0;
++ CpaStatus lacStatus = CPA_STATUS_SUCCESS;
++
++ workstore = (struct icp_ocfDrvFreeLacSession *)arg;
++ if (NULL == workstore) {
++ DPRINTK("%s() function called with null parameter \n",
++ __FUNCTION__);
++ return;
++ }
++
++ sessionToDeregister = workstore->sessionToDeregister;
++ icp_kfree(workstore);
++
++ /*if exiting, give deregistration one more blast only */
++ if (icp_atomic_read(&icp_ocfDrvIsExiting) == CPA_TRUE) {
++ lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE,
++ sessionToDeregister);
++
++ if (lacStatus != CPA_STATUS_SUCCESS) {
++ DPRINTK("%s() Failed to Dereg LAC session %p "
++ "during module exit\n", __FUNCTION__,
++ sessionToDeregister);
++ return;
++ }
++
++ icp_atomic_dec(&lac_session_failed_dereg_count);
++ return;
++ }
++
++ for (i = 0; i <= num_dereg_retries; i++) {
++ lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE,
++ sessionToDeregister);
++
++ if (lacStatus == CPA_STATUS_SUCCESS) {
++ icp_atomic_dec(&lac_session_failed_dereg_count);
++ return;
++ }
++ if (lacStatus != CPA_STATUS_RETRY) {
++ DPRINTK("%s() Failed to deregister session - lacStatus "
++ " = %d", __FUNCTION__, lacStatus);
++ break;
++ }
++
++ /*schedule_timout returns the time left for completion if this
++ task is set to TASK_INTERRUPTIBLE */
++ remaining_delay_time_in_jiffies = dereg_retry_delay_in_jiffies;
++ while (0 < remaining_delay_time_in_jiffies) {
++ remaining_delay_time_in_jiffies =
++ icp_schedule_timeout(NULL,
++ remaining_delay_time_in_jiffies);
++ }
++
++ }
++
++ DPRINTK("%s(): Unable to deregister session\n", __FUNCTION__);
++ DPRINTK("%s(): Number of unavailable LAC sessions = %d\n", __FUNCTION__,
++ icp_atomic_read(&lac_session_failed_dereg_count));
++}
++
++/* Name : icp_ocfDrvPtrAndLenToFlatBuffer
++ *
++ * Description : This function converts a "pointer and length" buffer
++ * structure to Fredericksburg Flat Buffer (CpaFlatBuffer) format.
++ *
++ * This function assumes that the data passed in are valid.
++ */
++inline void
++icp_ocfDrvPtrAndLenToFlatBuffer(void *pData, uint32_t len,
++ CpaFlatBuffer * pFlatBuffer)
++{
++ pFlatBuffer->pData = pData;
++ pFlatBuffer->dataLenInBytes = len;
++}
++
++/* Name : icp_ocfDrvPtrAndLenToBufferList
++ *
++ * Description : This function converts a "pointer and length" buffer
++ * structure to Fredericksburg Scatter/Gather Buffer (CpaBufferList) format.
++ *
++ * This function assumes that the data passed in are valid.
++ */
++inline void
++icp_ocfDrvPtrAndLenToBufferList(void *pDataIn, uint32_t length,
++ CpaBufferList * pBufferList)
++{
++ pBufferList->numBuffers = 1;
++ pBufferList->pBuffers->pData = pDataIn;
++ pBufferList->pBuffers->dataLenInBytes = length;
++}
++
++/* Name : icp_ocfDrvBufferListToPtrAndLen
++ *
++ * Description : This function converts Fredericksburg Scatter/Gather Buffer
++ * (CpaBufferList) format to a "pointer and length" buffer structure.
++ *
++ * This function assumes that the data passed in are valid.
++ */
++inline void
++icp_ocfDrvBufferListToPtrAndLen(CpaBufferList * pBufferList,
++ void **ppDataOut, uint32_t * pLength)
++{
++ *ppDataOut = pBufferList->pBuffers->pData;
++ *pLength = pBufferList->pBuffers->dataLenInBytes;
++}
++
++/* Name : icp_ocfDrvBufferListMemInfo
++ *
++ * Description : This function will set the number of flat buffers in
++ * bufferlist, the size of memory to allocate for the pPrivateMetaData
++ * member of the CpaBufferList.
++ */
++int
++icp_ocfDrvBufferListMemInfo(uint16_t numBuffers,
++ struct icp_drvBuffListInfo *buffListInfo)
++{
++ buffListInfo->numBuffers = numBuffers;
++
++ if (CPA_STATUS_SUCCESS !=
++ cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE,
++ buffListInfo->numBuffers,
++ &(buffListInfo->metaSize))) {
++ EPRINTK("%s() Failed to get buffer list meta size.\n",
++ __FUNCTION__);
++ return ICP_OCF_DRV_STATUS_FAIL;
++ }
++
++ return ICP_OCF_DRV_STATUS_SUCCESS;
++}
++
++/* Name : icp_ocfDrvFreeFlatBuffer
++ *
++ * Description : This function will deallocate flat buffer.
++ */
++inline void icp_ocfDrvFreeFlatBuffer(CpaFlatBuffer * pFlatBuffer)
++{
++ if (pFlatBuffer != NULL) {
++ memset(pFlatBuffer, 0, sizeof(CpaFlatBuffer));
++ ICP_CACHE_FREE(drvFlatBuffer_zone, pFlatBuffer);
++ }
++}
++
++/* Name : icp_ocfDrvAllocMetaData
++ *
++ * Description : This function will allocate memory for the
++ * pPrivateMetaData member of CpaBufferList.
++ */
++inline int
++icp_ocfDrvAllocMetaData(CpaBufferList * pBufferList,
++ struct icp_drvOpData *pOpData)
++{
++ Cpa32U metaSize = 0;
++
++ if (pBufferList->numBuffers <= ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) {
++ uint8_t *pOpDataStartAddr = (uint8_t *) pOpData;
++
++ if (0 == defBuffListInfo.metaSize) {
++ pBufferList->pPrivateMetaData = NULL;
++ return ICP_OCF_DRV_STATUS_SUCCESS;
++ }
++ /*
++ * The meta data allocation has been included as part of the
++ * op data. It has been pre-allocated in memory just after the
++ * icp_drvOpData structure.
++ */
++ pBufferList->pPrivateMetaData = (void *)(pOpDataStartAddr +
++ sizeof(struct
++ icp_drvOpData));
++ } else {
++ if (CPA_STATUS_SUCCESS !=
++ cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE,
++ pBufferList->numBuffers,
++ &metaSize)) {
++ EPRINTK("%s() Failed to get buffer list meta size.\n",
++ __FUNCTION__);
++ return ICP_OCF_DRV_STATUS_FAIL;
++ }
++
++ if (0 == metaSize) {
++ pBufferList->pPrivateMetaData = NULL;
++ return ICP_OCF_DRV_STATUS_SUCCESS;
++ }
++
++ pBufferList->pPrivateMetaData =
++ icp_kmalloc(metaSize, ICP_M_NOWAIT);
++ }
++ if (NULL == pBufferList->pPrivateMetaData) {
++ EPRINTK("%s() Failed to allocate pPrivateMetaData.\n",
++ __FUNCTION__);
++ return ICP_OCF_DRV_STATUS_FAIL;
++ }
++
++ return ICP_OCF_DRV_STATUS_SUCCESS;
++}
++
++/* Name : icp_ocfDrvFreeMetaData
++ *
++ * Description : This function will deallocate pPrivateMetaData memory.
++ */
++inline void icp_ocfDrvFreeMetaData(CpaBufferList * pBufferList)
++{
++ if (NULL == pBufferList->pPrivateMetaData) {
++ return;
++ }
++
++ /*
++ * Only free the meta data if the BufferList has more than
++ * ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS number of buffers.
++ * Otherwise, the meta data shall be freed when the icp_drvOpData is
++ * freed.
++ */
++ if (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS < pBufferList->numBuffers) {
++ icp_kfree(pBufferList->pPrivateMetaData);
++ }
++}
++
++/* Module declaration, init and exit functions */
++ICP_DECLARE_MODULE(icp_ocf, icp_ocfDrvInit, icp_ocfDrvExit);
++ICP_MODULE_DESCRIPTION("OCF Driver for Intel Quick Assist crypto acceleration");
++ICP_MODULE_VERSION(icp_ocf, ICP_OCF_VER_MJR);
++ICP_MODULE_LICENSE("Dual BSD/GPL");
++ICP_MODULE_AUTHOR("Intel");
++
++/* Module parameters */
++ICP_MODULE_PARAM_INT(icp_ocf, num_dereg_retries,
++ "Number of times to retry LAC Sym Session Deregistration. "
++ "Default 10, Max 100");
++ICP_MODULE_PARAM_INT(icp_ocf, dereg_retry_delay_in_jiffies, "Delay in jiffies "
++ "(added to a schedule() function call) before a LAC Sym "
++ "Session Dereg is retried. Default 10");
++ICP_MODULE_PARAM_INT(icp_ocf, max_sessions,
++ "This sets the maximum number of sessions "
++ "between OCF and this driver. If this value is set to zero,"
++ "max session count checking is disabled. Default is zero(0)");
++
++/* Module dependencies */
++#define MODULE_MIN_VER 1
++#define CRYPTO_MAX_VER 3
++#define LAC_MAX_VER 2
++
++ICP_MODULE_DEPEND(icp_ocf, crypto, MODULE_MIN_VER, MODULE_MIN_VER,
++ CRYPTO_MAX_VER);
++ICP_MODULE_DEPEND(icp_ocf, cryptodev, MODULE_MIN_VER, MODULE_MIN_VER,
++ CRYPTO_MAX_VER);
++ICP_MODULE_DEPEND(icp_ocf, icp_crypto, MODULE_MIN_VER, MODULE_MIN_VER,
++ LAC_MAX_VER);
+diff -Nur linux-2.6.36.orig/crypto/ocf/ep80579/icp_ocf.h linux-2.6.36/crypto/ocf/ep80579/icp_ocf.h
+--- linux-2.6.36.orig/crypto/ocf/ep80579/icp_ocf.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/ep80579/icp_ocf.h 2010-11-09 20:28:04.662495462 +0100
+@@ -0,0 +1,376 @@
++/***************************************************************************
++ *
++ * This file is provided under a dual BSD/GPLv2 license. When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * GPL LICENSE SUMMARY
++ *
++ * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ * The full GNU General Public License is included in this distribution
++ * in the file called LICENSE.GPL.
++ *
++ * Contact Information:
++ * Intel Corporation
++ *
++ * BSD LICENSE
++ *
++ * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
++ * 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 Intel Corporation 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE 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.
++ *
++ *
++ * version: Security.L.1.0.2-229
++ *
++ ***************************************************************************/
++
++/*
++ * OCF driver header file for the Intel ICP processor.
++ */
++
++#ifndef ICP_OCF_H_
++#define ICP_OCF_H_
++
++#include <cpa.h>
++#include <cpa_cy_im.h>
++#include <cpa_cy_sym.h>
++#include <cpa_cy_rand.h>
++#include <cpa_cy_dh.h>
++#include <cpa_cy_rsa.h>
++#include <cpa_cy_ln.h>
++#include <cpa_cy_common.h>
++#include <cpa_cy_dsa.h>
++
++#include "icp_os.h"
++
++#define NUM_BITS_IN_BYTE (8)
++#define NUM_BITS_IN_BYTE_MINUS_ONE (NUM_BITS_IN_BYTE -1)
++#define INVALID_DRIVER_ID (-1)
++#define RETURN_RAND_NUM_GEN_FAILED (-1)
++
++/*This is the max block cipher initialisation vector*/
++#define MAX_IV_LEN_IN_BYTES (20)
++/*This is used to check whether the OCF to this driver session limit has
++ been disabled*/
++#define NO_OCF_TO_DRV_MAX_SESSIONS (0)
++
++/*OCF values mapped here*/
++#define ICP_SHA1_DIGEST_SIZE_IN_BYTES (SHA1_HASH_LEN)
++#define ICP_SHA256_DIGEST_SIZE_IN_BYTES (SHA2_256_HASH_LEN)
++#define ICP_SHA384_DIGEST_SIZE_IN_BYTES (SHA2_384_HASH_LEN)
++#define ICP_SHA512_DIGEST_SIZE_IN_BYTES (SHA2_512_HASH_LEN)
++#define ICP_MD5_DIGEST_SIZE_IN_BYTES (MD5_HASH_LEN)
++#define ARC4_COUNTER_LEN (ARC4_BLOCK_LEN)
++
++#define OCF_REGISTRATION_STATUS_SUCCESS (0)
++#define OCF_ZERO_FUNCTIONALITY_REGISTERED (0)
++#define ICP_OCF_DRV_NO_CRYPTO_PROCESS_ERROR (0)
++#define ICP_OCF_DRV_STATUS_SUCCESS (0)
++#define ICP_OCF_DRV_STATUS_FAIL (1)
++
++/*Turn on/off debug options*/
++#define ICP_OCF_PRINT_DEBUG_MESSAGES (0)
++#define ICP_OCF_PRINT_KERN_ALERT (1)
++#define ICP_OCF_PRINT_KERN_ERRS (1)
++
++#if ICP_OCF_PRINT_DEBUG_MESSAGES == 1
++#define DPRINTK(args...) \
++{ \
++ ICP_IPRINTK(args); \
++}
++
++#else //ICP_OCF_PRINT_DEBUG_MESSAGES == 1
++
++#define DPRINTK(args...)
++
++#endif //ICP_OCF_PRINT_DEBUG_MESSAGES == 1
++
++#if ICP_OCF_PRINT_KERN_ALERT == 1
++#define APRINTK(args...) \
++{ \
++ ICP_APRINTK(args); \
++}
++
++#else //ICP_OCF_PRINT_KERN_ALERT == 1
++
++#define APRINTK(args...)
++
++#endif //ICP_OCF_PRINT_KERN_ALERT == 1
++
++#if ICP_OCF_PRINT_KERN_ERRS == 1
++#define EPRINTK(args...) \
++{ \
++ ICP_EPRINTK(args); \
++}
++
++#else //ICP_OCF_PRINT_KERN_ERRS == 1
++
++#define EPRINTK(args...)
++
++#endif //ICP_OCF_PRINT_KERN_ERRS == 1
++
++#define IPRINTK(args...) \
++{ \
++ ICP_IPRINTK(args); \
++}
++
++/*DSA Prime Q size in bytes (as defined in the standard) */
++#define DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES (20)
++
++#define BITS_TO_BYTES(bytes, bits) \
++ bytes = (bits + NUM_BITS_IN_BYTE_MINUS_ONE) / NUM_BITS_IN_BYTE
++
++typedef enum {
++ ICP_OCF_DRV_ALG_CIPHER = 0,
++ ICP_OCF_DRV_ALG_HASH
++} icp_ocf_drv_alg_type_t;
++
++typedef ICP_LIST_HEAD(icp_drvSessionListHead_s,
++ icp_drvSessionData) icp_drvSessionListHead_t;
++
++/*Values used to derisk chances of performs being called against
++deregistered sessions (for which the slab page has been reclaimed)
++This is not a fix - since page frames are reclaimed from a slab, one cannot
++rely on that memory not being re-used by another app.*/
++typedef enum {
++ ICP_SESSION_INITIALISED = 0x5C5C5C,
++ ICP_SESSION_RUNNING = 0x005C00,
++ ICP_SESSION_DEREGISTERED = 0xC5C5C5
++} usage_derisk;
++
++/* This struct is required for deferred session
++ deregistration as a work queue function can
++ only have one argument*/
++struct icp_ocfDrvFreeLacSession {
++ CpaCySymSessionCtx sessionToDeregister;
++ icp_workstruct work;
++};
++
++/*
++This is the OCF<->OCF_DRV session object:
++
++1.listNode
++ The first member is a listNode. These session objects are added to a linked
++ list in order to make it easier to remove them all at session exit time.
++
++2.inUse
++ The second member is used to give the session object state and derisk the
++ possibility of OCF batch calls executing against a deregistered session (as
++ described above).
++
++3.sessHandle
++ The third member is a LAC<->OCF_DRV session handle (initialised with the first
++ perform request for that session).
++
++4.lacSessCtx
++ The fourth is the LAC session context. All the parameters for this structure
++ are only known when the first perform request for this session occurs. That is
++ why the OCF EP80579 Driver only registers a new LAC session at perform time
++*/
++struct icp_drvSessionData {
++ ICP_LIST_ENTRY(icp_drvSessionData) listNode;
++ usage_derisk inUse;
++ CpaCySymSessionCtx sessHandle;
++ CpaCySymSessionSetupData lacSessCtx;
++};
++
++/* These are all defined in icp_common.c */
++extern icp_atomic_t lac_session_failed_dereg_count;
++extern icp_atomic_t icp_ocfDrvIsExiting;
++extern icp_atomic_t num_ocf_to_drv_registered_sessions;
++
++extern int32_t icp_ocfDrvDriverId;
++
++extern icp_drvSessionListHead_t icp_ocfDrvGlobalSymListHead;
++extern icp_drvSessionListHead_t icp_ocfDrvGlobalSymListHead_FreeMemList;
++extern icp_workqueue *icp_ocfDrvFreeLacSessionWorkQ;
++extern icp_spinlock_t icp_ocfDrvSymSessInfoListSpinlock;
++
++/*Slab zones for symettric functionality, instantiated in icp_common.c*/
++extern icp_kmem_cache drvSessionData_zone;
++extern icp_kmem_cache drvOpData_zone;
++
++/*Slabs zones for asymettric functionality, instantiated in icp_common.c*/
++extern icp_kmem_cache drvDH_zone;
++extern icp_kmem_cache drvLnModExp_zone;
++extern icp_kmem_cache drvRSADecrypt_zone;
++extern icp_kmem_cache drvRSAPrivateKey_zone;
++extern icp_kmem_cache drvDSARSSign_zone;
++extern icp_kmem_cache drvDSARSSignKValue_zone;
++extern icp_kmem_cache drvDSAVerify_zone;
++
++/* Module parameters defined in icp_cpmmon.c*/
++
++/* Module parameters - gives the number of times LAC deregistration shall be
++ re-tried */
++extern int num_dereg_retries;
++
++/* Module parameter - gives the delay time in jiffies before a LAC session
++ shall be attempted to be deregistered again */
++extern int dereg_retry_delay_in_jiffies;
++
++/* Module parameter - gives the maximum number of sessions possible between
++ OCF and the OCF EP80579 Driver. If set to zero, there is no limit.*/
++extern int max_sessions;
++
++/*Slab zones for flatbuffers and bufferlist*/
++extern icp_kmem_cache drvFlatBuffer_zone;
++
++#define ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS (16)
++
++struct icp_drvBuffListInfo {
++ Cpa16U numBuffers;
++ Cpa32U metaSize;
++ Cpa32U metaOffset;
++ Cpa32U buffListSize;
++};
++
++extern struct icp_drvBuffListInfo defBuffListInfo;
++
++/* This struct is used to keep a reference to the relevant node in the list
++ of sessionData structs, to the buffer type required by OCF and to the OCF
++ provided crp struct that needs to be returned. All this info is needed in
++ the callback function.*/
++struct icp_drvOpData {
++ CpaCySymOpData lacOpData;
++ uint32_t digestSizeInBytes;
++ struct cryptop *crp;
++ uint8_t bufferType;
++ uint8_t ivData[MAX_IV_LEN_IN_BYTES];
++ uint16_t numBufferListArray;
++ CpaBufferList srcBuffer;
++ CpaFlatBuffer bufferListArray[ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS];
++ CpaBoolean verifyResult;
++};
++
++/* Create a new session between OCF and this driver*/
++int icp_ocfDrvNewSession(icp_device_t dev, uint32_t * sild,
++ struct cryptoini *cri);
++
++/* Free a session between this driver and the Quick Assist Framework*/
++int icp_ocfDrvFreeLACSession(icp_device_t dev, uint64_t sid);
++
++/* Defer freeing a Quick Assist session*/
++void icp_ocfDrvDeferedFreeLacSessionProcess(void *arg);
++
++/* Process OCF cryptographic request for a symmetric algorithm*/
++int icp_ocfDrvSymProcess(icp_device_t dev, struct cryptop *crp, int hint);
++
++/* Process OCF cryptographic request for an asymmetric algorithm*/
++int icp_ocfDrvPkeProcess(icp_device_t dev, struct cryptkop *krp, int hint);
++
++/* Populate a buffer with random data*/
++int icp_ocfDrvReadRandom(void *arg, uint32_t * buf, int maxwords);
++
++/* Retry Quick Assist session deregistration*/
++int icp_ocfDrvDeregRetry(CpaCySymSessionCtx sessionToDeregister);
++
++/* Convert an OS scatter gather list to a CPA buffer list*/
++int icp_ocfDrvPacketBuffToBufferList(icp_packet_buffer_t * pPacketBuffer,
++ CpaBufferList * bufferList);
++
++/* Convert a CPA buffer list to an OS scatter gather list*/
++int icp_ocfDrvBufferListToPacketBuff(CpaBufferList * bufferList,
++ icp_packet_buffer_t ** pPacketBuffer);
++
++/* Get the number of buffers in an OS scatter gather list*/
++uint16_t icp_ocfDrvGetPacketBuffFrags(icp_packet_buffer_t * pPacketBuffer);
++
++/* Convert a single OS buffer to a CPA Flat Buffer*/
++void icp_ocfDrvSinglePacketBuffToFlatBuffer(icp_packet_buffer_t * pPacketBuffer,
++ CpaFlatBuffer * pFlatBuffer);
++
++/* Add pointer and length to a CPA Flat Buffer structure*/
++void icp_ocfDrvPtrAndLenToFlatBuffer(void *pData, uint32_t len,
++ CpaFlatBuffer * pFlatBuffer);
++
++/* Convert pointer and length values to a CPA buffer list*/
++void icp_ocfDrvPtrAndLenToBufferList(void *pDataIn, uint32_t length,
++ CpaBufferList * pBufferList);
++
++/* Convert a CPA buffer list to pointer and length values*/
++void icp_ocfDrvBufferListToPtrAndLen(CpaBufferList * pBufferList,
++ void **ppDataOut, uint32_t * pLength);
++
++/* Set the number of flat buffers in bufferlist and the size of memory
++ to allocate for the pPrivateMetaData member of the CpaBufferList.*/
++int icp_ocfDrvBufferListMemInfo(uint16_t numBuffers,
++ struct icp_drvBuffListInfo *buffListInfo);
++
++/* Find pointer position of the digest within an OS scatter gather list*/
++uint8_t *icp_ocfDrvPacketBufferDigestPointerFind(struct icp_drvOpData
++ *drvOpData,
++ int offsetInBytes,
++ uint32_t digestSizeInBytes);
++
++/*This top level function is used to find a pointer to where a digest is
++ stored/needs to be inserted. */
++uint8_t *icp_ocfDrvDigestPointerFind(struct icp_drvOpData *drvOpData,
++ struct cryptodesc *crp_desc);
++
++/* Free a CPA flat buffer*/
++void icp_ocfDrvFreeFlatBuffer(CpaFlatBuffer * pFlatBuffer);
++
++/* This function will allocate memory for the pPrivateMetaData
++ member of CpaBufferList. */
++int icp_ocfDrvAllocMetaData(CpaBufferList * pBufferList,
++ struct icp_drvOpData *pOpData);
++
++/* Free data allocated for the pPrivateMetaData
++ member of CpaBufferList.*/
++void icp_ocfDrvFreeMetaData(CpaBufferList * pBufferList);
++
++#define ICP_CACHE_CREATE(cache_ID, cache_name) \
++ icp_kmem_cache_create(cache_ID, sizeof(cache_name),ICP_KERNEL_CACHE_ALIGN,\
++ ICP_KERNEL_CACHE_NOINIT)
++
++#define ICP_CACHE_FREE(args...) \
++ icp_kmem_cache_free (args)
++
++#define ICP_CACHE_DESTROY(slab_zone)\
++{\
++ if(NULL != slab_zone){\
++ icp_kmem_cache_destroy(slab_zone);\
++ slab_zone = NULL;\
++ }\
++}
++
++#endif
++/* ICP_OCF_H_ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/ep80579/icp_sym.c linux-2.6.36/crypto/ocf/ep80579/icp_sym.c
+--- linux-2.6.36.orig/crypto/ocf/ep80579/icp_sym.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/ep80579/icp_sym.c 2010-11-09 20:28:04.702495471 +0100
+@@ -0,0 +1,1153 @@
++/***************************************************************************
++ *
++ * This file is provided under a dual BSD/GPLv2 license. When using or
++ * redistributing this file, you may do so under either license.
++ *
++ * GPL LICENSE SUMMARY
++ *
++ * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ * The full GNU General Public License is included in this distribution
++ * in the file called LICENSE.GPL.
++ *
++ * Contact Information:
++ * Intel Corporation
++ *
++ * BSD LICENSE
++ *
++ * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
++ * 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 Intel Corporation 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE 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.
++ *
++ *
++ * version: Security.L.1.0.2-229
++ *
++ ***************************************************************************/
++/*
++ * An OCF module that uses the API for Intel® QuickAssist Technology to do the
++ * cryptography.
++ *
++ * This driver requires the ICP Access Library that is available from Intel in
++ * order to operate.
++ */
++
++#include "icp_ocf.h"
++
++/*This is the call back function for all symmetric cryptographic processes.
++ Its main functionality is to free driver crypto operation structure and to
++ call back to OCF*/
++static void
++icp_ocfDrvSymCallBack(void *callbackTag,
++ CpaStatus status,
++ const CpaCySymOp operationType,
++ void *pOpData,
++ CpaBufferList * pDstBuffer, CpaBoolean verifyResult);
++
++/*This function is used to extract crypto processing information from the OCF
++ inputs, so as that it may be passed onto LAC*/
++static int
++icp_ocfDrvProcessDataSetup(struct icp_drvOpData *drvOpData,
++ struct cryptodesc *crp_desc);
++
++/*This function checks whether the crp_desc argument pertains to a digest or a
++ cipher operation*/
++static int icp_ocfDrvAlgCheck(struct cryptodesc *crp_desc);
++
++/*This function copies all the passed in session context information and stores
++ it in a LAC context structure*/
++static int
++icp_ocfDrvAlgorithmSetup(struct cryptoini *cri,
++ CpaCySymSessionSetupData * lacSessCtx);
++
++/*This function is used to free an OCF->OCF_DRV session object*/
++static void icp_ocfDrvFreeOCFSession(struct icp_drvSessionData *sessionData);
++
++/*max IOV buffs supported in a UIO structure*/
++#define NUM_IOV_SUPPORTED (1)
++
++/* Name : icp_ocfDrvSymCallBack
++ *
++ * Description : When this function returns it signifies that the LAC
++ * component has completed the relevant symmetric operation.
++ *
++ * Notes : The callbackTag is a pointer to an icp_drvOpData. This memory
++ * object was passed to LAC for the cryptographic processing and contains all
++ * the relevant information for cleaning up buffer handles etc. so that the
++ * OCF EP80579 Driver portion of this crypto operation can be fully completed.
++ */
++static void
++icp_ocfDrvSymCallBack(void *callbackTag,
++ CpaStatus status,
++ const CpaCySymOp operationType,
++ void *pOpData,
++ CpaBufferList * pDstBuffer, CpaBoolean verifyResult)
++{
++ struct cryptop *crp = NULL;
++ struct icp_drvOpData *temp_drvOpData =
++ (struct icp_drvOpData *)callbackTag;
++ uint64_t *tempBasePtr = NULL;
++ uint32_t tempLen = 0;
++
++ if (NULL == temp_drvOpData) {
++ DPRINTK("%s(): The callback from the LAC component"
++ " has failed due to Null userOpaque data"
++ "(status == %d).\n", __FUNCTION__, status);
++ DPRINTK("%s(): Unable to call OCF back! \n", __FUNCTION__);
++ return;
++ }
++
++ crp = temp_drvOpData->crp;
++ crp->crp_etype = ICP_OCF_DRV_NO_CRYPTO_PROCESS_ERROR;
++
++ if (NULL == pOpData) {
++ DPRINTK("%s(): The callback from the LAC component"
++ " has failed due to Null Symmetric Op data"
++ "(status == %d).\n", __FUNCTION__, status);
++ crp->crp_etype = ECANCELED;
++ crypto_done(crp);
++ return;
++ }
++
++ if (NULL == pDstBuffer) {
++ DPRINTK("%s(): The callback from the LAC component"
++ " has failed due to Null Dst Bufferlist data"
++ "(status == %d).\n", __FUNCTION__, status);
++ crp->crp_etype = ECANCELED;
++ crypto_done(crp);
++ return;
++ }
++
++ if (CPA_STATUS_SUCCESS == status) {
++
++ if (temp_drvOpData->bufferType == ICP_CRYPTO_F_PACKET_BUF) {
++ if (ICP_OCF_DRV_STATUS_SUCCESS !=
++ icp_ocfDrvBufferListToPacketBuff(pDstBuffer,
++ (icp_packet_buffer_t
++ **)
++ & (crp->crp_buf))) {
++ EPRINTK("%s(): BufferList to SkBuff "
++ "conversion error.\n", __FUNCTION__);
++ crp->crp_etype = EPERM;
++ }
++ } else {
++ icp_ocfDrvBufferListToPtrAndLen(pDstBuffer,
++ (void **)&tempBasePtr,
++ &tempLen);
++ crp->crp_olen = (int)tempLen;
++ }
++
++ } else {
++ DPRINTK("%s(): The callback from the LAC component has failed"
++ "(status == %d).\n", __FUNCTION__, status);
++
++ crp->crp_etype = ECANCELED;
++ }
++
++ if (temp_drvOpData->numBufferListArray >
++ ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) {
++ icp_kfree(pDstBuffer->pBuffers);
++ }
++ icp_ocfDrvFreeMetaData(pDstBuffer);
++ ICP_CACHE_FREE(drvOpData_zone, temp_drvOpData);
++
++ /* Invoke the OCF callback function */
++ crypto_done(crp);
++
++ return;
++}
++
++/* Name : icp_ocfDrvNewSession
++ *
++ * Description : This function will create a new Driver<->OCF session
++ *
++ * Notes : LAC session registration happens during the first perform call.
++ * That is the first time we know all information about a given session.
++ */
++int icp_ocfDrvNewSession(icp_device_t dev, uint32_t * sid,
++ struct cryptoini *cri)
++{
++ struct icp_drvSessionData *sessionData = NULL;
++ uint32_t delete_session = 0;
++
++ /* The SID passed in should be our driver ID. We can return the */
++ /* local ID (LID) which is a unique identifier which we can use */
++ /* to differentiate between the encrypt/decrypt LAC session handles */
++ if (NULL == sid) {
++ EPRINTK("%s(): Invalid input parameters - NULL sid.\n",
++ __FUNCTION__);
++ return EINVAL;
++ }
++
++ if (NULL == cri) {
++ EPRINTK("%s(): Invalid input parameters - NULL cryptoini.\n",
++ __FUNCTION__);
++ return EINVAL;
++ }
++
++ if (icp_ocfDrvDriverId != *sid) {
++ EPRINTK("%s(): Invalid input parameters - bad driver ID\n",
++ __FUNCTION__);
++ EPRINTK("\t sid = 0x08%p \n \t cri = 0x08%p \n", sid, cri);
++ return EINVAL;
++ }
++
++ sessionData = icp_kmem_cache_zalloc(drvSessionData_zone, ICP_M_NOWAIT);
++ if (NULL == sessionData) {
++ DPRINTK("%s():No memory for Session Data\n", __FUNCTION__);
++ return ENOMEM;
++ }
++
++ /*ENTER CRITICAL SECTION */
++ icp_spin_lockbh_lock(&icp_ocfDrvSymSessInfoListSpinlock);
++ /*put this check in the spinlock so no new sessions can be added to the
++ linked list when we are exiting */
++ if (CPA_TRUE == icp_atomic_read(&icp_ocfDrvIsExiting)) {
++ delete_session++;
++
++ } else if (NO_OCF_TO_DRV_MAX_SESSIONS != max_sessions) {
++ if (icp_atomic_read(&num_ocf_to_drv_registered_sessions) >=
++ (max_sessions -
++ icp_atomic_read(&lac_session_failed_dereg_count))) {
++ delete_session++;
++ } else {
++ icp_atomic_inc(&num_ocf_to_drv_registered_sessions);
++ /* Add to session data linked list */
++ ICP_LIST_ADD(sessionData, &icp_ocfDrvGlobalSymListHead,
++ listNode);
++ }
++
++ } else if (NO_OCF_TO_DRV_MAX_SESSIONS == max_sessions) {
++ ICP_LIST_ADD(sessionData, &icp_ocfDrvGlobalSymListHead,
++ listNode);
++ }
++
++ sessionData->inUse = ICP_SESSION_INITIALISED;
++
++ /*EXIT CRITICAL SECTION */
++ icp_spin_lockbh_unlock(&icp_ocfDrvSymSessInfoListSpinlock);
++
++ if (delete_session) {
++ DPRINTK("%s():No Session handles available\n", __FUNCTION__);
++ ICP_CACHE_FREE(drvSessionData_zone, sessionData);
++ return EPERM;
++ }
++
++ if (ICP_OCF_DRV_STATUS_SUCCESS !=
++ icp_ocfDrvAlgorithmSetup(cri, &(sessionData->lacSessCtx))) {
++ DPRINTK("%s():algorithm not supported\n", __FUNCTION__);
++ icp_ocfDrvFreeOCFSession(sessionData);
++ return EINVAL;
++ }
++
++ if (cri->cri_next) {
++ if (cri->cri_next->cri_next != NULL) {
++ DPRINTK("%s():only two chained algorithms supported\n",
++ __FUNCTION__);
++ icp_ocfDrvFreeOCFSession(sessionData);
++ return EPERM;
++ }
++
++ if (ICP_OCF_DRV_STATUS_SUCCESS !=
++ icp_ocfDrvAlgorithmSetup(cri->cri_next,
++ &(sessionData->lacSessCtx))) {
++ DPRINTK("%s():second algorithm not supported\n",
++ __FUNCTION__);
++ icp_ocfDrvFreeOCFSession(sessionData);
++ return EINVAL;
++ }
++
++ sessionData->lacSessCtx.symOperation =
++ CPA_CY_SYM_OP_ALGORITHM_CHAINING;
++ }
++
++ *sid = (uint32_t) sessionData;
++
++ return ICP_OCF_DRV_STATUS_SUCCESS;
++}
++
++/* Name : icp_ocfDrvAlgorithmSetup
++ *
++ * Description : This function builds the session context data from the
++ * information supplied through OCF. Algorithm chain order and whether the
++ * session is Encrypt/Decrypt can only be found out at perform time however, so
++ * the session is registered with LAC at that time.
++ */
++static int
++icp_ocfDrvAlgorithmSetup(struct cryptoini *cri,
++ CpaCySymSessionSetupData * lacSessCtx)
++{
++
++ lacSessCtx->sessionPriority = CPA_CY_PRIORITY_NORMAL;
++
++ switch (cri->cri_alg) {
++
++ case CRYPTO_NULL_CBC:
++ DPRINTK("%s(): NULL CBC\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER;
++ lacSessCtx->cipherSetupData.cipherAlgorithm =
++ CPA_CY_SYM_CIPHER_NULL;
++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes =
++ cri->cri_klen / NUM_BITS_IN_BYTE;
++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key;
++ break;
++
++ case CRYPTO_DES_CBC:
++ DPRINTK("%s(): DES CBC\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER;
++ lacSessCtx->cipherSetupData.cipherAlgorithm =
++ CPA_CY_SYM_CIPHER_DES_CBC;
++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes =
++ cri->cri_klen / NUM_BITS_IN_BYTE;
++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key;
++ break;
++
++ case CRYPTO_3DES_CBC:
++ DPRINTK("%s(): 3DES CBC\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER;
++ lacSessCtx->cipherSetupData.cipherAlgorithm =
++ CPA_CY_SYM_CIPHER_3DES_CBC;
++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes =
++ cri->cri_klen / NUM_BITS_IN_BYTE;
++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key;
++ break;
++
++ case CRYPTO_AES_CBC:
++ DPRINTK("%s(): AES CBC\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER;
++ lacSessCtx->cipherSetupData.cipherAlgorithm =
++ CPA_CY_SYM_CIPHER_AES_CBC;
++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes =
++ cri->cri_klen / NUM_BITS_IN_BYTE;
++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key;
++ break;
++
++ case CRYPTO_ARC4:
++ DPRINTK("%s(): ARC4\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER;
++ lacSessCtx->cipherSetupData.cipherAlgorithm =
++ CPA_CY_SYM_CIPHER_ARC4;
++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes =
++ cri->cri_klen / NUM_BITS_IN_BYTE;
++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key;
++ break;
++
++ case CRYPTO_SHA1:
++ DPRINTK("%s(): SHA1\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH;
++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_SHA1;
++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN;
++ lacSessCtx->hashSetupData.digestResultLenInBytes =
++ (cri->cri_mlen ?
++ cri->cri_mlen : ICP_SHA1_DIGEST_SIZE_IN_BYTES);
++
++ break;
++
++ case CRYPTO_SHA1_HMAC:
++ DPRINTK("%s(): SHA1_HMAC\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH;
++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_SHA1;
++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH;
++ lacSessCtx->hashSetupData.digestResultLenInBytes =
++ (cri->cri_mlen ?
++ cri->cri_mlen : ICP_SHA1_DIGEST_SIZE_IN_BYTES);
++ lacSessCtx->hashSetupData.authModeSetupData.authKey =
++ cri->cri_key;
++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes =
++ cri->cri_klen / NUM_BITS_IN_BYTE;
++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0;
++
++ break;
++
++ case CRYPTO_SHA2_256:
++ DPRINTK("%s(): SHA256\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH;
++ lacSessCtx->hashSetupData.hashAlgorithm =
++ CPA_CY_SYM_HASH_SHA256;
++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN;
++ lacSessCtx->hashSetupData.digestResultLenInBytes =
++ (cri->cri_mlen ?
++ cri->cri_mlen : ICP_SHA256_DIGEST_SIZE_IN_BYTES);
++
++ break;
++
++ case CRYPTO_SHA2_256_HMAC:
++ DPRINTK("%s(): SHA256_HMAC\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH;
++ lacSessCtx->hashSetupData.hashAlgorithm =
++ CPA_CY_SYM_HASH_SHA256;
++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH;
++ lacSessCtx->hashSetupData.digestResultLenInBytes =
++ (cri->cri_mlen ?
++ cri->cri_mlen : ICP_SHA256_DIGEST_SIZE_IN_BYTES);
++ lacSessCtx->hashSetupData.authModeSetupData.authKey =
++ cri->cri_key;
++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes =
++ cri->cri_klen / NUM_BITS_IN_BYTE;
++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0;
++
++ break;
++
++ case CRYPTO_SHA2_384:
++ DPRINTK("%s(): SHA384\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH;
++ lacSessCtx->hashSetupData.hashAlgorithm =
++ CPA_CY_SYM_HASH_SHA384;
++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN;
++ lacSessCtx->hashSetupData.digestResultLenInBytes =
++ (cri->cri_mlen ?
++ cri->cri_mlen : ICP_SHA384_DIGEST_SIZE_IN_BYTES);
++
++ break;
++
++ case CRYPTO_SHA2_384_HMAC:
++ DPRINTK("%s(): SHA384_HMAC\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH;
++ lacSessCtx->hashSetupData.hashAlgorithm =
++ CPA_CY_SYM_HASH_SHA384;
++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH;
++ lacSessCtx->hashSetupData.digestResultLenInBytes =
++ (cri->cri_mlen ?
++ cri->cri_mlen : ICP_SHA384_DIGEST_SIZE_IN_BYTES);
++ lacSessCtx->hashSetupData.authModeSetupData.authKey =
++ cri->cri_key;
++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes =
++ cri->cri_klen / NUM_BITS_IN_BYTE;
++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0;
++
++ break;
++
++ case CRYPTO_SHA2_512:
++ DPRINTK("%s(): SHA512\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH;
++ lacSessCtx->hashSetupData.hashAlgorithm =
++ CPA_CY_SYM_HASH_SHA512;
++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN;
++ lacSessCtx->hashSetupData.digestResultLenInBytes =
++ (cri->cri_mlen ?
++ cri->cri_mlen : ICP_SHA512_DIGEST_SIZE_IN_BYTES);
++
++ break;
++
++ case CRYPTO_SHA2_512_HMAC:
++ DPRINTK("%s(): SHA512_HMAC\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH;
++ lacSessCtx->hashSetupData.hashAlgorithm =
++ CPA_CY_SYM_HASH_SHA512;
++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH;
++ lacSessCtx->hashSetupData.digestResultLenInBytes =
++ (cri->cri_mlen ?
++ cri->cri_mlen : ICP_SHA512_DIGEST_SIZE_IN_BYTES);
++ lacSessCtx->hashSetupData.authModeSetupData.authKey =
++ cri->cri_key;
++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes =
++ cri->cri_klen / NUM_BITS_IN_BYTE;
++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0;
++
++ break;
++
++ case CRYPTO_MD5:
++ DPRINTK("%s(): MD5\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH;
++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_MD5;
++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN;
++ lacSessCtx->hashSetupData.digestResultLenInBytes =
++ (cri->cri_mlen ?
++ cri->cri_mlen : ICP_MD5_DIGEST_SIZE_IN_BYTES);
++
++ break;
++
++ case CRYPTO_MD5_HMAC:
++ DPRINTK("%s(): MD5_HMAC\n", __FUNCTION__);
++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH;
++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_MD5;
++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH;
++ lacSessCtx->hashSetupData.digestResultLenInBytes =
++ (cri->cri_mlen ?
++ cri->cri_mlen : ICP_MD5_DIGEST_SIZE_IN_BYTES);
++ lacSessCtx->hashSetupData.authModeSetupData.authKey =
++ cri->cri_key;
++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes =
++ cri->cri_klen / NUM_BITS_IN_BYTE;
++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0;
++
++ break;
++
++ default:
++ DPRINTK("%s(): ALG Setup FAIL\n", __FUNCTION__);
++ return ICP_OCF_DRV_STATUS_FAIL;
++ }
++
++ return ICP_OCF_DRV_STATUS_SUCCESS;
++}
++
++/* Name : icp_ocfDrvFreeOCFSession
++ *
++ * Description : This function deletes all existing Session data representing
++ * the Cryptographic session established between OCF and this driver. This
++ * also includes freeing the memory allocated for the session context. The
++ * session object is also removed from the session linked list.
++ */
++static void icp_ocfDrvFreeOCFSession(struct icp_drvSessionData *sessionData)
++{
++
++ sessionData->inUse = ICP_SESSION_DEREGISTERED;
++
++ /*ENTER CRITICAL SECTION */
++ icp_spin_lockbh_lock(&icp_ocfDrvSymSessInfoListSpinlock);
++
++ if (CPA_TRUE == icp_atomic_read(&icp_ocfDrvIsExiting)) {
++ /*If the Driver is exiting, allow that process to
++ handle any deletions */
++ /*EXIT CRITICAL SECTION */
++ icp_spin_lockbh_unlock(&icp_ocfDrvSymSessInfoListSpinlock);
++ return;
++ }
++
++ icp_atomic_dec(&num_ocf_to_drv_registered_sessions);
++
++ ICP_LIST_DEL(sessionData, listNode);
++
++ /*EXIT CRITICAL SECTION */
++ icp_spin_lockbh_unlock(&icp_ocfDrvSymSessInfoListSpinlock);
++
++ if (NULL != sessionData->sessHandle) {
++ icp_kfree(sessionData->sessHandle);
++ }
++ ICP_CACHE_FREE(drvSessionData_zone, sessionData);
++}
++
++/* Name : icp_ocfDrvFreeLACSession
++ *
++ * Description : This attempts to deregister a LAC session. If it fails, the
++ * deregistation retry function is called.
++ */
++int icp_ocfDrvFreeLACSession(icp_device_t dev, uint64_t sid)
++{
++ CpaCySymSessionCtx sessionToDeregister = NULL;
++ struct icp_drvSessionData *sessionData = NULL;
++ CpaStatus lacStatus = CPA_STATUS_SUCCESS;
++ int retval = 0;
++
++ sessionData = (struct icp_drvSessionData *)CRYPTO_SESID2LID(sid);
++ if (NULL == sessionData) {
++ EPRINTK("%s(): OCF Free session called with Null Session ID.\n",
++ __FUNCTION__);
++ return EINVAL;
++ }
++
++ sessionToDeregister = sessionData->sessHandle;
++
++ if ((ICP_SESSION_INITIALISED != sessionData->inUse) &&
++ (ICP_SESSION_RUNNING != sessionData->inUse) &&
++ (ICP_SESSION_DEREGISTERED != sessionData->inUse)) {
++ DPRINTK("%s() Session not initialised.\n", __FUNCTION__);
++ return EINVAL;
++ }
++
++ if (ICP_SESSION_RUNNING == sessionData->inUse) {
++ lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE,
++ sessionToDeregister);
++ if (CPA_STATUS_RETRY == lacStatus) {
++ if (ICP_OCF_DRV_STATUS_SUCCESS !=
++ icp_ocfDrvDeregRetry(&sessionToDeregister)) {
++ /* the retry function increments the
++ dereg failed count */
++ DPRINTK("%s(): LAC failed to deregister the "
++ "session. (localSessionId= %p)\n",
++ __FUNCTION__, sessionToDeregister);
++ retval = EPERM;
++ }
++
++ } else if (CPA_STATUS_SUCCESS != lacStatus) {
++ DPRINTK("%s(): LAC failed to deregister the session. "
++ "localSessionId= %p, lacStatus = %d\n",
++ __FUNCTION__, sessionToDeregister, lacStatus);
++ icp_atomic_inc(&lac_session_failed_dereg_count);
++ retval = EPERM;
++ }
++ } else {
++ DPRINTK("%s() Session not registered with LAC.\n",
++ __FUNCTION__);
++ }
++
++ icp_ocfDrvFreeOCFSession(sessionData);
++ return retval;
++
++}
++
++/* Name : icp_ocfDrvAlgCheck
++ *
++ * Description : This function checks whether the cryptodesc argument pertains
++ * to a sym or hash function
++ */
++static int icp_ocfDrvAlgCheck(struct cryptodesc *crp_desc)
++{
++
++ if (crp_desc->crd_alg == CRYPTO_3DES_CBC ||
++ crp_desc->crd_alg == CRYPTO_AES_CBC ||
++ crp_desc->crd_alg == CRYPTO_DES_CBC ||
++ crp_desc->crd_alg == CRYPTO_NULL_CBC ||
++ crp_desc->crd_alg == CRYPTO_ARC4) {
++ return ICP_OCF_DRV_ALG_CIPHER;
++ }
++
++ return ICP_OCF_DRV_ALG_HASH;
++}
++
++/* Name : icp_ocfDrvSymProcess
++ *
++ * Description : This function will map symmetric functionality calls from OCF
++ * to the LAC API. It will also allocate memory to store the session context.
++ *
++ * Notes: If it is the first perform call for a given session, then a LAC
++ * session is registered. After the session is registered, no checks as
++ * to whether session paramaters have changed (e.g. alg chain order) are
++ * done.
++ */
++int icp_ocfDrvSymProcess(icp_device_t dev, struct cryptop *crp, int hint)
++{
++ struct icp_drvSessionData *sessionData = NULL;
++ struct icp_drvOpData *drvOpData = NULL;
++ CpaStatus lacStatus = CPA_STATUS_SUCCESS;
++ Cpa32U sessionCtxSizeInBytes = 0;
++
++ if (NULL == crp) {
++ DPRINTK("%s(): Invalid input parameters, cryptop is NULL\n",
++ __FUNCTION__);
++ return EINVAL;
++ }
++
++ if (NULL == crp->crp_desc) {
++ DPRINTK("%s(): Invalid input parameters, no crp_desc attached "
++ "to crp\n", __FUNCTION__);
++ crp->crp_etype = EINVAL;
++ return EINVAL;
++ }
++
++ if (NULL == crp->crp_buf) {
++ DPRINTK("%s(): Invalid input parameters, no buffer attached "
++ "to crp\n", __FUNCTION__);
++ crp->crp_etype = EINVAL;
++ return EINVAL;
++ }
++
++ if (CPA_TRUE == icp_atomic_read(&icp_ocfDrvIsExiting)) {
++ crp->crp_etype = EFAULT;
++ return EFAULT;
++ }
++
++ sessionData = (struct icp_drvSessionData *)
++ (CRYPTO_SESID2LID(crp->crp_sid));
++ if (NULL == sessionData) {
++ DPRINTK("%s(): Invalid input parameters, Null Session ID \n",
++ __FUNCTION__);
++ crp->crp_etype = EINVAL;
++ return EINVAL;
++ }
++
++/*If we get a request against a deregisted session, cancel operation*/
++ if (ICP_SESSION_DEREGISTERED == sessionData->inUse) {
++ DPRINTK("%s(): Session ID %d was deregistered \n",
++ __FUNCTION__, (int)(CRYPTO_SESID2LID(crp->crp_sid)));
++ crp->crp_etype = EFAULT;
++ return EFAULT;
++ }
++
++/*If none of the session states are set, then the session structure was either
++ not initialised properly or we are reading from a freed memory area (possible
++ due to OCF batch mode not removing queued requests against deregistered
++ sessions*/
++ if (ICP_SESSION_INITIALISED != sessionData->inUse &&
++ ICP_SESSION_RUNNING != sessionData->inUse) {
++ DPRINTK("%s(): Session - ID %d - not properly initialised or "
++ "memory freed back to the kernel \n",
++ __FUNCTION__, (int)(CRYPTO_SESID2LID(crp->crp_sid)));
++ crp->crp_etype = EINVAL;
++ return EINVAL;
++ }
++
++ /*For the below checks, remember error checking is already done in LAC.
++ We're not validating inputs subsequent to registration */
++ if (sessionData->inUse == ICP_SESSION_INITIALISED) {
++ DPRINTK("%s(): Initialising session\n", __FUNCTION__);
++
++ if (NULL != crp->crp_desc->crd_next) {
++ if (ICP_OCF_DRV_ALG_CIPHER ==
++ icp_ocfDrvAlgCheck(crp->crp_desc)) {
++
++ sessionData->lacSessCtx.algChainOrder =
++ CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH;
++
++ if (crp->crp_desc->crd_flags & CRD_F_ENCRYPT) {
++ sessionData->lacSessCtx.cipherSetupData.
++ cipherDirection =
++ CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT;
++ } else {
++ sessionData->lacSessCtx.cipherSetupData.
++ cipherDirection =
++ CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT;
++ }
++ } else {
++ sessionData->lacSessCtx.algChainOrder =
++ CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER;
++
++ if (crp->crp_desc->crd_next->crd_flags &
++ CRD_F_ENCRYPT) {
++ sessionData->lacSessCtx.cipherSetupData.
++ cipherDirection =
++ CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT;
++ } else {
++ sessionData->lacSessCtx.cipherSetupData.
++ cipherDirection =
++ CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT;
++ }
++
++ }
++
++ } else if (ICP_OCF_DRV_ALG_CIPHER ==
++ icp_ocfDrvAlgCheck(crp->crp_desc)) {
++ if (crp->crp_desc->crd_flags & CRD_F_ENCRYPT) {
++ sessionData->lacSessCtx.cipherSetupData.
++ cipherDirection =
++ CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT;
++ } else {
++ sessionData->lacSessCtx.cipherSetupData.
++ cipherDirection =
++ CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT;
++ }
++
++ }
++
++ /*No action required for standalone Auth here */
++
++ /* Allocate memory for SymSessionCtx before the Session Registration */
++ lacStatus =
++ cpaCySymSessionCtxGetSize(CPA_INSTANCE_HANDLE_SINGLE,
++ &(sessionData->lacSessCtx),
++ &sessionCtxSizeInBytes);
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): cpaCySymSessionCtxGetSize failed - %d\n",
++ __FUNCTION__, lacStatus);
++ crp->crp_etype = EINVAL;
++ return EINVAL;
++ }
++ sessionData->sessHandle =
++ icp_kmalloc(sessionCtxSizeInBytes, ICP_M_NOWAIT);
++ if (NULL == sessionData->sessHandle) {
++ EPRINTK
++ ("%s(): Failed to get memory for SymSessionCtx\n",
++ __FUNCTION__);
++ crp->crp_etype = ENOMEM;
++ return ENOMEM;
++ }
++
++ lacStatus = cpaCySymInitSession(CPA_INSTANCE_HANDLE_SINGLE,
++ icp_ocfDrvSymCallBack,
++ &(sessionData->lacSessCtx),
++ sessionData->sessHandle);
++
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): cpaCySymInitSession failed -%d \n",
++ __FUNCTION__, lacStatus);
++ crp->crp_etype = EFAULT;
++ return EFAULT;
++ }
++
++ sessionData->inUse = ICP_SESSION_RUNNING;
++ }
++
++ drvOpData = icp_kmem_cache_zalloc(drvOpData_zone, ICP_M_NOWAIT);
++ if (NULL == drvOpData) {
++ EPRINTK("%s():Failed to get memory for drvOpData\n",
++ __FUNCTION__);
++ crp->crp_etype = ENOMEM;
++ return ENOMEM;
++ }
++
++ drvOpData->lacOpData.pSessionCtx = sessionData->sessHandle;
++ drvOpData->digestSizeInBytes = sessionData->lacSessCtx.hashSetupData.
++ digestResultLenInBytes;
++ drvOpData->crp = crp;
++
++ /* Set the default buffer list array memory allocation */
++ drvOpData->srcBuffer.pBuffers = drvOpData->bufferListArray;
++ drvOpData->numBufferListArray = ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS;
++
++ if (ICP_OCF_DRV_STATUS_SUCCESS !=
++ icp_ocfDrvProcessDataSetup(drvOpData, drvOpData->crp->crp_desc)) {
++ crp->crp_etype = EINVAL;
++ goto err;
++ }
++
++ if (drvOpData->crp->crp_desc->crd_next != NULL) {
++ if (icp_ocfDrvProcessDataSetup(drvOpData, drvOpData->crp->
++ crp_desc->crd_next)) {
++ crp->crp_etype = EINVAL;
++ goto err;
++ }
++
++ }
++
++ /*
++ * Allocate buffer list array memory if the data fragment is more than
++ * the default number (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) and not
++ * calculated already
++ */
++ if (crp->crp_flags & ICP_CRYPTO_F_PACKET_BUF) {
++ if (NULL == drvOpData->lacOpData.pDigestResult) {
++ drvOpData->numBufferListArray =
++ icp_ocfDrvGetPacketBuffFrags((icp_packet_buffer_t *)
++ crp->crp_buf);
++ }
++
++ if (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS <
++ drvOpData->numBufferListArray) {
++ DPRINTK("%s() numBufferListArray more than default\n",
++ __FUNCTION__);
++ drvOpData->srcBuffer.pBuffers = NULL;
++ drvOpData->srcBuffer.pBuffers =
++ icp_kmalloc(drvOpData->numBufferListArray *
++ sizeof(CpaFlatBuffer), ICP_M_NOWAIT);
++ if (NULL == drvOpData->srcBuffer.pBuffers) {
++ EPRINTK("%s() Failed to get memory for "
++ "pBuffers\n", __FUNCTION__);
++ ICP_CACHE_FREE(drvOpData_zone, drvOpData);
++ crp->crp_etype = ENOMEM;
++ return ENOMEM;
++ }
++ }
++ }
++
++ /*
++ * Check the type of buffer structure we got and convert it into
++ * CpaBufferList format.
++ */
++ if (crp->crp_flags & ICP_CRYPTO_F_PACKET_BUF) {
++ if (ICP_OCF_DRV_STATUS_SUCCESS !=
++ icp_ocfDrvPacketBuffToBufferList((icp_packet_buffer_t *)
++ crp->crp_buf,
++ &(drvOpData->srcBuffer))) {
++ EPRINTK("%s():Failed to translate from packet buffer "
++ "to bufferlist\n", __FUNCTION__);
++ crp->crp_etype = EINVAL;
++ goto err;
++ }
++
++ drvOpData->bufferType = ICP_CRYPTO_F_PACKET_BUF;
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ /* OCF only supports IOV of one entry. */
++ if (NUM_IOV_SUPPORTED ==
++ ((struct uio *)(crp->crp_buf))->uio_iovcnt) {
++
++ icp_ocfDrvPtrAndLenToBufferList(((struct uio *)(crp->
++ crp_buf))->
++ uio_iov[0].iov_base,
++ ((struct uio *)(crp->
++ crp_buf))->
++ uio_iov[0].iov_len,
++ &(drvOpData->
++ srcBuffer));
++
++ drvOpData->bufferType = CRYPTO_F_IOV;
++
++ } else {
++ DPRINTK("%s():Unable to handle IOVs with lengths of "
++ "greater than one!\n", __FUNCTION__);
++ crp->crp_etype = EINVAL;
++ goto err;
++ }
++
++ } else {
++ icp_ocfDrvPtrAndLenToBufferList(crp->crp_buf,
++ crp->crp_ilen,
++ &(drvOpData->srcBuffer));
++
++ drvOpData->bufferType = CRYPTO_BUF_CONTIG;
++ }
++
++ /* Allocate srcBuffer's private meta data */
++ if (ICP_OCF_DRV_STATUS_SUCCESS !=
++ icp_ocfDrvAllocMetaData(&(drvOpData->srcBuffer), drvOpData)) {
++ EPRINTK("%s() icp_ocfDrvAllocMetaData failed\n", __FUNCTION__);
++ memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData));
++ crp->crp_etype = EINVAL;
++ goto err;
++ }
++
++ /* Perform "in-place" crypto operation */
++ lacStatus = cpaCySymPerformOp(CPA_INSTANCE_HANDLE_SINGLE,
++ (void *)drvOpData,
++ &(drvOpData->lacOpData),
++ &(drvOpData->srcBuffer),
++ &(drvOpData->srcBuffer),
++ &(drvOpData->verifyResult));
++ if (CPA_STATUS_RETRY == lacStatus) {
++ DPRINTK("%s(): cpaCySymPerformOp retry, lacStatus = %d\n",
++ __FUNCTION__, lacStatus);
++ memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData));
++ crp->crp_etype = ERESTART;
++ goto err;
++ }
++ if (CPA_STATUS_SUCCESS != lacStatus) {
++ EPRINTK("%s(): cpaCySymPerformOp failed, lacStatus = %d\n",
++ __FUNCTION__, lacStatus);
++ memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData));
++ crp->crp_etype = EINVAL;
++ goto err;
++ }
++
++ return 0; //OCF success status value
++
++ err:
++ if (drvOpData->numBufferListArray > ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) {
++ icp_kfree(drvOpData->srcBuffer.pBuffers);
++ }
++ icp_ocfDrvFreeMetaData(&(drvOpData->srcBuffer));
++ ICP_CACHE_FREE(drvOpData_zone, drvOpData);
++
++ return crp->crp_etype;
++}
++
++/* Name : icp_ocfDrvProcessDataSetup
++ *
++ * Description : This function will setup all the cryptographic operation data
++ * that is required by LAC to execute the operation.
++ */
++static int icp_ocfDrvProcessDataSetup(struct icp_drvOpData *drvOpData,
++ struct cryptodesc *crp_desc)
++{
++ CpaCyRandGenOpData randGenOpData;
++ CpaFlatBuffer randData;
++
++ drvOpData->lacOpData.packetType = CPA_CY_SYM_PACKET_TYPE_FULL;
++
++ /* Convert from the cryptop to the ICP LAC crypto parameters */
++ switch (crp_desc->crd_alg) {
++ case CRYPTO_NULL_CBC:
++ drvOpData->lacOpData.
++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip;
++ drvOpData->lacOpData.
++ messageLenToCipherInBytes = crp_desc->crd_len;
++ drvOpData->verifyResult = CPA_FALSE;
++ drvOpData->lacOpData.ivLenInBytes = NULL_BLOCK_LEN;
++ break;
++ case CRYPTO_DES_CBC:
++ drvOpData->lacOpData.
++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip;
++ drvOpData->lacOpData.
++ messageLenToCipherInBytes = crp_desc->crd_len;
++ drvOpData->verifyResult = CPA_FALSE;
++ drvOpData->lacOpData.ivLenInBytes = DES_BLOCK_LEN;
++ break;
++ case CRYPTO_3DES_CBC:
++ drvOpData->lacOpData.
++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip;
++ drvOpData->lacOpData.
++ messageLenToCipherInBytes = crp_desc->crd_len;
++ drvOpData->verifyResult = CPA_FALSE;
++ drvOpData->lacOpData.ivLenInBytes = DES3_BLOCK_LEN;
++ break;
++ case CRYPTO_ARC4:
++ drvOpData->lacOpData.
++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip;
++ drvOpData->lacOpData.
++ messageLenToCipherInBytes = crp_desc->crd_len;
++ drvOpData->verifyResult = CPA_FALSE;
++ drvOpData->lacOpData.ivLenInBytes = ARC4_COUNTER_LEN;
++ break;
++ case CRYPTO_AES_CBC:
++ drvOpData->lacOpData.
++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip;
++ drvOpData->lacOpData.
++ messageLenToCipherInBytes = crp_desc->crd_len;
++ drvOpData->verifyResult = CPA_FALSE;
++ drvOpData->lacOpData.ivLenInBytes = RIJNDAEL128_BLOCK_LEN;
++ break;
++ case CRYPTO_SHA1:
++ case CRYPTO_SHA1_HMAC:
++ case CRYPTO_SHA2_256:
++ case CRYPTO_SHA2_256_HMAC:
++ case CRYPTO_SHA2_384:
++ case CRYPTO_SHA2_384_HMAC:
++ case CRYPTO_SHA2_512:
++ case CRYPTO_SHA2_512_HMAC:
++ case CRYPTO_MD5:
++ case CRYPTO_MD5_HMAC:
++ drvOpData->lacOpData.
++ hashStartSrcOffsetInBytes = crp_desc->crd_skip;
++ drvOpData->lacOpData.
++ messageLenToHashInBytes = crp_desc->crd_len;
++ drvOpData->lacOpData.
++ pDigestResult =
++ icp_ocfDrvDigestPointerFind(drvOpData, crp_desc);
++
++ if (NULL == drvOpData->lacOpData.pDigestResult) {
++ DPRINTK("%s(): ERROR - could not calculate "
++ "Digest Result memory address\n", __FUNCTION__);
++ return ICP_OCF_DRV_STATUS_FAIL;
++ }
++
++ drvOpData->lacOpData.digestVerify = CPA_FALSE;
++ break;
++ default:
++ DPRINTK("%s(): Crypto process error - algorithm not "
++ "found \n", __FUNCTION__);
++ return ICP_OCF_DRV_STATUS_FAIL;
++ }
++
++ /* Figure out what the IV is supposed to be */
++ if ((crp_desc->crd_alg == CRYPTO_DES_CBC) ||
++ (crp_desc->crd_alg == CRYPTO_3DES_CBC) ||
++ (crp_desc->crd_alg == CRYPTO_AES_CBC)) {
++ /*ARC4 doesn't use an IV */
++ if (crp_desc->crd_flags & CRD_F_IV_EXPLICIT) {
++ /* Explicit IV provided to OCF */
++ drvOpData->lacOpData.pIv = crp_desc->crd_iv;
++ } else {
++ /* IV is not explicitly provided to OCF */
++
++ /* Point the LAC OP Data IV pointer to our allocated
++ storage location for this session. */
++ drvOpData->lacOpData.pIv = drvOpData->ivData;
++
++ if ((crp_desc->crd_flags & CRD_F_ENCRYPT) &&
++ ((crp_desc->crd_flags & CRD_F_IV_PRESENT) == 0)) {
++
++ /* Encrypting - need to create IV */
++ randGenOpData.generateBits = CPA_TRUE;
++ randGenOpData.lenInBytes = MAX_IV_LEN_IN_BYTES;
++
++ icp_ocfDrvPtrAndLenToFlatBuffer((Cpa8U *)
++ drvOpData->
++ ivData,
++ MAX_IV_LEN_IN_BYTES,
++ &randData);
++
++ if (CPA_STATUS_SUCCESS !=
++ cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE,
++ NULL, NULL,
++ &randGenOpData, &randData)) {
++ DPRINTK("%s(): ERROR - Failed to"
++ " generate"
++ " Initialisation Vector\n",
++ __FUNCTION__);
++ return ICP_OCF_DRV_STATUS_FAIL;
++ }
++
++ crypto_copyback(drvOpData->crp->
++ crp_flags,
++ drvOpData->crp->crp_buf,
++ crp_desc->crd_inject,
++ drvOpData->lacOpData.
++ ivLenInBytes,
++ (caddr_t) (drvOpData->lacOpData.
++ pIv));
++ } else {
++ /* Reading IV from buffer */
++ crypto_copydata(drvOpData->crp->
++ crp_flags,
++ drvOpData->crp->crp_buf,
++ crp_desc->crd_inject,
++ drvOpData->lacOpData.
++ ivLenInBytes,
++ (caddr_t) (drvOpData->lacOpData.
++ pIv));
++ }
++
++ }
++
++ }
++
++ return ICP_OCF_DRV_STATUS_SUCCESS;
++}
++
++/* Name : icp_ocfDrvDigestPointerFind
++ *
++ * Description : This function is used to find the memory address of where the
++ * digest information shall be stored in. Input buffer types are an skbuff, iov
++ * or flat buffer. The address is found using the buffer data start address and
++ * an offset.
++ *
++ * Note: In the case of a linux skbuff, the digest address may exist within
++ * a memory space linked to from the start buffer. These linked memory spaces
++ * must be traversed by the data length offset in order to find the digest start
++ * address. Whether there is enough space for the digest must also be checked.
++ */
++uint8_t *icp_ocfDrvDigestPointerFind(struct icp_drvOpData * drvOpData,
++ struct cryptodesc * crp_desc)
++{
++
++ int offsetInBytes = crp_desc->crd_inject;
++ uint32_t digestSizeInBytes = drvOpData->digestSizeInBytes;
++ uint8_t *flat_buffer_base = NULL;
++ int flat_buffer_length = 0;
++
++ if (drvOpData->crp->crp_flags & ICP_CRYPTO_F_PACKET_BUF) {
++
++ return icp_ocfDrvPacketBufferDigestPointerFind(drvOpData,
++ offsetInBytes,
++ digestSizeInBytes);
++
++ } else {
++ /* IOV or flat buffer */
++ if (drvOpData->crp->crp_flags & CRYPTO_F_IOV) {
++ /*single IOV check has already been done */
++ flat_buffer_base = ((struct uio *)
++ (drvOpData->crp->crp_buf))->
++ uio_iov[0].iov_base;
++ flat_buffer_length = ((struct uio *)
++ (drvOpData->crp->crp_buf))->
++ uio_iov[0].iov_len;
++ } else {
++ flat_buffer_base = (uint8_t *) drvOpData->crp->crp_buf;
++ flat_buffer_length = drvOpData->crp->crp_ilen;
++ }
++
++ if (flat_buffer_length < (offsetInBytes + digestSizeInBytes)) {
++ DPRINTK("%s() Not enough space for Digest "
++ "(IOV/Flat Buffer) \n", __FUNCTION__);
++ return NULL;
++ } else {
++ return (uint8_t *) (flat_buffer_base + offsetInBytes);
++ }
++ }
++ DPRINTK("%s() Should not reach this point\n", __FUNCTION__);
++ return NULL;
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/ep80579/Makefile linux-2.6.36/crypto/ocf/ep80579/Makefile
+--- linux-2.6.36.orig/crypto/ocf/ep80579/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/ep80579/Makefile 2010-11-09 20:28:04.742495461 +0100
+@@ -0,0 +1,119 @@
++#########################################################################
++#
++# Targets supported
++# all - builds everything and installs
++# install - identical to all
++# depend - build dependencies
++# clean - clears derived objects except the .depend files
++# distclean- clears all derived objects and the .depend file
++#
++# @par
++# This file is provided under a dual BSD/GPLv2 license. When using or
++# redistributing this file, you may do so under either license.
++#
++# GPL LICENSE SUMMARY
++#
++# Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of version 2 of the GNU General Public License as
++# published by the Free Software Foundation.
++#
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++# The full GNU General Public License is included in this distribution
++# in the file called LICENSE.GPL.
++#
++# Contact Information:
++# Intel Corporation
++#
++# BSD LICENSE
++#
++# Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
++# 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 Intel Corporation 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++# A PARTICULAR PURPOSE 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.
++#
++#
++# version: Security.L.1.0.2-229
++############################################################################
++
++
++####################Common variables and definitions########################
++
++ifndef ICP_ROOT
++$(warning ICP_ROOT is undefined. Please set the path to EP80579 release package directory \
++ "-> setenv ICP_ROOT <path>")
++all fastdep:
++ :
++else
++
++ifndef KERNEL_SOURCE_ROOT
++$(error KERNEL_SOURCE_ROOT is undefined. Please set the path to the kernel source directory \
++ "-> setenv KERNEL_SOURCE_ROOT <path>")
++endif
++
++# Ensure The ENV_DIR environmental var is defined.
++ifndef ICP_ENV_DIR
++$(error ICP_ENV_DIR is undefined. Please set the path to EP80579 driver environment.mk file \
++ "-> setenv ICP_ENV_DIR <path>")
++endif
++
++#Add your project environment Makefile
++include ${ICP_ENV_DIR}/environment.mk
++
++#include the makefile with all the default and common Make variable definitions
++include ${ICP_BUILDSYSTEM_PATH}/build_files/common.mk
++
++#Add the name for the executable, Library or Module output definitions
++OUTPUT_NAME= icp_ocf
++
++# List of Source Files to be compiled
++SOURCES= icp_common.c icp_sym.c icp_asym.c icp_ocf_linux.c
++
++#common includes between all supported OSes
++INCLUDES= -I ${ICP_API_DIR} -I${ICP_LAC_API} \
++-I${ICP_OCF_SRC_DIR}
++
++# The location of the os level makefile needs to be changed.
++include ${ICP_ENV_DIR}/${ICP_OS}_${ICP_OS_LEVEL}.mk
++
++# On the line directly below list the outputs you wish to build for,
++# e.g "lib_static lib_shared exe module" as shown below
++install: module
++
++###################Include rules makefiles########################
++include ${ICP_BUILDSYSTEM_PATH}/build_files/rules.mk
++###################End of Rules inclusion#########################
++
++endif
+diff -Nur linux-2.6.36.orig/crypto/ocf/hifn/hifn7751.c linux-2.6.36/crypto/ocf/hifn/hifn7751.c
+--- linux-2.6.36.orig/crypto/ocf/hifn/hifn7751.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/hifn/hifn7751.c 2010-11-09 20:28:04.752495537 +0100
+@@ -0,0 +1,2976 @@
++/* $OpenBSD: hifn7751.c,v 1.120 2002/05/17 00:33:34 deraadt Exp $ */
++
++/*-
++ * Invertex AEON / Hifn 7751 driver
++ * Copyright (c) 1999 Invertex Inc. All rights reserved.
++ * Copyright (c) 1999 Theo de Raadt
++ * Copyright (c) 2000-2001 Network Security Technologies, Inc.
++ * http://www.netsec.net
++ * Copyright (c) 2003 Hifn Inc.
++ *
++ * This driver is based on a previous driver by Invertex, for which they
++ * requested: Please send any comments, feedback, bug-fixes, or feature
++ * requests to software@invertex.com.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++ *
++__FBSDID("$FreeBSD: src/sys/dev/hifn/hifn7751.c,v 1.40 2007/03/21 03:42:49 sam Exp $");
++ */
++
++/*
++ * Driver for various Hifn encryption processors.
++ */
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/random.h>
++#include <linux/version.h>
++#include <linux/skbuff.h>
++#include <asm/io.h>
++
++#include <cryptodev.h>
++#include <uio.h>
++#include <hifn/hifn7751reg.h>
++#include <hifn/hifn7751var.h>
++
++#if 1
++#define DPRINTF(a...) if (hifn_debug) { \
++ printk("%s: ", sc ? \
++ device_get_nameunit(sc->sc_dev) : "hifn"); \
++ printk(a); \
++ } else
++#else
++#define DPRINTF(a...)
++#endif
++
++static inline int
++pci_get_revid(struct pci_dev *dev)
++{
++ u8 rid = 0;
++ pci_read_config_byte(dev, PCI_REVISION_ID, &rid);
++ return rid;
++}
++
++static struct hifn_stats hifnstats;
++
++#define debug hifn_debug
++int hifn_debug = 0;
++module_param(hifn_debug, int, 0644);
++MODULE_PARM_DESC(hifn_debug, "Enable debug");
++
++int hifn_maxbatch = 1;
++module_param(hifn_maxbatch, int, 0644);
++MODULE_PARM_DESC(hifn_maxbatch, "max ops to batch w/o interrupt");
++
++int hifn_cache_linesize = 0x10;
++module_param(hifn_cache_linesize, int, 0444);
++MODULE_PARM_DESC(hifn_cache_linesize, "PCI config cache line size");
++
++#ifdef MODULE_PARM
++char *hifn_pllconfig = NULL;
++MODULE_PARM(hifn_pllconfig, "s");
++#else
++char hifn_pllconfig[32]; /* This setting is RO after loading */
++module_param_string(hifn_pllconfig, hifn_pllconfig, 32, 0444);
++#endif
++MODULE_PARM_DESC(hifn_pllconfig, "PLL config, ie., pci66, ext33, ...");
++
++#ifdef HIFN_VULCANDEV
++#include <sys/conf.h>
++#include <sys/uio.h>
++
++static struct cdevsw vulcanpk_cdevsw; /* forward declaration */
++#endif
++
++/*
++ * Prototypes and count for the pci_device structure
++ */
++static int hifn_probe(struct pci_dev *dev, const struct pci_device_id *ent);
++static void hifn_remove(struct pci_dev *dev);
++
++static int hifn_newsession(device_t, u_int32_t *, struct cryptoini *);
++static int hifn_freesession(device_t, u_int64_t);
++static int hifn_process(device_t, struct cryptop *, int);
++
++static device_method_t hifn_methods = {
++ /* crypto device methods */
++ DEVMETHOD(cryptodev_newsession, hifn_newsession),
++ DEVMETHOD(cryptodev_freesession,hifn_freesession),
++ DEVMETHOD(cryptodev_process, hifn_process),
++};
++
++static void hifn_reset_board(struct hifn_softc *, int);
++static void hifn_reset_puc(struct hifn_softc *);
++static void hifn_puc_wait(struct hifn_softc *);
++static int hifn_enable_crypto(struct hifn_softc *);
++static void hifn_set_retry(struct hifn_softc *sc);
++static void hifn_init_dma(struct hifn_softc *);
++static void hifn_init_pci_registers(struct hifn_softc *);
++static int hifn_sramsize(struct hifn_softc *);
++static int hifn_dramsize(struct hifn_softc *);
++static int hifn_ramtype(struct hifn_softc *);
++static void hifn_sessions(struct hifn_softc *);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++static irqreturn_t hifn_intr(int irq, void *arg);
++#else
++static irqreturn_t hifn_intr(int irq, void *arg, struct pt_regs *regs);
++#endif
++static u_int hifn_write_command(struct hifn_command *, u_int8_t *);
++static u_int32_t hifn_next_signature(u_int32_t a, u_int cnt);
++static void hifn_callback(struct hifn_softc *, struct hifn_command *, u_int8_t *);
++static int hifn_crypto(struct hifn_softc *, struct hifn_command *, struct cryptop *, int);
++static int hifn_readramaddr(struct hifn_softc *, int, u_int8_t *);
++static int hifn_writeramaddr(struct hifn_softc *, int, u_int8_t *);
++static int hifn_dmamap_load_src(struct hifn_softc *, struct hifn_command *);
++static int hifn_dmamap_load_dst(struct hifn_softc *, struct hifn_command *);
++static int hifn_init_pubrng(struct hifn_softc *);
++static void hifn_tick(unsigned long arg);
++static void hifn_abort(struct hifn_softc *);
++static void hifn_alloc_slot(struct hifn_softc *, int *, int *, int *, int *);
++
++static void hifn_write_reg_0(struct hifn_softc *, bus_size_t, u_int32_t);
++static void hifn_write_reg_1(struct hifn_softc *, bus_size_t, u_int32_t);
++
++#ifdef CONFIG_OCF_RANDOMHARVEST
++static int hifn_read_random(void *arg, u_int32_t *buf, int len);
++#endif
++
++#define HIFN_MAX_CHIPS 8
++static struct hifn_softc *hifn_chip_idx[HIFN_MAX_CHIPS];
++
++static __inline u_int32_t
++READ_REG_0(struct hifn_softc *sc, bus_size_t reg)
++{
++ u_int32_t v = readl(sc->sc_bar0 + reg);
++ sc->sc_bar0_lastreg = (bus_size_t) -1;
++ return (v);
++}
++#define WRITE_REG_0(sc, reg, val) hifn_write_reg_0(sc, reg, val)
++
++static __inline u_int32_t
++READ_REG_1(struct hifn_softc *sc, bus_size_t reg)
++{
++ u_int32_t v = readl(sc->sc_bar1 + reg);
++ sc->sc_bar1_lastreg = (bus_size_t) -1;
++ return (v);
++}
++#define WRITE_REG_1(sc, reg, val) hifn_write_reg_1(sc, reg, val)
++
++/*
++ * map in a given buffer (great on some arches :-)
++ */
++
++static int
++pci_map_uio(struct hifn_softc *sc, struct hifn_operand *buf, struct uio *uio)
++{
++ struct iovec *iov = uio->uio_iov;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ buf->mapsize = 0;
++ for (buf->nsegs = 0; buf->nsegs < uio->uio_iovcnt; ) {
++ buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_pcidev,
++ iov->iov_base, iov->iov_len,
++ PCI_DMA_BIDIRECTIONAL);
++ buf->segs[buf->nsegs].ds_len = iov->iov_len;
++ buf->mapsize += iov->iov_len;
++ iov++;
++ buf->nsegs++;
++ }
++ /* identify this buffer by the first segment */
++ buf->map = (void *) buf->segs[0].ds_addr;
++ return(0);
++}
++
++/*
++ * map in a given sk_buff
++ */
++
++static int
++pci_map_skb(struct hifn_softc *sc,struct hifn_operand *buf,struct sk_buff *skb)
++{
++ int i;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ buf->mapsize = 0;
++
++ buf->segs[0].ds_addr = pci_map_single(sc->sc_pcidev,
++ skb->data, skb_headlen(skb), PCI_DMA_BIDIRECTIONAL);
++ buf->segs[0].ds_len = skb_headlen(skb);
++ buf->mapsize += buf->segs[0].ds_len;
++
++ buf->nsegs = 1;
++
++ for (i = 0; i < skb_shinfo(skb)->nr_frags; ) {
++ buf->segs[buf->nsegs].ds_len = skb_shinfo(skb)->frags[i].size;
++ buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_pcidev,
++ page_address(skb_shinfo(skb)->frags[i].page) +
++ skb_shinfo(skb)->frags[i].page_offset,
++ buf->segs[buf->nsegs].ds_len, PCI_DMA_BIDIRECTIONAL);
++ buf->mapsize += buf->segs[buf->nsegs].ds_len;
++ buf->nsegs++;
++ }
++
++ /* identify this buffer by the first segment */
++ buf->map = (void *) buf->segs[0].ds_addr;
++ return(0);
++}
++
++/*
++ * map in a given contiguous buffer
++ */
++
++static int
++pci_map_buf(struct hifn_softc *sc,struct hifn_operand *buf, void *b, int len)
++{
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ buf->mapsize = 0;
++ buf->segs[0].ds_addr = pci_map_single(sc->sc_pcidev,
++ b, len, PCI_DMA_BIDIRECTIONAL);
++ buf->segs[0].ds_len = len;
++ buf->mapsize += buf->segs[0].ds_len;
++ buf->nsegs = 1;
++
++ /* identify this buffer by the first segment */
++ buf->map = (void *) buf->segs[0].ds_addr;
++ return(0);
++}
++
++#if 0 /* not needed at this time */
++static void
++pci_sync_iov(struct hifn_softc *sc, struct hifn_operand *buf)
++{
++ int i;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++ for (i = 0; i < buf->nsegs; i++)
++ pci_dma_sync_single_for_cpu(sc->sc_pcidev, buf->segs[i].ds_addr,
++ buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL);
++}
++#endif
++
++static void
++pci_unmap_buf(struct hifn_softc *sc, struct hifn_operand *buf)
++{
++ int i;
++ DPRINTF("%s()\n", __FUNCTION__);
++ for (i = 0; i < buf->nsegs; i++) {
++ pci_unmap_single(sc->sc_pcidev, buf->segs[i].ds_addr,
++ buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL);
++ buf->segs[i].ds_addr = 0;
++ buf->segs[i].ds_len = 0;
++ }
++ buf->nsegs = 0;
++ buf->mapsize = 0;
++ buf->map = 0;
++}
++
++static const char*
++hifn_partname(struct hifn_softc *sc)
++{
++ /* XXX sprintf numbers when not decoded */
++ switch (pci_get_vendor(sc->sc_pcidev)) {
++ case PCI_VENDOR_HIFN:
++ switch (pci_get_device(sc->sc_pcidev)) {
++ case PCI_PRODUCT_HIFN_6500: return "Hifn 6500";
++ case PCI_PRODUCT_HIFN_7751: return "Hifn 7751";
++ case PCI_PRODUCT_HIFN_7811: return "Hifn 7811";
++ case PCI_PRODUCT_HIFN_7951: return "Hifn 7951";
++ case PCI_PRODUCT_HIFN_7955: return "Hifn 7955";
++ case PCI_PRODUCT_HIFN_7956: return "Hifn 7956";
++ }
++ return "Hifn unknown-part";
++ case PCI_VENDOR_INVERTEX:
++ switch (pci_get_device(sc->sc_pcidev)) {
++ case PCI_PRODUCT_INVERTEX_AEON: return "Invertex AEON";
++ }
++ return "Invertex unknown-part";
++ case PCI_VENDOR_NETSEC:
++ switch (pci_get_device(sc->sc_pcidev)) {
++ case PCI_PRODUCT_NETSEC_7751: return "NetSec 7751";
++ }
++ return "NetSec unknown-part";
++ }
++ return "Unknown-vendor unknown-part";
++}
++
++static u_int
++checkmaxmin(struct pci_dev *dev, const char *what, u_int v, u_int min, u_int max)
++{
++ struct hifn_softc *sc = pci_get_drvdata(dev);
++ if (v > max) {
++ device_printf(sc->sc_dev, "Warning, %s %u out of range, "
++ "using max %u\n", what, v, max);
++ v = max;
++ } else if (v < min) {
++ device_printf(sc->sc_dev, "Warning, %s %u out of range, "
++ "using min %u\n", what, v, min);
++ v = min;
++ }
++ return v;
++}
++
++/*
++ * Select PLL configuration for 795x parts. This is complicated in
++ * that we cannot determine the optimal parameters without user input.
++ * The reference clock is derived from an external clock through a
++ * multiplier. The external clock is either the host bus (i.e. PCI)
++ * or an external clock generator. When using the PCI bus we assume
++ * the clock is either 33 or 66 MHz; for an external source we cannot
++ * tell the speed.
++ *
++ * PLL configuration is done with a string: "pci" for PCI bus, or "ext"
++ * for an external source, followed by the frequency. We calculate
++ * the appropriate multiplier and PLL register contents accordingly.
++ * When no configuration is given we default to "pci66" since that
++ * always will allow the card to work. If a card is using the PCI
++ * bus clock and in a 33MHz slot then it will be operating at half
++ * speed until the correct information is provided.
++ *
++ * We use a default setting of "ext66" because according to Mike Ham
++ * of HiFn, almost every board in existence has an external crystal
++ * populated at 66Mhz. Using PCI can be a problem on modern motherboards,
++ * because PCI33 can have clocks from 0 to 33Mhz, and some have
++ * non-PCI-compliant spread-spectrum clocks, which can confuse the pll.
++ */
++static void
++hifn_getpllconfig(struct pci_dev *dev, u_int *pll)
++{
++ const char *pllspec = hifn_pllconfig;
++ u_int freq, mul, fl, fh;
++ u_int32_t pllconfig;
++ char *nxt;
++
++ if (pllspec == NULL)
++ pllspec = "ext66";
++ fl = 33, fh = 66;
++ pllconfig = 0;
++ if (strncmp(pllspec, "ext", 3) == 0) {
++ pllspec += 3;
++ pllconfig |= HIFN_PLL_REF_SEL;
++ switch (pci_get_device(dev)) {
++ case PCI_PRODUCT_HIFN_7955:
++ case PCI_PRODUCT_HIFN_7956:
++ fl = 20, fh = 100;
++ break;
++#ifdef notyet
++ case PCI_PRODUCT_HIFN_7954:
++ fl = 20, fh = 66;
++ break;
++#endif
++ }
++ } else if (strncmp(pllspec, "pci", 3) == 0)
++ pllspec += 3;
++ freq = strtoul(pllspec, &nxt, 10);
++ if (nxt == pllspec)
++ freq = 66;
++ else
++ freq = checkmaxmin(dev, "frequency", freq, fl, fh);
++ /*
++ * Calculate multiplier. We target a Fck of 266 MHz,
++ * allowing only even values, possibly rounded down.
++ * Multipliers > 8 must set the charge pump current.
++ */
++ mul = checkmaxmin(dev, "PLL divisor", (266 / freq) &~ 1, 2, 12);
++ pllconfig |= (mul / 2 - 1) << HIFN_PLL_ND_SHIFT;
++ if (mul > 8)
++ pllconfig |= HIFN_PLL_IS;
++ *pll = pllconfig;
++}
++
++/*
++ * Attach an interface that successfully probed.
++ */
++static int
++hifn_probe(struct pci_dev *dev, const struct pci_device_id *ent)
++{
++ struct hifn_softc *sc = NULL;
++ char rbase;
++ u_int16_t ena, rev;
++ int rseg, rc;
++ unsigned long mem_start, mem_len;
++ static int num_chips = 0;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ if (pci_enable_device(dev) < 0)
++ return(-ENODEV);
++
++ if (pci_set_mwi(dev))
++ return(-ENODEV);
++
++ if (!dev->irq) {
++ printk("hifn: found device with no IRQ assigned. check BIOS settings!");
++ pci_disable_device(dev);
++ return(-ENODEV);
++ }
++
++ sc = (struct hifn_softc *) kmalloc(sizeof(*sc), GFP_KERNEL);
++ if (!sc)
++ return(-ENOMEM);
++ memset(sc, 0, sizeof(*sc));
++
++ softc_device_init(sc, "hifn", num_chips, hifn_methods);
++
++ sc->sc_pcidev = dev;
++ sc->sc_irq = -1;
++ sc->sc_cid = -1;
++ sc->sc_num = num_chips++;
++ if (sc->sc_num < HIFN_MAX_CHIPS)
++ hifn_chip_idx[sc->sc_num] = sc;
++
++ pci_set_drvdata(sc->sc_pcidev, sc);
++
++ spin_lock_init(&sc->sc_mtx);
++
++ /* XXX handle power management */
++
++ /*
++ * The 7951 and 795x have a random number generator and
++ * public key support; note this.
++ */
++ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN &&
++ (pci_get_device(dev) == PCI_PRODUCT_HIFN_7951 ||
++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 ||
++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7956))
++ sc->sc_flags = HIFN_HAS_RNG | HIFN_HAS_PUBLIC;
++ /*
++ * The 7811 has a random number generator and
++ * we also note it's identity 'cuz of some quirks.
++ */
++ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN &&
++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7811)
++ sc->sc_flags |= HIFN_IS_7811 | HIFN_HAS_RNG;
++
++ /*
++ * The 795x parts support AES.
++ */
++ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN &&
++ (pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 ||
++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) {
++ sc->sc_flags |= HIFN_IS_7956 | HIFN_HAS_AES;
++ /*
++ * Select PLL configuration. This depends on the
++ * bus and board design and must be manually configured
++ * if the default setting is unacceptable.
++ */
++ hifn_getpllconfig(dev, &sc->sc_pllconfig);
++ }
++
++ /*
++ * Setup PCI resources. Note that we record the bus
++ * tag and handle for each register mapping, this is
++ * used by the READ_REG_0, WRITE_REG_0, READ_REG_1,
++ * and WRITE_REG_1 macros throughout the driver.
++ */
++ mem_start = pci_resource_start(sc->sc_pcidev, 0);
++ mem_len = pci_resource_len(sc->sc_pcidev, 0);
++ sc->sc_bar0 = (ocf_iomem_t) ioremap(mem_start, mem_len);
++ if (!sc->sc_bar0) {
++ device_printf(sc->sc_dev, "cannot map bar%d register space\n", 0);
++ goto fail;
++ }
++ sc->sc_bar0_lastreg = (bus_size_t) -1;
++
++ mem_start = pci_resource_start(sc->sc_pcidev, 1);
++ mem_len = pci_resource_len(sc->sc_pcidev, 1);
++ sc->sc_bar1 = (ocf_iomem_t) ioremap(mem_start, mem_len);
++ if (!sc->sc_bar1) {
++ device_printf(sc->sc_dev, "cannot map bar%d register space\n", 1);
++ goto fail;
++ }
++ sc->sc_bar1_lastreg = (bus_size_t) -1;
++
++ /* fix up the bus size */
++ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
++ device_printf(sc->sc_dev, "No usable DMA configuration, aborting.\n");
++ goto fail;
++ }
++ if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) {
++ device_printf(sc->sc_dev,
++ "No usable consistent DMA configuration, aborting.\n");
++ goto fail;
++ }
++
++ hifn_set_retry(sc);
++
++ /*
++ * Setup the area where the Hifn DMA's descriptors
++ * and associated data structures.
++ */
++ sc->sc_dma = (struct hifn_dma *) pci_alloc_consistent(dev,
++ sizeof(*sc->sc_dma),
++ &sc->sc_dma_physaddr);
++ if (!sc->sc_dma) {
++ device_printf(sc->sc_dev, "cannot alloc sc_dma\n");
++ goto fail;
++ }
++ bzero(sc->sc_dma, sizeof(*sc->sc_dma));
++
++ /*
++ * Reset the board and do the ``secret handshake''
++ * to enable the crypto support. Then complete the
++ * initialization procedure by setting up the interrupt
++ * and hooking in to the system crypto support so we'll
++ * get used for system services like the crypto device,
++ * IPsec, RNG device, etc.
++ */
++ hifn_reset_board(sc, 0);
++
++ if (hifn_enable_crypto(sc) != 0) {
++ device_printf(sc->sc_dev, "crypto enabling failed\n");
++ goto fail;
++ }
++ hifn_reset_puc(sc);
++
++ hifn_init_dma(sc);
++ hifn_init_pci_registers(sc);
++
++ pci_set_master(sc->sc_pcidev);
++
++ /* XXX can't dynamically determine ram type for 795x; force dram */
++ if (sc->sc_flags & HIFN_IS_7956)
++ sc->sc_drammodel = 1;
++ else if (hifn_ramtype(sc))
++ goto fail;
++
++ if (sc->sc_drammodel == 0)
++ hifn_sramsize(sc);
++ else
++ hifn_dramsize(sc);
++
++ /*
++ * Workaround for NetSec 7751 rev A: half ram size because two
++ * of the address lines were left floating
++ */
++ if (pci_get_vendor(dev) == PCI_VENDOR_NETSEC &&
++ pci_get_device(dev) == PCI_PRODUCT_NETSEC_7751 &&
++ pci_get_revid(dev) == 0x61) /*XXX???*/
++ sc->sc_ramsize >>= 1;
++
++ /*
++ * Arrange the interrupt line.
++ */
++ rc = request_irq(dev->irq, hifn_intr, IRQF_SHARED, "hifn", sc);
++ if (rc) {
++ device_printf(sc->sc_dev, "could not map interrupt: %d\n", rc);
++ goto fail;
++ }
++ sc->sc_irq = dev->irq;
++
++ hifn_sessions(sc);
++
++ /*
++ * NB: Keep only the low 16 bits; this masks the chip id
++ * from the 7951.
++ */
++ rev = READ_REG_1(sc, HIFN_1_REVID) & 0xffff;
++
++ rseg = sc->sc_ramsize / 1024;
++ rbase = 'K';
++ if (sc->sc_ramsize >= (1024 * 1024)) {
++ rbase = 'M';
++ rseg /= 1024;
++ }
++ device_printf(sc->sc_dev, "%s, rev %u, %d%cB %cram",
++ hifn_partname(sc), rev,
++ rseg, rbase, sc->sc_drammodel ? 'd' : 's');
++ if (sc->sc_flags & HIFN_IS_7956)
++ printf(", pll=0x%x<%s clk, %ux mult>",
++ sc->sc_pllconfig,
++ sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci",
++ 2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11));
++ printf("\n");
++
++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE);
++ if (sc->sc_cid < 0) {
++ device_printf(sc->sc_dev, "could not get crypto driver id\n");
++ goto fail;
++ }
++
++ WRITE_REG_0(sc, HIFN_0_PUCNFG,
++ READ_REG_0(sc, HIFN_0_PUCNFG) | HIFN_PUCNFG_CHIPID);
++ ena = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA;
++
++ switch (ena) {
++ case HIFN_PUSTAT_ENA_2:
++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0);
++ if (sc->sc_flags & HIFN_HAS_AES)
++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
++ /*FALLTHROUGH*/
++ case HIFN_PUSTAT_ENA_1:
++ crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
++ break;
++ }
++
++ if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG))
++ hifn_init_pubrng(sc);
++
++ init_timer(&sc->sc_tickto);
++ sc->sc_tickto.function = hifn_tick;
++ sc->sc_tickto.data = (unsigned long) sc->sc_num;
++ mod_timer(&sc->sc_tickto, jiffies + HZ);
++
++ return (0);
++
++fail:
++ if (sc->sc_cid >= 0)
++ crypto_unregister_all(sc->sc_cid);
++ if (sc->sc_irq != -1)
++ free_irq(sc->sc_irq, sc);
++ if (sc->sc_dma) {
++ /* Turn off DMA polling */
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++
++ pci_free_consistent(sc->sc_pcidev,
++ sizeof(*sc->sc_dma),
++ sc->sc_dma, sc->sc_dma_physaddr);
++ }
++ kfree(sc);
++ return (-ENXIO);
++}
++
++/*
++ * Detach an interface that successfully probed.
++ */
++static void
++hifn_remove(struct pci_dev *dev)
++{
++ struct hifn_softc *sc = pci_get_drvdata(dev);
++ unsigned long l_flags;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ KASSERT(sc != NULL, ("hifn_detach: null software carrier!"));
++
++ /* disable interrupts */
++ HIFN_LOCK(sc);
++ WRITE_REG_1(sc, HIFN_1_DMA_IER, 0);
++ HIFN_UNLOCK(sc);
++
++ /*XXX other resources */
++ del_timer_sync(&sc->sc_tickto);
++
++ /* Turn off DMA polling */
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++
++ crypto_unregister_all(sc->sc_cid);
++
++ free_irq(sc->sc_irq, sc);
++
++ pci_free_consistent(sc->sc_pcidev, sizeof(*sc->sc_dma),
++ sc->sc_dma, sc->sc_dma_physaddr);
++}
++
++
++static int
++hifn_init_pubrng(struct hifn_softc *sc)
++{
++ int i;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ if ((sc->sc_flags & HIFN_IS_7811) == 0) {
++ /* Reset 7951 public key/rng engine */
++ WRITE_REG_1(sc, HIFN_1_PUB_RESET,
++ READ_REG_1(sc, HIFN_1_PUB_RESET) | HIFN_PUBRST_RESET);
++
++ for (i = 0; i < 100; i++) {
++ DELAY(1000);
++ if ((READ_REG_1(sc, HIFN_1_PUB_RESET) &
++ HIFN_PUBRST_RESET) == 0)
++ break;
++ }
++
++ if (i == 100) {
++ device_printf(sc->sc_dev, "public key init failed\n");
++ return (1);
++ }
++ }
++
++ /* Enable the rng, if available */
++#ifdef CONFIG_OCF_RANDOMHARVEST
++ if (sc->sc_flags & HIFN_HAS_RNG) {
++ if (sc->sc_flags & HIFN_IS_7811) {
++ u_int32_t r;
++ r = READ_REG_1(sc, HIFN_1_7811_RNGENA);
++ if (r & HIFN_7811_RNGENA_ENA) {
++ r &= ~HIFN_7811_RNGENA_ENA;
++ WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r);
++ }
++ WRITE_REG_1(sc, HIFN_1_7811_RNGCFG,
++ HIFN_7811_RNGCFG_DEFL);
++ r |= HIFN_7811_RNGENA_ENA;
++ WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r);
++ } else
++ WRITE_REG_1(sc, HIFN_1_RNG_CONFIG,
++ READ_REG_1(sc, HIFN_1_RNG_CONFIG) |
++ HIFN_RNGCFG_ENA);
++
++ sc->sc_rngfirst = 1;
++ crypto_rregister(sc->sc_cid, hifn_read_random, sc);
++ }
++#endif
++
++ /* Enable public key engine, if available */
++ if (sc->sc_flags & HIFN_HAS_PUBLIC) {
++ WRITE_REG_1(sc, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE);
++ sc->sc_dmaier |= HIFN_DMAIER_PUBDONE;
++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
++#ifdef HIFN_VULCANDEV
++ sc->sc_pkdev = make_dev(&vulcanpk_cdevsw, 0,
++ UID_ROOT, GID_WHEEL, 0666,
++ "vulcanpk");
++ sc->sc_pkdev->si_drv1 = sc;
++#endif
++ }
++
++ return (0);
++}
++
++#ifdef CONFIG_OCF_RANDOMHARVEST
++static int
++hifn_read_random(void *arg, u_int32_t *buf, int len)
++{
++ struct hifn_softc *sc = (struct hifn_softc *) arg;
++ u_int32_t sts;
++ int i, rc = 0;
++
++ if (len <= 0)
++ return rc;
++
++ if (sc->sc_flags & HIFN_IS_7811) {
++ /* ONLY VALID ON 7811!!!! */
++ for (i = 0; i < 5; i++) {
++ sts = READ_REG_1(sc, HIFN_1_7811_RNGSTS);
++ if (sts & HIFN_7811_RNGSTS_UFL) {
++ device_printf(sc->sc_dev,
++ "RNG underflow: disabling\n");
++ /* DAVIDM perhaps return -1 */
++ break;
++ }
++ if ((sts & HIFN_7811_RNGSTS_RDY) == 0)
++ break;
++
++ /*
++ * There are at least two words in the RNG FIFO
++ * at this point.
++ */
++ if (rc < len)
++ buf[rc++] = READ_REG_1(sc, HIFN_1_7811_RNGDAT);
++ if (rc < len)
++ buf[rc++] = READ_REG_1(sc, HIFN_1_7811_RNGDAT);
++ }
++ } else
++ buf[rc++] = READ_REG_1(sc, HIFN_1_RNG_DATA);
++
++ /* NB: discard first data read */
++ if (sc->sc_rngfirst) {
++ sc->sc_rngfirst = 0;
++ rc = 0;
++ }
++
++ return(rc);
++}
++#endif /* CONFIG_OCF_RANDOMHARVEST */
++
++static void
++hifn_puc_wait(struct hifn_softc *sc)
++{
++ int i;
++ int reg = HIFN_0_PUCTRL;
++
++ if (sc->sc_flags & HIFN_IS_7956) {
++ reg = HIFN_0_PUCTRL2;
++ }
++
++ for (i = 5000; i > 0; i--) {
++ DELAY(1);
++ if (!(READ_REG_0(sc, reg) & HIFN_PUCTRL_RESET))
++ break;
++ }
++ if (!i)
++ device_printf(sc->sc_dev, "proc unit did not reset(0x%x)\n",
++ READ_REG_0(sc, HIFN_0_PUCTRL));
++}
++
++/*
++ * Reset the processing unit.
++ */
++static void
++hifn_reset_puc(struct hifn_softc *sc)
++{
++ /* Reset processing unit */
++ int reg = HIFN_0_PUCTRL;
++
++ if (sc->sc_flags & HIFN_IS_7956) {
++ reg = HIFN_0_PUCTRL2;
++ }
++ WRITE_REG_0(sc, reg, HIFN_PUCTRL_DMAENA);
++
++ hifn_puc_wait(sc);
++}
++
++/*
++ * Set the Retry and TRDY registers; note that we set them to
++ * zero because the 7811 locks up when forced to retry (section
++ * 3.6 of "Specification Update SU-0014-04". Not clear if we
++ * should do this for all Hifn parts, but it doesn't seem to hurt.
++ */
++static void
++hifn_set_retry(struct hifn_softc *sc)
++{
++ DPRINTF("%s()\n", __FUNCTION__);
++ /* NB: RETRY only responds to 8-bit reads/writes */
++ pci_write_config_byte(sc->sc_pcidev, HIFN_RETRY_TIMEOUT, 0);
++ pci_write_config_dword(sc->sc_pcidev, HIFN_TRDY_TIMEOUT, 0);
++ /* piggy back the cache line setting here */
++ pci_write_config_byte(sc->sc_pcidev, PCI_CACHE_LINE_SIZE, hifn_cache_linesize);
++}
++
++/*
++ * Resets the board. Values in the regesters are left as is
++ * from the reset (i.e. initial values are assigned elsewhere).
++ */
++static void
++hifn_reset_board(struct hifn_softc *sc, int full)
++{
++ u_int32_t reg;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++ /*
++ * Set polling in the DMA configuration register to zero. 0x7 avoids
++ * resetting the board and zeros out the other fields.
++ */
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++
++ /*
++ * Now that polling has been disabled, we have to wait 1 ms
++ * before resetting the board.
++ */
++ DELAY(1000);
++
++ /* Reset the DMA unit */
++ if (full) {
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE);
++ DELAY(1000);
++ } else {
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG,
++ HIFN_DMACNFG_MODE | HIFN_DMACNFG_MSTRESET);
++ hifn_reset_puc(sc);
++ }
++
++ KASSERT(sc->sc_dma != NULL, ("hifn_reset_board: null DMA tag!"));
++ bzero(sc->sc_dma, sizeof(*sc->sc_dma));
++
++ /* Bring dma unit out of reset */
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++
++ hifn_puc_wait(sc);
++ hifn_set_retry(sc);
++
++ if (sc->sc_flags & HIFN_IS_7811) {
++ for (reg = 0; reg < 1000; reg++) {
++ if (READ_REG_1(sc, HIFN_1_7811_MIPSRST) &
++ HIFN_MIPSRST_CRAMINIT)
++ break;
++ DELAY(1000);
++ }
++ if (reg == 1000)
++ device_printf(sc->sc_dev, ": cram init timeout\n");
++ } else {
++ /* set up DMA configuration register #2 */
++ /* turn off all PK and BAR0 swaps */
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG2,
++ (3 << HIFN_DMACNFG2_INIT_WRITE_BURST_SHIFT)|
++ (3 << HIFN_DMACNFG2_INIT_READ_BURST_SHIFT)|
++ (2 << HIFN_DMACNFG2_TGT_WRITE_BURST_SHIFT)|
++ (2 << HIFN_DMACNFG2_TGT_READ_BURST_SHIFT));
++ }
++}
++
++static u_int32_t
++hifn_next_signature(u_int32_t a, u_int cnt)
++{
++ int i;
++ u_int32_t v;
++
++ for (i = 0; i < cnt; i++) {
++
++ /* get the parity */
++ v = a & 0x80080125;
++ v ^= v >> 16;
++ v ^= v >> 8;
++ v ^= v >> 4;
++ v ^= v >> 2;
++ v ^= v >> 1;
++
++ a = (v & 1) ^ (a << 1);
++ }
++
++ return a;
++}
++
++
++/*
++ * Checks to see if crypto is already enabled. If crypto isn't enable,
++ * "hifn_enable_crypto" is called to enable it. The check is important,
++ * as enabling crypto twice will lock the board.
++ */
++static int
++hifn_enable_crypto(struct hifn_softc *sc)
++{
++ u_int32_t dmacfg, ramcfg, encl, addr, i;
++ char offtbl[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00 };
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ ramcfg = READ_REG_0(sc, HIFN_0_PUCNFG);
++ dmacfg = READ_REG_1(sc, HIFN_1_DMA_CNFG);
++
++ /*
++ * The RAM config register's encrypt level bit needs to be set before
++ * every read performed on the encryption level register.
++ */
++ WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID);
++
++ encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA;
++
++ /*
++ * Make sure we don't re-unlock. Two unlocks kills chip until the
++ * next reboot.
++ */
++ if (encl == HIFN_PUSTAT_ENA_1 || encl == HIFN_PUSTAT_ENA_2) {
++#ifdef HIFN_DEBUG
++ if (hifn_debug)
++ device_printf(sc->sc_dev,
++ "Strong crypto already enabled!\n");
++#endif
++ goto report;
++ }
++
++ if (encl != 0 && encl != HIFN_PUSTAT_ENA_0) {
++#ifdef HIFN_DEBUG
++ if (hifn_debug)
++ device_printf(sc->sc_dev,
++ "Unknown encryption level 0x%x\n", encl);
++#endif
++ return 1;
++ }
++
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_UNLOCK |
++ HIFN_DMACNFG_MSTRESET | HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++ DELAY(1000);
++ addr = READ_REG_1(sc, HIFN_UNLOCK_SECRET1);
++ DELAY(1000);
++ WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, 0);
++ DELAY(1000);
++
++ for (i = 0; i <= 12; i++) {
++ addr = hifn_next_signature(addr, offtbl[i] + 0x101);
++ WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, addr);
++
++ DELAY(1000);
++ }
++
++ WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID);
++ encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA;
++
++#ifdef HIFN_DEBUG
++ if (hifn_debug) {
++ if (encl != HIFN_PUSTAT_ENA_1 && encl != HIFN_PUSTAT_ENA_2)
++ device_printf(sc->sc_dev, "Engine is permanently "
++ "locked until next system reset!\n");
++ else
++ device_printf(sc->sc_dev, "Engine enabled "
++ "successfully!\n");
++ }
++#endif
++
++report:
++ WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg);
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, dmacfg);
++
++ switch (encl) {
++ case HIFN_PUSTAT_ENA_1:
++ case HIFN_PUSTAT_ENA_2:
++ break;
++ case HIFN_PUSTAT_ENA_0:
++ default:
++ device_printf(sc->sc_dev, "disabled\n");
++ break;
++ }
++
++ return 0;
++}
++
++/*
++ * Give initial values to the registers listed in the "Register Space"
++ * section of the HIFN Software Development reference manual.
++ */
++static void
++hifn_init_pci_registers(struct hifn_softc *sc)
++{
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ /* write fixed values needed by the Initialization registers */
++ WRITE_REG_0(sc, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA);
++ WRITE_REG_0(sc, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD);
++ WRITE_REG_0(sc, HIFN_0_PUIER, HIFN_PUIER_DSTOVER);
++
++ /* write all 4 ring address registers */
++ WRITE_REG_1(sc, HIFN_1_DMA_CRAR, sc->sc_dma_physaddr +
++ offsetof(struct hifn_dma, cmdr[0]));
++ WRITE_REG_1(sc, HIFN_1_DMA_SRAR, sc->sc_dma_physaddr +
++ offsetof(struct hifn_dma, srcr[0]));
++ WRITE_REG_1(sc, HIFN_1_DMA_DRAR, sc->sc_dma_physaddr +
++ offsetof(struct hifn_dma, dstr[0]));
++ WRITE_REG_1(sc, HIFN_1_DMA_RRAR, sc->sc_dma_physaddr +
++ offsetof(struct hifn_dma, resr[0]));
++
++ DELAY(2000);
++
++ /* write status register */
++ WRITE_REG_1(sc, HIFN_1_DMA_CSR,
++ HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS |
++ HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS |
++ HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST |
++ HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER |
++ HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST |
++ HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER |
++ HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST |
++ HIFN_DMACSR_S_WAIT |
++ HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST |
++ HIFN_DMACSR_C_WAIT |
++ HIFN_DMACSR_ENGINE |
++ ((sc->sc_flags & HIFN_HAS_PUBLIC) ?
++ HIFN_DMACSR_PUBDONE : 0) |
++ ((sc->sc_flags & HIFN_IS_7811) ?
++ HIFN_DMACSR_ILLW | HIFN_DMACSR_ILLR : 0));
++
++ sc->sc_d_busy = sc->sc_r_busy = sc->sc_s_busy = sc->sc_c_busy = 0;
++ sc->sc_dmaier |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT |
++ HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER |
++ HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT |
++ ((sc->sc_flags & HIFN_IS_7811) ?
++ HIFN_DMAIER_ILLW | HIFN_DMAIER_ILLR : 0);
++ sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT;
++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
++
++
++ if (sc->sc_flags & HIFN_IS_7956) {
++ u_int32_t pll;
++
++ WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING |
++ HIFN_PUCNFG_TCALLPHASES |
++ HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32);
++
++ /* turn off the clocks and insure bypass is set */
++ pll = READ_REG_1(sc, HIFN_1_PLL);
++ pll = (pll &~ (HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL))
++ | HIFN_PLL_BP | HIFN_PLL_MBSET;
++ WRITE_REG_1(sc, HIFN_1_PLL, pll);
++ DELAY(10*1000); /* 10ms */
++
++ /* change configuration */
++ pll = (pll &~ HIFN_PLL_CONFIG) | sc->sc_pllconfig;
++ WRITE_REG_1(sc, HIFN_1_PLL, pll);
++ DELAY(10*1000); /* 10ms */
++
++ /* disable bypass */
++ pll &= ~HIFN_PLL_BP;
++ WRITE_REG_1(sc, HIFN_1_PLL, pll);
++ /* enable clocks with new configuration */
++ pll |= HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL;
++ WRITE_REG_1(sc, HIFN_1_PLL, pll);
++ } else {
++ WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING |
++ HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES |
++ HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 |
++ (sc->sc_drammodel ? HIFN_PUCNFG_DRAM : HIFN_PUCNFG_SRAM));
++ }
++
++ WRITE_REG_0(sc, HIFN_0_PUISR, HIFN_PUISR_DSTOVER);
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST |
++ ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) |
++ ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL));
++}
++
++/*
++ * The maximum number of sessions supported by the card
++ * is dependent on the amount of context ram, which
++ * encryption algorithms are enabled, and how compression
++ * is configured. This should be configured before this
++ * routine is called.
++ */
++static void
++hifn_sessions(struct hifn_softc *sc)
++{
++ u_int32_t pucnfg;
++ int ctxsize;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ pucnfg = READ_REG_0(sc, HIFN_0_PUCNFG);
++
++ if (pucnfg & HIFN_PUCNFG_COMPSING) {
++ if (pucnfg & HIFN_PUCNFG_ENCCNFG)
++ ctxsize = 128;
++ else
++ ctxsize = 512;
++ /*
++ * 7955/7956 has internal context memory of 32K
++ */
++ if (sc->sc_flags & HIFN_IS_7956)
++ sc->sc_maxses = 32768 / ctxsize;
++ else
++ sc->sc_maxses = 1 +
++ ((sc->sc_ramsize - 32768) / ctxsize);
++ } else
++ sc->sc_maxses = sc->sc_ramsize / 16384;
++
++ if (sc->sc_maxses > 2048)
++ sc->sc_maxses = 2048;
++}
++
++/*
++ * Determine ram type (sram or dram). Board should be just out of a reset
++ * state when this is called.
++ */
++static int
++hifn_ramtype(struct hifn_softc *sc)
++{
++ u_int8_t data[8], dataexpect[8];
++ int i;
++
++ for (i = 0; i < sizeof(data); i++)
++ data[i] = dataexpect[i] = 0x55;
++ if (hifn_writeramaddr(sc, 0, data))
++ return (-1);
++ if (hifn_readramaddr(sc, 0, data))
++ return (-1);
++ if (bcmp(data, dataexpect, sizeof(data)) != 0) {
++ sc->sc_drammodel = 1;
++ return (0);
++ }
++
++ for (i = 0; i < sizeof(data); i++)
++ data[i] = dataexpect[i] = 0xaa;
++ if (hifn_writeramaddr(sc, 0, data))
++ return (-1);
++ if (hifn_readramaddr(sc, 0, data))
++ return (-1);
++ if (bcmp(data, dataexpect, sizeof(data)) != 0) {
++ sc->sc_drammodel = 1;
++ return (0);
++ }
++
++ return (0);
++}
++
++#define HIFN_SRAM_MAX (32 << 20)
++#define HIFN_SRAM_STEP_SIZE 16384
++#define HIFN_SRAM_GRANULARITY (HIFN_SRAM_MAX / HIFN_SRAM_STEP_SIZE)
++
++static int
++hifn_sramsize(struct hifn_softc *sc)
++{
++ u_int32_t a;
++ u_int8_t data[8];
++ u_int8_t dataexpect[sizeof(data)];
++ int32_t i;
++
++ for (i = 0; i < sizeof(data); i++)
++ data[i] = dataexpect[i] = i ^ 0x5a;
++
++ for (i = HIFN_SRAM_GRANULARITY - 1; i >= 0; i--) {
++ a = i * HIFN_SRAM_STEP_SIZE;
++ bcopy(&i, data, sizeof(i));
++ hifn_writeramaddr(sc, a, data);
++ }
++
++ for (i = 0; i < HIFN_SRAM_GRANULARITY; i++) {
++ a = i * HIFN_SRAM_STEP_SIZE;
++ bcopy(&i, dataexpect, sizeof(i));
++ if (hifn_readramaddr(sc, a, data) < 0)
++ return (0);
++ if (bcmp(data, dataexpect, sizeof(data)) != 0)
++ return (0);
++ sc->sc_ramsize = a + HIFN_SRAM_STEP_SIZE;
++ }
++
++ return (0);
++}
++
++/*
++ * XXX For dram boards, one should really try all of the
++ * HIFN_PUCNFG_DSZ_*'s. This just assumes that PUCNFG
++ * is already set up correctly.
++ */
++static int
++hifn_dramsize(struct hifn_softc *sc)
++{
++ u_int32_t cnfg;
++
++ if (sc->sc_flags & HIFN_IS_7956) {
++ /*
++ * 7955/7956 have a fixed internal ram of only 32K.
++ */
++ sc->sc_ramsize = 32768;
++ } else {
++ cnfg = READ_REG_0(sc, HIFN_0_PUCNFG) &
++ HIFN_PUCNFG_DRAMMASK;
++ sc->sc_ramsize = 1 << ((cnfg >> 13) + 18);
++ }
++ return (0);
++}
++
++static void
++hifn_alloc_slot(struct hifn_softc *sc, int *cmdp, int *srcp, int *dstp, int *resp)
++{
++ struct hifn_dma *dma = sc->sc_dma;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ if (dma->cmdi == HIFN_D_CMD_RSIZE) {
++ dma->cmdi = 0;
++ dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++ wmb();
++ dma->cmdr[HIFN_D_CMD_RSIZE].l |= htole32(HIFN_D_VALID);
++ HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE,
++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++ }
++ *cmdp = dma->cmdi++;
++ dma->cmdk = dma->cmdi;
++
++ if (dma->srci == HIFN_D_SRC_RSIZE) {
++ dma->srci = 0;
++ dma->srcr[HIFN_D_SRC_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++ wmb();
++ dma->srcr[HIFN_D_SRC_RSIZE].l |= htole32(HIFN_D_VALID);
++ HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE,
++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++ }
++ *srcp = dma->srci++;
++ dma->srck = dma->srci;
++
++ if (dma->dsti == HIFN_D_DST_RSIZE) {
++ dma->dsti = 0;
++ dma->dstr[HIFN_D_DST_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++ wmb();
++ dma->dstr[HIFN_D_DST_RSIZE].l |= htole32(HIFN_D_VALID);
++ HIFN_DSTR_SYNC(sc, HIFN_D_DST_RSIZE,
++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++ }
++ *dstp = dma->dsti++;
++ dma->dstk = dma->dsti;
++
++ if (dma->resi == HIFN_D_RES_RSIZE) {
++ dma->resi = 0;
++ dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++ wmb();
++ dma->resr[HIFN_D_RES_RSIZE].l |= htole32(HIFN_D_VALID);
++ HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE,
++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++ }
++ *resp = dma->resi++;
++ dma->resk = dma->resi;
++}
++
++static int
++hifn_writeramaddr(struct hifn_softc *sc, int addr, u_int8_t *data)
++{
++ struct hifn_dma *dma = sc->sc_dma;
++ hifn_base_command_t wc;
++ const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ;
++ int r, cmdi, resi, srci, dsti;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ wc.masks = htole16(3 << 13);
++ wc.session_num = htole16(addr >> 14);
++ wc.total_source_count = htole16(8);
++ wc.total_dest_count = htole16(addr & 0x3fff);
++
++ hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi);
++
++ WRITE_REG_1(sc, HIFN_1_DMA_CSR,
++ HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA |
++ HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA);
++
++ /* build write command */
++ bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND);
++ *(hifn_base_command_t *)dma->command_bufs[cmdi] = wc;
++ bcopy(data, &dma->test_src, sizeof(dma->test_src));
++
++ dma->srcr[srci].p = htole32(sc->sc_dma_physaddr
++ + offsetof(struct hifn_dma, test_src));
++ dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr
++ + offsetof(struct hifn_dma, test_dst));
++
++ dma->cmdr[cmdi].l = htole32(16 | masks);
++ dma->srcr[srci].l = htole32(8 | masks);
++ dma->dstr[dsti].l = htole32(4 | masks);
++ dma->resr[resi].l = htole32(4 | masks);
++
++ for (r = 10000; r >= 0; r--) {
++ DELAY(10);
++ if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0)
++ break;
++ }
++ if (r == 0) {
++ device_printf(sc->sc_dev, "writeramaddr -- "
++ "result[%d](addr %d) still valid\n", resi, addr);
++ r = -1;
++ return (-1);
++ } else
++ r = 0;
++
++ WRITE_REG_1(sc, HIFN_1_DMA_CSR,
++ HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS |
++ HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS);
++
++ return (r);
++}
++
++static int
++hifn_readramaddr(struct hifn_softc *sc, int addr, u_int8_t *data)
++{
++ struct hifn_dma *dma = sc->sc_dma;
++ hifn_base_command_t rc;
++ const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ;
++ int r, cmdi, srci, dsti, resi;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ rc.masks = htole16(2 << 13);
++ rc.session_num = htole16(addr >> 14);
++ rc.total_source_count = htole16(addr & 0x3fff);
++ rc.total_dest_count = htole16(8);
++
++ hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi);
++
++ WRITE_REG_1(sc, HIFN_1_DMA_CSR,
++ HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA |
++ HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA);
++
++ bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND);
++ *(hifn_base_command_t *)dma->command_bufs[cmdi] = rc;
++
++ dma->srcr[srci].p = htole32(sc->sc_dma_physaddr +
++ offsetof(struct hifn_dma, test_src));
++ dma->test_src = 0;
++ dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr +
++ offsetof(struct hifn_dma, test_dst));
++ dma->test_dst = 0;
++ dma->cmdr[cmdi].l = htole32(8 | masks);
++ dma->srcr[srci].l = htole32(8 | masks);
++ dma->dstr[dsti].l = htole32(8 | masks);
++ dma->resr[resi].l = htole32(HIFN_MAX_RESULT | masks);
++
++ for (r = 10000; r >= 0; r--) {
++ DELAY(10);
++ if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0)
++ break;
++ }
++ if (r == 0) {
++ device_printf(sc->sc_dev, "readramaddr -- "
++ "result[%d](addr %d) still valid\n", resi, addr);
++ r = -1;
++ } else {
++ r = 0;
++ bcopy(&dma->test_dst, data, sizeof(dma->test_dst));
++ }
++
++ WRITE_REG_1(sc, HIFN_1_DMA_CSR,
++ HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS |
++ HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS);
++
++ return (r);
++}
++
++/*
++ * Initialize the descriptor rings.
++ */
++static void
++hifn_init_dma(struct hifn_softc *sc)
++{
++ struct hifn_dma *dma = sc->sc_dma;
++ int i;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ hifn_set_retry(sc);
++
++ /* initialize static pointer values */
++ for (i = 0; i < HIFN_D_CMD_RSIZE; i++)
++ dma->cmdr[i].p = htole32(sc->sc_dma_physaddr +
++ offsetof(struct hifn_dma, command_bufs[i][0]));
++ for (i = 0; i < HIFN_D_RES_RSIZE; i++)
++ dma->resr[i].p = htole32(sc->sc_dma_physaddr +
++ offsetof(struct hifn_dma, result_bufs[i][0]));
++
++ dma->cmdr[HIFN_D_CMD_RSIZE].p =
++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, cmdr[0]));
++ dma->srcr[HIFN_D_SRC_RSIZE].p =
++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, srcr[0]));
++ dma->dstr[HIFN_D_DST_RSIZE].p =
++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, dstr[0]));
++ dma->resr[HIFN_D_RES_RSIZE].p =
++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, resr[0]));
++
++ dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0;
++ dma->cmdi = dma->srci = dma->dsti = dma->resi = 0;
++ dma->cmdk = dma->srck = dma->dstk = dma->resk = 0;
++}
++
++/*
++ * Writes out the raw command buffer space. Returns the
++ * command buffer size.
++ */
++static u_int
++hifn_write_command(struct hifn_command *cmd, u_int8_t *buf)
++{
++ struct hifn_softc *sc = NULL;
++ u_int8_t *buf_pos;
++ hifn_base_command_t *base_cmd;
++ hifn_mac_command_t *mac_cmd;
++ hifn_crypt_command_t *cry_cmd;
++ int using_mac, using_crypt, len, ivlen;
++ u_int32_t dlen, slen;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ buf_pos = buf;
++ using_mac = cmd->base_masks & HIFN_BASE_CMD_MAC;
++ using_crypt = cmd->base_masks & HIFN_BASE_CMD_CRYPT;
++
++ base_cmd = (hifn_base_command_t *)buf_pos;
++ base_cmd->masks = htole16(cmd->base_masks);
++ slen = cmd->src_mapsize;
++ if (cmd->sloplen)
++ dlen = cmd->dst_mapsize - cmd->sloplen + sizeof(u_int32_t);
++ else
++ dlen = cmd->dst_mapsize;
++ base_cmd->total_source_count = htole16(slen & HIFN_BASE_CMD_LENMASK_LO);
++ base_cmd->total_dest_count = htole16(dlen & HIFN_BASE_CMD_LENMASK_LO);
++ dlen >>= 16;
++ slen >>= 16;
++ base_cmd->session_num = htole16(
++ ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) |
++ ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M));
++ buf_pos += sizeof(hifn_base_command_t);
++
++ if (using_mac) {
++ mac_cmd = (hifn_mac_command_t *)buf_pos;
++ dlen = cmd->maccrd->crd_len;
++ mac_cmd->source_count = htole16(dlen & 0xffff);
++ dlen >>= 16;
++ mac_cmd->masks = htole16(cmd->mac_masks |
++ ((dlen << HIFN_MAC_CMD_SRCLEN_S) & HIFN_MAC_CMD_SRCLEN_M));
++ mac_cmd->header_skip = htole16(cmd->maccrd->crd_skip);
++ mac_cmd->reserved = 0;
++ buf_pos += sizeof(hifn_mac_command_t);
++ }
++
++ if (using_crypt) {
++ cry_cmd = (hifn_crypt_command_t *)buf_pos;
++ dlen = cmd->enccrd->crd_len;
++ cry_cmd->source_count = htole16(dlen & 0xffff);
++ dlen >>= 16;
++ cry_cmd->masks = htole16(cmd->cry_masks |
++ ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & HIFN_CRYPT_CMD_SRCLEN_M));
++ cry_cmd->header_skip = htole16(cmd->enccrd->crd_skip);
++ cry_cmd->reserved = 0;
++ buf_pos += sizeof(hifn_crypt_command_t);
++ }
++
++ if (using_mac && cmd->mac_masks & HIFN_MAC_CMD_NEW_KEY) {
++ bcopy(cmd->mac, buf_pos, HIFN_MAC_KEY_LENGTH);
++ buf_pos += HIFN_MAC_KEY_LENGTH;
++ }
++
++ if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_KEY) {
++ switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) {
++ case HIFN_CRYPT_CMD_ALG_3DES:
++ bcopy(cmd->ck, buf_pos, HIFN_3DES_KEY_LENGTH);
++ buf_pos += HIFN_3DES_KEY_LENGTH;
++ break;
++ case HIFN_CRYPT_CMD_ALG_DES:
++ bcopy(cmd->ck, buf_pos, HIFN_DES_KEY_LENGTH);
++ buf_pos += HIFN_DES_KEY_LENGTH;
++ break;
++ case HIFN_CRYPT_CMD_ALG_RC4:
++ len = 256;
++ do {
++ int clen;
++
++ clen = MIN(cmd->cklen, len);
++ bcopy(cmd->ck, buf_pos, clen);
++ len -= clen;
++ buf_pos += clen;
++ } while (len > 0);
++ bzero(buf_pos, 4);
++ buf_pos += 4;
++ break;
++ case HIFN_CRYPT_CMD_ALG_AES:
++ /*
++ * AES keys are variable 128, 192 and
++ * 256 bits (16, 24 and 32 bytes).
++ */
++ bcopy(cmd->ck, buf_pos, cmd->cklen);
++ buf_pos += cmd->cklen;
++ break;
++ }
++ }
++
++ if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_IV) {
++ switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) {
++ case HIFN_CRYPT_CMD_ALG_AES:
++ ivlen = HIFN_AES_IV_LENGTH;
++ break;
++ default:
++ ivlen = HIFN_IV_LENGTH;
++ break;
++ }
++ bcopy(cmd->iv, buf_pos, ivlen);
++ buf_pos += ivlen;
++ }
++
++ if ((cmd->base_masks & (HIFN_BASE_CMD_MAC|HIFN_BASE_CMD_CRYPT)) == 0) {
++ bzero(buf_pos, 8);
++ buf_pos += 8;
++ }
++
++ return (buf_pos - buf);
++}
++
++static int
++hifn_dmamap_aligned(struct hifn_operand *op)
++{
++ struct hifn_softc *sc = NULL;
++ int i;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ for (i = 0; i < op->nsegs; i++) {
++ if (op->segs[i].ds_addr & 3)
++ return (0);
++ if ((i != (op->nsegs - 1)) && (op->segs[i].ds_len & 3))
++ return (0);
++ }
++ return (1);
++}
++
++static __inline int
++hifn_dmamap_dstwrap(struct hifn_softc *sc, int idx)
++{
++ struct hifn_dma *dma = sc->sc_dma;
++
++ if (++idx == HIFN_D_DST_RSIZE) {
++ dma->dstr[idx].l = htole32(HIFN_D_VALID | HIFN_D_JUMP |
++ HIFN_D_MASKDONEIRQ);
++ HIFN_DSTR_SYNC(sc, idx,
++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++ idx = 0;
++ }
++ return (idx);
++}
++
++static int
++hifn_dmamap_load_dst(struct hifn_softc *sc, struct hifn_command *cmd)
++{
++ struct hifn_dma *dma = sc->sc_dma;
++ struct hifn_operand *dst = &cmd->dst;
++ u_int32_t p, l;
++ int idx, used = 0, i;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ idx = dma->dsti;
++ for (i = 0; i < dst->nsegs - 1; i++) {
++ dma->dstr[idx].p = htole32(dst->segs[i].ds_addr);
++ dma->dstr[idx].l = htole32(HIFN_D_MASKDONEIRQ | dst->segs[i].ds_len);
++ wmb();
++ dma->dstr[idx].l |= htole32(HIFN_D_VALID);
++ HIFN_DSTR_SYNC(sc, idx,
++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++ used++;
++
++ idx = hifn_dmamap_dstwrap(sc, idx);
++ }
++
++ if (cmd->sloplen == 0) {
++ p = dst->segs[i].ds_addr;
++ l = HIFN_D_MASKDONEIRQ | HIFN_D_LAST |
++ dst->segs[i].ds_len;
++ } else {
++ p = sc->sc_dma_physaddr +
++ offsetof(struct hifn_dma, slop[cmd->slopidx]);
++ l = HIFN_D_MASKDONEIRQ | HIFN_D_LAST |
++ sizeof(u_int32_t);
++
++ if ((dst->segs[i].ds_len - cmd->sloplen) != 0) {
++ dma->dstr[idx].p = htole32(dst->segs[i].ds_addr);
++ dma->dstr[idx].l = htole32(HIFN_D_MASKDONEIRQ |
++ (dst->segs[i].ds_len - cmd->sloplen));
++ wmb();
++ dma->dstr[idx].l |= htole32(HIFN_D_VALID);
++ HIFN_DSTR_SYNC(sc, idx,
++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++ used++;
++
++ idx = hifn_dmamap_dstwrap(sc, idx);
++ }
++ }
++ dma->dstr[idx].p = htole32(p);
++ dma->dstr[idx].l = htole32(l);
++ wmb();
++ dma->dstr[idx].l |= htole32(HIFN_D_VALID);
++ HIFN_DSTR_SYNC(sc, idx, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++ used++;
++
++ idx = hifn_dmamap_dstwrap(sc, idx);
++
++ dma->dsti = idx;
++ dma->dstu += used;
++ return (idx);
++}
++
++static __inline int
++hifn_dmamap_srcwrap(struct hifn_softc *sc, int idx)
++{
++ struct hifn_dma *dma = sc->sc_dma;
++
++ if (++idx == HIFN_D_SRC_RSIZE) {
++ dma->srcr[idx].l = htole32(HIFN_D_VALID |
++ HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
++ HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE,
++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++ idx = 0;
++ }
++ return (idx);
++}
++
++static int
++hifn_dmamap_load_src(struct hifn_softc *sc, struct hifn_command *cmd)
++{
++ struct hifn_dma *dma = sc->sc_dma;
++ struct hifn_operand *src = &cmd->src;
++ int idx, i;
++ u_int32_t last = 0;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ idx = dma->srci;
++ for (i = 0; i < src->nsegs; i++) {
++ if (i == src->nsegs - 1)
++ last = HIFN_D_LAST;
++
++ dma->srcr[idx].p = htole32(src->segs[i].ds_addr);
++ dma->srcr[idx].l = htole32(src->segs[i].ds_len |
++ HIFN_D_MASKDONEIRQ | last);
++ wmb();
++ dma->srcr[idx].l |= htole32(HIFN_D_VALID);
++ HIFN_SRCR_SYNC(sc, idx,
++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++
++ idx = hifn_dmamap_srcwrap(sc, idx);
++ }
++ dma->srci = idx;
++ dma->srcu += src->nsegs;
++ return (idx);
++}
++
++
++static int
++hifn_crypto(
++ struct hifn_softc *sc,
++ struct hifn_command *cmd,
++ struct cryptop *crp,
++ int hint)
++{
++ struct hifn_dma *dma = sc->sc_dma;
++ u_int32_t cmdlen, csr;
++ int cmdi, resi, err = 0;
++ unsigned long l_flags;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ /*
++ * need 1 cmd, and 1 res
++ *
++ * NB: check this first since it's easy.
++ */
++ HIFN_LOCK(sc);
++ if ((dma->cmdu + 1) > HIFN_D_CMD_RSIZE ||
++ (dma->resu + 1) > HIFN_D_RES_RSIZE) {
++#ifdef HIFN_DEBUG
++ if (hifn_debug) {
++ device_printf(sc->sc_dev,
++ "cmd/result exhaustion, cmdu %u resu %u\n",
++ dma->cmdu, dma->resu);
++ }
++#endif
++ hifnstats.hst_nomem_cr++;
++ sc->sc_needwakeup |= CRYPTO_SYMQ;
++ HIFN_UNLOCK(sc);
++ return (ERESTART);
++ }
++
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ if (pci_map_skb(sc, &cmd->src, cmd->src_skb)) {
++ hifnstats.hst_nomem_load++;
++ err = ENOMEM;
++ goto err_srcmap1;
++ }
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ if (pci_map_uio(sc, &cmd->src, cmd->src_io)) {
++ hifnstats.hst_nomem_load++;
++ err = ENOMEM;
++ goto err_srcmap1;
++ }
++ } else {
++ if (pci_map_buf(sc, &cmd->src, cmd->src_buf, crp->crp_ilen)) {
++ hifnstats.hst_nomem_load++;
++ err = ENOMEM;
++ goto err_srcmap1;
++ }
++ }
++
++ if (hifn_dmamap_aligned(&cmd->src)) {
++ cmd->sloplen = cmd->src_mapsize & 3;
++ cmd->dst = cmd->src;
++ } else {
++ if (crp->crp_flags & CRYPTO_F_IOV) {
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ err = EINVAL;
++ goto err_srcmap;
++ } else if (crp->crp_flags & CRYPTO_F_SKBUF) {
++#ifdef NOTYET
++ int totlen, len;
++ struct mbuf *m, *m0, *mlast;
++
++ KASSERT(cmd->dst_m == cmd->src_m,
++ ("hifn_crypto: dst_m initialized improperly"));
++ hifnstats.hst_unaligned++;
++ /*
++ * Source is not aligned on a longword boundary.
++ * Copy the data to insure alignment. If we fail
++ * to allocate mbufs or clusters while doing this
++ * we return ERESTART so the operation is requeued
++ * at the crypto later, but only if there are
++ * ops already posted to the hardware; otherwise we
++ * have no guarantee that we'll be re-entered.
++ */
++ totlen = cmd->src_mapsize;
++ if (cmd->src_m->m_flags & M_PKTHDR) {
++ len = MHLEN;
++ MGETHDR(m0, M_DONTWAIT, MT_DATA);
++ if (m0 && !m_dup_pkthdr(m0, cmd->src_m, M_DONTWAIT)) {
++ m_free(m0);
++ m0 = NULL;
++ }
++ } else {
++ len = MLEN;
++ MGET(m0, M_DONTWAIT, MT_DATA);
++ }
++ if (m0 == NULL) {
++ hifnstats.hst_nomem_mbuf++;
++ err = dma->cmdu ? ERESTART : ENOMEM;
++ goto err_srcmap;
++ }
++ if (totlen >= MINCLSIZE) {
++ MCLGET(m0, M_DONTWAIT);
++ if ((m0->m_flags & M_EXT) == 0) {
++ hifnstats.hst_nomem_mcl++;
++ err = dma->cmdu ? ERESTART : ENOMEM;
++ m_freem(m0);
++ goto err_srcmap;
++ }
++ len = MCLBYTES;
++ }
++ totlen -= len;
++ m0->m_pkthdr.len = m0->m_len = len;
++ mlast = m0;
++
++ while (totlen > 0) {
++ MGET(m, M_DONTWAIT, MT_DATA);
++ if (m == NULL) {
++ hifnstats.hst_nomem_mbuf++;
++ err = dma->cmdu ? ERESTART : ENOMEM;
++ m_freem(m0);
++ goto err_srcmap;
++ }
++ len = MLEN;
++ if (totlen >= MINCLSIZE) {
++ MCLGET(m, M_DONTWAIT);
++ if ((m->m_flags & M_EXT) == 0) {
++ hifnstats.hst_nomem_mcl++;
++ err = dma->cmdu ? ERESTART : ENOMEM;
++ mlast->m_next = m;
++ m_freem(m0);
++ goto err_srcmap;
++ }
++ len = MCLBYTES;
++ }
++
++ m->m_len = len;
++ m0->m_pkthdr.len += len;
++ totlen -= len;
++
++ mlast->m_next = m;
++ mlast = m;
++ }
++ cmd->dst_m = m0;
++#else
++ device_printf(sc->sc_dev,
++ "%s,%d: CRYPTO_F_SKBUF unaligned not implemented\n",
++ __FILE__, __LINE__);
++ err = EINVAL;
++ goto err_srcmap;
++#endif
++ } else {
++ device_printf(sc->sc_dev,
++ "%s,%d: unaligned contig buffers not implemented\n",
++ __FILE__, __LINE__);
++ err = EINVAL;
++ goto err_srcmap;
++ }
++ }
++
++ if (cmd->dst_map == NULL) {
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ if (pci_map_skb(sc, &cmd->dst, cmd->dst_skb)) {
++ hifnstats.hst_nomem_map++;
++ err = ENOMEM;
++ goto err_dstmap1;
++ }
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ if (pci_map_uio(sc, &cmd->dst, cmd->dst_io)) {
++ hifnstats.hst_nomem_load++;
++ err = ENOMEM;
++ goto err_dstmap1;
++ }
++ } else {
++ if (pci_map_buf(sc, &cmd->dst, cmd->dst_buf, crp->crp_ilen)) {
++ hifnstats.hst_nomem_load++;
++ err = ENOMEM;
++ goto err_dstmap1;
++ }
++ }
++ }
++
++#ifdef HIFN_DEBUG
++ if (hifn_debug) {
++ device_printf(sc->sc_dev,
++ "Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n",
++ READ_REG_1(sc, HIFN_1_DMA_CSR),
++ READ_REG_1(sc, HIFN_1_DMA_IER),
++ dma->cmdu, dma->srcu, dma->dstu, dma->resu,
++ cmd->src_nsegs, cmd->dst_nsegs);
++ }
++#endif
++
++#if 0
++ if (cmd->src_map == cmd->dst_map) {
++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++ BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
++ } else {
++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++ BUS_DMASYNC_PREWRITE);
++ bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
++ BUS_DMASYNC_PREREAD);
++ }
++#endif
++
++ /*
++ * need N src, and N dst
++ */
++ if ((dma->srcu + cmd->src_nsegs) > HIFN_D_SRC_RSIZE ||
++ (dma->dstu + cmd->dst_nsegs + 1) > HIFN_D_DST_RSIZE) {
++#ifdef HIFN_DEBUG
++ if (hifn_debug) {
++ device_printf(sc->sc_dev,
++ "src/dst exhaustion, srcu %u+%u dstu %u+%u\n",
++ dma->srcu, cmd->src_nsegs,
++ dma->dstu, cmd->dst_nsegs);
++ }
++#endif
++ hifnstats.hst_nomem_sd++;
++ err = ERESTART;
++ goto err_dstmap;
++ }
++
++ if (dma->cmdi == HIFN_D_CMD_RSIZE) {
++ dma->cmdi = 0;
++ dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++ wmb();
++ dma->cmdr[HIFN_D_CMD_RSIZE].l |= htole32(HIFN_D_VALID);
++ HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE,
++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++ }
++ cmdi = dma->cmdi++;
++ cmdlen = hifn_write_command(cmd, dma->command_bufs[cmdi]);
++ HIFN_CMD_SYNC(sc, cmdi, BUS_DMASYNC_PREWRITE);
++
++ /* .p for command/result already set */
++ dma->cmdr[cmdi].l = htole32(cmdlen | HIFN_D_LAST |
++ HIFN_D_MASKDONEIRQ);
++ wmb();
++ dma->cmdr[cmdi].l |= htole32(HIFN_D_VALID);
++ HIFN_CMDR_SYNC(sc, cmdi,
++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
++ dma->cmdu++;
++
++ /*
++ * We don't worry about missing an interrupt (which a "command wait"
++ * interrupt salvages us from), unless there is more than one command
++ * in the queue.
++ */
++ if (dma->cmdu > 1) {
++ sc->sc_dmaier |= HIFN_DMAIER_C_WAIT;
++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
++ }
++
++ hifnstats.hst_ipackets++;
++ hifnstats.hst_ibytes += cmd->src_mapsize;
++
++ hifn_dmamap_load_src(sc, cmd);
++
++ /*
++ * Unlike other descriptors, we don't mask done interrupt from
++ * result descriptor.
++ */
++#ifdef HIFN_DEBUG
++ if (hifn_debug)
++ device_printf(sc->sc_dev, "load res\n");
++#endif
++ if (dma->resi == HIFN_D_RES_RSIZE) {
++ dma->resi = 0;
++ dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ);
++ wmb();
++ dma->resr[HIFN_D_RES_RSIZE].l |= htole32(HIFN_D_VALID);
++ HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE,
++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++ }
++ resi = dma->resi++;
++ KASSERT(dma->hifn_commands[resi] == NULL,
++ ("hifn_crypto: command slot %u busy", resi));
++ dma->hifn_commands[resi] = cmd;
++ HIFN_RES_SYNC(sc, resi, BUS_DMASYNC_PREREAD);
++ if ((hint & CRYPTO_HINT_MORE) && sc->sc_curbatch < hifn_maxbatch) {
++ dma->resr[resi].l = htole32(HIFN_MAX_RESULT |
++ HIFN_D_LAST | HIFN_D_MASKDONEIRQ);
++ wmb();
++ dma->resr[resi].l |= htole32(HIFN_D_VALID);
++ sc->sc_curbatch++;
++ if (sc->sc_curbatch > hifnstats.hst_maxbatch)
++ hifnstats.hst_maxbatch = sc->sc_curbatch;
++ hifnstats.hst_totbatch++;
++ } else {
++ dma->resr[resi].l = htole32(HIFN_MAX_RESULT | HIFN_D_LAST);
++ wmb();
++ dma->resr[resi].l |= htole32(HIFN_D_VALID);
++ sc->sc_curbatch = 0;
++ }
++ HIFN_RESR_SYNC(sc, resi,
++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++ dma->resu++;
++
++ if (cmd->sloplen)
++ cmd->slopidx = resi;
++
++ hifn_dmamap_load_dst(sc, cmd);
++
++ csr = 0;
++ if (sc->sc_c_busy == 0) {
++ csr |= HIFN_DMACSR_C_CTRL_ENA;
++ sc->sc_c_busy = 1;
++ }
++ if (sc->sc_s_busy == 0) {
++ csr |= HIFN_DMACSR_S_CTRL_ENA;
++ sc->sc_s_busy = 1;
++ }
++ if (sc->sc_r_busy == 0) {
++ csr |= HIFN_DMACSR_R_CTRL_ENA;
++ sc->sc_r_busy = 1;
++ }
++ if (sc->sc_d_busy == 0) {
++ csr |= HIFN_DMACSR_D_CTRL_ENA;
++ sc->sc_d_busy = 1;
++ }
++ if (csr)
++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, csr);
++
++#ifdef HIFN_DEBUG
++ if (hifn_debug) {
++ device_printf(sc->sc_dev, "command: stat %8x ier %8x\n",
++ READ_REG_1(sc, HIFN_1_DMA_CSR),
++ READ_REG_1(sc, HIFN_1_DMA_IER));
++ }
++#endif
++
++ sc->sc_active = 5;
++ HIFN_UNLOCK(sc);
++ KASSERT(err == 0, ("hifn_crypto: success with error %u", err));
++ return (err); /* success */
++
++err_dstmap:
++ if (cmd->src_map != cmd->dst_map)
++ pci_unmap_buf(sc, &cmd->dst);
++err_dstmap1:
++err_srcmap:
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ if (cmd->src_skb != cmd->dst_skb)
++#ifdef NOTYET
++ m_freem(cmd->dst_m);
++#else
++ device_printf(sc->sc_dev,
++ "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n",
++ __FILE__, __LINE__);
++#endif
++ }
++ pci_unmap_buf(sc, &cmd->src);
++err_srcmap1:
++ HIFN_UNLOCK(sc);
++ return (err);
++}
++
++static void
++hifn_tick(unsigned long arg)
++{
++ struct hifn_softc *sc;
++ unsigned long l_flags;
++
++ if (arg >= HIFN_MAX_CHIPS)
++ return;
++ sc = hifn_chip_idx[arg];
++ if (!sc)
++ return;
++
++ HIFN_LOCK(sc);
++ if (sc->sc_active == 0) {
++ struct hifn_dma *dma = sc->sc_dma;
++ u_int32_t r = 0;
++
++ if (dma->cmdu == 0 && sc->sc_c_busy) {
++ sc->sc_c_busy = 0;
++ r |= HIFN_DMACSR_C_CTRL_DIS;
++ }
++ if (dma->srcu == 0 && sc->sc_s_busy) {
++ sc->sc_s_busy = 0;
++ r |= HIFN_DMACSR_S_CTRL_DIS;
++ }
++ if (dma->dstu == 0 && sc->sc_d_busy) {
++ sc->sc_d_busy = 0;
++ r |= HIFN_DMACSR_D_CTRL_DIS;
++ }
++ if (dma->resu == 0 && sc->sc_r_busy) {
++ sc->sc_r_busy = 0;
++ r |= HIFN_DMACSR_R_CTRL_DIS;
++ }
++ if (r)
++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, r);
++ } else
++ sc->sc_active--;
++ HIFN_UNLOCK(sc);
++ mod_timer(&sc->sc_tickto, jiffies + HZ);
++}
++
++static irqreturn_t
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++hifn_intr(int irq, void *arg)
++#else
++hifn_intr(int irq, void *arg, struct pt_regs *regs)
++#endif
++{
++ struct hifn_softc *sc = arg;
++ struct hifn_dma *dma;
++ u_int32_t dmacsr, restart;
++ int i, u;
++ unsigned long l_flags;
++
++ dmacsr = READ_REG_1(sc, HIFN_1_DMA_CSR);
++
++ /* Nothing in the DMA unit interrupted */
++ if ((dmacsr & sc->sc_dmaier) == 0)
++ return IRQ_NONE;
++
++ HIFN_LOCK(sc);
++
++ dma = sc->sc_dma;
++
++#ifdef HIFN_DEBUG
++ if (hifn_debug) {
++ device_printf(sc->sc_dev,
++ "irq: stat %08x ien %08x damier %08x i %d/%d/%d/%d k %d/%d/%d/%d u %d/%d/%d/%d\n",
++ dmacsr, READ_REG_1(sc, HIFN_1_DMA_IER), sc->sc_dmaier,
++ dma->cmdi, dma->srci, dma->dsti, dma->resi,
++ dma->cmdk, dma->srck, dma->dstk, dma->resk,
++ dma->cmdu, dma->srcu, dma->dstu, dma->resu);
++ }
++#endif
++
++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, dmacsr & sc->sc_dmaier);
++
++ if ((sc->sc_flags & HIFN_HAS_PUBLIC) &&
++ (dmacsr & HIFN_DMACSR_PUBDONE))
++ WRITE_REG_1(sc, HIFN_1_PUB_STATUS,
++ READ_REG_1(sc, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE);
++
++ restart = dmacsr & (HIFN_DMACSR_D_OVER | HIFN_DMACSR_R_OVER);
++ if (restart)
++ device_printf(sc->sc_dev, "overrun %x\n", dmacsr);
++
++ if (sc->sc_flags & HIFN_IS_7811) {
++ if (dmacsr & HIFN_DMACSR_ILLR)
++ device_printf(sc->sc_dev, "illegal read\n");
++ if (dmacsr & HIFN_DMACSR_ILLW)
++ device_printf(sc->sc_dev, "illegal write\n");
++ }
++
++ restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT |
++ HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT);
++ if (restart) {
++ device_printf(sc->sc_dev, "abort, resetting.\n");
++ hifnstats.hst_abort++;
++ hifn_abort(sc);
++ HIFN_UNLOCK(sc);
++ return IRQ_HANDLED;
++ }
++
++ if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) {
++ /*
++ * If no slots to process and we receive a "waiting on
++ * command" interrupt, we disable the "waiting on command"
++ * (by clearing it).
++ */
++ sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT;
++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
++ }
++
++ /* clear the rings */
++ i = dma->resk; u = dma->resu;
++ while (u != 0) {
++ HIFN_RESR_SYNC(sc, i,
++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++ if (dma->resr[i].l & htole32(HIFN_D_VALID)) {
++ HIFN_RESR_SYNC(sc, i,
++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++ break;
++ }
++
++ if (i != HIFN_D_RES_RSIZE) {
++ struct hifn_command *cmd;
++ u_int8_t *macbuf = NULL;
++
++ HIFN_RES_SYNC(sc, i, BUS_DMASYNC_POSTREAD);
++ cmd = dma->hifn_commands[i];
++ KASSERT(cmd != NULL,
++ ("hifn_intr: null command slot %u", i));
++ dma->hifn_commands[i] = NULL;
++
++ if (cmd->base_masks & HIFN_BASE_CMD_MAC) {
++ macbuf = dma->result_bufs[i];
++ macbuf += 12;
++ }
++
++ hifn_callback(sc, cmd, macbuf);
++ hifnstats.hst_opackets++;
++ u--;
++ }
++
++ if (++i == (HIFN_D_RES_RSIZE + 1))
++ i = 0;
++ }
++ dma->resk = i; dma->resu = u;
++
++ i = dma->srck; u = dma->srcu;
++ while (u != 0) {
++ if (i == HIFN_D_SRC_RSIZE)
++ i = 0;
++ HIFN_SRCR_SYNC(sc, i,
++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++ if (dma->srcr[i].l & htole32(HIFN_D_VALID)) {
++ HIFN_SRCR_SYNC(sc, i,
++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++ break;
++ }
++ i++, u--;
++ }
++ dma->srck = i; dma->srcu = u;
++
++ i = dma->cmdk; u = dma->cmdu;
++ while (u != 0) {
++ HIFN_CMDR_SYNC(sc, i,
++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++ if (dma->cmdr[i].l & htole32(HIFN_D_VALID)) {
++ HIFN_CMDR_SYNC(sc, i,
++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++ break;
++ }
++ if (i != HIFN_D_CMD_RSIZE) {
++ u--;
++ HIFN_CMD_SYNC(sc, i, BUS_DMASYNC_POSTWRITE);
++ }
++ if (++i == (HIFN_D_CMD_RSIZE + 1))
++ i = 0;
++ }
++ dma->cmdk = i; dma->cmdu = u;
++
++ HIFN_UNLOCK(sc);
++
++ if (sc->sc_needwakeup) { /* XXX check high watermark */
++ int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ);
++#ifdef HIFN_DEBUG
++ if (hifn_debug)
++ device_printf(sc->sc_dev,
++ "wakeup crypto (%x) u %d/%d/%d/%d\n",
++ sc->sc_needwakeup,
++ dma->cmdu, dma->srcu, dma->dstu, dma->resu);
++#endif
++ sc->sc_needwakeup &= ~wakeup;
++ crypto_unblock(sc->sc_cid, wakeup);
++ }
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * Allocate a new 'session' and return an encoded session id. 'sidp'
++ * contains our registration id, and should contain an encoded session
++ * id on successful allocation.
++ */
++static int
++hifn_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
++{
++ struct hifn_softc *sc = device_get_softc(dev);
++ struct cryptoini *c;
++ int mac = 0, cry = 0, sesn;
++ struct hifn_session *ses = NULL;
++ unsigned long l_flags;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ KASSERT(sc != NULL, ("hifn_newsession: null softc"));
++ if (sidp == NULL || cri == NULL || sc == NULL) {
++ DPRINTF("%s,%d: %s - EINVAL\n", __FILE__, __LINE__, __FUNCTION__);
++ return (EINVAL);
++ }
++
++ HIFN_LOCK(sc);
++ if (sc->sc_sessions == NULL) {
++ ses = sc->sc_sessions = (struct hifn_session *)kmalloc(sizeof(*ses),
++ SLAB_ATOMIC);
++ if (ses == NULL) {
++ HIFN_UNLOCK(sc);
++ return (ENOMEM);
++ }
++ sesn = 0;
++ sc->sc_nsessions = 1;
++ } else {
++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
++ if (!sc->sc_sessions[sesn].hs_used) {
++ ses = &sc->sc_sessions[sesn];
++ break;
++ }
++ }
++
++ if (ses == NULL) {
++ sesn = sc->sc_nsessions;
++ ses = (struct hifn_session *)kmalloc((sesn + 1) * sizeof(*ses),
++ SLAB_ATOMIC);
++ if (ses == NULL) {
++ HIFN_UNLOCK(sc);
++ return (ENOMEM);
++ }
++ bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses));
++ bzero(sc->sc_sessions, sesn * sizeof(*ses));
++ kfree(sc->sc_sessions);
++ sc->sc_sessions = ses;
++ ses = &sc->sc_sessions[sesn];
++ sc->sc_nsessions++;
++ }
++ }
++ HIFN_UNLOCK(sc);
++
++ bzero(ses, sizeof(*ses));
++ ses->hs_used = 1;
++
++ for (c = cri; c != NULL; c = c->cri_next) {
++ switch (c->cri_alg) {
++ case CRYPTO_MD5:
++ case CRYPTO_SHA1:
++ case CRYPTO_MD5_HMAC:
++ case CRYPTO_SHA1_HMAC:
++ if (mac) {
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ return (EINVAL);
++ }
++ mac = 1;
++ ses->hs_mlen = c->cri_mlen;
++ if (ses->hs_mlen == 0) {
++ switch (c->cri_alg) {
++ case CRYPTO_MD5:
++ case CRYPTO_MD5_HMAC:
++ ses->hs_mlen = 16;
++ break;
++ case CRYPTO_SHA1:
++ case CRYPTO_SHA1_HMAC:
++ ses->hs_mlen = 20;
++ break;
++ }
++ }
++ break;
++ case CRYPTO_DES_CBC:
++ case CRYPTO_3DES_CBC:
++ case CRYPTO_AES_CBC:
++ /* XXX this may read fewer, does it matter? */
++ read_random(ses->hs_iv,
++ c->cri_alg == CRYPTO_AES_CBC ?
++ HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH);
++ /*FALLTHROUGH*/
++ case CRYPTO_ARC4:
++ if (cry) {
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ return (EINVAL);
++ }
++ cry = 1;
++ break;
++ default:
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ return (EINVAL);
++ }
++ }
++ if (mac == 0 && cry == 0) {
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ return (EINVAL);
++ }
++
++ *sidp = HIFN_SID(device_get_unit(sc->sc_dev), sesn);
++
++ return (0);
++}
++
++/*
++ * Deallocate a session.
++ * XXX this routine should run a zero'd mac/encrypt key into context ram.
++ * XXX to blow away any keys already stored there.
++ */
++static int
++hifn_freesession(device_t dev, u_int64_t tid)
++{
++ struct hifn_softc *sc = device_get_softc(dev);
++ int session, error;
++ u_int32_t sid = CRYPTO_SESID2LID(tid);
++ unsigned long l_flags;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ KASSERT(sc != NULL, ("hifn_freesession: null softc"));
++ if (sc == NULL) {
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ return (EINVAL);
++ }
++
++ HIFN_LOCK(sc);
++ session = HIFN_SESSION(sid);
++ if (session < sc->sc_nsessions) {
++ bzero(&sc->sc_sessions[session], sizeof(struct hifn_session));
++ error = 0;
++ } else {
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ error = EINVAL;
++ }
++ HIFN_UNLOCK(sc);
++
++ return (error);
++}
++
++static int
++hifn_process(device_t dev, struct cryptop *crp, int hint)
++{
++ struct hifn_softc *sc = device_get_softc(dev);
++ struct hifn_command *cmd = NULL;
++ int session, err, ivlen;
++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ if (crp == NULL || crp->crp_callback == NULL) {
++ hifnstats.hst_invalid++;
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ return (EINVAL);
++ }
++ session = HIFN_SESSION(crp->crp_sid);
++
++ if (sc == NULL || session >= sc->sc_nsessions) {
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ err = EINVAL;
++ goto errout;
++ }
++
++ cmd = kmalloc(sizeof(struct hifn_command), SLAB_ATOMIC);
++ if (cmd == NULL) {
++ hifnstats.hst_nomem++;
++ err = ENOMEM;
++ goto errout;
++ }
++ memset(cmd, 0, sizeof(*cmd));
++
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ cmd->src_skb = (struct sk_buff *)crp->crp_buf;
++ cmd->dst_skb = (struct sk_buff *)crp->crp_buf;
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ cmd->src_io = (struct uio *)crp->crp_buf;
++ cmd->dst_io = (struct uio *)crp->crp_buf;
++ } else {
++ cmd->src_buf = crp->crp_buf;
++ cmd->dst_buf = crp->crp_buf;
++ }
++
++ crd1 = crp->crp_desc;
++ if (crd1 == NULL) {
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ err = EINVAL;
++ goto errout;
++ }
++ crd2 = crd1->crd_next;
++
++ if (crd2 == NULL) {
++ if (crd1->crd_alg == CRYPTO_MD5_HMAC ||
++ crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++ crd1->crd_alg == CRYPTO_SHA1 ||
++ crd1->crd_alg == CRYPTO_MD5) {
++ maccrd = crd1;
++ enccrd = NULL;
++ } else if (crd1->crd_alg == CRYPTO_DES_CBC ||
++ crd1->crd_alg == CRYPTO_3DES_CBC ||
++ crd1->crd_alg == CRYPTO_AES_CBC ||
++ crd1->crd_alg == CRYPTO_ARC4) {
++ if ((crd1->crd_flags & CRD_F_ENCRYPT) == 0)
++ cmd->base_masks |= HIFN_BASE_CMD_DECODE;
++ maccrd = NULL;
++ enccrd = crd1;
++ } else {
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ err = EINVAL;
++ goto errout;
++ }
++ } else {
++ if ((crd1->crd_alg == CRYPTO_MD5_HMAC ||
++ crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++ crd1->crd_alg == CRYPTO_MD5 ||
++ crd1->crd_alg == CRYPTO_SHA1) &&
++ (crd2->crd_alg == CRYPTO_DES_CBC ||
++ crd2->crd_alg == CRYPTO_3DES_CBC ||
++ crd2->crd_alg == CRYPTO_AES_CBC ||
++ crd2->crd_alg == CRYPTO_ARC4) &&
++ ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) {
++ cmd->base_masks = HIFN_BASE_CMD_DECODE;
++ maccrd = crd1;
++ enccrd = crd2;
++ } else if ((crd1->crd_alg == CRYPTO_DES_CBC ||
++ crd1->crd_alg == CRYPTO_ARC4 ||
++ crd1->crd_alg == CRYPTO_3DES_CBC ||
++ crd1->crd_alg == CRYPTO_AES_CBC) &&
++ (crd2->crd_alg == CRYPTO_MD5_HMAC ||
++ crd2->crd_alg == CRYPTO_SHA1_HMAC ||
++ crd2->crd_alg == CRYPTO_MD5 ||
++ crd2->crd_alg == CRYPTO_SHA1) &&
++ (crd1->crd_flags & CRD_F_ENCRYPT)) {
++ enccrd = crd1;
++ maccrd = crd2;
++ } else {
++ /*
++ * We cannot order the 7751 as requested
++ */
++ DPRINTF("%s,%d: %s %d,%d,%d - EINVAL\n",__FILE__,__LINE__,__FUNCTION__, crd1->crd_alg, crd2->crd_alg, crd1->crd_flags & CRD_F_ENCRYPT);
++ err = EINVAL;
++ goto errout;
++ }
++ }
++
++ if (enccrd) {
++ cmd->enccrd = enccrd;
++ cmd->base_masks |= HIFN_BASE_CMD_CRYPT;
++ switch (enccrd->crd_alg) {
++ case CRYPTO_ARC4:
++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_RC4;
++ break;
++ case CRYPTO_DES_CBC:
++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_DES |
++ HIFN_CRYPT_CMD_MODE_CBC |
++ HIFN_CRYPT_CMD_NEW_IV;
++ break;
++ case CRYPTO_3DES_CBC:
++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_3DES |
++ HIFN_CRYPT_CMD_MODE_CBC |
++ HIFN_CRYPT_CMD_NEW_IV;
++ break;
++ case CRYPTO_AES_CBC:
++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_AES |
++ HIFN_CRYPT_CMD_MODE_CBC |
++ HIFN_CRYPT_CMD_NEW_IV;
++ break;
++ default:
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ err = EINVAL;
++ goto errout;
++ }
++ if (enccrd->crd_alg != CRYPTO_ARC4) {
++ ivlen = ((enccrd->crd_alg == CRYPTO_AES_CBC) ?
++ HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH);
++ if (enccrd->crd_flags & CRD_F_ENCRYPT) {
++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++ bcopy(enccrd->crd_iv, cmd->iv, ivlen);
++ else
++ bcopy(sc->sc_sessions[session].hs_iv,
++ cmd->iv, ivlen);
++
++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT)
++ == 0) {
++ crypto_copyback(crp->crp_flags,
++ crp->crp_buf, enccrd->crd_inject,
++ ivlen, cmd->iv);
++ }
++ } else {
++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++ bcopy(enccrd->crd_iv, cmd->iv, ivlen);
++ else {
++ crypto_copydata(crp->crp_flags,
++ crp->crp_buf, enccrd->crd_inject,
++ ivlen, cmd->iv);
++ }
++ }
++ }
++
++ if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT)
++ cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY;
++ cmd->ck = enccrd->crd_key;
++ cmd->cklen = enccrd->crd_klen >> 3;
++ cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY;
++
++ /*
++ * Need to specify the size for the AES key in the masks.
++ */
++ if ((cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) ==
++ HIFN_CRYPT_CMD_ALG_AES) {
++ switch (cmd->cklen) {
++ case 16:
++ cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_128;
++ break;
++ case 24:
++ cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_192;
++ break;
++ case 32:
++ cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_256;
++ break;
++ default:
++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__);
++ err = EINVAL;
++ goto errout;
++ }
++ }
++ }
++
++ if (maccrd) {
++ cmd->maccrd = maccrd;
++ cmd->base_masks |= HIFN_BASE_CMD_MAC;
++
++ switch (maccrd->crd_alg) {
++ case CRYPTO_MD5:
++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 |
++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH |
++ HIFN_MAC_CMD_POS_IPSEC;
++ break;
++ case CRYPTO_MD5_HMAC:
++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 |
++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC |
++ HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC;
++ break;
++ case CRYPTO_SHA1:
++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 |
++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH |
++ HIFN_MAC_CMD_POS_IPSEC;
++ break;
++ case CRYPTO_SHA1_HMAC:
++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 |
++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC |
++ HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC;
++ break;
++ }
++
++ if (maccrd->crd_alg == CRYPTO_SHA1_HMAC ||
++ maccrd->crd_alg == CRYPTO_MD5_HMAC) {
++ cmd->mac_masks |= HIFN_MAC_CMD_NEW_KEY;
++ bcopy(maccrd->crd_key, cmd->mac, maccrd->crd_klen >> 3);
++ bzero(cmd->mac + (maccrd->crd_klen >> 3),
++ HIFN_MAC_KEY_LENGTH - (maccrd->crd_klen >> 3));
++ }
++ }
++
++ cmd->crp = crp;
++ cmd->session_num = session;
++ cmd->softc = sc;
++
++ err = hifn_crypto(sc, cmd, crp, hint);
++ if (!err) {
++ return 0;
++ } else if (err == ERESTART) {
++ /*
++ * There weren't enough resources to dispatch the request
++ * to the part. Notify the caller so they'll requeue this
++ * request and resubmit it again soon.
++ */
++#ifdef HIFN_DEBUG
++ if (hifn_debug)
++ device_printf(sc->sc_dev, "requeue request\n");
++#endif
++ kfree(cmd);
++ sc->sc_needwakeup |= CRYPTO_SYMQ;
++ return (err);
++ }
++
++errout:
++ if (cmd != NULL)
++ kfree(cmd);
++ if (err == EINVAL)
++ hifnstats.hst_invalid++;
++ else
++ hifnstats.hst_nomem++;
++ crp->crp_etype = err;
++ crypto_done(crp);
++ return (err);
++}
++
++static void
++hifn_abort(struct hifn_softc *sc)
++{
++ struct hifn_dma *dma = sc->sc_dma;
++ struct hifn_command *cmd;
++ struct cryptop *crp;
++ int i, u;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ i = dma->resk; u = dma->resu;
++ while (u != 0) {
++ cmd = dma->hifn_commands[i];
++ KASSERT(cmd != NULL, ("hifn_abort: null command slot %u", i));
++ dma->hifn_commands[i] = NULL;
++ crp = cmd->crp;
++
++ if ((dma->resr[i].l & htole32(HIFN_D_VALID)) == 0) {
++ /* Salvage what we can. */
++ u_int8_t *macbuf;
++
++ if (cmd->base_masks & HIFN_BASE_CMD_MAC) {
++ macbuf = dma->result_bufs[i];
++ macbuf += 12;
++ } else
++ macbuf = NULL;
++ hifnstats.hst_opackets++;
++ hifn_callback(sc, cmd, macbuf);
++ } else {
++#if 0
++ if (cmd->src_map == cmd->dst_map) {
++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
++ } else {
++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++ BUS_DMASYNC_POSTWRITE);
++ bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
++ BUS_DMASYNC_POSTREAD);
++ }
++#endif
++
++ if (cmd->src_skb != cmd->dst_skb) {
++#ifdef NOTYET
++ m_freem(cmd->src_m);
++ crp->crp_buf = (caddr_t)cmd->dst_m;
++#else
++ device_printf(sc->sc_dev,
++ "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n",
++ __FILE__, __LINE__);
++#endif
++ }
++
++ /* non-shared buffers cannot be restarted */
++ if (cmd->src_map != cmd->dst_map) {
++ /*
++ * XXX should be EAGAIN, delayed until
++ * after the reset.
++ */
++ crp->crp_etype = ENOMEM;
++ pci_unmap_buf(sc, &cmd->dst);
++ } else
++ crp->crp_etype = ENOMEM;
++
++ pci_unmap_buf(sc, &cmd->src);
++
++ kfree(cmd);
++ if (crp->crp_etype != EAGAIN)
++ crypto_done(crp);
++ }
++
++ if (++i == HIFN_D_RES_RSIZE)
++ i = 0;
++ u--;
++ }
++ dma->resk = i; dma->resu = u;
++
++ hifn_reset_board(sc, 1);
++ hifn_init_dma(sc);
++ hifn_init_pci_registers(sc);
++}
++
++static void
++hifn_callback(struct hifn_softc *sc, struct hifn_command *cmd, u_int8_t *macbuf)
++{
++ struct hifn_dma *dma = sc->sc_dma;
++ struct cryptop *crp = cmd->crp;
++ struct cryptodesc *crd;
++ int i, u, ivlen;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++#if 0
++ if (cmd->src_map == cmd->dst_map) {
++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
++ } else {
++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
++ BUS_DMASYNC_POSTWRITE);
++ bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
++ BUS_DMASYNC_POSTREAD);
++ }
++#endif
++
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ if (cmd->src_skb != cmd->dst_skb) {
++#ifdef NOTYET
++ crp->crp_buf = (caddr_t)cmd->dst_m;
++ totlen = cmd->src_mapsize;
++ for (m = cmd->dst_m; m != NULL; m = m->m_next) {
++ if (totlen < m->m_len) {
++ m->m_len = totlen;
++ totlen = 0;
++ } else
++ totlen -= m->m_len;
++ }
++ cmd->dst_m->m_pkthdr.len = cmd->src_m->m_pkthdr.len;
++ m_freem(cmd->src_m);
++#else
++ device_printf(sc->sc_dev,
++ "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n",
++ __FILE__, __LINE__);
++#endif
++ }
++ }
++
++ if (cmd->sloplen != 0) {
++ crypto_copyback(crp->crp_flags, crp->crp_buf,
++ cmd->src_mapsize - cmd->sloplen, cmd->sloplen,
++ (caddr_t)&dma->slop[cmd->slopidx]);
++ }
++
++ i = dma->dstk; u = dma->dstu;
++ while (u != 0) {
++ if (i == HIFN_D_DST_RSIZE)
++ i = 0;
++#if 0
++ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++#endif
++ if (dma->dstr[i].l & htole32(HIFN_D_VALID)) {
++#if 0
++ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
++#endif
++ break;
++ }
++ i++, u--;
++ }
++ dma->dstk = i; dma->dstu = u;
++
++ hifnstats.hst_obytes += cmd->dst_mapsize;
++
++ if ((cmd->base_masks & (HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE)) ==
++ HIFN_BASE_CMD_CRYPT) {
++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
++ if (crd->crd_alg != CRYPTO_DES_CBC &&
++ crd->crd_alg != CRYPTO_3DES_CBC &&
++ crd->crd_alg != CRYPTO_AES_CBC)
++ continue;
++ ivlen = ((crd->crd_alg == CRYPTO_AES_CBC) ?
++ HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH);
++ crypto_copydata(crp->crp_flags, crp->crp_buf,
++ crd->crd_skip + crd->crd_len - ivlen, ivlen,
++ cmd->softc->sc_sessions[cmd->session_num].hs_iv);
++ break;
++ }
++ }
++
++ if (macbuf != NULL) {
++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
++ int len;
++
++ if (crd->crd_alg != CRYPTO_MD5 &&
++ crd->crd_alg != CRYPTO_SHA1 &&
++ crd->crd_alg != CRYPTO_MD5_HMAC &&
++ crd->crd_alg != CRYPTO_SHA1_HMAC) {
++ continue;
++ }
++ len = cmd->softc->sc_sessions[cmd->session_num].hs_mlen;
++ crypto_copyback(crp->crp_flags, crp->crp_buf,
++ crd->crd_inject, len, macbuf);
++ break;
++ }
++ }
++
++ if (cmd->src_map != cmd->dst_map)
++ pci_unmap_buf(sc, &cmd->dst);
++ pci_unmap_buf(sc, &cmd->src);
++ kfree(cmd);
++ crypto_done(crp);
++}
++
++/*
++ * 7811 PB3 rev/2 parts lock-up on burst writes to Group 0
++ * and Group 1 registers; avoid conditions that could create
++ * burst writes by doing a read in between the writes.
++ *
++ * NB: The read we interpose is always to the same register;
++ * we do this because reading from an arbitrary (e.g. last)
++ * register may not always work.
++ */
++static void
++hifn_write_reg_0(struct hifn_softc *sc, bus_size_t reg, u_int32_t val)
++{
++ if (sc->sc_flags & HIFN_IS_7811) {
++ if (sc->sc_bar0_lastreg == reg - 4)
++ readl(sc->sc_bar0 + HIFN_0_PUCNFG);
++ sc->sc_bar0_lastreg = reg;
++ }
++ writel(val, sc->sc_bar0 + reg);
++}
++
++static void
++hifn_write_reg_1(struct hifn_softc *sc, bus_size_t reg, u_int32_t val)
++{
++ if (sc->sc_flags & HIFN_IS_7811) {
++ if (sc->sc_bar1_lastreg == reg - 4)
++ readl(sc->sc_bar1 + HIFN_1_REVID);
++ sc->sc_bar1_lastreg = reg;
++ }
++ writel(val, sc->sc_bar1 + reg);
++}
++
++
++static struct pci_device_id hifn_pci_tbl[] = {
++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7951,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7955,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7956,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++ { PCI_VENDOR_NETSEC, PCI_PRODUCT_NETSEC_7751,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++ { PCI_VENDOR_INVERTEX, PCI_PRODUCT_INVERTEX_AEON,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7811,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++ /*
++ * Other vendors share this PCI ID as well, such as
++ * http://www.powercrypt.com, and obviously they also
++ * use the same key.
++ */
++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7751,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++ { 0, 0, 0, 0, 0, 0, }
++};
++MODULE_DEVICE_TABLE(pci, hifn_pci_tbl);
++
++static struct pci_driver hifn_driver = {
++ .name = "hifn",
++ .id_table = hifn_pci_tbl,
++ .probe = hifn_probe,
++ .remove = hifn_remove,
++ /* add PM stuff here one day */
++};
++
++static int __init hifn_init (void)
++{
++ struct hifn_softc *sc = NULL;
++ int rc;
++
++ DPRINTF("%s(%p)\n", __FUNCTION__, hifn_init);
++
++ rc = pci_register_driver(&hifn_driver);
++ pci_register_driver_compat(&hifn_driver, rc);
++
++ return rc;
++}
++
++static void __exit hifn_exit (void)
++{
++ pci_unregister_driver(&hifn_driver);
++}
++
++module_init(hifn_init);
++module_exit(hifn_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
++MODULE_DESCRIPTION("OCF driver for hifn PCI crypto devices");
+diff -Nur linux-2.6.36.orig/crypto/ocf/hifn/hifn7751reg.h linux-2.6.36/crypto/ocf/hifn/hifn7751reg.h
+--- linux-2.6.36.orig/crypto/ocf/hifn/hifn7751reg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/hifn/hifn7751reg.h 2010-11-09 20:28:04.792495416 +0100
+@@ -0,0 +1,540 @@
++/* $FreeBSD: src/sys/dev/hifn/hifn7751reg.h,v 1.7 2007/03/21 03:42:49 sam Exp $ */
++/* $OpenBSD: hifn7751reg.h,v 1.35 2002/04/08 17:49:42 jason Exp $ */
++
++/*-
++ * Invertex AEON / Hifn 7751 driver
++ * Copyright (c) 1999 Invertex Inc. All rights reserved.
++ * Copyright (c) 1999 Theo de Raadt
++ * Copyright (c) 2000-2001 Network Security Technologies, Inc.
++ * http://www.netsec.net
++ *
++ * Please send any comments, feedback, bug-fixes, or feature requests to
++ * software@invertex.com.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++ */
++#ifndef __HIFN_H__
++#define __HIFN_H__
++
++/*
++ * Some PCI configuration space offset defines. The names were made
++ * identical to the names used by the Linux kernel.
++ */
++#define HIFN_BAR0 PCIR_BAR(0) /* PUC register map */
++#define HIFN_BAR1 PCIR_BAR(1) /* DMA register map */
++#define HIFN_TRDY_TIMEOUT 0x40
++#define HIFN_RETRY_TIMEOUT 0x41
++
++/*
++ * PCI vendor and device identifiers
++ * (the names are preserved from their OpenBSD source).
++ */
++#define PCI_VENDOR_HIFN 0x13a3 /* Hifn */
++#define PCI_PRODUCT_HIFN_7751 0x0005 /* 7751 */
++#define PCI_PRODUCT_HIFN_6500 0x0006 /* 6500 */
++#define PCI_PRODUCT_HIFN_7811 0x0007 /* 7811 */
++#define PCI_PRODUCT_HIFN_7855 0x001f /* 7855 */
++#define PCI_PRODUCT_HIFN_7951 0x0012 /* 7951 */
++#define PCI_PRODUCT_HIFN_7955 0x0020 /* 7954/7955 */
++#define PCI_PRODUCT_HIFN_7956 0x001d /* 7956 */
++
++#define PCI_VENDOR_INVERTEX 0x14e1 /* Invertex */
++#define PCI_PRODUCT_INVERTEX_AEON 0x0005 /* AEON */
++
++#define PCI_VENDOR_NETSEC 0x1660 /* NetSec */
++#define PCI_PRODUCT_NETSEC_7751 0x7751 /* 7751 */
++
++/*
++ * The values below should multiple of 4 -- and be large enough to handle
++ * any command the driver implements.
++ *
++ * MAX_COMMAND = base command + mac command + encrypt command +
++ * mac-key + rc4-key
++ * MAX_RESULT = base result + mac result + mac + encrypt result
++ *
++ *
++ */
++#define HIFN_MAX_COMMAND (8 + 8 + 8 + 64 + 260)
++#define HIFN_MAX_RESULT (8 + 4 + 20 + 4)
++
++/*
++ * hifn_desc_t
++ *
++ * Holds an individual descriptor for any of the rings.
++ */
++typedef struct hifn_desc {
++ volatile u_int32_t l; /* length and status bits */
++ volatile u_int32_t p;
++} hifn_desc_t;
++
++/*
++ * Masks for the "length" field of struct hifn_desc.
++ */
++#define HIFN_D_LENGTH 0x0000ffff /* length bit mask */
++#define HIFN_D_MASKDONEIRQ 0x02000000 /* mask the done interrupt */
++#define HIFN_D_DESTOVER 0x04000000 /* destination overflow */
++#define HIFN_D_OVER 0x08000000 /* overflow */
++#define HIFN_D_LAST 0x20000000 /* last descriptor in chain */
++#define HIFN_D_JUMP 0x40000000 /* jump descriptor */
++#define HIFN_D_VALID 0x80000000 /* valid bit */
++
++
++/*
++ * Processing Unit Registers (offset from BASEREG0)
++ */
++#define HIFN_0_PUDATA 0x00 /* Processing Unit Data */
++#define HIFN_0_PUCTRL 0x04 /* Processing Unit Control */
++#define HIFN_0_PUISR 0x08 /* Processing Unit Interrupt Status */
++#define HIFN_0_PUCNFG 0x0c /* Processing Unit Configuration */
++#define HIFN_0_PUIER 0x10 /* Processing Unit Interrupt Enable */
++#define HIFN_0_PUSTAT 0x14 /* Processing Unit Status/Chip ID */
++#define HIFN_0_FIFOSTAT 0x18 /* FIFO Status */
++#define HIFN_0_FIFOCNFG 0x1c /* FIFO Configuration */
++#define HIFN_0_PUCTRL2 0x28 /* Processing Unit Control (2nd map) */
++#define HIFN_0_MUTE1 0x80
++#define HIFN_0_MUTE2 0x90
++#define HIFN_0_SPACESIZE 0x100 /* Register space size */
++
++/* Processing Unit Control Register (HIFN_0_PUCTRL) */
++#define HIFN_PUCTRL_CLRSRCFIFO 0x0010 /* clear source fifo */
++#define HIFN_PUCTRL_STOP 0x0008 /* stop pu */
++#define HIFN_PUCTRL_LOCKRAM 0x0004 /* lock ram */
++#define HIFN_PUCTRL_DMAENA 0x0002 /* enable dma */
++#define HIFN_PUCTRL_RESET 0x0001 /* Reset processing unit */
++
++/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */
++#define HIFN_PUISR_CMDINVAL 0x8000 /* Invalid command interrupt */
++#define HIFN_PUISR_DATAERR 0x4000 /* Data error interrupt */
++#define HIFN_PUISR_SRCFIFO 0x2000 /* Source FIFO ready interrupt */
++#define HIFN_PUISR_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */
++#define HIFN_PUISR_DSTOVER 0x0200 /* Destination overrun interrupt */
++#define HIFN_PUISR_SRCCMD 0x0080 /* Source command interrupt */
++#define HIFN_PUISR_SRCCTX 0x0040 /* Source context interrupt */
++#define HIFN_PUISR_SRCDATA 0x0020 /* Source data interrupt */
++#define HIFN_PUISR_DSTDATA 0x0010 /* Destination data interrupt */
++#define HIFN_PUISR_DSTRESULT 0x0004 /* Destination result interrupt */
++
++/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */
++#define HIFN_PUCNFG_DRAMMASK 0xe000 /* DRAM size mask */
++#define HIFN_PUCNFG_DSZ_256K 0x0000 /* 256k dram */
++#define HIFN_PUCNFG_DSZ_512K 0x2000 /* 512k dram */
++#define HIFN_PUCNFG_DSZ_1M 0x4000 /* 1m dram */
++#define HIFN_PUCNFG_DSZ_2M 0x6000 /* 2m dram */
++#define HIFN_PUCNFG_DSZ_4M 0x8000 /* 4m dram */
++#define HIFN_PUCNFG_DSZ_8M 0xa000 /* 8m dram */
++#define HIFN_PUNCFG_DSZ_16M 0xc000 /* 16m dram */
++#define HIFN_PUCNFG_DSZ_32M 0xe000 /* 32m dram */
++#define HIFN_PUCNFG_DRAMREFRESH 0x1800 /* DRAM refresh rate mask */
++#define HIFN_PUCNFG_DRFR_512 0x0000 /* 512 divisor of ECLK */
++#define HIFN_PUCNFG_DRFR_256 0x0800 /* 256 divisor of ECLK */
++#define HIFN_PUCNFG_DRFR_128 0x1000 /* 128 divisor of ECLK */
++#define HIFN_PUCNFG_TCALLPHASES 0x0200 /* your guess is as good as mine... */
++#define HIFN_PUCNFG_TCDRVTOTEM 0x0100 /* your guess is as good as mine... */
++#define HIFN_PUCNFG_BIGENDIAN 0x0080 /* DMA big endian mode */
++#define HIFN_PUCNFG_BUS32 0x0040 /* Bus width 32bits */
++#define HIFN_PUCNFG_BUS16 0x0000 /* Bus width 16 bits */
++#define HIFN_PUCNFG_CHIPID 0x0020 /* Allow chipid from PUSTAT */
++#define HIFN_PUCNFG_DRAM 0x0010 /* Context RAM is DRAM */
++#define HIFN_PUCNFG_SRAM 0x0000 /* Context RAM is SRAM */
++#define HIFN_PUCNFG_COMPSING 0x0004 /* Enable single compression context */
++#define HIFN_PUCNFG_ENCCNFG 0x0002 /* Encryption configuration */
++
++/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */
++#define HIFN_PUIER_CMDINVAL 0x8000 /* Invalid command interrupt */
++#define HIFN_PUIER_DATAERR 0x4000 /* Data error interrupt */
++#define HIFN_PUIER_SRCFIFO 0x2000 /* Source FIFO ready interrupt */
++#define HIFN_PUIER_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */
++#define HIFN_PUIER_DSTOVER 0x0200 /* Destination overrun interrupt */
++#define HIFN_PUIER_SRCCMD 0x0080 /* Source command interrupt */
++#define HIFN_PUIER_SRCCTX 0x0040 /* Source context interrupt */
++#define HIFN_PUIER_SRCDATA 0x0020 /* Source data interrupt */
++#define HIFN_PUIER_DSTDATA 0x0010 /* Destination data interrupt */
++#define HIFN_PUIER_DSTRESULT 0x0004 /* Destination result interrupt */
++
++/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */
++#define HIFN_PUSTAT_CMDINVAL 0x8000 /* Invalid command interrupt */
++#define HIFN_PUSTAT_DATAERR 0x4000 /* Data error interrupt */
++#define HIFN_PUSTAT_SRCFIFO 0x2000 /* Source FIFO ready interrupt */
++#define HIFN_PUSTAT_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */
++#define HIFN_PUSTAT_DSTOVER 0x0200 /* Destination overrun interrupt */
++#define HIFN_PUSTAT_SRCCMD 0x0080 /* Source command interrupt */
++#define HIFN_PUSTAT_SRCCTX 0x0040 /* Source context interrupt */
++#define HIFN_PUSTAT_SRCDATA 0x0020 /* Source data interrupt */
++#define HIFN_PUSTAT_DSTDATA 0x0010 /* Destination data interrupt */
++#define HIFN_PUSTAT_DSTRESULT 0x0004 /* Destination result interrupt */
++#define HIFN_PUSTAT_CHIPREV 0x00ff /* Chip revision mask */
++#define HIFN_PUSTAT_CHIPENA 0xff00 /* Chip enabled mask */
++#define HIFN_PUSTAT_ENA_2 0x1100 /* Level 2 enabled */
++#define HIFN_PUSTAT_ENA_1 0x1000 /* Level 1 enabled */
++#define HIFN_PUSTAT_ENA_0 0x3000 /* Level 0 enabled */
++#define HIFN_PUSTAT_REV_2 0x0020 /* 7751 PT6/2 */
++#define HIFN_PUSTAT_REV_3 0x0030 /* 7751 PT6/3 */
++
++/* FIFO Status Register (HIFN_0_FIFOSTAT) */
++#define HIFN_FIFOSTAT_SRC 0x7f00 /* Source FIFO available */
++#define HIFN_FIFOSTAT_DST 0x007f /* Destination FIFO available */
++
++/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */
++#define HIFN_FIFOCNFG_THRESHOLD 0x0400 /* must be written as this value */
++
++/*
++ * DMA Interface Registers (offset from BASEREG1)
++ */
++#define HIFN_1_DMA_CRAR 0x0c /* DMA Command Ring Address */
++#define HIFN_1_DMA_SRAR 0x1c /* DMA Source Ring Address */
++#define HIFN_1_DMA_RRAR 0x2c /* DMA Result Ring Address */
++#define HIFN_1_DMA_DRAR 0x3c /* DMA Destination Ring Address */
++#define HIFN_1_DMA_CSR 0x40 /* DMA Status and Control */
++#define HIFN_1_DMA_IER 0x44 /* DMA Interrupt Enable */
++#define HIFN_1_DMA_CNFG 0x48 /* DMA Configuration */
++#define HIFN_1_PLL 0x4c /* 7955/7956: PLL config */
++#define HIFN_1_7811_RNGENA 0x60 /* 7811: rng enable */
++#define HIFN_1_7811_RNGCFG 0x64 /* 7811: rng config */
++#define HIFN_1_7811_RNGDAT 0x68 /* 7811: rng data */
++#define HIFN_1_7811_RNGSTS 0x6c /* 7811: rng status */
++#define HIFN_1_DMA_CNFG2 0x6c /* 7955/7956: dma config #2 */
++#define HIFN_1_7811_MIPSRST 0x94 /* 7811: MIPS reset */
++#define HIFN_1_REVID 0x98 /* Revision ID */
++
++#define HIFN_1_PUB_RESET 0x204 /* Public/RNG Reset */
++#define HIFN_1_PUB_BASE 0x300 /* Public Base Address */
++#define HIFN_1_PUB_OPLEN 0x304 /* 7951-compat Public Operand Length */
++#define HIFN_1_PUB_OP 0x308 /* 7951-compat Public Operand */
++#define HIFN_1_PUB_STATUS 0x30c /* 7951-compat Public Status */
++#define HIFN_1_PUB_IEN 0x310 /* Public Interrupt enable */
++#define HIFN_1_RNG_CONFIG 0x314 /* RNG config */
++#define HIFN_1_RNG_DATA 0x318 /* RNG data */
++#define HIFN_1_PUB_MODE 0x320 /* PK mode */
++#define HIFN_1_PUB_FIFO_OPLEN 0x380 /* first element of oplen fifo */
++#define HIFN_1_PUB_FIFO_OP 0x384 /* first element of op fifo */
++#define HIFN_1_PUB_MEM 0x400 /* start of Public key memory */
++#define HIFN_1_PUB_MEMEND 0xbff /* end of Public key memory */
++
++/* DMA Status and Control Register (HIFN_1_DMA_CSR) */
++#define HIFN_DMACSR_D_CTRLMASK 0xc0000000 /* Destinition Ring Control */
++#define HIFN_DMACSR_D_CTRL_NOP 0x00000000 /* Dest. Control: no-op */
++#define HIFN_DMACSR_D_CTRL_DIS 0x40000000 /* Dest. Control: disable */
++#define HIFN_DMACSR_D_CTRL_ENA 0x80000000 /* Dest. Control: enable */
++#define HIFN_DMACSR_D_ABORT 0x20000000 /* Destinition Ring PCIAbort */
++#define HIFN_DMACSR_D_DONE 0x10000000 /* Destinition Ring Done */
++#define HIFN_DMACSR_D_LAST 0x08000000 /* Destinition Ring Last */
++#define HIFN_DMACSR_D_WAIT 0x04000000 /* Destinition Ring Waiting */
++#define HIFN_DMACSR_D_OVER 0x02000000 /* Destinition Ring Overflow */
++#define HIFN_DMACSR_R_CTRL 0x00c00000 /* Result Ring Control */
++#define HIFN_DMACSR_R_CTRL_NOP 0x00000000 /* Result Control: no-op */
++#define HIFN_DMACSR_R_CTRL_DIS 0x00400000 /* Result Control: disable */
++#define HIFN_DMACSR_R_CTRL_ENA 0x00800000 /* Result Control: enable */
++#define HIFN_DMACSR_R_ABORT 0x00200000 /* Result Ring PCI Abort */
++#define HIFN_DMACSR_R_DONE 0x00100000 /* Result Ring Done */
++#define HIFN_DMACSR_R_LAST 0x00080000 /* Result Ring Last */
++#define HIFN_DMACSR_R_WAIT 0x00040000 /* Result Ring Waiting */
++#define HIFN_DMACSR_R_OVER 0x00020000 /* Result Ring Overflow */
++#define HIFN_DMACSR_S_CTRL 0x0000c000 /* Source Ring Control */
++#define HIFN_DMACSR_S_CTRL_NOP 0x00000000 /* Source Control: no-op */
++#define HIFN_DMACSR_S_CTRL_DIS 0x00004000 /* Source Control: disable */
++#define HIFN_DMACSR_S_CTRL_ENA 0x00008000 /* Source Control: enable */
++#define HIFN_DMACSR_S_ABORT 0x00002000 /* Source Ring PCI Abort */
++#define HIFN_DMACSR_S_DONE 0x00001000 /* Source Ring Done */
++#define HIFN_DMACSR_S_LAST 0x00000800 /* Source Ring Last */
++#define HIFN_DMACSR_S_WAIT 0x00000400 /* Source Ring Waiting */
++#define HIFN_DMACSR_ILLW 0x00000200 /* Illegal write (7811 only) */
++#define HIFN_DMACSR_ILLR 0x00000100 /* Illegal read (7811 only) */
++#define HIFN_DMACSR_C_CTRL 0x000000c0 /* Command Ring Control */
++#define HIFN_DMACSR_C_CTRL_NOP 0x00000000 /* Command Control: no-op */
++#define HIFN_DMACSR_C_CTRL_DIS 0x00000040 /* Command Control: disable */
++#define HIFN_DMACSR_C_CTRL_ENA 0x00000080 /* Command Control: enable */
++#define HIFN_DMACSR_C_ABORT 0x00000020 /* Command Ring PCI Abort */
++#define HIFN_DMACSR_C_DONE 0x00000010 /* Command Ring Done */
++#define HIFN_DMACSR_C_LAST 0x00000008 /* Command Ring Last */
++#define HIFN_DMACSR_C_WAIT 0x00000004 /* Command Ring Waiting */
++#define HIFN_DMACSR_PUBDONE 0x00000002 /* Public op done (7951 only) */
++#define HIFN_DMACSR_ENGINE 0x00000001 /* Command Ring Engine IRQ */
++
++/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */
++#define HIFN_DMAIER_D_ABORT 0x20000000 /* Destination Ring PCIAbort */
++#define HIFN_DMAIER_D_DONE 0x10000000 /* Destination Ring Done */
++#define HIFN_DMAIER_D_LAST 0x08000000 /* Destination Ring Last */
++#define HIFN_DMAIER_D_WAIT 0x04000000 /* Destination Ring Waiting */
++#define HIFN_DMAIER_D_OVER 0x02000000 /* Destination Ring Overflow */
++#define HIFN_DMAIER_R_ABORT 0x00200000 /* Result Ring PCI Abort */
++#define HIFN_DMAIER_R_DONE 0x00100000 /* Result Ring Done */
++#define HIFN_DMAIER_R_LAST 0x00080000 /* Result Ring Last */
++#define HIFN_DMAIER_R_WAIT 0x00040000 /* Result Ring Waiting */
++#define HIFN_DMAIER_R_OVER 0x00020000 /* Result Ring Overflow */
++#define HIFN_DMAIER_S_ABORT 0x00002000 /* Source Ring PCI Abort */
++#define HIFN_DMAIER_S_DONE 0x00001000 /* Source Ring Done */
++#define HIFN_DMAIER_S_LAST 0x00000800 /* Source Ring Last */
++#define HIFN_DMAIER_S_WAIT 0x00000400 /* Source Ring Waiting */
++#define HIFN_DMAIER_ILLW 0x00000200 /* Illegal write (7811 only) */
++#define HIFN_DMAIER_ILLR 0x00000100 /* Illegal read (7811 only) */
++#define HIFN_DMAIER_C_ABORT 0x00000020 /* Command Ring PCI Abort */
++#define HIFN_DMAIER_C_DONE 0x00000010 /* Command Ring Done */
++#define HIFN_DMAIER_C_LAST 0x00000008 /* Command Ring Last */
++#define HIFN_DMAIER_C_WAIT 0x00000004 /* Command Ring Waiting */
++#define HIFN_DMAIER_PUBDONE 0x00000002 /* public op done (7951 only) */
++#define HIFN_DMAIER_ENGINE 0x00000001 /* Engine IRQ */
++
++/* DMA Configuration Register (HIFN_1_DMA_CNFG) */
++#define HIFN_DMACNFG_BIGENDIAN 0x10000000 /* big endian mode */
++#define HIFN_DMACNFG_POLLFREQ 0x00ff0000 /* Poll frequency mask */
++#define HIFN_DMACNFG_UNLOCK 0x00000800
++#define HIFN_DMACNFG_POLLINVAL 0x00000700 /* Invalid Poll Scalar */
++#define HIFN_DMACNFG_LAST 0x00000010 /* Host control LAST bit */
++#define HIFN_DMACNFG_MODE 0x00000004 /* DMA mode */
++#define HIFN_DMACNFG_DMARESET 0x00000002 /* DMA Reset # */
++#define HIFN_DMACNFG_MSTRESET 0x00000001 /* Master Reset # */
++
++/* DMA Configuration Register (HIFN_1_DMA_CNFG2) */
++#define HIFN_DMACNFG2_PKSWAP32 (1 << 19) /* swap the OPLEN/OP reg */
++#define HIFN_DMACNFG2_PKSWAP8 (1 << 18) /* swap the bits of OPLEN/OP */
++#define HIFN_DMACNFG2_BAR0_SWAP32 (1<<17) /* swap the bytes of BAR0 */
++#define HIFN_DMACNFG2_BAR1_SWAP8 (1<<16) /* swap the bits of BAR0 */
++#define HIFN_DMACNFG2_INIT_WRITE_BURST_SHIFT 12
++#define HIFN_DMACNFG2_INIT_READ_BURST_SHIFT 8
++#define HIFN_DMACNFG2_TGT_WRITE_BURST_SHIFT 4
++#define HIFN_DMACNFG2_TGT_READ_BURST_SHIFT 0
++
++/* 7811 RNG Enable Register (HIFN_1_7811_RNGENA) */
++#define HIFN_7811_RNGENA_ENA 0x00000001 /* enable RNG */
++
++/* 7811 RNG Config Register (HIFN_1_7811_RNGCFG) */
++#define HIFN_7811_RNGCFG_PRE1 0x00000f00 /* first prescalar */
++#define HIFN_7811_RNGCFG_OPRE 0x00000080 /* output prescalar */
++#define HIFN_7811_RNGCFG_DEFL 0x00000f80 /* 2 words/ 1/100 sec */
++
++/* 7811 RNG Status Register (HIFN_1_7811_RNGSTS) */
++#define HIFN_7811_RNGSTS_RDY 0x00004000 /* two numbers in FIFO */
++#define HIFN_7811_RNGSTS_UFL 0x00001000 /* rng underflow */
++
++/* 7811 MIPS Reset Register (HIFN_1_7811_MIPSRST) */
++#define HIFN_MIPSRST_BAR2SIZE 0xffff0000 /* sdram size */
++#define HIFN_MIPSRST_GPRAMINIT 0x00008000 /* gpram can be accessed */
++#define HIFN_MIPSRST_CRAMINIT 0x00004000 /* ctxram can be accessed */
++#define HIFN_MIPSRST_LED2 0x00000400 /* external LED2 */
++#define HIFN_MIPSRST_LED1 0x00000200 /* external LED1 */
++#define HIFN_MIPSRST_LED0 0x00000100 /* external LED0 */
++#define HIFN_MIPSRST_MIPSDIS 0x00000004 /* disable MIPS */
++#define HIFN_MIPSRST_MIPSRST 0x00000002 /* warm reset MIPS */
++#define HIFN_MIPSRST_MIPSCOLD 0x00000001 /* cold reset MIPS */
++
++/* Public key reset register (HIFN_1_PUB_RESET) */
++#define HIFN_PUBRST_RESET 0x00000001 /* reset public/rng unit */
++
++/* Public operation register (HIFN_1_PUB_OP) */
++#define HIFN_PUBOP_AOFFSET 0x0000003e /* A offset */
++#define HIFN_PUBOP_BOFFSET 0x00000fc0 /* B offset */
++#define HIFN_PUBOP_MOFFSET 0x0003f000 /* M offset */
++#define HIFN_PUBOP_OP_MASK 0x003c0000 /* Opcode: */
++#define HIFN_PUBOP_OP_NOP 0x00000000 /* NOP */
++#define HIFN_PUBOP_OP_ADD 0x00040000 /* ADD */
++#define HIFN_PUBOP_OP_ADDC 0x00080000 /* ADD w/carry */
++#define HIFN_PUBOP_OP_SUB 0x000c0000 /* SUB */
++#define HIFN_PUBOP_OP_SUBC 0x00100000 /* SUB w/carry */
++#define HIFN_PUBOP_OP_MODADD 0x00140000 /* Modular ADD */
++#define HIFN_PUBOP_OP_MODSUB 0x00180000 /* Modular SUB */
++#define HIFN_PUBOP_OP_INCA 0x001c0000 /* INC A */
++#define HIFN_PUBOP_OP_DECA 0x00200000 /* DEC A */
++#define HIFN_PUBOP_OP_MULT 0x00240000 /* MULT */
++#define HIFN_PUBOP_OP_MODMULT 0x00280000 /* Modular MULT */
++#define HIFN_PUBOP_OP_MODRED 0x002c0000 /* Modular Red */
++#define HIFN_PUBOP_OP_MODEXP 0x00300000 /* Modular Exp */
++
++/* Public operand length register (HIFN_1_PUB_OPLEN) */
++#define HIFN_PUBOPLEN_MODLEN 0x0000007f
++#define HIFN_PUBOPLEN_EXPLEN 0x0003ff80
++#define HIFN_PUBOPLEN_REDLEN 0x003c0000
++
++/* Public status register (HIFN_1_PUB_STATUS) */
++#define HIFN_PUBSTS_DONE 0x00000001 /* operation done */
++#define HIFN_PUBSTS_CARRY 0x00000002 /* carry */
++#define HIFN_PUBSTS_FIFO_EMPTY 0x00000100 /* fifo empty */
++#define HIFN_PUBSTS_FIFO_FULL 0x00000200 /* fifo full */
++#define HIFN_PUBSTS_FIFO_OVFL 0x00000400 /* fifo overflow */
++#define HIFN_PUBSTS_FIFO_WRITE 0x000f0000 /* fifo write */
++#define HIFN_PUBSTS_FIFO_READ 0x0f000000 /* fifo read */
++
++/* Public interrupt enable register (HIFN_1_PUB_IEN) */
++#define HIFN_PUBIEN_DONE 0x00000001 /* operation done interrupt */
++
++/* Random number generator config register (HIFN_1_RNG_CONFIG) */
++#define HIFN_RNGCFG_ENA 0x00000001 /* enable rng */
++
++/*
++ * Register offsets in register set 1
++ */
++
++#define HIFN_UNLOCK_SECRET1 0xf4
++#define HIFN_UNLOCK_SECRET2 0xfc
++
++/*
++ * PLL config register
++ *
++ * This register is present only on 7954/7955/7956 parts. It must be
++ * programmed according to the bus interface method used by the h/w.
++ * Note that the parts require a stable clock. Since the PCI clock
++ * may vary the reference clock must usually be used. To avoid
++ * overclocking the core logic, setup must be done carefully, refer
++ * to the driver for details. The exact multiplier required varies
++ * by part and system configuration; refer to the Hifn documentation.
++ */
++#define HIFN_PLL_REF_SEL 0x00000001 /* REF/HBI clk selection */
++#define HIFN_PLL_BP 0x00000002 /* bypass (used during setup) */
++/* bit 2 reserved */
++#define HIFN_PLL_PK_CLK_SEL 0x00000008 /* public key clk select */
++#define HIFN_PLL_PE_CLK_SEL 0x00000010 /* packet engine clk select */
++/* bits 5-9 reserved */
++#define HIFN_PLL_MBSET 0x00000400 /* must be set to 1 */
++#define HIFN_PLL_ND 0x00003800 /* Fpll_ref multiplier select */
++#define HIFN_PLL_ND_SHIFT 11
++#define HIFN_PLL_ND_2 0x00000000 /* 2x */
++#define HIFN_PLL_ND_4 0x00000800 /* 4x */
++#define HIFN_PLL_ND_6 0x00001000 /* 6x */
++#define HIFN_PLL_ND_8 0x00001800 /* 8x */
++#define HIFN_PLL_ND_10 0x00002000 /* 10x */
++#define HIFN_PLL_ND_12 0x00002800 /* 12x */
++/* bits 14-15 reserved */
++#define HIFN_PLL_IS 0x00010000 /* charge pump current select */
++/* bits 17-31 reserved */
++
++/*
++ * Board configuration specifies only these bits.
++ */
++#define HIFN_PLL_CONFIG (HIFN_PLL_IS|HIFN_PLL_ND|HIFN_PLL_REF_SEL)
++
++/*
++ * Public Key Engine Mode Register
++ */
++#define HIFN_PKMODE_HOSTINVERT (1 << 0) /* HOST INVERT */
++#define HIFN_PKMODE_ENHANCED (1 << 1) /* Enable enhanced mode */
++
++
++/*********************************************************************
++ * Structs for board commands
++ *
++ *********************************************************************/
++
++/*
++ * Structure to help build up the command data structure.
++ */
++typedef struct hifn_base_command {
++ volatile u_int16_t masks;
++ volatile u_int16_t session_num;
++ volatile u_int16_t total_source_count;
++ volatile u_int16_t total_dest_count;
++} hifn_base_command_t;
++
++#define HIFN_BASE_CMD_MAC 0x0400
++#define HIFN_BASE_CMD_CRYPT 0x0800
++#define HIFN_BASE_CMD_DECODE 0x2000
++#define HIFN_BASE_CMD_SRCLEN_M 0xc000
++#define HIFN_BASE_CMD_SRCLEN_S 14
++#define HIFN_BASE_CMD_DSTLEN_M 0x3000
++#define HIFN_BASE_CMD_DSTLEN_S 12
++#define HIFN_BASE_CMD_LENMASK_HI 0x30000
++#define HIFN_BASE_CMD_LENMASK_LO 0x0ffff
++
++/*
++ * Structure to help build up the command data structure.
++ */
++typedef struct hifn_crypt_command {
++ volatile u_int16_t masks;
++ volatile u_int16_t header_skip;
++ volatile u_int16_t source_count;
++ volatile u_int16_t reserved;
++} hifn_crypt_command_t;
++
++#define HIFN_CRYPT_CMD_ALG_MASK 0x0003 /* algorithm: */
++#define HIFN_CRYPT_CMD_ALG_DES 0x0000 /* DES */
++#define HIFN_CRYPT_CMD_ALG_3DES 0x0001 /* 3DES */
++#define HIFN_CRYPT_CMD_ALG_RC4 0x0002 /* RC4 */
++#define HIFN_CRYPT_CMD_ALG_AES 0x0003 /* AES */
++#define HIFN_CRYPT_CMD_MODE_MASK 0x0018 /* Encrypt mode: */
++#define HIFN_CRYPT_CMD_MODE_ECB 0x0000 /* ECB */
++#define HIFN_CRYPT_CMD_MODE_CBC 0x0008 /* CBC */
++#define HIFN_CRYPT_CMD_MODE_CFB 0x0010 /* CFB */
++#define HIFN_CRYPT_CMD_MODE_OFB 0x0018 /* OFB */
++#define HIFN_CRYPT_CMD_CLR_CTX 0x0040 /* clear context */
++#define HIFN_CRYPT_CMD_NEW_KEY 0x0800 /* expect new key */
++#define HIFN_CRYPT_CMD_NEW_IV 0x1000 /* expect new iv */
++
++#define HIFN_CRYPT_CMD_SRCLEN_M 0xc000
++#define HIFN_CRYPT_CMD_SRCLEN_S 14
++
++#define HIFN_CRYPT_CMD_KSZ_MASK 0x0600 /* AES key size: */
++#define HIFN_CRYPT_CMD_KSZ_128 0x0000 /* 128 bit */
++#define HIFN_CRYPT_CMD_KSZ_192 0x0200 /* 192 bit */
++#define HIFN_CRYPT_CMD_KSZ_256 0x0400 /* 256 bit */
++
++/*
++ * Structure to help build up the command data structure.
++ */
++typedef struct hifn_mac_command {
++ volatile u_int16_t masks;
++ volatile u_int16_t header_skip;
++ volatile u_int16_t source_count;
++ volatile u_int16_t reserved;
++} hifn_mac_command_t;
++
++#define HIFN_MAC_CMD_ALG_MASK 0x0001
++#define HIFN_MAC_CMD_ALG_SHA1 0x0000
++#define HIFN_MAC_CMD_ALG_MD5 0x0001
++#define HIFN_MAC_CMD_MODE_MASK 0x000c
++#define HIFN_MAC_CMD_MODE_HMAC 0x0000
++#define HIFN_MAC_CMD_MODE_SSL_MAC 0x0004
++#define HIFN_MAC_CMD_MODE_HASH 0x0008
++#define HIFN_MAC_CMD_MODE_FULL 0x0004
++#define HIFN_MAC_CMD_TRUNC 0x0010
++#define HIFN_MAC_CMD_RESULT 0x0020
++#define HIFN_MAC_CMD_APPEND 0x0040
++#define HIFN_MAC_CMD_SRCLEN_M 0xc000
++#define HIFN_MAC_CMD_SRCLEN_S 14
++
++/*
++ * MAC POS IPsec initiates authentication after encryption on encodes
++ * and before decryption on decodes.
++ */
++#define HIFN_MAC_CMD_POS_IPSEC 0x0200
++#define HIFN_MAC_CMD_NEW_KEY 0x0800
++
++/*
++ * The poll frequency and poll scalar defines are unshifted values used
++ * to set fields in the DMA Configuration Register.
++ */
++#ifndef HIFN_POLL_FREQUENCY
++#define HIFN_POLL_FREQUENCY 0x1
++#endif
++
++#ifndef HIFN_POLL_SCALAR
++#define HIFN_POLL_SCALAR 0x0
++#endif
++
++#define HIFN_MAX_SEGLEN 0xffff /* maximum dma segment len */
++#define HIFN_MAX_DMALEN 0x3ffff /* maximum dma length */
++#endif /* __HIFN_H__ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/hifn/hifn7751var.h linux-2.6.36/crypto/ocf/hifn/hifn7751var.h
+--- linux-2.6.36.orig/crypto/ocf/hifn/hifn7751var.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/hifn/hifn7751var.h 2010-11-09 20:28:04.832495385 +0100
+@@ -0,0 +1,369 @@
++/* $FreeBSD: src/sys/dev/hifn/hifn7751var.h,v 1.9 2007/03/21 03:42:49 sam Exp $ */
++/* $OpenBSD: hifn7751var.h,v 1.42 2002/04/08 17:49:42 jason Exp $ */
++
++/*-
++ * Invertex AEON / Hifn 7751 driver
++ * Copyright (c) 1999 Invertex Inc. All rights reserved.
++ * Copyright (c) 1999 Theo de Raadt
++ * Copyright (c) 2000-2001 Network Security Technologies, Inc.
++ * http://www.netsec.net
++ *
++ * Please send any comments, feedback, bug-fixes, or feature requests to
++ * software@invertex.com.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++ */
++
++#ifndef __HIFN7751VAR_H__
++#define __HIFN7751VAR_H__
++
++#ifdef __KERNEL__
++
++/*
++ * Some configurable values for the driver. By default command+result
++ * descriptor rings are the same size. The src+dst descriptor rings
++ * are sized at 3.5x the number of potential commands. Slower parts
++ * (e.g. 7951) tend to run out of src descriptors; faster parts (7811)
++ * src+cmd/result descriptors. It's not clear that increasing the size
++ * of the descriptor rings helps performance significantly as other
++ * factors tend to come into play (e.g. copying misaligned packets).
++ */
++#define HIFN_D_CMD_RSIZE 24 /* command descriptors */
++#define HIFN_D_SRC_RSIZE ((HIFN_D_CMD_RSIZE * 7) / 2) /* source descriptors */
++#define HIFN_D_RES_RSIZE HIFN_D_CMD_RSIZE /* result descriptors */
++#define HIFN_D_DST_RSIZE HIFN_D_SRC_RSIZE /* destination descriptors */
++
++/*
++ * Length values for cryptography
++ */
++#define HIFN_DES_KEY_LENGTH 8
++#define HIFN_3DES_KEY_LENGTH 24
++#define HIFN_MAX_CRYPT_KEY_LENGTH HIFN_3DES_KEY_LENGTH
++#define HIFN_IV_LENGTH 8
++#define HIFN_AES_IV_LENGTH 16
++#define HIFN_MAX_IV_LENGTH HIFN_AES_IV_LENGTH
++
++/*
++ * Length values for authentication
++ */
++#define HIFN_MAC_KEY_LENGTH 64
++#define HIFN_MD5_LENGTH 16
++#define HIFN_SHA1_LENGTH 20
++#define HIFN_MAC_TRUNC_LENGTH 12
++
++#define MAX_SCATTER 64
++
++/*
++ * Data structure to hold all 4 rings and any other ring related data.
++ */
++struct hifn_dma {
++ /*
++ * Descriptor rings. We add +1 to the size to accomidate the
++ * jump descriptor.
++ */
++ struct hifn_desc cmdr[HIFN_D_CMD_RSIZE+1];
++ struct hifn_desc srcr[HIFN_D_SRC_RSIZE+1];
++ struct hifn_desc dstr[HIFN_D_DST_RSIZE+1];
++ struct hifn_desc resr[HIFN_D_RES_RSIZE+1];
++
++ struct hifn_command *hifn_commands[HIFN_D_RES_RSIZE];
++
++ u_char command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND];
++ u_char result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT];
++ u_int32_t slop[HIFN_D_CMD_RSIZE];
++
++ u_int64_t test_src, test_dst;
++
++ /*
++ * Our current positions for insertion and removal from the desriptor
++ * rings.
++ */
++ int cmdi, srci, dsti, resi;
++ volatile int cmdu, srcu, dstu, resu;
++ int cmdk, srck, dstk, resk;
++};
++
++struct hifn_session {
++ int hs_used;
++ int hs_mlen;
++ u_int8_t hs_iv[HIFN_MAX_IV_LENGTH];
++};
++
++#define HIFN_RING_SYNC(sc, r, i, f) \
++ /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */
++
++#define HIFN_CMDR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), cmdr, (i), (f))
++#define HIFN_RESR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), resr, (i), (f))
++#define HIFN_SRCR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), srcr, (i), (f))
++#define HIFN_DSTR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), dstr, (i), (f))
++
++#define HIFN_CMD_SYNC(sc, i, f) \
++ /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */
++
++#define HIFN_RES_SYNC(sc, i, f) \
++ /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */
++
++typedef int bus_size_t;
++
++/*
++ * Holds data specific to a single HIFN board.
++ */
++struct hifn_softc {
++ softc_device_decl sc_dev;
++
++ struct pci_dev *sc_pcidev; /* PCI device pointer */
++ spinlock_t sc_mtx; /* per-instance lock */
++
++ int sc_num; /* for multiple devs */
++
++ ocf_iomem_t sc_bar0;
++ bus_size_t sc_bar0_lastreg;/* bar0 last reg written */
++ ocf_iomem_t sc_bar1;
++ bus_size_t sc_bar1_lastreg;/* bar1 last reg written */
++
++ int sc_irq;
++
++ u_int32_t sc_dmaier;
++ u_int32_t sc_drammodel; /* 1=dram, 0=sram */
++ u_int32_t sc_pllconfig; /* 7954/7955/7956 PLL config */
++
++ struct hifn_dma *sc_dma;
++ dma_addr_t sc_dma_physaddr;/* physical address of sc_dma */
++
++ int sc_dmansegs;
++ int32_t sc_cid;
++ int sc_maxses;
++ int sc_nsessions;
++ struct hifn_session *sc_sessions;
++ int sc_ramsize;
++ int sc_flags;
++#define HIFN_HAS_RNG 0x1 /* includes random number generator */
++#define HIFN_HAS_PUBLIC 0x2 /* includes public key support */
++#define HIFN_HAS_AES 0x4 /* includes AES support */
++#define HIFN_IS_7811 0x8 /* Hifn 7811 part */
++#define HIFN_IS_7956 0x10 /* Hifn 7956/7955 don't have SDRAM */
++
++ struct timer_list sc_tickto; /* for managing DMA */
++
++ int sc_rngfirst;
++ int sc_rnghz; /* RNG polling frequency */
++
++ int sc_c_busy; /* command ring busy */
++ int sc_s_busy; /* source data ring busy */
++ int sc_d_busy; /* destination data ring busy */
++ int sc_r_busy; /* result ring busy */
++ int sc_active; /* for initial countdown */
++ int sc_needwakeup; /* ops q'd wating on resources */
++ int sc_curbatch; /* # ops submitted w/o int */
++ int sc_suspended;
++#ifdef HIFN_VULCANDEV
++ struct cdev *sc_pkdev;
++#endif
++};
++
++#define HIFN_LOCK(_sc) spin_lock_irqsave(&(_sc)->sc_mtx, l_flags)
++#define HIFN_UNLOCK(_sc) spin_unlock_irqrestore(&(_sc)->sc_mtx, l_flags)
++
++/*
++ * hifn_command_t
++ *
++ * This is the control structure used to pass commands to hifn_encrypt().
++ *
++ * flags
++ * -----
++ * Flags is the bitwise "or" values for command configuration. A single
++ * encrypt direction needs to be set:
++ *
++ * HIFN_ENCODE or HIFN_DECODE
++ *
++ * To use cryptography, a single crypto algorithm must be included:
++ *
++ * HIFN_CRYPT_3DES or HIFN_CRYPT_DES
++ *
++ * To use authentication is used, a single MAC algorithm must be included:
++ *
++ * HIFN_MAC_MD5 or HIFN_MAC_SHA1
++ *
++ * By default MD5 uses a 16 byte hash and SHA-1 uses a 20 byte hash.
++ * If the value below is set, hash values are truncated or assumed
++ * truncated to 12 bytes:
++ *
++ * HIFN_MAC_TRUNC
++ *
++ * Keys for encryption and authentication can be sent as part of a command,
++ * or the last key value used with a particular session can be retrieved
++ * and used again if either of these flags are not specified.
++ *
++ * HIFN_CRYPT_NEW_KEY, HIFN_MAC_NEW_KEY
++ *
++ * session_num
++ * -----------
++ * A number between 0 and 2048 (for DRAM models) or a number between
++ * 0 and 768 (for SRAM models). Those who don't want to use session
++ * numbers should leave value at zero and send a new crypt key and/or
++ * new MAC key on every command. If you use session numbers and
++ * don't send a key with a command, the last key sent for that same
++ * session number will be used.
++ *
++ * Warning: Using session numbers and multiboard at the same time
++ * is currently broken.
++ *
++ * mbuf
++ * ----
++ * Either fill in the mbuf pointer and npa=0 or
++ * fill packp[] and packl[] and set npa to > 0
++ *
++ * mac_header_skip
++ * ---------------
++ * The number of bytes of the source_buf that are skipped over before
++ * authentication begins. This must be a number between 0 and 2^16-1
++ * and can be used by IPsec implementers to skip over IP headers.
++ * *** Value ignored if authentication not used ***
++ *
++ * crypt_header_skip
++ * -----------------
++ * The number of bytes of the source_buf that are skipped over before
++ * the cryptographic operation begins. This must be a number between 0
++ * and 2^16-1. For IPsec, this number will always be 8 bytes larger
++ * than the auth_header_skip (to skip over the ESP header).
++ * *** Value ignored if cryptography not used ***
++ *
++ */
++struct hifn_operand {
++ union {
++ struct sk_buff *skb;
++ struct uio *io;
++ unsigned char *buf;
++ } u;
++ void *map;
++ bus_size_t mapsize;
++ int nsegs;
++ struct {
++ dma_addr_t ds_addr;
++ int ds_len;
++ } segs[MAX_SCATTER];
++};
++
++struct hifn_command {
++ u_int16_t session_num;
++ u_int16_t base_masks, cry_masks, mac_masks;
++ u_int8_t iv[HIFN_MAX_IV_LENGTH], *ck, mac[HIFN_MAC_KEY_LENGTH];
++ int cklen;
++ int sloplen, slopidx;
++
++ struct hifn_operand src;
++ struct hifn_operand dst;
++
++ struct hifn_softc *softc;
++ struct cryptop *crp;
++ struct cryptodesc *enccrd, *maccrd;
++};
++
++#define src_skb src.u.skb
++#define src_io src.u.io
++#define src_map src.map
++#define src_mapsize src.mapsize
++#define src_segs src.segs
++#define src_nsegs src.nsegs
++#define src_buf src.u.buf
++
++#define dst_skb dst.u.skb
++#define dst_io dst.u.io
++#define dst_map dst.map
++#define dst_mapsize dst.mapsize
++#define dst_segs dst.segs
++#define dst_nsegs dst.nsegs
++#define dst_buf dst.u.buf
++
++/*
++ * Return values for hifn_crypto()
++ */
++#define HIFN_CRYPTO_SUCCESS 0
++#define HIFN_CRYPTO_BAD_INPUT (-1)
++#define HIFN_CRYPTO_RINGS_FULL (-2)
++
++/**************************************************************************
++ *
++ * Function: hifn_crypto
++ *
++ * Purpose: Called by external drivers to begin an encryption on the
++ * HIFN board.
++ *
++ * Blocking/Non-blocking Issues
++ * ============================
++ * The driver cannot block in hifn_crypto (no calls to tsleep) currently.
++ * hifn_crypto() returns HIFN_CRYPTO_RINGS_FULL if there is not enough
++ * room in any of the rings for the request to proceed.
++ *
++ * Return Values
++ * =============
++ * 0 for success, negative values on error
++ *
++ * Defines for negative error codes are:
++ *
++ * HIFN_CRYPTO_BAD_INPUT : The passed in command had invalid settings.
++ * HIFN_CRYPTO_RINGS_FULL : All DMA rings were full and non-blocking
++ * behaviour was requested.
++ *
++ *************************************************************************/
++
++/*
++ * Convert back and forth from 'sid' to 'card' and 'session'
++ */
++#define HIFN_CARD(sid) (((sid) & 0xf0000000) >> 28)
++#define HIFN_SESSION(sid) ((sid) & 0x000007ff)
++#define HIFN_SID(crd,ses) (((crd) << 28) | ((ses) & 0x7ff))
++
++#endif /* _KERNEL */
++
++struct hifn_stats {
++ u_int64_t hst_ibytes;
++ u_int64_t hst_obytes;
++ u_int32_t hst_ipackets;
++ u_int32_t hst_opackets;
++ u_int32_t hst_invalid;
++ u_int32_t hst_nomem; /* malloc or one of hst_nomem_* */
++ u_int32_t hst_abort;
++ u_int32_t hst_noirq; /* IRQ for no reason */
++ u_int32_t hst_totbatch; /* ops submitted w/o interrupt */
++ u_int32_t hst_maxbatch; /* max ops submitted together */
++ u_int32_t hst_unaligned; /* unaligned src caused copy */
++ /*
++ * The following divides hst_nomem into more specific buckets.
++ */
++ u_int32_t hst_nomem_map; /* bus_dmamap_create failed */
++ u_int32_t hst_nomem_load; /* bus_dmamap_load_* failed */
++ u_int32_t hst_nomem_mbuf; /* MGET* failed */
++ u_int32_t hst_nomem_mcl; /* MCLGET* failed */
++ u_int32_t hst_nomem_cr; /* out of command/result descriptor */
++ u_int32_t hst_nomem_sd; /* out of src/dst descriptors */
++};
++
++#endif /* __HIFN7751VAR_H__ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/hifn/hifnHIPP.c linux-2.6.36/crypto/ocf/hifn/hifnHIPP.c
+--- linux-2.6.36.orig/crypto/ocf/hifn/hifnHIPP.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/hifn/hifnHIPP.c 2010-11-09 20:28:04.881244876 +0100
+@@ -0,0 +1,420 @@
++/*-
++ * Driver for Hifn HIPP-I/II chipset
++ * Copyright (c) 2006 Michael Richardson <mcr@xelerance.com>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * Effort sponsored by Hifn Inc.
++ *
++ */
++
++/*
++ * Driver for various Hifn encryption processors.
++ */
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/random.h>
++#include <linux/version.h>
++#include <linux/skbuff.h>
++#include <linux/uio.h>
++#include <linux/sysfs.h>
++#include <linux/miscdevice.h>
++#include <asm/io.h>
++
++#include <cryptodev.h>
++
++#include "hifnHIPPreg.h"
++#include "hifnHIPPvar.h"
++
++#if 1
++#define DPRINTF(a...) if (hipp_debug) { \
++ printk("%s: ", sc ? \
++ device_get_nameunit(sc->sc_dev) : "hifn"); \
++ printk(a); \
++ } else
++#else
++#define DPRINTF(a...)
++#endif
++
++typedef int bus_size_t;
++
++static inline int
++pci_get_revid(struct pci_dev *dev)
++{
++ u8 rid = 0;
++ pci_read_config_byte(dev, PCI_REVISION_ID, &rid);
++ return rid;
++}
++
++#define debug hipp_debug
++int hipp_debug = 0;
++module_param(hipp_debug, int, 0644);
++MODULE_PARM_DESC(hipp_debug, "Enable debug");
++
++int hipp_maxbatch = 1;
++module_param(hipp_maxbatch, int, 0644);
++MODULE_PARM_DESC(hipp_maxbatch, "max ops to batch w/o interrupt");
++
++static int hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent);
++static void hipp_remove(struct pci_dev *dev);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++static irqreturn_t hipp_intr(int irq, void *arg);
++#else
++static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs);
++#endif
++
++static int hipp_num_chips = 0;
++static struct hipp_softc *hipp_chip_idx[HIPP_MAX_CHIPS];
++
++static int hipp_newsession(device_t, u_int32_t *, struct cryptoini *);
++static int hipp_freesession(device_t, u_int64_t);
++static int hipp_process(device_t, struct cryptop *, int);
++
++static device_method_t hipp_methods = {
++ /* crypto device methods */
++ DEVMETHOD(cryptodev_newsession, hipp_newsession),
++ DEVMETHOD(cryptodev_freesession,hipp_freesession),
++ DEVMETHOD(cryptodev_process, hipp_process),
++};
++
++static __inline u_int32_t
++READ_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg)
++{
++ u_int32_t v = readl(sc->sc_bar[barno] + reg);
++ //sc->sc_bar0_lastreg = (bus_size_t) -1;
++ return (v);
++}
++static __inline void
++WRITE_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg, u_int32_t val)
++{
++ writel(val, sc->sc_bar[barno] + reg);
++}
++
++#define READ_REG_0(sc, reg) READ_REG(sc, 0, reg)
++#define WRITE_REG_0(sc, reg, val) WRITE_REG(sc,0, reg, val)
++#define READ_REG_1(sc, reg) READ_REG(sc, 1, reg)
++#define WRITE_REG_1(sc, reg, val) WRITE_REG(sc,1, reg, val)
++
++static int
++hipp_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
++{
++ return EINVAL;
++}
++
++static int
++hipp_freesession(device_t dev, u_int64_t tid)
++{
++ return EINVAL;
++}
++
++static int
++hipp_process(device_t dev, struct cryptop *crp, int hint)
++{
++ return EINVAL;
++}
++
++static const char*
++hipp_partname(struct hipp_softc *sc, char buf[128], size_t blen)
++{
++ char *n = NULL;
++
++ switch (pci_get_vendor(sc->sc_pcidev)) {
++ case PCI_VENDOR_HIFN:
++ switch (pci_get_device(sc->sc_pcidev)) {
++ case PCI_PRODUCT_HIFN_7855: n = "Hifn 7855";
++ case PCI_PRODUCT_HIFN_8155: n = "Hifn 8155";
++ case PCI_PRODUCT_HIFN_6500: n = "Hifn 6500";
++ }
++ }
++
++ if(n==NULL) {
++ snprintf(buf, blen, "VID=%02x,PID=%02x",
++ pci_get_vendor(sc->sc_pcidev),
++ pci_get_device(sc->sc_pcidev));
++ } else {
++ buf[0]='\0';
++ strncat(buf, n, blen);
++ }
++ return buf;
++}
++
++struct hipp_fs_entry {
++ struct attribute attr;
++ /* other stuff */
++};
++
++
++static ssize_t
++cryptoid_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct hipp_softc *sc;
++
++ sc = pci_get_drvdata(to_pci_dev (dev));
++ return sprintf (buf, "%d\n", sc->sc_cid);
++}
++
++struct device_attribute hipp_dev_cryptoid = __ATTR_RO(cryptoid);
++
++/*
++ * Attach an interface that successfully probed.
++ */
++static int
++hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent)
++{
++ struct hipp_softc *sc = NULL;
++ int i;
++ //char rbase;
++ //u_int16_t ena;
++ int rev;
++ //int rseg;
++ int rc;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ if (pci_enable_device(dev) < 0)
++ return(-ENODEV);
++
++ if (pci_set_mwi(dev))
++ return(-ENODEV);
++
++ if (!dev->irq) {
++ printk("hifn: found device with no IRQ assigned. check BIOS settings!");
++ pci_disable_device(dev);
++ return(-ENODEV);
++ }
++
++ sc = (struct hipp_softc *) kmalloc(sizeof(*sc), GFP_KERNEL);
++ if (!sc)
++ return(-ENOMEM);
++ memset(sc, 0, sizeof(*sc));
++
++ softc_device_init(sc, "hifn-hipp", hipp_num_chips, hipp_methods);
++
++ sc->sc_pcidev = dev;
++ sc->sc_irq = -1;
++ sc->sc_cid = -1;
++ sc->sc_num = hipp_num_chips++;
++
++ if (sc->sc_num < HIPP_MAX_CHIPS)
++ hipp_chip_idx[sc->sc_num] = sc;
++
++ pci_set_drvdata(sc->sc_pcidev, sc);
++
++ spin_lock_init(&sc->sc_mtx);
++
++ /*
++ * Setup PCI resources.
++ * The READ_REG_0, WRITE_REG_0, READ_REG_1,
++ * and WRITE_REG_1 macros throughout the driver are used
++ * to permit better debugging.
++ */
++ for(i=0; i<4; i++) {
++ unsigned long mem_start, mem_len;
++ mem_start = pci_resource_start(sc->sc_pcidev, i);
++ mem_len = pci_resource_len(sc->sc_pcidev, i);
++ sc->sc_barphy[i] = (caddr_t)mem_start;
++ sc->sc_bar[i] = (ocf_iomem_t) ioremap(mem_start, mem_len);
++ if (!sc->sc_bar[i]) {
++ device_printf(sc->sc_dev, "cannot map bar%d register space\n", i);
++ goto fail;
++ }
++ }
++
++ //hipp_reset_board(sc, 0);
++ pci_set_master(sc->sc_pcidev);
++
++ /*
++ * Arrange the interrupt line.
++ */
++ rc = request_irq(dev->irq, hipp_intr, IRQF_SHARED, "hifn", sc);
++ if (rc) {
++ device_printf(sc->sc_dev, "could not map interrupt: %d\n", rc);
++ goto fail;
++ }
++ sc->sc_irq = dev->irq;
++
++ rev = READ_REG_1(sc, HIPP_1_REVID) & 0xffff;
++
++ {
++ char b[32];
++ device_printf(sc->sc_dev, "%s, rev %u",
++ hipp_partname(sc, b, sizeof(b)), rev);
++ }
++
++#if 0
++ if (sc->sc_flags & HIFN_IS_7956)
++ printf(", pll=0x%x<%s clk, %ux mult>",
++ sc->sc_pllconfig,
++ sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci",
++ 2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11));
++#endif
++ printf("\n");
++
++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE);
++ if (sc->sc_cid < 0) {
++ device_printf(sc->sc_dev, "could not get crypto driver id\n");
++ goto fail;
++ }
++
++#if 0 /* cannot work with a non-GPL module */
++ /* make a sysfs entry to let the world know what entry we got */
++ sysfs_create_file(&sc->sc_pcidev->dev.kobj, &hipp_dev_cryptoid.attr);
++#endif
++
++#if 0
++ init_timer(&sc->sc_tickto);
++ sc->sc_tickto.function = hifn_tick;
++ sc->sc_tickto.data = (unsigned long) sc->sc_num;
++ mod_timer(&sc->sc_tickto, jiffies + HZ);
++#endif
++
++#if 0 /* no code here yet ?? */
++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
++#endif
++
++ return (0);
++
++fail:
++ if (sc->sc_cid >= 0)
++ crypto_unregister_all(sc->sc_cid);
++ if (sc->sc_irq != -1)
++ free_irq(sc->sc_irq, sc);
++
++#if 0
++ if (sc->sc_dma) {
++ /* Turn off DMA polling */
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++
++ pci_free_consistent(sc->sc_pcidev,
++ sizeof(*sc->sc_dma),
++ sc->sc_dma, sc->sc_dma_physaddr);
++ }
++#endif
++ kfree(sc);
++ return (-ENXIO);
++}
++
++/*
++ * Detach an interface that successfully probed.
++ */
++static void
++hipp_remove(struct pci_dev *dev)
++{
++ struct hipp_softc *sc = pci_get_drvdata(dev);
++ unsigned long l_flags;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ /* disable interrupts */
++ HIPP_LOCK(sc);
++
++#if 0
++ WRITE_REG_1(sc, HIFN_1_DMA_IER, 0);
++ HIFN_UNLOCK(sc);
++
++ /*XXX other resources */
++ del_timer_sync(&sc->sc_tickto);
++
++ /* Turn off DMA polling */
++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
++#endif
++
++ crypto_unregister_all(sc->sc_cid);
++
++ free_irq(sc->sc_irq, sc);
++
++#if 0
++ pci_free_consistent(sc->sc_pcidev, sizeof(*sc->sc_dma),
++ sc->sc_dma, sc->sc_dma_physaddr);
++#endif
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++static irqreturn_t hipp_intr(int irq, void *arg)
++#else
++static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs)
++#endif
++{
++ struct hipp_softc *sc = arg;
++
++ sc = sc; /* shut up compiler */
++
++ return IRQ_HANDLED;
++}
++
++static struct pci_device_id hipp_pci_tbl[] = {
++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7855,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_8155,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++};
++MODULE_DEVICE_TABLE(pci, hipp_pci_tbl);
++
++static struct pci_driver hipp_driver = {
++ .name = "hipp",
++ .id_table = hipp_pci_tbl,
++ .probe = hipp_probe,
++ .remove = hipp_remove,
++ /* add PM stuff here one day */
++};
++
++static int __init hipp_init (void)
++{
++ struct hipp_softc *sc = NULL;
++ int rc;
++
++ DPRINTF("%s(%p)\n", __FUNCTION__, hipp_init);
++
++ rc = pci_register_driver(&hipp_driver);
++ pci_register_driver_compat(&hipp_driver, rc);
++
++ return rc;
++}
++
++static void __exit hipp_exit (void)
++{
++ pci_unregister_driver(&hipp_driver);
++}
++
++module_init(hipp_init);
++module_exit(hipp_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("Michael Richardson <mcr@xelerance.com>");
++MODULE_DESCRIPTION("OCF driver for hifn HIPP-I/II PCI crypto devices");
+diff -Nur linux-2.6.36.orig/crypto/ocf/hifn/hifnHIPPreg.h linux-2.6.36/crypto/ocf/hifn/hifnHIPPreg.h
+--- linux-2.6.36.orig/crypto/ocf/hifn/hifnHIPPreg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/hifn/hifnHIPPreg.h 2010-11-09 20:28:04.922495399 +0100
+@@ -0,0 +1,46 @@
++/*-
++ * Hifn HIPP-I/HIPP-II (7855/8155) driver.
++ * Copyright (c) 2006 Michael Richardson <mcr@xelerance.com>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * Effort sponsored by Hifn inc.
++ *
++ */
++
++#ifndef __HIFNHIPP_H__
++#define __HIFNHIPP_H__
++
++/*
++ * PCI vendor and device identifiers
++ */
++#define PCI_VENDOR_HIFN 0x13a3 /* Hifn */
++#define PCI_PRODUCT_HIFN_6500 0x0006 /* 6500 */
++#define PCI_PRODUCT_HIFN_7855 0x001f /* 7855 */
++#define PCI_PRODUCT_HIFN_8155 0x999 /* XXX 8155 */
++
++#define HIPP_1_REVID 0x01 /* BOGUS */
++
++#endif /* __HIPP_H__ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/hifn/hifnHIPPvar.h linux-2.6.36/crypto/ocf/hifn/hifnHIPPvar.h
+--- linux-2.6.36.orig/crypto/ocf/hifn/hifnHIPPvar.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/hifn/hifnHIPPvar.h 2010-11-09 20:28:04.964807923 +0100
+@@ -0,0 +1,93 @@
++/*
++ * Hifn HIPP-I/HIPP-II (7855/8155) driver.
++ * Copyright (c) 2006 Michael Richardson <mcr@xelerance.com> *
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * Effort sponsored by Hifn inc.
++ *
++ */
++
++#ifndef __HIFNHIPPVAR_H__
++#define __HIFNHIPPVAR_H__
++
++#define HIPP_MAX_CHIPS 8
++
++/*
++ * Holds data specific to a single Hifn HIPP-I board.
++ */
++struct hipp_softc {
++ softc_device_decl sc_dev;
++
++ struct pci_dev *sc_pcidev; /* device backpointer */
++ ocf_iomem_t sc_bar[5];
++ caddr_t sc_barphy[5]; /* physical address */
++ int sc_num; /* for multiple devs */
++ spinlock_t sc_mtx; /* per-instance lock */
++ int32_t sc_cid;
++ int sc_irq;
++
++#if 0
++
++ u_int32_t sc_dmaier;
++ u_int32_t sc_drammodel; /* 1=dram, 0=sram */
++ u_int32_t sc_pllconfig; /* 7954/7955/7956 PLL config */
++
++ struct hifn_dma *sc_dma;
++ dma_addr_t sc_dma_physaddr;/* physical address of sc_dma */
++
++ int sc_dmansegs;
++ int sc_maxses;
++ int sc_nsessions;
++ struct hifn_session *sc_sessions;
++ int sc_ramsize;
++ int sc_flags;
++#define HIFN_HAS_RNG 0x1 /* includes random number generator */
++#define HIFN_HAS_PUBLIC 0x2 /* includes public key support */
++#define HIFN_HAS_AES 0x4 /* includes AES support */
++#define HIFN_IS_7811 0x8 /* Hifn 7811 part */
++#define HIFN_IS_7956 0x10 /* Hifn 7956/7955 don't have SDRAM */
++
++ struct timer_list sc_tickto; /* for managing DMA */
++
++ int sc_rngfirst;
++ int sc_rnghz; /* RNG polling frequency */
++
++ int sc_c_busy; /* command ring busy */
++ int sc_s_busy; /* source data ring busy */
++ int sc_d_busy; /* destination data ring busy */
++ int sc_r_busy; /* result ring busy */
++ int sc_active; /* for initial countdown */
++ int sc_needwakeup; /* ops q'd wating on resources */
++ int sc_curbatch; /* # ops submitted w/o int */
++ int sc_suspended;
++ struct miscdevice sc_miscdev;
++#endif
++};
++
++#define HIPP_LOCK(_sc) spin_lock_irqsave(&(_sc)->sc_mtx, l_flags)
++#define HIPP_UNLOCK(_sc) spin_unlock_irqrestore(&(_sc)->sc_mtx, l_flags)
++
++#endif /* __HIFNHIPPVAR_H__ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/hifn/Makefile linux-2.6.36/crypto/ocf/hifn/Makefile
+--- linux-2.6.36.orig/crypto/ocf/hifn/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/hifn/Makefile 2010-11-09 20:28:05.002825564 +0100
+@@ -0,0 +1,13 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_HIFN) += hifn7751.o
++obj-$(CONFIG_OCF_HIFNHIPP) += hifnHIPP.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/ixp4xx/ixp4xx.c linux-2.6.36/crypto/ocf/ixp4xx/ixp4xx.c
+--- linux-2.6.36.orig/crypto/ocf/ixp4xx/ixp4xx.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/ixp4xx/ixp4xx.c 2010-11-09 20:28:05.051258556 +0100
+@@ -0,0 +1,1324 @@
++/*
++ * An OCF module that uses Intels IXP CryptACC API to do the crypto.
++ * This driver requires the IXP400 Access Library that is available
++ * from Intel in order to operate (or compile).
++ *
++ * Written by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ * 1. distributions of this source code include the above copyright
++ * notice, this list of conditions and the following disclaimer;
++ *
++ * 2. distributions in binary form include the above copyright
++ * notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other associated materials;
++ *
++ * 3. the copyright holder's name is not used to endorse products
++ * built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/crypto.h>
++#include <linux/interrupt.h>
++#include <asm/scatterlist.h>
++
++#include <IxTypes.h>
++#include <IxOsBuffMgt.h>
++#include <IxNpeDl.h>
++#include <IxCryptoAcc.h>
++#include <IxQMgr.h>
++#include <IxOsServices.h>
++#include <IxOsCacheMMU.h>
++
++#include <cryptodev.h>
++#include <uio.h>
++
++#ifndef IX_MBUF_PRIV
++#define IX_MBUF_PRIV(x) ((x)->priv)
++#endif
++
++struct ixp_data;
++
++struct ixp_q {
++ struct list_head ixp_q_list;
++ struct ixp_data *ixp_q_data;
++ struct cryptop *ixp_q_crp;
++ struct cryptodesc *ixp_q_ccrd;
++ struct cryptodesc *ixp_q_acrd;
++ IX_MBUF ixp_q_mbuf;
++ UINT8 *ixp_hash_dest; /* Location for hash in client buffer */
++ UINT8 *ixp_hash_src; /* Location of hash in internal buffer */
++ unsigned char ixp_q_iv_data[IX_CRYPTO_ACC_MAX_CIPHER_IV_LENGTH];
++ unsigned char *ixp_q_iv;
++};
++
++struct ixp_data {
++ int ixp_registered; /* is the context registered */
++ int ixp_crd_flags; /* detect direction changes */
++
++ int ixp_cipher_alg;
++ int ixp_auth_alg;
++
++ UINT32 ixp_ctx_id;
++ UINT32 ixp_hash_key_id; /* used when hashing */
++ IxCryptoAccCtx ixp_ctx;
++ IX_MBUF ixp_pri_mbuf;
++ IX_MBUF ixp_sec_mbuf;
++
++ struct work_struct ixp_pending_work;
++ struct work_struct ixp_registration_work;
++ struct list_head ixp_q; /* unprocessed requests */
++};
++
++#ifdef __ixp46X
++
++#define MAX_IOP_SIZE 64 /* words */
++#define MAX_OOP_SIZE 128
++
++#define MAX_PARAMS 3
++
++struct ixp_pkq {
++ struct list_head pkq_list;
++ struct cryptkop *pkq_krp;
++
++ IxCryptoAccPkeEauInOperands pkq_op;
++ IxCryptoAccPkeEauOpResult pkq_result;
++
++ UINT32 pkq_ibuf0[MAX_IOP_SIZE];
++ UINT32 pkq_ibuf1[MAX_IOP_SIZE];
++ UINT32 pkq_ibuf2[MAX_IOP_SIZE];
++ UINT32 pkq_obuf[MAX_OOP_SIZE];
++};
++
++static LIST_HEAD(ixp_pkq); /* current PK wait list */
++static struct ixp_pkq *ixp_pk_cur;
++static spinlock_t ixp_pkq_lock;
++
++#endif /* __ixp46X */
++
++static int ixp_blocked = 0;
++
++static int32_t ixp_id = -1;
++static struct ixp_data **ixp_sessions = NULL;
++static u_int32_t ixp_sesnum = 0;
++
++static int ixp_process(device_t, struct cryptop *, int);
++static int ixp_newsession(device_t, u_int32_t *, struct cryptoini *);
++static int ixp_freesession(device_t, u_int64_t);
++#ifdef __ixp46X
++static int ixp_kprocess(device_t, struct cryptkop *krp, int hint);
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++static kmem_cache_t *qcache;
++#else
++static struct kmem_cache *qcache;
++#endif
++
++#define debug ixp_debug
++static int ixp_debug = 0;
++module_param(ixp_debug, int, 0644);
++MODULE_PARM_DESC(ixp_debug, "Enable debug");
++
++static int ixp_init_crypto = 1;
++module_param(ixp_init_crypto, int, 0444); /* RO after load/boot */
++MODULE_PARM_DESC(ixp_init_crypto, "Call ixCryptoAccInit (default is 1)");
++
++static void ixp_process_pending(void *arg);
++static void ixp_registration(void *arg);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void ixp_process_pending_wq(struct work_struct *work);
++static void ixp_registration_wq(struct work_struct *work);
++#endif
++
++/*
++ * dummy device structure
++ */
++
++static struct {
++ softc_device_decl sc_dev;
++} ixpdev;
++
++static device_method_t ixp_methods = {
++ /* crypto device methods */
++ DEVMETHOD(cryptodev_newsession, ixp_newsession),
++ DEVMETHOD(cryptodev_freesession,ixp_freesession),
++ DEVMETHOD(cryptodev_process, ixp_process),
++#ifdef __ixp46X
++ DEVMETHOD(cryptodev_kprocess, ixp_kprocess),
++#endif
++};
++
++/*
++ * Generate a new software session.
++ */
++static int
++ixp_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
++{
++ struct ixp_data *ixp;
++ u_int32_t i;
++#define AUTH_LEN(cri, def) \
++ (cri->cri_mlen ? cri->cri_mlen : (def))
++
++ dprintk("%s():alg %d\n", __FUNCTION__,cri->cri_alg);
++ if (sid == NULL || cri == NULL) {
++ dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ if (ixp_sessions) {
++ for (i = 1; i < ixp_sesnum; i++)
++ if (ixp_sessions[i] == NULL)
++ break;
++ } else
++ i = 1; /* NB: to silence compiler warning */
++
++ if (ixp_sessions == NULL || i == ixp_sesnum) {
++ struct ixp_data **ixpd;
++
++ if (ixp_sessions == NULL) {
++ i = 1; /* We leave ixp_sessions[0] empty */
++ ixp_sesnum = CRYPTO_SW_SESSIONS;
++ } else
++ ixp_sesnum *= 2;
++
++ ixpd = kmalloc(ixp_sesnum * sizeof(struct ixp_data *), SLAB_ATOMIC);
++ if (ixpd == NULL) {
++ /* Reset session number */
++ if (ixp_sesnum == CRYPTO_SW_SESSIONS)
++ ixp_sesnum = 0;
++ else
++ ixp_sesnum /= 2;
++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++ return ENOBUFS;
++ }
++ memset(ixpd, 0, ixp_sesnum * sizeof(struct ixp_data *));
++
++ /* Copy existing sessions */
++ if (ixp_sessions) {
++ memcpy(ixpd, ixp_sessions,
++ (ixp_sesnum / 2) * sizeof(struct ixp_data *));
++ kfree(ixp_sessions);
++ }
++
++ ixp_sessions = ixpd;
++ }
++
++ ixp_sessions[i] = (struct ixp_data *) kmalloc(sizeof(struct ixp_data),
++ SLAB_ATOMIC);
++ if (ixp_sessions[i] == NULL) {
++ ixp_freesession(NULL, i);
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return ENOBUFS;
++ }
++
++ *sid = i;
++
++ ixp = ixp_sessions[i];
++ memset(ixp, 0, sizeof(*ixp));
++
++ ixp->ixp_cipher_alg = -1;
++ ixp->ixp_auth_alg = -1;
++ ixp->ixp_ctx_id = -1;
++ INIT_LIST_HEAD(&ixp->ixp_q);
++
++ ixp->ixp_ctx.useDifferentSrcAndDestMbufs = 0;
++
++ while (cri) {
++ switch (cri->cri_alg) {
++ case CRYPTO_DES_CBC:
++ ixp->ixp_cipher_alg = cri->cri_alg;
++ ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_DES;
++ ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC;
++ ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8;
++ ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64;
++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen =
++ IX_CRYPTO_ACC_DES_IV_64;
++ memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey,
++ cri->cri_key, (cri->cri_klen + 7) / 8);
++ break;
++
++ case CRYPTO_3DES_CBC:
++ ixp->ixp_cipher_alg = cri->cri_alg;
++ ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES;
++ ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC;
++ ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8;
++ ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64;
++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen =
++ IX_CRYPTO_ACC_DES_IV_64;
++ memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey,
++ cri->cri_key, (cri->cri_klen + 7) / 8);
++ break;
++
++ case CRYPTO_RIJNDAEL128_CBC:
++ ixp->ixp_cipher_alg = cri->cri_alg;
++ ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_AES;
++ ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC;
++ ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8;
++ ixp->ixp_ctx.cipherCtx.cipherBlockLen = 16;
++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = 16;
++ memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey,
++ cri->cri_key, (cri->cri_klen + 7) / 8);
++ break;
++
++ case CRYPTO_MD5:
++ case CRYPTO_MD5_HMAC:
++ ixp->ixp_auth_alg = cri->cri_alg;
++ ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_MD5;
++ ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, MD5_HASH_LEN);
++ ixp->ixp_ctx.authCtx.aadLen = 0;
++ /* Only MD5_HMAC needs a key */
++ if (cri->cri_alg == CRYPTO_MD5_HMAC) {
++ ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8;
++ if (ixp->ixp_ctx.authCtx.authKeyLen >
++ sizeof(ixp->ixp_ctx.authCtx.key.authKey)) {
++ printk(
++ "ixp4xx: Invalid key length for MD5_HMAC - %d bits\n",
++ cri->cri_klen);
++ ixp_freesession(NULL, i);
++ return EINVAL;
++ }
++ memcpy(ixp->ixp_ctx.authCtx.key.authKey,
++ cri->cri_key, (cri->cri_klen + 7) / 8);
++ }
++ break;
++
++ case CRYPTO_SHA1:
++ case CRYPTO_SHA1_HMAC:
++ ixp->ixp_auth_alg = cri->cri_alg;
++ ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1;
++ ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, SHA1_HASH_LEN);
++ ixp->ixp_ctx.authCtx.aadLen = 0;
++ /* Only SHA1_HMAC needs a key */
++ if (cri->cri_alg == CRYPTO_SHA1_HMAC) {
++ ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8;
++ if (ixp->ixp_ctx.authCtx.authKeyLen >
++ sizeof(ixp->ixp_ctx.authCtx.key.authKey)) {
++ printk(
++ "ixp4xx: Invalid key length for SHA1_HMAC - %d bits\n",
++ cri->cri_klen);
++ ixp_freesession(NULL, i);
++ return EINVAL;
++ }
++ memcpy(ixp->ixp_ctx.authCtx.key.authKey,
++ cri->cri_key, (cri->cri_klen + 7) / 8);
++ }
++ break;
++
++ default:
++ printk("ixp: unknown algo 0x%x\n", cri->cri_alg);
++ ixp_freesession(NULL, i);
++ return EINVAL;
++ }
++ cri = cri->cri_next;
++ }
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++ INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending_wq);
++ INIT_WORK(&ixp->ixp_registration_work, ixp_registration_wq);
++#else
++ INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending, ixp);
++ INIT_WORK(&ixp->ixp_registration_work, ixp_registration, ixp);
++#endif
++
++ return 0;
++}
++
++
++/*
++ * Free a session.
++ */
++static int
++ixp_freesession(device_t dev, u_int64_t tid)
++{
++ u_int32_t sid = CRYPTO_SESID2LID(tid);
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (sid > ixp_sesnum || ixp_sessions == NULL ||
++ ixp_sessions[sid] == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ /* Silently accept and return */
++ if (sid == 0)
++ return 0;
++
++ if (ixp_sessions[sid]) {
++ if (ixp_sessions[sid]->ixp_ctx_id != -1) {
++ ixCryptoAccCtxUnregister(ixp_sessions[sid]->ixp_ctx_id);
++ ixp_sessions[sid]->ixp_ctx_id = -1;
++ }
++ kfree(ixp_sessions[sid]);
++ }
++ ixp_sessions[sid] = NULL;
++ if (ixp_blocked) {
++ ixp_blocked = 0;
++ crypto_unblock(ixp_id, CRYPTO_SYMQ);
++ }
++ return 0;
++}
++
++
++/*
++ * callback for when hash processing is complete
++ */
++
++static void
++ixp_hash_perform_cb(
++ UINT32 hash_key_id,
++ IX_MBUF *bufp,
++ IxCryptoAccStatus status)
++{
++ struct ixp_q *q;
++
++ dprintk("%s(%u, %p, 0x%x)\n", __FUNCTION__, hash_key_id, bufp, status);
++
++ if (bufp == NULL) {
++ printk("ixp: NULL buf in %s\n", __FUNCTION__);
++ return;
++ }
++
++ q = IX_MBUF_PRIV(bufp);
++ if (q == NULL) {
++ printk("ixp: NULL priv in %s\n", __FUNCTION__);
++ return;
++ }
++
++ if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) {
++ /* On success, need to copy hash back into original client buffer */
++ memcpy(q->ixp_hash_dest, q->ixp_hash_src,
++ (q->ixp_q_data->ixp_auth_alg == CRYPTO_SHA1) ?
++ SHA1_HASH_LEN : MD5_HASH_LEN);
++ }
++ else {
++ printk("ixp: hash perform failed status=%d\n", status);
++ q->ixp_q_crp->crp_etype = EINVAL;
++ }
++
++ /* Free internal buffer used for hashing */
++ kfree(IX_MBUF_MDATA(&q->ixp_q_mbuf));
++
++ crypto_done(q->ixp_q_crp);
++ kmem_cache_free(qcache, q);
++}
++
++/*
++ * setup a request and perform it
++ */
++static void
++ixp_q_process(struct ixp_q *q)
++{
++ IxCryptoAccStatus status;
++ struct ixp_data *ixp = q->ixp_q_data;
++ int auth_off = 0;
++ int auth_len = 0;
++ int crypt_off = 0;
++ int crypt_len = 0;
++ int icv_off = 0;
++ char *crypt_func;
++
++ dprintk("%s(%p)\n", __FUNCTION__, q);
++
++ if (q->ixp_q_ccrd) {
++ if (q->ixp_q_ccrd->crd_flags & CRD_F_IV_EXPLICIT) {
++ q->ixp_q_iv = q->ixp_q_ccrd->crd_iv;
++ } else {
++ q->ixp_q_iv = q->ixp_q_iv_data;
++ crypto_copydata(q->ixp_q_crp->crp_flags, q->ixp_q_crp->crp_buf,
++ q->ixp_q_ccrd->crd_inject,
++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen,
++ (caddr_t) q->ixp_q_iv);
++ }
++
++ if (q->ixp_q_acrd) {
++ auth_off = q->ixp_q_acrd->crd_skip;
++ auth_len = q->ixp_q_acrd->crd_len;
++ icv_off = q->ixp_q_acrd->crd_inject;
++ }
++
++ crypt_off = q->ixp_q_ccrd->crd_skip;
++ crypt_len = q->ixp_q_ccrd->crd_len;
++ } else { /* if (q->ixp_q_acrd) */
++ auth_off = q->ixp_q_acrd->crd_skip;
++ auth_len = q->ixp_q_acrd->crd_len;
++ icv_off = q->ixp_q_acrd->crd_inject;
++ }
++
++ if (q->ixp_q_crp->crp_flags & CRYPTO_F_SKBUF) {
++ struct sk_buff *skb = (struct sk_buff *) q->ixp_q_crp->crp_buf;
++ if (skb_shinfo(skb)->nr_frags) {
++ /*
++ * DAVIDM fix this limitation one day by using
++ * a buffer pool and chaining, it is not currently
++ * needed for current user/kernel space acceleration
++ */
++ printk("ixp: Cannot handle fragmented skb's yet !\n");
++ q->ixp_q_crp->crp_etype = ENOENT;
++ goto done;
++ }
++ IX_MBUF_MLEN(&q->ixp_q_mbuf) =
++ IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = skb->len;
++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = skb->data;
++ } else if (q->ixp_q_crp->crp_flags & CRYPTO_F_IOV) {
++ struct uio *uiop = (struct uio *) q->ixp_q_crp->crp_buf;
++ if (uiop->uio_iovcnt != 1) {
++ /*
++ * DAVIDM fix this limitation one day by using
++ * a buffer pool and chaining, it is not currently
++ * needed for current user/kernel space acceleration
++ */
++ printk("ixp: Cannot handle more than 1 iovec yet !\n");
++ q->ixp_q_crp->crp_etype = ENOENT;
++ goto done;
++ }
++ IX_MBUF_MLEN(&q->ixp_q_mbuf) =
++ IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_len;
++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_base;
++ } else /* contig buffer */ {
++ IX_MBUF_MLEN(&q->ixp_q_mbuf) =
++ IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_ilen;
++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_buf;
++ }
++
++ IX_MBUF_PRIV(&q->ixp_q_mbuf) = q;
++
++ if (ixp->ixp_auth_alg == CRYPTO_SHA1 || ixp->ixp_auth_alg == CRYPTO_MD5) {
++ /*
++ * For SHA1 and MD5 hash, need to create an internal buffer that is big
++ * enough to hold the original data + the appropriate padding for the
++ * hash algorithm.
++ */
++ UINT8 *tbuf = NULL;
++
++ IX_MBUF_MLEN(&q->ixp_q_mbuf) = IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) =
++ ((IX_MBUF_MLEN(&q->ixp_q_mbuf) * 8) + 72 + 511) / 8;
++ tbuf = kmalloc(IX_MBUF_MLEN(&q->ixp_q_mbuf), SLAB_ATOMIC);
++
++ if (IX_MBUF_MDATA(&q->ixp_q_mbuf) == NULL) {
++ printk("ixp: kmalloc(%u, SLAB_ATOMIC) failed\n",
++ IX_MBUF_MLEN(&q->ixp_q_mbuf));
++ q->ixp_q_crp->crp_etype = ENOMEM;
++ goto done;
++ }
++ memcpy(tbuf, &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off], auth_len);
++
++ /* Set location in client buffer to copy hash into */
++ q->ixp_hash_dest =
++ &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off + auth_len];
++
++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = tbuf;
++
++ /* Set location in internal buffer for where hash starts */
++ q->ixp_hash_src = &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_len];
++
++ crypt_func = "ixCryptoAccHashPerform";
++ status = ixCryptoAccHashPerform(ixp->ixp_ctx.authCtx.authAlgo,
++ &q->ixp_q_mbuf, ixp_hash_perform_cb, 0, auth_len, auth_len,
++ &ixp->ixp_hash_key_id);
++ }
++ else {
++ crypt_func = "ixCryptoAccAuthCryptPerform";
++ status = ixCryptoAccAuthCryptPerform(ixp->ixp_ctx_id, &q->ixp_q_mbuf,
++ NULL, auth_off, auth_len, crypt_off, crypt_len, icv_off,
++ q->ixp_q_iv);
++ }
++
++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status)
++ return;
++
++ if (IX_CRYPTO_ACC_STATUS_QUEUE_FULL == status) {
++ q->ixp_q_crp->crp_etype = ENOMEM;
++ goto done;
++ }
++
++ printk("ixp: %s failed %u\n", crypt_func, status);
++ q->ixp_q_crp->crp_etype = EINVAL;
++
++done:
++ crypto_done(q->ixp_q_crp);
++ kmem_cache_free(qcache, q);
++}
++
++
++/*
++ * because we cannot process the Q from the Register callback
++ * we do it here on a task Q.
++ */
++
++static void
++ixp_process_pending(void *arg)
++{
++ struct ixp_data *ixp = arg;
++ struct ixp_q *q = NULL;
++
++ dprintk("%s(%p)\n", __FUNCTION__, arg);
++
++ if (!ixp)
++ return;
++
++ while (!list_empty(&ixp->ixp_q)) {
++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list);
++ list_del(&q->ixp_q_list);
++ ixp_q_process(q);
++ }
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void
++ixp_process_pending_wq(struct work_struct *work)
++{
++ struct ixp_data *ixp = container_of(work, struct ixp_data, ixp_pending_work);
++ ixp_process_pending(ixp);
++}
++#endif
++
++/*
++ * callback for when context registration is complete
++ */
++
++static void
++ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status)
++{
++ int i;
++ struct ixp_data *ixp;
++ struct ixp_q *q;
++
++ dprintk("%s(%d, %p, %d)\n", __FUNCTION__, ctx_id, bufp, status);
++
++ /*
++ * free any buffer passed in to this routine
++ */
++ if (bufp) {
++ IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0;
++ kfree(IX_MBUF_MDATA(bufp));
++ IX_MBUF_MDATA(bufp) = NULL;
++ }
++
++ for (i = 0; i < ixp_sesnum; i++) {
++ ixp = ixp_sessions[i];
++ if (ixp && ixp->ixp_ctx_id == ctx_id)
++ break;
++ }
++ if (i >= ixp_sesnum) {
++ printk("ixp: invalid context id %d\n", ctx_id);
++ return;
++ }
++
++ if (IX_CRYPTO_ACC_STATUS_WAIT == status) {
++ /* this is normal to free the first of two buffers */
++ dprintk("ixp: register not finished yet.\n");
++ return;
++ }
++
++ if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) {
++ printk("ixp: register failed 0x%x\n", status);
++ while (!list_empty(&ixp->ixp_q)) {
++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list);
++ list_del(&q->ixp_q_list);
++ q->ixp_q_crp->crp_etype = EINVAL;
++ crypto_done(q->ixp_q_crp);
++ kmem_cache_free(qcache, q);
++ }
++ return;
++ }
++
++ /*
++ * we are now registered, we cannot start processing the Q here
++ * or we get strange errors with AES (DES/3DES seem to be ok).
++ */
++ ixp->ixp_registered = 1;
++ schedule_work(&ixp->ixp_pending_work);
++}
++
++
++/*
++ * callback for when data processing is complete
++ */
++
++static void
++ixp_perform_cb(
++ UINT32 ctx_id,
++ IX_MBUF *sbufp,
++ IX_MBUF *dbufp,
++ IxCryptoAccStatus status)
++{
++ struct ixp_q *q;
++
++ dprintk("%s(%d, %p, %p, 0x%x)\n", __FUNCTION__, ctx_id, sbufp,
++ dbufp, status);
++
++ if (sbufp == NULL) {
++ printk("ixp: NULL sbuf in ixp_perform_cb\n");
++ return;
++ }
++
++ q = IX_MBUF_PRIV(sbufp);
++ if (q == NULL) {
++ printk("ixp: NULL priv in ixp_perform_cb\n");
++ return;
++ }
++
++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) {
++ printk("ixp: perform failed status=%d\n", status);
++ q->ixp_q_crp->crp_etype = EINVAL;
++ }
++
++ crypto_done(q->ixp_q_crp);
++ kmem_cache_free(qcache, q);
++}
++
++
++/*
++ * registration is not callable at IRQ time, so we defer
++ * to a task queue, this routines completes the registration for us
++ * when the task queue runs
++ *
++ * Unfortunately this means we cannot tell OCF that the driver is blocked,
++ * we do that on the next request.
++ */
++
++static void
++ixp_registration(void *arg)
++{
++ struct ixp_data *ixp = arg;
++ struct ixp_q *q = NULL;
++ IX_MBUF *pri = NULL, *sec = NULL;
++ int status = IX_CRYPTO_ACC_STATUS_SUCCESS;
++
++ if (!ixp) {
++ printk("ixp: ixp_registration with no arg\n");
++ return;
++ }
++
++ if (ixp->ixp_ctx_id != -1) {
++ ixCryptoAccCtxUnregister(ixp->ixp_ctx_id);
++ ixp->ixp_ctx_id = -1;
++ }
++
++ if (list_empty(&ixp->ixp_q)) {
++ printk("ixp: ixp_registration with no Q\n");
++ return;
++ }
++
++ /*
++ * setup the primary and secondary buffers
++ */
++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list);
++ if (q->ixp_q_acrd) {
++ pri = &ixp->ixp_pri_mbuf;
++ sec = &ixp->ixp_sec_mbuf;
++ IX_MBUF_MLEN(pri) = IX_MBUF_PKT_LEN(pri) = 128;
++ IX_MBUF_MDATA(pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC);
++ IX_MBUF_MLEN(sec) = IX_MBUF_PKT_LEN(sec) = 128;
++ IX_MBUF_MDATA(sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC);
++ }
++
++ /* Only need to register if a crypt op or HMAC op */
++ if (!(ixp->ixp_auth_alg == CRYPTO_SHA1 ||
++ ixp->ixp_auth_alg == CRYPTO_MD5)) {
++ status = ixCryptoAccCtxRegister(
++ &ixp->ixp_ctx,
++ pri, sec,
++ ixp_register_cb,
++ ixp_perform_cb,
++ &ixp->ixp_ctx_id);
++ }
++ else {
++ /* Otherwise we start processing pending q */
++ schedule_work(&ixp->ixp_pending_work);
++ }
++
++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status)
++ return;
++
++ if (IX_CRYPTO_ACC_STATUS_EXCEED_MAX_TUNNELS == status) {
++ printk("ixp: ixCryptoAccCtxRegister failed (out of tunnels)\n");
++ ixp_blocked = 1;
++ /* perhaps we should return EGAIN on queued ops ? */
++ return;
++ }
++
++ printk("ixp: ixCryptoAccCtxRegister failed %d\n", status);
++ ixp->ixp_ctx_id = -1;
++
++ /*
++ * everything waiting is toasted
++ */
++ while (!list_empty(&ixp->ixp_q)) {
++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list);
++ list_del(&q->ixp_q_list);
++ q->ixp_q_crp->crp_etype = ENOENT;
++ crypto_done(q->ixp_q_crp);
++ kmem_cache_free(qcache, q);
++ }
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void
++ixp_registration_wq(struct work_struct *work)
++{
++ struct ixp_data *ixp = container_of(work, struct ixp_data,
++ ixp_registration_work);
++ ixp_registration(ixp);
++}
++#endif
++
++/*
++ * Process a request.
++ */
++static int
++ixp_process(device_t dev, struct cryptop *crp, int hint)
++{
++ struct ixp_data *ixp;
++ unsigned int lid;
++ struct ixp_q *q = NULL;
++ int status;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ /* Sanity check */
++ if (crp == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ crp->crp_etype = 0;
++
++ if (ixp_blocked)
++ return ERESTART;
++
++ if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ crp->crp_etype = EINVAL;
++ goto done;
++ }
++
++ /*
++ * find the session we are using
++ */
++
++ lid = crp->crp_sid & 0xffffffff;
++ if (lid >= ixp_sesnum || lid == 0 || ixp_sessions == NULL ||
++ ixp_sessions[lid] == NULL) {
++ crp->crp_etype = ENOENT;
++ dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);
++ goto done;
++ }
++ ixp = ixp_sessions[lid];
++
++ /*
++ * setup a new request ready for queuing
++ */
++ q = kmem_cache_alloc(qcache, SLAB_ATOMIC);
++ if (q == NULL) {
++ dprintk("%s,%d: ENOMEM\n", __FILE__, __LINE__);
++ crp->crp_etype = ENOMEM;
++ goto done;
++ }
++ /*
++ * save some cycles by only zeroing the important bits
++ */
++ memset(&q->ixp_q_mbuf, 0, sizeof(q->ixp_q_mbuf));
++ q->ixp_q_ccrd = NULL;
++ q->ixp_q_acrd = NULL;
++ q->ixp_q_crp = crp;
++ q->ixp_q_data = ixp;
++
++ /*
++ * point the cipher and auth descriptors appropriately
++ * check that we have something to do
++ */
++ if (crp->crp_desc->crd_alg == ixp->ixp_cipher_alg)
++ q->ixp_q_ccrd = crp->crp_desc;
++ else if (crp->crp_desc->crd_alg == ixp->ixp_auth_alg)
++ q->ixp_q_acrd = crp->crp_desc;
++ else {
++ crp->crp_etype = ENOENT;
++ dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__);
++ goto done;
++ }
++ if (crp->crp_desc->crd_next) {
++ if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_cipher_alg)
++ q->ixp_q_ccrd = crp->crp_desc->crd_next;
++ else if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_auth_alg)
++ q->ixp_q_acrd = crp->crp_desc->crd_next;
++ else {
++ crp->crp_etype = ENOENT;
++ dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__);
++ goto done;
++ }
++ }
++
++ /*
++ * If there is a direction change for this context then we mark it as
++ * unregistered and re-register is for the new direction. This is not
++ * a very expensive operation and currently only tends to happen when
++ * user-space application are doing benchmarks
++ *
++ * DM - we should be checking for pending requests before unregistering.
++ */
++ if (q->ixp_q_ccrd && ixp->ixp_registered &&
++ ixp->ixp_crd_flags != (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT)) {
++ dprintk("%s - detected direction change on session\n", __FUNCTION__);
++ ixp->ixp_registered = 0;
++ }
++
++ /*
++ * if we are registered, call straight into the perform code
++ */
++ if (ixp->ixp_registered) {
++ ixp_q_process(q);
++ return 0;
++ }
++
++ /*
++ * the only part of the context not set in newsession is the direction
++ * dependent parts
++ */
++ if (q->ixp_q_ccrd) {
++ ixp->ixp_crd_flags = (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT);
++ if (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT) {
++ ixp->ixp_ctx.operation = q->ixp_q_acrd ?
++ IX_CRYPTO_ACC_OP_ENCRYPT_AUTH : IX_CRYPTO_ACC_OP_ENCRYPT;
++ } else {
++ ixp->ixp_ctx.operation = q->ixp_q_acrd ?
++ IX_CRYPTO_ACC_OP_AUTH_DECRYPT : IX_CRYPTO_ACC_OP_DECRYPT;
++ }
++ } else {
++ /* q->ixp_q_acrd must be set if we are here */
++ ixp->ixp_ctx.operation = IX_CRYPTO_ACC_OP_AUTH_CALC;
++ }
++
++ status = list_empty(&ixp->ixp_q);
++ list_add_tail(&q->ixp_q_list, &ixp->ixp_q);
++ if (status)
++ schedule_work(&ixp->ixp_registration_work);
++ return 0;
++
++done:
++ if (q)
++ kmem_cache_free(qcache, q);
++ crypto_done(crp);
++ return 0;
++}
++
++
++#ifdef __ixp46X
++/*
++ * key processing support for the ixp465
++ */
++
++
++/*
++ * copy a BN (LE) into a buffer (BE) an fill out the op appropriately
++ * assume zeroed and only copy bits that are significant
++ */
++
++static int
++ixp_copy_ibuf(struct crparam *p, IxCryptoAccPkeEauOperand *op, UINT32 *buf)
++{
++ unsigned char *src = (unsigned char *) p->crp_p;
++ unsigned char *dst;
++ int len, bits = p->crp_nbits;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if (bits > MAX_IOP_SIZE * sizeof(UINT32) * 8) {
++ dprintk("%s - ibuf too big (%d > %d)\n", __FUNCTION__,
++ bits, MAX_IOP_SIZE * sizeof(UINT32) * 8);
++ return -1;
++ }
++
++ len = (bits + 31) / 32; /* the number UINT32's needed */
++
++ dst = (unsigned char *) &buf[len];
++ dst--;
++
++ while (bits > 0) {
++ *dst-- = *src++;
++ bits -= 8;
++ }
++
++#if 0 /* no need to zero remaining bits as it is done during request alloc */
++ while (dst > (unsigned char *) buf)
++ *dst-- = '\0';
++#endif
++
++ op->pData = buf;
++ op->dataLen = len;
++ return 0;
++}
++
++/*
++ * copy out the result, be as forgiving as we can about small output buffers
++ */
++
++static int
++ixp_copy_obuf(struct crparam *p, IxCryptoAccPkeEauOpResult *op, UINT32 *buf)
++{
++ unsigned char *dst = (unsigned char *) p->crp_p;
++ unsigned char *src = (unsigned char *) buf;
++ int len, z, bits = p->crp_nbits;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ len = op->dataLen * sizeof(UINT32);
++
++ /* skip leading zeroes to be small buffer friendly */
++ z = 0;
++ while (z < len && src[z] == '\0')
++ z++;
++
++ src += len;
++ src--;
++ len -= z;
++
++ while (len > 0 && bits > 0) {
++ *dst++ = *src--;
++ len--;
++ bits -= 8;
++ }
++
++ while (bits > 0) {
++ *dst++ = '\0';
++ bits -= 8;
++ }
++
++ if (len > 0) {
++ dprintk("%s - obuf is %d (z=%d, ob=%d) bytes too small\n",
++ __FUNCTION__, len, z, p->crp_nbits / 8);
++ return -1;
++ }
++
++ return 0;
++}
++
++
++/*
++ * the parameter offsets for exp_mod
++ */
++
++#define IXP_PARAM_BASE 0
++#define IXP_PARAM_EXP 1
++#define IXP_PARAM_MOD 2
++#define IXP_PARAM_RES 3
++
++/*
++ * key processing complete callback, is also used to start processing
++ * by passing a NULL for pResult
++ */
++
++static void
++ixp_kperform_cb(
++ IxCryptoAccPkeEauOperation operation,
++ IxCryptoAccPkeEauOpResult *pResult,
++ BOOL carryOrBorrow,
++ IxCryptoAccStatus status)
++{
++ struct ixp_pkq *q, *tmp;
++ unsigned long flags;
++
++ dprintk("%s(0x%x, %p, %d, 0x%x)\n", __FUNCTION__, operation, pResult,
++ carryOrBorrow, status);
++
++ /* handle a completed request */
++ if (pResult) {
++ if (ixp_pk_cur && &ixp_pk_cur->pkq_result == pResult) {
++ q = ixp_pk_cur;
++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) {
++ dprintk("%s() - op failed 0x%x\n", __FUNCTION__, status);
++ q->pkq_krp->krp_status = ERANGE; /* could do better */
++ } else {
++ /* copy out the result */
++ if (ixp_copy_obuf(&q->pkq_krp->krp_param[IXP_PARAM_RES],
++ &q->pkq_result, q->pkq_obuf))
++ q->pkq_krp->krp_status = ERANGE;
++ }
++ crypto_kdone(q->pkq_krp);
++ kfree(q);
++ ixp_pk_cur = NULL;
++ } else
++ printk("%s - callback with invalid result pointer\n", __FUNCTION__);
++ }
++
++ spin_lock_irqsave(&ixp_pkq_lock, flags);
++ if (ixp_pk_cur || list_empty(&ixp_pkq)) {
++ spin_unlock_irqrestore(&ixp_pkq_lock, flags);
++ return;
++ }
++
++ list_for_each_entry_safe(q, tmp, &ixp_pkq, pkq_list) {
++
++ list_del(&q->pkq_list);
++ ixp_pk_cur = q;
++
++ spin_unlock_irqrestore(&ixp_pkq_lock, flags);
++
++ status = ixCryptoAccPkeEauPerform(
++ IX_CRYPTO_ACC_OP_EAU_MOD_EXP,
++ &q->pkq_op,
++ ixp_kperform_cb,
++ &q->pkq_result);
++
++ if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) {
++ dprintk("%s() - ixCryptoAccPkeEauPerform SUCCESS\n", __FUNCTION__);
++ return; /* callback will return here for callback */
++ } else if (status == IX_CRYPTO_ACC_STATUS_RETRY) {
++ printk("%s() - ixCryptoAccPkeEauPerform RETRY\n", __FUNCTION__);
++ } else {
++ printk("%s() - ixCryptoAccPkeEauPerform failed %d\n",
++ __FUNCTION__, status);
++ }
++ q->pkq_krp->krp_status = ERANGE; /* could do better */
++ crypto_kdone(q->pkq_krp);
++ kfree(q);
++ spin_lock_irqsave(&ixp_pkq_lock, flags);
++ }
++ spin_unlock_irqrestore(&ixp_pkq_lock, flags);
++}
++
++
++static int
++ixp_kprocess(device_t dev, struct cryptkop *krp, int hint)
++{
++ struct ixp_pkq *q;
++ int rc = 0;
++ unsigned long flags;
++
++ dprintk("%s l1=%d l2=%d l3=%d l4=%d\n", __FUNCTION__,
++ krp->krp_param[IXP_PARAM_BASE].crp_nbits,
++ krp->krp_param[IXP_PARAM_EXP].crp_nbits,
++ krp->krp_param[IXP_PARAM_MOD].crp_nbits,
++ krp->krp_param[IXP_PARAM_RES].crp_nbits);
++
++
++ if (krp->krp_op != CRK_MOD_EXP) {
++ krp->krp_status = EOPNOTSUPP;
++ goto err;
++ }
++
++ q = (struct ixp_pkq *) kmalloc(sizeof(*q), GFP_KERNEL);
++ if (q == NULL) {
++ krp->krp_status = ENOMEM;
++ goto err;
++ }
++
++ /*
++ * The PKE engine does not appear to zero the output buffer
++ * appropriately, so we need to do it all here.
++ */
++ memset(q, 0, sizeof(*q));
++
++ q->pkq_krp = krp;
++ INIT_LIST_HEAD(&q->pkq_list);
++
++ if (ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_BASE], &q->pkq_op.modExpOpr.M,
++ q->pkq_ibuf0))
++ rc = 1;
++ if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_EXP],
++ &q->pkq_op.modExpOpr.e, q->pkq_ibuf1))
++ rc = 2;
++ if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_MOD],
++ &q->pkq_op.modExpOpr.N, q->pkq_ibuf2))
++ rc = 3;
++
++ if (rc) {
++ kfree(q);
++ krp->krp_status = ERANGE;
++ goto err;
++ }
++
++ q->pkq_result.pData = q->pkq_obuf;
++ q->pkq_result.dataLen =
++ (krp->krp_param[IXP_PARAM_RES].crp_nbits + 31) / 32;
++
++ spin_lock_irqsave(&ixp_pkq_lock, flags);
++ list_add_tail(&q->pkq_list, &ixp_pkq);
++ spin_unlock_irqrestore(&ixp_pkq_lock, flags);
++
++ if (!ixp_pk_cur)
++ ixp_kperform_cb(0, NULL, 0, 0);
++ return (0);
++
++err:
++ crypto_kdone(krp);
++ return (0);
++}
++
++
++
++#ifdef CONFIG_OCF_RANDOMHARVEST
++/*
++ * We run the random number generator output through SHA so that it
++ * is FIPS compliant.
++ */
++
++static volatile int sha_done = 0;
++static unsigned char sha_digest[20];
++
++static void
++ixp_hash_cb(UINT8 *digest, IxCryptoAccStatus status)
++{
++ dprintk("%s(%p, %d)\n", __FUNCTION__, digest, status);
++ if (sha_digest != digest)
++ printk("digest error\n");
++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status)
++ sha_done = 1;
++ else
++ sha_done = -status;
++}
++
++static int
++ixp_read_random(void *arg, u_int32_t *buf, int maxwords)
++{
++ IxCryptoAccStatus status;
++ int i, n, rc;
++
++ dprintk("%s(%p, %d)\n", __FUNCTION__, buf, maxwords);
++ memset(buf, 0, maxwords * sizeof(*buf));
++ status = ixCryptoAccPkePseudoRandomNumberGet(maxwords, buf);
++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) {
++ dprintk("%s: ixCryptoAccPkePseudoRandomNumberGet failed %d\n",
++ __FUNCTION__, status);
++ return 0;
++ }
++
++ /*
++ * run the random data through SHA to make it look more random
++ */
++
++ n = sizeof(sha_digest); /* process digest bytes at a time */
++
++ rc = 0;
++ for (i = 0; i < maxwords; i += n / sizeof(*buf)) {
++ if ((maxwords - i) * sizeof(*buf) < n)
++ n = (maxwords - i) * sizeof(*buf);
++ sha_done = 0;
++ status = ixCryptoAccPkeHashPerform(IX_CRYPTO_ACC_AUTH_SHA1,
++ (UINT8 *) &buf[i], n, ixp_hash_cb, sha_digest);
++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) {
++ dprintk("ixCryptoAccPkeHashPerform failed %d\n", status);
++ return -EIO;
++ }
++ while (!sha_done)
++ schedule();
++ if (sha_done < 0) {
++ dprintk("ixCryptoAccPkeHashPerform failed CB %d\n", -sha_done);
++ return 0;
++ }
++ memcpy(&buf[i], sha_digest, n);
++ rc += n / sizeof(*buf);;
++ }
++
++ return rc;
++}
++#endif /* CONFIG_OCF_RANDOMHARVEST */
++
++#endif /* __ixp46X */
++
++
++
++/*
++ * our driver startup and shutdown routines
++ */
++
++static int
++ixp_init(void)
++{
++ dprintk("%s(%p)\n", __FUNCTION__, ixp_init);
++
++ if (ixp_init_crypto && ixCryptoAccInit() != IX_CRYPTO_ACC_STATUS_SUCCESS)
++ printk("ixCryptoAccInit failed, assuming already initialised!\n");
++
++ qcache = kmem_cache_create("ixp4xx_q", sizeof(struct ixp_q), 0,
++ SLAB_HWCACHE_ALIGN, NULL
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++ , NULL
++#endif
++ );
++ if (!qcache) {
++ printk("failed to create Qcache\n");
++ return -ENOENT;
++ }
++
++ memset(&ixpdev, 0, sizeof(ixpdev));
++ softc_device_init(&ixpdev, "ixp4xx", 0, ixp_methods);
++
++ ixp_id = crypto_get_driverid(softc_get_device(&ixpdev),
++ CRYPTOCAP_F_HARDWARE);
++ if (ixp_id < 0)
++ panic("IXP/OCF crypto device cannot initialize!");
++
++#define REGISTER(alg) \
++ crypto_register(ixp_id,alg,0,0)
++
++ REGISTER(CRYPTO_DES_CBC);
++ REGISTER(CRYPTO_3DES_CBC);
++ REGISTER(CRYPTO_RIJNDAEL128_CBC);
++#ifdef CONFIG_OCF_IXP4XX_SHA1_MD5
++ REGISTER(CRYPTO_MD5);
++ REGISTER(CRYPTO_SHA1);
++#endif
++ REGISTER(CRYPTO_MD5_HMAC);
++ REGISTER(CRYPTO_SHA1_HMAC);
++#undef REGISTER
++
++#ifdef __ixp46X
++ spin_lock_init(&ixp_pkq_lock);
++ /*
++ * we do not enable the go fast options here as they can potentially
++ * allow timing based attacks
++ *
++ * http://www.openssl.org/news/secadv_20030219.txt
++ */
++ ixCryptoAccPkeEauExpConfig(0, 0);
++ crypto_kregister(ixp_id, CRK_MOD_EXP, 0);
++#ifdef CONFIG_OCF_RANDOMHARVEST
++ crypto_rregister(ixp_id, ixp_read_random, NULL);
++#endif
++#endif
++
++ return 0;
++}
++
++static void
++ixp_exit(void)
++{
++ dprintk("%s()\n", __FUNCTION__);
++ crypto_unregister_all(ixp_id);
++ ixp_id = -1;
++ kmem_cache_destroy(qcache);
++ qcache = NULL;
++}
++
++module_init(ixp_init);
++module_exit(ixp_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("David McCullough <dmccullough@cyberguard.com>");
++MODULE_DESCRIPTION("ixp (OCF module for IXP4xx crypto)");
+diff -Nur linux-2.6.36.orig/crypto/ocf/ixp4xx/Makefile linux-2.6.36/crypto/ocf/ixp4xx/Makefile
+--- linux-2.6.36.orig/crypto/ocf/ixp4xx/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/ixp4xx/Makefile 2010-11-09 20:28:05.113478850 +0100
+@@ -0,0 +1,104 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++#
++# You will need to point this at your Intel ixp425 includes, this portion
++# of the Makefile only really works under SGLinux with the appropriate libs
++# installed. They can be downloaded from http://www.snapgear.org/
++#
++ifeq ($(CONFIG_CPU_IXP46X),y)
++IXPLATFORM = ixp46X
++else
++ifeq ($(CONFIG_CPU_IXP43X),y)
++IXPLATFORM = ixp43X
++else
++IXPLATFORM = ixp42X
++endif
++endif
++
++ifdef CONFIG_IXP400_LIB_2_4
++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.4/ixp400_xscale_sw
++OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.4/ixp_osal
++endif
++ifdef CONFIG_IXP400_LIB_2_1
++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.1/ixp400_xscale_sw
++OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.1/ixp_osal
++endif
++ifdef CONFIG_IXP400_LIB_2_0
++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.0/ixp400_xscale_sw
++OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.0/ixp_osal
++endif
++ifdef IX_XSCALE_SW
++ifdef CONFIG_IXP400_LIB_2_4
++IXP_CFLAGS = \
++ -I$(ROOTDIR)/. \
++ -I$(IX_XSCALE_SW)/src/include \
++ -I$(OSAL_DIR)/common/include/ \
++ -I$(OSAL_DIR)/common/include/modules/ \
++ -I$(OSAL_DIR)/common/include/modules/ddk/ \
++ -I$(OSAL_DIR)/common/include/modules/bufferMgt/ \
++ -I$(OSAL_DIR)/common/include/modules/ioMem/ \
++ -I$(OSAL_DIR)/common/os/linux/include/ \
++ -I$(OSAL_DIR)/common/os/linux/include/core/ \
++ -I$(OSAL_DIR)/common/os/linux/include/modules/ \
++ -I$(OSAL_DIR)/common/os/linux/include/modules/ddk/ \
++ -I$(OSAL_DIR)/common/os/linux/include/modules/bufferMgt/ \
++ -I$(OSAL_DIR)/common/os/linux/include/modules/ioMem/ \
++ -I$(OSAL_DIR)/platforms/$(IXPLATFORM)/include/ \
++ -I$(OSAL_DIR)/platforms/$(IXPLATFORM)/os/linux/include/ \
++ -DENABLE_IOMEM -DENABLE_BUFFERMGT -DENABLE_DDK \
++ -DUSE_IXP4XX_CRYPTO
++else
++IXP_CFLAGS = \
++ -I$(ROOTDIR)/. \
++ -I$(IX_XSCALE_SW)/src/include \
++ -I$(OSAL_DIR)/ \
++ -I$(OSAL_DIR)/os/linux/include/ \
++ -I$(OSAL_DIR)/os/linux/include/modules/ \
++ -I$(OSAL_DIR)/os/linux/include/modules/ioMem/ \
++ -I$(OSAL_DIR)/os/linux/include/modules/bufferMgt/ \
++ -I$(OSAL_DIR)/os/linux/include/core/ \
++ -I$(OSAL_DIR)/os/linux/include/platforms/ \
++ -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ \
++ -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ixp425 \
++ -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ixp465 \
++ -I$(OSAL_DIR)/os/linux/include/core/ \
++ -I$(OSAL_DIR)/include/ \
++ -I$(OSAL_DIR)/include/modules/ \
++ -I$(OSAL_DIR)/include/modules/bufferMgt/ \
++ -I$(OSAL_DIR)/include/modules/ioMem/ \
++ -I$(OSAL_DIR)/include/platforms/ \
++ -I$(OSAL_DIR)/include/platforms/ixp400/ \
++ -DUSE_IXP4XX_CRYPTO
++endif
++endif
++ifdef CONFIG_IXP400_LIB_1_4
++IXP_CFLAGS = \
++ -I$(ROOTDIR)/. \
++ -I$(ROOTDIR)/modules/ixp425/ixp400-1.4/ixp400_xscale_sw/src/include \
++ -I$(ROOTDIR)/modules/ixp425/ixp400-1.4/ixp400_xscale_sw/src/linux \
++ -DUSE_IXP4XX_CRYPTO
++endif
++ifndef IXPDIR
++IXPDIR = ixp-version-is-not-supported
++endif
++
++ifeq ($(CONFIG_CPU_IXP46X),y)
++IXP_CFLAGS += -D__ixp46X
++else
++ifeq ($(CONFIG_CPU_IXP43X),y)
++IXP_CFLAGS += -D__ixp43X
++else
++IXP_CFLAGS += -D__ixp42X
++endif
++endif
++
++obj-$(CONFIG_OCF_IXP4XX) += ixp4xx.o
++
++obj ?= .
++EXTRA_CFLAGS += $(IXP_CFLAGS) -I$(obj)/.. -I$(obj)/.
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/Kconfig linux-2.6.36/crypto/ocf/Kconfig
+--- linux-2.6.36.orig/crypto/ocf/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/Kconfig 2010-11-09 20:28:05.141255099 +0100
+@@ -0,0 +1,119 @@
++menu "OCF Configuration"
++
++config OCF_OCF
++ tristate "OCF (Open Cryptograhic Framework)"
++ help
++ A linux port of the OpenBSD/FreeBSD crypto framework.
++
++config OCF_RANDOMHARVEST
++ bool "crypto random --- harvest entropy for /dev/random"
++ depends on OCF_OCF
++ help
++ Includes code to harvest random numbers from devices that support it.
++
++config OCF_FIPS
++ bool "enable fips RNG checks"
++ depends on OCF_OCF && OCF_RANDOMHARVEST
++ help
++ Run all RNG provided data through a fips check before
++ adding it /dev/random's entropy pool.
++
++config OCF_CRYPTODEV
++ tristate "cryptodev (user space support)"
++ depends on OCF_OCF
++ help
++ The user space API to access crypto hardware.
++
++config OCF_CRYPTOSOFT
++ tristate "cryptosoft (software crypto engine)"
++ depends on OCF_OCF
++ help
++ A software driver for the OCF framework that uses
++ the kernel CryptoAPI.
++
++config OCF_SAFE
++ tristate "safenet (HW crypto engine)"
++ depends on OCF_OCF
++ help
++ A driver for a number of the safenet Excel crypto accelerators.
++ Currently tested and working on the 1141 and 1741.
++
++config OCF_IXP4XX
++ tristate "IXP4xx (HW crypto engine)"
++ depends on OCF_OCF
++ help
++ XScale IXP4xx crypto accelerator driver. Requires the
++ Intel Access library.
++
++config OCF_IXP4XX_SHA1_MD5
++ bool "IXP4xx SHA1 and MD5 Hashing"
++ depends on OCF_IXP4XX
++ help
++ Allows the IXP4xx crypto accelerator to perform SHA1 and MD5 hashing.
++ Note: this is MUCH slower than using cryptosoft (software crypto engine).
++
++config OCF_HIFN
++ tristate "hifn (HW crypto engine)"
++ depends on OCF_OCF
++ help
++ OCF driver for various HIFN based crypto accelerators.
++ (7951, 7955, 7956, 7751, 7811)
++
++config OCF_HIFNHIPP
++ tristate "Hifn HIPP (HW packet crypto engine)"
++ depends on OCF_OCF
++ help
++ OCF driver for various HIFN (HIPP) based crypto accelerators
++ (7855)
++
++config OCF_TALITOS
++ tristate "talitos (HW crypto engine)"
++ depends on OCF_OCF
++ help
++ OCF driver for Freescale's security engine (SEC/talitos).
++
++config OCF_PASEMI
++ tristate "pasemi (HW crypto engine)"
++ depends on OCF_OCF && PPC_PASEMI
++ help
++ OCF driver for the PA Semi PWRficient DMA Engine
++
++config OCF_EP80579
++ tristate "ep80579 (HW crypto engine)"
++ depends on OCF_OCF
++ help
++ OCF driver for the Intel EP80579 Integrated Processor Product Line.
++
++config OCF_CRYPTOCTEON
++ tristate "cryptocteon (HW crypto engine)"
++ depends on OCF_OCF
++ help
++ OCF driver for the Cavium OCTEON Processors.
++
++config OCF_KIRKWOOD
++ tristate "kirkwood (HW crypto engine)"
++ depends on OCF_OCF
++ help
++ OCF driver for the Marvell Kirkwood (88F6xxx) Processors.
++
++config OCF_C7108
++ tristate "Micronas 7108 (HW crypto engine)"
++ depends on OCF_OCF
++ help
++ OCF driver for the Microna 7108 Cipher processors.
++
++config OCF_OCFNULL
++ tristate "ocfnull (fake crypto engine)"
++ depends on OCF_OCF
++ help
++ OCF driver for measuring ipsec overheads (does no crypto)
++
++config OCF_BENCH
++ tristate "ocf-bench (HW crypto in-kernel benchmark)"
++ depends on OCF_OCF
++ help
++ A very simple encryption test for the in-kernel interface
++ of OCF. Also includes code to benchmark the IXP Access library
++ for comparison.
++
++endmenu
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.c linux-2.6.36/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.c 2010-11-09 20:28:05.189557501 +0100
+@@ -0,0 +1,317 @@
++/* rijndael-alg-ref.c v2.0 August '99
++ * Reference ANSI C code
++ * authors: Paulo Barreto
++ * Vincent Rijmen, K.U.Leuven
++ *
++ * This code is placed in the public domain.
++ */
++
++#include "mvOs.h"
++
++#include "mvAesAlg.h"
++
++#include "mvAesBoxes.dat"
++
++
++MV_U8 mul1(MV_U8 aa, MV_U8 bb);
++void KeyAddition(MV_U8 a[4][MAXBC], MV_U8 rk[4][MAXBC], MV_U8 BC);
++void ShiftRow128Enc(MV_U8 a[4][MAXBC]);
++void ShiftRow128Dec(MV_U8 a[4][MAXBC]);
++void Substitution(MV_U8 a[4][MAXBC], MV_U8 box[256]);
++void MixColumn(MV_U8 a[4][MAXBC], MV_U8 rk[4][MAXBC]);
++void InvMixColumn(MV_U8 a[4][MAXBC]);
++
++
++#define mul(aa, bb) (mask[bb] & Alogtable[aa + Logtable[bb]])
++
++MV_U8 mul1(MV_U8 aa, MV_U8 bb)
++{
++ return mask[bb] & Alogtable[aa + Logtable[bb]];
++}
++
++
++void KeyAddition(MV_U8 a[4][MAXBC], MV_U8 rk[4][MAXBC], MV_U8 BC)
++{
++ /* Exor corresponding text input and round key input bytes
++ */
++ ((MV_U32*)(&(a[0][0])))[0] ^= ((MV_U32*)(&(rk[0][0])))[0];
++ ((MV_U32*)(&(a[1][0])))[0] ^= ((MV_U32*)(&(rk[1][0])))[0];
++ ((MV_U32*)(&(a[2][0])))[0] ^= ((MV_U32*)(&(rk[2][0])))[0];
++ ((MV_U32*)(&(a[3][0])))[0] ^= ((MV_U32*)(&(rk[3][0])))[0];
++
++}
++
++void ShiftRow128Enc(MV_U8 a[4][MAXBC]) {
++ /* Row 0 remains unchanged
++ * The other three rows are shifted a variable amount
++ */
++ MV_U8 tmp[MAXBC];
++
++ tmp[0] = a[1][1];
++ tmp[1] = a[1][2];
++ tmp[2] = a[1][3];
++ tmp[3] = a[1][0];
++
++ ((MV_U32*)(&(a[1][0])))[0] = ((MV_U32*)(&(tmp[0])))[0];
++ /*
++ a[1][0] = tmp[0];
++ a[1][1] = tmp[1];
++ a[1][2] = tmp[2];
++ a[1][3] = tmp[3];
++ */
++ tmp[0] = a[2][2];
++ tmp[1] = a[2][3];
++ tmp[2] = a[2][0];
++ tmp[3] = a[2][1];
++
++ ((MV_U32*)(&(a[2][0])))[0] = ((MV_U32*)(&(tmp[0])))[0];
++ /*
++ a[2][0] = tmp[0];
++ a[2][1] = tmp[1];
++ a[2][2] = tmp[2];
++ a[2][3] = tmp[3];
++ */
++ tmp[0] = a[3][3];
++ tmp[1] = a[3][0];
++ tmp[2] = a[3][1];
++ tmp[3] = a[3][2];
++
++ ((MV_U32*)(&(a[3][0])))[0] = ((MV_U32*)(&(tmp[0])))[0];
++ /*
++ a[3][0] = tmp[0];
++ a[3][1] = tmp[1];
++ a[3][2] = tmp[2];
++ a[3][3] = tmp[3];
++ */
++}
++
++void ShiftRow128Dec(MV_U8 a[4][MAXBC]) {
++ /* Row 0 remains unchanged
++ * The other three rows are shifted a variable amount
++ */
++ MV_U8 tmp[MAXBC];
++
++ tmp[0] = a[1][3];
++ tmp[1] = a[1][0];
++ tmp[2] = a[1][1];
++ tmp[3] = a[1][2];
++
++ ((MV_U32*)(&(a[1][0])))[0] = ((MV_U32*)(&(tmp[0])))[0];
++ /*
++ a[1][0] = tmp[0];
++ a[1][1] = tmp[1];
++ a[1][2] = tmp[2];
++ a[1][3] = tmp[3];
++ */
++
++ tmp[0] = a[2][2];
++ tmp[1] = a[2][3];
++ tmp[2] = a[2][0];
++ tmp[3] = a[2][1];
++
++ ((MV_U32*)(&(a[2][0])))[0] = ((MV_U32*)(&(tmp[0])))[0];
++ /*
++ a[2][0] = tmp[0];
++ a[2][1] = tmp[1];
++ a[2][2] = tmp[2];
++ a[2][3] = tmp[3];
++ */
++
++ tmp[0] = a[3][1];
++ tmp[1] = a[3][2];
++ tmp[2] = a[3][3];
++ tmp[3] = a[3][0];
++
++ ((MV_U32*)(&(a[3][0])))[0] = ((MV_U32*)(&(tmp[0])))[0];
++ /*
++ a[3][0] = tmp[0];
++ a[3][1] = tmp[1];
++ a[3][2] = tmp[2];
++ a[3][3] = tmp[3];
++ */
++}
++
++void Substitution(MV_U8 a[4][MAXBC], MV_U8 box[256]) {
++ /* Replace every byte of the input by the byte at that place
++ * in the nonlinear S-box
++ */
++ int i, j;
++
++ for(i = 0; i < 4; i++)
++ for(j = 0; j < 4; j++) a[i][j] = box[a[i][j]] ;
++}
++
++void MixColumn(MV_U8 a[4][MAXBC], MV_U8 rk[4][MAXBC]) {
++ /* Mix the four bytes of every column in a linear way
++ */
++ MV_U8 b[4][MAXBC];
++ int i, j;
++
++ for(j = 0; j < 4; j++){
++ b[0][j] = mul(25,a[0][j]) ^ mul(1,a[1][j]) ^ a[2][j] ^ a[3][j];
++ b[1][j] = mul(25,a[1][j]) ^ mul(1,a[2][j]) ^ a[3][j] ^ a[0][j];
++ b[2][j] = mul(25,a[2][j]) ^ mul(1,a[3][j]) ^ a[0][j] ^ a[1][j];
++ b[3][j] = mul(25,a[3][j]) ^ mul(1,a[0][j]) ^ a[1][j] ^ a[2][j];
++ }
++ for(i = 0; i < 4; i++)
++ /*for(j = 0; j < BC; j++) a[i][j] = b[i][j];*/
++ ((MV_U32*)(&(a[i][0])))[0] = ((MV_U32*)(&(b[i][0])))[0] ^ ((MV_U32*)(&(rk[i][0])))[0];;
++}
++
++void InvMixColumn(MV_U8 a[4][MAXBC]) {
++ /* Mix the four bytes of every column in a linear way
++ * This is the opposite operation of Mixcolumn
++ */
++ MV_U8 b[4][MAXBC];
++ int i, j;
++
++ for(j = 0; j < 4; j++){
++ b[0][j] = mul(223,a[0][j]) ^ mul(104,a[1][j]) ^ mul(238,a[2][j]) ^ mul(199,a[3][j]);
++ b[1][j] = mul(223,a[1][j]) ^ mul(104,a[2][j]) ^ mul(238,a[3][j]) ^ mul(199,a[0][j]);
++ b[2][j] = mul(223,a[2][j]) ^ mul(104,a[3][j]) ^ mul(238,a[0][j]) ^ mul(199,a[1][j]);
++ b[3][j] = mul(223,a[3][j]) ^ mul(104,a[0][j]) ^ mul(238,a[1][j]) ^ mul(199,a[2][j]);
++ }
++ for(i = 0; i < 4; i++)
++ /*for(j = 0; j < BC; j++) a[i][j] = b[i][j];*/
++ ((MV_U32*)(&(a[i][0])))[0] = ((MV_U32*)(&(b[i][0])))[0];
++}
++
++int rijndaelKeySched (MV_U8 k[4][MAXKC], int keyBits, int blockBits, MV_U8 W[MAXROUNDS+1][4][MAXBC])
++{
++ /* Calculate the necessary round keys
++ * The number of calculations depends on keyBits and blockBits
++ */
++ int KC, BC, ROUNDS;
++ int i, j, t, rconpointer = 0;
++ MV_U8 tk[4][MAXKC];
++
++ switch (keyBits) {
++ case 128: KC = 4; break;
++ case 192: KC = 6; break;
++ case 256: KC = 8; break;
++ default : return (-1);
++ }
++
++ switch (blockBits) {
++ case 128: BC = 4; break;
++ case 192: BC = 6; break;
++ case 256: BC = 8; break;
++ default : return (-2);
++ }
++
++ switch (keyBits >= blockBits ? keyBits : blockBits) {
++ case 128: ROUNDS = 10; break;
++ case 192: ROUNDS = 12; break;
++ case 256: ROUNDS = 14; break;
++ default : return (-3); /* this cannot happen */
++ }
++
++
++ for(j = 0; j < KC; j++)
++ for(i = 0; i < 4; i++)
++ tk[i][j] = k[i][j];
++ t = 0;
++ /* copy values into round key array */
++ for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++)
++ for(i = 0; i < 4; i++) W[t / BC][i][t % BC] = tk[i][j];
++
++ while (t < (ROUNDS+1)*BC) { /* while not enough round key material calculated */
++ /* calculate new values */
++ for(i = 0; i < 4; i++)
++ tk[i][0] ^= S[tk[(i+1)%4][KC-1]];
++ tk[0][0] ^= rcon[rconpointer++];
++
++ if (KC != 8)
++ for(j = 1; j < KC; j++)
++ for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1];
++ else {
++ for(j = 1; j < KC/2; j++)
++ for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1];
++ for(i = 0; i < 4; i++) tk[i][KC/2] ^= S[tk[i][KC/2 - 1]];
++ for(j = KC/2 + 1; j < KC; j++)
++ for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1];
++ }
++ /* copy values into round key array */
++ for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++)
++ for(i = 0; i < 4; i++) W[t / BC][i][t % BC] = tk[i][j];
++ }
++
++ return 0;
++}
++
++
++
++int rijndaelEncrypt128(MV_U8 a[4][MAXBC], MV_U8 rk[MAXROUNDS+1][4][MAXBC], int rounds)
++{
++ /* Encryption of one block.
++ */
++ int r, BC, ROUNDS;
++
++ BC = 4;
++ ROUNDS = rounds;
++
++ /* begin with a key addition
++ */
++
++ KeyAddition(a,rk[0],BC);
++
++ /* ROUNDS-1 ordinary rounds
++ */
++ for(r = 1; r < ROUNDS; r++) {
++ Substitution(a,S);
++ ShiftRow128Enc(a);
++ MixColumn(a, rk[r]);
++ /*KeyAddition(a,rk[r],BC);*/
++ }
++
++ /* Last round is special: there is no MixColumn
++ */
++ Substitution(a,S);
++ ShiftRow128Enc(a);
++ KeyAddition(a,rk[ROUNDS],BC);
++
++ return 0;
++}
++
++
++int rijndaelDecrypt128(MV_U8 a[4][MAXBC], MV_U8 rk[MAXROUNDS+1][4][MAXBC], int rounds)
++{
++ int r, BC, ROUNDS;
++
++ BC = 4;
++ ROUNDS = rounds;
++
++ /* To decrypt: apply the inverse operations of the encrypt routine,
++ * in opposite order
++ *
++ * (KeyAddition is an involution: it 's equal to its inverse)
++ * (the inverse of Substitution with table S is Substitution with the inverse table of S)
++ * (the inverse of Shiftrow is Shiftrow over a suitable distance)
++ */
++
++ /* First the special round:
++ * without InvMixColumn
++ * with extra KeyAddition
++ */
++ KeyAddition(a,rk[ROUNDS],BC);
++ ShiftRow128Dec(a);
++ Substitution(a,Si);
++
++ /* ROUNDS-1 ordinary rounds
++ */
++ for(r = ROUNDS-1; r > 0; r--) {
++ KeyAddition(a,rk[r],BC);
++ InvMixColumn(a);
++ ShiftRow128Dec(a);
++ Substitution(a,Si);
++
++ }
++
++ /* End with the extra key addition
++ */
++
++ KeyAddition(a,rk[0],BC);
++
++ return 0;
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.h linux-2.6.36/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.h 2010-11-09 20:28:05.222495460 +0100
+@@ -0,0 +1,19 @@
++/* rijndael-alg-ref.h v2.0 August '99
++ * Reference ANSI C code
++ * authors: Paulo Barreto
++ * Vincent Rijmen, K.U.Leuven
++ */
++#ifndef __RIJNDAEL_ALG_H
++#define __RIJNDAEL_ALG_H
++
++#define MAXBC (128/32)
++#define MAXKC (256/32)
++#define MAXROUNDS 14
++
++
++int rijndaelKeySched (MV_U8 k[4][MAXKC], int keyBits, int blockBits, MV_U8 rk[MAXROUNDS+1][4][MAXBC]);
++
++int rijndaelEncrypt128(MV_U8 a[4][MAXBC], MV_U8 rk[MAXROUNDS+1][4][MAXBC], int rounds);
++int rijndaelDecrypt128(MV_U8 a[4][MAXBC], MV_U8 rk[MAXROUNDS+1][4][MAXBC], int rounds);
++
++#endif /* __RIJNDAEL_ALG_H */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/AES/mvAesApi.c linux-2.6.36/crypto/ocf/kirkwood/cesa/AES/mvAesApi.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/AES/mvAesApi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/AES/mvAesApi.c 2010-11-09 20:28:05.264499847 +0100
+@@ -0,0 +1,312 @@
++/* rijndael-api-ref.c v2.1 April 2000
++ * Reference ANSI C code
++ * authors: v2.0 Paulo Barreto
++ * Vincent Rijmen, K.U.Leuven
++ * v2.1 Vincent Rijmen, K.U.Leuven
++ *
++ * This code is placed in the public domain.
++ */
++#include "mvOs.h"
++
++#include "mvAes.h"
++#include "mvAesAlg.h"
++
++
++/* Defines:
++ Add any additional defines you need
++*/
++
++#define MODE_ECB 1 /* Are we ciphering in ECB mode? */
++#define MODE_CBC 2 /* Are we ciphering in CBC mode? */
++#define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */
++
++
++int aesMakeKey(MV_U8 *expandedKey, MV_U8 *keyMaterial, int keyLen, int blockLen)
++{
++ MV_U8 W[MAXROUNDS+1][4][MAXBC];
++ MV_U8 k[4][MAXKC];
++ MV_U8 j;
++ int i, rounds, KC;
++
++ if (expandedKey == NULL)
++ {
++ return AES_BAD_KEY_INSTANCE;
++ }
++
++ if (!((keyLen == 128) || (keyLen == 192) || (keyLen == 256)))
++ {
++ return AES_BAD_KEY_MAT;
++ }
++
++ if (keyMaterial == NULL)
++ {
++ return AES_BAD_KEY_MAT;
++ }
++
++ /* initialize key schedule: */
++ for(i=0; i<keyLen/8; i++)
++ {
++ j = keyMaterial[i];
++ k[i % 4][i / 4] = j;
++ }
++
++ rijndaelKeySched (k, keyLen, blockLen, W);
++#ifdef MV_AES_DEBUG
++ {
++ MV_U8* pW = &W[0][0][0];
++ int x;
++
++ mvOsPrintf("Expended Key: size = %d\n", sizeof(W));
++ for(i=0; i<sizeof(W); i++)
++ {
++ mvOsPrintf("%02x ", pW[i]);
++ }
++ for(i=0; i<MAXROUNDS+1; i++)
++ {
++ mvOsPrintf("\n Round #%02d: ", i);
++ for(x=0; x<MAXBC; x++)
++ {
++ mvOsPrintf("%02x%02x%02x%02x ",
++ W[i][0][x], W[i][1][x], W[i][2][x], W[i][3][x]);
++ }
++ mvOsPrintf("\n");
++ }
++ }
++#endif /* MV_AES_DEBUG */
++ switch (keyLen)
++ {
++ case 128:
++ rounds = 10;
++ KC = 4;
++ break;
++ case 192:
++ rounds = 12;
++ KC = 6;
++ break;
++ case 256:
++ rounds = 14;
++ KC = 8;
++ break;
++ default :
++ return (-1);
++ }
++
++ for(i=0; i<MAXBC; i++)
++ {
++ for(j=0; j<4; j++)
++ {
++ expandedKey[i*4+j] = W[rounds][j][i];
++ }
++ }
++ for(; i<KC; i++)
++ {
++ for(j=0; j<4; j++)
++ {
++ expandedKey[i*4+j] = W[rounds-1][j][i+MAXBC-KC];
++ }
++ }
++
++
++ return 0;
++}
++
++int aesBlockEncrypt128(MV_U8 mode, MV_U8 *IV, MV_U8 *expandedKey, int keyLen,
++ MV_U32 *plain, int numBlocks, MV_U32 *cipher)
++{
++ int i, j, t;
++ MV_U8 block[4][MAXBC];
++ int rounds;
++ char *input, *outBuffer;
++
++ input = (char*)plain;
++ outBuffer = (char*)cipher;
++
++ /* check parameter consistency: */
++ if( (expandedKey == NULL) || ((keyLen != 128) && (keyLen != 192) && (keyLen != 256)))
++ {
++ return AES_BAD_KEY_MAT;
++ }
++ if ((mode != MODE_ECB && mode != MODE_CBC))
++ {
++ return AES_BAD_CIPHER_STATE;
++ }
++
++ switch (keyLen)
++ {
++ case 128: rounds = 10; break;
++ case 192: rounds = 12; break;
++ case 256: rounds = 14; break;
++ default : return (-3); /* this cannot happen */
++ }
++
++
++ switch (mode)
++ {
++ case MODE_ECB:
++ for (i = 0; i < numBlocks; i++)
++ {
++ for (j = 0; j < 4; j++)
++ {
++ for(t = 0; t < 4; t++)
++ /* parse input stream into rectangular array */
++ block[t][j] = input[16*i+4*j+t] & 0xFF;
++ }
++ rijndaelEncrypt128(block, (MV_U8 (*)[4][MAXBC])expandedKey, rounds);
++ for (j = 0; j < 4; j++)
++ {
++ /* parse rectangular array into output ciphertext bytes */
++ for(t = 0; t < 4; t++)
++ outBuffer[16*i+4*j+t] = (MV_U8) block[t][j];
++
++ }
++ }
++ break;
++
++ case MODE_CBC:
++ for (j = 0; j < 4; j++)
++ {
++ for(t = 0; t < 4; t++)
++ /* parse initial value into rectangular array */
++ block[t][j] = IV[t+4*j] & 0xFF;
++ }
++ for (i = 0; i < numBlocks; i++)
++ {
++ for (j = 0; j < 4; j++)
++ {
++ for(t = 0; t < 4; t++)
++ /* parse input stream into rectangular array and exor with
++ IV or the previous ciphertext */
++ block[t][j] ^= input[16*i+4*j+t] & 0xFF;
++ }
++ rijndaelEncrypt128(block, (MV_U8 (*)[4][MAXBC])expandedKey, rounds);
++ for (j = 0; j < 4; j++)
++ {
++ /* parse rectangular array into output ciphertext bytes */
++ for(t = 0; t < 4; t++)
++ outBuffer[16*i+4*j+t] = (MV_U8) block[t][j];
++ }
++ }
++ break;
++
++ default: return AES_BAD_CIPHER_STATE;
++ }
++
++ return 0;
++}
++
++int aesBlockDecrypt128(MV_U8 mode, MV_U8 *IV, MV_U8 *expandedKey, int keyLen,
++ MV_U32 *srcData, int numBlocks, MV_U32 *dstData)
++{
++ int i, j, t;
++ MV_U8 block[4][MAXBC];
++ MV_U8 iv[4][MAXBC];
++ int rounds;
++ char *input, *outBuffer;
++
++ input = (char*)srcData;
++ outBuffer = (char*)dstData;
++
++ if (expandedKey == NULL)
++ {
++ return AES_BAD_KEY_MAT;
++ }
++
++ /* check parameter consistency: */
++ if (keyLen != 128 && keyLen != 192 && keyLen != 256)
++ {
++ return AES_BAD_KEY_MAT;
++ }
++ if ((mode != MODE_ECB && mode != MODE_CBC))
++ {
++ return AES_BAD_CIPHER_STATE;
++ }
++
++ switch (keyLen)
++ {
++ case 128: rounds = 10; break;
++ case 192: rounds = 12; break;
++ case 256: rounds = 14; break;
++ default : return (-3); /* this cannot happen */
++ }
++
++
++ switch (mode)
++ {
++ case MODE_ECB:
++ for (i = 0; i < numBlocks; i++)
++ {
++ for (j = 0; j < 4; j++)
++ {
++ for(t = 0; t < 4; t++)
++ {
++ /* parse input stream into rectangular array */
++ block[t][j] = input[16*i+4*j+t] & 0xFF;
++ }
++ }
++ rijndaelDecrypt128(block, (MV_U8 (*)[4][MAXBC])expandedKey, rounds);
++ for (j = 0; j < 4; j++)
++ {
++ /* parse rectangular array into output ciphertext bytes */
++ for(t = 0; t < 4; t++)
++ outBuffer[16*i+4*j+t] = (MV_U8) block[t][j];
++ }
++ }
++ break;
++
++ case MODE_CBC:
++ /* first block */
++ for (j = 0; j < 4; j++)
++ {
++ for(t = 0; t < 4; t++)
++ {
++ /* parse input stream into rectangular array */
++ block[t][j] = input[4*j+t] & 0xFF;
++ iv[t][j] = block[t][j];
++ }
++ }
++ rijndaelDecrypt128(block, (MV_U8 (*)[4][MAXBC])expandedKey, rounds);
++
++ for (j = 0; j < 4; j++)
++ {
++ /* exor the IV and parse rectangular array into output ciphertext bytes */
++ for(t = 0; t < 4; t++)
++ {
++ outBuffer[4*j+t] = (MV_U8) (block[t][j] ^ IV[t+4*j]);
++ IV[t+4*j] = iv[t][j];
++ }
++ }
++
++ /* next blocks */
++ for (i = 1; i < numBlocks; i++)
++ {
++ for (j = 0; j < 4; j++)
++ {
++ for(t = 0; t < 4; t++)
++ {
++ /* parse input stream into rectangular array */
++ iv[t][j] = input[16*i+4*j+t] & 0xFF;
++ block[t][j] = iv[t][j];
++ }
++ }
++ rijndaelDecrypt128(block, (MV_U8 (*)[4][MAXBC])expandedKey, rounds);
++
++ for (j = 0; j < 4; j++)
++ {
++ /* exor previous ciphertext block and parse rectangular array
++ into output ciphertext bytes */
++ for(t = 0; t < 4; t++)
++ {
++ outBuffer[16*i+4*j+t] = (MV_U8) (block[t][j] ^ IV[t+4*j]);
++ IV[t+4*j] = iv[t][j];
++ }
++ }
++ }
++ break;
++
++ default: return AES_BAD_CIPHER_STATE;
++ }
++
++ return 0;
++}
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/AES/mvAes.h linux-2.6.36/crypto/ocf/kirkwood/cesa/AES/mvAes.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/AES/mvAes.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/AES/mvAes.h 2010-11-09 20:28:05.292495461 +0100
+@@ -0,0 +1,62 @@
++/* mvAes.h v2.0 August '99
++ * Reference ANSI C code
++ */
++
++/* AES Cipher header file for ANSI C Submissions
++ Lawrence E. Bassham III
++ Computer Security Division
++ National Institute of Standards and Technology
++
++ April 15, 1998
++
++ This sample is to assist implementers developing to the Cryptographic
++API Profile for AES Candidate Algorithm Submissions. Please consult this
++document as a cross-reference.
++
++ ANY CHANGES, WHERE APPROPRIATE, TO INFORMATION PROVIDED IN THIS FILE
++MUST BE DOCUMENTED. CHANGES ARE ONLY APPROPRIATE WHERE SPECIFIED WITH
++THE STRING "CHANGE POSSIBLE". FUNCTION CALLS AND THEIR PARAMETERS CANNOT
++BE CHANGED. STRUCTURES CAN BE ALTERED TO ALLOW IMPLEMENTERS TO INCLUDE
++IMPLEMENTATION SPECIFIC INFORMATION.
++*/
++
++/* Includes:
++ Standard include files
++*/
++
++#include "mvOs.h"
++
++
++/* Error Codes - CHANGE POSSIBLE: inclusion of additional error codes */
++
++/* Key direction is invalid, e.g., unknown value */
++#define AES_BAD_KEY_DIR -1
++
++/* Key material not of correct length */
++#define AES_BAD_KEY_MAT -2
++
++/* Key passed is not valid */
++#define AES_BAD_KEY_INSTANCE -3
++
++/* Params struct passed to cipherInit invalid */
++#define AES_BAD_CIPHER_MODE -4
++
++/* Cipher in wrong state (e.g., not initialized) */
++#define AES_BAD_CIPHER_STATE -5
++
++#define AES_BAD_CIPHER_INSTANCE -7
++
++
++/* Function protoypes */
++/* CHANGED: makeKey(): parameter blockLen added
++ this parameter is absolutely necessary if you want to
++ setup the round keys in a variable block length setting
++ cipherInit(): parameter blockLen added (for obvious reasons)
++ */
++int aesMakeKey(MV_U8 *expandedKey, MV_U8 *keyMaterial, int keyLen, int blockLen);
++int aesBlockEncrypt128(MV_U8 mode, MV_U8 *IV, MV_U8 *expandedKey, int keyLen,
++ MV_U32 *plain, int numBlocks, MV_U32 *cipher);
++int aesBlockDecrypt128(MV_U8 mode, MV_U8 *IV, MV_U8 *expandedKey, int keyLen,
++ MV_U32 *plain, int numBlocks, MV_U32 *cipher);
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvCesa.c linux-2.6.36/crypto/ocf/kirkwood/cesa/mvCesa.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvCesa.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/mvCesa.c 2010-11-09 20:28:05.302495516 +0100
+@@ -0,0 +1,3126 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "cesa/mvCesa.h"
++
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#undef CESA_DEBUG
++
++
++/********** Global variables **********/
++
++/* If request size is more than MV_CESA_MAX_BUF_SIZE the
++ * request is processed as fragmented request.
++ */
++
++MV_CESA_STATS cesaStats;
++
++MV_BUF_INFO cesaSramSaBuf;
++short cesaLastSid = -1;
++MV_CESA_SA* pCesaSAD = NULL;
++MV_U16 cesaMaxSA = 0;
++
++MV_CESA_REQ* pCesaReqFirst = NULL;
++MV_CESA_REQ* pCesaReqLast = NULL;
++MV_CESA_REQ* pCesaReqEmpty = NULL;
++MV_CESA_REQ* pCesaReqProcess = NULL;
++int cesaQueueDepth = 0;
++int cesaReqResources = 0;
++
++MV_CESA_SRAM_MAP* cesaSramVirtPtr = NULL;
++MV_U32 cesaCryptEngBase = 0;
++void *cesaOsHandle = NULL;
++#if (MV_CESA_VERSION >= 3)
++MV_U32 cesaChainLength = 0;
++int chainReqNum = 0;
++MV_U32 chainIndex = 0;
++MV_CESA_REQ* pNextActiveChain = 0;
++MV_CESA_REQ* pEndCurrChain = 0;
++MV_BOOL isFirstReq = MV_TRUE;
++#endif
++
++static INLINE MV_U8* mvCesaSramAddrGet(void)
++{
++#ifdef MV_CESA_NO_SRAM
++ return (MV_U8*)cesaSramVirtPtr;
++#else
++ return (MV_U8*)cesaCryptEngBase;
++#endif /* MV_CESA_NO_SRAM */
++}
++
++static INLINE MV_ULONG mvCesaSramVirtToPhys(void* pDev, MV_U8* pSramVirt)
++{
++#ifdef MV_CESA_NO_SRAM
++ return (MV_ULONG)mvOsIoVirtToPhy(NULL, pSramVirt);
++#else
++ return (MV_ULONG)pSramVirt;
++#endif /* MV_CESA_NO_SRAM */
++}
++
++/* Internal Function prototypes */
++
++static INLINE void mvCesaSramDescrBuild(MV_U32 config, int frag,
++ int cryptoOffset, int ivOffset, int cryptoLength,
++ int macOffset, int digestOffset, int macLength, int macTotalLen,
++ MV_CESA_REQ *pCesaReq, MV_DMA_DESC* pDmaDesc);
++
++static INLINE void mvCesaSramSaUpdate(short sid, MV_DMA_DESC *pDmaDesc);
++
++static INLINE int mvCesaDmaCopyPrepare(MV_CESA_MBUF* pMbuf, MV_U8* pSramBuf,
++ MV_DMA_DESC* pDmaDesc, MV_BOOL isToMbuf,
++ int offset, int copySize, MV_BOOL skipFlush);
++
++static void mvCesaHmacIvGet(MV_CESA_MAC_MODE macMode, unsigned char key[], int keyLength,
++ unsigned char innerIV[], unsigned char outerIV[]);
++
++static MV_STATUS mvCesaFragAuthComplete(MV_CESA_REQ* pReq, MV_CESA_SA* pSA,
++ int macDataSize);
++
++static MV_CESA_COMMAND* mvCesaCtrModeInit(void);
++
++static MV_STATUS mvCesaCtrModePrepare(MV_CESA_COMMAND *pCtrModeCmd, MV_CESA_COMMAND *pCmd);
++static MV_STATUS mvCesaCtrModeComplete(MV_CESA_COMMAND *pOrgCmd, MV_CESA_COMMAND *pCmd);
++static void mvCesaCtrModeFinish(MV_CESA_COMMAND *pCmd);
++
++static INLINE MV_STATUS mvCesaReqProcess(MV_CESA_REQ* pReq);
++static MV_STATUS mvCesaFragReqProcess(MV_CESA_REQ* pReq, MV_U8 frag);
++
++static INLINE MV_STATUS mvCesaParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd, MV_U8* pFixOffset);
++static INLINE MV_STATUS mvCesaFragParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd);
++
++static INLINE void mvCesaFragSizeFind(MV_CESA_SA* pSA, MV_CESA_REQ* pReq,
++ int cryptoOffset, int macOffset,
++ int* pCopySize, int* pCryptoDataSize, int* pMacDataSize);
++static MV_STATUS mvCesaMbufCacheUnmap(MV_CESA_MBUF* pMbuf, int offset, int size);
++
++
++/* Go to the next request in the request queue */
++static INLINE MV_CESA_REQ* MV_CESA_REQ_NEXT_PTR(MV_CESA_REQ* pReq)
++{
++ if(pReq == pCesaReqLast)
++ return pCesaReqFirst;
++
++ return pReq+1;
++}
++
++#if (MV_CESA_VERSION >= 3)
++/* Go to the previous request in the request queue */
++static INLINE MV_CESA_REQ* MV_CESA_REQ_PREV_PTR(MV_CESA_REQ* pReq)
++{
++ if(pReq == pCesaReqFirst)
++ return pCesaReqLast;
++
++ return pReq-1;
++}
++
++#endif
++
++
++static INLINE void mvCesaReqProcessStart(MV_CESA_REQ* pReq)
++{
++ int frag;
++
++#if (MV_CESA_VERSION >= 3)
++ pReq->state = MV_CESA_CHAIN;
++#else
++ pReq->state = MV_CESA_PROCESS;
++#endif
++ cesaStats.startCount++;
++
++ if(pReq->fragMode == MV_CESA_FRAG_NONE)
++ {
++ frag = 0;
++ }
++ else
++ {
++ frag = pReq->frags.nextFrag;
++ pReq->frags.nextFrag++;
++ }
++#if (MV_CESA_VERSION >= 2)
++ /* Enable TDMA engine */
++ MV_REG_WRITE(MV_CESA_TDMA_CURR_DESC_PTR_REG, 0);
++ MV_REG_WRITE(MV_CESA_TDMA_NEXT_DESC_PTR_REG,
++ (MV_U32)mvCesaVirtToPhys(&pReq->dmaDescBuf, pReq->dma[frag].pDmaFirst));
++#else
++ /* Enable IDMA engine */
++ MV_REG_WRITE(IDMA_CURR_DESC_PTR_REG(0), 0);
++ MV_REG_WRITE(IDMA_NEXT_DESC_PTR_REG(0),
++ (MV_U32)mvCesaVirtToPhys(&pReq->dmaDescBuf, pReq->dma[frag].pDmaFirst));
++#endif /* MV_CESA_VERSION >= 2 */
++
++#if defined(MV_BRIDGE_SYNC_REORDER)
++ mvOsBridgeReorderWA();
++#endif
++
++ /* Start Accelerator */
++ MV_REG_WRITE(MV_CESA_CMD_REG, MV_CESA_CMD_CHAN_ENABLE_MASK);
++}
++
++
++/*******************************************************************************
++* mvCesaHalInit - Initialize the CESA driver
++*
++* DESCRIPTION:
++* This function initialize the CESA driver.
++* 1) Session database
++* 2) Request queue
++* 4) DMA descriptor lists - one list per request. Each list
++* has MV_CESA_MAX_DMA_DESC descriptors.
++*
++* INPUT:
++* numOfSession - maximum number of supported sessions
++* queueDepth - number of elements in the request queue.
++* pSramBase - virtual address of Sram
++* osHandle - A handle used by the OS to allocate memory for the
++* module (Passed to the OS Services layer)
++*
++* RETURN:
++* MV_OK - Success
++* MV_NO_RESOURCE - Fail, can't allocate resources:
++* Session database, request queue,
++* DMA descriptors list, LRU cache database.
++* MV_NOT_ALIGNED - Sram base address is not 8 byte aligned.
++*
++*******************************************************************************/
++MV_STATUS mvCesaHalInit (int numOfSession, int queueDepth, char* pSramBase, MV_U32 cryptEngBase,
++ void *osHandle)
++{
++ int i, req;
++ MV_U32 descOffsetReg, configReg;
++ MV_CESA_SRAM_SA *pSramSA;
++
++
++ mvOsPrintf("mvCesaInit: sessions=%d, queue=%d, pSram=%p\n",
++ numOfSession, queueDepth, pSramBase);
++
++ cesaOsHandle = osHandle;
++ /* Create Session database */
++ pCesaSAD = mvOsMalloc(sizeof(MV_CESA_SA)*numOfSession);
++ if(pCesaSAD == NULL)
++ {
++ mvOsPrintf("mvCesaInit: Can't allocate %u bytes for %d SAs\n",
++ sizeof(MV_CESA_SA)*numOfSession, numOfSession);
++ mvCesaFinish();
++ return MV_NO_RESOURCE;
++ }
++ memset(pCesaSAD, 0, sizeof(MV_CESA_SA)*numOfSession);
++ cesaMaxSA = numOfSession;
++
++ /* Allocate imag of sramSA in the DRAM */
++ cesaSramSaBuf.bufSize = sizeof(MV_CESA_SRAM_SA)*numOfSession +
++ CPU_D_CACHE_LINE_SIZE;
++
++ cesaSramSaBuf.bufVirtPtr = mvOsIoCachedMalloc(osHandle,cesaSramSaBuf.bufSize,
++ &cesaSramSaBuf.bufPhysAddr,
++ &cesaSramSaBuf.memHandle);
++
++ if(cesaSramSaBuf.bufVirtPtr == NULL)
++ {
++ mvOsPrintf("mvCesaInit: Can't allocate %d bytes for sramSA structures\n",
++ cesaSramSaBuf.bufSize);
++ mvCesaFinish();
++ return MV_NO_RESOURCE;
++ }
++ memset(cesaSramSaBuf.bufVirtPtr, 0, cesaSramSaBuf.bufSize);
++ pSramSA = (MV_CESA_SRAM_SA*)MV_ALIGN_UP((MV_ULONG)cesaSramSaBuf.bufVirtPtr,
++ CPU_D_CACHE_LINE_SIZE);
++ for(i=0; i<numOfSession; i++)
++ {
++ pCesaSAD[i].pSramSA = &pSramSA[i];
++ }
++
++ /* Create request queue */
++ pCesaReqFirst = mvOsMalloc(sizeof(MV_CESA_REQ)*queueDepth);
++ if(pCesaReqFirst == NULL)
++ {
++ mvOsPrintf("mvCesaInit: Can't allocate %u bytes for %d requests\n",
++ sizeof(MV_CESA_REQ)*queueDepth, queueDepth);
++ mvCesaFinish();
++ return MV_NO_RESOURCE;
++ }
++ memset(pCesaReqFirst, 0, sizeof(MV_CESA_REQ)*queueDepth);
++ pCesaReqEmpty = pCesaReqFirst;
++ pCesaReqLast = pCesaReqFirst + (queueDepth-1);
++ pCesaReqProcess = pCesaReqEmpty;
++ cesaQueueDepth = queueDepth;
++ cesaReqResources = queueDepth;
++#if (MV_CESA_VERSION >= 3)
++ cesaChainLength = MAX_CESA_CHAIN_LENGTH;
++#endif
++ /* pSramBase must be 8 byte aligned */
++ if( MV_IS_NOT_ALIGN((MV_ULONG)pSramBase, 8) )
++ {
++ mvOsPrintf("mvCesaInit: pSramBase (%p) must be 8 byte aligned\n",
++ pSramBase);
++ mvCesaFinish();
++ return MV_NOT_ALIGNED;
++ }
++ cesaSramVirtPtr = (MV_CESA_SRAM_MAP*)pSramBase;
++
++ cesaCryptEngBase = cryptEngBase;
++
++ /*memset(cesaSramVirtPtr, 0, sizeof(MV_CESA_SRAM_MAP));*/
++
++ /* Clear registers */
++ MV_REG_WRITE( MV_CESA_CFG_REG, 0);
++ MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0);
++ MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0);
++
++ /* Initialize DMA descriptor lists for all requests in Request queue */
++ descOffsetReg = configReg = 0;
++ for(req=0; req<queueDepth; req++)
++ {
++ int frag;
++ MV_CESA_REQ* pReq;
++ MV_DMA_DESC* pDmaDesc;
++
++ pReq = &pCesaReqFirst[req];
++
++ pReq->cesaDescBuf.bufSize = sizeof(MV_CESA_DESC)*MV_CESA_MAX_REQ_FRAGS +
++ CPU_D_CACHE_LINE_SIZE;
++
++ pReq->cesaDescBuf.bufVirtPtr =
++ mvOsIoCachedMalloc(osHandle,pReq->cesaDescBuf.bufSize,
++ &pReq->cesaDescBuf.bufPhysAddr,
++ &pReq->cesaDescBuf.memHandle);
++
++ if(pReq->cesaDescBuf.bufVirtPtr == NULL)
++ {
++ mvOsPrintf("mvCesaInit: req=%d, Can't allocate %d bytes for CESA descriptors\n",
++ req, pReq->cesaDescBuf.bufSize);
++ mvCesaFinish();
++ return MV_NO_RESOURCE;
++ }
++ memset(pReq->cesaDescBuf.bufVirtPtr, 0, pReq->cesaDescBuf.bufSize);
++ pReq->pCesaDesc = (MV_CESA_DESC*)MV_ALIGN_UP((MV_ULONG)pReq->cesaDescBuf.bufVirtPtr,
++ CPU_D_CACHE_LINE_SIZE);
++
++ pReq->dmaDescBuf.bufSize = sizeof(MV_DMA_DESC)*MV_CESA_MAX_DMA_DESC*MV_CESA_MAX_REQ_FRAGS +
++ CPU_D_CACHE_LINE_SIZE;
++
++ pReq->dmaDescBuf.bufVirtPtr =
++ mvOsIoCachedMalloc(osHandle,pReq->dmaDescBuf.bufSize,
++ &pReq->dmaDescBuf.bufPhysAddr,
++ &pReq->dmaDescBuf.memHandle);
++
++ if(pReq->dmaDescBuf.bufVirtPtr == NULL)
++ {
++ mvOsPrintf("mvCesaInit: req=%d, Can't allocate %d bytes for DMA descriptor list\n",
++ req, pReq->dmaDescBuf.bufSize);
++ mvCesaFinish();
++ return MV_NO_RESOURCE;
++ }
++ memset(pReq->dmaDescBuf.bufVirtPtr, 0, pReq->dmaDescBuf.bufSize);
++ pDmaDesc = (MV_DMA_DESC*)MV_ALIGN_UP((MV_ULONG)pReq->dmaDescBuf.bufVirtPtr,
++ CPU_D_CACHE_LINE_SIZE);
++
++ for(frag=0; frag<MV_CESA_MAX_REQ_FRAGS; frag++)
++ {
++ MV_CESA_DMA* pDma = &pReq->dma[frag];
++
++ pDma->pDmaFirst = pDmaDesc;
++ pDma->pDmaLast = NULL;
++
++ for(i=0; i<MV_CESA_MAX_DMA_DESC-1; i++)
++ {
++ /* link all DMA descriptors together */
++ pDma->pDmaFirst[i].phyNextDescPtr =
++ MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, &pDmaDesc[i+1]));
++ }
++ pDma->pDmaFirst[i].phyNextDescPtr = 0;
++ mvOsCacheFlush(NULL, &pDma->pDmaFirst[0], MV_CESA_MAX_DMA_DESC*sizeof(MV_DMA_DESC));
++
++ pDmaDesc += MV_CESA_MAX_DMA_DESC;
++ }
++ }
++ /*mvCesaCryptoIvSet(NULL, MV_CESA_MAX_IV_LENGTH);*/
++ descOffsetReg = (MV_U16)((MV_U8*)&cesaSramVirtPtr->desc - mvCesaSramAddrGet());
++ MV_REG_WRITE(MV_CESA_CHAN_DESC_OFFSET_REG, descOffsetReg);
++
++ configReg |= (MV_CESA_CFG_WAIT_DMA_MASK | MV_CESA_CFG_ACT_DMA_MASK);
++#if (MV_CESA_VERSION >= 3)
++ configReg |= MV_CESA_CFG_CHAIN_MODE_MASK;
++#endif
++
++#if (MV_CESA_VERSION >= 2)
++ /* Initialize TDMA engine */
++ MV_REG_WRITE(MV_CESA_TDMA_CTRL_REG, MV_CESA_TDMA_CTRL_VALUE);
++ MV_REG_WRITE(MV_CESA_TDMA_BYTE_COUNT_REG, 0);
++ MV_REG_WRITE(MV_CESA_TDMA_CURR_DESC_PTR_REG, 0);
++#else
++ /* Initialize IDMA #0 engine */
++ MV_REG_WRITE(IDMA_CTRL_LOW_REG(0), 0);
++ MV_REG_WRITE(IDMA_BYTE_COUNT_REG(0), 0);
++ MV_REG_WRITE(IDMA_CURR_DESC_PTR_REG(0), 0);
++ MV_REG_WRITE(IDMA_CTRL_HIGH_REG(0), ICCHR_ENDIAN_LITTLE
++#ifdef MV_CPU_LE
++ | ICCHR_DESC_BYTE_SWAP_EN
++#endif
++ );
++ /* Clear Cause Byte of IDMA channel to be used */
++ MV_REG_WRITE( IDMA_CAUSE_REG, ~ICICR_CAUSE_MASK_ALL(0));
++ MV_REG_WRITE(IDMA_CTRL_LOW_REG(0), MV_CESA_IDMA_CTRL_LOW_VALUE);
++#endif /* (MV_CESA_VERSION >= 2) */
++
++ /* Set CESA configuration registers */
++ MV_REG_WRITE( MV_CESA_CFG_REG, configReg);
++ mvCesaDebugStatsClear();
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCesaFinish - Shutdown the CESA driver
++*
++* DESCRIPTION:
++* This function shutdown the CESA driver and free all allocted resources.
++*
++* INPUT: None
++*
++* RETURN:
++* MV_OK - Success
++* Other - Fail
++*
++*******************************************************************************/
++MV_STATUS mvCesaFinish (void)
++{
++ int req;
++ MV_CESA_REQ* pReq;
++
++ mvOsPrintf("mvCesaFinish: \n");
++
++ cesaSramVirtPtr = NULL;
++
++ /* Free all resources: DMA list, etc. */
++ for(req=0; req<cesaQueueDepth; req++)
++ {
++ pReq = &pCesaReqFirst[req];
++ if(pReq->dmaDescBuf.bufVirtPtr != NULL)
++ {
++ mvOsIoCachedFree(cesaOsHandle,pReq->dmaDescBuf.bufSize,
++ pReq->dmaDescBuf.bufPhysAddr,
++ pReq->dmaDescBuf.bufVirtPtr,
++ pReq->dmaDescBuf.memHandle);
++ }
++ if(pReq->cesaDescBuf.bufVirtPtr != NULL)
++ {
++ mvOsIoCachedFree(cesaOsHandle,pReq->cesaDescBuf.bufSize,
++ pReq->cesaDescBuf.bufPhysAddr,
++ pReq->cesaDescBuf.bufVirtPtr,
++ pReq->cesaDescBuf.memHandle);
++ }
++ }
++#if (MV_CESA_VERSION < 2)
++ MV_REG_WRITE(IDMA_CTRL_LOW_REG(0), 0);
++#endif /* (MV_CESA_VERSION < 2) */
++
++ /* Free request queue */
++ if(pCesaReqFirst != NULL)
++ {
++ mvOsFree(pCesaReqFirst);
++ pCesaReqFirst = pCesaReqLast = NULL;
++ pCesaReqEmpty = pCesaReqProcess = NULL;
++ cesaQueueDepth = cesaReqResources = 0;
++ }
++ /* Free SA database */
++ if(pCesaSAD != NULL)
++ {
++ mvOsFree(pCesaSAD);
++ pCesaSAD = NULL;
++ cesaMaxSA = 0;
++ }
++ MV_REG_WRITE( MV_CESA_CFG_REG, 0);
++ MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0);
++ MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCesaCryptoIvSet - Set IV value for Crypto algorithm working in CBC mode
++*
++* DESCRIPTION:
++* This function set IV value using by Crypto algorithms in CBC mode.
++* Each channel has its own IV value.
++* This function gets IV value from the caller. If no IV value passed from
++* the caller or only part of IV passed, the function will init the rest part
++* of IV value (or the whole IV) by random value.
++*
++* INPUT:
++* MV_U8* pIV - Pointer to IV value supplied by user. If pIV==NULL
++* the function will generate random IV value.
++* int ivSize - size (in bytes) of IV provided by user. If ivSize is
++* smaller than maximum IV size, the function will complete
++* IV by random value.
++*
++* RETURN:
++* MV_OK - Success
++* Other - Fail
++*
++*******************************************************************************/
++MV_STATUS mvCesaCryptoIvSet(MV_U8* pIV, int ivSize)
++{
++ MV_U8* pSramIV;
++#if defined(MV646xx)
++ mvOsPrintf("mvCesaCryptoIvSet: ERR. shouldn't use this call on MV64660\n");
++#endif
++ pSramIV = cesaSramVirtPtr->cryptoIV;
++ if(ivSize > MV_CESA_MAX_IV_LENGTH)
++ {
++ mvOsPrintf("mvCesaCryptoIvSet: ivSize (%d) is too large\n", ivSize);
++ ivSize = MV_CESA_MAX_IV_LENGTH;
++ }
++ if(pIV != NULL)
++ {
++ memcpy(pSramIV, pIV, ivSize);
++ ivSize = MV_CESA_MAX_IV_LENGTH - ivSize;
++ pSramIV += ivSize;
++ }
++
++ while(ivSize > 0)
++ {
++ int size, mv_random = mvOsRand();
++
++ size = MV_MIN(ivSize, sizeof(mv_random));
++ memcpy(pSramIV, (void*)&mv_random, size);
++
++ pSramIV += size;
++ ivSize -= size;
++ }
++/*
++ mvOsCacheFlush(NULL, cesaSramVirtPtr->cryptoIV,
++ MV_CESA_MAX_IV_LENGTH);
++ mvOsCacheInvalidate(NULL, cesaSramVirtPtr->cryptoIV,
++ MV_CESA_MAX_IV_LENGTH);
++*/
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCesaSessionOpen - Open new uni-directional crypto session
++*
++* DESCRIPTION:
++* This function open new session.
++*
++* INPUT:
++* MV_CESA_OPEN_SESSION *pSession - pointer to new session input parameters
++*
++* OUTPUT:
++* short *pSid - session ID, should be used for all future
++* requests over this session.
++*
++* RETURN:
++* MV_OK - Session opend successfully.
++* MV_FULL - All sessions are in use, no free place in
++* SA database.
++* MV_BAD_PARAM - One of session input parameters is invalid.
++*
++*******************************************************************************/
++MV_STATUS mvCesaSessionOpen(MV_CESA_OPEN_SESSION *pSession, short* pSid)
++{
++ short sid;
++ MV_U32 config = 0;
++ int digestSize;
++
++ cesaStats.openedCount++;
++
++ /* Find free entry in SAD */
++ for(sid=0; sid<cesaMaxSA; sid++)
++ {
++ if(pCesaSAD[sid].valid == 0)
++ {
++ break;
++ }
++ }
++ if(sid == cesaMaxSA)
++ {
++ mvOsPrintf("mvCesaSessionOpen: SA Database is FULL\n");
++ return MV_FULL;
++ }
++
++ /* Check Input parameters for Open session */
++ if (pSession->operation >= MV_CESA_MAX_OPERATION)
++ {
++ mvOsPrintf("mvCesaSessionOpen: Unexpected operation %d\n",
++ pSession->operation);
++ return MV_BAD_PARAM;
++ }
++ config |= (pSession->operation << MV_CESA_OPERATION_OFFSET);
++
++ if( (pSession->direction != MV_CESA_DIR_ENCODE) &&
++ (pSession->direction != MV_CESA_DIR_DECODE) )
++ {
++ mvOsPrintf("mvCesaSessionOpen: Unexpected direction %d\n",
++ pSession->direction);
++ return MV_BAD_PARAM;
++ }
++ config |= (pSession->direction << MV_CESA_DIRECTION_BIT);
++ /* Clear SA entry */
++ /* memset(&pCesaSAD[sid], 0, sizeof(pCesaSAD[sid])); */
++
++ /* Check AUTH parameters and update SA entry */
++ if(pSession->operation != MV_CESA_CRYPTO_ONLY)
++ {
++ /* For HMAC (MD5 and SHA1) - Maximum Key size is 64 bytes */
++ if( (pSession->macMode == MV_CESA_MAC_HMAC_MD5) ||
++ (pSession->macMode == MV_CESA_MAC_HMAC_SHA1) )
++ {
++ if(pSession->macKeyLength > MV_CESA_MAX_MAC_KEY_LENGTH)
++ {
++ mvOsPrintf("mvCesaSessionOpen: macKeyLength %d is too large\n",
++ pSession->macKeyLength);
++ return MV_BAD_PARAM;
++ }
++ mvCesaHmacIvGet(pSession->macMode, pSession->macKey, pSession->macKeyLength,
++ pCesaSAD[sid].pSramSA->macInnerIV,
++ pCesaSAD[sid].pSramSA->macOuterIV);
++ pCesaSAD[sid].macKeyLength = pSession->macKeyLength;
++ }
++ switch(pSession->macMode)
++ {
++ case MV_CESA_MAC_MD5:
++ case MV_CESA_MAC_HMAC_MD5:
++ digestSize = MV_CESA_MD5_DIGEST_SIZE;
++ break;
++
++ case MV_CESA_MAC_SHA1:
++ case MV_CESA_MAC_HMAC_SHA1:
++ digestSize = MV_CESA_SHA1_DIGEST_SIZE;
++ break;
++
++ default:
++ mvOsPrintf("mvCesaSessionOpen: Unexpected macMode %d\n",
++ pSession->macMode);
++ return MV_BAD_PARAM;
++ }
++ config |= (pSession->macMode << MV_CESA_MAC_MODE_OFFSET);
++
++ /* Supported digest sizes: MD5 - 16 bytes (128 bits), */
++ /* SHA1 - 20 bytes (160 bits) or 12 bytes (96 bits) for both */
++ if( (pSession->digestSize != digestSize) && (pSession->digestSize != 12))
++ {
++ mvOsPrintf("mvCesaSessionOpen: Unexpected digest size %d\n",
++ pSession->digestSize);
++ mvOsPrintf("\t Valid values [bytes]: MD5-16, SHA1-20, Both-12\n");
++ return MV_BAD_PARAM;
++ }
++ pCesaSAD[sid].digestSize = pSession->digestSize;
++
++ if(pCesaSAD[sid].digestSize == 12)
++ {
++ /* Set MV_CESA_MAC_DIGEST_SIZE_BIT if digest size is 96 bits */
++ config |= (MV_CESA_MAC_DIGEST_96B << MV_CESA_MAC_DIGEST_SIZE_BIT);
++ }
++ }
++
++ /* Check CRYPTO parameters and update SA entry */
++ if(pSession->operation != MV_CESA_MAC_ONLY)
++ {
++ switch(pSession->cryptoAlgorithm)
++ {
++ case MV_CESA_CRYPTO_DES:
++ pCesaSAD[sid].cryptoKeyLength = MV_CESA_DES_KEY_LENGTH;
++ pCesaSAD[sid].cryptoBlockSize = MV_CESA_DES_BLOCK_SIZE;
++ break;
++
++ case MV_CESA_CRYPTO_3DES:
++ pCesaSAD[sid].cryptoKeyLength = MV_CESA_3DES_KEY_LENGTH;
++ pCesaSAD[sid].cryptoBlockSize = MV_CESA_DES_BLOCK_SIZE;
++ /* Only EDE mode is supported */
++ config |= (MV_CESA_CRYPTO_3DES_EDE <<
++ MV_CESA_CRYPTO_3DES_MODE_BIT);
++ break;
++
++ case MV_CESA_CRYPTO_AES:
++ switch(pSession->cryptoKeyLength)
++ {
++ case 16:
++ pCesaSAD[sid].cryptoKeyLength = MV_CESA_AES_128_KEY_LENGTH;
++ config |= (MV_CESA_CRYPTO_AES_KEY_128 <<
++ MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET);
++ break;
++
++ case 24:
++ pCesaSAD[sid].cryptoKeyLength = MV_CESA_AES_192_KEY_LENGTH;
++ config |= (MV_CESA_CRYPTO_AES_KEY_192 <<
++ MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET);
++ break;
++
++ case 32:
++ default:
++ pCesaSAD[sid].cryptoKeyLength = MV_CESA_AES_256_KEY_LENGTH;
++ config |= (MV_CESA_CRYPTO_AES_KEY_256 <<
++ MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET);
++ break;
++ }
++ pCesaSAD[sid].cryptoBlockSize = MV_CESA_AES_BLOCK_SIZE;
++ break;
++
++ default:
++ mvOsPrintf("mvCesaSessionOpen: Unexpected cryptoAlgorithm %d\n",
++ pSession->cryptoAlgorithm);
++ return MV_BAD_PARAM;
++ }
++ config |= (pSession->cryptoAlgorithm << MV_CESA_CRYPTO_ALG_OFFSET);
++
++ if(pSession->cryptoKeyLength != pCesaSAD[sid].cryptoKeyLength)
++ {
++ mvOsPrintf("cesaSessionOpen: Wrong CryptoKeySize %d != %d\n",
++ pSession->cryptoKeyLength, pCesaSAD[sid].cryptoKeyLength);
++ return MV_BAD_PARAM;
++ }
++
++ /* Copy Crypto key */
++ if( (pSession->cryptoAlgorithm == MV_CESA_CRYPTO_AES) &&
++ (pSession->direction == MV_CESA_DIR_DECODE))
++ {
++ /* Crypto Key for AES decode is computed from original key material */
++ /* and depend on cryptoKeyLength (128/192/256 bits) */
++ aesMakeKey(pCesaSAD[sid].pSramSA->cryptoKey, pSession->cryptoKey,
++ pSession->cryptoKeyLength*8, MV_CESA_AES_BLOCK_SIZE*8);
++ }
++ else
++ {
++ /*panic("mvCesaSessionOpen2");*/
++ memcpy(pCesaSAD[sid].pSramSA->cryptoKey, pSession->cryptoKey,
++ pCesaSAD[sid].cryptoKeyLength);
++
++ }
++
++ switch(pSession->cryptoMode)
++ {
++ case MV_CESA_CRYPTO_ECB:
++ pCesaSAD[sid].cryptoIvSize = 0;
++ break;
++
++ case MV_CESA_CRYPTO_CBC:
++ pCesaSAD[sid].cryptoIvSize = pCesaSAD[sid].cryptoBlockSize;
++ break;
++
++ case MV_CESA_CRYPTO_CTR:
++ /* Supported only for AES algorithm */
++ if(pSession->cryptoAlgorithm != MV_CESA_CRYPTO_AES)
++ {
++ mvOsPrintf("mvCesaSessionOpen: CRYPTO CTR mode supported for AES only\n");
++ return MV_BAD_PARAM;
++ }
++ pCesaSAD[sid].cryptoIvSize = 0;
++ pCesaSAD[sid].ctrMode = 1;
++ /* Replace to ECB mode for HW */
++ pSession->cryptoMode = MV_CESA_CRYPTO_ECB;
++ break;
++
++ default:
++ mvOsPrintf("mvCesaSessionOpen: Unexpected cryptoMode %d\n",
++ pSession->cryptoMode);
++ return MV_BAD_PARAM;
++ }
++
++ config |= (pSession->cryptoMode << MV_CESA_CRYPTO_MODE_BIT);
++ }
++ pCesaSAD[sid].config = config;
++
++ mvOsCacheFlush(NULL, pCesaSAD[sid].pSramSA, sizeof(MV_CESA_SRAM_SA));
++ if(pSid != NULL)
++ *pSid = sid;
++
++ pCesaSAD[sid].valid = 1;
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCesaSessionClose - Close active crypto session
++*
++* DESCRIPTION:
++* This function closes existing session
++*
++* INPUT:
++* short sid - Unique identifier of the session to be closed
++*
++* RETURN:
++* MV_OK - Session closed successfully.
++* MV_BAD_PARAM - Session identifier is out of valid range.
++* MV_NOT_FOUND - There is no active session with such ID.
++*
++*******************************************************************************/
++MV_STATUS mvCesaSessionClose(short sid)
++{
++ cesaStats.closedCount++;
++
++ if(sid >= cesaMaxSA)
++ {
++ mvOsPrintf("CESA Error: sid (%d) is too big\n", sid);
++ return MV_BAD_PARAM;
++ }
++ if(pCesaSAD[sid].valid == 0)
++ {
++ mvOsPrintf("CESA Warning: Session (sid=%d) is invalid\n", sid);
++ return MV_NOT_FOUND;
++ }
++ if(cesaLastSid == sid)
++ cesaLastSid = -1;
++
++ pCesaSAD[sid].valid = 0;
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCesaAction - Perform crypto operation
++*
++* DESCRIPTION:
++* This function set new CESA request FIFO queue for further HW processing.
++* The function checks request parameters before set new request to the queue.
++* If one of the CESA channels is ready for processing the request will be
++* passed to HW. When request processing is finished the CESA interrupt will
++* be generated by HW. The caller should call mvCesaReadyGet() function to
++* complete request processing and get result.
++*
++* INPUT:
++* MV_CESA_COMMAND *pCmd - pointer to new CESA request.
++* It includes pointers to Source and Destination
++* buffers, session identifier get from
++* mvCesaSessionOpen() function, pointer to caller
++* private data and all needed crypto parameters.
++*
++* RETURN:
++* MV_OK - request successfully added to request queue
++* and will be processed.
++* MV_NO_MORE - request successfully added to request queue and will
++* be processed, but request queue became Full and next
++* request will not be accepted.
++* MV_NO_RESOURCE - request queue is FULL and the request can not
++* be processed.
++* MV_OUT_OF_CPU_MEM - memory allocation needed for request processing is
++* failed. Request can not be processed.
++* MV_NOT_ALLOWED - This mixed request (CRYPTO+MAC) can not be processed
++* as one request and should be splitted for two requests:
++* CRYPTO_ONLY and MAC_ONLY.
++* MV_BAD_PARAM - One of the request parameters is out of valid range.
++* The request can not be processed.
++*
++*******************************************************************************/
++MV_STATUS mvCesaAction (MV_CESA_COMMAND *pCmd)
++{
++ MV_STATUS status;
++ MV_CESA_REQ* pReq = pCesaReqEmpty;
++ int sid = pCmd->sessionId;
++ MV_CESA_SA* pSA = &pCesaSAD[sid];
++#if (MV_CESA_VERSION >= 3)
++ MV_CESA_REQ* pFromReq;
++ MV_CESA_REQ* pToReq;
++#endif
++ cesaStats.reqCount++;
++
++ /* Check that the request queue is not FULL */
++ if(cesaReqResources == 0)
++ return MV_NO_RESOURCE;
++
++ if( (sid >= cesaMaxSA) || (!pSA->valid) )
++ {
++ mvOsPrintf("CESA Action Error: Session sid=%d is INVALID\n", sid);
++ return MV_BAD_PARAM;
++ }
++ pSA->count++;
++
++ if(pSA->ctrMode)
++ {
++ /* AES in CTR mode can't be mixed with Authentication */
++ if( (pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) )
++ {
++ mvOsPrintf("mvCesaAction : CRYPTO CTR mode can't be mixed with AUTH\n");
++ return MV_NOT_ALLOWED;
++ }
++ /* All other request parameters should not be checked because key stream */
++ /* (not user data) processed by AES HW engine */
++ pReq->pOrgCmd = pCmd;
++ /* Allocate temporary pCmd structure for Key stream */
++ pCmd = mvCesaCtrModeInit();
++ if(pCmd == NULL)
++ return MV_OUT_OF_CPU_MEM;
++
++ /* Prepare Key stream */
++ mvCesaCtrModePrepare(pCmd, pReq->pOrgCmd);
++ pReq->fixOffset = 0;
++ }
++ else
++ {
++ /* Check request parameters and calculae fixOffset */
++ status = mvCesaParamCheck(pSA, pCmd, &pReq->fixOffset);
++ if(status != MV_OK)
++ {
++ return status;
++ }
++ }
++ pReq->pCmd = pCmd;
++
++ /* Check if the packet need fragmentation */
++ if(pCmd->pSrc->mbufSize <= sizeof(cesaSramVirtPtr->buf) )
++ {
++ /* request size is smaller than single buffer size */
++ pReq->fragMode = MV_CESA_FRAG_NONE;
++
++ /* Prepare NOT fragmented packets */
++ status = mvCesaReqProcess(pReq);
++ if(status != MV_OK)
++ {
++ mvOsPrintf("CesaReady: ReqProcess error: pReq=%p, status=0x%x\n",
++ pReq, status);
++ }
++#if (MV_CESA_VERSION >= 3)
++ pReq->frags.numFrag = 1;
++#endif
++ }
++ else
++ {
++ MV_U8 frag = 0;
++
++ /* request size is larger than buffer size - needs fragmentation */
++
++ /* Check restrictions for processing fragmented packets */
++ status = mvCesaFragParamCheck(pSA, pCmd);
++ if(status != MV_OK)
++ return status;
++
++ pReq->fragMode = MV_CESA_FRAG_FIRST;
++ pReq->frags.nextFrag = 0;
++
++ /* Prepare Process Fragmented packets */
++ while(pReq->fragMode != MV_CESA_FRAG_LAST)
++ {
++ if(frag >= MV_CESA_MAX_REQ_FRAGS)
++ {
++ mvOsPrintf("mvCesaAction Error: Too large request frag=%d\n", frag);
++ return MV_OUT_OF_CPU_MEM;
++ }
++ status = mvCesaFragReqProcess(pReq, frag);
++ if(status == MV_OK) {
++#if (MV_CESA_VERSION >= 3)
++ if(frag) {
++ pReq->dma[frag-1].pDmaLast->phyNextDescPtr =
++ MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, pReq->dma[frag].pDmaFirst));
++ mvOsCacheFlush(NULL, pReq->dma[frag-1].pDmaLast, sizeof(MV_DMA_DESC));
++ }
++#endif
++ frag++;
++ }
++ }
++ pReq->frags.numFrag = frag;
++#if (MV_CESA_VERSION >= 3)
++ if(chainReqNum) {
++ chainReqNum += pReq->frags.numFrag;
++ if(chainReqNum >= MAX_CESA_CHAIN_LENGTH)
++ chainReqNum = MAX_CESA_CHAIN_LENGTH;
++ }
++#endif
++ }
++
++ pReq->state = MV_CESA_PENDING;
++
++ pCesaReqEmpty = MV_CESA_REQ_NEXT_PTR(pReq);
++ cesaReqResources -= 1;
++
++/* #ifdef CESA_DEBUG */
++ if( (cesaQueueDepth - cesaReqResources) > cesaStats.maxReqCount)
++ cesaStats.maxReqCount = (cesaQueueDepth - cesaReqResources);
++/* #endif CESA_DEBUG */
++
++ cesaLastSid = sid;
++
++#if (MV_CESA_VERSION >= 3)
++ /* Are we within chain bounderies and follows the first request ? */
++ if((chainReqNum > 0) && (chainReqNum < MAX_CESA_CHAIN_LENGTH)) {
++ if(chainIndex) {
++ pFromReq = MV_CESA_REQ_PREV_PTR(pReq);
++ pToReq = pReq;
++ pReq->state = MV_CESA_CHAIN;
++ /* assume concatenating is possible */
++ pFromReq->dma[pFromReq->frags.numFrag-1].pDmaLast->phyNextDescPtr =
++ MV_32BIT_LE(mvCesaVirtToPhys(&pToReq->dmaDescBuf, pToReq->dma[0].pDmaFirst));
++ mvOsCacheFlush(NULL, pFromReq->dma[pFromReq->frags.numFrag-1].pDmaLast, sizeof(MV_DMA_DESC));
++
++ /* align active & next pointers */
++ if(pNextActiveChain->state != MV_CESA_PENDING)
++ pEndCurrChain = pNextActiveChain = MV_CESA_REQ_NEXT_PTR(pReq);
++ }
++ else { /* we have only one chain, start new one */
++ chainReqNum = 0;
++ chainIndex++;
++ /* align active & next pointers */
++ if(pNextActiveChain->state != MV_CESA_PENDING)
++ pEndCurrChain = pNextActiveChain = pReq;
++ }
++ }
++ else {
++ /* In case we concatenate full chain */
++ if(chainReqNum == MAX_CESA_CHAIN_LENGTH) {
++ chainIndex++;
++ if(pNextActiveChain->state != MV_CESA_PENDING)
++ pEndCurrChain = pNextActiveChain = pReq;
++ chainReqNum = 0;
++ }
++
++ pReq = pCesaReqProcess;
++ if(pReq->state == MV_CESA_PENDING) {
++ pNextActiveChain = pReq;
++ pEndCurrChain = MV_CESA_REQ_NEXT_PTR(pReq);
++ /* Start Process new request */
++ mvCesaReqProcessStart(pReq);
++ }
++ }
++
++ chainReqNum++;
++
++ if((chainIndex < MAX_CESA_CHAIN_LENGTH) && (chainReqNum > cesaStats.maxChainUsage))
++ cesaStats.maxChainUsage = chainReqNum;
++
++#else
++
++ /* Check status of CESA channels and process requests if possible */
++ pReq = pCesaReqProcess;
++ if(pReq->state == MV_CESA_PENDING)
++ {
++ /* Start Process new request */
++ mvCesaReqProcessStart(pReq);
++ }
++#endif
++ /* If request queue became FULL - return MV_NO_MORE */
++ if(cesaReqResources == 0)
++ return MV_NO_MORE;
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvCesaReadyGet - Get crypto request that processing is finished
++*
++* DESCRIPTION:
++* This function complete request processing and return ready request to
++* caller. To don't miss interrupts the caller must call this function
++* while MV_OK or MV_TERMINATE values returned.
++*
++* INPUT:
++* MV_U32 chanMap - map of CESA channels finished thier job
++* accordingly with CESA Cause register.
++* MV_CESA_RESULT* pResult - pointer to structure contains information
++* about ready request. It includes pointer to
++* user private structure "pReqPrv", session identifier
++* for this request "sessionId" and return code.
++* Return code set to MV_FAIL if calculated digest value
++* on decode direction is different than digest value
++* in the packet.
++*
++* RETURN:
++* MV_OK - Success, ready request is returned.
++* MV_NOT_READY - Next request is not ready yet. New interrupt will
++* be generated for futher request processing.
++* MV_EMPTY - There is no more request for processing.
++* MV_BUSY - Fragmented request is not ready yet.
++* MV_TERMINATE - Call this function once more to complete processing
++* of fragmented request.
++*
++*******************************************************************************/
++MV_STATUS mvCesaReadyGet(MV_CESA_RESULT* pResult)
++{
++ MV_STATUS status, readyStatus = MV_NOT_READY;
++ MV_U32 statusReg;
++ MV_CESA_REQ* pReq;
++ MV_CESA_SA* pSA;
++
++#if (MV_CESA_VERSION >= 3)
++ if(isFirstReq == MV_TRUE) {
++ if(chainIndex == 0)
++ chainReqNum = 0;
++
++ isFirstReq = MV_FALSE;
++
++ if(pNextActiveChain->state == MV_CESA_PENDING) {
++ /* Start request Process */
++ mvCesaReqProcessStart(pNextActiveChain);
++ pEndCurrChain = pNextActiveChain;
++ if(chainIndex > 0)
++ chainIndex--;
++ /* Update pNextActiveChain to next chain head */
++ while(pNextActiveChain->state == MV_CESA_CHAIN)
++ pNextActiveChain = MV_CESA_REQ_NEXT_PTR(pNextActiveChain);
++ }
++ }
++
++ /* Check if there are more processed requests - can we remove pEndCurrChain ??? */
++ if(pCesaReqProcess == pEndCurrChain) {
++ isFirstReq = MV_TRUE;
++ pEndCurrChain = pNextActiveChain;
++#else
++ if(pCesaReqProcess->state != MV_CESA_PROCESS) {
++#endif
++ return MV_EMPTY;
++ }
++
++#ifdef CESA_DEBUG
++ statusReg = MV_REG_READ(MV_CESA_STATUS_REG);
++ if( statusReg & MV_CESA_STATUS_ACTIVE_MASK )
++ {
++ mvOsPrintf("mvCesaReadyGet: Not Ready, Status = 0x%x\n", statusReg);
++ cesaStats.notReadyCount++;
++ return MV_NOT_READY;
++ }
++#endif /* CESA_DEBUG */
++
++ cesaStats.readyCount++;
++
++ pReq = pCesaReqProcess;
++ pSA = &pCesaSAD[pReq->pCmd->sessionId];
++
++ pResult->retCode = MV_OK;
++ if(pReq->fragMode != MV_CESA_FRAG_NONE)
++ {
++ MV_U8* pNewDigest;
++ int frag;
++#if (MV_CESA_VERSION >= 3)
++ pReq->frags.nextFrag = 1;
++ while(pReq->frags.nextFrag <= pReq->frags.numFrag) {
++#endif
++ frag = (pReq->frags.nextFrag - 1);
++
++ /* Restore DMA descriptor list */
++ pReq->dma[frag].pDmaLast->phyNextDescPtr =
++ MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, &pReq->dma[frag].pDmaLast[1]));
++ pReq->dma[frag].pDmaLast = NULL;
++
++ /* Special processing for finished fragmented request */
++ if(pReq->frags.nextFrag >= pReq->frags.numFrag)
++ {
++ mvCesaMbufCacheUnmap(pReq->pCmd->pDst, 0, pReq->pCmd->pDst->mbufSize);
++
++ /* Fragmented packet is ready */
++ if( (pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) )
++ {
++ int macDataSize = pReq->pCmd->macLength - pReq->frags.macSize;
++
++ if(macDataSize != 0)
++ {
++ /* Calculate all other blocks by SW */
++ mvCesaFragAuthComplete(pReq, pSA, macDataSize);
++ }
++
++ /* Copy new digest from SRAM to the Destination buffer */
++ pNewDigest = cesaSramVirtPtr->buf + pReq->frags.newDigestOffset;
++ status = mvCesaCopyToMbuf(pNewDigest, pReq->pCmd->pDst,
++ pReq->pCmd->digestOffset, pSA->digestSize);
++
++ /* For decryption: Compare new digest value with original one */
++ if((pSA->config & MV_CESA_DIRECTION_MASK) ==
++ (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT))
++ {
++ if( memcmp(pNewDigest, pReq->frags.orgDigest, pSA->digestSize) != 0)
++ {
++/*
++ mvOsPrintf("Digest error: chan=%d, newDigest=%p, orgDigest=%p, status = 0x%x\n",
++ chan, pNewDigest, pReq->frags.orgDigest, MV_REG_READ(MV_CESA_STATUS_REG));
++*/
++ /* Signiture verification is failed */
++ pResult->retCode = MV_FAIL;
++ }
++ }
++ }
++ readyStatus = MV_OK;
++ }
++#if (MV_CESA_VERSION >= 3)
++ pReq->frags.nextFrag++;
++ }
++#endif
++ }
++ else
++ {
++ mvCesaMbufCacheUnmap(pReq->pCmd->pDst, 0, pReq->pCmd->pDst->mbufSize);
++
++ /* Restore DMA descriptor list */
++ pReq->dma[0].pDmaLast->phyNextDescPtr =
++ MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, &pReq->dma[0].pDmaLast[1]));
++ pReq->dma[0].pDmaLast = NULL;
++ if( ((pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) &&
++ ((pSA->config & MV_CESA_DIRECTION_MASK) ==
++ (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT)) )
++ {
++ /* For AUTH on decode : Check Digest result in Status register */
++ statusReg = MV_REG_READ(MV_CESA_STATUS_REG);
++ if(statusReg & MV_CESA_STATUS_DIGEST_ERR_MASK)
++ {
++/*
++ mvOsPrintf("Digest error: chan=%d, status = 0x%x\n",
++ chan, statusReg);
++*/
++ /* Signiture verification is failed */
++ pResult->retCode = MV_FAIL;
++ }
++ }
++ readyStatus = MV_OK;
++ }
++
++ if(readyStatus == MV_OK)
++ {
++ /* If Request is ready - Prepare pResult structure */
++ pResult->pReqPrv = pReq->pCmd->pReqPrv;
++ pResult->sessionId = pReq->pCmd->sessionId;
++
++ pReq->state = MV_CESA_IDLE;
++ pCesaReqProcess = MV_CESA_REQ_NEXT_PTR(pReq);
++ cesaReqResources++;
++
++ if(pSA->ctrMode)
++ {
++ /* For AES CTR mode - complete processing and free allocated resources */
++ mvCesaCtrModeComplete(pReq->pOrgCmd, pReq->pCmd);
++ mvCesaCtrModeFinish(pReq->pCmd);
++ pReq->pOrgCmd = NULL;
++ }
++ }
++
++#if (MV_CESA_VERSION < 3)
++ if(pCesaReqProcess->state == MV_CESA_PROCESS)
++ {
++ /* Start request Process */
++ mvCesaReqProcessStart(pCesaReqProcess);
++ if(readyStatus == MV_NOT_READY)
++ readyStatus = MV_BUSY;
++ }
++ else if(pCesaReqProcess != pCesaReqEmpty)
++ {
++ /* Start process new request from the queue */
++ mvCesaReqProcessStart(pCesaReqProcess);
++ }
++#endif
++ return readyStatus;
++}
++
++/***************** Functions to work with CESA_MBUF structure ******************/
++
++/*******************************************************************************
++* mvCesaMbufOffset - Locate offset in the Mbuf structure
++*
++* DESCRIPTION:
++* This function locates offset inside Multi-Bufeer structure.
++* It get fragment number and place in the fragment where the offset
++* is located.
++*
++*
++* INPUT:
++* MV_CESA_MBUF* pMbuf - Pointer to multi-buffer structure
++* int offset - Offset from the beginning of the data presented by
++* the Mbuf structure.
++*
++* OUTPUT:
++* int* pBufOffset - Offset from the beginning of the fragment where
++* the offset is located.
++*
++* RETURN:
++* int - Number of fragment, where the offset is located\
++*
++*******************************************************************************/
++int mvCesaMbufOffset(MV_CESA_MBUF* pMbuf, int offset, int* pBufOffset)
++{
++ int frag = 0;
++
++ while(offset > 0)
++ {
++ if(frag >= pMbuf->numFrags)
++ {
++ mvOsPrintf("mvCesaMbufOffset: Error: frag (%d) > numFrags (%d)\n",
++ frag, pMbuf->numFrags);
++ return MV_INVALID;
++ }
++ if(offset < pMbuf->pFrags[frag].bufSize)
++ {
++ break;
++ }
++ offset -= pMbuf->pFrags[frag].bufSize;
++ frag++;
++ }
++ if(pBufOffset != NULL)
++ *pBufOffset = offset;
++
++ return frag;
++}
++
++/*******************************************************************************
++* mvCesaCopyFromMbuf - Copy data from the Mbuf structure to continuous buffer
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_U8* pDstBuf - Pointer to continuous buffer, where data is
++* copied to.
++* MV_CESA_MBUF* pSrcMbuf - Pointer to multi-buffer structure where data is
++* copied from.
++* int offset - Offset in the Mbuf structure where located first
++* byte of data should be copied.
++* int size - Size of data should be copied
++*
++* RETURN:
++* MV_OK - Success, all data is copied successfully.
++* MV_OUT_OF_RANGE - Failed, offset is out of Multi-buffer data range.
++* No data is copied.
++* MV_EMPTY - Multi-buffer structure has not enough data to copy
++* Data from the offset to end of Mbuf data is copied.
++*
++*******************************************************************************/
++MV_STATUS mvCesaCopyFromMbuf(MV_U8* pDstBuf, MV_CESA_MBUF* pSrcMbuf,
++ int offset, int size)
++{
++ int frag, fragOffset, bufSize;
++ MV_U8* pBuf;
++
++ if(size == 0)
++ return MV_OK;
++
++ frag = mvCesaMbufOffset(pSrcMbuf, offset, &fragOffset);
++ if(frag == MV_INVALID)
++ {
++ mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset);
++ return MV_OUT_OF_RANGE;
++ }
++
++ bufSize = pSrcMbuf->pFrags[frag].bufSize - fragOffset;
++ pBuf = pSrcMbuf->pFrags[frag].bufVirtPtr + fragOffset;
++ while(MV_TRUE)
++ {
++ if(size <= bufSize)
++ {
++ memcpy(pDstBuf, pBuf, size);
++ return MV_OK;
++ }
++ memcpy(pDstBuf, pBuf, bufSize);
++ size -= bufSize;
++ frag++;
++ pDstBuf += bufSize;
++ if(frag >= pSrcMbuf->numFrags)
++ break;
++
++ bufSize = pSrcMbuf->pFrags[frag].bufSize;
++ pBuf = pSrcMbuf->pFrags[frag].bufVirtPtr;
++ }
++ mvOsPrintf("mvCesaCopyFromMbuf: Mbuf is EMPTY - %d bytes isn't copied\n",
++ size);
++ return MV_EMPTY;
++}
++
++/*******************************************************************************
++* mvCesaCopyToMbuf - Copy data from continuous buffer to the Mbuf structure
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_U8* pSrcBuf - Pointer to continuous buffer, where data is
++* copied from.
++* MV_CESA_MBUF* pDstMbuf - Pointer to multi-buffer structure where data is
++* copied to.
++* int offset - Offset in the Mbuf structure where located first
++* byte of data should be copied.
++* int size - Size of data should be copied
++*
++* RETURN:
++* MV_OK - Success, all data is copied successfully.
++* MV_OUT_OF_RANGE - Failed, offset is out of Multi-buffer data range.
++* No data is copied.
++* MV_FULL - Multi-buffer structure has not enough place to copy
++* all data. Data from the offset to end of Mbuf data
++* is copied.
++*
++*******************************************************************************/
++MV_STATUS mvCesaCopyToMbuf(MV_U8* pSrcBuf, MV_CESA_MBUF* pDstMbuf,
++ int offset, int size)
++{
++ int frag, fragOffset, bufSize;
++ MV_U8* pBuf;
++
++ if(size == 0)
++ return MV_OK;
++
++ frag = mvCesaMbufOffset(pDstMbuf, offset, &fragOffset);
++ if(frag == MV_INVALID)
++ {
++ mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset);
++ return MV_OUT_OF_RANGE;
++ }
++
++ bufSize = pDstMbuf->pFrags[frag].bufSize - fragOffset;
++ pBuf = pDstMbuf->pFrags[frag].bufVirtPtr + fragOffset;
++ while(MV_TRUE)
++ {
++ if(size <= bufSize)
++ {
++ memcpy(pBuf, pSrcBuf, size);
++ return MV_OK;
++ }
++ memcpy(pBuf, pSrcBuf, bufSize);
++ size -= bufSize;
++ frag++;
++ pSrcBuf += bufSize;
++ if(frag >= pDstMbuf->numFrags)
++ break;
++
++ bufSize = pDstMbuf->pFrags[frag].bufSize;
++ pBuf = pDstMbuf->pFrags[frag].bufVirtPtr;
++ }
++ mvOsPrintf("mvCesaCopyToMbuf: Mbuf is FULL - %d bytes isn't copied\n",
++ size);
++ return MV_FULL;
++}
++
++/*******************************************************************************
++* mvCesaMbufCopy - Copy data from one Mbuf structure to the other Mbuf structure
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++*
++* MV_CESA_MBUF* pDstMbuf - Pointer to multi-buffer structure where data is
++* copied to.
++* int dstMbufOffset - Offset in the dstMbuf structure where first byte
++* of data should be copied to.
++* MV_CESA_MBUF* pSrcMbuf - Pointer to multi-buffer structure where data is
++* copied from.
++* int srcMbufOffset - Offset in the srcMbuf structure where first byte
++* of data should be copied from.
++* int size - Size of data should be copied
++*
++* RETURN:
++* MV_OK - Success, all data is copied successfully.
++* MV_OUT_OF_RANGE - Failed, srcMbufOffset or dstMbufOffset is out of
++* srcMbuf or dstMbuf structure correspondently.
++* No data is copied.
++* MV_BAD_SIZE - srcMbuf or dstMbuf structure is too small to copy
++* all data. Partial data is copied
++*
++*******************************************************************************/
++MV_STATUS mvCesaMbufCopy(MV_CESA_MBUF* pMbufDst, int dstMbufOffset,
++ MV_CESA_MBUF* pMbufSrc, int srcMbufOffset, int size)
++{
++ int srcFrag, dstFrag, srcSize, dstSize, srcOffset, dstOffset;
++ int copySize;
++ MV_U8 *pSrc, *pDst;
++
++ if(size == 0)
++ return MV_OK;
++
++ srcFrag = mvCesaMbufOffset(pMbufSrc, srcMbufOffset, &srcOffset);
++ if(srcFrag == MV_INVALID)
++ {
++ mvOsPrintf("CESA srcMbuf Error: offset (%d) out of range\n", srcMbufOffset);
++ return MV_OUT_OF_RANGE;
++ }
++ pSrc = pMbufSrc->pFrags[srcFrag].bufVirtPtr + srcOffset;
++ srcSize = pMbufSrc->pFrags[srcFrag].bufSize - srcOffset;
++
++ dstFrag = mvCesaMbufOffset(pMbufDst, dstMbufOffset, &dstOffset);
++ if(dstFrag == MV_INVALID)
++ {
++ mvOsPrintf("CESA dstMbuf Error: offset (%d) out of range\n", dstMbufOffset);
++ return MV_OUT_OF_RANGE;
++ }
++ pDst = pMbufDst->pFrags[dstFrag].bufVirtPtr + dstOffset;
++ dstSize = pMbufDst->pFrags[dstFrag].bufSize - dstOffset;
++
++ while(size > 0)
++ {
++ copySize = MV_MIN(srcSize, dstSize);
++ if(size <= copySize)
++ {
++ memcpy(pDst, pSrc, size);
++ return MV_OK;
++ }
++ memcpy(pDst, pSrc, copySize);
++ size -= copySize;
++ srcSize -= copySize;
++ dstSize -= copySize;
++
++ if(srcSize == 0)
++ {
++ srcFrag++;
++ if(srcFrag >= pMbufSrc->numFrags)
++ break;
++
++ pSrc = pMbufSrc->pFrags[srcFrag].bufVirtPtr;
++ srcSize = pMbufSrc->pFrags[srcFrag].bufSize;
++ }
++
++ if(dstSize == 0)
++ {
++ dstFrag++;
++ if(dstFrag >= pMbufDst->numFrags)
++ break;
++
++ pDst = pMbufDst->pFrags[dstFrag].bufVirtPtr;
++ dstSize = pMbufDst->pFrags[dstFrag].bufSize;
++ }
++ }
++ mvOsPrintf("mvCesaMbufCopy: BAD size - %d bytes isn't copied\n",
++ size);
++
++ return MV_BAD_SIZE;
++}
++
++static MV_STATUS mvCesaMbufCacheUnmap(MV_CESA_MBUF* pMbuf, int offset, int size)
++{
++ int frag, fragOffset, bufSize;
++ MV_U8* pBuf;
++
++ if(size == 0)
++ return MV_OK;
++
++ frag = mvCesaMbufOffset(pMbuf, offset, &fragOffset);
++ if(frag == MV_INVALID)
++ {
++ mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset);
++ return MV_OUT_OF_RANGE;
++ }
++
++ bufSize = pMbuf->pFrags[frag].bufSize - fragOffset;
++ pBuf = pMbuf->pFrags[frag].bufVirtPtr + fragOffset;
++ while(MV_TRUE)
++ {
++ if(size <= bufSize)
++ {
++ mvOsCacheUnmap(NULL, mvOsIoVirtToPhy(NULL, pBuf), size);
++ return MV_OK;
++ }
++
++ mvOsCacheUnmap(NULL, mvOsIoVirtToPhy(NULL, pBuf), bufSize);
++ size -= bufSize;
++ frag++;
++ if(frag >= pMbuf->numFrags)
++ break;
++
++ bufSize = pMbuf->pFrags[frag].bufSize;
++ pBuf = pMbuf->pFrags[frag].bufVirtPtr;
++ }
++ mvOsPrintf("%s: Mbuf is FULL - %d bytes isn't Unmapped\n",
++ __FUNCTION__, size);
++ return MV_FULL;
++}
++
++
++/*************************************** Local Functions ******************************/
++
++/*******************************************************************************
++* mvCesaFragReqProcess - Process fragmented request
++*
++* DESCRIPTION:
++* This function processes a fragment of fragmented request (First, Middle or Last)
++*
++*
++* INPUT:
++* MV_CESA_REQ* pReq - Pointer to the request in the request queue.
++*
++* RETURN:
++* MV_OK - The fragment is successfully passed to HW for processing.
++* MV_TERMINATE - Means, that HW finished its work on this packet and no more
++* interrupts will be generated for this request.
++* Function mvCesaReadyGet() must be called to complete request
++* processing and get request result.
++*
++*******************************************************************************/
++static MV_STATUS mvCesaFragReqProcess(MV_CESA_REQ* pReq, MV_U8 frag)
++{
++ int i, copySize, cryptoDataSize, macDataSize, sid;
++ int cryptoIvOffset, digestOffset;
++ MV_U32 config;
++ MV_CESA_COMMAND* pCmd = pReq->pCmd;
++ MV_CESA_SA* pSA;
++ MV_CESA_MBUF* pMbuf;
++ MV_DMA_DESC* pDmaDesc = pReq->dma[frag].pDmaFirst;
++ MV_U8* pSramBuf = cesaSramVirtPtr->buf;
++ int macTotalLen = 0;
++ int fixOffset, cryptoOffset, macOffset;
++
++ cesaStats.fragCount++;
++
++ sid = pReq->pCmd->sessionId;
++
++ pSA = &pCesaSAD[sid];
++
++ cryptoIvOffset = digestOffset = 0;
++ i = macDataSize = 0;
++ cryptoDataSize = 0;
++
++ /* First fragment processing */
++ if(pReq->fragMode == MV_CESA_FRAG_FIRST)
++ {
++ /* pReq->frags monitors processing of fragmented request between fragments */
++ pReq->frags.bufOffset = 0;
++ pReq->frags.cryptoSize = 0;
++ pReq->frags.macSize = 0;
++
++ config = pSA->config | (MV_CESA_FRAG_FIRST << MV_CESA_FRAG_MODE_OFFSET);
++
++ /* fixOffset can be not equal to zero only for FIRST fragment */
++ fixOffset = pReq->fixOffset;
++ /* For FIRST fragment crypto and mac offsets are taken from pCmd */
++ cryptoOffset = pCmd->cryptoOffset;
++ macOffset = pCmd->macOffset;
++
++ copySize = sizeof(cesaSramVirtPtr->buf) - pReq->fixOffset;
++
++ /* Find fragment size: Must meet all requirements for CRYPTO and MAC
++ * cryptoDataSize - size of data will be encrypted/decrypted in this fragment
++ * macDataSize - size of data will be signed/verified in this fragment
++ * copySize - size of data will be copied from srcMbuf to SRAM and
++ * back to dstMbuf for this fragment
++ */
++ mvCesaFragSizeFind(pSA, pReq, cryptoOffset, macOffset,
++ &copySize, &cryptoDataSize, &macDataSize);
++
++ if( (pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET))
++ {
++ /* CryptoIV special processing */
++ if( (pSA->config & MV_CESA_CRYPTO_MODE_MASK) ==
++ (MV_CESA_CRYPTO_CBC << MV_CESA_CRYPTO_MODE_BIT) )
++ {
++ /* In CBC mode for encode direction when IV from user */
++ if( (pCmd->ivFromUser) &&
++ ((pSA->config & MV_CESA_DIRECTION_MASK) ==
++ (MV_CESA_DIR_ENCODE << MV_CESA_DIRECTION_BIT)) )
++ {
++
++ /* For Crypto Encode in CBC mode HW always takes IV from SRAM IVPointer,
++ * (not from IVBufPointer). So when ivFromUser==1, we should copy IV from user place
++ * in the buffer to SRAM IVPointer
++ */
++ i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->cryptoIV, &pDmaDesc[i],
++ MV_FALSE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush);
++ }
++
++ /* Special processing when IV is not located in the first fragment */
++ if(pCmd->ivOffset > (copySize - pSA->cryptoIvSize))
++ {
++ /* Prepare dummy place for cryptoIV in SRAM */
++ cryptoIvOffset = cesaSramVirtPtr->tempCryptoIV - mvCesaSramAddrGet();
++
++ /* For Decryption: Copy IV value from pCmd->ivOffset to Special SRAM place */
++ if((pSA->config & MV_CESA_DIRECTION_MASK) ==
++ (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT))
++ {
++ i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->tempCryptoIV, &pDmaDesc[i],
++ MV_FALSE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush);
++ }
++ else
++ {
++ /* For Encryption when IV is NOT from User: */
++ /* Copy IV from SRAM to buffer (pCmd->ivOffset) */
++ if(pCmd->ivFromUser == 0)
++ {
++ /* copy IV value from cryptoIV to Buffer (pCmd->ivOffset) */
++ i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->cryptoIV, &pDmaDesc[i],
++ MV_TRUE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush);
++ }
++ }
++ }
++ else
++ {
++ cryptoIvOffset = pCmd->ivOffset;
++ }
++ }
++ }
++
++ if( (pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) )
++ {
++ /* MAC digest special processing on Decode direction */
++ if((pSA->config & MV_CESA_DIRECTION_MASK) ==
++ (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT))
++ {
++ /* Save digest from pCmd->digestOffset */
++ mvCesaCopyFromMbuf(pReq->frags.orgDigest,
++ pCmd->pSrc, pCmd->digestOffset, pSA->digestSize);
++
++ /* If pCmd->digestOffset is not located on the first */
++ if(pCmd->digestOffset > (copySize - pSA->digestSize))
++ {
++ MV_U8 digestZero[MV_CESA_MAX_DIGEST_SIZE];
++
++ /* Set zeros to pCmd->digestOffset (DRAM) */
++ memset(digestZero, 0, MV_CESA_MAX_DIGEST_SIZE);
++ mvCesaCopyToMbuf(digestZero, pCmd->pSrc, pCmd->digestOffset, pSA->digestSize);
++
++ /* Prepare dummy place for digest in SRAM */
++ digestOffset = cesaSramVirtPtr->tempDigest - mvCesaSramAddrGet();
++ }
++ else
++ {
++ digestOffset = pCmd->digestOffset;
++ }
++ }
++ }
++ /* Update SA in SRAM */
++ if(cesaLastSid != sid)
++ {
++ mvCesaSramSaUpdate(sid, &pDmaDesc[i]);
++ i++;
++ }
++
++ pReq->fragMode = MV_CESA_FRAG_MIDDLE;
++ }
++ else
++ {
++ /* Continue fragment */
++ fixOffset = 0;
++ cryptoOffset = 0;
++ macOffset = 0;
++ if( (pCmd->pSrc->mbufSize - pReq->frags.bufOffset) <= sizeof(cesaSramVirtPtr->buf))
++ {
++ /* Last fragment */
++ config = pSA->config | (MV_CESA_FRAG_LAST << MV_CESA_FRAG_MODE_OFFSET);
++ pReq->fragMode = MV_CESA_FRAG_LAST;
++ copySize = pCmd->pSrc->mbufSize - pReq->frags.bufOffset;
++
++ if( (pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) )
++ {
++ macDataSize = pCmd->macLength - pReq->frags.macSize;
++
++ /* If pCmd->digestOffset is not located on last fragment */
++ if(pCmd->digestOffset < pReq->frags.bufOffset)
++ {
++ /* Prepare dummy place for digest in SRAM */
++ digestOffset = cesaSramVirtPtr->tempDigest - mvCesaSramAddrGet();
++ }
++ else
++ {
++ digestOffset = pCmd->digestOffset - pReq->frags.bufOffset;
++ }
++ pReq->frags.newDigestOffset = digestOffset;
++ macTotalLen = pCmd->macLength;
++
++ /* HW can't calculate the Digest correctly for fragmented packets
++ * in the following cases:
++ * - MV88F5182 ||
++ * - MV88F5181L when total macLength more that 16 Kbytes ||
++ * - total macLength more that 64 Kbytes
++ */
++ if( (mvCtrlModelGet() == MV_5182_DEV_ID) ||
++ ( (mvCtrlModelGet() == MV_5181_DEV_ID) &&
++ (mvCtrlRevGet() >= MV_5181L_A0_REV) &&
++ (pCmd->macLength >= (1 << 14)) ) )
++ {
++ return MV_TERMINATE;
++ }
++ }
++ if( (pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET) )
++ {
++ cryptoDataSize = pCmd->cryptoLength - pReq->frags.cryptoSize;
++ }
++
++ /* cryptoIvOffset - don't care */
++ }
++ else
++ {
++ /* WA for MV88F5182 SHA1 and MD5 fragmentation mode */
++ if( (mvCtrlModelGet() == MV_5182_DEV_ID) &&
++ (((pSA->config & MV_CESA_MAC_MODE_MASK) ==
++ (MV_CESA_MAC_MD5 << MV_CESA_MAC_MODE_OFFSET)) ||
++ ((pSA->config & MV_CESA_MAC_MODE_MASK) ==
++ (MV_CESA_MAC_SHA1 << MV_CESA_MAC_MODE_OFFSET))) )
++ {
++ pReq->frags.newDigestOffset = cesaSramVirtPtr->tempDigest - mvCesaSramAddrGet();
++ pReq->fragMode = MV_CESA_FRAG_LAST;
++
++ return MV_TERMINATE;
++ }
++ /* Middle fragment */
++ config = pSA->config | (MV_CESA_FRAG_MIDDLE << MV_CESA_FRAG_MODE_OFFSET);
++ copySize = sizeof(cesaSramVirtPtr->buf);
++ /* digestOffset and cryptoIvOffset - don't care */
++
++ /* Find fragment size */
++ mvCesaFragSizeFind(pSA, pReq, cryptoOffset, macOffset,
++ &copySize, &cryptoDataSize, &macDataSize);
++ }
++ }
++ /********* Prepare DMA descriptors to copy from pSrc to SRAM *********/
++ pMbuf = pCmd->pSrc;
++ i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i],
++ MV_FALSE, pReq->frags.bufOffset, copySize, pCmd->skipFlush);
++
++ /* Prepare CESA descriptor to copy from DRAM to SRAM by DMA */
++ mvCesaSramDescrBuild(config, frag,
++ cryptoOffset + fixOffset, cryptoIvOffset + fixOffset,
++ cryptoDataSize, macOffset + fixOffset,
++ digestOffset + fixOffset, macDataSize, macTotalLen,
++ pReq, &pDmaDesc[i]);
++ i++;
++
++ /* Add special descriptor Ownership for CPU */
++ pDmaDesc[i].byteCnt = 0;
++ pDmaDesc[i].phySrcAdd = 0;
++ pDmaDesc[i].phyDestAdd = 0;
++ i++;
++
++ /********* Prepare DMA descriptors to copy from SRAM to pDst *********/
++ pMbuf = pCmd->pDst;
++ i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i],
++ MV_TRUE, pReq->frags.bufOffset, copySize, pCmd->skipFlush);
++
++ /* Next field of Last DMA descriptor must be NULL */
++ pDmaDesc[i-1].phyNextDescPtr = 0;
++ pReq->dma[frag].pDmaLast = &pDmaDesc[i-1];
++ mvOsCacheFlush(NULL, pReq->dma[frag].pDmaFirst,
++ i*sizeof(MV_DMA_DESC));
++
++ /*mvCesaDebugDescriptor(&cesaSramVirtPtr->desc[frag]);*/
++
++ pReq->frags.bufOffset += copySize;
++ pReq->frags.cryptoSize += cryptoDataSize;
++ pReq->frags.macSize += macDataSize;
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvCesaReqProcess - Process regular (Non-fragmented) request
++*
++* DESCRIPTION:
++* This function processes the whole (not fragmented) request
++*
++* INPUT:
++* MV_CESA_REQ* pReq - Pointer to the request in the request queue.
++*
++* RETURN:
++* MV_OK - The request is successfully passed to HW for processing.
++* Other - Failure. The request will not be processed
++*
++*******************************************************************************/
++static MV_STATUS mvCesaReqProcess(MV_CESA_REQ* pReq)
++{
++ MV_CESA_MBUF *pMbuf;
++ MV_DMA_DESC *pDmaDesc;
++ MV_U8 *pSramBuf;
++ int sid, i, fixOffset;
++ MV_CESA_SA *pSA;
++ MV_CESA_COMMAND *pCmd = pReq->pCmd;
++
++ cesaStats.procCount++;
++
++ sid = pCmd->sessionId;
++ pSA = &pCesaSAD[sid];
++ pDmaDesc = pReq->dma[0].pDmaFirst;
++ pSramBuf = cesaSramVirtPtr->buf;
++ fixOffset = pReq->fixOffset;
++
++/*
++ mvOsPrintf("mvCesaReqProcess: sid=%d, pSA=%p, pDmaDesc=%p, pSramBuf=%p\n",
++ sid, pSA, pDmaDesc, pSramBuf);
++*/
++ i = 0;
++
++ /* Crypto IV Special processing in CBC mode for Encryption direction */
++ if( ((pSA->config & MV_CESA_OPERATION_MASK) != (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET)) &&
++ ((pSA->config & MV_CESA_CRYPTO_MODE_MASK) == (MV_CESA_CRYPTO_CBC << MV_CESA_CRYPTO_MODE_BIT)) &&
++ ((pSA->config & MV_CESA_DIRECTION_MASK) == (MV_CESA_DIR_ENCODE << MV_CESA_DIRECTION_BIT)) &&
++ (pCmd->ivFromUser) )
++ {
++ /* For Crypto Encode in CBC mode HW always takes IV from SRAM IVPointer,
++ * (not from IVBufPointer). So when ivFromUser==1, we should copy IV from user place
++ * in the buffer to SRAM IVPointer
++ */
++ i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->cryptoIV, &pDmaDesc[i],
++ MV_FALSE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush);
++ }
++
++ /* Update SA in SRAM */
++ if(cesaLastSid != sid)
++ {
++ mvCesaSramSaUpdate(sid, &pDmaDesc[i]);
++ i++;
++ }
++
++ /********* Prepare DMA descriptors to copy from pSrc to SRAM *********/
++ pMbuf = pCmd->pSrc;
++ i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i],
++ MV_FALSE, 0, pMbuf->mbufSize, pCmd->skipFlush);
++
++ /* Prepare Security Accelerator descriptor to SRAM words 0 - 7 */
++ mvCesaSramDescrBuild(pSA->config, 0, pCmd->cryptoOffset + fixOffset,
++ pCmd->ivOffset + fixOffset, pCmd->cryptoLength,
++ pCmd->macOffset + fixOffset, pCmd->digestOffset + fixOffset,
++ pCmd->macLength, pCmd->macLength, pReq, &pDmaDesc[i]);
++ i++;
++
++ /* Add special descriptor Ownership for CPU */
++ pDmaDesc[i].byteCnt = 0;
++ pDmaDesc[i].phySrcAdd = 0;
++ pDmaDesc[i].phyDestAdd = 0;
++ i++;
++
++ /********* Prepare DMA descriptors to copy from SRAM to pDst *********/
++ pMbuf = pCmd->pDst;
++ i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i],
++ MV_TRUE, 0, pMbuf->mbufSize, pCmd->skipFlush);
++
++ /* Next field of Last DMA descriptor must be NULL */
++ pDmaDesc[i-1].phyNextDescPtr = 0;
++ pReq->dma[0].pDmaLast = &pDmaDesc[i-1];
++ mvOsCacheFlush(NULL, pReq->dma[0].pDmaFirst, i*sizeof(MV_DMA_DESC));
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvCesaSramDescrBuild - Set CESA descriptor in SRAM
++*
++* DESCRIPTION:
++* This function builds CESA descriptor in SRAM from all Command parameters
++*
++*
++* INPUT:
++* int chan - CESA channel uses the descriptor
++* MV_U32 config - 32 bits of WORD_0 in CESA descriptor structure
++* int cryptoOffset - Offset from the beginning of SRAM buffer where
++* data for encryption/decription is started.
++* int ivOffset - Offset of crypto IV from the SRAM base. Valid only
++* for first fragment.
++* int cryptoLength - Size (in bytes) of data for encryption/descryption
++* operation on this fragment.
++* int macOffset - Offset from the beginning of SRAM buffer where
++* data for Authentication is started
++* int digestOffset - Offset from the beginning of SRAM buffer where
++* digest is located. Valid for first and last fragments.
++* int macLength - Size (in bytes) of data for Authentication
++* operation on this fragment.
++* int macTotalLen - Toatl size (in bytes) of data for Authentication
++* operation on the whole request (packet). Valid for
++* last fragment only.
++*
++* RETURN: None
++*
++*******************************************************************************/
++static void mvCesaSramDescrBuild(MV_U32 config, int frag,
++ int cryptoOffset, int ivOffset, int cryptoLength,
++ int macOffset, int digestOffset, int macLength,
++ int macTotalLen, MV_CESA_REQ* pReq, MV_DMA_DESC* pDmaDesc)
++{
++ MV_CESA_DESC* pCesaDesc = &pReq->pCesaDesc[frag];
++ MV_CESA_DESC* pSramDesc = pSramDesc = &cesaSramVirtPtr->desc;
++ MV_U16 sramBufOffset = (MV_U16)((MV_U8*)cesaSramVirtPtr->buf - mvCesaSramAddrGet());
++
++ pCesaDesc->config = MV_32BIT_LE(config);
++
++ if( (config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET) )
++ {
++ /* word 1 */
++ pCesaDesc->cryptoSrcOffset = MV_16BIT_LE(sramBufOffset + cryptoOffset);
++ pCesaDesc->cryptoDstOffset = MV_16BIT_LE(sramBufOffset + cryptoOffset);
++ /* word 2 */
++ pCesaDesc->cryptoDataLen = MV_16BIT_LE(cryptoLength);
++ /* word 3 */
++ pCesaDesc->cryptoKeyOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->sramSA.cryptoKey -
++ mvCesaSramAddrGet()));
++ /* word 4 */
++ pCesaDesc->cryptoIvOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->cryptoIV -
++ mvCesaSramAddrGet()));
++ pCesaDesc->cryptoIvBufOffset = MV_16BIT_LE(sramBufOffset + ivOffset);
++ }
++
++ if( (config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) )
++ {
++ /* word 5 */
++ pCesaDesc->macSrcOffset = MV_16BIT_LE(sramBufOffset + macOffset);
++ pCesaDesc->macTotalLen = MV_16BIT_LE(macTotalLen);
++
++ /* word 6 */
++ pCesaDesc->macDigestOffset = MV_16BIT_LE(sramBufOffset + digestOffset);
++ pCesaDesc->macDataLen = MV_16BIT_LE(macLength);
++
++ /* word 7 */
++ pCesaDesc->macInnerIvOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->sramSA.macInnerIV -
++ mvCesaSramAddrGet()));
++ pCesaDesc->macOuterIvOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->sramSA.macOuterIV -
++ mvCesaSramAddrGet()));
++ }
++ /* Prepare DMA descriptor to CESA descriptor from DRAM to SRAM */
++ pDmaDesc->phySrcAdd = MV_32BIT_LE(mvCesaVirtToPhys(&pReq->cesaDescBuf, pCesaDesc));
++ pDmaDesc->phyDestAdd = MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (MV_U8*)pSramDesc));
++ pDmaDesc->byteCnt = MV_32BIT_LE(sizeof(MV_CESA_DESC) | BIT31);
++
++ /* flush Source buffer */
++ mvOsCacheFlush(NULL, pCesaDesc, sizeof(MV_CESA_DESC));
++}
++
++/*******************************************************************************
++* mvCesaSramSaUpdate - Move required SA information to SRAM if needed.
++*
++* DESCRIPTION:
++* Copy to SRAM values of the required SA.
++*
++*
++* INPUT:
++* short sid - Session ID needs SRAM Cache update
++* MV_DMA_DESC *pDmaDesc - Pointer to DMA descriptor used to
++* copy SA values from DRAM to SRAM.
++*
++* RETURN:
++* MV_OK - Cache entry for this SA copied to SRAM.
++* MV_NO_CHANGE - Cache entry for this SA already exist in SRAM
++*
++*******************************************************************************/
++static INLINE void mvCesaSramSaUpdate(short sid, MV_DMA_DESC *pDmaDesc)
++{
++ MV_CESA_SA *pSA = &pCesaSAD[sid];
++
++ /* Prepare DMA descriptor to Copy CACHE_SA from SA database in DRAM to SRAM */
++ pDmaDesc->byteCnt = MV_32BIT_LE(sizeof(MV_CESA_SRAM_SA) | BIT31);
++ pDmaDesc->phySrcAdd = MV_32BIT_LE(mvCesaVirtToPhys(&cesaSramSaBuf, pSA->pSramSA));
++ pDmaDesc->phyDestAdd =
++ MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (MV_U8*)&cesaSramVirtPtr->sramSA));
++
++ /* Source buffer is already flushed during OpenSession*/
++ /*mvOsCacheFlush(NULL, &pSA->sramSA, sizeof(MV_CESA_SRAM_SA));*/
++}
++
++/*******************************************************************************
++* mvCesaDmaCopyPrepare - prepare DMA descriptor list to copy data presented by
++* Mbuf structure from DRAM to SRAM
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_CESA_MBUF* pMbuf - pointer to Mbuf structure contains request
++* data in DRAM
++* MV_U8* pSramBuf - pointer to buffer in SRAM where data should
++* be copied to.
++* MV_DMA_DESC* pDmaDesc - pointer to first DMA descriptor for this copy.
++* The function set number of DMA descriptors needed
++* to copy the copySize bytes from Mbuf.
++* MV_BOOL isToMbuf - Copy direction.
++* MV_TRUE means copy from SRAM buffer to Mbuf in DRAM.
++* MV_FALSE means copy from Mbuf in DRAM to SRAM buffer.
++* int offset - Offset in the Mbuf structure that copy should be
++* started from.
++* int copySize - Size of data should be copied.
++*
++* RETURN:
++* int - number of DMA descriptors used for the copy.
++*
++*******************************************************************************/
++#ifndef MV_NETBSD
++static INLINE int mvCesaDmaCopyPrepare(MV_CESA_MBUF* pMbuf, MV_U8* pSramBuf,
++ MV_DMA_DESC* pDmaDesc, MV_BOOL isToMbuf,
++ int offset, int copySize, MV_BOOL skipFlush)
++{
++ int bufOffset, bufSize, size, frag, i;
++ MV_U8* pBuf;
++
++ i = 0;
++
++ /* Calculate start place for copy: fragment number and offset in the fragment */
++ frag = mvCesaMbufOffset(pMbuf, offset, &bufOffset);
++ bufSize = pMbuf->pFrags[frag].bufSize - bufOffset;
++ pBuf = pMbuf->pFrags[frag].bufVirtPtr + bufOffset;
++
++ /* Size accumulate total copy size */
++ size = 0;
++
++ /* Create DMA lists to copy mBuf from pSrc to SRAM */
++ while(size < copySize)
++ {
++ /* Find copy size for each DMA descriptor */
++ bufSize = MV_MIN(bufSize, (copySize - size));
++ pDmaDesc[i].byteCnt = MV_32BIT_LE(bufSize | BIT31);
++ if(isToMbuf)
++ {
++ pDmaDesc[i].phyDestAdd = MV_32BIT_LE(mvOsIoVirtToPhy(NULL, pBuf));
++ pDmaDesc[i].phySrcAdd =
++ MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (pSramBuf + size)));
++ /* invalidate the buffer */
++ if(skipFlush == MV_FALSE)
++ mvOsCacheInvalidate(NULL, pBuf, bufSize);
++ }
++ else
++ {
++ pDmaDesc[i].phySrcAdd = MV_32BIT_LE(mvOsIoVirtToPhy(NULL, pBuf));
++ pDmaDesc[i].phyDestAdd =
++ MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (pSramBuf + size)));
++ /* flush the buffer */
++ if(skipFlush == MV_FALSE)
++ mvOsCacheFlush(NULL, pBuf, bufSize);
++ }
++
++ /* Count number of used DMA descriptors */
++ i++;
++ size += bufSize;
++
++ /* go to next fragment in the Mbuf */
++ frag++;
++ pBuf = pMbuf->pFrags[frag].bufVirtPtr;
++ bufSize = pMbuf->pFrags[frag].bufSize;
++ }
++ return i;
++}
++#else /* MV_NETBSD */
++static int mvCesaDmaCopyPrepare(MV_CESA_MBUF* pMbuf, MV_U8* pSramBuf,
++ MV_DMA_DESC* pDmaDesc, MV_BOOL isToMbuf,
++ int offset, int copySize, MV_BOOL skipFlush)
++{
++ int bufOffset, bufSize, thisSize, size, frag, i;
++ MV_ULONG bufPhys, sramPhys;
++ MV_U8* pBuf;
++
++ /*
++ * Calculate start place for copy: fragment number and offset in
++ * the fragment
++ */
++ frag = mvCesaMbufOffset(pMbuf, offset, &bufOffset);
++
++ /*
++ * Get SRAM physical address only once. We can update it in-place
++ * as we build the descriptor chain.
++ */
++ sramPhys = mvCesaSramVirtToPhys(NULL, pSramBuf);
++
++ /*
++ * 'size' accumulates total copy size, 'i' counts desccriptors.
++ */
++ size = i = 0;
++
++ /* Create DMA lists to copy mBuf from pSrc to SRAM */
++ while (size < copySize) {
++ /*
++ * Calculate # of bytes to copy from the current fragment,
++ * and the pointer to the start of data
++ */
++ bufSize = pMbuf->pFrags[frag].bufSize - bufOffset;
++ pBuf = pMbuf->pFrags[frag].bufVirtPtr + bufOffset;
++ bufOffset = 0; /* First frag may be non-zero */
++ frag++;
++
++ /*
++ * As long as there is data in the current fragment...
++ */
++ while (bufSize > 0) {
++ /*
++ * Ensure we don't cross an MMU page boundary.
++ * XXX: This is NetBSD-specific, but it is a
++ * quick and dirty way to fix the problem.
++ * A true HAL would rely on the OS-specific
++ * driver to do this...
++ */
++ thisSize = PAGE_SIZE -
++ (((MV_ULONG)pBuf) & (PAGE_SIZE - 1));
++ thisSize = MV_MIN(bufSize, thisSize);
++ /*
++ * Make sure we don't copy more than requested
++ */
++ if (thisSize > (copySize - size)) {
++ thisSize = copySize - size;
++ bufSize = 0;
++ }
++
++ /*
++ * Physicall address of this fragment
++ */
++ bufPhys = MV_32BIT_LE(mvOsIoVirtToPhy(NULL, pBuf));
++
++ /*
++ * Set up the descriptor
++ */
++ pDmaDesc[i].byteCnt = MV_32BIT_LE(thisSize | BIT31);
++ if(isToMbuf) {
++ pDmaDesc[i].phyDestAdd = bufPhys;
++ pDmaDesc[i].phySrcAdd = MV_32BIT_LE(sramPhys);
++ /* invalidate the buffer */
++ if(skipFlush == MV_FALSE)
++ mvOsCacheInvalidate(NULL, pBuf, thisSize);
++ } else {
++ pDmaDesc[i].phySrcAdd = bufPhys;
++ pDmaDesc[i].phyDestAdd = MV_32BIT_LE(sramPhys);
++ /* flush the buffer */
++ if(skipFlush == MV_FALSE)
++ mvOsCacheFlush(NULL, pBuf, thisSize);
++ }
++
++ pDmaDesc[i].phyNextDescPtr =
++ MV_32BIT_LE(mvOsIoVirtToPhy(NULL,(&pDmaDesc[i+1])));
++
++ /* flush the DMA desc */
++ mvOsCacheFlush(NULL, &pDmaDesc[i], sizeof(MV_DMA_DESC));
++
++ /* Update state */
++ bufSize -= thisSize;
++ sramPhys += thisSize;
++ pBuf += thisSize;
++ size += thisSize;
++ i++;
++ }
++ }
++
++ return i;
++}
++#endif /* MV_NETBSD */
++/*******************************************************************************
++* mvCesaHmacIvGet - Calculate Inner and Outter values from HMAC key
++*
++* DESCRIPTION:
++* This function calculate Inner and Outer values used for HMAC algorithm.
++* This operation allows improve performance fro the whole HMAC processing.
++*
++* INPUT:
++* MV_CESA_MAC_MODE macMode - Authentication mode: HMAC_MD5 or HMAC_SHA1.
++* unsigned char key[] - Pointer to HMAC key.
++* int keyLength - Size of HMAC key (maximum 64 bytes)
++*
++* OUTPUT:
++* unsigned char innerIV[] - HASH(key^inner)
++* unsigned char outerIV[] - HASH(key^outter)
++*
++* RETURN: None
++*
++*******************************************************************************/
++static void mvCesaHmacIvGet(MV_CESA_MAC_MODE macMode, unsigned char key[], int keyLength,
++ unsigned char innerIV[], unsigned char outerIV[])
++{
++ unsigned char inner[MV_CESA_MAX_MAC_KEY_LENGTH];
++ unsigned char outer[MV_CESA_MAX_MAC_KEY_LENGTH];
++ int i, digestSize = 0;
++#if defined(MV_CPU_LE) || defined(MV_PPC)
++ MV_U32 swapped32, val32, *pVal32;
++#endif
++ for(i=0; i<keyLength; i++)
++ {
++ inner[i] = 0x36 ^ key[i];
++ outer[i] = 0x5c ^ key[i];
++ }
++
++ for(i=keyLength; i<MV_CESA_MAX_MAC_KEY_LENGTH; i++)
++ {
++ inner[i] = 0x36;
++ outer[i] = 0x5c;
++ }
++ if(macMode == MV_CESA_MAC_HMAC_MD5)
++ {
++ MV_MD5_CONTEXT ctx;
++
++ mvMD5Init(&ctx);
++ mvMD5Update(&ctx, inner, MV_CESA_MAX_MAC_KEY_LENGTH);
++
++ memcpy(innerIV, ctx.buf, MV_CESA_MD5_DIGEST_SIZE);
++ memset(&ctx, 0, sizeof(ctx));
++
++ mvMD5Init(&ctx);
++ mvMD5Update(&ctx, outer, MV_CESA_MAX_MAC_KEY_LENGTH);
++ memcpy(outerIV, ctx.buf, MV_CESA_MD5_DIGEST_SIZE);
++ memset(&ctx, 0, sizeof(ctx));
++ digestSize = MV_CESA_MD5_DIGEST_SIZE;
++ }
++ else if(macMode == MV_CESA_MAC_HMAC_SHA1)
++ {
++ MV_SHA1_CTX ctx;
++
++ mvSHA1Init(&ctx);
++ mvSHA1Update(&ctx, inner, MV_CESA_MAX_MAC_KEY_LENGTH);
++ memcpy(innerIV, ctx.state, MV_CESA_SHA1_DIGEST_SIZE);
++ memset(&ctx, 0, sizeof(ctx));
++
++ mvSHA1Init(&ctx);
++ mvSHA1Update(&ctx, outer, MV_CESA_MAX_MAC_KEY_LENGTH);
++ memcpy(outerIV, ctx.state, MV_CESA_SHA1_DIGEST_SIZE);
++ memset(&ctx, 0, sizeof(ctx));
++ digestSize = MV_CESA_SHA1_DIGEST_SIZE;
++ }
++ else
++ {
++ mvOsPrintf("hmacGetIV: Unexpected macMode %d\n", macMode);
++ }
++#if defined(MV_CPU_LE) || defined(MV_PPC)
++ /* 32 bits Swap of Inner and Outer values */
++ pVal32 = (MV_U32*)innerIV;
++ for(i=0; i<digestSize/4; i++)
++ {
++ val32 = *pVal32;
++ swapped32 = MV_BYTE_SWAP_32BIT(val32);
++ *pVal32 = swapped32;
++ pVal32++;
++ }
++ pVal32 = (MV_U32*)outerIV;
++ for(i=0; i<digestSize/4; i++)
++ {
++ val32 = *pVal32;
++ swapped32 = MV_BYTE_SWAP_32BIT(val32);
++ *pVal32 = swapped32;
++ pVal32++;
++ }
++#endif /* defined(MV_CPU_LE) || defined(MV_PPC) */
++}
++
++
++/*******************************************************************************
++* mvCesaFragSha1Complete - Complete SHA1 authentication started by HW using SW
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_CESA_MBUF* pMbuf - Pointer to Mbuf structure where data
++* for SHA1 is placed.
++* int offset - Offset in the Mbuf structure where
++* unprocessed data for SHA1 is started.
++* MV_U8* pOuterIV - Pointer to OUTER for this session.
++* If pOuterIV==NULL - MAC mode is HASH_SHA1
++* If pOuterIV!=NULL - MAC mode is HMAC_SHA1
++* int macLeftSize - Size of unprocessed data for SHA1.
++* int macTotalSize - Total size of data for SHA1 in the
++* request (processed + unprocessed)
++*
++* OUTPUT:
++* MV_U8* pDigest - Pointer to place where calculated Digest will
++* be stored.
++*
++* RETURN: None
++*
++*******************************************************************************/
++static void mvCesaFragSha1Complete(MV_CESA_MBUF* pMbuf, int offset,
++ MV_U8* pOuterIV, int macLeftSize,
++ int macTotalSize, MV_U8* pDigest)
++{
++ MV_SHA1_CTX ctx;
++ MV_U8 *pData;
++ int i, frag, fragOffset, size;
++
++ /* Read temporary Digest from HW */
++ for(i=0; i<MV_CESA_SHA1_DIGEST_SIZE/4; i++)
++ {
++ ctx.state[i] = MV_REG_READ(MV_CESA_AUTH_INIT_VAL_DIGEST_REG(i));
++ }
++ /* Initialize MV_SHA1_CTX structure */
++ memset(ctx.buffer, 0, 64);
++ /* Set count[0] in bits. 32 bits is enough for 512 MBytes */
++ /* so count[1] is always 0 */
++ ctx.count[0] = ((macTotalSize - macLeftSize) * 8);
++ ctx.count[1] = 0;
++
++ /* If HMAC - add size of Inner block (64 bytes) ro count[0] */
++ if(pOuterIV != NULL)
++ ctx.count[0] += (64 * 8);
++
++ /* Get place of unprocessed data in the Mbuf structure */
++ frag = mvCesaMbufOffset(pMbuf, offset, &fragOffset);
++ if(frag == MV_INVALID)
++ {
++ mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset);
++ return;
++ }
++
++ pData = pMbuf->pFrags[frag].bufVirtPtr + fragOffset;
++ size = pMbuf->pFrags[frag].bufSize - fragOffset;
++
++ /* Complete Inner part */
++ while(macLeftSize > 0)
++ {
++ if(macLeftSize <= size)
++ {
++ mvSHA1Update(&ctx, pData, macLeftSize);
++ break;
++ }
++ mvSHA1Update(&ctx, pData, size);
++ macLeftSize -= size;
++ frag++;
++ pData = pMbuf->pFrags[frag].bufVirtPtr;
++ size = pMbuf->pFrags[frag].bufSize;
++ }
++ mvSHA1Final(pDigest, &ctx);
++/*
++ mvOsPrintf("mvCesaFragSha1Complete: pOuterIV=%p, macLeftSize=%d, macTotalSize=%d\n",
++ pOuterIV, macLeftSize, macTotalSize);
++ mvDebugMemDump(pDigest, MV_CESA_SHA1_DIGEST_SIZE, 1);
++*/
++
++ if(pOuterIV != NULL)
++ {
++ /* If HMAC - Complete Outer part */
++ for(i=0; i<MV_CESA_SHA1_DIGEST_SIZE/4; i++)
++ {
++#if defined(MV_CPU_LE) || defined(MV_ARM)
++ ctx.state[i] = MV_BYTE_SWAP_32BIT(((MV_U32*)pOuterIV)[i]);
++#else
++ ctx.state[i] = ((MV_U32*)pOuterIV)[i];
++#endif
++ }
++ memset(ctx.buffer, 0, 64);
++
++ ctx.count[0] = 64*8;
++ ctx.count[1] = 0;
++ mvSHA1Update(&ctx, pDigest, MV_CESA_SHA1_DIGEST_SIZE);
++ mvSHA1Final(pDigest, &ctx);
++ }
++}
++
++/*******************************************************************************
++* mvCesaFragMd5Complete - Complete MD5 authentication started by HW using SW
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_CESA_MBUF* pMbuf - Pointer to Mbuf structure where data
++* for SHA1 is placed.
++* int offset - Offset in the Mbuf structure where
++* unprocessed data for MD5 is started.
++* MV_U8* pOuterIV - Pointer to OUTER for this session.
++* If pOuterIV==NULL - MAC mode is HASH_MD5
++* If pOuterIV!=NULL - MAC mode is HMAC_MD5
++* int macLeftSize - Size of unprocessed data for MD5.
++* int macTotalSize - Total size of data for MD5 in the
++* request (processed + unprocessed)
++*
++* OUTPUT:
++* MV_U8* pDigest - Pointer to place where calculated Digest will
++* be stored.
++*
++* RETURN: None
++*
++*******************************************************************************/
++static void mvCesaFragMd5Complete(MV_CESA_MBUF* pMbuf, int offset,
++ MV_U8* pOuterIV, int macLeftSize,
++ int macTotalSize, MV_U8* pDigest)
++{
++ MV_MD5_CONTEXT ctx;
++ MV_U8 *pData;
++ int i, frag, fragOffset, size;
++
++ /* Read temporary Digest from HW */
++ for(i=0; i<MV_CESA_MD5_DIGEST_SIZE/4; i++)
++ {
++ ctx.buf[i] = MV_REG_READ(MV_CESA_AUTH_INIT_VAL_DIGEST_REG(i));
++ }
++ memset(ctx.in, 0, 64);
++
++ /* Set count[0] in bits. 32 bits is enough for 512 MBytes */
++ /* so count[1] is always 0 */
++ ctx.bits[0] = ((macTotalSize - macLeftSize) * 8);
++ ctx.bits[1] = 0;
++
++ /* If HMAC - add size of Inner block (64 bytes) ro count[0] */
++ if(pOuterIV != NULL)
++ ctx.bits[0] += (64 * 8);
++
++ frag = mvCesaMbufOffset(pMbuf, offset, &fragOffset);
++ if(frag == MV_INVALID)
++ {
++ mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset);
++ return;
++ }
++
++ pData = pMbuf->pFrags[frag].bufVirtPtr + fragOffset;
++ size = pMbuf->pFrags[frag].bufSize - fragOffset;
++
++ /* Complete Inner part */
++ while(macLeftSize > 0)
++ {
++ if(macLeftSize <= size)
++ {
++ mvMD5Update(&ctx, pData, macLeftSize);
++ break;
++ }
++ mvMD5Update(&ctx, pData, size);
++ macLeftSize -= size;
++ frag++;
++ pData = pMbuf->pFrags[frag].bufVirtPtr;
++ size = pMbuf->pFrags[frag].bufSize;
++ }
++ mvMD5Final(pDigest, &ctx);
++
++/*
++ mvOsPrintf("mvCesaFragMd5Complete: pOuterIV=%p, macLeftSize=%d, macTotalSize=%d\n",
++ pOuterIV, macLeftSize, macTotalSize);
++ mvDebugMemDump(pDigest, MV_CESA_MD5_DIGEST_SIZE, 1);
++*/
++ if(pOuterIV != NULL)
++ {
++ /* Complete Outer part */
++ for(i=0; i<MV_CESA_MD5_DIGEST_SIZE/4; i++)
++ {
++#if defined(MV_CPU_LE) || defined(MV_ARM)
++ ctx.buf[i] = MV_BYTE_SWAP_32BIT(((MV_U32*)pOuterIV)[i]);
++#else
++ ctx.buf[i] = ((MV_U32*)pOuterIV)[i];
++#endif
++ }
++ memset(ctx.in, 0, 64);
++
++ ctx.bits[0] = 64*8;
++ ctx.bits[1] = 0;
++ mvMD5Update(&ctx, pDigest, MV_CESA_MD5_DIGEST_SIZE);
++ mvMD5Final(pDigest, &ctx);
++ }
++}
++
++/*******************************************************************************
++* mvCesaFragAuthComplete -
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_CESA_REQ* pReq,
++* MV_CESA_SA* pSA,
++* int macDataSize
++*
++* RETURN:
++* MV_STATUS
++*
++*******************************************************************************/
++static MV_STATUS mvCesaFragAuthComplete(MV_CESA_REQ* pReq, MV_CESA_SA* pSA,
++ int macDataSize)
++{
++ MV_CESA_COMMAND* pCmd = pReq->pCmd;
++ MV_U8* pDigest;
++ MV_CESA_MAC_MODE macMode;
++ MV_U8* pOuterIV = NULL;
++
++ /* Copy data from Source fragment to Destination */
++ if(pCmd->pSrc != pCmd->pDst)
++ {
++ mvCesaMbufCopy(pCmd->pDst, pReq->frags.bufOffset,
++ pCmd->pSrc, pReq->frags.bufOffset, macDataSize);
++ }
++
++/*
++ mvCesaCopyFromMbuf(cesaSramVirtPtr->buf[0], pCmd->pSrc, pReq->frags.bufOffset, macDataSize);
++ mvCesaCopyToMbuf(cesaSramVirtPtr->buf[0], pCmd->pDst, pReq->frags.bufOffset, macDataSize);
++*/
++ pDigest = (mvCesaSramAddrGet() + pReq->frags.newDigestOffset);
++
++ macMode = (pSA->config & MV_CESA_MAC_MODE_MASK) >> MV_CESA_MAC_MODE_OFFSET;
++/*
++ mvOsPrintf("macDataSize=%d, macLength=%d, digestOffset=%d, macMode=%d\n",
++ macDataSize, pCmd->macLength, pCmd->digestOffset, macMode);
++*/
++ switch(macMode)
++ {
++ case MV_CESA_MAC_HMAC_MD5:
++ pOuterIV = pSA->pSramSA->macOuterIV;
++
++ case MV_CESA_MAC_MD5:
++ mvCesaFragMd5Complete(pCmd->pDst, pReq->frags.bufOffset, pOuterIV,
++ macDataSize, pCmd->macLength, pDigest);
++ break;
++
++ case MV_CESA_MAC_HMAC_SHA1:
++ pOuterIV = pSA->pSramSA->macOuterIV;
++
++ case MV_CESA_MAC_SHA1:
++ mvCesaFragSha1Complete(pCmd->pDst, pReq->frags.bufOffset, pOuterIV,
++ macDataSize, pCmd->macLength, pDigest);
++ break;
++
++ default:
++ mvOsPrintf("mvCesaFragAuthComplete: Unexpected macMode %d\n", macMode);
++ return MV_BAD_PARAM;
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCesaCtrModeInit -
++*
++* DESCRIPTION:
++*
++*
++* INPUT: NONE
++*
++*
++* RETURN:
++* MV_CESA_COMMAND*
++*
++*******************************************************************************/
++static MV_CESA_COMMAND* mvCesaCtrModeInit(void)
++{
++ MV_CESA_MBUF *pMbuf;
++ MV_U8 *pBuf;
++ MV_CESA_COMMAND *pCmd;
++
++ pBuf = mvOsMalloc(sizeof(MV_CESA_COMMAND) +
++ sizeof(MV_CESA_MBUF) + sizeof(MV_BUF_INFO) + 100);
++ if(pBuf == NULL)
++ {
++ mvOsPrintf("mvCesaSessionOpen: Can't allocate %u bytes for CTR Mode\n",
++ sizeof(MV_CESA_COMMAND) + sizeof(MV_CESA_MBUF) + sizeof(MV_BUF_INFO) );
++ return NULL;
++ }
++ pCmd = (MV_CESA_COMMAND*)pBuf;
++ pBuf += sizeof(MV_CESA_COMMAND);
++
++ pMbuf = (MV_CESA_MBUF*)pBuf;
++ pBuf += sizeof(MV_CESA_MBUF);
++
++ pMbuf->pFrags = (MV_BUF_INFO*)pBuf;
++
++ pMbuf->numFrags = 1;
++ pCmd->pSrc = pMbuf;
++ pCmd->pDst = pMbuf;
++/*
++ mvOsPrintf("CtrModeInit: pCmd=%p, pSrc=%p, pDst=%p, pFrags=%p\n",
++ pCmd, pCmd->pSrc, pCmd->pDst,
++ pMbuf->pFrags);
++*/
++ return pCmd;
++}
++
++/*******************************************************************************
++* mvCesaCtrModePrepare -
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_CESA_COMMAND *pCtrModeCmd, MV_CESA_COMMAND *pCmd
++*
++* RETURN:
++* MV_STATUS
++*
++*******************************************************************************/
++static MV_STATUS mvCesaCtrModePrepare(MV_CESA_COMMAND *pCtrModeCmd, MV_CESA_COMMAND *pCmd)
++{
++ MV_CESA_MBUF *pMbuf;
++ MV_U8 *pBuf, *pIV;
++ MV_U32 counter, *pCounter;
++ int cryptoSize = MV_ALIGN_UP(pCmd->cryptoLength, MV_CESA_AES_BLOCK_SIZE);
++/*
++ mvOsPrintf("CtrModePrepare: pCmd=%p, pCtrSrc=%p, pCtrDst=%p, pOrgCmd=%p, pOrgSrc=%p, pOrgDst=%p\n",
++ pCmd, pCmd->pSrc, pCmd->pDst,
++ pCtrModeCmd, pCtrModeCmd->pSrc, pCtrModeCmd->pDst);
++*/
++ pMbuf = pCtrModeCmd->pSrc;
++
++ /* Allocate buffer for Key stream */
++ pBuf = mvOsIoCachedMalloc(cesaOsHandle,cryptoSize,
++ &pMbuf->pFrags[0].bufPhysAddr,
++ &pMbuf->pFrags[0].memHandle);
++ if(pBuf == NULL)
++ {
++ mvOsPrintf("mvCesaCtrModePrepare: Can't allocate %d bytes\n", cryptoSize);
++ return MV_OUT_OF_CPU_MEM;
++ }
++ memset(pBuf, 0, cryptoSize);
++ mvOsCacheFlush(NULL, pBuf, cryptoSize);
++
++ pMbuf->pFrags[0].bufVirtPtr = pBuf;
++ pMbuf->mbufSize = cryptoSize;
++ pMbuf->pFrags[0].bufSize = cryptoSize;
++
++ pCtrModeCmd->pReqPrv = pCmd->pReqPrv;
++ pCtrModeCmd->sessionId = pCmd->sessionId;
++
++ /* ivFromUser and ivOffset are don't care */
++ pCtrModeCmd->cryptoOffset = 0;
++ pCtrModeCmd->cryptoLength = cryptoSize;
++
++ /* digestOffset, macOffset and macLength are don't care */
++
++ mvCesaCopyFromMbuf(pBuf, pCmd->pSrc, pCmd->ivOffset, MV_CESA_AES_BLOCK_SIZE);
++ pCounter = (MV_U32*)(pBuf + (MV_CESA_AES_BLOCK_SIZE - sizeof(counter)));
++ counter = *pCounter;
++ counter = MV_32BIT_BE(counter);
++ pIV = pBuf;
++ cryptoSize -= MV_CESA_AES_BLOCK_SIZE;
++
++ /* fill key stream */
++ while(cryptoSize > 0)
++ {
++ pBuf += MV_CESA_AES_BLOCK_SIZE;
++ memcpy(pBuf, pIV, MV_CESA_AES_BLOCK_SIZE - sizeof(counter));
++ pCounter = (MV_U32*)(pBuf + (MV_CESA_AES_BLOCK_SIZE - sizeof(counter)));
++ counter++;
++ *pCounter = MV_32BIT_BE(counter);
++ cryptoSize -= MV_CESA_AES_BLOCK_SIZE;
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCesaCtrModeComplete -
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_CESA_COMMAND *pOrgCmd, MV_CESA_COMMAND *pCmd
++*
++* RETURN:
++* MV_STATUS
++*
++*******************************************************************************/
++static MV_STATUS mvCesaCtrModeComplete(MV_CESA_COMMAND *pOrgCmd, MV_CESA_COMMAND *pCmd)
++{
++ int srcFrag, dstFrag, srcOffset, dstOffset, keyOffset, srcSize, dstSize;
++ int cryptoSize = pCmd->cryptoLength;
++ MV_U8 *pSrc, *pDst, *pKey;
++ MV_STATUS status = MV_OK;
++/*
++ mvOsPrintf("CtrModeComplete: pCmd=%p, pCtrSrc=%p, pCtrDst=%p, pOrgCmd=%p, pOrgSrc=%p, pOrgDst=%p\n",
++ pCmd, pCmd->pSrc, pCmd->pDst,
++ pOrgCmd, pOrgCmd->pSrc, pOrgCmd->pDst);
++*/
++ /* XOR source data with key stream to destination data */
++ pKey = pCmd->pDst->pFrags[0].bufVirtPtr;
++ keyOffset = 0;
++
++ if( (pOrgCmd->pSrc != pOrgCmd->pDst) &&
++ (pOrgCmd->cryptoOffset > 0) )
++ {
++ /* Copy Prefix from source buffer to destination buffer */
++
++ status = mvCesaMbufCopy(pOrgCmd->pDst, 0,
++ pOrgCmd->pSrc, 0, pOrgCmd->cryptoOffset);
++/*
++ status = mvCesaCopyFromMbuf(tempBuf, pOrgCmd->pSrc,
++ 0, pOrgCmd->cryptoOffset);
++ status = mvCesaCopyToMbuf(tempBuf, pOrgCmd->pDst,
++ 0, pOrgCmd->cryptoOffset);
++*/
++ }
++
++ srcFrag = mvCesaMbufOffset(pOrgCmd->pSrc, pOrgCmd->cryptoOffset, &srcOffset);
++ pSrc = pOrgCmd->pSrc->pFrags[srcFrag].bufVirtPtr;
++ srcSize = pOrgCmd->pSrc->pFrags[srcFrag].bufSize;
++
++ dstFrag = mvCesaMbufOffset(pOrgCmd->pDst, pOrgCmd->cryptoOffset, &dstOffset);
++ pDst = pOrgCmd->pDst->pFrags[dstFrag].bufVirtPtr;
++ dstSize = pOrgCmd->pDst->pFrags[dstFrag].bufSize;
++
++ while(cryptoSize > 0)
++ {
++ pDst[dstOffset] = (pSrc[srcOffset] ^ pKey[keyOffset]);
++
++ cryptoSize--;
++ dstOffset++;
++ srcOffset++;
++ keyOffset++;
++
++ if(srcOffset >= srcSize)
++ {
++ srcFrag++;
++ srcOffset = 0;
++ pSrc = pOrgCmd->pSrc->pFrags[srcFrag].bufVirtPtr;
++ srcSize = pOrgCmd->pSrc->pFrags[srcFrag].bufSize;
++ }
++
++ if(dstOffset >= dstSize)
++ {
++ dstFrag++;
++ dstOffset = 0;
++ pDst = pOrgCmd->pDst->pFrags[dstFrag].bufVirtPtr;
++ dstSize = pOrgCmd->pDst->pFrags[dstFrag].bufSize;
++ }
++ }
++
++ if(pOrgCmd->pSrc != pOrgCmd->pDst)
++ {
++ /* Copy Suffix from source buffer to destination buffer */
++ srcOffset = pOrgCmd->cryptoOffset + pOrgCmd->cryptoLength;
++
++ if( (pOrgCmd->pDst->mbufSize - srcOffset) > 0)
++ {
++ status = mvCesaMbufCopy(pOrgCmd->pDst, srcOffset,
++ pOrgCmd->pSrc, srcOffset,
++ pOrgCmd->pDst->mbufSize - srcOffset);
++ }
++
++/*
++ status = mvCesaCopyFromMbuf(tempBuf, pOrgCmd->pSrc,
++ srcOffset, pOrgCmd->pSrc->mbufSize - srcOffset);
++ status = mvCesaCopyToMbuf(tempBuf, pOrgCmd->pDst,
++ srcOffset, pOrgCmd->pDst->mbufSize - srcOffset);
++*/
++ }
++
++ /* Free buffer used for Key stream */
++ mvOsIoCachedFree(cesaOsHandle,pCmd->pDst->pFrags[0].bufSize,
++ pCmd->pDst->pFrags[0].bufPhysAddr,
++ pCmd->pDst->pFrags[0].bufVirtPtr,
++ pCmd->pDst->pFrags[0].memHandle);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCesaCtrModeFinish -
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_CESA_COMMAND* pCmd
++*
++* RETURN:
++* MV_STATUS
++*
++*******************************************************************************/
++static void mvCesaCtrModeFinish(MV_CESA_COMMAND* pCmd)
++{
++ mvOsFree(pCmd);
++}
++
++/*******************************************************************************
++* mvCesaParamCheck -
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd, MV_U8* pFixOffset
++*
++* RETURN:
++* MV_STATUS
++*
++*******************************************************************************/
++static MV_STATUS mvCesaParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd,
++ MV_U8* pFixOffset)
++{
++ MV_U8 fixOffset = 0xFF;
++
++ /* Check AUTH operation parameters */
++ if( ((pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET)) )
++ {
++ /* MAC offset should be at least 4 byte aligned */
++ if( MV_IS_NOT_ALIGN(pCmd->macOffset, 4) )
++ {
++ mvOsPrintf("mvCesaAction: macOffset %d must be 4 byte aligned\n",
++ pCmd->macOffset);
++ return MV_BAD_PARAM;
++ }
++ /* Digest offset must be 4 byte aligned */
++ if( MV_IS_NOT_ALIGN(pCmd->digestOffset, 4) )
++ {
++ mvOsPrintf("mvCesaAction: digestOffset %d must be 4 byte aligned\n",
++ pCmd->digestOffset);
++ return MV_BAD_PARAM;
++ }
++ /* In addition all offsets should be the same alignment: 8 or 4 */
++ if(fixOffset == 0xFF)
++ {
++ fixOffset = (pCmd->macOffset % 8);
++ }
++ else
++ {
++ if( (pCmd->macOffset % 8) != fixOffset)
++ {
++ mvOsPrintf("mvCesaAction: macOffset %d mod 8 must be equal %d\n",
++ pCmd->macOffset, fixOffset);
++ return MV_BAD_PARAM;
++ }
++ }
++ if( (pCmd->digestOffset % 8) != fixOffset)
++ {
++ mvOsPrintf("mvCesaAction: digestOffset %d mod 8 must be equal %d\n",
++ pCmd->digestOffset, fixOffset);
++ return MV_BAD_PARAM;
++ }
++ }
++ /* Check CRYPTO operation parameters */
++ if( ((pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET)) )
++ {
++ /* CryptoOffset should be at least 4 byte aligned */
++ if( MV_IS_NOT_ALIGN(pCmd->cryptoOffset, 4) )
++ {
++ mvOsPrintf("CesaAction: cryptoOffset=%d must be 4 byte aligned\n",
++ pCmd->cryptoOffset);
++ return MV_BAD_PARAM;
++ }
++ /* cryptoLength should be the whole number of blocks */
++ if( MV_IS_NOT_ALIGN(pCmd->cryptoLength, pSA->cryptoBlockSize) )
++ {
++ mvOsPrintf("mvCesaAction: cryptoLength=%d must be %d byte aligned\n",
++ pCmd->cryptoLength, pSA->cryptoBlockSize);
++ return MV_BAD_PARAM;
++ }
++ if(fixOffset == 0xFF)
++ {
++ fixOffset = (pCmd->cryptoOffset % 8);
++ }
++ else
++ {
++ /* In addition all offsets should be the same alignment: 8 or 4 */
++ if( (pCmd->cryptoOffset % 8) != fixOffset)
++ {
++ mvOsPrintf("mvCesaAction: cryptoOffset %d mod 8 must be equal %d \n",
++ pCmd->cryptoOffset, fixOffset);
++ return MV_BAD_PARAM;
++ }
++ }
++
++ /* check for CBC mode */
++ if(pSA->cryptoIvSize > 0)
++ {
++ /* cryptoIV must not be part of CryptoLength */
++ if( ((pCmd->ivOffset + pSA->cryptoIvSize) > pCmd->cryptoOffset) &&
++ (pCmd->ivOffset < (pCmd->cryptoOffset + pCmd->cryptoLength)) )
++ {
++ mvOsPrintf("mvCesaFragParamCheck: cryptoIvOffset (%d) is part of cryptoLength (%d+%d)\n",
++ pCmd->ivOffset, pCmd->macOffset, pCmd->macLength);
++ return MV_BAD_PARAM;
++ }
++
++ /* ivOffset must be 4 byte aligned */
++ if( MV_IS_NOT_ALIGN(pCmd->ivOffset, 4) )
++ {
++ mvOsPrintf("CesaAction: ivOffset=%d must be 4 byte aligned\n",
++ pCmd->ivOffset);
++ return MV_BAD_PARAM;
++ }
++ /* In addition all offsets should be the same alignment: 8 or 4 */
++ if( (pCmd->ivOffset % 8) != fixOffset)
++ {
++ mvOsPrintf("mvCesaAction: ivOffset %d mod 8 must be %d\n",
++ pCmd->ivOffset, fixOffset);
++ return MV_BAD_PARAM;
++ }
++ }
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCesaFragParamCheck -
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd
++*
++* RETURN:
++* MV_STATUS
++*
++*******************************************************************************/
++static MV_STATUS mvCesaFragParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd)
++{
++ int offset;
++
++ if( ((pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET)) )
++ {
++ /* macOffset must be less that SRAM buffer size */
++ if(pCmd->macOffset > (sizeof(cesaSramVirtPtr->buf) - MV_CESA_AUTH_BLOCK_SIZE))
++ {
++ mvOsPrintf("mvCesaFragParamCheck: macOffset is too large (%d)\n",
++ pCmd->macOffset);
++ return MV_BAD_PARAM;
++ }
++ /* macOffset+macSize must be more than mbufSize - SRAM buffer size */
++ if( ((pCmd->macOffset + pCmd->macLength) > pCmd->pSrc->mbufSize) ||
++ ((pCmd->pSrc->mbufSize - (pCmd->macOffset + pCmd->macLength)) >=
++ sizeof(cesaSramVirtPtr->buf)) )
++ {
++ mvOsPrintf("mvCesaFragParamCheck: macLength is too large (%d), mbufSize=%d\n",
++ pCmd->macLength, pCmd->pSrc->mbufSize);
++ return MV_BAD_PARAM;
++ }
++ }
++
++ if( ((pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET)) )
++ {
++ /* cryptoOffset must be less that SRAM buffer size */
++ /* 4 for possible fixOffset */
++ if( (pCmd->cryptoOffset + 4) > (sizeof(cesaSramVirtPtr->buf) - pSA->cryptoBlockSize))
++ {
++ mvOsPrintf("mvCesaFragParamCheck: cryptoOffset is too large (%d)\n",
++ pCmd->cryptoOffset);
++ return MV_BAD_PARAM;
++ }
++
++ /* cryptoOffset+cryptoSize must be more than mbufSize - SRAM buffer size */
++ if( ((pCmd->cryptoOffset + pCmd->cryptoLength) > pCmd->pSrc->mbufSize) ||
++ ((pCmd->pSrc->mbufSize - (pCmd->cryptoOffset + pCmd->cryptoLength)) >=
++ (sizeof(cesaSramVirtPtr->buf) - pSA->cryptoBlockSize)) )
++ {
++ mvOsPrintf("mvCesaFragParamCheck: cryptoLength is too large (%d), mbufSize=%d\n",
++ pCmd->cryptoLength, pCmd->pSrc->mbufSize);
++ return MV_BAD_PARAM;
++ }
++ }
++
++ /* When MAC_THEN_CRYPTO or CRYPTO_THEN_MAC */
++ if( ((pSA->config & MV_CESA_OPERATION_MASK) ==
++ (MV_CESA_MAC_THEN_CRYPTO << MV_CESA_OPERATION_OFFSET)) ||
++ ((pSA->config & MV_CESA_OPERATION_MASK) ==
++ (MV_CESA_CRYPTO_THEN_MAC << MV_CESA_OPERATION_OFFSET)) )
++ {
++ if( (mvCtrlModelGet() == MV_5182_DEV_ID) ||
++ ( (mvCtrlModelGet() == MV_5181_DEV_ID) &&
++ (mvCtrlRevGet() >= MV_5181L_A0_REV) &&
++ (pCmd->macLength >= (1 << 14)) ) )
++ {
++ return MV_NOT_ALLOWED;
++ }
++
++ /* abs(cryptoOffset-macOffset) must be aligned cryptoBlockSize */
++ if(pCmd->cryptoOffset > pCmd->macOffset)
++ {
++ offset = pCmd->cryptoOffset - pCmd->macOffset;
++ }
++ else
++ {
++ offset = pCmd->macOffset - pCmd->cryptoOffset;
++ }
++
++ if( MV_IS_NOT_ALIGN(offset, pSA->cryptoBlockSize) )
++ {
++/*
++ mvOsPrintf("mvCesaFragParamCheck: (cryptoOffset - macOffset) must be %d byte aligned\n",
++ pSA->cryptoBlockSize);
++*/
++ return MV_NOT_ALLOWED;
++ }
++ /* Digest must not be part of CryptoLength */
++ if( ((pCmd->digestOffset + pSA->digestSize) > pCmd->cryptoOffset) &&
++ (pCmd->digestOffset < (pCmd->cryptoOffset + pCmd->cryptoLength)) )
++ {
++/*
++ mvOsPrintf("mvCesaFragParamCheck: digestOffset (%d) is part of cryptoLength (%d+%d)\n",
++ pCmd->digestOffset, pCmd->cryptoOffset, pCmd->cryptoLength);
++*/
++ return MV_NOT_ALLOWED;
++ }
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCesaFragSizeFind -
++*
++* DESCRIPTION:
++*
++*
++* INPUT:
++* MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd,
++* int cryptoOffset, int macOffset,
++*
++* OUTPUT:
++* int* pCopySize, int* pCryptoDataSize, int* pMacDataSize
++*
++* RETURN:
++* MV_STATUS
++*
++*******************************************************************************/
++static void mvCesaFragSizeFind(MV_CESA_SA* pSA, MV_CESA_REQ* pReq,
++ int cryptoOffset, int macOffset,
++ int* pCopySize, int* pCryptoDataSize, int* pMacDataSize)
++{
++ MV_CESA_COMMAND *pCmd = pReq->pCmd;
++ int cryptoDataSize, macDataSize, copySize;
++
++ cryptoDataSize = macDataSize = 0;
++ copySize = *pCopySize;
++
++ if( (pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET) )
++ {
++ cryptoDataSize = MV_MIN( (copySize - cryptoOffset),
++ (pCmd->cryptoLength - (pReq->frags.cryptoSize + 1)) );
++
++ /* cryptoSize for each fragment must be the whole number of blocksSize */
++ if( MV_IS_NOT_ALIGN(cryptoDataSize, pSA->cryptoBlockSize) )
++ {
++ cryptoDataSize = MV_ALIGN_DOWN(cryptoDataSize, pSA->cryptoBlockSize);
++ copySize = cryptoOffset + cryptoDataSize;
++ }
++ }
++ if( (pSA->config & MV_CESA_OPERATION_MASK) !=
++ (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) )
++ {
++ macDataSize = MV_MIN( (copySize - macOffset),
++ (pCmd->macLength - (pReq->frags.macSize + 1)));
++
++ /* macSize for each fragment (except last) must be the whole number of blocksSize */
++ if( MV_IS_NOT_ALIGN(macDataSize, MV_CESA_AUTH_BLOCK_SIZE) )
++ {
++ macDataSize = MV_ALIGN_DOWN(macDataSize, MV_CESA_AUTH_BLOCK_SIZE);
++ copySize = macOffset + macDataSize;
++ }
++ cryptoDataSize = copySize - cryptoOffset;
++ }
++ *pCopySize = copySize;
++
++ if(pCryptoDataSize != NULL)
++ *pCryptoDataSize = cryptoDataSize;
++
++ if(pMacDataSize != NULL)
++ *pMacDataSize = macDataSize;
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvCesaDebug.c linux-2.6.36/crypto/ocf/kirkwood/cesa/mvCesaDebug.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvCesaDebug.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/mvCesaDebug.c 2010-11-09 20:28:05.342495385 +0100
+@@ -0,0 +1,484 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvOs.h"
++#include "mvDebug.h"
++
++#include "cesa/mvMD5.h"
++#include "cesa/mvSHA1.h"
++
++#include "cesa/mvCesa.h"
++#include "cesa/mvCesaRegs.h"
++#include "cesa/AES/mvAes.h"
++
++static const char* mvCesaDebugStateStr(MV_CESA_STATE state)
++{
++ switch(state)
++ {
++ case MV_CESA_IDLE:
++ return "Idle";
++
++ case MV_CESA_PENDING:
++ return "Pend";
++
++ case MV_CESA_PROCESS:
++ return "Proc";
++
++ case MV_CESA_READY:
++ return "Ready";
++
++ default:
++ break;
++ }
++ return "Unknown";
++}
++
++static const char* mvCesaDebugOperStr(MV_CESA_OPERATION oper)
++{
++ switch(oper)
++ {
++ case MV_CESA_MAC_ONLY:
++ return "MacOnly";
++
++ case MV_CESA_CRYPTO_ONLY:
++ return "CryptoOnly";
++
++ case MV_CESA_MAC_THEN_CRYPTO:
++ return "MacCrypto";
++
++ case MV_CESA_CRYPTO_THEN_MAC:
++ return "CryptoMac";
++
++ default:
++ break;
++ }
++ return "Null";
++}
++
++static const char* mvCesaDebugCryptoAlgStr(MV_CESA_CRYPTO_ALG cryptoAlg)
++{
++ switch(cryptoAlg)
++ {
++ case MV_CESA_CRYPTO_DES:
++ return "DES";
++
++ case MV_CESA_CRYPTO_3DES:
++ return "3DES";
++
++ case MV_CESA_CRYPTO_AES:
++ return "AES";
++
++ default:
++ break;
++ }
++ return "Null";
++}
++
++static const char* mvCesaDebugMacModeStr(MV_CESA_MAC_MODE macMode)
++{
++ switch(macMode)
++ {
++ case MV_CESA_MAC_MD5:
++ return "MD5";
++
++ case MV_CESA_MAC_SHA1:
++ return "SHA1";
++
++ case MV_CESA_MAC_HMAC_MD5:
++ return "HMAC-MD5";
++
++ case MV_CESA_MAC_HMAC_SHA1:
++ return "HMAC_SHA1";
++
++ default:
++ break;
++ }
++ return "Null";
++}
++
++void mvCesaDebugCmd(MV_CESA_COMMAND* pCmd, int mode)
++{
++ mvOsPrintf("pCmd=%p, pReqPrv=%p, pSrc=%p, pDst=%p, pCB=%p, sid=%d\n",
++ pCmd, pCmd->pReqPrv, pCmd->pSrc, pCmd->pDst,
++ pCmd->pFuncCB, pCmd->sessionId);
++ mvOsPrintf("isUser=%d, ivOffs=%d, crOffs=%d, crLen=%d, digest=%d, macOffs=%d, macLen=%d\n",
++ pCmd->ivFromUser, pCmd->ivOffset, pCmd->cryptoOffset, pCmd->cryptoLength,
++ pCmd->digestOffset, pCmd->macOffset, pCmd->macLength);
++}
++
++/* no need to use in tool */
++void mvCesaDebugMbuf(const char* str, MV_CESA_MBUF *pMbuf, int offset, int size)
++{
++ int frag, len, fragOffset;
++
++ if(str != NULL)
++ mvOsPrintf("%s: pMbuf=%p, numFrags=%d, mbufSize=%d\n",
++ str, pMbuf, pMbuf->numFrags, pMbuf->mbufSize);
++
++ frag = mvCesaMbufOffset(pMbuf, offset, &fragOffset);
++ if(frag == MV_INVALID)
++ {
++ mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset);
++ return;
++ }
++
++ for(; frag<pMbuf->numFrags; frag++)
++ {
++ mvOsPrintf("#%2d. bufVirt=%p, bufSize=%d\n",
++ frag, pMbuf->pFrags[frag].bufVirtPtr,
++ pMbuf->pFrags[frag].bufSize);
++ if(size > 0)
++ {
++ len = MV_MIN(pMbuf->pFrags[frag].bufSize, size);
++ mvDebugMemDump(pMbuf->pFrags[frag].bufVirtPtr+fragOffset, len, 1);
++ size -= len;
++ fragOffset = 0;
++ }
++ }
++}
++
++void mvCesaDebugRegs(void)
++{
++ mvOsPrintf("\t CESA Registers:\n");
++
++ mvOsPrintf("MV_CESA_CMD_REG : 0x%X = 0x%08x\n",
++ MV_CESA_CMD_REG,
++ MV_REG_READ( MV_CESA_CMD_REG ) );
++
++ mvOsPrintf("MV_CESA_CHAN_DESC_OFFSET_REG : 0x%X = 0x%08x\n",
++ MV_CESA_CHAN_DESC_OFFSET_REG,
++ MV_REG_READ(MV_CESA_CHAN_DESC_OFFSET_REG) );
++
++ mvOsPrintf("MV_CESA_CFG_REG : 0x%X = 0x%08x\n",
++ MV_CESA_CFG_REG,
++ MV_REG_READ( MV_CESA_CFG_REG ) );
++
++ mvOsPrintf("MV_CESA_STATUS_REG : 0x%X = 0x%08x\n",
++ MV_CESA_STATUS_REG,
++ MV_REG_READ( MV_CESA_STATUS_REG ) );
++
++ mvOsPrintf("MV_CESA_ISR_CAUSE_REG : 0x%X = 0x%08x\n",
++ MV_CESA_ISR_CAUSE_REG,
++ MV_REG_READ( MV_CESA_ISR_CAUSE_REG ) );
++
++ mvOsPrintf("MV_CESA_ISR_MASK_REG : 0x%X = 0x%08x\n",
++ MV_CESA_ISR_MASK_REG,
++ MV_REG_READ( MV_CESA_ISR_MASK_REG ) );
++#if (MV_CESA_VERSION >= 2)
++ mvOsPrintf("MV_CESA_TDMA_CTRL_REG : 0x%X = 0x%08x\n",
++ MV_CESA_TDMA_CTRL_REG,
++ MV_REG_READ( MV_CESA_TDMA_CTRL_REG ) );
++
++ mvOsPrintf("MV_CESA_TDMA_BYTE_COUNT_REG : 0x%X = 0x%08x\n",
++ MV_CESA_TDMA_BYTE_COUNT_REG,
++ MV_REG_READ( MV_CESA_TDMA_BYTE_COUNT_REG ) );
++
++ mvOsPrintf("MV_CESA_TDMA_SRC_ADDR_REG : 0x%X = 0x%08x\n",
++ MV_CESA_TDMA_SRC_ADDR_REG,
++ MV_REG_READ( MV_CESA_TDMA_SRC_ADDR_REG ) );
++
++ mvOsPrintf("MV_CESA_TDMA_DST_ADDR_REG : 0x%X = 0x%08x\n",
++ MV_CESA_TDMA_DST_ADDR_REG,
++ MV_REG_READ( MV_CESA_TDMA_DST_ADDR_REG ) );
++
++ mvOsPrintf("MV_CESA_TDMA_NEXT_DESC_PTR_REG : 0x%X = 0x%08x\n",
++ MV_CESA_TDMA_NEXT_DESC_PTR_REG,
++ MV_REG_READ( MV_CESA_TDMA_NEXT_DESC_PTR_REG ) );
++
++ mvOsPrintf("MV_CESA_TDMA_CURR_DESC_PTR_REG : 0x%X = 0x%08x\n",
++ MV_CESA_TDMA_CURR_DESC_PTR_REG,
++ MV_REG_READ( MV_CESA_TDMA_CURR_DESC_PTR_REG ) );
++
++ mvOsPrintf("MV_CESA_TDMA_ERROR_CAUSE_REG : 0x%X = 0x%08x\n",
++ MV_CESA_TDMA_ERROR_CAUSE_REG,
++ MV_REG_READ( MV_CESA_TDMA_ERROR_CAUSE_REG ) );
++
++ mvOsPrintf("MV_CESA_TDMA_ERROR_MASK_REG : 0x%X = 0x%08x\n",
++ MV_CESA_TDMA_ERROR_MASK_REG,
++ MV_REG_READ( MV_CESA_TDMA_ERROR_CAUSE_REG ) );
++
++#endif
++}
++
++void mvCesaDebugStatus(void)
++{
++ mvOsPrintf("\n\t CESA Status\n\n");
++
++ mvOsPrintf("pReqQ=%p, qDepth=%d, reqSize=%ld bytes, qRes=%d, ",
++ pCesaReqFirst, cesaQueueDepth, sizeof(MV_CESA_REQ),
++ cesaReqResources);
++#if (MV_CESA_VERSION >= 3)
++ mvOsPrintf("chainLength=%u\n",cesaChainLength);
++#else
++ mvOsPrintf("\n");
++#endif
++
++ mvOsPrintf("pSAD=%p, maxSA=%d, sizeSA=%ld bytes\n",
++ pCesaSAD, cesaMaxSA, sizeof(MV_CESA_SA));
++
++ mvOsPrintf("\n");
++
++ mvCesaDebugRegs();
++ mvCesaDebugStats();
++ mvCesaDebugStatsClear();
++}
++
++void mvCesaDebugDescriptor(MV_CESA_DESC* pDesc)
++{
++ mvOsPrintf("config=0x%08x, crSrcOffs=0x%04x, crDstOffs=0x%04x\n",
++ pDesc->config, pDesc->cryptoSrcOffset, pDesc->cryptoDstOffset);
++
++ mvOsPrintf("crLen=0x%04x, crKeyOffs=0x%04x, ivOffs=0x%04x, ivBufOffs=0x%04x\n",
++ pDesc->cryptoDataLen, pDesc->cryptoKeyOffset,
++ pDesc->cryptoIvOffset, pDesc->cryptoIvBufOffset);
++
++ mvOsPrintf("macSrc=0x%04x, digest=0x%04x, macLen=0x%04x, inIv=0x%04x, outIv=0x%04x\n",
++ pDesc->macSrcOffset, pDesc->macDigestOffset, pDesc->macDataLen,
++ pDesc->macInnerIvOffset, pDesc->macOuterIvOffset);
++}
++
++void mvCesaDebugQueue(int mode)
++{
++ mvOsPrintf("\n\t CESA Request Queue:\n\n");
++
++ mvOsPrintf("pFirstReq=%p, pLastReq=%p, qDepth=%d, reqSize=%ld bytes\n",
++ pCesaReqFirst, pCesaReqLast, cesaQueueDepth, sizeof(MV_CESA_REQ));
++
++ mvOsPrintf("pEmpty=%p, pProcess=%p, qResources=%d\n",
++ pCesaReqEmpty, pCesaReqProcess,
++ cesaReqResources);
++
++ if(mode != 0)
++ {
++ int count = 0;
++ MV_CESA_REQ* pReq = pCesaReqFirst;
++
++ for(count=0; count<cesaQueueDepth; count++)
++ {
++ /* Print out requsts */
++ mvOsPrintf("%02d. pReq=%p, state=%s, frag=0x%x, pCmd=%p, pDma=%p, pDesc=%p\n",
++ count, pReq, mvCesaDebugStateStr(pReq->state),
++ pReq->fragMode, pReq->pCmd, pReq->dma[0].pDmaFirst, &pReq->pCesaDesc[0]);
++ if(pReq->fragMode != MV_CESA_FRAG_NONE)
++ {
++ int frag;
++
++ mvOsPrintf("pFrags=%p, num=%d, next=%d, bufOffset=%d, cryptoSize=%d, macSize=%d\n",
++ &pReq->frags, pReq->frags.numFrag, pReq->frags.nextFrag,
++ pReq->frags.bufOffset, pReq->frags.cryptoSize, pReq->frags.macSize);
++ for(frag=0; frag<pReq->frags.numFrag; frag++)
++ {
++ mvOsPrintf("#%d: pDmaFirst=%p, pDesc=%p\n", frag,
++ pReq->dma[frag].pDmaFirst, &pReq->pCesaDesc[frag]);
++ }
++ }
++ if(mode > 1)
++ {
++ /* Print out Command */
++ mvCesaDebugCmd(pReq->pCmd, mode);
++
++ /* Print out Descriptor */
++ mvCesaDebugDescriptor(&pReq->pCesaDesc[0]);
++ }
++ pReq++;
++ }
++ }
++}
++
++
++void mvCesaDebugSramSA(MV_CESA_SRAM_SA* pSramSA, int mode)
++{
++ if(pSramSA == NULL)
++ {
++ mvOsPrintf("cesaSramSA: Unexpected pSramSA=%p\n", pSramSA);
++ return;
++ }
++ mvOsPrintf("pSramSA=%p, sizeSramSA=%ld bytes\n",
++ pSramSA, sizeof(MV_CESA_SRAM_SA));
++
++ if(mode != 0)
++ {
++ mvOsPrintf("cryptoKey=%p, maxCryptoKey=%d bytes\n",
++ pSramSA->cryptoKey, MV_CESA_MAX_CRYPTO_KEY_LENGTH);
++ mvDebugMemDump(pSramSA->cryptoKey, MV_CESA_MAX_CRYPTO_KEY_LENGTH, 1);
++
++ mvOsPrintf("macInnerIV=%p, maxInnerIV=%d bytes\n",
++ pSramSA->macInnerIV, MV_CESA_MAX_DIGEST_SIZE);
++ mvDebugMemDump(pSramSA->macInnerIV, MV_CESA_MAX_DIGEST_SIZE, 1);
++
++ mvOsPrintf("macOuterIV=%p, maxOuterIV=%d bytes\n",
++ pSramSA->macOuterIV, MV_CESA_MAX_DIGEST_SIZE);
++ mvDebugMemDump(pSramSA->macOuterIV, MV_CESA_MAX_DIGEST_SIZE, 1);
++ }
++}
++
++void mvCesaDebugSA(short sid, int mode)
++{
++ MV_CESA_OPERATION oper;
++ MV_CESA_DIRECTION dir;
++ MV_CESA_CRYPTO_ALG cryptoAlg;
++ MV_CESA_CRYPTO_MODE cryptoMode;
++ MV_CESA_MAC_MODE macMode;
++ MV_CESA_SA* pSA = &pCesaSAD[sid];
++
++ if( (pSA->valid) || ((pSA->count != 0) && (mode > 0)) || (mode >= 2) )
++ {
++ mvOsPrintf("\n\nCESA SA Entry #%d (%p) - %s (count=%d)\n",
++ sid, pSA,
++ pSA->valid ? "Valid" : "Invalid", pSA->count);
++
++ oper = (pSA->config & MV_CESA_OPERATION_MASK) >> MV_CESA_OPERATION_OFFSET;
++ dir = (pSA->config & MV_CESA_DIRECTION_MASK) >> MV_CESA_DIRECTION_BIT;
++ mvOsPrintf("%s - %s ", mvCesaDebugOperStr(oper),
++ (dir == MV_CESA_DIR_ENCODE) ? "Encode" : "Decode");
++ if(oper != MV_CESA_MAC_ONLY)
++ {
++ cryptoAlg = (pSA->config & MV_CESA_CRYPTO_ALG_MASK) >> MV_CESA_CRYPTO_ALG_OFFSET;
++ cryptoMode = (pSA->config & MV_CESA_CRYPTO_MODE_MASK) >> MV_CESA_CRYPTO_MODE_BIT;
++ mvOsPrintf("- %s - %s ", mvCesaDebugCryptoAlgStr(cryptoAlg),
++ (cryptoMode == MV_CESA_CRYPTO_ECB) ? "ECB" : "CBC");
++ }
++ if(oper != MV_CESA_CRYPTO_ONLY)
++ {
++ macMode = (pSA->config & MV_CESA_MAC_MODE_MASK) >> MV_CESA_MAC_MODE_OFFSET;
++ mvOsPrintf("- %s ", mvCesaDebugMacModeStr(macMode));
++ }
++ mvOsPrintf("\n");
++
++ if(mode > 0)
++ {
++ mvOsPrintf("config=0x%08x, cryptoKeySize=%d, digestSize=%d\n",
++ pCesaSAD[sid].config, pCesaSAD[sid].cryptoKeyLength,
++ pCesaSAD[sid].digestSize);
++
++ mvCesaDebugSramSA(pCesaSAD[sid].pSramSA, mode);
++ }
++ }
++}
++
++
++/**/
++void mvCesaDebugSram(int mode)
++{
++ mvOsPrintf("\n\t SRAM contents: size=%ld, pVirt=%p\n\n",
++ sizeof(MV_CESA_SRAM_MAP), cesaSramVirtPtr);
++
++ mvOsPrintf("\n\t Sram buffer: size=%d, pVirt=%p\n",
++ MV_CESA_MAX_BUF_SIZE, cesaSramVirtPtr->buf);
++ if(mode != 0)
++ mvDebugMemDump(cesaSramVirtPtr->buf, 64, 1);
++
++ mvOsPrintf("\n");
++ mvOsPrintf("\n\t Sram descriptor: size=%ld, pVirt=%p\n",
++ sizeof(MV_CESA_DESC), &cesaSramVirtPtr->desc);
++ if(mode != 0)
++ {
++ mvOsPrintf("\n");
++ mvCesaDebugDescriptor(&cesaSramVirtPtr->desc);
++ }
++ mvOsPrintf("\n\t Sram IV: size=%d, pVirt=%p\n",
++ MV_CESA_MAX_IV_LENGTH, &cesaSramVirtPtr->cryptoIV);
++ if(mode != 0)
++ {
++ mvOsPrintf("\n");
++ mvDebugMemDump(cesaSramVirtPtr->cryptoIV, MV_CESA_MAX_IV_LENGTH, 1);
++ }
++ mvOsPrintf("\n");
++ mvCesaDebugSramSA(&cesaSramVirtPtr->sramSA, 0);
++}
++
++void mvCesaDebugSAD(int mode)
++{
++ int sid;
++
++ mvOsPrintf("\n\t Cesa SAD status: pSAD=%p, maxSA=%d\n",
++ pCesaSAD, cesaMaxSA);
++
++ for(sid=0; sid<cesaMaxSA; sid++)
++ {
++ mvCesaDebugSA(sid, mode);
++ }
++}
++
++void mvCesaDebugStats(void)
++{
++ mvOsPrintf("\n\t Cesa Statistics\n");
++
++ mvOsPrintf("Opened=%u, Closed=%u\n",
++ cesaStats.openedCount, cesaStats.closedCount);
++ mvOsPrintf("Req=%u, maxReq=%u, frags=%u, start=%u\n",
++ cesaStats.reqCount, cesaStats.maxReqCount,
++ cesaStats.fragCount, cesaStats.startCount);
++#if (MV_CESA_VERSION >= 3)
++ mvOsPrintf("maxChainUsage=%u\n",cesaStats.maxChainUsage);
++#endif
++ mvOsPrintf("\n");
++ mvOsPrintf("proc=%u, ready=%u, notReady=%u\n",
++ cesaStats.procCount, cesaStats.readyCount, cesaStats.notReadyCount);
++}
++
++void mvCesaDebugStatsClear(void)
++{
++ memset(&cesaStats, 0, sizeof(cesaStats));
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvCesa.h linux-2.6.36/crypto/ocf/kirkwood/cesa/mvCesa.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvCesa.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/mvCesa.h 2010-11-09 20:28:05.737859537 +0100
+@@ -0,0 +1,412 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++/*******************************************************************************
++* mvCesa.h - Header File for Cryptographic Engines and Security Accelerator
++*
++* DESCRIPTION:
++* This header file contains macros typedefs and function declaration for
++* the Marvell Cryptographic Engines and Security Accelerator.
++*
++*******************************************************************************/
++
++#ifndef __mvCesa_h__
++#define __mvCesa_h__
++
++#include "mvOs.h"
++#include "mvCommon.h"
++#include "mvDebug.h"
++
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++
++#include "cesa/mvMD5.h"
++#include "cesa/mvSHA1.h"
++
++#include "cesa/mvCesa.h"
++#include "cesa/AES/mvAes.h"
++#include "mvSysHwConfig.h"
++
++#ifdef MV_INCLUDE_IDMA
++#include "idma/mvIdma.h"
++#include "idma/mvIdmaRegs.h"
++#else
++/* Redefine MV_DMA_DESC structure */
++typedef struct _mvDmaDesc
++{
++ MV_U32 byteCnt; /* The total number of bytes to transfer */
++ MV_U32 phySrcAdd; /* The physical source address */
++ MV_U32 phyDestAdd; /* The physical destination address */
++ MV_U32 phyNextDescPtr; /* If we are using chain mode DMA transfer, */
++ /* then this pointer should point to the */
++ /* physical address of the next descriptor, */
++ /* otherwise it should be NULL. */
++}MV_DMA_DESC;
++#endif /* MV_INCLUDE_IDMA */
++
++#include "cesa/mvCesaRegs.h"
++
++#define MV_CESA_AUTH_BLOCK_SIZE 64 /* bytes */
++
++#define MV_CESA_MD5_DIGEST_SIZE 16 /* bytes */
++#define MV_CESA_SHA1_DIGEST_SIZE 20 /* bytes */
++
++#define MV_CESA_MAX_DIGEST_SIZE MV_CESA_SHA1_DIGEST_SIZE
++
++#define MV_CESA_DES_KEY_LENGTH 8 /* bytes = 64 bits */
++#define MV_CESA_3DES_KEY_LENGTH 24 /* bytes = 192 bits */
++#define MV_CESA_AES_128_KEY_LENGTH 16 /* bytes = 128 bits */
++#define MV_CESA_AES_192_KEY_LENGTH 24 /* bytes = 192 bits */
++#define MV_CESA_AES_256_KEY_LENGTH 32 /* bytes = 256 bits */
++
++#define MV_CESA_MAX_CRYPTO_KEY_LENGTH MV_CESA_AES_256_KEY_LENGTH
++
++#define MV_CESA_DES_BLOCK_SIZE 8 /* bytes = 64 bits */
++#define MV_CESA_3DES_BLOCK_SIZE 8 /* bytes = 64 bits */
++
++#define MV_CESA_AES_BLOCK_SIZE 16 /* bytes = 128 bits */
++
++#define MV_CESA_MAX_IV_LENGTH MV_CESA_AES_BLOCK_SIZE
++
++#define MV_CESA_MAX_MAC_KEY_LENGTH 64 /* bytes */
++
++typedef struct
++{
++ MV_U8 cryptoKey[MV_CESA_MAX_CRYPTO_KEY_LENGTH];
++ MV_U8 macKey[MV_CESA_MAX_MAC_KEY_LENGTH];
++ MV_CESA_OPERATION operation;
++ MV_CESA_DIRECTION direction;
++ MV_CESA_CRYPTO_ALG cryptoAlgorithm;
++ MV_CESA_CRYPTO_MODE cryptoMode;
++ MV_U8 cryptoKeyLength;
++ MV_CESA_MAC_MODE macMode;
++ MV_U8 macKeyLength;
++ MV_U8 digestSize;
++
++} MV_CESA_OPEN_SESSION;
++
++typedef struct
++{
++ MV_BUF_INFO *pFrags;
++ MV_U16 numFrags;
++ MV_U16 mbufSize;
++
++} MV_CESA_MBUF;
++
++typedef struct
++{
++ void* pReqPrv; /* instead of reqId */
++ MV_U32 retCode;
++ MV_16 sessionId;
++
++} MV_CESA_RESULT;
++
++typedef void (*MV_CESA_CALLBACK) (MV_CESA_RESULT* pResult);
++
++
++typedef struct
++{
++ void* pReqPrv; /* instead of reqId */
++ MV_CESA_MBUF* pSrc;
++ MV_CESA_MBUF* pDst;
++ MV_CESA_CALLBACK* pFuncCB;
++ MV_16 sessionId;
++ MV_U16 ivFromUser;
++ MV_U16 ivOffset;
++ MV_U16 cryptoOffset;
++ MV_U16 cryptoLength;
++ MV_U16 digestOffset;
++ MV_U16 macOffset;
++ MV_U16 macLength;
++ MV_BOOL skipFlush;
++} MV_CESA_COMMAND;
++
++
++
++MV_STATUS mvCesaHalInit (int numOfSession, int queueDepth, char* pSramBase, MV_U32 cryptEngBase, void *osHandle);
++MV_STATUS mvCesaFinish (void);
++MV_STATUS mvCesaSessionOpen(MV_CESA_OPEN_SESSION *pSession, short* pSid);
++MV_STATUS mvCesaSessionClose(short sid);
++MV_STATUS mvCesaCryptoIvSet(MV_U8* pIV, int ivSize);
++
++MV_STATUS mvCesaAction (MV_CESA_COMMAND* pCmd);
++
++MV_U32 mvCesaInProcessGet(void);
++MV_STATUS mvCesaReadyDispatch(void);
++MV_STATUS mvCesaReadyGet(MV_CESA_RESULT* pResult);
++MV_BOOL mvCesaIsReady(void);
++
++int mvCesaMbufOffset(MV_CESA_MBUF* pMbuf, int offset, int* pBufOffset);
++MV_STATUS mvCesaCopyFromMbuf(MV_U8* pDst, MV_CESA_MBUF* pSrcMbuf,
++ int offset, int size);
++MV_STATUS mvCesaCopyToMbuf(MV_U8* pSrc, MV_CESA_MBUF* pDstMbuf,
++ int offset, int size);
++MV_STATUS mvCesaMbufCopy(MV_CESA_MBUF* pMbufDst, int dstMbufOffset,
++ MV_CESA_MBUF* pMbufSrc, int srcMbufOffset, int size);
++
++/********** Debug functions ********/
++
++void mvCesaDebugMbuf(const char* str, MV_CESA_MBUF *pMbuf, int offset, int size);
++void mvCesaDebugSA(short sid, int mode);
++void mvCesaDebugStats(void);
++void mvCesaDebugStatsClear(void);
++void mvCesaDebugRegs(void);
++void mvCesaDebugStatus(void);
++void mvCesaDebugQueue(int mode);
++void mvCesaDebugSram(int mode);
++void mvCesaDebugSAD(int mode);
++
++
++/******** CESA Private definitions ********/
++#if (MV_CESA_VERSION >= 2)
++#if (MV_CACHE_COHERENCY == MV_CACHE_COHER_SW)
++#define MV_CESA_TDMA_CTRL_VALUE MV_CESA_TDMA_DST_BURST_MASK(MV_CESA_TDMA_BURST_128B) \
++ | MV_CESA_TDMA_SRC_BURST_MASK(MV_CESA_TDMA_BURST_128B) \
++ | MV_CESA_TDMA_OUTSTAND_READ_EN_MASK \
++ | MV_CESA_TDMA_NO_BYTE_SWAP_MASK \
++ | MV_CESA_TDMA_ENABLE_MASK
++#else
++#define MV_CESA_TDMA_CTRL_VALUE MV_CESA_TDMA_DST_BURST_MASK(MV_CESA_TDMA_BURST_32B) \
++ | MV_CESA_TDMA_SRC_BURST_MASK(MV_CESA_TDMA_BURST_128B) \
++ /*| MV_CESA_TDMA_OUTSTAND_READ_EN_MASK */\
++ | MV_CESA_TDMA_ENABLE_MASK
++
++#endif
++#else
++#define MV_CESA_IDMA_CTRL_LOW_VALUE ICCLR_DST_BURST_LIM_128BYTE \
++ | ICCLR_SRC_BURST_LIM_128BYTE \
++ | ICCLR_INT_MODE_MASK \
++ | ICCLR_BLOCK_MODE \
++ | ICCLR_CHAN_ENABLE \
++ | ICCLR_DESC_MODE_16M
++#endif /* MV_CESA_VERSION >= 2 */
++
++#define MV_CESA_MAX_PKT_SIZE (64 * 1024)
++#define MV_CESA_MAX_MBUF_FRAGS 20
++
++#define MV_CESA_MAX_REQ_FRAGS ( (MV_CESA_MAX_PKT_SIZE / MV_CESA_MAX_BUF_SIZE) + 1)
++
++#define MV_CESA_MAX_DMA_DESC (MV_CESA_MAX_MBUF_FRAGS*2 + 5)
++
++#define MAX_CESA_CHAIN_LENGTH 20
++
++typedef enum
++{
++ MV_CESA_IDLE = 0,
++ MV_CESA_PENDING,
++ MV_CESA_PROCESS,
++ MV_CESA_READY,
++#if (MV_CESA_VERSION >= 3)
++ MV_CESA_CHAIN,
++#endif
++} MV_CESA_STATE;
++
++
++/* Session database */
++
++/* Map of Key materials of the session in SRAM.
++ * Each field must be 8 byte aligned
++ * Total size: 32 + 24 + 24 = 80 bytes
++ */
++typedef struct
++{
++ MV_U8 cryptoKey[MV_CESA_MAX_CRYPTO_KEY_LENGTH];
++ MV_U8 macInnerIV[MV_CESA_MAX_DIGEST_SIZE];
++ MV_U8 reservedInner[4];
++ MV_U8 macOuterIV[MV_CESA_MAX_DIGEST_SIZE];
++ MV_U8 reservedOuter[4];
++
++} MV_CESA_SRAM_SA;
++
++typedef struct
++{
++ MV_CESA_SRAM_SA* pSramSA;
++ MV_U32 config;
++ MV_U8 cryptoKeyLength;
++ MV_U8 cryptoIvSize;
++ MV_U8 cryptoBlockSize;
++ MV_U8 digestSize;
++ MV_U8 macKeyLength;
++ MV_U8 valid;
++ MV_U8 ctrMode;
++ MV_U32 count;
++
++} MV_CESA_SA;
++
++/* DMA list management */
++typedef struct
++{
++ MV_DMA_DESC* pDmaFirst;
++ MV_DMA_DESC* pDmaLast;
++
++} MV_CESA_DMA;
++
++
++typedef struct
++{
++ MV_U8 numFrag;
++ MV_U8 nextFrag;
++ int bufOffset;
++ int cryptoSize;
++ int macSize;
++ int newDigestOffset;
++ MV_U8 orgDigest[MV_CESA_MAX_DIGEST_SIZE];
++
++} MV_CESA_FRAGS;
++
++/* Request queue */
++typedef struct
++{
++ MV_U8 state;
++ MV_U8 fragMode;
++ MV_U8 fixOffset;
++ MV_CESA_COMMAND* pCmd;
++ MV_CESA_COMMAND* pOrgCmd;
++ MV_BUF_INFO dmaDescBuf;
++ MV_CESA_DMA dma[MV_CESA_MAX_REQ_FRAGS];
++ MV_BUF_INFO cesaDescBuf;
++ MV_CESA_DESC* pCesaDesc;
++ MV_CESA_FRAGS frags;
++
++
++} MV_CESA_REQ;
++
++
++/* SRAM map */
++/* Total SRAM size calculation */
++/* SRAM size =
++ * MV_CESA_MAX_BUF_SIZE +
++ * sizeof(MV_CESA_DESC) +
++ * MV_CESA_MAX_IV_LENGTH +
++ * MV_CESA_MAX_IV_LENGTH +
++ * MV_CESA_MAX_DIGEST_SIZE +
++ * sizeof(MV_CESA_SRAM_SA)
++ * = 1600 + 32 + 16 + 16 + 24 + 80 + 280 (reserved) = 2048 bytes
++ * = 3200 + 32 + 16 + 16 + 24 + 80 + 728 (reserved) = 4096 bytes
++ */
++typedef struct
++{
++ MV_U8 buf[MV_CESA_MAX_BUF_SIZE];
++ MV_CESA_DESC desc;
++ MV_U8 cryptoIV[MV_CESA_MAX_IV_LENGTH];
++ MV_U8 tempCryptoIV[MV_CESA_MAX_IV_LENGTH];
++ MV_U8 tempDigest[MV_CESA_MAX_DIGEST_SIZE+4];
++ MV_CESA_SRAM_SA sramSA;
++
++} MV_CESA_SRAM_MAP;
++
++
++typedef struct
++{
++ MV_U32 openedCount;
++ MV_U32 closedCount;
++ MV_U32 fragCount;
++ MV_U32 reqCount;
++ MV_U32 maxReqCount;
++ MV_U32 procCount;
++ MV_U32 readyCount;
++ MV_U32 notReadyCount;
++ MV_U32 startCount;
++#if (MV_CESA_VERSION >= 3)
++ MV_U32 maxChainUsage;
++#endif
++
++} MV_CESA_STATS;
++
++
++/* External variables */
++
++extern MV_CESA_STATS cesaStats;
++extern MV_CESA_FRAGS cesaFrags;
++
++extern MV_BUF_INFO cesaSramSaBuf;
++
++extern MV_CESA_SA* pCesaSAD;
++extern MV_U16 cesaMaxSA;
++
++extern MV_CESA_REQ* pCesaReqFirst;
++extern MV_CESA_REQ* pCesaReqLast;
++extern MV_CESA_REQ* pCesaReqEmpty;
++extern MV_CESA_REQ* pCesaReqProcess;
++extern int cesaQueueDepth;
++extern int cesaReqResources;
++#if (MV_CESA_VERSION>= 3)
++extern MV_U32 cesaChainLength;
++#endif
++
++extern MV_CESA_SRAM_MAP* cesaSramVirtPtr;
++extern MV_U32 cesaSramPhysAddr;
++
++static INLINE MV_ULONG mvCesaVirtToPhys(MV_BUF_INFO* pBufInfo, void* pVirt)
++{
++ return (pBufInfo->bufPhysAddr + ((MV_U8*)pVirt - pBufInfo->bufVirtPtr));
++}
++
++/* Additional DEBUG functions */
++void mvCesaDebugSramSA(MV_CESA_SRAM_SA* pSramSA, int mode);
++void mvCesaDebugCmd(MV_CESA_COMMAND* pCmd, int mode);
++void mvCesaDebugDescriptor(MV_CESA_DESC* pDesc);
++
++
++
++#endif /* __mvCesa_h__ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvCesaRegs.h linux-2.6.36/crypto/ocf/kirkwood/cesa/mvCesaRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvCesaRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/mvCesaRegs.h 2010-11-09 20:28:05.772495441 +0100
+@@ -0,0 +1,357 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __mvCesaRegs_h__
++#define __mvCesaRegs_h__
++
++#include "mvTypes.h"
++
++typedef struct
++{
++ /* word 0 */
++ MV_U32 config;
++ /* word 1 */
++ MV_U16 cryptoSrcOffset;
++ MV_U16 cryptoDstOffset;
++ /* word 2 */
++ MV_U16 cryptoDataLen;
++ MV_U16 reserved1;
++ /* word 3 */
++ MV_U16 cryptoKeyOffset;
++ MV_U16 reserved2;
++ /* word 4 */
++ MV_U16 cryptoIvOffset;
++ MV_U16 cryptoIvBufOffset;
++ /* word 5 */
++ MV_U16 macSrcOffset;
++ MV_U16 macTotalLen;
++ /* word 6 */
++ MV_U16 macDigestOffset;
++ MV_U16 macDataLen;
++ /* word 7 */
++ MV_U16 macInnerIvOffset;
++ MV_U16 macOuterIvOffset;
++
++} MV_CESA_DESC;
++
++/* operation */
++typedef enum
++{
++ MV_CESA_MAC_ONLY = 0,
++ MV_CESA_CRYPTO_ONLY = 1,
++ MV_CESA_MAC_THEN_CRYPTO = 2,
++ MV_CESA_CRYPTO_THEN_MAC = 3,
++
++ MV_CESA_MAX_OPERATION
++
++} MV_CESA_OPERATION;
++
++#define MV_CESA_OPERATION_OFFSET 0
++#define MV_CESA_OPERATION_MASK (0x3 << MV_CESA_OPERATION_OFFSET)
++
++/* mac algorithm */
++typedef enum
++{
++ MV_CESA_MAC_NULL = 0,
++ MV_CESA_MAC_MD5 = 4,
++ MV_CESA_MAC_SHA1 = 5,
++ MV_CESA_MAC_HMAC_MD5 = 6,
++ MV_CESA_MAC_HMAC_SHA1 = 7,
++
++} MV_CESA_MAC_MODE;
++
++#define MV_CESA_MAC_MODE_OFFSET 4
++#define MV_CESA_MAC_MODE_MASK (0x7 << MV_CESA_MAC_MODE_OFFSET)
++
++typedef enum
++{
++ MV_CESA_MAC_DIGEST_FULL = 0,
++ MV_CESA_MAC_DIGEST_96B = 1,
++
++} MV_CESA_MAC_DIGEST_SIZE;
++
++#define MV_CESA_MAC_DIGEST_SIZE_BIT 7
++#define MV_CESA_MAC_DIGEST_SIZE_MASK (1 << MV_CESA_MAC_DIGEST_SIZE_BIT)
++
++
++typedef enum
++{
++ MV_CESA_CRYPTO_NULL = 0,
++ MV_CESA_CRYPTO_DES = 1,
++ MV_CESA_CRYPTO_3DES = 2,
++ MV_CESA_CRYPTO_AES = 3,
++
++} MV_CESA_CRYPTO_ALG;
++
++#define MV_CESA_CRYPTO_ALG_OFFSET 8
++#define MV_CESA_CRYPTO_ALG_MASK (0x3 << MV_CESA_CRYPTO_ALG_OFFSET)
++
++
++/* direction */
++typedef enum
++{
++ MV_CESA_DIR_ENCODE = 0,
++ MV_CESA_DIR_DECODE = 1,
++
++} MV_CESA_DIRECTION;
++
++#define MV_CESA_DIRECTION_BIT 12
++#define MV_CESA_DIRECTION_MASK (1 << MV_CESA_DIRECTION_BIT)
++
++/* crypto IV mode */
++typedef enum
++{
++ MV_CESA_CRYPTO_ECB = 0,
++ MV_CESA_CRYPTO_CBC = 1,
++
++ /* NO HW Support */
++ MV_CESA_CRYPTO_CTR = 10,
++
++} MV_CESA_CRYPTO_MODE;
++
++#define MV_CESA_CRYPTO_MODE_BIT 16
++#define MV_CESA_CRYPTO_MODE_MASK (1 << MV_CESA_CRYPTO_MODE_BIT)
++
++/* 3DES mode */
++typedef enum
++{
++ MV_CESA_CRYPTO_3DES_EEE = 0,
++ MV_CESA_CRYPTO_3DES_EDE = 1,
++
++} MV_CESA_CRYPTO_3DES_MODE;
++
++#define MV_CESA_CRYPTO_3DES_MODE_BIT 20
++#define MV_CESA_CRYPTO_3DES_MODE_MASK (1 << MV_CESA_CRYPTO_3DES_MODE_BIT)
++
++
++/* AES Key Length */
++typedef enum
++{
++ MV_CESA_CRYPTO_AES_KEY_128 = 0,
++ MV_CESA_CRYPTO_AES_KEY_192 = 1,
++ MV_CESA_CRYPTO_AES_KEY_256 = 2,
++
++} MV_CESA_CRYPTO_AES_KEY_LEN;
++
++#define MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET 24
++#define MV_CESA_CRYPTO_AES_KEY_LEN_MASK (0x3 << MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET)
++
++/* Fragmentation mode */
++typedef enum
++{
++ MV_CESA_FRAG_NONE = 0,
++ MV_CESA_FRAG_FIRST = 1,
++ MV_CESA_FRAG_LAST = 2,
++ MV_CESA_FRAG_MIDDLE = 3,
++
++} MV_CESA_FRAG_MODE;
++
++#define MV_CESA_FRAG_MODE_OFFSET 30
++#define MV_CESA_FRAG_MODE_MASK (0x3 << MV_CESA_FRAG_MODE_OFFSET)
++/*---------------------------------------------------------------------------*/
++
++/********** Security Accelerator Command Register **************/
++#define MV_CESA_CMD_REG (MV_CESA_REG_BASE + 0xE00)
++
++#define MV_CESA_CMD_CHAN_ENABLE_BIT 0
++#define MV_CESA_CMD_CHAN_ENABLE_MASK (1 << MV_CESA_CMD_CHAN_ENABLE_BIT)
++
++#define MV_CESA_CMD_CHAN_DISABLE_BIT 2
++#define MV_CESA_CMD_CHAN_DISABLE_MASK (1 << MV_CESA_CMD_CHAN_DISABLE_BIT)
++
++/********** Security Accelerator Descriptor Pointers Register **********/
++#define MV_CESA_CHAN_DESC_OFFSET_REG (MV_CESA_REG_BASE + 0xE04)
++
++/********** Security Accelerator Configuration Register **********/
++#define MV_CESA_CFG_REG (MV_CESA_REG_BASE + 0xE08)
++
++#define MV_CESA_CFG_STOP_DIGEST_ERR_BIT 0
++#define MV_CESA_CFG_STOP_DIGEST_ERR_MASK (1 << MV_CESA_CFG_STOP_DIGEST_ERR_BIT)
++
++#define MV_CESA_CFG_WAIT_DMA_BIT 7
++#define MV_CESA_CFG_WAIT_DMA_MASK (1 << MV_CESA_CFG_WAIT_DMA_BIT)
++
++#define MV_CESA_CFG_ACT_DMA_BIT 9
++#define MV_CESA_CFG_ACT_DMA_MASK (1 << MV_CESA_CFG_ACT_DMA_BIT)
++
++#define MV_CESA_CFG_CHAIN_MODE_BIT 11
++#define MV_CESA_CFG_CHAIN_MODE_MASK (1 << MV_CESA_CFG_CHAIN_MODE_BIT)
++
++/********** Security Accelerator Status Register ***********/
++#define MV_CESA_STATUS_REG (MV_CESA_REG_BASE + 0xE0C)
++
++#define MV_CESA_STATUS_ACTIVE_BIT 0
++#define MV_CESA_STATUS_ACTIVE_MASK (1 << MV_CESA_STATUS_ACTIVE_BIT)
++
++#define MV_CESA_STATUS_DIGEST_ERR_BIT 8
++#define MV_CESA_STATUS_DIGEST_ERR_MASK (1 << MV_CESA_STATUS_DIGEST_ERR_BIT)
++
++
++/* Cryptographic Engines and Security Accelerator Interrupt Cause Register */
++#define MV_CESA_ISR_CAUSE_REG (MV_CESA_REG_BASE + 0xE20)
++
++/* Cryptographic Engines and Security Accelerator Interrupt Mask Register */
++#define MV_CESA_ISR_MASK_REG (MV_CESA_REG_BASE + 0xE24)
++
++#define MV_CESA_CAUSE_AUTH_MASK (1 << 0)
++#define MV_CESA_CAUSE_DES_MASK (1 << 1)
++#define MV_CESA_CAUSE_AES_ENCR_MASK (1 << 2)
++#define MV_CESA_CAUSE_AES_DECR_MASK (1 << 3)
++#define MV_CESA_CAUSE_DES_ALL_MASK (1 << 4)
++
++#define MV_CESA_CAUSE_ACC_BIT 5
++#define MV_CESA_CAUSE_ACC_MASK (1 << MV_CESA_CAUSE_ACC_BIT)
++
++#define MV_CESA_CAUSE_ACC_DMA_BIT 7
++#define MV_CESA_CAUSE_ACC_DMA_MASK (1 << MV_CESA_CAUSE_ACC_DMA_BIT)
++#define MV_CESA_CAUSE_ACC_DMA_ALL_MASK (3 << MV_CESA_CAUSE_ACC_DMA_BIT)
++
++#define MV_CESA_CAUSE_DMA_COMPL_BIT 9
++#define MV_CESA_CAUSE_DMA_COMPL_MASK (1 << MV_CESA_CAUSE_DMA_COMPL_BIT)
++
++#define MV_CESA_CAUSE_DMA_OWN_ERR_BIT 10
++#define MV_CESA_CAUSE_DMA_OWN_ERR_MASK (1 < MV_CESA_CAUSE_DMA_OWN_ERR_BIT)
++
++#define MV_CESA_CAUSE_DMA_CHAIN_PKT_BIT 11
++#define MV_CESA_CAUSE_DMA_CHAIN_PKT_MASK (1 < MV_CESA_CAUSE_DMA_CHAIN_PKT_BIT)
++
++
++#define MV_CESA_AUTH_DATA_IN_REG (MV_CESA_REG_BASE + 0xd38)
++#define MV_CESA_AUTH_BIT_COUNT_LOW_REG (MV_CESA_REG_BASE + 0xd20)
++#define MV_CESA_AUTH_BIT_COUNT_HIGH_REG (MV_CESA_REG_BASE + 0xd24)
++
++#define MV_CESA_AUTH_INIT_VAL_DIGEST_REG(i) (MV_CESA_REG_BASE + 0xd00 + (i<<2))
++
++#define MV_CESA_AUTH_INIT_VAL_DIGEST_A_REG (MV_CESA_REG_BASE + 0xd00)
++#define MV_CESA_AUTH_INIT_VAL_DIGEST_B_REG (MV_CESA_REG_BASE + 0xd04)
++#define MV_CESA_AUTH_INIT_VAL_DIGEST_C_REG (MV_CESA_REG_BASE + 0xd08)
++#define MV_CESA_AUTH_INIT_VAL_DIGEST_D_REG (MV_CESA_REG_BASE + 0xd0c)
++#define MV_CESA_AUTH_INIT_VAL_DIGEST_E_REG (MV_CESA_REG_BASE + 0xd10)
++#define MV_CESA_AUTH_COMMAND_REG (MV_CESA_REG_BASE + 0xd18)
++
++#define MV_CESA_AUTH_ALGORITHM_BIT 0
++#define MV_CESA_AUTH_ALGORITHM_MD5 (0<<AUTH_ALGORITHM_BIT)
++#define MV_CESA_AUTH_ALGORITHM_SHA1 (1<<AUTH_ALGORITHM_BIT)
++
++#define MV_CESA_AUTH_IV_MODE_BIT 1
++#define MV_CESA_AUTH_IV_MODE_INIT (0<<AUTH_IV_MODE_BIT)
++#define MV_CESA_AUTH_IV_MODE_CONTINUE (1<<AUTH_IV_MODE_BIT)
++
++#define MV_CESA_AUTH_DATA_BYTE_SWAP_BIT 2
++#define MV_CESA_AUTH_DATA_BYTE_SWAP_MASK (1<<AUTH_DATA_BYTE_SWAP_BIT)
++
++
++#define MV_CESA_AUTH_IV_BYTE_SWAP_BIT 4
++#define MV_CESA_AUTH_IV_BYTE_SWAP_MASK (1<<AUTH_IV_BYTE_SWAP_BIT)
++
++#define MV_CESA_AUTH_TERMINATION_BIT 31
++#define MV_CESA_AUTH_TERMINATION_MASK (1<<AUTH_TERMINATION_BIT)
++
++
++/*************** TDMA Control Register ************************************************/
++#define MV_CESA_TDMA_CTRL_REG (MV_CESA_TDMA_REG_BASE + 0x840)
++
++#define MV_CESA_TDMA_BURST_32B 3
++#define MV_CESA_TDMA_BURST_128B 4
++
++#define MV_CESA_TDMA_DST_BURST_OFFSET 0
++#define MV_CESA_TDMA_DST_BURST_ALL_MASK (0x7<<MV_CESA_TDMA_DST_BURST_OFFSET)
++#define MV_CESA_TDMA_DST_BURST_MASK(burst) ((burst)<<MV_CESA_TDMA_DST_BURST_OFFSET)
++
++#define MV_CESA_TDMA_OUTSTAND_READ_EN_BIT 4
++#define MV_CESA_TDMA_OUTSTAND_READ_EN_MASK (1<<MV_CESA_TDMA_OUTSTAND_READ_EN_BIT)
++
++#define MV_CESA_TDMA_SRC_BURST_OFFSET 6
++#define MV_CESA_TDMA_SRC_BURST_ALL_MASK (0x7<<MV_CESA_TDMA_SRC_BURST_OFFSET)
++#define MV_CESA_TDMA_SRC_BURST_MASK(burst) ((burst)<<MV_CESA_TDMA_SRC_BURST_OFFSET)
++
++#define MV_CESA_TDMA_CHAIN_MODE_BIT 9
++#define MV_CESA_TDMA_NON_CHAIN_MODE_MASK (1<<MV_CESA_TDMA_CHAIN_MODE_BIT)
++
++#define MV_CESA_TDMA_BYTE_SWAP_BIT 11
++#define MV_CESA_TDMA_BYTE_SWAP_MASK (0 << MV_CESA_TDMA_BYTE_SWAP_BIT)
++#define MV_CESA_TDMA_NO_BYTE_SWAP_MASK (1 << MV_CESA_TDMA_BYTE_SWAP_BIT)
++
++#define MV_CESA_TDMA_ENABLE_BIT 12
++#define MV_CESA_TDMA_ENABLE_MASK (1<<MV_CESA_TDMA_ENABLE_BIT)
++
++#define MV_CESA_TDMA_FETCH_NEXT_DESC_BIT 13
++#define MV_CESA_TDMA_FETCH_NEXT_DESC_MASK (1<<MV_CESA_TDMA_FETCH_NEXT_DESC_BIT)
++
++#define MV_CESA_TDMA_CHAN_ACTIVE_BIT 14
++#define MV_CESA_TDMA_CHAN_ACTIVE_MASK (1<<MV_CESA_TDMA_CHAN_ACTIVE_BIT)
++/*------------------------------------------------------------------------------------*/
++
++#define MV_CESA_TDMA_BYTE_COUNT_REG (MV_CESA_TDMA_REG_BASE + 0x800)
++#define MV_CESA_TDMA_SRC_ADDR_REG (MV_CESA_TDMA_REG_BASE + 0x810)
++#define MV_CESA_TDMA_DST_ADDR_REG (MV_CESA_TDMA_REG_BASE + 0x820)
++#define MV_CESA_TDMA_NEXT_DESC_PTR_REG (MV_CESA_TDMA_REG_BASE + 0x830)
++#define MV_CESA_TDMA_CURR_DESC_PTR_REG (MV_CESA_TDMA_REG_BASE + 0x870)
++
++#define MV_CESA_TDMA_ERROR_CAUSE_REG (MV_CESA_TDMA_REG_BASE + 0x8C0)
++#define MV_CESA_TDMA_ERROR_MASK_REG (MV_CESA_TDMA_REG_BASE + 0x8C4)
++
++
++#endif /* __mvCesaRegs_h__ */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvCesaTest.c linux-2.6.36/crypto/ocf/kirkwood/cesa/mvCesaTest.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvCesaTest.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/mvCesaTest.c 2010-11-09 20:28:05.782495527 +0100
+@@ -0,0 +1,3096 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvOs.h"
++
++#if defined(MV_VXWORKS)
++
++#include "sysLib.h"
++#include "logLib.h"
++#include "tickLib.h"
++#include "intLib.h"
++#include "config.h"
++
++
++SEM_ID cesaSemId = NULL;
++SEM_ID cesaWaitSemId = NULL;
++
++#define CESA_TEST_LOCK(flags) flags = intLock()
++#define CESA_TEST_UNLOCK(flags) intUnlock(flags)
++
++#define CESA_TEST_WAIT_INIT() cesaWaitSemId = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY)
++#define CESA_TEST_WAKE_UP() semGive(cesaWaitSemId)
++#define CESA_TEST_WAIT(cond, ms) semTake(cesaWaitSemId, (sysClkRateGet()*ms)/1000)
++
++#define CESA_TEST_TICK_GET() tickGet()
++#define CESA_TEST_TICK_TO_MS(tick) (((tick)*1000)/sysClkRateGet())
++
++#elif defined(MV_LINUX)
++
++#include <linux/wait.h>
++wait_queue_head_t cesaTest_waitq;
++spinlock_t cesaLock;
++
++#define CESA_TEST_LOCK(flags) spin_lock_irqsave( &cesaLock, flags)
++#define CESA_TEST_UNLOCK(flags) spin_unlock_irqrestore( &cesaLock, flags);
++
++#define CESA_TEST_WAIT_INIT() init_waitqueue_head(&cesaTest_waitq)
++#define CESA_TEST_WAKE_UP() wake_up(&cesaTest_waitq)
++#define CESA_TEST_WAIT(cond, ms) wait_event_timeout(cesaTest_waitq, (cond), msecs_to_jiffies(ms))
++
++#define CESA_TEST_TICK_GET() jiffies
++#define CESA_TEST_TICK_TO_MS(tick) jiffies_to_msecs(tick)
++
++#elif defined(MV_NETBSD)
++
++#include <sys/param.h>
++#include <sys/kernel.h>
++static int cesaLock;
++
++#define CESA_TEST_LOCK(flags) flags = splnet()
++#define CESA_TEST_UNLOCK(flags) splx(flags)
++
++#define CESA_TEST_WAIT_INIT() /* nothing */
++#define CESA_TEST_WAKE_UP() wakeup(&cesaLock)
++#define CESA_TEST_WAIT(cond, ms) \
++do { \
++ while (!(cond)) \
++ tsleep(&cesaLock, PWAIT, "cesatest",mstohz(ms)); \
++} while (/*CONSTCOND*/0)
++
++#define CESA_TEST_TICK_GET() hardclock_ticks
++#define CESA_TEST_TICK_TO_MS(tick) ((1000/hz)*(tick))
++
++#define request_irq(i,h,t,n,a) \
++ !mv_intr_establish((i),IPL_NET,(int(*)(void *))(h),(a))
++
++#else
++#error "Only Linux, VxWorks, or NetBSD OS are supported"
++#endif
++
++#include "mvDebug.h"
++
++#include "mvSysHwConfig.h"
++#include "boardEnv/mvBoardEnvLib.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++#include "cntmr/mvCntmr.h"
++#include "cesa/mvCesa.h"
++#include "cesa/mvCesaRegs.h"
++#include "cesa/mvMD5.h"
++#include "cesa/mvSHA1.h"
++
++#if defined(CONFIG_MV646xx)
++#include "marvell_pic.h"
++#endif
++
++#define MV_CESA_USE_TIMER_ID 0
++#define CESA_DEF_BUF_SIZE 1500
++#define CESA_DEF_BUF_NUM 1
++#define CESA_DEF_SESSION_NUM 32
++
++#define CESA_DEF_ITER_NUM 100
++
++#define CESA_DEF_REQ_SIZE 256
++
++
++/* CESA Tests Debug */
++#undef CESA_TEST_DEBUG
++
++#ifdef CESA_TEST_DEBUG
++
++# define CESA_TEST_DEBUG_PRINT(msg) mvOsPrintf msg
++# define CESA_TEST_DEBUG_CODE(code) code
++
++typedef struct
++{
++ int type; /* 0 - isrEmpty, 1 - cesaReadyGet, 2 - cesaAction */
++ MV_U32 timeStamp;
++ MV_U32 cause;
++ MV_U32 realCause;
++ MV_U32 dmaCause;
++ int resources;
++ MV_CESA_REQ* pReqReady;
++ MV_CESA_REQ* pReqEmpty;
++ MV_CESA_REQ* pReqProcess;
++} MV_CESA_TEST_TRACE;
++
++#define MV_CESA_TEST_TRACE_SIZE 25
++
++static int cesaTestTraceIdx = 0;
++static MV_CESA_TEST_TRACE cesaTestTrace[MV_CESA_TEST_TRACE_SIZE];
++
++static void cesaTestTraceAdd(int type, MV_U32 cause)
++{
++ cesaTestTrace[cesaTestTraceIdx].type = type;
++ cesaTestTrace[cesaTestTraceIdx].cause = cause;
++ cesaTestTrace[cesaTestTraceIdx].realCause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
++ cesaTestTrace[cesaTestTraceIdx].dmaCause = MV_REG_READ(IDMA_CAUSE_REG);
++ cesaTestTrace[cesaTestTraceIdx].resources = cesaReqResources;
++ cesaTestTrace[cesaTestTraceIdx].pReqReady = pCesaReqReady;
++ cesaTestTrace[cesaTestTraceIdx].pReqEmpty = pCesaReqEmpty;
++ cesaTestTrace[cesaTestTraceIdx].pReqProcess = pCesaReqProcess;
++ cesaTestTrace[cesaTestTraceIdx].timeStamp = mvCntmrRead(MV_CESA_USE_TIMER_ID);
++ cesaTestTraceIdx++;
++ if(cesaTestTraceIdx == MV_CESA_TEST_TRACE_SIZE)
++ cesaTestTraceIdx = 0;
++}
++
++#else
++
++# define CESA_TEST_DEBUG_PRINT(msg)
++# define CESA_TEST_DEBUG_CODE(code)
++
++#endif /* CESA_TEST_DEBUG */
++
++int cesaExpReqId=0;
++int cesaCbIter=0;
++
++int cesaIdx;
++int cesaIteration;
++int cesaRateSize;
++int cesaReqSize;
++unsigned long cesaTaskId;
++int cesaBufNum;
++int cesaBufSize;
++int cesaCheckOffset;
++int cesaCheckSize;
++int cesaCheckMode;
++int cesaTestIdx;
++int cesaCaseIdx;
++
++
++MV_U32 cesaTestIsrCount = 0;
++MV_U32 cesaTestIsrMissCount = 0;
++
++MV_U32 cesaCryptoError = 0;
++MV_U32 cesaReqIdError = 0;
++MV_U32 cesaError = 0;
++
++char* cesaHexBuffer = NULL;
++
++char* cesaBinBuffer = NULL;
++char* cesaExpBinBuffer = NULL;
++
++char* cesaInputHexStr = NULL;
++char* cesaOutputHexStr = NULL;
++
++MV_BUF_INFO cesaReqBufs[CESA_DEF_REQ_SIZE];
++
++MV_CESA_COMMAND* cesaCmdRing;
++MV_CESA_RESULT cesaResult;
++
++int cesaTestFull = 0;
++
++MV_BOOL cesaIsReady = MV_FALSE;
++MV_U32 cesaCycles = 0;
++MV_U32 cesaBeginTicks = 0;
++MV_U32 cesaEndTicks = 0;
++MV_U32 cesaRate = 0;
++MV_U32 cesaRateAfterDot = 0;
++
++void *cesaTestOSHandle = NULL;
++
++enum
++{
++ CESA_FAST_CHECK_MODE = 0,
++ CESA_FULL_CHECK_MODE,
++ CESA_NULL_CHECK_MODE,
++ CESA_SHOW_CHECK_MODE,
++ CESA_SW_SHOW_CHECK_MODE,
++ CESA_SW_NULL_CHECK_MODE,
++
++ CESA_MAX_CHECK_MODE
++};
++
++enum
++{
++ DES_TEST_TYPE = 0,
++ TRIPLE_DES_TEST_TYPE = 1,
++ AES_TEST_TYPE = 2,
++ MD5_TEST_TYPE = 3,
++ SHA_TEST_TYPE = 4,
++ COMBINED_TEST_TYPE = 5,
++
++ MAX_TEST_TYPE
++};
++
++/* Tests data base */
++typedef struct
++{
++ short sid;
++ char cryptoAlgorithm; /* DES/3DES/AES */
++ char cryptoMode; /* ECB or CBC */
++ char macAlgorithm; /* MD5 / SHA1 */
++ char operation; /* CRYPTO/HMAC/CRYPTO+HMAC/HMAC+CRYPTO */
++ char direction; /* ENCODE(SIGN)/DECODE(VERIFY) */
++ unsigned char* pCryptoKey;
++ int cryptoKeySize;
++ unsigned char* pMacKey;
++ int macKeySize;
++ const char* name;
++
++} MV_CESA_TEST_SESSION;
++
++typedef struct
++{
++ MV_CESA_TEST_SESSION* pSessions;
++ int numSessions;
++
++} MV_CESA_TEST_DB_ENTRY;
++
++typedef struct
++{
++ char* plainHexStr;
++ char* cipherHexStr;
++ unsigned char* pCryptoIV;
++ int cryptoLength;
++ int macLength;
++ int digestOffset;
++
++} MV_CESA_TEST_CASE;
++
++typedef struct
++{
++ int size;
++ const char* outputHexStr;
++
++} MV_CESA_SIZE_TEST;
++
++static unsigned char cryptoKey1[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
++ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
++ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
++
++static unsigned char cryptoKey7[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
++static unsigned char iv1[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef};
++
++
++static unsigned char cryptoKey2[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
++
++static unsigned char cryptoKey3[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17};
++
++static unsigned char cryptoKey4[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
++
++static unsigned char cryptoKey5[] = {0x56, 0xe4, 0x7a, 0x38, 0xc5, 0x59, 0x89, 0x74,
++ 0xbc, 0x46, 0x90, 0x3d, 0xba, 0x29, 0x03, 0x49};
++
++
++static unsigned char key3des1[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
++ 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01,
++ 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23};
++
++/* Input ASCII string: The quick brown fox jump */
++static char plain3des1[] = "54686520717566636B2062726F776E20666F78206A756D70";
++static char cipher3des1[] = "A826FD8CE53B855FCCE21C8112256FE668D5C05DD9B6B900";
++
++static unsigned char key3des2[] = {0x62, 0x7f, 0x46, 0x0e, 0x08, 0x10, 0x4a, 0x10,
++ 0x43, 0xcd, 0x26, 0x5d, 0x58, 0x40, 0xea, 0xf1,
++ 0x31, 0x3e, 0xdf, 0x97, 0xdf, 0x2a, 0x8a, 0x8c};
++
++static unsigned char iv3des2[] = {0x8e, 0x29, 0xf7, 0x5e, 0xa7, 0x7e, 0x54, 0x75};
++
++static char plain3des2[] = "326a494cd33fe756";
++
++static char cipher3desCbc2[] = "8e29f75ea77e5475"
++ "b22b8d66de970692";
++
++static unsigned char key3des3[] = {0x37, 0xae, 0x5e, 0xbf, 0x46, 0xdf, 0xf2, 0xdc,
++ 0x07, 0x54, 0xb9, 0x4f, 0x31, 0xcb, 0xb3, 0x85,
++ 0x5e, 0x7f, 0xd3, 0x6d, 0xc8, 0x70, 0xbf, 0xae};
++
++static unsigned char iv3des3[] = {0x3d, 0x1d, 0xe3, 0xcc, 0x13, 0x2e, 0x3b, 0x65};
++
++static char plain3des3[] = "84401f78fe6c10876d8ea23094ea5309";
++
++static char cipher3desCbc3[] = "3d1de3cc132e3b65"
++ "7b1f7c7e3b1c948ebd04a75ffba7d2f5";
++
++static unsigned char iv5[] = {0x8c, 0xe8, 0x2e, 0xef, 0xbe, 0xa0, 0xda, 0x3c,
++ 0x44, 0x69, 0x9e, 0xd7, 0xdb, 0x51, 0xb7, 0xd9};
++
++static unsigned char aesCtrKey[] = {0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8,
++ 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC};
++
++static unsigned char mdKey1[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
++
++static unsigned char mdKey2[] = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
++ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
++
++static unsigned char shaKey1[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
++ 0x0b, 0x0b, 0x0b, 0x0b};
++
++static unsigned char shaKey2[] = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
++ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
++ 0xaa, 0xaa, 0xaa, 0xaa};
++
++static unsigned char mdKey4[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
++
++static unsigned char shaKey4[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
++ 0x11, 0x12, 0x13, 0x14};
++
++
++static MV_CESA_TEST_SESSION desTestSessions[] =
++{
++/*000*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey7, sizeof(cryptoKey7)/sizeof(cryptoKey7[0]),
++ NULL, 0,
++ "DES ECB encode",
++ },
++/*001*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_DECODE,
++ cryptoKey7, sizeof(cryptoKey7)/sizeof(cryptoKey7[0]),
++ NULL, 0,
++ "DES ECB decode",
++ },
++/*002*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey7, sizeof(cryptoKey7)/sizeof(cryptoKey7[0]),
++ NULL, 0,
++ "DES CBC encode"
++ },
++/*003*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_DECODE,
++ cryptoKey7, sizeof(cryptoKey7)/sizeof(cryptoKey7[0]),
++ NULL, 0,
++ "DES CBC decode"
++ },
++/*004*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ NULL, 0, NULL, 0,
++ "NULL Crypto Algorithm encode"
++ },
++};
++
++
++static MV_CESA_TEST_SESSION tripleDesTestSessions[] =
++{
++/*100*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]),
++ NULL, 0,
++ "3DES ECB encode",
++ },
++/*101*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_DECODE,
++ cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]),
++ NULL, 0,
++ "3DES ECB decode",
++ },
++/*102*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]),
++ NULL, 0,
++ "3DES CBC encode"
++ },
++/*103*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_DECODE,
++ cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]),
++ NULL, 0,
++ "3DES CBC decode"
++ },
++/*104*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ key3des1, sizeof(key3des1),
++ NULL, 0,
++ "3DES ECB encode"
++ },
++/*105*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ key3des2, sizeof(key3des2),
++ NULL, 0,
++ "3DES ECB encode"
++ },
++/*106*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ key3des3, sizeof(key3des3),
++ NULL, 0,
++ "3DES ECB encode"
++ },
++};
++
++
++static MV_CESA_TEST_SESSION aesTestSessions[] =
++{
++/*200*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey2, sizeof(cryptoKey2)/sizeof(cryptoKey2[0]),
++ NULL, 0,
++ "AES-128 ECB encode"
++ },
++/*201*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_DECODE,
++ cryptoKey2, sizeof(cryptoKey2)/sizeof(cryptoKey2[0]),
++ NULL, 0,
++ "AES-128 ECB decode"
++ },
++/*202*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey5, sizeof(cryptoKey5)/sizeof(cryptoKey5[0]),
++ NULL, 0,
++ "AES-128 CBC encode"
++ },
++/*203*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_DECODE,
++ cryptoKey5, sizeof(cryptoKey5)/sizeof(cryptoKey5[0]),
++ NULL, 0,
++ "AES-128 CBC decode"
++ },
++/*204*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey3, sizeof(cryptoKey3)/sizeof(cryptoKey3[0]),
++ NULL, 0,
++ "AES-192 ECB encode"
++ },
++/*205*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_DECODE,
++ cryptoKey3, sizeof(cryptoKey3)/sizeof(cryptoKey3[0]),
++ NULL, 0,
++ "AES-192 ECB decode"
++ },
++/*206*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey4, sizeof(cryptoKey4)/sizeof(cryptoKey4[0]),
++ NULL, 0,
++ "AES-256 ECB encode"
++ },
++/*207*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_DECODE,
++ cryptoKey4, sizeof(cryptoKey4)/sizeof(cryptoKey4[0]),
++ NULL, 0,
++ "AES-256 ECB decode"
++ },
++/*208*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_CTR,
++ MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY,
++ MV_CESA_DIR_ENCODE,
++ aesCtrKey, sizeof(aesCtrKey)/sizeof(aesCtrKey[0]),
++ NULL, 0,
++ "AES-128 CTR encode"
++ },
++};
++
++
++static MV_CESA_TEST_SESSION md5TestSessions[] =
++{
++/*300*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_ENCODE,
++ NULL, 0,
++ mdKey1, sizeof(mdKey1),
++ "HMAC-MD5 Generate Signature"
++ },
++/*301*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_DECODE,
++ NULL, 0,
++ mdKey1, sizeof(mdKey1),
++ "HMAC-MD5 Verify Signature"
++ },
++/*302*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_ENCODE,
++ NULL, 0,
++ mdKey2, sizeof(mdKey2),
++ "HMAC-MD5 Generate Signature"
++ },
++/*303*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_DECODE,
++ NULL, 0,
++ mdKey2, sizeof(mdKey2),
++ "HMAC-MD5 Verify Signature"
++ },
++/*304*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_ENCODE,
++ NULL, 0,
++ mdKey4, sizeof(mdKey4),
++ "HMAC-MD5 Generate Signature"
++ },
++/*305*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_MD5, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_ENCODE,
++ NULL, 0,
++ NULL, 0,
++ "HASH-MD5 Generate Signature"
++ },
++};
++
++
++static MV_CESA_TEST_SESSION shaTestSessions[] =
++{
++/*400*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_SHA1, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_ENCODE,
++ NULL, 0,
++ shaKey1, sizeof(shaKey1),
++ "HMAC-SHA1 Generate Signature"
++ },
++/*401*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_SHA1, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_DECODE,
++ NULL, 0,
++ shaKey1, sizeof(shaKey1),
++ "HMAC-SHA1 Verify Signature"
++ },
++/*402*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_SHA1, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_ENCODE,
++ NULL, 0,
++ shaKey2, sizeof(shaKey2),
++ "HMAC-SHA1 Generate Signature"
++ },
++/*403*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_SHA1, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_DECODE,
++ NULL, 0,
++ shaKey2, sizeof(shaKey2),
++ "HMAC-SHA1 Verify Signature"
++ },
++/*404*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_SHA1, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_ENCODE,
++ NULL, 0,
++ shaKey4, sizeof(shaKey4),
++ "HMAC-SHA1 Generate Signature"
++ },
++/*405*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_SHA1, MV_CESA_MAC_ONLY,
++ MV_CESA_DIR_ENCODE,
++ NULL, 0,
++ NULL, 0,
++ "HASH-SHA1 Generate Signature"
++ },
++};
++
++static MV_CESA_TEST_SESSION combinedTestSessions[] =
++{
++/*500*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_MD5, MV_CESA_CRYPTO_THEN_MAC,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey1, MV_CESA_DES_KEY_LENGTH,
++ mdKey4, sizeof(mdKey4),
++ "DES + MD5 encode"
++ },
++/*501*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_SHA1, MV_CESA_CRYPTO_THEN_MAC,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey1, MV_CESA_DES_KEY_LENGTH,
++ shaKey4, sizeof(shaKey4),
++ "DES + SHA1 encode"
++ },
++/*502*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_MD5, MV_CESA_CRYPTO_THEN_MAC,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]),
++ mdKey4, sizeof(mdKey4),
++ "3DES + MD5 encode"
++ },
++/*503*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_SHA1, MV_CESA_CRYPTO_THEN_MAC,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]),
++ shaKey4, sizeof(shaKey4),
++ "3DES + SHA1 encode"
++ },
++/*504*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_HMAC_MD5, MV_CESA_CRYPTO_THEN_MAC,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]),
++ mdKey4, sizeof(mdKey4),
++ "3DES CBC + MD5 encode"
++ },
++/*505*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_HMAC_SHA1, MV_CESA_CRYPTO_THEN_MAC,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]),
++ shaKey4, sizeof(shaKey4),
++ "3DES CBC + SHA1 encode"
++ },
++/*506*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_HMAC_MD5, MV_CESA_CRYPTO_THEN_MAC,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey5, sizeof(cryptoKey5)/sizeof(cryptoKey5[0]),
++ mdKey4, sizeof(mdKey4),
++ "AES-128 CBC + MD5 encode"
++ },
++/*507*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_CBC,
++ MV_CESA_MAC_HMAC_SHA1, MV_CESA_CRYPTO_THEN_MAC,
++ MV_CESA_DIR_ENCODE,
++ cryptoKey5, sizeof(cryptoKey5)/sizeof(cryptoKey5[0]),
++ shaKey4, sizeof(shaKey4),
++ "AES-128 CBC + SHA1 encode"
++ },
++/*508*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB,
++ MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_THEN_CRYPTO,
++ MV_CESA_DIR_DECODE,
++ cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]),
++ mdKey4, sizeof(mdKey4),
++ "HMAC-MD5 + 3DES decode"
++ },
++};
++
++
++static MV_CESA_TEST_DB_ENTRY cesaTestsDB[MAX_TEST_TYPE+1] =
++{
++ { desTestSessions, sizeof(desTestSessions)/sizeof(desTestSessions[0]) },
++ { tripleDesTestSessions, sizeof(tripleDesTestSessions)/sizeof(tripleDesTestSessions[0]) },
++ { aesTestSessions, sizeof(aesTestSessions)/sizeof(aesTestSessions[0]) },
++ { md5TestSessions, sizeof(md5TestSessions)/sizeof(md5TestSessions[0]) },
++ { shaTestSessions, sizeof(shaTestSessions)/sizeof(shaTestSessions[0]) },
++ { combinedTestSessions, sizeof(combinedTestSessions)/sizeof(combinedTestSessions[0]) },
++ { NULL, 0 }
++};
++
++
++char cesaNullPlainHexText[] = "000000000000000000000000000000000000000000000000";
++
++char cesaPlainAsciiText[] = "Now is the time for all ";
++char cesaPlainHexEbc[] = "4e6f77206973207468652074696d6520666f7220616c6c20";
++char cesaCipherHexEcb[] = "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53";
++char cesaPlainHexCbc[] = "1234567890abcdef4e6f77206973207468652074696d6520666f7220616c6c20";
++char cesaCipherHexCbc[] = "1234567890abcdefe5c7cdde872bf27c43e934008c389c0f683788499a7c05f6";
++
++char cesaAesPlainHexEcb[] = "000102030405060708090a0b0c0d0e0f";
++char cesaAes128cipherHexEcb[] = "0a940bb5416ef045f1c39458c653ea5a";
++char cesaAes192cipherHexEcb[] = "0060bffe46834bb8da5cf9a61ff220ae";
++char cesaAes256cipherHexEcb[] = "5a6e045708fb7196f02e553d02c3a692";
++
++char cesaAsciiStr1[] = "Hi There";
++char cesaDataHexStr1[] = "4869205468657265";
++char cesaHmacMd5digestHex1[] = "9294727a3638bb1c13f48ef8158bfc9d";
++char cesaHmacSha1digestHex1[] = "b617318655057264e28bc0b6fb378c8ef146be00";
++char cesaDataAndMd5digest1[] = "48692054686572659294727a3638bb1c13f48ef8158bfc9d";
++char cesaDataAndSha1digest1[] = "4869205468657265b617318655057264e28bc0b6fb378c8ef146be00";
++
++char cesaAesPlainText[] = "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
++ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
++ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
++ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf";
++
++char cesaAes128CipherCbc[] = "c30e32ffedc0774e6aff6af0869f71aa"
++ "0f3af07a9a31a9c684db207eb0ef8e4e"
++ "35907aa632c3ffdf868bb7b29d3d46ad"
++ "83ce9f9a102ee99d49a53e87f4c3da55";
++
++char cesaAesIvPlainText[] = "8ce82eefbea0da3c44699ed7db51b7d9"
++ "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
++ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
++ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
++ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf";
++
++char cesaAes128IvCipherCbc[] = "8ce82eefbea0da3c44699ed7db51b7d9"
++ "c30e32ffedc0774e6aff6af0869f71aa"
++ "0f3af07a9a31a9c684db207eb0ef8e4e"
++ "35907aa632c3ffdf868bb7b29d3d46ad"
++ "83ce9f9a102ee99d49a53e87f4c3da55";
++
++char cesaAesCtrPlain[] = "00E0017B27777F3F4A1786F000000001"
++ "000102030405060708090A0B0C0D0E0F"
++ "101112131415161718191A1B1C1D1E1F"
++ "20212223";
++
++char cesaAesCtrCipher[] = "00E0017B27777F3F4A1786F000000001"
++ "C1CF48A89F2FFDD9CF4652E9EFDB72D7"
++ "4540A42BDE6D7836D59A5CEAAEF31053"
++ "25B2072F";
++
++
++
++/* Input cesaHmacHex3 is '0xdd' repeated 50 times */
++char cesaHmacMd5digestHex3[] = "56be34521d144c88dbb8c733f0e8b3f6";
++char cesaHmacSha1digestHex3[] = "125d7342b9ac11cd91a39af48aa17b4f63f175d3";
++char cesaDataHexStr3[50*2+1] = "";
++char cesaDataAndMd5digest3[sizeof(cesaDataHexStr3)+sizeof(cesaHmacMd5digestHex3)+8*2+1] = "";
++char cesaDataAndSha1digest3[sizeof(cesaDataHexStr3)+sizeof(cesaHmacSha1digestHex3)+8*2+1] = "";
++
++/* Ascii string is "abc" */
++char hashHexStr3[] = "616263";
++char hashMd5digest3[] = "900150983cd24fb0d6963f7d28e17f72";
++char hashSha1digest3[] = "a9993e364706816aba3e25717850c26c9cd0d89d";
++
++char hashHexStr80[] = "31323334353637383930"
++ "31323334353637383930"
++ "31323334353637383930"
++ "31323334353637383930"
++ "31323334353637383930"
++ "31323334353637383930"
++ "31323334353637383930"
++ "31323334353637383930";
++
++char hashMd5digest80[] = "57edf4a22be3c955ac49da2e2107b67a";
++
++char tripleDesThenMd5digest80[] = "b7726a03aad490bd6c5a452a89a1b271";
++char tripleDesThenSha1digest80[] = "b2ddeaca91030eab5b95a234ef2c0f6e738ff883";
++
++char cbc3desThenMd5digest80[] = "6f463057e1a90e0e91ae505b527bcec0";
++char cbc3desThenSha1digest80[] = "1b002ed050be743aa98860cf35659646bb8efcc0";
++
++char cbcAes128ThenMd5digest80[] = "6b6e863ac5a71d15e3e9b1c86c9ba05f";
++char cbcAes128ThenSha1digest80[] = "13558472d1fc1c90dffec6e5136c7203452d509b";
++
++
++static MV_CESA_TEST_CASE cesaTestCases[] =
++{
++ /* plainHexStr cipherHexStr IV crypto mac digest */
++ /* Length Length Offset */
++ /*0*/ { NULL, NULL, NULL, 0, 0, -1 },
++ /*1*/ { cesaPlainHexEbc, cesaCipherHexEcb, NULL, 24, 0, -1 },
++ /*2*/ { cesaPlainHexCbc, cesaCipherHexCbc, NULL, 24, 0, -1 },
++ /*3*/ { cesaAesPlainHexEcb, cesaAes128cipherHexEcb, NULL, 16, 0, -1 },
++ /*4*/ { cesaAesPlainHexEcb, cesaAes192cipherHexEcb, NULL, 16, 0, -1 },
++ /*5*/ { cesaAesPlainHexEcb, cesaAes256cipherHexEcb, NULL, 16, 0, -1 },
++ /*6*/ { cesaDataHexStr1, cesaHmacMd5digestHex1, NULL, 0, 8, -1 },
++ /*7*/ { NULL, cesaDataAndMd5digest1, NULL, 0, 8, -1 },
++ /*8*/ { cesaDataHexStr3, cesaHmacMd5digestHex3, NULL, 0, 50, -1 },
++ /*9*/ { NULL, cesaDataAndMd5digest3, NULL, 0, 50, -1 },
++/*10*/ { cesaAesPlainText, cesaAes128IvCipherCbc, iv5, 64, 0, -1 },
++/*11*/ { cesaDataHexStr1, cesaHmacSha1digestHex1, NULL, 0, 8, -1 },
++/*12*/ { NULL, cesaDataAndSha1digest1, NULL, 0, 8, -1 },
++/*13*/ { cesaDataHexStr3, cesaHmacSha1digestHex3, NULL, 0, 50, -1 },
++/*14*/ { NULL, cesaDataAndSha1digest3, NULL, 0, 50, -1 },
++/*15*/ { hashHexStr3, hashMd5digest3, NULL, 0, 3, -1 },
++/*16*/ { hashHexStr3, hashSha1digest3, NULL, 0, 3, -1 },
++/*17*/ { hashHexStr80, tripleDesThenMd5digest80, NULL, 80, 80, -1 },
++/*18*/ { hashHexStr80, tripleDesThenSha1digest80, NULL, 80, 80, -1 },
++/*19*/ { hashHexStr80, cbc3desThenMd5digest80, iv1, 80, 80, -1 },
++/*20*/ { hashHexStr80, cbc3desThenSha1digest80, iv1, 80, 80, -1 },
++/*21*/ { hashHexStr80, cbcAes128ThenMd5digest80, iv5, 80, 80, -1 },
++/*22*/ { hashHexStr80, cbcAes128ThenSha1digest80, iv5, 80, 80, -1 },
++/*23*/ { cesaAesCtrPlain, cesaAesCtrCipher, NULL, 36, 0, -1 },
++/*24*/ { cesaAesIvPlainText, cesaAes128IvCipherCbc, NULL, 64, 0, -1 },
++/*25*/ { plain3des1, cipher3des1, NULL, 0, 0, -1 },
++/*26*/ { plain3des2, cipher3desCbc2, iv3des2,0, 0, -1 },
++/*27*/ { plain3des3, cipher3desCbc3, iv3des3,0, 0, -1 },
++};
++
++
++/* Key = 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
++ * 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
++ * Input 0xdd repeated "size" times
++ */
++static MV_CESA_SIZE_TEST mdMultiSizeTest302[] =
++{
++ { 80, "7a031a640c14a4872814930b1ef3a5b2" },
++ { 512, "5488e6c5a14dc72a79f28312ca5b939b" },
++ { 1000, "d00814f586a8b78a05724239d2531821" },
++ { 1001, "bf07df7b7f49d3f5b5ecacd4e9e63281" },
++ { 1002, "1ed4a1a802e87817a819d4e37bb4d0f7" },
++ { 1003, "5972ab64a4f265ee371dac2f2f137f90" },
++ { 1004, "71f95e7ec3aa7df2548e90898abdb28e" },
++ { 1005, "e082790b4857fcfc266e92e59e608814" },
++ { 1006, "9500f02fd8ac7fde8b10e4fece9a920d" },
++ { 1336, "e42edcce57d0b75b01aa09d71427948b" },
++ { 1344, "bb5454ada0deb49ba0a97ffd60f57071" },
++ { 1399, "0f44d793e744b24d53f44f295082ee8c" },
++ { 1400, "359de8a03a9b707928c6c60e0e8d79f1" },
++ { 1401, "e913858b484cbe2b384099ea88d8855b" },
++ { 1402, "d9848a164af53620e0540c1d7d87629e" },
++ { 1403, "0c9ee1c2c9ef45e9b625c26cbaf3e822" },
++ { 1404, "12edd4f609416e3c936170360561b064" },
++ { 1405, "7fc912718a05446395345009132bf562" },
++ { 1406, "882f17425e579ff0d85a91a59f308aa0" },
++ { 1407, "005cae408630a2fb5db82ad9db7e59da" },
++ { 1408, "64655f8b404b3fea7a3e3e609bc5088f" },
++ { 1409, "4a145284a7f74e01b6bb1a0ec6a0dd80" },
++ { 2048, "67caf64475650732def374ebb8bde3fd" },
++ { 2049, "6c84f11f472825f7e6cd125c2981884b" },
++ { 2050, "8999586754a73a99efbe4dbad2816d41" },
++ { 2051, "ba6946b610e098d286bc81091659dfff" },
++ { 2052, "d0afa01c92d4d13def2b024f36faed83" },
++ { 3072, "61d8beac61806afa2585d74a9a0e6974" },
++ { 3074, "f6501a28dcc24d1e4770505c51a87ed3" },
++ { 3075, "ea4a6929be67e33e61ff475369248b73" },
++ { 4048, "aa8c4d68f282a07e7385acdfa69f4bed" },
++ { 4052, "afb5ed2c0e1d430ea59e59ed5ed6b18a" },
++ { 4058, "9e8553f9bdd43aebe0bd729f0e600c99" },
++ { 6144, "f628f3e5d183fe5cdd3a5abee39cf872" },
++ { 6150, "89a3efcea9a2f25f919168ad4a1fd292" },
++ { 6400, "cdd176b7fb747873efa4da5e32bdf88f" },
++ { 6528, "b1d707b027354aca152c45ee559ccd3f" },
++ { 8192, "c600ea4429ac47f9941f09182166e51a" },
++ {16384, "16e8754bfbeb4c649218422792267a37" },
++ {18432, "0fd0607521b0aa8b52219cfbe215f63e" },
++ { 0, NULL },
++};
++
++/* Key = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
++ * InputHexStr = "31323334353637383930" (ASCII = "1234567890")
++ */
++static MV_CESA_SIZE_TEST mdMultiSizeTest304[] =
++{
++ { 80, "a456c4723fee6068530af5a2afa71627" },
++ { 512, "f85c2a2344f5de68b432208ad13e5794" },
++ { 1000, "35464d6821fd4a293a41eb84e274c8c5" },
++ { 1001, "c08eedbdce60cceb54bc2d732bb32c8b" },
++ { 1002, "5664f71800c011cc311cb6943339c1b8" },
++ { 1003, "779c723b044c585dc7802b13e8501bdc" },
++ { 1004, "55e500766a2c307bc5c5fdd15e4cacd4" },
++ { 1005, "d5f978954f5c38529d1679d2b714f068" },
++ { 1006, "cd3efc827ce628b7281b72172693abf9" },
++ { 1336, "6f04479910785878ae6335b8d1e87edf" },
++ { 1344, "b6d27b50c2bce1ba2a8e1b5cc4324368" },
++ { 1399, "65f70a1d4c86e5eaeb0704c8a7816795" },
++ { 1400, "3394b5adc4cb3ff98843ca260a44a88a" },
++ { 1401, "3a06f3582033a66a4e57e0603ce94e74" },
++ { 1402, "e4d97f5ed51edc48abfa46eeb5c31752" },
++ { 1403, "3d05e40b080ee3bedf293cb87b7140e7" },
++ { 1404, "8cf294fc3cd153ab18dccb2a52cbf244" },
++ { 1405, "d1487bd42f6edd9b4dab316631159221" },
++ { 1406, "0527123b6bf6936cf5d369dc18c6c70f" },
++ { 1407, "3224a06639db70212a0cd1ae1fcc570a" },
++ { 1408, "a9e13335612c0356f5e2c27086e86c43" },
++ { 1409, "a86d1f37d1ed8a3552e9a4f04dceea98" },
++ { 2048, "396905c9b961cd0f6152abfb69c4449c" },
++ { 2049, "49f39bff85d9dcf059fadb89efc4a70f" },
++ { 2050, "3a2b4823bc4d0415656550226a63e34a" },
++ { 2051, "dec60580d406c782540f398ad0bcc7e0" },
++ { 2052, "32f76610a14310309eb748fe025081bf" },
++ { 3072, "45edc1a42bf9d708a621076b63b774da" },
++ { 3074, "9be1b333fe7c0c9f835fb369dc45f778" },
++ { 3075, "8c06fcac7bd0e7b7a17fd6508c09a549" },
++ { 4048, "0ddaef848184bf0ad98507a10f1e90e4" },
++ { 4052, "81976bcaeb274223983996c137875cb8" },
++ { 4058, "0b0a7a1c82bc7cbc64d8b7cd2dc2bb22" },
++ { 6144, "1c24056f52725ede2dff0d7f9fc9855f" },
++ { 6150, "b7f4b65681c4e43ee68ca466ca9ca4ec" },
++ { 6400, "443bbaab9f7331ddd4bf11b659cd43c8" },
++ { 6528, "216f44f23047cfee03a7a64f88f9a995" },
++ { 8192, "ac7a993b2cad54879dba1bde63e39097" },
++ { 8320, "55ed7be9682d6c0025b3221a62088d08" },
++ {16384, "c6c722087653b62007aea668277175e5" },
++ {18432, "f1faca8e907872c809e14ffbd85792d6" },
++ { 0, NULL },
++};
++
++/* HASH-MD5
++ * InputHexStr = "31323334353637383930" (ASCII = "1234567890")
++ * repeated "size" times
++ */
++static MV_CESA_SIZE_TEST mdMultiSizeTest305[] =
++{
++ { 80, "57edf4a22be3c955ac49da2e2107b67a" },
++ { 512, "c729ae8f0736cc377a9767a660eaa04e" },
++ { 1000, "f1257a8659eb92d36fe14c6bf3852a6a" },
++ { 1001, "f8a46fe8ea04fdc8c7de0e84042d3878" },
++ { 1002, "da188dd67bff87d58aa3c02af2d0cc0f" },
++ { 1003, "961753017feee04c9b93a8e51658a829" },
++ { 1004, "dd68c4338608dcc87807a711636bf2af" },
++ { 1005, "e338d567d3ce66bf69ada29658a8759b" },
++ { 1006, "443c9811e8b92599b0b149e8d7ec700a" },
++ { 1336, "89a98511706008ba4cbd0b4a24fa5646" },
++ { 1344, "335a919805f370b9e402a62c6fe01739" },
++ { 1399, "5d18d0eddcd84212fe28d812b5e80e3b" },
++ { 1400, "6b695c240d2dffd0dffc99459ca76db6" },
++ { 1401, "49590f61298a76719bc93a57a30136f5" },
++ { 1402, "94c2999fa3ef1910a683d69b2b8476f2" },
++ { 1403, "37073a02ab00ecba2645c57c228860db" },
++ { 1404, "1bcd06994fce28b624f0c5fdc2dcdd2b" },
++ { 1405, "11b93671a64c95079e8cf9e7cddc8b3d" },
++ { 1406, "4b6695772a4c66313fa4871017d05f36" },
++ { 1407, "d1539b97fbfda1c075624e958de19c5b" },
++ { 1408, "b801b9b69920907cd018e8063092ede9" },
++ { 1409, "b765f1406cfe78e238273ed01bbcaf7e" },
++ { 2048, "1d7e2c64ac29e2b3fb4c272844ed31f5" },
++ { 2049, "71d38fac49c6b1f4478d8d88447bcdd0" },
++ { 2050, "141c34a5592b1bebfa731e0b23d0cdba" },
++ { 2051, "c5e1853f21c59f5d6039bd13d4b380d8" },
++ { 2052, "dd44a0d128b63d4b5cccd967906472d7" },
++ { 3072, "37d158e33b21390822739d13db7b87fe" },
++ { 3074, "aef3b209d01d39d0597fe03634bbf441" },
++ { 3075, "335ffb428eabf210bada96d74d5a4012" },
++ { 4048, "2434c2b43d798d2819487a886261fc64" },
++ { 4052, "ac2fa84a8a33065b2e92e36432e861f8" },
++ { 4058, "856781f85616c341c3533d090c1e1e84" },
++ { 6144, "e5d134c652c18bf19833e115f7a82e9b" },
++ { 6150, "a09a353be7795fac2401dac5601872e6" },
++ { 6400, "08b9033ac6a1821398f50af75a2dbc83" },
++ { 6528, "3d47aa193a8540c091e7e02f779e6751" },
++ { 8192, "d3164e710c0626f6f395b38f20141cb7" },
++ { 8320, "b727589d9183ff4e8491dd24466974a3" },
++ {16384, "3f54d970793d2274d5b20d10a69938ac" },
++ {18432, "f558511dcf81985b7a1bb57fad970531" },
++ { 0, NULL },
++};
++
++
++/* Key = 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
++ * 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
++ * 0xaa, 0xaa, 0xaa, 0xaa
++ * InputHexStr = "31323334353637383930" (ASCII = "1234567890")
++ */
++static MV_CESA_SIZE_TEST shaMultiSizeTest402[] =
++{
++ { 80, "e812f370e659705a1649940d1f78cd7af18affd3" },
++ { 512, "e547f886b2c15d995ed76a8a924cb408c8080f66" },
++ { 1000, "239443194409f1a5342ecde1a092c8f3a3ed790a" },
++ { 1001, "f278ab9a102850a9f48dc4e9e6822afe2d0c52b5" },
++ { 1002, "8bcc667df5ab6ece988b3af361d09747c77f4e72" },
++ { 1003, "0fae6046c7dc1d3e356b25af836f6077a363f338" },
++ { 1004, "0ea48401cc92ae6bc92ae76685269cb0167fbe1a" },
++ { 1005, "ecbcd7c879b295bafcd8766cbeac58cc371e31d1" },
++ { 1006, "eb4a4a3d07d1e9a15e6f1ab8a9c47f243e27324c" },
++ { 1336, "f5950ee1d77c10e9011d2149699c9366fe52529c" },
++ { 1344, "b04263604a63c351b0b3b9cf1785b4bdba6c8838" },
++ { 1399, "8cb1cff61d5b784045974a2fc69386e3b8d24218" },
++ { 1400, "9bb2f3fcbeddb2b90f0be797cd647334a2816d51" },
++ { 1401, "23ae462a7a0cb440f7445791079a5d75a535dd33" },
++ { 1402, "832974b524a4d3f9cc2f45a3cabf5ccef65cd2aa" },
++ { 1403, "d1c683742fe404c3c20d5704a5430e7832a7ec95" },
++ { 1404, "867c79042e64f310628e219d8b85594cd0c7adc3" },
++ { 1405, "c9d81d49d13d94358f56ccfd61af02b36c69f7c3" },
++ { 1406, "0df43daab2786172f9b8d07d61f14a070cf1287a" },
++ { 1407, "0fd8f3ad7f169534b274d4c66bbddd89f759e391" },
++ { 1408, "3987511182b18473a564436003139b808fa46343" },
++ { 1409, "ef667e063c9e9f539a8987a8d0bd3066ee85d901" },
++ { 2048, "921109c99f3fedaca21727156d5f2b4460175327" },
++ { 2049, "47188600dd165eb45f27c27196d3c46f4f042c1b" },
++ { 2050, "8831939904009338de10e7fa670847041387807d" },
++ { 2051, "2f8ebb5db2997d614e767be1050366f3641e7520" },
++ { 2052, "669e51cd730dae158d3bef8adba075bd95a0d011" },
++ { 3072, "cfee66cfd83abc8451af3c96c6b35a41cc6c55f5" },
++ { 3074, "216ea26f02976a261b7d21a4dd3085157bedfabd" },
++ { 3075, "bd612ebba021fd8e012b14c3bd60c8c5161fabc0" },
++ { 4048, "c2564c1fdf2d5e9d7dde7aace2643428e90662e8" },
++ { 4052, "91ce61fe924b445dfe7b5a1dcd10a27caec16df6" },
++ { 4058, "db2a9be5ee8124f091c7ebd699266c5de223c164" },
++ { 6144, "855109903feae2ba3a7a05a326b8a171116eb368" },
++ { 6150, "37520bb3a668294d9c7b073e7e3daf8fee248a78" },
++ { 6400, "60a353c841b6d2b1a05890349dad2fa33c7536b7" },
++ { 6528, "9e53a43a69bb42d7c8522ca8bd632e421d5edb36" },
++ { 8192, "a918cb0da862eaea0a33ee0efea50243e6b4927c" },
++ { 8320, "29a5dcf55d1db29cd113fcf0572ae414f1c71329" },
++ {16384, "6fb27966138e0c8d5a0d65ace817ebd53633cee1" },
++ {18432, "ca09900d891c7c9ae2a559b10f63a217003341c1" },
++ { 0, NULL },
++};
++
++/* Key = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
++ * 0x11, 0x12, 0x13, 0x14
++ * InputHexStr = "31323334353637383930" (ASCII = "1234567890")
++ */
++static MV_CESA_SIZE_TEST shaMultiSizeTest404[] =
++{
++ { 80, "beaf20a34b06a87558d156c0949bc3957d40222e" },
++ { 512, "3353955358d886bc2940a3c7f337ff7dafb59c7b" },
++ { 1000, "8737a542c5e9b2b6244b757ebb69d5bd602a829f" },
++ { 1001, "fd9e7582d8a5d3c9fe3b923e4e6a41b07a1eb4d4" },
++ { 1002, "a146d14a6fc3c274ff600568f4d75b977989e00d" },
++ { 1003, "be22601bbc027ddef2dec97d30b3dc424fd803c5" },
++ { 1004, "3e71fe99b2fe2b7bfdf4dbf0c7f3da25d7ea35e7" },
++ { 1005, "2c422735d7295408fddd76f5e8a83a2a8da13df3" },
++ { 1006, "6d875319049314b61855101a647b9ba3313428e6" },
++ { 1336, "c1631ea80bad9dc43a180712461b65a0598c711c" },
++ { 1344, "816069bf91d34581005746e2e0283d0f9c7b7605" },
++ { 1399, "4e139866dc61cfcb8b67ca2ebd637b3a538593af" },
++ { 1400, "ff2a0f8dd2b02c5417910f6f55d33a78e081a723" },
++ { 1401, "ab00c12be62336964cbce31ae97fe2a0002984d5" },
++ { 1402, "61349e7f999f3a1acc56c3e9a5060a9c4a7b05b6" },
++ { 1403, "3edbc0f61e435bc1317fa27d840076093fb79353" },
++ { 1404, "d052c6dfdbe63d45dab23ef9893e2aa4636aca1e" },
++ { 1405, "0cc16b7388d67bf0add15a31e6e6c753cfae4987" },
++ { 1406, "c96ba7eaad74253c38c22101b558d2850b1d1b90" },
++ { 1407, "3445428a40d2c6556e7c55797ad8d323b61a48d9" },
++ { 1408, "8d6444f937a09317c89834187b8ea9b8d3a8c56b" },
++ { 1409, "c700acd3ecd19014ea2bdb4d42510c467e088475" },
++ { 2048, "ee27d2a0cb77470c2f496212dfd68b5bb7b04e4b" },
++ { 2049, "683762d7a02983b26a6d046e6451d9cd82c25932" },
++ { 2050, "0fd20f1d55a9ee18363c2a6fd54aa13aee69992f" },
++ { 2051, "86c267d8cc4bc8d59090e4f8b303da960fd228b7" },
++ { 2052, "452395ae05b3ec503eea34f86fc0832485ad97c1" },
++ { 3072, "75198e3cfd0b9bcff2dabdf8e38e6fdaa33ca49a" },
++ { 3074, "4e24785ef080141ce4aab4675986d9acea624d7c" },
++ { 3075, "3a20c5978dd637ec0e809bf84f0d9ccf30bc65bf" },
++ { 4048, "3c32da256be7a7554922bf5fed51b0d2d09e59ad" },
++ { 4052, "fff898426ea16e54325ae391a32c6c9bce4c23c0" },
++ { 4058, "c800b9e562e1c91e1310116341a3c91d37f848ec" },
++ { 6144, "d91d509d0cc4376c2d05bf9a5097717a373530e6" },
++ { 6150, "d957030e0f13c5df07d9eec298542d8f94a07f12" },
++ { 6400, "bb745313c3d7dc17b3f955e5534ad500a1082613" },
++ { 6528, "77905f80d9ca82080bbb3e5654896dabfcfd1bdb" },
++ { 8192, "5237fd9a81830c974396f99f32047586612ff3c0" },
++ { 8320, "57668e28d5f2dba0839518a11db0f6af3d7e08bf" },
++ {16384, "62e093fde467f0748087beea32e9af97d5c61241" },
++ {18432, "845fb33130c7d6ea554fd5aacb9c50cf7ccb5929" },
++ { 0, NULL },
++};
++
++/* HASH-SHA1
++ * InputHexStr = "31323334353637383930" (ASCII = "1234567890")
++ * repeated "size" times
++ */
++static MV_CESA_SIZE_TEST shaMultiSizeTest405[] =
++{
++ { 80, "50abf5706a150990a08b2c5ea40fa0e585554732" },
++ { 512, "f14516a08948fa27917a974d219741a697ba0087" },
++ { 1000, "0bd18c378d5788817eb4f1e5dc07d867efa5cbf4" },
++ { 1001, "ca29b85c35db1b8aef83c977893a11159d1b7aa2" },
++ { 1002, "d83bc973eaaedb8a31437994dabbb3304b0be086" },
++ { 1003, "2cf7bbef0acd6c00536b5c58ca470df9a3a90b6c" },
++ { 1004, "e4375d09b1223385a8a393066f8209acfd936a80" },
++ { 1005, "1029b38043e027745d019ce1d2d68e3d8b9d8f99" },
++ { 1006, "deea16dcebbd8ac137e2b984deb639b9fb5e9680" },
++ { 1336, "ea031b065fff63dcfb6a41956e4777520cdbc55d" },
++ { 1344, "b52096c6445e6c0a8355995c70dc36ae186c863c" },
++ { 1399, "cde2f6f8379870db4b32cf17471dc828a8dbff2b" },
++ { 1400, "e53ff664064bc09fe5054c650806bd42d8179518" },
++ { 1401, "d1156db5ddafcace64cdb510ff0d4af9b9a8ad64" },
++ { 1402, "34ede0e9a909dd84a2ae291539105c0507b958e1" },
++ { 1403, "a772ca3536da77e6ad3251e4f9e1234a4d7b87c0" },
++ { 1404, "29740fd2b04e7a8bfd32242db6233156ad699948" },
++ { 1405, "65b17397495b70ce4865dad93bf991b74c97cce1" },
++ { 1406, "a7ee89cd0754061fdb91af7ea6abad2c69d542e3" },
++ { 1407, "3eebf82f7420188e23d328b7ce93580b279a5715" },
++ { 1408, "e08d3363a8b9a490dfb3a4c453452b8f114deeec" },
++ { 1409, "95d74df739181a4ff30b8c39e28793a36598e924" },
++ { 2048, "aa40262509c2abf84aab0197f83187fc90056d91" },
++ { 2049, "7dec28ef105bc313bade8d9a7cdeac58b99de5ea" },
++ { 2050, "d2e30f77ec81197de20f56588a156094ecb88450" },
++ { 2051, "6b22ccc874833e96551a39da0c0edcaa0d969d92" },
++ { 2052, "f843141e57875cd669af58744bc60aa9ea59549c" },
++ { 3072, "09c5fedeaa62c132e673cc3c608a00142273d086" },
++ { 3074, "b09e95eea9c7b1b007a58accec488301901a7f3d" },
++ { 3075, "e6226b77b4ada287a8c9bbcf4ed71eec5ce632dc" },
++ { 4048, "e99394894f855821951ddddf5bfc628547435f5c" },
++ { 4052, "32d2f1af38be9cfba6cd03d55a254d0b3e1eb382" },
++ { 4058, "d906552a4f2aca3a22e1fecccbcd183d7289d0ef" },
++ { 6144, "2e7f62d35a860988e1224dc0543204af19316041" },
++ { 6150, "d6b89698ee133df46fec9d552fadc328aa5a1b51" },
++ { 6400, "dff50e90c46853988fa3a4b4ce5dda6945aae976" },
++ { 6528, "9e63ec0430b96db02d38bc78357a2f63de2ab7f8" },
++ { 8192, "971eb71ed60394d5ab5abb12e88420bdd41b5992" },
++ { 8320, "91606a31b46afeaac965cecf87297e791b211013" },
++ {16384, "547f830a5ec1f5f170ce818f156b1002cabc7569" },
++ {18432, "f16f272787f3b8d539652e4dc315af6ab4fda0ef" },
++ { 0, NULL },
++};
++
++/* CryptoKey = 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef;
++ * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
++ * InputHexStr = "31323334353637383930" (ASCII = "1234567890")
++ * Note: only sizes aligned to 3DES block size (8 bytes) allowed
++ */
++static MV_CESA_SIZE_TEST tripleDesMdMultiSizeTest502[] =
++{
++ { 64, "9586962a2aaaef28803dec2e17807a7f" },
++ { 80, "b7726a03aad490bd6c5a452a89a1b271" },
++ { 352, "f1ed9563aecc3c0d2766eb2bed3b4e4c" },
++ { 512, "0f9decb11ab40fe86f4d4d9397bc020e" },
++ { 1000, "3ba69deac12cab8ff9dff7dbd9669927" },
++ { 1336, "6cf47bf1e80e03e2c1d0945bc50d37d2" },
++ { 1344, "4be388dab21ceb3fa1b8d302e9b821f7" },
++ { 1400, "a58b79fb21dd9bfc6ec93e3b99fb0ef1" },
++ { 1408, "8bc97379fc2ac3237effcdd4f7a86528" },
++ { 2048, "1339f03ab3076f25a20bc4cba16eb5bf" },
++ { 3072, "731204d2d90c4b36ae41f5e1fb874288" },
++ { 4048, "c028d998cfda5642547b7e1ed5ea16e4" },
++ { 6144, "b1b19cd910cc51bd22992f1e59f1e068" },
++ { 6400, "44e4613496ba622deb0e7cb768135a2f" },
++ { 6528, "3b06b0a86f8db9cd67f9448dfcf10549" },
++ { 8192, "d581780b7163138a0f412be681457d82" },
++ {16384, "03b8ac05527faaf1bed03df149c65ccf" },
++ {18432, "677c8a86a41dab6c5d81b85b8fb10ff6" },
++ { 0, NULL },
++};
++
++
++/* CryptoKey = 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef;
++ * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
++ * 0x11, 0x12, 0x13, 0x14
++ * InputHexStr = "31323334353637383930" (ASCII = "1234567890")
++ * Note: only sizes aligned to 3DES block size (8 bytes) allowed
++ */
++static MV_CESA_SIZE_TEST tripleDesShaMultiSizeTest503[] =
++{
++ { 64, "44a1e9bcbfc1429630d9ea68b7a48b0427a684f2" },
++ { 80, "b2ddeaca91030eab5b95a234ef2c0f6e738ff883" },
++ { 352, "4b91864c7ff629bdff75d9726421f76705452aaf" },
++ { 512, "6dd37faceeb2aa98ba74f4242ed6734a4d546af5" },
++ { 1000, "463661c30300be512a9df40904f0757cde5f1141" },
++ { 1336, "b931f831d9034fe59c65176400b039fe9c1f44a5" },
++ { 1344, "af8866b1cd4a4887d6185bfe72470ffdfb3648e1" },
++ { 1400, "49c6caf07296d5e31d2504d088bc5b20c3ee7cdb" },
++ { 1408, "fcae8deedbc6ebf0763575dc7e9de075b448a0f4" },
++ { 2048, "edece5012146c1faa0dd10f50b183ba5d2af58ac" },
++ { 3072, "5b83625adb43a488b8d64fecf39bb766818547b7" },
++ { 4048, "d2c533678d26c970293af60f14c8279dc708bfc9" },
++ { 6144, "b8f67af4f991b08b725f969b049ebf813bfacc5c" },
++ { 6400, "d9a6c7f746ac7a60ef2edbed2841cf851c25cfb0" },
++ { 6528, "376792b8c8d18161d15579fb7829e6e3a27e9946" },
++ { 8192, "d890eabdca195b34ef8724b28360cffa92ae5655" },
++ {16384, "a167ee52639ec7bf19aee9c6e8f76667c14134b9" },
++ {18432, "e4396ab56f67296b220985a12078f4a0e365d2cc" },
++ { 0, NULL },
++};
++
++/* CryptoKey = 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef
++ * IV = 0x12345678, 0x90abcdef
++ * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
++ * InputHexStr = "31323334353637383930" (ASCII = "1234567890")
++ * Note: only sizes aligned to 3DES block size (8 bytes) allowed
++ */
++static MV_CESA_SIZE_TEST cbc3desMdMultiSizeTest504[] =
++{
++ { 64, "8d10e00802460ede0058c139ba48bd2d" },
++ { 80, "6f463057e1a90e0e91ae505b527bcec0" },
++ { 352, "4938d48bdf86aece2c6851e7c6079788" },
++ { 512, "516705d59f3cf810ebf2a13a23a7d42e" },
++ { 1000, "a5a000ee5c830e67ddc6a2d2e5644b31" },
++ { 1336, "44af60087b74ed07950088efbe3b126a" },
++ { 1344, "1f5b39e0577920af731dabbfcf6dfc2a" },
++ { 1400, "6804ea640e29b9cd39e08bc37dbce734" },
++ { 1408, "4fb436624b02516fc9d1535466574bf9" },
++ { 2048, "c909b0985c423d8d86719f701e9e83db" },
++ { 3072, "cfe0bc34ef97213ee3d3f8b10122db21" },
++ { 4048, "03ea10b5ae4ddeb20aed6af373082ed1" },
++ { 6144, "b9a0ff4f87fc14b3c2dc6f0ed0998fdf" },
++ { 6400, "6995f85d9d4985dd99e974ec7dda9dd6" },
++ { 6528, "bbbb548ce2fa3d58467f6a6a5168a0e6" },
++ { 8192, "afe101fbe745bb449ae4f50d10801456" },
++ {16384, "9741706d0b1c923340c4660ff97cacdf" },
++ {18432, "b0217becb73cb8f61fd79c7ce9d023fb" },
++ { 0, NULL },
++};
++
++
++/* CryptoKey = 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef;
++ * IV = 0x12345678, 0x90abcdef
++ * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
++ * 0x11, 0x12, 0x13, 0x14
++ * InputHexStr = "31323334353637383930" (ASCII = "1234567890")
++ * Note: only sizes aligned to 3DES block size (8 bytes) allowed
++ */
++static MV_CESA_SIZE_TEST cbc3desShaMultiSizeTest505[] =
++{
++ { 64, "409187e5bdb0be4a7754ca3747f7433dc4f01b98" },
++ { 80, "1b002ed050be743aa98860cf35659646bb8efcc0" },
++ { 352, "6cbf7ebe50fa4fa6eecc19eca23f9eae553ccfff" },
++ { 512, "cfb5253fb4bf72b743320c30c7e48c54965853b0" },
++ { 1000, "95e04e1ca2937e7c5a9aba9e42d2bcdb8a7af21f" },
++ { 1336, "3b5c1f5eee5837ebf67b83ae01405542d77a6627" },
++ { 1344, "2b3d42ab25615437f98a1ee310b81d07a02badc2" },
++ { 1400, "7f8687df7c1af44e4baf3c934b6cca5ab6bc993e" },
++ { 1408, "473a581c5f04f7527d50793c845471ac87e86430" },
++ { 2048, "e41d20cae7ebe34e6e828ed62b1e5734019037bb" },
++ { 3072, "275664afd7a561d804e6b0d204e53939cde653ae" },
++ { 4048, "0d220cc5b34aeeb46bbbd637dde6290b5a8285a3" },
++ { 6144, "cb393ddcc8b1c206060625b7d822ef9839e67bc5" },
++ { 6400, "dd3317e2a627fc04800f74a4b05bfda00fab0347" },
++ { 6528, "8a74c3b2441ab3f5a7e08895cc432566219a7c41" },
++ { 8192, "b8e6ef3a549ed0e005bd5b8b1a5fe6689e9711a7" },
++ {16384, "55f59404008276cdac0e2ba0d193af2d40eac5ce" },
++ {18432, "86ae6c4fc72369a54cce39938e2d0296cd9c6ec5" },
++ { 0, NULL },
++};
++
++
++/* CryptoKey = 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef
++ * IV = 0x12345678, 0x90abcdef
++ * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
++ * InputHexStr = "31323334353637383930" (ASCII = "1234567890")
++ * Note: only sizes aligned to AES block size (16 bytes) allowed
++ */
++static MV_CESA_SIZE_TEST cbcAes128md5multiSizeTest506[] =
++{
++ { 16, "7ca4c2ba866751598720c5c4aa0d6786" },
++ { 64, "7dba7fb988e80da609b1fea7254bced8" },
++ { 80, "6b6e863ac5a71d15e3e9b1c86c9ba05f" },
++ { 352, "a1ceb9c2e3021002400d525187a9f38c" },
++ { 512, "596c055c1c55db748379223164075641" },
++ { 1008, "f920989c02f3b3603f53c99d89492377" },
++ { 1344, "2e496b73759d77ed32ea222dbd2e7b41" },
++ { 1408, "7178c046b3a8d772efdb6a71c4991ea4" },
++ { 2048, "a917f0099c69eb94079a8421714b6aad" },
++ { 3072, "693cd5033d7f5391d3c958519fa9e934" },
++ { 4048, "139dca91bcff65b3c40771749052906b" },
++ { 6144, "428d9cef6df4fb70a6e9b6bbe4819e55" },
++ { 6400, "9c0b909e76daa811e12b1fc17000a0c4" },
++ { 6528, "ad876f6297186a7be1f1b907ed860eda" },
++ { 8192, "479cbbaca37dd3191ea1f3e8134a0ef4" },
++ {16384, "60fda559c74f91df538100c9842f2f15" },
++ {18432, "4a3eb1cba1fa45f3981270953f720c42" },
++ { 0, NULL },
++};
++
++
++/* CryptoKey = 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef,
++ * 0x01234567, 0x89abcdef;
++ * IV = 0x12345678, 0x90abcdef
++ * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
++ * 0x11, 0x12, 0x13, 0x14
++ * InputHexStr = "31323334353637383930" (ASCII = "1234567890")
++ * Note: only sizes aligned to AES block size (16 bytes) allowed
++ */
++static MV_CESA_SIZE_TEST cbcAes128sha1multiSizeTest507[] =
++{
++ { 16, "9aa8dc1c45f0946daf78057fa978759c625c1fee" },
++ { 64, "9f588fc1ede851e5f8b20256abc9979465ae2189" },
++ { 80, "13558472d1fc1c90dffec6e5136c7203452d509b" },
++ { 352, "6b93518e006cfaa1f7adb24615e7291fb0a27e06" },
++ { 512, "096874951a77fbbf333e49d80c096ee2016e09bd" },
++ { 1008, "696fc203c2e4b5ae0ec5d1db3f623c490bc6dbac" },
++ { 1344, "79bf77509935ccd3528caaac6a5eb6481f74029b" },
++ { 1408, "627f9462b95fc188e8cfa7eec15119bdc5d4fcf1" },
++ { 2048, "3d50d0c005feba92fe41502d609fced9c882b4d1" },
++ { 3072, "758807e5b983e3a91c06fb218fe0f73f77111e94" },
++ { 4048, "ca90e85242e33f005da3504416a52098d0d31fb2" },
++ { 6144, "8044c1d4fd06642dfc46990b4f18b61ef1e972cf" },
++ { 6400, "166f1f4ea57409f04feba9fb1e39af0e00bd6f43" },
++ { 6528, "0389016a39485d6e330f8b4215ddf718b404f7e9" },
++ { 8192, "6df7ee2a8b61d6f7f860ce8dbf778f0c2a5b508b" },
++ {16384, "a70a6d8dfa1f91ded621c3dbaed34162bc48783f" },
++ {18432, "8dfad627922ce15df1eed10bdbed49244efa57db" },
++ { 0, NULL },
++};
++
++
++void cesaTestPrintStatus(void);
++
++
++/*------------------------- LOCAL FUNCTIONs ---------------------------------*/
++MV_STATUS testCmd(int sid, int iter, MV_CESA_COMMAND* pCmd,
++ MV_CESA_TEST_SESSION* pTestSession, MV_U8* pIV, int ivSize);
++MV_STATUS testClose(int idx);
++MV_STATUS testOpen(int idx);
++void close_session(int sid);
++void cesaTestCheckReady(const MV_CESA_RESULT *r);
++void cesaCheckReady(MV_CESA_RESULT* r);
++void printTestResults(int idx, MV_STATUS status, int checkMode);
++void cesaLastResult(void);
++void cesaTestPrintReq(int req, int offset, int size);
++
++void cesaTestPrintStatus(void);
++void cesaTestPrintSession(int idx);
++void sizeTest(int testIdx, int iter, int checkMode);
++void multiTest(int iter, int reqSize, int checkMode);
++void oneTest(int testIdx, int caseIdx,int iter, int reqSize, int checkMode);
++void multiSizeTest(int idx, int iter, int checkMode, char* inputData);
++void cesaTest(int iter, int reqSize, int checkMode);
++void cesaOneTest(int testIdx, int caseIdx,int iter, int reqSize, int checkMode);
++void combiTest(int iter, int reqSize, int checkMode);
++void shaTest(int iter, int reqSize, int checkMode);
++void mdTest(int iter, int reqSize, int checkMode);
++void aesTest(int iter, int reqSize, int checkMode);
++void tripleDesTest(int iter, int reqSize, int checkMode);
++void desTest(int iter, int reqSize, int checkMode);
++void cesaTestStop(void);
++MV_STATUS testRun(int idx, int caseIdx, int iter,int reqSize, int checkMode);
++void cesaTestStart(int bufNum, int bufSize);
++
++
++static MV_U32 getRate(MV_U32* remainder)
++{
++ MV_U32 kBits, milliSec, rate;
++
++ milliSec = 0;
++ if( (cesaEndTicks - cesaBeginTicks) > 0)
++ {
++ milliSec = CESA_TEST_TICK_TO_MS(cesaEndTicks - cesaBeginTicks);
++ }
++ if(milliSec == 0)
++ {
++ if(remainder != NULL)
++ *remainder = 0;
++ return 0;
++ }
++
++ kBits = (cesaIteration*cesaRateSize*8)/1000;
++ rate = kBits/milliSec;
++ if(remainder != NULL)
++ *remainder = ((kBits % milliSec)*10)/milliSec;
++
++ return rate;
++}
++
++static char* extractMbuf(MV_CESA_MBUF *pMbuf,
++ int offset, int size, char* hexStr)
++{
++ mvCesaCopyFromMbuf((MV_U8*)cesaBinBuffer, pMbuf, offset, size);
++ mvBinToHex((const MV_U8*)cesaBinBuffer, hexStr, size);
++
++ return hexStr;
++}
++
++static MV_BOOL cesaCheckMbuf(MV_CESA_MBUF *pMbuf,
++ const char* hexString, int offset,
++ int checkSize)
++{
++ MV_BOOL isFailed = MV_FALSE;
++ MV_STATUS status;
++ int size = strlen(hexString)/2;
++ int checkedSize = 0;
++/*
++ mvOsPrintf("cesaCheckMbuf: pMbuf=%p, offset=%d, checkSize=%d, mBufSize=%d\n",
++ pMbuf, offset, checkSize, pMbuf->mbufSize);
++*/
++ if(pMbuf->mbufSize < (checkSize + offset))
++ {
++ mvOsPrintf("checkSize (%d) is too large: offset=%d, mbufSize=%d\n",
++ checkSize, offset, pMbuf->mbufSize);
++ return MV_TRUE;
++ }
++ status = mvCesaCopyFromMbuf((MV_U8*)cesaBinBuffer, pMbuf, offset, checkSize);
++ if(status != MV_OK)
++ {
++ mvOsPrintf("CesaTest: Can't copy %d bytes from Mbuf=%p to checkBuf=%p\n",
++ checkSize, pMbuf, cesaBinBuffer);
++ return MV_TRUE;
++ }
++/*
++ mvDebugMemDump(cesaBinBuffer, size, 1);
++*/
++ mvHexToBin(hexString, (MV_U8*)cesaExpBinBuffer, size);
++
++ /* Compare buffers */
++ while(checkSize > checkedSize)
++ {
++ size = MV_MIN(size, (checkSize - checkedSize));
++ if(memcmp(cesaExpBinBuffer, &cesaBinBuffer[checkedSize], size) != 0)
++ {
++ mvOsPrintf("CheckMbuf failed: checkSize=%d, size=%d, checkedSize=%d\n",
++ checkSize, size, checkedSize);
++ mvDebugMemDump(&cesaBinBuffer[checkedSize], size, 1);
++ mvDebugMemDump(cesaExpBinBuffer, size, 1);
++
++ isFailed = MV_TRUE;
++ break;
++ }
++ checkedSize += size;
++ }
++
++ return isFailed;
++}
++
++static MV_STATUS cesaSetMbuf(MV_CESA_MBUF *pMbuf,
++ const char* hexString,
++ int offset, int reqSize)
++{
++ MV_STATUS status = MV_OK;
++ int copySize, size = strlen(hexString)/2;
++
++ mvHexToBin(hexString, (MV_U8*)cesaBinBuffer, size);
++
++ copySize = 0;
++ while(reqSize > copySize)
++ {
++ size = MV_MIN(size, (reqSize - copySize));
++
++ status = mvCesaCopyToMbuf((MV_U8*)cesaBinBuffer, pMbuf, offset+copySize, size);
++ if(status != MV_OK)
++ {
++ mvOsPrintf("cesaSetMbuf Error: Copy %d of %d bytes to MBuf\n",
++ copySize, reqSize);
++ break;
++ }
++ copySize += size;
++ }
++ pMbuf->mbufSize = offset+copySize;
++ return status;
++}
++
++static MV_CESA_TEST_SESSION* getTestSessionDb(int idx, int* pTestIdx)
++{
++ int testIdx, dbIdx = idx/100;
++
++ if(dbIdx > MAX_TEST_TYPE)
++ {
++ mvOsPrintf("Wrong index %d - No such test type\n", idx);
++ return NULL;
++ }
++ testIdx = idx % 100;
++
++ if(testIdx >= cesaTestsDB[dbIdx].numSessions)
++ {
++ mvOsPrintf("Wrong index %d - No such test\n", idx);
++ return NULL;
++ }
++ if(pTestIdx != NULL)
++ *pTestIdx = testIdx;
++
++ return cesaTestsDB[dbIdx].pSessions;
++}
++
++/* Debug */
++void cesaTestPrintReq(int req, int offset, int size)
++{
++ MV_CESA_MBUF* pMbuf;
++
++ mvOsPrintf("cesaTestPrintReq: req=%d, offset=%d, size=%d\n",
++ req, offset, size);
++ mvDebugMemDump(cesaCmdRing, 128, 4);
++
++ pMbuf = cesaCmdRing[req].pSrc;
++ mvCesaDebugMbuf("src", pMbuf, offset,size);
++ pMbuf = cesaCmdRing[req].pDst;
++ mvCesaDebugMbuf("dst", pMbuf, offset, size);
++
++ cesaTestPrintStatus();
++}
++
++void cesaLastResult(void)
++{
++ mvOsPrintf("Last Result: ReqId = %d, SessionId = %d, rc = (%d)\n",
++ (MV_U32)cesaResult.pReqPrv, cesaResult.sessionId,
++ cesaResult.retCode);
++}
++
++void printTestResults(int idx, MV_STATUS status, int checkMode)
++{
++ int testIdx;
++ MV_CESA_TEST_SESSION* pTestSessions = getTestSessionDb(idx, &testIdx);
++
++ if(pTestSessions == NULL)
++ return;
++
++ mvOsPrintf("%-35s %4dx%-4d : ", pTestSessions[testIdx].name,
++ cesaIteration, cesaReqSize);
++ if( (status == MV_OK) &&
++ (cesaCryptoError == 0) &&
++ (cesaError == 0) &&
++ (cesaReqIdError == 0) )
++ {
++ mvOsPrintf("Passed, Rate=%3u.%u Mbps (%5u cpp)\n",
++ cesaRate, cesaRateAfterDot, cesaEndTicks - cesaBeginTicks);
++ }
++ else
++ {
++ mvOsPrintf("Failed, Status = 0x%x\n", status);
++ if(cesaCryptoError > 0)
++ mvOsPrintf("cryptoError : %d\n", cesaCryptoError);
++ if(cesaReqIdError > 0)
++ mvOsPrintf("reqIdError : %d\n", cesaReqIdError);
++ if(cesaError > 0)
++ mvOsPrintf("cesaError : %d\n", cesaError);
++ }
++ if(cesaTestIsrMissCount > 0)
++ mvOsPrintf("cesaIsrMissed : %d\n", cesaTestIsrMissCount);
++}
++
++void cesaCheckReady(MV_CESA_RESULT* r)
++{
++ int reqId;
++ MV_CESA_MBUF *pMbuf;
++ MV_BOOL isFailed;
++
++ cesaResult = *r;
++ reqId = (int)cesaResult.pReqPrv;
++ pMbuf = cesaCmdRing[reqId].pDst;
++
++/*
++ mvOsPrintf("cesaCheckReady: reqId=%d, checkOffset=%d, checkSize=%d\n",
++ reqId, cesaCheckOffset, cesaCheckSize);
++*/
++ /* Check expected reqId */
++ if(reqId != cesaExpReqId)
++ {
++ cesaReqIdError++;
++/*
++ mvOsPrintf("CESA reqId Error: cbIter=%d (%d), reqId=%d, expReqId=%d\n",
++ cesaCbIter, cesaIteration, reqId, cesaExpReqId);
++*/
++ }
++ else
++ {
++ if( (cesaCheckMode == CESA_FULL_CHECK_MODE) ||
++ (cesaCheckMode == CESA_FAST_CHECK_MODE) )
++ {
++ if(cesaResult.retCode != MV_OK)
++ {
++ cesaError++;
++
++ mvOsPrintf("CESA Error: cbIter=%d (%d), reqId=%d, rc=%d\n",
++ cesaCbIter, cesaIteration, reqId, cesaResult.retCode);
++ }
++ else
++ {
++ if( (cesaCheckSize > 0) && (cesaOutputHexStr != NULL) )
++ {
++ /* Check expected output */
++
++ isFailed = cesaCheckMbuf(pMbuf, cesaOutputHexStr, cesaCheckOffset, cesaCheckSize);
++ if(isFailed)
++ {
++ mvOsPrintf("CESA Crypto Error: cbIter=%d (%d), reqId=%d\n",
++ cesaCbIter, cesaIteration, reqId);
++
++ CESA_TEST_DEBUG_PRINT(("Error: reqId=%d, reqSize=%d, checkOffset=%d, checkSize=%d\n",
++ reqId, cesaReqSize, cesaCheckOffset, cesaCheckSize));
++
++ CESA_TEST_DEBUG_PRINT(("Output str: %s\n", cesaOutputHexStr));
++
++ CESA_TEST_DEBUG_CODE( mvCesaDebugMbuf("error", pMbuf, 0, cesaCheckOffset+cesaCheckSize) );
++
++ cesaCryptoError++;
++ }
++ }
++ }
++ }
++ }
++ if(cesaCheckMode == CESA_SHOW_CHECK_MODE)
++ {
++ extractMbuf(pMbuf, cesaCheckOffset, cesaCheckSize, cesaHexBuffer);
++ mvOsPrintf("%4d, %s\n", cesaCheckOffset, cesaHexBuffer);
++ }
++
++ cesaCbIter++;
++ if(cesaCbIter >= cesaIteration)
++ {
++ cesaCbIter = 0;
++ cesaExpReqId = 0;
++ cesaIsReady = MV_TRUE;
++
++ cesaEndTicks = CESA_TEST_TICK_GET();
++ cesaRate = getRate(&cesaRateAfterDot);
++ }
++ else
++ {
++ cesaExpReqId = reqId + 1;
++ if(cesaExpReqId == CESA_DEF_REQ_SIZE)
++ cesaExpReqId = 0;
++ }
++}
++
++
++#ifdef MV_NETBSD
++static int cesaTestReadyIsr(void *arg)
++#else
++#ifdef __KERNEL__
++static irqreturn_t cesaTestReadyIsr( int irq , void *dev_id)
++#endif
++#ifdef MV_VXWORKS
++void cesaTestReadyIsr(void)
++#endif
++#endif
++{
++ MV_U32 cause;
++ MV_STATUS status;
++ MV_CESA_RESULT result;
++
++ cesaTestIsrCount++;
++ /* Clear cause register */
++ cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
++ if( (cause & MV_CESA_CAUSE_ACC_DMA_ALL_MASK) == 0)
++ {
++ mvOsPrintf("cesaTestReadyIsr: cause=0x%x\n", cause);
++#ifdef MV_NETBSD
++ return 0;
++#else
++#ifdef __KERNEL__
++ return 1;
++#else
++ return;
++#endif
++#endif
++ }
++
++ MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0);
++
++ while(MV_TRUE)
++ {
++ /* Get Ready requests */
++ status = mvCesaReadyGet(&result);
++ if(status == MV_OK)
++ cesaCheckReady(&result);
++
++ break;
++ }
++ if( (cesaTestFull == 1) && (status != MV_BUSY) )
++ {
++ cesaTestFull = 0;
++ CESA_TEST_WAKE_UP();
++ }
++
++#ifdef __KERNEL__
++ return 1;
++#endif
++}
++
++void
++cesaTestCheckReady(const MV_CESA_RESULT *r)
++{
++ MV_CESA_RESULT result = *r;
++
++ cesaCheckReady(&result);
++
++ if (cesaTestFull == 1) {
++ cesaTestFull = 0;
++ CESA_TEST_WAKE_UP();
++ }
++}
++
++static INLINE int open_session(MV_CESA_OPEN_SESSION* pOs)
++{
++ MV_U16 sid;
++ MV_STATUS status;
++
++ status = mvCesaSessionOpen(pOs, (short*)&sid);
++ if(status != MV_OK)
++ {
++ mvOsPrintf("CesaTest: Can't open new session - status = 0x%x\n",
++ status);
++ return -1;
++ }
++
++ return (int)sid;
++}
++
++void close_session(int sid)
++{
++ MV_STATUS status;
++
++ status = mvCesaSessionClose(sid);
++ if(status != MV_OK)
++ {
++ mvOsPrintf("CesaTest: Can't close session %d - status = 0x%x\n",
++ sid, status);
++ }
++}
++
++MV_STATUS testOpen(int idx)
++{
++ MV_CESA_OPEN_SESSION os;
++ int sid, i, testIdx;
++ MV_CESA_TEST_SESSION* pTestSession;
++ MV_U16 digestSize = 0;
++
++ pTestSession = getTestSessionDb(idx, &testIdx);
++ if(pTestSession == NULL)
++ {
++ mvOsPrintf("Test %d is not exist\n", idx);
++ return MV_BAD_PARAM;
++ }
++ pTestSession = &pTestSession[testIdx];
++
++ if(pTestSession->sid != -1)
++ {
++ mvOsPrintf("Session for test %d already created: sid=%d\n",
++ idx, pTestSession->sid);
++ return MV_OK;
++ }
++
++ os.cryptoAlgorithm = pTestSession->cryptoAlgorithm;
++ os.macMode = pTestSession->macAlgorithm;
++ switch(os.macMode)
++ {
++ case MV_CESA_MAC_MD5:
++ case MV_CESA_MAC_HMAC_MD5:
++ digestSize = MV_CESA_MD5_DIGEST_SIZE;
++ break;
++
++ case MV_CESA_MAC_SHA1:
++ case MV_CESA_MAC_HMAC_SHA1:
++ digestSize = MV_CESA_SHA1_DIGEST_SIZE;
++ break;
++
++ case MV_CESA_MAC_NULL:
++ digestSize = 0;
++ }
++ os.cryptoMode = pTestSession->cryptoMode;
++ os.direction = pTestSession->direction;
++ os.operation = pTestSession->operation;
++
++ for(i=0; i<pTestSession->cryptoKeySize; i++)
++ os.cryptoKey[i] = pTestSession->pCryptoKey[i];
++
++ os.cryptoKeyLength = pTestSession->cryptoKeySize;
++
++ for(i=0; i<pTestSession->macKeySize; i++)
++ os.macKey[i] = pTestSession->pMacKey[i];
++
++ os.macKeyLength = pTestSession->macKeySize;
++ os.digestSize = digestSize;
++
++ sid = open_session(&os);
++ if(sid == -1)
++ {
++ mvOsPrintf("Can't open session for test %d: rc=0x%x\n",
++ idx, cesaResult.retCode);
++ return cesaResult.retCode;
++ }
++ CESA_TEST_DEBUG_PRINT(("Opened session: sid = %d\n", sid));
++ pTestSession->sid = sid;
++ return MV_OK;
++}
++
++MV_STATUS testClose(int idx)
++{
++ int testIdx;
++ MV_CESA_TEST_SESSION* pTestSession;
++
++ pTestSession = getTestSessionDb(idx, &testIdx);
++ if(pTestSession == NULL)
++ {
++ mvOsPrintf("Test %d is not exist\n", idx);
++ return MV_BAD_PARAM;
++ }
++ pTestSession = &pTestSession[testIdx];
++
++ if(pTestSession->sid == -1)
++ {
++ mvOsPrintf("Test session %d is not opened\n", idx);
++ return MV_NO_SUCH;
++ }
++
++ close_session(pTestSession->sid);
++ pTestSession->sid = -1;
++
++ return MV_OK;
++}
++
++MV_STATUS testCmd(int sid, int iter, MV_CESA_COMMAND* pCmd,
++ MV_CESA_TEST_SESSION* pTestSession, MV_U8* pIV, int ivSize)
++{
++ int cmdReqId = 0;
++ int i;
++ MV_STATUS rc = MV_OK;
++ char ivZeroHex[] = "0000";
++
++ if(iter == 0)
++ iter = CESA_DEF_ITER_NUM;
++
++ if(pCmd == NULL)
++ {
++ mvOsPrintf("testCmd failed: pCmd=NULL\n");
++ return MV_BAD_PARAM;
++ }
++ pCmd->sessionId = sid;
++
++ cesaCryptoError = 0;
++ cesaReqIdError = 0;
++ cesaError = 0;
++ cesaTestIsrMissCount = 0;
++ cesaIsReady = MV_FALSE;
++ cesaIteration = iter;
++
++ if(cesaInputHexStr == NULL)
++ cesaInputHexStr = cesaPlainHexEbc;
++
++ for(i=0; i<CESA_DEF_REQ_SIZE; i++)
++ {
++ pCmd->pSrc = (MV_CESA_MBUF*)(cesaCmdRing[i].pSrc);
++ if(pIV != NULL)
++ {
++ /* If IV from SA - set IV in Source buffer to zeros */
++ cesaSetMbuf(pCmd->pSrc, ivZeroHex, 0, pCmd->cryptoOffset);
++ cesaSetMbuf(pCmd->pSrc, cesaInputHexStr, pCmd->cryptoOffset,
++ (cesaReqSize - pCmd->cryptoOffset));
++ }
++ else
++ {
++ cesaSetMbuf(pCmd->pSrc, cesaInputHexStr, 0, cesaReqSize);
++ }
++ pCmd->pDst = (MV_CESA_MBUF*)(cesaCmdRing[i].pDst);
++ cesaSetMbuf(pCmd->pDst, cesaNullPlainHexText, 0, cesaReqSize);
++
++ memcpy(&cesaCmdRing[i], pCmd, sizeof(*pCmd));
++ }
++
++ if(cesaCheckMode == CESA_SW_SHOW_CHECK_MODE)
++ {
++ MV_U8 pDigest[MV_CESA_MAX_DIGEST_SIZE];
++
++ if(pTestSession->macAlgorithm == MV_CESA_MAC_MD5)
++ {
++ mvMD5(pCmd->pSrc->pFrags[0].bufVirtPtr, pCmd->macLength, pDigest);
++ mvOsPrintf("SW HASH_MD5: reqSize=%d, macLength=%d\n",
++ cesaReqSize, pCmd->macLength);
++ mvDebugMemDump(pDigest, MV_CESA_MD5_DIGEST_SIZE, 1);
++ return MV_OK;
++ }
++ if(pTestSession->macAlgorithm == MV_CESA_MAC_SHA1)
++ {
++ mvSHA1(pCmd->pSrc->pFrags[0].bufVirtPtr, pCmd->macLength, pDigest);
++ mvOsPrintf("SW HASH_SHA1: reqSize=%d, macLength=%d\n",
++ cesaReqSize, pCmd->macLength);
++ mvDebugMemDump(pDigest, MV_CESA_SHA1_DIGEST_SIZE, 1);
++ return MV_OK;
++ }
++ }
++
++ cesaBeginTicks = CESA_TEST_TICK_GET();
++ CESA_TEST_DEBUG_CODE( memset(cesaTestTrace, 0, sizeof(cesaTestTrace));
++ cesaTestTraceIdx = 0;
++ );
++
++ if(cesaCheckMode == CESA_SW_NULL_CHECK_MODE)
++ {
++ volatile MV_U8 pDigest[MV_CESA_MAX_DIGEST_SIZE];
++
++ for(i=0; i<iter; i++)
++ {
++ if(pTestSession->macAlgorithm == MV_CESA_MAC_MD5)
++ {
++ mvMD5(pCmd->pSrc->pFrags[0].bufVirtPtr, pCmd->macLength, (unsigned char*)pDigest);
++ }
++ if(pTestSession->macAlgorithm == MV_CESA_MAC_SHA1)
++ {
++ mvSHA1(pCmd->pSrc->pFrags[0].bufVirtPtr, pCmd->macLength, (MV_U8 *)pDigest);
++ }
++ }
++ cesaEndTicks = CESA_TEST_TICK_GET();
++ cesaRate = getRate(&cesaRateAfterDot);
++ cesaIsReady = MV_TRUE;
++
++ return MV_OK;
++ }
++
++ /*cesaTestIsrCount = 0;*/
++ /*mvCesaDebugStatsClear();*/
++
++#ifndef MV_NETBSD
++ MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0);
++#endif
++
++ for(i=0; i<iter; i++)
++ {
++ unsigned long flags;
++
++ pCmd = &cesaCmdRing[cmdReqId];
++ pCmd->pReqPrv = (void*)cmdReqId;
++
++ CESA_TEST_LOCK(flags);
++
++ rc = mvCesaAction(pCmd);
++ if(rc == MV_NO_RESOURCE)
++ cesaTestFull = 1;
++
++ CESA_TEST_UNLOCK(flags);
++
++ if(rc == MV_NO_RESOURCE)
++ {
++ CESA_TEST_LOCK(flags);
++ CESA_TEST_WAIT( (cesaTestFull == 0), 100);
++ CESA_TEST_UNLOCK(flags);
++ if(cesaTestFull == 1)
++ {
++ mvOsPrintf("CESA Test timeout: i=%d, iter=%d, cesaTestFull=%d\n",
++ i, iter, cesaTestFull);
++ cesaTestFull = 0;
++ return MV_TIMEOUT;
++ }
++
++ CESA_TEST_LOCK(flags);
++
++ rc = mvCesaAction(pCmd);
++
++ CESA_TEST_UNLOCK(flags);
++ }
++ if( (rc != MV_OK) && (rc != MV_NO_MORE) )
++ {
++ mvOsPrintf("mvCesaAction failed: rc=%d\n", rc);
++ return rc;
++ }
++
++ cmdReqId++;
++ if(cmdReqId >= CESA_DEF_REQ_SIZE)
++ cmdReqId = 0;
++
++#ifdef MV_LINUX
++ /* Reschedule each 16 requests */
++ if( (i & 0xF) == 0)
++ schedule();
++#endif
++ }
++ return MV_OK;
++}
++
++void cesaTestStart(int bufNum, int bufSize)
++{
++ int i, j, idx;
++ MV_CESA_MBUF *pMbufSrc, *pMbufDst;
++ MV_BUF_INFO *pFragsSrc, *pFragsDst;
++ char *pBuf;
++#ifndef MV_NETBSD
++ int numOfSessions, queueDepth;
++ char *pSram;
++ MV_STATUS status;
++ MV_CPU_DEC_WIN addrDecWin;
++#endif
++
++ cesaCmdRing = mvOsMalloc(sizeof(MV_CESA_COMMAND) * CESA_DEF_REQ_SIZE);
++ if(cesaCmdRing == NULL)
++ {
++ mvOsPrintf("testStart: Can't allocate %ld bytes of memory\n",
++ sizeof(MV_CESA_COMMAND) * CESA_DEF_REQ_SIZE);
++ return;
++ }
++ memset(cesaCmdRing, 0, sizeof(MV_CESA_COMMAND) * CESA_DEF_REQ_SIZE);
++
++ if(bufNum == 0)
++ bufNum = CESA_DEF_BUF_NUM;
++
++ if(bufSize == 0)
++ bufSize = CESA_DEF_BUF_SIZE;
++
++ cesaBufNum = bufNum;
++ cesaBufSize = bufSize;
++ mvOsPrintf("CESA test started: bufNum = %d, bufSize = %d\n",
++ bufNum, bufSize);
++
++ cesaHexBuffer = mvOsMalloc(2*bufNum*bufSize);
++ if(cesaHexBuffer == NULL)
++ {
++ mvOsPrintf("testStart: Can't malloc %d bytes for cesaHexBuffer.\n",
++ 2*bufNum*bufSize);
++ return;
++ }
++ memset(cesaHexBuffer, 0, (2*bufNum*bufSize));
++
++ cesaBinBuffer = mvOsMalloc(bufNum*bufSize);
++ if(cesaBinBuffer == NULL)
++ {
++ mvOsPrintf("testStart: Can't malloc %d bytes for cesaBinBuffer\n",
++ bufNum*bufSize);
++ return;
++ }
++ memset(cesaBinBuffer, 0, (bufNum*bufSize));
++
++ cesaExpBinBuffer = mvOsMalloc(bufNum*bufSize);
++ if(cesaExpBinBuffer == NULL)
++ {
++ mvOsPrintf("testStart: Can't malloc %d bytes for cesaExpBinBuffer\n",
++ bufNum*bufSize);
++ return;
++ }
++ memset(cesaExpBinBuffer, 0, (bufNum*bufSize));
++
++ CESA_TEST_WAIT_INIT();
++
++ pMbufSrc = mvOsMalloc(sizeof(MV_CESA_MBUF) * CESA_DEF_REQ_SIZE);
++ pFragsSrc = mvOsMalloc(sizeof(MV_BUF_INFO) * bufNum * CESA_DEF_REQ_SIZE);
++
++ pMbufDst = mvOsMalloc(sizeof(MV_CESA_MBUF) * CESA_DEF_REQ_SIZE);
++ pFragsDst = mvOsMalloc(sizeof(MV_BUF_INFO) * bufNum * CESA_DEF_REQ_SIZE);
++
++ if( (pMbufSrc == NULL) || (pFragsSrc == NULL) ||
++ (pMbufDst == NULL) || (pFragsDst == NULL) )
++ {
++ mvOsPrintf("testStart: Can't malloc Src and Dst pMbuf and pFrags structures.\n");
++ /* !!!! Dima cesaTestCleanup();*/
++ return;
++ }
++
++ memset(pMbufSrc, 0, sizeof(MV_CESA_MBUF) * CESA_DEF_REQ_SIZE);
++ memset(pFragsSrc, 0, sizeof(MV_BUF_INFO) * bufNum * CESA_DEF_REQ_SIZE);
++
++ memset(pMbufDst, 0, sizeof(MV_CESA_MBUF) * CESA_DEF_REQ_SIZE);
++ memset(pFragsDst, 0, sizeof(MV_BUF_INFO) * bufNum * CESA_DEF_REQ_SIZE);
++
++ mvOsPrintf("Cesa Test Start: pMbufSrc=%p, pFragsSrc=%p, pMbufDst=%p, pFragsDst=%p\n",
++ pMbufSrc, pFragsSrc, pMbufDst, pFragsDst);
++
++ idx = 0;
++ for(i=0; i<CESA_DEF_REQ_SIZE; i++)
++ {
++ pBuf = mvOsIoCachedMalloc(cesaTestOSHandle,bufSize * bufNum * 2,
++ &cesaReqBufs[i].bufPhysAddr,
++ &cesaReqBufs[i].memHandle);
++ if(pBuf == NULL)
++ {
++ mvOsPrintf("testStart: Can't malloc %d bytes for pBuf\n",
++ bufSize * bufNum * 2);
++ return;
++ }
++
++ memset(pBuf, 0, bufSize * bufNum * 2);
++ mvOsCacheFlush(cesaTestOSHandle,pBuf, bufSize * bufNum * 2);
++ if(pBuf == NULL)
++ {
++ mvOsPrintf("cesaTestStart: Can't allocate %d bytes for req_%d buffers\n",
++ bufSize * bufNum * 2, i);
++ return;
++ }
++
++ cesaReqBufs[i].bufVirtPtr = (MV_U8*)pBuf;
++ cesaReqBufs[i].bufSize = bufSize * bufNum * 2;
++
++ cesaCmdRing[i].pSrc = &pMbufSrc[i];
++ cesaCmdRing[i].pSrc->pFrags = &pFragsSrc[idx];
++ cesaCmdRing[i].pSrc->numFrags = bufNum;
++ cesaCmdRing[i].pSrc->mbufSize = 0;
++
++ cesaCmdRing[i].pDst = &pMbufDst[i];
++ cesaCmdRing[i].pDst->pFrags = &pFragsDst[idx];
++ cesaCmdRing[i].pDst->numFrags = bufNum;
++ cesaCmdRing[i].pDst->mbufSize = 0;
++
++ for(j=0; j<bufNum; j++)
++ {
++ cesaCmdRing[i].pSrc->pFrags[j].bufVirtPtr = (MV_U8*)pBuf;
++ cesaCmdRing[i].pSrc->pFrags[j].bufSize = bufSize;
++ pBuf += bufSize;
++ cesaCmdRing[i].pDst->pFrags[j].bufVirtPtr = (MV_U8*)pBuf;
++ cesaCmdRing[i].pDst->pFrags[j].bufSize = bufSize;
++ pBuf += bufSize;
++ }
++ idx += bufNum;
++ }
++
++#ifndef MV_NETBSD
++ if (mvCpuIfTargetWinGet(CRYPT_ENG, &addrDecWin) == MV_OK)
++ pSram = (char*)addrDecWin.addrWin.baseLow;
++ else
++ {
++ mvOsPrintf("mvCesaInit: ERR. mvCpuIfTargetWinGet failed\n");
++ return;
++ }
++
++#ifdef MV_CESA_NO_SRAM
++ pSram = mvOsMalloc(4*1024+8);
++ if(pSram == NULL)
++ {
++ mvOsPrintf("CesaTest: can't allocate %d bytes for SRAM simulation\n",
++ 4*1024+8);
++ /* !!!! Dima cesaTestCleanup();*/
++ return;
++ }
++ pSram = (MV_U8*)MV_ALIGN_UP((MV_U32)pSram, 8);
++#endif /* MV_CESA_NO_SRAM */
++
++ numOfSessions = CESA_DEF_SESSION_NUM;
++ queueDepth = CESA_DEF_REQ_SIZE - MV_CESA_MAX_CHAN;
++
++ status = mvCesaInit(numOfSessions, queueDepth, pSram, NULL);
++ if(status != MV_OK)
++ {
++ mvOsPrintf("mvCesaInit is Failed: status = 0x%x\n", status);
++ /* !!!! Dima cesaTestCleanup();*/
++ return;
++ }
++#endif /* !MV_NETBSD */
++
++ /* Prepare data for tests */
++ for(i=0; i<50; i++)
++ strcat((char*)cesaDataHexStr3, "dd");
++
++ strcpy((char*)cesaDataAndMd5digest3, cesaDataHexStr3);
++ strcpy((char*)cesaDataAndSha1digest3, cesaDataHexStr3);
++
++ /* Digest must be 8 byte aligned */
++ for(; i<56; i++)
++ {
++ strcat((char*)cesaDataAndMd5digest3, "00");
++ strcat((char*)cesaDataAndSha1digest3, "00");
++ }
++ strcat((char*)cesaDataAndMd5digest3, cesaHmacMd5digestHex3);
++ strcat((char*)cesaDataAndSha1digest3, cesaHmacSha1digestHex3);
++
++#ifndef MV_NETBSD
++ MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0);
++ MV_REG_WRITE( MV_CESA_ISR_MASK_REG, MV_CESA_CAUSE_ACC_DMA_MASK);
++#endif
++
++#ifdef MV_VXWORKS
++ {
++ MV_STATUS status;
++
++ status = intConnect((VOIDFUNCPTR *)INT_LVL_CESA, cesaTestReadyIsr, (int)NULL);
++ if (status != OK)
++ {
++ mvOsPrintf("CESA: Can't connect CESA (%d) interrupt, status=0x%x \n",
++ INT_LVL_CESA, status);
++ /* !!!! Dima cesaTestCleanup();*/
++ return;
++ }
++ cesaSemId = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE);
++ if(cesaSemId == NULL)
++ {
++ mvOsPrintf("cesaTestStart: Can't create semaphore\n");
++ return;
++ }
++ intEnable(INT_LVL_CESA);
++ }
++#endif /* MV_VXWORKS */
++
++#if !defined(MV_NETBSD) && defined(__KERNEL__)
++ if( request_irq(CESA_IRQ, cesaTestReadyIsr, (SA_INTERRUPT) , "cesa_test", NULL ) )
++ {
++ mvOsPrintf( "cannot assign irq\n" );
++ /* !!!! Dima cesaTestCleanup();*/
++ return;
++ }
++ spin_lock_init( &cesaLock );
++#endif
++}
++
++MV_STATUS testRun(int idx, int caseIdx, int iter,
++ int reqSize, int checkMode)
++{
++ int testIdx, count, sid, digestSize;
++ int blockSize;
++ MV_CESA_TEST_SESSION* pTestSession;
++ MV_CESA_COMMAND cmd;
++ MV_STATUS status;
++
++ memset(&cmd, 0, sizeof(cmd));
++
++ pTestSession = getTestSessionDb(idx, &testIdx);
++ if(pTestSession == NULL)
++ {
++ mvOsPrintf("Test %d is not exist\n", idx);
++ return MV_BAD_PARAM;
++ }
++ pTestSession = &pTestSession[testIdx];
++
++ sid = pTestSession->sid;
++ if(sid == -1)
++ {
++ mvOsPrintf("Test %d is not opened\n", idx);
++ return MV_BAD_STATE;
++ }
++ switch(pTestSession->cryptoAlgorithm)
++ {
++ case MV_CESA_CRYPTO_DES:
++ case MV_CESA_CRYPTO_3DES:
++ blockSize = MV_CESA_DES_BLOCK_SIZE;
++ break;
++
++ case MV_CESA_CRYPTO_AES:
++ blockSize = MV_CESA_AES_BLOCK_SIZE;
++ break;
++
++ case MV_CESA_CRYPTO_NULL:
++ blockSize = 0;
++ break;
++
++ default:
++ mvOsPrintf("cesaTestRun: Bad CryptoAlgorithm=%d\n",
++ pTestSession->cryptoAlgorithm);
++ return MV_BAD_PARAM;
++ }
++ switch(pTestSession->macAlgorithm)
++ {
++ case MV_CESA_MAC_MD5:
++ case MV_CESA_MAC_HMAC_MD5:
++ digestSize = MV_CESA_MD5_DIGEST_SIZE;
++ break;
++
++ case MV_CESA_MAC_SHA1:
++ case MV_CESA_MAC_HMAC_SHA1:
++ digestSize = MV_CESA_SHA1_DIGEST_SIZE;
++ break;
++ default:
++ digestSize = 0;
++ }
++
++ if(iter == 0)
++ iter = CESA_DEF_ITER_NUM;
++
++ if(pTestSession->direction == MV_CESA_DIR_ENCODE)
++ {
++ cesaOutputHexStr = cesaTestCases[caseIdx].cipherHexStr;
++ cesaInputHexStr = cesaTestCases[caseIdx].plainHexStr;
++ }
++ else
++ {
++ cesaOutputHexStr = cesaTestCases[caseIdx].plainHexStr;
++ cesaInputHexStr = cesaTestCases[caseIdx].cipherHexStr;
++ }
++
++ cmd.sessionId = sid;
++ if(checkMode == CESA_FAST_CHECK_MODE)
++ {
++ cmd.cryptoLength = cesaTestCases[caseIdx].cryptoLength;
++ cmd.macLength = cesaTestCases[caseIdx].macLength;
++ }
++ else
++ {
++ cmd.cryptoLength = reqSize;
++ cmd.macLength = reqSize;
++ }
++ cesaRateSize = cmd.cryptoLength;
++ cesaReqSize = cmd.cryptoLength;
++ cmd.cryptoOffset = 0;
++ if(pTestSession->operation != MV_CESA_MAC_ONLY)
++ {
++ if( (pTestSession->cryptoMode == MV_CESA_CRYPTO_CBC) ||
++ (pTestSession->cryptoMode == MV_CESA_CRYPTO_CTR) )
++ {
++ cmd.ivOffset = 0;
++ cmd.cryptoOffset = blockSize;
++ if(cesaTestCases[caseIdx].pCryptoIV == NULL)
++ {
++ cmd.ivFromUser = 1;
++ }
++ else
++ {
++ cmd.ivFromUser = 0;
++ mvCesaCryptoIvSet(cesaTestCases[caseIdx].pCryptoIV, blockSize);
++ }
++ cesaReqSize = cmd.cryptoOffset + cmd.cryptoLength;
++ }
++ }
++
++/*
++ mvOsPrintf("ivFromUser=%d, cryptoLength=%d, cesaReqSize=%d, cryptoOffset=%d\n",
++ cmd.ivFromUser, cmd.cryptoLength, cesaReqSize, cmd.cryptoOffset);
++*/
++ if(pTestSession->operation != MV_CESA_CRYPTO_ONLY)
++ {
++ cmd.macOffset = cmd.cryptoOffset;
++
++ if(cesaTestCases[caseIdx].digestOffset == -1)
++ {
++ cmd.digestOffset = cmd.macOffset + cmd.macLength;
++ cmd.digestOffset = MV_ALIGN_UP(cmd.digestOffset, 8);
++ }
++ else
++ {
++ cmd.digestOffset = cesaTestCases[caseIdx].digestOffset;
++ }
++ if( (cmd.digestOffset + digestSize) > cesaReqSize)
++ cesaReqSize = cmd.digestOffset + digestSize;
++ }
++
++ cesaCheckMode = checkMode;
++
++ if(checkMode == CESA_NULL_CHECK_MODE)
++ {
++ cesaCheckSize = 0;
++ cesaCheckOffset = 0;
++ }
++ else
++ {
++ if(pTestSession->operation == MV_CESA_CRYPTO_ONLY)
++ {
++ cesaCheckOffset = 0;
++ cesaCheckSize = cmd.cryptoLength;
++ }
++ else
++ {
++ cesaCheckSize = digestSize;
++ cesaCheckOffset = cmd.digestOffset;
++ }
++ }
++/*
++ mvOsPrintf("reqSize=%d, checkSize=%d, checkOffset=%d, checkMode=%d\n",
++ cesaReqSize, cesaCheckSize, cesaCheckOffset, cesaCheckMode);
++
++ mvOsPrintf("blockSize=%d, ivOffset=%d, ivFromUser=%d, crOffset=%d, crLength=%d\n",
++ blockSize, cmd.ivOffset, cmd.ivFromUser,
++ cmd.cryptoOffset, cmd.cryptoLength);
++
++ mvOsPrintf("macOffset=%d, digestOffset=%d, macLength=%d\n",
++ cmd.macOffset, cmd.digestOffset, cmd.macLength);
++*/
++ status = testCmd(sid, iter, &cmd, pTestSession,
++ cesaTestCases[caseIdx].pCryptoIV, blockSize);
++
++ if(status != MV_OK)
++ return status;
++
++ /* Wait when all callbacks is received */
++ count = 0;
++ while(cesaIsReady == MV_FALSE)
++ {
++ mvOsSleep(10);
++ count++;
++ if(count > 100)
++ {
++ mvOsPrintf("testRun: Timeout occured\n");
++ return MV_TIMEOUT;
++ }
++ }
++
++ return MV_OK;
++}
++
++
++void cesaTestStop(void)
++{
++ MV_CESA_MBUF *pMbufSrc, *pMbufDst;
++ MV_BUF_INFO *pFragsSrc, *pFragsDst;
++ int i;
++
++ /* Release all allocated memories */
++ pMbufSrc = (MV_CESA_MBUF*)(cesaCmdRing[0].pSrc);
++ pFragsSrc = cesaCmdRing[0].pSrc->pFrags;
++
++ pMbufDst = (MV_CESA_MBUF*)(cesaCmdRing[0].pDst);
++ pFragsDst = cesaCmdRing[0].pDst->pFrags;
++
++ mvOsFree(pMbufSrc);
++ mvOsFree(pMbufDst);
++ mvOsFree(pFragsSrc);
++ mvOsFree(pFragsDst);
++
++ for(i=0; i<CESA_DEF_REQ_SIZE; i++)
++ {
++ mvOsIoCachedFree(cesaTestOSHandle,cesaReqBufs[i].bufSize,
++ cesaReqBufs[i].bufPhysAddr,cesaReqBufs[i].bufVirtPtr,
++ cesaReqBufs[i].memHandle);
++ }
++ cesaDataHexStr3[0] = '\0';
++}
++
++void desTest(int iter, int reqSize, int checkMode)
++{
++ int mode, i;
++ MV_STATUS status;
++
++ mode = checkMode;
++ if(checkMode == CESA_FULL_CHECK_MODE)
++ mode = CESA_FAST_CHECK_MODE;
++ i = iter;
++ if(mode != CESA_NULL_CHECK_MODE)
++ i = 1;
++
++ testOpen(0);
++ testOpen(1);
++ testOpen(2);
++ testOpen(3);
++
++/* DES / ECB mode / Encrypt only */
++ status = testRun(0, 1, iter, reqSize, checkMode);
++ printTestResults(0, status, checkMode);
++
++/* DES / ECB mode / Decrypt only */
++ status = testRun(1, 1, iter, reqSize, checkMode);
++ printTestResults(1, status, checkMode);
++
++/* DES / CBC mode / Encrypt only */
++ status = testRun(2, 2, i, reqSize, mode);
++ printTestResults(2, status, mode);
++
++/* DES / CBC mode / Decrypt only */
++ status = testRun(3, 2, iter, reqSize, mode);
++ printTestResults(3, status, mode);
++
++ testClose(0);
++ testClose(1);
++ testClose(2);
++ testClose(3);
++}
++
++void tripleDesTest(int iter, int reqSize, int checkMode)
++{
++ int mode, i;
++ MV_STATUS status;
++
++ mode = checkMode;
++ if(checkMode == CESA_FULL_CHECK_MODE)
++ mode = CESA_FAST_CHECK_MODE;
++ i = iter;
++ if(mode != CESA_NULL_CHECK_MODE)
++ i = 1;
++
++ testOpen(100);
++ testOpen(101);
++ testOpen(102);
++ testOpen(103);
++
++/* 3DES / ECB mode / Encrypt only */
++ status = testRun(100, 1, iter, reqSize, checkMode);
++ printTestResults(100, status, checkMode);
++
++/* 3DES / ECB mode / Decrypt only */
++ status = testRun(101, 1, iter, reqSize, checkMode);
++ printTestResults(101, status, checkMode);
++
++/* 3DES / CBC mode / Encrypt only */
++ status = testRun(102, 2, i, reqSize, mode);
++ printTestResults(102, status, mode);
++
++/* 3DES / CBC mode / Decrypt only */
++ status = testRun(103, 2, iter, reqSize, mode);
++ printTestResults(103, status, mode);
++
++ testClose(100);
++ testClose(101);
++ testClose(102);
++ testClose(103);
++}
++
++void aesTest(int iter, int reqSize, int checkMode)
++{
++ MV_STATUS status;
++ int mode, i;
++
++ mode = checkMode;
++ if(checkMode == CESA_FULL_CHECK_MODE)
++ mode = CESA_FAST_CHECK_MODE;
++
++ i = iter;
++ if(mode != CESA_NULL_CHECK_MODE)
++ i = 1;
++
++ testOpen(200);
++ testOpen(201);
++ testOpen(202);
++ testOpen(203);
++ testOpen(204);
++ testOpen(205);
++ testOpen(206);
++ testOpen(207);
++ testOpen(208);
++
++/* AES-128 Encode ECB mode */
++ status = testRun(200, 3, iter, reqSize, checkMode);
++ printTestResults(200, status, checkMode);
++
++/* AES-128 Decode ECB mode */
++ status = testRun(201, 3, iter, reqSize, checkMode);
++ printTestResults(201, status, checkMode);
++
++/* AES-128 Encode CBC mode (IV from SA) */
++ status = testRun(202, 10, i, reqSize, mode);
++ printTestResults(202, status, mode);
++
++/* AES-128 Encode CBC mode (IV from User) */
++ status = testRun(202, 24, i, reqSize, mode);
++ printTestResults(202, status, mode);
++
++/* AES-128 Decode CBC mode */
++ status = testRun(203, 24, iter, reqSize, mode);
++ printTestResults(203, status, checkMode);
++
++/* AES-192 Encode ECB mode */
++ status = testRun(204, 4, iter, reqSize, checkMode);
++ printTestResults(204, status, checkMode);
++
++/* AES-192 Decode ECB mode */
++ status = testRun(205, 4, iter, reqSize, checkMode);
++ printTestResults(205, status, checkMode);
++
++/* AES-256 Encode ECB mode */
++ status = testRun(206, 5, iter, reqSize, checkMode);
++ printTestResults(206, status, checkMode);
++
++/* AES-256 Decode ECB mode */
++ status = testRun(207, 5, iter, reqSize, checkMode);
++ printTestResults(207, status, checkMode);
++
++#if defined(MV_LINUX)
++/* AES-128 Encode CTR mode */
++ status = testRun(208, 23, iter, reqSize, mode);
++ printTestResults(208, status, checkMode);
++#endif
++ testClose(200);
++ testClose(201);
++ testClose(202);
++ testClose(203);
++ testClose(204);
++ testClose(205);
++ testClose(206);
++ testClose(207);
++ testClose(208);
++}
++
++
++void mdTest(int iter, int reqSize, int checkMode)
++{
++ int mode;
++ MV_STATUS status;
++
++ if(iter == 0)
++ iter = CESA_DEF_ITER_NUM;
++
++ mode = checkMode;
++ if(checkMode == CESA_FULL_CHECK_MODE)
++ mode = CESA_FAST_CHECK_MODE;
++
++ testOpen(300);
++ testOpen(301);
++ testOpen(302);
++ testOpen(303);
++ testOpen(305);
++
++/* HMAC-MD5 Generate signature test */
++ status = testRun(300, 6, iter, reqSize, mode);
++ printTestResults(300, status, checkMode);
++
++/* HMAC-MD5 Verify Signature test */
++ status = testRun(301, 7, iter, reqSize, mode);
++ printTestResults(301, status, checkMode);
++
++/* HMAC-MD5 Generate signature test */
++ status = testRun(302, 8, iter, reqSize, mode);
++ printTestResults(302, status, checkMode);
++
++/* HMAC-MD5 Verify Signature test */
++ status = testRun(303, 9, iter, reqSize, mode);
++ printTestResults(303, status, checkMode);
++
++/* HASH-MD5 Generate signature test */
++ status = testRun(305, 15, iter, reqSize, mode);
++ printTestResults(305, status, checkMode);
++
++ testClose(300);
++ testClose(301);
++ testClose(302);
++ testClose(303);
++ testClose(305);
++}
++
++void shaTest(int iter, int reqSize, int checkMode)
++{
++ int mode;
++ MV_STATUS status;
++
++ if(iter == 0)
++ iter = CESA_DEF_ITER_NUM;
++
++ mode = checkMode;
++ if(checkMode == CESA_FULL_CHECK_MODE)
++ mode = CESA_FAST_CHECK_MODE;
++
++ testOpen(400);
++ testOpen(401);
++ testOpen(402);
++ testOpen(403);
++ testOpen(405);
++
++/* HMAC-SHA1 Generate signature test */
++ status = testRun(400, 11, iter, reqSize, mode);
++ printTestResults(400, status, checkMode);
++
++/* HMAC-SHA1 Verify Signature test */
++ status = testRun(401, 12, iter, reqSize, mode);
++ printTestResults(401, status, checkMode);
++
++/* HMAC-SHA1 Generate signature test */
++ status = testRun(402, 13, iter, reqSize, mode);
++ printTestResults(402, status, checkMode);
++
++/* HMAC-SHA1 Verify Signature test */
++ status = testRun(403, 14, iter, reqSize, mode);
++ printTestResults(403, status, checkMode);
++
++/* HMAC-SHA1 Generate signature test */
++ status = testRun(405, 16, iter, reqSize, mode);
++ printTestResults(405, status, checkMode);
++
++ testClose(400);
++ testClose(401);
++ testClose(402);
++ testClose(403);
++ testClose(405);
++}
++
++void combiTest(int iter, int reqSize, int checkMode)
++{
++ MV_STATUS status;
++ int mode, i;
++
++ mode = checkMode;
++ if(checkMode == CESA_FULL_CHECK_MODE)
++ mode = CESA_FAST_CHECK_MODE;
++
++ if(iter == 0)
++ iter = CESA_DEF_ITER_NUM;
++
++ i = iter;
++ if(mode != CESA_NULL_CHECK_MODE)
++ i = 1;
++
++ testOpen(500);
++ testOpen(501);
++ testOpen(502);
++ testOpen(503);
++ testOpen(504);
++ testOpen(505);
++ testOpen(506);
++ testOpen(507);
++
++/* DES ECB + MD5 encode test */
++ status = testRun(500, 17, iter, reqSize, mode);
++ printTestResults(500, status, mode);
++
++/* DES ECB + SHA1 encode test */
++ status = testRun(501, 18, iter, reqSize, mode);
++ printTestResults(501, status, mode);
++
++/* 3DES ECB + MD5 encode test */
++ status = testRun(502, 17, iter, reqSize, mode);
++ printTestResults(502, status, mode);
++
++/* 3DES ECB + SHA1 encode test */
++ status = testRun(503, 18, iter, reqSize, mode);
++ printTestResults(503, status, mode);
++
++/* 3DES CBC + MD5 encode test */
++ status = testRun(504, 19, i, reqSize, mode);
++ printTestResults(504, status, mode);
++
++/* 3DES CBC + SHA1 encode test */
++ status = testRun(505, 20, i, reqSize, mode);
++ printTestResults(505, status, mode);
++
++/* AES-128 CBC + MD5 encode test */
++ status = testRun(506, 21, i, reqSize, mode);
++ printTestResults(506, status, mode);
++
++/* AES-128 CBC + SHA1 encode test */
++ status = testRun(507, 22, i, reqSize, mode);
++ printTestResults(507, status, mode);
++
++ testClose(500);
++ testClose(501);
++ testClose(502);
++ testClose(503);
++ testClose(504);
++ testClose(505);
++ testClose(506);
++ testClose(507);
++}
++
++void cesaOneTest(int testIdx, int caseIdx,
++ int iter, int reqSize, int checkMode)
++{
++ MV_STATUS status;
++
++ if(iter == 0)
++ iter = CESA_DEF_ITER_NUM;
++
++ mvOsPrintf("test=%d, case=%d, size=%d, iter=%d\n",
++ testIdx, caseIdx, reqSize, iter);
++
++ status = testOpen(testIdx);
++
++ status = testRun(testIdx, caseIdx, iter, reqSize, checkMode);
++ printTestResults(testIdx, status, checkMode);
++ status = testClose(testIdx);
++
++}
++
++void cesaTest(int iter, int reqSize, int checkMode)
++{
++ if(iter == 0)
++ iter = CESA_DEF_ITER_NUM;
++
++ mvOsPrintf("%d iteration\n", iter);
++ mvOsPrintf("%d size\n\n", reqSize);
++
++/* DES tests */
++ desTest(iter, reqSize, checkMode);
++
++/* 3DES tests */
++ tripleDesTest(iter, reqSize, checkMode);
++
++/* AES tests */
++ aesTest(iter, reqSize, checkMode);
++
++/* MD5 tests */
++ mdTest(iter, reqSize, checkMode);
++
++/* SHA-1 tests */
++ shaTest(iter, reqSize, checkMode);
++}
++
++void multiSizeTest(int idx, int iter, int checkMode, char* inputData)
++{
++ MV_STATUS status;
++ int i;
++ MV_CESA_SIZE_TEST* pMultiTest;
++
++ if( testOpen(idx) != MV_OK)
++ return;
++
++ if(iter == 0)
++ iter = CESA_DEF_ITER_NUM;
++
++ if(checkMode == CESA_SHOW_CHECK_MODE)
++ {
++ iter = 1;
++ }
++ else
++ checkMode = CESA_FULL_CHECK_MODE;
++
++ cesaTestCases[0].plainHexStr = inputData;
++ cesaTestCases[0].pCryptoIV = NULL;
++
++ switch(idx)
++ {
++ case 302:
++ pMultiTest = mdMultiSizeTest302;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = cesaDataHexStr3;
++ break;
++
++ case 304:
++ pMultiTest = mdMultiSizeTest304;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ break;
++
++ case 305:
++ pMultiTest = mdMultiSizeTest305;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ break;
++
++ case 402:
++ pMultiTest = shaMultiSizeTest402;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ break;
++
++ case 404:
++ pMultiTest = shaMultiSizeTest404;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ break;
++
++ case 405:
++ pMultiTest = shaMultiSizeTest405;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ break;
++
++ case 502:
++ pMultiTest = tripleDesMdMultiSizeTest502;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ break;
++
++ case 503:
++ pMultiTest = tripleDesShaMultiSizeTest503;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ break;
++
++ case 504:
++ iter = 1;
++ pMultiTest = cbc3desMdMultiSizeTest504;
++ cesaTestCases[0].pCryptoIV = iv1;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ break;
++
++ case 505:
++ iter = 1;
++ pMultiTest = cbc3desShaMultiSizeTest505;
++ cesaTestCases[0].pCryptoIV = iv1;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ break;
++
++ case 506:
++ iter = 1;
++ pMultiTest = cbcAes128md5multiSizeTest506;
++ cesaTestCases[0].pCryptoIV = iv5;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ break;
++
++ case 507:
++ iter = 1;
++ pMultiTest = cbcAes128sha1multiSizeTest507;
++ cesaTestCases[0].pCryptoIV = iv5;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ break;
++
++ default:
++ iter = 1;
++ checkMode = CESA_SHOW_CHECK_MODE;
++ pMultiTest = mdMultiSizeTest302;
++ if(inputData == NULL)
++ cesaTestCases[0].plainHexStr = hashHexStr80;
++ }
++ i = 0;
++ while(pMultiTest[i].outputHexStr != NULL)
++ {
++ cesaTestCases[0].cipherHexStr = (char *)pMultiTest[i].outputHexStr;
++ status = testRun(idx, 0, iter, pMultiTest[i].size,
++ checkMode);
++ if(checkMode != CESA_SHOW_CHECK_MODE)
++ {
++ cesaReqSize = pMultiTest[i].size;
++ printTestResults(idx, status, checkMode);
++ }
++ if(status != MV_OK)
++ break;
++ i++;
++ }
++ testClose(idx);
++/*
++ mvCesaDebugStatus();
++ cesaTestPrintStatus();
++*/
++}
++
++void open_session_test(int idx, int caseIdx, int iter)
++{
++ int reqIdError, cryptoError, openErrors, i;
++ int openErrDisp[100];
++ MV_STATUS status;
++
++ memset(openErrDisp, 0, sizeof(openErrDisp));
++ openErrors = 0;
++ reqIdError = 0;
++ cryptoError = 0;
++ for(i=0; i<iter; i++)
++ {
++ status = testOpen(idx);
++ if(status != MV_OK)
++ {
++ openErrors++;
++ openErrDisp[status]++;
++ }
++ else
++ {
++ testRun(idx, caseIdx, 1, 0, CESA_FAST_CHECK_MODE);
++ if(cesaCryptoError > 0)
++ cryptoError++;
++ if(cesaReqIdError > 0)
++ reqIdError++;
++
++ testClose(idx);
++ }
++ }
++ if(cryptoError > 0)
++ mvOsPrintf("cryptoError : %d\n", cryptoError);
++ if(reqIdError > 0)
++ mvOsPrintf("reqIdError : %d\n", reqIdError);
++
++ if(openErrors > 0)
++ {
++ mvOsPrintf("Open Errors = %d\n", openErrors);
++ for(i=0; i<100; i++)
++ {
++ if(openErrDisp[i] != 0)
++ mvOsPrintf("Error %d - occurs %d times\n", i, openErrDisp[i]);
++ }
++ }
++}
++
++
++void loopback_test(int idx, int iter, int size, char* pPlainData)
++{
++}
++
++
++#if defined(MV_VXWORKS)
++int testMode = 0;
++unsigned __TASKCONV cesaTask(void* args)
++{
++ int reqSize = cesaReqSize;
++
++ if(testMode == 0)
++ {
++ cesaOneTest(cesaTestIdx, cesaCaseIdx, cesaIteration,
++ reqSize, cesaCheckMode);
++ }
++ else
++ {
++ if(testMode == 1)
++ {
++ cesaTest(cesaIteration, reqSize, cesaCheckMode);
++ combiTest(cesaIteration, reqSize, cesaCheckMode);
++ }
++ else
++ {
++ multiSizeTest(cesaIdx, cesaIteration, cesaCheckMode, NULL);
++ }
++ }
++ return 0;
++}
++
++void oneTest(int testIdx, int caseIdx,
++ int iter, int reqSize, int checkMode)
++{
++ long rc;
++
++ cesaIteration = iter;
++ cesaReqSize = cesaRateSize = reqSize;
++ cesaCheckMode = checkMode;
++ testMode = 0;
++ cesaTestIdx = testIdx;
++ cesaCaseIdx = caseIdx;
++ rc = mvOsTaskCreate("CESA_T", 100, 4*1024, cesaTask, NULL, &cesaTaskId);
++ if (rc != MV_OK)
++ {
++ mvOsPrintf("hMW: Can't create CESA multiCmd test task, rc = %ld\n", rc);
++ }
++}
++
++void multiTest(int iter, int reqSize, int checkMode)
++{
++ long rc;
++
++ cesaIteration = iter;
++ cesaCheckMode = checkMode;
++ cesaReqSize = reqSize;
++ testMode = 1;
++ rc = mvOsTaskCreate("CESA_T", 100, 4*1024, cesaTask, NULL, &cesaTaskId);
++ if (rc != MV_OK)
++ {
++ mvOsPrintf("hMW: Can't create CESA multiCmd test task, rc = %ld\n", rc);
++ }
++}
++
++void sizeTest(int testIdx, int iter, int checkMode)
++{
++ long rc;
++
++ cesaIteration = iter;
++ cesaCheckMode = checkMode;
++ testMode = 2;
++ cesaIdx = testIdx;
++ rc = mvOsTaskCreate("CESA_T", 100, 4*1024, cesaTask, NULL, &cesaTaskId);
++ if (rc != MV_OK)
++ {
++ mvOsPrintf("hMW: Can't create CESA test task, rc = %ld\n", rc);
++ }
++}
++
++#endif /* MV_VXWORKS */
++
++extern void mvCesaDebugSA(short sid, int mode);
++void cesaTestPrintSession(int idx)
++{
++ int testIdx;
++ MV_CESA_TEST_SESSION* pTestSession;
++
++ pTestSession = getTestSessionDb(idx, &testIdx);
++ if(pTestSession == NULL)
++ {
++ mvOsPrintf("Test %d is not exist\n", idx);
++ return;
++ }
++ pTestSession = &pTestSession[testIdx];
++
++ if(pTestSession->sid == -1)
++ {
++ mvOsPrintf("Test session %d is not opened\n", idx);
++ return;
++ }
++
++ mvCesaDebugSA(pTestSession->sid, 1);
++}
++
++void cesaTestPrintStatus(void)
++{
++ mvOsPrintf("\n\t Cesa Test Status\n\n");
++
++ mvOsPrintf("isrCount=%d\n",
++ cesaTestIsrCount);
++
++#ifdef CESA_TEST_DEBUG
++ {
++ int i, j;
++ j = cesaTestTraceIdx;
++ mvOsPrintf("No Type Cause rCause iCause Res Time pReady pProc pEmpty\n");
++ for(i=0; i<MV_CESA_TEST_TRACE_SIZE; i++)
++ {
++ mvOsPrintf("%02d. %d 0x%04x 0x%04x 0x%04x 0x%02x 0x%02x %02d 0x%06x %p %p %p\n",
++ j, cesaTestTrace[j].type, cesaTestTrace[j].cause, cesaTestTrace[j].realCause,
++ cesaTestTrace[j].dmaCause, cesaTestTrace[j].resources, cesaTestTrace[j].timeStamp,
++ cesaTestTrace[j].pReqReady, cesaTestTrace[j].pReqProcess, cesaTestTrace[j].pReqEmpty);
++ j++;
++ if(j == MV_CESA_TEST_TRACE_SIZE)
++ j = 0;
++ }
++ }
++#endif /* CESA_TEST_DEBUG */
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvLru.c linux-2.6.36/crypto/ocf/kirkwood/cesa/mvLru.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvLru.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/mvLru.c 2010-11-09 20:28:05.822495424 +0100
+@@ -0,0 +1,158 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvOs.h"
++#include "mvLru.h"
++/* LRU Cache support */
++
++
++/* Init LRU cache database */
++MV_LRU_CACHE* mvLruCacheInit(int numOfEntries)
++{
++ int i;
++ MV_LRU_CACHE* pLruCache;
++
++ pLruCache = mvOsMalloc(sizeof(MV_LRU_CACHE));
++ if(pLruCache == NULL)
++ {
++ return NULL;
++ }
++ memset(pLruCache, 0, sizeof(MV_LRU_CACHE));
++
++ pLruCache->table = mvOsMalloc(numOfEntries*sizeof(MV_LRU_ENTRY));
++ if(pLruCache->table == NULL)
++ {
++ mvOsFree(pLruCache);
++ return NULL;
++ }
++ memset(pLruCache->table, 0, numOfEntries*sizeof(MV_LRU_ENTRY));
++ pLruCache->tableSize = numOfEntries;
++
++ for(i=0; i<numOfEntries; i++)
++ {
++ pLruCache->table[i].next = i+1;
++ pLruCache->table[i].prev = i-1;
++ }
++ pLruCache->least = 0;
++ pLruCache->most = numOfEntries-1;
++
++ return pLruCache;
++}
++
++void mvLruCacheFinish(MV_LRU_CACHE* pLruCache)
++{
++ mvOsFree(pLruCache->table);
++ mvOsFree(pLruCache);
++}
++
++/* Update LRU cache database after using cache Index */
++void mvLruCacheIdxUpdate(MV_LRU_CACHE* pLruHndl, int cacheIdx)
++{
++ int prev, next;
++
++ if(cacheIdx == pLruHndl->most)
++ return;
++
++ next = pLruHndl->table[cacheIdx].next;
++ if(cacheIdx == pLruHndl->least)
++ {
++ pLruHndl->least = next;
++ }
++ else
++ {
++ prev = pLruHndl->table[cacheIdx].prev;
++
++ pLruHndl->table[next].prev = prev;
++ pLruHndl->table[prev].next = next;
++ }
++
++ pLruHndl->table[pLruHndl->most].next = cacheIdx;
++ pLruHndl->table[cacheIdx].prev = pLruHndl->most;
++ pLruHndl->most = cacheIdx;
++}
++
++/* Delete LRU cache entry */
++void mvLruCacheIdxDelete(MV_LRU_CACHE* pLruHndl, int cacheIdx)
++{
++ int prev, next;
++
++ if(cacheIdx == pLruHndl->least)
++ return;
++
++ prev = pLruHndl->table[cacheIdx].prev;
++ if(cacheIdx == pLruHndl->most)
++ {
++ pLruHndl->most = prev;
++ }
++ else
++ {
++ next = pLruHndl->table[cacheIdx].next;
++
++ pLruHndl->table[next].prev = prev;
++ pLruHndl->table[prev].next = next;
++ }
++ pLruHndl->table[pLruHndl->least].prev = cacheIdx;
++ pLruHndl->table[cacheIdx].next = pLruHndl->least;
++ pLruHndl->least = cacheIdx;
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvLru.h linux-2.6.36/crypto/ocf/kirkwood/cesa/mvLru.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvLru.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/mvLru.h 2010-11-09 20:28:05.861235773 +0100
+@@ -0,0 +1,112 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++/*******************************************************************************
++* mvLru.h - Header File for Least Recently Used Cache algorithm
++*
++* DESCRIPTION:
++* This header file contains macros typedefs and function declaration for
++* the Least Recently Used Cache algorithm.
++*
++*******************************************************************************/
++
++#ifndef __mvLru_h__
++#define __mvLru_h__
++
++
++typedef struct
++{
++ int next;
++ int prev;
++} MV_LRU_ENTRY;
++
++typedef struct
++{
++ int least;
++ int most;
++ MV_LRU_ENTRY* table;
++ int tableSize;
++
++}MV_LRU_CACHE;
++
++
++/* Find Cache index for replacement LRU */
++static INLINE int mvLruCacheIdxFind(MV_LRU_CACHE* pLruHndl)
++{
++ return pLruHndl->least;
++}
++
++/* Init LRU cache module */
++MV_LRU_CACHE* mvLruCacheInit(int numOfEntries);
++
++/* Finish LRU cache module */
++void mvLruCacheFinish(MV_LRU_CACHE* pLruHndl);
++
++/* Update LRU cache database after using cache Index */
++void mvLruCacheIdxUpdate(MV_LRU_CACHE* pLruHndl, int cacheIdx);
++
++/* Delete LRU cache entry */
++void mvLruCacheIdxDelete(MV_LRU_CACHE* pLruHndl, int cacheIdx);
++
++
++#endif /* __mvLru_h__ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvMD5.c linux-2.6.36/crypto/ocf/kirkwood/cesa/mvMD5.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvMD5.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/mvMD5.c 2010-11-09 20:28:05.902495799 +0100
+@@ -0,0 +1,349 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvOs.h"
++#include "mvMD5.h"
++
++static void mvMD5Transform(MV_U32 buf[4], MV_U32 const in[MV_MD5_MAC_LEN]);
++
++#ifdef MV_CPU_LE
++#define mvByteReverse(buf, len) /* Nothing */
++#else
++static void mvByteReverse(unsigned char *buf, unsigned longs);
++
++/*
++ * Note: this code is harmless on little-endian machines.
++ */
++static void mvByteReverse(unsigned char *buf, unsigned longs)
++{
++ MV_U32 t;
++
++ do
++ {
++ t = (MV_U32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
++ ((unsigned) buf[1] << 8 | buf[0]);
++ *(MV_U32 *) buf = t;
++ buf += 4;
++ } while (--longs);
++}
++#endif
++
++/*
++ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
++ * initialization constants.
++ */
++void mvMD5Init(MV_MD5_CONTEXT *ctx)
++{
++ ctx->buf[0] = 0x67452301;
++ ctx->buf[1] = 0xefcdab89;
++ ctx->buf[2] = 0x98badcfe;
++ ctx->buf[3] = 0x10325476;
++
++ ctx->bits[0] = 0;
++ ctx->bits[1] = 0;
++}
++
++/*
++ * Update context to reflect the concatenation of another buffer full
++ * of bytes.
++ */
++void mvMD5Update(MV_MD5_CONTEXT *ctx, unsigned char const *buf, unsigned len)
++{
++ MV_U32 t;
++
++ /* Update bitcount */
++
++ t = ctx->bits[0];
++ if ((ctx->bits[0] = t + ((MV_U32) len << 3)) < t)
++ ctx->bits[1]++; /* Carry from low to high */
++ ctx->bits[1] += len >> 29;
++
++ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
++
++ /* Handle any leading odd-sized chunks */
++
++ if (t)
++ {
++ unsigned char *p = (unsigned char *) ctx->in + t;
++
++ t = 64 - t;
++ if (len < t)
++ {
++ memcpy(p, buf, len);
++ return;
++ }
++ memcpy(p, buf, t);
++ mvByteReverse(ctx->in, MV_MD5_MAC_LEN);
++ mvMD5Transform(ctx->buf, (MV_U32 *) ctx->in);
++ buf += t;
++ len -= t;
++ }
++ /* Process data in 64-byte chunks */
++
++ while (len >= 64)
++ {
++ memcpy(ctx->in, buf, 64);
++ mvByteReverse(ctx->in, MV_MD5_MAC_LEN);
++ mvMD5Transform(ctx->buf, (MV_U32 *) ctx->in);
++ buf += 64;
++ len -= 64;
++ }
++
++ /* Handle any remaining bytes of data. */
++
++ memcpy(ctx->in, buf, len);
++}
++
++/*
++ * Final wrapup - pad to 64-byte boundary with the bit pattern
++ * 1 0* (64-bit count of bits processed, MSB-first)
++ */
++void mvMD5Final(unsigned char digest[MV_MD5_MAC_LEN], MV_MD5_CONTEXT *ctx)
++{
++ unsigned count;
++ unsigned char *p;
++
++ /* Compute number of bytes mod 64 */
++ count = (ctx->bits[0] >> 3) & 0x3F;
++
++ /* Set the first char of padding to 0x80. This is safe since there is
++ always at least one byte free */
++ p = ctx->in + count;
++ *p++ = 0x80;
++
++ /* Bytes of padding needed to make 64 bytes */
++ count = 64 - 1 - count;
++
++ /* Pad out to 56 mod 64 */
++ if (count < 8)
++ {
++ /* Two lots of padding: Pad the first block to 64 bytes */
++ memset(p, 0, count);
++ mvByteReverse(ctx->in, MV_MD5_MAC_LEN);
++ mvMD5Transform(ctx->buf, (MV_U32 *) ctx->in);
++
++ /* Now fill the next block with 56 bytes */
++ memset(ctx->in, 0, 56);
++ }
++ else
++ {
++ /* Pad block to 56 bytes */
++ memset(p, 0, count - 8);
++ }
++ mvByteReverse(ctx->in, 14);
++
++ /* Append length in bits and transform */
++ ((MV_U32 *) ctx->in)[14] = ctx->bits[0];
++ ((MV_U32 *) ctx->in)[15] = ctx->bits[1];
++
++ mvMD5Transform(ctx->buf, (MV_U32 *) ctx->in);
++ mvByteReverse((unsigned char *) ctx->buf, 4);
++ memcpy(digest, ctx->buf, MV_MD5_MAC_LEN);
++ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
++}
++
++/* The four core functions - F1 is optimized somewhat */
++
++/* #define F1(x, y, z) (x & y | ~x & z) */
++#define F1(x, y, z) (z ^ (x & (y ^ z)))
++#define F2(x, y, z) F1(z, x, y)
++#define F3(x, y, z) (x ^ y ^ z)
++#define F4(x, y, z) (y ^ (x | ~z))
++
++/* This is the central step in the MD5 algorithm. */
++#define MD5STEP(f, w, x, y, z, data, s) \
++ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
++
++/*
++ * The core of the MD5 algorithm, this alters an existing MD5 hash to
++ * reflect the addition of 16 longwords of new data. MD5Update blocks
++ * the data and converts bytes into longwords for this routine.
++ */
++static void mvMD5Transform(MV_U32 buf[4], MV_U32 const in[MV_MD5_MAC_LEN])
++{
++ register MV_U32 a, b, c, d;
++
++ a = buf[0];
++ b = buf[1];
++ c = buf[2];
++ d = buf[3];
++
++ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
++ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
++ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
++ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
++ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
++ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
++ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
++ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
++ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
++ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
++ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
++ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
++ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
++ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
++ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
++ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
++
++ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
++ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
++ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
++ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
++ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
++ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
++ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
++ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
++ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
++ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
++ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
++ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
++ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
++ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
++ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
++ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
++
++ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
++ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
++ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
++ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
++ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
++ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
++ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
++ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
++ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
++ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
++ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
++ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
++ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
++ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
++ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
++ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
++
++ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
++ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
++ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
++ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
++ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
++ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
++ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
++ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
++ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
++ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
++ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
++ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
++ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
++ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
++ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
++ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
++
++ buf[0] += a;
++ buf[1] += b;
++ buf[2] += c;
++ buf[3] += d;
++}
++
++void mvMD5(unsigned char const *buf, unsigned len, unsigned char* digest)
++{
++ MV_MD5_CONTEXT ctx;
++
++ mvMD5Init(&ctx);
++ mvMD5Update(&ctx, buf, len);
++ mvMD5Final(digest, &ctx);
++}
++
++
++void mvHmacMd5(unsigned char const* text, int text_len,
++ unsigned char const* key, int key_len,
++ unsigned char* digest)
++{
++ int i;
++ MV_MD5_CONTEXT ctx;
++ unsigned char k_ipad[64+1]; /* inner padding - key XORd with ipad */
++ unsigned char k_opad[64+1]; /* outer padding - key XORd with opad */
++
++ /* start out by storing key in pads */
++ memset(k_ipad, 0, 64);
++ memcpy(k_ipad, key, key_len);
++ memset(k_opad, 0, 64);
++ memcpy(k_opad, key, key_len);
++
++ /* XOR key with ipad and opad values */
++ for (i=0; i<64; i++)
++ {
++ k_ipad[i] ^= 0x36;
++ k_opad[i] ^= 0x5c;
++ }
++
++ /* perform inner MD5 */
++ mvMD5Init(&ctx); /* init ctx for 1st pass */
++ mvMD5Update(&ctx, k_ipad, 64); /* start with inner pad */
++ mvMD5Update(&ctx, text, text_len); /* then text of datagram */
++ mvMD5Final(digest, &ctx); /* finish up 1st pass */
++
++ /* perform outer MD5 */
++ mvMD5Init(&ctx); /* init ctx for 2nd pass */
++ mvMD5Update(&ctx, k_opad, 64); /* start with outer pad */
++ mvMD5Update(&ctx, digest, 16); /* then results of 1st hash */
++ mvMD5Final(digest, &ctx); /* finish up 2nd pass */
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvMD5.h linux-2.6.36/crypto/ocf/kirkwood/cesa/mvMD5.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvMD5.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/mvMD5.h 2010-11-09 20:28:05.942495390 +0100
+@@ -0,0 +1,93 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __mvMD5_h__
++#define __mvMD5_h__
++
++#include "mvMD5.h"
++
++#define MV_MD5_MAC_LEN 16
++
++
++typedef struct
++{
++ MV_U32 buf[4];
++ MV_U32 bits[2];
++ MV_U8 in[64];
++
++} MV_MD5_CONTEXT;
++
++void mvMD5Init(MV_MD5_CONTEXT *context);
++void mvMD5Update(MV_MD5_CONTEXT *context, unsigned char const *buf,
++ unsigned len);
++void mvMD5Final(unsigned char digest[16], MV_MD5_CONTEXT *context);
++
++void mvMD5(unsigned char const *buf, unsigned len, unsigned char* digest);
++
++void mvHmacMd5(unsigned char const* text, int text_len,
++ unsigned char const* key, int key_len,
++ unsigned char* digest);
++
++
++#endif /* __mvMD5_h__ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvSHA1.c linux-2.6.36/crypto/ocf/kirkwood/cesa/mvSHA1.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvSHA1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/mvSHA1.c 2010-11-09 20:28:05.972495400 +0100
+@@ -0,0 +1,239 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvOs.h"
++#include "mvSHA1.h"
++
++#define SHA1HANDSOFF
++
++typedef union
++{
++ MV_U8 c[64];
++ MV_U32 l[16];
++
++} CHAR64LONG16;
++
++static void mvSHA1Transform(MV_U32 state[5], const MV_U8 *buffer);
++
++#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
++
++
++#ifdef MV_CPU_LE
++#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \
++ (rol(block->l[i], 8) & 0x00FF00FF))
++#else
++#define blk0(i) block->l[i]
++#endif
++#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \
++ block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1))
++
++/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
++#define R0(v,w,x,y,z,i) \
++ z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
++ w = rol(w, 30);
++#define R1(v,w,x,y,z,i) \
++ z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
++ w = rol(w, 30);
++#define R2(v,w,x,y,z,i) \
++ z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30);
++#define R3(v,w,x,y,z,i) \
++ z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
++ w = rol(w, 30);
++#define R4(v,w,x,y,z,i) \
++ z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
++ w=rol(w, 30);
++
++/* Hash a single 512-bit block. This is the core of the algorithm. */
++static void mvSHA1Transform(MV_U32 state[5], const MV_U8 *buffer)
++{
++ MV_U32 a, b, c, d, e;
++ CHAR64LONG16* block;
++
++#ifdef SHA1HANDSOFF
++ static MV_U32 workspace[16];
++
++ block = (CHAR64LONG16 *) workspace;
++ memcpy(block, buffer, 64);
++#else
++ block = (CHAR64LONG16 *) buffer;
++#endif
++ /* Copy context->state[] to working vars */
++ a = state[0];
++ b = state[1];
++ c = state[2];
++ d = state[3];
++ e = state[4];
++ /* 4 rounds of 20 operations each. Loop unrolled. */
++ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
++ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
++ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
++ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
++ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
++ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
++ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
++ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
++ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
++ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
++ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
++ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
++ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
++ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
++ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
++ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
++ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
++ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
++ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
++ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
++ /* Add the working vars back into context.state[] */
++ state[0] += a;
++ state[1] += b;
++ state[2] += c;
++ state[3] += d;
++ state[4] += e;
++ /* Wipe variables */
++ a = b = c = d = e = 0;
++}
++
++void mvSHA1Init(MV_SHA1_CTX* context)
++{
++ /* SHA1 initialization constants */
++ context->state[0] = 0x67452301;
++ context->state[1] = 0xEFCDAB89;
++ context->state[2] = 0x98BADCFE;
++ context->state[3] = 0x10325476;
++ context->state[4] = 0xC3D2E1F0;
++ context->count[0] = context->count[1] = 0;
++}
++
++
++/* Run your data through this. */
++void mvSHA1Update(MV_SHA1_CTX *context, MV_U8 const *data,
++ unsigned int len)
++{
++ MV_U32 i, j;
++
++ j = (context->count[0] >> 3) & 63;
++ if ((context->count[0] += len << 3) < (len << 3))
++ context->count[1]++;
++ context->count[1] += (len >> 29);
++ if ((j + len) > 63)
++ {
++ memcpy(&context->buffer[j], data, (i = 64-j));
++ mvSHA1Transform(context->state, context->buffer);
++ for ( ; i + 63 < len; i += 64)
++ {
++ mvSHA1Transform(context->state, &data[i]);
++ }
++ j = 0;
++ }
++ else
++ {
++ i = 0;
++ }
++ memcpy(&context->buffer[j], &data[i], len - i);
++}
++
++void mvSHA1Final(MV_U8* digest, MV_SHA1_CTX* context)
++{
++ MV_U32 i;
++ MV_U8 finalcount[8];
++
++ for (i = 0; i < 8; i++)
++ {
++ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >>
++ ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
++ }
++ mvSHA1Update(context, (const unsigned char *) "\200", 1);
++ while ((context->count[0] & 504) != 448)
++ {
++ mvSHA1Update(context, (const unsigned char *) "\0", 1);
++ }
++ mvSHA1Update(context, finalcount, 8); /* Should cause a mvSHA1Transform()
++ */
++ for (i = 0; i < 20; i++)
++ {
++ digest[i] = (unsigned char)
++ ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
++ }
++ /* Wipe variables */
++ i = 0;
++ memset(context->buffer, 0, 64);
++ memset(context->state, 0, 20);
++ memset(context->count, 0, 8);
++ memset(finalcount, 0, 8);
++
++#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
++ mvSHA1Transform(context->state, context->buffer);
++#endif
++}
++
++
++void mvSHA1(MV_U8 const *buf, unsigned int len, MV_U8* digest)
++{
++ MV_SHA1_CTX ctx;
++
++ mvSHA1Init(&ctx);
++ mvSHA1Update(&ctx, buf, len);
++ mvSHA1Final(digest, &ctx);
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvSHA1.h linux-2.6.36/crypto/ocf/kirkwood/cesa/mvSHA1.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa/mvSHA1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa/mvSHA1.h 2010-11-09 20:28:06.012495345 +0100
+@@ -0,0 +1,88 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __mvSHA1_h__
++#define __mvSHA1_h__
++
++#include "mvSHA1.h"
++
++#define MV_SHA1_MAC_LEN 20
++
++
++typedef struct
++{
++ MV_U32 state[5];
++ MV_U32 count[2];
++ MV_U8 buffer[64];
++
++} MV_SHA1_CTX;
++
++void mvSHA1Init(MV_SHA1_CTX *context);
++void mvSHA1Update(MV_SHA1_CTX *context, MV_U8 const *buf, unsigned int len);
++void mvSHA1Final(MV_U8* digest, MV_SHA1_CTX *context);
++
++void mvSHA1(MV_U8 const *buf, unsigned int len, MV_U8* digest);
++
++
++#endif /* __mvSHA1_h__ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/cesa_ocf_drv.c linux-2.6.36/crypto/ocf/kirkwood/cesa_ocf_drv.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/cesa_ocf_drv.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/cesa_ocf_drv.c 2010-11-09 20:28:06.052495403 +0100
+@@ -0,0 +1,1296 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++*******************************************************************************/
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/crypto.h>
++#include <linux/mm.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++#include <linux/platform_device.h>
++#include <asm/scatterlist.h>
++#include <linux/spinlock.h>
++#include "ctrlEnv/sys/mvSysCesa.h"
++#include "cesa/mvCesa.h" /* moved here before cryptodev.h due to include dependencies */
++#include <cryptodev.h>
++#include <uio.h>
++#include <plat/mv_cesa.h>
++#include <linux/mbus.h>
++#include "mvDebug.h"
++
++#include "cesa/mvMD5.h"
++#include "cesa/mvSHA1.h"
++
++#include "cesa/mvCesaRegs.h"
++#include "cesa/AES/mvAes.h"
++#include "cesa/mvLru.h"
++
++#undef RT_DEBUG
++#ifdef RT_DEBUG
++static int debug = 1;
++module_param(debug, int, 1);
++MODULE_PARM_DESC(debug, "Enable debug");
++#undef dprintk
++#define dprintk(a...) if (debug) { printk(a); } else
++#else
++static int debug = 0;
++#undef dprintk
++#define dprintk(a...)
++#endif
++
++
++/* TDMA Regs */
++#define WINDOW_BASE(i) 0xA00 + (i << 3)
++#define WINDOW_CTRL(i) 0xA04 + (i << 3)
++
++/* interrupt handling */
++#undef CESA_OCF_POLLING
++#undef CESA_OCF_TASKLET
++
++#if defined(CESA_OCF_POLLING) && defined(CESA_OCF_TASKLET)
++#error "don't use both tasklet and polling mode"
++#endif
++
++extern int cesaReqResources;
++/* support for spliting action into 2 actions */
++#define CESA_OCF_SPLIT
++
++/* general defines */
++#define CESA_OCF_MAX_SES 128
++#define CESA_Q_SIZE 64
++
++
++/* data structures */
++struct cesa_ocf_data {
++ int cipher_alg;
++ int auth_alg;
++ int encrypt_tn_auth;
++#define auth_tn_decrypt encrypt_tn_auth
++ int ivlen;
++ int digestlen;
++ short sid_encrypt;
++ short sid_decrypt;
++ /* fragment workaround sessions */
++ short frag_wa_encrypt;
++ short frag_wa_decrypt;
++ short frag_wa_auth;
++};
++
++/* CESA device data */
++struct cesa_dev {
++ void __iomem *sram;
++ void __iomem *reg;
++ struct mv_cesa_platform_data *plat_data;
++ int irq;
++};
++
++#define DIGEST_BUF_SIZE 32
++struct cesa_ocf_process {
++ MV_CESA_COMMAND cesa_cmd;
++ MV_CESA_MBUF cesa_mbuf;
++ MV_BUF_INFO cesa_bufs[MV_CESA_MAX_MBUF_FRAGS];
++ char digest[DIGEST_BUF_SIZE];
++ int digest_len;
++ struct cryptop *crp;
++ int need_cb;
++};
++
++/* global variables */
++static int32_t cesa_ocf_id = -1;
++static struct cesa_ocf_data *cesa_ocf_sessions[CESA_OCF_MAX_SES];
++static spinlock_t cesa_lock;
++static struct cesa_dev cesa_device;
++
++/* static APIs */
++static int cesa_ocf_process (device_t, struct cryptop *, int);
++static int cesa_ocf_newsession (device_t, u_int32_t *, struct cryptoini *);
++static int cesa_ocf_freesession (device_t, u_int64_t);
++static void cesa_callback (unsigned long);
++static irqreturn_t cesa_interrupt_handler (int, void *);
++#ifdef CESA_OCF_POLLING
++static void cesa_interrupt_polling(void);
++#endif
++#ifdef CESA_OCF_TASKLET
++static struct tasklet_struct cesa_ocf_tasklet;
++#endif
++
++static struct timeval tt_start;
++static struct timeval tt_end;
++
++/*
++ * dummy device structure
++ */
++
++static struct {
++ softc_device_decl sc_dev;
++} mv_cesa_dev;
++
++static device_method_t mv_cesa_methods = {
++ /* crypto device methods */
++ DEVMETHOD(cryptodev_newsession, cesa_ocf_newsession),
++ DEVMETHOD(cryptodev_freesession,cesa_ocf_freesession),
++ DEVMETHOD(cryptodev_process, cesa_ocf_process),
++ DEVMETHOD(cryptodev_kprocess, NULL),
++};
++
++
++
++/* Add debug Trace */
++#undef CESA_OCF_TRACE_DEBUG
++#ifdef CESA_OCF_TRACE_DEBUG
++
++#define MV_CESA_USE_TIMER_ID 0
++
++typedef struct
++{
++ int type; /* 0 - isrEmpty, 1 - cesaReadyGet, 2 - cesaAction */
++ MV_U32 timeStamp;
++ MV_U32 cause;
++ MV_U32 realCause;
++ MV_U32 dmaCause;
++ int resources;
++ MV_CESA_REQ* pReqReady;
++ MV_CESA_REQ* pReqEmpty;
++ MV_CESA_REQ* pReqProcess;
++} MV_CESA_TEST_TRACE;
++
++#define MV_CESA_TEST_TRACE_SIZE 50
++
++static int cesaTestTraceIdx = 0;
++static MV_CESA_TEST_TRACE cesaTestTrace[MV_CESA_TEST_TRACE_SIZE];
++
++static void cesaTestTraceAdd(int type)
++{
++ cesaTestTrace[cesaTestTraceIdx].type = type;
++ cesaTestTrace[cesaTestTraceIdx].realCause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
++ //cesaTestTrace[cesaTestTraceIdx].idmaCause = MV_REG_READ(IDMA_CAUSE_REG);
++ cesaTestTrace[cesaTestTraceIdx].resources = cesaReqResources;
++ cesaTestTrace[cesaTestTraceIdx].pReqReady = pCesaReqReady;
++ cesaTestTrace[cesaTestTraceIdx].pReqEmpty = pCesaReqEmpty;
++ cesaTestTrace[cesaTestTraceIdx].pReqProcess = pCesaReqProcess;
++ cesaTestTrace[cesaTestTraceIdx].timeStamp = mvCntmrRead(MV_CESA_USE_TIMER_ID);
++ cesaTestTraceIdx++;
++ if(cesaTestTraceIdx == MV_CESA_TEST_TRACE_SIZE)
++ cesaTestTraceIdx = 0;
++}
++
++#else /* CESA_OCF_TRACE_DEBUG */
++
++#define cesaTestTraceAdd(x)
++
++#endif /* CESA_OCF_TRACE_DEBUG */
++
++unsigned int
++get_usec(unsigned int start)
++{
++ if(start) {
++ do_gettimeofday (&tt_start);
++ return 0;
++ }
++ else {
++ do_gettimeofday (&tt_end);
++ tt_end.tv_sec -= tt_start.tv_sec;
++ tt_end.tv_usec -= tt_start.tv_usec;
++ if (tt_end.tv_usec < 0) {
++ tt_end.tv_usec += 1000 * 1000;
++ tt_end.tv_sec -= 1;
++ }
++ }
++ printk("time taken is %d\n", (unsigned int)(tt_end.tv_usec + tt_end.tv_sec * 1000000));
++ return (tt_end.tv_usec + tt_end.tv_sec * 1000000);
++}
++
++#ifdef RT_DEBUG
++/*
++ * check that the crp action match the current session
++ */
++static int
++ocf_check_action(struct cryptop *crp, struct cesa_ocf_data *cesa_ocf_cur_ses) {
++ int count = 0;
++ int encrypt = 0, decrypt = 0, auth = 0;
++ struct cryptodesc *crd;
++
++ /* Go through crypto descriptors, processing as we go */
++ for (crd = crp->crp_desc; crd; crd = crd->crd_next, count++) {
++ if(count > 2) {
++ printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
++ return 1;
++ }
++
++ /* Encryption /Decryption */
++ if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) {
++ /* check that the action is compatible with session */
++ if(encrypt || decrypt) {
++ printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
++ return 1;
++ }
++
++ if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
++ if( (count == 2) && (cesa_ocf_cur_ses->encrypt_tn_auth) ) {
++ printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
++ return 1;
++ }
++ encrypt++;
++ }
++ else { /* decrypt */
++ if( (count == 2) && !(cesa_ocf_cur_ses->auth_tn_decrypt) ) {
++ printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
++ return 1;
++ }
++ decrypt++;
++ }
++
++ }
++ /* Authentication */
++ else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) {
++ /* check that the action is compatible with session */
++ if(auth) {
++ printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
++ return 1;
++ }
++ if( (count == 2) && (decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) {
++ printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
++ return 1;
++ }
++ if( (count == 2) && (encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)) {
++ printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
++ return 1;
++ }
++ auth++;
++ }
++ else {
++ printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__);
++ return 1;
++ }
++ }
++ return 0;
++
++}
++#endif
++
++/*
++ * Process a request.
++ */
++static int
++cesa_ocf_process(device_t dev, struct cryptop *crp, int hint)
++{
++ struct cesa_ocf_process *cesa_ocf_cmd = NULL;
++ struct cesa_ocf_process *cesa_ocf_cmd_wa = NULL;
++ MV_CESA_COMMAND *cesa_cmd;
++ struct cryptodesc *crd;
++ struct cesa_ocf_data *cesa_ocf_cur_ses;
++ int sid = 0, temp_len = 0, i;
++ int encrypt = 0, decrypt = 0, auth = 0;
++ int status;
++ struct sk_buff *skb = NULL;
++ struct uio *uiop = NULL;
++ unsigned char *ivp;
++ MV_BUF_INFO *p_buf_info;
++ MV_CESA_MBUF *p_mbuf_info;
++ unsigned long flags;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ if( cesaReqResources <= 1 ) {
++ dprintk("%s,%d: ERESTART\n", __FILE__, __LINE__);
++ return ERESTART;
++ }
++
++#ifdef RT_DEBUG
++ /* Sanity check */
++ if (crp == NULL) {
++ printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ if (crp->crp_desc == NULL || crp->crp_buf == NULL ) {
++ printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ crp->crp_etype = EINVAL;
++ return EINVAL;
++ }
++
++ sid = crp->crp_sid & 0xffffffff;
++ if ((sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL)) {
++ crp->crp_etype = ENOENT;
++ printk("%s,%d: ENOENT session %d \n", __FILE__, __LINE__, sid);
++ return EINVAL;
++ }
++#endif
++
++ sid = crp->crp_sid & 0xffffffff;
++ crp->crp_etype = 0;
++ cesa_ocf_cur_ses = cesa_ocf_sessions[sid];
++
++#ifdef RT_DEBUG
++ if(ocf_check_action(crp, cesa_ocf_cur_ses)){
++ goto p_error;
++ }
++#endif
++
++ /* malloc a new cesa process */
++ cesa_ocf_cmd = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC);
++
++ if (cesa_ocf_cmd == NULL) {
++ printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
++ goto p_error;
++ }
++ memset(cesa_ocf_cmd, 0, sizeof(struct cesa_ocf_process));
++
++ /* init cesa_process */
++ cesa_ocf_cmd->crp = crp;
++ /* always call callback */
++ cesa_ocf_cmd->need_cb = 1;
++
++ /* init cesa_cmd for usage of the HALs */
++ cesa_cmd = &cesa_ocf_cmd->cesa_cmd;
++ cesa_cmd->pReqPrv = (void *)cesa_ocf_cmd;
++ cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_encrypt; /* defualt use encrypt */
++
++ /* prepare src buffer */
++ /* we send the entire buffer to the HAL, even if only part of it should be encrypt/auth. */
++ /* if not using seesions for both encrypt and auth, then it will be wiser to to copy only */
++ /* from skip to crd_len. */
++ p_buf_info = cesa_ocf_cmd->cesa_bufs;
++ p_mbuf_info = &cesa_ocf_cmd->cesa_mbuf;
++
++ p_buf_info += 2; /* save 2 first buffers for IV and digest -
++ we won't append them to the end since, they
++ might be places in an unaligned addresses. */
++
++ p_mbuf_info->pFrags = p_buf_info;
++ temp_len = 0;
++
++ /* handle SKB */
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++
++ dprintk("%s,%d: handle SKB.\n", __FILE__, __LINE__);
++ skb = (struct sk_buff *) crp->crp_buf;
++
++ if (skb_shinfo(skb)->nr_frags >= (MV_CESA_MAX_MBUF_FRAGS - 1)) {
++ printk("%s,%d: %d nr_frags > MV_CESA_MAX_MBUF_FRAGS", __FILE__, __LINE__, skb_shinfo(skb)->nr_frags);
++ goto p_error;
++ }
++
++ p_mbuf_info->mbufSize = skb->len;
++ temp_len = skb->len;
++ /* first skb fragment */
++ p_buf_info->bufSize = skb_headlen(skb);
++ p_buf_info->bufVirtPtr = skb->data;
++ p_buf_info++;
++
++ /* now handle all other skb fragments */
++ for ( i = 0; i < skb_shinfo(skb)->nr_frags; i++ ) {
++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
++ p_buf_info->bufSize = frag->size;
++ p_buf_info->bufVirtPtr = page_address(frag->page) + frag->page_offset;
++ p_buf_info++;
++ }
++ p_mbuf_info->numFrags = skb_shinfo(skb)->nr_frags + 1;
++ }
++ /* handle UIO */
++ else if(crp->crp_flags & CRYPTO_F_IOV) {
++
++ dprintk("%s,%d: handle UIO.\n", __FILE__, __LINE__);
++ uiop = (struct uio *) crp->crp_buf;
++
++ if (uiop->uio_iovcnt > (MV_CESA_MAX_MBUF_FRAGS - 1)) {
++ printk("%s,%d: %d uio_iovcnt > MV_CESA_MAX_MBUF_FRAGS \n", __FILE__, __LINE__, uiop->uio_iovcnt);
++ goto p_error;
++ }
++
++ p_mbuf_info->mbufSize = crp->crp_ilen;
++ p_mbuf_info->numFrags = uiop->uio_iovcnt;
++ for(i = 0; i < uiop->uio_iovcnt; i++) {
++ p_buf_info->bufVirtPtr = uiop->uio_iov[i].iov_base;
++ p_buf_info->bufSize = uiop->uio_iov[i].iov_len;
++ temp_len += p_buf_info->bufSize;
++ dprintk("%s,%d: buf %x-> addr %x, size %x \n"
++ , __FILE__, __LINE__, i, (unsigned int)p_buf_info->bufVirtPtr, p_buf_info->bufSize);
++ p_buf_info++;
++ }
++
++ }
++ /* handle CONTIG */
++ else {
++ dprintk("%s,%d: handle CONTIG.\n", __FILE__, __LINE__);
++ p_mbuf_info->numFrags = 1;
++ p_mbuf_info->mbufSize = crp->crp_ilen;
++ p_buf_info->bufVirtPtr = crp->crp_buf;
++ p_buf_info->bufSize = crp->crp_ilen;
++ temp_len = crp->crp_ilen;
++ p_buf_info++;
++ }
++
++ /* Support up to 64K why? cause! */
++ if(crp->crp_ilen > 64*1024) {
++ printk("%s,%d: buf too big %x \n", __FILE__, __LINE__, crp->crp_ilen);
++ goto p_error;
++ }
++
++ if( temp_len != crp->crp_ilen ) {
++ printk("%s,%d: warning size don't match.(%x %x) \n", __FILE__, __LINE__, temp_len, crp->crp_ilen);
++ }
++
++ cesa_cmd->pSrc = p_mbuf_info;
++ cesa_cmd->pDst = p_mbuf_info;
++
++ /* restore p_buf_info to point to first available buf */
++ p_buf_info = cesa_ocf_cmd->cesa_bufs;
++ p_buf_info += 1;
++
++
++ /* Go through crypto descriptors, processing as we go */
++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
++
++ /* Encryption /Decryption */
++ if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) {
++
++ dprintk("%s,%d: cipher", __FILE__, __LINE__);
++
++ cesa_cmd->cryptoOffset = crd->crd_skip;
++ cesa_cmd->cryptoLength = crd->crd_len;
++
++ if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
++ dprintk(" encrypt \n");
++ encrypt++;
++
++ /* handle IV */
++ if (crd->crd_flags & CRD_F_IV_EXPLICIT) { /* IV from USER */
++ dprintk("%s,%d: IV from USER (offset %x) \n", __FILE__, __LINE__, crd->crd_inject);
++ cesa_cmd->ivFromUser = 1;
++ ivp = crd->crd_iv;
++
++ /*
++ * do we have to copy the IV back to the buffer ?
++ */
++ if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++ dprintk("%s,%d: copy the IV back to the buffer\n", __FILE__, __LINE__);
++ cesa_cmd->ivOffset = crd->crd_inject;
++ crypto_copy_bits_back(crp->crp_buf, crd->crd_inject, ivp, cesa_ocf_cur_ses->ivlen);
++ }
++ else {
++ dprintk("%s,%d: don't copy the IV back to the buffer \n", __FILE__, __LINE__);
++ p_mbuf_info->numFrags++;
++ p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen;
++ p_mbuf_info->pFrags = p_buf_info;
++
++ p_buf_info->bufVirtPtr = ivp;
++ p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen;
++ p_buf_info--;
++
++ /* offsets */
++ cesa_cmd->ivOffset = 0;
++ cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen;
++ if(auth) {
++ cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen;
++ cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen;
++ }
++ }
++ }
++ else { /* random IV */
++ dprintk("%s,%d: random IV \n", __FILE__, __LINE__);
++ cesa_cmd->ivFromUser = 0;
++
++ /*
++ * do we have to copy the IV back to the buffer ?
++ */
++ /* in this mode the HAL will always copy the IV */
++ /* given by the session to the ivOffset */
++ if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++ cesa_cmd->ivOffset = crd->crd_inject;
++ }
++ else {
++ /* if IV isn't copy, then how will the user know which IV did we use??? */
++ printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ goto p_error;
++ }
++ }
++ }
++ else { /* decrypt */
++ dprintk(" decrypt \n");
++ decrypt++;
++ cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_decrypt;
++
++ /* handle IV */
++ if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
++ dprintk("%s,%d: IV from USER \n", __FILE__, __LINE__);
++ /* append the IV buf to the mbuf */
++ cesa_cmd->ivFromUser = 1;
++ p_mbuf_info->numFrags++;
++ p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen;
++ p_mbuf_info->pFrags = p_buf_info;
++
++ p_buf_info->bufVirtPtr = crd->crd_iv;
++ p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen;
++ p_buf_info--;
++
++ /* offsets */
++ cesa_cmd->ivOffset = 0;
++ cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen;
++ if(auth) {
++ cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen;
++ cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen;
++ }
++ }
++ else {
++ dprintk("%s,%d: IV inside the buffer \n", __FILE__, __LINE__);
++ cesa_cmd->ivFromUser = 0;
++ cesa_cmd->ivOffset = crd->crd_inject;
++ }
++ }
++
++ }
++ /* Authentication */
++ else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) {
++ dprintk("%s,%d: Authentication \n", __FILE__, __LINE__);
++ auth++;
++ cesa_cmd->macOffset = crd->crd_skip;
++ cesa_cmd->macLength = crd->crd_len;
++
++ /* digest + mac */
++ cesa_cmd->digestOffset = crd->crd_inject;
++ }
++ else {
++ printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__);
++ goto p_error;
++ }
++ }
++
++ dprintk("\n");
++ dprintk("%s,%d: Sending Action: \n", __FILE__, __LINE__);
++ dprintk("%s,%d: IV from user: %d. IV offset %x \n", __FILE__, __LINE__, cesa_cmd->ivFromUser, cesa_cmd->ivOffset);
++ dprintk("%s,%d: crypt offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->cryptoOffset, cesa_cmd->cryptoLength);
++ dprintk("%s,%d: Auth offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->macOffset, cesa_cmd->macLength);
++ dprintk("%s,%d: set digest in offset %x . \n", __FILE__, __LINE__, cesa_cmd->digestOffset);
++ if(debug) {
++ mvCesaDebugMbuf("SRC BUFFER", cesa_cmd->pSrc, 0, cesa_cmd->pSrc->mbufSize);
++ }
++
++
++ /* send action to HAL */
++ spin_lock_irqsave(&cesa_lock, flags);
++ status = mvCesaAction(cesa_cmd);
++ spin_unlock_irqrestore(&cesa_lock, flags);
++
++ /* action not allowed */
++ if(status == MV_NOT_ALLOWED) {
++#ifdef CESA_OCF_SPLIT
++ /* if both encrypt and auth try to split */
++ if(auth && (encrypt || decrypt)) {
++ MV_CESA_COMMAND *cesa_cmd_wa;
++
++ /* malloc a new cesa process and init it */
++ cesa_ocf_cmd_wa = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC);
++
++ if (cesa_ocf_cmd_wa == NULL) {
++ printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
++ goto p_error;
++ }
++ memcpy(cesa_ocf_cmd_wa, cesa_ocf_cmd, sizeof(struct cesa_ocf_process));
++ cesa_cmd_wa = &cesa_ocf_cmd_wa->cesa_cmd;
++ cesa_cmd_wa->pReqPrv = (void *)cesa_ocf_cmd_wa;
++ cesa_ocf_cmd_wa->need_cb = 0;
++
++ /* break requests to two operation, first operation completion won't call callback */
++ if((decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) {
++ cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
++ cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt;
++ }
++ else if((decrypt) && !(cesa_ocf_cur_ses->auth_tn_decrypt)) {
++ cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt;
++ cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
++ }
++ else if((encrypt) && (cesa_ocf_cur_ses->encrypt_tn_auth)) {
++ cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt;
++ cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
++ }
++ else if((encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)){
++ cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
++ cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt;
++ }
++ else {
++ printk("%s,%d: Unsupporterd fragment wa mode \n", __FILE__, __LINE__);
++ goto p_error;
++ }
++
++ /* send the 2 actions to the HAL */
++ spin_lock_irqsave(&cesa_lock, flags);
++ status = mvCesaAction(cesa_cmd_wa);
++ spin_unlock_irqrestore(&cesa_lock, flags);
++
++ if((status != MV_NO_MORE) && (status != MV_OK)) {
++ printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status);
++ goto p_error;
++ }
++ spin_lock_irqsave(&cesa_lock, flags);
++ status = mvCesaAction(cesa_cmd);
++ spin_unlock_irqrestore(&cesa_lock, flags);
++
++ }
++ /* action not allowed and can't split */
++ else
++#endif
++ {
++ goto p_error;
++ }
++ }
++
++ /* Hal Q is full, send again. This should never happen */
++ if(status == MV_NO_RESOURCE) {
++ printk("%s,%d: cesa no more resources \n", __FILE__, __LINE__);
++ if(cesa_ocf_cmd)
++ kfree(cesa_ocf_cmd);
++ if(cesa_ocf_cmd_wa)
++ kfree(cesa_ocf_cmd_wa);
++ return ERESTART;
++ }
++ else if((status != MV_NO_MORE) && (status != MV_OK)) {
++ printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status);
++ goto p_error;
++ }
++
++
++#ifdef CESA_OCF_POLLING
++ cesa_interrupt_polling();
++#endif
++ cesaTestTraceAdd(5);
++
++ return 0;
++p_error:
++ crp->crp_etype = EINVAL;
++ if(cesa_ocf_cmd)
++ kfree(cesa_ocf_cmd);
++ if(cesa_ocf_cmd_wa)
++ kfree(cesa_ocf_cmd_wa);
++ return EINVAL;
++}
++
++/*
++ * cesa callback.
++ */
++static void
++cesa_callback(unsigned long dummy)
++{
++ struct cesa_ocf_process *cesa_ocf_cmd = NULL;
++ struct cryptop *crp = NULL;
++ MV_CESA_RESULT result[MV_CESA_MAX_CHAN];
++ int res_idx = 0,i;
++ MV_STATUS status;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++#ifdef CESA_OCF_TASKLET
++ disable_irq(cesa_device.irq);
++#endif
++ while(MV_TRUE) {
++
++ /* Get Ready requests */
++ spin_lock(&cesa_lock);
++ status = mvCesaReadyGet(&result[res_idx]);
++ spin_unlock(&cesa_lock);
++
++ cesaTestTraceAdd(2);
++
++ if(status != MV_OK) {
++#ifdef CESA_OCF_POLLING
++ if(status == MV_BUSY) { /* Fragment */
++ cesa_interrupt_polling();
++ return;
++ }
++#endif
++ break;
++ }
++ res_idx++;
++ break;
++ }
++
++ for(i = 0; i < res_idx; i++) {
++
++ if(!result[i].pReqPrv) {
++ printk("%s,%d: warning private is NULL\n", __FILE__, __LINE__);
++ break;
++ }
++
++ cesa_ocf_cmd = result[i].pReqPrv;
++ crp = cesa_ocf_cmd->crp;
++
++ // ignore HMAC error.
++ //if(result->retCode)
++ // crp->crp_etype = EIO;
++
++#if defined(CESA_OCF_POLLING)
++ if(!cesa_ocf_cmd->need_cb){
++ cesa_interrupt_polling();
++ }
++#endif
++ if(cesa_ocf_cmd->need_cb) {
++ if(debug) {
++ mvCesaDebugMbuf("DST BUFFER", cesa_ocf_cmd->cesa_cmd.pDst, 0, cesa_ocf_cmd->cesa_cmd.pDst->mbufSize);
++ }
++ crypto_done(crp);
++ }
++ kfree(cesa_ocf_cmd);
++ }
++#ifdef CESA_OCF_TASKLET
++ enable_irq(cesa_device.irq);
++#endif
++
++ cesaTestTraceAdd(3);
++
++ return;
++}
++
++#ifdef CESA_OCF_POLLING
++static void
++cesa_interrupt_polling(void)
++{
++ u32 cause;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ /* Read cause register */
++ do {
++ cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
++ cause &= MV_CESA_CAUSE_ACC_DMA_ALL_MASK;
++
++ } while (cause == 0);
++
++ /* clear interrupts */
++ MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0);
++
++ cesa_callback(0);
++
++ return;
++}
++
++#endif
++
++/*
++ * cesa Interrupt polling routine.
++ */
++static irqreturn_t
++cesa_interrupt_handler(int irq, void *arg)
++{
++ u32 cause;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ cesaTestTraceAdd(0);
++
++ /* Read cause register */
++ cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
++
++ if( (cause & MV_CESA_CAUSE_ACC_DMA_ALL_MASK) == 0)
++ {
++ /* Empty interrupt */
++ dprintk("%s,%d: cesaTestReadyIsr: cause=0x%x\n", __FILE__, __LINE__, cause);
++ return IRQ_HANDLED;
++ }
++
++ /* clear interrupts */
++ MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0);
++
++ cesaTestTraceAdd(1);
++#ifdef CESA_OCF_TASKLET
++ tasklet_hi_schedule(&cesa_ocf_tasklet);
++#else
++ cesa_callback(0);
++#endif
++ return IRQ_HANDLED;
++}
++
++/*
++ * Open a session.
++ */
++static int
++/*cesa_ocf_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri)*/
++cesa_ocf_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
++{
++ u32 status = 0, i;
++ u32 count = 0, auth = 0, encrypt =0;
++ struct cesa_ocf_data *cesa_ocf_cur_ses;
++ MV_CESA_OPEN_SESSION cesa_session;
++ MV_CESA_OPEN_SESSION *cesa_ses = &cesa_session;
++
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (sid == NULL || cri == NULL) {
++ printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ /* leave first empty like in other implementations */
++ for (i = 1; i < CESA_OCF_MAX_SES; i++) {
++ if (cesa_ocf_sessions[i] == NULL)
++ break;
++ }
++
++ if(i >= CESA_OCF_MAX_SES) {
++ printk("%s,%d: no more sessions \n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ cesa_ocf_sessions[i] = (struct cesa_ocf_data *) kmalloc(sizeof(struct cesa_ocf_data), GFP_ATOMIC);
++ if (cesa_ocf_sessions[i] == NULL) {
++ cesa_ocf_freesession(NULL, i);
++ printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
++ return ENOBUFS;
++ }
++ dprintk("%s,%d: new session %d \n", __FILE__, __LINE__, i);
++
++ *sid = i;
++ cesa_ocf_cur_ses = cesa_ocf_sessions[i];
++ memset(cesa_ocf_cur_ses, 0, sizeof(struct cesa_ocf_data));
++ cesa_ocf_cur_ses->sid_encrypt = -1;
++ cesa_ocf_cur_ses->sid_decrypt = -1;
++ cesa_ocf_cur_ses->frag_wa_encrypt = -1;
++ cesa_ocf_cur_ses->frag_wa_decrypt = -1;
++ cesa_ocf_cur_ses->frag_wa_auth = -1;
++
++ /* init the session */
++ memset(cesa_ses, 0, sizeof(MV_CESA_OPEN_SESSION));
++ count = 1;
++ while (cri) {
++ if(count > 2) {
++ printk("%s,%d: don't support more then 2 operations\n", __FILE__, __LINE__);
++ goto error;
++ }
++ switch (cri->cri_alg) {
++ case CRYPTO_AES_CBC:
++ dprintk("%s,%d: (%d) AES CBC \n", __FILE__, __LINE__, count);
++ cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
++ cesa_ocf_cur_ses->ivlen = MV_CESA_AES_BLOCK_SIZE;
++ cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_AES;
++ cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
++ if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
++ printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
++ goto error;
++ }
++ memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
++ dprintk("%s,%d: key length %d \n", __FILE__, __LINE__, cri->cri_klen/8);
++ cesa_ses->cryptoKeyLength = cri->cri_klen/8;
++ encrypt += count;
++ break;
++ case CRYPTO_3DES_CBC:
++ dprintk("%s,%d: (%d) 3DES CBC \n", __FILE__, __LINE__, count);
++ cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
++ cesa_ocf_cur_ses->ivlen = MV_CESA_3DES_BLOCK_SIZE;
++ cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_3DES;
++ cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
++ if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
++ printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
++ goto error;
++ }
++ memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
++ cesa_ses->cryptoKeyLength = cri->cri_klen/8;
++ encrypt += count;
++ break;
++ case CRYPTO_DES_CBC:
++ dprintk("%s,%d: (%d) DES CBC \n", __FILE__, __LINE__, count);
++ cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
++ cesa_ocf_cur_ses->ivlen = MV_CESA_DES_BLOCK_SIZE;
++ cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_DES;
++ cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
++ if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
++ printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
++ goto error;
++ }
++ memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
++ cesa_ses->cryptoKeyLength = cri->cri_klen/8;
++ encrypt += count;
++ break;
++ case CRYPTO_MD5:
++ case CRYPTO_MD5_HMAC:
++ dprintk("%s,%d: (%d) %sMD5 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_MD5)? "H-":" ");
++ cesa_ocf_cur_ses->auth_alg = cri->cri_alg;
++ cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MD5_DIGEST_SIZE : 12;
++ cesa_ses->macMode = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MAC_MD5 : MV_CESA_MAC_HMAC_MD5;
++ if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
++ printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__);
++ goto error;
++ }
++ cesa_ses->macKeyLength = cri->cri_klen/8;
++ memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8);
++ cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen;
++ auth += count;
++ break;
++ case CRYPTO_SHA1:
++ case CRYPTO_SHA1_HMAC:
++ dprintk("%s,%d: (%d) %sSHA1 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_SHA1)? "H-":" ");
++ cesa_ocf_cur_ses->auth_alg = cri->cri_alg;
++ cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_SHA1_DIGEST_SIZE : 12;
++ cesa_ses->macMode = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_MAC_SHA1 : MV_CESA_MAC_HMAC_SHA1;
++ if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
++ printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__);
++ goto error;
++ }
++ cesa_ses->macKeyLength = cri->cri_klen/8;
++ memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8);
++ cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen;
++ auth += count;
++ break;
++ default:
++ printk("%s,%d: unknown algo 0x%x\n", __FILE__, __LINE__, cri->cri_alg);
++ goto error;
++ }
++ cri = cri->cri_next;
++ count++;
++ }
++
++ if((encrypt > 2) || (auth > 2)) {
++ printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
++ goto error;
++ }
++ /* create new sessions in HAL */
++ if(encrypt) {
++ cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
++ /* encrypt session */
++ if(auth == 1) {
++ cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO;
++ }
++ else if(auth == 2) {
++ cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC;
++ cesa_ocf_cur_ses->encrypt_tn_auth = 1;
++ }
++ else {
++ cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
++ }
++ cesa_ses->direction = MV_CESA_DIR_ENCODE;
++ status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt);
++ if(status != MV_OK) {
++ printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
++ goto error;
++ }
++ /* decrypt session */
++ if( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) {
++ cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC;
++ }
++ else if( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC ) {
++ cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO;
++ }
++ cesa_ses->direction = MV_CESA_DIR_DECODE;
++ status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_decrypt);
++ if(status != MV_OK) {
++ printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
++ goto error;
++ }
++
++ /* preapre one action sessions for case we will need to split an action */
++#ifdef CESA_OCF_SPLIT
++ if(( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) ||
++ ( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC )) {
++ /* open one session for encode and one for decode */
++ cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
++ cesa_ses->direction = MV_CESA_DIR_ENCODE;
++ status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_encrypt);
++ if(status != MV_OK) {
++ printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
++ goto error;
++ }
++
++ cesa_ses->direction = MV_CESA_DIR_DECODE;
++ status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_decrypt);
++ if(status != MV_OK) {
++ printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
++ goto error;
++ }
++ /* open one session for auth */
++ cesa_ses->operation = MV_CESA_MAC_ONLY;
++ cesa_ses->direction = MV_CESA_DIR_ENCODE;
++ status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_auth);
++ if(status != MV_OK) {
++ printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
++ goto error;
++ }
++ }
++#endif
++ }
++ else { /* only auth */
++ cesa_ses->operation = MV_CESA_MAC_ONLY;
++ cesa_ses->direction = MV_CESA_DIR_ENCODE;
++ status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt);
++ if(status != MV_OK) {
++ printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
++ goto error;
++ }
++ }
++
++ return 0;
++error:
++ cesa_ocf_freesession(NULL, *sid);
++ return EINVAL;
++
++}
++
++
++/*
++ * Free a session.
++ */
++static int
++cesa_ocf_freesession(device_t dev, u_int64_t tid)
++{
++ struct cesa_ocf_data *cesa_ocf_cur_ses;
++ u_int32_t sid = CRYPTO_SESID2LID(tid);
++ //unsigned long flags;
++
++ dprintk("%s() %d \n", __FUNCTION__, sid);
++ if ( (sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL) ) {
++ printk("%s,%d: EINVAL can't free session %d \n", __FILE__, __LINE__, sid);
++ return(EINVAL);
++ }
++
++ /* Silently accept and return */
++ if (sid == 0)
++ return(0);
++
++ /* release session from HAL */
++ cesa_ocf_cur_ses = cesa_ocf_sessions[sid];
++ if (cesa_ocf_cur_ses->sid_encrypt != -1) {
++ mvCesaSessionClose(cesa_ocf_cur_ses->sid_encrypt);
++ }
++ if (cesa_ocf_cur_ses->sid_decrypt != -1) {
++ mvCesaSessionClose(cesa_ocf_cur_ses->sid_decrypt);
++ }
++ if (cesa_ocf_cur_ses->frag_wa_encrypt != -1) {
++ mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_encrypt);
++ }
++ if (cesa_ocf_cur_ses->frag_wa_decrypt != -1) {
++ mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_decrypt);
++ }
++ if (cesa_ocf_cur_ses->frag_wa_auth != -1) {
++ mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_auth);
++ }
++
++ kfree(cesa_ocf_cur_ses);
++ cesa_ocf_sessions[sid] = NULL;
++
++ return 0;
++}
++
++
++/* TDMA Window setup */
++
++static void __init
++setup_tdma_mbus_windows(struct cesa_dev *dev)
++{
++ int i;
++
++ for (i = 0; i < 4; i++) {
++ writel(0, dev->reg + WINDOW_BASE(i));
++ writel(0, dev->reg + WINDOW_CTRL(i));
++ }
++
++ for (i = 0; i < dev->plat_data->dram->num_cs; i++) {
++ struct mbus_dram_window *cs = dev->plat_data->dram->cs + i;
++ writel(
++ ((cs->size - 1) & 0xffff0000) |
++ (cs->mbus_attr << 8) |
++ (dev->plat_data->dram->mbus_dram_target_id << 4) | 1,
++ dev->reg + WINDOW_CTRL(i)
++ );
++ writel(cs->base, dev->reg + WINDOW_BASE(i));
++ }
++}
++
++/*
++ * our driver startup and shutdown routines
++ */
++static int
++mv_cesa_ocf_init(struct platform_device *pdev)
++{
++#if defined(CONFIG_MV78200) || defined(CONFIG_MV632X)
++ if (MV_FALSE == mvSocUnitIsMappedToThisCpu(CESA))
++ {
++ dprintk("CESA is not mapped to this CPU\n");
++ return -ENODEV;
++ }
++#endif
++
++ dprintk("%s\n", __FUNCTION__);
++ memset(&mv_cesa_dev, 0, sizeof(mv_cesa_dev));
++ softc_device_init(&mv_cesa_dev, "MV CESA", 0, mv_cesa_methods);
++ cesa_ocf_id = crypto_get_driverid(softc_get_device(&mv_cesa_dev),CRYPTOCAP_F_HARDWARE);
++
++ if (cesa_ocf_id < 0)
++ panic("MV CESA crypto device cannot initialize!");
++
++ dprintk("%s,%d: cesa ocf device id is %d \n", __FILE__, __LINE__, cesa_ocf_id);
++
++ /* CESA unit is auto power on off */
++#if 0
++ if (MV_FALSE == mvCtrlPwrClckGet(CESA_UNIT_ID,0))
++ {
++ printk("\nWarning CESA %d is Powered Off\n",0);
++ return EINVAL;
++ }
++#endif
++
++ memset(&cesa_device, 0, sizeof(struct cesa_dev));
++ /* Get the IRQ, and crypto memory regions */
++ {
++ struct resource *res;
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
++
++ if (!res)
++ return -ENXIO;
++
++ cesa_device.sram = ioremap(res->start, res->end - res->start + 1);
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
++
++ if (!res) {
++ iounmap(cesa_device.sram);
++ return -ENXIO;
++ }
++ cesa_device.reg = ioremap(res->start, res->end - res->start + 1);
++ cesa_device.irq = platform_get_irq(pdev, 0);
++ cesa_device.plat_data = pdev->dev.platform_data;
++ setup_tdma_mbus_windows(&cesa_device);
++
++ }
++
++
++ if( MV_OK != mvCesaInit(CESA_OCF_MAX_SES*5, CESA_Q_SIZE, cesa_device.reg,
++ NULL) ) {
++ printk("%s,%d: mvCesaInit Failed. \n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ /* clear and unmask Int */
++ MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0);
++#ifndef CESA_OCF_POLLING
++ MV_REG_WRITE( MV_CESA_ISR_MASK_REG, MV_CESA_CAUSE_ACC_DMA_MASK);
++#endif
++#ifdef CESA_OCF_TASKLET
++ tasklet_init(&cesa_ocf_tasklet, cesa_callback, (unsigned int) 0);
++#endif
++ /* register interrupt */
++ if( request_irq( cesa_device.irq, cesa_interrupt_handler,
++ (IRQF_DISABLED) , "cesa", &cesa_ocf_id) < 0) {
++ printk("%s,%d: cannot assign irq %x\n", __FILE__, __LINE__, cesa_device.reg);
++ return EINVAL;
++ }
++
++
++ memset(cesa_ocf_sessions, 0, sizeof(struct cesa_ocf_data *) * CESA_OCF_MAX_SES);
++
++#define REGISTER(alg) \
++ crypto_register(cesa_ocf_id, alg, 0,0)
++ REGISTER(CRYPTO_AES_CBC);
++ REGISTER(CRYPTO_DES_CBC);
++ REGISTER(CRYPTO_3DES_CBC);
++ REGISTER(CRYPTO_MD5);
++ REGISTER(CRYPTO_MD5_HMAC);
++ REGISTER(CRYPTO_SHA1);
++ REGISTER(CRYPTO_SHA1_HMAC);
++#undef REGISTER
++
++ return 0;
++}
++
++static void
++mv_cesa_ocf_exit(struct platform_device *pdev)
++{
++ dprintk("%s()\n", __FUNCTION__);
++
++ crypto_unregister_all(cesa_ocf_id);
++ cesa_ocf_id = -1;
++ iounmap(cesa_device.reg);
++ iounmap(cesa_device.sram);
++ free_irq(cesa_device.irq, NULL);
++
++ /* mask and clear Int */
++ MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0);
++ MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0);
++
++
++ if( MV_OK != mvCesaFinish() ) {
++ printk("%s,%d: mvCesaFinish Failed. \n", __FILE__, __LINE__);
++ return;
++ }
++}
++
++
++void cesa_ocf_debug(void)
++{
++
++#ifdef CESA_OCF_TRACE_DEBUG
++ {
++ int i, j;
++ j = cesaTestTraceIdx;
++ mvOsPrintf("No Type rCause iCause Proc Isr Res Time pReady pProc pEmpty\n");
++ for(i=0; i<MV_CESA_TEST_TRACE_SIZE; i++)
++ {
++ mvOsPrintf("%02d. %d 0x%04x 0x%04x 0x%02x 0x%02x %02d 0x%06x %p %p %p\n",
++ j, cesaTestTrace[j].type, cesaTestTrace[j].realCause,
++ cesaTestTrace[j].idmaCause,
++ cesaTestTrace[j].resources, cesaTestTrace[j].timeStamp,
++ cesaTestTrace[j].pReqReady, cesaTestTrace[j].pReqProcess, cesaTestTrace[j].pReqEmpty);
++ j++;
++ if(j == MV_CESA_TEST_TRACE_SIZE)
++ j = 0;
++ }
++ }
++#endif
++
++}
++
++static struct platform_driver marvell_cesa = {
++ .probe = mv_cesa_ocf_init,
++ .remove = mv_cesa_ocf_exit,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "mv_crypto",
++ },
++};
++
++MODULE_ALIAS("platform:mv_crypto");
++
++static int __init mv_cesa_init(void)
++{
++ return platform_driver_register(&marvell_cesa);
++}
++
++module_init(mv_cesa_init);
++
++static void __exit mv_cesa_exit(void)
++{
++ platform_driver_unregister(&marvell_cesa);
++}
++
++module_exit(mv_cesa_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Ronen Shitrit");
++MODULE_DESCRIPTION("OCF module for Orion CESA crypto");
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/Makefile linux-2.6.36/crypto/ocf/kirkwood/Makefile
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/Makefile 2010-11-09 20:28:06.092495440 +0100
+@@ -0,0 +1,19 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_KIRKWOOD) += mv_cesa.o
++
++mv_cesa-y := cesa/mvCesa.o cesa/mvLru.o cesa/mvMD5.o cesa/mvSHA1.o cesa/AES/mvAesAlg.o cesa/AES/mvAesApi.o cesa/mvCesaDebug.o cesa_ocf_drv.o
++
++# Extra objects required by the CESA driver
++mv_cesa-y += mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.o mvHal/kw_family/boardEnv/mvBoardEnvLib.o mvHal/mv_hal/twsi/mvTwsi.o mvHal/kw_family/ctrlEnv/sys/mvCpuIf.o mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.o mvHal/kw_family/ctrlEnv/sys/mvSysDram.o mvHal/linux_oss/mvOs.o mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.o mvHal/mv_hal/gpp/mvGpp.o mvHal/kw_family/ctrlEnv/sys/mvSysPex.o mvHal/mv_hal/pex/mvPex.o mvHal/kw_family/boardEnv/mvBoardEnvSpec.o mvHal/common/mvCommon.o mvHal/common/mvDebug.o mvHal/kw_family/ctrlEnv/sys/mvSysCesa.o
++
++ifdef src
++EXTRA_CFLAGS += -I$(src)/.. -I$(src)/cesa -I$(src)/mvHal -I$(src)/mvHal/common -I$(src)/mvHal/kw_family -I$(src)/mvHal/mv_hal -I$(src)/mvHal/linux_oss -I$(src)
++endif
++
++EXTRA_CFLAGS += -DMV_LINUX -DMV_CPU_LE -DMV_ARM -DMV_INCLUDE_CESA -DMV_INCLUDE_PEX -DMV_CACHE_COHERENCY=3
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mv802_3.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mv802_3.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mv802_3.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mv802_3.h 2010-11-09 20:28:06.131247793 +0100
+@@ -0,0 +1,213 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmv802_3h
++#define __INCmv802_3h
++
++
++/* includes */
++#include "mvTypes.h"
++
++/* Defines */
++#define MV_MAX_ETH_DATA 1500
++
++/* 802.3 types */
++#define MV_IP_TYPE 0x0800
++#define MV_IP_ARP_TYPE 0x0806
++#define MV_APPLE_TALK_ARP_TYPE 0x80F3
++#define MV_NOVELL_IPX_TYPE 0x8137
++#define MV_EAPOL_TYPE 0x888e
++
++
++
++/* Encapsulation header for RFC1042 and Ethernet_tunnel */
++
++#define MV_RFC1042_SNAP_HEADER {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00}
++
++#define MV_ETH_SNAP_LSB 0xF8
++
++
++#define MV_MAC_ADDR_SIZE (6)
++#define MV_MAC_STR_SIZE (20)
++#define MV_VLAN_HLEN (4)
++
++/* This macro checks for a multicast mac address */
++#define MV_IS_MULTICAST_MAC(mac) (((mac)[0] & 0x1) == 1)
++
++
++/* This macro checks for an broadcast mac address */
++#define MV_IS_BROADCAST_MAC(mac) \
++ (((mac)[0] == 0xFF) && \
++ ((mac)[1] == 0xFF) && \
++ ((mac)[2] == 0xFF) && \
++ ((mac)[3] == 0xFF) && \
++ ((mac)[4] == 0xFF) && \
++ ((mac)[5] == 0xFF))
++
++
++/* Typedefs */
++typedef struct
++{
++ MV_U8 pDA[MV_MAC_ADDR_SIZE];
++ MV_U8 pSA[MV_MAC_ADDR_SIZE];
++ MV_U16 typeOrLen;
++
++} MV_802_3_HEADER;
++
++enum {
++ MV_IP_PROTO_NULL = 0, /* Dummy protocol for TCP */
++ MV_IP_PROTO_ICMP = 1, /* Internet Control Message Protocol */
++ MV_IP_PROTO_IGMP = 2, /* Internet Group Management Protocol */
++ MV_IP_PROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */
++ MV_IP_PROTO_TCP = 6, /* Transmission Control Protocol */
++ MV_IP_PROTO_EGP = 8, /* Exterior Gateway Protocol */
++ MV_IP_PROTO_PUP = 12, /* PUP protocol */
++ MV_IP_PROTO_UDP = 17, /* User Datagram Protocol */
++ MV_IP_PROTO_IDP = 22, /* XNS IDP protocol */
++ MV_IP_PROTO_DCCP = 33, /* Datagram Congestion Control Protocol */
++ MV_IP_PROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */
++ MV_IP_PROTO_RSVP = 46, /* RSVP protocol */
++ MV_IP_PROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */
++ MV_IP_PROTO_ESP = 50, /* Encapsulation Security Payload protocol */
++ MV_IP_PROTO_AH = 51, /* Authentication Header protocol */
++ MV_IP_PROTO_BEETPH = 94, /* IP option pseudo header for BEET */
++ MV_IP_PROTO_PIM = 103,
++ MV_IP_PROTO_COMP = 108, /* Compression Header protocol */
++ MV_IP_PROTO_ZERO_HOP = 114, /* Any 0 hop protocol (IANA) */
++ MV_IP_PROTO_SCTP = 132, /* Stream Control Transport Protocol */
++ MV_IP_PROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */
++
++ MV_IP_PROTO_RAW = 255, /* Raw IP packets */
++ MV_IP_PROTO_MAX
++};
++
++typedef struct
++{
++ MV_U8 version;
++ MV_U8 tos;
++ MV_U16 totalLength;
++ MV_U16 identifier;
++ MV_U16 fragmentCtrl;
++ MV_U8 ttl;
++ MV_U8 protocol;
++ MV_U16 checksum;
++ MV_U32 srcIP;
++ MV_U32 dstIP;
++
++} MV_IP_HEADER;
++
++typedef struct
++{
++ MV_U32 spi;
++ MV_U32 seqNum;
++} MV_ESP_HEADER;
++
++#define MV_ICMP_ECHOREPLY 0 /* Echo Reply */
++#define MV_ICMP_DEST_UNREACH 3 /* Destination Unreachable */
++#define MV_ICMP_SOURCE_QUENCH 4 /* Source Quench */
++#define MV_ICMP_REDIRECT 5 /* Redirect (change route) */
++#define MV_ICMP_ECHO 8 /* Echo Request */
++#define MV_ICMP_TIME_EXCEEDED 11 /* Time Exceeded */
++#define MV_ICMP_PARAMETERPROB 12 /* Parameter Problem */
++#define MV_ICMP_TIMESTAMP 13 /* Timestamp Request */
++#define MV_ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */
++#define MV_ICMP_INFO_REQUEST 15 /* Information Request */
++#define MV_ICMP_INFO_REPLY 16 /* Information Reply */
++#define MV_ICMP_ADDRESS 17 /* Address Mask Request */
++#define MV_ICMP_ADDRESSREPLY 18 /* Address Mask Reply */
++
++typedef struct
++{
++ MV_U8 type;
++ MV_U8 code;
++ MV_U16 checksum;
++ MV_U16 id;
++ MV_U16 sequence;
++
++} MV_ICMP_ECHO_HEADER;
++
++typedef struct
++{
++ MV_U16 source;
++ MV_U16 dest;
++ MV_U32 seq;
++ MV_U32 ack_seq;
++ MV_U16 flags;
++ MV_U16 window;
++ MV_U16 chksum;
++ MV_U16 urg_offset;
++
++} MV_TCP_HEADER;
++
++typedef struct
++{
++ MV_U16 source;
++ MV_U16 dest;
++ MV_U16 len;
++ MV_U16 check;
++
++} MV_UDP_HEADER;
++
++#endif /* __INCmv802_3h */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvCommon.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvCommon.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvCommon.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvCommon.c 2010-11-09 20:28:06.172495450 +0100
+@@ -0,0 +1,277 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvOs.h"
++#include "mv802_3.h"
++#include "mvCommon.h"
++
++
++/*******************************************************************************
++* mvMacStrToHex - Convert MAC format string to hex.
++*
++* DESCRIPTION:
++* This function convert MAC format string to hex.
++*
++* INPUT:
++* macStr - MAC address string. Fornat of address string is
++* uu:vv:ww:xx:yy:zz, where ":" can be any delimiter.
++*
++* OUTPUT:
++* macHex - MAC in hex format.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvMacStrToHex(const char* macStr, MV_U8* macHex)
++{
++ int i;
++ char tmp[3];
++
++ for(i = 0; i < MV_MAC_ADDR_SIZE; i++)
++ {
++ tmp[0] = macStr[(i * 3) + 0];
++ tmp[1] = macStr[(i * 3) + 1];
++ tmp[2] = '\0';
++ macHex[i] = (MV_U8) (strtol(tmp, NULL, 16));
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvMacHexToStr - Convert MAC in hex format to string format.
++*
++* DESCRIPTION:
++* This function convert MAC in hex format to string format.
++*
++* INPUT:
++* macHex - MAC in hex format.
++*
++* OUTPUT:
++* macStr - MAC address string. String format is uu:vv:ww:xx:yy:zz.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvMacHexToStr(MV_U8* macHex, char* macStr)
++{
++ int i;
++
++ for(i = 0; i < MV_MAC_ADDR_SIZE; i++)
++ {
++ mvOsSPrintf(&macStr[i * 3], "%02x:", macHex[i]);
++ }
++ macStr[(i * 3) - 1] = '\0';
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSizePrint - Print the given size with size unit description.
++*
++* DESCRIPTION:
++* This function print the given size with size unit description.
++* FOr example when size paramter is 0x180000, the function prints:
++* "size 1MB+500KB"
++*
++* INPUT:
++* size - Size in bytes.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvSizePrint(MV_U32 size)
++{
++ mvOsOutput("size ");
++
++ if(size >= _1G)
++ {
++ mvOsOutput("%3dGB ", size / _1G);
++ size %= _1G;
++ if(size)
++ mvOsOutput("+");
++ }
++ if(size >= _1M )
++ {
++ mvOsOutput("%3dMB ", size / _1M);
++ size %= _1M;
++ if(size)
++ mvOsOutput("+");
++ }
++ if(size >= _1K)
++ {
++ mvOsOutput("%3dKB ", size / _1K);
++ size %= _1K;
++ if(size)
++ mvOsOutput("+");
++ }
++ if(size > 0)
++ {
++ mvOsOutput("%3dB ", size);
++ }
++}
++
++/*******************************************************************************
++* mvHexToBin - Convert hex to binary
++*
++* DESCRIPTION:
++* This function Convert hex to binary.
++*
++* INPUT:
++* pHexStr - hex buffer pointer.
++* size - Size to convert.
++*
++* OUTPUT:
++* pBin - Binary buffer pointer.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvHexToBin(const char* pHexStr, MV_U8* pBin, int size)
++{
++ int j, i;
++ char tmp[3];
++ MV_U8 byte;
++
++ for(j=0, i=0; j<size; j++, i+=2)
++ {
++ tmp[0] = pHexStr[i];
++ tmp[1] = pHexStr[i+1];
++ tmp[2] = '\0';
++ byte = (MV_U8) (strtol(tmp, NULL, 16) & 0xFF);
++ pBin[j] = byte;
++ }
++}
++
++void mvAsciiToHex(const char* asciiStr, char* hexStr)
++{
++ int i=0;
++
++ while(asciiStr[i] != 0)
++ {
++ mvOsSPrintf(&hexStr[i*2], "%02x", asciiStr[i]);
++ i++;
++ }
++ hexStr[i*2] = 0;
++}
++
++
++void mvBinToHex(const MV_U8* bin, char* hexStr, int size)
++{
++ int i;
++
++ for(i=0; i<size; i++)
++ {
++ mvOsSPrintf(&hexStr[i*2], "%02x", bin[i]);
++ }
++ hexStr[i*2] = '\0';
++}
++
++void mvBinToAscii(const MV_U8* bin, char* asciiStr, int size)
++{
++ int i;
++
++ for(i=0; i<size; i++)
++ {
++ mvOsSPrintf(&asciiStr[i*2], "%c", bin[i]);
++ }
++ asciiStr[i*2] = '\0';
++}
++
++/*******************************************************************************
++* mvLog2 -
++*
++* DESCRIPTION:
++* Calculate the Log2 of a given number.
++*
++* INPUT:
++* num - A number to calculate the Log2 for.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Log 2 of the input number, or 0xFFFFFFFF if input is 0.
++*
++*******************************************************************************/
++MV_U32 mvLog2(MV_U32 num)
++{
++ MV_U32 result = 0;
++ if(num == 0)
++ return 0xFFFFFFFF;
++ while(num != 1)
++ {
++ num = num >> 1;
++ result++;
++ }
++ return result;
++}
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvCommon.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvCommon.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvCommon.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvCommon.h 2010-11-09 20:28:06.212495496 +0100
+@@ -0,0 +1,308 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvCommonh
++#define __INCmvCommonh
++
++#include "mvTypes.h"
++
++/* Swap tool */
++
++/* 16bit nibble swap. For example 0x1234 -> 0x2143 */
++#define MV_NIBBLE_SWAP_16BIT(X) (((X&0xf) << 4) | \
++ ((X&0xf0) >> 4) | \
++ ((X&0xf00) << 4) | \
++ ((X&0xf000) >> 4))
++
++/* 32bit nibble swap. For example 0x12345678 -> 0x21436587 */
++#define MV_NIBBLE_SWAP_32BIT(X) (((X&0xf) << 4) | \
++ ((X&0xf0) >> 4) | \
++ ((X&0xf00) << 4) | \
++ ((X&0xf000) >> 4) | \
++ ((X&0xf0000) << 4) | \
++ ((X&0xf00000) >> 4) | \
++ ((X&0xf000000) << 4) | \
++ ((X&0xf0000000) >> 4))
++
++/* 16bit byte swap. For example 0x1122 -> 0x2211 */
++#define MV_BYTE_SWAP_16BIT(X) ((((X)&0xff)<<8) | (((X)&0xff00)>>8))
++
++/* 32bit byte swap. For example 0x11223344 -> 0x44332211 */
++#define MV_BYTE_SWAP_32BIT(X) ((((X)&0xff)<<24) | \
++ (((X)&0xff00)<<8) | \
++ (((X)&0xff0000)>>8) | \
++ (((X)&0xff000000)>>24))
++
++/* 64bit byte swap. For example 0x11223344.55667788 -> 0x88776655.44332211 */
++#define MV_BYTE_SWAP_64BIT(X) ((l64) ((((X)&0xffULL)<<56) | \
++ (((X)&0xff00ULL)<<40) | \
++ (((X)&0xff0000ULL)<<24) | \
++ (((X)&0xff000000ULL)<<8) | \
++ (((X)&0xff00000000ULL)>>8) | \
++ (((X)&0xff0000000000ULL)>>24) | \
++ (((X)&0xff000000000000ULL)>>40) | \
++ (((X)&0xff00000000000000ULL)>>56)))
++
++/* Endianess macros. */
++#if defined(MV_CPU_LE)
++ #define MV_16BIT_LE(X) (X)
++ #define MV_32BIT_LE(X) (X)
++ #define MV_64BIT_LE(X) (X)
++ #define MV_16BIT_BE(X) MV_BYTE_SWAP_16BIT(X)
++ #define MV_32BIT_BE(X) MV_BYTE_SWAP_32BIT(X)
++ #define MV_64BIT_BE(X) MV_BYTE_SWAP_64BIT(X)
++#elif defined(MV_CPU_BE)
++ #define MV_16BIT_LE(X) MV_BYTE_SWAP_16BIT(X)
++ #define MV_32BIT_LE(X) MV_BYTE_SWAP_32BIT(X)
++ #define MV_64BIT_LE(X) MV_BYTE_SWAP_64BIT(X)
++ #define MV_16BIT_BE(X) (X)
++ #define MV_32BIT_BE(X) (X)
++ #define MV_64BIT_BE(X) (X)
++#else
++ #error "CPU endianess isn't defined!\n"
++#endif
++
++
++/* Bit field definitions */
++#define NO_BIT 0x00000000
++#define BIT0 0x00000001
++#define BIT1 0x00000002
++#define BIT2 0x00000004
++#define BIT3 0x00000008
++#define BIT4 0x00000010
++#define BIT5 0x00000020
++#define BIT6 0x00000040
++#define BIT7 0x00000080
++#define BIT8 0x00000100
++#define BIT9 0x00000200
++#define BIT10 0x00000400
++#define BIT11 0x00000800
++#define BIT12 0x00001000
++#define BIT13 0x00002000
++#define BIT14 0x00004000
++#define BIT15 0x00008000
++#define BIT16 0x00010000
++#define BIT17 0x00020000
++#define BIT18 0x00040000
++#define BIT19 0x00080000
++#define BIT20 0x00100000
++#define BIT21 0x00200000
++#define BIT22 0x00400000
++#define BIT23 0x00800000
++#define BIT24 0x01000000
++#define BIT25 0x02000000
++#define BIT26 0x04000000
++#define BIT27 0x08000000
++#define BIT28 0x10000000
++#define BIT29 0x20000000
++#define BIT30 0x40000000
++#define BIT31 0x80000000
++
++/* Handy sizes */
++#define _1K 0x00000400
++#define _2K 0x00000800
++#define _4K 0x00001000
++#define _8K 0x00002000
++#define _16K 0x00004000
++#define _32K 0x00008000
++#define _64K 0x00010000
++#define _128K 0x00020000
++#define _256K 0x00040000
++#define _512K 0x00080000
++
++#define _1M 0x00100000
++#define _2M 0x00200000
++#define _4M 0x00400000
++#define _8M 0x00800000
++#define _16M 0x01000000
++#define _32M 0x02000000
++#define _64M 0x04000000
++#define _128M 0x08000000
++#define _256M 0x10000000
++#define _512M 0x20000000
++
++#define _1G 0x40000000
++#define _2G 0x80000000
++
++/* Tclock and Sys clock define */
++#define _100MHz 100000000
++#define _125MHz 125000000
++#define _133MHz 133333334
++#define _150MHz 150000000
++#define _160MHz 160000000
++#define _166MHz 166666667
++#define _175MHz 175000000
++#define _178MHz 178000000
++#define _183MHz 183333334
++#define _187MHz 187000000
++#define _192MHz 192000000
++#define _194MHz 194000000
++#define _200MHz 200000000
++#define _233MHz 233333334
++#define _250MHz 250000000
++#define _266MHz 266666667
++#define _300MHz 300000000
++
++/* For better address window table readability */
++#define EN MV_TRUE
++#define DIS MV_FALSE
++#define N_A -1 /* Not applicable */
++
++/* Cache configuration options for memory (DRAM, SRAM, ... ) */
++
++/* Memory uncached, HW or SW cache coherency is not needed */
++#define MV_UNCACHED 0
++/* Memory cached, HW cache coherency supported in WriteThrough mode */
++#define MV_CACHE_COHER_HW_WT 1
++/* Memory cached, HW cache coherency supported in WriteBack mode */
++#define MV_CACHE_COHER_HW_WB 2
++/* Memory cached, No HW cache coherency, Cache coherency must be in SW */
++#define MV_CACHE_COHER_SW 3
++
++
++/* Macro for testing aligment. Positive if number is NOT aligned */
++#define MV_IS_NOT_ALIGN(number, align) ((number) & ((align) - 1))
++
++/* Macro for alignment up. For example, MV_ALIGN_UP(0x0330, 0x20) = 0x0340 */
++#define MV_ALIGN_UP(number, align) \
++(((number) & ((align) - 1)) ? (((number) + (align)) & ~((align)-1)) : (number))
++
++/* Macro for alignment down. For example, MV_ALIGN_UP(0x0330, 0x20) = 0x0320 */
++#define MV_ALIGN_DOWN(number, align) ((number) & ~((align)-1))
++
++/* This macro returns absolute value */
++#define MV_ABS(number) (((int)(number) < 0) ? -(int)(number) : (int)(number))
++
++
++/* Bit fields manipulation macros */
++
++/* An integer word which its 'x' bit is set */
++#define MV_BIT_MASK(bitNum) (1 << (bitNum) )
++
++/* Checks wheter bit 'x' in integer word is set */
++#define MV_BIT_CHECK(word, bitNum) ( (word) & MV_BIT_MASK(bitNum) )
++
++/* Clear (reset) bit 'x' in integer word (RMW - Read-Modify-Write) */
++#define MV_BIT_CLEAR(word, bitNum) ( (word) &= ~(MV_BIT_MASK(bitNum)) )
++
++/* Set bit 'x' in integer word (RMW) */
++#define MV_BIT_SET(word, bitNum) ( (word) |= MV_BIT_MASK(bitNum) )
++
++/* Invert bit 'x' in integer word (RMW) */
++#define MV_BIT_INV(word, bitNum) ( (word) ^= MV_BIT_MASK(bitNum) )
++
++/* Get the min between 'a' or 'b' */
++#define MV_MIN(a,b) (((a) < (b)) ? (a) : (b))
++
++/* Get the max between 'a' or 'b' */
++#define MV_MAX(a,b) (((a) < (b)) ? (b) : (a))
++
++/* Temporary */
++#define mvOsDivide(num, div) \
++({ \
++ int i=0, rem=(num); \
++ \
++ while(rem >= (div)) \
++ { \
++ rem -= (div); \
++ i++; \
++ } \
++ (i); \
++})
++
++/* Temporary */
++#define mvOsReminder(num, div) \
++({ \
++ int rem = (num); \
++ \
++ while(rem >= (div)) \
++ rem -= (div); \
++ (rem); \
++})
++
++#define MV_IP_QUAD(ipAddr) ((ipAddr >> 24) & 0xFF), ((ipAddr >> 16) & 0xFF), \
++ ((ipAddr >> 8) & 0xFF), ((ipAddr >> 0) & 0xFF)
++
++#define MV_IS_POWER_OF_2(num) ((num != 0) && ((num & (num - 1)) == 0))
++
++#ifndef MV_ASMLANGUAGE
++/* mvCommon API list */
++
++MV_VOID mvHexToBin(const char* pHexStr, MV_U8* pBin, int size);
++void mvAsciiToHex(const char* asciiStr, char* hexStr);
++void mvBinToHex(const MV_U8* bin, char* hexStr, int size);
++void mvBinToAscii(const MV_U8* bin, char* asciiStr, int size);
++
++MV_STATUS mvMacStrToHex(const char* macStr, MV_U8* macHex);
++MV_STATUS mvMacHexToStr(MV_U8* macHex, char* macStr);
++void mvSizePrint(MV_U32);
++
++MV_U32 mvLog2(MV_U32 num);
++
++#endif /* MV_ASMLANGUAGE */
++
++
++#endif /* __INCmvCommonh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvDebug.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvDebug.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvDebug.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvDebug.c 2010-11-09 20:28:06.252495437 +0100
+@@ -0,0 +1,326 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++
++
++/* includes */
++#include "mvOs.h"
++#include "mv802_3.h"
++#include "mvCommon.h"
++#include "mvDebug.h"
++
++/* Global variables effect on behave MV_DEBUG_PRINT and MV_DEBUG_CODE macros
++ * mvDebug - map of bits (one for each module) bit=1 means enable
++ * debug code and messages for this module
++ * mvModuleDebug - array of 32 bits varables one for each module
++ */
++MV_U32 mvDebug = 0;
++MV_U32 mvDebugModules[MV_MODULE_MAX];
++
++/* Init mvModuleDebug array to default values */
++void mvDebugInit(void)
++{
++ int bit;
++
++ mvDebug = 0;
++ for(bit=0; bit<MV_MODULE_MAX; bit++)
++ {
++ mvDebugModules[bit] = MV_DEBUG_FLAG_ERR | MV_DEBUG_FLAG_STATS;
++ mvDebug |= MV_BIT_MASK(bit);
++ }
++}
++
++void mvDebugModuleEnable(MV_MODULE_ID module, MV_BOOL isEnable)
++{
++ if (isEnable)
++ {
++ MV_BIT_SET(mvDebug, module);
++ }
++ else
++ MV_BIT_CLEAR(mvDebug, module);
++}
++
++void mvDebugModuleSetFlags(MV_MODULE_ID module, MV_U32 flags)
++{
++ mvDebugModules[module] |= flags;
++}
++
++void mvDebugModuleClearFlags(MV_MODULE_ID module, MV_U32 flags)
++{
++ mvDebugModules[module] &= ~flags;
++}
++
++/* Dump memory in specific format:
++ * address: X1X1X1X1 X2X2X2X2 ... X8X8X8X8
++ */
++void mvDebugMemDump(void* addr, int size, int access)
++{
++ int i, j;
++ MV_U32 memAddr = (MV_U32)addr;
++
++ if(access == 0)
++ access = 1;
++
++ if( (access != 4) && (access != 2) && (access != 1) )
++ {
++ mvOsPrintf("%d wrong access size. Access must be 1 or 2 or 4\n",
++ access);
++ return;
++ }
++ memAddr = MV_ALIGN_DOWN( (unsigned int)addr, 4);
++ size = MV_ALIGN_UP(size, 4);
++ addr = (void*)MV_ALIGN_DOWN( (unsigned int)addr, access);
++ while(size > 0)
++ {
++ mvOsPrintf("%08x: ", memAddr);
++ i = 0;
++ /* 32 bytes in the line */
++ while(i < 32)
++ {
++ if(memAddr >= (MV_U32)addr)
++ {
++ switch(access)
++ {
++ case 1:
++ if( memAddr == CPU_PHY_MEM(memAddr) )
++ {
++ mvOsPrintf("%02x ", MV_MEMIO8_READ(memAddr));
++ }
++ else
++ {
++ mvOsPrintf("%02x ", *((MV_U8*)memAddr));
++ }
++ break;
++
++ case 2:
++ if( memAddr == CPU_PHY_MEM(memAddr) )
++ {
++ mvOsPrintf("%04x ", MV_MEMIO16_READ(memAddr));
++ }
++ else
++ {
++ mvOsPrintf("%04x ", *((MV_U16*)memAddr));
++ }
++ break;
++
++ case 4:
++ if( memAddr == CPU_PHY_MEM(memAddr) )
++ {
++ mvOsPrintf("%08x ", MV_MEMIO32_READ(memAddr));
++ }
++ else
++ {
++ mvOsPrintf("%08x ", *((MV_U32*)memAddr));
++ }
++ break;
++ }
++ }
++ else
++ {
++ for(j=0; j<(access*2+1); j++)
++ mvOsPrintf(" ");
++ }
++ i += access;
++ memAddr += access;
++ size -= access;
++ if(size <= 0)
++ break;
++ }
++ mvOsPrintf("\n");
++ }
++}
++
++void mvDebugPrintBufInfo(BUF_INFO* pBufInfo, int size, int access)
++{
++ if(pBufInfo == NULL)
++ {
++ mvOsPrintf("\n!!! pBufInfo = NULL\n");
++ return;
++ }
++ mvOsPrintf("\n*** pBufInfo=0x%x, cmdSts=0x%08x, pBuf=0x%x, bufSize=%d\n",
++ (unsigned int)pBufInfo,
++ (unsigned int)pBufInfo->cmdSts,
++ (unsigned int)pBufInfo->pBuff,
++ (unsigned int)pBufInfo->bufSize);
++ mvOsPrintf("pData=0x%x, byteCnt=%d, pNext=0x%x, uInfo1=0x%x, uInfo2=0x%x\n",
++ (unsigned int)pBufInfo->pData,
++ (unsigned int)pBufInfo->byteCnt,
++ (unsigned int)pBufInfo->pNextBufInfo,
++ (unsigned int)pBufInfo->userInfo1,
++ (unsigned int)pBufInfo->userInfo2);
++ if(pBufInfo->pData != NULL)
++ {
++ if(size > pBufInfo->byteCnt)
++ size = pBufInfo->byteCnt;
++ mvDebugMemDump(pBufInfo->pData, size, access);
++ }
++}
++
++void mvDebugPrintPktInfo(MV_PKT_INFO* pPktInfo, int size, int access)
++{
++ int frag, len;
++
++ if(pPktInfo == NULL)
++ {
++ mvOsPrintf("\n!!! pPktInfo = NULL\n");
++ return;
++ }
++ mvOsPrintf("\npPkt=%p, stat=0x%08x, numFr=%d, size=%d, pFr=%p, osInfo=0x%lx\n",
++ pPktInfo, pPktInfo->status, pPktInfo->numFrags, pPktInfo->pktSize,
++ pPktInfo->pFrags, pPktInfo->osInfo);
++
++ for(frag=0; frag<pPktInfo->numFrags; frag++)
++ {
++ mvOsPrintf("#%2d. bufVirt=%p, bufSize=%d\n",
++ frag, pPktInfo->pFrags[frag].bufVirtPtr,
++ pPktInfo->pFrags[frag].bufSize);
++ if(size > 0)
++ {
++ len = MV_MIN((int)pPktInfo->pFrags[frag].bufSize, size);
++ mvDebugMemDump(pPktInfo->pFrags[frag].bufVirtPtr, len, access);
++ size -= len;
++ }
++ }
++
++}
++
++void mvDebugPrintIpAddr(MV_U32 ipAddr)
++{
++ mvOsPrintf("%d.%d.%d.%d", ((ipAddr >> 24) & 0xFF), ((ipAddr >> 16) & 0xFF),
++ ((ipAddr >> 8) & 0xFF), ((ipAddr >> 0) & 0xFF));
++}
++
++void mvDebugPrintMacAddr(const MV_U8* pMacAddr)
++{
++ int i;
++
++ mvOsPrintf("%02x", (unsigned int)pMacAddr[0]);
++ for(i=1; i<MV_MAC_ADDR_SIZE; i++)
++ {
++ mvOsPrintf(":%02x", pMacAddr[i]);
++ }
++ /* mvOsPrintf("\n");*/
++}
++
++
++/******* There are three functions deals with MV_DEBUG_TIMES structure ********/
++
++/* Reset MV_DEBUG_TIMES entry */
++void mvDebugResetTimeEntry(MV_DEBUG_TIMES* pTimeEntry, int count, char* pName)
++{
++ pTimeEntry->begin = 0;
++ pTimeEntry->count = count;
++ pTimeEntry->end = 0;
++ pTimeEntry->left = pTimeEntry->count;
++ pTimeEntry->total = 0;
++ pTimeEntry->min = 0xFFFFFFFF;
++ pTimeEntry->max = 0x0;
++ strncpy(pTimeEntry->name, pName, sizeof(pTimeEntry->name)-1);
++ pTimeEntry->name[sizeof(pTimeEntry->name)-1] = '\0';
++}
++
++/* Print out MV_DEBUG_TIMES entry */
++void mvDebugPrintTimeEntry(MV_DEBUG_TIMES* pTimeEntry, MV_BOOL isTitle)
++{
++ int num;
++
++ if(isTitle == MV_TRUE)
++ mvOsPrintf("Event NumOfEvents TotalTime Average Min Max\n");
++
++ num = pTimeEntry->count-pTimeEntry->left;
++ if(num > 0)
++ {
++ mvOsPrintf("%-11s %6u 0x%08lx %6lu %6lu %6lu\n",
++ pTimeEntry->name, num, pTimeEntry->total, pTimeEntry->total/num,
++ pTimeEntry->min, pTimeEntry->max);
++ }
++}
++
++/* Update MV_DEBUG_TIMES entry */
++void mvDebugUpdateTimeEntry(MV_DEBUG_TIMES* pTimeEntry)
++{
++ MV_U32 delta;
++
++ if(pTimeEntry->left > 0)
++ {
++ if(pTimeEntry->end <= pTimeEntry->begin)
++ {
++ delta = pTimeEntry->begin - pTimeEntry->end;
++ }
++ else
++ {
++ delta = ((MV_U32)0x10000 - pTimeEntry->end) + pTimeEntry->begin;
++ }
++ pTimeEntry->total += delta;
++
++ if(delta < pTimeEntry->min)
++ pTimeEntry->min = delta;
++
++ if(delta > pTimeEntry->max)
++ pTimeEntry->max = delta;
++
++ pTimeEntry->left--;
++ }
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvDebug.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvDebug.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvDebug.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvDebug.h 2010-11-09 20:28:06.292495404 +0100
+@@ -0,0 +1,178 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDebugh
++#define __INCmvDebugh
++
++/* includes */
++#include "mvTypes.h"
++
++typedef enum
++{
++ MV_MODULE_INVALID = -1,
++ MV_MODULE_ETH = 0,
++ MV_MODULE_IDMA,
++ MV_MODULE_XOR,
++ MV_MODULE_TWASI,
++ MV_MODULE_MGI,
++ MV_MODULE_USB,
++ MV_MODULE_CESA,
++
++ MV_MODULE_MAX
++}MV_MODULE_ID;
++
++/* Define generic flags useful for most of modules */
++#define MV_DEBUG_FLAG_ALL (0)
++#define MV_DEBUG_FLAG_INIT (1 << 0)
++#define MV_DEBUG_FLAG_RX (1 << 1)
++#define MV_DEBUG_FLAG_TX (1 << 2)
++#define MV_DEBUG_FLAG_ERR (1 << 3)
++#define MV_DEBUG_FLAG_TRACE (1 << 4)
++#define MV_DEBUG_FLAG_DUMP (1 << 5)
++#define MV_DEBUG_FLAG_CACHE (1 << 6)
++#define MV_DEBUG_FLAG_IOCTL (1 << 7)
++#define MV_DEBUG_FLAG_STATS (1 << 8)
++
++extern MV_U32 mvDebug;
++extern MV_U32 mvDebugModules[MV_MODULE_MAX];
++
++#ifdef MV_DEBUG
++# define MV_DEBUG_PRINT(module, flags, msg) mvOsPrintf msg
++# define MV_DEBUG_CODE(module, flags, code) code
++#elif defined(MV_RT_DEBUG)
++# define MV_DEBUG_PRINT(module, flags, msg) \
++ if( (mvDebug & (1<<(module))) && \
++ ((mvDebugModules[(module)] & (flags)) == (flags)) ) \
++ mvOsPrintf msg
++# define MV_DEBUG_CODE(module, flags, code) \
++ if( (mvDebug & (1<<(module))) && \
++ ((mvDebugModules[(module)] & (flags)) == (flags)) ) \
++ code
++#else
++# define MV_DEBUG_PRINT(module, flags, msg)
++# define MV_DEBUG_CODE(module, flags, code)
++#endif
++
++
++
++/* typedefs */
++
++/* time measurement structure used to check how much time pass between
++ * two points
++ */
++typedef struct {
++ char name[20]; /* name of the entry */
++ unsigned long begin; /* time measured on begin point */
++ unsigned long end; /* time measured on end point */
++ unsigned long total; /* Accumulated time */
++ unsigned long left; /* The rest measurement actions */
++ unsigned long count; /* Maximum measurement actions */
++ unsigned long min; /* Minimum time from begin to end */
++ unsigned long max; /* Maximum time from begin to end */
++} MV_DEBUG_TIMES;
++
++
++/* mvDebug.h API list */
++
++/****** Error Recording ******/
++
++/* Dump memory in specific format:
++ * address: X1X1X1X1 X2X2X2X2 ... X8X8X8X8
++ */
++void mvDebugMemDump(void* addr, int size, int access);
++
++void mvDebugPrintBufInfo(BUF_INFO* pBufInfo, int size, int access);
++
++void mvDebugPrintPktInfo(MV_PKT_INFO* pPktInfo, int size, int access);
++
++void mvDebugPrintIpAddr(MV_U32 ipAddr);
++
++void mvDebugPrintMacAddr(const MV_U8* pMacAddr);
++
++/**** There are three functions deals with MV_DEBUG_TIMES structure ****/
++
++/* Reset MV_DEBUG_TIMES entry */
++void mvDebugResetTimeEntry(MV_DEBUG_TIMES* pTimeEntry, int count, char* name);
++
++/* Update MV_DEBUG_TIMES entry */
++void mvDebugUpdateTimeEntry(MV_DEBUG_TIMES* pTimeEntry);
++
++/* Print out MV_DEBUG_TIMES entry */
++void mvDebugPrintTimeEntry(MV_DEBUG_TIMES* pTimeEntry, MV_BOOL isTitle);
++
++
++/******** General ***********/
++
++/* Change value of mvDebugPrint global variable */
++
++void mvDebugInit(void);
++void mvDebugModuleEnable(MV_MODULE_ID module, MV_BOOL isEnable);
++void mvDebugModuleSetFlags(MV_MODULE_ID module, MV_U32 flags);
++void mvDebugModuleClearFlags(MV_MODULE_ID module, MV_U32 flags);
++
++
++#endif /* __INCmvDebug.h */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvDeviceId.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvDeviceId.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvDeviceId.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvDeviceId.h 2010-11-09 20:28:06.332495486 +0100
+@@ -0,0 +1,225 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDeviceIdh
++#define __INCmvDeviceIdh
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/* defines */
++#define MARVELL_VEN_ID 0x11ab
++
++/* Disco-3 */
++#define MV64460_DEV_ID 0x6480
++#define MV64460B_DEV_ID 0x6485
++#define MV64430_DEV_ID 0x6420
++
++/* Disco-5 */
++#define MV64560_DEV_ID 0x6450
++
++/* Disco-6 */
++#define MV64660_DEV_ID 0x6460
++
++/* Orion */
++#define MV_1181_DEV_ID 0x1181
++#define MV_5181_DEV_ID 0x5181
++#define MV_5281_DEV_ID 0x5281
++#define MV_5182_DEV_ID 0x5182
++#define MV_8660_DEV_ID 0x8660
++#define MV_5180_DEV_ID 0x5180
++#define MV_5082_DEV_ID 0x5082
++#define MV_1281_DEV_ID 0x1281
++#define MV_6082_DEV_ID 0x6082
++#define MV_6183_DEV_ID 0x6183
++#define MV_6183L_DEV_ID 0x6083
++
++#define MV_5281_D0_REV 0x4
++#define MV_5281_D0_ID ((MV_5281_DEV_ID << 16) | MV_5281_D0_REV)
++#define MV_5281_D0_NAME "88F5281 D0"
++
++#define MV_5281_D1_REV 0x5
++#define MV_5281_D1_ID ((MV_5281_DEV_ID << 16) | MV_5281_D1_REV)
++#define MV_5281_D1_NAME "88F5281 D1"
++
++#define MV_5281_D2_REV 0x6
++#define MV_5281_D2_ID ((MV_5281_DEV_ID << 16) | MV_5281_D2_REV)
++#define MV_5281_D2_NAME "88F5281 D2"
++
++
++#define MV_5181L_A0_REV 0x8 /* need for PCIE Er */
++#define MV_5181_A1_REV 0x1 /* for USB Er ..*/
++#define MV_5181_B0_REV 0x2
++#define MV_5181_B1_REV 0x3
++#define MV_5182_A1_REV 0x1
++#define MV_5180N_B1_REV 0x3
++#define MV_5181L_A0_ID ((MV_5181_DEV_ID << 16) | MV_5181L_A0_REV)
++
++
++
++/* kw */
++#define MV_6281_DEV_ID 0x6281
++#define MV_6192_DEV_ID 0x6192
++#define MV_6190_DEV_ID 0x6190
++#define MV_6180_DEV_ID 0x6180
++
++#define MV_6281_A0_REV 0x2
++#define MV_6281_A0_ID ((MV_6281_DEV_ID << 16) | MV_6281_A0_REV)
++#define MV_6281_A0_NAME "88F6281 A0"
++
++#define MV_6192_A0_REV 0x2
++#define MV_6192_A0_ID ((MV_6192_DEV_ID << 16) | MV_6192_A0_REV)
++#define MV_6192_A0_NAME "88F6192 A0"
++
++#define MV_6190_A0_REV 0x2
++#define MV_6190_A0_ID ((MV_6190_DEV_ID << 16) | MV_6190_A0_REV)
++#define MV_6190_A0_NAME "88F6190 A0"
++
++#define MV_6180_A0_REV 0x2
++#define MV_6180_A0_ID ((MV_6180_DEV_ID << 16) | MV_6180_A0_REV)
++#define MV_6180_A0_NAME "88F6180 A0"
++
++#define MV_6281_A1_REV 0x3
++#define MV_6281_A1_ID ((MV_6281_DEV_ID << 16) | MV_6281_A1_REV)
++#define MV_6281_A1_NAME "88F6281 A1"
++
++#define MV_6192_A1_REV 0x3
++#define MV_6192_A1_ID ((MV_6192_DEV_ID << 16) | MV_6192_A1_REV)
++#define MV_6192_A1_NAME "88F6192 A1"
++
++#define MV_6190_A1_REV 0x3
++#define MV_6190_A1_ID ((MV_6190_DEV_ID << 16) | MV_6190_A1_REV)
++#define MV_6190_A1_NAME "88F6190 A1"
++
++#define MV_6180_A1_REV 0x3
++#define MV_6180_A1_ID ((MV_6180_DEV_ID << 16) | MV_6180_A1_REV)
++#define MV_6180_A1_NAME "88F6180 A1"
++
++#define MV_88F6XXX_A0_REV 0x2
++#define MV_88F6XXX_A1_REV 0x3
++/* Disco-Duo */
++#define MV_78XX0_ZY_DEV_ID 0x6381
++#define MV_78XX0_ZY_NAME "MV78X00"
++
++#define MV_78XX0_Z0_REV 0x1
++#define MV_78XX0_Z0_ID ((MV_78XX0_ZY_DEV_ID << 16) | MV_78XX0_Z0_REV)
++#define MV_78XX0_Z0_NAME "78X00 Z0"
++
++#define MV_78XX0_Y0_REV 0x2
++#define MV_78XX0_Y0_ID ((MV_78XX0_ZY_DEV_ID << 16) | MV_78XX0_Y0_REV)
++#define MV_78XX0_Y0_NAME "78X00 Y0"
++
++#define MV_78XX0_DEV_ID 0x7800
++#define MV_78XX0_NAME "MV78X00"
++
++#define MV_76100_DEV_ID 0x7610
++#define MV_78200_DEV_ID 0x7820
++#define MV_78100_DEV_ID 0x7810
++#define MV_78XX0_A0_REV 0x1
++#define MV_78XX0_A1_REV 0x2
++
++#define MV_76100_NAME "MV76100"
++#define MV_78100_NAME "MV78100"
++#define MV_78200_NAME "MV78200"
++
++#define MV_76100_A0_ID ((MV_76100_DEV_ID << 16) | MV_78XX0_A0_REV)
++#define MV_78100_A0_ID ((MV_78100_DEV_ID << 16) | MV_78XX0_A0_REV)
++#define MV_78200_A0_ID ((MV_78200_DEV_ID << 16) | MV_78XX0_A0_REV)
++
++#define MV_76100_A1_ID ((MV_76100_DEV_ID << 16) | MV_78XX0_A1_REV)
++#define MV_78100_A1_ID ((MV_78100_DEV_ID << 16) | MV_78XX0_A1_REV)
++#define MV_78200_A1_ID ((MV_78200_DEV_ID << 16) | MV_78XX0_A1_REV)
++
++#define MV_76100_A0_NAME "MV76100 A0"
++#define MV_78100_A0_NAME "MV78100 A0"
++#define MV_78200_A0_NAME "MV78200 A0"
++#define MV_78XX0_A0_NAME "MV78XX0 A0"
++
++#define MV_76100_A1_NAME "MV76100 A1"
++#define MV_78100_A1_NAME "MV78100 A1"
++#define MV_78200_A1_NAME "MV78200 A1"
++#define MV_78XX0_A1_NAME "MV78XX0 A1"
++
++/*MV88F632X family*/
++#define MV_6321_DEV_ID 0x6321
++#define MV_6322_DEV_ID 0x6322
++#define MV_6323_DEV_ID 0x6323
++
++#define MV_6321_NAME "88F6321"
++#define MV_6322_NAME "88F6322"
++#define MV_6323_NAME "88F6323"
++
++#define MV_632X_A1_REV 0x2
++
++#define MV_6321_A1_ID ((MV_6321_DEV_ID << 16) | MV_632X_A1_REV)
++#define MV_6322_A1_ID ((MV_6322_DEV_ID << 16) | MV_632X_A1_REV)
++#define MV_6323_A1_ID ((MV_6323_DEV_ID << 16) | MV_632X_A1_REV)
++
++#define MV_6321_A1_NAME "88F6321 A1"
++#define MV_6322_A1_NAME "88F6322 A1"
++#define MV_6323_A1_NAME "88F6323 A1"
++
++
++#endif /* __INCmvDeviceIdh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvHalVer.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvHalVer.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvHalVer.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvHalVer.h 2010-11-09 20:28:07.069296580 +0100
+@@ -0,0 +1,73 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvHalVerh
++#define __INCmvHalVerh
++
++/* Defines */
++#define MV_HAL_VERSION "FEROCEON_HAL_3_1_7"
++#define MV_RELEASE_BASELINE "SoCandControllers_FEROCEON_RELEASE_7_9_2009_KW_4_3_4_DD_2_1_4_6183_1_1_4"
++
++#endif /* __INCmvHalVerh */
+\ No newline at end of file
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvStack.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvStack.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvStack.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvStack.c 2010-11-09 20:28:07.102606889 +0100
+@@ -0,0 +1,100 @@
++/*******************************************************************************
++* Copyright 2003, Marvell Semiconductor Israel LTD. *
++* THIS CODE CONTAINS CONFIDENTIAL INFORMATION OF MARVELL. *
++* NO RIGHTS ARE GRANTED HEREIN UNDER ANY PATENT, MASK WORK RIGHT OR COPYRIGHT *
++* OF MARVELL OR ANY THIRD PARTY. MARVELL RESERVES THE RIGHT AT ITS SOLE *
++* DISCRETION TO REQUEST THAT THIS CODE BE IMMEDIATELY RETURNED TO MARVELL. *
++* THIS CODE IS PROVIDED "AS IS". MARVELL MAKES NO WARRANTIES, EXPRESSED, *
++* IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, COMPLETENESS OR PERFORMANCE. *
++* *
++* MARVELL COMPRISES MARVELL TECHNOLOGY GROUP LTD. (MTGL) AND ITS SUBSIDIARIES, *
++* MARVELL INTERNATIONAL LTD. (MIL), MARVELL TECHNOLOGY, INC. (MTI), MARVELL *
++* SEMICONDUCTOR, INC. (MSI), MARVELL ASIA PTE LTD. (MAPL), MARVELL JAPAN K.K. *
++* (MJKK), MARVELL SEMICONDUCTOR ISRAEL LTD (MSIL). *
++********************************************************************************
++* mvQueue.c
++*
++* FILENAME: $Workfile: mvStack.c $
++* REVISION: $Revision: 1.1 $
++* LAST UPDATE: $Modtime: $
++*
++* DESCRIPTION:
++* This file implements simple Stack LIFO functionality.
++*******************************************************************************/
++
++/* includes */
++#include "mvOs.h"
++#include "mvTypes.h"
++#include "mvDebug.h"
++#include "mvStack.h"
++
++/* defines */
++
++
++/* Public functions */
++
++
++/* Purpose: Create new stack
++ * Inputs:
++ * - MV_U32 noOfElements - maximum number of elements in the stack.
++ * Each element 4 bytes size
++ * Return: void* - pointer to created stack.
++ */
++void* mvStackCreate(int numOfElements)
++{
++ MV_STACK* pStack;
++ MV_U32* pStackElements;
++
++ pStack = (MV_STACK*)mvOsMalloc(sizeof(MV_STACK));
++ pStackElements = (MV_U32*)mvOsMalloc(numOfElements*sizeof(MV_U32));
++ if( (pStack == NULL) || (pStackElements == NULL) )
++ {
++ mvOsPrintf("mvStack: Can't create new stack\n");
++ return NULL;
++ }
++ memset(pStackElements, 0, numOfElements*sizeof(MV_U32));
++ pStack->numOfElements = numOfElements;
++ pStack->stackIdx = 0;
++ pStack->stackElements = pStackElements;
++
++ return pStack;
++}
++
++/* Purpose: Delete existing stack
++ * Inputs:
++ * - void* stackHndl - Stack handle as returned by "mvStackCreate()" function
++ *
++ * Return: MV_STATUS MV_NOT_FOUND - Failure. StackHandle is not valid.
++ * MV_OK - Success.
++ */
++MV_STATUS mvStackDelete(void* stackHndl)
++{
++ MV_STACK* pStack = (MV_STACK*)stackHndl;
++
++ if( (pStack == NULL) || (pStack->stackElements == NULL) )
++ return MV_NOT_FOUND;
++
++ mvOsFree(pStack->stackElements);
++ mvOsFree(pStack);
++
++ return MV_OK;
++}
++
++
++/* PrintOut status of the stack */
++void mvStackStatus(void* stackHndl, MV_BOOL isPrintElements)
++{
++ int i;
++ MV_STACK* pStack = (MV_STACK*)stackHndl;
++
++ mvOsPrintf("StackHandle=%p, pElements=%p, numElements=%d, stackIdx=%d\n",
++ stackHndl, pStack->stackElements, pStack->numOfElements,
++ pStack->stackIdx);
++ if(isPrintElements == MV_TRUE)
++ {
++ for(i=0; i<pStack->stackIdx; i++)
++ {
++ mvOsPrintf("%3d. Value=0x%x\n", i, pStack->stackElements[i]);
++ }
++ }
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvStack.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvStack.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvStack.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvStack.h 2010-11-09 20:28:07.160842220 +0100
+@@ -0,0 +1,140 @@
++/*******************************************************************************
++* Copyright 2003, Marvell Semiconductor Israel LTD. *
++* THIS CODE CONTAINS CONFIDENTIAL INFORMATION OF MARVELL. *
++* NO RIGHTS ARE GRANTED HEREIN UNDER ANY PATENT, MASK WORK RIGHT OR COPYRIGHT *
++* OF MARVELL OR ANY THIRD PARTY. MARVELL RESERVES THE RIGHT AT ITS SOLE *
++* DISCRETION TO REQUEST THAT THIS CODE BE IMMEDIATELY RETURNED TO MARVELL. *
++* THIS CODE IS PROVIDED "AS IS". MARVELL MAKES NO WARRANTIES, EXPRESSED, *
++* IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, COMPLETENESS OR PERFORMANCE. *
++* *
++* MARVELL COMPRISES MARVELL TECHNOLOGY GROUP LTD. (MTGL) AND ITS SUBSIDIARIES, *
++* MARVELL INTERNATIONAL LTD. (MIL), MARVELL TECHNOLOGY, INC. (MTI), MARVELL *
++* SEMICONDUCTOR, INC. (MSI), MARVELL ASIA PTE LTD. (MAPL), MARVELL JAPAN K.K. *
++* (MJKK), MARVELL SEMICONDUCTOR ISRAEL LTD (MSIL). *
++********************************************************************************
++* mvStack.h - Header File for :
++*
++* FILENAME: $Workfile: mvStack.h $
++* REVISION: $Revision: 1.1 $
++* LAST UPDATE: $Modtime: $
++*
++* DESCRIPTION:
++* This file defines simple Stack (LIFO) functionality.
++*
++*******************************************************************************/
++
++#ifndef __mvStack_h__
++#define __mvStack_h__
++
++
++/* includes */
++#include "mvTypes.h"
++
++
++/* defines */
++
++
++/* typedefs */
++/* Data structure describes general purpose Stack */
++typedef struct
++{
++ int stackIdx;
++ int numOfElements;
++ MV_U32* stackElements;
++} MV_STACK;
++
++static INLINE MV_BOOL mvStackIsFull(void* stackHndl)
++{
++ MV_STACK* pStack = (MV_STACK*)stackHndl;
++
++ if(pStack->stackIdx == pStack->numOfElements)
++ return MV_TRUE;
++
++ return MV_FALSE;
++}
++
++static INLINE MV_BOOL mvStackIsEmpty(void* stackHndl)
++{
++ MV_STACK* pStack = (MV_STACK*)stackHndl;
++
++ if(pStack->stackIdx == 0)
++ return MV_TRUE;
++
++ return MV_FALSE;
++}
++/* Purpose: Push new element to stack
++ * Inputs:
++ * - void* stackHndl - Stack handle as returned by "mvStackCreate()" function.
++ * - MV_U32 value - New element.
++ *
++ * Return: MV_STATUS MV_FULL - Failure. Stack is full.
++ * MV_OK - Success. Element is put to stack.
++ */
++static INLINE void mvStackPush(void* stackHndl, MV_U32 value)
++{
++ MV_STACK* pStack = (MV_STACK*)stackHndl;
++
++#ifdef MV_RT_DEBUG
++ if(pStack->stackIdx == pStack->numOfElements)
++ {
++ mvOsPrintf("mvStackPush: Stack is FULL\n");
++ return;
++ }
++#endif /* MV_RT_DEBUG */
++
++ pStack->stackElements[pStack->stackIdx] = value;
++ pStack->stackIdx++;
++}
++
++/* Purpose: Pop element from the top of stack and copy it to "pValue"
++ * Inputs:
++ * - void* stackHndl - Stack handle as returned by "mvStackCreate()" function.
++ * - MV_U32 value - Element in the top of stack.
++ *
++ * Return: MV_STATUS MV_EMPTY - Failure. Stack is empty.
++ * MV_OK - Success. Element is removed from the stack and
++ * copied to pValue argument
++ */
++static INLINE MV_U32 mvStackPop(void* stackHndl)
++{
++ MV_STACK* pStack = (MV_STACK*)stackHndl;
++
++#ifdef MV_RT_DEBUG
++ if(pStack->stackIdx == 0)
++ {
++ mvOsPrintf("mvStackPop: Stack is EMPTY\n");
++ return 0;
++ }
++#endif /* MV_RT_DEBUG */
++
++ pStack->stackIdx--;
++ return pStack->stackElements[pStack->stackIdx];
++}
++
++static INLINE int mvStackIndex(void* stackHndl)
++{
++ MV_STACK* pStack = (MV_STACK*)stackHndl;
++
++ return pStack->stackIdx;
++}
++
++static INLINE int mvStackFreeElements(void* stackHndl)
++{
++ MV_STACK* pStack = (MV_STACK*)stackHndl;
++
++ return (pStack->numOfElements - pStack->stackIdx);
++}
++
++/* mvStack.h API list */
++
++/* Create new Stack */
++void* mvStackCreate(int numOfElements);
++
++/* Delete existing stack */
++MV_STATUS mvStackDelete(void* stackHndl);
++
++/* Print status of the stack */
++void mvStackStatus(void* stackHndl, MV_BOOL isPrintElements);
++
++#endif /* __mvStack_h__ */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvTypes.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvTypes.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/common/mvTypes.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/common/mvTypes.h 2010-11-09 20:28:07.191385803 +0100
+@@ -0,0 +1,245 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvTypesh
++#define __INCmvTypesh
++
++/* Defines */
++
++/* The following is a list of Marvell status */
++#define MV_ERROR (-1)
++#define MV_OK (0x00) /* Operation succeeded */
++#define MV_FAIL (0x01) /* Operation failed */
++#define MV_BAD_VALUE (0x02) /* Illegal value (general) */
++#define MV_OUT_OF_RANGE (0x03) /* The value is out of range */
++#define MV_BAD_PARAM (0x04) /* Illegal parameter in function called */
++#define MV_BAD_PTR (0x05) /* Illegal pointer value */
++#define MV_BAD_SIZE (0x06) /* Illegal size */
++#define MV_BAD_STATE (0x07) /* Illegal state of state machine */
++#define MV_SET_ERROR (0x08) /* Set operation failed */
++#define MV_GET_ERROR (0x09) /* Get operation failed */
++#define MV_CREATE_ERROR (0x0A) /* Fail while creating an item */
++#define MV_NOT_FOUND (0x0B) /* Item not found */
++#define MV_NO_MORE (0x0C) /* No more items found */
++#define MV_NO_SUCH (0x0D) /* No such item */
++#define MV_TIMEOUT (0x0E) /* Time Out */
++#define MV_NO_CHANGE (0x0F) /* Parameter(s) is already in this value */
++#define MV_NOT_SUPPORTED (0x10) /* This request is not support */
++#define MV_NOT_IMPLEMENTED (0x11) /* Request supported but not implemented */
++#define MV_NOT_INITIALIZED (0x12) /* The item is not initialized */
++#define MV_NO_RESOURCE (0x13) /* Resource not available (memory ...) */
++#define MV_FULL (0x14) /* Item is full (Queue or table etc...) */
++#define MV_EMPTY (0x15) /* Item is empty (Queue or table etc...) */
++#define MV_INIT_ERROR (0x16) /* Error occured while INIT process */
++#define MV_HW_ERROR (0x17) /* Hardware error */
++#define MV_TX_ERROR (0x18) /* Transmit operation not succeeded */
++#define MV_RX_ERROR (0x19) /* Recieve operation not succeeded */
++#define MV_NOT_READY (0x1A) /* The other side is not ready yet */
++#define MV_ALREADY_EXIST (0x1B) /* Tried to create existing item */
++#define MV_OUT_OF_CPU_MEM (0x1C) /* Cpu memory allocation failed. */
++#define MV_NOT_STARTED (0x1D) /* Not started yet */
++#define MV_BUSY (0x1E) /* Item is busy. */
++#define MV_TERMINATE (0x1F) /* Item terminates it's work. */
++#define MV_NOT_ALIGNED (0x20) /* Wrong alignment */
++#define MV_NOT_ALLOWED (0x21) /* Operation NOT allowed */
++#define MV_WRITE_PROTECT (0x22) /* Write protected */
++
++
++#define MV_INVALID (int)(-1)
++
++#define MV_FALSE 0
++#define MV_TRUE (!(MV_FALSE))
++
++
++#ifndef NULL
++#define NULL ((void*)0)
++#endif
++
++
++#ifndef MV_ASMLANGUAGE
++/* typedefs */
++
++typedef char MV_8;
++typedef unsigned char MV_U8;
++
++typedef int MV_32;
++typedef unsigned int MV_U32;
++
++typedef short MV_16;
++typedef unsigned short MV_U16;
++
++#ifdef MV_PPC64
++typedef long MV_64;
++typedef unsigned long MV_U64;
++#else
++typedef long long MV_64;
++typedef unsigned long long MV_U64;
++#endif
++
++typedef long MV_LONG; /* 32/64 */
++typedef unsigned long MV_ULONG; /* 32/64 */
++
++typedef int MV_STATUS;
++typedef int MV_BOOL;
++typedef void MV_VOID;
++typedef float MV_FLOAT;
++
++typedef int (*MV_FUNCPTR) (void); /* ptr to function returning int */
++typedef void (*MV_VOIDFUNCPTR) (void); /* ptr to function returning void */
++typedef double (*MV_DBLFUNCPTR) (void); /* ptr to function returning double*/
++typedef float (*MV_FLTFUNCPTR) (void); /* ptr to function returning float */
++
++typedef MV_U32 MV_KHZ;
++typedef MV_U32 MV_MHZ;
++typedef MV_U32 MV_HZ;
++
++
++/* This enumerator describes the set of commands that can be applied on */
++/* an engine (e.g. IDMA, XOR). Appling a comman depends on the current */
++/* status (see MV_STATE enumerator) */
++/* Start can be applied only when status is IDLE */
++/* Stop can be applied only when status is IDLE, ACTIVE or PAUSED */
++/* Pause can be applied only when status is ACTIVE */
++/* Restart can be applied only when status is PAUSED */
++typedef enum _mvCommand
++{
++ MV_START, /* Start */
++ MV_STOP, /* Stop */
++ MV_PAUSE, /* Pause */
++ MV_RESTART /* Restart */
++} MV_COMMAND;
++
++/* This enumerator describes the set of state conditions. */
++/* Moving from one state to other is stricted. */
++typedef enum _mvState
++{
++ MV_IDLE,
++ MV_ACTIVE,
++ MV_PAUSED,
++ MV_UNDEFINED_STATE
++} MV_STATE;
++
++
++/* This structure describes address space window. Window base can be */
++/* 64 bit, window size up to 4GB */
++typedef struct _mvAddrWin
++{
++ MV_U32 baseLow; /* 32bit base low */
++ MV_U32 baseHigh; /* 32bit base high */
++ MV_U32 size; /* 32bit size */
++}MV_ADDR_WIN;
++
++/* This binary enumerator describes protection attribute status */
++typedef enum _mvProtRight
++{
++ ALLOWED, /* Protection attribute allowed */
++ FORBIDDEN /* Protection attribute forbidden */
++}MV_PROT_RIGHT;
++
++/* Unified struct for Rx and Tx packet operations. The user is required to */
++/* be familier only with Tx/Rx descriptor command status. */
++typedef struct _bufInfo
++{
++ MV_U32 cmdSts; /* Tx/Rx command status */
++ MV_U16 byteCnt; /* Size of valid data in the buffer */
++ MV_U16 bufSize; /* Total size of the buffer */
++ MV_U8 *pBuff; /* Pointer to Buffer */
++ MV_U8 *pData; /* Pointer to data in the Buffer */
++ MV_U32 userInfo1; /* Tx/Rx attached user information 1 */
++ MV_U32 userInfo2; /* Tx/Rx attached user information 2 */
++ struct _bufInfo *pNextBufInfo; /* Next buffer in packet */
++} BUF_INFO;
++
++/* This structure contains information describing one of buffers
++ * (fragments) they are built Ethernet packet.
++ */
++typedef struct
++{
++ MV_U8* bufVirtPtr;
++ MV_ULONG bufPhysAddr;
++ MV_U32 bufSize;
++ MV_U32 dataSize;
++ MV_U32 memHandle;
++ MV_32 bufAddrShift;
++} MV_BUF_INFO;
++
++/* This structure contains information describing Ethernet packet.
++ * The packet can be divided for few buffers (fragments)
++ */
++typedef struct
++{
++ MV_ULONG osInfo;
++ MV_BUF_INFO *pFrags;
++ MV_U32 status;
++ MV_U16 pktSize;
++ MV_U16 numFrags;
++ MV_U32 ownerId;
++ MV_U32 fragIP;
++} MV_PKT_INFO;
++
++#endif /* MV_ASMLANGUAGE */
++
++#endif /* __INCmvTypesh */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/dbg-trace.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/dbg-trace.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/dbg-trace.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/dbg-trace.c 2010-11-09 20:28:07.232495685 +0100
+@@ -0,0 +1,110 @@
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/time.h>
++#include "dbg-trace.h"
++
++#define TRACE_ARR_LEN 800
++#define STR_LEN 128
++struct trace {
++ struct timeval tv;
++ char str[STR_LEN];
++ unsigned int callback_val1;
++ unsigned int callback_val2;
++ char valid;
++};
++static unsigned int (*trc_callback1) (unsigned char) = NULL;
++static unsigned int (*trc_callback2) (unsigned char) = NULL;
++static unsigned char trc_param1 = 0;
++static unsigned char trc_param2 = 0;
++struct trace *trc_arr;
++static int trc_index;
++static int trc_active = 0;
++
++void TRC_START()
++{
++ trc_active = 1;
++}
++
++void TRC_STOP()
++{
++ trc_active = 0;
++}
++
++void TRC_INIT(void *callback1, void *callback2, unsigned char callback1_param, unsigned char callback2_param)
++{
++ printk("Marvell debug tracing is on\n");
++ trc_arr = (struct trace *)kmalloc(TRACE_ARR_LEN*sizeof(struct trace),GFP_KERNEL);
++ if(trc_arr == NULL)
++ {
++ printk("Can't allocate Debug Trace buffer\n");
++ return;
++ }
++ memset(trc_arr,0,TRACE_ARR_LEN*sizeof(struct trace));
++ trc_index = 0;
++ trc_callback1 = callback1;
++ trc_callback2 = callback2;
++ trc_param1 = callback1_param;
++ trc_param2 = callback2_param;
++}
++void TRC_REC(char *fmt,...)
++{
++ va_list args;
++ struct trace *trc = &trc_arr[trc_index];
++
++ if(trc_active == 0)
++ return;
++
++ do_gettimeofday(&trc->tv);
++ if(trc_callback1)
++ trc->callback_val1 = trc_callback1(trc_param1);
++ if(trc_callback2)
++ trc->callback_val2 = trc_callback2(trc_param2);
++ va_start(args, fmt);
++ vsprintf(trc->str,fmt,args);
++ va_end(args);
++ trc->valid = 1;
++ if((++trc_index) == TRACE_ARR_LEN) {
++ trc_index = 0;
++ }
++}
++void TRC_OUTPUT(void)
++{
++ int i,j;
++ struct trace *p;
++ printk("\n\nTrace %d items\n",TRACE_ARR_LEN);
++ for(i=0,j=trc_index; i<TRACE_ARR_LEN; i++,j++) {
++ if(j == TRACE_ARR_LEN)
++ j = 0;
++ p = &trc_arr[j];
++ if(p->valid) {
++ unsigned long uoffs;
++ struct trace *plast;
++ if(p == &trc_arr[0])
++ plast = &trc_arr[TRACE_ARR_LEN-1];
++ else
++ plast = p-1;
++ if(p->tv.tv_sec == ((plast)->tv.tv_sec))
++ uoffs = (p->tv.tv_usec - ((plast)->tv.tv_usec));
++ else
++ uoffs = (1000000 - ((plast)->tv.tv_usec)) +
++ ((p->tv.tv_sec - ((plast)->tv.tv_sec) - 1) * 1000000) +
++ p->tv.tv_usec;
++ printk("%03d: [+%ld usec]", j, (unsigned long)uoffs);
++ if(trc_callback1)
++ printk("[%u]",p->callback_val1);
++ if(trc_callback2)
++ printk("[%u]",p->callback_val2);
++ printk(": %s",p->str);
++ }
++ p->valid = 0;
++ }
++ memset(trc_arr,0,TRACE_ARR_LEN*sizeof(struct trace));
++ trc_index = 0;
++}
++void TRC_RELEASE(void)
++{
++ kfree(trc_arr);
++ trc_index = 0;
++}
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/dbg-trace.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/dbg-trace.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/dbg-trace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/dbg-trace.h 2010-11-09 20:28:07.276291416 +0100
+@@ -0,0 +1,24 @@
++
++#ifndef _MV_DBG_TRCE_H_
++#define _MV_DBG_TRCE_H_
++
++#ifdef CONFIG_MV_DBG_TRACE
++void TRC_INIT(void *callback1, void *callback2,
++ unsigned char callback1_param, unsigned char callback2_param);
++void TRC_REC(char *fmt,...);
++void TRC_OUTPUT(void);
++void TRC_RELEASE(void);
++void TRC_START(void);
++void TRC_STOP(void);
++
++#else
++#define TRC_INIT(x1,x2,x3,x4)
++#define TRC_REC(X...)
++#define TRC_OUTPUT()
++#define TRC_RELEASE()
++#define TRC_START()
++#define TRC_STOP()
++#endif
++
++
++#endif
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.c 2010-11-09 20:28:07.327371127 +0100
+@@ -0,0 +1,2513 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "boardEnv/mvBoardEnvLib.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++#include "cpu/mvCpu.h"
++#include "cntmr/mvCntmr.h"
++#include "gpp/mvGpp.h"
++#include "twsi/mvTwsi.h"
++#include "pex/mvPex.h"
++#include "device/mvDevice.h"
++#include "eth/gbe/mvEthRegs.h"
++
++/* defines */
++/* #define MV_DEBUG */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++extern MV_CPU_ARM_CLK _cpuARMDDRCLK[];
++
++#define CODE_IN_ROM MV_FALSE
++#define CODE_IN_RAM MV_TRUE
++
++extern MV_BOARD_INFO* boardInfoTbl[];
++#define BOARD_INFO(boardId) boardInfoTbl[boardId - BOARD_ID_BASE]
++
++/* Locals */
++static MV_DEV_CS_INFO* boardGetDevEntry(MV_32 devNum, MV_BOARD_DEV_CLASS devClass);
++
++MV_U32 tClkRate = -1;
++
++
++/*******************************************************************************
++* mvBoardEnvInit - Init board
++*
++* DESCRIPTION:
++* In this function the board environment take care of device bank
++* initialization.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvBoardEnvInit(MV_VOID)
++{
++ MV_U32 boardId= mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardEnvInit:Board unknown.\n");
++ return;
++
++ }
++
++ /* Set GPP Out value */
++ MV_REG_WRITE(GPP_DATA_OUT_REG(0), BOARD_INFO(boardId)->gppOutValLow);
++ MV_REG_WRITE(GPP_DATA_OUT_REG(1), BOARD_INFO(boardId)->gppOutValHigh);
++
++ /* set GPP polarity */
++ mvGppPolaritySet(0, 0xFFFFFFFF, BOARD_INFO(boardId)->gppPolarityValLow);
++ mvGppPolaritySet(1, 0xFFFFFFFF, BOARD_INFO(boardId)->gppPolarityValHigh);
++
++ /* Workaround for Erratum FE-MISC-70*/
++ if(mvCtrlRevGet()==MV_88F6XXX_A0_REV)
++ {
++ BOARD_INFO(boardId)->gppOutEnValLow &= 0xfffffffd;
++ BOARD_INFO(boardId)->gppOutEnValLow |= (BOARD_INFO(boardId)->gppOutEnValHigh) & 0x00000002;
++ } /*End of WA*/
++
++ /* Set GPP Out Enable*/
++ mvGppTypeSet(0, 0xFFFFFFFF, BOARD_INFO(boardId)->gppOutEnValLow);
++ mvGppTypeSet(1, 0xFFFFFFFF, BOARD_INFO(boardId)->gppOutEnValHigh);
++
++ /* Nand CE */
++ MV_REG_BIT_SET(NAND_CTRL_REG, NAND_ACTCEBOOT_BIT);
++}
++
++/*******************************************************************************
++* mvBoardModelGet - Get Board model
++*
++* DESCRIPTION:
++* This function returns 16bit describing board model.
++* Board model is constructed of one byte major and minor numbers in the
++* following manner:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* String describing board model.
++*
++*******************************************************************************/
++MV_U16 mvBoardModelGet(MV_VOID)
++{
++ return (mvBoardIdGet() >> 16);
++}
++
++/*******************************************************************************
++* mbBoardRevlGet - Get Board revision
++*
++* DESCRIPTION:
++* This function returns a 32bit describing the board revision.
++* Board revision is constructed of 4bytes. 2bytes describes major number
++* and the other 2bytes describes minor munber.
++* For example for board revision 3.4 the function will return
++* 0x00030004.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* String describing board model.
++*
++*******************************************************************************/
++MV_U16 mvBoardRevGet(MV_VOID)
++{
++ return (mvBoardIdGet() & 0xFFFF);
++}
++
++/*******************************************************************************
++* mvBoardNameGet - Get Board name
++*
++* DESCRIPTION:
++* This function returns a string describing the board model and revision.
++* String is extracted from board I2C EEPROM.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* pNameBuff - Buffer to contain board name string. Minimum size 32 chars.
++*
++* RETURN:
++*
++* MV_ERROR if informantion can not be read.
++*******************************************************************************/
++MV_STATUS mvBoardNameGet(char *pNameBuff)
++{
++ MV_U32 boardId= mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsSPrintf (pNameBuff, "Board unknown.\n");
++ return MV_ERROR;
++
++ }
++
++ mvOsSPrintf (pNameBuff, "%s",BOARD_INFO(boardId)->boardName);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvBoardIsPortInSgmii -
++*
++* DESCRIPTION:
++* This routine returns MV_TRUE for port number works in SGMII or MV_FALSE
++* For all other options.
++*
++* INPUT:
++* ethPortNum - Ethernet port number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE - port in SGMII.
++* MV_FALSE - other.
++*
++*******************************************************************************/
++MV_BOOL mvBoardIsPortInSgmii(MV_U32 ethPortNum)
++{
++ MV_BOOL ethPortSgmiiSupport[BOARD_ETH_PORT_NUM] = MV_ETH_PORT_SGMII;
++
++ if(ethPortNum >= BOARD_ETH_PORT_NUM)
++ {
++ mvOsPrintf ("Invalid portNo=%d\n", ethPortNum);
++ return MV_FALSE;
++ }
++ return ethPortSgmiiSupport[ethPortNum];
++}
++
++/*******************************************************************************
++* mvBoardIsPortInGmii -
++*
++* DESCRIPTION:
++* This routine returns MV_TRUE for port number works in GMII or MV_FALSE
++* For all other options.
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE - port in GMII.
++* MV_FALSE - other.
++*
++*******************************************************************************/
++MV_BOOL mvBoardIsPortInGmii(MV_VOID)
++{
++ MV_U32 devClassId, devClass = 0;
++ if (mvBoardMppGroupTypeGet(devClass) == MV_BOARD_AUTO)
++ {
++ /* Get MPP module ID */
++ devClassId = mvBoarModuleTypeGet(devClass);
++ if (MV_BOARD_MODULE_GMII_ID == devClassId)
++ return MV_TRUE;
++ }
++ else if (mvBoardMppGroupTypeGet(devClass) == MV_BOARD_GMII)
++ return MV_TRUE;
++
++ return MV_FALSE;
++}
++/*******************************************************************************
++* mvBoardPhyAddrGet - Get the phy address
++*
++* DESCRIPTION:
++* This routine returns the Phy address of a given ethernet port.
++*
++* INPUT:
++* ethPortNum - Ethernet port number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit describing Phy address, -1 if the port number is wrong.
++*
++*******************************************************************************/
++MV_32 mvBoardPhyAddrGet(MV_U32 ethPortNum)
++{
++ MV_U32 boardId= mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardPhyAddrGet: Board unknown.\n");
++ return MV_ERROR;
++ }
++
++ return BOARD_INFO(boardId)->pBoardMacInfo[ethPortNum].boardEthSmiAddr;
++}
++
++/*******************************************************************************
++* mvBoardMacSpeedGet - Get the Mac speed
++*
++* DESCRIPTION:
++* This routine returns the Mac speed if pre define of a given ethernet port.
++*
++* INPUT:
++* ethPortNum - Ethernet port number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BOARD_MAC_SPEED, -1 if the port number is wrong.
++*
++*******************************************************************************/
++MV_BOARD_MAC_SPEED mvBoardMacSpeedGet(MV_U32 ethPortNum)
++{
++ MV_U32 boardId= mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardMacSpeedGet: Board unknown.\n");
++ return MV_ERROR;
++ }
++
++ return BOARD_INFO(boardId)->pBoardMacInfo[ethPortNum].boardMacSpeed;
++}
++
++/*******************************************************************************
++* mvBoardLinkStatusIrqGet - Get the IRQ number for the link status indication
++*
++* DESCRIPTION:
++* This routine returns the IRQ number for the link status indication.
++*
++* INPUT:
++* ethPortNum - Ethernet port number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* the number of the IRQ for the link status indication, -1 if the port
++* number is wrong or if not relevant.
++*
++*******************************************************************************/
++MV_32 mvBoardLinkStatusIrqGet(MV_U32 ethPortNum)
++{
++ MV_U32 boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardLinkStatusIrqGet: Board unknown.\n");
++ return MV_ERROR;
++ }
++
++ return BOARD_INFO(boardId)->pSwitchInfo[ethPortNum].linkStatusIrq;
++}
++
++/*******************************************************************************
++* mvBoardSwitchPortGet - Get the mapping between the board connector and the
++* Ethernet Switch port
++*
++* DESCRIPTION:
++* This routine returns the matching Switch port.
++*
++* INPUT:
++* ethPortNum - Ethernet port number.
++* boardPortNum - logical number of the connector on the board
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* the matching Switch port, -1 if the port number is wrong or if not relevant.
++*
++*******************************************************************************/
++MV_32 mvBoardSwitchPortGet(MV_U32 ethPortNum, MV_U8 boardPortNum)
++{
++ MV_U32 boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardSwitchPortGet: Board unknown.\n");
++ return MV_ERROR;
++ }
++ if (boardPortNum >= BOARD_ETH_SWITCH_PORT_NUM)
++ {
++ mvOsPrintf("mvBoardSwitchPortGet: Illegal board port number.\n");
++ return MV_ERROR;
++ }
++
++ return BOARD_INFO(boardId)->pSwitchInfo[ethPortNum].qdPort[boardPortNum];
++}
++
++/*******************************************************************************
++* mvBoardSwitchCpuPortGet - Get the the Ethernet Switch CPU port
++*
++* DESCRIPTION:
++* This routine returns the Switch CPU port.
++*
++* INPUT:
++* ethPortNum - Ethernet port number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* the Switch CPU port, -1 if the port number is wrong or if not relevant.
++*
++*******************************************************************************/
++MV_32 mvBoardSwitchCpuPortGet(MV_U32 ethPortNum)
++{
++ MV_U32 boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardSwitchCpuPortGet: Board unknown.\n");
++ return MV_ERROR;
++ }
++
++ return BOARD_INFO(boardId)->pSwitchInfo[ethPortNum].qdCpuPort;
++}
++
++/*******************************************************************************
++* mvBoardIsSwitchConnected - Get switch connection status
++* DESCRIPTION:
++* This routine returns port's connection status
++*
++* INPUT:
++* ethPortNum - Ethernet port number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 1 - if ethPortNum is connected to switch, 0 otherwise
++*
++*******************************************************************************/
++MV_32 mvBoardIsSwitchConnected(MV_U32 ethPortNum)
++{
++ MV_U32 boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardIsSwitchConnected: Board unknown.\n");
++ return MV_ERROR;
++ }
++
++ if(ethPortNum >= BOARD_INFO(boardId)->numBoardMacInfo)
++ {
++ mvOsPrintf("mvBoardIsSwitchConnected: Illegal port number(%u)\n", ethPortNum);
++ return MV_ERROR;
++ }
++
++ if((MV_32)(BOARD_INFO(boardId)->pSwitchInfo))
++ return (MV_32)(BOARD_INFO(boardId)->pSwitchInfo[ethPortNum].switchOnPort == ethPortNum);
++ else
++ return 0;
++}
++/*******************************************************************************
++* mvBoardSmiScanModeGet - Get Switch SMI scan mode
++*
++* DESCRIPTION:
++* This routine returns Switch SMI scan mode.
++*
++* INPUT:
++* ethPortNum - Ethernet port number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 1 for SMI_MANUAL_MODE, -1 if the port number is wrong or if not relevant.
++*
++*******************************************************************************/
++MV_32 mvBoardSmiScanModeGet(MV_U32 ethPortNum)
++{
++ MV_U32 boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardSmiScanModeGet: Board unknown.\n");
++ return MV_ERROR;
++ }
++
++ return BOARD_INFO(boardId)->pSwitchInfo[ethPortNum].smiScanMode;
++}
++/*******************************************************************************
++* mvBoardSpecInitGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN: Return MV_TRUE and parameters in case board need spesific phy init,
++* otherwise return MV_FALSE.
++*
++*
++*******************************************************************************/
++
++MV_BOOL mvBoardSpecInitGet(MV_U32* regOff, MV_U32* data)
++{
++ return MV_FALSE;
++}
++
++/*******************************************************************************
++* mvBoardTclkGet - Get the board Tclk (Controller clock)
++*
++* DESCRIPTION:
++* This routine extract the controller core clock.
++* This function uses the controller counters to make identification.
++* Note: In order to avoid interference, make sure task context switch
++* and interrupts will not occure during this function operation
++*
++* INPUT:
++* countNum - Counter number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit clock cycles in Hertz.
++*
++*******************************************************************************/
++MV_U32 mvBoardTclkGet(MV_VOID)
++{
++ if(mvCtrlModelGet()==MV_6281_DEV_ID)
++ {
++#if defined(TCLK_AUTO_DETECT)
++ MV_U32 tmpTClkRate = MV_BOARD_TCLK_166MHZ;
++
++ tmpTClkRate = MV_REG_READ(MPP_SAMPLE_AT_RESET);
++ tmpTClkRate &= MSAR_TCLCK_MASK;
++
++ switch (tmpTClkRate)
++ {
++ case MSAR_TCLCK_166:
++ return MV_BOARD_TCLK_166MHZ;
++ break;
++ case MSAR_TCLCK_200:
++ return MV_BOARD_TCLK_200MHZ;
++ break;
++ }
++#else
++ return MV_BOARD_TCLK_200MHZ;
++#endif
++ }
++
++ return MV_BOARD_TCLK_166MHZ;
++
++}
++/*******************************************************************************
++* mvBoardSysClkGet - Get the board SysClk (CPU bus clock)
++*
++* DESCRIPTION:
++* This routine extract the CPU bus clock.
++*
++* INPUT:
++* countNum - Counter number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit clock cycles in Hertz.
++*
++*******************************************************************************/
++static MV_U32 mvBoard6180SysClkGet(MV_VOID)
++{
++ MV_U32 sysClkRate=0;
++ MV_CPU_ARM_CLK _cpu6180_ddr_l2_CLK[] = MV_CPU6180_DDR_L2_CLCK_TBL;
++
++ sysClkRate = MV_REG_READ(MPP_SAMPLE_AT_RESET);
++ sysClkRate = sysClkRate & MSAR_CPUCLCK_MASK_6180;
++ sysClkRate = sysClkRate >> MSAR_CPUCLCK_OFFS_6180;
++
++ sysClkRate = _cpu6180_ddr_l2_CLK[sysClkRate].ddrClk;
++
++ return sysClkRate;
++
++}
++
++MV_U32 mvBoardSysClkGet(MV_VOID)
++{
++#ifdef SYSCLK_AUTO_DETECT
++ MV_U32 sysClkRate, tmp, pClkRate, indexDdrRtio;
++ MV_U32 cpuCLK[] = MV_CPU_CLCK_TBL;
++ MV_U32 ddrRtio[][2] = MV_DDR_CLCK_RTIO_TBL;
++
++ if(mvCtrlModelGet() == MV_6180_DEV_ID)
++ return mvBoard6180SysClkGet();
++
++ tmp = MV_REG_READ(MPP_SAMPLE_AT_RESET);
++ pClkRate = MSAR_CPUCLCK_EXTRACT(tmp);
++ pClkRate = cpuCLK[pClkRate];
++
++ indexDdrRtio = tmp & MSAR_DDRCLCK_RTIO_MASK;
++ indexDdrRtio = indexDdrRtio >> MSAR_DDRCLCK_RTIO_OFFS;
++ if(ddrRtio[indexDdrRtio][0] != 0)
++ sysClkRate = ((pClkRate * ddrRtio[indexDdrRtio][1]) / ddrRtio[indexDdrRtio][0]);
++ else
++ sysClkRate = 0;
++ return sysClkRate;
++#else
++ return MV_BOARD_DEFAULT_SYSCLK;
++#endif
++}
++
++
++/*******************************************************************************
++* mvBoardPexBridgeIntPinGet - Get PEX to PCI bridge interrupt pin number
++*
++* DESCRIPTION:
++* Multi-ported PCI Express bridges that is implemented on the board
++* collapse interrupts across multiple conventional PCI/PCI-X buses.
++* A dual-headed PCI Express bridge would map (or "swizzle") the
++* interrupts per the following table (in accordance with the respective
++* logical PCI/PCI-X bridge's Device Number), collapse the INTA#-INTD#
++* signals from its two logical PCI/PCI-X bridges, collapse the
++* INTA#-INTD# signals from any internal sources, and convert the
++* signals to in-band PCI Express messages. 10
++* This function returns the upstream interrupt as it was converted by
++* the bridge, according to board configuration and the following table:
++* PCI dev num
++* Interrupt pin 7, 8, 9
++* A -> A D C
++* B -> B A D
++* C -> C B A
++* D -> D C B
++*
++*
++* INPUT:
++* devNum - PCI/PCIX device number.
++* intPin - PCI Int pin
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Int pin connected to the Interrupt controller
++*
++*******************************************************************************/
++MV_U32 mvBoardPexBridgeIntPinGet(MV_U32 devNum, MV_U32 intPin)
++{
++ MV_U32 realIntPin = ((intPin + (3 - (devNum % 4))) %4 );
++
++ if (realIntPin == 0) return 4;
++ else return realIntPin;
++
++}
++
++/*******************************************************************************
++* mvBoardDebugLedNumGet - Get number of debug Leds
++*
++* DESCRIPTION:
++* INPUT:
++* boardId
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_U32 mvBoardDebugLedNumGet(MV_U32 boardId)
++{
++ return BOARD_INFO(boardId)->activeLedsNumber;
++}
++
++/*******************************************************************************
++* mvBoardDebugLeg - Set the board debug Leds
++*
++* DESCRIPTION: turn on/off status leds.
++* Note: assume MPP leds are part of group 0 only.
++*
++* INPUT:
++* hexNum - Number to be displied in hex by Leds.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvBoardDebugLed(MV_U32 hexNum)
++{
++ MV_U32 val = 0,totalMask, currentBitMask = 1,i;
++ MV_U32 boardId= mvBoardIdGet();
++
++ if (BOARD_INFO(boardId)->pLedGppPin == NULL)
++ return;
++
++ totalMask = (1 << BOARD_INFO(boardId)->activeLedsNumber) -1;
++ hexNum &= totalMask;
++ totalMask = 0;
++
++ for (i = 0 ; i < BOARD_INFO(boardId)->activeLedsNumber ; i++)
++ {
++ if (hexNum & currentBitMask)
++ {
++ val |= (1 << BOARD_INFO(boardId)->pLedGppPin[i]);
++ }
++
++ totalMask |= (1 << BOARD_INFO(boardId)->pLedGppPin[i]);
++
++ currentBitMask = (currentBitMask << 1);
++ }
++
++ if (BOARD_INFO(boardId)->ledsPolarity)
++ {
++ mvGppValueSet(0, totalMask, val);
++ }
++ else
++ {
++ mvGppValueSet(0, totalMask, ~val);
++ }
++}
++
++
++/*******************************************************************************
++* mvBoarGpioPinGet - mvBoarGpioPinGet
++*
++* DESCRIPTION:
++*
++* INPUT:
++* class - MV_BOARD_GPP_CLASS enum.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* GPIO pin number. The function return -1 for bad parameters.
++*
++*******************************************************************************/
++MV_32 mvBoarGpioPinNumGet(MV_BOARD_GPP_CLASS class, MV_U32 index)
++{
++ MV_U32 boardId, i;
++ MV_U32 indexFound = 0;
++
++ boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardRTCGpioPinGet:Board unknown.\n");
++ return MV_ERROR;
++
++ }
++
++ for (i = 0; i < BOARD_INFO(boardId)->numBoardGppInfo; i++)
++ if (BOARD_INFO(boardId)->pBoardGppInfo[i].devClass == class) {
++ if (indexFound == index)
++ return (MV_U32)BOARD_INFO(boardId)->pBoardGppInfo[i].gppPinNum;
++ else
++ indexFound++;
++
++ }
++
++ return MV_ERROR;
++}
++
++
++/*******************************************************************************
++* mvBoardRTCGpioPinGet - mvBoardRTCGpioPinGet
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* GPIO pin number. The function return -1 for bad parameters.
++*
++*******************************************************************************/
++MV_32 mvBoardRTCGpioPinGet(MV_VOID)
++{
++ return mvBoarGpioPinNumGet(BOARD_GPP_RTC, 0);
++}
++
++
++/*******************************************************************************
++* mvBoardReset - mvBoardReset
++*
++* DESCRIPTION:
++* Reset the board
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None
++*
++*******************************************************************************/
++MV_VOID mvBoardReset(MV_VOID)
++{
++ MV_32 resetPin;
++
++ /* Get gpp reset pin if define */
++ resetPin = mvBoardResetGpioPinGet();
++ if (resetPin != MV_ERROR)
++ {
++ MV_REG_BIT_RESET( GPP_DATA_OUT_REG(0) ,(1 << resetPin));
++ MV_REG_BIT_RESET( GPP_DATA_OUT_EN_REG(0) ,(1 << resetPin));
++
++ }
++ else
++ {
++ /* No gpp reset pin was found, try to reset ussing
++ system reset out */
++ MV_REG_BIT_SET( CPU_RSTOUTN_MASK_REG , BIT2);
++ MV_REG_BIT_SET( CPU_SYS_SOFT_RST_REG , BIT0);
++ }
++}
++
++/*******************************************************************************
++* mvBoardResetGpioPinGet - mvBoardResetGpioPinGet
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* GPIO pin number. The function return -1 for bad parameters.
++*
++*******************************************************************************/
++MV_32 mvBoardResetGpioPinGet(MV_VOID)
++{
++ return mvBoarGpioPinNumGet(BOARD_GPP_RESET, 0);
++}
++/*******************************************************************************
++* mvBoardSDIOGpioPinGet - mvBoardSDIOGpioPinGet
++*
++* DESCRIPTION:
++* used for hotswap detection
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* GPIO pin number. The function return -1 for bad parameters.
++*
++*******************************************************************************/
++MV_32 mvBoardSDIOGpioPinGet(MV_VOID)
++{
++ return mvBoarGpioPinNumGet(BOARD_GPP_SDIO_DETECT, 0);
++}
++
++/*******************************************************************************
++* mvBoardUSBVbusGpioPinGet - return Vbus input GPP
++*
++* DESCRIPTION:
++*
++* INPUT:
++* int devNo.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* GPIO pin number. The function return -1 for bad parameters.
++*
++*******************************************************************************/
++MV_32 mvBoardUSBVbusGpioPinGet(MV_32 devId)
++{
++ return mvBoarGpioPinNumGet(BOARD_GPP_USB_VBUS, devId);
++}
++
++/*******************************************************************************
++* mvBoardUSBVbusEnGpioPinGet - return Vbus Enable output GPP
++*
++* DESCRIPTION:
++*
++* INPUT:
++* int devNo.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* GPIO pin number. The function return -1 for bad parameters.
++*
++*******************************************************************************/
++MV_32 mvBoardUSBVbusEnGpioPinGet(MV_32 devId)
++{
++ return mvBoarGpioPinNumGet(BOARD_GPP_USB_VBUS_EN, devId);
++}
++
++
++/*******************************************************************************
++* mvBoardGpioIntMaskGet - Get GPIO mask for interrupt pins
++*
++* DESCRIPTION:
++* This function returns a 32-bit mask of GPP pins that connected to
++* interrupt generating sources on board.
++* For example if UART channel A is hardwired to GPP pin 8 and
++* UART channel B is hardwired to GPP pin 4 the fuinction will return
++* the value 0x000000110
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* See description. The function return -1 if board is not identified.
++*
++*******************************************************************************/
++MV_32 mvBoardGpioIntMaskLowGet(MV_VOID)
++{
++ MV_U32 boardId;
++
++ boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardGpioIntMaskGet:Board unknown.\n");
++ return MV_ERROR;
++
++ }
++
++ return BOARD_INFO(boardId)->intsGppMaskLow;
++}
++MV_32 mvBoardGpioIntMaskHighGet(MV_VOID)
++{
++ MV_U32 boardId;
++
++ boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardGpioIntMaskGet:Board unknown.\n");
++ return MV_ERROR;
++
++ }
++
++ return BOARD_INFO(boardId)->intsGppMaskHigh;
++}
++
++
++/*******************************************************************************
++* mvBoardMppGet - Get board dependent MPP register value
++*
++* DESCRIPTION:
++* MPP settings are derived from board design.
++* MPP group consist of 8 MPPs. An MPP group represent MPP
++* control register.
++* This function retrieves board dependend MPP register value.
++*
++* INPUT:
++* mppGroupNum - MPP group number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit value describing MPP control register value.
++*
++*******************************************************************************/
++MV_32 mvBoardMppGet(MV_U32 mppGroupNum)
++{
++ MV_U32 boardId;
++
++ boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardMppGet:Board unknown.\n");
++ return MV_ERROR;
++
++ }
++
++ return BOARD_INFO(boardId)->pBoardMppConfigValue[0].mppGroup[mppGroupNum];
++}
++
++
++/*******************************************************************************
++* mvBoardMppGroupId - If MPP group type is AUTO then identify it using twsi
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_VOID mvBoardMppGroupIdUpdate(MV_VOID)
++{
++
++ MV_BOARD_MPP_GROUP_CLASS devClass;
++ MV_BOARD_MODULE_ID_CLASS devClassId;
++ MV_BOARD_MPP_TYPE_CLASS mppGroupType;
++ MV_U32 devId;
++ MV_U32 maxMppGrp = 1;
++
++ devId = mvCtrlModelGet();
++
++ switch(devId){
++ case MV_6281_DEV_ID:
++ maxMppGrp = MV_6281_MPP_MAX_MODULE;
++ break;
++ case MV_6192_DEV_ID:
++ maxMppGrp = MV_6192_MPP_MAX_MODULE;
++ break;
++ case MV_6190_DEV_ID:
++ maxMppGrp = MV_6190_MPP_MAX_MODULE;
++ break;
++ case MV_6180_DEV_ID:
++ maxMppGrp = MV_6180_MPP_MAX_MODULE;
++ break;
++ }
++
++ for (devClass = 0; devClass < maxMppGrp; devClass++)
++ {
++ /* If MPP group can be defined by the module connected to it */
++ if (mvBoardMppGroupTypeGet(devClass) == MV_BOARD_AUTO)
++ {
++ /* Get MPP module ID */
++ devClassId = mvBoarModuleTypeGet(devClass);
++ if (MV_ERROR != devClassId)
++ {
++ switch(devClassId)
++ {
++ case MV_BOARD_MODULE_TDM_ID:
++ case MV_BOARD_MODULE_TDM_5CHAN_ID:
++ mppGroupType = MV_BOARD_TDM;
++ break;
++ case MV_BOARD_MODULE_AUDIO_ID:
++ mppGroupType = MV_BOARD_AUDIO;
++ break;
++ case MV_BOARD_MODULE_RGMII_ID:
++ mppGroupType = MV_BOARD_RGMII;
++ break;
++ case MV_BOARD_MODULE_GMII_ID:
++ mppGroupType = MV_BOARD_GMII;
++ break;
++ case MV_BOARD_MODULE_TS_ID:
++ mppGroupType = MV_BOARD_TS;
++ break;
++ case MV_BOARD_MODULE_MII_ID:
++ mppGroupType = MV_BOARD_MII;
++ break;
++ default:
++ mppGroupType = MV_BOARD_OTHER;
++ break;
++ }
++ }
++ else
++ /* The module bay is empty */
++ mppGroupType = MV_BOARD_OTHER;
++
++ /* Update MPP group type */
++ mvBoardMppGroupTypeSet(devClass, mppGroupType);
++ }
++
++ /* Update MPP output voltage for RGMII 1.8V. Set port to GMII for GMII module */
++ if ((mvBoardMppGroupTypeGet(devClass) == MV_BOARD_RGMII))
++ MV_REG_BIT_SET(MPP_OUTPUT_DRIVE_REG,MPP_1_8_RGMII1_OUTPUT_DRIVE | MPP_1_8_RGMII0_OUTPUT_DRIVE);
++ else
++ {
++ if ((mvBoardMppGroupTypeGet(devClass) == MV_BOARD_GMII))
++ {
++ MV_REG_BIT_RESET(MPP_OUTPUT_DRIVE_REG, BIT7 | BIT15);
++ MV_REG_BIT_RESET(ETH_PORT_SERIAL_CTRL_1_REG(0),BIT3);
++ MV_REG_BIT_RESET(ETH_PORT_SERIAL_CTRL_1_REG(1),BIT3);
++ }
++ else if ((mvBoardMppGroupTypeGet(devClass) == MV_BOARD_MII))
++ {
++ /* Assumption that the MDC & MDIO should be 3.3V */
++ MV_REG_BIT_RESET(MPP_OUTPUT_DRIVE_REG, BIT7 | BIT15);
++ /* Assumption that only ETH1 can be MII when using modules on DB */
++ MV_REG_BIT_RESET(ETH_PORT_SERIAL_CTRL_1_REG(1),BIT3);
++ }
++ }
++ }
++}
++
++/*******************************************************************************
++* mvBoardMppGroupTypeGet
++*
++* DESCRIPTION:
++*
++* INPUT:
++* mppGroupClass - MPP group number 0 for MPP[35:20] or 1 for MPP[49:36].
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_BOARD_MPP_TYPE_CLASS mvBoardMppGroupTypeGet(MV_BOARD_MPP_GROUP_CLASS mppGroupClass)
++{
++ MV_U32 boardId;
++
++ boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardMppGet:Board unknown.\n");
++ return MV_ERROR;
++
++ }
++
++ if (mppGroupClass == MV_BOARD_MPP_GROUP_1)
++ return BOARD_INFO(boardId)->pBoardMppTypeValue[0].boardMppGroup1;
++ else
++ return BOARD_INFO(boardId)->pBoardMppTypeValue[0].boardMppGroup2;
++}
++
++/*******************************************************************************
++* mvBoardMppGroupTypeSet
++*
++* DESCRIPTION:
++*
++* INPUT:
++* mppGroupClass - MPP group number 0 for MPP[35:20] or 1 for MPP[49:36].
++* mppGroupType - MPP group type for MPP[35:20] or for MPP[49:36].
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_VOID mvBoardMppGroupTypeSet(MV_BOARD_MPP_GROUP_CLASS mppGroupClass,
++ MV_BOARD_MPP_TYPE_CLASS mppGroupType)
++{
++ MV_U32 boardId;
++
++ boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardMppGet:Board unknown.\n");
++ }
++
++ if (mppGroupClass == MV_BOARD_MPP_GROUP_1)
++ BOARD_INFO(boardId)->pBoardMppTypeValue[0].boardMppGroup1 = mppGroupType;
++ else
++ BOARD_INFO(boardId)->pBoardMppTypeValue[0].boardMppGroup2 = mppGroupType;
++
++}
++
++/*******************************************************************************
++* mvBoardMppMuxSet - Update MPP mux
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_VOID mvBoardMppMuxSet(MV_VOID)
++{
++
++ MV_BOARD_MPP_GROUP_CLASS devClass;
++ MV_BOARD_MPP_TYPE_CLASS mppGroupType;
++ MV_U32 devId;
++ MV_U8 muxVal = 0xf;
++ MV_U32 maxMppGrp = 1;
++ MV_TWSI_SLAVE twsiSlave;
++ MV_TWSI_ADDR slave;
++
++ devId = mvCtrlModelGet();
++
++ switch(devId){
++ case MV_6281_DEV_ID:
++ maxMppGrp = MV_6281_MPP_MAX_MODULE;
++ break;
++ case MV_6192_DEV_ID:
++ maxMppGrp = MV_6192_MPP_MAX_MODULE;
++ break;
++ case MV_6190_DEV_ID:
++ maxMppGrp = MV_6190_MPP_MAX_MODULE;
++ break;
++ case MV_6180_DEV_ID:
++ maxMppGrp = MV_6180_MPP_MAX_MODULE;
++ break;
++ }
++
++ for (devClass = 0; devClass < maxMppGrp; devClass++)
++ {
++ mppGroupType = mvBoardMppGroupTypeGet(devClass);
++
++ switch(mppGroupType)
++ {
++ case MV_BOARD_TDM:
++ muxVal &= ~(devClass ? (0x2 << (devClass * 2)):0x0);
++ break;
++ case MV_BOARD_AUDIO:
++ muxVal &= ~(devClass ? 0x7 : 0x0); /*old Z0 value 0xd:0x0*/
++ break;
++ case MV_BOARD_TS:
++ muxVal &= ~(devClass ? (0x2 << (devClass * 2)):0x0);
++ break;
++ default:
++ muxVal |= (devClass ? 0xf : 0);
++ break;
++ }
++ }
++
++ /* TWSI init */
++ slave.type = ADDR7_BIT;
++ slave.address = 0;
++ mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0);
++
++ /* Read MPP module ID */
++ DB(mvOsPrintf("Board: twsi exp set\n"));
++ twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(MV_BOARD_MUX_I2C_ADDR_ENTRY);
++ twsiSlave.slaveAddr.type = mvBoardTwsiExpAddrTypeGet(MV_BOARD_MUX_I2C_ADDR_ENTRY);
++ twsiSlave.validOffset = MV_TRUE;
++ /* Offset is the first command after the address which indicate the register number to be read
++ in next operation */
++ twsiSlave.offset = 2;
++ twsiSlave.moreThen256 = MV_FALSE;
++
++
++
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) )
++ {
++ DB(mvOsPrintf("Board: twsi exp out val fail\n"));
++ return;
++ }
++ DB(mvOsPrintf("Board: twsi exp out val succeded\n"));
++
++ /* Change twsi exp to output */
++ twsiSlave.offset = 6;
++ muxVal = 0;
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) )
++ {
++ DB(mvOsPrintf("Board: twsi exp change to out fail\n"));
++ return;
++ }
++ DB(mvOsPrintf("Board: twsi exp change to out succeded\n"));
++
++}
++
++/*******************************************************************************
++* mvBoardTdmMppSet - set MPPs in TDM module
++*
++* DESCRIPTION:
++*
++* INPUT: type of second telephony device
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_VOID mvBoardTdmMppSet(MV_32 chType)
++{
++
++ MV_BOARD_MPP_GROUP_CLASS devClass;
++ MV_BOARD_MPP_TYPE_CLASS mppGroupType;
++ MV_U32 devId;
++ MV_U8 muxVal = 1;
++ MV_U8 muxValMask = 1;
++ MV_U8 twsiVal;
++ MV_U32 maxMppGrp = 1;
++ MV_TWSI_SLAVE twsiSlave;
++ MV_TWSI_ADDR slave;
++
++ devId = mvCtrlModelGet();
++
++ switch(devId){
++ case MV_6281_DEV_ID:
++ maxMppGrp = MV_6281_MPP_MAX_MODULE;
++ break;
++ case MV_6192_DEV_ID:
++ maxMppGrp = MV_6192_MPP_MAX_MODULE;
++ break;
++ case MV_6190_DEV_ID:
++ maxMppGrp = MV_6190_MPP_MAX_MODULE;
++ break;
++ case MV_6180_DEV_ID:
++ maxMppGrp = MV_6180_MPP_MAX_MODULE;
++ break;
++ }
++
++ for (devClass = 0; devClass < maxMppGrp; devClass++)
++ {
++ mppGroupType = mvBoardMppGroupTypeGet(devClass);
++ if(mppGroupType == MV_BOARD_TDM)
++ break;
++ }
++
++ if(devClass == maxMppGrp)
++ return; /* TDM module not found */
++
++ /* TWSI init */
++ slave.type = ADDR7_BIT;
++ slave.address = 0;
++ mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0);
++
++ /* Read MPP module ID */
++ DB(mvOsPrintf("Board: twsi exp set\n"));
++ twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(devClass);
++ twsiSlave.slaveAddr.type = ADDR7_BIT;
++ twsiSlave.validOffset = MV_TRUE;
++ /* Offset is the first command after the address which indicate the register number to be read
++ in next operation */
++ twsiSlave.offset = 3;
++ twsiSlave.moreThen256 = MV_FALSE;
++
++ if(mvBoardIdGet() == RD_88F6281A_ID)
++ {
++ muxVal = 0xc;
++ muxValMask = 0xf3;
++ }
++
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ muxVal = (twsiVal & muxValMask) | muxVal;
++
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) )
++ {
++ mvOsPrintf("Board: twsi exp out val fail\n");
++ return;
++ }
++ DB(mvOsPrintf("Board: twsi exp out val succeded\n"));
++
++ /* Change twsi exp to output */
++ twsiSlave.offset = 7;
++ muxVal = 0xfe;
++ if(mvBoardIdGet() == RD_88F6281A_ID)
++ muxVal = 0xf3;
++
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ muxVal = (twsiVal & muxVal);
++
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) )
++ {
++ mvOsPrintf("Board: twsi exp change to out fail\n");
++ return;
++ }
++ DB(mvOsPrintf("Board: twsi exp change to out succeded\n"));
++ /* reset the line to 0 */
++ twsiSlave.offset = 3;
++ muxVal = 0;
++ muxValMask = 1;
++
++ if(mvBoardIdGet() == RD_88F6281A_ID) {
++ muxVal = 0x0;
++ muxValMask = 0xf3;
++ }
++
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ muxVal = (twsiVal & muxValMask) | muxVal;
++
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) )
++ {
++ mvOsPrintf("Board: twsi exp out val fail\n");
++ return;
++ }
++ DB(mvOsPrintf("Board: twsi exp out val succeded\n"));
++
++ mvOsDelay(20);
++
++ /* set the line to 1 */
++ twsiSlave.offset = 3;
++ muxVal = 1;
++ muxValMask = 1;
++
++ if(mvBoardIdGet() == RD_88F6281A_ID)
++ {
++ muxVal = 0xc;
++ muxValMask = 0xf3;
++ if(chType) /* FXS - issue reset properly */
++ {
++ MV_REG_BIT_SET(GPP_DATA_OUT_REG(1), MV_GPP12);
++ mvOsDelay(50);
++ MV_REG_BIT_RESET(GPP_DATA_OUT_REG(1), MV_GPP12);
++ }
++ else /* FXO - issue reset via TDM_CODEC_RST*/
++ {
++ /* change MPP44 type to TDM_CODEC_RST(0x2) */
++ MV_REG_WRITE(MPP_CONTROL_REG5, ((MV_REG_READ(MPP_CONTROL_REG5) & 0xFFF0FFFF) | BIT17));
++ }
++ }
++
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ muxVal = (twsiVal & muxValMask) | muxVal;
++
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) )
++ {
++ mvOsPrintf("Board: twsi exp out val fail\n");
++ return;
++ }
++
++ /* TBD - 5 channels */
++#if defined(MV_TDM_5CHANNELS)
++ /* change MPP38 type to GPIO(0x0) & polarity for TDM_STROBE */
++ MV_REG_WRITE(MPP_CONTROL_REG4, (MV_REG_READ(MPP_CONTROL_REG4) & 0xF0FFFFFF));
++ mvGppPolaritySet(1, MV_GPP6, 0);
++
++ twsiSlave.offset = 6;
++ twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(2);
++
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ muxVal = (twsiVal & ~BIT2);
++
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) )
++ {
++ mvOsPrintf("Board: twsi exp change to out fail\n");
++ return;
++ }
++
++
++ twsiSlave.offset = 2;
++
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ muxVal = (twsiVal & ~BIT2);
++
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) )
++ {
++ mvOsPrintf("Board: twsi exp change to out fail\n");
++ return;
++ }
++#endif
++ DB(mvOsPrintf("Board: twsi exp out val succeded\n"));
++
++
++}
++/*******************************************************************************
++* mvBoardVoiceConnModeGet - return SLIC/DAA connection & interrupt modes
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*******************************************************************************/
++
++MV_VOID mvBoardVoiceConnModeGet(MV_32* connMode, MV_32* irqMode)
++{
++ switch(mvBoardIdGet())
++ {
++ case RD_88F6281A_ID:
++ *connMode = DAISY_CHAIN_MODE;
++ *irqMode = INTERRUPT_TO_TDM;
++ break;
++ case DB_88F6281A_BP_ID:
++ *connMode = DUAL_CHIP_SELECT_MODE;
++ *irqMode = INTERRUPT_TO_TDM;
++ break;
++ case RD_88F6192A_ID:
++ *connMode = DUAL_CHIP_SELECT_MODE;
++ *irqMode = INTERRUPT_TO_TDM;
++ break;
++ case DB_88F6192A_BP_ID:
++ *connMode = DUAL_CHIP_SELECT_MODE;
++ *irqMode = INTERRUPT_TO_TDM;
++ break;
++ default:
++ *connMode = *irqMode = -1;
++ mvOsPrintf("mvBoardVoiceAssembleModeGet: TDM not supported(boardId=0x%x)\n",mvBoardIdGet());
++ }
++ return;
++
++}
++
++/*******************************************************************************
++* mvBoardMppModuleTypePrint - print module detect
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_VOID mvBoardMppModuleTypePrint(MV_VOID)
++{
++
++ MV_BOARD_MPP_GROUP_CLASS devClass;
++ MV_BOARD_MPP_TYPE_CLASS mppGroupType;
++ MV_U32 devId;
++ MV_U32 maxMppGrp = 1;
++
++ devId = mvCtrlModelGet();
++
++ switch(devId){
++ case MV_6281_DEV_ID:
++ maxMppGrp = MV_6281_MPP_MAX_MODULE;
++ break;
++ case MV_6192_DEV_ID:
++ maxMppGrp = MV_6192_MPP_MAX_MODULE;
++ break;
++ case MV_6190_DEV_ID:
++ maxMppGrp = MV_6190_MPP_MAX_MODULE;
++ break;
++ case MV_6180_DEV_ID:
++ maxMppGrp = MV_6180_MPP_MAX_MODULE;
++ break;
++ }
++
++ for (devClass = 0; devClass < maxMppGrp; devClass++)
++ {
++ mppGroupType = mvBoardMppGroupTypeGet(devClass);
++
++ switch(mppGroupType)
++ {
++ case MV_BOARD_TDM:
++ if(devId != MV_6190_DEV_ID)
++ mvOsPrintf("Module %d is TDM\n", devClass);
++ break;
++ case MV_BOARD_AUDIO:
++ if(devId != MV_6190_DEV_ID)
++ mvOsPrintf("Module %d is AUDIO\n", devClass);
++ break;
++ case MV_BOARD_RGMII:
++ if(devId != MV_6190_DEV_ID)
++ mvOsPrintf("Module %d is RGMII\n", devClass);
++ break;
++ case MV_BOARD_GMII:
++ if(devId != MV_6190_DEV_ID)
++ mvOsPrintf("Module %d is GMII\n", devClass);
++ break;
++ case MV_BOARD_TS:
++ if(devId != MV_6190_DEV_ID)
++ mvOsPrintf("Module %d is TS\n", devClass);
++ break;
++ default:
++ break;
++ }
++ }
++}
++
++/* Board devices API managments */
++
++/*******************************************************************************
++* mvBoardGetDeviceNumber - Get number of device of some type on the board
++*
++* DESCRIPTION:
++*
++* INPUT:
++* devType - The device type ( Flash,RTC , etc .. )
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* If the device is found on the board the then the functions returns the
++* number of those devices else the function returns 0
++*
++*
++*******************************************************************************/
++MV_32 mvBoardGetDevicesNumber(MV_BOARD_DEV_CLASS devClass)
++{
++ MV_U32 foundIndex=0,devNum;
++ MV_U32 boardId= mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("mvBoardGetDeviceNumber:Board unknown.\n");
++ return 0xFFFFFFFF;
++
++ }
++
++ for (devNum = START_DEV_CS; devNum < BOARD_INFO(boardId)->numBoardDeviceIf; devNum++)
++ {
++ if (BOARD_INFO(boardId)->pDevCsInfo[devNum].devClass == devClass)
++ {
++ foundIndex++;
++ }
++ }
++
++ return foundIndex;
++
++}
++
++/*******************************************************************************
++* mvBoardGetDeviceBaseAddr - Get base address of a device existing on the board
++*
++* DESCRIPTION:
++*
++* INPUT:
++* devIndex - The device sequential number on the board
++* devType - The device type ( Flash,RTC , etc .. )
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* If the device is found on the board the then the functions returns the
++* Base address else the function returns 0xffffffff
++*
++*
++*******************************************************************************/
++MV_32 mvBoardGetDeviceBaseAddr(MV_32 devNum, MV_BOARD_DEV_CLASS devClass)
++{
++ MV_DEV_CS_INFO* devEntry;
++ devEntry = boardGetDevEntry(devNum,devClass);
++ if (devEntry != NULL)
++ {
++ return mvCpuIfTargetWinBaseLowGet(DEV_TO_TARGET(devEntry->deviceCS));
++
++ }
++
++ return 0xFFFFFFFF;
++}
++
++/*******************************************************************************
++* mvBoardGetDeviceBusWidth - Get Bus width of a device existing on the board
++*
++* DESCRIPTION:
++*
++* INPUT:
++* devIndex - The device sequential number on the board
++* devType - The device type ( Flash,RTC , etc .. )
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* If the device is found on the board the then the functions returns the
++* Bus width else the function returns 0xffffffff
++*
++*
++*******************************************************************************/
++MV_32 mvBoardGetDeviceBusWidth(MV_32 devNum, MV_BOARD_DEV_CLASS devClass)
++{
++ MV_DEV_CS_INFO* devEntry;
++
++ devEntry = boardGetDevEntry(devNum,devClass);
++ if (devEntry != NULL)
++ {
++ return 8;
++ }
++
++ return 0xFFFFFFFF;
++
++}
++
++/*******************************************************************************
++* mvBoardGetDeviceWidth - Get dev width of a device existing on the board
++*
++* DESCRIPTION:
++*
++* INPUT:
++* devIndex - The device sequential number on the board
++* devType - The device type ( Flash,RTC , etc .. )
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* If the device is found on the board the then the functions returns the
++* dev width else the function returns 0xffffffff
++*
++*
++*******************************************************************************/
++MV_32 mvBoardGetDeviceWidth(MV_32 devNum, MV_BOARD_DEV_CLASS devClass)
++{
++ MV_DEV_CS_INFO* devEntry;
++ MV_U32 boardId= mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("Board unknown.\n");
++ return 0xFFFFFFFF;
++ }
++
++ devEntry = boardGetDevEntry(devNum,devClass);
++ if (devEntry != NULL)
++ return devEntry->devWidth;
++
++ return MV_ERROR;
++
++}
++
++/*******************************************************************************
++* mvBoardGetDeviceWinSize - Get the window size of a device existing on the board
++*
++* DESCRIPTION:
++*
++* INPUT:
++* devIndex - The device sequential number on the board
++* devType - The device type ( Flash,RTC , etc .. )
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* If the device is found on the board the then the functions returns the
++* window size else the function returns 0xffffffff
++*
++*
++*******************************************************************************/
++MV_32 mvBoardGetDeviceWinSize(MV_32 devNum, MV_BOARD_DEV_CLASS devClass)
++{
++ MV_DEV_CS_INFO* devEntry;
++ MV_U32 boardId = mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("Board unknown.\n");
++ return 0xFFFFFFFF;
++ }
++
++ devEntry = boardGetDevEntry(devNum,devClass);
++ if (devEntry != NULL)
++ {
++ return mvCpuIfTargetWinSizeGet(DEV_TO_TARGET(devEntry->deviceCS));
++ }
++
++ return 0xFFFFFFFF;
++}
++
++
++/*******************************************************************************
++* boardGetDevEntry - returns the entry pointer of a device on the board
++*
++* DESCRIPTION:
++*
++* INPUT:
++* devIndex - The device sequential number on the board
++* devType - The device type ( Flash,RTC , etc .. )
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* If the device is found on the board the then the functions returns the
++* dev number else the function returns 0x0
++*
++*
++*******************************************************************************/
++static MV_DEV_CS_INFO* boardGetDevEntry(MV_32 devNum, MV_BOARD_DEV_CLASS devClass)
++{
++ MV_U32 foundIndex=0,devIndex;
++ MV_U32 boardId= mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("boardGetDevEntry: Board unknown.\n");
++ return NULL;
++
++ }
++
++ for (devIndex = START_DEV_CS; devIndex < BOARD_INFO(boardId)->numBoardDeviceIf; devIndex++)
++ {
++ /* TBR */
++ /*if (BOARD_INFO(boardId)->pDevCsInfo[devIndex].deviceCS == MV_BOOTDEVICE_INDEX)
++ continue;*/
++
++ if (BOARD_INFO(boardId)->pDevCsInfo[devIndex].devClass == devClass)
++ {
++ if (foundIndex == devNum)
++ {
++ return &(BOARD_INFO(boardId)->pDevCsInfo[devIndex]);
++ }
++ foundIndex++;
++ }
++ }
++
++ /* device not found */
++ return NULL;
++}
++
++/* Get device CS number */
++
++MV_U32 boardGetDevCSNum(MV_32 devNum, MV_BOARD_DEV_CLASS devClass)
++{
++ MV_DEV_CS_INFO* devEntry;
++ MV_U32 boardId= mvBoardIdGet();
++
++ if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID)))
++ {
++ mvOsPrintf("Board unknown.\n");
++ return 0xFFFFFFFF;
++
++ }
++
++
++ devEntry = boardGetDevEntry(devNum,devClass);
++ if (devEntry != NULL)
++ return devEntry->deviceCS;
++
++ return 0xFFFFFFFF;
++
++}
++
++/*******************************************************************************
++* mvBoardRtcTwsiAddrTypeGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*
++*******************************************************************************/
++MV_U8 mvBoardRtcTwsiAddrTypeGet()
++{
++ int i;
++ MV_U32 boardId= mvBoardIdGet();
++
++ for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++)
++ if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_TWSI_RTC)
++ return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddrType;
++ return (MV_ERROR);
++}
++
++/*******************************************************************************
++* mvBoardRtcTwsiAddrGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*
++*******************************************************************************/
++MV_U8 mvBoardRtcTwsiAddrGet()
++{
++ int i;
++ MV_U32 boardId= mvBoardIdGet();
++
++ for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++)
++ if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_TWSI_RTC)
++ return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddr;
++ return (0xFF);
++}
++
++/*******************************************************************************
++* mvBoardA2DTwsiAddrTypeGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*
++*******************************************************************************/
++MV_U8 mvBoardA2DTwsiAddrTypeGet()
++{
++ int i;
++ MV_U32 boardId= mvBoardIdGet();
++
++ for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++)
++ if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_TWSI_AUDIO_DEC)
++ return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddrType;
++ return (MV_ERROR);
++}
++
++/*******************************************************************************
++* mvBoardA2DTwsiAddrGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*
++*******************************************************************************/
++MV_U8 mvBoardA2DTwsiAddrGet()
++{
++ int i;
++ MV_U32 boardId= mvBoardIdGet();
++
++ for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++)
++ if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_TWSI_AUDIO_DEC)
++ return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddr;
++ return (0xFF);
++}
++
++/*******************************************************************************
++* mvBoardTwsiExpAddrTypeGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*
++*******************************************************************************/
++MV_U8 mvBoardTwsiExpAddrTypeGet(MV_U32 index)
++{
++ int i;
++ MV_U32 indexFound = 0;
++ MV_U32 boardId= mvBoardIdGet();
++
++ for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++)
++ if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_DEV_TWSI_EXP)
++ {
++ if (indexFound == index)
++ return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddrType;
++ else
++ indexFound++;
++ }
++
++ return (MV_ERROR);
++}
++
++/*******************************************************************************
++* mvBoardTwsiExpAddrGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*
++*******************************************************************************/
++MV_U8 mvBoardTwsiExpAddrGet(MV_U32 index)
++{
++ int i;
++ MV_U32 indexFound = 0;
++ MV_U32 boardId= mvBoardIdGet();
++
++ for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++)
++ if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_DEV_TWSI_EXP)
++ {
++ if (indexFound == index)
++ return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddr;
++ else
++ indexFound++;
++ }
++
++ return (0xFF);
++}
++
++
++/*******************************************************************************
++* mvBoardTwsiSatRAddrTypeGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*
++*******************************************************************************/
++MV_U8 mvBoardTwsiSatRAddrTypeGet(MV_U32 index)
++{
++ int i;
++ MV_U32 indexFound = 0;
++ MV_U32 boardId= mvBoardIdGet();
++
++ for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++)
++ if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_DEV_TWSI_SATR)
++ {
++ if (indexFound == index)
++ return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddrType;
++ else
++ indexFound++;
++ }
++
++ return (MV_ERROR);
++}
++
++/*******************************************************************************
++* mvBoardTwsiSatRAddrGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*
++*******************************************************************************/
++MV_U8 mvBoardTwsiSatRAddrGet(MV_U32 index)
++{
++ int i;
++ MV_U32 indexFound = 0;
++ MV_U32 boardId= mvBoardIdGet();
++
++ for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++)
++ if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_DEV_TWSI_SATR)
++ {
++ if (indexFound == index)
++ return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddr;
++ else
++ indexFound++;
++ }
++
++ return (0xFF);
++}
++
++/*******************************************************************************
++* mvBoardNandWidthGet -
++*
++* DESCRIPTION: Get the width of the first NAND device in byte.
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN: 1, 2, 4 or MV_ERROR
++*
++*
++*******************************************************************************/
++/* */
++MV_32 mvBoardNandWidthGet(void)
++{
++ MV_U32 devNum;
++ MV_U32 devWidth;
++ MV_U32 boardId= mvBoardIdGet();
++
++ for (devNum = START_DEV_CS; devNum < BOARD_INFO(boardId)->numBoardDeviceIf; devNum++)
++ {
++ devWidth = mvBoardGetDeviceWidth(devNum, BOARD_DEV_NAND_FLASH);
++ if (devWidth != MV_ERROR)
++ return (devWidth / 8);
++ }
++
++ /* NAND wasn't found */
++ return MV_ERROR;
++}
++
++MV_U32 gBoardId = -1;
++
++/*******************************************************************************
++* mvBoardIdGet - Get Board model
++*
++* DESCRIPTION:
++* This function returns board ID.
++* Board ID is 32bit word constructed of board model (16bit) and
++* board revision (16bit) in the following way: 0xMMMMRRRR.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit board ID number, '-1' if board is undefined.
++*
++*******************************************************************************/
++MV_U32 mvBoardIdGet(MV_VOID)
++{
++ MV_U32 tmpBoardId = -1;
++
++ if(gBoardId == -1)
++ {
++ #if defined(DB_88F6281A)
++ tmpBoardId = DB_88F6281A_BP_ID;
++ #elif defined(RD_88F6281A)
++ tmpBoardId = RD_88F6281A_ID;
++ #elif defined(DB_88F6192A)
++ tmpBoardId = DB_88F6192A_BP_ID;
++ #elif defined(DB_88F6190A)
++ tmpBoardId = DB_88F6190A_BP_ID;
++ #elif defined(RD_88F6192A)
++ tmpBoardId = RD_88F6192A_ID;
++ #elif defined(RD_88F6190A)
++ tmpBoardId = RD_88F6190A_ID;
++ #elif defined(DB_88F6180A)
++ tmpBoardId = DB_88F6180A_BP_ID;
++ #elif defined(RD_88F6281A_PCAC)
++ tmpBoardId = RD_88F6281A_PCAC_ID;
++ #elif defined(RD_88F6281A_SHEEVA_PLUG)
++ tmpBoardId = SHEEVA_PLUG_ID;
++ #elif defined(DB_CUSTOMER)
++ tmpBoardId = DB_CUSTOMER_ID;
++ #endif
++ gBoardId = tmpBoardId;
++ }
++
++ return gBoardId;
++}
++
++
++/*******************************************************************************
++* mvBoarModuleTypeGet - mvBoarModuleTypeGet
++*
++* DESCRIPTION:
++*
++* INPUT:
++* group num - MV_BOARD_MPP_GROUP_CLASS enum
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* module num - MV_BOARD_MODULE_CLASS enum
++*
++*******************************************************************************/
++MV_BOARD_MODULE_ID_CLASS mvBoarModuleTypeGet(MV_BOARD_MPP_GROUP_CLASS devClass)
++{
++ MV_TWSI_SLAVE twsiSlave;
++ MV_TWSI_ADDR slave;
++ MV_U8 data;
++
++ /* TWSI init */
++ slave.type = ADDR7_BIT;
++ slave.address = 0;
++ mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0);
++
++ /* Read MPP module ID */
++ DB(mvOsPrintf("Board: Read MPP module ID\n"));
++ twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(devClass);
++ twsiSlave.slaveAddr.type = mvBoardTwsiExpAddrTypeGet(devClass);
++ twsiSlave.validOffset = MV_TRUE;
++ /* Offset is the first command after the address which indicate the register number to be read
++ in next operation */
++ twsiSlave.offset = 0;
++ twsiSlave.moreThen256 = MV_FALSE;
++
++
++
++ if( MV_OK != mvTwsiRead (0, &twsiSlave, &data, 1) )
++ {
++ DB(mvOsPrintf("Board: Read MPP module ID fail\n"));
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Board: Read MPP module ID succeded\n"));
++
++ return data;
++}
++
++/*******************************************************************************
++* mvBoarTwsiSatRGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++* device num - one of three devices
++* reg num - 0 or 1
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* reg value
++*
++*******************************************************************************/
++MV_U8 mvBoarTwsiSatRGet(MV_U8 devNum, MV_U8 regNum)
++{
++ MV_TWSI_SLAVE twsiSlave;
++ MV_TWSI_ADDR slave;
++ MV_U8 data;
++
++ /* TWSI init */
++ slave.type = ADDR7_BIT;
++ slave.address = 0;
++ mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0);
++
++ /* Read MPP module ID */
++ DB(mvOsPrintf("Board: Read S@R device read\n"));
++ twsiSlave.slaveAddr.address = mvBoardTwsiSatRAddrGet(devNum);
++ twsiSlave.slaveAddr.type = mvBoardTwsiSatRAddrTypeGet(devNum);
++ twsiSlave.validOffset = MV_TRUE;
++ /* Use offset as command */
++ twsiSlave.offset = regNum;
++ twsiSlave.moreThen256 = MV_FALSE;
++
++ if( MV_OK != mvTwsiRead (0, &twsiSlave, &data, 1) )
++ {
++ DB(mvOsPrintf("Board: Read S@R fail\n"));
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Board: Read S@R succeded\n"));
++
++ return data;
++}
++
++/*******************************************************************************
++* mvBoarTwsiSatRSet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++* devNum - one of three devices
++* regNum - 0 or 1
++* regVal - value
++*
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* reg value
++*
++*******************************************************************************/
++MV_STATUS mvBoarTwsiSatRSet(MV_U8 devNum, MV_U8 regNum, MV_U8 regVal)
++{
++ MV_TWSI_SLAVE twsiSlave;
++ MV_TWSI_ADDR slave;
++
++ /* TWSI init */
++ slave.type = ADDR7_BIT;
++ slave.address = 0;
++ mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0);
++
++ /* Read MPP module ID */
++ twsiSlave.slaveAddr.address = mvBoardTwsiSatRAddrGet(devNum);
++ twsiSlave.slaveAddr.type = mvBoardTwsiSatRAddrTypeGet(devNum);
++ twsiSlave.validOffset = MV_TRUE;
++ DB(mvOsPrintf("Board: Write S@R device addr %x, type %x, data %x\n", twsiSlave.slaveAddr.address,\
++ twsiSlave.slaveAddr.type, regVal));
++ /* Use offset as command */
++ twsiSlave.offset = regNum;
++ twsiSlave.moreThen256 = MV_FALSE;
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &regVal, 1) )
++ {
++ DB(mvOsPrintf("Board: Write S@R fail\n"));
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Board: Write S@R succeded\n"));
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvBoardSlicGpioPinGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*
++*******************************************************************************/
++MV_32 mvBoardSlicGpioPinGet(MV_U32 slicNum)
++{
++ MV_U32 boardId;
++ boardId = mvBoardIdGet();
++
++ switch (boardId)
++ {
++ case DB_88F6281A_BP_ID:
++ case RD_88F6281A_ID:
++ default:
++ return MV_ERROR;
++ break;
++
++ }
++}
++
++/*******************************************************************************
++* mvBoardFanPowerControl - Turn on/off the fan power control on the RD-6281A
++*
++* DESCRIPTION:
++*
++* INPUT:
++* mode - MV_TRUE = on ; MV_FALSE = off
++*
++* OUTPUT:
++* MV_STATUS - MV_OK , MV_ERROR.
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_STATUS mvBoardFanPowerControl(MV_BOOL mode)
++{
++
++ MV_U8 val = 1, twsiVal;
++ MV_TWSI_SLAVE twsiSlave;
++ MV_TWSI_ADDR slave;
++
++ if(mvBoardIdGet() != RD_88F6281A_ID)
++ return MV_ERROR;
++
++ /* TWSI init */
++ slave.type = ADDR7_BIT;
++ slave.address = 0;
++ mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0);
++
++ /* Read MPP module ID */
++ DB(mvOsPrintf("Board: twsi exp set\n"));
++ twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(1);
++ twsiSlave.slaveAddr.type = ADDR7_BIT;
++ twsiSlave.validOffset = MV_TRUE;
++ /* Offset is the first command after the address which indicate the register number to be read
++ in next operation */
++ twsiSlave.offset = 3;
++ twsiSlave.moreThen256 = MV_FALSE;
++ if(mode == MV_TRUE)
++ val = 0x1;
++ else
++ val = 0;
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ val = (twsiVal & 0xfe) | val;
++
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) )
++ {
++ DB(mvOsPrintf("Board: twsi exp out val fail\n"));
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Board: twsi exp out val succeded\n"));
++
++ /* Change twsi exp to output */
++ twsiSlave.offset = 7;
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ val = (twsiVal & 0xfe);
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) )
++ {
++ DB(mvOsPrintf("Board: twsi exp change to out fail\n"));
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Board: twsi exp change to out succeded\n"));
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvBoardHDDPowerControl - Turn on/off the HDD power control on the RD-6281A
++*
++* DESCRIPTION:
++*
++* INPUT:
++* mode - MV_TRUE = on ; MV_FALSE = off
++*
++* OUTPUT:
++* MV_STATUS - MV_OK , MV_ERROR.
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_STATUS mvBoardHDDPowerControl(MV_BOOL mode)
++{
++
++ MV_U8 val = 1, twsiVal;
++ MV_TWSI_SLAVE twsiSlave;
++ MV_TWSI_ADDR slave;
++
++ if(mvBoardIdGet() != RD_88F6281A_ID)
++ return MV_ERROR;
++
++ /* TWSI init */
++ slave.type = ADDR7_BIT;
++ slave.address = 0;
++ mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0);
++
++ /* Read MPP module ID */
++ DB(mvOsPrintf("Board: twsi exp set\n"));
++ twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(1);
++ twsiSlave.slaveAddr.type = ADDR7_BIT;
++ twsiSlave.validOffset = MV_TRUE;
++ /* Offset is the first command after the address which indicate the register number to be read
++ in next operation */
++ twsiSlave.offset = 3;
++ twsiSlave.moreThen256 = MV_FALSE;
++ if(mode == MV_TRUE)
++ val = 0x2;
++ else
++ val = 0;
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ val = (twsiVal & 0xfd) | val;
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) )
++ {
++ DB(mvOsPrintf("Board: twsi exp out val fail\n"));
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Board: twsi exp out val succeded\n"));
++
++ /* Change twsi exp to output */
++ twsiSlave.offset = 7;
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ val = (twsiVal & 0xfd);
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) )
++ {
++ DB(mvOsPrintf("Board: twsi exp change to out fail\n"));
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Board: twsi exp change to out succeded\n"));
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvBoardSDioWPControl - Turn on/off the SDIO WP on the RD-6281A
++*
++* DESCRIPTION:
++*
++* INPUT:
++* mode - MV_TRUE = on ; MV_FALSE = off
++*
++* OUTPUT:
++* MV_STATUS - MV_OK , MV_ERROR.
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_STATUS mvBoardSDioWPControl(MV_BOOL mode)
++{
++
++ MV_U8 val = 1, twsiVal;
++ MV_TWSI_SLAVE twsiSlave;
++ MV_TWSI_ADDR slave;
++
++ if(mvBoardIdGet() != RD_88F6281A_ID)
++ return MV_ERROR;
++
++ /* TWSI init */
++ slave.type = ADDR7_BIT;
++ slave.address = 0;
++ mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0);
++
++ /* Read MPP module ID */
++ DB(mvOsPrintf("Board: twsi exp set\n"));
++ twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(0);
++ twsiSlave.slaveAddr.type = ADDR7_BIT;
++ twsiSlave.validOffset = MV_TRUE;
++ /* Offset is the first command after the address which indicate the register number to be read
++ in next operation */
++ twsiSlave.offset = 3;
++ twsiSlave.moreThen256 = MV_FALSE;
++ if(mode == MV_TRUE)
++ val = 0x10;
++ else
++ val = 0;
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ val = (twsiVal & 0xef) | val;
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) )
++ {
++ DB(mvOsPrintf("Board: twsi exp out val fail\n"));
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Board: twsi exp out val succeded\n"));
++
++ /* Change twsi exp to output */
++ twsiSlave.offset = 7;
++ mvTwsiRead(0, &twsiSlave, &twsiVal, 1);
++ val = (twsiVal & 0xef);
++ if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) )
++ {
++ DB(mvOsPrintf("Board: twsi exp change to out fail\n"));
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Board: twsi exp change to out succeded\n"));
++ return MV_OK;
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.h 2010-11-09 20:28:07.362495449 +0100
+@@ -0,0 +1,376 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvBoardEnvLibh
++#define __INCmvBoardEnvLibh
++
++/* defines */
++/* The below constant macros defines the board I2C EEPROM data offsets */
++
++
++
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "mvSysHwConfig.h"
++#include "boardEnv/mvBoardEnvSpec.h"
++
++
++/* DUART stuff for Tclk detection only */
++#define DUART_BAUD_RATE 115200
++#define MAX_CLOCK_MARGINE 5000000 /* Maximum detected clock margine */
++
++/* Voice devices assembly modes */
++#define DAISY_CHAIN_MODE 1
++#define DUAL_CHIP_SELECT_MODE 0
++#define INTERRUPT_TO_MPP 1
++#define INTERRUPT_TO_TDM 0
++
++
++#define BOARD_ETH_PORT_NUM MV_ETH_MAX_PORTS
++#define BOARD_ETH_SWITCH_PORT_NUM 5
++
++#define MV_BOARD_MAX_USB_IF 1
++#define MV_BOARD_MAX_MPP 7
++#define MV_BOARD_NAME_LEN 0x20
++
++typedef struct _boardData
++{
++ MV_U32 magic;
++ MV_U16 boardId;
++ MV_U8 boardVer;
++ MV_U8 boardRev;
++ MV_U32 reserved1;
++ MV_U32 reserved2;
++
++}BOARD_DATA;
++
++typedef enum _devBoardMppGroupClass
++{
++ MV_BOARD_MPP_GROUP_1,
++ MV_BOARD_MPP_GROUP_2,
++ MV_BOARD_MAX_MPP_GROUP
++}MV_BOARD_MPP_GROUP_CLASS;
++
++typedef enum _devBoardMppTypeClass
++{
++ MV_BOARD_AUTO,
++ MV_BOARD_TDM,
++ MV_BOARD_AUDIO,
++ MV_BOARD_RGMII,
++ MV_BOARD_GMII,
++ MV_BOARD_TS,
++ MV_BOARD_MII,
++ MV_BOARD_OTHER
++}MV_BOARD_MPP_TYPE_CLASS;
++
++typedef enum _devBoardModuleIdClass
++{
++ MV_BOARD_MODULE_TDM_ID = 1,
++ MV_BOARD_MODULE_AUDIO_ID,
++ MV_BOARD_MODULE_RGMII_ID,
++ MV_BOARD_MODULE_GMII_ID,
++ MV_BOARD_MODULE_TS_ID,
++ MV_BOARD_MODULE_MII_ID,
++ MV_BOARD_MODULE_TDM_5CHAN_ID,
++ MV_BOARD_MODULE_OTHER_ID
++}MV_BOARD_MODULE_ID_CLASS;
++
++typedef struct _boardMppTypeInfo
++{
++ MV_BOARD_MPP_TYPE_CLASS boardMppGroup1;
++ MV_BOARD_MPP_TYPE_CLASS boardMppGroup2;
++
++}MV_BOARD_MPP_TYPE_INFO;
++
++
++typedef enum _devBoardClass
++{
++ BOARD_DEV_NOR_FLASH,
++ BOARD_DEV_NAND_FLASH,
++ BOARD_DEV_SEVEN_SEG,
++ BOARD_DEV_FPGA,
++ BOARD_DEV_SRAM,
++ BOARD_DEV_SPI_FLASH,
++ BOARD_DEV_OTHER,
++}MV_BOARD_DEV_CLASS;
++
++typedef enum _devTwsiBoardClass
++{
++ BOARD_TWSI_RTC,
++ BOARD_DEV_TWSI_EXP,
++ BOARD_DEV_TWSI_SATR,
++ BOARD_TWSI_AUDIO_DEC,
++ BOARD_TWSI_OTHER
++}MV_BOARD_TWSI_CLASS;
++
++typedef enum _devGppBoardClass
++{
++ BOARD_GPP_RTC,
++ BOARD_GPP_MV_SWITCH,
++ BOARD_GPP_USB_VBUS,
++ BOARD_GPP_USB_VBUS_EN,
++ BOARD_GPP_USB_OC,
++ BOARD_GPP_USB_HOST_DEVICE,
++ BOARD_GPP_REF_CLCK,
++ BOARD_GPP_VOIP_SLIC,
++ BOARD_GPP_LIFELINE,
++ BOARD_GPP_BUTTON,
++ BOARD_GPP_TS_BUTTON_C,
++ BOARD_GPP_TS_BUTTON_U,
++ BOARD_GPP_TS_BUTTON_D,
++ BOARD_GPP_TS_BUTTON_L,
++ BOARD_GPP_TS_BUTTON_R,
++ BOARD_GPP_POWER_BUTTON,
++ BOARD_GPP_RESTOR_BUTTON,
++ BOARD_GPP_WPS_BUTTON,
++ BOARD_GPP_HDD0_POWER,
++ BOARD_GPP_HDD1_POWER,
++ BOARD_GPP_FAN_POWER,
++ BOARD_GPP_RESET,
++ BOARD_GPP_POWER_ON_LED,
++ BOARD_GPP_HDD_POWER,
++ BOARD_GPP_SDIO_POWER,
++ BOARD_GPP_SDIO_DETECT,
++ BOARD_GPP_SDIO_WP,
++ BOARD_GPP_SWITCH_PHY_INT,
++ BOARD_GPP_TSU_DIRCTION,
++ BOARD_GPP_OTHER
++}MV_BOARD_GPP_CLASS;
++
++
++typedef struct _devCsInfo
++{
++ MV_U8 deviceCS;
++ MV_U32 params;
++ MV_U32 devClass; /* MV_BOARD_DEV_CLASS */
++ MV_U8 devWidth;
++
++}MV_DEV_CS_INFO;
++
++
++#define MV_BOARD_PHY_FORCE_10MB 0x0
++#define MV_BOARD_PHY_FORCE_100MB 0x1
++#define MV_BOARD_PHY_FORCE_1000MB 0x2
++#define MV_BOARD_PHY_SPEED_AUTO 0x3
++
++typedef struct _boardSwitchInfo
++{
++ MV_32 linkStatusIrq;
++ MV_32 qdPort[BOARD_ETH_SWITCH_PORT_NUM];
++ MV_32 qdCpuPort;
++ MV_32 smiScanMode; /* 1 for SMI_MANUAL_MODE, 0 otherwise */
++ MV_32 switchOnPort;
++
++}MV_BOARD_SWITCH_INFO;
++
++typedef struct _boardLedInfo
++{
++ MV_U8 activeLedsNumber;
++ MV_U8 ledsPolarity; /* '0' or '1' to turn on led */
++ MV_U8* gppPinNum; /* Pointer to GPP values */
++
++}MV_BOARD_LED_INFO;
++
++typedef struct _boardGppInfo
++{
++ MV_BOARD_GPP_CLASS devClass;
++ MV_U8 gppPinNum;
++
++}MV_BOARD_GPP_INFO;
++
++
++typedef struct _boardTwsiInfo
++{
++ MV_BOARD_TWSI_CLASS devClass;
++ MV_U8 twsiDevAddr;
++ MV_U8 twsiDevAddrType;
++
++}MV_BOARD_TWSI_INFO;
++
++
++typedef enum _boardMacSpeed
++{
++ BOARD_MAC_SPEED_10M,
++ BOARD_MAC_SPEED_100M,
++ BOARD_MAC_SPEED_1000M,
++ BOARD_MAC_SPEED_AUTO,
++
++}MV_BOARD_MAC_SPEED;
++
++typedef struct _boardMacInfo
++{
++ MV_BOARD_MAC_SPEED boardMacSpeed;
++ MV_U8 boardEthSmiAddr;
++
++}MV_BOARD_MAC_INFO;
++
++typedef struct _boardMppInfo
++{
++ MV_U32 mppGroup[MV_BOARD_MAX_MPP];
++
++}MV_BOARD_MPP_INFO;
++
++typedef struct _boardInfo
++{
++ char boardName[MV_BOARD_NAME_LEN];
++ MV_U8 numBoardMppTypeValue;
++ MV_BOARD_MPP_TYPE_INFO* pBoardMppTypeValue;
++ MV_U8 numBoardMppConfigValue;
++ MV_BOARD_MPP_INFO* pBoardMppConfigValue;
++ MV_U32 intsGppMaskLow;
++ MV_U32 intsGppMaskHigh;
++ MV_U8 numBoardDeviceIf;
++ MV_DEV_CS_INFO* pDevCsInfo;
++ MV_U8 numBoardTwsiDev;
++ MV_BOARD_TWSI_INFO* pBoardTwsiDev;
++ MV_U8 numBoardMacInfo;
++ MV_BOARD_MAC_INFO* pBoardMacInfo;
++ MV_U8 numBoardGppInfo;
++ MV_BOARD_GPP_INFO* pBoardGppInfo;
++ MV_U8 activeLedsNumber;
++ MV_U8* pLedGppPin;
++ MV_U8 ledsPolarity; /* '0' or '1' to turn on led */
++ /* GPP values */
++ MV_U32 gppOutEnValLow;
++ MV_U32 gppOutEnValHigh;
++ MV_U32 gppOutValLow;
++ MV_U32 gppOutValHigh;
++ MV_U32 gppPolarityValLow;
++ MV_U32 gppPolarityValHigh;
++
++ /* Switch Configuration */
++ MV_BOARD_SWITCH_INFO* pSwitchInfo;
++}MV_BOARD_INFO;
++
++
++
++MV_VOID mvBoardEnvInit(MV_VOID);
++MV_U32 mvBoardIdGet(MV_VOID);
++MV_U16 mvBoardModelGet(MV_VOID);
++MV_U16 mvBoardRevGet(MV_VOID);
++MV_STATUS mvBoardNameGet(char *pNameBuff);
++MV_32 mvBoardPhyAddrGet(MV_U32 ethPortNum);
++MV_BOARD_MAC_SPEED mvBoardMacSpeedGet(MV_U32 ethPortNum);
++MV_32 mvBoardLinkStatusIrqGet(MV_U32 ethPortNum);
++MV_32 mvBoardSwitchPortGet(MV_U32 ethPortNum, MV_U8 boardPortNum);
++MV_32 mvBoardSwitchCpuPortGet(MV_U32 ethPortNum);
++MV_32 mvBoardIsSwitchConnected(MV_U32 ethPortNum);
++MV_32 mvBoardSmiScanModeGet(MV_U32 ethPortNum);
++MV_BOOL mvBoardIsPortInSgmii(MV_U32 ethPortNum);
++MV_BOOL mvBoardIsPortInGmii(MV_VOID);
++MV_U32 mvBoardTclkGet(MV_VOID);
++MV_U32 mvBoardSysClkGet(MV_VOID);
++MV_U32 mvBoardDebugLedNumGet(MV_U32 boardId);
++MV_VOID mvBoardDebugLed(MV_U32 hexNum);
++MV_32 mvBoardMppGet(MV_U32 mppGroupNum);
++
++MV_U8 mvBoardRtcTwsiAddrTypeGet(MV_VOID);
++MV_U8 mvBoardRtcTwsiAddrGet(MV_VOID);
++
++MV_U8 mvBoardA2DTwsiAddrTypeGet(MV_VOID);
++MV_U8 mvBoardA2DTwsiAddrGet(MV_VOID);
++
++MV_U8 mvBoardTwsiExpAddrGet(MV_U32 index);
++MV_U8 mvBoardTwsiSatRAddrTypeGet(MV_U32 index);
++MV_U8 mvBoardTwsiSatRAddrGet(MV_U32 index);
++MV_U8 mvBoardTwsiExpAddrTypeGet(MV_U32 index);
++MV_BOARD_MODULE_ID_CLASS mvBoarModuleTypeGet(MV_BOARD_MPP_GROUP_CLASS devClass);
++MV_BOARD_MPP_TYPE_CLASS mvBoardMppGroupTypeGet(MV_BOARD_MPP_GROUP_CLASS mppGroupClass);
++MV_VOID mvBoardMppGroupTypeSet(MV_BOARD_MPP_GROUP_CLASS mppGroupClass,
++ MV_BOARD_MPP_TYPE_CLASS mppGroupType);
++MV_VOID mvBoardMppGroupIdUpdate(MV_VOID);
++MV_VOID mvBoardMppMuxSet(MV_VOID);
++MV_VOID mvBoardTdmMppSet(MV_32 chType);
++MV_VOID mvBoardVoiceConnModeGet(MV_32* connMode, MV_32* irqMode);
++
++MV_VOID mvBoardMppModuleTypePrint(MV_VOID);
++MV_VOID mvBoardReset(MV_VOID);
++MV_U8 mvBoarTwsiSatRGet(MV_U8 devNum, MV_U8 regNum);
++MV_STATUS mvBoarTwsiSatRSet(MV_U8 devNum, MV_U8 regNum, MV_U8 regVal);
++MV_BOOL mvBoardSpecInitGet(MV_U32* regOff, MV_U32* data);
++/* Board devices API managments */
++MV_32 mvBoardGetDevicesNumber(MV_BOARD_DEV_CLASS devClass);
++MV_32 mvBoardGetDeviceBaseAddr(MV_32 devNum, MV_BOARD_DEV_CLASS devClass);
++MV_32 mvBoardGetDeviceBusWidth(MV_32 devNum, MV_BOARD_DEV_CLASS devClass);
++MV_32 mvBoardGetDeviceWidth(MV_32 devNum, MV_BOARD_DEV_CLASS devClass);
++MV_32 mvBoardGetDeviceWinSize(MV_32 devNum, MV_BOARD_DEV_CLASS devClass);
++MV_U32 boardGetDevCSNum(MV_32 devNum, MV_BOARD_DEV_CLASS devClass);
++
++/* Gpio Pin Connections API */
++MV_32 mvBoardUSBVbusGpioPinGet(int devId);
++MV_32 mvBoardUSBVbusEnGpioPinGet(int devId);
++MV_U32 mvBoardPexBridgeIntPinGet(MV_U32 devNum, MV_U32 intPin);
++
++MV_32 mvBoardResetGpioPinGet(MV_VOID);
++MV_32 mvBoardRTCGpioPinGet(MV_VOID);
++MV_32 mvBoardGpioIntMaskLowGet(MV_VOID);
++MV_32 mvBoardGpioIntMaskHighGet(MV_VOID);
++MV_32 mvBoardSlicGpioPinGet(MV_U32 slicNum);
++
++MV_32 mvBoardSDIOGpioPinGet(MV_VOID);
++MV_STATUS mvBoardSDioWPControl(MV_BOOL mode);
++MV_32 mvBoarGpioPinNumGet(MV_BOARD_GPP_CLASS class, MV_U32 index);
++
++MV_32 mvBoardNandWidthGet(void);
++MV_STATUS mvBoardFanPowerControl(MV_BOOL mode);
++MV_STATUS mvBoardHDDPowerControl(MV_BOOL mode);
++#endif /* __INCmvBoardEnvLibh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.c 2010-11-09 20:28:07.443751783 +0100
+@@ -0,0 +1,848 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvCommon.h"
++#include "mvBoardEnvLib.h"
++#include "mvBoardEnvSpec.h"
++#include "twsi/mvTwsi.h"
++
++#define DB_88F6281A_BOARD_PCI_IF_NUM 0x0
++#define DB_88F6281A_BOARD_TWSI_DEF_NUM 0x7
++#define DB_88F6281A_BOARD_MAC_INFO_NUM 0x2
++#define DB_88F6281A_BOARD_GPP_INFO_NUM 0x3
++#define DB_88F6281A_BOARD_MPP_CONFIG_NUM 0x1
++#define DB_88F6281A_BOARD_MPP_GROUP_TYPE_NUM 0x1
++#if defined(MV_NAND) && defined(MV_NAND_BOOT)
++ #define DB_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x1
++#elif defined(MV_NAND) && defined(MV_SPI_BOOT)
++ #define DB_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x2
++#else
++ #define DB_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x1
++#endif
++#define DB_88F6281A_BOARD_DEBUG_LED_NUM 0x0
++
++
++MV_BOARD_TWSI_INFO db88f6281AInfoBoardTwsiDev[] =
++ /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */
++ {
++ {BOARD_DEV_TWSI_EXP, 0x20, ADDR7_BIT},
++ {BOARD_DEV_TWSI_EXP, 0x21, ADDR7_BIT},
++ {BOARD_DEV_TWSI_EXP, 0x27, ADDR7_BIT},
++ {BOARD_DEV_TWSI_SATR, 0x4C, ADDR7_BIT},
++ {BOARD_DEV_TWSI_SATR, 0x4D, ADDR7_BIT},
++ {BOARD_DEV_TWSI_SATR, 0x4E, ADDR7_BIT},
++ {BOARD_TWSI_AUDIO_DEC, 0x4A, ADDR7_BIT}
++ };
++
++MV_BOARD_MAC_INFO db88f6281AInfoBoardMacInfo[] =
++ /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */
++ {
++ {BOARD_MAC_SPEED_AUTO, 0x8},
++ {BOARD_MAC_SPEED_AUTO, 0x9}
++ };
++
++MV_BOARD_MPP_TYPE_INFO db88f6281AInfoBoardMppTypeInfo[] =
++ /* {{MV_BOARD_MPP_TYPE_CLASS boardMppGroup1,
++ MV_BOARD_MPP_TYPE_CLASS boardMppGroup2}} */
++ {{MV_BOARD_AUTO, MV_BOARD_AUTO}
++ };
++
++MV_BOARD_GPP_INFO db88f6281AInfoBoardGppInfo[] =
++ /* {{MV_BOARD_GPP_CLASS devClass, MV_U8 gppPinNum}} */
++ {
++ {BOARD_GPP_TSU_DIRCTION, 33}
++ /*muxed with TDM/Audio module via IOexpender
++ {BOARD_GPP_SDIO_DETECT, 38},
++ {BOARD_GPP_USB_VBUS, 49}*/
++ };
++
++MV_DEV_CS_INFO db88f6281AInfoBoardDeCsInfo[] =
++ /*{deviceCS, params, devType, devWidth}*/
++#if defined(MV_NAND) && defined(MV_NAND_BOOT)
++ {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */
++#elif defined(MV_NAND) && defined(MV_SPI_BOOT)
++ {
++ {0, N_A, BOARD_DEV_NAND_FLASH, 8}, /* NAND DEV */
++ {1, N_A, BOARD_DEV_SPI_FLASH, 8}, /* SPI DEV */
++ };
++#else
++ {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */
++#endif
++
++MV_BOARD_MPP_INFO db88f6281AInfoBoardMppConfigValue[] =
++ {{{
++ DB_88F6281A_MPP0_7,
++ DB_88F6281A_MPP8_15,
++ DB_88F6281A_MPP16_23,
++ DB_88F6281A_MPP24_31,
++ DB_88F6281A_MPP32_39,
++ DB_88F6281A_MPP40_47,
++ DB_88F6281A_MPP48_55
++ }}};
++
++
++MV_BOARD_INFO db88f6281AInfo = {
++ "DB-88F6281A-BP", /* boardName[MAX_BOARD_NAME_LEN] */
++ DB_88F6281A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */
++ db88f6281AInfoBoardMppTypeInfo,
++ DB_88F6281A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */
++ db88f6281AInfoBoardMppConfigValue,
++ 0, /* intsGppMaskLow */
++ 0, /* intsGppMaskHigh */
++ DB_88F6281A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */
++ db88f6281AInfoBoardDeCsInfo,
++ DB_88F6281A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */
++ db88f6281AInfoBoardTwsiDev,
++ DB_88F6281A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */
++ db88f6281AInfoBoardMacInfo,
++ DB_88F6281A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */
++ db88f6281AInfoBoardGppInfo,
++ DB_88F6281A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */
++ NULL,
++ 0, /* ledsPolarity */
++ DB_88F6281A_OE_LOW, /* gppOutEnLow */
++ DB_88F6281A_OE_HIGH, /* gppOutEnHigh */
++ DB_88F6281A_OE_VAL_LOW, /* gppOutValLow */
++ DB_88F6281A_OE_VAL_HIGH, /* gppOutValHigh */
++ 0, /* gppPolarityValLow */
++ BIT6, /* gppPolarityValHigh */
++ NULL /* pSwitchInfo */
++};
++
++
++#define RD_88F6281A_BOARD_PCI_IF_NUM 0x0
++#define RD_88F6281A_BOARD_TWSI_DEF_NUM 0x2
++#define RD_88F6281A_BOARD_MAC_INFO_NUM 0x2
++#define RD_88F6281A_BOARD_GPP_INFO_NUM 0x5
++#define RD_88F6281A_BOARD_MPP_GROUP_TYPE_NUM 0x1
++#define RD_88F6281A_BOARD_MPP_CONFIG_NUM 0x1
++#if defined(MV_NAND) && defined(MV_NAND_BOOT)
++ #define RD_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x1
++#elif defined(MV_NAND) && defined(MV_SPI_BOOT)
++ #define RD_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x2
++#else
++ #define RD_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x1
++#endif
++#define RD_88F6281A_BOARD_DEBUG_LED_NUM 0x0
++
++MV_BOARD_MAC_INFO rd88f6281AInfoBoardMacInfo[] =
++ /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */
++ {{BOARD_MAC_SPEED_1000M, 0xa},
++ {BOARD_MAC_SPEED_AUTO, 0xb}
++ };
++
++MV_BOARD_SWITCH_INFO rd88f6281AInfoBoardSwitchInfo[] =
++ /* MV_32 linkStatusIrq, {MV_32 qdPort0, MV_32 qdPort1, MV_32 qdPort2, MV_32 qdPort3, MV_32 qdPort4},
++ MV_32 qdCpuPort, MV_32 smiScanMode, MV_32 switchOnPort} */
++ {{38, {0, 1, 2, 3, -1}, 5, 2, 0},
++ {-1, {-1}, -1, -1, -1}};
++
++MV_BOARD_TWSI_INFO rd88f6281AInfoBoardTwsiDev[] =
++ /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */
++ {
++ {BOARD_DEV_TWSI_EXP, 0xFF, ADDR7_BIT}, /* dummy entry to align with modules indexes */
++ {BOARD_DEV_TWSI_EXP, 0x27, ADDR7_BIT}
++ };
++
++MV_BOARD_MPP_TYPE_INFO rd88f6281AInfoBoardMppTypeInfo[] =
++ {{MV_BOARD_RGMII, MV_BOARD_TDM}
++ };
++
++MV_DEV_CS_INFO rd88f6281AInfoBoardDeCsInfo[] =
++ /*{deviceCS, params, devType, devWidth}*/
++#if defined(MV_NAND) && defined(MV_NAND_BOOT)
++ {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */
++#elif defined(MV_NAND) && defined(MV_SPI_BOOT)
++ {
++ {0, N_A, BOARD_DEV_NAND_FLASH, 8}, /* NAND DEV */
++ {1, N_A, BOARD_DEV_SPI_FLASH, 8}, /* SPI DEV */
++ };
++#else
++ {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */
++#endif
++
++MV_BOARD_GPP_INFO rd88f6281AInfoBoardGppInfo[] =
++ /* {{MV_BOARD_GPP_CLASS devClass, MV_U8 gppPinNum}} */
++ {{BOARD_GPP_SDIO_DETECT, 28},
++ {BOARD_GPP_USB_OC, 29},
++ {BOARD_GPP_WPS_BUTTON, 35},
++ {BOARD_GPP_MV_SWITCH, 38},
++ {BOARD_GPP_USB_VBUS, 49}
++ };
++
++MV_BOARD_MPP_INFO rd88f6281AInfoBoardMppConfigValue[] =
++ {{{
++ RD_88F6281A_MPP0_7,
++ RD_88F6281A_MPP8_15,
++ RD_88F6281A_MPP16_23,
++ RD_88F6281A_MPP24_31,
++ RD_88F6281A_MPP32_39,
++ RD_88F6281A_MPP40_47,
++ RD_88F6281A_MPP48_55
++ }}};
++
++MV_BOARD_INFO rd88f6281AInfo = {
++ "RD-88F6281A", /* boardName[MAX_BOARD_NAME_LEN] */
++ RD_88F6281A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */
++ rd88f6281AInfoBoardMppTypeInfo,
++ RD_88F6281A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */
++ rd88f6281AInfoBoardMppConfigValue,
++ 0, /* intsGppMaskLow */
++ (1 << 3), /* intsGppMaskHigh */
++ RD_88F6281A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */
++ rd88f6281AInfoBoardDeCsInfo,
++ RD_88F6281A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */
++ rd88f6281AInfoBoardTwsiDev,
++ RD_88F6281A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */
++ rd88f6281AInfoBoardMacInfo,
++ RD_88F6281A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */
++ rd88f6281AInfoBoardGppInfo,
++ RD_88F6281A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */
++ NULL,
++ 0, /* ledsPolarity */
++ RD_88F6281A_OE_LOW, /* gppOutEnLow */
++ RD_88F6281A_OE_HIGH, /* gppOutEnHigh */
++ RD_88F6281A_OE_VAL_LOW, /* gppOutValLow */
++ RD_88F6281A_OE_VAL_HIGH, /* gppOutValHigh */
++ 0, /* gppPolarityValLow */
++ BIT6, /* gppPolarityValHigh */
++ rd88f6281AInfoBoardSwitchInfo /* pSwitchInfo */
++};
++
++
++#define DB_88F6192A_BOARD_PCI_IF_NUM 0x0
++#define DB_88F6192A_BOARD_TWSI_DEF_NUM 0x7
++#define DB_88F6192A_BOARD_MAC_INFO_NUM 0x2
++#define DB_88F6192A_BOARD_GPP_INFO_NUM 0x3
++#define DB_88F6192A_BOARD_MPP_GROUP_TYPE_NUM 0x1
++#define DB_88F6192A_BOARD_MPP_CONFIG_NUM 0x1
++#if defined(MV_NAND) && defined(MV_NAND_BOOT)
++ #define DB_88F6192A_BOARD_DEVICE_CONFIG_NUM 0x1
++#elif defined(MV_NAND) && defined(MV_SPI_BOOT)
++ #define DB_88F6192A_BOARD_DEVICE_CONFIG_NUM 0x2
++#else
++ #define DB_88F6192A_BOARD_DEVICE_CONFIG_NUM 0x1
++#endif
++#define DB_88F6192A_BOARD_DEBUG_LED_NUM 0x0
++
++MV_BOARD_TWSI_INFO db88f6192AInfoBoardTwsiDev[] =
++ /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */
++ {
++ {BOARD_DEV_TWSI_EXP, 0x20, ADDR7_BIT},
++ {BOARD_DEV_TWSI_EXP, 0x21, ADDR7_BIT},
++ {BOARD_DEV_TWSI_EXP, 0x27, ADDR7_BIT},
++ {BOARD_DEV_TWSI_SATR, 0x4C, ADDR7_BIT},
++ {BOARD_DEV_TWSI_SATR, 0x4D, ADDR7_BIT},
++ {BOARD_DEV_TWSI_SATR, 0x4E, ADDR7_BIT},
++ {BOARD_TWSI_AUDIO_DEC, 0x4A, ADDR7_BIT}
++ };
++
++MV_BOARD_MAC_INFO db88f6192AInfoBoardMacInfo[] =
++ /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */
++ {
++ {BOARD_MAC_SPEED_AUTO, 0x8},
++ {BOARD_MAC_SPEED_AUTO, 0x9}
++ };
++
++MV_BOARD_MPP_TYPE_INFO db88f6192AInfoBoardMppTypeInfo[] =
++ /* {{MV_BOARD_MPP_TYPE_CLASS boardMppGroup1,
++ MV_BOARD_MPP_TYPE_CLASS boardMppGroup2}} */
++ {{MV_BOARD_AUTO, MV_BOARD_OTHER}
++ };
++
++MV_DEV_CS_INFO db88f6192AInfoBoardDeCsInfo[] =
++ /*{deviceCS, params, devType, devWidth}*/
++#if defined(MV_NAND) && defined(MV_NAND_BOOT)
++ {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */
++#elif defined(MV_NAND) && defined(MV_SPI_BOOT)
++ {
++ {0, N_A, BOARD_DEV_NAND_FLASH, 8}, /* NAND DEV */
++ {1, N_A, BOARD_DEV_SPI_FLASH, 8}, /* SPI DEV */
++ };
++#else
++ {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */
++#endif
++
++MV_BOARD_GPP_INFO db88f6192AInfoBoardGppInfo[] =
++ /* {{MV_BOARD_GPP_CLASS devClass, MV_U8 gppPinNum}} */
++ {
++ {BOARD_GPP_SDIO_WP, 20},
++ {BOARD_GPP_USB_VBUS, 22},
++ {BOARD_GPP_SDIO_DETECT, 23},
++ };
++
++MV_BOARD_MPP_INFO db88f6192AInfoBoardMppConfigValue[] =
++ {{{
++ DB_88F6192A_MPP0_7,
++ DB_88F6192A_MPP8_15,
++ DB_88F6192A_MPP16_23,
++ DB_88F6192A_MPP24_31,
++ DB_88F6192A_MPP32_35
++ }}};
++
++MV_BOARD_INFO db88f6192AInfo = {
++ "DB-88F6192A-BP", /* boardName[MAX_BOARD_NAME_LEN] */
++ DB_88F6192A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */
++ db88f6192AInfoBoardMppTypeInfo,
++ DB_88F6192A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */
++ db88f6192AInfoBoardMppConfigValue,
++ 0, /* intsGppMaskLow */
++ (1 << 3), /* intsGppMaskHigh */
++ DB_88F6192A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */
++ db88f6192AInfoBoardDeCsInfo,
++ DB_88F6192A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */
++ db88f6192AInfoBoardTwsiDev,
++ DB_88F6192A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */
++ db88f6192AInfoBoardMacInfo,
++ DB_88F6192A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */
++ db88f6192AInfoBoardGppInfo,
++ DB_88F6192A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */
++ NULL,
++ 0, /* ledsPolarity */
++ DB_88F6192A_OE_LOW, /* gppOutEnLow */
++ DB_88F6192A_OE_HIGH, /* gppOutEnHigh */
++ DB_88F6192A_OE_VAL_LOW, /* gppOutValLow */
++ DB_88F6192A_OE_VAL_HIGH, /* gppOutValHigh */
++ 0, /* gppPolarityValLow */
++ 0, /* gppPolarityValHigh */
++ NULL /* pSwitchInfo */
++};
++
++#define DB_88F6190A_BOARD_MAC_INFO_NUM 0x1
++
++MV_BOARD_INFO db88f6190AInfo = {
++ "DB-88F6190A-BP", /* boardName[MAX_BOARD_NAME_LEN] */
++ DB_88F6192A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */
++ db88f6192AInfoBoardMppTypeInfo,
++ DB_88F6192A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */
++ db88f6192AInfoBoardMppConfigValue,
++ 0, /* intsGppMaskLow */
++ (1 << 3), /* intsGppMaskHigh */
++ DB_88F6192A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */
++ db88f6192AInfoBoardDeCsInfo,
++ DB_88F6192A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */
++ db88f6192AInfoBoardTwsiDev,
++ DB_88F6190A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */
++ db88f6192AInfoBoardMacInfo,
++ DB_88F6192A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */
++ db88f6192AInfoBoardGppInfo,
++ DB_88F6192A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */
++ NULL,
++ 0, /* ledsPolarity */
++ DB_88F6192A_OE_LOW, /* gppOutEnLow */
++ DB_88F6192A_OE_HIGH, /* gppOutEnHigh */
++ DB_88F6192A_OE_VAL_LOW, /* gppOutValLow */
++ DB_88F6192A_OE_VAL_HIGH, /* gppOutValHigh */
++ 0, /* gppPolarityValLow */
++ 0, /* gppPolarityValHigh */
++ NULL /* pSwitchInfo */
++};
++
++#define RD_88F6192A_BOARD_PCI_IF_NUM 0x0
++#define RD_88F6192A_BOARD_TWSI_DEF_NUM 0x0
++#define RD_88F6192A_BOARD_MAC_INFO_NUM 0x1
++#define RD_88F6192A_BOARD_GPP_INFO_NUM 0xE
++#define RD_88F6192A_BOARD_MPP_GROUP_TYPE_NUM 0x1
++#define RD_88F6192A_BOARD_MPP_CONFIG_NUM 0x1
++#define RD_88F6192A_BOARD_DEVICE_CONFIG_NUM 0x1
++#define RD_88F6192A_BOARD_DEBUG_LED_NUM 0x3
++
++MV_U8 rd88f6192AInfoBoardDebugLedIf[] =
++ {17, 28, 29};
++
++MV_BOARD_MAC_INFO rd88f6192AInfoBoardMacInfo[] =
++ /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */
++ {{BOARD_MAC_SPEED_AUTO, 0x8}
++ };
++
++MV_BOARD_MPP_TYPE_INFO rd88f6192AInfoBoardMppTypeInfo[] =
++ /* {{MV_BOARD_MPP_TYPE_CLASS boardMppGroup1,
++ MV_BOARD_MPP_TYPE_CLASS boardMppGroup2}} */
++ {{MV_BOARD_OTHER, MV_BOARD_OTHER}
++ };
++
++MV_DEV_CS_INFO rd88f6192AInfoBoardDeCsInfo[] =
++ /*{deviceCS, params, devType, devWidth}*/
++ {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */
++
++MV_BOARD_GPP_INFO rd88f6192AInfoBoardGppInfo[] =
++ /* {{MV_BOARD_GPP_CLASS devClass, MV_U8 gppPinNum}} */
++ {
++ {BOARD_GPP_USB_VBUS_EN, 10},
++ {BOARD_GPP_USB_HOST_DEVICE, 11},
++ {BOARD_GPP_RESET, 14},
++ {BOARD_GPP_POWER_ON_LED, 15},
++ {BOARD_GPP_HDD_POWER, 16},
++ {BOARD_GPP_WPS_BUTTON, 24},
++ {BOARD_GPP_TS_BUTTON_C, 25},
++ {BOARD_GPP_USB_VBUS, 26},
++ {BOARD_GPP_USB_OC, 27},
++ {BOARD_GPP_TS_BUTTON_U, 30},
++ {BOARD_GPP_TS_BUTTON_R, 31},
++ {BOARD_GPP_TS_BUTTON_L, 32},
++ {BOARD_GPP_TS_BUTTON_D, 34},
++ {BOARD_GPP_FAN_POWER, 35}
++ };
++
++MV_BOARD_MPP_INFO rd88f6192AInfoBoardMppConfigValue[] =
++ {{{
++ RD_88F6192A_MPP0_7,
++ RD_88F6192A_MPP8_15,
++ RD_88F6192A_MPP16_23,
++ RD_88F6192A_MPP24_31,
++ RD_88F6192A_MPP32_35
++ }}};
++
++MV_BOARD_INFO rd88f6192AInfo = {
++ "RD-88F6192A-NAS", /* boardName[MAX_BOARD_NAME_LEN] */
++ RD_88F6192A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */
++ rd88f6192AInfoBoardMppTypeInfo,
++ RD_88F6192A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */
++ rd88f6192AInfoBoardMppConfigValue,
++ 0, /* intsGppMaskLow */
++ (1 << 3), /* intsGppMaskHigh */
++ RD_88F6192A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */
++ rd88f6192AInfoBoardDeCsInfo,
++ RD_88F6192A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */
++ NULL,
++ RD_88F6192A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */
++ rd88f6192AInfoBoardMacInfo,
++ RD_88F6192A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */
++ rd88f6192AInfoBoardGppInfo,
++ RD_88F6192A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */
++ rd88f6192AInfoBoardDebugLedIf,
++ 0, /* ledsPolarity */
++ RD_88F6192A_OE_LOW, /* gppOutEnLow */
++ RD_88F6192A_OE_HIGH, /* gppOutEnHigh */
++ RD_88F6192A_OE_VAL_LOW, /* gppOutValLow */
++ RD_88F6192A_OE_VAL_HIGH, /* gppOutValHigh */
++ 0, /* gppPolarityValLow */
++ 0, /* gppPolarityValHigh */
++ NULL /* pSwitchInfo */
++};
++
++MV_BOARD_INFO rd88f6190AInfo = {
++ "RD-88F6190A-NAS", /* boardName[MAX_BOARD_NAME_LEN] */
++ RD_88F6192A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */
++ rd88f6192AInfoBoardMppTypeInfo,
++ RD_88F6192A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */
++ rd88f6192AInfoBoardMppConfigValue,
++ 0, /* intsGppMaskLow */
++ (1 << 3), /* intsGppMaskHigh */
++ RD_88F6192A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */
++ rd88f6192AInfoBoardDeCsInfo,
++ RD_88F6192A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */
++ NULL,
++ RD_88F6192A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */
++ rd88f6192AInfoBoardMacInfo,
++ RD_88F6192A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */
++ rd88f6192AInfoBoardGppInfo,
++ RD_88F6192A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */
++ rd88f6192AInfoBoardDebugLedIf,
++ 0, /* ledsPolarity */
++ RD_88F6192A_OE_LOW, /* gppOutEnLow */
++ RD_88F6192A_OE_HIGH, /* gppOutEnHigh */
++ RD_88F6192A_OE_VAL_LOW, /* gppOutValLow */
++ RD_88F6192A_OE_VAL_HIGH, /* gppOutValHigh */
++ 0, /* gppPolarityValLow */
++ 0, /* gppPolarityValHigh */
++ NULL /* pSwitchInfo */
++};
++
++#define DB_88F6180A_BOARD_PCI_IF_NUM 0x0
++#define DB_88F6180A_BOARD_TWSI_DEF_NUM 0x5
++#define DB_88F6180A_BOARD_MAC_INFO_NUM 0x1
++#define DB_88F6180A_BOARD_GPP_INFO_NUM 0x0
++#define DB_88F6180A_BOARD_MPP_GROUP_TYPE_NUM 0x2
++#define DB_88F6180A_BOARD_MPP_CONFIG_NUM 0x1
++#define DB_88F6180A_BOARD_DEVICE_CONFIG_NUM 0x1
++#define DB_88F6180A_BOARD_DEBUG_LED_NUM 0x0
++
++MV_BOARD_TWSI_INFO db88f6180AInfoBoardTwsiDev[] =
++ /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */
++ {
++ {BOARD_DEV_TWSI_EXP, 0x20, ADDR7_BIT},
++ {BOARD_DEV_TWSI_EXP, 0x21, ADDR7_BIT},
++ {BOARD_DEV_TWSI_EXP, 0x27, ADDR7_BIT},
++ {BOARD_DEV_TWSI_SATR, 0x4C, ADDR7_BIT},
++ {BOARD_TWSI_AUDIO_DEC, 0x4A, ADDR7_BIT}
++ };
++
++MV_BOARD_MAC_INFO db88f6180AInfoBoardMacInfo[] =
++ /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */
++ {{BOARD_MAC_SPEED_AUTO, 0x8}
++ };
++
++MV_BOARD_GPP_INFO db88f6180AInfoBoardGppInfo[] =
++ /* {{MV_BOARD_GPP_CLASS devClass, MV_U8 gppPinNum}} */
++ {
++ /* Muxed with TDM/Audio module via IOexpender
++ {BOARD_GPP_USB_VBUS, 6} */
++ };
++
++MV_BOARD_MPP_TYPE_INFO db88f6180AInfoBoardMppTypeInfo[] =
++ /* {{MV_BOARD_MPP_TYPE_CLASS boardMppGroup1,
++ MV_BOARD_MPP_TYPE_CLASS boardMppGroup2}} */
++ {{MV_BOARD_OTHER, MV_BOARD_AUTO}
++ };
++
++MV_DEV_CS_INFO db88f6180AInfoBoardDeCsInfo[] =
++ /*{deviceCS, params, devType, devWidth}*/
++#if defined(MV_NAND_BOOT)
++ {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */
++#else
++ {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */
++#endif
++
++MV_BOARD_MPP_INFO db88f6180AInfoBoardMppConfigValue[] =
++ {{{
++ DB_88F6180A_MPP0_7,
++ DB_88F6180A_MPP8_15,
++ DB_88F6180A_MPP16_23,
++ DB_88F6180A_MPP24_31,
++ DB_88F6180A_MPP32_39,
++ DB_88F6180A_MPP40_44
++ }}};
++
++MV_BOARD_INFO db88f6180AInfo = {
++ "DB-88F6180A-BP", /* boardName[MAX_BOARD_NAME_LEN] */
++ DB_88F6180A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */
++ db88f6180AInfoBoardMppTypeInfo,
++ DB_88F6180A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */
++ db88f6180AInfoBoardMppConfigValue,
++ 0, /* intsGppMaskLow */
++ 0, /* intsGppMaskHigh */
++ DB_88F6180A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */
++ db88f6180AInfoBoardDeCsInfo,
++ DB_88F6180A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */
++ db88f6180AInfoBoardTwsiDev,
++ DB_88F6180A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */
++ db88f6180AInfoBoardMacInfo,
++ DB_88F6180A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */
++ NULL,
++ DB_88F6180A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */
++ NULL,
++ 0, /* ledsPolarity */
++ DB_88F6180A_OE_LOW, /* gppOutEnLow */
++ DB_88F6180A_OE_HIGH, /* gppOutEnHigh */
++ DB_88F6180A_OE_VAL_LOW, /* gppOutValLow */
++ DB_88F6180A_OE_VAL_HIGH, /* gppOutValHigh */
++ 0, /* gppPolarityValLow */
++ 0, /* gppPolarityValHigh */
++ NULL /* pSwitchInfo */
++};
++
++
++#define RD_88F6281A_PCAC_BOARD_PCI_IF_NUM 0x0
++#define RD_88F6281A_PCAC_BOARD_TWSI_DEF_NUM 0x1
++#define RD_88F6281A_PCAC_BOARD_MAC_INFO_NUM 0x1
++#define RD_88F6281A_PCAC_BOARD_GPP_INFO_NUM 0x0
++#define RD_88F6281A_PCAC_BOARD_MPP_GROUP_TYPE_NUM 0x1
++#define RD_88F6281A_PCAC_BOARD_MPP_CONFIG_NUM 0x1
++#if defined(MV_NAND) && defined(MV_NAND_BOOT)
++ #define RD_88F6281A_PCAC_BOARD_DEVICE_CONFIG_NUM 0x1
++#elif defined(MV_NAND) && defined(MV_SPI_BOOT)
++ #define RD_88F6281A_PCAC_BOARD_DEVICE_CONFIG_NUM 0x2
++#else
++ #define RD_88F6281A_PCAC_BOARD_DEVICE_CONFIG_NUM 0x1
++#endif
++#define RD_88F6281A_PCAC_BOARD_DEBUG_LED_NUM 0x4
++
++MV_U8 rd88f6281APcacInfoBoardDebugLedIf[] =
++ {38, 39, 40, 41};
++
++MV_BOARD_MAC_INFO rd88f6281APcacInfoBoardMacInfo[] =
++ /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */
++ {{BOARD_MAC_SPEED_AUTO, 0x8}
++ };
++
++MV_BOARD_TWSI_INFO rd88f6281APcacInfoBoardTwsiDev[] =
++ /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */
++ {
++ {BOARD_TWSI_OTHER, 0xa7, ADDR7_BIT}
++ };
++
++MV_BOARD_MPP_TYPE_INFO rd88f6281APcacInfoBoardMppTypeInfo[] =
++ {{MV_BOARD_OTHER, MV_BOARD_OTHER}
++ };
++
++MV_DEV_CS_INFO rd88f6281APcacInfoBoardDeCsInfo[] =
++ /*{deviceCS, params, devType, devWidth}*/
++#if defined(MV_NAND) && defined(MV_NAND_BOOT)
++ {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */
++#elif defined(MV_NAND) && defined(MV_SPI_BOOT)
++ {
++ {0, N_A, BOARD_DEV_NAND_FLASH, 8}, /* NAND DEV */
++ {1, N_A, BOARD_DEV_SPI_FLASH, 8}, /* SPI DEV */
++ };
++#else
++ {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */
++#endif
++
++MV_BOARD_MPP_INFO rd88f6281APcacInfoBoardMppConfigValue[] =
++ {{{
++ RD_88F6281A_PCAC_MPP0_7,
++ RD_88F6281A_PCAC_MPP8_15,
++ RD_88F6281A_PCAC_MPP16_23,
++ RD_88F6281A_PCAC_MPP24_31,
++ RD_88F6281A_PCAC_MPP32_39,
++ RD_88F6281A_PCAC_MPP40_47,
++ RD_88F6281A_PCAC_MPP48_55
++ }}};
++
++MV_BOARD_INFO rd88f6281APcacInfo = {
++ "RD-88F6281A-PCAC", /* boardName[MAX_BOARD_NAME_LEN] */
++ RD_88F6281A_PCAC_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */
++ rd88f6281APcacInfoBoardMppTypeInfo,
++ RD_88F6281A_PCAC_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */
++ rd88f6281APcacInfoBoardMppConfigValue,
++ 0, /* intsGppMaskLow */
++ (1 << 3), /* intsGppMaskHigh */
++ RD_88F6281A_PCAC_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */
++ rd88f6281APcacInfoBoardDeCsInfo,
++ RD_88F6281A_PCAC_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */
++ rd88f6281APcacInfoBoardTwsiDev,
++ RD_88F6281A_PCAC_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */
++ rd88f6281APcacInfoBoardMacInfo,
++ RD_88F6281A_PCAC_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */
++ 0,
++ RD_88F6281A_PCAC_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */
++ NULL,
++ 0, /* ledsPolarity */
++ RD_88F6281A_PCAC_OE_LOW, /* gppOutEnLow */
++ RD_88F6281A_PCAC_OE_HIGH, /* gppOutEnHigh */
++ RD_88F6281A_PCAC_OE_VAL_LOW, /* gppOutValLow */
++ RD_88F6281A_PCAC_OE_VAL_HIGH, /* gppOutValHigh */
++ 0, /* gppPolarityValLow */
++ 0, /* gppPolarityValHigh */
++ NULL /* pSwitchInfo */
++};
++
++
++/* 6281 Sheeva Plug*/
++
++#define SHEEVA_PLUG_BOARD_PCI_IF_NUM 0x0
++#define SHEEVA_PLUG_BOARD_TWSI_DEF_NUM 0x0
++#define SHEEVA_PLUG_BOARD_MAC_INFO_NUM 0x1
++#define SHEEVA_PLUG_BOARD_GPP_INFO_NUM 0x0
++#define SHEEVA_PLUG_BOARD_MPP_GROUP_TYPE_NUN 0x1
++#define SHEEVA_PLUG_BOARD_MPP_CONFIG_NUM 0x1
++#define SHEEVA_PLUG_BOARD_DEVICE_CONFIG_NUM 0x1
++#define SHEEVA_PLUG_BOARD_DEBUG_LED_NUM 0x1
++
++MV_U8 sheevaPlugInfoBoardDebugLedIf[] =
++ {49};
++
++MV_BOARD_MAC_INFO sheevaPlugInfoBoardMacInfo[] =
++ /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */
++ {{BOARD_MAC_SPEED_AUTO, 0x0}};
++
++MV_BOARD_TWSI_INFO sheevaPlugInfoBoardTwsiDev[] =
++ /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */
++ {{BOARD_TWSI_OTHER, 0x0, ADDR7_BIT}};
++
++MV_BOARD_MPP_TYPE_INFO sheevaPlugInfoBoardMppTypeInfo[] =
++ {{MV_BOARD_OTHER, MV_BOARD_OTHER}
++ };
++
++MV_DEV_CS_INFO sheevaPlugInfoBoardDeCsInfo[] =
++ /*{deviceCS, params, devType, devWidth}*/
++ {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */
++
++MV_BOARD_MPP_INFO sheevaPlugInfoBoardMppConfigValue[] =
++ {{{
++ RD_SHEEVA_PLUG_MPP0_7,
++ RD_SHEEVA_PLUG_MPP8_15,
++ RD_SHEEVA_PLUG_MPP16_23,
++ RD_SHEEVA_PLUG_MPP24_31,
++ RD_SHEEVA_PLUG_MPP32_39,
++ RD_SHEEVA_PLUG_MPP40_47,
++ RD_SHEEVA_PLUG_MPP48_55
++ }}};
++
++MV_BOARD_INFO sheevaPlugInfo = {
++ "SHEEVA PLUG", /* boardName[MAX_BOARD_NAME_LEN] */
++ SHEEVA_PLUG_BOARD_MPP_GROUP_TYPE_NUN, /* numBoardMppGroupType */
++ sheevaPlugInfoBoardMppTypeInfo,
++ SHEEVA_PLUG_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */
++ sheevaPlugInfoBoardMppConfigValue,
++ 0, /* intsGppMaskLow */
++ 0, /* intsGppMaskHigh */
++ SHEEVA_PLUG_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */
++ sheevaPlugInfoBoardDeCsInfo,
++ SHEEVA_PLUG_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */
++ sheevaPlugInfoBoardTwsiDev,
++ SHEEVA_PLUG_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */
++ sheevaPlugInfoBoardMacInfo,
++ SHEEVA_PLUG_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */
++ 0,
++ SHEEVA_PLUG_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */
++ sheevaPlugInfoBoardDebugLedIf,
++ 0, /* ledsPolarity */
++ RD_SHEEVA_PLUG_OE_LOW, /* gppOutEnLow */
++ RD_SHEEVA_PLUG_OE_HIGH, /* gppOutEnHigh */
++ RD_SHEEVA_PLUG_OE_VAL_LOW, /* gppOutValLow */
++ RD_SHEEVA_PLUG_OE_VAL_HIGH, /* gppOutValHigh */
++ 0, /* gppPolarityValLow */
++ 0, /* gppPolarityValHigh */
++ NULL /* pSwitchInfo */
++};
++
++/* Customer specific board place holder*/
++
++#define DB_CUSTOMER_BOARD_PCI_IF_NUM 0x0
++#define DB_CUSTOMER_BOARD_TWSI_DEF_NUM 0x0
++#define DB_CUSTOMER_BOARD_MAC_INFO_NUM 0x0
++#define DB_CUSTOMER_BOARD_GPP_INFO_NUM 0x0
++#define DB_CUSTOMER_BOARD_MPP_GROUP_TYPE_NUN 0x0
++#define DB_CUSTOMER_BOARD_MPP_CONFIG_NUM 0x0
++#if defined(MV_NAND) && defined(MV_NAND_BOOT)
++ #define DB_CUSTOMER_BOARD_DEVICE_CONFIG_NUM 0x0
++#elif defined(MV_NAND) && defined(MV_SPI_BOOT)
++ #define DB_CUSTOMER_BOARD_DEVICE_CONFIG_NUM 0x0
++#else
++ #define DB_CUSTOMER_BOARD_DEVICE_CONFIG_NUM 0x0
++#endif
++#define DB_CUSTOMER_BOARD_DEBUG_LED_NUM 0x0
++
++MV_U8 dbCustomerInfoBoardDebugLedIf[] =
++ {0};
++
++MV_BOARD_MAC_INFO dbCustomerInfoBoardMacInfo[] =
++ /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */
++ {{BOARD_MAC_SPEED_AUTO, 0x0}};
++
++MV_BOARD_TWSI_INFO dbCustomerInfoBoardTwsiDev[] =
++ /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */
++ {{BOARD_TWSI_OTHER, 0x0, ADDR7_BIT}};
++
++MV_BOARD_MPP_TYPE_INFO dbCustomerInfoBoardMppTypeInfo[] =
++ {{MV_BOARD_OTHER, MV_BOARD_OTHER}
++ };
++
++MV_DEV_CS_INFO dbCustomerInfoBoardDeCsInfo[] =
++ /*{deviceCS, params, devType, devWidth}*/
++#if defined(MV_NAND) && defined(MV_NAND_BOOT)
++ {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */
++#elif defined(MV_NAND) && defined(MV_SPI_BOOT)
++ {
++ {0, N_A, BOARD_DEV_NAND_FLASH, 8}, /* NAND DEV */
++ {2, N_A, BOARD_DEV_SPI_FLASH, 8}, /* SPI DEV */
++ };
++#else
++ {{2, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */
++#endif
++
++MV_BOARD_MPP_INFO dbCustomerInfoBoardMppConfigValue[] =
++ {{{
++ DB_CUSTOMER_MPP0_7,
++ DB_CUSTOMER_MPP8_15,
++ DB_CUSTOMER_MPP16_23,
++ DB_CUSTOMER_MPP24_31,
++ DB_CUSTOMER_MPP32_39,
++ DB_CUSTOMER_MPP40_47,
++ DB_CUSTOMER_MPP48_55
++ }}};
++
++MV_BOARD_INFO dbCustomerInfo = {
++ "DB-CUSTOMER", /* boardName[MAX_BOARD_NAME_LEN] */
++ DB_CUSTOMER_BOARD_MPP_GROUP_TYPE_NUN, /* numBoardMppGroupType */
++ dbCustomerInfoBoardMppTypeInfo,
++ DB_CUSTOMER_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */
++ dbCustomerInfoBoardMppConfigValue,
++ 0, /* intsGppMaskLow */
++ 0, /* intsGppMaskHigh */
++ DB_CUSTOMER_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */
++ dbCustomerInfoBoardDeCsInfo,
++ DB_CUSTOMER_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */
++ dbCustomerInfoBoardTwsiDev,
++ DB_CUSTOMER_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */
++ dbCustomerInfoBoardMacInfo,
++ DB_CUSTOMER_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */
++ 0,
++ DB_CUSTOMER_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */
++ NULL,
++ 0, /* ledsPolarity */
++ DB_CUSTOMER_OE_LOW, /* gppOutEnLow */
++ DB_CUSTOMER_OE_HIGH, /* gppOutEnHigh */
++ DB_CUSTOMER_OE_VAL_LOW, /* gppOutValLow */
++ DB_CUSTOMER_OE_VAL_HIGH, /* gppOutValHigh */
++ 0, /* gppPolarityValLow */
++ 0, /* gppPolarityValHigh */
++ NULL /* pSwitchInfo */
++};
++
++MV_BOARD_INFO* boardInfoTbl[] = {
++ &db88f6281AInfo,
++ &rd88f6281AInfo,
++ &db88f6192AInfo,
++ &rd88f6192AInfo,
++ &db88f6180AInfo,
++ &db88f6190AInfo,
++ &rd88f6190AInfo,
++ &rd88f6281APcacInfo,
++ &dbCustomerInfo,
++ &sheevaPlugInfo
++ };
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.h 2010-11-09 20:28:07.482495476 +0100
+@@ -0,0 +1,262 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvBoardEnvSpech
++#define __INCmvBoardEnvSpech
++
++#include "mvSysHwConfig.h"
++
++
++/* For future use */
++#define BD_ID_DATA_START_OFFS 0x0
++#define BD_DETECT_SEQ_OFFS 0x0
++#define BD_SYS_NUM_OFFS 0x4
++#define BD_NAME_OFFS 0x8
++
++/* I2C bus addresses */
++#define MV_BOARD_CTRL_I2C_ADDR 0x0 /* Controller slave addr */
++#define MV_BOARD_CTRL_I2C_ADDR_TYPE ADDR7_BIT
++#define MV_BOARD_DIMM0_I2C_ADDR 0x56
++#define MV_BOARD_DIMM0_I2C_ADDR_TYPE ADDR7_BIT
++#define MV_BOARD_DIMM1_I2C_ADDR 0x54
++#define MV_BOARD_DIMM1_I2C_ADDR_TYPE ADDR7_BIT
++#define MV_BOARD_EEPROM_I2C_ADDR 0x51
++#define MV_BOARD_EEPROM_I2C_ADDR_TYPE ADDR7_BIT
++#define MV_BOARD_MAIN_EEPROM_I2C_ADDR 0x50
++#define MV_BOARD_MAIN_EEPROM_I2C_ADDR_TYPE ADDR7_BIT
++#define MV_BOARD_MUX_I2C_ADDR_ENTRY 0x2
++#define MV_BOARD_DIMM_I2C_CHANNEL 0x0
++
++#define BOOT_FLASH_INDEX 0
++#define MAIN_FLASH_INDEX 1
++
++#define BOARD_ETH_START_PORT_NUM 0
++
++/* Supported clocks */
++#define MV_BOARD_TCLK_100MHZ 100000000
++#define MV_BOARD_TCLK_125MHZ 125000000
++#define MV_BOARD_TCLK_133MHZ 133333333
++#define MV_BOARD_TCLK_150MHZ 150000000
++#define MV_BOARD_TCLK_166MHZ 166666667
++#define MV_BOARD_TCLK_200MHZ 200000000
++
++#define MV_BOARD_SYSCLK_100MHZ 100000000
++#define MV_BOARD_SYSCLK_125MHZ 125000000
++#define MV_BOARD_SYSCLK_133MHZ 133333333
++#define MV_BOARD_SYSCLK_150MHZ 150000000
++#define MV_BOARD_SYSCLK_166MHZ 166666667
++#define MV_BOARD_SYSCLK_200MHZ 200000000
++#define MV_BOARD_SYSCLK_233MHZ 233333333
++#define MV_BOARD_SYSCLK_250MHZ 250000000
++#define MV_BOARD_SYSCLK_267MHZ 266666667
++#define MV_BOARD_SYSCLK_300MHZ 300000000
++#define MV_BOARD_SYSCLK_333MHZ 333333334
++#define MV_BOARD_SYSCLK_400MHZ 400000000
++
++#define MV_BOARD_REFCLK_25MHZ 25000000
++
++/* Board specific */
++/* =============================== */
++
++/* boards ID numbers */
++
++#define BOARD_ID_BASE 0x0
++
++/* New board ID numbers */
++#define DB_88F6281A_BP_ID (BOARD_ID_BASE)
++#define DB_88F6281_BP_MLL_ID 1680
++#define RD_88F6281A_ID (BOARD_ID_BASE+0x1)
++#define RD_88F6281_MLL_ID 1682
++#define DB_88F6192A_BP_ID (BOARD_ID_BASE+0x2)
++#define RD_88F6192A_ID (BOARD_ID_BASE+0x3)
++#define RD_88F6192_MLL_ID 1681
++#define DB_88F6180A_BP_ID (BOARD_ID_BASE+0x4)
++#define DB_88F6190A_BP_ID (BOARD_ID_BASE+0x5)
++#define RD_88F6190A_ID (BOARD_ID_BASE+0x6)
++#define RD_88F6281A_PCAC_ID (BOARD_ID_BASE+0x7)
++#define DB_CUSTOMER_ID (BOARD_ID_BASE+0x8)
++#define SHEEVA_PLUG_ID (BOARD_ID_BASE+0x9)
++#define MV_MAX_BOARD_ID (SHEEVA_PLUG_ID + 1)
++
++/* DB-88F6281A-BP */
++#if defined(MV_NAND)
++ #define DB_88F6281A_MPP0_7 0x21111111
++#else
++ #define DB_88F6281A_MPP0_7 0x21112220
++#endif
++#define DB_88F6281A_MPP8_15 0x11113311
++#define DB_88F6281A_MPP16_23 0x00551111
++#define DB_88F6281A_MPP24_31 0x00000000
++#define DB_88F6281A_MPP32_39 0x00000000
++#define DB_88F6281A_MPP40_47 0x00000000
++#define DB_88F6281A_MPP48_55 0x00000000
++#define DB_88F6281A_OE_LOW 0x0
++#if defined(MV_TDM_5CHANNELS)
++ #define DB_88F6281A_OE_HIGH (BIT6)
++#else
++#define DB_88F6281A_OE_HIGH 0x0
++#endif
++#define DB_88F6281A_OE_VAL_LOW 0x0
++#define DB_88F6281A_OE_VAL_HIGH 0x0
++
++/* RD-88F6281A */
++#if defined(MV_NAND)
++ #define RD_88F6281A_MPP0_7 0x21111111
++#else
++ #define RD_88F6281A_MPP0_7 0x21112220
++#endif
++#define RD_88F6281A_MPP8_15 0x11113311
++#define RD_88F6281A_MPP16_23 0x33331111
++#define RD_88F6281A_MPP24_31 0x33003333
++#define RD_88F6281A_MPP32_39 0x20440533
++#define RD_88F6281A_MPP40_47 0x22202222
++#define RD_88F6281A_MPP48_55 0x00000002
++#define RD_88F6281A_OE_LOW (BIT28 | BIT29)
++#define RD_88F6281A_OE_HIGH (BIT3 | BIT6 | BIT17)
++#define RD_88F6281A_OE_VAL_LOW 0x0
++#define RD_88F6281A_OE_VAL_HIGH 0x0
++
++/* DB-88F6192A-BP */
++#if defined(MV_NAND)
++ #define DB_88F6192A_MPP0_7 0x21111111
++#else
++ #define DB_88F6192A_MPP0_7 0x21112220
++#endif
++#define DB_88F6192A_MPP8_15 0x11113311
++#define DB_88F6192A_MPP16_23 0x00501111
++#define DB_88F6192A_MPP24_31 0x00000000
++#define DB_88F6192A_MPP32_35 0x00000000
++#define DB_88F6192A_OE_LOW (BIT22 | BIT23)
++#define DB_88F6192A_OE_HIGH 0x0
++#define DB_88F6192A_OE_VAL_LOW 0x0
++#define DB_88F6192A_OE_VAL_HIGH 0x0
++
++/* RD-88F6192A */
++#define RD_88F6192A_MPP0_7 0x01222222
++#define RD_88F6192A_MPP8_15 0x00000011
++#define RD_88F6192A_MPP16_23 0x05550000
++#define RD_88F6192A_MPP24_31 0x0
++#define RD_88F6192A_MPP32_35 0x0
++#define RD_88F6192A_OE_LOW (BIT11 | BIT14 | BIT24 | BIT25 | BIT26 | BIT27 | BIT30 | BIT31)
++#define RD_88F6192A_OE_HIGH (BIT0 | BIT2)
++#define RD_88F6192A_OE_VAL_LOW 0x18400
++#define RD_88F6192A_OE_VAL_HIGH 0x8
++
++/* DB-88F6180A-BP */
++#if defined(MV_NAND)
++ #define DB_88F6180A_MPP0_7 0x21111111
++#else
++ #define DB_88F6180A_MPP0_7 0x01112222
++#endif
++#define DB_88F6180A_MPP8_15 0x11113311
++#define DB_88F6180A_MPP16_23 0x00001111
++#define DB_88F6180A_MPP24_31 0x0
++#define DB_88F6180A_MPP32_39 0x4444c000
++#define DB_88F6180A_MPP40_44 0x00044444
++#define DB_88F6180A_OE_LOW 0x0
++#define DB_88F6180A_OE_HIGH 0x0
++#define DB_88F6180A_OE_VAL_LOW 0x0
++#define DB_88F6180A_OE_VAL_HIGH 0x0
++
++/* RD-88F6281A_PCAC */
++#define RD_88F6281A_PCAC_MPP0_7 0x21111111
++#define RD_88F6281A_PCAC_MPP8_15 0x00003311
++#define RD_88F6281A_PCAC_MPP16_23 0x00001100
++#define RD_88F6281A_PCAC_MPP24_31 0x00000000
++#define RD_88F6281A_PCAC_MPP32_39 0x00000000
++#define RD_88F6281A_PCAC_MPP40_47 0x00000000
++#define RD_88F6281A_PCAC_MPP48_55 0x00000000
++#define RD_88F6281A_PCAC_OE_LOW 0x0
++#define RD_88F6281A_PCAC_OE_HIGH 0x0
++#define RD_88F6281A_PCAC_OE_VAL_LOW 0x0
++#define RD_88F6281A_PCAC_OE_VAL_HIGH 0x0
++
++/* SHEEVA PLUG */
++#define RD_SHEEVA_PLUG_MPP0_7 0x01111111
++#define RD_SHEEVA_PLUG_MPP8_15 0x11113322
++#define RD_SHEEVA_PLUG_MPP16_23 0x00001111
++#define RD_SHEEVA_PLUG_MPP24_31 0x00100000
++#define RD_SHEEVA_PLUG_MPP32_39 0x00000000
++#define RD_SHEEVA_PLUG_MPP40_47 0x00000000
++#define RD_SHEEVA_PLUG_MPP48_55 0x00000000
++#define RD_SHEEVA_PLUG_OE_LOW 0x0
++#define RD_SHEEVA_PLUG_OE_HIGH 0x0
++#define RD_SHEEVA_PLUG_OE_VAL_LOW (BIT29)
++#define RD_SHEEVA_PLUG_OE_VAL_HIGH ((~(BIT17 | BIT16 | BIT15)) | BIT14)
++
++/* DB-CUSTOMER */
++#define DB_CUSTOMER_MPP0_7 0x21111111
++#define DB_CUSTOMER_MPP8_15 0x00003311
++#define DB_CUSTOMER_MPP16_23 0x00001100
++#define DB_CUSTOMER_MPP24_31 0x00000000
++#define DB_CUSTOMER_MPP32_39 0x00000000
++#define DB_CUSTOMER_MPP40_47 0x00000000
++#define DB_CUSTOMER_MPP48_55 0x00000000
++#define DB_CUSTOMER_OE_LOW 0x0
++#define DB_CUSTOMER_OE_HIGH (~((BIT6) | (BIT7) | (BIT8) | (BIT9)))
++#define DB_CUSTOMER_OE_VAL_LOW 0x0
++#define DB_CUSTOMER_OE_VAL_HIGH 0x0
++
++#endif /* __INCmvBoardEnvSpech */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.c 2010-11-09 20:28:07.522495500 +0100
+@@ -0,0 +1,320 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "cpu/mvCpu.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/mvCtrlEnvRegs.h"
++#include "ctrlEnv/sys/mvCpuIfRegs.h"
++
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++/* locals */
++
++/*******************************************************************************
++* mvCpuPclkGet - Get the CPU pClk (pipe clock)
++*
++* DESCRIPTION:
++* This routine extract the CPU core clock.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit clock cycles in MHertz.
++*
++*******************************************************************************/
++/* 6180 have different clk reset sampling */
++
++static MV_U32 mvCpu6180PclkGet(MV_VOID)
++{
++ MV_U32 tmpPClkRate=0;
++ MV_CPU_ARM_CLK cpu6180_ddr_l2_CLK[] = MV_CPU6180_DDR_L2_CLCK_TBL;
++
++ tmpPClkRate = MV_REG_READ(MPP_SAMPLE_AT_RESET);
++ tmpPClkRate = tmpPClkRate & MSAR_CPUCLCK_MASK_6180;
++ tmpPClkRate = tmpPClkRate >> MSAR_CPUCLCK_OFFS_6180;
++
++ tmpPClkRate = cpu6180_ddr_l2_CLK[tmpPClkRate].cpuClk;
++
++ return tmpPClkRate;
++}
++
++
++MV_U32 mvCpuPclkGet(MV_VOID)
++{
++#if defined(PCLCK_AUTO_DETECT)
++ MV_U32 tmpPClkRate=0;
++ MV_U32 cpuCLK[] = MV_CPU_CLCK_TBL;
++
++ if(mvCtrlModelGet() == MV_6180_DEV_ID)
++ return mvCpu6180PclkGet();
++
++ tmpPClkRate = MV_REG_READ(MPP_SAMPLE_AT_RESET);
++ tmpPClkRate = MSAR_CPUCLCK_EXTRACT(tmpPClkRate);
++ tmpPClkRate = cpuCLK[tmpPClkRate];
++
++ return tmpPClkRate;
++#else
++ return MV_DEFAULT_PCLK
++#endif
++}
++
++/*******************************************************************************
++* mvCpuL2ClkGet - Get the CPU L2 (CPU bus clock)
++*
++* DESCRIPTION:
++* This routine extract the CPU L2 clock.
++*
++* RETURN:
++* 32bit clock cycles in Hertz.
++*
++*******************************************************************************/
++static MV_U32 mvCpu6180L2ClkGet(MV_VOID)
++{
++ MV_U32 L2ClkRate=0;
++ MV_CPU_ARM_CLK _cpu6180_ddr_l2_CLK[] = MV_CPU6180_DDR_L2_CLCK_TBL;
++
++ L2ClkRate = MV_REG_READ(MPP_SAMPLE_AT_RESET);
++ L2ClkRate = L2ClkRate & MSAR_CPUCLCK_MASK_6180;
++ L2ClkRate = L2ClkRate >> MSAR_CPUCLCK_OFFS_6180;
++
++ L2ClkRate = _cpu6180_ddr_l2_CLK[L2ClkRate].l2Clk;
++
++ return L2ClkRate;
++
++}
++
++MV_U32 mvCpuL2ClkGet(MV_VOID)
++{
++#ifdef L2CLK_AUTO_DETECT
++ MV_U32 L2ClkRate, tmp, pClkRate, indexL2Rtio;
++ MV_U32 L2Rtio[][2] = MV_L2_CLCK_RTIO_TBL;
++
++ if(mvCtrlModelGet() == MV_6180_DEV_ID)
++ return mvCpu6180L2ClkGet();
++
++ pClkRate = mvCpuPclkGet();
++
++ tmp = MV_REG_READ(MPP_SAMPLE_AT_RESET);
++ indexL2Rtio = MSAR_L2CLCK_EXTRACT(tmp);
++
++ L2ClkRate = ((pClkRate * L2Rtio[indexL2Rtio][1]) / L2Rtio[indexL2Rtio][0]);
++
++ return L2ClkRate;
++#else
++ return MV_BOARD_DEFAULT_L2CLK;
++#endif
++}
++
++
++/*******************************************************************************
++* mvCpuNameGet - Get CPU name
++*
++* DESCRIPTION:
++* This function returns a string describing the CPU model and revision.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* pNameBuff - Buffer to contain board name string. Minimum size 32 chars.
++*
++* RETURN:
++* None.
++*******************************************************************************/
++MV_VOID mvCpuNameGet(char *pNameBuff)
++{
++ MV_U32 cpuModel;
++
++ cpuModel = mvOsCpuPartGet();
++
++ /* The CPU module is indicated in the Processor Version Register (PVR) */
++ switch(cpuModel)
++ {
++ case CPU_PART_MRVL131:
++ mvOsSPrintf(pNameBuff, "%s (Rev %d)", "Marvell Feroceon",mvOsCpuRevGet());
++ break;
++ case CPU_PART_ARM926:
++ mvOsSPrintf(pNameBuff, "%s (Rev %d)", "ARM926",mvOsCpuRevGet());
++ break;
++ case CPU_PART_ARM946:
++ mvOsSPrintf(pNameBuff, "%s (Rev %d)", "ARM946",mvOsCpuRevGet());
++ break;
++ default:
++ mvOsSPrintf(pNameBuff,"??? (0x%04x) (Rev %d)",cpuModel,mvOsCpuRevGet());
++ break;
++ } /* switch */
++
++ return;
++}
++
++
++#define MV_PROC_STR_SIZE 50
++
++static void mvCpuIfGetL2EccMode(MV_8 *buf)
++{
++ MV_U32 regVal = MV_REG_READ(CPU_L2_CONFIG_REG);
++ if (regVal & BIT2)
++ mvOsSPrintf(buf, "L2 ECC Enabled");
++ else
++ mvOsSPrintf(buf, "L2 ECC Disabled");
++}
++
++static void mvCpuIfGetL2Mode(MV_8 *buf)
++{
++ MV_U32 regVal = 0;
++ __asm volatile ("mrc p15, 1, %0, c15, c1, 0" : "=r" (regVal)); /* Read Marvell extra features register */
++ if (regVal & BIT22)
++ mvOsSPrintf(buf, "L2 Enabled");
++ else
++ mvOsSPrintf(buf, "L2 Disabled");
++}
++
++static void mvCpuIfGetL2PrefetchMode(MV_8 *buf)
++{
++ MV_U32 regVal = 0;
++ __asm volatile ("mrc p15, 1, %0, c15, c1, 0" : "=r" (regVal)); /* Read Marvell extra features register */
++ if (regVal & BIT24)
++ mvOsSPrintf(buf, "L2 Prefetch Disabled");
++ else
++ mvOsSPrintf(buf, "L2 Prefetch Enabled");
++}
++
++static void mvCpuIfGetWriteAllocMode(MV_8 *buf)
++{
++ MV_U32 regVal = 0;
++ __asm volatile ("mrc p15, 1, %0, c15, c1, 0" : "=r" (regVal)); /* Read Marvell extra features register */
++ if (regVal & BIT28)
++ mvOsSPrintf(buf, "Write Allocate Enabled");
++ else
++ mvOsSPrintf(buf, "Write Allocate Disabled");
++}
++
++static void mvCpuIfGetCpuStreamMode(MV_8 *buf)
++{
++ MV_U32 regVal = 0;
++ __asm volatile ("mrc p15, 1, %0, c15, c1, 0" : "=r" (regVal)); /* Read Marvell extra features register */
++ if (regVal & BIT29)
++ mvOsSPrintf(buf, "CPU Streaming Enabled");
++ else
++ mvOsSPrintf(buf, "CPU Streaming Disabled");
++}
++
++static void mvCpuIfPrintCpuRegs(void)
++{
++ MV_U32 regVal = 0;
++
++ __asm volatile ("mrc p15, 1, %0, c15, c1, 0" : "=r" (regVal)); /* Read Marvell extra features register */
++ mvOsPrintf("Extra Feature Reg = 0x%x\n",regVal);
++
++ __asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (regVal)); /* Read Control register */
++ mvOsPrintf("Control Reg = 0x%x\n",regVal);
++
++ __asm volatile ("mrc p15, 0, %0, c0, c0, 0" : "=r" (regVal)); /* Read ID Code register */
++ mvOsPrintf("ID Code Reg = 0x%x\n",regVal);
++
++ __asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r" (regVal)); /* Read Cache Type register */
++ mvOsPrintf("Cache Type Reg = 0x%x\n",regVal);
++
++}
++
++MV_U32 mvCpuIfPrintSystemConfig(MV_8 *buffer, MV_U32 index)
++{
++ MV_U32 count = 0;
++
++ MV_8 L2_ECC_str[MV_PROC_STR_SIZE];
++ MV_8 L2_En_str[MV_PROC_STR_SIZE];
++ MV_8 L2_Prefetch_str[MV_PROC_STR_SIZE];
++ MV_8 Write_Alloc_str[MV_PROC_STR_SIZE];
++ MV_8 Cpu_Stream_str[MV_PROC_STR_SIZE];
++
++ mvCpuIfGetL2Mode(L2_En_str);
++ mvCpuIfGetL2EccMode(L2_ECC_str);
++ mvCpuIfGetL2PrefetchMode(L2_Prefetch_str);
++ mvCpuIfGetWriteAllocMode(Write_Alloc_str);
++ mvCpuIfGetCpuStreamMode(Cpu_Stream_str);
++ mvCpuIfPrintCpuRegs();
++
++ count += mvOsSPrintf(buffer + count + index, "%s\n", L2_En_str);
++ count += mvOsSPrintf(buffer + count + index, "%s\n", L2_ECC_str);
++ count += mvOsSPrintf(buffer + count + index, "%s\n", L2_Prefetch_str);
++ count += mvOsSPrintf(buffer + count + index, "%s\n", Write_Alloc_str);
++ count += mvOsSPrintf(buffer + count + index, "%s\n", Cpu_Stream_str);
++ return count;
++}
++
++MV_U32 whoAmI(MV_VOID)
++{
++ return 0;
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.h 2010-11-09 20:28:07.562495452 +0100
+@@ -0,0 +1,99 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvCpuh
++#define __INCmvCpuh
++
++#include "mvCommon.h"
++#include "mvOs.h"
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++
++/* defines */
++#define CPU_PART_MRVL131 0x131
++#define CPU_PART_ARM926 0x926
++#define CPU_PART_ARM946 0x946
++#define MV_CPU_ARM_CLK_ELM_SIZE 12
++#define MV_CPU_ARM_CLK_RATIO_OFF 8
++#define MV_CPU_ARM_CLK_DDR_OFF 4
++
++#ifndef MV_ASMLANGUAGE
++typedef struct _mvCpuArmClk
++{
++ MV_U32 cpuClk; /* CPU clock in MHz */
++ MV_U32 ddrClk; /* DDR clock in MHz */
++ MV_U32 l2Clk; /* CPU DDR clock ratio */
++
++}MV_CPU_ARM_CLK;
++
++MV_U32 mvCpuPclkGet(MV_VOID);
++MV_VOID mvCpuNameGet(char *pNameBuff);
++MV_U32 mvCpuL2ClkGet(MV_VOID);
++MV_U32 mvCpuIfPrintSystemConfig(MV_8 *buffer, MV_U32 index);
++MV_U32 whoAmI(MV_VOID);
++
++#endif /* MV_ASMLANGUAGE */
++
++
++#endif /* __INCmvCpuh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.c 2010-11-09 20:28:07.602495466 +0100
+@@ -0,0 +1,296 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++/*******************************************************************************
++* mvCtrlEnvAddrDec.h - Marvell controller address decode library
++*
++* DESCRIPTION:
++*
++* DEPENDENCIES:
++* None.
++*
++*******************************************************************************/
++
++/* includes */
++#include "ctrlEnv/mvCtrlEnvAddrDec.h"
++#include "ctrlEnv/sys/mvAhbToMbusRegs.h"
++#include "ddr2/mvDramIfRegs.h"
++#include "pex/mvPexRegs.h"
++
++#define MV_DEBUG
++
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++/* Default Attributes array */
++MV_TARGET_ATTRIB mvTargetDefaultsArray[] = TARGETS_DEF_ARRAY;
++extern MV_TARGET *sampleAtResetTargetArray;
++/* Dram\AHBToMbus\PEX share regsiter */
++
++#define CTRL_DEC_BASE_OFFS 16
++#define CTRL_DEC_BASE_MASK (0xffff << CTRL_DEC_BASE_OFFS)
++#define CTRL_DEC_BASE_ALIGNMENT 0x10000
++
++#define CTRL_DEC_SIZE_OFFS 16
++#define CTRL_DEC_SIZE_MASK (0xffff << CTRL_DEC_SIZE_OFFS)
++#define CTRL_DEC_SIZE_ALIGNMENT 0x10000
++
++#define CTRL_DEC_WIN_EN BIT0
++
++
++
++/*******************************************************************************
++* mvCtrlAddrDecToReg - Get address decode register format values
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_STATUS mvCtrlAddrDecToReg(MV_ADDR_WIN *pAddrDecWin, MV_DEC_REGS *pAddrDecRegs)
++{
++
++ MV_U32 baseToReg=0 , sizeToReg=0;
++
++ /* BaseLow[31:16] => base register [31:16] */
++ baseToReg = pAddrDecWin->baseLow & CTRL_DEC_BASE_MASK;
++
++ /* Write to address decode Base Address Register */
++ pAddrDecRegs->baseReg &= ~CTRL_DEC_BASE_MASK;
++ pAddrDecRegs->baseReg |= baseToReg;
++
++ /* Get size register value according to window size */
++ sizeToReg = ctrlSizeToReg(pAddrDecWin->size, CTRL_DEC_SIZE_ALIGNMENT);
++
++ /* Size parameter validity check. */
++ if (-1 == sizeToReg)
++ {
++ return MV_BAD_PARAM;
++ }
++
++ /* set size */
++ pAddrDecRegs->sizeReg &= ~CTRL_DEC_SIZE_MASK;
++ pAddrDecRegs->sizeReg |= (sizeToReg << CTRL_DEC_SIZE_OFFS);
++
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvCtrlRegToAddrDec - Extract address decode struct from registers.
++*
++* DESCRIPTION:
++* This function extract address decode struct from address decode
++* registers given as parameters.
++*
++* INPUT:
++* pAddrDecRegs - Address decode register struct.
++*
++* OUTPUT:
++* pAddrDecWin - Target window data structure.
++*
++* RETURN:
++* MV_BAD_PARAM if address decode registers data is invalid.
++*
++*******************************************************************************/
++MV_STATUS mvCtrlRegToAddrDec(MV_DEC_REGS *pAddrDecRegs, MV_ADDR_WIN *pAddrDecWin)
++{
++ MV_U32 sizeRegVal;
++
++ sizeRegVal = (pAddrDecRegs->sizeReg & CTRL_DEC_SIZE_MASK) >>
++ CTRL_DEC_SIZE_OFFS;
++
++ pAddrDecWin->size = ctrlRegToSize(sizeRegVal, CTRL_DEC_SIZE_ALIGNMENT);
++
++
++ /* Extract base address */
++ /* Base register [31:16] ==> baseLow[31:16] */
++ pAddrDecWin->baseLow = pAddrDecRegs->baseReg & CTRL_DEC_BASE_MASK;
++
++ pAddrDecWin->baseHigh = 0;
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvCtrlAttribGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++*
++*******************************************************************************/
++
++MV_STATUS mvCtrlAttribGet(MV_TARGET target,
++ MV_TARGET_ATTRIB *targetAttrib)
++{
++
++ targetAttrib->attrib = mvTargetDefaultsArray[MV_CHANGE_BOOT_CS(target)].attrib;
++ targetAttrib->targetId = mvTargetDefaultsArray[MV_CHANGE_BOOT_CS(target)].targetId;
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvCtrlGetAttrib -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_TARGET mvCtrlTargetGet(MV_TARGET_ATTRIB *targetAttrib)
++{
++ MV_TARGET target;
++ MV_TARGET x;
++ for (target = SDRAM_CS0; target < MAX_TARGETS ; target ++)
++ {
++ x = MV_CHANGE_BOOT_CS(target);
++ if ((mvTargetDefaultsArray[x].attrib == targetAttrib->attrib) &&
++ (mvTargetDefaultsArray[MV_CHANGE_BOOT_CS(target)].targetId == targetAttrib->targetId))
++ {
++ /* found it */
++ break;
++ }
++ }
++
++ return target;
++}
++
++MV_STATUS mvCtrlAddrDecToParams(MV_DEC_WIN *pAddrDecWin,
++ MV_DEC_WIN_PARAMS *pWinParam)
++{
++ MV_U32 baseToReg=0, sizeToReg=0;
++
++ /* BaseLow[31:16] => base register [31:16] */
++ baseToReg = pAddrDecWin->addrWin.baseLow & CTRL_DEC_BASE_MASK;
++
++ /* Write to address decode Base Address Register */
++ pWinParam->baseAddr &= ~CTRL_DEC_BASE_MASK;
++ pWinParam->baseAddr |= baseToReg;
++
++ /* Get size register value according to window size */
++ sizeToReg = ctrlSizeToReg(pAddrDecWin->addrWin.size, CTRL_DEC_SIZE_ALIGNMENT);
++
++ /* Size parameter validity check. */
++ if (-1 == sizeToReg)
++ {
++ mvOsPrintf("mvCtrlAddrDecToParams: ERR. ctrlSizeToReg failed.\n");
++ return MV_BAD_PARAM;
++ }
++ pWinParam->size = sizeToReg;
++
++ pWinParam->attrib = mvTargetDefaultsArray[MV_CHANGE_BOOT_CS(pAddrDecWin->target)].attrib;
++ pWinParam->targetId = mvTargetDefaultsArray[MV_CHANGE_BOOT_CS(pAddrDecWin->target)].targetId;
++
++ return MV_OK;
++}
++
++MV_STATUS mvCtrlParamsToAddrDec(MV_DEC_WIN_PARAMS *pWinParam,
++ MV_DEC_WIN *pAddrDecWin)
++{
++ MV_TARGET_ATTRIB targetAttrib;
++
++ pAddrDecWin->addrWin.baseLow = pWinParam->baseAddr;
++
++ /* Upper 32bit address base is supported under PCI High Address remap */
++ pAddrDecWin->addrWin.baseHigh = 0;
++
++ /* Prepare sizeReg to ctrlRegToSize function */
++ pAddrDecWin->addrWin.size = ctrlRegToSize(pWinParam->size, CTRL_DEC_SIZE_ALIGNMENT);
++
++ if (-1 == pAddrDecWin->addrWin.size)
++ {
++ DB(mvOsPrintf("mvCtrlParamsToAddrDec: ERR. ctrlRegToSize failed.\n"));
++ return MV_BAD_PARAM;
++ }
++ targetAttrib.targetId = pWinParam->targetId;
++ targetAttrib.attrib = pWinParam->attrib;
++
++ pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib);
++
++ return MV_OK;
++}
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.h 2010-11-09 20:28:07.642495620 +0100
+@@ -0,0 +1,203 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvCtrlEnvAddrDech
++#define __INCmvCtrlEnvAddrDech
++
++/* includes */
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/mvCtrlEnvRegs.h"
++
++
++/* defines */
++/* DUnit attributes */
++#define ATMWCR_WIN_DUNIT_CS0_OFFS 0
++#define ATMWCR_WIN_DUNIT_CS0_MASK BIT0
++#define ATMWCR_WIN_DUNIT_CS0_REQ (0 << ATMWCR_WIN_DUNIT_CS0_OFFS)
++
++#define ATMWCR_WIN_DUNIT_CS1_OFFS 1
++#define ATMWCR_WIN_DUNIT_CS1_MASK BIT1
++#define ATMWCR_WIN_DUNIT_CS1_REQ (0 << ATMWCR_WIN_DUNIT_CS1_OFFS)
++
++#define ATMWCR_WIN_DUNIT_CS2_OFFS 2
++#define ATMWCR_WIN_DUNIT_CS2_MASK BIT2
++#define ATMWCR_WIN_DUNIT_CS2_REQ (0 << ATMWCR_WIN_DUNIT_CS2_OFFS)
++
++#define ATMWCR_WIN_DUNIT_CS3_OFFS 3
++#define ATMWCR_WIN_DUNIT_CS3_MASK BIT3
++#define ATMWCR_WIN_DUNIT_CS3_REQ (0 << ATMWCR_WIN_DUNIT_CS3_OFFS)
++
++/* RUnit (Device) attributes */
++#define ATMWCR_WIN_RUNIT_DEVCS0_OFFS 0
++#define ATMWCR_WIN_RUNIT_DEVCS0_MASK BIT0
++#define ATMWCR_WIN_RUNIT_DEVCS0_REQ (0 << ATMWCR_WIN_RUNIT_DEVCS0_OFFS)
++
++#define ATMWCR_WIN_RUNIT_DEVCS1_OFFS 1
++#define ATMWCR_WIN_RUNIT_DEVCS1_MASK BIT1
++#define ATMWCR_WIN_RUNIT_DEVCS1_REQ (0 << ATMWCR_WIN_RUNIT_DEVCS1_OFFS)
++
++#define ATMWCR_WIN_RUNIT_DEVCS2_OFFS 2
++#define ATMWCR_WIN_RUNIT_DEVCS2_MASK BIT2
++#define ATMWCR_WIN_RUNIT_DEVCS2_REQ (0 << ATMWCR_WIN_RUNIT_DEVCS2_OFFS)
++
++#define ATMWCR_WIN_RUNIT_BOOTCS_OFFS 4
++#define ATMWCR_WIN_RUNIT_BOOTCS_MASK BIT4
++#define ATMWCR_WIN_RUNIT_BOOTCS_REQ (0 << ATMWCR_WIN_RUNIT_BOOTCS_OFFS)
++
++/* LMaster (PCI) attributes */
++#define ATMWCR_WIN_LUNIT_BYTE_SWP_OFFS 0
++#define ATMWCR_WIN_LUNIT_BYTE_SWP_MASK BIT0
++#define ATMWCR_WIN_LUNIT_BYTE_SWP (0 << ATMWCR_WIN_LUNIT_BYTE_SWP_OFFS)
++#define ATMWCR_WIN_LUNIT_BYTE_NO_SWP (1 << ATMWCR_WIN_LUNIT_BYTE_SWP_OFFS)
++
++
++#define ATMWCR_WIN_LUNIT_WORD_SWP_OFFS 1
++#define ATMWCR_WIN_LUNIT_WORD_SWP_MASK BIT1
++#define ATMWCR_WIN_LUNIT_WORD_SWP (0 << ATMWCR_WIN_LUNIT_WORD_SWP_OFFS)
++#define ATMWCR_WIN_LUNIT_WORD_NO_SWP (1 << ATMWCR_WIN_LUNIT_WORD_SWP_OFFS)
++
++#define ATMWCR_WIN_LUNIT_NO_SNOOP BIT2
++
++#define ATMWCR_WIN_LUNIT_TYPE_OFFS 3
++#define ATMWCR_WIN_LUNIT_TYPE_MASK BIT3
++#define ATMWCR_WIN_LUNIT_TYPE_IO (0 << ATMWCR_WIN_LUNIT_TYPE_OFFS)
++#define ATMWCR_WIN_LUNIT_TYPE_MEM (1 << ATMWCR_WIN_LUNIT_TYPE_OFFS)
++
++#define ATMWCR_WIN_LUNIT_FORCE64_OFFS 4
++#define ATMWCR_WIN_LUNIT_FORCE64_MASK BIT4
++#define ATMWCR_WIN_LUNIT_FORCE64 (0 << ATMWCR_WIN_LUNIT_FORCE64_OFFS)
++
++#define ATMWCR_WIN_LUNIT_ORDERING_OFFS 6
++#define ATMWCR_WIN_LUNIT_ORDERING_MASK BIT6
++#define ATMWCR_WIN_LUNIT_ORDERING (1 << ATMWCR_WIN_LUNIT_FORCE64_OFFS)
++
++/* PEX Attributes */
++#define ATMWCR_WIN_PEX_TYPE_OFFS 3
++#define ATMWCR_WIN_PEX_TYPE_MASK BIT3
++#define ATMWCR_WIN_PEX_TYPE_IO (0 << ATMWCR_WIN_PEX_TYPE_OFFS)
++#define ATMWCR_WIN_PEX_TYPE_MEM (1 << ATMWCR_WIN_PEX_TYPE_OFFS)
++
++/* typedefs */
++
++/* Unsupported attributes for address decode: */
++/* 2) PCI0/1_REQ64n control */
++
++typedef struct _mvDecRegs
++{
++ MV_U32 baseReg;
++ MV_U32 baseRegHigh;
++ MV_U32 sizeReg;
++
++}MV_DEC_REGS;
++
++typedef struct _mvTargetAttrib
++{
++ MV_U8 attrib; /* chip select attributes */
++ MV_TARGET_ID targetId; /* Target Id of this MV_TARGET */
++
++}MV_TARGET_ATTRIB;
++
++
++/* This structure describes address decode window */
++typedef struct _mvDecWin
++{
++ MV_TARGET target; /* Target for addr decode window */
++ MV_ADDR_WIN addrWin; /* Address window of target */
++ MV_BOOL enable; /* Window enable/disable */
++}MV_DEC_WIN;
++
++typedef struct _mvDecWinParams
++{
++ MV_TARGET_ID targetId; /* Target ID field */
++ MV_U8 attrib; /* Attribute field */
++ MV_U32 baseAddr; /* Base address in register format */
++ MV_U32 size; /* Size in register format */
++}MV_DEC_WIN_PARAMS;
++
++
++/* mvCtrlEnvAddrDec API list */
++
++MV_STATUS mvCtrlAddrDecToReg(MV_ADDR_WIN *pAddrDecWin,
++ MV_DEC_REGS *pAddrDecRegs);
++
++MV_STATUS mvCtrlRegToAddrDec(MV_DEC_REGS *pAddrDecRegs,
++ MV_ADDR_WIN *pAddrDecWin);
++
++MV_STATUS mvCtrlAttribGet(MV_TARGET target,
++ MV_TARGET_ATTRIB *targetAttrib);
++
++MV_TARGET mvCtrlTargetGet(MV_TARGET_ATTRIB *targetAttrib);
++
++
++MV_STATUS mvCtrlAddrDecToParams(MV_DEC_WIN *pAddrDecWin,
++ MV_DEC_WIN_PARAMS *pWinParam);
++
++MV_STATUS mvCtrlParamsToAddrDec(MV_DEC_WIN_PARAMS *pWinParam,
++ MV_DEC_WIN *pAddrDecWin);
++
++
++
++
++#endif /* __INCmvCtrlEnvAddrDech */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAsm.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAsm.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAsm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAsm.h 2010-11-09 20:28:07.682495401 +0100
+@@ -0,0 +1,98 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvCtrlEnvAsmh
++#define __INCmvCtrlEnvAsmh
++#include "pex/mvPexRegs.h"
++
++#define CHIP_BOND_REG 0x10034
++#define PCKG_OPT_MASK_AS #3
++#define PXCCARI_REVID_MASK_AS #PXCCARI_REVID_MASK
++
++/* Read device ID into toReg bits 15:0 from 0xd0000000 */
++/* defines */
++#define MV_DV_CTRL_MODEL_GET_ASM(toReg, tmpReg) \
++ MV_DV_REG_READ_ASM(toReg, tmpReg, CHIP_BOND_REG);\
++ and toReg, toReg, PCKG_OPT_MASK_AS /* Mask for package ID */
++
++/* Read device ID into toReg bits 15:0 from 0xf1000000*/
++#define MV_CTRL_MODEL_GET_ASM(toReg, tmpReg) \
++ MV_REG_READ_ASM(toReg, tmpReg, CHIP_BOND_REG);\
++ and toReg, toReg, PCKG_OPT_MASK_AS /* Mask for package ID */
++
++/* Read Revision into toReg bits 7:0 0xd0000000*/
++#define MV_DV_CTRL_REV_GET_ASM(toReg, tmpReg) \
++ /* Read device revision */ \
++ MV_DV_REG_READ_ASM(toReg, tmpReg, PEX_CFG_DIRECT_ACCESS(0,PEX_CLASS_CODE_AND_REVISION_ID));\
++ and toReg, toReg, PXCCARI_REVID_MASK_AS /* Mask for calss ID */
++
++/* Read Revision into toReg bits 7:0 0xf1000000*/
++#define MV_CTRL_REV_GET_ASM(toReg, tmpReg) \
++ /* Read device revision */ \
++ MV_REG_READ_ASM(toReg, tmpReg, PEX_CFG_DIRECT_ACCESS(0,PEX_CLASS_CODE_AND_REVISION_ID));\
++ and toReg, toReg, PXCCARI_REVID_MASK_AS /* Mask for calss ID */
++
++
++#endif /* __INCmvCtrlEnvAsmh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.c 2010-11-09 20:28:07.712495488 +0100
+@@ -0,0 +1,1825 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++
++/* includes */
++#include "mvCommon.h"
++#include "mvCtrlEnvLib.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++
++#if defined(MV_INCLUDE_PEX)
++#include "pex/mvPex.h"
++#include "ctrlEnv/sys/mvSysPex.h"
++#endif
++
++#if defined(MV_INCLUDE_GIG_ETH)
++#include "ctrlEnv/sys/mvSysGbe.h"
++#endif
++
++#if defined(MV_INCLUDE_XOR)
++#include "ctrlEnv/sys/mvSysXor.h"
++#endif
++
++#if defined(MV_INCLUDE_SATA)
++#include "ctrlEnv/sys/mvSysSata.h"
++#endif
++
++#if defined(MV_INCLUDE_USB)
++#include "ctrlEnv/sys/mvSysUsb.h"
++#endif
++
++#if defined(MV_INCLUDE_AUDIO)
++#include "ctrlEnv/sys/mvSysAudio.h"
++#endif
++
++#if defined(MV_INCLUDE_CESA)
++#include "ctrlEnv/sys/mvSysCesa.h"
++#endif
++
++#if defined(MV_INCLUDE_TS)
++#include "ctrlEnv/sys/mvSysTs.h"
++#endif
++
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++/*******************************************************************************
++* mvCtrlEnvInit - Initialize Marvell controller environment.
++*
++* DESCRIPTION:
++* This function get environment information and initialize controller
++* internal/external environment. For example
++* 1) MPP settings according to board MPP macros.
++* NOTE: It is the user responsibility to shut down all DMA channels
++* in device and disable controller sub units interrupts during
++* boot process.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvCtrlEnvInit(MV_VOID)
++{
++ MV_U32 mppGroup;
++ MV_U32 devId;
++ MV_U32 boardId;
++ MV_U32 i;
++ MV_U32 maxMppGrp = 1;
++ MV_U32 mppVal = 0;
++ MV_U32 bootVal = 0;
++ MV_U32 mppGroupType = 0;
++ MV_U32 mppGroup1[][3] = MPP_GROUP_1_TYPE;
++ MV_U32 mppGroup2[][3] = MPP_GROUP_2_TYPE;
++
++ devId = mvCtrlModelGet();
++ boardId= mvBoardIdGet();
++
++ switch(devId){
++ case MV_6281_DEV_ID:
++ maxMppGrp = MV_6281_MPP_MAX_GROUP;
++ break;
++ case MV_6192_DEV_ID:
++ maxMppGrp = MV_6192_MPP_MAX_GROUP;
++ break;
++ case MV_6190_DEV_ID:
++ maxMppGrp = MV_6190_MPP_MAX_GROUP;
++ break;
++ case MV_6180_DEV_ID:
++ maxMppGrp = MV_6180_MPP_MAX_GROUP;
++ break;
++ }
++
++ /* MPP Init */
++ /* We split mpp init to 3 phases:
++ * 1. We init mpp[19:0] from the board info. mpp[23:20] will be over write
++ * in phase 2.
++ * 2. We detect the mpp group type and according the mpp values [35:20].
++ * 3. We detect the mpp group type and according the mpp values [49:36].
++ */
++ /* Mpp phase 1 mpp[19:0] */
++ /* Read MPP group from board level and assign to MPP register */
++ for (mppGroup = 0; mppGroup < 3; mppGroup++)
++ {
++ mppVal = mvBoardMppGet(mppGroup);
++ if (mppGroup == 0)
++ {
++ bootVal = MV_REG_READ(mvCtrlMppRegGet(mppGroup));
++ if (mvCtrlIsBootFromSPI())
++ {
++ mppVal &= ~0xffff;
++ bootVal &= 0xffff;
++ mppVal |= bootVal;
++ }
++ else if (mvCtrlIsBootFromSPIUseNAND())
++ {
++ mppVal &= ~0xf0000000;
++ bootVal &= 0xf0000000;
++ mppVal |= bootVal;
++ }
++ else if (mvCtrlIsBootFromNAND())
++ {
++ mppVal &= ~0xffffff;
++ bootVal &= 0xffffff;
++ mppVal |= bootVal;
++ }
++ }
++
++ if (mppGroup == 2)
++ {
++ bootVal = MV_REG_READ(mvCtrlMppRegGet(mppGroup));
++ if (mvCtrlIsBootFromNAND())
++ {
++ mppVal &= ~0xff00;
++ bootVal &= 0xff00;
++ mppVal |= bootVal;
++ }
++ }
++
++ MV_REG_WRITE(mvCtrlMppRegGet(mppGroup), mppVal);
++ }
++
++ /* Identify MPPs group */
++ mvBoardMppGroupIdUpdate();
++
++ /* Update MPPs mux relevent only on Marvell DB */
++ if ((boardId == DB_88F6281A_BP_ID) ||
++ (boardId == DB_88F6180A_BP_ID))
++ mvBoardMppMuxSet();
++
++ mppGroupType = mvBoardMppGroupTypeGet(MV_BOARD_MPP_GROUP_1);
++
++ /* Mpp phase 2 */
++ /* Read MPP group from board level and assign to MPP register */
++ if (devId != MV_6180_DEV_ID)
++ {
++ i = 0;
++ for (mppGroup = 2; mppGroup < 5; mppGroup++)
++ {
++ if ((mppGroupType == MV_BOARD_OTHER) ||
++ (boardId == RD_88F6281A_ID) ||
++ (boardId == RD_88F6192A_ID) ||
++ (boardId == RD_88F6190A_ID) ||
++ (boardId == RD_88F6281A_PCAC_ID) ||
++ (boardId == SHEEVA_PLUG_ID))
++ mppVal = mvBoardMppGet(mppGroup);
++ else
++ {
++ mppVal = mppGroup1[mppGroupType][i];
++ i++;
++ }
++
++ /* Group 2 is shared mpp[23:16] */
++ if (mppGroup == 2)
++ {
++ bootVal = MV_REG_READ(mvCtrlMppRegGet(mppGroup));
++ mppVal &= ~0xffff;
++ bootVal &= 0xffff;
++ mppVal |= bootVal;
++ }
++
++ MV_REG_WRITE(mvCtrlMppRegGet(mppGroup), mppVal);
++ }
++ }
++
++ if ((devId == MV_6192_DEV_ID) || (devId == MV_6190_DEV_ID))
++ return MV_OK;
++
++ /* Mpp phase 3 */
++ mppGroupType = mvBoardMppGroupTypeGet(MV_BOARD_MPP_GROUP_2);
++ /* Read MPP group from board level and assign to MPP register */
++ i = 0;
++ for (mppGroup = 4; mppGroup < 7; mppGroup++)
++ {
++ if ((mppGroupType == MV_BOARD_OTHER) ||
++ (boardId == RD_88F6281A_ID) ||
++ (boardId == RD_88F6281A_PCAC_ID) ||
++ (boardId == SHEEVA_PLUG_ID))
++ mppVal = mvBoardMppGet(mppGroup);
++ else
++ {
++ mppVal = mppGroup2[mppGroupType][i];
++ i++;
++ }
++
++ /* Group 4 is shared mpp[35:32] */
++ if (mppGroup == 4)
++ {
++ bootVal = MV_REG_READ(mvCtrlMppRegGet(mppGroup));
++ mppVal &= ~0xffff;
++ bootVal &= 0xffff;
++ mppVal |= bootVal;
++ }
++
++ MV_REG_WRITE(mvCtrlMppRegGet(mppGroup), mppVal);
++ }
++ /* Update SSCG configuration register*/
++ if(mvBoardIdGet() == DB_88F6281A_BP_ID || mvBoardIdGet() == DB_88F6192A_BP_ID ||
++ mvBoardIdGet() == DB_88F6190A_BP_ID || mvBoardIdGet() == DB_88F6180A_BP_ID)
++ MV_REG_WRITE(0x100d8, 0x53);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCtrlMppRegGet - return reg address of mpp group
++*
++* DESCRIPTION:
++*
++* INPUT:
++* mppGroup - MPP group.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_U32 - Register address.
++*
++*******************************************************************************/
++MV_U32 mvCtrlMppRegGet(MV_U32 mppGroup)
++{
++ MV_U32 ret;
++
++ switch(mppGroup){
++ case (0): ret = MPP_CONTROL_REG0;
++ break;
++ case (1): ret = MPP_CONTROL_REG1;
++ break;
++ case (2): ret = MPP_CONTROL_REG2;
++ break;
++ case (3): ret = MPP_CONTROL_REG3;
++ break;
++ case (4): ret = MPP_CONTROL_REG4;
++ break;
++ case (5): ret = MPP_CONTROL_REG5;
++ break;
++ case (6): ret = MPP_CONTROL_REG6;
++ break;
++ default: ret = MPP_CONTROL_REG0;
++ break;
++ }
++ return ret;
++}
++#if defined(MV_INCLUDE_PEX)
++/*******************************************************************************
++* mvCtrlPexMaxIfGet - Get Marvell controller number of PEX interfaces.
++*
++* DESCRIPTION:
++* This function returns Marvell controller number of PEX interfaces.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Marvell controller number of PEX interfaces. If controller
++* ID is undefined the function returns '0'.
++*
++*******************************************************************************/
++MV_U32 mvCtrlPexMaxIfGet(MV_VOID)
++{
++
++ return MV_PEX_MAX_IF;
++}
++#endif
++
++#if defined(MV_INCLUDE_GIG_ETH)
++/*******************************************************************************
++* mvCtrlEthMaxPortGet - Get Marvell controller number of etherent ports.
++*
++* DESCRIPTION:
++* This function returns Marvell controller number of etherent port.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Marvell controller number of etherent port.
++*
++*******************************************************************************/
++MV_U32 mvCtrlEthMaxPortGet(MV_VOID)
++{
++ MV_U32 devId;
++
++ devId = mvCtrlModelGet();
++
++ switch(devId){
++ case MV_6281_DEV_ID:
++ return MV_6281_ETH_MAX_PORTS;
++ break;
++ case MV_6192_DEV_ID:
++ return MV_6192_ETH_MAX_PORTS;
++ break;
++ case MV_6190_DEV_ID:
++ return MV_6190_ETH_MAX_PORTS;
++ break;
++ case MV_6180_DEV_ID:
++ return MV_6180_ETH_MAX_PORTS;
++ break;
++ }
++ return 0;
++
++}
++#endif
++
++#if defined(MV_INCLUDE_XOR)
++/*******************************************************************************
++* mvCtrlXorMaxChanGet - Get Marvell controller number of XOR channels.
++*
++* DESCRIPTION:
++* This function returns Marvell controller number of XOR channels.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Marvell controller number of XOR channels.
++*
++*******************************************************************************/
++MV_U32 mvCtrlXorMaxChanGet(MV_VOID)
++{
++ return MV_XOR_MAX_CHAN;
++}
++#endif
++
++#if defined(MV_INCLUDE_USB)
++/*******************************************************************************
++* mvCtrlUsbHostMaxGet - Get number of Marvell Usb controllers
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* returns number of Marvell USB controllers.
++*
++*******************************************************************************/
++MV_U32 mvCtrlUsbMaxGet(void)
++{
++ return MV_USB_MAX_PORTS;
++}
++#endif
++
++
++#if defined(MV_INCLUDE_NAND)
++/*******************************************************************************
++* mvCtrlNandSupport - Return if this controller has integrated NAND flash support
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if NAND is supported and MV_FALSE otherwise
++*
++*******************************************************************************/
++MV_U32 mvCtrlNandSupport(MV_VOID)
++{
++ MV_U32 devId;
++
++ devId = mvCtrlModelGet();
++
++ switch(devId){
++ case MV_6281_DEV_ID:
++ return MV_6281_NAND;
++ break;
++ case MV_6192_DEV_ID:
++ return MV_6192_NAND;
++ break;
++ case MV_6190_DEV_ID:
++ return MV_6190_NAND;
++ break;
++ case MV_6180_DEV_ID:
++ return MV_6180_NAND;
++ break;
++ }
++ return 0;
++
++}
++#endif
++
++#if defined(MV_INCLUDE_SDIO)
++/*******************************************************************************
++* mvCtrlSdioSupport - Return if this controller has integrated SDIO flash support
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if SDIO is supported and MV_FALSE otherwise
++*
++*******************************************************************************/
++MV_U32 mvCtrlSdioSupport(MV_VOID)
++{
++ MV_U32 devId;
++
++ devId = mvCtrlModelGet();
++
++ switch(devId){
++ case MV_6281_DEV_ID:
++ return MV_6281_SDIO;
++ break;
++ case MV_6192_DEV_ID:
++ return MV_6192_SDIO;
++ break;
++ case MV_6190_DEV_ID:
++ return MV_6190_SDIO;
++ break;
++ case MV_6180_DEV_ID:
++ return MV_6180_SDIO;
++ break;
++ }
++ return 0;
++
++}
++#endif
++
++#if defined(MV_INCLUDE_TS)
++/*******************************************************************************
++* mvCtrlTsSupport - Return if this controller has integrated TS flash support
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if TS is supported and MV_FALSE otherwise
++*
++*******************************************************************************/
++MV_U32 mvCtrlTsSupport(MV_VOID)
++{
++ MV_U32 devId;
++
++ devId = mvCtrlModelGet();
++
++ switch(devId){
++ case MV_6281_DEV_ID:
++ return MV_6281_TS;
++ break;
++ case MV_6192_DEV_ID:
++ return MV_6192_TS;
++ break;
++ case MV_6190_DEV_ID:
++ return MV_6190_TS;
++ break;
++ case MV_6180_DEV_ID:
++ return MV_6180_TS;
++ break;
++ }
++ return 0;
++}
++#endif
++
++#if defined(MV_INCLUDE_AUDIO)
++/*******************************************************************************
++* mvCtrlAudioSupport - Return if this controller has integrated AUDIO flash support
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if AUDIO is supported and MV_FALSE otherwise
++*
++*******************************************************************************/
++MV_U32 mvCtrlAudioSupport(MV_VOID)
++{
++ MV_U32 devId;
++
++ devId = mvCtrlModelGet();
++
++ switch(devId){
++ case MV_6281_DEV_ID:
++ return MV_6281_AUDIO;
++ break;
++ case MV_6192_DEV_ID:
++ return MV_6192_AUDIO;
++ break;
++ case MV_6190_DEV_ID:
++ return MV_6190_AUDIO;
++ break;
++ case MV_6180_DEV_ID:
++ return MV_6180_AUDIO;
++ break;
++ }
++ return 0;
++
++}
++#endif
++
++#if defined(MV_INCLUDE_TDM)
++/*******************************************************************************
++* mvCtrlTdmSupport - Return if this controller has integrated TDM flash support
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if TDM is supported and MV_FALSE otherwise
++*
++*******************************************************************************/
++MV_U32 mvCtrlTdmSupport(MV_VOID)
++{
++ MV_U32 devId;
++
++ devId = mvCtrlModelGet();
++
++ switch(devId){
++ case MV_6281_DEV_ID:
++ return MV_6281_TDM;
++ break;
++ case MV_6192_DEV_ID:
++ return MV_6192_TDM;
++ break;
++ case MV_6190_DEV_ID:
++ return MV_6190_TDM;
++ break;
++ case MV_6180_DEV_ID:
++ return MV_6180_TDM;
++ break;
++ }
++ return 0;
++
++}
++#endif
++
++/*******************************************************************************
++* mvCtrlModelGet - Get Marvell controller device model (Id)
++*
++* DESCRIPTION:
++* This function returns 16bit describing the device model (ID) as defined
++* in PCI Device and Vendor ID configuration register offset 0x0.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 16bit desscribing Marvell controller ID
++*
++*******************************************************************************/
++MV_U16 mvCtrlModelGet(MV_VOID)
++{
++ MV_U32 devId;
++
++ devId = MV_REG_READ(CHIP_BOND_REG);
++ devId &= PCKG_OPT_MASK;
++
++ switch(devId){
++ case 2:
++ return MV_6281_DEV_ID;
++ break;
++ case 1:
++ if (((MV_REG_READ(PEX_CFG_DIRECT_ACCESS(0,PEX_DEVICE_AND_VENDOR_ID))& 0xffff0000) >> 16)
++ == MV_6190_DEV_ID)
++ return MV_6190_DEV_ID;
++ else
++ return MV_6192_DEV_ID;
++ break;
++ case 0:
++ return MV_6180_DEV_ID;
++ break;
++ }
++
++ return 0;
++}
++/*******************************************************************************
++* mvCtrlRevGet - Get Marvell controller device revision number
++*
++* DESCRIPTION:
++* This function returns 8bit describing the device revision as defined
++* in PCI Express Class Code and Revision ID Register.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 8bit desscribing Marvell controller revision number
++*
++*******************************************************************************/
++MV_U8 mvCtrlRevGet(MV_VOID)
++{
++ MV_U8 revNum;
++#if defined(MV_INCLUDE_CLK_PWR_CNTRL)
++ /* Check pex power state */
++ MV_U32 pexPower;
++ pexPower = mvCtrlPwrClckGet(PEX_UNIT_ID,0);
++ if (pexPower == MV_FALSE)
++ mvCtrlPwrClckSet(PEX_UNIT_ID, 0, MV_TRUE);
++#endif
++ revNum = (MV_U8)MV_REG_READ(PEX_CFG_DIRECT_ACCESS(0,PCI_CLASS_CODE_AND_REVISION_ID));
++#if defined(MV_INCLUDE_CLK_PWR_CNTRL)
++ /* Return to power off state */
++ if (pexPower == MV_FALSE)
++ mvCtrlPwrClckSet(PEX_UNIT_ID, 0, MV_FALSE);
++#endif
++ return ((revNum & PCCRIR_REVID_MASK) >> PCCRIR_REVID_OFFS);
++}
++
++/*******************************************************************************
++* mvCtrlNameGet - Get Marvell controller name
++*
++* DESCRIPTION:
++* This function returns a string describing the device model and revision.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* pNameBuff - Buffer to contain device name string. Minimum size 30 chars.
++*
++* RETURN:
++*
++* MV_ERROR if informantion can not be read.
++*******************************************************************************/
++MV_STATUS mvCtrlNameGet(char *pNameBuff)
++{
++ mvOsSPrintf (pNameBuff, "%s%x Rev %d", SOC_NAME_PREFIX,
++ mvCtrlModelGet(), mvCtrlRevGet());
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCtrlModelRevGet - Get Controller Model (Device ID) and Revision
++*
++* DESCRIPTION:
++* This function returns 32bit value describing both Device ID and Revision
++* as defined in PCI Express Device and Vendor ID Register and device revision
++* as defined in PCI Express Class Code and Revision ID Register.
++
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit describing both controller device ID and revision number
++*
++*******************************************************************************/
++MV_U32 mvCtrlModelRevGet(MV_VOID)
++{
++ return ((mvCtrlModelGet() << 16) | mvCtrlRevGet());
++}
++
++/*******************************************************************************
++* mvCtrlModelRevNameGet - Get Marvell controller name
++*
++* DESCRIPTION:
++* This function returns a string describing the device model and revision.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* pNameBuff - Buffer to contain device name string. Minimum size 30 chars.
++*
++* RETURN:
++*
++* MV_ERROR if informantion can not be read.
++*******************************************************************************/
++
++MV_STATUS mvCtrlModelRevNameGet(char *pNameBuff)
++{
++
++ switch (mvCtrlModelRevGet())
++ {
++ case MV_6281_A0_ID:
++ mvOsSPrintf (pNameBuff, "%s",MV_6281_A0_NAME);
++ break;
++ case MV_6192_A0_ID:
++ mvOsSPrintf (pNameBuff, "%s",MV_6192_A0_NAME);
++ break;
++ case MV_6180_A0_ID:
++ mvOsSPrintf (pNameBuff, "%s",MV_6180_A0_NAME);
++ break;
++ case MV_6190_A0_ID:
++ mvOsSPrintf (pNameBuff, "%s",MV_6190_A0_NAME);
++ break;
++ case MV_6281_A1_ID:
++ mvOsSPrintf (pNameBuff, "%s",MV_6281_A1_NAME);
++ break;
++ case MV_6192_A1_ID:
++ mvOsSPrintf (pNameBuff, "%s",MV_6192_A1_NAME);
++ break;
++ case MV_6180_A1_ID:
++ mvOsSPrintf (pNameBuff, "%s",MV_6180_A1_NAME);
++ break;
++ case MV_6190_A1_ID:
++ mvOsSPrintf (pNameBuff, "%s",MV_6190_A1_NAME);
++ break;
++ default:
++ mvCtrlNameGet(pNameBuff);
++ break;
++ }
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* ctrlWinOverlapTest - Test address windows for overlaping.
++*
++* DESCRIPTION:
++* This function checks the given two address windows for overlaping.
++*
++* INPUT:
++* pAddrWin1 - Address window 1.
++* pAddrWin2 - Address window 2.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++* MV_TRUE if address window overlaps, MV_FALSE otherwise.
++*******************************************************************************/
++MV_STATUS ctrlWinOverlapTest(MV_ADDR_WIN *pAddrWin1, MV_ADDR_WIN *pAddrWin2)
++{
++ MV_U32 winBase1, winBase2;
++ MV_U32 winTop1, winTop2;
++
++ /* check if we have overflow than 4G*/
++ if (((0xffffffff - pAddrWin1->baseLow) < pAddrWin1->size-1)||
++ ((0xffffffff - pAddrWin2->baseLow) < pAddrWin2->size-1))
++ {
++ return MV_TRUE;
++ }
++
++ winBase1 = pAddrWin1->baseLow;
++ winBase2 = pAddrWin2->baseLow;
++ winTop1 = winBase1 + pAddrWin1->size-1;
++ winTop2 = winBase2 + pAddrWin2->size-1;
++
++
++ if (((winBase1 <= winTop2 ) && ( winTop2 <= winTop1)) ||
++ ((winBase1 <= winBase2) && (winBase2 <= winTop1)))
++ {
++ return MV_TRUE;
++ }
++ else
++ {
++ return MV_FALSE;
++ }
++}
++
++/*******************************************************************************
++* ctrlWinWithinWinTest - Test address windows for overlaping.
++*
++* DESCRIPTION:
++* This function checks the given win1 boundries is within
++* win2 boundries.
++*
++* INPUT:
++* pAddrWin1 - Address window 1.
++* pAddrWin2 - Address window 2.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++* MV_TRUE if found win1 inside win2, MV_FALSE otherwise.
++*******************************************************************************/
++MV_STATUS ctrlWinWithinWinTest(MV_ADDR_WIN *pAddrWin1, MV_ADDR_WIN *pAddrWin2)
++{
++ MV_U32 winBase1, winBase2;
++ MV_U32 winTop1, winTop2;
++
++ winBase1 = pAddrWin1->baseLow;
++ winBase2 = pAddrWin2->baseLow;
++ winTop1 = winBase1 + pAddrWin1->size -1;
++ winTop2 = winBase2 + pAddrWin2->size -1;
++
++ if (((winBase1 >= winBase2 ) && ( winBase1 <= winTop2)) ||
++ ((winTop1 >= winBase2) && (winTop1 <= winTop2)))
++ {
++ return MV_TRUE;
++ }
++ else
++ {
++ return MV_FALSE;
++ }
++}
++
++static const char* cntrlName[] = TARGETS_NAME_ARRAY;
++
++/*******************************************************************************
++* mvCtrlTargetNameGet - Get Marvell controller target name
++*
++* DESCRIPTION:
++* This function convert the trget enumeration to string.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Target name (const MV_8 *)
++*******************************************************************************/
++const MV_8* mvCtrlTargetNameGet( MV_TARGET target )
++{
++
++ if (target >= MAX_TARGETS)
++ {
++ return "target unknown";
++ }
++
++ return cntrlName[target];
++}
++
++/*******************************************************************************
++* mvCtrlAddrDecShow - Print the Controller units address decode map.
++*
++* DESCRIPTION:
++* This function the Controller units address decode map.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvCtrlAddrDecShow(MV_VOID)
++{
++ mvCpuIfAddDecShow();
++ mvAhbToMbusAddDecShow();
++#if defined(MV_INCLUDE_PEX)
++ mvPexAddrDecShow();
++#endif
++#if defined(MV_INCLUDE_USB)
++ mvUsbAddrDecShow();
++#endif
++#if defined(MV_INCLUDE_GIG_ETH)
++ mvEthAddrDecShow();
++#endif
++#if defined(MV_INCLUDE_XOR)
++ mvXorAddrDecShow();
++#endif
++#if defined(MV_INCLUDE_SATA)
++ mvSataAddrDecShow();
++#endif
++#if defined(MV_INCLUDE_AUDIO)
++ mvAudioAddrDecShow();
++#endif
++#if defined(MV_INCLUDE_TS)
++ mvTsuAddrDecShow();
++#endif
++}
++
++/*******************************************************************************
++* ctrlSizeToReg - Extract size value for register assignment.
++*
++* DESCRIPTION:
++* Address decode size parameter must be programed from LSB to MSB as
++* sequence of 1's followed by sequence of 0's. The number of 1's
++* specifies the size of the window in 64 KB granularity (e.g. a
++* value of 0x00ff specifies 256x64k = 16 MB).
++* This function extract the size value from the size parameter according
++* to given aligment paramter. For example for size 0x1000000 (16MB) and
++* aligment 0x10000 (64KB) the function will return 0x00FF.
++*
++* INPUT:
++* size - Size.
++* alignment - Size alignment. Note that alignment must be power of 2!
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit describing size register value correspond to size parameter.
++* If value is '-1' size parameter or aligment are invalid.
++*******************************************************************************/
++MV_U32 ctrlSizeToReg(MV_U32 size, MV_U32 alignment)
++{
++ MV_U32 retVal;
++
++ /* Check size parameter alignment */
++ if ((0 == size) || (MV_IS_NOT_ALIGN(size, alignment)))
++ {
++ DB(mvOsPrintf("ctrlSizeToReg: ERR. Size is zero or not aligned.\n"));
++ return -1;
++ }
++
++ /* Take out the "alignment" portion out of the size parameter */
++ alignment--; /* Now the alignmet is a sequance of '1' (e.g. 0xffff) */
++ /* and size is 0x1000000 (16MB) for example */
++ while(alignment & 1) /* Check that alignmet LSB is set */
++ {
++ size = (size >> 1); /* If LSB is set, move 'size' one bit to right */
++ alignment = (alignment >> 1);
++ }
++
++ /* If after the alignment first '0' was met we still have '1' in */
++ /* it then aligment is invalid (not power of 2) */
++ if (alignment)
++ {
++ DB(mvOsPrintf("ctrlSizeToReg: ERR. Alignment parameter 0x%x invalid.\n",
++ (MV_U32)alignment));
++ return -1;
++ }
++
++ /* Now the size is shifted right according to aligment: 0x0100 */
++ size--; /* Now the size is a sequance of '1': 0x00ff */
++
++ retVal = size ;
++
++ /* Check that LSB to MSB is sequence of 1's followed by sequence of 0's */
++ while(size & 1) /* Check that LSB is set */
++ {
++ size = (size >> 1); /* If LSB is set, move one bit to the right */
++ }
++
++ if (size) /* Sequance of 1's is over. Check that we have no other 1's */
++ {
++ DB(mvOsPrintf("ctrlSizeToReg: ERR. Size parameter 0x%x invalid.\n",
++ size));
++ return -1;
++ }
++
++ return retVal;
++
++}
++
++/*******************************************************************************
++* ctrlRegToSize - Extract size value from register value.
++*
++* DESCRIPTION:
++* This function extract a size value from the register size parameter
++* according to given aligment paramter. For example for register size
++* value 0xff and aligment 0x10000 the function will return 0x01000000.
++*
++* INPUT:
++* regSize - Size as in register format. See ctrlSizeToReg.
++* alignment - Size alignment. Note that alignment must be power of 2!
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit describing size.
++* If value is '-1' size parameter or aligment are invalid.
++*******************************************************************************/
++MV_U32 ctrlRegToSize(MV_U32 regSize, MV_U32 alignment)
++{
++ MV_U32 temp;
++
++ /* Check that LSB to MSB is sequence of 1's followed by sequence of 0's */
++ temp = regSize; /* Now the size is a sequance of '1': 0x00ff */
++
++ while(temp & 1) /* Check that LSB is set */
++ {
++ temp = (temp >> 1); /* If LSB is set, move one bit to the right */
++ }
++
++ if (temp) /* Sequance of 1's is over. Check that we have no other 1's */
++ {
++ DB(mvOsPrintf("ctrlRegToSize: ERR. Size parameter 0x%x invalid.\n",
++ regSize));
++ return -1;
++ }
++
++
++ /* Check that aligment is a power of two */
++ temp = alignment - 1;/* Now the alignmet is a sequance of '1' (0xffff) */
++
++ while(temp & 1) /* Check that alignmet LSB is set */
++ {
++ temp = (temp >> 1); /* If LSB is set, move 'size' one bit to right */
++ }
++
++ /* If after the 'temp' first '0' was met we still have '1' in 'temp' */
++ /* then 'temp' is invalid (not power of 2) */
++ if (temp)
++ {
++ DB(mvOsPrintf("ctrlSizeToReg: ERR. Alignment parameter 0x%x invalid.\n",
++ alignment));
++ return -1;
++ }
++
++ regSize++; /* Now the size is 0x0100 */
++
++ /* Add in the "alignment" portion to the register size parameter */
++ alignment--; /* Now the alignmet is a sequance of '1' (e.g. 0xffff) */
++
++ while(alignment & 1) /* Check that alignmet LSB is set */
++ {
++ regSize = (regSize << 1); /* LSB is set, move 'size' one bit left */
++ alignment = (alignment >> 1);
++ }
++
++ return regSize;
++}
++
++
++/*******************************************************************************
++* ctrlSizeRegRoundUp - Round up given size
++*
++* DESCRIPTION:
++* This function round up a given size to a size that fits the
++* restrictions of size format given an aligment parameter.
++* to given aligment paramter. For example for size parameter 0xa1000 and
++* aligment 0x1000 the function will return 0xFF000.
++*
++* INPUT:
++* size - Size.
++* alignment - Size alignment. Note that alignment must be power of 2!
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit describing size value correspond to size in register.
++*******************************************************************************/
++MV_U32 ctrlSizeRegRoundUp(MV_U32 size, MV_U32 alignment)
++{
++ MV_U32 msbBit = 0;
++ MV_U32 retSize;
++
++ /* Check if size parameter is already comply with restriction */
++ if (!(-1 == ctrlSizeToReg(size, alignment)))
++ {
++ return size;
++ }
++
++ while(size)
++ {
++ size = (size >> 1);
++ msbBit++;
++ }
++
++ retSize = (1 << msbBit);
++
++ if (retSize < alignment)
++ {
++ return alignment;
++ }
++ else
++ {
++ return retSize;
++ }
++}
++/*******************************************************************************
++* mvCtrlSysRstLengthCounterGet - Return number of milliseconds the reset button
++* was pressed and clear counter
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN: number of milliseconds the reset button was pressed
++*******************************************************************************/
++MV_U32 mvCtrlSysRstLengthCounterGet(MV_VOID)
++{
++ static volatile MV_U32 Count = 0;
++
++ if(!Count) {
++ Count = (MV_REG_READ(SYSRST_LENGTH_COUNTER_REG) & SLCR_COUNT_MASK);
++ Count = (Count / (MV_BOARD_REFCLK_25MHZ / 1000));
++ /* clear counter for next boot */
++ MV_REG_BIT_SET(SYSRST_LENGTH_COUNTER_REG, SLCR_CLR_MASK);
++ }
++
++ DB(mvOsPrintf("mvCtrlSysRstLengthCounterGet: Reset button was pressed for %u milliseconds\n", Count));
++
++ return Count;
++}
++
++MV_BOOL mvCtrlIsBootFromSPI(MV_VOID)
++{
++ MV_U32 satr = 0;
++ satr = MV_REG_READ(MPP_SAMPLE_AT_RESET);
++ if(mvCtrlModelGet() == MV_6180_DEV_ID)
++ {
++ if (MSAR_BOOT_MODE_6180(satr) == MSAR_BOOT_SPI_WITH_BOOTROM_6180)
++ return MV_TRUE;
++ else
++ return MV_FALSE;
++ }
++ satr = satr & MSAR_BOOT_MODE_MASK;
++ if (satr == MSAR_BOOT_SPI_WITH_BOOTROM)
++ return MV_TRUE;
++ else
++ return MV_FALSE;
++}
++
++MV_BOOL mvCtrlIsBootFromSPIUseNAND(MV_VOID)
++{
++ MV_U32 satr = 0;
++ if(mvCtrlModelGet() == MV_6180_DEV_ID)
++ return MV_FALSE;
++ satr = MV_REG_READ(MPP_SAMPLE_AT_RESET);
++ satr = satr & MSAR_BOOT_MODE_MASK;
++
++ if (satr == MSAR_BOOT_SPI_USE_NAND_WITH_BOOTROM)
++ return MV_TRUE;
++ else
++ return MV_FALSE;
++}
++
++MV_BOOL mvCtrlIsBootFromNAND(MV_VOID)
++{
++ MV_U32 satr = 0;
++ satr = MV_REG_READ(MPP_SAMPLE_AT_RESET);
++ if(mvCtrlModelGet() == MV_6180_DEV_ID)
++ {
++ if (MSAR_BOOT_MODE_6180(satr) == MSAR_BOOT_NAND_WITH_BOOTROM_6180)
++ return MV_TRUE;
++ else
++ return MV_FALSE;
++ }
++ satr = satr & MSAR_BOOT_MODE_MASK;
++ if ((satr == MSAR_BOOT_NAND_WITH_BOOTROM))
++ return MV_TRUE;
++ else
++ return MV_FALSE;
++}
++
++#if defined(MV_INCLUDE_CLK_PWR_CNTRL)
++/*******************************************************************************
++* mvCtrlPwrSaveOn - Set Power save mode
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++*******************************************************************************/
++MV_VOID mvCtrlPwrSaveOn(MV_VOID)
++{
++ unsigned long old,temp;
++ /* Disable int */
++ __asm__ __volatile__("mrs %0, cpsr\n"
++ "orr %1, %0, #0xc0\n"
++ "msr cpsr_c, %1"
++ : "=r" (old), "=r" (temp)
++ :
++ : "memory");
++
++ /* Set SoC in power save */
++ MV_REG_BIT_SET(POWER_MNG_CTRL_REG, BIT11);
++ /* Wait for int */
++ __asm__ __volatile__("mcr p15, 0, r0, c7, c0, 4");
++
++ /* Enabled int */
++ __asm__ __volatile__("msr cpsr_c, %0"
++ :
++ : "r" (old)
++ : "memory");
++}
++
++
++
++/*******************************************************************************
++* mvCtrlPwrSaveOff - Go out of power save mode
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++*******************************************************************************/
++MV_VOID mvCtrlPwrSaveOff(MV_VOID)
++{
++ unsigned long old,temp;
++ /* Disable int */
++ __asm__ __volatile__("mrs %0, cpsr\n"
++ "orr %1, %0, #0xc0\n"
++ "msr cpsr_c, %1"
++ : "=r" (old), "=r" (temp)
++ :
++ : "memory");
++
++ /* Set SoC in power save */
++ MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, BIT11);
++ /* Wait for int */
++ __asm__ __volatile__("mcr p15, 0, r0, c7, c0, 4");
++
++ /* Enabled int */
++ __asm__ __volatile__("msr cpsr_c, %0"
++ :
++ : "r" (old)
++ : "memory");
++}
++
++/*******************************************************************************
++* mvCtrlPwrClckSet - Set Power State for specific Unit
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++*******************************************************************************/
++MV_VOID mvCtrlPwrClckSet(MV_UNIT_ID unitId, MV_U32 index, MV_BOOL enable)
++{
++ switch (unitId)
++ {
++#if defined(MV_INCLUDE_PEX)
++ case PEX_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_PEXSTOPCLOCK_MASK);
++ }
++ else
++ {
++ MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_PEXSTOPCLOCK_MASK);
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_GIG_ETH)
++ case ETH_GIG_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_GESTOPCLOCK_MASK(index));
++ }
++ else
++ {
++ MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_GESTOPCLOCK_MASK(index));
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_INTEG_SATA)
++ case SATA_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_SATASTOPCLOCK_MASK(index));
++ }
++ else
++ {
++ MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_SATASTOPCLOCK_MASK(index));
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_CESA)
++ case CESA_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_SESTOPCLOCK_MASK);
++ }
++ else
++ {
++ MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_SESTOPCLOCK_MASK);
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_USB)
++ case USB_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_USBSTOPCLOCK_MASK);
++ }
++ else
++ {
++ MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_USBSTOPCLOCK_MASK);
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_AUDIO)
++ case AUDIO_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_AUDIOSTOPCLOCK_MASK);
++ }
++ else
++ {
++ MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_AUDIOSTOPCLOCK_MASK);
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_TS)
++ case TS_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_TSSTOPCLOCK_MASK);
++ }
++ else
++ {
++ MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_TSSTOPCLOCK_MASK);
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_SDIO)
++ case SDIO_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_SDIOSTOPCLOCK_MASK);
++ }
++ else
++ {
++ MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_SDIOSTOPCLOCK_MASK);
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_TDM)
++ case TDM_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_TDMSTOPCLOCK_MASK);
++ }
++ else
++ {
++ MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_TDMSTOPCLOCK_MASK);
++ }
++ break;
++#endif
++
++ default:
++
++ break;
++
++ }
++}
++
++/*******************************************************************************
++* mvCtrlPwrClckGet - Get Power State of specific Unit
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++******************************************************************************/
++MV_BOOL mvCtrlPwrClckGet(MV_UNIT_ID unitId, MV_U32 index)
++{
++ MV_U32 reg = MV_REG_READ(POWER_MNG_CTRL_REG);
++ MV_BOOL state = MV_TRUE;
++
++ switch (unitId)
++ {
++#if defined(MV_INCLUDE_PEX)
++ case PEX_UNIT_ID:
++ if ((reg & PMC_PEXSTOPCLOCK_MASK) == PMC_PEXSTOPCLOCK_STOP)
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++
++ break;
++#endif
++#if defined(MV_INCLUDE_GIG_ETH)
++ case ETH_GIG_UNIT_ID:
++ if ((reg & PMC_GESTOPCLOCK_MASK(index)) == PMC_GESTOPCLOCK_STOP(index))
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_SATA)
++ case SATA_UNIT_ID:
++ if ((reg & PMC_SATASTOPCLOCK_MASK(index)) == PMC_SATASTOPCLOCK_STOP(index))
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_CESA)
++ case CESA_UNIT_ID:
++ if ((reg & PMC_SESTOPCLOCK_MASK) == PMC_SESTOPCLOCK_STOP)
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_USB)
++ case USB_UNIT_ID:
++ if ((reg & PMC_USBSTOPCLOCK_MASK) == PMC_USBSTOPCLOCK_STOP)
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_AUDIO)
++ case AUDIO_UNIT_ID:
++ if ((reg & PMC_AUDIOSTOPCLOCK_MASK) == PMC_AUDIOSTOPCLOCK_STOP)
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_TS)
++ case TS_UNIT_ID:
++ if ((reg & PMC_TSSTOPCLOCK_MASK) == PMC_TSSTOPCLOCK_STOP)
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_SDIO)
++ case SDIO_UNIT_ID:
++ if ((reg & PMC_SDIOSTOPCLOCK_MASK)== PMC_SDIOSTOPCLOCK_STOP)
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_TDM)
++ case TDM_UNIT_ID:
++ if ((reg & PMC_TDMSTOPCLOCK_MASK) == PMC_TDMSTOPCLOCK_STOP)
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++
++ default:
++ state = MV_TRUE;
++ break;
++ }
++
++
++ return state;
++}
++/*******************************************************************************
++* mvCtrlPwrMemSet - Set Power State for memory on specific Unit
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++*******************************************************************************/
++MV_VOID mvCtrlPwrMemSet(MV_UNIT_ID unitId, MV_U32 index, MV_BOOL enable)
++{
++ switch (unitId)
++ {
++#if defined(MV_INCLUDE_PEX)
++ case PEX_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_PEXSTOPMEM_MASK);
++ }
++ else
++ {
++ MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_PEXSTOPMEM_MASK);
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_GIG_ETH)
++ case ETH_GIG_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_GESTOPMEM_MASK(index));
++ }
++ else
++ {
++ MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_GESTOPMEM_MASK(index));
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_INTEG_SATA)
++ case SATA_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_SATASTOPMEM_MASK(index));
++ }
++ else
++ {
++ MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_SATASTOPMEM_MASK(index));
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_CESA)
++ case CESA_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_SESTOPMEM_MASK);
++ }
++ else
++ {
++ MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_SESTOPMEM_MASK);
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_USB)
++ case USB_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_USBSTOPMEM_MASK);
++ }
++ else
++ {
++ MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_USBSTOPMEM_MASK);
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_AUDIO)
++ case AUDIO_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_AUDIOSTOPMEM_MASK);
++ }
++ else
++ {
++ MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_AUDIOSTOPMEM_MASK);
++ }
++ break;
++#endif
++#if defined(MV_INCLUDE_XOR)
++ case XOR_UNIT_ID:
++ if (enable == MV_FALSE)
++ {
++ MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_XORSTOPMEM_MASK(index));
++ }
++ else
++ {
++ MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_XORSTOPMEM_MASK(index));
++ }
++ break;
++#endif
++ default:
++
++ break;
++
++ }
++}
++
++/*******************************************************************************
++* mvCtrlPwrMemGet - Get Power State of memory on specific Unit
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++******************************************************************************/
++MV_BOOL mvCtrlPwrMemGet(MV_UNIT_ID unitId, MV_U32 index)
++{
++ MV_U32 reg = MV_REG_READ(POWER_MNG_MEM_CTRL_REG);
++ MV_BOOL state = MV_TRUE;
++
++ switch (unitId)
++ {
++#if defined(MV_INCLUDE_PEX)
++ case PEX_UNIT_ID:
++ if ((reg & PMC_PEXSTOPMEM_MASK) == PMC_PEXSTOPMEM_STOP)
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++
++ break;
++#endif
++#if defined(MV_INCLUDE_GIG_ETH)
++ case ETH_GIG_UNIT_ID:
++ if ((reg & PMC_GESTOPMEM_MASK(index)) == PMC_GESTOPMEM_STOP(index))
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_SATA)
++ case SATA_UNIT_ID:
++ if ((reg & PMC_SATASTOPMEM_MASK(index)) == PMC_SATASTOPMEM_STOP(index))
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_CESA)
++ case CESA_UNIT_ID:
++ if ((reg & PMC_SESTOPMEM_MASK) == PMC_SESTOPMEM_STOP)
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_USB)
++ case USB_UNIT_ID:
++ if ((reg & PMC_USBSTOPMEM_MASK) == PMC_USBSTOPMEM_STOP)
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_AUDIO)
++ case AUDIO_UNIT_ID:
++ if ((reg & PMC_AUDIOSTOPMEM_MASK) == PMC_AUDIOSTOPMEM_STOP)
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++#if defined(MV_INCLUDE_XOR)
++ case XOR_UNIT_ID:
++ if ((reg & PMC_XORSTOPMEM_MASK(index)) == PMC_XORSTOPMEM_STOP(index))
++ {
++ state = MV_FALSE;
++ }
++ else state = MV_TRUE;
++ break;
++#endif
++
++ default:
++ state = MV_TRUE;
++ break;
++ }
++
++
++ return state;
++}
++#else
++MV_VOID mvCtrlPwrClckSet(MV_UNIT_ID unitId, MV_U32 index, MV_BOOL enable) {return;}
++MV_BOOL mvCtrlPwrClckGet(MV_UNIT_ID unitId, MV_U32 index) {return MV_TRUE;}
++#endif /* #if defined(MV_INCLUDE_CLK_PWR_CNTRL) */
++
++
++/*******************************************************************************
++* mvMPPConfigToSPI - Change MPP[3:0] configuration to SPI mode
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++******************************************************************************/
++MV_VOID mvMPPConfigToSPI(MV_VOID)
++{
++ MV_U32 mppVal = 0;
++ MV_U32 bootVal = 0;
++
++ if(!mvCtrlIsBootFromSPIUseNAND())
++ return;
++ mppVal = 0x00002220; /* Set MPP [3:1] to SPI mode */
++ bootVal = MV_REG_READ(mvCtrlMppRegGet(0));
++ bootVal &= 0xffff000f;
++ mppVal |= bootVal;
++
++ MV_REG_WRITE(mvCtrlMppRegGet(0), mppVal);
++}
++
++
++/*******************************************************************************
++* mvMPPConfigToDefault - Change MPP[7:0] configuration to default configuration
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++******************************************************************************/
++MV_VOID mvMPPConfigToDefault(MV_VOID)
++{
++ MV_U32 mppVal = 0;
++ MV_U32 bootVal = 0;
++
++ if(!mvCtrlIsBootFromSPIUseNAND())
++ return;
++ mppVal = mvBoardMppGet(0);
++ bootVal = MV_REG_READ(mvCtrlMppRegGet(0));
++ mppVal &= ~0xffff000f;
++ bootVal &= 0xffff000f;
++ mppVal |= bootVal;
++
++ MV_REG_WRITE(mvCtrlMppRegGet(0), mppVal);
++}
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.h 2010-11-09 20:28:07.742495476 +0100
+@@ -0,0 +1,185 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvCtrlEnvLibh
++#define __INCmvCtrlEnvLibh
++
++/* includes */
++#include "mvSysHwConfig.h"
++#include "mvCommon.h"
++#include "mvTypes.h"
++#include "mvOs.h"
++#include "boardEnv/mvBoardEnvLib.h"
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++#include "ctrlEnv/mvCtrlEnvRegs.h"
++#include "ctrlEnv/mvCtrlEnvAddrDec.h"
++
++
++/* typedefs */
++
++/* This enumerator describes the possible HW cache coherency policies the */
++/* controllers supports. */
++typedef enum _mvCachePolicy
++{
++ NO_COHERENCY, /* No HW cache coherency support */
++ WT_COHERENCY, /* HW cache coherency supported in Write Through policy */
++ WB_COHERENCY /* HW cache coherency supported in Write Back policy */
++}MV_CACHE_POLICY;
++
++
++/* The swapping is referred to a 64-bit words (as this is the controller */
++/* internal data path width). This enumerator describes the possible */
++/* data swap types. Below is an example of the data 0x0011223344556677 */
++typedef enum _mvSwapType
++{
++ MV_BYTE_SWAP, /* Byte Swap 77 66 55 44 33 22 11 00 */
++ MV_NO_SWAP, /* No swapping 00 11 22 33 44 55 66 77 */
++ MV_BYTE_WORD_SWAP, /* Both byte and word swap 33 22 11 00 77 66 55 44 */
++ MV_WORD_SWAP, /* Word swap 44 55 66 77 00 11 22 33 */
++ SWAP_TYPE_MAX /* Delimiter for this enumerator */
++}MV_SWAP_TYPE;
++
++/* This structure describes access rights for Access protection windows */
++/* that can be found in IDMA, XOR, Ethernet and MPSC units. */
++/* Note that the permission enumerator coresponds to its register format. */
++/* For example, Read only premission is presented as "1" in register field. */
++typedef enum _mvAccessRights
++{
++ NO_ACCESS_ALLOWED = 0, /* No access allowed */
++ READ_ONLY = 1, /* Read only permission */
++ ACC_RESERVED = 2, /* Reserved access right */
++ FULL_ACCESS = 3, /* Read and Write permission */
++ MAX_ACC_RIGHTS
++}MV_ACCESS_RIGHTS;
++
++
++/* mcspLib.h API list */
++
++MV_STATUS mvCtrlEnvInit(MV_VOID);
++MV_U32 mvCtrlMppRegGet(MV_U32 mppGroup);
++
++#if defined(MV_INCLUDE_PEX)
++MV_U32 mvCtrlPexMaxIfGet(MV_VOID);
++#else
++#define mvCtrlPexMaxIfGet() (0)
++#endif
++
++#define mvCtrlPciIfMaxIfGet() (0)
++
++#if defined(MV_INCLUDE_GIG_ETH)
++MV_U32 mvCtrlEthMaxPortGet(MV_VOID);
++#endif
++#if defined(MV_INCLUDE_XOR)
++MV_U32 mvCtrlXorMaxChanGet(MV_VOID);
++#endif
++#if defined(MV_INCLUDE_USB)
++MV_U32 mvCtrlUsbMaxGet(MV_VOID);
++#endif
++#if defined(MV_INCLUDE_NAND)
++MV_U32 mvCtrlNandSupport(MV_VOID);
++#endif
++#if defined(MV_INCLUDE_SDIO)
++MV_U32 mvCtrlSdioSupport(MV_VOID);
++#endif
++#if defined(MV_INCLUDE_TS)
++MV_U32 mvCtrlTsSupport(MV_VOID);
++#endif
++#if defined(MV_INCLUDE_AUDIO)
++MV_U32 mvCtrlAudioSupport(MV_VOID);
++#endif
++#if defined(MV_INCLUDE_TDM)
++MV_U32 mvCtrlTdmSupport(MV_VOID);
++#endif
++
++MV_U16 mvCtrlModelGet(MV_VOID);
++MV_U8 mvCtrlRevGet(MV_VOID);
++MV_STATUS mvCtrlNameGet(char *pNameBuff);
++MV_U32 mvCtrlModelRevGet(MV_VOID);
++MV_STATUS mvCtrlModelRevNameGet(char *pNameBuff);
++MV_VOID mvCtrlAddrDecShow(MV_VOID);
++const MV_8* mvCtrlTargetNameGet(MV_TARGET target);
++MV_U32 ctrlSizeToReg(MV_U32 size, MV_U32 alignment);
++MV_U32 ctrlRegToSize(MV_U32 regSize, MV_U32 alignment);
++MV_U32 ctrlSizeRegRoundUp(MV_U32 size, MV_U32 alignment);
++MV_U32 mvCtrlSysRstLengthCounterGet(MV_VOID);
++MV_STATUS ctrlWinOverlapTest(MV_ADDR_WIN *pAddrWin1, MV_ADDR_WIN *pAddrWin2);
++MV_STATUS ctrlWinWithinWinTest(MV_ADDR_WIN *pAddrWin1, MV_ADDR_WIN *pAddrWin2);
++
++MV_VOID mvCtrlPwrClckSet(MV_UNIT_ID unitId, MV_U32 index, MV_BOOL enable);
++MV_BOOL mvCtrlPwrClckGet(MV_UNIT_ID unitId, MV_U32 index);
++MV_VOID mvCtrlPwrMemSet(MV_UNIT_ID unitId, MV_U32 index, MV_BOOL enable);
++MV_BOOL mvCtrlIsBootFromSPI(MV_VOID);
++MV_BOOL mvCtrlIsBootFromSPIUseNAND(MV_VOID);
++MV_BOOL mvCtrlIsBootFromNAND(MV_VOID);
++#if defined(MV_INCLUDE_CLK_PWR_CNTRL)
++MV_VOID mvCtrlPwrSaveOn(MV_VOID);
++MV_VOID mvCtrlPwrSaveOff(MV_VOID);
++#endif
++MV_BOOL mvCtrlPwrMemGet(MV_UNIT_ID unitId, MV_U32 index);
++MV_VOID mvMPPConfigToSPI(MV_VOID);
++MV_VOID mvMPPConfigToDefault(MV_VOID);
++
++
++#endif /* __INCmvCtrlEnvLibh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvRegs.h 2010-11-09 20:28:07.772495664 +0100
+@@ -0,0 +1,419 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvCtrlEnvRegsh
++#define __INCmvCtrlEnvRegsh
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/* CV Support */
++#define PEX0_MEM0 PEX0_MEM
++#define PCI0_MEM0 PEX0_MEM
++
++/* Controller revision info */
++#define PCI_CLASS_CODE_AND_REVISION_ID 0x008
++#define PCCRIR_REVID_OFFS 0 /* Revision ID */
++#define PCCRIR_REVID_MASK (0xff << PCCRIR_REVID_OFFS)
++
++/* Controler environment registers offsets */
++
++/* Power Managment Control */
++#define POWER_MNG_MEM_CTRL_REG 0x20118
++
++#define PMC_GESTOPMEM_OFFS(port) ((port)? 13 : 0)
++#define PMC_GESTOPMEM_MASK(port) (1 << PMC_GESTOPMEM_OFFS(port))
++#define PMC_GESTOPMEM_EN(port) (0 << PMC_GESTOPMEM_OFFS(port))
++#define PMC_GESTOPMEM_STOP(port) (1 << PMC_GESTOPMEM_OFFS(port))
++
++#define PMC_PEXSTOPMEM_OFFS 1
++#define PMC_PEXSTOPMEM_MASK (1 << PMC_PEXSTOPMEM_OFFS)
++#define PMC_PEXSTOPMEM_EN (0 << PMC_PEXSTOPMEM_OFFS)
++#define PMC_PEXSTOPMEM_STOP (1 << PMC_PEXSTOPMEM_OFFS)
++
++#define PMC_USBSTOPMEM_OFFS 2
++#define PMC_USBSTOPMEM_MASK (1 << PMC_USBSTOPMEM_OFFS)
++#define PMC_USBSTOPMEM_EN (0 << PMC_USBSTOPMEM_OFFS)
++#define PMC_USBSTOPMEM_STOP (1 << PMC_USBSTOPMEM_OFFS)
++
++#define PMC_DUNITSTOPMEM_OFFS 3
++#define PMC_DUNITSTOPMEM_MASK (1 << PMC_DUNITSTOPMEM_OFFS)
++#define PMC_DUNITSTOPMEM_EN (0 << PMC_DUNITSTOPMEM_OFFS)
++#define PMC_DUNITSTOPMEM_STOP (1 << PMC_DUNITSTOPMEM_OFFS)
++
++#define PMC_RUNITSTOPMEM_OFFS 4
++#define PMC_RUNITSTOPMEM_MASK (1 << PMC_RUNITSTOPMEM_OFFS)
++#define PMC_RUNITSTOPMEM_EN (0 << PMC_RUNITSTOPMEM_OFFS)
++#define PMC_RUNITSTOPMEM_STOP (1 << PMC_RUNITSTOPMEM_OFFS)
++
++#define PMC_XORSTOPMEM_OFFS(port) (5+(port*2))
++#define PMC_XORSTOPMEM_MASK(port) (1 << PMC_XORSTOPMEM_OFFS(port))
++#define PMC_XORSTOPMEM_EN(port) (0 << PMC_XORSTOPMEM_OFFS(port))
++#define PMC_XORSTOPMEM_STOP(port) (1 << PMC_XORSTOPMEM_OFFS(port))
++
++#define PMC_SATASTOPMEM_OFFS(port) (6+(port*5))
++#define PMC_SATASTOPMEM_MASK(port) (1 << PMC_SATASTOPMEM_OFFS(port))
++#define PMC_SATASTOPMEM_EN(port) (0 << PMC_SATASTOPMEM_OFFS(port))
++#define PMC_SATASTOPMEM_STOP(port) (1 << PMC_SATASTOPMEM_OFFS(port))
++
++#define PMC_SESTOPMEM_OFFS 8
++#define PMC_SESTOPMEM_MASK (1 << PMC_SESTOPMEM_OFFS)
++#define PMC_SESTOPMEM_EN (0 << PMC_SESTOPMEM_OFFS)
++#define PMC_SESTOPMEM_STOP (1 << PMC_SESTOPMEM_OFFS)
++
++#define PMC_AUDIOSTOPMEM_OFFS 9
++#define PMC_AUDIOSTOPMEM_MASK (1 << PMC_AUDIOSTOPMEM_OFFS)
++#define PMC_AUDIOSTOPMEM_EN (0 << PMC_AUDIOSTOPMEM_OFFS)
++#define PMC_AUDIOSTOPMEM_STOP (1 << PMC_AUDIOSTOPMEM_OFFS)
++
++#define POWER_MNG_CTRL_REG 0x2011C
++
++#define PMC_GESTOPCLOCK_OFFS(port) ((port)? 19 : 0)
++#define PMC_GESTOPCLOCK_MASK(port) (1 << PMC_GESTOPCLOCK_OFFS(port))
++#define PMC_GESTOPCLOCK_EN(port) (1 << PMC_GESTOPCLOCK_OFFS(port))
++#define PMC_GESTOPCLOCK_STOP(port) (0 << PMC_GESTOPCLOCK_OFFS(port))
++
++#define PMC_PEXPHYSTOPCLOCK_OFFS 1
++#define PMC_PEXPHYSTOPCLOCK_MASK (1 << PMC_PEXPHYSTOPCLOCK_OFFS)
++#define PMC_PEXPHYSTOPCLOCK_EN (1 << PMC_PEXPHYSTOPCLOCK_OFFS)
++#define PMC_PEXPHYSTOPCLOCK_STOP (0 << PMC_PEXPHYSTOPCLOCK_OFFS)
++
++#define PMC_PEXSTOPCLOCK_OFFS 2
++#define PMC_PEXSTOPCLOCK_MASK (1 << PMC_PEXSTOPCLOCK_OFFS)
++#define PMC_PEXSTOPCLOCK_EN (1 << PMC_PEXSTOPCLOCK_OFFS)
++#define PMC_PEXSTOPCLOCK_STOP (0 << PMC_PEXSTOPCLOCK_OFFS)
++
++#define PMC_USBSTOPCLOCK_OFFS 3
++#define PMC_USBSTOPCLOCK_MASK (1 << PMC_USBSTOPCLOCK_OFFS)
++#define PMC_USBSTOPCLOCK_EN (1 << PMC_USBSTOPCLOCK_OFFS)
++#define PMC_USBSTOPCLOCK_STOP (0 << PMC_USBSTOPCLOCK_OFFS)
++
++#define PMC_SDIOSTOPCLOCK_OFFS 4
++#define PMC_SDIOSTOPCLOCK_MASK (1 << PMC_SDIOSTOPCLOCK_OFFS)
++#define PMC_SDIOSTOPCLOCK_EN (1 << PMC_SDIOSTOPCLOCK_OFFS)
++#define PMC_SDIOSTOPCLOCK_STOP (0 << PMC_SDIOSTOPCLOCK_OFFS)
++
++#define PMC_TSSTOPCLOCK_OFFS 5
++#define PMC_TSSTOPCLOCK_MASK (1 << PMC_TSSTOPCLOCK_OFFS)
++#define PMC_TSSTOPCLOCK_EN (1 << PMC_TSSTOPCLOCK_OFFS)
++#define PMC_TSSTOPCLOCK_STOP (0 << PMC_TSSTOPCLOCK_OFFS)
++
++#define PMC_AUDIOSTOPCLOCK_OFFS 9
++#define PMC_AUDIOSTOPCLOCK_MASK (1 << PMC_AUDIOSTOPCLOCK_OFFS)
++#define PMC_AUDIOSTOPCLOCK_EN (1 << PMC_AUDIOSTOPCLOCK_OFFS)
++#define PMC_AUDIOSTOPCLOCK_STOP (0 << PMC_AUDIOSTOPCLOCK_OFFS)
++
++#define PMC_POWERSAVE_OFFS 11
++#define PMC_POWERSAVE_MASK (1 << PMC_POWERSAVE_OFFS)
++#define PMC_POWERSAVE_EN (1 << PMC_POWERSAVE_OFFS)
++#define PMC_POWERSAVE_STOP (0 << PMC_POWERSAVE_OFFS)
++
++
++
++
++#define PMC_SATASTOPCLOCK_OFFS(port) (14+(port))
++#define PMC_SATASTOPCLOCK_MASK(port) (1 << PMC_SATASTOPCLOCK_OFFS(port))
++#define PMC_SATASTOPCLOCK_EN(port) (1 << PMC_SATASTOPCLOCK_OFFS(port))
++#define PMC_SATASTOPCLOCK_STOP(port) (0 << PMC_SATASTOPCLOCK_OFFS(port))
++
++#define PMC_SESTOPCLOCK_OFFS 17
++#define PMC_SESTOPCLOCK_MASK (1 << PMC_SESTOPCLOCK_OFFS)
++#define PMC_SESTOPCLOCK_EN (1 << PMC_SESTOPCLOCK_OFFS)
++#define PMC_SESTOPCLOCK_STOP (0 << PMC_SESTOPCLOCK_OFFS)
++
++#define PMC_TDMSTOPCLOCK_OFFS 20
++#define PMC_TDMSTOPCLOCK_MASK (1 << PMC_TDMSTOPCLOCK_OFFS)
++#define PMC_TDMSTOPCLOCK_EN (1 << PMC_TDMSTOPCLOCK_OFFS)
++#define PMC_TDMSTOPCLOCK_STOP (0 << PMC_TDMSTOPCLOCK_OFFS)
++
++
++/* Controler environment registers offsets */
++#define MPP_CONTROL_REG0 0x10000
++#define MPP_CONTROL_REG1 0x10004
++#define MPP_CONTROL_REG2 0x10008
++#define MPP_CONTROL_REG3 0x1000C
++#define MPP_CONTROL_REG4 0x10010
++#define MPP_CONTROL_REG5 0x10014
++#define MPP_CONTROL_REG6 0x10018
++#define MPP_SAMPLE_AT_RESET 0x10030
++#define CHIP_BOND_REG 0x10034
++#define SYSRST_LENGTH_COUNTER_REG 0x10050
++#define SLCR_COUNT_OFFS 0
++#define SLCR_COUNT_MASK (0x1FFFFFFF << SLCR_COUNT_OFFS)
++#define SLCR_CLR_OFFS 31
++#define SLCR_CLR_MASK (1 << SLCR_CLR_OFFS)
++#define PCKG_OPT_MASK 0x3
++#define MPP_OUTPUT_DRIVE_REG 0x100E0
++#define MPP_RGMII0_OUTPUT_DRIVE_OFFS 7
++#define MPP_3_3_RGMII0_OUTPUT_DRIVE (0x0 << MPP_RGMII0_OUTPUT_DRIVE_OFFS)
++#define MPP_1_8_RGMII0_OUTPUT_DRIVE (0x1 << MPP_RGMII0_OUTPUT_DRIVE_OFFS)
++#define MPP_RGMII1_OUTPUT_DRIVE_OFFS 15
++#define MPP_3_3_RGMII1_OUTPUT_DRIVE (0x0 << MPP_RGMII1_OUTPUT_DRIVE_OFFS)
++#define MPP_1_8_RGMII1_OUTPUT_DRIVE (0x1 << MPP_RGMII1_OUTPUT_DRIVE_OFFS)
++
++#define MSAR_BOOT_MODE_OFFS 12
++#define MSAR_BOOT_MODE_MASK (0x7 << MSAR_BOOT_MODE_OFFS)
++#define MSAR_BOOT_NAND_WITH_BOOTROM (0x5 << MSAR_BOOT_MODE_OFFS)
++#define MSAR_BOOT_SPI_WITH_BOOTROM (0x4 << MSAR_BOOT_MODE_OFFS)
++#define MSAR_BOOT_SPI_USE_NAND_WITH_BOOTROM (0x2 << MSAR_BOOT_MODE_OFFS)
++
++#define MSAR_BOOT_MODE_6180(X) (((X & 0x3000) >> 12) | \
++ ((X & 0x2) << 1))
++#define MSAR_BOOT_SPI_WITH_BOOTROM_6180 0x1
++#define MSAR_BOOT_NAND_WITH_BOOTROM_6180 0x5
++
++#define MSAR_TCLCK_OFFS 21
++#define MSAR_TCLCK_MASK (0x1 << MSAR_TCLCK_OFFS)
++#define MSAR_TCLCK_166 (0x1 << MSAR_TCLCK_OFFS)
++#define MSAR_TCLCK_200 (0x0 << MSAR_TCLCK_OFFS)
++
++
++#define MSAR_CPUCLCK_EXTRACT(X) (((X & 0x2) >> 1) | ((X & 0x400000) >> 21) | \
++ ((X & 0x18) >> 1))
++
++#define MSAR_CPUCLCK_OFFS_6180 2
++#define MSAR_CPUCLCK_MASK_6180 (0x7 << MSAR_CPUCLCK_OFFS_6180)
++
++#define MSAR_DDRCLCK_RTIO_OFFS 5
++#define MSAR_DDRCLCK_RTIO_MASK (0xF << MSAR_DDRCLCK_RTIO_OFFS)
++
++#define MSAR_L2CLCK_EXTRACT(X) (((X & 0x600) >> 9) | ((X & 0x80000) >> 17))
++
++#ifndef MV_ASMLANGUAGE
++/* CPU clock for 6281,6192 0->Resereved */
++#define MV_CPU_CLCK_TBL { 0, 0, 0, 0, \
++ 600000000, 0, 800000000, 1000000000, \
++ 0, 1200000000, 0, 0, \
++ 1500000000, 0, 0, 0}
++
++/* DDR clock RATIO for 6281,6192 {0,0}->Reserved */
++#define MV_DDR_CLCK_RTIO_TBL {\
++ {0, 0}, {0, 0}, {2, 1}, {0, 0}, \
++ {3, 1}, {0, 0}, {4, 1}, {9, 2}, \
++ {5, 1}, {6, 1}, {0, 0}, {0, 0}, \
++ {0, 0}, {0, 0}, {0, 0}, {0, 0} \
++}
++
++/* L2 clock RATIO for 6281,6192 {1,1}->Reserved */
++#define MV_L2_CLCK_RTIO_TBL {\
++ {0, 0}, {2, 1}, {0, 0}, {3, 1}, \
++ {0, 0}, {0, 0}, {0, 0}, {0, 0} \
++}
++
++/* 6180 have different clk reset sampling */
++/* ARM CPU, DDR, L2 clock for 6180 {0,0,0}->Reserved */
++#define MV_CPU6180_DDR_L2_CLCK_TBL { \
++ {0, 0, 0 },\
++ {0, 0, 0 },\
++ {0, 0, 0 },\
++ {0, 0, 0 },\
++ {0, 0, 0 },\
++ {600000000, 200000000, 300000000 },\
++ {800000000, 200000000, 400000000 },\
++ {0, 0, 0 }\
++}
++
++
++
++/* These macros help units to identify a target Mbus Arbiter group */
++#define MV_TARGET_IS_DRAM(target) \
++ ((target >= SDRAM_CS0) && (target <= SDRAM_CS3))
++
++#define MV_TARGET_IS_PEX0(target) \
++ ((target >= PEX0_MEM) && (target <= PEX0_IO))
++
++#define MV_TARGET_IS_PEX1(target) 0
++
++#define MV_TARGET_IS_PEX(target) (MV_TARGET_IS_PEX0(target) || MV_TARGET_IS_PEX1(target))
++
++#define MV_TARGET_IS_DEVICE(target) \
++ ((target >= DEVICE_CS0) && (target <= DEVICE_CS3))
++
++#define MV_PCI_DRAM_BAR_TO_DRAM_TARGET(bar) 0
++
++#define MV_TARGET_IS_AS_BOOT(target) ((target) == (sampleAtResetTargetArray[ \
++ (mvCtrlModelGet() == MV_6180_DEV_ID)? MSAR_BOOT_MODE_6180 \
++ (MV_REG_READ(MPP_SAMPLE_AT_RESET)):((MV_REG_READ(MPP_SAMPLE_AT_RESET)\
++ & MSAR_BOOT_MODE_MASK) >> MSAR_BOOT_MODE_OFFS)]))
++
++
++#define MV_CHANGE_BOOT_CS(target) (((target) == DEV_BOOCS)?\
++ sampleAtResetTargetArray[(mvCtrlModelGet() == MV_6180_DEV_ID)? \
++ MSAR_BOOT_MODE_6180(MV_REG_READ(MPP_SAMPLE_AT_RESET)): \
++ ((MV_REG_READ(MPP_SAMPLE_AT_RESET) & MSAR_BOOT_MODE_MASK)\
++ >> MSAR_BOOT_MODE_OFFS)]:(target))
++
++#define TCLK_TO_COUNTER_RATIO 1 /* counters running in Tclk */
++
++#define BOOT_TARGETS_NAME_ARRAY { \
++ TBL_TERM, \
++ TBL_TERM, \
++ BOOT_ROM_CS, \
++ TBL_TERM, \
++ BOOT_ROM_CS, \
++ BOOT_ROM_CS, \
++ TBL_TERM, \
++ TBL_TERM \
++}
++
++#define BOOT_TARGETS_NAME_ARRAY_6180 { \
++ TBL_TERM, \
++ BOOT_ROM_CS, \
++ TBL_TERM, \
++ TBL_TERM, \
++ TBL_TERM, \
++ BOOT_ROM_CS, \
++ TBL_TERM, \
++ TBL_TERM \
++}
++
++
++/* For old competability */
++#define DEVICE_CS0 NFLASH_CS
++#define DEVICE_CS1 SPI_CS
++#define DEVICE_CS2 BOOT_ROM_CS
++#define DEVICE_CS3 DEV_BOOCS
++#define MV_BOOTDEVICE_INDEX 0
++
++#define START_DEV_CS DEV_CS0
++#define DEV_TO_TARGET(dev) ((dev) + DEVICE_CS0)
++
++#define PCI_IF0_MEM0 PEX0_MEM
++#define PCI_IF0_IO PEX0_IO
++
++
++/* This enumerator defines the Marvell controller target ID */
++typedef enum _mvTargetId
++{
++ DRAM_TARGET_ID = 0 , /* Port 0 -> DRAM interface */
++ DEV_TARGET_ID = 1, /* Port 1 -> Nand/SPI */
++ PEX0_TARGET_ID = 4 , /* Port 4 -> PCI Express0 */
++ CRYPT_TARGET_ID = 3 , /* Port 3 --> Crypto Engine */
++ SAGE_TARGET_ID = 12 , /* Port 12 -> SAGE Unit */
++ MAX_TARGETS_ID
++}MV_TARGET_ID;
++
++
++/* This enumerator described the possible Controller paripheral targets. */
++/* Controller peripherals are designated memory/IO address spaces that the */
++/* controller can access. They are also refered as "targets" */
++typedef enum _mvTarget
++{
++ TBL_TERM = -1, /* none valid target, used as targets list terminator*/
++ SDRAM_CS0, /* SDRAM chip select 0 */
++ SDRAM_CS1, /* SDRAM chip select 1 */
++ SDRAM_CS2, /* SDRAM chip select 2 */
++ SDRAM_CS3, /* SDRAM chip select 3 */
++ PEX0_MEM, /* PCI Express 0 Memory */
++ PEX0_IO, /* PCI Express 0 IO */
++ INTER_REGS, /* Internal registers */
++ NFLASH_CS, /* NFLASH_CS */
++ SPI_CS, /* SPI_CS */
++ BOOT_ROM_CS, /* BOOT_ROM_CS */
++ DEV_BOOCS, /* DEV_BOOCS */
++ CRYPT_ENG, /* Crypto Engine */
++#ifdef MV_INCLUDE_SAGE
++ SAGE_UNIT, /* SAGE Unit */
++#endif
++ MAX_TARGETS
++
++}MV_TARGET;
++
++#define TARGETS_DEF_ARRAY { \
++ {0x0E, DRAM_TARGET_ID }, /* SDRAM_CS0 */ \
++ {0x0D, DRAM_TARGET_ID }, /* SDRAM_CS1 */ \
++ {0x0B, DRAM_TARGET_ID }, /* SDRAM_CS0 */ \
++ {0x07, DRAM_TARGET_ID }, /* SDRAM_CS1 */ \
++ {0xE8, PEX0_TARGET_ID }, /* PEX0_MEM */ \
++ {0xE0, PEX0_TARGET_ID }, /* PEX0_IO */ \
++ {0xFF, 0xFF }, /* INTER_REGS */ \
++ {0x2F, DEV_TARGET_ID }, /* NFLASH_CS */ \
++ {0x1E, DEV_TARGET_ID }, /* SPI_CS */ \
++ {0x1D, DEV_TARGET_ID }, /* BOOT_ROM_CS */ \
++ {0x1E, DEV_TARGET_ID }, /* DEV_BOOCS */ \
++ {0x01, CRYPT_TARGET_ID}, /* CRYPT_ENG */ \
++ {0x00, SAGE_TARGET_ID } \
++}
++
++
++#define TARGETS_NAME_ARRAY { \
++ "SDRAM_CS0", /* SDRAM_CS0 */ \
++ "SDRAM_CS1", /* SDRAM_CS1 */ \
++ "SDRAM_CS2", /* SDRAM_CS2 */ \
++ "SDRAM_CS3", /* SDRAM_CS3 */ \
++ "PEX0_MEM", /* PEX0_MEM */ \
++ "PEX0_IO", /* PEX0_IO */ \
++ "INTER_REGS", /* INTER_REGS */ \
++ "NFLASH_CS", /* NFLASH_CS */ \
++ "SPI_CS", /* SPI_CS */ \
++ "BOOT_ROM_CS", /* BOOT_ROM_CS */ \
++ "DEV_BOOTCS", /* DEV_BOOCS */ \
++ "CRYPT_ENG", /* CRYPT_ENG */ \
++ "SAGE_UNIT" /* SAGE_UNIT */ \
++}
++#endif /* MV_ASMLANGUAGE */
++
++
++#endif
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvSpec.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvSpec.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvSpec.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvSpec.h 2010-11-09 20:28:07.802495420 +0100
+@@ -0,0 +1,257 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvCtrlEnvSpech
++#define __INCmvCtrlEnvSpech
++
++#include "mvDeviceId.h"
++#include "mvSysHwConfig.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++#define MV_ARM_SOC
++#define SOC_NAME_PREFIX "MV88F"
++
++
++/* units base and port numbers */
++#ifdef MV_ASMLANGUAGE
++#define XOR_UNIT_BASE(unit) 0x60800
++#else
++#define MV_XOR_REG_BASE 0x60000
++#define XOR_UNIT_BASE(unit) ((unit)? 0x60900:0x60800)
++#endif
++
++#define TDM_REG_BASE 0xD0000
++#define USB_REG_BASE(dev) 0x50000
++#define AUDIO_REG_BASE 0xA0000
++#define SATA_REG_BASE 0x80000
++#define MV_CESA_REG_BASE 0x3D000
++#define MV_CESA_TDMA_REG_BASE 0x30000
++#define MV_SDIO_REG_BASE 0x90000
++#define MV_ETH_REG_BASE(port) (((port) == 0) ? 0x72000 : 0x76000)
++#define MV_UART_CHAN_BASE(chanNum) (0x12000 + (chanNum * 0x100))
++#define DRAM_BASE 0x0
++#define CNTMR_BASE 0x20300
++#define TWSI_SLAVE_BASE(chanNum) 0x11000
++#define PEX_IF_BASE(pexIf) 0x40000
++#define MPP_REG_BASE 0x10000
++#define TSU_GLOBAL_REG_BASE 0xB4000
++#define MAX_AHB_TO_MBUS_REG_BASE 0x20000
++
++#define INTER_REGS_SIZE _1M
++/* This define describes the TWSI interrupt bit and location */
++#define TWSI_CPU_MAIN_INT_CAUSE_REG 0x20200
++#define TWSI0_CPU_MAIN_INT_BIT (1<<29)
++#define TWSI_SPEED 100000
++
++#define MV_GPP_MAX_GROUP 2
++#define MV_CNTMR_MAX_COUNTER 2
++#define MV_UART_MAX_CHAN 2
++#define MV_XOR_MAX_UNIT 2
++#define MV_XOR_MAX_CHAN 4 /* total channels for all units together*/
++#define MV_XOR_MAX_CHAN_PER_UNIT 2 /* channels for units */
++#define MV_SATA_MAX_CHAN 2
++
++#define MV_6281_MPP_MAX_MODULE 2
++#define MV_6192_MPP_MAX_MODULE 1
++#define MV_6190_MPP_MAX_MODULE 1
++#define MV_6180_MPP_MAX_MODULE 2
++#define MV_6281_MPP_MAX_GROUP 7
++#define MV_6192_MPP_MAX_GROUP 4
++#define MV_6190_MPP_MAX_GROUP 4
++#define MV_6180_MPP_MAX_GROUP 3
++
++#define MV_DRAM_MAX_CS 4
++
++/* This define describes the maximum number of supported PCI\PCIX Interfaces*/
++#define MV_PCI_MAX_IF 0
++#define MV_PCI_START_IF 0
++
++/* This define describes the maximum number of supported PEX Interfaces */
++#define MV_INCLUDE_PEX0
++#define MV_DISABLE_PEX_DEVICE_BAR
++#define MV_PEX_MAX_IF 1
++#define MV_PEX_START_IF MV_PCI_MAX_IF
++
++/* This define describes the maximum number of supported PCI Interfaces */
++#define MV_PCI_IF_MAX_IF (MV_PEX_MAX_IF+MV_PCI_MAX_IF)
++
++#define MV_ETH_MAX_PORTS 2
++#define MV_6281_ETH_MAX_PORTS 2
++#define MV_6192_ETH_MAX_PORTS 2
++#define MV_6190_ETH_MAX_PORTS 1
++#define MV_6180_ETH_MAX_PORTS 1
++
++#define MV_IDMA_MAX_CHAN 0
++
++#define MV_USB_MAX_PORTS 1
++
++#define MV_USB_VERSION 1
++
++
++#define MV_6281_NAND 1
++#define MV_6192_NAND 1
++#define MV_6190_NAND 1
++#define MV_6180_NAND 0
++
++#define MV_6281_SDIO 1
++#define MV_6192_SDIO 1
++#define MV_6190_SDIO 1
++#define MV_6180_SDIO 1
++
++#define MV_6281_TS 1
++#define MV_6192_TS 1
++#define MV_6190_TS 0
++#define MV_6180_TS 0
++
++#define MV_6281_AUDIO 1
++#define MV_6192_AUDIO 1
++#define MV_6190_AUDIO 0
++#define MV_6180_AUDIO 1
++
++#define MV_6281_TDM 1
++#define MV_6192_TDM 1
++#define MV_6190_TDM 0
++#define MV_6180_TDM 0
++
++#define MV_DEVICE_MAX_CS 4
++
++/* Others */
++#define PEX_HOST_BUS_NUM(pciIf) (pciIf)
++#define PEX_HOST_DEV_NUM(pciIf) 0
++
++#define PCI_IO(pciIf) (PEX0_IO)
++#define PCI_MEM(pciIf, memNum) (PEX0_MEM0)
++/* CESA version #2: One channel, 2KB SRAM, TDMA */
++#if defined(MV_CESA_CHAIN_MODE_SUPPORT)
++ #define MV_CESA_VERSION 3
++#else
++#define MV_CESA_VERSION 2
++#endif
++#define MV_CESA_SRAM_SIZE 2*1024
++/* This define describes the maximum number of supported Ethernet ports */
++#define MV_ETH_VERSION 4
++#define MV_ETH_MAX_RXQ 8
++#define MV_ETH_MAX_TXQ 8
++#define MV_ETH_PORT_SGMII { MV_FALSE, MV_FALSE }
++/* This define describes the the support of USB */
++#define MV_USB_VERSION 1
++
++#define MV_INCLUDE_SDRAM_CS0
++#define MV_INCLUDE_SDRAM_CS1
++#define MV_INCLUDE_SDRAM_CS2
++#define MV_INCLUDE_SDRAM_CS3
++
++#define MV_INCLUDE_DEVICE_CS0
++#define MV_INCLUDE_DEVICE_CS1
++#define MV_INCLUDE_DEVICE_CS2
++#define MV_INCLUDE_DEVICE_CS3
++
++#define MPP_GROUP_1_TYPE {\
++ {0, 0, 0}, /* Reserved for AUTO */ \
++ {0x22220000, 0x22222222, 0x2222}, /* TDM */ \
++ {0x44440000, 0x00044444, 0x0000}, /* AUDIO */ \
++ {0x33330000, 0x33003333, 0x0033}, /* RGMII */ \
++ {0x33330000, 0x03333333, 0x0033}, /* GMII */ \
++ {0x11110000, 0x11111111, 0x0001}, /* TS */ \
++ {0x33330000, 0x33333333, 0x3333} /* MII */ \
++}
++
++#define MPP_GROUP_2_TYPE {\
++ {0, 0, 0}, /* Reserved for AUTO */ \
++ {0x22220000, 0x22222222, 0x22}, /* TDM */ \
++ {0x44440000, 0x00044444, 0x0}, /* AUDIO */ \
++ {0, 0, 0}, /* N_A */ \
++ {0, 0, 0}, /* N_A */ \
++ {0x11110000, 0x11111111, 0x01} /* TS */ \
++}
++
++#ifndef MV_ASMLANGUAGE
++
++/* This enumerator defines the Marvell Units ID */
++typedef enum _mvUnitId
++{
++ DRAM_UNIT_ID,
++ PEX_UNIT_ID,
++ ETH_GIG_UNIT_ID,
++ USB_UNIT_ID,
++ IDMA_UNIT_ID,
++ XOR_UNIT_ID,
++ SATA_UNIT_ID,
++ TDM_UNIT_ID,
++ UART_UNIT_ID,
++ CESA_UNIT_ID,
++ SPI_UNIT_ID,
++ AUDIO_UNIT_ID,
++ SDIO_UNIT_ID,
++ TS_UNIT_ID,
++ MAX_UNITS_ID
++
++}MV_UNIT_ID;
++
++#endif
++
++#endif /* __INCmvCtrlEnvSpech */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.c 2010-11-09 20:28:07.842495395 +0100
+@@ -0,0 +1,1048 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++
++/* includes */
++#include "ctrlEnv/sys/mvAhbToMbus.h"
++#include "ctrlEnv/mvCtrlEnvAddrDec.h"
++
++#undef MV_DEBUG
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++/* typedefs */
++
++
++/* CPU address remap registers offsets are inconsecutive. This struct */
++/* describes address remap register offsets */
++typedef struct _ahbToMbusRemapRegOffs
++{
++ MV_U32 lowRegOffs; /* Low 32-bit remap register offset */
++ MV_U32 highRegOffs; /* High 32 bit remap register offset */
++}AHB_TO_MBUS_REMAP_REG_OFFS;
++
++/* locals */
++static MV_STATUS ahbToMbusRemapRegOffsGet (MV_U32 winNum,
++ AHB_TO_MBUS_REMAP_REG_OFFS *pRemapRegs);
++
++/*******************************************************************************
++* mvAhbToMbusInit - Initialize Ahb To Mbus Address Map !
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_OK laways.
++*
++*******************************************************************************/
++MV_STATUS mvAhbToMbusInit(void)
++{
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvAhbToMbusWinSet - Set CPU-to-peripheral winNum address window
++*
++* DESCRIPTION:
++* This function sets
++* address window, also known as address decode window.
++* A new address decode window is set for specified winNum address window.
++* If address decode window parameter structure enables the window,
++* the routine will also enable the winNum window, allowing CPU to access
++* the winNum window.
++*
++* INPUT:
++* winNum - Windows number.
++* pAddrDecWin - CPU winNum window data structure.
++*
++* OUTPUT:
++* N/A
++*
++* RETURN:
++* MV_OK if CPU winNum window was set correctly, MV_ERROR in case of
++* address window overlapps with other active CPU winNum window or
++* trying to assign 36bit base address while CPU does not support that.
++* The function returns MV_NOT_SUPPORTED, if the winNum is unsupported.
++*
++*******************************************************************************/
++MV_STATUS mvAhbToMbusWinSet(MV_U32 winNum, MV_AHB_TO_MBUS_DEC_WIN *pAddrDecWin)
++{
++ MV_TARGET_ATTRIB targetAttribs;
++ MV_DEC_REGS decRegs;
++
++ /* Parameter checking */
++ if (winNum >= MAX_AHB_TO_MBUS_WINS)
++ {
++ mvOsPrintf("mvAhbToMbusWinSet: ERR. Invalid winNum %d\n", winNum);
++ return MV_NOT_SUPPORTED;
++ }
++
++
++ /* read base register*/
++ if (winNum != MV_AHB_TO_MBUS_INTREG_WIN)
++ {
++ decRegs.baseReg = MV_REG_READ(AHB_TO_MBUS_WIN_BASE_REG(winNum));
++ }
++ else
++ {
++ decRegs.baseReg = MV_REG_READ(AHB_TO_MBUS_WIN_INTEREG_REG);
++ }
++
++ /* check if address is aligned to the size */
++ if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size))
++ {
++ mvOsPrintf("mvAhbToMbusWinSet:Error setting AHB to MBUS window %d to "\
++ "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ winNum,
++ mvCtrlTargetNameGet(pAddrDecWin->target),
++ pAddrDecWin->addrWin.baseLow,
++ pAddrDecWin->addrWin.size);
++ return MV_ERROR;
++ }
++
++ /* read control register*/
++ if (winNum != MV_AHB_TO_MBUS_INTREG_WIN)
++ {
++ decRegs.sizeReg = MV_REG_READ(AHB_TO_MBUS_WIN_CTRL_REG(winNum));
++ }
++
++ if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs))
++ {
++ mvOsPrintf("mvAhbToMbusWinSet:mvCtrlAddrDecToReg Failed\n");
++ return MV_ERROR;
++ }
++
++ /* enable\Disable */
++ if (MV_TRUE == pAddrDecWin->enable)
++ {
++ decRegs.sizeReg |= ATMWCR_WIN_ENABLE;
++ }
++ else
++ {
++ decRegs.sizeReg &= ~ATMWCR_WIN_ENABLE;
++ }
++
++ mvCtrlAttribGet(pAddrDecWin->target,&targetAttribs);
++
++ /* set attributes */
++ decRegs.sizeReg &= ~ATMWCR_WIN_ATTR_MASK;
++ decRegs.sizeReg |= targetAttribs.attrib << ATMWCR_WIN_ATTR_OFFS;
++ /* set target ID */
++ decRegs.sizeReg &= ~ATMWCR_WIN_TARGET_MASK;
++ decRegs.sizeReg |= targetAttribs.targetId << ATMWCR_WIN_TARGET_OFFS;
++
++#if !defined(MV_RUN_FROM_FLASH)
++ /* To be on the safe side we disable the window before writing the */
++ /* new values. */
++ if (winNum != MV_AHB_TO_MBUS_INTREG_WIN)
++ {
++ mvAhbToMbusWinEnable(winNum,MV_FALSE);
++ }
++#endif
++
++ /* 3) Write to address decode Base Address Register */
++ if (winNum != MV_AHB_TO_MBUS_INTREG_WIN)
++ {
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_BASE_REG(winNum), decRegs.baseReg);
++ }
++ else
++ {
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_INTEREG_REG, decRegs.baseReg);
++ }
++
++
++ /* Internal register space have no size */
++ /* register. Do not perform size register assigment for those targets */
++ if (winNum != MV_AHB_TO_MBUS_INTREG_WIN)
++ {
++ /* Write to address decode Size Register */
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_CTRL_REG(winNum), decRegs.sizeReg);
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvAhbToMbusWinGet - Get CPU-to-peripheral winNum address window
++*
++* DESCRIPTION:
++* Get the CPU peripheral winNum address window.
++*
++* INPUT:
++* winNum - Peripheral winNum enumerator
++*
++* OUTPUT:
++* pAddrDecWin - CPU winNum window information data structure.
++*
++* RETURN:
++* MV_OK if winNum exist, MV_ERROR otherwise.
++*
++*******************************************************************************/
++MV_STATUS mvAhbToMbusWinGet(MV_U32 winNum, MV_AHB_TO_MBUS_DEC_WIN *pAddrDecWin)
++{
++ MV_DEC_REGS decRegs;
++ MV_TARGET_ATTRIB targetAttrib;
++
++
++ /* Parameter checking */
++ if (winNum >= MAX_AHB_TO_MBUS_WINS)
++ {
++ mvOsPrintf("mvAhbToMbusWinGet: ERR. Invalid winNum %d\n", winNum);
++ return MV_NOT_SUPPORTED;
++ }
++
++
++ /* Internal register space size have no size register*/
++ if (winNum != MV_AHB_TO_MBUS_INTREG_WIN)
++ {
++ decRegs.sizeReg = MV_REG_READ(AHB_TO_MBUS_WIN_CTRL_REG(winNum));
++ }
++ else
++ {
++ decRegs.sizeReg = 0;
++ }
++
++
++ /* Read base and size */
++ if (winNum != MV_AHB_TO_MBUS_INTREG_WIN)
++ {
++ decRegs.baseReg = MV_REG_READ(AHB_TO_MBUS_WIN_BASE_REG(winNum));
++ }
++ else
++ {
++ decRegs.baseReg = MV_REG_READ(AHB_TO_MBUS_WIN_INTEREG_REG);
++ }
++
++
++
++ if (MV_OK != mvCtrlRegToAddrDec(&decRegs,&(pAddrDecWin->addrWin)))
++ {
++ mvOsPrintf("mvAhbToMbusWinGet: mvCtrlRegToAddrDec Failed \n");
++ return MV_ERROR;
++ }
++
++ if (winNum == MV_AHB_TO_MBUS_INTREG_WIN)
++ {
++ pAddrDecWin->addrWin.size = INTER_REGS_SIZE;
++ pAddrDecWin->target = INTER_REGS;
++ pAddrDecWin->enable = MV_TRUE;
++
++ return MV_OK;
++ }
++
++
++ if (decRegs.sizeReg & ATMWCR_WIN_ENABLE)
++ {
++ pAddrDecWin->enable = MV_TRUE;
++ }
++ else
++ {
++ pAddrDecWin->enable = MV_FALSE;
++
++ }
++
++
++
++ if (-1 == pAddrDecWin->addrWin.size)
++ {
++ return MV_ERROR;
++ }
++
++ /* attrib and targetId */
++ targetAttrib.attrib = (decRegs.sizeReg & ATMWCR_WIN_ATTR_MASK) >>
++ ATMWCR_WIN_ATTR_OFFS;
++ targetAttrib.targetId = (decRegs.sizeReg & ATMWCR_WIN_TARGET_MASK) >>
++ ATMWCR_WIN_TARGET_OFFS;
++
++ pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvAhbToMbusWinTargetGet - Get Window number associated with target
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_U32 mvAhbToMbusWinTargetGet(MV_TARGET target)
++{
++ MV_AHB_TO_MBUS_DEC_WIN decWin;
++ MV_U32 winNum;
++
++ /* Check parameters */
++ if (target >= MAX_TARGETS)
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetGet: target %d is Illigal\n", target);
++ return 0xffffffff;
++ }
++
++ if (INTER_REGS == target)
++ {
++ return MV_AHB_TO_MBUS_INTREG_WIN;
++ }
++
++ for (winNum = 0; winNum < MAX_AHB_TO_MBUS_WINS ; winNum++)
++ {
++ if (winNum == MV_AHB_TO_MBUS_INTREG_WIN)
++ continue;
++
++ if (mvAhbToMbusWinGet(winNum,&decWin) != MV_OK)
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetGet: mvAhbToMbusWinGet fail\n");
++ return 0xffffffff;
++
++ }
++
++ if (decWin.enable == MV_TRUE)
++ {
++ if (decWin.target == target)
++ {
++ return winNum;
++ }
++
++ }
++
++ }
++
++ return 0xFFFFFFFF;
++
++
++}
++
++/*******************************************************************************
++* mvAhbToMbusWinAvailGet - Get First Available window number.
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_U32 mvAhbToMbusWinAvailGet(MV_VOID)
++{
++ MV_AHB_TO_MBUS_DEC_WIN decWin;
++ MV_U32 winNum;
++
++ for (winNum = 0; winNum < MAX_AHB_TO_MBUS_WINS ; winNum++)
++ {
++ if (winNum == MV_AHB_TO_MBUS_INTREG_WIN)
++ continue;
++
++ if (mvAhbToMbusWinGet(winNum,&decWin) != MV_OK)
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetGet: mvAhbToMbusWinGet fail\n");
++ return 0xffffffff;
++
++ }
++
++ if (decWin.enable == MV_FALSE)
++ {
++ return winNum;
++ }
++
++ }
++
++ return 0xFFFFFFFF;
++}
++
++
++/*******************************************************************************
++* mvAhbToMbusWinEnable - Enable/disable a CPU address decode window
++*
++* DESCRIPTION:
++* This function enable/disable a CPU address decode window.
++* if parameter 'enable' == MV_TRUE the routine will enable the
++* window, thus enabling CPU accesses (before enabling the window it is
++* tested for overlapping). Otherwise, the window will be disabled.
++*
++* INPUT:
++* winNum - Peripheral winNum enumerator.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* N/A
++*
++* RETURN:
++* MV_ERROR if protection window number was wrong, or the window
++* overlapps other winNum window.
++*
++*******************************************************************************/
++MV_STATUS mvAhbToMbusWinEnable(MV_U32 winNum, MV_BOOL enable)
++{
++
++ /* Parameter checking */
++ if (winNum >= MAX_AHB_TO_MBUS_WINS)
++ {
++ mvOsPrintf("mvAhbToMbusWinEnable: ERR. Invalid winNum %d\n", winNum);
++ return MV_NOT_SUPPORTED;
++ }
++
++ /* Internal registers bar can't be disable or enabled */
++ if (winNum == MV_AHB_TO_MBUS_INTREG_WIN)
++ {
++ return (enable ? MV_OK : MV_ERROR);
++ }
++
++ if (enable == MV_TRUE)
++ {
++ /* enable the window */
++ MV_REG_BIT_SET(AHB_TO_MBUS_WIN_CTRL_REG(winNum), ATMWCR_WIN_ENABLE);
++ }
++ else
++ { /* Disable address decode winNum window */
++ MV_REG_BIT_RESET(AHB_TO_MBUS_WIN_CTRL_REG(winNum), ATMWCR_WIN_ENABLE);
++ }
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvAhbToMbusWinRemap - Set CPU remap register for address windows.
++*
++* DESCRIPTION:
++* After a CPU address hits one of PCI address decode windows there is an
++* option to remap the address to a different one. For example, CPU
++* executes a read from PCI winNum window address 0x1200.0000. This
++* can be modified so the address on the PCI bus would be 0x1400.0000
++* Using the PCI address remap mechanism.
++*
++* INPUT:
++* winNum - Peripheral winNum enumerator. Must be a PCI winNum.
++* pAddrDecWin - CPU winNum window information data structure.
++* Note that caller has to fill in the base field only. The
++* size field is ignored.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if winNum is not a PCI one, MV_OK otherwise.
++*
++*******************************************************************************/
++MV_U32 mvAhbToMbusWinRemap(MV_U32 winNum, MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 baseAddr;
++ AHB_TO_MBUS_REMAP_REG_OFFS remapRegOffs;
++
++ MV_U32 effectiveBaseAddress=0,
++ baseAddrValue=0,windowSizeValue=0;
++
++
++ /* Get registers offsets of given winNum */
++ if (MV_NO_SUCH == ahbToMbusRemapRegOffsGet(winNum, &remapRegOffs))
++ {
++ return 0xffffffff;
++ }
++
++ /* 1) Set address remap low */
++ baseAddr = pAddrWin->baseLow;
++
++ /* Check base address aligment */
++ /*
++ if (MV_IS_NOT_ALIGN(baseAddr, ATMWRLR_REMAP_LOW_ALIGNMENT))
++ {
++ mvOsPrintf("mvAhbToMbusPciRemap: Warning. Target base 0x%x unaligned\n",
++ baseAddr);
++ return MV_ERROR;
++ }
++ */
++
++ /* BaseLow[31:16] => base register [31:16] */
++ baseAddr = baseAddr & ATMWRLR_REMAP_LOW_MASK;
++
++ MV_REG_WRITE(remapRegOffs.lowRegOffs, baseAddr);
++
++ MV_REG_WRITE(remapRegOffs.highRegOffs, pAddrWin->baseHigh);
++
++
++ baseAddrValue = MV_REG_READ(AHB_TO_MBUS_WIN_BASE_REG(winNum));
++ windowSizeValue = MV_REG_READ(AHB_TO_MBUS_WIN_CTRL_REG(winNum));
++
++ baseAddrValue &= ATMWBR_BASE_MASK;
++ windowSizeValue &=ATMWCR_WIN_SIZE_MASK;
++
++ /* Start calculating the effective Base Address */
++ effectiveBaseAddress = baseAddrValue ;
++
++ /* The effective base address will be combined from the chopped (if any)
++ remap value (according to the size value and remap mechanism) and the
++ window's base address */
++ effectiveBaseAddress |= (((windowSizeValue) | 0xffff) & pAddrWin->baseLow);
++ /* If the effectiveBaseAddress exceed the window boundaries return an
++ invalid value. */
++
++ if (effectiveBaseAddress > (baseAddrValue + (windowSizeValue | 0xffff)))
++ {
++ mvOsPrintf("mvAhbToMbusPciRemap: Error\n");
++ return 0xffffffff;
++ }
++
++ return effectiveBaseAddress;
++
++
++}
++/*******************************************************************************
++* mvAhbToMbusWinTargetSwap - Swap AhbToMbus windows between targets
++*
++* DESCRIPTION:
++*
++* INPUT:
++* target1 - CPU Interface target 1
++* target2 - CPU Interface target 2
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if targets are illigal, or if one of the targets is not
++* associated to a valid window .
++* MV_OK otherwise.
++*
++*******************************************************************************/
++
++
++MV_STATUS mvAhbToMbusWinTargetSwap(MV_TARGET target1,MV_TARGET target2)
++{
++ MV_U32 winNum1,winNum2;
++ MV_AHB_TO_MBUS_DEC_WIN winDec1,winDec2,winDecTemp;
++ AHB_TO_MBUS_REMAP_REG_OFFS remapRegs1,remapRegs2;
++ MV_U32 remapBaseLow1=0,remapBaseLow2=0;
++ MV_U32 remapBaseHigh1=0,remapBaseHigh2=0;
++
++
++ /* Check parameters */
++ if (target1 >= MAX_TARGETS)
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetSwap: target %d is Illigal\n", target1);
++ return MV_ERROR;
++ }
++
++ if (target2 >= MAX_TARGETS)
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetSwap: target %d is Illigal\n", target1);
++ return MV_ERROR;
++ }
++
++
++ /* get window associated with this target */
++ winNum1 = mvAhbToMbusWinTargetGet(target1);
++
++ if (winNum1 == 0xffffffff)
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetSwap: target %d has illigal win %d\n",
++ target1,winNum1);
++ return MV_ERROR;
++
++ }
++
++ /* get window associated with this target */
++ winNum2 = mvAhbToMbusWinTargetGet(target2);
++
++ if (winNum2 == 0xffffffff)
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetSwap: target %d has illigal win %d\n",
++ target2,winNum2);
++ return MV_ERROR;
++
++ }
++
++ /* now Get original values of both Windows */
++ if (MV_OK != mvAhbToMbusWinGet(winNum1,&winDec1))
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetSwap: mvAhbToMbusWinGet failed win %d\n",
++ winNum1);
++ return MV_ERROR;
++
++ }
++ if (MV_OK != mvAhbToMbusWinGet(winNum2,&winDec2))
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetSwap: mvAhbToMbusWinGet failed win %d\n",
++ winNum2);
++ return MV_ERROR;
++
++ }
++
++
++ /* disable both windows */
++ if (MV_OK != mvAhbToMbusWinEnable(winNum1,MV_FALSE))
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetSwap: failed to enable window %d\n",
++ winNum1);
++ return MV_ERROR;
++
++ }
++ if (MV_OK != mvAhbToMbusWinEnable(winNum2,MV_FALSE))
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetSwap: failed to enable windo %d\n",
++ winNum2);
++ return MV_ERROR;
++
++ }
++
++
++ /* now swap targets */
++
++ /* first save winDec2 values */
++ winDecTemp.addrWin.baseHigh = winDec2.addrWin.baseHigh;
++ winDecTemp.addrWin.baseLow = winDec2.addrWin.baseLow;
++ winDecTemp.addrWin.size = winDec2.addrWin.size;
++ winDecTemp.enable = winDec2.enable;
++ winDecTemp.target = winDec2.target;
++
++ /* winDec2 = winDec1 */
++ winDec2.addrWin.baseHigh = winDec1.addrWin.baseHigh;
++ winDec2.addrWin.baseLow = winDec1.addrWin.baseLow;
++ winDec2.addrWin.size = winDec1.addrWin.size;
++ winDec2.enable = winDec1.enable;
++ winDec2.target = winDec1.target;
++
++
++ /* winDec1 = winDecTemp */
++ winDec1.addrWin.baseHigh = winDecTemp.addrWin.baseHigh;
++ winDec1.addrWin.baseLow = winDecTemp.addrWin.baseLow;
++ winDec1.addrWin.size = winDecTemp.addrWin.size;
++ winDec1.enable = winDecTemp.enable;
++ winDec1.target = winDecTemp.target;
++
++
++ /* now set the new values */
++
++
++ mvAhbToMbusWinSet(winNum1,&winDec1);
++ mvAhbToMbusWinSet(winNum2,&winDec2);
++
++
++
++
++
++ /* now we will treat the remap windows if exist */
++
++
++ /* now check if one or both windows has a remap window
++ as well after the swap ! */
++
++ /* if a window had a remap value differnt than the base value
++ before the swap , then after the swap the remap value will be
++ equal to the base value unless both windows has a remap windows*/
++
++ /* first get old values */
++ if (MV_NO_SUCH != ahbToMbusRemapRegOffsGet(winNum1,&remapRegs1))
++ {
++ remapBaseLow1 = MV_REG_READ(remapRegs1.lowRegOffs);
++ remapBaseHigh1 = MV_REG_READ(remapRegs1.highRegOffs);
++
++ }
++ if (MV_NO_SUCH != ahbToMbusRemapRegOffsGet(winNum2,&remapRegs2))
++ {
++ remapBaseLow2 = MV_REG_READ(remapRegs2.lowRegOffs);
++ remapBaseHigh2 = MV_REG_READ(remapRegs2.highRegOffs);
++
++
++ }
++
++ /* now do the swap */
++ if (MV_NO_SUCH != ahbToMbusRemapRegOffsGet(winNum1,&remapRegs1))
++ {
++ if (MV_NO_SUCH != ahbToMbusRemapRegOffsGet(winNum2,&remapRegs2))
++ {
++ /* Two windows has a remap !!! so swap */
++
++ MV_REG_WRITE(remapRegs2.highRegOffs,remapBaseHigh1);
++ MV_REG_WRITE(remapRegs2.lowRegOffs,remapBaseLow1);
++
++ MV_REG_WRITE(remapRegs1.highRegOffs,remapBaseHigh2);
++ MV_REG_WRITE(remapRegs1.lowRegOffs,remapBaseLow2);
++
++
++
++ }
++ else
++ {
++ /* remap == base */
++ MV_REG_WRITE(remapRegs1.highRegOffs,winDec1.addrWin.baseHigh);
++ MV_REG_WRITE(remapRegs1.lowRegOffs,winDec1.addrWin.baseLow);
++
++ }
++
++ }
++ else if (MV_NO_SUCH != ahbToMbusRemapRegOffsGet(winNum2,&remapRegs2))
++ {
++ /* remap == base */
++ MV_REG_WRITE(remapRegs2.highRegOffs,winDec2.addrWin.baseHigh);
++ MV_REG_WRITE(remapRegs2.lowRegOffs,winDec2.addrWin.baseLow);
++
++ }
++
++
++
++ return MV_OK;
++
++
++}
++
++
++
++#if defined(MV_88F1181)
++
++/*******************************************************************************
++* mvAhbToMbusXbarCtrlSet - Set The CPU master Xbar arbitration.
++*
++* DESCRIPTION:
++* This function sets CPU Mbus Arbiter
++*
++* INPUT:
++* pPizzaArbArray - A priority Structure describing 16 "pizza slices". At
++* each clock cycle, the crossbar arbiter samples all
++* requests and gives the bus to the next agent according
++* to the "pizza".
++*
++* OUTPUT:
++* N/A
++*
++* RETURN:
++* MV_ERROR if paramers to function invalid.
++*
++*******************************************************************************/
++MV_STATUS mvMbusArbSet(MV_MBUS_ARB_TARGET *pPizzaArbArray)
++{
++ MV_U32 sliceNum;
++ MV_U32 xbarCtrl = 0;
++ MV_MBUS_ARB_TARGET xbarTarget;
++
++ /* 1) Set crossbar control low register */
++ for (sliceNum = 0; sliceNum < MRLR_SLICE_NUM; sliceNum++)
++ {
++ xbarTarget = pPizzaArbArray[sliceNum];
++
++ /* sliceNum parameter check */
++ if (xbarTarget > MAX_MBUS_ARB_TARGETS)
++ {
++ mvOsPrintf("mvAhbToMbusXbarCtrlSet: ERR. Can't set Target %d\n",
++ xbarTarget);
++ return MV_ERROR;
++ }
++ xbarCtrl |= (xbarTarget << MRLR_LOW_ARB_OFFS(sliceNum));
++ }
++ /* Write to crossbar control low register */
++ MV_REG_WRITE(MBUS_ARBITER_LOW_REG, xbarCtrl);
++
++ xbarCtrl = 0;
++
++ /* 2) Set crossbar control high register */
++ for (sliceNum = MRLR_SLICE_NUM;
++ sliceNum < MRLR_SLICE_NUM+MRHR_SLICE_NUM;
++ sliceNum++)
++ {
++
++ xbarTarget = pPizzaArbArray[sliceNum];
++
++ /* sliceNum parameter check */
++ if (xbarTarget > MAX_MBUS_ARB_TARGETS)
++ {
++ mvOsPrintf("mvAhbToMbusXbarCtrlSet: ERR. Can't set Target %d\n",
++ xbarTarget);
++ return MV_ERROR;
++ }
++ xbarCtrl |= (xbarTarget << MRHR_HIGH_ARB_OFFS(sliceNum));
++ }
++ /* Write to crossbar control high register */
++ MV_REG_WRITE(MBUS_ARBITER_HIGH_REG, xbarCtrl);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvMbusArbCtrlSet - Set MBus Arbiter control register
++*
++* DESCRIPTION:
++*
++* INPUT:
++* ctrl - pointer to MV_MBUS_ARB_CTRL register
++*
++* OUTPUT:
++* N/A
++*
++* RETURN:
++* MV_ERROR if paramers to function invalid.
++*
++*******************************************************************************/
++MV_STATUS mvMbusArbCtrlSet(MV_MBUS_ARB_CTRL *ctrl)
++{
++
++ if (ctrl->highPrio == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(MBUS_ARBITER_CTRL_REG, MACR_ARB_ARM_TOP);
++ }
++ else
++ {
++ MV_REG_BIT_SET(MBUS_ARBITER_CTRL_REG, MACR_ARB_ARM_TOP);
++ }
++
++ if (ctrl->fixedRoundRobin == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(MBUS_ARBITER_CTRL_REG, MACR_ARB_TARGET_FIXED);
++ }
++ else
++ {
++ MV_REG_BIT_SET(MBUS_ARBITER_CTRL_REG, MACR_ARB_TARGET_FIXED);
++ }
++
++ if (ctrl->starvEn == MV_FALSE)
++ {
++ MV_REG_BIT_RESET(MBUS_ARBITER_CTRL_REG, MACR_ARB_REQ_CTRL_EN);
++ }
++ else
++ {
++ MV_REG_BIT_SET(MBUS_ARBITER_CTRL_REG, MACR_ARB_REQ_CTRL_EN);
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvMbusArbCtrlGet - Get MBus Arbiter control register
++*
++* DESCRIPTION:
++*
++* INPUT:
++* ctrl - pointer to MV_MBUS_ARB_CTRL register
++*
++* OUTPUT:
++* ctrl - pointer to MV_MBUS_ARB_CTRL register
++*
++* RETURN:
++* MV_ERROR if paramers to function invalid.
++*
++*******************************************************************************/
++MV_STATUS mvMbusArbCtrlGet(MV_MBUS_ARB_CTRL *ctrl)
++{
++
++ MV_U32 ctrlReg = MV_REG_READ(MBUS_ARBITER_CTRL_REG);
++
++ if (ctrlReg & MACR_ARB_ARM_TOP)
++ {
++ ctrl->highPrio = MV_TRUE;
++ }
++ else
++ {
++ ctrl->highPrio = MV_FALSE;
++ }
++
++ if (ctrlReg & MACR_ARB_TARGET_FIXED)
++ {
++ ctrl->fixedRoundRobin = MV_TRUE;
++ }
++ else
++ {
++ ctrl->fixedRoundRobin = MV_FALSE;
++ }
++
++ if (ctrlReg & MACR_ARB_REQ_CTRL_EN)
++ {
++ ctrl->starvEn = MV_TRUE;
++ }
++ else
++ {
++ ctrl->starvEn = MV_FALSE;
++ }
++
++
++ return MV_OK;
++}
++
++#endif /* #if defined(MV_88F1181) */
++
++
++
++/*******************************************************************************
++* ahbToMbusRemapRegOffsGet - Get CPU address remap register offsets
++*
++* DESCRIPTION:
++* CPU to PCI address remap registers offsets are inconsecutive.
++* This function returns PCI address remap registers offsets.
++*
++* INPUT:
++* winNum - Address decode window number. See MV_U32 enumerator.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if winNum is not a PCI one.
++*
++*******************************************************************************/
++static MV_STATUS ahbToMbusRemapRegOffsGet(MV_U32 winNum,
++ AHB_TO_MBUS_REMAP_REG_OFFS *pRemapRegs)
++{
++ switch (winNum)
++ {
++ case 0:
++ case 1:
++ pRemapRegs->lowRegOffs = AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum);
++ pRemapRegs->highRegOffs = AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum);
++ break;
++ case 2:
++ case 3:
++ if((mvCtrlModelGet() == MV_5281_DEV_ID) ||
++ (mvCtrlModelGet() == MV_1281_DEV_ID) ||
++ (mvCtrlModelGet() == MV_6183_DEV_ID) ||
++ (mvCtrlModelGet() == MV_6183L_DEV_ID))
++ {
++ pRemapRegs->lowRegOffs = AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum);
++ pRemapRegs->highRegOffs = AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum);
++ break;
++ }
++ else
++ {
++ pRemapRegs->lowRegOffs = 0;
++ pRemapRegs->highRegOffs = 0;
++
++ DB(mvOsPrintf("ahbToMbusRemapRegOffsGet: ERR. Invalid winNum %d\n",
++ winNum));
++ return MV_NO_SUCH;
++ }
++ default:
++ {
++ pRemapRegs->lowRegOffs = 0;
++ pRemapRegs->highRegOffs = 0;
++
++ DB(mvOsPrintf("ahbToMbusRemapRegOffsGet: ERR. Invalid winNum %d\n",
++ winNum));
++ return MV_NO_SUCH;
++ }
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvAhbToMbusAddDecShow - Print the AHB to MBus bridge address decode map.
++*
++* DESCRIPTION:
++* This function print the CPU address decode map.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvAhbToMbusAddDecShow(MV_VOID)
++{
++ MV_AHB_TO_MBUS_DEC_WIN win;
++ MV_U32 winNum;
++ mvOsOutput( "\n" );
++ mvOsOutput( "AHB To MBUS Bridge:\n" );
++ mvOsOutput( "-------------------\n" );
++
++ for( winNum = 0; winNum < MAX_AHB_TO_MBUS_WINS; winNum++ )
++ {
++ memset( &win, 0, sizeof(MV_AHB_TO_MBUS_DEC_WIN) );
++
++ mvOsOutput( "win%d - ", winNum );
++
++ if( mvAhbToMbusWinGet( winNum, &win ) == MV_OK )
++ {
++ if( win.enable )
++ {
++ mvOsOutput( "%s base %08x, ",
++ mvCtrlTargetNameGet(win.target), win.addrWin.baseLow );
++ mvOsOutput( "...." );
++ mvSizePrint( win.addrWin.size );
++
++ mvOsOutput( "\n" );
++
++ }
++ else
++ mvOsOutput( "disable\n" );
++ }
++ }
++
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.h 2010-11-09 20:28:07.872495394 +0100
+@@ -0,0 +1,130 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvAhbToMbush
++#define __INCmvAhbToMbush
++
++/* includes */
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/sys/mvAhbToMbusRegs.h"
++#include "ctrlEnv/mvCtrlEnvAddrDec.h"
++
++/* defines */
++
++#if defined(MV_88F1181)
++/* This enumerator defines the Marvell controller possible MBUS arbiter */
++/* target ports. It is used to define crossbar priority scheame (pizza) */
++typedef enum _mvMBusArbTargetId
++{
++ DRAM_MBUS_ARB_TARGET = 0, /* Port 0 -> DRAM interface */
++ TWSI_MBUS_ARB_TARGET = 1, /* Port 1 -> TWSI */
++ ARM_MBUS_ARB_TARGET = 2, /* Port 2 -> ARM */
++ PEX1_MBUS_ARB_TARGET = 3, /* Port 3 -> PCI Express 1 */
++ PEX0_MBUS_ARB_TARGET = 4, /* Port 4 -> PCI Express0 */
++ MAX_MBUS_ARB_TARGETS
++}MV_MBUS_ARB_TARGET;
++
++typedef struct _mvMBusArbCtrl
++{
++ MV_BOOL starvEn;
++ MV_BOOL highPrio;
++ MV_BOOL fixedRoundRobin;
++
++}MV_MBUS_ARB_CTRL;
++
++#endif /* #if defined(MV_88F1181) */
++
++typedef struct _mvAhbtoMbusDecWin
++{
++ MV_TARGET target;
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++
++}MV_AHB_TO_MBUS_DEC_WIN;
++
++/* mvAhbToMbus.h API list */
++
++MV_STATUS mvAhbToMbusInit(MV_VOID);
++MV_STATUS mvAhbToMbusWinSet(MV_U32 winNum, MV_AHB_TO_MBUS_DEC_WIN *pAddrDecWin);
++MV_STATUS mvAhbToMbusWinGet(MV_U32 winNum, MV_AHB_TO_MBUS_DEC_WIN *pAddrDecWin);
++MV_STATUS mvAhbToMbusWinEnable(MV_U32 winNum,MV_BOOL enable);
++MV_U32 mvAhbToMbusWinRemap(MV_U32 winNum, MV_ADDR_WIN *pAddrDecWin);
++MV_U32 mvAhbToMbusWinTargetGet(MV_TARGET target);
++MV_U32 mvAhbToMbusWinAvailGet(MV_VOID);
++MV_STATUS mvAhbToMbusWinTargetSwap(MV_TARGET target1,MV_TARGET target2);
++
++#if defined(MV_88F1181)
++
++MV_STATUS mvMbusArbSet(MV_MBUS_ARB_TARGET *pPizzaArbArray);
++MV_STATUS mvMbusArbCtrlSet(MV_MBUS_ARB_CTRL *ctrl);
++MV_STATUS mvMbusArbCtrlGet(MV_MBUS_ARB_CTRL *ctrl);
++
++#endif /* #if defined(MV_88F1181) */
++
++
++MV_VOID mvAhbToMbusAddDecShow(MV_VOID);
++
++
++#endif /* __INCmvAhbToMbush */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbusRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbusRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbusRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbusRegs.h 2010-11-09 20:28:07.902495495 +0100
+@@ -0,0 +1,143 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvAhbToMbusRegsh
++#define __INCmvAhbToMbusRegsh
++
++/******************************/
++/* ARM Address Map Registers */
++/******************************/
++
++#define MAX_AHB_TO_MBUS_WINS 9
++#define MV_AHB_TO_MBUS_INTREG_WIN 8
++
++
++#define AHB_TO_MBUS_WIN_CTRL_REG(winNum) (0x20000 + (winNum)*0x10)
++#define AHB_TO_MBUS_WIN_BASE_REG(winNum) (0x20004 + (winNum)*0x10)
++#define AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum) (0x20008 + (winNum)*0x10)
++#define AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum) (0x2000C + (winNum)*0x10)
++#define AHB_TO_MBUS_WIN_INTEREG_REG 0x20080
++
++/* Window Control Register */
++/* AHB_TO_MBUS_WIN_CTRL_REG (ATMWCR)*/
++#define ATMWCR_WIN_ENABLE BIT0 /* Window Enable */
++
++#define ATMWCR_WIN_TARGET_OFFS 4 /* The target interface associated
++ with this window*/
++#define ATMWCR_WIN_TARGET_MASK (0xf << ATMWCR_WIN_TARGET_OFFS)
++
++#define ATMWCR_WIN_ATTR_OFFS 8 /* The target interface attributes
++ Associated with this window */
++#define ATMWCR_WIN_ATTR_MASK (0xff << ATMWCR_WIN_ATTR_OFFS)
++
++
++/*
++Used with the Base register to set the address window size and location
++Must be programed from LSB to MSB as sequence of 1’s followed
++by sequence of 0’s. The number of 1’s specifies the size of the window
++in 64 KB granularity (e.g. a value of 0x00FF specifies 256 = 16 MB).
++
++NOTE: A value of 0x0 specifies 64KB size.
++*/
++#define ATMWCR_WIN_SIZE_OFFS 16 /* Window Size */
++#define ATMWCR_WIN_SIZE_MASK (0xffff << ATMWCR_WIN_SIZE_OFFS)
++#define ATMWCR_WIN_SIZE_ALIGNMENT 0x10000
++
++/* Window Base Register */
++/* AHB_TO_MBUS_WIN_BASE_REG (ATMWBR) */
++
++/*
++Used with the size field to set the address window size and location.
++Corresponds to transaction address[31:16]
++*/
++#define ATMWBR_BASE_OFFS 16 /* Base Address */
++#define ATMWBR_BASE_MASK (0xffff << ATMWBR_BASE_OFFS)
++#define ATMWBR_BASE_ALIGNMENT 0x10000
++
++/* Window Remap Low Register */
++/* AHB_TO_MBUS_WIN_REMAP_LOW_REG (ATMWRLR) */
++
++/*
++Used with the size field to specifies address bits[31:0] to be driven to
++the target interface.:
++target_addr[31:16] = (addr[31:16] & size[15:0]) | (remap[31:16] & ~size[15:0])
++*/
++#define ATMWRLR_REMAP_LOW_OFFS 16 /* Remap Address */
++#define ATMWRLR_REMAP_LOW_MASK (0xffff << ATMWRLR_REMAP_LOW_OFFS)
++#define ATMWRLR_REMAP_LOW_ALIGNMENT 0x10000
++
++/* Window Remap High Register */
++/* AHB_TO_MBUS_WIN_REMAP_HIGH_REG (ATMWRHR) */
++
++/*
++Specifies address bits[63:32] to be driven to the target interface.
++target_addr[63:32] = (RemapHigh[31:0]
++*/
++#define ATMWRHR_REMAP_HIGH_OFFS 0 /* Remap Address */
++#define ATMWRHR_REMAP_HIGH_MASK (0xffffffff << ATMWRHR_REMAP_HIGH_OFFS)
++
++
++#endif /* __INCmvAhbToMbusRegsh */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.c 2010-11-09 20:28:07.942495425 +0100
+@@ -0,0 +1,1036 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++
++/* includes */
++#include "ctrlEnv/sys/mvCpuIf.h"
++#include "ctrlEnv/sys/mvAhbToMbusRegs.h"
++#include "cpu/mvCpu.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "mvSysHwConfig.h"
++#include "mvSysDram.h"
++
++/*#define MV_DEBUG*/
++/* defines */
++
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++/* locals */
++/* static functions */
++static MV_BOOL cpuTargetWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin);
++
++MV_TARGET * sampleAtResetTargetArray;
++MV_TARGET sampleAtResetTargetArrayP[] = BOOT_TARGETS_NAME_ARRAY;
++MV_TARGET sampleAtResetTargetArray6180P[] = BOOT_TARGETS_NAME_ARRAY_6180;
++/*******************************************************************************
++* mvCpuIfInit - Initialize Controller CPU interface
++*
++* DESCRIPTION:
++* This function initialize Controller CPU interface:
++* 1. Set CPU interface configuration registers.
++* 2. Set CPU master Pizza arbiter control according to static
++* configuration described in configuration file.
++* 3. Opens CPU address decode windows. DRAM windows are assumed to be
++* already set (auto detection).
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvCpuIfInit(MV_CPU_DEC_WIN *cpuAddrWinMap)
++{
++ MV_U32 regVal;
++ MV_TARGET target;
++ MV_ADDR_WIN addrWin;
++
++ if (cpuAddrWinMap == NULL)
++ {
++ DB(mvOsPrintf("mvCpuIfInit:ERR. cpuAddrWinMap == NULL\n"));
++ return MV_ERROR;
++ }
++
++ /*Initialize the boot target array according to device type*/
++ if(mvCtrlModelGet() == MV_6180_DEV_ID)
++ sampleAtResetTargetArray = sampleAtResetTargetArray6180P;
++ else
++ sampleAtResetTargetArray = sampleAtResetTargetArrayP;
++
++ /* Set ARM Configuration register */
++ regVal = MV_REG_READ(CPU_CONFIG_REG);
++ regVal &= ~CPU_CONFIG_DEFAULT_MASK;
++ regVal |= CPU_CONFIG_DEFAULT;
++ MV_REG_WRITE(CPU_CONFIG_REG,regVal);
++
++ /* First disable all CPU target windows */
++ for (target = 0; cpuAddrWinMap[target].enable != TBL_TERM; target++)
++ {
++ if ((MV_TARGET_IS_DRAM(target))||(target == INTER_REGS))
++ {
++ continue;
++ }
++
++#if defined(MV_MEM_OVER_PCI_WA) || defined(MV_UART_OVER_PCI_WA)
++ /* If the target PEX or PCI and memory is over PEX or PCI we don't touch this CPU windows */
++ if (MV_TARGET_IS_PCI(target))
++ {
++ continue;
++ }
++#endif
++
++#if defined(MV_MEM_OVER_PEX_WA) || defined(MV_UART_OVER_PEX_WA)
++ /* If the target PEX or PCI and memory is over PEX or PCI we don't touch this CPU windows */
++ if (MV_TARGET_IS_PEX(target))
++ {
++ continue;
++ }
++#endif
++#if defined(MV_RUN_FROM_FLASH)
++ /* Don't disable the boot device. */
++ if (target == DEV_BOOCS)
++ {
++ continue;
++ }
++#endif /* MV_RUN_FROM_FLASH */
++ mvCpuIfTargetWinEnable(MV_CHANGE_BOOT_CS(target),MV_FALSE);
++ }
++
++#if defined(MV_RUN_FROM_FLASH)
++ /* Resize the bootcs windows before other windows, because this */
++ /* window is enabled and will cause an overlap if not resized. */
++ target = DEV_BOOCS;
++
++ if (MV_OK != mvCpuIfTargetWinSet(target, &cpuAddrWinMap[target]))
++ {
++ DB(mvOsPrintf("mvCpuIfInit:ERR. mvCpuIfTargetWinSet fail\n"));
++ return MV_ERROR;
++ }
++
++ addrWin.baseLow = cpuAddrWinMap[target].addrWin.baseLow;
++ addrWin.baseHigh = cpuAddrWinMap[target].addrWin.baseHigh;
++ if (0xffffffff == mvAhbToMbusWinRemap(cpuAddrWinMap[target].winNum ,&addrWin))
++ {
++ DB(mvOsPrintf("mvCpuIfInit:WARN. mvAhbToMbusWinRemap can't remap winNum=%d\n",
++ cpuAddrWinMap[target].winNum));
++ }
++
++#endif /* MV_RUN_FROM_FLASH */
++
++ /* Go through all targets in user table until table terminator */
++ for (target = 0; cpuAddrWinMap[target].enable != TBL_TERM; target++)
++ {
++
++#if defined(MV_RUN_FROM_FLASH)
++ if (target == DEV_BOOCS)
++ {
++ continue;
++ }
++#endif /* MV_RUN_FROM_FLASH */
++
++ /* if DRAM auto sizing is used do not initialized DRAM target windows, */
++ /* assuming this already has been done earlier. */
++#ifdef MV_DRAM_AUTO_SIZE
++ if (MV_TARGET_IS_DRAM(target))
++ {
++ continue;
++ }
++#endif
++
++#if defined(MV_MEM_OVER_PCI_WA) || defined(MV_UART_OVER_PCI_WA)
++ /* If the target PEX or PCI and memory is over PEX or PCI we don't touch this CPU windows */
++ if (MV_TARGET_IS_PCI(target))
++ {
++ continue;
++ }
++#endif
++
++#if defined(MV_MEM_OVER_PEX_WA) || defined(MV_UART_OVER_PEX_WA)
++ /* If the target PEX or PCI and memory is over PEX or PCI we don't touch this CPU windows */
++ if (MV_TARGET_IS_PEX(target))
++ {
++ continue;
++ }
++#endif
++ /* If the target attribute is the same as the boot device attribute */
++ /* then it's stays disable */
++ if (MV_TARGET_IS_AS_BOOT(target))
++ {
++ continue;
++ }
++
++ if((0 == cpuAddrWinMap[target].addrWin.size) ||
++ (DIS == cpuAddrWinMap[target].enable))
++
++ {
++ if (MV_OK != mvCpuIfTargetWinEnable(target, MV_FALSE))
++ {
++ DB(mvOsPrintf("mvCpuIfInit:ERR. mvCpuIfTargetWinEnable fail\n"));
++ return MV_ERROR;
++ }
++
++ }
++ else
++ {
++ if (MV_OK != mvCpuIfTargetWinSet(target, &cpuAddrWinMap[target]))
++ {
++ DB(mvOsPrintf("mvCpuIfInit:ERR. mvCpuIfTargetWinSet fail\n"));
++ return MV_ERROR;
++ }
++
++ addrWin.baseLow = cpuAddrWinMap[target].addrWin.baseLow;
++ addrWin.baseHigh = cpuAddrWinMap[target].addrWin.baseHigh;
++ if (0xffffffff == mvAhbToMbusWinRemap(cpuAddrWinMap[target].winNum ,&addrWin))
++ {
++ DB(mvOsPrintf("mvCpuIfInit:WARN. mvAhbToMbusWinRemap can't remap winNum=%d\n",
++ cpuAddrWinMap[target].winNum));
++ }
++
++
++ }
++ }
++
++ return MV_OK;
++
++
++}
++
++
++/*******************************************************************************
++* mvCpuIfTargetWinSet - Set CPU-to-peripheral target address window
++*
++* DESCRIPTION:
++* This function sets a peripheral target (e.g. SDRAM bank0, PCI0_MEM0)
++* address window, also known as address decode window.
++* A new address decode window is set for specified target address window.
++* If address decode window parameter structure enables the window,
++* the routine will also enable the target window, allowing CPU to access
++* the target window.
++*
++* INPUT:
++* target - Peripheral target enumerator.
++* pAddrDecWin - CPU target window data structure.
++*
++* OUTPUT:
++* N/A
++*
++* RETURN:
++* MV_OK if CPU target window was set correctly, MV_ERROR in case of
++* address window overlapps with other active CPU target window or
++* trying to assign 36bit base address while CPU does not support that.
++* The function returns MV_NOT_SUPPORTED, if the target is unsupported.
++*
++*******************************************************************************/
++MV_STATUS mvCpuIfTargetWinSet(MV_TARGET target, MV_CPU_DEC_WIN *pAddrDecWin)
++{
++ MV_AHB_TO_MBUS_DEC_WIN decWin;
++ MV_U32 existingWinNum;
++ MV_DRAM_DEC_WIN addrDecWin;
++
++ target = MV_CHANGE_BOOT_CS(target);
++
++ /* Check parameters */
++ if (target >= MAX_TARGETS)
++ {
++ mvOsPrintf("mvCpuIfTargetWinSet: target %d is Illigal\n", target);
++ return MV_ERROR;
++ }
++
++ /* 2) Check if the requested window overlaps with current windows */
++ if (MV_TRUE == cpuTargetWinOverlap(target, &pAddrDecWin->addrWin))
++ {
++ mvOsPrintf("mvCpuIfTargetWinSet: ERR. Target %d overlap\n", target);
++ return MV_BAD_PARAM;
++ }
++
++ if (MV_TARGET_IS_DRAM(target))
++ {
++ /* copy relevant data to MV_DRAM_DEC_WIN structure */
++ addrDecWin.addrWin.baseHigh = pAddrDecWin->addrWin.baseHigh;
++ addrDecWin.addrWin.baseLow = pAddrDecWin->addrWin.baseLow;
++ addrDecWin.addrWin.size = pAddrDecWin->addrWin.size;
++ addrDecWin.enable = pAddrDecWin->enable;
++
++
++ if (mvDramIfWinSet(target,&addrDecWin) != MV_OK);
++ {
++ mvOsPrintf("mvCpuIfTargetWinSet: mvDramIfWinSet Failed\n");
++ return MV_ERROR;
++ }
++
++ }
++ else
++ {
++ /* copy relevant data to MV_AHB_TO_MBUS_DEC_WIN structure */
++ decWin.addrWin.baseLow = pAddrDecWin->addrWin.baseLow;
++ decWin.addrWin.baseHigh = pAddrDecWin->addrWin.baseHigh;
++ decWin.addrWin.size = pAddrDecWin->addrWin.size;
++ decWin.enable = pAddrDecWin->enable;
++ decWin.target = target;
++
++ existingWinNum = mvAhbToMbusWinTargetGet(target);
++
++ /* check if there is already another Window configured
++ for this target */
++ if ((existingWinNum < MAX_AHB_TO_MBUS_WINS )&&
++ (existingWinNum != pAddrDecWin->winNum))
++ {
++ /* if we want to enable the new winow number
++ passed by the user , then the old one should
++ be disabled */
++ if (MV_TRUE == pAddrDecWin->enable)
++ {
++ /* be sure it is disabled */
++ mvAhbToMbusWinEnable(existingWinNum , MV_FALSE);
++ }
++ }
++
++ if (mvAhbToMbusWinSet(pAddrDecWin->winNum,&decWin) != MV_OK)
++ {
++ mvOsPrintf("mvCpuIfTargetWinSet: mvAhbToMbusWinSet Failed\n");
++ return MV_ERROR;
++ }
++
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCpuIfTargetWinGet - Get CPU-to-peripheral target address window
++*
++* DESCRIPTION:
++* Get the CPU peripheral target address window.
++*
++* INPUT:
++* target - Peripheral target enumerator
++*
++* OUTPUT:
++* pAddrDecWin - CPU target window information data structure.
++*
++* RETURN:
++* MV_OK if target exist, MV_ERROR otherwise.
++*
++*******************************************************************************/
++MV_STATUS mvCpuIfTargetWinGet(MV_TARGET target, MV_CPU_DEC_WIN *pAddrDecWin)
++{
++
++ MV_U32 winNum=0xffffffff;
++ MV_AHB_TO_MBUS_DEC_WIN decWin;
++ MV_DRAM_DEC_WIN addrDecWin;
++
++ target = MV_CHANGE_BOOT_CS(target);
++
++ /* Check parameters */
++ if (target >= MAX_TARGETS)
++ {
++ mvOsPrintf("mvCpuIfTargetWinGet: target %d is Illigal\n", target);
++ return MV_ERROR;
++ }
++
++ if (MV_TARGET_IS_DRAM(target))
++ {
++ if (mvDramIfWinGet(target,&addrDecWin) != MV_OK)
++ {
++ mvOsPrintf("mvCpuIfTargetWinGet: Failed to get window target %d\n",
++ target);
++ return MV_ERROR;
++ }
++
++ /* copy relevant data to MV_CPU_DEC_WIN structure */
++ pAddrDecWin->addrWin.baseLow = addrDecWin.addrWin.baseLow;
++ pAddrDecWin->addrWin.baseHigh = addrDecWin.addrWin.baseHigh;
++ pAddrDecWin->addrWin.size = addrDecWin.addrWin.size;
++ pAddrDecWin->enable = addrDecWin.enable;
++ pAddrDecWin->winNum = 0xffffffff;
++
++ }
++ else
++ {
++ /* get the Window number associated with this target */
++
++ winNum = mvAhbToMbusWinTargetGet(target);
++ if (winNum >= MAX_AHB_TO_MBUS_WINS)
++ {
++ return MV_NO_SUCH;
++
++ }
++
++ if (mvAhbToMbusWinGet(winNum , &decWin) != MV_OK)
++ {
++ mvOsPrintf("%s: mvAhbToMbusWinGet Failed at winNum = %d\n",
++ __FUNCTION__, winNum);
++ return MV_ERROR;
++
++ }
++
++ /* copy relevant data to MV_CPU_DEC_WIN structure */
++ pAddrDecWin->addrWin.baseLow = decWin.addrWin.baseLow;
++ pAddrDecWin->addrWin.baseHigh = decWin.addrWin.baseHigh;
++ pAddrDecWin->addrWin.size = decWin.addrWin.size;
++ pAddrDecWin->enable = decWin.enable;
++ pAddrDecWin->winNum = winNum;
++
++ }
++
++
++
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvCpuIfTargetWinEnable - Enable/disable a CPU address decode window
++*
++* DESCRIPTION:
++* This function enable/disable a CPU address decode window.
++* if parameter 'enable' == MV_TRUE the routine will enable the
++* window, thus enabling CPU accesses (before enabling the window it is
++* tested for overlapping). Otherwise, the window will be disabled.
++*
++* INPUT:
++* target - Peripheral target enumerator.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* N/A
++*
++* RETURN:
++* MV_ERROR if protection window number was wrong, or the window
++* overlapps other target window.
++*
++*******************************************************************************/
++MV_STATUS mvCpuIfTargetWinEnable(MV_TARGET target,MV_BOOL enable)
++{
++ MV_U32 winNum, temp;
++ MV_CPU_DEC_WIN addrDecWin;
++
++ target = MV_CHANGE_BOOT_CS(target);
++
++ /* Check parameters */
++ if (target >= MAX_TARGETS)
++ {
++ mvOsPrintf("mvCpuIfTargetWinEnable: target %d is Illigal\n", target);
++ return MV_ERROR;
++ }
++
++ /* get the window and check if it exist */
++ temp = mvCpuIfTargetWinGet(target, &addrDecWin);
++ if (MV_NO_SUCH == temp)
++ {
++ return (enable? MV_ERROR: MV_OK);
++ }
++ else if( MV_OK != temp)
++ {
++ mvOsPrintf("%s: ERR. Getting target %d failed.\n",__FUNCTION__, target);
++ return MV_ERROR;
++ }
++
++
++ /* check overlap */
++
++ if (MV_TRUE == enable)
++ {
++ if (MV_TRUE == cpuTargetWinOverlap(target, &addrDecWin.addrWin))
++ {
++ DB(mvOsPrintf("%s: ERR. Target %d overlap\n",__FUNCTION__, target));
++ return MV_ERROR;
++ }
++
++ }
++
++
++ if (MV_TARGET_IS_DRAM(target))
++ {
++ if (mvDramIfWinEnable(target , enable) != MV_OK)
++ {
++ mvOsPrintf("mvCpuIfTargetWinGet: mvDramIfWinEnable Failed at \n");
++ return MV_ERROR;
++
++ }
++
++ }
++ else
++ {
++ /* get the Window number associated with this target */
++
++ winNum = mvAhbToMbusWinTargetGet(target);
++
++ if (winNum >= MAX_AHB_TO_MBUS_WINS)
++ {
++ return (enable? MV_ERROR: MV_OK);
++ }
++
++ if (mvAhbToMbusWinEnable(winNum , enable) != MV_OK)
++ {
++ mvOsPrintf("mvCpuIfTargetWinGet: Failed to enable window = %d\n",
++ winNum);
++ return MV_ERROR;
++
++ }
++
++ }
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvCpuIfTargetWinSizeGet - Get CPU target address window size
++*
++* DESCRIPTION:
++* Get the size of CPU-to-peripheral target window.
++*
++* INPUT:
++* target - Peripheral target enumerator
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit size. Function also returns '0' if window is closed.
++* Function returns 0xFFFFFFFF in case of an error.
++*
++*******************************************************************************/
++MV_U32 mvCpuIfTargetWinSizeGet(MV_TARGET target)
++{
++ MV_CPU_DEC_WIN addrDecWin;
++
++ target = MV_CHANGE_BOOT_CS(target);
++
++ /* Check parameters */
++ if (target >= MAX_TARGETS)
++ {
++ mvOsPrintf("mvCpuIfTargetWinSizeGet: target %d is Illigal\n", target);
++ return 0;
++ }
++
++ /* Get the winNum window */
++ if (MV_OK != mvCpuIfTargetWinGet(target, &addrDecWin))
++ {
++ mvOsPrintf("mvCpuIfTargetWinSizeGet:ERR. Getting target %d failed.\n",
++ target);
++ return 0;
++ }
++
++ /* Check if window is enabled */
++ if (addrDecWin.enable == MV_TRUE)
++ {
++ return (addrDecWin.addrWin.size);
++ }
++ else
++ {
++ return 0; /* Window disabled. return 0 */
++ }
++}
++
++/*******************************************************************************
++* mvCpuIfTargetWinBaseLowGet - Get CPU target address window base low
++*
++* DESCRIPTION:
++* CPU-to-peripheral target address window base is constructed of
++* two parts: Low and high.
++* This function gets the CPU peripheral target low base address.
++*
++* INPUT:
++* target - Peripheral target enumerator
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit low base address.
++*
++*******************************************************************************/
++MV_U32 mvCpuIfTargetWinBaseLowGet(MV_TARGET target)
++{
++ MV_CPU_DEC_WIN addrDecWin;
++
++ target = MV_CHANGE_BOOT_CS(target);
++
++ /* Check parameters */
++ if (target >= MAX_TARGETS)
++ {
++ mvOsPrintf("mvCpuIfTargetWinBaseLowGet: target %d is Illigal\n", target);
++ return 0xffffffff;
++ }
++
++ /* Get the target window */
++ if (MV_OK != mvCpuIfTargetWinGet(target, &addrDecWin))
++ {
++ mvOsPrintf("mvCpuIfTargetWinBaseLowGet:ERR. Getting target %d failed.\n",
++ target);
++ return 0xffffffff;
++ }
++
++ if (MV_FALSE == addrDecWin.enable)
++ {
++ return 0xffffffff;
++ }
++ return (addrDecWin.addrWin.baseLow);
++}
++
++/*******************************************************************************
++* mvCpuIfTargetWinBaseHighGet - Get CPU target address window base high
++*
++* DESCRIPTION:
++* CPU-to-peripheral target address window base is constructed of
++* two parts: Low and high.
++* This function gets the CPU peripheral target high base address.
++*
++* INPUT:
++* target - Peripheral target enumerator
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit high base address.
++*
++*******************************************************************************/
++MV_U32 mvCpuIfTargetWinBaseHighGet(MV_TARGET target)
++{
++ MV_CPU_DEC_WIN addrDecWin;
++
++ target = MV_CHANGE_BOOT_CS(target);
++
++ /* Check parameters */
++ if (target >= MAX_TARGETS)
++ {
++ mvOsPrintf("mvCpuIfTargetWinBaseLowGet: target %d is Illigal\n", target);
++ return 0xffffffff;
++ }
++
++ /* Get the target window */
++ if (MV_OK != mvCpuIfTargetWinGet(target, &addrDecWin))
++ {
++ mvOsPrintf("mvCpuIfTargetWinBaseHighGet:ERR. Getting target %d failed.\n",
++ target);
++ return 0xffffffff;
++ }
++
++ if (MV_FALSE == addrDecWin.enable)
++ {
++ return 0;
++ }
++
++ return (addrDecWin.addrWin.baseHigh);
++}
++
++#if defined(MV_INCLUDE_PEX)
++/*******************************************************************************
++* mvCpuIfPexRemap - Set CPU remap register for address windows.
++*
++* DESCRIPTION:
++*
++* INPUT:
++* pexTarget - Peripheral target enumerator. Must be a PEX target.
++* pAddrDecWin - CPU target window information data structure.
++* Note that caller has to fill in the base field only. The
++* size field is ignored.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if target is not a PEX one, MV_OK otherwise.
++*
++*******************************************************************************/
++MV_U32 mvCpuIfPexRemap(MV_TARGET pexTarget, MV_ADDR_WIN *pAddrDecWin)
++{
++ MV_U32 winNum;
++
++ /* Check parameters */
++
++ if (mvCtrlPexMaxIfGet() > 1)
++ {
++ if ((!MV_TARGET_IS_PEX1(pexTarget))&&(!MV_TARGET_IS_PEX0(pexTarget)))
++ {
++ mvOsPrintf("mvCpuIfPexRemap: target %d is Illigal\n",pexTarget);
++ return 0xffffffff;
++ }
++
++ }
++ else
++ {
++ if (!MV_TARGET_IS_PEX0(pexTarget))
++ {
++ mvOsPrintf("mvCpuIfPexRemap: target %d is Illigal\n",pexTarget);
++ return 0xffffffff;
++ }
++
++ }
++
++ /* get the Window number associated with this target */
++ winNum = mvAhbToMbusWinTargetGet(pexTarget);
++
++ if (winNum >= MAX_AHB_TO_MBUS_WINS)
++ {
++ mvOsPrintf("mvCpuIfPexRemap: mvAhbToMbusWinTargetGet Failed\n");
++ return 0xffffffff;
++
++ }
++
++ return mvAhbToMbusWinRemap(winNum , pAddrDecWin);
++}
++
++#endif
++
++#if defined(MV_INCLUDE_PCI)
++/*******************************************************************************
++* mvCpuIfPciRemap - Set CPU remap register for address windows.
++*
++* DESCRIPTION:
++*
++* INPUT:
++* pciTarget - Peripheral target enumerator. Must be a PCI target.
++* pAddrDecWin - CPU target window information data structure.
++* Note that caller has to fill in the base field only. The
++* size field is ignored.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if target is not a PCI one, MV_OK otherwise.
++*
++*******************************************************************************/
++MV_U32 mvCpuIfPciRemap(MV_TARGET pciTarget, MV_ADDR_WIN *pAddrDecWin)
++{
++ MV_U32 winNum;
++
++ /* Check parameters */
++ if (!MV_TARGET_IS_PCI(pciTarget))
++ {
++ mvOsPrintf("mvCpuIfPciRemap: target %d is Illigal\n",pciTarget);
++ return 0xffffffff;
++ }
++
++ /* get the Window number associated with this target */
++ winNum = mvAhbToMbusWinTargetGet(pciTarget);
++
++ if (winNum >= MAX_AHB_TO_MBUS_WINS)
++ {
++ mvOsPrintf("mvCpuIfPciRemap: mvAhbToMbusWinTargetGet Failed\n");
++ return 0xffffffff;
++
++ }
++
++ return mvAhbToMbusWinRemap(winNum , pAddrDecWin);
++}
++#endif /* MV_INCLUDE_PCI */
++
++
++/*******************************************************************************
++* mvCpuIfPciIfRemap - Set CPU remap register for address windows.
++*
++* DESCRIPTION:
++*
++* INPUT:
++* pciTarget - Peripheral target enumerator. Must be a PCI target.
++* pAddrDecWin - CPU target window information data structure.
++* Note that caller has to fill in the base field only. The
++* size field is ignored.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if target is not a PCI one, MV_OK otherwise.
++*
++*******************************************************************************/
++MV_U32 mvCpuIfPciIfRemap(MV_TARGET pciIfTarget, MV_ADDR_WIN *pAddrDecWin)
++{
++#if defined(MV_INCLUDE_PEX)
++ if (MV_TARGET_IS_PEX(pciIfTarget))
++ {
++ return mvCpuIfPexRemap(pciIfTarget,pAddrDecWin);
++ }
++#endif
++#if defined(MV_INCLUDE_PCI)
++
++ if (MV_TARGET_IS_PCI(pciIfTarget))
++ {
++ return mvCpuIfPciRemap(pciIfTarget,pAddrDecWin);
++ }
++#endif
++ return 0;
++}
++
++
++
++/*******************************************************************************
++* mvCpuIfTargetOfBaseAddressGet - Get the target according to base address
++*
++* DESCRIPTION:
++*
++* INPUT:
++* baseAddress - base address to be checked
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* the target number that baseAddress belongs to or MAX_TARGETS is not
++* found
++*
++*******************************************************************************/
++
++MV_TARGET mvCpuIfTargetOfBaseAddressGet(MV_U32 baseAddress)
++{
++ MV_CPU_DEC_WIN win;
++ MV_U32 target;
++
++ for( target = 0; target < MAX_TARGETS; target++ )
++ {
++ if( mvCpuIfTargetWinGet( target, &win ) == MV_OK )
++ {
++ if( win.enable )
++ {
++ if ((baseAddress >= win.addrWin.baseLow) &&
++ (baseAddress < win.addrWin.baseLow + win.addrWin.size)) break;
++ }
++ }
++ else return MAX_TARGETS;
++
++ }
++
++ return target;
++}
++/*******************************************************************************
++* cpuTargetWinOverlap - Detect CPU address decode windows overlapping
++*
++* DESCRIPTION:
++* An unpredicted behaviur is expected in case CPU address decode
++* windows overlapps.
++* This function detects CPU address decode windows overlapping of a
++* specified target. The function does not check the target itself for
++* overlapping. The function also skipps disabled address decode windows.
++*
++* INPUT:
++* target - Peripheral target enumerator.
++* pAddrDecWin - An address decode window struct.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlaps current address
++* decode map, MV_FALSE otherwise.
++*
++*******************************************************************************/
++static MV_BOOL cpuTargetWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 targetNum;
++ MV_CPU_DEC_WIN addrDecWin;
++ MV_STATUS status;
++
++
++ for(targetNum = 0; targetNum < MAX_TARGETS; targetNum++)
++ {
++#if defined(MV_RUN_FROM_FLASH)
++ if(MV_TARGET_IS_AS_BOOT(target))
++ {
++ if (MV_CHANGE_BOOT_CS(targetNum) == target)
++ continue;
++ }
++#endif /* MV_RUN_FROM_FLASH */
++
++ /* don't check our target or illegal targets */
++ if (targetNum == target)
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ status = mvCpuIfTargetWinGet(targetNum, &addrDecWin);
++ if(MV_NO_SUCH == status)
++ {
++ continue;
++ }
++ if(MV_OK != status)
++ {
++ DB(mvOsPrintf("cpuTargetWinOverlap: ERR. TargetWinGet failed\n"));
++ return MV_TRUE;
++ }
++
++ /* Do not check disabled windows */
++ if (MV_FALSE == addrDecWin.enable)
++ {
++ continue;
++ }
++
++ if(MV_TRUE == ctrlWinOverlapTest(pAddrWin, &addrDecWin.addrWin))
++ {
++ DB(mvOsPrintf(
++ "cpuTargetWinOverlap: Required target %d overlap current %d\n",
++ target, targetNum));
++ return MV_TRUE;
++ }
++ }
++
++ return MV_FALSE;
++
++}
++
++/*******************************************************************************
++* mvCpuIfAddDecShow - Print the CPU address decode map.
++*
++* DESCRIPTION:
++* This function print the CPU address decode map.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvCpuIfAddDecShow(MV_VOID)
++{
++ MV_CPU_DEC_WIN win;
++ MV_U32 target;
++ mvOsOutput( "\n" );
++ mvOsOutput( "CPU Interface\n" );
++ mvOsOutput( "-------------\n" );
++
++ for( target = 0; target < MAX_TARGETS; target++ )
++ {
++
++ memset( &win, 0, sizeof(MV_CPU_DEC_WIN) );
++
++ mvOsOutput( "%s ",mvCtrlTargetNameGet(target));
++ mvOsOutput( "...." );
++
++ if( mvCpuIfTargetWinGet( target, &win ) == MV_OK )
++ {
++ if( win.enable )
++ {
++ mvOsOutput( "base %08x, ", win.addrWin.baseLow );
++ mvSizePrint( win.addrWin.size );
++ mvOsOutput( "\n" );
++
++ }
++ else
++ mvOsOutput( "disable\n" );
++ }
++ else if( mvCpuIfTargetWinGet( target, &win ) == MV_NO_SUCH )
++ {
++ mvOsOutput( "no such\n" );
++ }
++ }
++}
++
++/*******************************************************************************
++* mvCpuIfEnablePex - Enable PCI Express.
++*
++* DESCRIPTION:
++* This function Enable PCI Express.
++*
++* INPUT:
++* pexIf - PEX interface number.
++* pexType - MV_PEX_ROOT_COMPLEX - root complex device
++* MV_PEX_END_POINT - end point device
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++#if defined(MV_INCLUDE_PEX)
++MV_VOID mvCpuIfEnablePex(MV_U32 pexIf, MV_PEX_TYPE pexType)
++{
++ /* Set pex mode incase S@R not exist */
++ if( pexType == MV_PEX_END_POINT)
++ {
++ MV_REG_BIT_RESET(PEX_CTRL_REG(pexIf),PXCR_DEV_TYPE_CTRL_MASK);
++ /* Change pex mode in capability reg */
++ MV_REG_BIT_RESET(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_CAPABILITY_REG), BIT22);
++ MV_REG_BIT_SET(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_CAPABILITY_REG), BIT20);
++
++ }
++ else
++ {
++ MV_REG_BIT_SET(PEX_CTRL_REG(pexIf),PXCR_DEV_TYPE_CTRL_MASK);
++ }
++
++ /* CPU config register Pex enable */
++ MV_REG_BIT_SET(CPU_CTRL_STAT_REG,CCSR_PCI_ACCESS_MASK);
++}
++#endif
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.h 2010-11-09 20:28:07.982495689 +0100
+@@ -0,0 +1,120 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvCpuIfh
++#define __INCmvCpuIfh
++
++/* includes */
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/sys/mvCpuIfRegs.h"
++#include "ctrlEnv/sys/mvAhbToMbus.h"
++#include "ddr2/mvDramIf.h"
++#include "ctrlEnv/sys/mvSysDram.h"
++#if defined(MV_INCLUDE_PEX)
++#include "pex/mvPex.h"
++#endif
++
++/* defines */
++
++/* typedefs */
++/* This structure describes CPU interface address decode window */
++typedef struct _mvCpuIfDecWin
++{
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_U32 winNum; /* Window Number in the AHB To Mbus bridge */
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++
++}MV_CPU_DEC_WIN;
++
++
++
++/* mvCpuIfLib.h API list */
++
++/* mvCpuIfLib.h API list */
++
++MV_STATUS mvCpuIfInit(MV_CPU_DEC_WIN *cpuAddrWinMap);
++MV_STATUS mvCpuIfTargetWinSet(MV_TARGET target, MV_CPU_DEC_WIN *pAddrDecWin);
++MV_STATUS mvCpuIfTargetWinGet(MV_TARGET target, MV_CPU_DEC_WIN *pAddrDecWin);
++MV_STATUS mvCpuIfTargetWinEnable(MV_TARGET target,MV_BOOL enable);
++MV_U32 mvCpuIfTargetWinSizeGet(MV_TARGET target);
++MV_U32 mvCpuIfTargetWinBaseLowGet(MV_TARGET target);
++MV_U32 mvCpuIfTargetWinBaseHighGet(MV_TARGET target);
++MV_TARGET mvCpuIfTargetOfBaseAddressGet(MV_U32 baseAddress);
++#if defined(MV_INCLUDE_PEX)
++MV_U32 mvCpuIfPexRemap(MV_TARGET pexTarget, MV_ADDR_WIN *pAddrDecWin);
++MV_VOID mvCpuIfEnablePex(MV_U32 pexIf, MV_PEX_TYPE pexType);
++#endif
++#if defined(MV_INCLUDE_PCI)
++MV_U32 mvCpuIfPciRemap(MV_TARGET pciTarget, MV_ADDR_WIN *pAddrDecWin);
++#endif
++MV_U32 mvCpuIfPciIfRemap(MV_TARGET pciTarget, MV_ADDR_WIN *pAddrDecWin);
++
++MV_VOID mvCpuIfAddDecShow(MV_VOID);
++
++#if defined(MV88F6281)
++MV_STATUS mvCpuIfBridgeReorderWAInit(void);
++#endif
++
++#endif /* __INCmvCpuIfh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfRegs.h 2010-11-09 20:28:08.012495399 +0100
+@@ -0,0 +1,304 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvCpuIfRegsh
++#define __INCmvCpuIfRegsh
++
++/****************************************/
++/* ARM Control and Status Registers Map */
++/****************************************/
++
++#define CPU_CONFIG_REG 0x20100
++#define CPU_CTRL_STAT_REG 0x20104
++#define CPU_RSTOUTN_MASK_REG 0x20108
++#define CPU_SYS_SOFT_RST_REG 0x2010C
++#define CPU_AHB_MBUS_CAUSE_INT_REG 0x20110
++#define CPU_AHB_MBUS_MASK_INT_REG 0x20114
++#define CPU_FTDLL_CONFIG_REG 0x20120
++#define CPU_L2_CONFIG_REG 0x20128
++
++
++
++/* ARM Configuration register */
++/* CPU_CONFIG_REG (CCR) */
++
++
++/* Reset vector location */
++#define CCR_VEC_INIT_LOC_OFFS 1
++#define CCR_VEC_INIT_LOC_MASK BIT1
++/* reset at 0x00000000 */
++#define CCR_VEC_INIT_LOC_0000 (0 << CCR_VEC_INIT_LOC_OFFS)
++/* reset at 0xFFFF0000 */
++#define CCR_VEC_INIT_LOC_FF00 (1 << CCR_VEC_INIT_LOC_OFFS)
++
++
++#define CCR_AHB_ERROR_PROP_OFFS 2
++#define CCR_AHB_ERROR_PROP_MASK BIT2
++/* Erros are not propogated to AHB */
++#define CCR_AHB_ERROR_PROP_NO_INDICATE (0 << CCR_AHB_ERROR_PROP_OFFS)
++/* Erros are propogated to AHB */
++#define CCR_AHB_ERROR_PROP_INDICATE (1 << CCR_AHB_ERROR_PROP_OFFS)
++
++
++#define CCR_ENDIAN_INIT_OFFS 3
++#define CCR_ENDIAN_INIT_MASK BIT3
++#define CCR_ENDIAN_INIT_LITTLE (0 << CCR_ENDIAN_INIT_OFFS)
++#define CCR_ENDIAN_INIT_BIG (1 << CCR_ENDIAN_INIT_OFFS)
++
++
++#define CCR_INCR_EN_OFFS 4
++#define CCR_INCR_EN_MASK BIT4
++#define CCR_INCR_EN BIT4
++
++
++#define CCR_NCB_BLOCKING_OFFS 5
++#define CCR_NCB_BLOCKING_MASK (1 << CCR_NCB_BLOCKING_OFFS)
++#define CCR_NCB_BLOCKING_NON (0 << CCR_NCB_BLOCKING_OFFS)
++#define CCR_NCB_BLOCKING_EN (1 << CCR_NCB_BLOCKING_OFFS)
++
++#define CCR_CPU_2_MBUSL_TICK_DRV_OFFS 8
++#define CCR_CPU_2_MBUSL_TICK_DRV_MASK (0xF << CCR_CPU_2_MBUSL_TICK_DRV_OFFS)
++#define CCR_CPU_2_MBUSL_TICK_SMPL_OFFS 12
++#define CCR_CPU_2_MBUSL_TICK_SMPL_MASK (0xF << CCR_CPU_2_MBUSL_TICK_SMPL_OFFS)
++#define CCR_ICACH_PREF_BUF_ENABLE BIT16
++#define CCR_DCACH_PREF_BUF_ENABLE BIT17
++
++/* Ratio options for CPU to DDR for 6281/6192/6190 */
++#define CPU_2_DDR_CLK_1x3 4
++#define CPU_2_DDR_CLK_1x4 6
++
++/* Ratio options for CPU to DDR for 6281 only */
++#define CPU_2_DDR_CLK_2x9 7
++#define CPU_2_DDR_CLK_1x5 8
++#define CPU_2_DDR_CLK_1x6 9
++
++/* Ratio options for CPU to DDR for 6180 only */
++#define CPU_2_DDR_CLK_1x3_1 0x5
++#define CPU_2_DDR_CLK_1x4_1 0x6
++
++/* Default values for CPU to Mbus-L DDR Interface Tick Driver and */
++/* CPU to Mbus-L Tick Sample fields in CPU config register */
++
++#define TICK_DRV_1x1 0
++#define TICK_DRV_1x2 0
++#define TICK_DRV_1x3 1
++#define TICK_DRV_1x4 2
++#define TICK_SMPL_1x1 0
++#define TICK_SMPL_1x2 1
++#define TICK_SMPL_1x3 0
++#define TICK_SMPL_1x4 0
++
++#define CPU_2_MBUSL_DDR_CLK_1x2 \
++ ((TICK_DRV_1x2 << CCR_CPU_2_MBUSL_TICK_DRV_OFFS) | \
++ (TICK_SMPL_1x2 << CCR_CPU_2_MBUSL_TICK_SMPL_OFFS))
++#define CPU_2_MBUSL_DDR_CLK_1x3 \
++ ((TICK_DRV_1x3 << CCR_CPU_2_MBUSL_TICK_DRV_OFFS) | \
++ (TICK_SMPL_1x3 << CCR_CPU_2_MBUSL_TICK_SMPL_OFFS))
++#define CPU_2_MBUSL_DDR_CLK_1x4 \
++ ((TICK_DRV_1x4 << CCR_CPU_2_MBUSL_TICK_DRV_OFFS) | \
++ (TICK_SMPL_1x4 << CCR_CPU_2_MBUSL_TICK_SMPL_OFFS))
++
++/* ARM Control and Status register */
++/* CPU_CTRL_STAT_REG (CCSR) */
++
++
++/*
++This is used to block PCI express\PCI from access Socrates/Feroceon GP
++while ARM boot is still in progress
++*/
++
++#define CCSR_PCI_ACCESS_OFFS 0
++#define CCSR_PCI_ACCESS_MASK BIT0
++#define CCSR_PCI_ACCESS_ENABLE (0 << CCSR_PCI_ACCESS_OFFS)
++#define CCSR_PCI_ACCESS_DISBALE (1 << CCSR_PCI_ACCESS_OFFS)
++
++#define CCSR_ARM_RESET BIT1
++#define CCSR_SELF_INT BIT2
++#define CCSR_BIG_ENDIAN BIT15
++
++
++/* RSTOUTn Mask Register */
++/* CPU_RSTOUTN_MASK_REG (CRMR) */
++
++#define CRMR_PEX_RST_OUT_OFFS 0
++#define CRMR_PEX_RST_OUT_MASK BIT0
++#define CRMR_PEX_RST_OUT_ENABLE (1 << CRMR_PEX_RST_OUT_OFFS)
++#define CRMR_PEX_RST_OUT_DISABLE (0 << CRMR_PEX_RST_OUT_OFFS)
++
++#define CRMR_WD_RST_OUT_OFFS 1
++#define CRMR_WD_RST_OUT_MASK BIT1
++#define CRMR_WD_RST_OUT_ENABLE (1 << CRMR_WD_RST_OUT_OFFS)
++#define CRMR_WD_RST_OUT_DISBALE (0 << CRMR_WD_RST_OUT_OFFS)
++
++#define CRMR_SOFT_RST_OUT_OFFS 2
++#define CRMR_SOFT_RST_OUT_MASK BIT2
++#define CRMR_SOFT_RST_OUT_ENABLE (1 << CRMR_SOFT_RST_OUT_OFFS)
++#define CRMR_SOFT_RST_OUT_DISBALE (0 << CRMR_SOFT_RST_OUT_OFFS)
++
++/* System Software Reset Register */
++/* CPU_SYS_SOFT_RST_REG (CSSRR) */
++
++#define CSSRR_SYSTEM_SOFT_RST BIT0
++
++/* AHB to Mbus Bridge Interrupt Cause Register*/
++/* CPU_AHB_MBUS_CAUSE_INT_REG (CAMCIR) */
++
++#define CAMCIR_ARM_SELF_INT BIT0
++#define CAMCIR_ARM_TIMER0_INT_REQ BIT1
++#define CAMCIR_ARM_TIMER1_INT_REQ BIT2
++#define CAMCIR_ARM_WD_TIMER_INT_REQ BIT3
++
++
++/* AHB to Mbus Bridge Interrupt Mask Register*/
++/* CPU_AHB_MBUS_MASK_INT_REG (CAMMIR) */
++
++#define CAMCIR_ARM_SELF_INT_OFFS 0
++#define CAMCIR_ARM_SELF_INT_MASK BIT0
++#define CAMCIR_ARM_SELF_INT_EN (1 << CAMCIR_ARM_SELF_INT_OFFS)
++#define CAMCIR_ARM_SELF_INT_DIS (0 << CAMCIR_ARM_SELF_INT_OFFS)
++
++
++#define CAMCIR_ARM_TIMER0_INT_REQ_OFFS 1
++#define CAMCIR_ARM_TIMER0_INT_REQ_MASK BIT1
++#define CAMCIR_ARM_TIMER0_INT_REQ_EN (1 << CAMCIR_ARM_TIMER0_INT_REQ_OFFS)
++#define CAMCIR_ARM_TIMER0_INT_REQ_DIS (0 << CAMCIR_ARM_TIMER0_INT_REQ_OFFS)
++
++#define CAMCIR_ARM_TIMER1_INT_REQ_OFFS 2
++#define CAMCIR_ARM_TIMER1_INT_REQ_MASK BIT2
++#define CAMCIR_ARM_TIMER1_INT_REQ_EN (1 << CAMCIR_ARM_TIMER1_INT_REQ_OFFS)
++#define CAMCIR_ARM_TIMER1_INT_REQ_DIS (0 << CAMCIR_ARM_TIMER1_INT_REQ_OFFS)
++
++#define CAMCIR_ARM_WD_TIMER_INT_REQ_OFFS 3
++#define CAMCIR_ARM_WD_TIMER_INT_REQ_MASK BIT3
++#define CAMCIR_ARM_WD_TIMER_INT_REQ_EN (1 << CAMCIR_ARM_WD_TIMER_INT_REQ_OFFS)
++#define CAMCIR_ARM_WD_TIMER_INT_REQ_DIS (0 << CAMCIR_ARM_WD_TIMER_INT_REQ_OFFS)
++
++/* CPU FTDLL Config register (CFCR) fields */
++#define CFCR_FTDLL_ICACHE_TAG_OFFS 0
++#define CFCR_FTDLL_ICACHE_TAG_MASK (0x7F << CFCR_FTDLL_ICACHE_TAG_OFFS)
++#define CFCR_FTDLL_DCACHE_TAG_OFFS 8
++#define CFCR_FTDLL_DCACHE_TAG_MASK (0x7F << CFCR_FTDLL_DCACHE_TAG_OFFS)
++#define CFCR_FTDLL_OVERWRITE_ENABLE (1 << 15)
++/* For Orion 2 D2 only */
++#define CFCR_MRVL_CPU_ID_OFFS 16
++#define CFCR_MRVL_CPU_ID_MASK (0x1 << CFCR_MRVL_CPU_ID_OFFS)
++#define CFCR_ARM_CPU_ID (0x0 << CFCR_MRVL_CPU_ID_OFFS)
++#define CFCR_MRVL_CPU_ID (0x1 << CFCR_MRVL_CPU_ID_OFFS)
++#define CFCR_VFP_SUB_ARC_NUM_OFFS 7
++#define CFCR_VFP_SUB_ARC_NUM_MASK (0x1 << CFCR_VFP_SUB_ARC_NUM_OFFS)
++#define CFCR_VFP_SUB_ARC_NUM_1 (0x0 << CFCR_VFP_SUB_ARC_NUM_OFFS)
++#define CFCR_VFP_SUB_ARC_NUM_2 (0x1 << CFCR_VFP_SUB_ARC_NUM_OFFS)
++
++/* CPU_L2_CONFIG_REG fields */
++#ifdef MV_CPU_LE
++#define CL2CR_L2_ECC_EN_OFFS 2
++#define CL2CR_L2_WT_MODE_OFFS 4
++#else
++#define CL2CR_L2_ECC_EN_OFFS 26
++#define CL2CR_L2_WT_MODE_OFFS 28
++#endif
++
++#define CL2CR_L2_ECC_EN_MASK (1 << CL2CR_L2_ECC_EN_OFFS)
++#define CL2CR_L2_WT_MODE_MASK (1 << CL2CR_L2_WT_MODE_OFFS)
++
++/*******************************************/
++/* Main Interrupt Controller Registers Map */
++/*******************************************/
++
++#define CPU_MAIN_INT_CAUSE_REG 0x20200
++#define CPU_MAIN_IRQ_MASK_REG 0x20204
++#define CPU_MAIN_FIQ_MASK_REG 0x20208
++#define CPU_ENPOINT_MASK_REG 0x2020C
++#define CPU_MAIN_INT_CAUSE_HIGH_REG 0x20210
++#define CPU_MAIN_IRQ_MASK_HIGH_REG 0x20214
++#define CPU_MAIN_FIQ_MASK_HIGH_REG 0x20218
++#define CPU_ENPOINT_MASK_HIGH_REG 0x2021C
++
++
++/*******************************************/
++/* ARM Doorbell Registers Map */
++/*******************************************/
++
++#define CPU_HOST_TO_ARM_DRBL_REG 0x20400
++#define CPU_HOST_TO_ARM_MASK_REG 0x20404
++#define CPU_ARM_TO_HOST_DRBL_REG 0x20408
++#define CPU_ARM_TO_HOST_MASK_REG 0x2040C
++
++
++
++/* CPU control register map */
++/* Set bits means value is about to change according to new value */
++#define CPU_CONFIG_DEFAULT_MASK (CCR_VEC_INIT_LOC_MASK | CCR_AHB_ERROR_PROP_MASK)
++
++#define CPU_CONFIG_DEFAULT (CCR_VEC_INIT_LOC_FF00)
++
++/* CPU Control and status defaults */
++#define CPU_CTRL_STAT_DEFAULT_MASK (CCSR_PCI_ACCESS_MASK)
++
++
++#define CPU_CTRL_STAT_DEFAULT (CCSR_PCI_ACCESS_ENABLE)
++
++#endif /* __INCmvCpuIfRegsh */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.c 2010-11-09 20:28:08.042495347 +0100
+@@ -0,0 +1,324 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvSysAudio.h"
++
++/*******************************************************************************
++* mvAudioWinSet - Set AUDIO target address window
++*
++* DESCRIPTION:
++* This function sets a peripheral target (e.g. SDRAM bank0, PCI_MEM0)
++* address window, also known as address decode window.
++* After setting this target window, the AUDIO will be able to access the
++* target within the address window.
++*
++* INPUT:
++* winNum - AUDIO target address decode window number.
++* pAddrDecWin - AUDIO target window data structure.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if address window overlapps with other address decode windows.
++* MV_BAD_PARAM if base address is invalid parameter or target is
++* unknown.
++*
++*******************************************************************************/
++MV_STATUS mvAudioWinSet(MV_U32 winNum, MV_AUDIO_DEC_WIN *pAddrDecWin)
++{
++ MV_TARGET_ATTRIB targetAttribs;
++ MV_DEC_REGS decRegs;
++
++ /* Parameter checking */
++ if (winNum >= MV_AUDIO_MAX_ADDR_DECODE_WIN)
++ {
++ mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__, winNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* check if address is aligned to the size */
++ if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size))
++ {
++ mvOsPrintf("mvAudioWinSet:Error setting AUDIO window %d to "\
++ "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ winNum,
++ mvCtrlTargetNameGet(pAddrDecWin->target),
++ pAddrDecWin->addrWin.baseLow,
++ pAddrDecWin->addrWin.size);
++ return MV_ERROR;
++ }
++
++ decRegs.baseReg = 0;
++ decRegs.sizeReg = 0;
++
++ if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs))
++ {
++ mvOsPrintf("%s: mvCtrlAddrDecToReg Failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ mvCtrlAttribGet(pAddrDecWin->target, &targetAttribs);
++
++ /* set attributes */
++ decRegs.sizeReg &= ~MV_AUDIO_WIN_ATTR_MASK;
++ decRegs.sizeReg |= (targetAttribs.attrib << MV_AUDIO_WIN_ATTR_OFFSET);
++
++ /* set target ID */
++ decRegs.sizeReg &= ~MV_AUDIO_WIN_TARGET_MASK;
++ decRegs.sizeReg |= (targetAttribs.targetId << MV_AUDIO_WIN_TARGET_OFFSET);
++
++ if (pAddrDecWin->enable == MV_TRUE)
++ {
++ decRegs.sizeReg |= MV_AUDIO_WIN_ENABLE_MASK;
++ }
++ else
++ {
++ decRegs.sizeReg &= ~MV_AUDIO_WIN_ENABLE_MASK;
++ }
++
++ MV_REG_WRITE( MV_AUDIO_WIN_CTRL_REG(winNum), decRegs.sizeReg);
++ MV_REG_WRITE( MV_AUDIO_WIN_BASE_REG(winNum), decRegs.baseReg);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvAudioWinGet - Get AUDIO peripheral target address window.
++*
++* DESCRIPTION:
++* Get AUDIO peripheral target address window.
++*
++* INPUT:
++* winNum - AUDIO target address decode window number.
++*
++* OUTPUT:
++* pAddrDecWin - AUDIO target window data structure.
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++MV_STATUS mvAudioWinGet(MV_U32 winNum, MV_AUDIO_DEC_WIN *pAddrDecWin)
++{
++ MV_DEC_REGS decRegs;
++ MV_TARGET_ATTRIB targetAttrib;
++
++ /* Parameter checking */
++ if (winNum >= MV_AUDIO_MAX_ADDR_DECODE_WIN)
++ {
++ mvOsPrintf("%s : ERR. Invalid winNum %d\n",
++ __FUNCTION__, winNum);
++ return MV_NOT_SUPPORTED;
++ }
++
++ decRegs.baseReg = MV_REG_READ( MV_AUDIO_WIN_BASE_REG(winNum) );
++ decRegs.sizeReg = MV_REG_READ( MV_AUDIO_WIN_CTRL_REG(winNum) );
++
++ if (MV_OK != mvCtrlRegToAddrDec(&decRegs, &pAddrDecWin->addrWin) )
++ {
++ mvOsPrintf("%s: mvCtrlRegToAddrDec Failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ /* attrib and targetId */
++ targetAttrib.attrib = (decRegs.sizeReg & MV_AUDIO_WIN_ATTR_MASK) >>
++ MV_AUDIO_WIN_ATTR_OFFSET;
++ targetAttrib.targetId = (decRegs.sizeReg & MV_AUDIO_WIN_TARGET_MASK) >>
++ MV_AUDIO_WIN_TARGET_OFFSET;
++
++ pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib);
++
++ /* Check if window is enabled */
++ if(decRegs.sizeReg & MV_AUDIO_WIN_ENABLE_MASK)
++ {
++ pAddrDecWin->enable = MV_TRUE;
++ }
++ else
++ {
++ pAddrDecWin->enable = MV_FALSE;
++ }
++ return MV_OK;
++}
++/*******************************************************************************
++* mvAudioAddrDecShow - Print the AUDIO address decode map.
++*
++* DESCRIPTION:
++* This function print the AUDIO address decode map.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvAudioAddrDecShow(MV_VOID)
++{
++
++ MV_AUDIO_DEC_WIN win;
++ int i;
++
++ if (MV_FALSE == mvCtrlPwrClckGet(AUDIO_UNIT_ID, 0))
++ return;
++
++
++ mvOsOutput( "\n" );
++ mvOsOutput( "AUDIO:\n" );
++ mvOsOutput( "----\n" );
++
++ for( i = 0; i < MV_AUDIO_MAX_ADDR_DECODE_WIN; i++ )
++ {
++ memset( &win, 0, sizeof(MV_AUDIO_DEC_WIN) );
++
++ mvOsOutput( "win%d - ", i );
++
++ if( mvAudioWinGet( i, &win ) == MV_OK )
++ {
++ if( win.enable )
++ {
++ mvOsOutput( "%s base %08x, ",
++ mvCtrlTargetNameGet(win.target), win.addrWin.baseLow );
++ mvOsOutput( "...." );
++
++ mvSizePrint( win.addrWin.size );
++
++ mvOsOutput( "\n" );
++ }
++ else
++ mvOsOutput( "disable\n" );
++ }
++ }
++}
++
++
++/*******************************************************************************
++* mvAudioWinInit - Initialize the integrated AUDIO target address window.
++*
++* DESCRIPTION:
++* Initialize the AUDIO peripheral target address window.
++*
++* INPUT:
++*
++*
++* OUTPUT:
++*
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++MV_STATUS mvAudioInit(MV_VOID)
++{
++ int winNum;
++ MV_AUDIO_DEC_WIN audioWin;
++ MV_CPU_DEC_WIN cpuAddrDecWin;
++ MV_U32 status;
++
++ mvAudioHalInit();
++
++ /* Initiate Audio address decode */
++
++ /* First disable all address decode windows */
++ for(winNum = 0; winNum < MV_AUDIO_MAX_ADDR_DECODE_WIN; winNum++)
++ {
++ MV_U32 regVal = MV_REG_READ(MV_AUDIO_WIN_CTRL_REG(winNum));
++ regVal &= ~MV_AUDIO_WIN_ENABLE_MASK;
++ MV_REG_WRITE(MV_AUDIO_WIN_CTRL_REG(winNum), regVal);
++ }
++
++ for(winNum = 0; winNum < MV_AUDIO_MAX_ADDR_DECODE_WIN; winNum++)
++ {
++
++ /* We will set the Window to DRAM_CS0 in default */
++ /* first get attributes from CPU If */
++ status = mvCpuIfTargetWinGet(SDRAM_CS0,
++ &cpuAddrDecWin);
++
++ if (MV_OK != status)
++ {
++ mvOsPrintf("%s: ERR. mvCpuIfTargetWinGet failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ if (cpuAddrDecWin.enable == MV_TRUE)
++ {
++ audioWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh;
++ audioWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow;
++ audioWin.addrWin.size = cpuAddrDecWin.addrWin.size;
++ audioWin.enable = MV_TRUE;
++ audioWin.target = SDRAM_CS0;
++
++ if(MV_OK != mvAudioWinSet(winNum, &audioWin))
++ {
++ return MV_ERROR;
++ }
++ }
++ }
++
++ return MV_OK;
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.h 2010-11-09 20:28:08.082495466 +0100
+@@ -0,0 +1,123 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCMVSysAudioH
++#define __INCMVSysAudioH
++
++#include "mvCommon.h"
++#include "audio/mvAudio.h"
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++
++/***********************************/
++/* Audio Address Decoding registers*/
++/***********************************/
++
++#define MV_AUDIO_MAX_ADDR_DECODE_WIN 2
++#define MV_AUDIO_RECORD_WIN_NUM 0
++#define MV_AUDIO_PLAYBACK_WIN_NUM 1
++
++#define MV_AUDIO_WIN_CTRL_REG(win) (AUDIO_REG_BASE + 0xA04 + ((win)<<3))
++#define MV_AUDIO_WIN_BASE_REG(win) (AUDIO_REG_BASE + 0xA00 + ((win)<<3))
++
++#define MV_AUDIO_RECORD_WIN_CTRL_REG MV_AUDIO_WIN_CTRL_REG(MV_AUDIO_RECORD_WIN_NUM)
++#define MV_AUDIO_RECORD_WIN_BASE_REG MV_AUDIO_WIN_BASE_REG(MV_AUDIO_RECORD_WIN_NUM)
++#define MV_AUDIO_PLAYBACK_WIN_CTRL_REG MV_AUDIO_WIN_CTRL_REG(MV_AUDIO_PLAYBACK_WIN_NUM)
++#define MV_AUDIO_PLAYBACK_WIN_BASE_REG MV_AUDIO_WIN_BASE_REG(MV_AUDIO_PLAYBACK_WIN_NUM)
++
++
++/* BITs in Windows 0-3 Control and Base Registers */
++#define MV_AUDIO_WIN_ENABLE_BIT 0
++#define MV_AUDIO_WIN_ENABLE_MASK (1<<MV_AUDIO_WIN_ENABLE_BIT)
++
++#define MV_AUDIO_WIN_TARGET_OFFSET 4
++#define MV_AUDIO_WIN_TARGET_MASK (0xF<<MV_AUDIO_WIN_TARGET_OFFSET)
++
++#define MV_AUDIO_WIN_ATTR_OFFSET 8
++#define MV_AUDIO_WIN_ATTR_MASK (0xFF<<MV_AUDIO_WIN_ATTR_OFFSET)
++
++#define MV_AUDIO_WIN_SIZE_OFFSET 16
++#define MV_AUDIO_WIN_SIZE_MASK (0xFFFF<<MV_AUDIO_WIN_SIZE_OFFSET)
++
++#define MV_AUDIO_WIN_BASE_OFFSET 16
++#define MV_AUDIO_WIN_BASE_MASK (0xFFFF<<MV_AUDIO_WIN_BASE_OFFSET)
++
++
++typedef struct _mvAudioDecWin
++{
++ MV_TARGET target;
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++
++} MV_AUDIO_DEC_WIN;
++
++
++MV_STATUS mvAudioInit(MV_VOID);
++MV_STATUS mvAudioWinGet(MV_U32 winNum, MV_AUDIO_DEC_WIN *pAddrDecWin);
++MV_STATUS mvAudioWinSet(MV_U32 winNum, MV_AUDIO_DEC_WIN *pAddrDecWin);
++MV_STATUS mvAudioWinInit(MV_VOID);
++MV_VOID mvAudioAddrDecShow(MV_VOID);
++
++
++#endif
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.c 2010-11-09 20:28:08.121241788 +0100
+@@ -0,0 +1,382 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvSysCesa.h"
++
++#if (MV_CESA_VERSION >= 2)
++MV_TARGET tdmaAddrDecPrioTable[] =
++{
++#if defined(MV_INCLUDE_SDRAM_CS0)
++ SDRAM_CS0,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS1)
++ SDRAM_CS1,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS2)
++ SDRAM_CS2,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS3)
++ SDRAM_CS3,
++#endif
++#if defined(MV_INCLUDE_PEX)
++ PEX0_MEM,
++#endif
++
++ TBL_TERM
++};
++
++/*******************************************************************************
++* mvCesaWinGet - Get TDMA target address window.
++*
++* DESCRIPTION:
++* Get TDMA target address window.
++*
++* INPUT:
++* winNum - TDMA target address decode window number.
++*
++* OUTPUT:
++* pDecWin - TDMA target window data structure.
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++static MV_STATUS mvCesaWinGet(MV_U32 winNum, MV_DEC_WIN *pDecWin)
++{
++ MV_DEC_WIN_PARAMS winParam;
++ MV_U32 sizeReg, baseReg;
++
++ /* Parameter checking */
++ if (winNum >= MV_CESA_TDMA_ADDR_DEC_WIN)
++ {
++ mvOsPrintf("%s : ERR. Invalid winNum %d\n",
++ __FUNCTION__, winNum);
++ return MV_NOT_SUPPORTED;
++ }
++
++ baseReg = MV_REG_READ( MV_CESA_TDMA_BASE_ADDR_REG(winNum) );
++ sizeReg = MV_REG_READ( MV_CESA_TDMA_WIN_CTRL_REG(winNum) );
++
++ /* Check if window is enabled */
++ if(sizeReg & MV_CESA_TDMA_WIN_ENABLE_MASK)
++ {
++ pDecWin->enable = MV_TRUE;
++
++ /* Extract window parameters from registers */
++ winParam.targetId = (sizeReg & MV_CESA_TDMA_WIN_TARGET_MASK) >> MV_CESA_TDMA_WIN_TARGET_OFFSET;
++ winParam.attrib = (sizeReg & MV_CESA_TDMA_WIN_ATTR_MASK) >> MV_CESA_TDMA_WIN_ATTR_OFFSET;
++ winParam.size = (sizeReg & MV_CESA_TDMA_WIN_SIZE_MASK) >> MV_CESA_TDMA_WIN_SIZE_OFFSET;
++ winParam.baseAddr = (baseReg & MV_CESA_TDMA_WIN_BASE_MASK);
++
++ /* Translate the decode window parameters to address decode struct */
++ if (MV_OK != mvCtrlParamsToAddrDec(&winParam, pDecWin))
++ {
++ mvOsPrintf("Failed to translate register parameters to CESA address" \
++ " decode window structure\n");
++ return MV_ERROR;
++ }
++ }
++ else
++ {
++ pDecWin->enable = MV_FALSE;
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* cesaWinOverlapDetect - Detect CESA TDMA address windows overlapping
++*
++* DESCRIPTION:
++* An unpredicted behaviur is expected in case TDMA address decode
++* windows overlapps.
++* This function detects TDMA address decode windows overlapping of a
++* specified window. The function does not check the window itself for
++* overlapping. The function also skipps disabled address decode windows.
++*
++* INPUT:
++* winNum - address decode window number.
++* pAddrDecWin - An address decode window struct.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE - if the given address window overlap current address
++* decode map,
++* MV_FALSE - otherwise, MV_ERROR if reading invalid data
++* from registers.
++*
++*******************************************************************************/
++static MV_STATUS cesaWinOverlapDetect(MV_U32 winNum, MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 winNumIndex;
++ MV_DEC_WIN addrDecWin;
++
++ for(winNumIndex=0; winNumIndex<MV_CESA_TDMA_ADDR_DEC_WIN; winNumIndex++)
++ {
++ /* Do not check window itself */
++ if (winNumIndex == winNum)
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ if (MV_OK != mvCesaWinGet(winNumIndex, &addrDecWin))
++ {
++ mvOsPrintf("%s: ERR. TargetWinGet failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ /* Do not check disabled windows */
++ if(addrDecWin.enable == MV_FALSE)
++ {
++ continue;
++ }
++
++ if (MV_TRUE == ctrlWinOverlapTest(pAddrWin, &(addrDecWin.addrWin)))
++ {
++ return MV_TRUE;
++ }
++ }
++ return MV_FALSE;
++}
++
++/*******************************************************************************
++* mvCesaTdmaWinSet - Set CESA TDMA target address window
++*
++* DESCRIPTION:
++* This function sets a peripheral target (e.g. SDRAM bank0, PCI_MEM0)
++* address window, also known as address decode window.
++* After setting this target window, the CESA TDMA will be able to access the
++* target within the address window.
++*
++* INPUT:
++* winNum - CESA TDMA target address decode window number.
++* pAddrDecWin - CESA TDMA target window data structure.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR - if address window overlapps with other address decode windows.
++* MV_BAD_PARAM - if base address is invalid parameter or target is
++* unknown.
++*
++*******************************************************************************/
++static MV_STATUS mvCesaTdmaWinSet(MV_U32 winNum, MV_DEC_WIN *pDecWin)
++{
++ MV_DEC_WIN_PARAMS winParams;
++ MV_U32 sizeReg, baseReg;
++
++ /* Parameter checking */
++ if (winNum >= MV_CESA_TDMA_ADDR_DEC_WIN)
++ {
++ mvOsPrintf("mvCesaTdmaWinSet: ERR. Invalid win num %d\n",winNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check if the requested window overlapps with current windows */
++ if (MV_TRUE == cesaWinOverlapDetect(winNum, &pDecWin->addrWin))
++ {
++ mvOsPrintf("%s: ERR. Window %d overlap\n", __FUNCTION__, winNum);
++ return MV_ERROR;
++ }
++
++ /* check if address is aligned to the size */
++ if(MV_IS_NOT_ALIGN(pDecWin->addrWin.baseLow, pDecWin->addrWin.size))
++ {
++ mvOsPrintf("mvCesaTdmaWinSet: Error setting CESA TDMA window %d to "\
++ "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ winNum,
++ mvCtrlTargetNameGet(pDecWin->target),
++ pDecWin->addrWin.baseLow,
++ pDecWin->addrWin.size);
++ return MV_ERROR;
++ }
++
++ if(MV_OK != mvCtrlAddrDecToParams(pDecWin, &winParams))
++ {
++ mvOsPrintf("%s: mvCtrlAddrDecToParams Failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ /* set Size, Attributes and TargetID */
++ sizeReg = (((winParams.targetId << MV_CESA_TDMA_WIN_TARGET_OFFSET) & MV_CESA_TDMA_WIN_TARGET_MASK) |
++ ((winParams.attrib << MV_CESA_TDMA_WIN_ATTR_OFFSET) & MV_CESA_TDMA_WIN_ATTR_MASK) |
++ ((winParams.size << MV_CESA_TDMA_WIN_SIZE_OFFSET) & MV_CESA_TDMA_WIN_SIZE_MASK));
++
++ if (pDecWin->enable == MV_TRUE)
++ {
++ sizeReg |= MV_CESA_TDMA_WIN_ENABLE_MASK;
++ }
++ else
++ {
++ sizeReg &= ~MV_CESA_TDMA_WIN_ENABLE_MASK;
++ }
++
++ /* Update Base value */
++ baseReg = (winParams.baseAddr & MV_CESA_TDMA_WIN_BASE_MASK);
++
++ MV_REG_WRITE( MV_CESA_TDMA_WIN_CTRL_REG(winNum), sizeReg);
++ MV_REG_WRITE( MV_CESA_TDMA_BASE_ADDR_REG(winNum), baseReg);
++
++ return MV_OK;
++}
++
++
++static MV_STATUS mvCesaTdmaAddrDecInit (void)
++{
++ MV_U32 winNum;
++ MV_STATUS status;
++ MV_CPU_DEC_WIN cpuAddrDecWin;
++ MV_DEC_WIN cesaWin;
++ MV_U32 winPrioIndex = 0;
++
++ /* First disable all address decode windows */
++ for(winNum=0; winNum<MV_CESA_TDMA_ADDR_DEC_WIN; winNum++)
++ {
++ MV_REG_BIT_RESET(MV_CESA_TDMA_WIN_CTRL_REG(winNum), MV_CESA_TDMA_WIN_ENABLE_MASK);
++ }
++
++ /* Go through all windows in user table until table terminator */
++ winNum = 0;
++ while( (tdmaAddrDecPrioTable[winPrioIndex] != TBL_TERM) &&
++ (winNum < MV_CESA_TDMA_ADDR_DEC_WIN) ) {
++
++ /* first get attributes from CPU If */
++ status = mvCpuIfTargetWinGet(tdmaAddrDecPrioTable[winPrioIndex],
++ &cpuAddrDecWin);
++ if(MV_NO_SUCH == status){
++ winPrioIndex++;
++ continue;
++ }
++
++ if (MV_OK != status)
++ {
++ mvOsPrintf("cesaInit: TargetWinGet failed. winNum=%d, winIdx=%d, target=%d, status=0x%x\n",
++ winNum, winPrioIndex, tdmaAddrDecPrioTable[winPrioIndex], status);
++ return MV_ERROR;
++ }
++ if (cpuAddrDecWin.enable == MV_TRUE)
++ {
++ cesaWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh;
++ cesaWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow;
++ cesaWin.addrWin.size = cpuAddrDecWin.addrWin.size;
++ cesaWin.enable = MV_TRUE;
++ cesaWin.target = tdmaAddrDecPrioTable[winPrioIndex];
++
++#if defined(MV646xx)
++ /* Get the default attributes for that target window */
++ mvCtrlDefAttribGet(cesaWin.target, &cesaWin.addrWinAttr);
++#endif /* MV646xx */
++
++ if(MV_OK != mvCesaTdmaWinSet(winNum, &cesaWin))
++ {
++ mvOsPrintf("mvCesaTdmaWinSet FAILED: winNum=%d\n",
++ winNum);
++ return MV_ERROR;
++ }
++ winNum++;
++ }
++ winPrioIndex++;
++ }
++ return MV_OK;
++}
++#endif /* MV_CESA_VERSION >= 2 */
++
++
++
++
++MV_STATUS mvCesaInit (int numOfSession, int queueDepth, char* pSramBase, void *osHandle)
++{
++ MV_U32 cesaCryptEngBase;
++ MV_CPU_DEC_WIN addrDecWin;
++
++ if(sizeof(MV_CESA_SRAM_MAP) > MV_CESA_SRAM_SIZE)
++ {
++ mvOsPrintf("mvCesaInit: Wrong SRAM map - %ld > %d\n",
++ sizeof(MV_CESA_SRAM_MAP), MV_CESA_SRAM_SIZE);
++ return MV_FAIL;
++ }
++#if 0
++ if (mvCpuIfTargetWinGet(CRYPT_ENG, &addrDecWin) == MV_OK)
++ cesaCryptEngBase = addrDecWin.addrWin.baseLow;
++ else
++ {
++ mvOsPrintf("mvCesaInit: ERR. mvCpuIfTargetWinGet failed\n");
++ return MV_ERROR;
++ }
++#else
++ cesaCryptEngBase = (MV_U32)pSramBase;
++#endif
++
++#if 0 /* Already done in the platform init */
++#if (MV_CESA_VERSION >= 2)
++ mvCesaTdmaAddrDecInit();
++#endif /* MV_CESA_VERSION >= 2 */
++#endif
++ return mvCesaHalInit(numOfSession, queueDepth, pSramBase, cesaCryptEngBase,
++ osHandle);
++
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.h 2010-11-09 20:28:08.152495441 +0100
+@@ -0,0 +1,100 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __mvSysCesa_h__
++#define __mvSysCesa_h__
++
++
++#include "mvCommon.h"
++#include "cesa/mvCesa.h"
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++
++/***************************** TDMA Registers *************************************/
++
++#define MV_CESA_TDMA_ADDR_DEC_WIN 4
++
++#define MV_CESA_TDMA_BASE_ADDR_REG(win) (MV_CESA_TDMA_REG_BASE + 0xa00 + (win<<3))
++
++#define MV_CESA_TDMA_WIN_CTRL_REG(win) (MV_CESA_TDMA_REG_BASE + 0xa04 + (win<<3))
++
++#define MV_CESA_TDMA_WIN_ENABLE_BIT 0
++#define MV_CESA_TDMA_WIN_ENABLE_MASK (1 << MV_CESA_TDMA_WIN_ENABLE_BIT)
++
++#define MV_CESA_TDMA_WIN_TARGET_OFFSET 4
++#define MV_CESA_TDMA_WIN_TARGET_MASK (0xf << MV_CESA_TDMA_WIN_TARGET_OFFSET)
++
++#define MV_CESA_TDMA_WIN_ATTR_OFFSET 8
++#define MV_CESA_TDMA_WIN_ATTR_MASK (0xff << MV_CESA_TDMA_WIN_ATTR_OFFSET)
++
++#define MV_CESA_TDMA_WIN_SIZE_OFFSET 16
++#define MV_CESA_TDMA_WIN_SIZE_MASK (0xFFFF << MV_CESA_TDMA_WIN_SIZE_OFFSET)
++
++#define MV_CESA_TDMA_WIN_BASE_OFFSET 16
++#define MV_CESA_TDMA_WIN_BASE_MASK (0xFFFF << MV_CESA_TDMA_WIN_BASE_OFFSET)
++
++
++MV_STATUS mvCesaInit (int numOfSession, int queueDepth, char* pSramBase, void *osHandle);
++
++#endif
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.c 2010-11-09 20:28:08.192500699 +0100
+@@ -0,0 +1,348 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++
++/* includes */
++
++#include "ddr2/mvDramIf.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++#include "ctrlEnv/sys/mvSysDram.h"
++
++/* #define MV_DEBUG */
++#ifdef MV_DEBUG
++#define DB(x) x
++#else
++#define DB(x)
++#endif
++
++static MV_BOOL sdramIfWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin);
++
++/*******************************************************************************
++* mvDramIfWinSet - Set DRAM interface address decode window
++*
++* DESCRIPTION:
++* This function sets DRAM interface address decode window.
++*
++* INPUT:
++* target - System target. Use only SDRAM targets.
++* pAddrDecWin - SDRAM address window structure.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* MV_BAD_PARAM if parameters are invalid or window is invalid, MV_OK
++* otherwise.
++*******************************************************************************/
++MV_STATUS mvDramIfWinSet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin)
++{
++ MV_U32 baseReg=0,sizeReg=0;
++ MV_U32 baseToReg=0 , sizeToReg=0;
++
++ /* Check parameters */
++ if (!MV_TARGET_IS_DRAM(target))
++ {
++ mvOsPrintf("mvDramIfWinSet: target %d is not SDRAM\n", target);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check if the requested window overlaps with current enabled windows */
++ if (MV_TRUE == sdramIfWinOverlap(target, &pAddrDecWin->addrWin))
++ {
++ mvOsPrintf("mvDramIfWinSet: ERR. Target %d overlaps\n", target);
++ return MV_BAD_PARAM;
++ }
++
++ /* check if address is aligned to the size */
++ if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size))
++ {
++ mvOsPrintf("mvDramIfWinSet:Error setting DRAM interface window %d."\
++ "\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ target,
++ pAddrDecWin->addrWin.baseLow,
++ pAddrDecWin->addrWin.size);
++ return MV_ERROR;
++ }
++
++ /* read base register*/
++ baseReg = MV_REG_READ(SDRAM_BASE_ADDR_REG(0,target));
++
++ /* read size register */
++ sizeReg = MV_REG_READ(SDRAM_SIZE_REG(0,target));
++
++ /* BaseLow[31:16] => base register [31:16] */
++ baseToReg = pAddrDecWin->addrWin.baseLow & SCBAR_BASE_MASK;
++
++ /* Write to address decode Base Address Register */
++ baseReg &= ~SCBAR_BASE_MASK;
++ baseReg |= baseToReg;
++
++ /* Translate the given window size to register format */
++ sizeToReg = ctrlSizeToReg(pAddrDecWin->addrWin.size, SCSR_SIZE_ALIGNMENT);
++
++ /* Size parameter validity check. */
++ if (-1 == sizeToReg)
++ {
++ mvOsPrintf("mvCtrlAddrDecToReg: ERR. Win %d size invalid.\n",target);
++ return MV_BAD_PARAM;
++ }
++
++ /* set size */
++ sizeReg &= ~SCSR_SIZE_MASK;
++ /* Size is located at upper 16 bits */
++ sizeReg |= (sizeToReg << SCSR_SIZE_OFFS);
++
++ /* enable/Disable */
++ if (MV_TRUE == pAddrDecWin->enable)
++ {
++ sizeReg |= SCSR_WIN_EN;
++ }
++ else
++ {
++ sizeReg &= ~SCSR_WIN_EN;
++ }
++
++ /* 3) Write to address decode Base Address Register */
++ MV_REG_WRITE(SDRAM_BASE_ADDR_REG(0,target), baseReg);
++
++ /* Write to address decode Size Register */
++ MV_REG_WRITE(SDRAM_SIZE_REG(0,target), sizeReg);
++
++ return MV_OK;
++}
++/*******************************************************************************
++* mvDramIfWinGet - Get DRAM interface address decode window
++*
++* DESCRIPTION:
++* This function gets DRAM interface address decode window.
++*
++* INPUT:
++* target - System target. Use only SDRAM targets.
++*
++* OUTPUT:
++* pAddrDecWin - SDRAM address window structure.
++*
++* RETURN:
++* MV_BAD_PARAM if parameters are invalid or window is invalid, MV_OK
++* otherwise.
++*******************************************************************************/
++MV_STATUS mvDramIfWinGet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin)
++{
++ MV_U32 baseReg,sizeReg;
++ MV_U32 sizeRegVal;
++ /* Check parameters */
++ if (!MV_TARGET_IS_DRAM(target))
++ {
++ mvOsPrintf("mvDramIfWinGet: target %d is Illigal\n", target);
++ return MV_ERROR;
++ }
++
++ /* Read base and size registers */
++ sizeReg = MV_REG_READ(SDRAM_SIZE_REG(0,target));
++ baseReg = MV_REG_READ(SDRAM_BASE_ADDR_REG(0,target));
++
++ sizeRegVal = (sizeReg & SCSR_SIZE_MASK) >> SCSR_SIZE_OFFS;
++
++ pAddrDecWin->addrWin.size = ctrlRegToSize(sizeRegVal,
++ SCSR_SIZE_ALIGNMENT);
++
++ /* Check if ctrlRegToSize returned OK */
++ if (-1 == pAddrDecWin->addrWin.size)
++ {
++ mvOsPrintf("mvDramIfWinGet: size of target %d is Illigal\n", target);
++ return MV_ERROR;
++ }
++
++ /* Extract base address */
++ /* Base register [31:16] ==> baseLow[31:16] */
++ pAddrDecWin->addrWin.baseLow = baseReg & SCBAR_BASE_MASK;
++
++ pAddrDecWin->addrWin.baseHigh = 0;
++
++
++ if (sizeReg & SCSR_WIN_EN)
++ {
++ pAddrDecWin->enable = MV_TRUE;
++ }
++ else
++ {
++ pAddrDecWin->enable = MV_FALSE;
++ }
++
++ return MV_OK;
++}
++/*******************************************************************************
++* mvDramIfWinEnable - Enable/Disable SDRAM address decode window
++*
++* DESCRIPTION:
++* This function enable/Disable SDRAM address decode window.
++*
++* INPUT:
++* target - System target. Use only SDRAM targets.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR in case function parameter are invalid, MV_OK otherewise.
++*
++*******************************************************************************/
++MV_STATUS mvDramIfWinEnable(MV_TARGET target, MV_BOOL enable)
++{
++ MV_DRAM_DEC_WIN addrDecWin;
++
++ /* Check parameters */
++ if (!MV_TARGET_IS_DRAM(target))
++ {
++ mvOsPrintf("mvDramIfWinEnable: target %d is Illigal\n", target);
++ return MV_ERROR;
++ }
++
++ if (enable == MV_TRUE)
++ { /* First check for overlap with other enabled windows */
++ if (MV_OK != mvDramIfWinGet(target, &addrDecWin))
++ {
++ mvOsPrintf("mvDramIfWinEnable:ERR. Getting target %d failed.\n",
++ target);
++ return MV_ERROR;
++ }
++ /* Check for overlapping */
++ if (MV_FALSE == sdramIfWinOverlap(target, &(addrDecWin.addrWin)))
++ {
++ /* No Overlap. Enable address decode winNum window */
++ MV_REG_BIT_SET(SDRAM_SIZE_REG(0,target), SCSR_WIN_EN);
++ }
++ else
++ { /* Overlap detected */
++ mvOsPrintf("mvDramIfWinEnable: ERR. Target %d overlap detect\n",
++ target);
++ return MV_ERROR;
++ }
++ }
++ else
++ { /* Disable address decode winNum window */
++ MV_REG_BIT_RESET(SDRAM_SIZE_REG(0, target), SCSR_WIN_EN);
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* sdramIfWinOverlap - Check if an address window overlap an SDRAM address window
++*
++* DESCRIPTION:
++* This function scan each SDRAM address decode window to test if it
++* overlapps the given address windoow
++*
++* INPUT:
++* target - SDRAM target where the function skips checking.
++* pAddrDecWin - The tested address window for overlapping with
++* SDRAM windows.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlaps any enabled address
++* decode map, MV_FALSE otherwise.
++*
++*******************************************************************************/
++static MV_BOOL sdramIfWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin)
++{
++ MV_TARGET targetNum;
++ MV_DRAM_DEC_WIN addrDecWin;
++
++ for(targetNum = SDRAM_CS0; targetNum < MV_DRAM_MAX_CS ; targetNum++)
++ {
++ /* don't check our winNum or illegal targets */
++ if (targetNum == target)
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ if (MV_OK != mvDramIfWinGet(targetNum, &addrDecWin))
++ {
++ mvOsPrintf("sdramIfWinOverlap: ERR. TargetWinGet failed\n");
++ return MV_ERROR;
++ }
++
++ /* Do not check disabled windows */
++ if (MV_FALSE == addrDecWin.enable)
++ {
++ continue;
++ }
++
++ if(MV_TRUE == ctrlWinOverlapTest(pAddrWin, &addrDecWin.addrWin))
++ {
++ mvOsPrintf(
++ "sdramIfWinOverlap: Required target %d overlap winNum %d\n",
++ target, targetNum);
++ return MV_TRUE;
++ }
++ }
++
++ return MV_FALSE;
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.h 2010-11-09 20:28:08.232495451 +0100
+@@ -0,0 +1,80 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __sysDram
++#define __sysDram
++
++/* This structure describes CPU interface address decode window */
++typedef struct _mvDramIfDecWin
++{
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++}MV_DRAM_DEC_WIN;
++
++MV_STATUS mvDramIfWinSet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin);
++MV_STATUS mvDramIfWinGet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin);
++MV_STATUS mvDramIfWinEnable(MV_TARGET target, MV_BOOL enable);
++
++#endif
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.c 2010-11-09 20:28:08.262495451 +0100
+@@ -0,0 +1,658 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "ctrlEnv/sys/mvSysGbe.h"
++
++
++
++typedef struct _mvEthDecWin
++{
++ MV_TARGET target;
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++
++}MV_ETH_DEC_WIN;
++
++MV_TARGET ethAddrDecPrioTap[] =
++{
++#if defined(MV_INCLUDE_SDRAM_CS0)
++ SDRAM_CS0,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS1)
++ SDRAM_CS1,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS2)
++ SDRAM_CS2,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS3)
++ SDRAM_CS3,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS0)
++ DEVICE_CS0,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS1)
++ DEVICE_CS1,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS2)
++ DEVICE_CS2,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS3)
++ DEVICE_CS3,
++#endif
++#if defined(MV_INCLUDE_PEX)
++ PEX0_IO,
++#endif
++ TBL_TERM
++};
++
++static MV_STATUS ethWinOverlapDetect(int port, MV_U32 winNum, MV_ADDR_WIN *pAddrWin);
++static MV_STATUS mvEthWinSet(int port, MV_U32 winNum, MV_ETH_DEC_WIN *pAddrDecWin);
++static MV_STATUS mvEthWinGet(int port, MV_U32 winNum, MV_ETH_DEC_WIN *pAddrDecWin);
++
++
++/*******************************************************************************
++* mvEthWinInit - Initialize ETH address decode windows
++*
++* DESCRIPTION:
++* This function initialize ETH window decode unit. It set the
++* default address decode windows of the unit.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if setting fail.
++*******************************************************************************/
++/* Configure EthDrv memory map registes. */
++MV_STATUS mvEthWinInit (int port)
++{
++ MV_U32 winNum, status, winPrioIndex=0, i, regVal=0;
++ MV_ETH_DEC_WIN ethWin;
++ MV_CPU_DEC_WIN cpuAddrDecWin;
++ static MV_U32 accessProtReg = 0;
++
++#if (MV_ETH_VERSION <= 1)
++ static MV_BOOL isFirst = MV_TRUE;
++
++ if(isFirst == MV_FALSE)
++ {
++ MV_REG_WRITE(ETH_ACCESS_PROTECT_REG(port), accessProtReg);
++ return MV_OK;
++ }
++ isFirst = MV_FALSE;
++#endif /* MV_GIGA_ETH_VERSION */
++
++ /* Initiate Ethernet address decode */
++
++ /* First disable all address decode windows */
++ for(winNum=0; winNum<ETH_MAX_DECODE_WIN; winNum++)
++ {
++ regVal |= MV_BIT_MASK(winNum);
++ }
++ MV_REG_WRITE(ETH_BASE_ADDR_ENABLE_REG(port), regVal);
++
++ /* Go through all windows in user table until table terminator */
++ for (winNum=0; ((ethAddrDecPrioTap[winPrioIndex] != TBL_TERM) &&
++ (winNum < ETH_MAX_DECODE_WIN)); )
++ {
++ /* first get attributes from CPU If */
++ status = mvCpuIfTargetWinGet(ethAddrDecPrioTap[winPrioIndex],
++ &cpuAddrDecWin);
++
++ if(MV_NO_SUCH == status)
++ {
++ winPrioIndex++;
++ continue;
++ }
++ if (MV_OK != status)
++ {
++ mvOsPrintf("mvEthWinInit: ERR. mvCpuIfTargetWinGet failed\n");
++ return MV_ERROR;
++ }
++
++ if (cpuAddrDecWin.enable == MV_TRUE)
++ {
++ ethWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh;
++ ethWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow;
++ ethWin.addrWin.size = cpuAddrDecWin.addrWin.size;
++ ethWin.enable = MV_TRUE;
++ ethWin.target = ethAddrDecPrioTap[winPrioIndex];
++
++ if(MV_OK != mvEthWinSet(port, winNum, &ethWin))
++ {
++ mvOsPrintf("mvEthWinInit: ERR. mvEthWinSet failed winNum=%d\n",
++ winNum);
++ return MV_ERROR;
++ }
++ winNum++;
++ }
++ winPrioIndex ++;
++ }
++
++ /* set full access to all windows. */
++ for(i=0; i<winNum; i++)
++ {
++ accessProtReg |= (FULL_ACCESS << (i*2));
++ }
++ MV_REG_WRITE(ETH_ACCESS_PROTECT_REG(port), accessProtReg);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthWinSet - Set ETH target address window
++*
++* DESCRIPTION:
++* This function sets a peripheral target (e.g. SDRAM bank0, PCI_MEM0)
++* address window, also known as address decode window.
++* After setting this target window, the ETH will be able to access the
++* target within the address window.
++*
++* INPUT:
++* winNum - ETH to target address decode window number.
++* pAddrDecWin - ETH target window data structure.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if address window overlapps with other address decode windows.
++* MV_BAD_PARAM if base address is invalid parameter or target is
++* unknown.
++*
++*******************************************************************************/
++MV_STATUS mvEthWinSet(int port, MV_U32 winNum, MV_ETH_DEC_WIN *pAddrDecWin)
++{
++ MV_TARGET_ATTRIB targetAttribs;
++ MV_DEC_REGS decRegs;
++
++ /* Parameter checking */
++ if (winNum >= ETH_MAX_DECODE_WIN)
++ {
++ mvOsPrintf("mvEthWinSet: ERR. Invalid win num %d\n",winNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check if the requested window overlapps with current windows */
++ if (MV_TRUE == ethWinOverlapDetect(port, winNum, &pAddrDecWin->addrWin))
++ {
++ mvOsPrintf("mvEthWinSet: ERR. Window %d overlap\n", winNum);
++ return MV_ERROR;
++ }
++
++ /* check if address is aligned to the size */
++ if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size))
++ {
++ mvOsPrintf("mvEthWinSet: Error setting Ethernet window %d to "\
++ "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ winNum,
++ mvCtrlTargetNameGet(pAddrDecWin->target),
++ pAddrDecWin->addrWin.baseLow,
++ pAddrDecWin->addrWin.size);
++ return MV_ERROR;
++ }
++
++
++ decRegs.baseReg = MV_REG_READ(ETH_WIN_BASE_REG(port, winNum));
++ decRegs.sizeReg = MV_REG_READ(ETH_WIN_SIZE_REG(port, winNum));
++
++ if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs))
++ {
++ mvOsPrintf("mvEthWinSet:mvCtrlAddrDecToReg Failed\n");
++ return MV_ERROR;
++ }
++
++ mvCtrlAttribGet(pAddrDecWin->target,&targetAttribs);
++
++ /* set attributes */
++ decRegs.baseReg &= ~ETH_WIN_ATTR_MASK;
++ decRegs.baseReg |= targetAttribs.attrib << ETH_WIN_ATTR_OFFS;
++ /* set target ID */
++ decRegs.baseReg &= ~ETH_WIN_TARGET_MASK;
++ decRegs.baseReg |= targetAttribs.targetId << ETH_WIN_TARGET_OFFS;
++
++ /* for the safe side we disable the window before writing the new
++ values */
++ mvEthWinEnable(port, winNum, MV_FALSE);
++ MV_REG_WRITE(ETH_WIN_BASE_REG(port, winNum), decRegs.baseReg);
++
++ /* Write to address decode Size Register */
++ MV_REG_WRITE(ETH_WIN_SIZE_REG(port, winNum), decRegs.sizeReg);
++
++ /* Enable address decode target window */
++ if (pAddrDecWin->enable == MV_TRUE)
++ {
++ mvEthWinEnable(port, winNum, MV_TRUE);
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvETHWinGet - Get dma peripheral target address window.
++*
++* DESCRIPTION:
++* Get ETH peripheral target address window.
++*
++* INPUT:
++* winNum - ETH to target address decode window number.
++*
++* OUTPUT:
++* pAddrDecWin - ETH target window data structure.
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++MV_STATUS mvEthWinGet(int port, MV_U32 winNum, MV_ETH_DEC_WIN *pAddrDecWin)
++{
++ MV_DEC_REGS decRegs;
++ MV_TARGET_ATTRIB targetAttrib;
++
++ /* Parameter checking */
++ if (winNum >= ETH_MAX_DECODE_WIN)
++ {
++ mvOsPrintf("mvEthWinGet: ERR. Invalid winNum %d\n", winNum);
++ return MV_NOT_SUPPORTED;
++ }
++
++ decRegs.baseReg = MV_REG_READ(ETH_WIN_BASE_REG(port, winNum));
++ decRegs.sizeReg = MV_REG_READ(ETH_WIN_SIZE_REG(port, winNum));
++
++ if (MV_OK != mvCtrlRegToAddrDec(&decRegs,&(pAddrDecWin->addrWin)))
++ {
++ mvOsPrintf("mvAhbToMbusWinGet: mvCtrlRegToAddrDec Failed \n");
++ return MV_ERROR;
++ }
++
++ /* attrib and targetId */
++ targetAttrib.attrib =
++ (decRegs.baseReg & ETH_WIN_ATTR_MASK) >> ETH_WIN_ATTR_OFFS;
++ targetAttrib.targetId =
++ (decRegs.baseReg & ETH_WIN_TARGET_MASK) >> ETH_WIN_TARGET_OFFS;
++
++ pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib);
++
++ /* Check if window is enabled */
++ if (~(MV_REG_READ(ETH_BASE_ADDR_ENABLE_REG(port))) & (1 << winNum) )
++ {
++ pAddrDecWin->enable = MV_TRUE;
++ }
++ else
++ {
++ pAddrDecWin->enable = MV_FALSE;
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthWinEnable - Enable/disable a ETH to target address window
++*
++* DESCRIPTION:
++* This function enable/disable a ETH to target address window.
++* According to parameter 'enable' the routine will enable the
++* window, thus enabling ETH accesses (before enabling the window it is
++* tested for overlapping). Otherwise, the window will be disabled.
++*
++* INPUT:
++* winNum - ETH to target address decode window number.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* N/A
++*
++* RETURN:
++* MV_ERROR if decode window number was wrong or enabled window overlapps.
++*
++*******************************************************************************/
++MV_STATUS mvEthWinEnable(int port, MV_U32 winNum,MV_BOOL enable)
++{
++ MV_ETH_DEC_WIN addrDecWin;
++
++ /* Parameter checking */
++ if (winNum >= ETH_MAX_DECODE_WIN)
++ {
++ mvOsPrintf("mvEthTargetWinEnable:ERR. Invalid winNum%d\n",winNum);
++ return MV_ERROR;
++ }
++
++ if (enable == MV_TRUE)
++ { /* First check for overlap with other enabled windows */
++ /* Get current window */
++ if (MV_OK != mvEthWinGet(port, winNum, &addrDecWin))
++ {
++ mvOsPrintf("mvEthTargetWinEnable:ERR. targetWinGet fail\n");
++ return MV_ERROR;
++ }
++ /* Check for overlapping */
++ if (MV_FALSE == ethWinOverlapDetect(port, winNum, &(addrDecWin.addrWin)))
++ {
++ /* No Overlap. Enable address decode target window */
++ MV_REG_BIT_RESET(ETH_BASE_ADDR_ENABLE_REG(port), (1 << winNum));
++ }
++ else
++ { /* Overlap detected */
++ mvOsPrintf("mvEthTargetWinEnable:ERR. Overlap detected\n");
++ return MV_ERROR;
++ }
++ }
++ else
++ { /* Disable address decode target window */
++ MV_REG_BIT_SET(ETH_BASE_ADDR_ENABLE_REG(port), (1 << winNum));
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthWinTargetGet - Get Window number associated with target
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++* window number
++*
++*******************************************************************************/
++MV_U32 mvEthWinTargetGet(int port, MV_TARGET target)
++{
++ MV_ETH_DEC_WIN decWin;
++ MV_U32 winNum;
++
++ /* Check parameters */
++ if (target >= MAX_TARGETS)
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetGet: target %d is Illigal\n", target);
++ return 0xffffffff;
++ }
++
++ for (winNum=0; winNum<ETH_MAX_DECODE_WIN; winNum++)
++ {
++ if (mvEthWinGet(port, winNum,&decWin) != MV_OK)
++ {
++ mvOsPrintf("mvAhbToMbusWinTargetGet: window returned error\n");
++ return 0xffffffff;
++ }
++
++ if (decWin.enable == MV_TRUE)
++ {
++ if (decWin.target == target)
++ {
++ return winNum;
++ }
++ }
++ }
++ return 0xFFFFFFFF;
++}
++
++/*******************************************************************************
++* mvEthProtWinSet - Set access protection of Ethernet to target window.
++*
++* DESCRIPTION:
++* Each Ethernet port can be configured with access attributes for each
++* of the Ethenret to target windows (address decode windows). This
++* function sets access attributes to a given window for the given channel.
++*
++* INPUTS:
++* ethPort - ETH channel number. See MV_ETH_CHANNEL enumerator.
++* winNum - IETH to target address decode window number.
++* access - IETH access rights. See MV_ACCESS_RIGHTS enumerator.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR in case window number is invalid or access right reserved.
++*
++*******************************************************************************/
++MV_STATUS mvEthProtWinSet(MV_U32 portNo, MV_U32 winNum, MV_ACCESS_RIGHTS access)
++{
++ MV_U32 protReg;
++
++ /* Parameter checking */
++ if(portNo >= mvCtrlEthMaxPortGet())
++ {
++ mvOsPrintf("mvEthProtWinSet:ERR. Invalid port number %d\n", portNo);
++ return MV_ERROR;
++ }
++
++ if (winNum >= ETH_MAX_DECODE_WIN)
++ {
++ mvOsPrintf("mvEthProtWinSet:ERR. Invalid winNum%d\n",winNum);
++ return MV_ERROR;
++ }
++
++ if((access == ACC_RESERVED) || (access >= MAX_ACC_RIGHTS))
++ {
++ mvOsPrintf("mvEthProtWinSet:ERR. Inv access param %d\n", access);
++ return MV_ERROR;
++ }
++ /* Read current protection register */
++ protReg = MV_REG_READ(ETH_ACCESS_PROTECT_REG(portNo));
++
++ /* Clear protection window field */
++ protReg &= ~(ETH_PROT_WIN_MASK(winNum));
++
++ /* Set new protection field value */
++ protReg |= (access << (ETH_PROT_WIN_OFFS(winNum)));
++
++ /* Write protection register back */
++ MV_REG_WRITE(ETH_ACCESS_PROTECT_REG(portNo), protReg);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* ethWinOverlapDetect - Detect ETH address windows overlapping
++*
++* DESCRIPTION:
++* An unpredicted behaviur is expected in case ETH address decode
++* windows overlapps.
++* This function detects ETH address decode windows overlapping of a
++* specified window. The function does not check the window itself for
++* overlapping. The function also skipps disabled address decode windows.
++*
++* INPUT:
++* winNum - address decode window number.
++* pAddrDecWin - An address decode window struct.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlap current address
++* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data
++* from registers.
++*
++*******************************************************************************/
++static MV_STATUS ethWinOverlapDetect(int port, MV_U32 winNum, MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 baseAddrEnableReg;
++ MV_U32 winNumIndex;
++ MV_ETH_DEC_WIN addrDecWin;
++
++ /* Read base address enable register. Do not check disabled windows */
++ baseAddrEnableReg = MV_REG_READ(ETH_BASE_ADDR_ENABLE_REG(port));
++
++ for (winNumIndex=0; winNumIndex<ETH_MAX_DECODE_WIN; winNumIndex++)
++ {
++ /* Do not check window itself */
++ if (winNumIndex == winNum)
++ {
++ continue;
++ }
++
++ /* Do not check disabled windows */
++ if (baseAddrEnableReg & (1 << winNumIndex))
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ if (MV_OK != mvEthWinGet(port, winNumIndex, &addrDecWin))
++ {
++ mvOsPrintf("ethWinOverlapDetect: ERR. TargetWinGet failed\n");
++ return MV_ERROR;
++ }
++/*
++ mvOsPrintf("ethWinOverlapDetect:\n
++ winNumIndex =%d baseHigh =0x%x baseLow=0x%x size=0x%x enable=0x%x\n",
++ winNumIndex,
++ addrDecWin.addrWin.baseHigh,
++ addrDecWin.addrWin.baseLow,
++ addrDecWin.addrWin.size,
++ addrDecWin.enable);
++*/
++ if (MV_TRUE == ctrlWinOverlapTest(pAddrWin, &(addrDecWin.addrWin)))
++ {
++ return MV_TRUE;
++ }
++ }
++ return MV_FALSE;
++}
++
++/*******************************************************************************
++* mvEthAddrDecShow - Print the Etherent address decode map.
++*
++* DESCRIPTION:
++* This function print the Etherent address decode map.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++void mvEthPortAddrDecShow(int port)
++{
++ MV_ETH_DEC_WIN win;
++ int i;
++
++ mvOsOutput( "\n" );
++ mvOsOutput( "ETH %d:\n", port );
++ mvOsOutput( "----\n" );
++
++ for( i = 0; i < ETH_MAX_DECODE_WIN; i++ )
++ {
++ memset( &win, 0, sizeof(ETH_MAX_DECODE_WIN) );
++
++ mvOsOutput( "win%d - ", i );
++
++ if( mvEthWinGet(port, i, &win ) == MV_OK )
++ {
++ if( win.enable )
++ {
++ mvOsOutput( "%s base %08x, ",
++ mvCtrlTargetNameGet(win.target), win.addrWin.baseLow );
++ mvOsOutput( "...." );
++ mvSizePrint( win.addrWin.size );
++
++ mvOsOutput( "\n" );
++ }
++ else
++ mvOsOutput( "disable\n" );
++ }
++ }
++ return;
++}
++
++void mvEthAddrDecShow(void)
++{
++ int port;
++
++ for(port=0; port<mvCtrlEthMaxPortGet(); port++)
++ {
++ if (MV_FALSE == mvCtrlPwrClckGet(ETH_GIG_UNIT_ID, port)) continue;
++
++ mvEthPortAddrDecShow(port);
++ }
++}
++
++
++void mvEthInit(void)
++{
++ MV_U32 port;
++
++ /* Power down all existing ports */
++ for(port=0; port<mvCtrlEthMaxPortGet(); port++)
++ {
++ if (MV_FALSE == mvCtrlPwrClckGet(ETH_GIG_UNIT_ID, port))
++ continue;
++
++ mvEthPortPowerUp(port);
++ mvEthWinInit(port);
++ }
++ mvEthHalInit();
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.h 2010-11-09 20:28:08.292495558 +0100
+@@ -0,0 +1,113 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvSysGbeh
++#define __INCmvSysGbeh
++
++#include "mvCommon.h"
++#include "eth/mvEth.h"
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++
++#define ETH_WIN_BASE_REG(port, win) (MV_ETH_REG_BASE(port) + 0x200 + ((win)<<3))
++#define ETH_WIN_SIZE_REG(port, win) (MV_ETH_REG_BASE(port) + 0x204 + ((win)<<3))
++#define ETH_WIN_REMAP_REG(port, win) (MV_ETH_REG_BASE(port) + 0x280 + ((win)<<2))
++#define ETH_BASE_ADDR_ENABLE_REG(port) (MV_ETH_REG_BASE(port) + 0x290)
++#define ETH_ACCESS_PROTECT_REG(port) (MV_ETH_REG_BASE(port) + 0x294)
++
++/**** Address decode parameters ****/
++
++/* Ethernet Base Address Register bits */
++#define ETH_MAX_DECODE_WIN 6
++#define ETH_MAX_HIGH_ADDR_REMAP_WIN 4
++
++/* Ethernet Port Access Protect (EPAP) register */
++
++/* The target associated with this window*/
++#define ETH_WIN_TARGET_OFFS 0
++#define ETH_WIN_TARGET_MASK (0xf << ETH_WIN_TARGET_OFFS)
++/* The target attributes Associated with window */
++#define ETH_WIN_ATTR_OFFS 8
++#define ETH_WIN_ATTR_MASK (0xff << ETH_WIN_ATTR_OFFS)
++
++/* Ethernet Port Access Protect Register (EPAPR) */
++#define ETH_PROT_NO_ACCESS NO_ACCESS_ALLOWED
++#define ETH_PROT_READ_ONLY READ_ONLY
++#define ETH_PROT_FULL_ACCESS FULL_ACCESS
++#define ETH_PROT_WIN_OFFS(winNum) (2 * (winNum))
++#define ETH_PROT_WIN_MASK(winNum) (0x3 << ETH_PROT_WIN_OFFS(winNum))
++
++MV_STATUS mvEthWinInit (int port);
++MV_STATUS mvEthWinEnable(int port, MV_U32 winNum, MV_BOOL enable);
++MV_U32 mvEthWinTargetGet(int port, MV_TARGET target);
++MV_STATUS mvEthProtWinSet(MV_U32 portNo, MV_U32 winNum, MV_ACCESS_RIGHTS
++ access);
++
++void mvEthPortAddrDecShow(int port);
++
++MV_VOID mvEthAddrDecShow(MV_VOID);
++
++void mvEthInit(void);
++
++#endif
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.c 2010-11-09 20:28:08.332495446 +0100
+@@ -0,0 +1,1697 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "ctrlEnv/sys/mvSysPex.h"
++
++/* this structure describes the mapping between a Pex Window and a CPU target*/
++typedef struct _pexWinToTarget
++{
++ MV_TARGET target;
++ MV_BOOL enable;
++
++}PEX_WIN_TO_TARGET;
++
++/* this array is a priority array that define How Pex windows should be
++configured , We have only 6 Pex Windows that can be configured , but we
++have maximum of 9 CPU target windows ! the following array is a priority
++array where the lowest index has the highest priotiy and the highest
++index has the lowest priority of being cnfigured */
++
++MV_U32 pexDevBarPrioTable[] =
++{
++#if defined(MV_INCLUDE_DEVICE_CS0)
++ DEVICE_CS0,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS1)
++ DEVICE_CS1,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS2)
++ DEVICE_CS2,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS3)
++ DEVICE_CS3,
++#endif
++/*
++#if defined(MV_INCLUDE_DEVICE_CS4)
++ DEVICE_CS4,
++#endif
++*/
++ TBL_TERM
++};
++
++
++/* PEX Wins registers offsets are inconsecutive. This struct describes WIN */
++/* register offsets and its function where its is located. */
++/* Also, PEX address remap registers offsets are inconsecutive. This struct */
++/* describes address remap register offsets */
++typedef struct _pexWinRegInfo
++{
++ MV_U32 baseLowRegOffs;
++ MV_U32 baseHighRegOffs;
++ MV_U32 sizeRegOffs;
++ MV_U32 remapLowRegOffs;
++ MV_U32 remapHighRegOffs;
++
++}PEX_WIN_REG_INFO;
++
++static MV_STATUS pexWinOverlapDetect(MV_U32 pexIf, MV_U32 winNum,
++ MV_ADDR_WIN *pAddrWin);
++static MV_STATUS pexWinRegInfoGet(MV_U32 pexIf, MV_U32 winNum,
++ PEX_WIN_REG_INFO *pWinRegInfo);
++
++static MV_STATUS pexBarIsValid(MV_U32 baseLow, MV_U32 size);
++
++static MV_BOOL pexIsWinWithinBar(MV_U32 pexIf,MV_ADDR_WIN *pAddrWin);
++static MV_BOOL pexBarOverlapDetect(MV_U32 pexIf,MV_U32 barNum,
++ MV_ADDR_WIN *pAddrWin);
++const MV_8* pexBarNameGet( MV_U32 bar );
++
++
++/*******************************************************************************
++* mvPexInit - Initialize PEX interfaces
++*
++* DESCRIPTION:
++*
++* This function is responsible of intialization of the Pex Interface , It
++* configure the Pex Bars and Windows in the following manner:
++*
++* Assumptions :
++* Bar0 is always internal registers bar
++* Bar1 is always the DRAM bar
++* Bar2 is always the Device bar
++*
++* 1) Sets the Internal registers bar base by obtaining the base from
++* the CPU Interface
++* 2) Sets the DRAM bar base and size by getting the base and size from
++* the CPU Interface when the size is the sum of all enabled DRAM
++* chip selects and the base is the base of CS0 .
++* 3) Sets the Device bar base and size by getting these values from the
++* CPU Interface when the base is the base of the lowest base of the
++* Device chip selects, and the
++*
++*
++* INPUT:
++*
++* pexIf - PEX interface number.
++*
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_OK if function success otherwise MV_ERROR or MV_BAD_PARAM
++*
++*******************************************************************************/
++MV_STATUS mvPexInit(MV_U32 pexIf, MV_PEX_TYPE pexType)
++{
++ MV_U32 bar;
++ MV_U32 winNum;
++ MV_PEX_BAR pexBar;
++ MV_PEX_DEC_WIN pexWin;
++ MV_CPU_DEC_WIN addrDecWin;
++ MV_TARGET target;
++ MV_U32 pexCurrWin=0;
++ MV_U32 status;
++ /* default and exapntion rom
++ are always configured */
++
++#ifndef MV_DISABLE_PEX_DEVICE_BAR
++ MV_U32 winIndex;
++ MV_U32 maxBase=0, sizeOfMaxBase=0;
++ MV_U32 pexStartWindow;
++#endif
++
++ /* Parameter checking */
++ if(pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexInit: ERR. Invalid PEX interface %d\n", pexIf);
++ return MV_BAD_PARAM;
++ }
++
++ /* Enabled CPU access to PCI-Express */
++ mvCpuIfEnablePex(pexIf, pexType);
++
++ /* Start with bars */
++ /* First disable all PEX bars*/
++ for (bar = 0; bar < PEX_MAX_BARS; bar++)
++ {
++ if (PEX_INTER_REGS_BAR != bar)
++ {
++ if (MV_OK != mvPexBarEnable(pexIf, bar, MV_FALSE))
++ {
++ mvOsPrintf("mvPexInit:mvPexBarEnable bar =%d failed \n",bar);
++ return MV_ERROR;
++ }
++
++ }
++
++ }
++
++ /* and disable all PEX target windows */
++ for (winNum = 0; winNum < PEX_MAX_TARGET_WIN - 2; winNum++)
++ {
++ if (MV_OK != mvPexTargetWinEnable(pexIf, winNum, MV_FALSE))
++ {
++ mvOsPrintf("mvPexInit:mvPexTargetWinEnable winNum =%d failed \n",
++ winNum);
++ return MV_ERROR;
++
++ }
++ }
++
++ /* Now, go through all bars*/
++
++
++
++/******************************************************************************/
++/* Internal registers bar */
++/******************************************************************************/
++ bar = PEX_INTER_REGS_BAR;
++
++ /* we only open the bar , no need to open windows for this bar */
++
++ /* first get the CS attribute from the CPU Interface */
++ if (MV_OK !=mvCpuIfTargetWinGet(INTER_REGS,&addrDecWin))
++ {
++ mvOsPrintf("mvPexInit: ERR. mvCpuIfTargetWinGet failed target =%d\n",INTER_REGS);
++ return MV_ERROR;
++ }
++
++ pexBar.addrWin.baseHigh = addrDecWin.addrWin.baseHigh;
++ pexBar.addrWin.baseLow = addrDecWin.addrWin.baseLow;
++ pexBar.addrWin.size = addrDecWin.addrWin.size;
++ pexBar.enable = MV_TRUE;
++
++ if (MV_OK != mvPexBarSet(pexIf, bar, &pexBar))
++ {
++ mvOsPrintf("mvPexInit: ERR. mvPexBarSet %d failed\n", bar);
++ return MV_ERROR;
++ }
++
++/******************************************************************************/
++/* DRAM bar */
++/******************************************************************************/
++
++ bar = PEX_DRAM_BAR;
++
++ pexBar.addrWin.size = 0;
++
++ for (target = SDRAM_CS0;target < MV_DRAM_MAX_CS; target++ )
++ {
++
++ status = mvCpuIfTargetWinGet(target,&addrDecWin);
++
++ if((MV_NO_SUCH == status)&&(target != SDRAM_CS0))
++ {
++ continue;
++ }
++
++ /* first get attributes from CPU If */
++ if (MV_OK != status)
++ {
++ mvOsPrintf("mvPexInit: ERR. mvCpuIfTargetWinGet failed target =%d\n",target);
++ return MV_ERROR;
++ }
++ if (addrDecWin.enable == MV_TRUE)
++ {
++ /* the base is the base of DRAM CS0 always */
++ if (SDRAM_CS0 == target )
++ {
++ pexBar.addrWin.baseHigh = addrDecWin.addrWin.baseHigh;
++ pexBar.addrWin.baseLow = addrDecWin.addrWin.baseLow;
++
++ }
++
++ /* increment the bar size to be the sum of the size of all
++ DRAM chips selecs */
++ pexBar.addrWin.size += addrDecWin.addrWin.size;
++
++ /* set a Pex window for this target !
++ DRAM CS always will have a Pex Window , and is not a
++ part of the priority table */
++ pexWin.addrWin.baseHigh = addrDecWin.addrWin.baseHigh;
++ pexWin.addrWin.baseLow = addrDecWin.addrWin.baseLow;
++ pexWin.addrWin.size = addrDecWin.addrWin.size;
++
++ /* we disable the windows at first because we are not
++ sure that it is witihin bar boundries */
++ pexWin.enable =MV_FALSE;
++ pexWin.target = target;
++ pexWin.targetBar = bar;
++
++ if (MV_OK != mvPexTargetWinSet(pexIf,pexCurrWin++,&pexWin))
++ {
++ mvOsPrintf("mvPexInit: ERR. mvPexTargetWinSet failed\n");
++ return MV_ERROR;
++ }
++ }
++ }
++
++ /* check if the size of the bar is illeggal */
++ if (-1 == ctrlSizeToReg(pexBar.addrWin.size, PXBCR_BAR_SIZE_ALIGNMENT))
++ {
++ /* try to get a good size */
++ pexBar.addrWin.size = ctrlSizeRegRoundUp(pexBar.addrWin.size,
++ PXBCR_BAR_SIZE_ALIGNMENT);
++ }
++
++ /* check if the size and base are valid */
++ if (MV_TRUE == pexBarOverlapDetect(pexIf,bar,&pexBar.addrWin))
++ {
++ mvOsPrintf("mvPexInit:Warning :Bar %d size is illigal\n",bar);
++ mvOsPrintf("it will be disabled\n");
++ mvOsPrintf("please check Pex and CPU windows configuration\n");
++ }
++ else
++ {
++ pexBar.enable = MV_TRUE;
++
++ /* configure the bar */
++ if (MV_OK != mvPexBarSet(pexIf, bar, &pexBar))
++ {
++ mvOsPrintf("mvPexInit: ERR. mvPexBarSet %d failed\n", bar);
++ return MV_ERROR;
++ }
++
++ /* after the bar was configured then we enable the Pex windows*/
++ for (winNum = 0;winNum < pexCurrWin ;winNum++)
++ {
++ if (MV_OK != mvPexTargetWinEnable(pexIf, winNum, MV_TRUE))
++ {
++ mvOsPrintf("mvPexInit: Can't enable window =%d\n",winNum);
++ return MV_ERROR;
++ }
++
++ }
++ }
++
++/******************************************************************************/
++/* DEVICE bar */
++/******************************************************************************/
++
++/* Open the Device BAR for non linux only */
++#ifndef MV_DISABLE_PEX_DEVICE_BAR
++
++ /* then device bar*/
++ bar = PEX_DEVICE_BAR;
++
++ /* save the starting window */
++ pexStartWindow = pexCurrWin;
++ pexBar.addrWin.size = 0;
++ pexBar.addrWin.baseLow = 0xffffffff;
++ pexBar.addrWin.baseHigh = 0;
++ maxBase = 0;
++
++ for (target = DEV_TO_TARGET(START_DEV_CS);target < DEV_TO_TARGET(MV_DEV_MAX_CS); target++ )
++ {
++ status = mvCpuIfTargetWinGet(target,&addrDecWin);
++
++ if (MV_NO_SUCH == status)
++ {
++ continue;
++ }
++
++ if (MV_OK != status)
++ {
++ mvOsPrintf("mvPexInit: ERR. mvCpuIfTargetWinGet failed target =%d\n",target);
++ return MV_ERROR;
++ }
++
++ if (addrDecWin.enable == MV_TRUE)
++ {
++ /* get the minimum base */
++ if (addrDecWin.addrWin.baseLow < pexBar.addrWin.baseLow)
++ {
++ pexBar.addrWin.baseLow = addrDecWin.addrWin.baseLow;
++ }
++
++ /* get the maximum base */
++ if (addrDecWin.addrWin.baseLow > maxBase)
++ {
++ maxBase = addrDecWin.addrWin.baseLow;
++ sizeOfMaxBase = addrDecWin.addrWin.size;
++ }
++
++ /* search in the priority table for this target */
++ for (winIndex = 0; pexDevBarPrioTable[winIndex] != TBL_TERM;
++ winIndex++)
++ {
++ if (pexDevBarPrioTable[winIndex] != target)
++ {
++ continue;
++ }
++ else if (pexDevBarPrioTable[winIndex] == target)
++ {
++ /*found it */
++
++ /* if the index of this target in the prio table is valid
++ then we set the Pex window for this target, a valid index is
++ an index that is lower than the number of the windows that
++ was not configured yet */
++
++ /* we subtract 2 always because the default and expantion
++ rom windows are always configured */
++ if ( pexCurrWin < PEX_MAX_TARGET_WIN - 2)
++ {
++ /* set a Pex window for this target ! */
++ pexWin.addrWin.baseHigh = addrDecWin.addrWin.baseHigh;
++ pexWin.addrWin.baseLow = addrDecWin.addrWin.baseLow;
++ pexWin.addrWin.size = addrDecWin.addrWin.size;
++
++ /* we disable the windows at first because we are not
++ sure that it is witihin bar boundries */
++ pexWin.enable = MV_FALSE;
++ pexWin.target = target;
++ pexWin.targetBar = bar;
++
++ if (MV_OK != mvPexTargetWinSet(pexIf,pexCurrWin++,
++ &pexWin))
++ {
++ mvOsPrintf("mvPexInit: ERR. Window Set failed\n");
++ return MV_ERROR;
++ }
++ }
++ }
++ }
++ }
++ }
++
++ pexBar.addrWin.size = maxBase - pexBar.addrWin.baseLow + sizeOfMaxBase;
++ pexBar.enable = MV_TRUE;
++
++ /* check if the size of the bar is illegal */
++ if (-1 == ctrlSizeToReg(pexBar.addrWin.size, PXBCR_BAR_SIZE_ALIGNMENT))
++ {
++ /* try to get a good size */
++ pexBar.addrWin.size = ctrlSizeRegRoundUp(pexBar.addrWin.size,
++ PXBCR_BAR_SIZE_ALIGNMENT);
++ }
++
++ /* check if the size and base are valid */
++ if (MV_TRUE == pexBarOverlapDetect(pexIf,bar,&pexBar.addrWin))
++ {
++ mvOsPrintf("mvPexInit:Warning :Bar %d size is illigal\n",bar);
++ mvOsPrintf("it will be disabled\n");
++ mvOsPrintf("please check Pex and CPU windows configuration\n");
++ }
++ else
++ {
++ if (MV_OK != mvPexBarSet(pexIf, bar, &pexBar))
++ {
++ mvOsPrintf("mvPexInit: ERR. mvPexBarSet %d failed\n", bar);
++ return MV_ERROR;
++ }
++
++ /* now enable the windows */
++ for (winNum = pexStartWindow; winNum < pexCurrWin ; winNum++)
++ {
++ if (MV_OK != mvPexTargetWinEnable(pexIf, winNum, MV_TRUE))
++ {
++ mvOsPrintf("mvPexInit:mvPexTargetWinEnable winNum =%d failed \n",
++ winNum);
++ return MV_ERROR;
++ }
++ }
++ }
++
++#endif
++
++ return mvPexHalInit(pexIf, pexType);
++
++}
++
++/*******************************************************************************
++* mvPexTargetWinSet - Set PEX to peripheral target address window BAR
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* N/A
++*
++* RETURN:
++* MV_OK if PEX BAR target window was set correctly,
++* MV_BAD_PARAM on bad params
++* MV_ERROR otherwise
++* (e.g. address window overlapps with other active PEX target window).
++*
++*******************************************************************************/
++MV_STATUS mvPexTargetWinSet(MV_U32 pexIf, MV_U32 winNum,
++ MV_PEX_DEC_WIN *pAddrDecWin)
++{
++
++ MV_DEC_REGS decRegs;
++ PEX_WIN_REG_INFO winRegInfo;
++ MV_TARGET_ATTRIB targetAttribs;
++
++ /* Parameter checking */
++ if(pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexTargetWinSet: ERR. Invalid PEX interface %d\n", pexIf);
++ return MV_BAD_PARAM;
++ }
++
++ if (winNum >= PEX_MAX_TARGET_WIN)
++ {
++ mvOsPrintf("mvPexTargetWinSet: ERR. Invalid PEX winNum %d\n", winNum);
++ return MV_BAD_PARAM;
++
++ }
++
++ /* get the pex Window registers offsets */
++ pexWinRegInfoGet(pexIf,winNum,&winRegInfo);
++
++
++ if (MV_TRUE == pAddrDecWin->enable)
++ {
++
++ /* 2) Check if the requested window overlaps with current windows */
++ if (MV_TRUE == pexWinOverlapDetect(pexIf,winNum, &pAddrDecWin->addrWin))
++ {
++ mvOsPrintf("mvPexTargetWinSet: ERR. Target %d overlap\n", winNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* 2) Check if the requested window overlaps with current windows */
++ if (MV_FALSE == pexIsWinWithinBar(pexIf,&pAddrDecWin->addrWin))
++ {
++ mvOsPrintf("mvPexTargetWinSet: Win %d should be in bar boundries\n",
++ winNum);
++ return MV_BAD_PARAM;
++ }
++
++ }
++
++
++
++ /* read base register*/
++
++ if (winRegInfo.baseLowRegOffs)
++ {
++ decRegs.baseReg = MV_REG_READ(winRegInfo.baseLowRegOffs);
++ }
++ else
++ {
++ decRegs.baseReg = 0;
++ }
++
++ if (winRegInfo.sizeRegOffs)
++ {
++ decRegs.sizeReg = MV_REG_READ(winRegInfo.sizeRegOffs);
++ }
++ else
++ {
++ decRegs.sizeReg =0;
++ }
++
++ if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs))
++ {
++ mvOsPrintf("mvPexTargetWinSet:mvCtrlAddrDecToReg Failed\n");
++ return MV_ERROR;
++ }
++
++ /* enable\Disable */
++ if (MV_TRUE == pAddrDecWin->enable)
++ {
++ decRegs.sizeReg |= PXWCR_WIN_EN;
++ }
++ else
++ {
++ decRegs.sizeReg &= ~PXWCR_WIN_EN;
++ }
++
++
++ /* clear bit location */
++ decRegs.sizeReg &= ~PXWCR_WIN_BAR_MAP_MASK;
++
++ /* set bar Mapping */
++ if (pAddrDecWin->targetBar == 1)
++ {
++ decRegs.sizeReg |= PXWCR_WIN_BAR_MAP_BAR1;
++ }
++ else if (pAddrDecWin->targetBar == 2)
++ {
++ decRegs.sizeReg |= PXWCR_WIN_BAR_MAP_BAR2;
++ }
++
++ mvCtrlAttribGet(pAddrDecWin->target,&targetAttribs);
++
++ /* set attributes */
++ decRegs.sizeReg &= ~PXWCR_ATTRIB_MASK;
++ decRegs.sizeReg |= targetAttribs.attrib << PXWCR_ATTRIB_OFFS;
++ /* set target ID */
++ decRegs.sizeReg &= ~PXWCR_TARGET_MASK;
++ decRegs.sizeReg |= targetAttribs.targetId << PXWCR_TARGET_OFFS;
++
++
++ /* 3) Write to address decode Base Address Register */
++
++ if (winRegInfo.baseLowRegOffs)
++ {
++ MV_REG_WRITE(winRegInfo.baseLowRegOffs, decRegs.baseReg);
++ }
++
++ /* write size reg */
++ if (winRegInfo.sizeRegOffs)
++ {
++ if ((MV_PEX_WIN_DEFAULT == winNum)||
++ (MV_PEX_WIN_EXP_ROM == winNum))
++ {
++ /* clear size because there is no size field*/
++ decRegs.sizeReg &= ~PXWCR_SIZE_MASK;
++
++ /* clear enable because there is no enable field*/
++ decRegs.sizeReg &= ~PXWCR_WIN_EN;
++
++ }
++
++ MV_REG_WRITE(winRegInfo.sizeRegOffs, decRegs.sizeReg);
++ }
++
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvPexTargetWinGet - Get PEX to peripheral target address window
++*
++* DESCRIPTION:
++* Get the PEX to peripheral target address window BAR.
++*
++* INPUT:
++* pexIf - PEX interface number.
++* bar - BAR to be accessed by slave.
++*
++* OUTPUT:
++* pAddrBarWin - PEX target window information data structure.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPexTargetWinGet(MV_U32 pexIf, MV_U32 winNum,
++ MV_PEX_DEC_WIN *pAddrDecWin)
++{
++ MV_TARGET_ATTRIB targetAttrib;
++ MV_DEC_REGS decRegs;
++
++ PEX_WIN_REG_INFO winRegInfo;
++
++ /* Parameter checking */
++ if(pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexTargetWinGet: ERR. Invalid PEX interface %d\n", pexIf);
++ return MV_BAD_PARAM;
++ }
++
++ if (winNum >= PEX_MAX_TARGET_WIN)
++ {
++ mvOsPrintf("mvPexTargetWinGet: ERR. Invalid PEX winNum %d\n", winNum);
++ return MV_BAD_PARAM;
++
++ }
++
++ /* get the pex Window registers offsets */
++ pexWinRegInfoGet(pexIf,winNum,&winRegInfo);
++
++ /* read base register*/
++ if (winRegInfo.baseLowRegOffs)
++ {
++ decRegs.baseReg = MV_REG_READ(winRegInfo.baseLowRegOffs);
++ }
++ else
++ {
++ decRegs.baseReg = 0;
++ }
++
++ /* read size reg */
++ if (winRegInfo.sizeRegOffs)
++ {
++ decRegs.sizeReg = MV_REG_READ(winRegInfo.sizeRegOffs);
++ }
++ else
++ {
++ decRegs.sizeReg =0;
++ }
++
++ if (MV_OK != mvCtrlRegToAddrDec(&decRegs,&(pAddrDecWin->addrWin)))
++ {
++ mvOsPrintf("mvPexTargetWinGet: mvCtrlRegToAddrDec Failed \n");
++ return MV_ERROR;
++
++ }
++
++ if (decRegs.sizeReg & PXWCR_WIN_EN)
++ {
++ pAddrDecWin->enable = MV_TRUE;
++ }
++ else
++ {
++ pAddrDecWin->enable = MV_FALSE;
++
++ }
++
++
++ #if 0
++ if (-1 == pAddrDecWin->addrWin.size)
++ {
++ return MV_ERROR;
++ }
++ #endif
++
++
++ /* get target bar */
++ if ((decRegs.sizeReg & PXWCR_WIN_BAR_MAP_MASK) == PXWCR_WIN_BAR_MAP_BAR1 )
++ {
++ pAddrDecWin->targetBar = 1;
++ }
++ else if ((decRegs.sizeReg & PXWCR_WIN_BAR_MAP_MASK) ==
++ PXWCR_WIN_BAR_MAP_BAR2 )
++ {
++ pAddrDecWin->targetBar = 2;
++ }
++
++ /* attrib and targetId */
++ pAddrDecWin->attrib = (decRegs.sizeReg & PXWCR_ATTRIB_MASK) >>
++ PXWCR_ATTRIB_OFFS;
++ pAddrDecWin->targetId = (decRegs.sizeReg & PXWCR_TARGET_MASK) >>
++ PXWCR_TARGET_OFFS;
++
++ targetAttrib.attrib = pAddrDecWin->attrib;
++ targetAttrib.targetId = pAddrDecWin->targetId;
++
++ pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib);
++
++ return MV_OK;
++
++}
++
++
++/*******************************************************************************
++* mvPexTargetWinEnable - Enable/disable a PEX BAR window
++*
++* DESCRIPTION:
++* This function enable/disable a PEX BAR window.
++* if parameter 'enable' == MV_TRUE the routine will enable the
++* window, thus enabling PEX accesses for that BAR (before enabling the
++* window it is tested for overlapping). Otherwise, the window will
++* be disabled.
++*
++* INPUT:
++* pexIf - PEX interface number.
++* bar - BAR to be accessed by slave.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPexTargetWinEnable(MV_U32 pexIf,MV_U32 winNum, MV_BOOL enable)
++{
++ PEX_WIN_REG_INFO winRegInfo;
++ MV_PEX_DEC_WIN addrDecWin;
++
++ /* Parameter checking */
++ if(pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexTargetWinEnable: ERR. Invalid PEX If %d\n", pexIf);
++ return MV_BAD_PARAM;
++ }
++
++ if (winNum >= PEX_MAX_TARGET_WIN)
++ {
++ mvOsPrintf("mvPexTargetWinEnable ERR. Invalid PEX winNum %d\n", winNum);
++ return MV_BAD_PARAM;
++
++ }
++
++
++ /* get the pex Window registers offsets */
++ pexWinRegInfoGet(pexIf,winNum,&winRegInfo);
++
++
++ /* if the address windows is disabled , we only disable the appropriare
++ pex window and ignore other settings */
++
++ if (MV_FALSE == enable)
++ {
++
++ /* this is not relevant to default and expantion rom
++ windows */
++ if (winRegInfo.sizeRegOffs)
++ {
++ if ((MV_PEX_WIN_DEFAULT != winNum)&&
++ (MV_PEX_WIN_EXP_ROM != winNum))
++ {
++ MV_REG_BIT_RESET(winRegInfo.sizeRegOffs, PXWCR_WIN_EN);
++ }
++ }
++
++ }
++ else
++ {
++ if (MV_OK != mvPexTargetWinGet(pexIf,winNum, &addrDecWin))
++ {
++ mvOsPrintf("mvPexTargetWinEnable: mvPexTargetWinGet Failed\n");
++ return MV_ERROR;
++ }
++
++ /* Check if the requested window overlaps with current windows */
++ if (MV_TRUE == pexWinOverlapDetect(pexIf,winNum, &addrDecWin.addrWin))
++ {
++ mvOsPrintf("mvPexTargetWinEnable: ERR. Target %d overlap\n", winNum);
++ return MV_BAD_PARAM;
++ }
++
++ if (MV_FALSE == pexIsWinWithinBar(pexIf,&addrDecWin.addrWin))
++ {
++ mvOsPrintf("mvPexTargetWinEnable: Win %d should be in bar boundries\n",
++ winNum);
++ return MV_BAD_PARAM;
++ }
++
++
++ /* this is not relevant to default and expantion rom
++ windows */
++ if (winRegInfo.sizeRegOffs)
++ {
++ if ((MV_PEX_WIN_DEFAULT != winNum)&&
++ (MV_PEX_WIN_EXP_ROM != winNum))
++ {
++ MV_REG_BIT_SET(winRegInfo.sizeRegOffs, PXWCR_WIN_EN);
++ }
++ }
++
++
++ }
++
++ return MV_OK;
++
++}
++
++
++
++/*******************************************************************************
++* mvPexTargetWinRemap - Set PEX to target address window remap.
++*
++* DESCRIPTION:
++* The PEX interface supports remap of the BAR original address window.
++* For each BAR it is possible to define a remap address. For example
++* an address 0x12345678 that hits BAR 0x10 (SDRAM CS[0]) will be modified
++* according to remap register but will also be targeted to the
++* SDRAM CS[0].
++*
++* INPUT:
++* pexIf - PEX interface number.
++* bar - Peripheral target enumerator accessed by slave.
++* pAddrWin - Address window to be checked.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPexTargetWinRemap(MV_U32 pexIf, MV_U32 winNum,
++ MV_PEX_REMAP_WIN *pAddrWin)
++{
++
++ PEX_WIN_REG_INFO winRegInfo;
++
++ /* Parameter checking */
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexTargetWinRemap: ERR. Invalid PEX interface num %d\n",
++ pexIf);
++ return MV_BAD_PARAM;
++ }
++ if (MV_PEX_WIN_DEFAULT == winNum)
++ {
++ mvOsPrintf("mvPexTargetWinRemap: ERR. Invalid PEX win num %d\n",
++ winNum);
++ return MV_BAD_PARAM;
++
++ }
++
++ if (MV_IS_NOT_ALIGN(pAddrWin->addrWin.baseLow, PXWRR_REMAP_ALIGNMENT))
++ {
++ mvOsPrintf("mvPexTargetWinRemap: Error remap PEX interface %d win %d."\
++ "\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ pexIf,
++ winNum,
++ pAddrWin->addrWin.baseLow,
++ pAddrWin->addrWin.size);
++
++ return MV_ERROR;
++ }
++
++ pexWinRegInfoGet(pexIf, winNum, &winRegInfo);
++
++ /* Set remap low register value */
++ MV_REG_WRITE(winRegInfo.remapLowRegOffs, pAddrWin->addrWin.baseLow);
++
++ /* Skip base high settings if the BAR has only base low (32-bit) */
++ if (0 != winRegInfo.remapHighRegOffs)
++ {
++ MV_REG_WRITE(winRegInfo.remapHighRegOffs, pAddrWin->addrWin.baseHigh);
++ }
++
++
++ if (pAddrWin->enable == MV_TRUE)
++ {
++ MV_REG_BIT_SET(winRegInfo.remapLowRegOffs,PXWRR_REMAP_EN);
++ }
++ else
++ {
++ MV_REG_BIT_RESET(winRegInfo.remapLowRegOffs,PXWRR_REMAP_EN);
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvPexTargetWinRemapEnable -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++
++MV_STATUS mvPexTargetWinRemapEnable(MV_U32 pexIf, MV_U32 winNum,
++ MV_BOOL enable)
++{
++ PEX_WIN_REG_INFO winRegInfo;
++
++ /* Parameter checking */
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexTargetWinRemap: ERR. Invalid PEX interface num %d\n",
++ pexIf);
++ return MV_BAD_PARAM;
++ }
++ if (MV_PEX_WIN_DEFAULT == winNum)
++ {
++ mvOsPrintf("mvPexTargetWinRemap: ERR. Invalid PEX win num %d\n",
++ winNum);
++ return MV_BAD_PARAM;
++
++ }
++
++
++ pexWinRegInfoGet(pexIf, winNum, &winRegInfo);
++
++ if (enable == MV_TRUE)
++ {
++ MV_REG_BIT_SET(winRegInfo.remapLowRegOffs,PXWRR_REMAP_EN);
++ }
++ else
++ {
++ MV_REG_BIT_RESET(winRegInfo.remapLowRegOffs,PXWRR_REMAP_EN);
++ }
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvPexBarSet - Set PEX bar address and size
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPexBarSet(MV_U32 pexIf,
++ MV_U32 barNum,
++ MV_PEX_BAR *pAddrWin)
++{
++ MV_U32 regBaseLow;
++ MV_U32 regSize,sizeToReg;
++
++
++ /* check parameters */
++ if(pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexBarSet: ERR. Invalid PEX interface %d\n", pexIf);
++ return MV_BAD_PARAM;
++ }
++
++ if(barNum >= PEX_MAX_BARS)
++ {
++ mvOsPrintf("mvPexBarSet: ERR. Invalid bar number %d\n", barNum);
++ return MV_BAD_PARAM;
++ }
++
++
++ if (pAddrWin->addrWin.size == 0)
++ {
++ mvOsPrintf("mvPexBarSet: Size zero is Illigal\n" );
++ return MV_BAD_PARAM;
++ }
++
++
++ /* Check if the window complies with PEX spec */
++ if (MV_TRUE != pexBarIsValid(pAddrWin->addrWin.baseLow,
++ pAddrWin->addrWin.size))
++ {
++ mvOsPrintf("mvPexBarSet: ERR. Target %d window invalid\n", barNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* 2) Check if the requested bar overlaps with current bars */
++ if (MV_TRUE == pexBarOverlapDetect(pexIf,barNum, &pAddrWin->addrWin))
++ {
++ mvOsPrintf("mvPexBarSet: ERR. Target %d overlap\n", barNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* Get size register value according to window size */
++ sizeToReg = ctrlSizeToReg(pAddrWin->addrWin.size, PXBCR_BAR_SIZE_ALIGNMENT);
++
++ /* Read bar size */
++ if (PEX_INTER_REGS_BAR != barNum) /* internal registers have no size */
++ {
++ regSize = MV_REG_READ(PEX_BAR_CTRL_REG(pexIf,barNum));
++
++ /* Size parameter validity check. */
++ if (-1 == sizeToReg)
++ {
++ mvOsPrintf("mvPexBarSet: ERR. Target BAR %d size invalid.\n",barNum);
++ return MV_BAD_PARAM;
++ }
++
++ regSize &= ~PXBCR_BAR_SIZE_MASK;
++ regSize |= (sizeToReg << PXBCR_BAR_SIZE_OFFS) ;
++
++ MV_REG_WRITE(PEX_BAR_CTRL_REG(pexIf,barNum),regSize);
++
++ }
++
++ /* set size */
++
++
++
++ /* Read base address low */
++ regBaseLow = MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf,
++ PEX_MV_BAR_BASE(barNum)));
++
++ /* clear current base */
++ if (PEX_INTER_REGS_BAR == barNum)
++ {
++ regBaseLow &= ~PXBIR_BASE_MASK;
++ regBaseLow |= (pAddrWin->addrWin.baseLow & PXBIR_BASE_MASK);
++ }
++ else
++ {
++ regBaseLow &= ~PXBR_BASE_MASK;
++ regBaseLow |= (pAddrWin->addrWin.baseLow & PXBR_BASE_MASK);
++ }
++
++ /* if we had a previous value that contain the bar type (MeM\IO), we want to
++ restore it */
++ regBaseLow |= PEX_BAR_DEFAULT_ATTRIB;
++
++
++
++ /* write base low */
++ MV_REG_WRITE(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_MV_BAR_BASE(barNum)),
++ regBaseLow);
++
++ if (pAddrWin->addrWin.baseHigh != 0)
++ {
++ /* Read base address high */
++ MV_REG_WRITE(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_MV_BAR_BASE_HIGH(barNum)),
++ pAddrWin->addrWin.baseHigh);
++
++ }
++
++ /* lastly enable the Bar */
++ if (pAddrWin->enable == MV_TRUE)
++ {
++ if (PEX_INTER_REGS_BAR != barNum) /* internal registers
++ are enabled always */
++ {
++ MV_REG_BIT_SET(PEX_BAR_CTRL_REG(pexIf,barNum),PXBCR_BAR_EN);
++ }
++ }
++ else if (MV_FALSE == pAddrWin->enable)
++ {
++ if (PEX_INTER_REGS_BAR != barNum) /* internal registers
++ are enabled always */
++ {
++ MV_REG_BIT_RESET(PEX_BAR_CTRL_REG(pexIf,barNum),PXBCR_BAR_EN);
++ }
++
++ }
++
++
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvPexBarGet - Get PEX bar address and size
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++
++MV_STATUS mvPexBarGet(MV_U32 pexIf,
++ MV_U32 barNum,
++ MV_PEX_BAR *pAddrWin)
++{
++ /* check parameters */
++ if(pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexBarGet: ERR. Invalid PEX interface %d\n", pexIf);
++ return MV_BAD_PARAM;
++ }
++
++ if(barNum >= PEX_MAX_BARS)
++ {
++ mvOsPrintf("mvPexBarGet: ERR. Invalid bar number %d\n", barNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* read base low */
++ pAddrWin->addrWin.baseLow =
++ MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_MV_BAR_BASE(barNum)));
++
++
++ if (PEX_INTER_REGS_BAR == barNum)
++ {
++ pAddrWin->addrWin.baseLow &= PXBIR_BASE_MASK;
++ }
++ else
++ {
++ pAddrWin->addrWin.baseLow &= PXBR_BASE_MASK;
++ }
++
++
++ /* read base high */
++ pAddrWin->addrWin.baseHigh =
++ MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_MV_BAR_BASE_HIGH(barNum)));
++
++
++ /* Read bar size */
++ if (PEX_INTER_REGS_BAR != barNum) /* internal registers have no size */
++ {
++ pAddrWin->addrWin.size = MV_REG_READ(PEX_BAR_CTRL_REG(pexIf,barNum));
++
++ /* check if enable or not */
++ if (pAddrWin->addrWin.size & PXBCR_BAR_EN)
++ {
++ pAddrWin->enable = MV_TRUE;
++ }
++ else
++ {
++ pAddrWin->enable = MV_FALSE;
++ }
++
++ /* now get the size */
++ pAddrWin->addrWin.size &= PXBCR_BAR_SIZE_MASK;
++ pAddrWin->addrWin.size >>= PXBCR_BAR_SIZE_OFFS;
++
++ pAddrWin->addrWin.size = ctrlRegToSize(pAddrWin->addrWin.size,
++ PXBCR_BAR_SIZE_ALIGNMENT);
++
++ }
++ else /* PEX_INTER_REGS_BAR */
++ {
++ pAddrWin->addrWin.size = INTER_REGS_SIZE;
++ pAddrWin->enable = MV_TRUE;
++ }
++
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvPexBarEnable -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++
++
++MV_STATUS mvPexBarEnable(MV_U32 pexIf, MV_U32 barNum, MV_BOOL enable)
++{
++
++ MV_PEX_BAR pexBar;
++
++ /* check parameters */
++ if(pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexBarEnable: ERR. Invalid PEX interface %d\n", pexIf);
++ return MV_BAD_PARAM;
++ }
++
++
++ if(barNum >= PEX_MAX_BARS)
++ {
++ mvOsPrintf("mvPexBarEnable: ERR. Invalid bar number %d\n", barNum);
++ return MV_BAD_PARAM;
++ }
++
++ if (PEX_INTER_REGS_BAR == barNum)
++ {
++ if (MV_TRUE == enable)
++ {
++ return MV_OK;
++ }
++ else
++ {
++ return MV_ERROR;
++ }
++ }
++
++
++ if (MV_FALSE == enable)
++ {
++ /* disable bar and quit */
++ MV_REG_BIT_RESET(PEX_BAR_CTRL_REG(pexIf,barNum),PXBCR_BAR_EN);
++ return MV_OK;
++ }
++
++ /* else */
++
++ if (mvPexBarGet(pexIf,barNum,&pexBar) != MV_OK)
++ {
++ mvOsPrintf("mvPexBarEnable: mvPexBarGet Failed\n");
++ return MV_ERROR;
++
++ }
++
++ if (MV_TRUE == pexBar.enable)
++ {
++ /* it is already enabled !!! */
++ return MV_OK;
++ }
++
++ /* else enable the bar*/
++
++ pexBar.enable = MV_TRUE;
++
++ if (mvPexBarSet(pexIf,barNum,&pexBar) != MV_OK)
++ {
++ mvOsPrintf("mvPexBarEnable: mvPexBarSet Failed\n");
++ return MV_ERROR;
++
++ }
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* pexWinOverlapDetect - Detect address windows overlapping
++*
++* DESCRIPTION:
++* This function detects address window overlapping of a given address
++* window in PEX BARs.
++*
++* INPUT:
++* pAddrWin - Address window to be checked.
++* bar - BAR to be accessed by slave.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlap current address
++* decode map, MV_FALSE otherwise.
++*
++*******************************************************************************/
++static MV_BOOL pexWinOverlapDetect(MV_U32 pexIf,
++ MV_U32 winNum,
++ MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 win;
++ MV_PEX_DEC_WIN addrDecWin;
++
++
++ for(win = 0; win < PEX_MAX_TARGET_WIN -2 ; win++)
++ {
++ /* don't check our target or illegal targets */
++ if (winNum == win)
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ if (MV_OK != mvPexTargetWinGet(pexIf, win, &addrDecWin))
++ {
++ mvOsPrintf("pexWinOverlapDetect: ERR. TargetWinGet failed win=%x\n",
++ win);
++ return MV_ERROR;
++ }
++
++ /* Do not check disabled windows */
++ if (MV_FALSE == addrDecWin.enable)
++ {
++ continue;
++ }
++
++
++ if(MV_TRUE == ctrlWinOverlapTest(pAddrWin, &addrDecWin.addrWin))
++ {
++ mvOsPrintf("pexWinOverlapDetect: winNum %d overlap current %d\n",
++ winNum, win);
++ return MV_TRUE;
++ }
++ }
++
++ return MV_FALSE;
++}
++
++/*******************************************************************************
++* pexIsWinWithinBar - Detect if address is within PEX bar boundries
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlap current address
++* decode map, MV_FALSE otherwise.
++*
++*******************************************************************************/
++static MV_BOOL pexIsWinWithinBar(MV_U32 pexIf,
++ MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 bar;
++ MV_PEX_BAR addrDecWin;
++
++ for(bar = 0; bar < PEX_MAX_BARS; bar++)
++ {
++
++ /* Get window parameters */
++ if (MV_OK != mvPexBarGet(pexIf, bar, &addrDecWin))
++ {
++ mvOsPrintf("pexIsWinWithinBar: ERR. mvPexBarGet failed\n");
++ return MV_ERROR;
++ }
++
++ /* Do not check disabled bars */
++ if (MV_FALSE == addrDecWin.enable)
++ {
++ continue;
++ }
++
++
++ if(MV_TRUE == ctrlWinWithinWinTest(pAddrWin, &addrDecWin.addrWin))
++ {
++ return MV_TRUE;
++ }
++ }
++
++ return MV_FALSE;
++
++}
++
++/*******************************************************************************
++* pexBarOverlapDetect - Detect address windows overlapping
++*
++* DESCRIPTION:
++* This function detects address window overlapping of a given address
++* window in PEX BARs.
++*
++* INPUT:
++* pAddrWin - Address window to be checked.
++* bar - BAR to be accessed by slave.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlap current address
++* decode map, MV_FALSE otherwise.
++*
++*******************************************************************************/
++static MV_BOOL pexBarOverlapDetect(MV_U32 pexIf,
++ MV_U32 barNum,
++ MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 bar;
++ MV_PEX_BAR barDecWin;
++
++
++ for(bar = 0; bar < PEX_MAX_BARS; bar++)
++ {
++ /* don't check our target or illegal targets */
++ if (barNum == bar)
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ if (MV_OK != mvPexBarGet(pexIf, bar, &barDecWin))
++ {
++ mvOsPrintf("pexBarOverlapDetect: ERR. TargetWinGet failed\n");
++ return MV_ERROR;
++ }
++
++ /* don'nt check disabled bars */
++ if (barDecWin.enable == MV_FALSE)
++ {
++ continue;
++ }
++
++
++ if(MV_TRUE == ctrlWinOverlapTest(pAddrWin, &barDecWin.addrWin))
++ {
++ mvOsPrintf("pexBarOverlapDetect: winNum %d overlap current %d\n",
++ barNum, bar);
++ return MV_TRUE;
++ }
++ }
++
++ return MV_FALSE;
++}
++
++/*******************************************************************************
++* pexBarIsValid - Check if the given address window is valid
++*
++* DESCRIPTION:
++* PEX spec restrict BAR base to be aligned to BAR size.
++* This function checks if the given address window is valid.
++*
++* INPUT:
++* baseLow - 32bit low base address.
++* size - Window size.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the address window is valid, MV_FALSE otherwise.
++*
++*******************************************************************************/
++static MV_STATUS pexBarIsValid(MV_U32 baseLow, MV_U32 size)
++{
++
++ /* PCI spec restrict BAR base to be aligned to BAR size */
++ if(MV_IS_NOT_ALIGN(baseLow, size))
++ {
++ return MV_ERROR;
++ }
++ else
++ {
++ return MV_TRUE;
++ }
++
++ return MV_TRUE;
++}
++
++/*******************************************************************************
++* pexBarRegInfoGet - Get BAR register information
++*
++* DESCRIPTION:
++* PEX BARs registers offsets are inconsecutive.
++* This function gets a PEX BAR register information like register offsets
++* and function location of the BAR.
++*
++* INPUT:
++* pexIf - PEX interface number.
++* bar - The PEX BAR in question.
++*
++* OUTPUT:
++* pBarRegInfo - BAR register info struct.
++*
++* RETURN:
++* MV_BAD_PARAM when bad parameters ,MV_ERROR on error ,othewise MV_OK
++*
++*******************************************************************************/
++static MV_STATUS pexWinRegInfoGet(MV_U32 pexIf,
++ MV_U32 winNum,
++ PEX_WIN_REG_INFO *pWinRegInfo)
++{
++
++ if ((winNum >= 0)&&(winNum <=3))
++ {
++ pWinRegInfo->baseLowRegOffs = PEX_WIN0_3_BASE_REG(pexIf,winNum);
++ pWinRegInfo->baseHighRegOffs = 0;
++ pWinRegInfo->sizeRegOffs = PEX_WIN0_3_CTRL_REG(pexIf,winNum);
++ pWinRegInfo->remapLowRegOffs = PEX_WIN0_3_REMAP_REG(pexIf,winNum);
++ pWinRegInfo->remapHighRegOffs = 0;
++ }
++ else if ((winNum >= 4)&&(winNum <=5))
++ {
++ pWinRegInfo->baseLowRegOffs = PEX_WIN4_5_BASE_REG(pexIf,winNum);
++ pWinRegInfo->baseHighRegOffs = 0;
++ pWinRegInfo->sizeRegOffs = PEX_WIN4_5_CTRL_REG(pexIf,winNum);
++ pWinRegInfo->remapLowRegOffs = PEX_WIN4_5_REMAP_REG(pexIf,winNum);
++ pWinRegInfo->remapHighRegOffs = PEX_WIN4_5_REMAP_HIGH_REG(pexIf,winNum);
++
++ }
++ else if (MV_PEX_WIN_DEFAULT == winNum)
++ {
++ pWinRegInfo->baseLowRegOffs = 0;
++ pWinRegInfo->baseHighRegOffs = 0;
++ pWinRegInfo->sizeRegOffs = PEX_WIN_DEFAULT_CTRL_REG(pexIf);
++ pWinRegInfo->remapLowRegOffs = 0;
++ pWinRegInfo->remapHighRegOffs = 0;
++ }
++ else if (MV_PEX_WIN_EXP_ROM == winNum)
++ {
++ pWinRegInfo->baseLowRegOffs = 0;
++ pWinRegInfo->baseHighRegOffs = 0;
++ pWinRegInfo->sizeRegOffs = PEX_WIN_EXP_ROM_CTRL_REG(pexIf);
++ pWinRegInfo->remapLowRegOffs = PEX_WIN_EXP_ROM_REMAP_REG(pexIf);
++ pWinRegInfo->remapHighRegOffs = 0;
++
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* pexBarNameGet - Get the string name of PEX BAR.
++*
++* DESCRIPTION:
++* This function get the string name of PEX BAR.
++*
++* INPUT:
++* bar - PEX bar number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* pointer to the string name of PEX BAR.
++*
++*******************************************************************************/
++const MV_8* pexBarNameGet( MV_U32 bar )
++{
++ switch( bar )
++ {
++ case PEX_INTER_REGS_BAR:
++ return "Internal Regs Bar0....";
++ case PEX_DRAM_BAR:
++ return "DRAM Bar1.............";
++ case PEX_DEVICE_BAR:
++ return "Devices Bar2..........";
++ default:
++ return "Bar unknown";
++ }
++}
++/*******************************************************************************
++* mvPexAddrDecShow - Print the PEX address decode map (BARs and windows).
++*
++* DESCRIPTION:
++* This function print the PEX address decode map (BARs and windows).
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvPexAddrDecShow(MV_VOID)
++{
++ MV_PEX_BAR pexBar;
++ MV_PEX_DEC_WIN win;
++ MV_U32 pexIf;
++ MV_U32 bar,winNum;
++
++ for( pexIf = 0; pexIf < mvCtrlPexMaxIfGet(); pexIf++ )
++ {
++ if (MV_FALSE == mvCtrlPwrClckGet(PEX_UNIT_ID, pexIf)) continue;
++ mvOsOutput( "\n" );
++ mvOsOutput( "PEX%d:\n", pexIf );
++ mvOsOutput( "-----\n" );
++
++ mvOsOutput( "\nPex Bars \n\n");
++
++ for( bar = 0; bar < PEX_MAX_BARS; bar++ )
++ {
++ memset( &pexBar, 0, sizeof(MV_PEX_BAR) );
++
++ mvOsOutput( "%s ", pexBarNameGet(bar) );
++
++ if( mvPexBarGet( pexIf, bar, &pexBar ) == MV_OK )
++ {
++ if( pexBar.enable )
++ {
++ mvOsOutput( "base %08x, ", pexBar.addrWin.baseLow );
++ mvSizePrint( pexBar.addrWin.size );
++ mvOsOutput( "\n" );
++ }
++ else
++ mvOsOutput( "disable\n" );
++ }
++ }
++ mvOsOutput( "\nPex Decode Windows\n\n");
++
++ for( winNum = 0; winNum < PEX_MAX_TARGET_WIN - 2; winNum++)
++ {
++ memset( &win, 0,sizeof(MV_PEX_DEC_WIN) );
++
++ mvOsOutput( "win%d - ", winNum );
++
++ if ( mvPexTargetWinGet(pexIf,winNum,&win) == MV_OK)
++ {
++ if (win.enable)
++ {
++ mvOsOutput( "%s base %08x, ",
++ mvCtrlTargetNameGet(win.target), win.addrWin.baseLow );
++ mvOsOutput( "...." );
++ mvSizePrint( win.addrWin.size );
++
++ mvOsOutput( "\n" );
++ }
++ else
++ mvOsOutput( "disable\n" );
++
++
++ }
++ }
++
++ memset( &win, 0,sizeof(MV_PEX_DEC_WIN) );
++
++ mvOsOutput( "default win - " );
++
++ if ( mvPexTargetWinGet(pexIf, MV_PEX_WIN_DEFAULT, &win) == MV_OK)
++ {
++ mvOsOutput( "%s ",
++ mvCtrlTargetNameGet(win.target) );
++ mvOsOutput( "\n" );
++ }
++ memset( &win, 0,sizeof(MV_PEX_DEC_WIN) );
++
++ mvOsOutput( "Expansion ROM - " );
++
++ if ( mvPexTargetWinGet(pexIf, MV_PEX_WIN_EXP_ROM, &win) == MV_OK)
++ {
++ mvOsOutput( "%s ",
++ mvCtrlTargetNameGet(win.target) );
++ mvOsOutput( "\n" );
++ }
++
++ }
++}
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.h 2010-11-09 20:28:08.372495456 +0100
+@@ -0,0 +1,348 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCSysPEXH
++#define __INCSysPEXH
++
++#include "mvCommon.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/mvCtrlEnvAddrDec.h"
++
++/* 4KB granularity */
++#define MINIMUM_WINDOW_SIZE 0x1000
++#define MINIMUM_BAR_SIZE 0x1000
++#define MINIMUM_BAR_SIZE_MASK 0xFFFFF000
++#define BAR_SIZE_OFFS 12
++#define BAR_SIZE_MASK (0xFFFFF << BAR_SIZE_OFFS)
++
++
++
++#define MV_PEX_WIN_DEFAULT 6
++#define MV_PEX_WIN_EXP_ROM 7
++#define PEX_MAX_TARGET_WIN 8
++
++
++#define PEX_MAX_BARS 3
++#define PEX_INTER_REGS_BAR 0
++#define PEX_DRAM_BAR 1
++#define PEX_DEVICE_BAR 2
++
++/*************************************/
++/* PCI Express BAR Control Registers */
++/*************************************/
++#define PEX_BAR_CTRL_REG(pexIf,bar) (0x41804 + (bar-1)*4- (pexIf)*0x10000)
++#define PEX_EXP_ROM_BAR_CTRL_REG(pexIf) (0x4180C - (pexIf)*0x10000)
++
++
++/* PCI Express BAR Control Register */
++/* PEX_BAR_CTRL_REG (PXBCR) */
++
++#define PXBCR_BAR_EN BIT0
++#define PXBCR_BAR_SIZE_OFFS 16
++#define PXBCR_BAR_SIZE_MASK (0xffff << PXBCR_BAR_SIZE_OFFS)
++#define PXBCR_BAR_SIZE_ALIGNMENT 0x10000
++
++
++
++/* PCI Express Expansion ROM BAR Control Register */
++/* PEX_EXP_ROM_BAR_CTRL_REG (PXERBCR) */
++
++#define PXERBCR_EXPROM_EN BIT0
++#define PXERBCR_EXPROMSZ_OFFS 19
++#define PXERBCR_EXPROMSZ_MASK (0xf << PXERBCR_EXPROMSZ_OFFS)
++#define PXERBCR_EXPROMSZ_512KB (0x0 << PXERBCR_EXPROMSZ_OFFS)
++#define PXERBCR_EXPROMSZ_1024KB (0x1 << PXERBCR_EXPROMSZ_OFFS)
++#define PXERBCR_EXPROMSZ_2048KB (0x3 << PXERBCR_EXPROMSZ_OFFS)
++#define PXERBCR_EXPROMSZ_4096KB (0x7 << PXERBCR_EXPROMSZ_OFFS)
++
++/************************************************/
++/* PCI Express Address Window Control Registers */
++/************************************************/
++#define PEX_WIN0_3_CTRL_REG(pexIf,winNum) \
++ (0x41820 + (winNum) * 0x10 - (pexIf) * 0x10000)
++#define PEX_WIN0_3_BASE_REG(pexIf,winNum) \
++ (0x41824 + (winNum) * 0x10 - (pexIf) * 0x10000)
++#define PEX_WIN0_3_REMAP_REG(pexIf,winNum) \
++ (0x4182C + (winNum) * 0x10 - (pexIf) * 0x10000)
++#define PEX_WIN4_5_CTRL_REG(pexIf,winNum) \
++ (0x41860 + (winNum - 4) * 0x20 - (pexIf) * 0x10000)
++#define PEX_WIN4_5_BASE_REG(pexIf,winNum) \
++ (0x41864 + (winNum - 4) * 0x20 - (pexIf) * 0x10000)
++#define PEX_WIN4_5_REMAP_REG(pexIf,winNum) \
++ (0x4186C + (winNum - 4) * 0x20 - (pexIf) * 0x10000)
++#define PEX_WIN4_5_REMAP_HIGH_REG(pexIf,winNum) \
++ (0x41870 + (winNum - 4) * 0x20 - (pexIf) * 0x10000)
++
++#define PEX_WIN_DEFAULT_CTRL_REG(pexIf) (0x418B0 - (pexIf) * 0x10000)
++#define PEX_WIN_EXP_ROM_CTRL_REG(pexIf) (0x418C0 - (pexIf) * 0x10000)
++#define PEX_WIN_EXP_ROM_REMAP_REG(pexIf) (0x418C4 - (pexIf) * 0x10000)
++
++/* PCI Express Window Control Register */
++/* PEX_WIN_CTRL_REG (PXWCR) */
++
++#define PXWCR_WIN_EN BIT0 /* Window Enable.*/
++
++#define PXWCR_WIN_BAR_MAP_OFFS 1 /* Mapping to BAR.*/
++#define PXWCR_WIN_BAR_MAP_MASK BIT1
++#define PXWCR_WIN_BAR_MAP_BAR1 (0 << PXWCR_WIN_BAR_MAP_OFFS)
++#define PXWCR_WIN_BAR_MAP_BAR2 (1 << PXWCR_WIN_BAR_MAP_OFFS)
++
++#define PXWCR_TARGET_OFFS 4 /*Unit ID */
++#define PXWCR_TARGET_MASK (0xf << PXWCR_TARGET_OFFS)
++
++#define PXWCR_ATTRIB_OFFS 8 /* target attributes */
++#define PXWCR_ATTRIB_MASK (0xff << PXWCR_ATTRIB_OFFS)
++
++#define PXWCR_SIZE_OFFS 16 /* size */
++#define PXWCR_SIZE_MASK (0xffff << PXWCR_SIZE_OFFS)
++#define PXWCR_SIZE_ALIGNMENT 0x10000
++
++/* PCI Express Window Base Register */
++/* PEX_WIN_BASE_REG (PXWBR)*/
++
++#define PXWBR_BASE_OFFS 16 /* address[31:16] */
++#define PXWBR_BASE_MASK (0xffff << PXWBR_BASE_OFFS)
++#define PXWBR_BASE_ALIGNMENT 0x10000
++
++/* PCI Express Window Remap Register */
++/* PEX_WIN_REMAP_REG (PXWRR)*/
++
++#define PXWRR_REMAP_EN BIT0
++#define PXWRR_REMAP_OFFS 16
++#define PXWRR_REMAP_MASK (0xffff << PXWRR_REMAP_OFFS)
++#define PXWRR_REMAP_ALIGNMENT 0x10000
++
++/* PCI Express Window Remap (High) Register */
++/* PEX_WIN_REMAP_HIGH_REG (PXWRHR)*/
++
++#define PXWRHR_REMAP_HIGH_OFFS 0
++#define PXWRHR_REMAP_HIGH_MASK (0xffffffff << PXWRHR_REMAP_HIGH_OFFS)
++
++/* PCI Express Default Window Control Register */
++/* PEX_WIN_DEFAULT_CTRL_REG (PXWDCR) */
++
++#define PXWDCR_TARGET_OFFS 4 /*Unit ID */
++#define PXWDCR_TARGET_MASK (0xf << PXWDCR_TARGET_OFFS)
++#define PXWDCR_ATTRIB_OFFS 8 /* target attributes */
++#define PXWDCR_ATTRIB_MASK (0xff << PXWDCR_ATTRIB_OFFS)
++
++/* PCI Express Expansion ROM Window Control Register */
++/* PEX_WIN_EXP_ROM_CTRL_REG (PXWERCR)*/
++
++#define PXWERCR_TARGET_OFFS 4 /*Unit ID */
++#define PXWERCR_TARGET_MASK (0xf << PXWERCR_TARGET_OFFS)
++#define PXWERCR_ATTRIB_OFFS 8 /* target attributes */
++#define PXWERCR_ATTRIB_MASK (0xff << PXWERCR_ATTRIB_OFFS)
++
++/* PCI Express Expansion ROM Window Remap Register */
++/* PEX_WIN_EXP_ROM_REMAP_REG (PXWERRR)*/
++
++#define PXWERRR_REMAP_EN BIT0
++#define PXWERRR_REMAP_OFFS 16
++#define PXWERRR_REMAP_MASK (0xffff << PXWERRR_REMAP_OFFS)
++#define PXWERRR_REMAP_ALIGNMENT 0x10000
++
++
++
++/*PEX_MEMORY_BAR_BASE_ADDR(barNum) (PXMBBA)*/
++/* PCI Express BAR0 Internal Register*/
++/*PEX BAR0_INTER_REG (PXBIR)*/
++
++#define PXBIR_IOSPACE BIT0 /* Memory Space Indicator */
++
++#define PXBIR_TYPE_OFFS 1 /* BAR Type/Init Val. */
++#define PXBIR_TYPE_MASK (0x3 << PXBIR_TYPE_OFFS)
++#define PXBIR_TYPE_32BIT_ADDR (0x0 << PXBIR_TYPE_OFFS)
++#define PXBIR_TYPE_64BIT_ADDR (0x2 << PXBIR_TYPE_OFFS)
++
++#define PXBIR_PREFETCH_EN BIT3 /* Prefetch Enable */
++
++#define PXBIR_BASE_OFFS 20 /* Base address. Address bits [31:20] */
++#define PXBIR_BASE_MASK (0xfff << PXBIR_BASE_OFFS)
++#define PXBIR_BASE_ALIGNMET (1 << PXBIR_BASE_OFFS)
++
++
++/* PCI Express BAR0 Internal (High) Register*/
++/*PEX BAR0_INTER_REG_HIGH (PXBIRH)*/
++
++#define PXBIRH_BASE_OFFS 0 /* Base address. Bits [63:32] */
++#define PXBIRH_BASE_MASK (0xffffffff << PBBHR_BASE_OFFS)
++
++
++#define PEX_BAR_DEFAULT_ATTRIB 0xc /* Memory - Prefetch - 64 bit address */
++#define PEX_BAR0_DEFAULT_ATTRIB PEX_BAR_DEFAULT_ATTRIB
++#define PEX_BAR1_DEFAULT_ATTRIB PEX_BAR_DEFAULT_ATTRIB
++#define PEX_BAR2_DEFAULT_ATTRIB PEX_BAR_DEFAULT_ATTRIB
++
++
++/* PCI Express BAR1 Register */
++/* PCI Express BAR2 Register*/
++/*PEX BAR1_REG (PXBR)*/
++/*PEX BAR2_REG (PXBR)*/
++
++#define PXBR_IOSPACE BIT0 /* Memory Space Indicator */
++
++#define PXBR_TYPE_OFFS 1 /* BAR Type/Init Val. */
++#define PXBR_TYPE_MASK (0x3 << PXBR_TYPE_OFFS)
++#define PXBR_TYPE_32BIT_ADDR (0x0 << PXBR_TYPE_OFFS)
++#define PXBR_TYPE_64BIT_ADDR (0x2 << PXBR_TYPE_OFFS)
++
++#define PXBR_PREFETCH_EN BIT3 /* Prefetch Enable */
++
++#define PXBR_BASE_OFFS 16 /* Base address. Address bits [31:16] */
++#define PXBR_BASE_MASK (0xffff << PXBR_BASE_OFFS)
++#define PXBR_BASE_ALIGNMET (1 << PXBR_BASE_OFFS)
++
++
++/* PCI Express BAR1 (High) Register*/
++/* PCI Express BAR2 (High) Register*/
++/*PEX BAR1_REG_HIGH (PXBRH)*/
++/*PEX BAR2_REG_HIGH (PXBRH)*/
++
++#define PXBRH_BASE_OFFS 0 /* Base address. Address bits [63:32] */
++#define PXBRH_BASE_MASK (0xffffffff << PXBRH_BASE_OFFS)
++
++/* PCI Express Expansion ROM BAR Register*/
++/*PEX_EXPANSION_ROM_BASE_ADDR_REG (PXERBAR)*/
++
++#define PXERBAR_EXPROMEN BIT0 /* Expansion ROM Enable */
++
++#define PXERBAR_BASE_512K_OFFS 19 /* Expansion ROM Base Address */
++#define PXERBAR_BASE_512K_MASK (0x1fff << PXERBAR_BASE_512K_OFFS)
++
++#define PXERBAR_BASE_1MB_OFFS 20 /* Expansion ROM Base Address */
++#define PXERBAR_BASE_1MB_MASK (0xfff << PXERBAR_BASE_1MB_OFFS)
++
++#define PXERBAR_BASE_2MB_OFFS 21 /* Expansion ROM Base Address */
++#define PXERBAR_BASE_2MB_MASK (0x7ff << PXERBAR_BASE_2MB_OFFS)
++
++#define PXERBAR_BASE_4MB_OFFS 22 /* Expansion ROM Base Address */
++#define PXERBAR_BASE_4MB_MASK (0x3ff << PXERBAR_BASE_4MB_OFFS)
++
++/* PEX Bar attributes */
++typedef struct _mvPexBar
++{
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++
++}MV_PEX_BAR;
++
++/* PEX Remap Window attributes */
++typedef struct _mvPexRemapWin
++{
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++
++}MV_PEX_REMAP_WIN;
++
++/* PEX Remap Window attributes */
++typedef struct _mvPexDecWin
++{
++ MV_TARGET target;
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_U32 targetBar;
++ MV_U8 attrib; /* chip select attributes */
++ MV_TARGET_ID targetId; /* Target Id of this MV_TARGET */
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++
++}MV_PEX_DEC_WIN;
++
++/* Global Functions prototypes */
++/* mvPexHalInit - Initialize PEX interfaces*/
++MV_STATUS mvPexInit(MV_U32 pexIf, MV_PEX_TYPE pexType);
++
++
++/* mvPexTargetWinSet - Set PEX to peripheral target address window BAR*/
++MV_STATUS mvPexTargetWinSet(MV_U32 pexIf, MV_U32 winNum,
++ MV_PEX_DEC_WIN *pAddrDecWin);
++
++/* mvPexTargetWinGet - Get PEX to peripheral target address window*/
++MV_STATUS mvPexTargetWinGet(MV_U32 pexIf, MV_U32 winNum,
++ MV_PEX_DEC_WIN *pAddrDecWin);
++
++/* mvPexTargetWinEnable - Enable/disable a PEX BAR window*/
++MV_STATUS mvPexTargetWinEnable(MV_U32 pexIf,MV_U32 winNum, MV_BOOL enable);
++
++/* mvPexTargetWinRemap - Set PEX to target address window remap.*/
++MV_STATUS mvPexTargetWinRemap(MV_U32 pexIf, MV_U32 winNum,
++ MV_PEX_REMAP_WIN *pAddrWin);
++
++/* mvPexTargetWinRemapEnable -enable\disable a PEX Window remap.*/
++MV_STATUS mvPexTargetWinRemapEnable(MV_U32 pexIf, MV_U32 winNum,
++ MV_BOOL enable);
++
++/* mvPexBarSet - Set PEX bar address and size */
++MV_STATUS mvPexBarSet(MV_U32 pexIf, MV_U32 barNum, MV_PEX_BAR *addrWin);
++
++/* mvPexBarGet - Get PEX bar address and size */
++MV_STATUS mvPexBarGet(MV_U32 pexIf, MV_U32 barNum, MV_PEX_BAR *addrWin);
++
++/* mvPexBarEnable - enable\disable a PEX bar*/
++MV_STATUS mvPexBarEnable(MV_U32 pexIf, MV_U32 barNum, MV_BOOL enable);
++
++/* mvPexAddrDecShow - Display address decode windows attributes */
++MV_VOID mvPexAddrDecShow(MV_VOID);
++
++#endif
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.c 2010-11-09 20:28:08.402495399 +0100
+@@ -0,0 +1,430 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvTypes.h"
++#include "mvCommon.h"
++#include "mvOs.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "cpu/mvCpu.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++#include "sata/CoreDriver/mvRegs.h"
++#include "ctrlEnv/sys/mvSysSata.h"
++
++MV_TARGET sataAddrDecPrioTab[] =
++{
++#if defined(MV_INCLUDE_SDRAM_CS0)
++ SDRAM_CS0,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS1)
++ SDRAM_CS1,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS2)
++ SDRAM_CS2,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS3)
++ SDRAM_CS3,
++#endif
++#if defined(MV_INCLUDE_PEX)
++ PEX0_MEM,
++#endif
++ TBL_TERM
++};
++
++
++/*******************************************************************************
++* sataWinOverlapDetect - Detect SATA address windows overlapping
++*
++* DESCRIPTION:
++* An unpredicted behaviur is expected in case SATA address decode
++* windows overlapps.
++* This function detects SATA address decode windows overlapping of a
++* specified window. The function does not check the window itself for
++* overlapping. The function also skipps disabled address decode windows.
++*
++* INPUT:
++* winNum - address decode window number.
++* pAddrDecWin - An address decode window struct.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlap current address
++* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data
++* from registers.
++*
++*******************************************************************************/
++static MV_STATUS sataWinOverlapDetect(int dev, MV_U32 winNum,
++ MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 winNumIndex;
++ MV_SATA_DEC_WIN addrDecWin;
++
++ for(winNumIndex=0; winNumIndex<MV_SATA_MAX_ADDR_DECODE_WIN; winNumIndex++)
++ {
++ /* Do not check window itself */
++ if (winNumIndex == winNum)
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ if (MV_OK != mvSataWinGet(dev, winNumIndex, &addrDecWin))
++ {
++ mvOsPrintf("%s: ERR. TargetWinGet failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ /* Do not check disabled windows */
++ if(addrDecWin.enable == MV_FALSE)
++ {
++ continue;
++ }
++
++ if (MV_TRUE == ctrlWinOverlapTest(pAddrWin, &(addrDecWin.addrWin)))
++ {
++ return MV_TRUE;
++ }
++ }
++ return MV_FALSE;
++}
++
++
++/*******************************************************************************
++* mvSataWinSet - Set SATA target address window
++*
++* DESCRIPTION:
++* This function sets a peripheral target (e.g. SDRAM bank0, PCI_MEM0)
++* address window, also known as address decode window.
++* After setting this target window, the SATA will be able to access the
++* target within the address window.
++*
++* INPUT:
++* winNum - SATA target address decode window number.
++* pAddrDecWin - SATA target window data structure.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if address window overlapps with other address decode windows.
++* MV_BAD_PARAM if base address is invalid parameter or target is
++* unknown.
++*
++*******************************************************************************/
++MV_STATUS mvSataWinSet(int dev, MV_U32 winNum, MV_SATA_DEC_WIN *pAddrDecWin)
++{
++ MV_TARGET_ATTRIB targetAttribs;
++ MV_DEC_REGS decRegs;
++
++ /* Parameter checking */
++ if (winNum >= MV_SATA_MAX_ADDR_DECODE_WIN)
++ {
++ mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__, winNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check if the requested window overlapps with current windows */
++ if (MV_TRUE == sataWinOverlapDetect(dev, winNum, &pAddrDecWin->addrWin))
++ {
++ mvOsPrintf("%s: ERR. Window %d overlap\n", __FUNCTION__, winNum);
++ return MV_ERROR;
++ }
++
++ /* check if address is aligned to the size */
++ if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size))
++ {
++ mvOsPrintf("mvSataWinSet:Error setting SATA window %d to "\
++ "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ winNum,
++ mvCtrlTargetNameGet(pAddrDecWin->target),
++ pAddrDecWin->addrWin.baseLow,
++ pAddrDecWin->addrWin.size);
++ return MV_ERROR;
++ }
++
++ decRegs.baseReg = 0;
++ decRegs.sizeReg = 0;
++
++ if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs))
++ {
++ mvOsPrintf("%s: mvCtrlAddrDecToReg Failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ mvCtrlAttribGet(pAddrDecWin->target, &targetAttribs);
++
++ /* set attributes */
++ decRegs.sizeReg &= ~MV_SATA_WIN_ATTR_MASK;
++ decRegs.sizeReg |= (targetAttribs.attrib << MV_SATA_WIN_ATTR_OFFSET);
++
++ /* set target ID */
++ decRegs.sizeReg &= ~MV_SATA_WIN_TARGET_MASK;
++ decRegs.sizeReg |= (targetAttribs.targetId << MV_SATA_WIN_TARGET_OFFSET);
++
++ if (pAddrDecWin->enable == MV_TRUE)
++ {
++ decRegs.sizeReg |= MV_SATA_WIN_ENABLE_MASK;
++ }
++ else
++ {
++ decRegs.sizeReg &= ~MV_SATA_WIN_ENABLE_MASK;
++ }
++
++ MV_REG_WRITE( MV_SATA_WIN_CTRL_REG(dev, winNum), decRegs.sizeReg);
++ MV_REG_WRITE( MV_SATA_WIN_BASE_REG(dev, winNum), decRegs.baseReg);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSataWinGet - Get SATA peripheral target address window.
++*
++* DESCRIPTION:
++* Get SATA peripheral target address window.
++*
++* INPUT:
++* winNum - SATA target address decode window number.
++*
++* OUTPUT:
++* pAddrDecWin - SATA target window data structure.
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++MV_STATUS mvSataWinGet(int dev, MV_U32 winNum, MV_SATA_DEC_WIN *pAddrDecWin)
++{
++ MV_DEC_REGS decRegs;
++ MV_TARGET_ATTRIB targetAttrib;
++
++ /* Parameter checking */
++ if (winNum >= MV_SATA_MAX_ADDR_DECODE_WIN)
++ {
++ mvOsPrintf("%s (dev=%d): ERR. Invalid winNum %d\n",
++ __FUNCTION__, dev, winNum);
++ return MV_NOT_SUPPORTED;
++ }
++
++ decRegs.baseReg = MV_REG_READ( MV_SATA_WIN_BASE_REG(dev, winNum) );
++ decRegs.sizeReg = MV_REG_READ( MV_SATA_WIN_CTRL_REG(dev, winNum) );
++
++ if (MV_OK != mvCtrlRegToAddrDec(&decRegs, &pAddrDecWin->addrWin) )
++ {
++ mvOsPrintf("%s: mvCtrlRegToAddrDec Failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ /* attrib and targetId */
++ targetAttrib.attrib = (decRegs.sizeReg & MV_SATA_WIN_ATTR_MASK) >>
++ MV_SATA_WIN_ATTR_OFFSET;
++ targetAttrib.targetId = (decRegs.sizeReg & MV_SATA_WIN_TARGET_MASK) >>
++ MV_SATA_WIN_TARGET_OFFSET;
++
++ pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib);
++
++ /* Check if window is enabled */
++ if(decRegs.sizeReg & MV_SATA_WIN_ENABLE_MASK)
++ {
++ pAddrDecWin->enable = MV_TRUE;
++ }
++ else
++ {
++ pAddrDecWin->enable = MV_FALSE;
++ }
++ return MV_OK;
++}
++/*******************************************************************************
++* mvSataAddrDecShow - Print the SATA address decode map.
++*
++* DESCRIPTION:
++* This function print the SATA address decode map.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvSataAddrDecShow(MV_VOID)
++{
++
++ MV_SATA_DEC_WIN win;
++ int i,j;
++
++
++
++ for( j = 0; j < MV_SATA_MAX_CHAN; j++ )
++ {
++ if (MV_FALSE == mvCtrlPwrClckGet(SATA_UNIT_ID, j))
++ return;
++
++ mvOsOutput( "\n" );
++ mvOsOutput( "SATA %d:\n", j );
++ mvOsOutput( "----\n" );
++
++ for( i = 0; i < MV_SATA_MAX_ADDR_DECODE_WIN; i++ )
++ {
++ memset( &win, 0, sizeof(MV_SATA_DEC_WIN) );
++
++ mvOsOutput( "win%d - ", i );
++
++ if( mvSataWinGet(j, i, &win ) == MV_OK )
++ {
++ if( win.enable )
++ {
++ mvOsOutput( "%s base %08x, ",
++ mvCtrlTargetNameGet(win.target), win.addrWin.baseLow );
++ mvOsOutput( "...." );
++
++ mvSizePrint( win.addrWin.size );
++
++ mvOsOutput( "\n" );
++ }
++ else
++ mvOsOutput( "disable\n" );
++ }
++ }
++ }
++}
++
++
++/*******************************************************************************
++* mvSataWinInit - Initialize the integrated SATA target address window.
++*
++* DESCRIPTION:
++* Initialize the SATA peripheral target address window.
++*
++* INPUT:
++*
++*
++* OUTPUT:
++*
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++MV_STATUS mvSataWinInit(MV_VOID)
++{
++ int winNum;
++ MV_SATA_DEC_WIN sataWin;
++ MV_CPU_DEC_WIN cpuAddrDecWin;
++ MV_U32 status, winPrioIndex = 0;
++
++ /* Initiate Sata address decode */
++
++ /* First disable all address decode windows */
++ for(winNum = 0; winNum < MV_SATA_MAX_ADDR_DECODE_WIN; winNum++)
++ {
++ MV_U32 regVal = MV_REG_READ(MV_SATA_WIN_CTRL_REG(0, winNum));
++ regVal &= ~MV_SATA_WIN_ENABLE_MASK;
++ MV_REG_WRITE(MV_SATA_WIN_CTRL_REG(0, winNum), regVal);
++ }
++
++ winNum = 0;
++ while( (sataAddrDecPrioTab[winPrioIndex] != TBL_TERM) &&
++ (winNum < MV_SATA_MAX_ADDR_DECODE_WIN) )
++ {
++ /* first get attributes from CPU If */
++ status = mvCpuIfTargetWinGet(sataAddrDecPrioTab[winPrioIndex],
++ &cpuAddrDecWin);
++
++ if(MV_NO_SUCH == status)
++ {
++ winPrioIndex++;
++ continue;
++ }
++ if (MV_OK != status)
++ {
++ mvOsPrintf("%s: ERR. mvCpuIfTargetWinGet failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ if (cpuAddrDecWin.enable == MV_TRUE)
++ {
++ sataWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh;
++ sataWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow;
++ sataWin.addrWin.size = cpuAddrDecWin.addrWin.size;
++ sataWin.enable = MV_TRUE;
++ sataWin.target = sataAddrDecPrioTab[winPrioIndex];
++
++ if(MV_OK != mvSataWinSet(0/*dev*/, winNum, &sataWin))
++ {
++ return MV_ERROR;
++ }
++ winNum++;
++ }
++ winPrioIndex++;
++ }
++ return MV_OK;
++}
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.h 2010-11-09 20:28:08.526524216 +0100
+@@ -0,0 +1,128 @@
++
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCMVSysSataAddrDech
++#define __INCMVSysSataAddrDech
++
++#include "mvCommon.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++typedef struct _mvSataDecWin
++{
++ MV_TARGET target;
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++
++} MV_SATA_DEC_WIN;
++
++
++#define MV_SATA_MAX_ADDR_DECODE_WIN 4
++
++#define MV_SATA_WIN_CTRL_REG(dev, win) (SATA_REG_BASE + 0x30 + ((win)<<4))
++#define MV_SATA_WIN_BASE_REG(dev, win) (SATA_REG_BASE + 0x34 + ((win)<<4))
++
++/* BITs in Bridge Interrupt Cause and Mask registers */
++#define MV_SATA_ADDR_DECODE_ERROR_BIT 0
++#define MV_SATA_ADDR_DECODE_ERROR_MASK (1<<MV_SATA_ADDR_DECODE_ERROR_BIT)
++
++/* BITs in Windows 0-3 Control and Base Registers */
++#define MV_SATA_WIN_ENABLE_BIT 0
++#define MV_SATA_WIN_ENABLE_MASK (1<<MV_SATA_WIN_ENABLE_BIT)
++
++#define MV_SATA_WIN_TARGET_OFFSET 4
++#define MV_SATA_WIN_TARGET_MASK (0xF<<MV_SATA_WIN_TARGET_OFFSET)
++
++#define MV_SATA_WIN_ATTR_OFFSET 8
++#define MV_SATA_WIN_ATTR_MASK (0xFF<<MV_SATA_WIN_ATTR_OFFSET)
++
++#define MV_SATA_WIN_SIZE_OFFSET 16
++#define MV_SATA_WIN_SIZE_MASK (0xFFFF<<MV_SATA_WIN_SIZE_OFFSET)
++
++#define MV_SATA_WIN_BASE_OFFSET 16
++#define MV_SATA_WIN_BASE_MASK (0xFFFF<<MV_SATA_WIN_BASE_OFFSET)
++
++MV_STATUS mvSataWinGet(int dev, MV_U32 winNum, MV_SATA_DEC_WIN *pAddrDecWin);
++MV_STATUS mvSataWinSet(int dev, MV_U32 winNum, MV_SATA_DEC_WIN *pAddrDecWin);
++MV_STATUS mvSataWinByTargetGet(MV_TARGET target, MV_SATA_DEC_WIN *pAddrDecWin);
++MV_STATUS mvSataWinInit(MV_VOID);
++MV_VOID mvSataAddrDecShow(MV_VOID);
++
++
++#ifdef __cplusplus
++}
++#endif
++
++
++#endif
++
++
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.c 2010-11-09 20:28:08.633445891 +0100
+@@ -0,0 +1,427 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvTypes.h"
++#include "mvCommon.h"
++#include "mvOs.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "cpu/mvCpu.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++#include "mvRegs.h"
++#include "ctrlEnv/sys/mvSysSdmmc.h"
++
++MV_TARGET sdmmcAddrDecPrioTab[] =
++{
++#if defined(MV_INCLUDE_SDRAM_CS0)
++ SDRAM_CS0,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS1)
++ SDRAM_CS1,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS2)
++ SDRAM_CS2,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS3)
++ SDRAM_CS3,
++#endif
++#if defined(MV_INCLUDE_PEX)
++ PEX0_MEM,
++#endif
++ TBL_TERM
++};
++
++
++/*******************************************************************************
++* sdmmcWinOverlapDetect - Detect SDMMC address windows overlapping
++*
++* DESCRIPTION:
++* An unpredicted behaviur is expected in case SDMMC address decode
++* windows overlapps.
++* This function detects SDMMC address decode windows overlapping of a
++* specified window. The function does not check the window itself for
++* overlapping. The function also skipps disabled address decode windows.
++*
++* INPUT:
++* winNum - address decode window number.
++* pAddrDecWin - An address decode window struct.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlap current address
++* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data
++* from registers.
++*
++*******************************************************************************/
++static MV_STATUS sdmmcWinOverlapDetect(int dev, MV_U32 winNum,
++ MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 winNumIndex;
++ MV_SDMMC_DEC_WIN addrDecWin;
++
++ for(winNumIndex=0; winNumIndex<MV_SDMMC_MAX_ADDR_DECODE_WIN; winNumIndex++)
++ {
++ /* Do not check window itself */
++ if (winNumIndex == winNum)
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ if (MV_OK != mvSdmmcWinGet(dev, winNumIndex, &addrDecWin))
++ {
++ mvOsPrintf("%s: ERR. TargetWinGet failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ /* Do not check disabled windows */
++ if(addrDecWin.enable == MV_FALSE)
++ {
++ continue;
++ }
++
++ if (MV_TRUE == ctrlWinOverlapTest(pAddrWin, &(addrDecWin.addrWin)))
++ {
++ return MV_TRUE;
++ }
++ }
++ return MV_FALSE;
++}
++
++
++/*******************************************************************************
++* mvSdmmcWinSet - Set SDMMC target address window
++*
++* DESCRIPTION:
++* This function sets a peripheral target (e.g. SDRAM bank0, PCI_MEM0)
++* address window, also known as address decode window.
++* After setting this target window, the SDMMC will be able to access the
++* target within the address window.
++*
++* INPUT:
++* winNum - SDMMC target address decode window number.
++* pAddrDecWin - SDMMC target window data structure.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if address window overlapps with other address decode windows.
++* MV_BAD_PARAM if base address is invalid parameter or target is
++* unknown.
++*
++*******************************************************************************/
++MV_STATUS mvSdmmcWinSet(int dev, MV_U32 winNum, MV_SDMMC_DEC_WIN *pAddrDecWin)
++{
++ MV_TARGET_ATTRIB targetAttribs;
++ MV_DEC_REGS decRegs;
++
++ /* Parameter checking */
++ if (winNum >= MV_SDMMC_MAX_ADDR_DECODE_WIN)
++ {
++ mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__, winNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check if the requested window overlapps with current windows */
++ if (MV_TRUE == sdmmcWinOverlapDetect(dev, winNum, &pAddrDecWin->addrWin))
++ {
++ mvOsPrintf("%s: ERR. Window %d overlap\n", __FUNCTION__, winNum);
++ return MV_ERROR;
++ }
++
++ /* check if address is aligned to the size */
++ if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size))
++ {
++ mvOsPrintf("mvSdmmcWinSet:Error setting SDMMC window %d to "\
++ "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ winNum,
++ mvCtrlTargetNameGet(pAddrDecWin->target),
++ pAddrDecWin->addrWin.baseLow,
++ pAddrDecWin->addrWin.size);
++ return MV_ERROR;
++ }
++
++ decRegs.baseReg = 0;
++ decRegs.sizeReg = 0;
++
++ if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs))
++ {
++ mvOsPrintf("%s: mvCtrlAddrDecToReg Failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ mvCtrlAttribGet(pAddrDecWin->target, &targetAttribs);
++
++ /* set attributes */
++ decRegs.sizeReg &= ~MV_SDMMC_WIN_ATTR_MASK;
++ decRegs.sizeReg |= (targetAttribs.attrib << MV_SDMMC_WIN_ATTR_OFFSET);
++
++ /* set target ID */
++ decRegs.sizeReg &= ~MV_SDMMC_WIN_TARGET_MASK;
++ decRegs.sizeReg |= (targetAttribs.targetId << MV_SDMMC_WIN_TARGET_OFFSET);
++
++ if (pAddrDecWin->enable == MV_TRUE)
++ {
++ decRegs.sizeReg |= MV_SDMMC_WIN_ENABLE_MASK;
++ }
++ else
++ {
++ decRegs.sizeReg &= ~MV_SDMMC_WIN_ENABLE_MASK;
++ }
++
++ MV_REG_WRITE( MV_SDMMC_WIN_CTRL_REG(dev, winNum), decRegs.sizeReg);
++ MV_REG_WRITE( MV_SDMMC_WIN_BASE_REG(dev, winNum), decRegs.baseReg);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSdmmcWinGet - Get SDMMC peripheral target address window.
++*
++* DESCRIPTION:
++* Get SDMMC peripheral target address window.
++*
++* INPUT:
++* winNum - SDMMC target address decode window number.
++*d
++* OUTPUT:
++* pAddrDecWin - SDMMC target window data structure.
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++MV_STATUS mvSdmmcWinGet(int dev, MV_U32 winNum, MV_SDMMC_DEC_WIN *pAddrDecWin)
++{
++ MV_DEC_REGS decRegs;
++ MV_TARGET_ATTRIB targetAttrib;
++
++ /* Parameter checking */
++ if (winNum >= MV_SDMMC_MAX_ADDR_DECODE_WIN)
++ {
++ mvOsPrintf("%s (dev=%d): ERR. Invalid winNum %d\n",
++ __FUNCTION__, dev, winNum);
++ return MV_NOT_SUPPORTED;
++ }
++
++ decRegs.baseReg = MV_REG_READ( MV_SDMMC_WIN_BASE_REG(dev, winNum) );
++ decRegs.sizeReg = MV_REG_READ( MV_SDMMC_WIN_CTRL_REG(dev, winNum) );
++
++ if (MV_OK != mvCtrlRegToAddrDec(&decRegs, &pAddrDecWin->addrWin) )
++ {
++ mvOsPrintf("%s: mvCtrlRegToAddrDec Failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ /* attrib and targetId */
++ targetAttrib.attrib = (decRegs.sizeReg & MV_SDMMC_WIN_ATTR_MASK) >>
++ MV_SDMMC_WIN_ATTR_OFFSET;
++ targetAttrib.targetId = (decRegs.sizeReg & MV_SDMMC_WIN_TARGET_MASK) >>
++ MV_SDMMC_WIN_TARGET_OFFSET;
++
++ pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib);
++
++ /* Check if window is enabled */
++ if(decRegs.sizeReg & MV_SDMMC_WIN_ENABLE_MASK)
++ {
++ pAddrDecWin->enable = MV_TRUE;
++ }
++ else
++ {
++ pAddrDecWin->enable = MV_FALSE;
++ }
++ return MV_OK;
++}
++/*******************************************************************************
++* mvSdmmcAddrDecShow - Print the SDMMC address decode map.
++*
++* DESCRIPTION:
++* This function print the SDMMC address decode map.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvSdmmcAddrDecShow(MV_VOID)
++{
++
++ MV_SDMMC_DEC_WIN win;
++ int i,j=0;
++
++
++
++ if (MV_FALSE == mvCtrlPwrClckGet(SDIO_UNIT_ID, 0))
++ return;
++
++ mvOsOutput( "\n" );
++ mvOsOutput( "SDMMC %d:\n", j );
++ mvOsOutput( "----\n" );
++
++ for( i = 0; i < MV_SDMMC_MAX_ADDR_DECODE_WIN; i++ )
++ {
++ memset( &win, 0, sizeof(MV_SDMMC_DEC_WIN) );
++
++ mvOsOutput( "win%d - ", i );
++
++ if( mvSdmmcWinGet(j, i, &win ) == MV_OK )
++ {
++ if( win.enable )
++ {
++ mvOsOutput( "%s base %08x, ",
++ mvCtrlTargetNameGet(win.target), win.addrWin.baseLow );
++ mvOsOutput( "...." );
++
++ mvSizePrint( win.addrWin.size );
++
++ mvOsOutput( "\n" );
++ }
++ else
++ mvOsOutput( "disable\n" );
++ }
++ }
++}
++
++
++/*******************************************************************************
++* mvSdmmcWinInit - Initialize the integrated SDMMC target address window.
++*
++* DESCRIPTION:
++* Initialize the SDMMC peripheral target address window.
++*
++* INPUT:
++*
++*
++* OUTPUT:
++*
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++MV_STATUS mvSdmmcWinInit(MV_VOID)
++{
++ int winNum;
++ MV_SDMMC_DEC_WIN sdmmcWin;
++ MV_CPU_DEC_WIN cpuAddrDecWin;
++ MV_U32 status, winPrioIndex = 0;
++
++ /* Initiate Sdmmc address decode */
++
++ /* First disable all address decode windows */
++ for(winNum = 0; winNum < MV_SDMMC_MAX_ADDR_DECODE_WIN; winNum++)
++ {
++ MV_U32 regVal = MV_REG_READ(MV_SDMMC_WIN_CTRL_REG(0, winNum));
++ regVal &= ~MV_SDMMC_WIN_ENABLE_MASK;
++ MV_REG_WRITE(MV_SDMMC_WIN_CTRL_REG(0, winNum), regVal);
++ }
++
++ winNum = 0;
++ while( (sdmmcAddrDecPrioTab[winPrioIndex] != TBL_TERM) &&
++ (winNum < MV_SDMMC_MAX_ADDR_DECODE_WIN) )
++ {
++ /* first get attributes from CPU If */
++ status = mvCpuIfTargetWinGet(sdmmcAddrDecPrioTab[winPrioIndex],
++ &cpuAddrDecWin);
++
++ if(MV_NO_SUCH == status)
++ {
++ winPrioIndex++;
++ continue;
++ }
++ if (MV_OK != status)
++ {
++ mvOsPrintf("%s: ERR. mvCpuIfTargetWinGet failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ if (cpuAddrDecWin.enable == MV_TRUE)
++ {
++ sdmmcWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh;
++ sdmmcWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow;
++ sdmmcWin.addrWin.size = cpuAddrDecWin.addrWin.size;
++ sdmmcWin.enable = MV_TRUE;
++ sdmmcWin.target = sdmmcAddrDecPrioTab[winPrioIndex];
++
++ if(MV_OK != mvSdmmcWinSet(0/*dev*/, winNum, &sdmmcWin))
++ {
++ return MV_ERROR;
++ }
++ winNum++;
++ }
++ winPrioIndex++;
++ }
++ return MV_OK;
++}
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.h 2010-11-09 20:28:08.891243103 +0100
+@@ -0,0 +1,125 @@
++
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCMVSysSdmmcAddrDech
++#define __INCMVSysSdmmcAddrDech
++
++#include "mvCommon.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++typedef struct _mvSdmmcDecWin
++{
++ MV_TARGET target;
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++
++} MV_SDMMC_DEC_WIN;
++
++
++#define MV_SDMMC_MAX_ADDR_DECODE_WIN 4
++
++#define MV_SDMMC_WIN_CTRL_REG(dev, win) (MV_SDIO_REG_BASE + 0x108 + ((win)<<3))
++#define MV_SDMMC_WIN_BASE_REG(dev, win) (MV_SDIO_REG_BASE + 0x10c + ((win)<<3))
++
++
++/* BITs in Windows 0-3 Control and Base Registers */
++#define MV_SDMMC_WIN_ENABLE_BIT 0
++#define MV_SDMMC_WIN_ENABLE_MASK (1<<MV_SDMMC_WIN_ENABLE_BIT)
++
++#define MV_SDMMC_WIN_TARGET_OFFSET 4
++#define MV_SDMMC_WIN_TARGET_MASK (0xF<<MV_SDMMC_WIN_TARGET_OFFSET)
++
++#define MV_SDMMC_WIN_ATTR_OFFSET 8
++#define MV_SDMMC_WIN_ATTR_MASK (0xFF<<MV_SDMMC_WIN_ATTR_OFFSET)
++
++#define MV_SDMMC_WIN_SIZE_OFFSET 16
++#define MV_SDMMC_WIN_SIZE_MASK (0xFFFF<<MV_SDMMC_WIN_SIZE_OFFSET)
++
++#define MV_SDMMC_WIN_BASE_OFFSET 16
++#define MV_SDMMC_WIN_BASE_MASK (0xFFFF<<MV_SDMMC_WIN_BASE_OFFSET)
++
++MV_STATUS mvSdmmcWinGet(int dev, MV_U32 winNum, MV_SDMMC_DEC_WIN *pAddrDecWin);
++MV_STATUS mvSdmmcWinSet(int dev, MV_U32 winNum, MV_SDMMC_DEC_WIN *pAddrDecWin);
++MV_STATUS mvSdmmcWinByTargetGet(MV_TARGET target, MV_SDMMC_DEC_WIN *pAddrDecWin);
++MV_STATUS mvSdmmcWinInit(MV_VOID);
++MV_VOID mvSdmmcAddrDecShow(MV_VOID);
++
++
++#ifdef __cplusplus
++}
++#endif
++
++
++#endif
++
++
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.c 2010-11-09 20:28:09.164485759 +0100
+@@ -0,0 +1,462 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvSysTdm.h"
++
++
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++static MV_TARGET tdmAddrDecPrioTap[] =
++{
++ PEX0_MEM,
++ SDRAM_CS0,
++ SDRAM_CS1,
++ SDRAM_CS2,
++ SDRAM_CS3,
++ DEVICE_CS0,
++ DEVICE_CS1,
++ DEVICE_CS2,
++ DEV_BOOCS,
++ PEX0_IO,
++ TBL_TERM
++};
++
++static MV_STATUS tdmWinOverlapDetect(MV_U32 winNum, MV_ADDR_WIN *pAddrWin);
++
++/*******************************************************************************
++* mvTdmWinInit - Initialize TDM address decode windows
++*
++* DESCRIPTION:
++* This function initialize TDM window decode unit. It set the
++* default address decode
++* windows of the unit.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if setting fail.
++*******************************************************************************/
++
++MV_STATUS mvTdmWinInit(void)
++{
++ MV_U32 winNum;
++ MV_U32 winPrioIndex = 0;
++ MV_CPU_DEC_WIN cpuAddrDecWin;
++ MV_TDM_DEC_WIN tdmWin;
++ MV_STATUS status;
++
++ /*Disable all windows*/
++ for (winNum = 0; winNum < TDM_MBUS_MAX_WIN; winNum++)
++ {
++ mvTdmWinEnable(winNum, MV_FALSE);
++ }
++
++ for (winNum = 0; ((tdmAddrDecPrioTap[winPrioIndex] != TBL_TERM) &&
++ (winNum < TDM_MBUS_MAX_WIN)); )
++ {
++ status = mvCpuIfTargetWinGet(tdmAddrDecPrioTap[winPrioIndex],
++ &cpuAddrDecWin);
++ if (MV_NO_SUCH == status)
++ {
++ winPrioIndex++;
++ continue;
++ }
++ if (MV_OK != status)
++ {
++ mvOsPrintf("mvTdmInit: ERR. mvCpuIfTargetWinGet failed\n");
++ return MV_ERROR;
++ }
++
++ if (cpuAddrDecWin.enable == MV_TRUE)
++ {
++ tdmWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh;
++ tdmWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow;
++ tdmWin.addrWin.size = cpuAddrDecWin.addrWin.size;
++ tdmWin.enable = MV_TRUE;
++ tdmWin.target = tdmAddrDecPrioTap[winPrioIndex];
++ if (MV_OK != mvTdmWinSet(winNum, &tdmWin))
++ {
++ return MV_ERROR;
++ }
++ winNum++;
++ }
++ winPrioIndex++;
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvTdmWinSet - Set TDM target address window
++*
++* DESCRIPTION:
++* This function sets a peripheral target (e.g. SDRAM bank0, PCI_MEM0)
++* address window, also known as address decode window.
++* After setting this target window, the TDM will be able to access the
++* target within the address window.
++*
++* INPUT:
++* winNum - TDM to target address decode window number.
++* pAddrDecWin - TDM target window data structure.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if address window overlapps with other address decode windows.
++* MV_BAD_PARAM if base address is invalid parameter or target is
++* unknown.
++*
++*******************************************************************************/
++
++MV_STATUS mvTdmWinSet(MV_U32 winNum, MV_TDM_DEC_WIN *pAddrDecWin)
++{
++ MV_TARGET_ATTRIB targetAttribs;
++ MV_DEC_REGS decRegs;
++ MV_U32 ctrlReg = 0;
++
++ /* Parameter checking */
++ if (winNum >= TDM_MBUS_MAX_WIN)
++ {
++ mvOsPrintf("mvTdmWinSet: ERR. Invalid win num %d\n",winNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check if the requested window overlapps with current windows */
++ if (MV_TRUE == tdmWinOverlapDetect(winNum, &pAddrDecWin->addrWin))
++ {
++ mvOsPrintf("mvTdmWinSet: ERR. Window %d overlap\n", winNum);
++ return MV_ERROR;
++ }
++
++ /* check if address is aligned to the size */
++ if (MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size))
++ {
++ mvOsPrintf("mvTdmWinSet: Error setting TDM window %d to "\
++ "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ winNum,
++ mvCtrlTargetNameGet(pAddrDecWin->target),
++ pAddrDecWin->addrWin.baseLow,
++ pAddrDecWin->addrWin.size);
++ return MV_ERROR;
++ }
++
++ decRegs.baseReg = MV_REG_READ(TDM_WIN_BASE_REG(winNum));
++ decRegs.sizeReg = (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_SIZE_MASK) >> TDM_WIN_SIZE_OFFS;
++
++ if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs))
++ {
++ mvOsPrintf("mvTdmWinSet: mvCtrlAddrDecToReg Failed\n");
++ return MV_ERROR;
++ }
++
++ mvCtrlAttribGet(pAddrDecWin->target, &targetAttribs);
++
++ /* for the safe side we disable the window before writing the new
++ values */
++ mvTdmWinEnable(winNum, MV_FALSE);
++
++ ctrlReg |= (targetAttribs.attrib << TDM_WIN_ATTRIB_OFFS);
++ ctrlReg |= (targetAttribs.targetId << TDM_WIN_TARGET_OFFS);
++ ctrlReg |= (decRegs.sizeReg & TDM_WIN_SIZE_MASK);
++
++ /* Write to address base and control registers */
++ MV_REG_WRITE(TDM_WIN_BASE_REG(winNum), decRegs.baseReg);
++ MV_REG_WRITE(TDM_WIN_CTRL_REG(winNum), ctrlReg);
++ /* Enable address decode target window */
++ if (pAddrDecWin->enable == MV_TRUE)
++ {
++ mvTdmWinEnable(winNum, MV_TRUE);
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvTdmWinGet - Get peripheral target address window.
++*
++* DESCRIPTION:
++* Get TDM peripheral target address window.
++*
++* INPUT:
++* winNum - TDM to target address decode window number.
++*
++* OUTPUT:
++* pAddrDecWin - TDM target window data structure.
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++
++MV_STATUS mvTdmWinGet(MV_U32 winNum, MV_TDM_DEC_WIN *pAddrDecWin)
++{
++
++ MV_DEC_REGS decRegs;
++ MV_TARGET_ATTRIB targetAttrib;
++
++ /* Parameter checking */
++ if (winNum >= TDM_MBUS_MAX_WIN)
++ {
++ mvOsPrintf("mvTdmWinGet: ERR. Invalid winNum %d\n", winNum);
++ return MV_NOT_SUPPORTED;
++ }
++
++ decRegs.baseReg = MV_REG_READ(TDM_WIN_BASE_REG(winNum));
++ decRegs.sizeReg = (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_SIZE_MASK) >> TDM_WIN_SIZE_OFFS;
++
++ if (MV_OK != mvCtrlRegToAddrDec(&decRegs,&(pAddrDecWin->addrWin)))
++ {
++ mvOsPrintf("mvTdmWinGet: mvCtrlRegToAddrDec Failed \n");
++ return MV_ERROR;
++ }
++
++ /* attrib and targetId */
++ targetAttrib.attrib =
++ (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_ATTRIB_MASK) >> TDM_WIN_ATTRIB_OFFS;
++ targetAttrib.targetId =
++ (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_TARGET_MASK) >> TDM_WIN_TARGET_OFFS;
++
++ pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib);
++
++ /* Check if window is enabled */
++ if (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_ENABLE_MASK)
++ {
++ pAddrDecWin->enable = MV_TRUE;
++ }
++ else
++ {
++ pAddrDecWin->enable = MV_FALSE;
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvTdmWinEnable - Enable/disable a TDM to target address window
++*
++* DESCRIPTION:
++* This function enable/disable a TDM to target address window.
++* According to parameter 'enable' the routine will enable the
++* window, thus enabling TDM accesses (before enabling the window it is
++* tested for overlapping). Otherwise, the window will be disabled.
++*
++* INPUT:
++* winNum - TDM to target address decode window number.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* N/A
++*
++* RETURN:
++* MV_ERROR if decode window number was wrong or enabled window overlapps.
++*
++*******************************************************************************/
++MV_STATUS mvTdmWinEnable(int winNum, MV_BOOL enable)
++{
++ MV_TDM_DEC_WIN addrDecWin;
++
++ if (MV_TRUE == enable)
++ {
++ if (winNum >= TDM_MBUS_MAX_WIN)
++ {
++ mvOsPrintf("mvTdmWinEnable:ERR. Invalid winNum%d\n",winNum);
++ return MV_ERROR;
++ }
++
++ /* First check for overlap with other enabled windows */
++ /* Get current window */
++ if (MV_OK != mvTdmWinGet(winNum, &addrDecWin))
++ {
++ mvOsPrintf("mvTdmWinEnable:ERR. targetWinGet fail\n");
++ return MV_ERROR;
++ }
++ /* Check for overlapping */
++ if (MV_FALSE == tdmWinOverlapDetect(winNum, &(addrDecWin.addrWin)))
++ {
++ /* No Overlap. Enable address decode target window */
++ MV_REG_BIT_SET(TDM_WIN_CTRL_REG(winNum), TDM_WIN_ENABLE_MASK);
++ }
++ else
++ { /* Overlap detected */
++ mvOsPrintf("mvTdmWinEnable:ERR. Overlap detected\n");
++ return MV_ERROR;
++ }
++ }
++ else
++ {
++ MV_REG_BIT_RESET(TDM_WIN_CTRL_REG(winNum), TDM_WIN_ENABLE_MASK);
++ }
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* tdmWinOverlapDetect - Detect TDM address windows overlapping
++*
++* DESCRIPTION:
++* An unpredicted behaviour is expected in case TDM address decode
++* windows overlapps.
++* This function detects TDM address decode windows overlapping of a
++* specified window. The function does not check the window itself for
++* overlapping. The function also skipps disabled address decode windows.
++*
++* INPUT:
++* winNum - address decode window number.
++* pAddrDecWin - An address decode window struct.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlap current address
++* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data
++* from registers.
++*
++*******************************************************************************/
++static MV_STATUS tdmWinOverlapDetect(MV_U32 winNum, MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 winNumIndex;
++ MV_TDM_DEC_WIN addrDecWin;
++
++ for (winNumIndex = 0; winNumIndex < TDM_MBUS_MAX_WIN; winNumIndex++)
++ {
++ /* Do not check window itself */
++ if (winNumIndex == winNum)
++ {
++ continue;
++ }
++ /* Do not check disabled windows */
++ if (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_ENABLE_MASK)
++ {
++ /* Get window parameters */
++ if (MV_OK != mvTdmWinGet(winNumIndex, &addrDecWin))
++ {
++ DB(mvOsPrintf("dmaWinOverlapDetect: ERR. TargetWinGet failed\n"));
++ return MV_ERROR;
++ }
++
++ if (MV_TRUE == ctrlWinOverlapTest(pAddrWin, &(addrDecWin.addrWin)))
++ {
++ return MV_TRUE;
++ }
++ }
++ }
++ return MV_FALSE;
++}
++
++/*******************************************************************************
++* mvTdmAddrDecShow - Print the TDM address decode map.
++*
++* DESCRIPTION:
++* This function print the TDM address decode map.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvTdmAddrDecShow(MV_VOID)
++{
++ MV_TDM_DEC_WIN win;
++ int i;
++
++ mvOsOutput( "\n" );
++ mvOsOutput( "TDM:\n" );
++ mvOsOutput( "----\n" );
++
++ for( i = 0; i < TDM_MBUS_MAX_WIN; i++ )
++ {
++ memset( &win, 0, sizeof(MV_TDM_DEC_WIN) );
++
++ mvOsOutput( "win%d - ", i );
++
++ if (mvTdmWinGet(i, &win ) == MV_OK )
++ {
++ if( win.enable )
++ {
++ mvOsOutput( "%s base %08x, ",
++ mvCtrlTargetNameGet(win.target), win.addrWin.baseLow);
++ mvOsOutput( "...." );
++ mvSizePrint( win.addrWin.size );
++ mvOsOutput( "\n" );
++ }
++ else
++ mvOsOutput( "disable\n" );
++ }
++ }
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.h 2010-11-09 20:28:09.471497270 +0100
+@@ -0,0 +1,106 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvSysTdmh
++#define __INCmvSysTdmh
++
++#include "ctrlEnv/sys/mvCpuIf.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/mvCtrlEnvAddrDec.h"
++
++typedef struct _mvTdmDecWin
++{
++ MV_TARGET target;
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++} MV_TDM_DEC_WIN;
++
++MV_STATUS mvTdmWinInit(MV_VOID);
++MV_STATUS mvTdmWinSet(MV_U32 winNum, MV_TDM_DEC_WIN *pAddrDecWin);
++MV_STATUS mvTdmWinGet(MV_U32 winNum, MV_TDM_DEC_WIN *pAddrDecWin);
++MV_STATUS mvTdmWinEnable(int winNum, MV_BOOL enable);
++MV_VOID mvTdmAddrDecShow(MV_VOID);
++
++
++#define TDM_MBUS_MAX_WIN 4
++#define TDM_WIN_CTRL_REG(win) ((TDM_REG_BASE + 0x4030) + (win<<4))
++#define TDM_WIN_BASE_REG(win) ((TDM_REG_BASE +0x4034) + (win<<4))
++
++/* TDM_WIN_CTRL_REG bits */
++#define TDM_WIN_ENABLE_OFFS 0
++#define TDM_WIN_ENABLE_MASK (1<<TDM_WIN_ENABLE_OFFS)
++#define TDM_WIN_ENABLE 1
++#define TDM_WIN_TARGET_OFFS 4
++#define TDM_WIN_TARGET_MASK (0xf<<TDM_WIN_TARGET_OFFS)
++#define TDM_WIN_ATTRIB_OFFS 8
++#define TDM_WIN_ATTRIB_MASK (0xff<<TDM_WIN_ATTRIB_OFFS)
++#define TDM_WIN_SIZE_OFFS 16
++#define TDM_WIN_SIZE_MASK (0xffff<<TDM_WIN_SIZE_OFFS)
++
++/* TDM_WIN_BASE_REG bits */
++#define TDM_BASE_OFFS 16
++#define TDM_BASE_MASK (0xffff<<TDM_BASE_OFFS)
++
++#endif /*__INCmvSysTdmh*/
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.c 2010-11-09 20:28:09.721570932 +0100
+@@ -0,0 +1,591 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "ctrlEnv/sys/mvSysTs.h"
++
++
++typedef struct _mvTsuDecWin
++{
++ MV_TARGET target;
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++
++}MV_TSU_DEC_WIN;
++
++
++MV_TARGET tsuAddrDecPrioTap[] =
++{
++#if defined(MV_INCLUDE_PEX)
++ PEX0_MEM,
++#endif
++#if defined(MV_INCLUDE_PCI)
++ PCI0_MEM,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS0)
++ SDRAM_CS0,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS1)
++ SDRAM_CS1,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS2)
++ SDRAM_CS2,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS3)
++ SDRAM_CS3,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS0)
++ DEVICE_CS0,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS1)
++ DEVICE_CS1,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS2)
++ DEVICE_CS2,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS3)
++ DEVICE_CS3,
++#endif
++#if defined(MV_INCLUDE_PEX)
++ PEX0_IO,
++#endif
++#if defined(MV_INCLUDE_PCI)
++ PCI0_IO,
++#endif
++ TBL_TERM
++};
++
++static MV_STATUS tsuWinOverlapDetect(MV_U32 winNum, MV_ADDR_WIN *pAddrWin);
++static MV_STATUS mvTsuWinSet(MV_U32 winNum, MV_TSU_DEC_WIN *pAddrDecWin);
++static MV_STATUS mvTsuWinGet(MV_U32 winNum, MV_TSU_DEC_WIN *pAddrDecWin);
++MV_STATUS mvTsuWinEnable(MV_U32 winNum,MV_BOOL enable);
++
++/*******************************************************************************
++* mvTsuWinInit
++*
++* DESCRIPTION:
++* Initialize the TSU unit address decode windows.
++*
++* INPUT:
++* None.
++* OUTPUT:
++* None.
++* RETURN:
++* MV_OK - on success,
++*
++*******************************************************************************/
++MV_STATUS mvTsuWinInit(void)
++{
++ MV_U32 winNum, status, winPrioIndex=0;
++ MV_TSU_DEC_WIN tsuWin;
++ MV_CPU_DEC_WIN cpuAddrDecWin;
++
++ /* First disable all address decode windows */
++ for(winNum = 0; winNum < TSU_MAX_DECODE_WIN; winNum++)
++ {
++ MV_REG_BIT_RESET(MV_TSU_WIN_CTRL_REG(winNum),
++ TSU_WIN_CTRL_EN_MASK);
++ }
++
++ /* Go through all windows in user table until table terminator */
++ for(winNum = 0; ((tsuAddrDecPrioTap[winPrioIndex] != TBL_TERM) &&
++ (winNum < TSU_MAX_DECODE_WIN));)
++ {
++ /* first get attributes from CPU If */
++ status = mvCpuIfTargetWinGet(tsuAddrDecPrioTap[winPrioIndex],
++ &cpuAddrDecWin);
++
++ if(MV_NO_SUCH == status)
++ {
++ winPrioIndex++;
++ continue;
++ }
++ if(MV_OK != status)
++ {
++ mvOsPrintf("mvTsuWinInit: ERR. mvCpuIfTargetWinGet failed\n");
++ return MV_ERROR;
++ }
++
++ if (cpuAddrDecWin.enable == MV_TRUE)
++ {
++ tsuWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh;
++ tsuWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow;
++ tsuWin.addrWin.size = cpuAddrDecWin.addrWin.size;
++ tsuWin.enable = MV_TRUE;
++ tsuWin.target = tsuAddrDecPrioTap[winPrioIndex];
++
++ if(MV_OK != mvTsuWinSet(winNum, &tsuWin))
++ {
++ mvOsPrintf("mvTsuWinInit: ERR. mvTsuWinSet failed winNum=%d\n",
++ winNum);
++ return MV_ERROR;
++ }
++ winNum++;
++ }
++ winPrioIndex ++;
++ }
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvTsuWinSet
++*
++* DESCRIPTION:
++* This function sets a peripheral target (e.g. SDRAM bank0, PCI_MEM0)
++* address window, also known as address decode window.
++* After setting this target window, the TSU will be able to access the
++* target within the address window.
++*
++* INPUT:
++* winNum - TSU to target address decode window number.
++* pAddrDecWin - TSU target window data structure.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR - if address window overlapps with other address decode
++* windows.
++* MV_BAD_PARAM - if base address is invalid parameter or target is
++* unknown.
++*
++*******************************************************************************/
++MV_STATUS mvTsuWinSet(MV_U32 winNum, MV_TSU_DEC_WIN *pAddrDecWin)
++{
++ MV_TARGET_ATTRIB targetAttribs;
++ MV_DEC_REGS decRegs;
++
++ /* Parameter checking */
++ if(winNum >= TSU_MAX_DECODE_WIN)
++ {
++ mvOsPrintf("mvTsuWinSet: ERR. Invalid win num %d\n",winNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check if the requested window overlapps with current windows */
++ if(MV_TRUE == tsuWinOverlapDetect(winNum, &pAddrDecWin->addrWin))
++ {
++ mvOsPrintf("mvTsuWinSet: ERR. Window %d overlap\n", winNum);
++ return MV_ERROR;
++ }
++
++ /* check if address is aligned to the size */
++ if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow,pAddrDecWin->addrWin.size))
++ {
++ mvOsPrintf("mvTsuWinSet: Error setting TSU window %d to target "
++ "%s.\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ winNum, mvCtrlTargetNameGet(pAddrDecWin->target),
++ pAddrDecWin->addrWin.baseLow,
++ pAddrDecWin->addrWin.size);
++ return MV_ERROR;
++ }
++
++ decRegs.baseReg = MV_REG_READ(MV_TSU_WIN_BASE_REG(winNum));
++ decRegs.sizeReg = MV_REG_READ(MV_TSU_WIN_CTRL_REG(winNum));
++
++ if(MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs))
++ {
++ mvOsPrintf("mvTsuWinSet: mvCtrlAddrDecToReg Failed\n");
++ return MV_ERROR;
++ }
++
++ mvCtrlAttribGet(pAddrDecWin->target,&targetAttribs);
++
++ /* set attributes */
++ decRegs.sizeReg &= ~TSU_WIN_CTRL_ATTR_MASK;
++ decRegs.sizeReg |= targetAttribs.attrib << TSU_WIN_CTRL_ATTR_OFFS;
++ /* set target ID */
++ decRegs.sizeReg &= ~TSU_WIN_CTRL_TARGET_MASK;
++ decRegs.sizeReg |= targetAttribs.targetId << TSU_WIN_CTRL_TARGET_OFFS;
++
++ /* for the safe side we disable the window before writing the new */
++ /* values */
++ mvTsuWinEnable(winNum, MV_FALSE);
++ MV_REG_WRITE(MV_TSU_WIN_CTRL_REG(winNum),decRegs.sizeReg);
++
++ /* Write to address decode Size Register */
++ MV_REG_WRITE(MV_TSU_WIN_BASE_REG(winNum), decRegs.baseReg);
++
++ /* Enable address decode target window */
++ if(pAddrDecWin->enable == MV_TRUE)
++ {
++ mvTsuWinEnable(winNum,MV_TRUE);
++ }
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvTsuWinGet
++*
++* DESCRIPTION:
++* Get TSU peripheral target address window.
++*
++* INPUT:
++* winNum - TSU to target address decode window number.
++*
++* OUTPUT:
++* pAddrDecWin - TSU target window data structure.
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++MV_STATUS mvTsuWinGet(MV_U32 winNum, MV_TSU_DEC_WIN *pAddrDecWin)
++{
++ MV_DEC_REGS decRegs;
++ MV_TARGET_ATTRIB targetAttrib;
++
++ /* Parameter checking */
++ if(winNum >= TSU_MAX_DECODE_WIN)
++ {
++ mvOsPrintf("mvTsuWinGet: ERR. Invalid winNum %d\n", winNum);
++ return MV_NOT_SUPPORTED;
++ }
++
++ decRegs.baseReg = MV_REG_READ(MV_TSU_WIN_BASE_REG(winNum));
++ decRegs.sizeReg = MV_REG_READ(MV_TSU_WIN_CTRL_REG(winNum));
++
++ if(MV_OK != mvCtrlRegToAddrDec(&decRegs,&(pAddrDecWin->addrWin)))
++ {
++ mvOsPrintf("mvTsuWinGet: mvCtrlRegToAddrDec Failed \n");
++ return MV_ERROR;
++ }
++
++ /* attrib and targetId */
++ targetAttrib.attrib =
++ (decRegs.sizeReg & TSU_WIN_CTRL_ATTR_MASK) >> TSU_WIN_CTRL_ATTR_OFFS;
++ targetAttrib.targetId =
++ (decRegs.sizeReg & TSU_WIN_CTRL_TARGET_MASK) >> TSU_WIN_CTRL_TARGET_OFFS;
++
++ pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib);
++
++ /* Check if window is enabled */
++ if((MV_REG_READ(MV_TSU_WIN_CTRL_REG(winNum)) & TSU_WIN_CTRL_EN_MASK))
++ {
++ pAddrDecWin->enable = MV_TRUE;
++ }
++ else
++ {
++ pAddrDecWin->enable = MV_FALSE;
++ }
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvTsuWinEnable
++*
++* DESCRIPTION:
++* This function enable/disable a TSU to target address window.
++* According to parameter 'enable' the routine will enable the
++* window, thus enabling TSU accesses (before enabling the window it is
++* tested for overlapping). Otherwise, the window will be disabled.
++*
++* INPUT:
++* winNum - TSU to target address decode window number.
++* enable - Enable / disable parameter.
++*
++* OUTPUT:
++* N/A
++*
++* RETURN:
++* MV_ERROR if decode window number was wrong or enabled window overlapps.
++*
++*******************************************************************************/
++MV_STATUS mvTsuWinEnable(MV_U32 winNum,MV_BOOL enable)
++{
++ MV_TSU_DEC_WIN addrDecWin;
++
++ /* Parameter checking */
++ if(winNum >= TSU_MAX_DECODE_WIN)
++ {
++ mvOsPrintf("mvTsuWinEnable: ERR. Invalid winNum%d\n",winNum);
++ return MV_ERROR;
++ }
++
++ if(enable == MV_TRUE)
++ {
++ /* First check for overlap with other enabled windows */
++ /* Get current window. */
++ if(MV_OK != mvTsuWinGet(winNum,&addrDecWin))
++ {
++ mvOsPrintf("mvTsuWinEnable: ERR. targetWinGet fail\n");
++ return MV_ERROR;
++ }
++ /* Check for overlapping. */
++ if(MV_FALSE == tsuWinOverlapDetect(winNum,&(addrDecWin.addrWin)))
++ {
++ /* No Overlap. Enable address decode target window */
++ MV_REG_BIT_SET(MV_TSU_WIN_CTRL_REG(winNum),
++ TSU_WIN_CTRL_EN_MASK);
++ }
++ else
++ {
++ /* Overlap detected */
++ mvOsPrintf("mvTsuWinEnable: ERR. Overlap detected\n");
++ return MV_ERROR;
++ }
++ }
++ else
++ {
++ /* Disable address decode target window */
++ MV_REG_BIT_RESET(MV_TSU_WIN_CTRL_REG(winNum),
++ TSU_WIN_CTRL_EN_MASK);
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvTsuWinTargetGet
++*
++* DESCRIPTION:
++* Get Window number associated with target
++*
++* INPUT:
++* target - Target ID to get the window number for.
++* OUTPUT:
++*
++* RETURN:
++* window number or 0xFFFFFFFF on error.
++*
++*******************************************************************************/
++MV_U32 mvTsuWinTargetGet(MV_TARGET target)
++{
++ MV_TSU_DEC_WIN decWin;
++ MV_U32 winNum;
++
++ /* Check parameters */
++ if(target >= MAX_TARGETS)
++ {
++ mvOsPrintf("mvTsuWinTargetGet: target %d is Illigal\n", target);
++ return 0xffffffff;
++ }
++
++ for(winNum = 0; winNum < TSU_MAX_DECODE_WIN; winNum++)
++ {
++ if(mvTsuWinGet(winNum,&decWin) != MV_OK)
++ {
++ mvOsPrintf("mvTsuWinGet: window returned error\n");
++ return 0xffffffff;
++ }
++
++ if (decWin.enable == MV_TRUE)
++ {
++ if(decWin.target == target)
++ {
++ return winNum;
++ }
++ }
++ }
++ return 0xFFFFFFFF;
++}
++
++
++/*******************************************************************************
++* tsuWinOverlapDetect
++*
++* DESCRIPTION:
++* Detect TSU address windows overlapping
++* An unpredicted behaviur is expected in case TSU address decode
++* windows overlapps.
++* This function detects TSU address decode windows overlapping of a
++* specified window. The function does not check the window itself for
++* overlapping. The function also skipps disabled address decode windows.
++*
++* INPUT:
++* winNum - address decode window number.
++* pAddrDecWin - An address decode window struct.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlap current address
++* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data
++* from registers.
++*
++*******************************************************************************/
++static MV_STATUS tsuWinOverlapDetect(MV_U32 winNum, MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 ctrlReg;
++ MV_U32 winNumIndex;
++ MV_TSU_DEC_WIN addrDecWin;
++
++ for(winNumIndex = 0; winNumIndex < TSU_MAX_DECODE_WIN; winNumIndex++)
++ {
++ /* Do not check window itself */
++ if(winNumIndex == winNum)
++ {
++ continue;
++ }
++
++ /* Do not check disabled windows */
++ ctrlReg = MV_REG_READ(MV_TSU_WIN_CTRL_REG(winNumIndex));
++ if((ctrlReg & TSU_WIN_CTRL_EN_MASK) == 0)
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ if (MV_OK != mvTsuWinGet(winNumIndex, &addrDecWin))
++ {
++ mvOsPrintf("tsuWinOverlapDetect: ERR. mvTsuWinGet failed\n");
++ return MV_ERROR;
++ }
++
++ if (MV_TRUE == ctrlWinOverlapTest(pAddrWin, &(addrDecWin.addrWin)))
++ {
++ return MV_TRUE;
++ }
++ }
++ return MV_FALSE;
++}
++
++
++/*******************************************************************************
++* mvTsuAddrDecShow
++*
++* DESCRIPTION:
++* Print the TSU address decode map.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++void mvTsuAddrDecShow(void)
++{
++ MV_TSU_DEC_WIN win;
++ int i;
++
++ if (MV_FALSE == mvCtrlPwrClckGet(TS_UNIT_ID, 0))
++ return;
++
++ mvOsOutput( "\n" );
++ mvOsOutput( "TSU:\n");
++ mvOsOutput( "----\n" );
++
++ for(i = 0; i < TSU_MAX_DECODE_WIN; i++)
++ {
++ memset(&win, 0, sizeof(TSU_MAX_DECODE_WIN));
++ mvOsOutput( "win%d - ", i );
++
++ if(mvTsuWinGet(i, &win ) == MV_OK )
++ {
++ if(win.enable == MV_TRUE)
++ {
++ mvOsOutput("%s base %08x, ",
++ mvCtrlTargetNameGet(win.target),
++ win.addrWin.baseLow);
++ mvOsOutput( "...." );
++ mvSizePrint(win.addrWin.size );
++ mvOsOutput( "\n" );
++ }
++ else
++ {
++ mvOsOutput( "disable\n" );
++ }
++ }
++ }
++ return;
++}
++
++
++/*******************************************************************************
++* mvTsuInit
++*
++* DESCRIPTION:
++* Initialize the TSU unit, and get unit out of reset.
++*
++* INPUT:
++* coreClock - The core clock at which the TSU should operate.
++* mode - The mode on configure the unit into (serial/parallel).
++* memHandle - Memory handle used for memory allocations.
++* OUTPUT:
++* None.
++* RETURN:
++* MV_OK - on success,
++*
++*******************************************************************************/
++MV_STATUS mvTsuInit(MV_TSU_CORE_CLOCK coreClock, MV_TSU_PORTS_MODE mode,
++ void *osHandle)
++{
++ MV_STATUS status;
++
++ status = mvTsuWinInit();
++ if(status == MV_OK)
++ status = mvTsuHalInit(coreClock,mode,osHandle);
++
++ return status;
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.h 2010-11-09 20:28:09.894776606 +0100
+@@ -0,0 +1,110 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvSysTsh
++#define __INCmvSysTsh
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/* includes */
++#include "ts/mvTsu.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/mvCtrlEnvAddrDec.h"
++
++#define TSU_MAX_DECODE_WIN 4
++
++
++/*******************************************/
++/* TSU Windows Registers */
++/*******************************************/
++#define MV_TSU_WIN_CTRL_REG(win) (TSU_GLOBAL_REG_BASE +0x30 + 0x10 * win)
++#define MV_TSU_WIN_BASE_REG(win) (TSU_GLOBAL_REG_BASE +0x34 + 0x10 * win)
++
++/* TSU windows control register. */
++#define TSU_WIN_CTRL_EN_MASK (0x1 << 0)
++#define TSU_WIN_CTRL_TARGET_OFFS 4
++#define TSU_WIN_CTRL_TARGET_MASK (0xF << TSU_WIN_CTRL_TARGET_OFFS)
++#define TSU_WIN_CTRL_ATTR_OFFS 8
++#define TSU_WIN_CTRL_ATTR_MASK (0xFF << TSU_WIN_CTRL_ATTR_OFFS)
++#define TSU_WIN_CTRL_SIZE_OFFS 16
++#define TSU_WIN_CTRL_SIZE_MASK (0xFFFF << TSU_WIN_CTRL_SIZE_OFFS)
++
++/* TSU windows base register. */
++#define TSU_WIN_BASE_OFFS 16
++#define TSU_WIN_BASE_MASK (0xFFFF << TSU_WIN_BASE_OFFS)
++
++MV_STATUS mvTsuWinInit(void);
++
++void mvTsuAddrDecShow(void);
++MV_STATUS mvTsuInit(MV_TSU_CORE_CLOCK coreClock, MV_TSU_PORTS_MODE mode,
++ void *osHandle);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __INCmvTsh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.c 2010-11-09 20:28:09.932495382 +0100
+@@ -0,0 +1,497 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "ctrlEnv/sys/mvSysUsb.h"
++
++MV_TARGET usbAddrDecPrioTab[] =
++{
++#if defined(MV_INCLUDE_SDRAM_CS0)
++ SDRAM_CS0,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS1)
++ SDRAM_CS1,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS2)
++ SDRAM_CS2,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS3)
++ SDRAM_CS3,
++#endif
++#if defined(MV_INCLUDE_CESA) && defined(USB_UNDERRUN_WA)
++ CRYPT_ENG,
++#endif
++#if defined(MV_INCLUDE_PEX)
++ PEX0_MEM,
++#endif
++ TBL_TERM
++};
++
++
++
++MV_STATUS mvUsbInit(int dev, MV_BOOL isHost)
++{
++ MV_STATUS status;
++
++ status = mvUsbWinInit(dev);
++ if(status != MV_OK)
++ return status;
++
++ return mvUsbHalInit(dev, isHost);
++}
++
++
++/*******************************************************************************
++* usbWinOverlapDetect - Detect USB address windows overlapping
++*
++* DESCRIPTION:
++* An unpredicted behaviur is expected in case USB address decode
++* windows overlapps.
++* This function detects USB address decode windows overlapping of a
++* specified window. The function does not check the window itself for
++* overlapping. The function also skipps disabled address decode windows.
++*
++* INPUT:
++* winNum - address decode window number.
++* pAddrDecWin - An address decode window struct.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlap current address
++* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data
++* from registers.
++*
++*******************************************************************************/
++static MV_STATUS usbWinOverlapDetect(int dev, MV_U32 winNum,
++ MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 winNumIndex;
++ MV_DEC_WIN addrDecWin;
++
++ for(winNumIndex=0; winNumIndex<MV_USB_MAX_ADDR_DECODE_WIN; winNumIndex++)
++ {
++ /* Do not check window itself */
++ if (winNumIndex == winNum)
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ if (MV_OK != mvUsbWinGet(dev, winNumIndex, &addrDecWin))
++ {
++ mvOsPrintf("%s: ERR. TargetWinGet failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ /* Do not check disabled windows */
++ if(addrDecWin.enable == MV_FALSE)
++ {
++ continue;
++ }
++
++ if (MV_TRUE == ctrlWinOverlapTest(pAddrWin, &(addrDecWin.addrWin)))
++ {
++ return MV_TRUE;
++ }
++ }
++ return MV_FALSE;
++}
++
++/*******************************************************************************
++* mvUsbWinSet - Set USB target address window
++*
++* DESCRIPTION:
++* This function sets a peripheral target (e.g. SDRAM bank0, PCI_MEM0)
++* address window, also known as address decode window.
++* After setting this target window, the USB will be able to access the
++* target within the address window.
++*
++* INPUT:
++* winNum - USB target address decode window number.
++* pAddrDecWin - USB target window data structure.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR if address window overlapps with other address decode windows.
++* MV_BAD_PARAM if base address is invalid parameter or target is
++* unknown.
++*
++*******************************************************************************/
++MV_STATUS mvUsbWinSet(int dev, MV_U32 winNum, MV_DEC_WIN *pDecWin)
++{
++ MV_DEC_WIN_PARAMS winParams;
++ MV_U32 sizeReg, baseReg;
++
++ /* Parameter checking */
++ if (winNum >= MV_USB_MAX_ADDR_DECODE_WIN)
++ {
++ mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__, winNum);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check if the requested window overlapps with current windows */
++ if (MV_TRUE == usbWinOverlapDetect(dev, winNum, &pDecWin->addrWin))
++ {
++ mvOsPrintf("%s: ERR. Window %d overlap\n", __FUNCTION__, winNum);
++ return MV_ERROR;
++ }
++
++ /* check if address is aligned to the size */
++ if(MV_IS_NOT_ALIGN(pDecWin->addrWin.baseLow, pDecWin->addrWin.size))
++ {
++ mvOsPrintf("mvUsbWinSet:Error setting USB window %d to "\
++ "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ winNum,
++ mvCtrlTargetNameGet(pDecWin->target),
++ pDecWin->addrWin.baseLow,
++ pDecWin->addrWin.size);
++ return MV_ERROR;
++ }
++
++ if(MV_OK != mvCtrlAddrDecToParams(pDecWin, &winParams))
++ {
++ mvOsPrintf("%s: mvCtrlAddrDecToParams Failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ /* set Size, Attributes and TargetID */
++ sizeReg = (((winParams.targetId << MV_USB_WIN_TARGET_OFFSET) & MV_USB_WIN_TARGET_MASK) |
++ ((winParams.attrib << MV_USB_WIN_ATTR_OFFSET) & MV_USB_WIN_ATTR_MASK) |
++ ((winParams.size << MV_USB_WIN_SIZE_OFFSET) & MV_USB_WIN_SIZE_MASK));
++
++#if defined(MV645xx) || defined(MV646xx)
++ /* If window is DRAM with HW cache coherency, make sure bit2 is set */
++ sizeReg &= ~MV_USB_WIN_BURST_WR_LIMIT_MASK;
++
++ if((MV_TARGET_IS_DRAM(pDecWin->target)) &&
++ (pDecWin->addrWinAttr.cachePolicy != NO_COHERENCY))
++ {
++ sizeReg |= MV_USB_WIN_BURST_WR_32BIT_LIMIT;
++ }
++ else
++ {
++ sizeReg |= MV_USB_WIN_BURST_WR_NO_LIMIT;
++ }
++#endif /* MV645xx || MV646xx */
++
++ if (pDecWin->enable == MV_TRUE)
++ {
++ sizeReg |= MV_USB_WIN_ENABLE_MASK;
++ }
++ else
++ {
++ sizeReg &= ~MV_USB_WIN_ENABLE_MASK;
++ }
++
++ /* Update Base value */
++ baseReg = (winParams.baseAddr & MV_USB_WIN_BASE_MASK);
++
++ MV_REG_WRITE( MV_USB_WIN_CTRL_REG(dev, winNum), sizeReg);
++ MV_REG_WRITE( MV_USB_WIN_BASE_REG(dev, winNum), baseReg);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvUsbWinGet - Get USB peripheral target address window.
++*
++* DESCRIPTION:
++* Get USB peripheral target address window.
++*
++* INPUT:
++* winNum - USB target address decode window number.
++*
++* OUTPUT:
++* pDecWin - USB target window data structure.
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++MV_STATUS mvUsbWinGet(int dev, MV_U32 winNum, MV_DEC_WIN *pDecWin)
++{
++ MV_DEC_WIN_PARAMS winParam;
++ MV_U32 sizeReg, baseReg;
++
++ /* Parameter checking */
++ if (winNum >= MV_USB_MAX_ADDR_DECODE_WIN)
++ {
++ mvOsPrintf("%s (dev=%d): ERR. Invalid winNum %d\n",
++ __FUNCTION__, dev, winNum);
++ return MV_NOT_SUPPORTED;
++ }
++
++ baseReg = MV_REG_READ( MV_USB_WIN_BASE_REG(dev, winNum) );
++ sizeReg = MV_REG_READ( MV_USB_WIN_CTRL_REG(dev, winNum) );
++
++ /* Check if window is enabled */
++ if(sizeReg & MV_USB_WIN_ENABLE_MASK)
++ {
++ pDecWin->enable = MV_TRUE;
++
++ /* Extract window parameters from registers */
++ winParam.targetId = (sizeReg & MV_USB_WIN_TARGET_MASK) >> MV_USB_WIN_TARGET_OFFSET;
++ winParam.attrib = (sizeReg & MV_USB_WIN_ATTR_MASK) >> MV_USB_WIN_ATTR_OFFSET;
++ winParam.size = (sizeReg & MV_USB_WIN_SIZE_MASK) >> MV_USB_WIN_SIZE_OFFSET;
++ winParam.baseAddr = (baseReg & MV_USB_WIN_BASE_MASK);
++
++ /* Translate the decode window parameters to address decode struct */
++ if (MV_OK != mvCtrlParamsToAddrDec(&winParam, pDecWin))
++ {
++ mvOsPrintf("Failed to translate register parameters to USB address" \
++ " decode window structure\n");
++ return MV_ERROR;
++ }
++ }
++ else
++ {
++ pDecWin->enable = MV_FALSE;
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvUsbWinInit -
++*
++* INPUT:
++*
++* OUTPUT:
++*
++* RETURN:
++* MV_ERROR if register parameters are invalid.
++*
++*******************************************************************************/
++MV_STATUS mvUsbWinInit(int dev)
++{
++ MV_STATUS status;
++ MV_DEC_WIN usbWin;
++ MV_CPU_DEC_WIN cpuAddrDecWin;
++ int winNum;
++ MV_U32 winPrioIndex = 0;
++
++ /* First disable all address decode windows */
++ for(winNum = 0; winNum < MV_USB_MAX_ADDR_DECODE_WIN; winNum++)
++ {
++ MV_REG_BIT_RESET(MV_USB_WIN_CTRL_REG(dev, winNum), MV_USB_WIN_ENABLE_MASK);
++ }
++
++ /* Go through all windows in user table until table terminator */
++ winNum = 0;
++ while( (usbAddrDecPrioTab[winPrioIndex] != TBL_TERM) &&
++ (winNum < MV_USB_MAX_ADDR_DECODE_WIN) )
++ {
++ /* first get attributes from CPU If */
++ status = mvCpuIfTargetWinGet(usbAddrDecPrioTab[winPrioIndex],
++ &cpuAddrDecWin);
++
++ if(MV_NO_SUCH == status)
++ {
++ winPrioIndex++;
++ continue;
++ }
++ if (MV_OK != status)
++ {
++ mvOsPrintf("%s: ERR. mvCpuIfTargetWinGet failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ if (cpuAddrDecWin.enable == MV_TRUE)
++ {
++ usbWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh;
++ usbWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow;
++ usbWin.addrWin.size = cpuAddrDecWin.addrWin.size;
++ usbWin.enable = MV_TRUE;
++ usbWin.target = usbAddrDecPrioTab[winPrioIndex];
++
++#if defined(MV645xx) || defined(MV646xx)
++ /* Get the default attributes for that target window */
++ mvCtrlDefAttribGet(usbWin.target, &usbWin.addrWinAttr);
++#endif /* MV645xx || MV646xx */
++
++ if(MV_OK != mvUsbWinSet(dev, winNum, &usbWin))
++ {
++ return MV_ERROR;
++ }
++ winNum++;
++ }
++ winPrioIndex++;
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvUsbAddrDecShow - Print the USB address decode map.
++*
++* DESCRIPTION:
++* This function print the USB address decode map.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvUsbAddrDecShow(MV_VOID)
++{
++ MV_DEC_WIN addrDecWin;
++ int i, winNum;
++
++ mvOsOutput( "\n" );
++ mvOsOutput( "USB:\n" );
++ mvOsOutput( "----\n" );
++
++ for(i=0; i<mvCtrlUsbMaxGet(); i++)
++ {
++ mvOsOutput( "Device %d:\n", i);
++
++ for(winNum = 0; winNum < MV_USB_MAX_ADDR_DECODE_WIN; winNum++)
++ {
++ memset(&addrDecWin, 0, sizeof(MV_DEC_WIN) );
++
++ mvOsOutput( "win%d - ", winNum );
++
++ if( mvUsbWinGet(i, winNum, &addrDecWin ) == MV_OK )
++ {
++ if( addrDecWin.enable )
++ {
++ mvOsOutput( "%s base %08x, ",
++ mvCtrlTargetNameGet(addrDecWin.target), addrDecWin.addrWin.baseLow );
++
++ mvSizePrint( addrDecWin.addrWin.size );
++
++#if defined(MV645xx) || defined(MV646xx)
++ switch( addrDecWin.addrWinAttr.swapType)
++ {
++ case MV_BYTE_SWAP:
++ mvOsOutput( "BYTE_SWAP, " );
++ break;
++ case MV_NO_SWAP:
++ mvOsOutput( "NO_SWAP , " );
++ break;
++ case MV_BYTE_WORD_SWAP:
++ mvOsOutput( "BYTE_WORD_SWAP, " );
++ break;
++ case MV_WORD_SWAP:
++ mvOsOutput( "WORD_SWAP, " );
++ break;
++ default:
++ mvOsOutput( "SWAP N/A , " );
++ }
++
++ switch( addrDecWin.addrWinAttr.cachePolicy )
++ {
++ case NO_COHERENCY:
++ mvOsOutput( "NO_COHERENCY , " );
++ break;
++ case WT_COHERENCY:
++ mvOsOutput( "WT_COHERENCY , " );
++ break;
++ case WB_COHERENCY:
++ mvOsOutput( "WB_COHERENCY , " );
++ break;
++ default:
++ mvOsOutput( "COHERENCY N/A, " );
++ }
++
++ switch( addrDecWin.addrWinAttr.pcixNoSnoop )
++ {
++ case 0:
++ mvOsOutput( "PCI-X NS inactive, " );
++ break;
++ case 1:
++ mvOsOutput( "PCI-X NS active , " );
++ break;
++ default:
++ mvOsOutput( "PCI-X NS N/A , " );
++ }
++
++ switch( addrDecWin.addrWinAttr.p2pReq64 )
++ {
++ case 0:
++ mvOsOutput( "REQ64 force" );
++ break;
++ case 1:
++ mvOsOutput( "REQ64 detect" );
++ break;
++ default:
++ mvOsOutput( "REQ64 N/A" );
++ }
++#endif /* MV645xx || MV646xx */
++ mvOsOutput( "\n" );
++ }
++ else
++ mvOsOutput( "disable\n" );
++ }
++ }
++ }
++}
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.h 2010-11-09 20:28:09.972495420 +0100
+@@ -0,0 +1,125 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvSysUsbh
++#define __INCmvSysUsbh
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/* includes */
++#include "usb/mvUsb.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/mvCtrlEnvAddrDec.h"
++
++#define MV_USB_MAX_ADDR_DECODE_WIN 4
++
++/*******************************************/
++/* USB Bridge Registers */
++/*******************************************/
++#define MV_USB_BRIDGE_CTRL_REG(dev) (USB_REG_BASE(dev) + 0x300)
++
++#define MV_USB_WIN_CTRL_REG(dev, win) (USB_REG_BASE(dev) + 0x320 + ((win)<<4))
++#define MV_USB_WIN_BASE_REG(dev, win) (USB_REG_BASE(dev) + 0x324 + ((win)<<4))
++
++/* BITs in Windows 0-3 Control and Base Registers */
++#define MV_USB_WIN_ENABLE_BIT 0
++#define MV_USB_WIN_ENABLE_MASK (1 << MV_USB_WIN_ENABLE_BIT)
++
++#define MV_USB_WIN_BURST_WR_LIMIT_BIT 1
++#define MV_USB_WIN_BURST_WR_LIMIT_MASK (1 << MV_USB_WIN_BURST_WR_LIMIT_BIT)
++#define MV_USB_WIN_BURST_WR_NO_LIMIT (0 << MV_USB_WIN_BURST_WR_LIMIT_BIT)
++#define MV_USB_WIN_BURST_WR_32BIT_LIMIT (1 << MV_USB_WIN_BURST_WR_LIMIT_BIT)
++
++#define MV_USB_WIN_TARGET_OFFSET 4
++#define MV_USB_WIN_TARGET_MASK (0xF << MV_USB_WIN_TARGET_OFFSET)
++
++#define MV_USB_WIN_ATTR_OFFSET 8
++#define MV_USB_WIN_ATTR_MASK (0xFF << MV_USB_WIN_ATTR_OFFSET)
++
++#define MV_USB_WIN_SIZE_OFFSET 16
++#define MV_USB_WIN_SIZE_MASK (0xFFFF << MV_USB_WIN_SIZE_OFFSET)
++
++#define MV_USB_WIN_BASE_OFFSET 16
++#define MV_USB_WIN_BASE_MASK (0xFFFF << MV_USB_WIN_BASE_OFFSET)
++
++
++#define MV_USB_BRIDGE_IPG_REG(dev) (USB_REG_BASE(dev) + 0x360)
++
++
++MV_STATUS mvUsbInit(int dev, MV_BOOL isHost);
++
++MV_STATUS mvUsbWinInit(int dev);
++MV_STATUS mvUsbWinSet(int dev, MV_U32 winNum, MV_DEC_WIN *pAddrWin);
++MV_STATUS mvUsbWinGet(int dev, MV_U32 winNum, MV_DEC_WIN *pAddrWin);
++
++void mvUsbAddrDecShow(void);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __INCmvUsbh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.c 2010-11-09 20:28:10.022500031 +0100
+@@ -0,0 +1,662 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "xor/mvXor.h"
++#include "mvSysXor.h"
++
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++
++static MV_STATUS xorWinOverlapDetect(MV_U32 unit,MV_U32 winNum, MV_ADDR_WIN *pAddrWin);
++
++MV_TARGET xorAddrDecPrioTap[] =
++{
++#if defined(MV_INCLUDE_DEVICE_CS0)
++ DEVICE_CS0,
++#endif
++#if defined(MV_INCLUDE_PEX)
++ PEX0_MEM,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS0)
++ SDRAM_CS0,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS1)
++ SDRAM_CS1,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS2)
++ SDRAM_CS2,
++#endif
++#if defined(MV_INCLUDE_SDRAM_CS3)
++ SDRAM_CS3,
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS1)
++ DEVICE_CS1,
++#endif
++#if defined(MV_INCLUDE_CESA)
++ CRYPT_ENG,
++#endif
++ TBL_TERM
++};
++static MV_STATUS mvXorInitWinsUnit (MV_U32 unit)
++{
++ MV_U32 winNum;
++ MV_XOR_DEC_WIN addrDecWin;
++ MV_CPU_DEC_WIN cpuAddrDecWin;
++ MV_U32 status;
++ MV_U32 winPrioIndex=0;
++
++ /* Initiate XOR address decode */
++
++ /* First disable all address decode windows */
++ for(winNum = 0; winNum < XOR_MAX_ADDR_DEC_WIN; winNum++)
++ {
++ mvXorTargetWinEnable(unit,winNum, MV_FALSE);
++ }
++
++ /* Go through all windows in user table until table terminator */
++ for (winNum = 0; ((xorAddrDecPrioTap[winPrioIndex] != TBL_TERM) &&
++ (winNum < XOR_MAX_ADDR_DEC_WIN));)
++ {
++ /* first get attributes from CPU If */
++ status = mvCpuIfTargetWinGet(xorAddrDecPrioTap[winPrioIndex],
++ &cpuAddrDecWin);
++
++ if(MV_NO_SUCH == status)
++ {
++ winPrioIndex++;
++ continue;
++ }
++ if (MV_OK != status)
++ {
++ mvOsPrintf("%s: ERR. mvCpuIfTargetWinGet failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++
++ if (cpuAddrDecWin.enable == MV_TRUE)
++ {
++
++ addrDecWin.target = xorAddrDecPrioTap[winPrioIndex];
++ addrDecWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow;
++ addrDecWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh;
++ addrDecWin.addrWin.size = cpuAddrDecWin.addrWin.size;
++ addrDecWin.enable = MV_TRUE;
++
++ if (MV_OK != mvXorTargetWinSet(unit,winNum, &addrDecWin))
++ {
++ DB(mvOsPrintf("mvXorInit: ERR. mvDmaTargetWinSet failed\n"));
++ return MV_ERROR;
++ }
++ winNum++;
++ }
++ winPrioIndex++;
++
++ }
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvXorInit - Initialize XOR engine
++*
++* DESCRIPTION:
++* This function initialize XOR unit. It set the default address decode
++* windows of the unit.
++* Note that if the address window is disabled in xorAddrDecMap, the
++* window parameters will be set but the window will remain disabled.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
++*******************************************************************************/
++MV_STATUS mvXorInit (MV_VOID)
++{
++ MV_U32 i;
++
++ /* Initiate XOR address decode */
++ for(i = 0; i < MV_XOR_MAX_UNIT; i++)
++ mvXorInitWinsUnit(i);
++
++ mvXorHalInit(MV_XOR_MAX_CHAN);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvXorTargetWinSet - Set XOR target address window
++*
++* DESCRIPTION:
++* This function sets a peripheral target (e.g. SDRAM bank0, PCI_MEM0)
++* address window. After setting this target window, the XOR will be
++* able to access the target within the address window.
++*
++* INPUT:
++* winNum - One of the possible XOR memory decode windows.
++* target - Peripheral target enumerator.
++* base - Window base address.
++* size - Window size.
++* enable - Window enable/disable.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
++*
++*******************************************************************************/
++MV_STATUS mvXorTargetWinSet(MV_U32 unit, MV_U32 winNum, MV_XOR_DEC_WIN *pAddrDecWin)
++{
++ MV_DEC_REGS xorDecRegs;
++ MV_TARGET_ATTRIB targetAttribs;
++ MV_U32 chan;
++
++ /* Parameter checking */
++ if (winNum >= XOR_MAX_ADDR_DEC_WIN)
++ {
++ DB(mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__, winNum));
++ return MV_BAD_PARAM;
++ }
++ if (pAddrDecWin == NULL)
++ {
++ DB(mvOsPrintf("%s: ERR. pAddrDecWin is NULL pointer\n", __FUNCTION__ ));
++ return MV_BAD_PTR;
++ }
++ /* Check if the requested window overlaps with current windows */
++ if (MV_TRUE == xorWinOverlapDetect(unit, winNum, &pAddrDecWin->addrWin))
++ {
++ DB(mvOsPrintf("%s: ERR. Window %d overlap\n",__FUNCTION__,winNum));
++ return MV_ERROR;
++ }
++
++ xorDecRegs.baseReg = MV_REG_READ(XOR_BASE_ADDR_REG(unit,winNum));
++ xorDecRegs.sizeReg = MV_REG_READ(XOR_SIZE_MASK_REG(unit,winNum));
++
++ /* Get Base Address and size registers values */
++ if(MV_OK != mvCtrlAddrDecToReg(&pAddrDecWin->addrWin, &xorDecRegs))
++ {
++ DB(mvOsPrintf("%s: ERR. Invalid addr dec window\n",__FUNCTION__));
++ return MV_BAD_PARAM;
++ }
++
++
++ mvCtrlAttribGet(pAddrDecWin->target,&targetAttribs);
++
++ /* set attributes */
++ xorDecRegs.baseReg &= ~XEBARX_ATTR_MASK;
++ xorDecRegs.baseReg |= targetAttribs.attrib << XEBARX_ATTR_OFFS;
++ /* set target ID */
++ xorDecRegs.baseReg &= ~XEBARX_TARGET_MASK;
++ xorDecRegs.baseReg |= targetAttribs.targetId << XEBARX_TARGET_OFFS;
++
++
++ /* Write to address decode Base Address Register */
++ MV_REG_WRITE(XOR_BASE_ADDR_REG(unit,winNum), xorDecRegs.baseReg);
++
++ /* Write to Size Register */
++ MV_REG_WRITE(XOR_SIZE_MASK_REG(unit,winNum), xorDecRegs.sizeReg);
++
++ for (chan = 0; chan < MV_XOR_MAX_CHAN_PER_UNIT; chan++)
++ {
++ if (pAddrDecWin->enable)
++ {
++ MV_REG_BIT_SET(XOR_WINDOW_CTRL_REG(unit,chan),
++ XEXWCR_WIN_EN_MASK(winNum));
++ }
++ else
++ {
++ MV_REG_BIT_RESET(XOR_WINDOW_CTRL_REG(unit,chan),
++ XEXWCR_WIN_EN_MASK(winNum));
++ }
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvXorTargetWinGet - Get xor peripheral target address window.
++*
++* DESCRIPTION:
++* Get xor peripheral target address window.
++*
++* INPUT:
++* winNum - One of the possible XOR memory decode windows.
++*
++* OUTPUT:
++* base - Window base address.
++* size - Window size.
++* enable - window enable/disable.
++*
++* RETURN:
++* MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
++*
++*******************************************************************************/
++MV_STATUS mvXorTargetWinGet(MV_U32 unit,MV_U32 winNum, MV_XOR_DEC_WIN *pAddrDecWin)
++{
++ MV_DEC_REGS xorDecRegs;
++ MV_TARGET_ATTRIB targetAttrib;
++ MV_U32 chan=0,chanWinEn;
++
++ /* Parameter checking */
++ if (winNum >= XOR_MAX_ADDR_DEC_WIN)
++ {
++ DB(mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__ , winNum));
++ return MV_ERROR;
++ }
++
++ if (NULL == pAddrDecWin)
++ {
++ DB(mvOsPrintf("%s: ERR. pAddrDecWin is NULL pointer\n", __FUNCTION__ ));
++ return MV_BAD_PTR;
++ }
++
++ chanWinEn = MV_REG_READ(XOR_WINDOW_CTRL_REG(unit,0)) & XEXWCR_WIN_EN_MASK(winNum);
++
++ for (chan = 0; chan < MV_XOR_MAX_CHAN_PER_UNIT; chan++) /* we should scan here all channels per unit */
++ {
++ /* Check if enable bit is equal for all channels */
++ if ((MV_REG_READ(XOR_WINDOW_CTRL_REG(unit,chan)) &
++ XEXWCR_WIN_EN_MASK(winNum)) != chanWinEn)
++ {
++ mvOsPrintf("%s: ERR. Window enable field must be equal in "
++ "all channels(chan=%d)\n",__FUNCTION__, chan);
++ return MV_ERROR;
++ }
++ }
++
++
++
++ xorDecRegs.baseReg = MV_REG_READ(XOR_BASE_ADDR_REG(unit,winNum));
++ xorDecRegs.sizeReg = MV_REG_READ(XOR_SIZE_MASK_REG(unit,winNum));
++
++ if (MV_OK != mvCtrlRegToAddrDec(&xorDecRegs, &pAddrDecWin->addrWin))
++ {
++ mvOsPrintf("%s: ERR. mvCtrlRegToAddrDec failed\n", __FUNCTION__);
++ return MV_ERROR;
++ }
++
++ /* attrib and targetId */
++ targetAttrib.attrib =
++ (xorDecRegs.baseReg & XEBARX_ATTR_MASK) >> XEBARX_ATTR_OFFS;
++ targetAttrib.targetId =
++ (xorDecRegs.baseReg & XEBARX_TARGET_MASK) >> XEBARX_TARGET_OFFS;
++
++
++ pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib);
++
++ if(chanWinEn)
++ {
++ pAddrDecWin->enable = MV_TRUE;
++ }
++ else pAddrDecWin->enable = MV_FALSE;
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvXorTargetWinEnable - Enable/disable a Xor address decode window
++*
++* DESCRIPTION:
++* This function enable/disable a XOR address decode window.
++* if parameter 'enable' == MV_TRUE the routine will enable the
++* window, thus enabling XOR accesses (before enabling the window it is
++* tested for overlapping). Otherwise, the window will be disabled.
++*
++* INPUT:
++* winNum - Decode window number.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
++*
++*******************************************************************************/
++MV_STATUS mvXorTargetWinEnable(MV_U32 unit,MV_U32 winNum, MV_BOOL enable)
++{
++ MV_XOR_DEC_WIN addrDecWin;
++ MV_U32 chan;
++
++ /* Parameter checking */
++ if (winNum >= XOR_MAX_ADDR_DEC_WIN)
++ {
++ DB(mvOsPrintf("%s: ERR. Invalid winNum%d\n", __FUNCTION__, winNum));
++ return MV_ERROR;
++ }
++
++ if (enable == MV_TRUE)
++ {
++ /* Get current window */
++ if (MV_OK != mvXorTargetWinGet(unit,winNum, &addrDecWin))
++ {
++ DB(mvOsPrintf("%s: ERR. targetWinGet fail\n", __FUNCTION__));
++ return MV_ERROR;
++ }
++
++ /* Check for overlapping */
++ if (MV_TRUE == xorWinOverlapDetect(unit,winNum, &(addrDecWin.addrWin)))
++ {
++ /* Overlap detected */
++ DB(mvOsPrintf("%s: ERR. Overlap detected\n", __FUNCTION__));
++ return MV_ERROR;
++ }
++
++ /* No Overlap. Enable address decode target window */
++ for (chan = 0; chan < MV_XOR_MAX_CHAN_PER_UNIT; chan++)
++ {
++ MV_REG_BIT_SET(XOR_WINDOW_CTRL_REG(unit,chan),
++ XEXWCR_WIN_EN_MASK(winNum));
++ }
++
++ }
++ else
++ {
++ /* Disable address decode target window */
++
++ for (chan = 0; chan < MV_XOR_MAX_CHAN_PER_UNIT; chan++)
++ {
++ MV_REG_BIT_RESET(XOR_WINDOW_CTRL_REG(unit,chan),
++ XEXWCR_WIN_EN_MASK(winNum));
++ }
++
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvXorSetProtWinSet - Configure access attributes of a XOR engine
++* to one of the XOR memory windows.
++*
++* DESCRIPTION:
++* Each engine can be configured with access attributes for each of the
++* memory spaces. This function sets access attributes
++* to a given window for the given engine
++*
++* INPUTS:
++* chan - One of the possible engines.
++* winNum - One of the possible XOR memory spaces.
++* access - Protection access rights.
++* write - Write rights.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
++*
++*******************************************************************************/
++MV_STATUS mvXorProtWinSet (MV_U32 unit,MV_U32 chan, MV_U32 winNum, MV_BOOL access,
++ MV_BOOL write)
++{
++ MV_U32 temp;
++
++ /* Parameter checking */
++ if (chan >= MV_XOR_MAX_CHAN_PER_UNIT)
++ {
++ DB(mvOsPrintf("%s: ERR. Invalid chan num %d\n", __FUNCTION__ , chan));
++ return MV_BAD_PARAM;
++ }
++ if (winNum >= XOR_MAX_ADDR_DEC_WIN)
++ {
++ DB(mvOsPrintf("%s: ERR. Invalid win num %d\n", __FUNCTION__, winNum));
++ return MV_BAD_PARAM;
++ }
++
++ temp = MV_REG_READ(XOR_WINDOW_CTRL_REG(unit,chan)) &
++ (~XEXWCR_WIN_ACC_MASK(winNum));
++
++ /* if access is disable */
++ if (!access)
++ {
++ /* disable access */
++ temp |= XEXWCR_WIN_ACC_NO_ACC(winNum);
++ }
++ /* if access is enable */
++ else
++ {
++ /* if write is enable */
++ if (write)
++ {
++ /* enable write */
++ temp |= XEXWCR_WIN_ACC_RW(winNum);
++ }
++ /* if write is disable */
++ else
++ {
++ /* disable write */
++ temp |= XEXWCR_WIN_ACC_RO(winNum);
++ }
++ }
++ MV_REG_WRITE(XOR_WINDOW_CTRL_REG(unit,chan),temp);
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvXorPciRemap - Set XOR remap register for PCI address windows.
++*
++* DESCRIPTION:
++* only Windows 0-3 can be remapped.
++*
++* INPUT:
++* winNum - window number
++* pAddrDecWin - pointer to address space window structure
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
++*
++*******************************************************************************/
++MV_STATUS mvXorPciRemap(MV_U32 unit,MV_U32 winNum, MV_U32 addrHigh)
++{
++ /* Parameter checking */
++ if (winNum >= XOR_MAX_REMAP_WIN)
++ {
++ DB(mvOsPrintf("%s: ERR. Invalid win num %d\n", __FUNCTION__, winNum));
++ return MV_BAD_PARAM;
++ }
++
++ MV_REG_WRITE(XOR_HIGH_ADDR_REMAP_REG(unit,winNum), addrHigh);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* xorWinOverlapDetect - Detect XOR address windows overlaping
++*
++* DESCRIPTION:
++* An unpredicted behaviour is expected in case XOR address decode
++* windows overlaps.
++* This function detects XOR address decode windows overlaping of a
++* specified window. The function does not check the window itself for
++* overlaping. The function also skipps disabled address decode windows.
++*
++* INPUT:
++* winNum - address decode window number.
++* pAddrDecWin - An address decode window struct.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlap current address
++* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data
++* from registers.
++*
++*******************************************************************************/
++static MV_STATUS xorWinOverlapDetect(MV_U32 unit,MV_U32 winNum, MV_ADDR_WIN *pAddrWin)
++{
++ MV_U32 baseAddrEnableReg;
++ MV_U32 winNumIndex,chan;
++ MV_XOR_DEC_WIN addrDecWin;
++
++ if (pAddrWin == NULL)
++ {
++ DB(mvOsPrintf("%s: ERR. pAddrWin is NULL pointer\n", __FUNCTION__ ));
++ return MV_BAD_PTR;
++ }
++
++ for (chan = 0; chan < MV_XOR_MAX_CHAN_PER_UNIT; chan++)
++ {
++ /* Read base address enable register. Do not check disabled windows */
++ baseAddrEnableReg = MV_REG_READ(XOR_WINDOW_CTRL_REG(unit,chan));
++
++ for (winNumIndex = 0; winNumIndex < XOR_MAX_ADDR_DEC_WIN; winNumIndex++)
++ {
++ /* Do not check window itself */
++ if (winNumIndex == winNum)
++ {
++ continue;
++ }
++
++ /* Do not check disabled windows */
++ if ((baseAddrEnableReg & XEXWCR_WIN_EN_MASK(winNumIndex)) == 0)
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ if (MV_OK != mvXorTargetWinGet(unit,winNumIndex, &addrDecWin))
++ {
++ DB(mvOsPrintf("%s: ERR. TargetWinGet failed\n", __FUNCTION__ ));
++ return MV_ERROR;
++ }
++
++ if (MV_TRUE == ctrlWinOverlapTest(pAddrWin, &(addrDecWin.addrWin)))
++ {
++ return MV_TRUE;
++ }
++ }
++ }
++
++ return MV_FALSE;
++}
++
++static MV_VOID mvXorAddrDecShowUnit(MV_U32 unit)
++{
++ MV_XOR_DEC_WIN win;
++ int i;
++
++ mvOsOutput( "\n" );
++ mvOsOutput( "XOR %d:\n", unit );
++ mvOsOutput( "----\n" );
++
++ for( i = 0; i < XOR_MAX_ADDR_DEC_WIN; i++ )
++ {
++ memset( &win, 0, sizeof(MV_XOR_DEC_WIN) );
++
++ mvOsOutput( "win%d - ", i );
++
++ if( mvXorTargetWinGet(unit, i, &win ) == MV_OK )
++ {
++ if( win.enable )
++ {
++ mvOsOutput( "%s base %x, ",
++ mvCtrlTargetNameGet(win.target), win.addrWin.baseLow );
++
++ mvSizePrint( win.addrWin.size );
++
++ mvOsOutput( "\n" );
++ }
++ else
++ mvOsOutput( "disable\n" );
++ }
++ }
++}
++
++/*******************************************************************************
++* mvXorAddrDecShow - Print the XOR address decode map.
++*
++* DESCRIPTION:
++* This function print the XOR address decode map.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID mvXorAddrDecShow(MV_VOID)
++{
++ int i;
++
++ for( i = 0; i < MV_XOR_MAX_UNIT; i++ )
++ mvXorAddrDecShowUnit(i);
++
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.h 2010-11-09 20:28:10.062495382 +0100
+@@ -0,0 +1,140 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCMVSysXorh
++#define __INCMVSysXorh
++
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include "ctrlEnv/sys/mvCpuIf.h"
++
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/mvCtrlEnvAddrDec.h"
++
++#define XOR_MAX_ADDR_DEC_WIN 8 /* Maximum address decode windows */
++#define XOR_MAX_REMAP_WIN 4 /* Maximum address arbiter windows */
++
++/* XOR Engine Address Decoding Register Map */
++#define XOR_WINDOW_CTRL_REG(unit,chan) (XOR_UNIT_BASE(unit)+(0x240 + ((chan) * 4)))
++#define XOR_BASE_ADDR_REG(unit,winNum) (XOR_UNIT_BASE(unit)+(0x250 + ((winNum) * 4)))
++#define XOR_SIZE_MASK_REG(unit,winNum) (XOR_UNIT_BASE(unit)+(0x270 + ((winNum) * 4)))
++#define XOR_HIGH_ADDR_REMAP_REG(unit,winNum) (XOR_UNIT_BASE(unit)+(0x290 + ((winNum) * 4)))
++
++/* XOR Engine [0..1] Window Control Registers (XExWCR) */
++#define XEXWCR_WIN_EN_OFFS(winNum) (winNum)
++#define XEXWCR_WIN_EN_MASK(winNum) (1 << (XEXWCR_WIN_EN_OFFS(winNum)))
++#define XEXWCR_WIN_EN_ENABLE(winNum) (1 << (XEXWCR_WIN_EN_OFFS(winNum)))
++#define XEXWCR_WIN_EN_DISABLE(winNum) (0 << (XEXWCR_WIN_EN_OFFS(winNum)))
++
++#define XEXWCR_WIN_ACC_OFFS(winNum) ((2 * winNum) + 16)
++#define XEXWCR_WIN_ACC_MASK(winNum) (3 << (XEXWCR_WIN_ACC_OFFS(winNum)))
++#define XEXWCR_WIN_ACC_NO_ACC(winNum) (0 << (XEXWCR_WIN_ACC_OFFS(winNum)))
++#define XEXWCR_WIN_ACC_RO(winNum) (1 << (XEXWCR_WIN_ACC_OFFS(winNum)))
++#define XEXWCR_WIN_ACC_RW(winNum) (3 << (XEXWCR_WIN_ACC_OFFS(winNum)))
++
++/* XOR Engine Base Address Registers (XEBARx) */
++#define XEBARX_TARGET_OFFS (0)
++#define XEBARX_TARGET_MASK (0xF << XEBARX_TARGET_OFFS)
++#define XEBARX_ATTR_OFFS (8)
++#define XEBARX_ATTR_MASK (0xFF << XEBARX_ATTR_OFFS)
++#define XEBARX_BASE_OFFS (16)
++#define XEBARX_BASE_MASK (0xFFFF << XEBARX_BASE_OFFS)
++
++/* XOR Engine Size Mask Registers (XESMRx) */
++#define XESMRX_SIZE_MASK_OFFS (16)
++#define XESMRX_SIZE_MASK_MASK (0xFFFF << XESMRX_SIZE_MASK_OFFS)
++
++/* XOR Engine High Address Remap Register (XEHARRx1) */
++#define XEHARRX_REMAP_OFFS (0)
++#define XEHARRX_REMAP_MASK (0xFFFFFFFF << XEHARRX_REMAP_OFFS)
++
++typedef struct _mvXorDecWin
++{
++ MV_TARGET target;
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++
++}MV_XOR_DEC_WIN;
++
++MV_STATUS mvXorInit (MV_VOID);
++MV_STATUS mvXorTargetWinSet(MV_U32 unit, MV_U32 winNum,
++ MV_XOR_DEC_WIN *pAddrDecWin);
++MV_STATUS mvXorTargetWinGet(MV_U32 unit, MV_U32 winNum,
++ MV_XOR_DEC_WIN *pAddrDecWin);
++MV_STATUS mvXorTargetWinEnable(MV_U32 unit,
++ MV_U32 winNum, MV_BOOL enable);
++MV_STATUS mvXorProtWinSet (MV_U32 unit,MV_U32 chan, MV_U32 winNum, MV_BOOL access,
++ MV_BOOL write);
++MV_STATUS mvXorPciRemap(MV_U32 unit, MV_U32 winNum, MV_U32 addrHigh);
++
++MV_VOID mvXorAddrDecShow(MV_VOID);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.c 2010-11-09 20:28:10.101392611 +0100
+@@ -0,0 +1,75 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "device/mvDevice.h"
++
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.h 2010-11-09 20:28:10.141918633 +0100
+@@ -0,0 +1,74 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDeviceH
++#define __INCmvDeviceH
++
++#include "mvCommon.h"
++#include "mvOs.h"
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++#include "device/mvDeviceRegs.h"
++
++
++#endif /* #ifndef __INCmvDeviceH */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDeviceRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDeviceRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDeviceRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDeviceRegs.h 2010-11-09 20:28:10.181250318 +0100
+@@ -0,0 +1,101 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDeviceRegsH
++#define __INCmvDeviceRegsH
++
++#ifndef MV_ASMLANGUAGE
++#include "ctrlEnv/mvCtrlEnvLib.h"
++/* This enumerator describes the Marvell controller possible devices that */
++/* can be connected to its device interface. */
++typedef enum _mvDevice
++{
++#if defined(MV_INCLUDE_DEVICE_CS0)
++ DEV_CS0 = 0, /* Device connected to dev CS[0] */
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS1)
++ DEV_CS1 = 1, /* Device connected to dev CS[1] */
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS2)
++ DEV_CS2 = 2, /* Device connected to dev CS[2] */
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS3)
++ DEV_CS3 = 3, /* Device connected to dev CS[2] */
++#endif
++#if defined(MV_INCLUDE_DEVICE_CS4)
++ DEV_CS4 = 4, /* Device connected to BOOT dev */
++#endif
++ MV_DEV_MAX_CS = MV_DEVICE_MAX_CS
++}MV_DEVICE;
++
++
++#endif /* MV_ASMLANGUAGE */
++
++
++#define NAND_CTRL_REG 0x10470
++
++#define NAND_ACTCEBOOT_BIT BIT1
++
++
++#endif /* #ifndef __INCmvDeviceRegsH */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.c 2010-11-09 20:28:10.222495542 +0100
+@@ -0,0 +1,211 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++*******************************************************************************/
++/*******************************************************************************
++* mvOsCpuArchLib.c - Marvell CPU architecture library
++*
++* DESCRIPTION:
++* This library introduce Marvell API for OS dependent CPU architecture
++* APIs. This library introduce single CPU architecture services APKI
++* cross OS.
++*
++* DEPENDENCIES:
++* None.
++*
++*******************************************************************************/
++
++/* includes */
++#include <asm/processor.h>
++#include "mvOs.h"
++
++static MV_U32 read_p15_c0 (void);
++
++/* defines */
++#define ARM_ID_REVISION_OFFS 0
++#define ARM_ID_REVISION_MASK (0xf << ARM_ID_REVISION_OFFS)
++
++#define ARM_ID_PART_NUM_OFFS 4
++#define ARM_ID_PART_NUM_MASK (0xfff << ARM_ID_PART_NUM_OFFS)
++
++#define ARM_ID_ARCH_OFFS 16
++#define ARM_ID_ARCH_MASK (0xf << ARM_ID_ARCH_OFFS)
++
++#define ARM_ID_VAR_OFFS 20
++#define ARM_ID_VAR_MASK (0xf << ARM_ID_VAR_OFFS)
++
++#define ARM_ID_ASCII_OFFS 24
++#define ARM_ID_ASCII_MASK (0xff << ARM_ID_ASCII_OFFS)
++
++
++
++void* mvOsIoCachedMalloc( void* osHandle, MV_U32 size, MV_ULONG* pPhyAddr,
++ MV_U32 *memHandle)
++{
++ void *p = kmalloc( size, GFP_KERNEL );
++ *pPhyAddr = pci_map_single( osHandle, p, 0, PCI_DMA_BIDIRECTIONAL );
++ return p;
++}
++void* mvOsIoUncachedMalloc( void* osHandle, MV_U32 size, MV_ULONG* pPhyAddr,
++ MV_U32 *memHandle)
++{
++ return pci_alloc_consistent( osHandle, size, (dma_addr_t *)pPhyAddr );
++}
++
++void mvOsIoUncachedFree( void* osHandle, MV_U32 size, MV_ULONG phyAddr, void* pVirtAddr,
++ MV_U32 memHandle)
++{
++ return pci_free_consistent( osHandle, size, pVirtAddr, (dma_addr_t)phyAddr );
++}
++
++void mvOsIoCachedFree( void* osHandle, MV_U32 size, MV_ULONG phyAddr, void* pVirtAddr,
++ MV_U32 memHandle )
++{
++ return kfree( pVirtAddr );
++}
++
++int mvOsRand(void)
++{
++ int rand;
++ get_random_bytes(&rand, sizeof(rand) );
++ return rand;
++}
++
++/*******************************************************************************
++* mvOsCpuVerGet() -
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit CPU Revision
++*
++*******************************************************************************/
++MV_U32 mvOsCpuRevGet( MV_VOID )
++{
++ return ((read_p15_c0() & ARM_ID_REVISION_MASK ) >> ARM_ID_REVISION_OFFS);
++}
++/*******************************************************************************
++* mvOsCpuPartGet() -
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit CPU Part number
++*
++*******************************************************************************/
++MV_U32 mvOsCpuPartGet( MV_VOID )
++{
++ return ((read_p15_c0() & ARM_ID_PART_NUM_MASK ) >> ARM_ID_PART_NUM_OFFS);
++}
++/*******************************************************************************
++* mvOsCpuArchGet() -
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit CPU Architicture number
++*
++*******************************************************************************/
++MV_U32 mvOsCpuArchGet( MV_VOID )
++{
++ return ((read_p15_c0() & ARM_ID_ARCH_MASK ) >> ARM_ID_ARCH_OFFS);
++}
++/*******************************************************************************
++* mvOsCpuVarGet() -
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit CPU Variant number
++*
++*******************************************************************************/
++MV_U32 mvOsCpuVarGet( MV_VOID )
++{
++ return ((read_p15_c0() & ARM_ID_VAR_MASK ) >> ARM_ID_VAR_OFFS);
++}
++/*******************************************************************************
++* mvOsCpuAsciiGet() -
++*
++* DESCRIPTION:
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit CPU Variant number
++*
++*******************************************************************************/
++MV_U32 mvOsCpuAsciiGet( MV_VOID )
++{
++ return ((read_p15_c0() & ARM_ID_ASCII_MASK ) >> ARM_ID_ASCII_OFFS);
++}
++
++
++
++/*
++static unsigned long read_p15_c0 (void)
++*/
++/* read co-processor 15, register #0 (ID register) */
++static MV_U32 read_p15_c0 (void)
++{
++ MV_U32 value;
++
++ __asm__ __volatile__(
++ "mrc p15, 0, %0, c0, c0, 0 @ read control reg\n"
++ : "=r" (value)
++ :
++ : "memory");
++
++ return value;
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.h 2010-11-09 20:28:10.262495482 +0100
+@@ -0,0 +1,423 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++*******************************************************************************/
++#ifndef _MV_OS_LNX_H_
++#define _MV_OS_LNX_H_
++
++
++#ifdef __KERNEL__
++/* for kernel space */
++#include <linux/autoconf.h>
++#include <linux/interrupt.h>
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/reboot.h>
++#include <linux/pci.h>
++#include <linux/kdev_t.h>
++#include <linux/major.h>
++#include <linux/blkdev.h>
++#include <linux/console.h>
++#include <linux/delay.h>
++#include <linux/seq_file.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++
++#include <asm/system.h>
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/hardirq.h>
++#include <asm/dma.h>
++#include <asm/io.h>
++
++#include <linux/random.h>
++
++#include "dbg-trace.h"
++
++extern void mv_early_printk(char *fmt,...);
++
++#define MV_ASM __asm__ __volatile__
++#define INLINE inline
++#define MV_TRC_REC TRC_REC
++#define mvOsPrintf printk
++#define mvOsEarlyPrintf mv_early_printk
++#define mvOsOutput printk
++#define mvOsSPrintf sprintf
++#define mvOsMalloc(_size_) kmalloc(_size_,GFP_ATOMIC)
++#define mvOsFree kfree
++#define mvOsMemcpy memcpy
++#define mvOsSleep(_mils_) mdelay(_mils_)
++#define mvOsTaskLock()
++#define mvOsTaskUnlock()
++#define strtol simple_strtoul
++#define mvOsDelay(x) mdelay(x)
++#define mvOsUDelay(x) udelay(x)
++#define mvCopyFromOs copy_from_user
++#define mvCopyToOs copy_to_user
++
++
++#include "mvTypes.h"
++#include "mvCommon.h"
++
++#ifdef MV_NDEBUG
++#define mvOsAssert(cond)
++#else
++#define mvOsAssert(cond) { do { if(!(cond)) { BUG(); } }while(0); }
++#endif /* MV_NDEBUG */
++
++#else /* __KERNEL__ */
++
++/* for user space applications */
++#include <stdlib.h>
++#include <stdio.h>
++#include <assert.h>
++#include <string.h>
++
++#define INLINE inline
++#define mvOsPrintf printf
++#define mvOsOutput printf
++#define mvOsMalloc(_size_) malloc(_size_)
++#define mvOsFree free
++#define mvOsAssert(cond) assert(cond)
++
++#endif /* __KERNEL__ */
++#define mvOsIoVirtToPhy(pDev, pVirtAddr) \
++ pci_map_single( (pDev), (pVirtAddr), 0, PCI_DMA_BIDIRECTIONAL )
++
++#define mvOsCacheClear(pDev, p, size ) \
++ pci_map_single( (pDev), (p), (size), PCI_DMA_BIDIRECTIONAL)
++
++#define mvOsCacheFlush(pDev, p, size ) \
++ pci_map_single( (pDev), (p), (size), PCI_DMA_TODEVICE)
++
++#define mvOsCacheInvalidate(pDev, p, size) \
++ pci_map_single( (pDev), (p), (size), PCI_DMA_FROMDEVICE )
++
++#define mvOsCacheUnmap(pDev, phys, size) \
++ pci_unmap_single( (pDev), (dma_addr_t)(phys), (size), PCI_DMA_FROMDEVICE )
++
++
++#define CPU_PHY_MEM(x) (MV_U32)x
++#define CPU_MEMIO_CACHED_ADDR(x) (void*)x
++#define CPU_MEMIO_UNCACHED_ADDR(x) (void*)x
++
++
++/* CPU architecture dependent 32, 16, 8 bit read/write IO addresses */
++#define MV_MEMIO32_WRITE(addr, data) \
++ ((*((volatile unsigned int*)(addr))) = ((unsigned int)(data)))
++
++#define MV_MEMIO32_READ(addr) \
++ ((*((volatile unsigned int*)(addr))))
++
++#define MV_MEMIO16_WRITE(addr, data) \
++ ((*((volatile unsigned short*)(addr))) = ((unsigned short)(data)))
++
++#define MV_MEMIO16_READ(addr) \
++ ((*((volatile unsigned short*)(addr))))
++
++#define MV_MEMIO8_WRITE(addr, data) \
++ ((*((volatile unsigned char*)(addr))) = ((unsigned char)(data)))
++
++#define MV_MEMIO8_READ(addr) \
++ ((*((volatile unsigned char*)(addr))))
++
++
++/* No Fast Swap implementation (in assembler) for ARM */
++#define MV_32BIT_LE_FAST(val) MV_32BIT_LE(val)
++#define MV_16BIT_LE_FAST(val) MV_16BIT_LE(val)
++#define MV_32BIT_BE_FAST(val) MV_32BIT_BE(val)
++#define MV_16BIT_BE_FAST(val) MV_16BIT_BE(val)
++
++/* 32 and 16 bit read/write in big/little endian mode */
++
++/* 16bit write in little endian mode */
++#define MV_MEMIO_LE16_WRITE(addr, data) \
++ MV_MEMIO16_WRITE(addr, MV_16BIT_LE_FAST(data))
++
++/* 16bit read in little endian mode */
++static __inline MV_U16 MV_MEMIO_LE16_READ(MV_U32 addr)
++{
++ MV_U16 data;
++
++ data= (MV_U16)MV_MEMIO16_READ(addr);
++
++ return (MV_U16)MV_16BIT_LE_FAST(data);
++}
++
++/* 32bit write in little endian mode */
++#define MV_MEMIO_LE32_WRITE(addr, data) \
++ MV_MEMIO32_WRITE(addr, MV_32BIT_LE_FAST(data))
++
++/* 32bit read in little endian mode */
++static __inline MV_U32 MV_MEMIO_LE32_READ(MV_U32 addr)
++{
++ MV_U32 data;
++
++ data= (MV_U32)MV_MEMIO32_READ(addr);
++
++ return (MV_U32)MV_32BIT_LE_FAST(data);
++}
++
++static __inline void mvOsBCopy(char* srcAddr, char* dstAddr, int byteCount)
++{
++ while(byteCount != 0)
++ {
++ *dstAddr = *srcAddr;
++ dstAddr++;
++ srcAddr++;
++ byteCount--;
++ }
++}
++
++static INLINE MV_U64 mvOsDivMod64(MV_U64 divided, MV_U64 divisor, MV_U64* modulu)
++{
++ MV_U64 division = 0;
++
++ if(divisor == 1)
++ return divided;
++
++ while(divided >= divisor)
++ {
++ division++;
++ divided -= divisor;
++ }
++ if (modulu != NULL)
++ *modulu = divided;
++
++ return division;
++}
++
++#if defined(MV_BRIDGE_SYNC_REORDER)
++extern MV_U32 *mvUncachedParam;
++
++static __inline void mvOsBridgeReorderWA(void)
++{
++ volatile MV_U32 val = 0;
++
++ val = mvUncachedParam[0];
++}
++#endif
++
++
++/* Flash APIs */
++#define MV_FL_8_READ MV_MEMIO8_READ
++#define MV_FL_16_READ MV_MEMIO_LE16_READ
++#define MV_FL_32_READ MV_MEMIO_LE32_READ
++#define MV_FL_8_DATA_READ MV_MEMIO8_READ
++#define MV_FL_16_DATA_READ MV_MEMIO16_READ
++#define MV_FL_32_DATA_READ MV_MEMIO32_READ
++#define MV_FL_8_WRITE MV_MEMIO8_WRITE
++#define MV_FL_16_WRITE MV_MEMIO_LE16_WRITE
++#define MV_FL_32_WRITE MV_MEMIO_LE32_WRITE
++#define MV_FL_8_DATA_WRITE MV_MEMIO8_WRITE
++#define MV_FL_16_DATA_WRITE MV_MEMIO16_WRITE
++#define MV_FL_32_DATA_WRITE MV_MEMIO32_WRITE
++
++
++/* CPU cache information */
++#define CPU_I_CACHE_LINE_SIZE 32 /* 2do: replace 32 with linux core macro */
++#define CPU_D_CACHE_LINE_SIZE 32 /* 2do: replace 32 with linux core macro */
++
++#ifdef CONFIG_L2_CACHE_ENABLE
++/* Data cache flush one line */
++#define mvOsCacheLineFlushInv(handle, addr) \
++{ \
++ __asm__ __volatile__ ("mcr p15, 0, %0, c7, c14, 1" : : "r" (addr));\
++ __asm__ __volatile__ ("mcr p15, 1, %0, c15, c10, 1" : : "r" (addr));\
++ __asm__ __volatile__ ("mcr p15, 0, r0, c7, c10, 4"); \
++}
++
++#else
++
++/* Data cache flush one line */
++#define mvOsCacheLineFlushInv(handle, addr) \
++{ \
++ __asm__ __volatile__ ("mcr p15, 0, %0, c7, c14, 1" : : "r" (addr));\
++ __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" : : "r" (addr)); \
++}
++#endif
++
++#ifdef CONFIG_L2_CACHE_ENABLE
++#define mvOsCacheLineInv(handle,addr) \
++{ \
++ __asm__ __volatile__ ("mcr p15, 0, %0, c7, c6, 1" : : "r" (addr)); \
++ __asm__ __volatile__ ("mcr p15, 1, %0, c15, c11, 1" : : "r" (addr)); \
++}
++#else
++#define mvOsCacheLineInv(handle,addr) \
++{ \
++ __asm__ __volatile__ ("mcr p15, 0, %0, c7, c6, 1" : : "r" (addr)); \
++}
++#endif
++
++#ifdef CONFIG_L2_CACHE_ENABLE
++/* Data cache flush one line */
++#define mvOsCacheLineFlush(handle, addr) \
++{ \
++ __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 1" : : "r" (addr));\
++ __asm__ __volatile__ ("mcr p15, 1, %0, c15, c9, 1" : : "r" (addr));\
++ __asm__ __volatile__ ("mcr p15, 0, r0, c7, c10, 4"); \
++}
++
++#else
++/* Data cache flush one line */
++#define mvOsCacheLineFlush(handle, addr) \
++{ \
++ __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 1" : : "r" (addr));\
++ __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" : : "r" (addr)); \
++}
++#endif
++
++static __inline void mvOsPrefetch(const void *ptr)
++{
++#ifdef CONFIG_USE_DSP
++ __asm__ __volatile__(
++ "pld\t%0"
++ :
++ : "o" (*(char *)ptr)
++ : "cc");
++#else
++ return;
++#endif
++}
++
++
++/* Flush CPU pipe */
++#define CPU_PIPE_FLUSH
++
++
++
++
++
++/* register manipulations */
++
++/******************************************************************************
++* This debug function enable the write of each register that u-boot access to
++* to an array in the DRAM, the function record only MV_REG_WRITE access.
++* The function could not be operate when booting from flash.
++* In order to print the array we use the printreg command.
++******************************************************************************/
++/* #define REG_DEBUG */
++#if defined(REG_DEBUG)
++extern int reg_arry[2048][2];
++extern int reg_arry_index;
++#endif
++
++/* Marvell controller register read/write macros */
++#define MV_REG_VALUE(offset) \
++ (MV_MEMIO32_READ((INTER_REGS_BASE | (offset))))
++
++#define MV_REG_READ(offset) \
++ (MV_MEMIO_LE32_READ(INTER_REGS_BASE | (offset)))
++
++#if defined(REG_DEBUG)
++#define MV_REG_WRITE(offset, val) \
++ MV_MEMIO_LE32_WRITE((INTER_REGS_BASE | (offset)), (val)); \
++ { \
++ reg_arry[reg_arry_index][0] = (INTER_REGS_BASE | (offset));\
++ reg_arry[reg_arry_index][1] = (val);\
++ reg_arry_index++;\
++ }
++#else
++#define MV_REG_WRITE(offset, val) \
++ MV_MEMIO_LE32_WRITE((INTER_REGS_BASE | (offset)), (val));
++#endif
++
++#define MV_REG_BYTE_READ(offset) \
++ (MV_MEMIO8_READ((INTER_REGS_BASE | (offset))))
++
++#if defined(REG_DEBUG)
++#define MV_REG_BYTE_WRITE(offset, val) \
++ MV_MEMIO8_WRITE((INTER_REGS_BASE | (offset)), (val)); \
++ { \
++ reg_arry[reg_arry_index][0] = (INTER_REGS_BASE | (offset));\
++ reg_arry[reg_arry_index][1] = (val);\
++ reg_arry_index++;\
++ }
++#else
++#define MV_REG_BYTE_WRITE(offset, val) \
++ MV_MEMIO8_WRITE((INTER_REGS_BASE | (offset)), (val))
++#endif
++
++#if defined(REG_DEBUG)
++#define MV_REG_BIT_SET(offset, bitMask) \
++ (MV_MEMIO32_WRITE((INTER_REGS_BASE | (offset)), \
++ (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)) | \
++ MV_32BIT_LE_FAST(bitMask)))); \
++ { \
++ reg_arry[reg_arry_index][0] = (INTER_REGS_BASE | (offset));\
++ reg_arry[reg_arry_index][1] = (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)));\
++ reg_arry_index++;\
++ }
++#else
++#define MV_REG_BIT_SET(offset, bitMask) \
++ (MV_MEMIO32_WRITE((INTER_REGS_BASE | (offset)), \
++ (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)) | \
++ MV_32BIT_LE_FAST(bitMask))))
++#endif
++
++#if defined(REG_DEBUG)
++#define MV_REG_BIT_RESET(offset,bitMask) \
++ (MV_MEMIO32_WRITE((INTER_REGS_BASE | (offset)), \
++ (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)) & \
++ MV_32BIT_LE_FAST(~bitMask)))); \
++ { \
++ reg_arry[reg_arry_index][0] = (INTER_REGS_BASE | (offset));\
++ reg_arry[reg_arry_index][1] = (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)));\
++ reg_arry_index++;\
++ }
++#else
++#define MV_REG_BIT_RESET(offset,bitMask) \
++ (MV_MEMIO32_WRITE((INTER_REGS_BASE | (offset)), \
++ (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)) & \
++ MV_32BIT_LE_FAST(~bitMask))))
++#endif
++
++
++
++/* ARM architecture APIs */
++MV_U32 mvOsCpuRevGet (MV_VOID);
++MV_U32 mvOsCpuPartGet (MV_VOID);
++MV_U32 mvOsCpuArchGet (MV_VOID);
++MV_U32 mvOsCpuVarGet (MV_VOID);
++MV_U32 mvOsCpuAsciiGet (MV_VOID);
++
++/* Other APIs */
++void* mvOsIoCachedMalloc( void* osHandle, MV_U32 size, MV_ULONG* pPhyAddr, MV_U32 *memHandle);
++void* mvOsIoUncachedMalloc( void* osHandle, MV_U32 size, MV_ULONG* pPhyAddr, MV_U32 *memHandle );
++void mvOsIoUncachedFree( void* osHandle, MV_U32 size, MV_ULONG phyAddr, void* pVirtAddr, MV_U32 memHandle );
++void mvOsIoCachedFree( void* osHandle, MV_U32 size, MV_ULONG phyAddr, void* pVirtAddr, MV_U32 memHandle );
++int mvOsRand(void);
++
++#endif /* _MV_OS_LNX_H_ */
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/linux_oss/mvOsSata.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/linux_oss/mvOsSata.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/linux_oss/mvOsSata.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/linux_oss/mvOsSata.h 2010-11-09 20:28:10.302495426 +0100
+@@ -0,0 +1,158 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++*******************************************************************************/
++/*******************************************************************************
++* mvOsLinux.h - O.S. interface header file for Linux
++*
++* DESCRIPTION:
++* This header file contains OS dependent definition under Linux
++*
++* DEPENDENCIES:
++* Linux kernel header files.
++*
++* FILE REVISION NUMBER:
++* $Revision: 1.1 $
++*******************************************************************************/
++
++#ifndef __INCmvOsLinuxh
++#define __INCmvOsLinuxh
++
++/* Includes */
++#include <linux/autoconf.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/timer.h>
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/major.h>
++#include <linux/errno.h>
++#include <linux/genhd.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/ide.h>
++#include <linux/pci.h>
++
++#include <asm/byteorder.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include "mvOs.h"
++
++
++/* Definitions */
++#define MV_DEFAULT_QUEUE_DEPTH 2
++#define MV_SATA_SUPPORT_EDMA_SINGLE_DATA_REGION
++#define MV_SATA_SUPPORT_GEN2E_128_QUEUE_LEN
++
++#ifdef CONFIG_MV88F6082
++ #define MV_SATA_OVERRIDE_SW_QUEUE_SIZE
++ #define MV_SATA_REQUESTED_SW_QUEUE_SIZE 2
++ #undef MV_SATA_SUPPORT_GEN2E_128_QUEUE_LEN
++#endif
++
++/* System dependent macro for flushing CPU write cache */
++#if defined (MV_BRIDGE_SYNC_REORDER)
++#define MV_CPU_WRITE_BUFFER_FLUSH() do { \
++ wmb(); \
++ mvOsBridgeReorderWA(); \
++ } while (0)
++#else
++#define MV_CPU_WRITE_BUFFER_FLUSH() wmb()
++#endif /* CONFIG_MV78XX0 */
++
++/* System dependent little endian from / to CPU conversions */
++#define MV_CPU_TO_LE16(x) cpu_to_le16(x)
++#define MV_CPU_TO_LE32(x) cpu_to_le32(x)
++
++#define MV_LE16_TO_CPU(x) le16_to_cpu(x)
++#define MV_LE32_TO_CPU(x) le32_to_cpu(x)
++
++#ifdef __BIG_ENDIAN_BITFIELD
++#define MV_BIG_ENDIAN_BITFIELD
++#endif
++
++/* System dependent register read / write in byte/word/dword variants */
++#define MV_REG_WRITE_BYTE(base, offset, val) writeb(val, base + offset)
++#define MV_REG_WRITE_WORD(base, offset, val) writew(val, base + offset)
++#define MV_REG_WRITE_DWORD(base, offset, val) writel(val, base + offset)
++#define MV_REG_READ_BYTE(base, offset) readb(base + offset)
++#define MV_REG_READ_WORD(base, offset) readw(base + offset)
++#define MV_REG_READ_DWORD(base, offset) readl(base + offset)
++
++
++/* Typedefs */
++
++/* System dependant typedefs */
++typedef void *MV_VOID_PTR;
++typedef u32 *MV_U32_PTR;
++typedef u16 *MV_U16_PTR;
++typedef u8 *MV_U8_PTR;
++typedef char *MV_CHAR_PTR;
++typedef void *MV_BUS_ADDR_T;
++typedef unsigned long MV_CPU_FLAGS;
++
++
++/* Structures */
++/* System dependent structure */
++typedef struct mvOsSemaphore
++{
++ int notUsed;
++} MV_OS_SEMAPHORE;
++
++
++/* Functions (User implemented)*/
++
++/* Semaphore init, take and release */
++#define mvOsSemInit(x) MV_TRUE
++#define mvOsSemTake(x)
++#define mvOsSemRelease(x)
++
++/* Interrupt masking and unmasking functions */
++MV_CPU_FLAGS mvOsSaveFlagsAndMaskCPUInterrupts(MV_VOID);
++MV_VOID mvOsRestoreFlags(MV_CPU_FLAGS);
++
++/* Delay function in micro seconds resolution */
++void mvMicroSecondsDelay(MV_VOID_PTR, MV_U32);
++
++/* Typedefs */
++typedef enum mvBoolean
++{
++ MV_SFALSE, MV_STRUE
++} MV_BOOLEAN;
++
++/* System logging function */
++#include "mvLog.h"
++/* Enable READ/WRITE Long SCSI command only when driver is compiled for debugging */
++#ifdef MV_LOGGER
++#define MV_SATA_SUPPORT_READ_WRITE_LONG
++#endif
++
++#define MV_IAL_LOG_ID 3
++
++#endif /* __INCmvOsLinuxh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.c 2010-11-09 20:28:10.342495568 +0100
+@@ -0,0 +1,376 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvCntmr.h"
++#include "cpu/mvCpu.h"
++
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++extern unsigned int whoAmI(void);
++
++/*******************************************************************************
++* mvCntmrLoad -
++*
++* DESCRIPTION:
++* Load an init Value to a given counter/timer
++*
++* INPUT:
++* countNum - counter number
++* value - value to be loaded
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM on bad parameters , MV_ERROR on error ,MV_OK on sucess
++*******************************************************************************/
++MV_STATUS mvCntmrLoad(MV_U32 countNum, MV_U32 value)
++{
++ if (countNum >= MV_CNTMR_MAX_COUNTER )
++ {
++
++ mvOsPrintf(("mvCntmrLoad: Err. Illigal counter number \n"));
++ return MV_BAD_PARAM;;
++
++ }
++
++ MV_REG_WRITE(CNTMR_RELOAD_REG(countNum),value);
++ MV_REG_WRITE(CNTMR_VAL_REG(countNum),value);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCntmrRead -
++*
++* DESCRIPTION:
++* Returns the value of the given Counter/Timer
++*
++* INPUT:
++* countNum - counter number
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_U32 counter value
++*******************************************************************************/
++MV_U32 mvCntmrRead(MV_U32 countNum)
++{
++ return MV_REG_READ(CNTMR_VAL_REG(countNum));
++}
++
++/*******************************************************************************
++* mvCntmrWrite -
++*
++* DESCRIPTION:
++* Returns the value of the given Counter/Timer
++*
++* INPUT:
++* countNum - counter number
++* countVal - value to write
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None
++*******************************************************************************/
++void mvCntmrWrite(MV_U32 countNum,MV_U32 countVal)
++{
++ MV_REG_WRITE(CNTMR_VAL_REG(countNum),countVal);
++}
++
++/*******************************************************************************
++* mvCntmrCtrlSet -
++*
++* DESCRIPTION:
++* Set the Control to a given counter/timer
++*
++* INPUT:
++* countNum - counter number
++* pCtrl - pointer to MV_CNTMR_CTRL structure
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM on bad parameters , MV_ERROR on error ,MV_OK on sucess
++*******************************************************************************/
++MV_STATUS mvCntmrCtrlSet(MV_U32 countNum, MV_CNTMR_CTRL *pCtrl)
++{
++ MV_U32 cntmrCtrl;
++
++ if (countNum >= MV_CNTMR_MAX_COUNTER )
++ {
++
++ DB(mvOsPrintf(("mvCntmrCtrlSet: Err. Illigal counter number \n")));
++ return MV_BAD_PARAM;;
++
++ }
++
++ /* read control register */
++ cntmrCtrl = MV_REG_READ(CNTMR_CTRL_REG);
++
++
++ if (pCtrl->enable) /* enable counter\timer */
++ {
++ cntmrCtrl |= CTCR_ARM_TIMER_EN(countNum);
++ }
++ else /* disable counter\timer */
++ {
++ cntmrCtrl &= ~CTCR_ARM_TIMER_EN(countNum);
++ }
++
++ if ( pCtrl->autoEnable ) /* Auto mode */
++ {
++ cntmrCtrl |= CTCR_ARM_TIMER_AUTO_EN(countNum);
++
++ }
++ else /* no auto mode */
++ {
++ cntmrCtrl &= ~CTCR_ARM_TIMER_AUTO_EN(countNum);
++ }
++
++ MV_REG_WRITE(CNTMR_CTRL_REG,cntmrCtrl);
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvCntmrCtrlGet -
++*
++* DESCRIPTION:
++* Get the Control value of a given counter/timer
++*
++* INPUT:
++* countNum - counter number
++* pCtrl - pointer to MV_CNTMR_CTRL structure
++*
++* OUTPUT:
++* Counter\Timer control value
++*
++* RETURN:
++* MV_BAD_PARAM on bad parameters , MV_ERROR on error ,MV_OK on sucess
++*******************************************************************************/
++MV_STATUS mvCntmrCtrlGet(MV_U32 countNum, MV_CNTMR_CTRL *pCtrl)
++{
++ MV_U32 cntmrCtrl;
++
++ if (countNum >= MV_CNTMR_MAX_COUNTER )
++ {
++ DB(mvOsPrintf(("mvCntmrCtrlGet: Err. Illigal counter number \n")));
++ return MV_BAD_PARAM;;
++ }
++
++ /* read control register */
++ cntmrCtrl = MV_REG_READ(CNTMR_CTRL_REG);
++
++ /* enable counter\timer */
++ if (cntmrCtrl & CTCR_ARM_TIMER_EN(countNum))
++ {
++ pCtrl->enable = MV_TRUE;
++ }
++ else
++ {
++ pCtrl->enable = MV_FALSE;
++ }
++
++ /* counter mode */
++ if (cntmrCtrl & CTCR_ARM_TIMER_AUTO_EN(countNum))
++ {
++ pCtrl->autoEnable = MV_TRUE;
++ }
++ else
++ {
++ pCtrl->autoEnable = MV_FALSE;
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCntmrEnable -
++*
++* DESCRIPTION:
++* Set the Enable-Bit to logic '1' ==> starting the counter
++*
++* INPUT:
++* countNum - counter number
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM on bad parameters , MV_ERROR on error ,MV_OK on sucess
++*******************************************************************************/
++MV_STATUS mvCntmrEnable(MV_U32 countNum)
++{
++ MV_U32 cntmrCtrl;
++
++ if (countNum >= MV_CNTMR_MAX_COUNTER )
++ {
++
++ DB(mvOsPrintf(("mvCntmrEnable: Err. Illigal counter number \n")));
++ return MV_BAD_PARAM;;
++
++ }
++
++ /* read control register */
++ cntmrCtrl = MV_REG_READ(CNTMR_CTRL_REG);
++
++ /* enable counter\timer */
++ cntmrCtrl |= CTCR_ARM_TIMER_EN(countNum);
++
++
++ MV_REG_WRITE(CNTMR_CTRL_REG,cntmrCtrl);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCntmrDisable -
++*
++* DESCRIPTION:
++* Stop the counter/timer running, and returns its Value
++*
++* INPUT:
++* countNum - counter number
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_U32 counter\timer value
++*******************************************************************************/
++MV_STATUS mvCntmrDisable(MV_U32 countNum)
++{
++ MV_U32 cntmrCtrl;
++
++ if (countNum >= MV_CNTMR_MAX_COUNTER )
++ {
++
++ DB(mvOsPrintf(("mvCntmrDisable: Err. Illigal counter number \n")));
++ return MV_BAD_PARAM;;
++
++ }
++
++ /* read control register */
++ cntmrCtrl = MV_REG_READ(CNTMR_CTRL_REG);
++
++ /* disable counter\timer */
++ cntmrCtrl &= ~CTCR_ARM_TIMER_EN(countNum);
++
++ MV_REG_WRITE(CNTMR_CTRL_REG,cntmrCtrl);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvCntmrStart -
++*
++* DESCRIPTION:
++* Combined all the sub-operations above to one function: Load,setMode,Enable
++*
++* INPUT:
++* countNum - counter number
++* value - value of the counter\timer to be set
++* pCtrl - pointer to MV_CNTMR_CTRL structure
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM on bad parameters , MV_ERROR on error ,MV_OK on sucess
++*******************************************************************************/
++MV_STATUS mvCntmrStart(MV_U32 countNum, MV_U32 value,
++ MV_CNTMR_CTRL *pCtrl)
++{
++
++ if (countNum >= MV_CNTMR_MAX_COUNTER )
++ {
++
++ mvOsPrintf(("mvCntmrDisable: Err. Illigal counter number \n"));
++ return MV_BAD_PARAM;;
++
++ }
++
++ /* load value onto counter\timer */
++ mvCntmrLoad(countNum,value);
++
++ /* set the counter to load in the first time */
++ mvCntmrWrite(countNum,value);
++
++ /* set control for timer \ cunter and enable */
++ mvCntmrCtrlSet(countNum,pCtrl);
++
++ return MV_OK;
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.h 2010-11-09 20:28:10.381238003 +0100
+@@ -0,0 +1,121 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvTmrWtdgh
++#define __INCmvTmrWtdgh
++
++/* includes */
++#include "mvCommon.h"
++#include "mvOs.h"
++#include "cntmr/mvCntmrRegs.h"
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++
++
++/* This enumerator describe counters\watchdog numbers */
++typedef enum _mvCntmrID
++{
++ TIMER0 = 0,
++ TIMER1,
++ WATCHDOG,
++ TIMER2,
++ TIMER3,
++}MV_CNTMR_ID;
++
++
++/* Counter / Timer control structure */
++typedef struct _mvCntmrCtrl
++{
++ MV_BOOL enable; /* enable */
++ MV_BOOL autoEnable; /* counter/Timer */
++}MV_CNTMR_CTRL;
++
++
++/* Functions */
++
++/* Load an init Value to a given counter/timer */
++MV_STATUS mvCntmrLoad(MV_U32 countNum, MV_U32 value);
++
++/* Returns the value of the given Counter/Timer */
++MV_U32 mvCntmrRead(MV_U32 countNum);
++
++/* Write a value of the given Counter/Timer */
++void mvCntmrWrite(MV_U32 countNum,MV_U32 countVal);
++
++/* Set the Control to a given counter/timer */
++MV_STATUS mvCntmrCtrlSet(MV_U32 countNum, MV_CNTMR_CTRL *pCtrl);
++
++/* Get the value of a given counter/timer */
++MV_STATUS mvCntmrCtrlGet(MV_U32 countNum, MV_CNTMR_CTRL *pCtrl);
++
++/* Set the Enable-Bit to logic '1' ==> starting the counter. */
++MV_STATUS mvCntmrEnable(MV_U32 countNum);
++
++/* Stop the counter/timer running, and returns its Value. */
++MV_STATUS mvCntmrDisable(MV_U32 countNum);
++
++/* Combined all the sub-operations above to one function: Load,setMode,Enable */
++MV_STATUS mvCntmrStart(MV_U32 countNum, MV_U32 value,
++ MV_CNTMR_CTRL *pCtrl);
++
++#endif /* __INCmvTmrWtdgh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmrRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmrRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmrRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmrRegs.h 2010-11-09 20:28:10.422495568 +0100
+@@ -0,0 +1,121 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvTmrwtdgRegsh
++#define __INCmvTmrwtdgRegsh
++
++/*******************************************/
++/* ARM Timers Registers Map */
++/*******************************************/
++
++#define CNTMR_RELOAD_REG(tmrNum) (CNTMR_BASE + 0x10 + (tmrNum)*8 + \
++ (((tmrNum) <= 3)?0:8))
++#define CNTMR_VAL_REG(tmrNum) (CNTMR_BASE + 0x14 + (tmrNum)*8 + \
++ (((tmrNum) <= 3)?0:8))
++#define CNTMR_CTRL_REG (CNTMR_BASE)
++
++/*For MV78XX0*/
++#define CNTMR_CAUSE_REG (CPU_AHB_MBUS_CAUSE_INT_REG(whoAmI()))
++#define CNTMR_MASK_REG (CPU_AHB_MBUS_MASK_INT_REG(whoAmI()))
++
++/* ARM Timers Registers Map */
++/*******************************************/
++
++
++/* ARM Timers Control Register */
++/* CPU_TIMERS_CTRL_REG (CTCR) */
++
++#define TIMER0_NUM 0
++#define TIMER1_NUM 1
++#define WATCHDOG_NUM 2
++#define TIMER2_NUM 3
++#define TIMER3_NUM 4
++
++#define CTCR_ARM_TIMER_EN_OFFS(cntr) (cntr * 2)
++#define CTCR_ARM_TIMER_EN_MASK(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS)
++#define CTCR_ARM_TIMER_EN(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS(cntr))
++#define CTCR_ARM_TIMER_DIS(cntr) (0 << CTCR_ARM_TIMER_EN_OFFS(cntr))
++
++#define CTCR_ARM_TIMER_AUTO_OFFS(cntr) ((cntr * 2) + 1)
++#define CTCR_ARM_TIMER_AUTO_MASK(cntr) BIT1
++#define CTCR_ARM_TIMER_AUTO_EN(cntr) (1 << CTCR_ARM_TIMER_AUTO_OFFS(cntr))
++#define CTCR_ARM_TIMER_AUTO_DIS(cntr) (0 << CTCR_ARM_TIMER_AUTO_OFFS(cntr))
++
++
++/* ARM Timer\Watchdog Reload Register */
++/* CNTMR_RELOAD_REG (TRR) */
++
++#define TRG_ARM_TIMER_REL_OFFS 0
++#define TRG_ARM_TIMER_REL_MASK 0xffffffff
++
++/* ARM Timer\Watchdog Register */
++/* CNTMR_VAL_REG (TVRG) */
++
++#define TVR_ARM_TIMER_OFFS 0
++#define TVR_ARM_TIMER_MASK 0xffffffff
++#define TVR_ARM_TIMER_MAX 0xffffffff
++
++
++
++#endif /* __INCmvTmrwtdgRegsh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.c 2010-11-09 20:28:10.462495409 +0100
+@@ -0,0 +1,207 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include "mvOs.h"
++#include "mvCpuCntrs.h"
++
++
++const static MV_CPU_CNTRS_OPS mvCpuCntrsOpsTbl[MV_CPU_CNTRS_NUM][MV_CPU_CNTRS_OPS_NUM] =
++{
++ /*0*/
++ {
++ MV_CPU_CNTRS_CYCLES, MV_CPU_CNTRS_DCACHE_READ_HIT, MV_CPU_CNTRS_DCACHE_READ_MISS,
++ MV_CPU_CNTRS_DCACHE_WRITE_HIT, MV_CPU_CNTRS_DCACHE_WRITE_MISS, MV_CPU_CNTRS_INSTRUCTIONS,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID,
++ MV_CPU_CNTRS_MMU_READ_LATENCY, MV_CPU_CNTRS_ICACHE_READ_LATENCY, MV_CPU_CNTRS_WB_WRITE_LATENCY,
++ MV_CPU_CNTRS_LDM_STM_HOLD, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID,
++ MV_CPU_CNTRS_DATA_WRITE_ACCESS, MV_CPU_CNTRS_DATA_READ_ACCESS, MV_CPU_CNTRS_INVALID,
++ MV_CPU_CNTRS_BRANCH_PREDICT_COUNT,
++ },
++ /*1*/
++ {
++ MV_CPU_CNTRS_CYCLES, MV_CPU_CNTRS_ICACHE_READ_MISS, MV_CPU_CNTRS_DCACHE_READ_MISS,
++ MV_CPU_CNTRS_DCACHE_WRITE_MISS, MV_CPU_CNTRS_ITLB_MISS, MV_CPU_CNTRS_SINGLE_ISSUE,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_BRANCH_RETIRED, MV_CPU_CNTRS_INVALID,
++ MV_CPU_CNTRS_MMU_READ_BEAT, MV_CPU_CNTRS_ICACHE_READ_LATENCY, MV_CPU_CNTRS_WB_WRITE_BEAT,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_IS_HOLD, MV_CPU_CNTRS_DATA_READ_ACCESS,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID,
++ MV_CPU_CNTRS_INVALID,
++ },
++ /*2*/
++ {
++ MV_CPU_CNTRS_CYCLES, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_DCACHE_ACCESS,
++ MV_CPU_CNTRS_DTLB_MISS, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_BRANCH_PREDICT_MISS, MV_CPU_CNTRS_WB_WRITE_BEAT,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_DCACHE_READ_LATENCY, MV_CPU_CNTRS_DCACHE_WRITE_LATENCY,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_BIU_SIMULT_ACCESS,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID,
++ MV_CPU_CNTRS_INVALID,
++ },
++ /*3*/
++ {
++ MV_CPU_CNTRS_CYCLES, MV_CPU_CNTRS_DCACHE_READ_MISS, MV_CPU_CNTRS_DCACHE_WRITE_MISS,
++ MV_CPU_CNTRS_TLB_MISS, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_BRANCH_TAKEN, MV_CPU_CNTRS_WB_FULL_CYCLES,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_DCACHE_READ_BEAT, MV_CPU_CNTRS_DCACHE_WRITE_BEAT,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_BIU_ANY_ACCESS,
++ MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_DATA_WRITE_ACCESS,
++ MV_CPU_CNTRS_INVALID,
++ }
++};
++
++MV_CPU_CNTRS_ENTRY mvCpuCntrsTbl[MV_CPU_CNTRS_NUM];
++
++MV_CPU_CNTRS_EVENT* mvCpuCntrsEventTbl[128];
++
++void mvCpuCntrsReset(void)
++{
++ MV_U32 reg = 0;
++
++ MV_ASM ("mcr p15, 0, %0, c15, c13, 0" : : "r" (reg));
++ MV_ASM ("mcr p15, 0, %0, c15, c13, 1" : : "r" (reg));
++ MV_ASM ("mcr p15, 0, %0, c15, c13, 2" : : "r" (reg));
++ MV_ASM ("mcr p15, 0, %0, c15, c13, 3" : : "r" (reg));
++ MV_ASM ("mcr p15, 0, %0, c15, c13, 4" : : "r" (reg));
++ MV_ASM ("mcr p15, 0, %0, c15, c13, 5" : : "r" (reg));
++ MV_ASM ("mcr p15, 0, %0, c15, c13, 6" : : "r" (reg));
++ MV_ASM ("mcr p15, 0, %0, c15, c13, 7" : : "r" (reg));
++}
++
++void program_counter(int counter, int op)
++{
++ MV_U32 reg = (1 << op) | 0x1; /*enable*/
++
++ switch(counter)
++ {
++ case 0:
++ __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 0" : : "r" (reg));
++ return;
++
++ case 1:
++ __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 1" : : "r" (reg));
++ return;
++
++ case 2:
++ __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 2" : : "r" (reg));
++ return;
++
++ case 3:
++ __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 3" : : "r" (reg));
++ return;
++
++ default:
++ mvOsPrintf("error in program_counter: bad counter number (%d)\n", counter);
++ }
++ return;
++}
++
++void mvCpuCntrsEventClear(MV_CPU_CNTRS_EVENT* pEvent)
++{
++ int i;
++
++ for(i=0; i<MV_CPU_CNTRS_NUM; i++)
++ {
++ pEvent->counters_sum[i] = 0;
++ }
++ pEvent->num_of_measurements = 0;
++}
++
++
++MV_CPU_CNTRS_EVENT* mvCpuCntrsEventCreate(char* name, MV_U32 print_threshold)
++{
++ int i;
++ MV_CPU_CNTRS_EVENT* event = mvOsMalloc(sizeof(MV_CPU_CNTRS_EVENT));
++
++ if(event)
++ {
++ strncpy(event->name, name, sizeof(event->name));
++ event->num_of_measurements = 0;
++ event->avg_sample_count = print_threshold;
++ for(i=0; i<MV_CPU_CNTRS_NUM; i++)
++ {
++ event->counters_before[i] = 0;
++ event->counters_after[i] = 0;
++ event->counters_sum[i] = 0;
++ }
++ }
++ return event;
++}
++
++void mvCpuCntrsEventDelete(MV_CPU_CNTRS_EVENT* event)
++{
++ if(event != NULL)
++ mvOsFree(event);
++}
++
++
++MV_STATUS mvCpuCntrsProgram(int counter, MV_CPU_CNTRS_OPS op,
++ char* name, MV_U32 overhead)
++{
++ int i;
++
++ /* Find required operations */
++ for(i=0; i<MV_CPU_CNTRS_OPS_NUM; i++)
++ {
++ if( mvCpuCntrsOpsTbl[counter][i] == op)
++ {
++ strncpy(mvCpuCntrsTbl[counter].name, name, sizeof(mvCpuCntrsTbl[counter].name));
++ mvCpuCntrsTbl[counter].operation = op;
++ mvCpuCntrsTbl[counter].opIdx = i+1;
++ mvCpuCntrsTbl[counter].overhead = overhead;
++ program_counter(counter, mvCpuCntrsTbl[counter].opIdx);
++ mvOsPrintf("Counter=%d, opIdx=%d, overhead=%d\n",
++ counter, mvCpuCntrsTbl[counter].opIdx, mvCpuCntrsTbl[counter].overhead);
++ return MV_OK;
++ }
++ }
++ return MV_NOT_FOUND;
++}
++
++void mvCpuCntrsShow(MV_CPU_CNTRS_EVENT* pEvent)
++{
++ int i;
++ MV_U64 counters_avg;
++
++ if(pEvent->num_of_measurements < pEvent->avg_sample_count)
++ return;
++
++ mvOsPrintf("%16s: ", pEvent->name);
++ for(i=0; i<MV_CPU_CNTRS_NUM; i++)
++ {
++ counters_avg = mvOsDivMod64(pEvent->counters_sum[i],
++ pEvent->num_of_measurements, NULL);
++ if(counters_avg >= mvCpuCntrsTbl[i].overhead)
++ counters_avg -= mvCpuCntrsTbl[i].overhead;
++ else
++ counters_avg = 0;
++
++ mvOsPrintf("%s=%5llu, ", mvCpuCntrsTbl[i].name, counters_avg);
++ }
++ mvOsPrintf("\n");
++ mvCpuCntrsEventClear(pEvent);
++ mvCpuCntrsReset();
++}
++
++void mvCpuCntrsStatus(void)
++{
++ int i;
++
++ for(i=0; i<MV_CPU_CNTRS_NUM; i++)
++ {
++ mvOsPrintf("#%d: %s, overhead=%d\n",
++ i, mvCpuCntrsTbl[i].name, mvCpuCntrsTbl[i].overhead);
++ }
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.h 2010-11-09 20:28:10.492495484 +0100
+@@ -0,0 +1,213 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++*******************************************************************************/
++#ifndef __mvCpuCntrs_h__
++#define __mvCpuCntrs_h__
++
++#include "mvTypes.h"
++#include "mvOs.h"
++
++
++#define MV_CPU_CNTRS_NUM 4
++#define MV_CPU_CNTRS_OPS_NUM 32
++
++typedef enum
++{
++ MV_CPU_CNTRS_INVALID = 0,
++ MV_CPU_CNTRS_CYCLES,
++ MV_CPU_CNTRS_ICACHE_READ_MISS,
++ MV_CPU_CNTRS_DCACHE_ACCESS,
++ MV_CPU_CNTRS_DCACHE_READ_MISS,
++ MV_CPU_CNTRS_DCACHE_READ_HIT,
++ MV_CPU_CNTRS_DCACHE_WRITE_MISS,
++ MV_CPU_CNTRS_DCACHE_WRITE_HIT,
++ MV_CPU_CNTRS_DTLB_MISS,
++ MV_CPU_CNTRS_TLB_MISS,
++ MV_CPU_CNTRS_ITLB_MISS,
++ MV_CPU_CNTRS_INSTRUCTIONS,
++ MV_CPU_CNTRS_SINGLE_ISSUE,
++ MV_CPU_CNTRS_MMU_READ_LATENCY,
++ MV_CPU_CNTRS_MMU_READ_BEAT,
++ MV_CPU_CNTRS_BRANCH_RETIRED,
++ MV_CPU_CNTRS_BRANCH_TAKEN,
++ MV_CPU_CNTRS_BRANCH_PREDICT_MISS,
++ MV_CPU_CNTRS_BRANCH_PREDICT_COUNT,
++ MV_CPU_CNTRS_WB_FULL_CYCLES,
++ MV_CPU_CNTRS_WB_WRITE_LATENCY,
++ MV_CPU_CNTRS_WB_WRITE_BEAT,
++ MV_CPU_CNTRS_ICACHE_READ_LATENCY,
++ MV_CPU_CNTRS_ICACHE_READ_BEAT,
++ MV_CPU_CNTRS_DCACHE_READ_LATENCY,
++ MV_CPU_CNTRS_DCACHE_READ_BEAT,
++ MV_CPU_CNTRS_DCACHE_WRITE_LATENCY,
++ MV_CPU_CNTRS_DCACHE_WRITE_BEAT,
++ MV_CPU_CNTRS_LDM_STM_HOLD,
++ MV_CPU_CNTRS_IS_HOLD,
++ MV_CPU_CNTRS_DATA_WRITE_ACCESS,
++ MV_CPU_CNTRS_DATA_READ_ACCESS,
++ MV_CPU_CNTRS_BIU_SIMULT_ACCESS,
++ MV_CPU_CNTRS_BIU_ANY_ACCESS,
++
++} MV_CPU_CNTRS_OPS;
++
++typedef struct
++{
++ char name[16];
++ MV_CPU_CNTRS_OPS operation;
++ int opIdx;
++ MV_U32 overhead;
++
++} MV_CPU_CNTRS_ENTRY;
++
++
++typedef struct
++{
++ char name[16];
++ MV_U32 num_of_measurements;
++ MV_U32 avg_sample_count;
++ MV_U64 counters_before[MV_CPU_CNTRS_NUM];
++ MV_U64 counters_after[MV_CPU_CNTRS_NUM];
++ MV_U64 counters_sum[MV_CPU_CNTRS_NUM];
++
++} MV_CPU_CNTRS_EVENT;
++
++extern MV_CPU_CNTRS_ENTRY mvCpuCntrsTbl[MV_CPU_CNTRS_NUM];
++
++
++MV_STATUS mvCpuCntrsProgram(int counter, MV_CPU_CNTRS_OPS op,
++ char* name, MV_U32 overhead);
++void mvCpuCntrsInit(void);
++MV_CPU_CNTRS_EVENT* mvCpuCntrsEventCreate(char* name, MV_U32 print_threshold);
++void mvCpuCntrsEventDelete(MV_CPU_CNTRS_EVENT* event);
++void mvCpuCntrsReset(void);
++void mvCpuCntrsShow(MV_CPU_CNTRS_EVENT* pEvent);
++void mvCpuCntrsEventClear(MV_CPU_CNTRS_EVENT* pEvent);
++
++/* internal */
++void program_counter(int counter, int op);
++
++static INLINE MV_U64 mvCpuCntrsRead(const int counter)
++{
++ MV_U32 low = 0, high = 0;
++ MV_U32 ll = 0;
++
++ switch(counter)
++ {
++ case 0:
++ MV_ASM ("mcr p15, 0, %0, c15, c12, 0" : : "r" (ll));
++ MV_ASM ("mrc p15, 0, %0, c15, c13, 0" : "=r" (low));
++ MV_ASM ("mrc p15, 0, %0, c15, c13, 1" : "=r" (high));
++ break;
++
++ case 1:
++ MV_ASM ("mcr p15, 0, %0, c15, c12, 1" : : "r" (ll));
++ MV_ASM ("mrc p15, 0, %0, c15, c13, 2" : "=r" (low));
++ MV_ASM ("mrc p15, 0, %0, c15, c13, 3" : "=r" (high));
++ break;
++
++ case 2:
++ MV_ASM ("mcr p15, 0, %0, c15, c12, 2" : : "r" (ll));
++ MV_ASM ("mrc p15, 0, %0, c15, c13, 4" : "=r" (low));
++ MV_ASM ("mrc p15, 0, %0, c15, c13, 5" : "=r" (high));
++ break;
++
++ case 3:
++ MV_ASM ("mcr p15, 0, %0, c15, c12, 3" : : "r" (ll));
++ MV_ASM ("mrc p15, 0, %0, c15, c13, 6" : "=r" (low));
++ MV_ASM ("mrc p15, 0, %0, c15, c13, 7" : "=r" (high));
++ break;
++
++ default:
++ mvOsPrintf("mv_cpu_cntrs_read: bad counter number (%d)\n", counter);
++ }
++ program_counter(counter, mvCpuCntrsTbl[counter].opIdx);
++ return (((MV_U64)high << 32 ) | low);
++
++}
++
++
++static INLINE void mvCpuCntrsReadBefore(MV_CPU_CNTRS_EVENT* pEvent)
++{
++#if 0
++ int i;
++
++ /* order is important - we want to measure the cycle count last here! */
++ for(i=0; i<MV_CPU_CNTRS_NUM; i++)
++ pEvent->counters_before[i] = mvCpuCntrsRead(i);
++#else
++ pEvent->counters_before[1] = mvCpuCntrsRead(1);
++ pEvent->counters_before[3] = mvCpuCntrsRead(3);
++ pEvent->counters_before[0] = mvCpuCntrsRead(0);
++ pEvent->counters_before[2] = mvCpuCntrsRead(2);
++#endif
++}
++
++static INLINE void mvCpuCntrsReadAfter(MV_CPU_CNTRS_EVENT* pEvent)
++{
++ int i;
++
++#if 0
++ /* order is important - we want to measure the cycle count first here! */
++ for(i=0; i<MV_CPU_CNTRS_NUM; i++)
++ pEvent->counters_after[i] = mvCpuCntrsRead(i);
++#else
++ pEvent->counters_after[2] = mvCpuCntrsRead(2);
++ pEvent->counters_after[0] = mvCpuCntrsRead(0);
++ pEvent->counters_after[3] = mvCpuCntrsRead(3);
++ pEvent->counters_after[1] = mvCpuCntrsRead(1);
++#endif
++
++ for(i=0; i<MV_CPU_CNTRS_NUM; i++)
++ {
++ pEvent->counters_sum[i] += (pEvent->counters_after[i] - pEvent->counters_before[i]);
++ }
++ pEvent->num_of_measurements++;
++}
++
++
++#ifdef CONFIG_MV_CPU_PERF_CNTRS
++
++#define MV_CPU_CNTRS_READ(counter) mvCpuCntrsRead(counter)
++
++#define MV_CPU_CNTRS_START(event) mvCpuCntrsReadBefore(event)
++
++#define MV_CPU_CNTRS_STOP(event) mvCpuCntrsReadAfter(event)
++
++#define MV_CPU_CNTRS_SHOW(event) mvCpuCntrsShow(event)
++
++#else
++
++#define MV_CPU_CNTRS_READ(counter)
++#define MV_CPU_CNTRS_START(event)
++#define MV_CPU_CNTRS_STOP(event)
++#define MV_CPU_CNTRS_SHOW(event)
++
++#endif /* CONFIG_MV_CPU_PERF_CNTRS */
++
++
++#endif /* __mvCpuCntrs_h__ */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.c 2010-11-09 20:28:10.522495411 +0100
+@@ -0,0 +1,143 @@
++/*
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include "mvOs.h"
++#include "mvCpuL2Cntrs.h"
++
++
++
++MV_CPU_L2_CNTRS_ENTRY mvCpuL2CntrsTbl[MV_CPU_L2_CNTRS_NUM];
++
++MV_CPU_L2_CNTRS_EVENT* mvCpuL2CntrsEventTbl[128];
++
++void mvCpuL2CntrsReset(void)
++{
++ MV_U32 reg = 0;
++
++ MV_ASM ("mcr p15, 6, %0, c15, c13, 0" : : "r" (reg));
++ MV_ASM ("mcr p15, 6, %0, c15, c13, 1" : : "r" (reg));
++ MV_ASM ("mcr p15, 6, %0, c15, c13, 2" : : "r" (reg));
++ MV_ASM ("mcr p15, 6, %0, c15, c13, 3" : : "r" (reg));
++}
++
++static void mvCpuL2CntrConfig(int counter, int op)
++{
++ MV_U32 reg = (1 << op) | 0x1; /*enable*/
++
++ switch(counter)
++ {
++ case 0:
++ MV_ASM ("mcr p15, 6, %0, c15, c12, 0" : : "r" (reg));
++ return;
++
++ case 1:
++ MV_ASM ("mcr p15, 6, %0, c15, c12, 1" : : "r" (reg));
++ return;
++
++ default:
++ mvOsPrintf("mvCpuL2CntrConfig: bad counter number (%d)\n", counter);
++ }
++ return;
++}
++
++void mvCpuL2CntrsEventClear(MV_CPU_L2_CNTRS_EVENT* pEvent)
++{
++ int i;
++
++ for(i=0; i<MV_CPU_L2_CNTRS_NUM; i++)
++ {
++ pEvent->counters_sum[i] = 0;
++ }
++ pEvent->num_of_measurements = 0;
++}
++
++
++MV_CPU_L2_CNTRS_EVENT* mvCpuL2CntrsEventCreate(char* name, MV_U32 print_threshold)
++{
++ int i;
++ MV_CPU_L2_CNTRS_EVENT* event = mvOsMalloc(sizeof(MV_CPU_L2_CNTRS_EVENT));
++
++ if(event)
++ {
++ strncpy(event->name, name, sizeof(event->name));
++ event->num_of_measurements = 0;
++ event->avg_sample_count = print_threshold;
++ for(i=0; i<MV_CPU_L2_CNTRS_NUM; i++)
++ {
++ event->counters_before[i] = 0;
++ event->counters_after[i] = 0;
++ event->counters_sum[i] = 0;
++ }
++ }
++ return event;
++}
++
++void mvCpuL2CntrsEventDelete(MV_CPU_L2_CNTRS_EVENT* event)
++{
++ if(event != NULL)
++ mvOsFree(event);
++}
++
++
++MV_STATUS mvCpuL2CntrsProgram(int counter, MV_CPU_L2_CNTRS_OPS op,
++ char* name, MV_U32 overhead)
++{
++ strncpy(mvCpuL2CntrsTbl[counter].name, name, sizeof(mvCpuL2CntrsTbl[counter].name));
++ mvCpuL2CntrsTbl[counter].operation = op;
++ mvCpuL2CntrsTbl[counter].opIdx = op;
++ mvCpuL2CntrsTbl[counter].overhead = overhead;
++ mvCpuL2CntrConfig(counter, op);
++ mvOsPrintf("CPU L2 Counter %d: operation=%d, overhead=%d\n",
++ counter, op, overhead);
++ return MV_OK;
++}
++
++void mvCpuL2CntrsShow(MV_CPU_L2_CNTRS_EVENT* pEvent)
++{
++ int i;
++ MV_U64 counters_avg;
++
++ if(pEvent->num_of_measurements < pEvent->avg_sample_count)
++ return;
++
++ mvOsPrintf("%16s: ", pEvent->name);
++ for(i=0; i<MV_CPU_L2_CNTRS_NUM; i++)
++ {
++ counters_avg = mvOsDivMod64(pEvent->counters_sum[i],
++ pEvent->num_of_measurements, NULL);
++
++ if(counters_avg >= mvCpuL2CntrsTbl[i].overhead)
++ counters_avg -= mvCpuL2CntrsTbl[i].overhead;
++ else
++ counters_avg = 0;
++
++ mvOsPrintf("%s=%5llu, ", mvCpuL2CntrsTbl[i].name, counters_avg);
++ }
++ mvOsPrintf("\n");
++ mvCpuL2CntrsEventClear(pEvent);
++ mvCpuL2CntrsReset();
++}
++
++void mvCpuL2CntrsStatus(void)
++{
++ int i;
++
++ for(i=0; i<MV_CPU_L2_CNTRS_NUM; i++)
++ {
++ mvOsPrintf("#%d: %s, overhead=%d\n",
++ i, mvCpuL2CntrsTbl[i].name, mvCpuL2CntrsTbl[i].overhead);
++ }
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.h 2010-11-09 20:28:10.562495466 +0100
+@@ -0,0 +1,151 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++*******************************************************************************/
++#ifndef __mvCpuL2Cntrs_h__
++#define __mvCpuL2Cntrs_h__
++
++#include "mvTypes.h"
++#include "mvOs.h"
++
++
++#define MV_CPU_L2_CNTRS_NUM 2
++
++typedef enum
++{
++ MV_CPU_L2_CNTRS_ENABLE = 0,
++ MV_CPU_L2_CNTRS_DATA_REQ,
++ MV_CPU_L2_CNTRS_DATA_MISS_REQ,
++ MV_CPU_L2_CNTRS_INST_REQ,
++ MV_CPU_L2_CNTRS_INST_MISS_REQ,
++ MV_CPU_L2_CNTRS_DATA_READ_REQ,
++ MV_CPU_L2_CNTRS_DATA_READ_MISS_REQ,
++ MV_CPU_L2_CNTRS_DATA_WRITE_REQ,
++ MV_CPU_L2_CNTRS_DATA_WRITE_MISS_REQ,
++ MV_CPU_L2_CNTRS_RESERVED,
++ MV_CPU_L2_CNTRS_DIRTY_EVICT_REQ,
++ MV_CPU_L2_CNTRS_EVICT_BUFF_STALL,
++ MV_CPU_L2_CNTRS_ACTIVE_CYCLES,
++
++} MV_CPU_L2_CNTRS_OPS;
++
++typedef struct
++{
++ char name[16];
++ MV_CPU_L2_CNTRS_OPS operation;
++ int opIdx;
++ MV_U32 overhead;
++
++} MV_CPU_L2_CNTRS_ENTRY;
++
++
++typedef struct
++{
++ char name[16];
++ MV_U32 num_of_measurements;
++ MV_U32 avg_sample_count;
++ MV_U64 counters_before[MV_CPU_L2_CNTRS_NUM];
++ MV_U64 counters_after[MV_CPU_L2_CNTRS_NUM];
++ MV_U64 counters_sum[MV_CPU_L2_CNTRS_NUM];
++
++} MV_CPU_L2_CNTRS_EVENT;
++
++
++MV_STATUS mvCpuL2CntrsProgram(int counter, MV_CPU_L2_CNTRS_OPS op,
++ char* name, MV_U32 overhead);
++void mvCpuL2CntrsInit(void);
++MV_CPU_L2_CNTRS_EVENT* mvCpuL2CntrsEventCreate(char* name, MV_U32 print_threshold);
++void mvCpuL2CntrsEventDelete(MV_CPU_L2_CNTRS_EVENT* event);
++void mvCpuL2CntrsReset(void);
++void mvCpuL2CntrsShow(MV_CPU_L2_CNTRS_EVENT* pEvent);
++void mvCpuL2CntrsEventClear(MV_CPU_L2_CNTRS_EVENT* pEvent);
++
++static INLINE MV_U64 mvCpuL2CntrsRead(const int counter)
++{
++ MV_U32 low = 0, high = 0;
++
++ switch(counter)
++ {
++ case 0:
++ MV_ASM ("mrc p15, 6, %0, c15, c13, 0" : "=r" (low));
++ MV_ASM ("mrc p15, 6, %0, c15, c13, 1" : "=r" (high));
++ break;
++
++ case 1:
++ MV_ASM ("mrc p15, 6, %0, c15, c13, 2" : "=r" (low));
++ MV_ASM ("mrc p15, 6, %0, c15, c13, 3" : "=r" (high));
++ break;
++
++ default:
++ mvOsPrintf("mvCpuL2CntrsRead: bad counter number (%d)\n", counter);
++ }
++ return (((MV_U64)high << 32 ) | low);
++
++}
++
++static INLINE void mvCpuL2CntrsReadBefore(MV_CPU_L2_CNTRS_EVENT* pEvent)
++{
++ int i;
++
++ for(i=0; i<MV_CPU_L2_CNTRS_NUM; i++)
++ pEvent->counters_before[i] = mvCpuL2CntrsRead(i);
++}
++
++static INLINE void mvCpuL2CntrsReadAfter(MV_CPU_L2_CNTRS_EVENT* pEvent)
++{
++ int i;
++
++ for(i=0; i<MV_CPU_L2_CNTRS_NUM; i++)
++ {
++ pEvent->counters_after[i] = mvCpuL2CntrsRead(i);
++ pEvent->counters_sum[i] += (pEvent->counters_after[i] - pEvent->counters_before[i]);
++ }
++ pEvent->num_of_measurements++;
++}
++
++
++#ifdef CONFIG_MV_CPU_L2_PERF_CNTRS
++
++#define MV_CPU_L2_CNTRS_READ(counter) mvCpuL2CntrsRead(counter)
++
++#define MV_CPU_L2_CNTRS_START(event) mvCpuL2CntrsReadBefore(event)
++
++#define MV_CPU_L2_CNTRS_STOP(event) mvCpuL2CntrsReadAfter(event)
++
++#define MV_CPU_L2_CNTRS_SHOW(event) mvCpuL2CntrsShow(event)
++
++#else
++
++#define MV_CPU_L2_CNTRS_READ(counter)
++#define MV_CPU_L2_CNTRS_START(event)
++#define MV_CPU_L2_CNTRS_STOP(event)
++#define MV_CPU_L2_CNTRS_SHOW(event)
++
++#endif /* CONFIG_MV_CPU_L2_PERF_CNTRS */
++
++
++#endif /* __mvCpuL2Cntrs_h__ */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.c 2010-11-09 20:28:10.592495381 +0100
+@@ -0,0 +1,1479 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "ddr1_2/mvDram.h"
++#include "boardEnv/mvBoardEnvLib.h"
++
++#undef MV_DEBUG
++#ifdef MV_DEBUG
++#define DB(x) x
++#else
++#define DB(x)
++#endif
++
++static MV_VOID cpyDimm2BankInfo(MV_DIMM_INFO *pDimmInfo,
++ MV_DRAM_BANK_INFO *pBankInfo);
++static MV_U32 cas2ps(MV_U8 spd_byte);
++/*******************************************************************************
++* mvDramBankGet - Get the DRAM bank paramters.
++*
++* DESCRIPTION:
++* This function retrieves DRAM bank parameters as described in
++* DRAM_BANK_INFO struct to the controller DRAM unit. In case the board
++* has its DRAM on DIMMs it will use its EEPROM to extract SPD data
++* from it. Otherwise, if the DRAM is soldered on board, the function
++* should insert its bank information into MV_DRAM_BANK_INFO struct.
++*
++* INPUT:
++* bankNum - Board DRAM bank number.
++*
++* OUTPUT:
++* pBankInfo - DRAM bank information struct.
++*
++* RETURN:
++* MV_FAIL - Bank parameters could not be read.
++*
++*******************************************************************************/
++MV_STATUS mvDramBankInfoGet(MV_U32 bankNum, MV_DRAM_BANK_INFO *pBankInfo)
++{
++ MV_DIMM_INFO dimmInfo;
++
++ DB(mvOsPrintf("Dram: mvDramBankInfoGet bank %d\n", bankNum));
++ /* zero pBankInfo structure */
++ memset(pBankInfo, 0, sizeof(*pBankInfo));
++
++ if((NULL == pBankInfo) || (bankNum >= MV_DRAM_MAX_CS ))
++ {
++ DB(mvOsPrintf("Dram: mvDramBankInfoGet bad params \n"));
++ return MV_BAD_PARAM;
++ }
++ if( MV_OK != dimmSpdGet((MV_U32)(bankNum/2), &dimmInfo))
++ {
++ DB(mvOsPrintf("Dram: ERR dimmSpdGet failed to get dimm info \n"));
++ return MV_FAIL;
++ }
++ if((dimmInfo.numOfModuleBanks == 1) && ((bankNum % 2) == 1))
++ {
++ DB(mvOsPrintf("Dram: ERR dimmSpdGet. Can't find DIMM bank 2 \n"));
++ return MV_FAIL;
++ }
++
++ /* convert Dimm info to Bank info */
++ cpyDimm2BankInfo(&dimmInfo, pBankInfo);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* cpyDimm2BankInfo - Convert a Dimm info struct into a bank info struct.
++*
++* DESCRIPTION:
++* Convert a Dimm info struct into a bank info struct.
++*
++* INPUT:
++* pDimmInfo - DIMM information structure.
++*
++* OUTPUT:
++* pBankInfo - DRAM bank information struct.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++static MV_VOID cpyDimm2BankInfo(MV_DIMM_INFO *pDimmInfo,
++ MV_DRAM_BANK_INFO *pBankInfo)
++{
++ pBankInfo->memoryType = pDimmInfo->memoryType;
++
++ /* DIMM dimensions */
++ pBankInfo->numOfRowAddr = pDimmInfo->numOfRowAddr;
++ pBankInfo->numOfColAddr = pDimmInfo->numOfColAddr;
++ pBankInfo->dataWidth = pDimmInfo->dataWidth;
++ pBankInfo->errorCheckType = pDimmInfo->errorCheckType;
++ pBankInfo->sdramWidth = pDimmInfo->sdramWidth;
++ pBankInfo->errorCheckDataWidth = pDimmInfo->errorCheckDataWidth;
++ pBankInfo->numOfBanksOnEachDevice = pDimmInfo->numOfBanksOnEachDevice;
++ pBankInfo->suportedCasLatencies = pDimmInfo->suportedCasLatencies;
++ pBankInfo->refreshInterval = pDimmInfo->refreshInterval;
++
++ /* DIMM timing parameters */
++ pBankInfo->minCycleTimeAtMaxCasLatPs = pDimmInfo->minCycleTimeAtMaxCasLatPs;
++ pBankInfo->minCycleTimeAtMaxCasLatMinus1Ps =
++ pDimmInfo->minCycleTimeAtMaxCasLatMinus1Ps;
++ pBankInfo->minCycleTimeAtMaxCasLatMinus2Ps =
++ pDimmInfo->minCycleTimeAtMaxCasLatMinus2Ps;
++
++ pBankInfo->minRowPrechargeTime = pDimmInfo->minRowPrechargeTime;
++ pBankInfo->minRowActiveToRowActive = pDimmInfo->minRowActiveToRowActive;
++ pBankInfo->minRasToCasDelay = pDimmInfo->minRasToCasDelay;
++ pBankInfo->minRasPulseWidth = pDimmInfo->minRasPulseWidth;
++ pBankInfo->minWriteRecoveryTime = pDimmInfo->minWriteRecoveryTime;
++ pBankInfo->minWriteToReadCmdDelay = pDimmInfo->minWriteToReadCmdDelay;
++ pBankInfo->minReadToPrechCmdDelay = pDimmInfo->minReadToPrechCmdDelay;
++ pBankInfo->minRefreshToActiveCmd = pDimmInfo->minRefreshToActiveCmd;
++
++ /* Parameters calculated from the extracted DIMM information */
++ pBankInfo->size = pDimmInfo->size/pDimmInfo->numOfModuleBanks;
++ pBankInfo->deviceDensity = pDimmInfo->deviceDensity;
++ pBankInfo->numberOfDevices = pDimmInfo->numberOfDevices /
++ pDimmInfo->numOfModuleBanks;
++
++ /* DIMM attributes (MV_TRUE for yes) */
++
++ if ((pDimmInfo->memoryType == MEM_TYPE_SDRAM) ||
++ (pDimmInfo->memoryType == MEM_TYPE_DDR1) )
++ {
++ if (pDimmInfo->dimmAttributes & BIT1)
++ pBankInfo->registeredAddrAndControlInputs = MV_TRUE;
++ else
++ pBankInfo->registeredAddrAndControlInputs = MV_FALSE;
++ }
++ else /* pDimmInfo->memoryType == MEM_TYPE_DDR2 */
++ {
++ if (pDimmInfo->dimmTypeInfo & (BIT0 | BIT4))
++ pBankInfo->registeredAddrAndControlInputs = MV_TRUE;
++ else
++ pBankInfo->registeredAddrAndControlInputs = MV_FALSE;
++ }
++
++ return;
++}
++
++/*******************************************************************************
++* dimmSpdCpy - Cpy SPD parameters from dimm 0 to dimm 1.
++*
++* DESCRIPTION:
++* Read the DIMM SPD parameters from dimm 0 into dimm 1 SPD.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if function could read DIMM parameters, MV_FALSE otherwise.
++*
++*******************************************************************************/
++MV_STATUS dimmSpdCpy(MV_VOID)
++{
++ MV_U32 i;
++ MV_U32 spdChecksum;
++
++ MV_TWSI_SLAVE twsiSlave;
++ MV_U8 data[SPD_SIZE];
++
++ /* zero dimmInfo structure */
++ memset(data, 0, SPD_SIZE);
++
++ /* read the dimm eeprom */
++ DB(mvOsPrintf("DRAM: Read Dimm eeprom\n"));
++ twsiSlave.slaveAddr.address = MV_BOARD_DIMM0_I2C_ADDR;
++ twsiSlave.slaveAddr.type = ADDR7_BIT;
++ twsiSlave.validOffset = MV_TRUE;
++ twsiSlave.offset = 0;
++ twsiSlave.moreThen256 = MV_FALSE;
++
++ if( MV_OK != mvTwsiRead (MV_BOARD_DIMM_I2C_CHANNEL,
++ &twsiSlave, data, SPD_SIZE) )
++ {
++ DB(mvOsPrintf("DRAM: ERR. no DIMM in dimmNum 0\n"));
++ return MV_FAIL;
++ }
++ DB(puts("DRAM: Reading dimm info succeded.\n"));
++
++ /* calculate SPD checksum */
++ spdChecksum = 0;
++
++ for(i = 0 ; i <= 62 ; i++)
++ {
++ spdChecksum += data[i];
++ }
++
++ if ((spdChecksum & 0xff) != data[63])
++ {
++ DB(mvOsPrintf("DRAM: Warning. Wrong SPD Checksum %2x, expValue=%2x\n",
++ (MV_U32)(spdChecksum & 0xff), data[63]));
++ }
++ else
++ {
++ DB(mvOsPrintf("DRAM: SPD Checksum ok!\n"));
++ }
++
++ /* copy the SPD content 1:1 into the DIMM 1 SPD */
++ twsiSlave.slaveAddr.address = MV_BOARD_DIMM1_I2C_ADDR;
++ twsiSlave.slaveAddr.type = ADDR7_BIT;
++ twsiSlave.validOffset = MV_TRUE;
++ twsiSlave.offset = 0;
++ twsiSlave.moreThen256 = MV_FALSE;
++
++ for(i = 0 ; i < SPD_SIZE ; i++)
++ {
++ twsiSlave.offset = i;
++ if( MV_OK != mvTwsiWrite (MV_BOARD_DIMM_I2C_CHANNEL,
++ &twsiSlave, &data[i], 1) )
++ {
++ mvOsPrintf("DRAM: ERR. no DIMM in dimmNum 1 byte %d \n",i);
++ return MV_FAIL;
++ }
++ mvOsDelay(5);
++ }
++
++ DB(puts("DRAM: Reading dimm info succeded.\n"));
++ return MV_OK;
++}
++
++/*******************************************************************************
++* dimmSpdGet - Get the SPD parameters.
++*
++* DESCRIPTION:
++* Read the DIMM SPD parameters into given struct parameter.
++*
++* INPUT:
++* dimmNum - DIMM number. See MV_BOARD_DIMM_NUM enumerator.
++*
++* OUTPUT:
++* pDimmInfo - DIMM information structure.
++*
++* RETURN:
++* MV_TRUE if function could read DIMM parameters, MV_FALSE otherwise.
++*
++*******************************************************************************/
++MV_STATUS dimmSpdGet(MV_U32 dimmNum, MV_DIMM_INFO *pDimmInfo)
++{
++ MV_U32 i;
++ MV_U32 density = 1;
++ MV_U32 spdChecksum;
++
++ MV_TWSI_SLAVE twsiSlave;
++ MV_U8 data[SPD_SIZE];
++
++ if((NULL == pDimmInfo)|| (dimmNum >= MAX_DIMM_NUM))
++ {
++ DB(mvOsPrintf("Dram: mvDramBankInfoGet bad params \n"));
++ return MV_BAD_PARAM;
++ }
++
++ /* zero dimmInfo structure */
++ memset(data, 0, SPD_SIZE);
++
++ /* read the dimm eeprom */
++ DB(mvOsPrintf("DRAM: Read Dimm eeprom\n"));
++ twsiSlave.slaveAddr.address = (dimmNum == 0) ?
++ MV_BOARD_DIMM0_I2C_ADDR : MV_BOARD_DIMM1_I2C_ADDR;
++ twsiSlave.slaveAddr.type = ADDR7_BIT;
++ twsiSlave.validOffset = MV_TRUE;
++ twsiSlave.offset = 0;
++ twsiSlave.moreThen256 = MV_FALSE;
++
++ if( MV_OK != mvTwsiRead (MV_BOARD_DIMM_I2C_CHANNEL,
++ &twsiSlave, data, SPD_SIZE) )
++ {
++ DB(mvOsPrintf("DRAM: ERR. no DIMM in dimmNum %d \n", dimmNum));
++ return MV_FAIL;
++ }
++ DB(puts("DRAM: Reading dimm info succeded.\n"));
++
++ /* calculate SPD checksum */
++ spdChecksum = 0;
++
++ for(i = 0 ; i <= 62 ; i++)
++ {
++ spdChecksum += data[i];
++ }
++
++ if ((spdChecksum & 0xff) != data[63])
++ {
++ DB(mvOsPrintf("DRAM: Warning. Wrong SPD Checksum %2x, expValue=%2x\n",
++ (MV_U32)(spdChecksum & 0xff), data[63]));
++ }
++ else
++ {
++ DB(mvOsPrintf("DRAM: SPD Checksum ok!\n"));
++ }
++
++ /* copy the SPD content 1:1 into the dimmInfo structure*/
++ for(i = 0 ; i < SPD_SIZE ; i++)
++ {
++ pDimmInfo->spdRawData[i] = data[i];
++ DB(mvOsPrintf("SPD-EEPROM Byte %3d = %3x (%3d)\n",i, data[i], data[i]));
++ }
++
++ DB(mvOsPrintf("DRAM SPD Information:\n"));
++
++ /* Memory type (DDR / SDRAM) */
++ switch (data[DIMM_MEM_TYPE])
++ {
++ case (DIMM_MEM_TYPE_SDRAM):
++ pDimmInfo->memoryType = MEM_TYPE_SDRAM;
++ DB(mvOsPrintf("DRAM Memeory type SDRAM\n"));
++ break;
++ case (DIMM_MEM_TYPE_DDR1):
++ pDimmInfo->memoryType = MEM_TYPE_DDR1;
++ DB(mvOsPrintf("DRAM Memeory type DDR1\n"));
++ break;
++ case (DIMM_MEM_TYPE_DDR2):
++ pDimmInfo->memoryType = MEM_TYPE_DDR2;
++ DB(mvOsPrintf("DRAM Memeory type DDR2\n"));
++ break;
++ default:
++ mvOsPrintf("ERROR: Undefined memory type!\n");
++ return MV_ERROR;
++ }
++
++
++ /* Number Of Row Addresses */
++ pDimmInfo->numOfRowAddr = data[DIMM_ROW_NUM];
++ DB(mvOsPrintf("DRAM numOfRowAddr[3] %d\n",pDimmInfo->numOfRowAddr));
++
++ /* Number Of Column Addresses */
++ pDimmInfo->numOfColAddr = data[DIMM_COL_NUM];
++ DB(mvOsPrintf("DRAM numOfColAddr[4] %d\n",pDimmInfo->numOfColAddr));
++
++ /* Number Of Module Banks */
++ pDimmInfo->numOfModuleBanks = data[DIMM_MODULE_BANK_NUM];
++ DB(mvOsPrintf("DRAM numOfModuleBanks[5] 0x%x\n",
++ pDimmInfo->numOfModuleBanks));
++
++ /* Number of module banks encoded differently for DDR2 */
++ if (pDimmInfo->memoryType == MEM_TYPE_DDR2)
++ pDimmInfo->numOfModuleBanks = (pDimmInfo->numOfModuleBanks & 0x7)+1;
++
++ /* Data Width */
++ pDimmInfo->dataWidth = data[DIMM_DATA_WIDTH];
++ DB(mvOsPrintf("DRAM dataWidth[6] 0x%x\n", pDimmInfo->dataWidth));
++
++ /* Minimum Cycle Time At Max CasLatancy */
++ pDimmInfo->minCycleTimeAtMaxCasLatPs = cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS]);
++
++ /* Error Check Type */
++ pDimmInfo->errorCheckType = data[DIMM_ERR_CHECK_TYPE];
++ DB(mvOsPrintf("DRAM errorCheckType[11] 0x%x\n",
++ pDimmInfo->errorCheckType));
++
++ /* Refresh Interval */
++ pDimmInfo->refreshInterval = data[DIMM_REFRESH_INTERVAL];
++ DB(mvOsPrintf("DRAM refreshInterval[12] 0x%x\n",
++ pDimmInfo->refreshInterval));
++
++ /* Sdram Width */
++ pDimmInfo->sdramWidth = data[DIMM_SDRAM_WIDTH];
++ DB(mvOsPrintf("DRAM sdramWidth[13] 0x%x\n",pDimmInfo->sdramWidth));
++
++ /* Error Check Data Width */
++ pDimmInfo->errorCheckDataWidth = data[DIMM_ERR_CHECK_DATA_WIDTH];
++ DB(mvOsPrintf("DRAM errorCheckDataWidth[14] 0x%x\n",
++ pDimmInfo->errorCheckDataWidth));
++
++ /* Burst Length Supported */
++ /* SDRAM/DDR1:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ burst length = * Page | TBD | TBD | TBD | 8 | 4 | 2 | 1 *
++ *********************************************************/
++ /* DDR2:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ burst length = * Page | TBD | TBD | TBD | 8 | 4 | TBD | TBD *
++ *********************************************************/
++
++ pDimmInfo->burstLengthSupported = data[DIMM_BURST_LEN_SUP];
++ DB(mvOsPrintf("DRAM burstLengthSupported[16] 0x%x\n",
++ pDimmInfo->burstLengthSupported));
++
++ /* Number Of Banks On Each Device */
++ pDimmInfo->numOfBanksOnEachDevice = data[DIMM_DEV_BANK_NUM];
++ DB(mvOsPrintf("DRAM numOfBanksOnEachDevice[17] 0x%x\n",
++ pDimmInfo->numOfBanksOnEachDevice));
++
++ /* Suported Cas Latencies */
++
++ /* SDRAM:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | 7 | 6 | 5 | 4 | 3 | 2 | 1 *
++ ********************************************************/
++
++ /* DDR 1:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 *
++ *********************************************************/
++
++ /* DDR 2:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD *
++ *********************************************************/
++
++ pDimmInfo->suportedCasLatencies = data[DIMM_SUP_CAL];
++ DB(mvOsPrintf("DRAM suportedCasLatencies[18] 0x%x\n",
++ pDimmInfo->suportedCasLatencies));
++
++ /* For DDR2 only, get the DIMM type information */
++ if (pDimmInfo->memoryType == MEM_TYPE_DDR2)
++ {
++ pDimmInfo->dimmTypeInfo = data[DIMM_DDR2_TYPE_INFORMATION];
++ DB(mvOsPrintf("DRAM dimmTypeInfo[20] (DDR2) 0x%x\n",
++ pDimmInfo->dimmTypeInfo));
++ }
++
++ /* SDRAM Modules Attributes */
++ pDimmInfo->dimmAttributes = data[DIMM_BUF_ADDR_CONT_IN];
++ DB(mvOsPrintf("DRAM dimmAttributes[21] 0x%x\n",
++ pDimmInfo->dimmAttributes));
++
++ /* Minimum Cycle Time At Max CasLatancy Minus 1*/
++ pDimmInfo->minCycleTimeAtMaxCasLatMinus1Ps =
++ cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS_MINUS1]);
++
++ /* Minimum Cycle Time At Max CasLatancy Minus 2*/
++ pDimmInfo->minCycleTimeAtMaxCasLatMinus2Ps =
++ cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS_MINUS2]);
++
++ pDimmInfo->minRowPrechargeTime = data[DIMM_MIN_ROW_PRECHARGE_TIME];
++ DB(mvOsPrintf("DRAM minRowPrechargeTime[27] 0x%x\n",
++ pDimmInfo->minRowPrechargeTime));
++ pDimmInfo->minRowActiveToRowActive = data[DIMM_MIN_ROW_ACTIVE_TO_ROW_ACTIVE];
++ DB(mvOsPrintf("DRAM minRowActiveToRowActive[28] 0x%x\n",
++ pDimmInfo->minRowActiveToRowActive));
++ pDimmInfo->minRasToCasDelay = data[DIMM_MIN_RAS_TO_CAS_DELAY];
++ DB(mvOsPrintf("DRAM minRasToCasDelay[29] 0x%x\n",
++ pDimmInfo->minRasToCasDelay));
++ pDimmInfo->minRasPulseWidth = data[DIMM_MIN_RAS_PULSE_WIDTH];
++ DB(mvOsPrintf("DRAM minRasPulseWidth[30] 0x%x\n",
++ pDimmInfo->minRasPulseWidth));
++
++ /* DIMM Bank Density */
++ pDimmInfo->dimmBankDensity = data[DIMM_BANK_DENSITY];
++ DB(mvOsPrintf("DRAM dimmBankDensity[31] 0x%x\n",
++ pDimmInfo->dimmBankDensity));
++
++ /* Only DDR2 includes Write Recovery Time field. Other SDRAM ignore */
++ pDimmInfo->minWriteRecoveryTime = data[DIMM_MIN_WRITE_RECOVERY_TIME];
++ DB(mvOsPrintf("DRAM minWriteRecoveryTime[36] 0x%x\n",
++ pDimmInfo->minWriteRecoveryTime));
++
++ /* Only DDR2 includes Internal Write To Read Command Delay field. */
++ pDimmInfo->minWriteToReadCmdDelay = data[DIMM_MIN_WRITE_TO_READ_CMD_DELAY];
++ DB(mvOsPrintf("DRAM minWriteToReadCmdDelay[37] 0x%x\n",
++ pDimmInfo->minWriteToReadCmdDelay));
++
++ /* Only DDR2 includes Internal Read To Precharge Command Delay field. */
++ pDimmInfo->minReadToPrechCmdDelay = data[DIMM_MIN_READ_TO_PRECH_CMD_DELAY];
++ DB(mvOsPrintf("DRAM minReadToPrechCmdDelay[38] 0x%x\n",
++ pDimmInfo->minReadToPrechCmdDelay));
++
++ /* Only DDR2 includes Minimum Refresh to Activate/Refresh Command field */
++ pDimmInfo->minRefreshToActiveCmd = data[DIMM_MIN_REFRESH_TO_ACTIVATE_CMD];
++ DB(mvOsPrintf("DRAM minRefreshToActiveCmd[42] 0x%x\n",
++ pDimmInfo->minRefreshToActiveCmd));
++
++ /* calculating the sdram density. Representing device density from */
++ /* bit 20 to allow representation of 4GB and above. */
++ /* For example, if density is 512Mbit 0x20000000, will be represent in */
++ /* deviceDensity by 0x20000000 >> 16 --> 0x00000200. Another example */
++ /* is density 8GB 0x200000000 >> 16 --> 0x00002000. */
++ density = (1 << ((pDimmInfo->numOfRowAddr + pDimmInfo->numOfColAddr) - 20));
++ pDimmInfo->deviceDensity = density *
++ pDimmInfo->numOfBanksOnEachDevice *
++ pDimmInfo->sdramWidth;
++ DB(mvOsPrintf("DRAM deviceDensity %d\n",pDimmInfo->deviceDensity));
++
++ /* Number of devices includeing Error correction */
++ pDimmInfo->numberOfDevices = (pDimmInfo->dataWidth/pDimmInfo->sdramWidth) *
++ pDimmInfo->numOfModuleBanks;
++ DB(mvOsPrintf("DRAM numberOfDevices %d\n",
++ pDimmInfo->numberOfDevices));
++
++ pDimmInfo->size = 0;
++
++ /* Note that pDimmInfo->size is in MB units */
++ if (pDimmInfo->memoryType == MEM_TYPE_SDRAM)
++ {
++ if (pDimmInfo->dimmBankDensity & BIT0)
++ pDimmInfo->size += 1024; /* Equal to 1GB */
++ else if (pDimmInfo->dimmBankDensity & BIT1)
++ pDimmInfo->size += 8; /* Equal to 8MB */
++ else if (pDimmInfo->dimmBankDensity & BIT2)
++ pDimmInfo->size += 16; /* Equal to 16MB */
++ else if (pDimmInfo->dimmBankDensity & BIT3)
++ pDimmInfo->size += 32; /* Equal to 32MB */
++ else if (pDimmInfo->dimmBankDensity & BIT4)
++ pDimmInfo->size += 64; /* Equal to 64MB */
++ else if (pDimmInfo->dimmBankDensity & BIT5)
++ pDimmInfo->size += 128; /* Equal to 128MB */
++ else if (pDimmInfo->dimmBankDensity & BIT6)
++ pDimmInfo->size += 256; /* Equal to 256MB */
++ else if (pDimmInfo->dimmBankDensity & BIT7)
++ pDimmInfo->size += 512; /* Equal to 512MB */
++ }
++ else if (pDimmInfo->memoryType == MEM_TYPE_DDR1)
++ {
++ if (pDimmInfo->dimmBankDensity & BIT0)
++ pDimmInfo->size += 1024; /* Equal to 1GB */
++ else if (pDimmInfo->dimmBankDensity & BIT1)
++ pDimmInfo->size += 2048; /* Equal to 2GB */
++ else if (pDimmInfo->dimmBankDensity & BIT2)
++ pDimmInfo->size += 16; /* Equal to 16MB */
++ else if (pDimmInfo->dimmBankDensity & BIT3)
++ pDimmInfo->size += 32; /* Equal to 32MB */
++ else if (pDimmInfo->dimmBankDensity & BIT4)
++ pDimmInfo->size += 64; /* Equal to 64MB */
++ else if (pDimmInfo->dimmBankDensity & BIT5)
++ pDimmInfo->size += 128; /* Equal to 128MB */
++ else if (pDimmInfo->dimmBankDensity & BIT6)
++ pDimmInfo->size += 256; /* Equal to 256MB */
++ else if (pDimmInfo->dimmBankDensity & BIT7)
++ pDimmInfo->size += 512; /* Equal to 512MB */
++ }
++ else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */
++ {
++ if (pDimmInfo->dimmBankDensity & BIT0)
++ pDimmInfo->size += 1024; /* Equal to 1GB */
++ else if (pDimmInfo->dimmBankDensity & BIT1)
++ pDimmInfo->size += 2048; /* Equal to 2GB */
++ else if (pDimmInfo->dimmBankDensity & BIT2)
++ pDimmInfo->size += 4096; /* Equal to 4GB */
++ else if (pDimmInfo->dimmBankDensity & BIT3)
++ pDimmInfo->size += 8192; /* Equal to 8GB */
++ else if (pDimmInfo->dimmBankDensity & BIT4)
++ pDimmInfo->size += 16384; /* Equal to 16GB */
++ else if (pDimmInfo->dimmBankDensity & BIT5)
++ pDimmInfo->size += 128; /* Equal to 128MB */
++ else if (pDimmInfo->dimmBankDensity & BIT6)
++ pDimmInfo->size += 256; /* Equal to 256MB */
++ else if (pDimmInfo->dimmBankDensity & BIT7)
++ pDimmInfo->size += 512; /* Equal to 512MB */
++ }
++
++ pDimmInfo->size *= pDimmInfo->numOfModuleBanks;
++
++ DB(mvOsPrintf("Dram: dimm size %dMB \n",pDimmInfo->size));
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* dimmSpdPrint - Print the SPD parameters.
++*
++* DESCRIPTION:
++* Print the Dimm SPD parameters.
++*
++* INPUT:
++* pDimmInfo - DIMM information structure.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID dimmSpdPrint(MV_U32 dimmNum)
++{
++ MV_DIMM_INFO dimmInfo;
++ MV_U32 i, temp = 0;
++ MV_U32 k, maskLeftOfPoint = 0, maskRightOfPoint = 0;
++ MV_U32 rightOfPoint = 0,leftOfPoint = 0, div, time_tmp, shift;
++ MV_U32 busClkPs;
++ MV_U8 trp_clocks=0, trcd_clocks, tras_clocks, trrd_clocks,
++ temp_buf[40], *spdRawData;
++
++ busClkPs = 1000000000 / (mvBoardSysClkGet() / 100); /* in 10 ps units */
++
++ spdRawData = dimmInfo.spdRawData;
++
++ if(MV_OK != dimmSpdGet(dimmNum, &dimmInfo))
++ {
++ mvOsOutput("ERROR: Could not read SPD information!\n");
++ return;
++ }
++
++ /* find Manufactura of Dimm Module */
++ mvOsOutput("\nManufacturer's JEDEC ID Code: ");
++ for(i = 0 ; i < DIMM_MODULE_MANU_SIZE ; i++)
++ {
++ mvOsOutput("%x",spdRawData[DIMM_MODULE_MANU_OFFS + i]);
++ }
++ mvOsOutput("\n");
++
++ /* Manufacturer's Specific Data */
++ for(i = 0 ; i < DIMM_MODULE_ID_SIZE ; i++)
++ {
++ temp_buf[i] = spdRawData[DIMM_MODULE_ID_OFFS + i];
++ }
++ mvOsOutput("Manufacturer's Specific Data: %s\n", temp_buf);
++
++ /* Module Part Number */
++ for(i = 0 ; i < DIMM_MODULE_VEN_SIZE ; i++)
++ {
++ temp_buf[i] = spdRawData[DIMM_MODULE_VEN_OFFS + i];
++ }
++ mvOsOutput("Module Part Number: %s\n", temp_buf);
++
++ /* Module Serial Number */
++ for(i = 0; i < sizeof(MV_U32); i++)
++ {
++ temp |= spdRawData[95+i] << 8*i;
++ }
++ mvOsOutput("DIMM Serial No. %ld (%lx)\n", (long)temp,
++ (long)temp);
++
++ /* find Manufac-Data of Dimm Module */
++ mvOsOutput("Manufactoring Date: Year 20%d%d/ ww %d%d\n",
++ ((spdRawData[93] & 0xf0) >> 4), (spdRawData[93] & 0xf),
++ ((spdRawData[94] & 0xf0) >> 4), (spdRawData[94] & 0xf));
++ /* find modul_revision of Dimm Module */
++ mvOsOutput("Module Revision: %d.%d\n",
++ spdRawData[91], spdRawData[92]);
++
++ /* find manufac_place of Dimm Module */
++ mvOsOutput("manufac_place: %d\n", spdRawData[72]);
++
++ /* go over the first 35 I2C data bytes */
++ for(i = 2 ; i <= 35 ; i++)
++ switch(i)
++ {
++ case 2: /* Memory type (DDR1/2 / SDRAM) */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ mvOsOutput("Dram Type is: SDRAM\n");
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR1)
++ mvOsOutput("Dram Type is: SDRAM DDR1\n");
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR2)
++ mvOsOutput("Dram Type is: SDRAM DDR2\n");
++ else
++ mvOsOutput("Dram Type unknown\n");
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 3: /* Number Of Row Addresses */
++ mvOsOutput("Module Number of row addresses: %d\n",
++ dimmInfo.numOfRowAddr);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 4: /* Number Of Column Addresses */
++ mvOsOutput("Module Number of col addresses: %d\n",
++ dimmInfo.numOfColAddr);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 5: /* Number Of Module Banks */
++ mvOsOutput("Number of Banks on Mod.: %d\n",
++ dimmInfo.numOfModuleBanks);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 6: /* Data Width */
++ mvOsOutput("Module Data Width: %d bit\n",
++ dimmInfo.dataWidth);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 8: /* Voltage Interface */
++ switch(spdRawData[i])
++ {
++ case 0x0:
++ mvOsOutput("Module is TTL_5V_TOLERANT\n");
++ break;
++ case 0x1:
++ mvOsOutput("Module is LVTTL\n");
++ break;
++ case 0x2:
++ mvOsOutput("Module is HSTL_1_5V\n");
++ break;
++ case 0x3:
++ mvOsOutput("Module is SSTL_3_3V\n");
++ break;
++ case 0x4:
++ mvOsOutput("Module is SSTL_2_5V\n");
++ break;
++ case 0x5:
++ if (dimmInfo.memoryType != MEM_TYPE_SDRAM)
++ {
++ mvOsOutput("Module is SSTL_1_8V\n");
++ break;
++ }
++ default:
++ mvOsOutput("Module is VOLTAGE_UNKNOWN\n");
++ break;
++ }
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 9: /* Minimum Cycle Time At Max CasLatancy */
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ rightOfPoint = (spdRawData[i] & 0x0f) * 10;
++
++ /* DDR2 addition of right of point */
++ if ((spdRawData[i] & 0x0f) == 0xA)
++ {
++ rightOfPoint = 25;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xB)
++ {
++ rightOfPoint = 33;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xC)
++ {
++ rightOfPoint = 66;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xD)
++ {
++ rightOfPoint = 75;
++ }
++ mvOsOutput("Minimum Cycle Time At Max CL: %d.%d [ns]\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 10: /* Clock To Data Out */
++ div = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 10:100;
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / div;
++ rightOfPoint = time_tmp % div;
++ mvOsOutput("Clock To Data Out: %d.%d [ns]\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 11: /* Error Check Type */
++ mvOsOutput("Error Check Type (0=NONE): %d\n",
++ dimmInfo.errorCheckType);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 12: /* Refresh Interval */
++ mvOsOutput("Refresh Rate: %x\n",
++ dimmInfo.refreshInterval);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 13: /* Sdram Width */
++ mvOsOutput("Sdram Width: %d bits\n",
++ dimmInfo.sdramWidth);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 14: /* Error Check Data Width */
++ mvOsOutput("Error Check Data Width: %d bits\n",
++ dimmInfo.errorCheckDataWidth);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 15: /* Minimum Clock Delay is unsupported */
++ if ((dimmInfo.memoryType == MEM_TYPE_SDRAM) ||
++ (dimmInfo.memoryType == MEM_TYPE_DDR1))
++ {
++ mvOsOutput("Minimum Clk Delay back to back: %d\n",
++ spdRawData[i]);
++ }
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 16: /* Burst Length Supported */
++ /* SDRAM/DDR1:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ burst length = * Page | TBD | TBD | TBD | 8 | 4 | 2 | 1 *
++ *********************************************************/
++ /* DDR2:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ burst length = * Page | TBD | TBD | TBD | 8 | 4 | TBD | TBD *
++ *********************************************************/
++ mvOsOutput("Burst Length Supported: ");
++ if ((dimmInfo.memoryType == MEM_TYPE_SDRAM) ||
++ (dimmInfo.memoryType == MEM_TYPE_DDR1))
++ {
++ if (dimmInfo.burstLengthSupported & BIT0)
++ mvOsOutput("1, ");
++ if (dimmInfo.burstLengthSupported & BIT1)
++ mvOsOutput("2, ");
++ }
++ if (dimmInfo.burstLengthSupported & BIT2)
++ mvOsOutput("4, ");
++ if (dimmInfo.burstLengthSupported & BIT3)
++ mvOsOutput("8, ");
++
++ mvOsOutput(" Bit \n");
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 17: /* Number Of Banks On Each Device */
++ mvOsOutput("Number Of Banks On Each Chip: %d\n",
++ dimmInfo.numOfBanksOnEachDevice);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 18: /* Suported Cas Latencies */
++
++ /* SDRAM:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | 7 | 6 | 5 | 4 | 3 | 2 | 1 *
++ ********************************************************/
++
++ /* DDR 1:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 *
++ *********************************************************/
++
++ /* DDR 2:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD *
++ *********************************************************/
++
++ mvOsOutput("Suported Cas Latencies: (CL) ");
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ for (k = 0; k <=7; k++)
++ {
++ if (dimmInfo.suportedCasLatencies & (1 << k))
++ mvOsOutput("%d, ", k+1);
++ }
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR1)
++ {
++ if (dimmInfo.suportedCasLatencies & BIT0)
++ mvOsOutput("1, ");
++ if (dimmInfo.suportedCasLatencies & BIT1)
++ mvOsOutput("1.5, ");
++ if (dimmInfo.suportedCasLatencies & BIT2)
++ mvOsOutput("2, ");
++ if (dimmInfo.suportedCasLatencies & BIT3)
++ mvOsOutput("2.5, ");
++ if (dimmInfo.suportedCasLatencies & BIT4)
++ mvOsOutput("3, ");
++ if (dimmInfo.suportedCasLatencies & BIT5)
++ mvOsOutput("3.5, ");
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR2)
++ {
++ if (dimmInfo.suportedCasLatencies & BIT2)
++ mvOsOutput("2, ");
++ if (dimmInfo.suportedCasLatencies & BIT3)
++ mvOsOutput("3, ");
++ if (dimmInfo.suportedCasLatencies & BIT4)
++ mvOsOutput("4, ");
++ if (dimmInfo.suportedCasLatencies & BIT5)
++ mvOsOutput("5, ");
++ }
++ else
++ mvOsOutput("?.?, ");
++ mvOsOutput("\n");
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 20: /* DDR2 DIMM type info */
++ if (dimmInfo.memoryType == MEM_TYPE_DDR2)
++ {
++ if (dimmInfo.dimmTypeInfo & (BIT0 | BIT4))
++ mvOsOutput("Registered DIMM (RDIMM)\n");
++ else if (dimmInfo.dimmTypeInfo & (BIT1 | BIT5))
++ mvOsOutput("Unbuffered DIMM (UDIMM)\n");
++ else
++ mvOsOutput("Unknown DIMM type.\n");
++ }
++
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 21: /* SDRAM Modules Attributes */
++ mvOsOutput("\nModule Attributes (SPD Byte 21): \n");
++
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ if (dimmInfo.dimmAttributes & BIT0)
++ mvOsOutput(" Buffered Addr/Control Input: Yes\n");
++ else
++ mvOsOutput(" Buffered Addr/Control Input: No\n");
++
++ if (dimmInfo.dimmAttributes & BIT1)
++ mvOsOutput(" Registered Addr/Control Input: Yes\n");
++ else
++ mvOsOutput(" Registered Addr/Control Input: No\n");
++
++ if (dimmInfo.dimmAttributes & BIT2)
++ mvOsOutput(" On-Card PLL (clock): Yes \n");
++ else
++ mvOsOutput(" On-Card PLL (clock): No \n");
++
++ if (dimmInfo.dimmAttributes & BIT3)
++ mvOsOutput(" Bufferd DQMB Input: Yes \n");
++ else
++ mvOsOutput(" Bufferd DQMB Inputs: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT4)
++ mvOsOutput(" Registered DQMB Inputs: Yes \n");
++ else
++ mvOsOutput(" Registered DQMB Inputs: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT5)
++ mvOsOutput(" Differential Clock Input: Yes \n");
++ else
++ mvOsOutput(" Differential Clock Input: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT6)
++ mvOsOutput(" redundant Row Addressing: Yes \n");
++ else
++ mvOsOutput(" redundant Row Addressing: No \n");
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR1)
++ {
++ if (dimmInfo.dimmAttributes & BIT0)
++ mvOsOutput(" Buffered Addr/Control Input: Yes\n");
++ else
++ mvOsOutput(" Buffered Addr/Control Input: No\n");
++
++ if (dimmInfo.dimmAttributes & BIT1)
++ mvOsOutput(" Registered Addr/Control Input: Yes\n");
++ else
++ mvOsOutput(" Registered Addr/Control Input: No\n");
++
++ if (dimmInfo.dimmAttributes & BIT2)
++ mvOsOutput(" On-Card PLL (clock): Yes \n");
++ else
++ mvOsOutput(" On-Card PLL (clock): No \n");
++
++ if (dimmInfo.dimmAttributes & BIT3)
++ mvOsOutput(" FET Switch On-Card Enabled: Yes \n");
++ else
++ mvOsOutput(" FET Switch On-Card Enabled: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT4)
++ mvOsOutput(" FET Switch External Enabled: Yes \n");
++ else
++ mvOsOutput(" FET Switch External Enabled: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT5)
++ mvOsOutput(" Differential Clock Input: Yes \n");
++ else
++ mvOsOutput(" Differential Clock Input: No \n");
++ }
++ else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */
++ {
++ mvOsOutput(" Number of Active Registers on the DIMM: %d\n",
++ (dimmInfo.dimmAttributes & 0x3) + 1);
++
++ mvOsOutput(" Number of PLLs on the DIMM: %d\n",
++ ((dimmInfo.dimmAttributes) >> 2) & 0x3);
++
++ if (dimmInfo.dimmAttributes & BIT4)
++ mvOsOutput(" FET Switch External Enabled: Yes \n");
++ else
++ mvOsOutput(" FET Switch External Enabled: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT6)
++ mvOsOutput(" Analysis probe installed: Yes \n");
++ else
++ mvOsOutput(" Analysis probe installed: No \n");
++ }
++
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 22: /* Suported AutoPreCharge */
++ mvOsOutput("\nModul Attributes (SPD Byte 22): \n");
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ if ( spdRawData[i] & BIT0 )
++ mvOsOutput(" Early Ras Precharge: Yes \n");
++ else
++ mvOsOutput(" Early Ras Precharge: No \n");
++
++ if ( spdRawData[i] & BIT1 )
++ mvOsOutput(" AutoPreCharge: Yes \n");
++ else
++ mvOsOutput(" AutoPreCharge: No \n");
++
++ if ( spdRawData[i] & BIT2 )
++ mvOsOutput(" Precharge All: Yes \n");
++ else
++ mvOsOutput(" Precharge All: No \n");
++
++ if ( spdRawData[i] & BIT3 )
++ mvOsOutput(" Write 1/ReadBurst: Yes \n");
++ else
++ mvOsOutput(" Write 1/ReadBurst: No \n");
++
++ if ( spdRawData[i] & BIT4 )
++ mvOsOutput(" lower VCC tolerance: 5%%\n");
++ else
++ mvOsOutput(" lower VCC tolerance: 10%%\n");
++
++ if ( spdRawData[i] & BIT5 )
++ mvOsOutput(" upper VCC tolerance: 5%%\n");
++ else
++ mvOsOutput(" upper VCC tolerance: 10%%\n");
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR1)
++ {
++ if ( spdRawData[i] & BIT0 )
++ mvOsOutput(" Supports Weak Driver: Yes \n");
++ else
++ mvOsOutput(" Supports Weak Driver: No \n");
++
++ if ( !(spdRawData[i] & BIT4) )
++ mvOsOutput(" lower VCC tolerance: 0.2V\n");
++
++ if ( !(spdRawData[i] & BIT5) )
++ mvOsOutput(" upper VCC tolerance: 0.2V\n");
++
++ if ( spdRawData[i] & BIT6 )
++ mvOsOutput(" Concurrent Auto Preharge: Yes \n");
++ else
++ mvOsOutput(" Concurrent Auto Preharge: No \n");
++
++ if ( spdRawData[i] & BIT7 )
++ mvOsOutput(" Supports Fast AP: Yes \n");
++ else
++ mvOsOutput(" Supports Fast AP: No \n");
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR2)
++ {
++ if ( spdRawData[i] & BIT0 )
++ mvOsOutput(" Supports Weak Driver: Yes \n");
++ else
++ mvOsOutput(" Supports Weak Driver: No \n");
++ }
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 23:
++ /* Minimum Cycle Time At Maximum Cas Latancy Minus 1 (2nd highest CL) */
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ rightOfPoint = (spdRawData[i] & 0x0f) * 10;
++
++ /* DDR2 addition of right of point */
++ if ((spdRawData[i] & 0x0f) == 0xA)
++ {
++ rightOfPoint = 25;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xB)
++ {
++ rightOfPoint = 33;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xC)
++ {
++ rightOfPoint = 66;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xD)
++ {
++ rightOfPoint = 75;
++ }
++
++ mvOsOutput("Minimum Cycle Time At 2nd highest CasLatancy"
++ "(0 = Not supported): %d.%d [ns]\n",
++ leftOfPoint, rightOfPoint );
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 24: /* Clock To Data Out 2nd highest Cas Latency Value*/
++ div = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 10:100;
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / div;
++ rightOfPoint = time_tmp % div;
++ mvOsOutput("Clock To Data Out (2nd CL value): %d.%d [ns]\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 25:
++ /* Minimum Cycle Time At Maximum Cas Latancy Minus 2 (3rd highest CL) */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ leftOfPoint = (spdRawData[i] & 0xfc) >> 2;
++ rightOfPoint = (spdRawData[i] & 0x3) * 25;
++ }
++ else /* DDR1 or DDR2 */
++ {
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ rightOfPoint = (spdRawData[i] & 0x0f) * 10;
++
++ /* DDR2 addition of right of point */
++ if ((spdRawData[i] & 0x0f) == 0xA)
++ {
++ rightOfPoint = 25;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xB)
++ {
++ rightOfPoint = 33;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xC)
++ {
++ rightOfPoint = 66;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xD)
++ {
++ rightOfPoint = 75;
++ }
++ }
++ mvOsOutput("Minimum Cycle Time At 3rd highest CasLatancy"
++ "(0 = Not supported): %d.%d [ns]\n",
++ leftOfPoint, rightOfPoint );
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 26: /* Clock To Data Out 3rd highest Cas Latency Value*/
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ leftOfPoint = (spdRawData[i] & 0xfc) >> 2;
++ rightOfPoint = (spdRawData[i] & 0x3) * 25;
++ }
++ else /* DDR1 or DDR2 */
++ {
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = 0;
++ rightOfPoint = time_tmp;
++ }
++ mvOsOutput("Clock To Data Out (3rd CL value): %d.%2d[ns]\n",
++ leftOfPoint, rightOfPoint );
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 27: /* Minimum Row Precharge Time */
++ shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2;
++ maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0xff : 0xfc;
++ maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0x00 : 0x03;
++ leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift);
++ rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25;
++ temp = ((leftOfPoint*100) + rightOfPoint);/* in 10ps Intervals*/
++ trp_clocks = (temp + (busClkPs-1)) / busClkPs;
++ mvOsOutput("Minimum Row Precharge Time [ns]: %d.%d = "
++ "in Clk cycles %d\n",
++ leftOfPoint, rightOfPoint, trp_clocks);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 28: /* Minimum Row Active to Row Active Time */
++ shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2;
++ maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0xff : 0xfc;
++ maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0x00 : 0x03;
++ leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift);
++ rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25;
++ temp = ((leftOfPoint*100) + rightOfPoint);/* in 100ns Interval*/
++ trrd_clocks = (temp + (busClkPs-1)) / busClkPs;
++ mvOsOutput("Minimum Row Active -To- Row Active Delay [ns]: "
++ "%d.%d = in Clk cycles %d\n",
++ leftOfPoint, rightOfPoint, trp_clocks);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 29: /* Minimum Ras-To-Cas Delay */
++ shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2;
++ maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0xff : 0xfc;
++ maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0x00 : 0x03;
++ leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift);
++ rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25;
++ temp = ((leftOfPoint*100) + rightOfPoint);/* in 100ns Interval*/
++ trcd_clocks = (temp + (busClkPs-1) )/ busClkPs;
++ mvOsOutput("Minimum Ras-To-Cas Delay [ns]: %d.%d = "
++ "in Clk cycles %d\n",
++ leftOfPoint, rightOfPoint, trp_clocks);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 30: /* Minimum Ras Pulse Width */
++ tras_clocks = (cas2ps(spdRawData[i])+(busClkPs-1)) / busClkPs;
++ mvOsOutput("Minimum Ras Pulse Width [ns]: %d = "
++ "in Clk cycles %d\n", spdRawData[i], tras_clocks);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 31: /* Module Bank Density */
++ mvOsOutput("Module Bank Density (more than 1= Multisize-Module):");
++
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ if (dimmInfo.dimmBankDensity & BIT0)
++ mvOsOutput("1GB, ");
++ if (dimmInfo.dimmBankDensity & BIT1)
++ mvOsOutput("8MB, ");
++ if (dimmInfo.dimmBankDensity & BIT2)
++ mvOsOutput("16MB, ");
++ if (dimmInfo.dimmBankDensity & BIT3)
++ mvOsOutput("32MB, ");
++ if (dimmInfo.dimmBankDensity & BIT4)
++ mvOsOutput("64MB, ");
++ if (dimmInfo.dimmBankDensity & BIT5)
++ mvOsOutput("128MB, ");
++ if (dimmInfo.dimmBankDensity & BIT6)
++ mvOsOutput("256MB, ");
++ if (dimmInfo.dimmBankDensity & BIT7)
++ mvOsOutput("512MB, ");
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR1)
++ {
++ if (dimmInfo.dimmBankDensity & BIT0)
++ mvOsOutput("1GB, ");
++ if (dimmInfo.dimmBankDensity & BIT1)
++ mvOsOutput("2GB, ");
++ if (dimmInfo.dimmBankDensity & BIT2)
++ mvOsOutput("16MB, ");
++ if (dimmInfo.dimmBankDensity & BIT3)
++ mvOsOutput("32MB, ");
++ if (dimmInfo.dimmBankDensity & BIT4)
++ mvOsOutput("64MB, ");
++ if (dimmInfo.dimmBankDensity & BIT5)
++ mvOsOutput("128MB, ");
++ if (dimmInfo.dimmBankDensity & BIT6)
++ mvOsOutput("256MB, ");
++ if (dimmInfo.dimmBankDensity & BIT7)
++ mvOsOutput("512MB, ");
++ }
++ else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */
++ {
++ if (dimmInfo.dimmBankDensity & BIT0)
++ mvOsOutput("1GB, ");
++ if (dimmInfo.dimmBankDensity & BIT1)
++ mvOsOutput("2GB, ");
++ if (dimmInfo.dimmBankDensity & BIT2)
++ mvOsOutput("4GB, ");
++ if (dimmInfo.dimmBankDensity & BIT3)
++ mvOsOutput("8GB, ");
++ if (dimmInfo.dimmBankDensity & BIT4)
++ mvOsOutput("16GB, ");
++ if (dimmInfo.dimmBankDensity & BIT5)
++ mvOsOutput("128MB, ");
++ if (dimmInfo.dimmBankDensity & BIT6)
++ mvOsOutput("256MB, ");
++ if (dimmInfo.dimmBankDensity & BIT7)
++ mvOsOutput("512MB, ");
++ }
++ mvOsOutput("\n");
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 32: /* Address And Command Setup Time (measured in ns/1000) */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ rightOfPoint = (spdRawData[i] & 0x0f);
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ if(leftOfPoint > 7)
++ {
++ leftOfPoint *= -1;
++ }
++ }
++ else /* DDR1 or DDR2 */
++ {
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / 100;
++ rightOfPoint = time_tmp % 100;
++ }
++ mvOsOutput("Address And Command Setup Time [ns]: %d.%d\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 33: /* Address And Command Hold Time */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ rightOfPoint = (spdRawData[i] & 0x0f);
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ if(leftOfPoint > 7)
++ {
++ leftOfPoint *= -1;
++ }
++ }
++ else /* DDR1 or DDR2 */
++ {
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / 100;
++ rightOfPoint = time_tmp % 100;
++ }
++ mvOsOutput("Address And Command Hold Time [ns]: %d.%d\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 34: /* Data Input Setup Time */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ rightOfPoint = (spdRawData[i] & 0x0f);
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ if(leftOfPoint > 7)
++ {
++ leftOfPoint *= -1;
++ }
++ }
++ else /* DDR1 or DDR2 */
++ {
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / 100;
++ rightOfPoint = time_tmp % 100;
++ }
++ mvOsOutput("Data Input Setup Time [ns]: %d.%d\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 35: /* Data Input Hold Time */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ rightOfPoint = (spdRawData[i] & 0x0f);
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ if(leftOfPoint > 7)
++ {
++ leftOfPoint *= -1;
++ }
++ }
++ else /* DDR1 or DDR2 */
++ {
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / 100;
++ rightOfPoint = time_tmp % 100;
++ }
++ mvOsOutput("Data Input Hold Time [ns]: %d.%d\n\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 36: /* Relevant for DDR2 only: Write Recovery Time */
++ leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> 2);
++ rightOfPoint = (spdRawData[i] & maskRightOfPoint) * 25;
++ mvOsOutput("Write Recovery Time [ns]: %d.%d\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++ }
++
++}
++
++
++/*
++ * translate ns.ns/10 coding of SPD timing values
++ * into ps unit values
++ */
++/*******************************************************************************
++* cas2ps - Translate x.y ns parameter to pico-seconds values
++*
++* DESCRIPTION:
++* This function translates x.y nano seconds to its value in pico seconds.
++* For example 3.75ns will return 3750.
++*
++* INPUT:
++* spd_byte - DIMM SPD byte.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* value in pico seconds.
++*
++*******************************************************************************/
++static MV_U32 cas2ps(MV_U8 spd_byte)
++{
++ MV_U32 ns, ns10;
++
++ /* isolate upper nibble */
++ ns = (spd_byte >> 4) & 0x0F;
++ /* isolate lower nibble */
++ ns10 = (spd_byte & 0x0F);
++
++ if( ns10 < 10 ) {
++ ns10 *= 10;
++ }
++ else if( ns10 == 10 )
++ ns10 = 25;
++ else if( ns10 == 11 )
++ ns10 = 33;
++ else if( ns10 == 12 )
++ ns10 = 66;
++ else if( ns10 == 13 )
++ ns10 = 75;
++ else
++ {
++ mvOsOutput("cas2ps Err. unsupported cycle time.\n");
++ }
++
++ return (ns*1000 + ns10*10);
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.h 2010-11-09 20:28:10.622495522 +0100
+@@ -0,0 +1,191 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDram
++#define __INCmvDram
++
++#include "ddr1_2/mvDramIf.h"
++#include "twsi/mvTwsi.h"
++
++#define MAX_DIMM_NUM 2
++#define SPD_SIZE 128
++
++/* Dimm spd offsets */
++#define DIMM_MEM_TYPE 2
++#define DIMM_ROW_NUM 3
++#define DIMM_COL_NUM 4
++#define DIMM_MODULE_BANK_NUM 5
++#define DIMM_DATA_WIDTH 6
++#define DIMM_VOLT_IF 8
++#define DIMM_MIN_CC_AT_MAX_CAS 9
++#define DIMM_ERR_CHECK_TYPE 11
++#define DIMM_REFRESH_INTERVAL 12
++#define DIMM_SDRAM_WIDTH 13
++#define DIMM_ERR_CHECK_DATA_WIDTH 14
++#define DIMM_MIN_CLK_DEL 15
++#define DIMM_BURST_LEN_SUP 16
++#define DIMM_DEV_BANK_NUM 17
++#define DIMM_SUP_CAL 18
++#define DIMM_DDR2_TYPE_INFORMATION 20 /* DDR2 only */
++#define DIMM_BUF_ADDR_CONT_IN 21
++#define DIMM_MIN_CC_AT_MAX_CAS_MINUS1 23
++#define DIMM_MIN_CC_AT_MAX_CAS_MINUS2 25
++#define DIMM_MIN_ROW_PRECHARGE_TIME 27
++#define DIMM_MIN_ROW_ACTIVE_TO_ROW_ACTIVE 28
++#define DIMM_MIN_RAS_TO_CAS_DELAY 29
++#define DIMM_MIN_RAS_PULSE_WIDTH 30
++#define DIMM_BANK_DENSITY 31
++#define DIMM_MIN_WRITE_RECOVERY_TIME 36
++#define DIMM_MIN_WRITE_TO_READ_CMD_DELAY 37
++#define DIMM_MIN_READ_TO_PRECH_CMD_DELAY 38
++#define DIMM_MIN_REFRESH_TO_ACTIVATE_CMD 42
++
++/* Dimm Memory Type values */
++#define DIMM_MEM_TYPE_SDRAM 0x4
++#define DIMM_MEM_TYPE_DDR1 0x7
++#define DIMM_MEM_TYPE_DDR2 0x8
++
++#define DIMM_MODULE_MANU_OFFS 64
++#define DIMM_MODULE_MANU_SIZE 8
++#define DIMM_MODULE_VEN_OFFS 73
++#define DIMM_MODULE_VEN_SIZE 25
++#define DIMM_MODULE_ID_OFFS 99
++#define DIMM_MODULE_ID_SIZE 18
++
++/* enumeration for voltage levels. */
++typedef enum _mvDimmVoltageIf
++{
++ TTL_5V_TOLERANT,
++ LVTTL,
++ HSTL_1_5V,
++ SSTL_3_3V,
++ SSTL_2_5V,
++ VOLTAGE_UNKNOWN,
++} MV_DIMM_VOLTAGE_IF;
++
++
++/* enumaration for SDRAM CAS Latencies. */
++typedef enum _mvDimmSdramCas
++{
++ SD_CL_1 =1,
++ SD_CL_2,
++ SD_CL_3,
++ SD_CL_4,
++ SD_CL_5,
++ SD_CL_6,
++ SD_CL_7,
++ SD_FAULT
++}MV_DIMM_SDRAM_CAS;
++
++
++/* DIMM information structure */
++typedef struct _mvDimmInfo
++{
++ MV_MEMORY_TYPE memoryType; /* DDR or SDRAM */
++
++ MV_U8 spdRawData[SPD_SIZE]; /* Content of SPD-EEPROM copied 1:1 */
++
++ /* DIMM dimensions */
++ MV_U32 numOfRowAddr;
++ MV_U32 numOfColAddr;
++ MV_U32 numOfModuleBanks;
++ MV_U32 dataWidth;
++ MV_U32 errorCheckType; /* ECC , PARITY..*/
++ MV_U32 sdramWidth; /* 4,8,16 or 32 */
++ MV_U32 errorCheckDataWidth; /* 0 - no, 1 - Yes */
++ MV_U32 burstLengthSupported;
++ MV_U32 numOfBanksOnEachDevice;
++ MV_U32 suportedCasLatencies;
++ MV_U32 refreshInterval;
++ MV_U32 dimmBankDensity;
++ MV_U32 dimmTypeInfo; /* DDR2 only */
++ MV_U32 dimmAttributes;
++
++ /* DIMM timing parameters */
++ MV_U32 minCycleTimeAtMaxCasLatPs;
++ MV_U32 minCycleTimeAtMaxCasLatMinus1Ps;
++ MV_U32 minCycleTimeAtMaxCasLatMinus2Ps;
++ MV_U32 minRowPrechargeTime;
++ MV_U32 minRowActiveToRowActive;
++ MV_U32 minRasToCasDelay;
++ MV_U32 minRasPulseWidth;
++ MV_U32 minWriteRecoveryTime; /* DDR2 only */
++ MV_U32 minWriteToReadCmdDelay; /* DDR2 only */
++ MV_U32 minReadToPrechCmdDelay; /* DDR2 only */
++ MV_U32 minRefreshToActiveCmd; /* DDR2 only */
++
++ /* Parameters calculated from the extracted DIMM information */
++ MV_U32 size; /* 16,64,128,256 or 512 MByte in MB units */
++ MV_U32 deviceDensity; /* 16,64,128,256 or 512 Mbit in MB units */
++ MV_U32 numberOfDevices;
++
++} MV_DIMM_INFO;
++
++
++MV_STATUS mvDramBankInfoGet(MV_U32 bankNum, MV_DRAM_BANK_INFO *pBankInfo);
++MV_STATUS dimmSpdGet(MV_U32 dimmNum, MV_DIMM_INFO *pDimmInfo);
++MV_VOID dimmSpdPrint(MV_U32 dimmNum);
++MV_STATUS dimmSpdCpy(MV_VOID);
++
++#endif /* __INCmvDram */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.c 2010-11-09 20:28:10.662495471 +0100
+@@ -0,0 +1,1599 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++
++/* includes */
++#include "ddr1_2/mvDramIf.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++
++
++
++#ifdef MV_DEBUG
++#define DB(x) x
++#else
++#define DB(x)
++#endif
++
++/* DRAM bank presence encoding */
++#define BANK_PRESENT_CS0 0x1
++#define BANK_PRESENT_CS0_CS1 0x3
++#define BANK_PRESENT_CS0_CS2 0x5
++#define BANK_PRESENT_CS0_CS1_CS2 0x7
++#define BANK_PRESENT_CS0_CS2_CS3 0xd
++#define BANK_PRESENT_CS0_CS2_CS3_CS4 0xf
++
++/* locals */
++static MV_BOOL sdramIfWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin);
++#if defined(MV_INC_BOARD_DDIM)
++static void sdramDDr2OdtConfig(MV_DRAM_BANK_INFO *pBankInfo);
++static MV_U32 dunitCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 minCas);
++static MV_U32 sdramModeRegCalc(MV_U32 minCas);
++static MV_U32 sdramExtModeRegCalc(MV_DRAM_BANK_INFO *pBankInfo);
++static MV_U32 sdramAddrCtrlRegCalc(MV_DRAM_BANK_INFO *pBankInfo);
++static MV_U32 sdramConfigRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk);
++static MV_U32 minCasCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk,
++ MV_U32 forcedCl);
++static MV_U32 sdramTimeCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo,
++ MV_U32 minCas, MV_U32 busClk);
++static MV_U32 sdramTimeCtrlHighRegCalc(MV_DRAM_BANK_INFO *pBankInfo,
++ MV_U32 busClk);
++
++/*******************************************************************************
++* mvDramIfDetect - Prepare DRAM interface configuration values.
++*
++* DESCRIPTION:
++* This function implements the full DRAM detection and timing
++* configuration for best system performance.
++* Since this routine runs from a ROM device (Boot Flash), its stack
++* resides on RAM, that might be the system DRAM. Changing DRAM
++* configuration values while keeping vital data in DRAM is risky. That
++* is why the function does not preform the configuration setting but
++* prepare those in predefined 32bit registers (in this case IDMA
++* registers are used) for other routine to perform the settings.
++* The function will call for board DRAM SPD information for each DRAM
++* chip select. The function will then analyze those SPD parameters of
++* all DRAM banks in order to decide on DRAM configuration compatible
++* for all DRAM banks.
++* The function will set the CPU DRAM address decode registers.
++* Note: This routine prepares values that will overide configuration of
++* mvDramBasicAsmInit().
++*
++* INPUT:
++* forcedCl - Forced CAL Latency. If equal to zero, do not force.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvDramIfDetect(MV_U32 forcedCl)
++{
++ MV_U32 retVal = MV_OK; /* return value */
++ MV_DRAM_BANK_INFO bankInfo[MV_DRAM_MAX_CS];
++ MV_U32 busClk, size, base = 0, i, temp, deviceW, dimmW;
++ MV_U8 minCas;
++ MV_DRAM_DEC_WIN dramDecWin;
++
++ dramDecWin.addrWin.baseHigh = 0;
++
++ busClk = mvBoardSysClkGet();
++
++ if (0 == busClk)
++ {
++ mvOsPrintf("Dram: ERR. Can't detect system clock! \n");
++ return MV_ERROR;
++ }
++
++ /* Close DRAM banks except bank 0 (in case code is excecuting from it...) */
++#if defined(MV_INCLUDE_SDRAM_CS1)
++ for(i= SDRAM_CS1; i < MV_DRAM_MAX_CS; i++)
++ mvCpuIfTargetWinEnable(i, MV_FALSE);
++#endif
++
++ /* we will use bank 0 as the representative of the all the DRAM banks, */
++ /* since bank 0 must exist. */
++ for(i = 0; i < MV_DRAM_MAX_CS; i++)
++ {
++ /* if Bank exist */
++ if(MV_OK == mvDramBankInfoGet(i, &bankInfo[i]))
++ {
++ /* check it isn't SDRAM */
++ if(bankInfo[i].memoryType == MEM_TYPE_SDRAM)
++ {
++ mvOsPrintf("Dram: ERR. SDRAM type not supported !!!\n");
++ return MV_ERROR;
++ }
++ /* All banks must support registry in order to activate it */
++ if(bankInfo[i].registeredAddrAndControlInputs !=
++ bankInfo[0].registeredAddrAndControlInputs)
++ {
++ mvOsPrintf("Dram: ERR. different Registered settings !!!\n");
++ return MV_ERROR;
++ }
++
++ /* Init the CPU window decode */
++ /* Note that the size in Bank info is in MB units */
++ /* Note that the Dimm width might be different then the device DRAM width */
++ temp = MV_REG_READ(SDRAM_CONFIG_REG);
++
++ deviceW = ((temp & SDRAM_DWIDTH_MASK) == SDRAM_DWIDTH_16BIT )? 16 : 32;
++ dimmW = bankInfo[0].dataWidth - (bankInfo[0].dataWidth % 16);
++ size = ((bankInfo[i].size << 20) / (dimmW/deviceW));
++
++ /* We can not change DRAM window settings while excecuting */
++ /* code from it. That is why we skip the DRAM CS[0], saving */
++ /* it to the ROM configuration routine */
++ if(i == SDRAM_CS0)
++ {
++ MV_U32 sizeToReg;
++
++ /* Translate the given window size to register format */
++ sizeToReg = ctrlSizeToReg(size, SCSR_SIZE_ALIGNMENT);
++
++ /* Size parameter validity check. */
++ if (-1 == sizeToReg)
++ {
++ mvOsPrintf("mvCtrlAddrDecToReg: ERR. Win %d size invalid.\n"
++ ,i);
++ return MV_BAD_PARAM;
++ }
++
++ /* Size is located at upper 16 bits */
++ sizeToReg <<= SCSR_SIZE_OFFS;
++
++ /* enable it */
++ sizeToReg |= SCSR_WIN_EN;
++
++ MV_REG_WRITE(DRAM_BUF_REG0, sizeToReg);
++ }
++ else
++ {
++ dramDecWin.addrWin.baseLow = base;
++ dramDecWin.addrWin.size = size;
++ dramDecWin.enable = MV_TRUE;
++
++ if (MV_OK != mvDramIfWinSet(SDRAM_CS0 + i, &dramDecWin))
++ {
++ mvOsPrintf("Dram: ERR. Fail to set bank %d!!!\n",
++ SDRAM_CS0 + i);
++ return MV_ERROR;
++ }
++ }
++
++ base += size;
++
++ /* update the suportedCasLatencies mask */
++ bankInfo[0].suportedCasLatencies &= bankInfo[i].suportedCasLatencies;
++
++ }
++ else
++ {
++ if( i == 0 ) /* bank 0 doesn't exist */
++ {
++ mvOsPrintf("Dram: ERR. Fail to detect bank 0 !!!\n");
++ return MV_ERROR;
++ }
++ else
++ {
++ DB(mvOsPrintf("Dram: Could not find bank %d\n", i));
++ bankInfo[i].size = 0; /* Mark this bank as non exist */
++ }
++ }
++ }
++
++ /* calculate minimum CAS */
++ minCas = minCasCalc(&bankInfo[0], busClk, forcedCl);
++ if (0 == minCas)
++ {
++ mvOsOutput("Dram: Warn: Could not find CAS compatible to SysClk %dMhz\n",
++ (busClk / 1000000));
++
++ if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2)
++ {
++ minCas = DDR2_CL_4; /* Continue with this CAS */
++ mvOsPrintf("Set default CAS latency 4\n");
++ }
++ else
++ {
++ minCas = DDR1_CL_3; /* Continue with this CAS */
++ mvOsPrintf("Set default CAS latency 3\n");
++ }
++ }
++
++ /* calc SDRAM_CONFIG_REG and save it to temp register */
++ temp = sdramConfigRegCalc(&bankInfo[0], busClk);
++ if(-1 == temp)
++ {
++ mvOsPrintf("Dram: ERR. sdramConfigRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ MV_REG_WRITE(DRAM_BUF_REG1, temp);
++
++ /* calc SDRAM_MODE_REG and save it to temp register */
++ temp = sdramModeRegCalc(minCas);
++ if(-1 == temp)
++ {
++ mvOsPrintf("Dram: ERR. sdramModeRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ MV_REG_WRITE(DRAM_BUF_REG2, temp);
++
++ /* calc SDRAM_EXTENDED_MODE_REG and save it to temp register */
++ temp = sdramExtModeRegCalc(&bankInfo[0]);
++ if(-1 == temp)
++ {
++ mvOsPrintf("Dram: ERR. sdramModeRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ MV_REG_WRITE(DRAM_BUF_REG10, temp);
++
++ /* calc D_UNIT_CONTROL_LOW and save it to temp register */
++ temp = dunitCtrlLowRegCalc(&bankInfo[0], minCas);
++ if(-1 == temp)
++ {
++ mvOsPrintf("Dram: ERR. dunitCtrlLowRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ MV_REG_WRITE(DRAM_BUF_REG3, temp);
++
++ /* calc SDRAM_ADDR_CTRL_REG and save it to temp register */
++ temp = sdramAddrCtrlRegCalc(&bankInfo[0]);
++ if(-1 == temp)
++ {
++ mvOsPrintf("Dram: ERR. sdramAddrCtrlRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ MV_REG_WRITE(DRAM_BUF_REG4, temp);
++
++ /* calc SDRAM_TIMING_CTRL_LOW_REG and save it to temp register */
++ temp = sdramTimeCtrlLowRegCalc(&bankInfo[0], minCas, busClk);
++ if(-1 == temp)
++ {
++ mvOsPrintf("Dram: ERR. sdramTimeCtrlLowRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ MV_REG_WRITE(DRAM_BUF_REG5, temp);
++
++ /* calc SDRAM_TIMING_CTRL_HIGH_REG and save it to temp register */
++ temp = sdramTimeCtrlHighRegCalc(&bankInfo[0], busClk);
++ if(-1 == temp)
++ {
++ mvOsPrintf("Dram: ERR. sdramTimeCtrlHighRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ MV_REG_WRITE(DRAM_BUF_REG6, temp);
++
++ /* Config DDR2 On Die Termination (ODT) registers */
++ if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2)
++ {
++ sdramDDr2OdtConfig(bankInfo);
++ }
++
++ /* Note that DDR SDRAM Address/Control and Data pad calibration */
++ /* settings is done in mvSdramIfConfig.s */
++
++ return retVal;
++}
++
++/*******************************************************************************
++* minCasCalc - Calculate the Minimum CAS latency which can be used.
++*
++* DESCRIPTION:
++* Calculate the minimum CAS latency that can be used, base on the DRAM
++* parameters and the SDRAM bus Clock freq.
++*
++* INPUT:
++* busClk - the DRAM bus Clock.
++* pBankInfo - bank info parameters.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* The minimum CAS Latency. The function returns 0 if max CAS latency
++* supported by banks is incompatible with system bus clock frequancy.
++*
++*******************************************************************************/
++static MV_U32 minCasCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk,
++ MV_U32 forcedCl)
++{
++ MV_U32 count = 1, j;
++ MV_U32 busClkPs = 1000000000 / (busClk / 1000); /* in ps units */
++ MV_U32 startBit, stopBit;
++
++ /* DDR 1:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 *
++ *********************************************************/
++
++ /* DDR 2:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD *
++ *********************************************************/
++
++
++ /* If we are asked to use the forced CAL */
++ if (forcedCl)
++ {
++ mvOsPrintf("DRAM: Using forced CL %d.%d\n", (forcedCl / 10),
++ (forcedCl % 10));
++
++ if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2)
++ {
++ if (forcedCl == 30)
++ pBankInfo->suportedCasLatencies = 0x08;
++ else if (forcedCl == 40)
++ pBankInfo->suportedCasLatencies = 0x10;
++ else
++ {
++ mvOsPrintf("Forced CL %d.%d not supported. Set default CL 4\n",
++ (forcedCl / 10), (forcedCl % 10));
++ pBankInfo->suportedCasLatencies = 0x10;
++ }
++ }
++ else
++ {
++ if (forcedCl == 15)
++ pBankInfo->suportedCasLatencies = 0x02;
++ else if (forcedCl == 20)
++ pBankInfo->suportedCasLatencies = 0x04;
++ else if (forcedCl == 25)
++ pBankInfo->suportedCasLatencies = 0x08;
++ else if (forcedCl == 30)
++ pBankInfo->suportedCasLatencies = 0x10;
++ else if (forcedCl == 40)
++ pBankInfo->suportedCasLatencies = 0x40;
++ else
++ {
++ mvOsPrintf("Forced CL %d.%d not supported. Set default CL 3\n",
++ (forcedCl / 10), (forcedCl % 10));
++ pBankInfo->suportedCasLatencies = 0x10;
++ }
++ }
++
++ return pBankInfo->suportedCasLatencies;
++ }
++
++ /* go over the supported cas mask from Max Cas down and check if the */
++ /* SysClk stands in its time requirments. */
++
++
++ DB(mvOsPrintf("Dram: minCasCalc supported mask = %x busClkPs = %x \n",
++ pBankInfo->suportedCasLatencies,busClkPs ));
++ for(j = 7; j > 0; j--)
++ {
++ if((pBankInfo->suportedCasLatencies >> j) & BIT0 )
++ {
++ /* Reset the bits for CL incompatible for the sysClk */
++ switch (count)
++ {
++ case 1:
++ if (pBankInfo->minCycleTimeAtMaxCasLatPs > busClkPs)
++ pBankInfo->suportedCasLatencies &= ~(BIT0 << j);
++ count++;
++ break;
++ case 2:
++ if (pBankInfo->minCycleTimeAtMaxCasLatMinus1Ps > busClkPs)
++ pBankInfo->suportedCasLatencies &= ~(BIT0 << j);
++ count++;
++ break;
++ case 3:
++ if (pBankInfo->minCycleTimeAtMaxCasLatMinus2Ps > busClkPs)
++ pBankInfo->suportedCasLatencies &= ~(BIT0 << j);
++ count++;
++ break;
++ default:
++ pBankInfo->suportedCasLatencies &= ~(BIT0 << j);
++ break;
++ }
++ }
++ }
++
++ DB(mvOsPrintf("Dram: minCasCalc support = %x (after SysCC calc)\n",
++ pBankInfo->suportedCasLatencies ));
++
++ /* SDRAM DDR1 controller supports CL 1.5 to 3.5 */
++ /* SDRAM DDR2 controller supports CL 3 to 5 */
++ if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2)
++ {
++ startBit = 3; /* DDR2 support CL start with CL3 (bit 3) */
++ stopBit = 5; /* DDR2 support CL stops with CL5 (bit 5) */
++ }
++ else
++ {
++ startBit = 1; /* DDR1 support CL start with CL1.5 (bit 3) */
++ stopBit = 4; /* DDR1 support CL stops with CL3 (bit 4) */
++ }
++
++ for(j = startBit; j <= stopBit ; j++)
++ {
++ if((pBankInfo->suportedCasLatencies >> j) & BIT0 )
++ {
++ DB(mvOsPrintf("Dram: minCasCalc choose CAS %x \n",(BIT0 << j)));
++ return (BIT0 << j);
++ }
++ }
++
++ return 0;
++}
++
++/*******************************************************************************
++* sdramConfigRegCalc - Calculate sdram config register
++*
++* DESCRIPTION: Calculate sdram config register optimized value based
++* on the bank info parameters.
++*
++* INPUT:
++* pBankInfo - sdram bank parameters
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram config reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramConfigRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk)
++{
++ MV_U32 sdramConfig = 0;
++ MV_U32 refreshPeriod;
++
++ busClk /= 1000000; /* we work with busClk in MHz */
++
++ sdramConfig = MV_REG_READ(SDRAM_CONFIG_REG);
++
++ /* figure out the memory refresh internal */
++ switch (pBankInfo->refreshInterval & 0xf)
++ {
++ case 0x0: /* refresh period is 15.625 usec */
++ refreshPeriod = 15625;
++ break;
++ case 0x1: /* refresh period is 3.9 usec */
++ refreshPeriod = 3900;
++ break;
++ case 0x2: /* refresh period is 7.8 usec */
++ refreshPeriod = 7800;
++ break;
++ case 0x3: /* refresh period is 31.3 usec */
++ refreshPeriod = 31300;
++ break;
++ case 0x4: /* refresh period is 62.5 usec */
++ refreshPeriod = 62500;
++ break;
++ case 0x5: /* refresh period is 125 usec */
++ refreshPeriod = 125000;
++ break;
++ default: /* refresh period undefined */
++ mvOsPrintf("Dram: ERR. DRAM refresh period is unknown!\n");
++ return -1;
++ }
++
++ /* Now the refreshPeriod is in register format value */
++ refreshPeriod = (busClk * refreshPeriod) / 1000;
++
++ DB(mvOsPrintf("Dram: sdramConfigRegCalc calculated refresh interval %0x\n",
++ refreshPeriod));
++
++ /* make sure the refresh value is only 14 bits */
++ if(refreshPeriod > SDRAM_REFRESH_MAX)
++ {
++ refreshPeriod = SDRAM_REFRESH_MAX;
++ DB(mvOsPrintf("Dram: sdramConfigRegCalc adjusted refresh interval %0x\n",
++ refreshPeriod));
++ }
++
++ /* Clear the refresh field */
++ sdramConfig &= ~SDRAM_REFRESH_MASK;
++
++ /* Set new value to refresh field */
++ sdramConfig |= (refreshPeriod & SDRAM_REFRESH_MASK);
++
++ /* registered DRAM ? */
++ if ( pBankInfo->registeredAddrAndControlInputs )
++ {
++ /* it's registered DRAM, so set the reg. DRAM bit */
++ sdramConfig |= SDRAM_REGISTERED;
++ mvOsPrintf("DRAM Attribute: Registered address and control inputs.\n");
++ }
++
++ /* set DDR SDRAM devices configuration */
++ sdramConfig &= ~SDRAM_DCFG_MASK; /* Clear Dcfg field */
++
++ switch (pBankInfo->sdramWidth)
++ {
++ case 8: /* memory is x8 */
++ sdramConfig |= SDRAM_DCFG_X8_DEV;
++ DB(mvOsPrintf("Dram: sdramConfigRegCalc SDRAM device width x8\n"));
++ break;
++ case 16:
++ sdramConfig |= SDRAM_DCFG_X16_DEV;
++ DB(mvOsPrintf("Dram: sdramConfigRegCalc SDRAM device width x16\n"));
++ break;
++ default: /* memory width unsupported */
++ mvOsPrintf("Dram: ERR. DRAM chip width is unknown!\n");
++ return -1;
++ }
++
++ /* Set static default settings */
++ sdramConfig |= SDRAM_CONFIG_DV;
++
++ DB(mvOsPrintf("Dram: sdramConfigRegCalc set sdramConfig to 0x%x\n",
++ sdramConfig));
++
++ return sdramConfig;
++}
++
++/*******************************************************************************
++* sdramModeRegCalc - Calculate sdram mode register
++*
++* DESCRIPTION: Calculate sdram mode register optimized value based
++* on the bank info parameters and the minCas.
++*
++* INPUT:
++* minCas - minimum CAS supported.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram mode reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramModeRegCalc(MV_U32 minCas)
++{
++ MV_U32 sdramMode;
++
++ sdramMode = MV_REG_READ(SDRAM_MODE_REG);
++
++ /* Clear CAS Latency field */
++ sdramMode &= ~SDRAM_CL_MASK;
++
++ mvOsPrintf("DRAM CAS Latency ");
++
++ if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2)
++ {
++ switch (minCas)
++ {
++ case DDR2_CL_3:
++ sdramMode |= SDRAM_DDR2_CL_3;
++ mvOsPrintf("3.\n");
++ break;
++ case DDR2_CL_4:
++ sdramMode |= SDRAM_DDR2_CL_4;
++ mvOsPrintf("4.\n");
++ break;
++ case DDR2_CL_5:
++ sdramMode |= SDRAM_DDR2_CL_5;
++ mvOsPrintf("5.\n");
++ break;
++ default:
++ mvOsPrintf("\nsdramModeRegCalc ERROR: Max. CL out of range\n");
++ return -1;
++ }
++ sdramMode |= DDR2_MODE_REG_DV;
++ }
++ else /* DDR1 */
++ {
++ switch (minCas)
++ {
++ case DDR1_CL_1_5:
++ sdramMode |= SDRAM_DDR1_CL_1_5;
++ mvOsPrintf("1.5\n");
++ break;
++ case DDR1_CL_2:
++ sdramMode |= SDRAM_DDR1_CL_2;
++ mvOsPrintf("2\n");
++ break;
++ case DDR1_CL_2_5:
++ sdramMode |= SDRAM_DDR1_CL_2_5;
++ mvOsPrintf("2.5\n");
++ break;
++ case DDR1_CL_3:
++ sdramMode |= SDRAM_DDR1_CL_3;
++ mvOsPrintf("3\n");
++ break;
++ case DDR1_CL_4:
++ sdramMode |= SDRAM_DDR1_CL_4;
++ mvOsPrintf("4\n");
++ break;
++ default:
++ mvOsPrintf("\nsdramModeRegCalc ERROR: Max. CL out of range\n");
++ return -1;
++ }
++ sdramMode |= DDR1_MODE_REG_DV;
++ }
++
++ DB(mvOsPrintf("nsdramModeRegCalc register 0x%x\n", sdramMode ));
++
++ return sdramMode;
++}
++
++/*******************************************************************************
++* sdramExtModeRegCalc - Calculate sdram Extended mode register
++*
++* DESCRIPTION:
++* Return sdram Extended mode register value based
++* on the bank info parameters and bank presence.
++*
++* INPUT:
++* pBankInfo - sdram bank parameters
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram Extended mode reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramExtModeRegCalc(MV_DRAM_BANK_INFO *pBankInfo)
++{
++ MV_U32 populateBanks = 0;
++ int bankNum;
++ if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2)
++ {
++ /* Represent the populate banks in binary form */
++ for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ {
++ if (0 != pBankInfo[bankNum].size)
++ {
++ populateBanks |= (1 << bankNum);
++ }
++ }
++
++ switch(populateBanks)
++ {
++ case(BANK_PRESENT_CS0):
++ return DDR_SDRAM_EXT_MODE_CS0_DV;
++
++ case(BANK_PRESENT_CS0_CS1):
++ return DDR_SDRAM_EXT_MODE_CS0_DV;
++
++ case(BANK_PRESENT_CS0_CS2):
++ return DDR_SDRAM_EXT_MODE_CS0_CS2_DV;
++
++ case(BANK_PRESENT_CS0_CS1_CS2):
++ return DDR_SDRAM_EXT_MODE_CS0_CS2_DV;
++
++ case(BANK_PRESENT_CS0_CS2_CS3):
++ return DDR_SDRAM_EXT_MODE_CS0_CS2_DV;
++
++ case(BANK_PRESENT_CS0_CS2_CS3_CS4):
++ return DDR_SDRAM_EXT_MODE_CS0_CS2_DV;
++
++ default:
++ mvOsPrintf("sdramExtModeRegCalc: Invalid DRAM bank presence\n");
++ return -1;
++ }
++ }
++ return 0;
++}
++
++/*******************************************************************************
++* dunitCtrlLowRegCalc - Calculate sdram dunit control low register
++*
++* DESCRIPTION: Calculate sdram dunit control low register optimized value based
++* on the bank info parameters and the minCas.
++*
++* INPUT:
++* pBankInfo - sdram bank parameters
++* minCas - minimum CAS supported.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram dunit control low reg value.
++*
++*******************************************************************************/
++static MV_U32 dunitCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 minCas)
++{
++ MV_U32 dunitCtrlLow;
++
++ dunitCtrlLow = MV_REG_READ(SDRAM_DUNIT_CTRL_REG);
++
++ /* Clear StBurstDel field */
++ dunitCtrlLow &= ~SDRAM_ST_BURST_DEL_MASK;
++
++#ifdef MV_88W8660
++ /* Clear address/control output timing field */
++ dunitCtrlLow &= ~SDRAM_CTRL_POS_RISE;
++#endif /* MV_88W8660 */
++
++ DB(mvOsPrintf("Dram: dunitCtrlLowRegCalc\n"));
++
++ /* For proper sample of read data set the Dunit Control register's */
++ /* stBurstDel bits [27:24] */
++ /********-********-********-********-********-*********
++ * CL=1.5 | CL=2 | CL=2.5 | CL=3 | CL=4 | CL=5 *
++ *********-********-********-********-********-*********
++Not Reg. * 0011 | 0011 | 0100 | 0100 | 0101 | TBD *
++ *********-********-********-********-********-*********
++Registered * 0100 | 0100 | 0101 | 0101 | 0110 | TBD *
++ *********-********-********-********-********-*********/
++
++ if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2)
++ {
++ switch (minCas)
++ {
++ case DDR2_CL_3:
++ /* registerd DDR SDRAM? */
++ if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE)
++ dunitCtrlLow |= 0x5 << SDRAM_ST_BURST_DEL_OFFS;
++ else
++ dunitCtrlLow |= 0x4 << SDRAM_ST_BURST_DEL_OFFS;
++ break;
++ case DDR2_CL_4:
++ /* registerd DDR SDRAM? */
++ if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE)
++ dunitCtrlLow |= 0x6 << SDRAM_ST_BURST_DEL_OFFS;
++ else
++ dunitCtrlLow |= 0x5 << SDRAM_ST_BURST_DEL_OFFS;
++ break;
++ default:
++ mvOsPrintf("Dram: dunitCtrlLowRegCalc Max. CL out of range %d\n",
++ minCas);
++ return -1;
++ }
++ }
++ else /* DDR1 */
++ {
++ switch (minCas)
++ {
++ case DDR1_CL_1_5:
++ /* registerd DDR SDRAM? */
++ if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE)
++ dunitCtrlLow |= 0x4 << SDRAM_ST_BURST_DEL_OFFS;
++ else
++ dunitCtrlLow |= 0x3 << SDRAM_ST_BURST_DEL_OFFS;
++ break;
++ case DDR1_CL_2:
++ /* registerd DDR SDRAM? */
++ if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE)
++ dunitCtrlLow |= 0x4 << SDRAM_ST_BURST_DEL_OFFS;
++ else
++ dunitCtrlLow |= 0x3 << SDRAM_ST_BURST_DEL_OFFS;
++ break;
++ case DDR1_CL_2_5:
++ /* registerd DDR SDRAM? */
++ if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE)
++ dunitCtrlLow |= 0x5 << SDRAM_ST_BURST_DEL_OFFS;
++ else
++ dunitCtrlLow |= 0x4 << SDRAM_ST_BURST_DEL_OFFS;
++ break;
++ case DDR1_CL_3:
++ /* registerd DDR SDRAM? */
++ if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE)
++ dunitCtrlLow |= 0x5 << SDRAM_ST_BURST_DEL_OFFS;
++ else
++ dunitCtrlLow |= 0x4 << SDRAM_ST_BURST_DEL_OFFS;
++ break;
++ case DDR1_CL_4:
++ /* registerd DDR SDRAM? */
++ if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE)
++ dunitCtrlLow |= 0x6 << SDRAM_ST_BURST_DEL_OFFS;
++ else
++ dunitCtrlLow |= 0x5 << SDRAM_ST_BURST_DEL_OFFS;
++ break;
++ default:
++ mvOsPrintf("Dram: dunitCtrlLowRegCalc Max. CL out of range %d\n",
++ minCas);
++ return -1;
++ }
++
++ }
++ DB(mvOsPrintf("Dram: Reg dunit control low = %x\n", dunitCtrlLow ));
++
++ return dunitCtrlLow;
++}
++
++/*******************************************************************************
++* sdramAddrCtrlRegCalc - Calculate sdram address control register
++*
++* DESCRIPTION: Calculate sdram address control register optimized value based
++* on the bank info parameters and the minCas.
++*
++* INPUT:
++* pBankInfo - sdram bank parameters
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram address control reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramAddrCtrlRegCalc(MV_DRAM_BANK_INFO *pBankInfo)
++{
++ MV_U32 addrCtrl = 0;
++
++ /* Set Address Control register static configuration bits */
++ addrCtrl = MV_REG_READ(SDRAM_ADDR_CTRL_REG);
++
++ /* Set address control default value */
++ addrCtrl |= SDRAM_ADDR_CTRL_DV;
++
++ /* Clear DSize field */
++ addrCtrl &= ~SDRAM_DSIZE_MASK;
++
++ /* Note that density is in MB units */
++ switch (pBankInfo->deviceDensity)
++ {
++ case 128: /* 128 Mbit */
++ DB(mvOsPrintf("DRAM Device Density 128Mbit\n"));
++ addrCtrl |= SDRAM_DSIZE_128Mb;
++ break;
++ case 256: /* 256 Mbit */
++ DB(mvOsPrintf("DRAM Device Density 256Mbit\n"));
++ addrCtrl |= SDRAM_DSIZE_256Mb;
++ break;
++ case 512: /* 512 Mbit */
++ DB(mvOsPrintf("DRAM Device Density 512Mbit\n"));
++ addrCtrl |= SDRAM_DSIZE_512Mb;
++ break;
++ default:
++ mvOsPrintf("Dram: sdramAddrCtrl unsupported RAM-Device size %d\n",
++ pBankInfo->deviceDensity);
++ return -1;
++ }
++
++ /* SDRAM address control */
++ DB(mvOsPrintf("Dram: setting sdram address control with: %x \n", addrCtrl));
++
++ return addrCtrl;
++}
++
++/*******************************************************************************
++* sdramTimeCtrlLowRegCalc - Calculate sdram timing control low register
++*
++* DESCRIPTION:
++* This function calculates sdram timing control low register
++* optimized value based on the bank info parameters and the minCas.
++*
++* INPUT:
++* pBankInfo - sdram bank parameters
++* busClk - Bus clock
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram timinf control low reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramTimeCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo,
++ MV_U32 minCas, MV_U32 busClk)
++{
++ MV_U32 tRp = 0;
++ MV_U32 tRrd = 0;
++ MV_U32 tRcd = 0;
++ MV_U32 tRas = 0;
++ MV_U32 tWr = 0;
++ MV_U32 tWtr = 0;
++ MV_U32 tRtp = 0;
++
++ MV_U32 bankNum;
++
++ busClk = busClk / 1000000; /* In MHz */
++
++ /* Scan all DRAM banks to find maximum timing values */
++ for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ {
++ tRp = MV_MAX(tRp, pBankInfo[bankNum].minRowPrechargeTime);
++ tRrd = MV_MAX(tRrd, pBankInfo[bankNum].minRowActiveToRowActive);
++ tRcd = MV_MAX(tRcd, pBankInfo[bankNum].minRasToCasDelay);
++ tRas = MV_MAX(tRas, pBankInfo[bankNum].minRasPulseWidth);
++ }
++
++ /* Extract timing (in ns) from SPD value. We ignore the tenth ns part. */
++ /* by shifting the data two bits right. */
++ tRp = tRp >> 2; /* For example 0x50 -> 20ns */
++ tRrd = tRrd >> 2;
++ tRcd = tRcd >> 2;
++
++ /* Extract clock cycles from time parameter. We need to round up */
++ tRp = ((busClk * tRp) / 1000) + (((busClk * tRp) % 1000) ? 1 : 0);
++ /* Micron work around for 133MHz */
++ if (busClk == 133)
++ tRp += 1;
++ DB(mvOsPrintf("Dram Timing Low: tRp = %d ", tRp));
++ tRrd = ((busClk * tRrd) / 1000) + (((busClk * tRrd) % 1000) ? 1 : 0);
++ /* JEDEC min reqeirments tRrd = 2 */
++ if (tRrd < 2)
++ tRrd = 2;
++ DB(mvOsPrintf("tRrd = %d ", tRrd));
++ tRcd = ((busClk * tRcd) / 1000) + (((busClk * tRcd) % 1000) ? 1 : 0);
++ DB(mvOsPrintf("tRcd = %d ", tRcd));
++ tRas = ((busClk * tRas) / 1000) + (((busClk * tRas) % 1000) ? 1 : 0);
++ DB(mvOsPrintf("tRas = %d ", tRas));
++
++ /* tWr and tWtr is different for DDR1 and DDR2. tRtp is only for DDR2 */
++ if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2)
++ {
++ /* Scan all DRAM banks to find maximum timing values */
++ for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ {
++ tWr = MV_MAX(tWr, pBankInfo[bankNum].minWriteRecoveryTime);
++ tWtr = MV_MAX(tWtr, pBankInfo[bankNum].minWriteToReadCmdDelay);
++ tRtp = MV_MAX(tRtp, pBankInfo[bankNum].minReadToPrechCmdDelay);
++ }
++
++ /* Extract timing (in ns) from SPD value. We ignore the tenth ns */
++ /* part by shifting the data two bits right. */
++ tWr = tWr >> 2; /* For example 0x50 -> 20ns */
++ tWtr = tWtr >> 2;
++ tRtp = tRtp >> 2;
++
++ /* Extract clock cycles from time parameter. We need to round up */
++ tWr = ((busClk * tWr) / 1000) + (((busClk * tWr) % 1000) ? 1 : 0);
++ DB(mvOsPrintf("tWr = %d ", tWr));
++ tWtr = ((busClk * tWtr) / 1000) + (((busClk * tWtr) % 1000) ? 1 : 0);
++ /* JEDEC min reqeirments tWtr = 2 */
++ if (tWtr < 2)
++ tWtr = 2;
++ DB(mvOsPrintf("tWtr = %d ", tWtr));
++ tRtp = ((busClk * tRtp) / 1000) + (((busClk * tRtp) % 1000) ? 1 : 0);
++ /* JEDEC min reqeirments tRtp = 2 */
++ if (tRtp < 2)
++ tRtp = 2;
++ DB(mvOsPrintf("tRtp = %d ", tRtp));
++ }
++ else
++ {
++ tWr = ((busClk*SDRAM_TWR) / 1000) + (((busClk*SDRAM_TWR) % 1000)?1:0);
++
++ if ((200 == busClk) || ((100 == busClk) && (DDR1_CL_1_5 == minCas)))
++ {
++ tWtr = 2;
++ }
++ else
++ {
++ tWtr = 1;
++ }
++
++ tRtp = 2; /* Must be set to 0x1 (two cycles) when using DDR1 */
++ }
++
++ DB(mvOsPrintf("tWtr = %d\n", tWtr));
++
++ /* Note: value of 0 in register means one cycle, 1 means two and so on */
++ return (((tRp - 1) << SDRAM_TRP_OFFS) |
++ ((tRrd - 1) << SDRAM_TRRD_OFFS) |
++ ((tRcd - 1) << SDRAM_TRCD_OFFS) |
++ ((tRas - 1) << SDRAM_TRAS_OFFS) |
++ ((tWr - 1) << SDRAM_TWR_OFFS) |
++ ((tWtr - 1) << SDRAM_TWTR_OFFS) |
++ ((tRtp - 1) << SDRAM_TRTP_OFFS));
++}
++
++/*******************************************************************************
++* sdramTimeCtrlHighRegCalc - Calculate sdram timing control high register
++*
++* DESCRIPTION:
++* This function calculates sdram timing control high register
++* optimized value based on the bank info parameters and the bus clock.
++*
++* INPUT:
++* pBankInfo - sdram bank parameters
++* busClk - Bus clock
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram timinf control high reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramTimeCtrlHighRegCalc(MV_DRAM_BANK_INFO *pBankInfo,
++ MV_U32 busClk)
++{
++ MV_U32 tRfc;
++ MV_U32 timeNs = 0;
++ int bankNum;
++ MV_U32 sdramTw2wCyc = 0;
++
++ busClk = busClk / 1000000; /* In MHz */
++
++ /* tRfc is different for DDR1 and DDR2. */
++ if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2)
++ {
++ MV_U32 bankNum;
++
++ /* Scan all DRAM banks to find maximum timing values */
++ for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ timeNs = MV_MAX(timeNs, pBankInfo[bankNum].minRefreshToActiveCmd);
++ }
++ else
++ {
++ if (pBankInfo[0].deviceDensity == _1G)
++ {
++ timeNs = SDRAM_TRFC_1G;
++ }
++ else
++ {
++ if (200 == busClk)
++ {
++ timeNs = SDRAM_TRFC_64_512M_AT_200MHZ;
++ }
++ else
++ {
++ timeNs = SDRAM_TRFC_64_512M;
++ }
++ }
++ }
++
++ tRfc = ((busClk * timeNs) / 1000) + (((busClk * timeNs) % 1000) ? 1 : 0);
++
++ DB(mvOsPrintf("Dram Timing High: tRfc = %d\n", tRfc));
++
++
++ /* Represent the populate banks in binary form */
++ for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ {
++ if (0 != pBankInfo[bankNum].size)
++ sdramTw2wCyc++;
++ }
++
++ /* If we have more the 1 bank then we need the TW2W in 1 for ODT switch */
++ if (sdramTw2wCyc > 1)
++ sdramTw2wCyc = 1;
++ else
++ sdramTw2wCyc = 0;
++
++ /* Note: value of 0 in register means one cycle, 1 means two and so on */
++ return ((((tRfc - 1) & SDRAM_TRFC_MASK) << SDRAM_TRFC_OFFS) |
++ ((SDRAM_TR2R_CYC - 1) << SDRAM_TR2R_OFFS) |
++ ((SDRAM_TR2WW2R_CYC - 1) << SDRAM_TR2W_W2R_OFFS) |
++ (((tRfc - 1) >> 4) << SDRAM_TRFC_EXT_OFFS) |
++ (sdramTw2wCyc << SDRAM_TW2W_OFFS));
++
++}
++
++/*******************************************************************************
++* sdramDDr2OdtConfig - Set DRAM DDR2 On Die Termination registers.
++*
++* DESCRIPTION:
++* This function config DDR2 On Die Termination (ODT) registers.
++* ODT configuration is done according to DIMM presence:
++*
++* Presence Ctrl Low Ctrl High Dunit Ctrl Ext Mode
++* CS0 0x84210000 0x00000000 0x0000780F 0x00000440
++* CS0+CS1 0x84210000 0x00000000 0x0000780F 0x00000440
++* CS0+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404
++* CS0+CS1+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404
++* CS0+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404
++* CS0+CS1+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404
++*
++* INPUT:
++* pBankInfo - bank info parameters.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* None
++*******************************************************************************/
++static void sdramDDr2OdtConfig(MV_DRAM_BANK_INFO *pBankInfo)
++{
++ MV_U32 populateBanks = 0;
++ MV_U32 odtCtrlLow, odtCtrlHigh, dunitOdtCtrl;
++ int bankNum;
++
++ /* Represent the populate banks in binary form */
++ for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ {
++ if (0 != pBankInfo[bankNum].size)
++ {
++ populateBanks |= (1 << bankNum);
++ }
++ }
++
++ switch(populateBanks)
++ {
++ case(BANK_PRESENT_CS0):
++ odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_DV;
++ odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_DV;
++ dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_DV;
++ break;
++ case(BANK_PRESENT_CS0_CS1):
++ odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_DV;
++ odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_DV;
++ dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_DV;
++ break;
++ case(BANK_PRESENT_CS0_CS2):
++ odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS2_DV;
++ odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS2_DV;
++ dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS2_DV;
++ break;
++ case(BANK_PRESENT_CS0_CS1_CS2):
++ odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS2_DV;
++ odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS2_DV;
++ dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS2_DV;
++ break;
++ case(BANK_PRESENT_CS0_CS2_CS3):
++ odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS2_DV;
++ odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS2_DV;
++ dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS2_DV;
++ break;
++ case(BANK_PRESENT_CS0_CS2_CS3_CS4):
++ odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS2_DV;
++ odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS2_DV;
++ dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS2_DV;
++ break;
++ default:
++ mvOsPrintf("sdramDDr2OdtConfig: Invalid DRAM bank presence\n");
++ return;
++ }
++ MV_REG_WRITE(DRAM_BUF_REG7, odtCtrlLow);
++ MV_REG_WRITE(DRAM_BUF_REG8, odtCtrlHigh);
++ MV_REG_WRITE(DRAM_BUF_REG9, dunitOdtCtrl);
++ return;
++}
++#endif /* defined(MV_INC_BOARD_DDIM) */
++
++/*******************************************************************************
++* mvDramIfWinSet - Set DRAM interface address decode window
++*
++* DESCRIPTION:
++* This function sets DRAM interface address decode window.
++*
++* INPUT:
++* target - System target. Use only SDRAM targets.
++* pAddrDecWin - SDRAM address window structure.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* MV_BAD_PARAM if parameters are invalid or window is invalid, MV_OK
++* otherwise.
++*******************************************************************************/
++MV_STATUS mvDramIfWinSet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin)
++{
++ MV_U32 baseReg=0,sizeReg=0;
++ MV_U32 baseToReg=0 , sizeToReg=0;
++
++ /* Check parameters */
++ if (!MV_TARGET_IS_DRAM(target))
++ {
++ mvOsPrintf("mvDramIfWinSet: target %d is not SDRAM\n", target);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check if the requested window overlaps with current enabled windows */
++ if (MV_TRUE == sdramIfWinOverlap(target, &pAddrDecWin->addrWin))
++ {
++ mvOsPrintf("mvDramIfWinSet: ERR. Target %d overlaps\n", target);
++ return MV_BAD_PARAM;
++ }
++
++ /* check if address is aligned to the size */
++ if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size))
++ {
++ mvOsPrintf("mvDramIfWinSet:Error setting DRAM interface window %d."\
++ "\nAddress 0x%08x is unaligned to size 0x%x.\n",
++ target,
++ pAddrDecWin->addrWin.baseLow,
++ pAddrDecWin->addrWin.size);
++ return MV_ERROR;
++ }
++
++ /* read base register*/
++ baseReg = MV_REG_READ(SDRAM_BASE_ADDR_REG(target));
++
++ /* read size register */
++ sizeReg = MV_REG_READ(SDRAM_SIZE_REG(target));
++
++ /* BaseLow[31:16] => base register [31:16] */
++ baseToReg = pAddrDecWin->addrWin.baseLow & SCBAR_BASE_MASK;
++
++ /* Write to address decode Base Address Register */
++ baseReg &= ~SCBAR_BASE_MASK;
++ baseReg |= baseToReg;
++
++ /* Translate the given window size to register format */
++ sizeToReg = ctrlSizeToReg(pAddrDecWin->addrWin.size, SCSR_SIZE_ALIGNMENT);
++
++ /* Size parameter validity check. */
++ if (-1 == sizeToReg)
++ {
++ mvOsPrintf("mvCtrlAddrDecToReg: ERR. Win %d size invalid.\n",target);
++ return MV_BAD_PARAM;
++ }
++
++ /* set size */
++ sizeReg &= ~SCSR_SIZE_MASK;
++ /* Size is located at upper 16 bits */
++ sizeReg |= (sizeToReg << SCSR_SIZE_OFFS);
++
++ /* enable/Disable */
++ if (MV_TRUE == pAddrDecWin->enable)
++ {
++ sizeReg |= SCSR_WIN_EN;
++ }
++ else
++ {
++ sizeReg &= ~SCSR_WIN_EN;
++ }
++
++ /* 3) Write to address decode Base Address Register */
++ MV_REG_WRITE(SDRAM_BASE_ADDR_REG(target), baseReg);
++
++ /* Write to address decode Size Register */
++ MV_REG_WRITE(SDRAM_SIZE_REG(target), sizeReg);
++
++ return MV_OK;
++}
++/*******************************************************************************
++* mvDramIfWinGet - Get DRAM interface address decode window
++*
++* DESCRIPTION:
++* This function gets DRAM interface address decode window.
++*
++* INPUT:
++* target - System target. Use only SDRAM targets.
++*
++* OUTPUT:
++* pAddrDecWin - SDRAM address window structure.
++*
++* RETURN:
++* MV_BAD_PARAM if parameters are invalid or window is invalid, MV_OK
++* otherwise.
++*******************************************************************************/
++MV_STATUS mvDramIfWinGet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin)
++{
++ MV_U32 baseReg,sizeReg;
++ MV_U32 sizeRegVal;
++
++ /* Check parameters */
++ if (!MV_TARGET_IS_DRAM(target))
++ {
++ mvOsPrintf("mvDramIfWinGet: target %d is Illigal\n", target);
++ return MV_ERROR;
++ }
++
++ /* Read base and size registers */
++ sizeReg = MV_REG_READ(SDRAM_SIZE_REG(target));
++ baseReg = MV_REG_READ(SDRAM_BASE_ADDR_REG(target));
++
++ sizeRegVal = (sizeReg & SCSR_SIZE_MASK) >> SCSR_SIZE_OFFS;
++
++ pAddrDecWin->addrWin.size = ctrlRegToSize(sizeRegVal,
++ SCSR_SIZE_ALIGNMENT);
++
++ /* Check if ctrlRegToSize returned OK */
++ if (-1 == pAddrDecWin->addrWin.size)
++ {
++ mvOsPrintf("mvDramIfWinGet: size of target %d is Illigal\n", target);
++ return MV_ERROR;
++ }
++
++ /* Extract base address */
++ /* Base register [31:16] ==> baseLow[31:16] */
++ pAddrDecWin->addrWin.baseLow = baseReg & SCBAR_BASE_MASK;
++
++ pAddrDecWin->addrWin.baseHigh = 0;
++
++
++ if (sizeReg & SCSR_WIN_EN)
++ {
++ pAddrDecWin->enable = MV_TRUE;
++ }
++ else
++ {
++ pAddrDecWin->enable = MV_FALSE;
++ }
++
++ return MV_OK;
++}
++/*******************************************************************************
++* mvDramIfWinEnable - Enable/Disable SDRAM address decode window
++*
++* DESCRIPTION:
++* This function enable/Disable SDRAM address decode window.
++*
++* INPUT:
++* target - System target. Use only SDRAM targets.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_ERROR in case function parameter are invalid, MV_OK otherewise.
++*
++*******************************************************************************/
++MV_STATUS mvDramIfWinEnable(MV_TARGET target,MV_BOOL enable)
++{
++ MV_DRAM_DEC_WIN addrDecWin;
++
++ /* Check parameters */
++ if (!MV_TARGET_IS_DRAM(target))
++ {
++ mvOsPrintf("mvDramIfWinEnable: target %d is Illigal\n", target);
++ return MV_ERROR;
++ }
++
++ if (enable == MV_TRUE)
++ { /* First check for overlap with other enabled windows */
++ if (MV_OK != mvDramIfWinGet(target, &addrDecWin))
++ {
++ mvOsPrintf("mvDramIfWinEnable:ERR. Getting target %d failed.\n",
++ target);
++ return MV_ERROR;
++ }
++ /* Check for overlapping */
++ if (MV_FALSE == sdramIfWinOverlap(target, &(addrDecWin.addrWin)))
++ {
++ /* No Overlap. Enable address decode winNum window */
++ MV_REG_BIT_SET(SDRAM_SIZE_REG(target), SCSR_WIN_EN);
++ }
++ else
++ { /* Overlap detected */
++ mvOsPrintf("mvDramIfWinEnable: ERR. Target %d overlap detect\n",
++ target);
++ return MV_ERROR;
++ }
++ }
++ else
++ { /* Disable address decode winNum window */
++ MV_REG_BIT_RESET(SDRAM_SIZE_REG(target), SCSR_WIN_EN);
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* sdramIfWinOverlap - Check if an address window overlap an SDRAM address window
++*
++* DESCRIPTION:
++* This function scan each SDRAM address decode window to test if it
++* overlapps the given address windoow
++*
++* INPUT:
++* target - SDRAM target where the function skips checking.
++* pAddrDecWin - The tested address window for overlapping with
++* SDRAM windows.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if the given address window overlaps any enabled address
++* decode map, MV_FALSE otherwise.
++*
++*******************************************************************************/
++static MV_BOOL sdramIfWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin)
++{
++ MV_TARGET targetNum;
++ MV_DRAM_DEC_WIN addrDecWin;
++
++ for(targetNum = SDRAM_CS0; targetNum < MV_DRAM_MAX_CS ; targetNum++)
++ {
++ /* don't check our winNum or illegal targets */
++ if (targetNum == target)
++ {
++ continue;
++ }
++
++ /* Get window parameters */
++ if (MV_OK != mvDramIfWinGet(targetNum, &addrDecWin))
++ {
++ mvOsPrintf("sdramIfWinOverlap: ERR. TargetWinGet failed\n");
++ return MV_ERROR;
++ }
++
++ /* Do not check disabled windows */
++ if (MV_FALSE == addrDecWin.enable)
++ {
++ continue;
++ }
++
++ if(MV_TRUE == ctrlWinOverlapTest(pAddrWin, &addrDecWin.addrWin))
++ {
++ mvOsPrintf(
++ "sdramIfWinOverlap: Required target %d overlap winNum %d\n",
++ target, targetNum);
++ return MV_TRUE;
++ }
++ }
++
++ return MV_FALSE;
++}
++
++/*******************************************************************************
++* mvDramIfBankSizeGet - Get DRAM interface bank size.
++*
++* DESCRIPTION:
++* This function returns the size of a given DRAM bank.
++*
++* INPUT:
++* bankNum - Bank number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* DRAM bank size. If bank is disabled the function return '0'. In case
++* or paramter is invalid, the function returns -1.
++*
++*******************************************************************************/
++MV_32 mvDramIfBankSizeGet(MV_U32 bankNum)
++{
++ MV_DRAM_DEC_WIN addrDecWin;
++
++ /* Check parameters */
++ if (!MV_TARGET_IS_DRAM(bankNum))
++ {
++ mvOsPrintf("mvDramIfBankBaseGet: bankNum %d is invalid\n", bankNum);
++ return -1;
++ }
++ /* Get window parameters */
++ if (MV_OK != mvDramIfWinGet(bankNum, &addrDecWin))
++ {
++ mvOsPrintf("sdramIfWinOverlap: ERR. TargetWinGet failed\n");
++ return -1;
++ }
++
++ if (MV_TRUE == addrDecWin.enable)
++ {
++ return addrDecWin.addrWin.size;
++ }
++ else
++ {
++ return 0;
++ }
++}
++
++
++/*******************************************************************************
++* mvDramIfSizeGet - Get DRAM interface total size.
++*
++* DESCRIPTION:
++* This function get the DRAM total size.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* DRAM total size. In case or paramter is invalid, the function
++* returns -1.
++*
++*******************************************************************************/
++MV_32 mvDramIfSizeGet(MV_VOID)
++{
++ MV_U32 totalSize = 0, bankSize = 0, bankNum;
++
++ for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ {
++ bankSize = mvDramIfBankSizeGet(bankNum);
++
++ if (-1 == bankSize)
++ {
++ mvOsPrintf("Dram: mvDramIfSizeGet error with bank %d \n",bankNum);
++ return -1;
++ }
++ else
++ {
++ totalSize += bankSize;
++ }
++ }
++
++ DB(mvOsPrintf("Dram: Total DRAM size is 0x%x \n",totalSize));
++
++ return totalSize;
++}
++
++/*******************************************************************************
++* mvDramIfBankBaseGet - Get DRAM interface bank base.
++*
++* DESCRIPTION:
++* This function returns the 32 bit base address of a given DRAM bank.
++*
++* INPUT:
++* bankNum - Bank number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* DRAM bank size. If bank is disabled or paramter is invalid, the
++* function returns -1.
++*
++*******************************************************************************/
++MV_32 mvDramIfBankBaseGet(MV_U32 bankNum)
++{
++ MV_DRAM_DEC_WIN addrDecWin;
++
++ /* Check parameters */
++ if (!MV_TARGET_IS_DRAM(bankNum))
++ {
++ mvOsPrintf("mvDramIfBankBaseGet: bankNum %d is invalid\n", bankNum);
++ return -1;
++ }
++ /* Get window parameters */
++ if (MV_OK != mvDramIfWinGet(bankNum, &addrDecWin))
++ {
++ mvOsPrintf("sdramIfWinOverlap: ERR. TargetWinGet failed\n");
++ return -1;
++ }
++
++ if (MV_TRUE == addrDecWin.enable)
++ {
++ return addrDecWin.addrWin.baseLow;
++ }
++ else
++ {
++ return -1;
++ }
++}
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.h 2010-11-09 20:28:10.692495407 +0100
+@@ -0,0 +1,192 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDramIfConfigh
++#define __INCmvDramIfConfigh
++
++/* includes */
++
++/* defines */
++
++/* registers defaults values */
++
++#define SDRAM_CONFIG_DV \
++ (SDRAM_PERR_WRITE | \
++ SDRAM_SRMODE | \
++ SDRAM_SRCLK_GATED)
++
++#define SDRAM_DUNIT_CTRL_LOW_DV \
++ (SDRAM_CTRL_POS_RISE | \
++ SDRAM_CLK1DRV_NORMAL | \
++ SDRAM_LOCKEN_ENABLE)
++
++#define SDRAM_ADDR_CTRL_DV 0
++
++#define SDRAM_TIMING_CTRL_LOW_REG_DV \
++ ((0x2 << SDRAM_TRCD_OFFS) | \
++ (0x2 << SDRAM_TRP_OFFS) | \
++ (0x1 << SDRAM_TWR_OFFS) | \
++ (0x0 << SDRAM_TWTR_OFFS) | \
++ (0x5 << SDRAM_TRAS_OFFS) | \
++ (0x1 << SDRAM_TRRD_OFFS))
++/* TRFC 0x27, TW2W 0x1 */
++#define SDRAM_TIMING_CTRL_HIGH_REG_DV (( 0x7 << SDRAM_TRFC_OFFS ) |\
++ ( 0x2 << SDRAM_TRFC_EXT_OFFS) |\
++ ( 0x1 << SDRAM_TW2W_OFFS))
++
++#define SDRAM_OPEN_PAGES_CTRL_REG_DV SDRAM_OPEN_PAGE_EN
++
++/* DDR2 ODT default register values */
++
++/* Presence Ctrl Low Ctrl High Dunit Ctrl Ext Mode */
++/* CS0 0x84210000 0x00000000 0x0000780F 0x00000440 */
++/* CS0+CS1 0x84210000 0x00000000 0x0000780F 0x00000440 */
++/* CS0+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404 */
++/* CS0+CS1+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404 */
++/* CS0+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404 */
++/* CS0+CS1+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404 */
++
++#define DDR2_ODT_CTRL_LOW_CS0_DV 0x84210000
++#define DDR2_ODT_CTRL_HIGH_CS0_DV 0x00000000
++#define DDR2_DUNIT_ODT_CTRL_CS0_DV 0x0000780F
++#define DDR_SDRAM_EXT_MODE_CS0_DV 0x00000440
++
++#define DDR2_ODT_CTRL_LOW_CS0_CS2_DV 0x030C030C
++#define DDR2_ODT_CTRL_HIGH_CS0_CS2_DV 0x00000000
++#define DDR2_DUNIT_ODT_CTRL_CS0_CS2_DV 0x0000740F
++#define DDR_SDRAM_EXT_MODE_CS0_CS2_DV 0x00000404
++
++
++/* DDR SDRAM Adderss/Control and Data Pads Calibration default values */
++#define DDR1_ADDR_CTRL_PAD_STRENGTH_TYPICAL_DV \
++ (1 << SDRAM_PRE_DRIVER_STRENGTH_OFFS)
++#define DDR2_ADDR_CTRL_PAD_STRENGTH_TYPICAL_DV \
++ (3 << SDRAM_PRE_DRIVER_STRENGTH_OFFS)
++
++
++#define DDR1_DATA_PAD_STRENGTH_TYPICAL_DV \
++ (1 << SDRAM_PRE_DRIVER_STRENGTH_OFFS)
++#define DDR2_DATA_PAD_STRENGTH_TYPICAL_DV \
++ (3 << SDRAM_PRE_DRIVER_STRENGTH_OFFS)
++
++/* DDR SDRAM Mode Register default value */
++#define DDR1_MODE_REG_DV 0x00000000
++#define DDR2_MODE_REG_DV 0x00000400
++
++/* DDR SDRAM Timing parameter default values */
++#define DDR1_TIMING_LOW_DV 0x11602220
++#define DDR1_TIMING_HIGH_DV 0x0000000d
++
++#define DDR2_TIMING_LOW_DV 0x11812220
++#define DDR2_TIMING_HIGH_DV 0x0000030f
++
++/* For Guideline (GL# MEM-4) DQS Reference Delay Tuning */
++#define FTDLL_DDR1_166MHZ ((0x1 << 0) | \
++ (0x7F<< 12) | \
++ (0x1 << 22))
++
++#define FTDLL_DDR1_133MHZ FTDLL_DDR1_166MHZ
++
++#define FTDLL_DDR1_200MHZ ((0x1 << 0) | \
++ (0x1 << 12) | \
++ (0x3 << 14) | \
++ (0x1 << 18) | \
++ (0x1 << 22))
++
++
++#define FTDLL_DDR2_166MHZ ((0x1 << 0) | \
++ (0x1 << 12) | \
++ (0x1 << 14) | \
++ (0x1 << 16) | \
++ (0x1 << 19) | \
++ (0xF << 20))
++
++#define FTDLL_DDR2_133MHZ FTDLL_DDR2_166MHZ
++
++#define FTDLL_DDR2_200MHZ ((0x1 << 0) | \
++ (0x1 << 12) | \
++ (0x1 << 14) | \
++ (0x1 << 16) | \
++ (0x1 << 19) | \
++ (0xF << 20))
++
++#define FTDLL_DDR2_250MHZ 0x445001
++
++/* Orion 1 B1 and above */
++#define FTDLL_DDR1_166MHZ_5181_B1 0x45D001
++
++/* Orion nas */
++#define FTDLL_DDR2_166MHZ_5182 0x597001
++
++/* Orion 2 D0 and above */
++#define FTDLL_DDR1_166MHZ_5281_D0 0x8D0001
++#define FTDLL_DDR1_200MHZ_5281_D0 0x8D0001
++#define FTDLL_DDR2_166MHZ_5281_D0 0x485001
++#define FTDLL_DDR2_200MHZ_5281_D0 0x485001
++#define FTDLL_DDR2_250MHZ_5281_D0 0x445001
++#define FTDLL_DDR2_200MHZ_5281_D1 0x995001
++#define FTDLL_DDR2_250MHZ_5281_D1 0x984801
++
++#endif /* __INCmvDramIfh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.h 2010-11-09 20:28:10.747105889 +0100
+@@ -0,0 +1,179 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDramIfh
++#define __INCmvDramIfh
++
++/* includes */
++#include "ddr1_2/mvDramIfRegs.h"
++#include "ddr1_2/mvDramIfConfig.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++
++/* defines */
++/* DRAM Timing parameters */
++#define SDRAM_TWR 15 /* ns tWr */
++#define SDRAM_TRFC_64_512M_AT_200MHZ 70 /* ns tRfc for dens 64-512 @ 200MHz */
++#define SDRAM_TRFC_64_512M 75 /* ns tRfc for dens 64-512 */
++#define SDRAM_TRFC_1G 120 /* ns tRfc for dens 1GB */
++#define SDRAM_TR2R_CYC 1 /* cycle for tR2r */
++#define SDRAM_TR2WW2R_CYC 1 /* cycle for tR2wW2r */
++
++/* typedefs */
++
++/* enumeration for memory types */
++typedef enum _mvMemoryType
++{
++ MEM_TYPE_SDRAM,
++ MEM_TYPE_DDR1,
++ MEM_TYPE_DDR2
++}MV_MEMORY_TYPE;
++
++/* enumeration for DDR1 supported CAS Latencies */
++typedef enum _mvDimmDdr1Cas
++{
++ DDR1_CL_1_5 = 0x02,
++ DDR1_CL_2 = 0x04,
++ DDR1_CL_2_5 = 0x08,
++ DDR1_CL_3 = 0x10,
++ DDR1_CL_4 = 0x40,
++ DDR1_CL_FAULT
++} MV_DIMM_DDR1_CAS;
++
++/* enumeration for DDR2 supported CAS Latencies */
++typedef enum _mvDimmDdr2Cas
++{
++ DDR2_CL_3 = 0x08,
++ DDR2_CL_4 = 0x10,
++ DDR2_CL_5 = 0x20,
++ DDR2_CL_FAULT
++} MV_DIMM_DDR2_CAS;
++
++
++typedef struct _mvDramBankInfo
++{
++ MV_MEMORY_TYPE memoryType; /* DDR1, DDR2 or SDRAM */
++
++ /* DIMM dimensions */
++ MV_U32 numOfRowAddr;
++ MV_U32 numOfColAddr;
++ MV_U32 dataWidth;
++ MV_U32 errorCheckType; /* ECC , PARITY..*/
++ MV_U32 sdramWidth; /* 4,8,16 or 32 */
++ MV_U32 errorCheckDataWidth; /* 0 - no, 1 - Yes */
++ MV_U32 burstLengthSupported;
++ MV_U32 numOfBanksOnEachDevice;
++ MV_U32 suportedCasLatencies;
++ MV_U32 refreshInterval;
++
++ /* DIMM timing parameters */
++ MV_U32 minCycleTimeAtMaxCasLatPs;
++ MV_U32 minCycleTimeAtMaxCasLatMinus1Ps;
++ MV_U32 minCycleTimeAtMaxCasLatMinus2Ps;
++ MV_U32 minRowPrechargeTime;
++ MV_U32 minRowActiveToRowActive;
++ MV_U32 minRasToCasDelay;
++ MV_U32 minRasPulseWidth;
++ MV_U32 minWriteRecoveryTime; /* DDR2 only */
++ MV_U32 minWriteToReadCmdDelay; /* DDR2 only */
++ MV_U32 minReadToPrechCmdDelay; /* DDR2 only */
++ MV_U32 minRefreshToActiveCmd; /* DDR2 only */
++
++ /* Parameters calculated from the extracted DIMM information */
++ MV_U32 size;
++ MV_U32 deviceDensity; /* 16,64,128,256 or 512 Mbit */
++ MV_U32 numberOfDevices;
++
++ /* DIMM attributes (MV_TRUE for yes) */
++ MV_BOOL registeredAddrAndControlInputs;
++
++}MV_DRAM_BANK_INFO;
++
++/* This structure describes CPU interface address decode window */
++typedef struct _mvDramIfDecWin
++{
++ MV_ADDR_WIN addrWin; /* An address window*/
++ MV_BOOL enable; /* Address decode window is enabled/disabled */
++}MV_DRAM_DEC_WIN;
++
++#include "ddr1_2/mvDram.h"
++
++/* mvDramIf.h API list */
++MV_VOID mvDramIfBasicAsmInit(MV_VOID);
++MV_STATUS mvDramIfDetect(MV_U32 forcedCl);
++MV_VOID _mvDramIfConfig(MV_VOID);
++
++MV_STATUS mvDramIfWinSet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin);
++MV_STATUS mvDramIfWinGet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin);
++MV_STATUS mvDramIfWinEnable(MV_TARGET target,MV_BOOL enable);
++MV_32 mvDramIfBankSizeGet(MV_U32 bankNum);
++MV_32 mvDramIfBankBaseGet(MV_U32 bankNum);
++MV_32 mvDramIfSizeGet(MV_VOID);
++
++#if 0
++MV_STATUS mvDramIfMbusCtrlSet(MV_XBAR_TARGET *pPizzaArbArray);
++MV_STATUS mvDramIfMbusToutSet(MV_U32 timeout, MV_BOOL enable);
++#endif
++
++#endif /* __INCmvDramIfh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfRegs.h 2010-11-09 20:28:10.772495655 +0100
+@@ -0,0 +1,306 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDramIfRegsh
++#define __INCmvDramIfRegsh
++
++
++/* DDR SDRAM Controller Address Decode Registers */
++/* SDRAM CSn Base Address Register (SCBAR) */
++#define SDRAM_BASE_ADDR_REG(csNum) (0x1500 + (csNum * 8))
++#define SCBAR_BASE_OFFS 16
++#define SCBAR_BASE_MASK (0xffff << SCBAR_BASE_OFFS)
++#define SCBAR_BASE_ALIGNMENT 0x10000
++
++/* SDRAM CSn Size Register (SCSR) */
++#define SDRAM_SIZE_REG(csNum) (0x1504 + (csNum * 8))
++#define SCSR_WIN_EN BIT0
++#define SCSR_SIZE_OFFS 16
++#define SCSR_SIZE_MASK (0xffff << SCSR_SIZE_OFFS)
++#define SCSR_SIZE_ALIGNMENT 0x10000
++
++/* configuration register */
++#define SDRAM_CONFIG_REG 0x1400
++#define SDRAM_REFRESH_OFFS 0
++#define SDRAM_REFRESH_MAX 0x3000
++#define SDRAM_REFRESH_MASK (SDRAM_REFRESH_MAX << SDRAM_REFRESH_OFFS)
++#define SDRAM_DWIDTH_OFFS 14
++#define SDRAM_DWIDTH_MASK (3 << SDRAM_DWIDTH_OFFS)
++#define SDRAM_DWIDTH_16BIT (1 << SDRAM_DWIDTH_OFFS)
++#define SDRAM_DWIDTH_32BIT (2 << SDRAM_DWIDTH_OFFS)
++#define SDRAM_DTYPE_OFFS 16
++#define SDRAM_DTYPE_MASK (1 << SDRAM_DTYPE_OFFS)
++#define SDRAM_DTYPE_DDR1 (0 << SDRAM_DTYPE_OFFS)
++#define SDRAM_DTYPE_DDR2 (1 << SDRAM_DTYPE_OFFS)
++#define SDRAM_REGISTERED (1 << 17)
++#define SDRAM_PERR_OFFS 18
++#define SDRAM_PERR_MASK (1 << SDRAM_PERR_OFFS)
++#define SDRAM_PERR_NO_WRITE (0 << SDRAM_PERR_OFFS)
++#define SDRAM_PERR_WRITE (1 << SDRAM_PERR_OFFS)
++#define SDRAM_DCFG_OFFS 20
++#define SDRAM_DCFG_MASK (0x3 << SDRAM_DCFG_OFFS)
++#define SDRAM_DCFG_X16_DEV (1 << SDRAM_DCFG_OFFS)
++#define SDRAM_DCFG_X8_DEV (2 << SDRAM_DCFG_OFFS)
++#define SDRAM_SRMODE (1 << 24)
++#define SDRAM_SRCLK_OFFS 25
++#define SDRAM_SRCLK_MASK (1 << SDRAM_SRCLK_OFFS)
++#define SDRAM_SRCLK_KEPT (0 << SDRAM_SRCLK_OFFS)
++#define SDRAM_SRCLK_GATED (1 << SDRAM_SRCLK_OFFS)
++#define SDRAM_CATTH_OFFS 26
++#define SDRAM_CATTHR_EN (1 << SDRAM_CATTH_OFFS)
++
++
++/* dunit control register */
++#define SDRAM_DUNIT_CTRL_REG 0x1404
++#define SDRAM_CTRL_POS_OFFS 6
++#define SDRAM_CTRL_POS_FALL (0 << SDRAM_CTRL_POS_OFFS)
++#define SDRAM_CTRL_POS_RISE (1 << SDRAM_CTRL_POS_OFFS)
++#define SDRAM_CLK1DRV_OFFS 12
++#define SDRAM_CLK1DRV_MASK (1 << SDRAM_CLK1DRV_OFFS)
++#define SDRAM_CLK1DRV_HIGH_Z (0 << SDRAM_CLK1DRV_OFFS)
++#define SDRAM_CLK1DRV_NORMAL (1 << SDRAM_CLK1DRV_OFFS)
++#define SDRAM_LOCKEN_OFFS 18
++#define SDRAM_LOCKEN_MASK (1 << SDRAM_LOCKEN_OFFS)
++#define SDRAM_LOCKEN_DISABLE (0 << SDRAM_LOCKEN_OFFS)
++#define SDRAM_LOCKEN_ENABLE (1 << SDRAM_LOCKEN_OFFS)
++#define SDRAM_ST_BURST_DEL_OFFS 24
++#define SDRAM_ST_BURST_DEL_MAX 0xf
++#define SDRAM_ST_BURST_DEL_MASK (SDRAM_ST_BURST_DEL_MAX<<SDRAM_ST_BURST_DEL_OFFS)
++
++/* sdram timing control low register */
++#define SDRAM_TIMING_CTRL_LOW_REG 0x1408
++#define SDRAM_TRCD_OFFS 4
++#define SDRAM_TRCD_MASK (0xF << SDRAM_TRCD_OFFS)
++#define SDRAM_TRP_OFFS 8
++#define SDRAM_TRP_MASK (0xF << SDRAM_TRP_OFFS)
++#define SDRAM_TWR_OFFS 12
++#define SDRAM_TWR_MASK (0xF << SDRAM_TWR_OFFS)
++#define SDRAM_TWTR_OFFS 16
++#define SDRAM_TWTR_MASK (0xF << SDRAM_TWTR_OFFS)
++#define SDRAM_TRAS_OFFS 20
++#define SDRAM_TRAS_MASK (0xF << SDRAM_TRAS_OFFS)
++#define SDRAM_TRRD_OFFS 24
++#define SDRAM_TRRD_MASK (0xF << SDRAM_TRRD_OFFS)
++#define SDRAM_TRTP_OFFS 28
++#define SDRAM_TRTP_MASK (0xF << SDRAM_TRTP_OFFS)
++
++/* sdram timing control high register */
++#define SDRAM_TIMING_CTRL_HIGH_REG 0x140c
++#define SDRAM_TRFC_OFFS 0
++#define SDRAM_TRFC_MASK (0xF << SDRAM_TRFC_OFFS)
++#define SDRAM_TR2R_OFFS 4
++#define SDRAM_TR2R_MASK (0x3 << SDRAM_TR2R_OFFS)
++#define SDRAM_TR2W_W2R_OFFS 6
++#define SDRAM_TR2W_W2R_MASK (0x3 << SDRAM_TR2W_W2R_OFFS)
++#define SDRAM_TRFC_EXT_OFFS 8
++#define SDRAM_TRFC_EXT_MASK (0x1 << SDRAM_TRFC_EXT_OFFS)
++#define SDRAM_TW2W_OFFS 10
++#define SDRAM_TW2W_MASK (0x1 << SDRAM_TW2W_OFFS)
++
++/* address control register */
++#define SDRAM_ADDR_CTRL_REG 0x1410
++#define SDRAM_DSIZE_OFFS 4
++#define SDRAM_DSIZE_MASK (0x3 << SDRAM_DSIZE_OFFS)
++#define SDRAM_DSIZE_128Mb (0x0 << SDRAM_DSIZE_OFFS)
++#define SDRAM_DSIZE_256Mb (0x1 << SDRAM_DSIZE_OFFS)
++#define SDRAM_DSIZE_512Mb (0x2 << SDRAM_DSIZE_OFFS)
++
++/* SDRAM Open Pages Control registers */
++#define SDRAM_OPEN_PAGE_CTRL_REG 0x1414
++#define SDRAM_OPEN_PAGE_EN (0 << 0)
++#define SDRAM_OPEN_PAGE_DIS (1 << 0)
++
++/* sdram opertion register */
++#define SDRAM_OPERATION_REG 0x1418
++#define SDRAM_CMD_OFFS 0
++#define SDRAM_CMD_MASK (0x7 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_NORMAL (0x0 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_PRECHARGE_ALL (0x1 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_REFRESH_ALL (0x2 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_REG_SET_CMD (0x3 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_EXT_MODE_SET (0x4 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_NOP (0x5 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_SLF_RFRSH (0x7 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_EMRS2_CMD (0x8 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_EMRS3_CMD (0x9 << SDRAM_CMD_OFFS)
++
++/* sdram mode register */
++#define SDRAM_MODE_REG 0x141c
++#define SDRAM_BURST_LEN_OFFS 0
++#define SDRAM_BURST_LEN_MASK (0x7 << SDRAM_BURST_LEN_OFFS)
++#define SDRAM_BURST_LEN_4 (0x2 << SDRAM_BURST_LEN_OFFS)
++#define SDRAM_CL_OFFS 4
++#define SDRAM_CL_MASK (0x7 << SDRAM_CL_OFFS)
++#define SDRAM_DDR1_CL_2 (0x2 << SDRAM_CL_OFFS)
++#define SDRAM_DDR1_CL_3 (0x3 << SDRAM_CL_OFFS)
++#define SDRAM_DDR1_CL_4 (0x4 << SDRAM_CL_OFFS)
++#define SDRAM_DDR1_CL_1_5 (0x5 << SDRAM_CL_OFFS)
++#define SDRAM_DDR1_CL_2_5 (0x6 << SDRAM_CL_OFFS)
++#define SDRAM_DDR2_CL_3 (0x3 << SDRAM_CL_OFFS)
++#define SDRAM_DDR2_CL_4 (0x4 << SDRAM_CL_OFFS)
++#define SDRAM_DDR2_CL_5 (0x5 << SDRAM_CL_OFFS)
++#define SDRAM_TM_OFFS 7
++#define SDRAM_TM_MASK (1 << SDRAM_TM_OFFS)
++#define SDRAM_TM_NORMAL (0 << SDRAM_TM_OFFS)
++#define SDRAM_TM_TEST_MODE (1 << SDRAM_TM_OFFS)
++#define SDRAM_DLL_OFFS 8
++#define SDRAM_DLL_MASK (1 << SDRAM_DLL_OFFS)
++#define SDRAM_DLL_NORMAL (0 << SDRAM_DLL_OFFS)
++#define SDRAM_DLL_RESET (1 << SDRAM_DLL_OFFS)
++#define SDRAM_WR_OFFS 11
++#define SDRAM_WR_MAX 7
++#define SDRAM_WR_MASK (SDRAM_WR_MAX << SDRAM_WR_OFFS)
++#define SDRAM_PD_OFFS 12
++#define SDRAM_PD_MASK (1 << SDRAM_PD_OFFS)
++#define SDRAM_PD_FAST_EXIT (0 << SDRAM_PD_OFFS)
++#define SDRAM_PD_SLOW_EXIT (1 << SDRAM_PD_OFFS)
++
++/* DDR SDRAM Extended Mode register (DSEMR) */
++#define SDRAM_EXTENDED_MODE_REG 0x1420
++#define DSEMR_DLL_ENABLE (1 << 0)
++#define DSEMR_DS_OFFS 1
++#define DSEMR_DS_MASK (1 << DSEMR_DS_OFFS)
++#define DSEMR_DS_NORMAL (0 << DSEMR_DS_OFFS)
++#define DSEMR_DS_REDUCED (1 << DSEMR_DS_OFFS)
++#define DSEMR_RTT0_OFFS 2
++#define DSEMR_RTT1_OFFS 6
++#define DSEMR_RTT_ODT_DISABLE ((0 << DSEMR_RTT0_OFFS)||(0 << DSEMR_RTT1_OFFS))
++#define DSEMR_RTT_ODT_75_OHM ((1 << DSEMR_RTT0_OFFS)||(0 << DSEMR_RTT1_OFFS))
++#define DSEMR_RTT_ODT_150_OHM ((0 << DSEMR_RTT0_OFFS)||(1 << DSEMR_RTT1_OFFS))
++#define DSEMR_OCD_OFFS 7
++#define DSEMR_OCD_MASK (0x7 << DSEMR_OCD_OFFS)
++#define DSEMR_OCD_EXIT_CALIB (0 << DSEMR_OCD_OFFS)
++#define DSEMR_OCD_DRIVE1 (1 << DSEMR_OCD_OFFS)
++#define DSEMR_OCD_DRIVE0 (2 << DSEMR_OCD_OFFS)
++#define DSEMR_OCD_ADJUST_MODE (4 << DSEMR_OCD_OFFS)
++#define DSEMR_OCD_CALIB_DEFAULT (7 << DSEMR_OCD_OFFS)
++#define DSEMR_DQS_OFFS 10
++#define DSEMR_DQS_MASK (1 << DSEMR_DQS_OFFS)
++#define DSEMR_DQS_DIFFERENTIAL (0 << DSEMR_DQS_OFFS)
++#define DSEMR_DQS_SINGLE_ENDED (0 << DSEMR_DQS_OFFS)
++#define DSEMR_RDQS_ENABLE (1 << 11)
++#define DSEMR_QOFF_OUTPUT_BUFF_EN (1 << 12)
++
++/* DDR SDRAM Operation Control Register */
++#define SDRAM_OPERATION_CTRL_REG 0x142c
++
++/* Dunit FTDLL Configuration Register */
++#define SDRAM_FTDLL_CONFIG_REG 0x1484
++
++/* Pads Calibration register */
++#define SDRAM_ADDR_CTRL_PADS_CAL_REG 0x14c0
++#define SDRAM_DATA_PADS_CAL_REG 0x14c4
++#define SDRAM_DRVN_OFFS 0
++#define SDRAM_DRVN_MASK (0x3F << SDRAM_DRVN_OFFS)
++#define SDRAM_DRVP_OFFS 6
++#define SDRAM_DRVP_MASK (0x3F << SDRAM_DRVP_OFFS)
++#define SDRAM_PRE_DRIVER_STRENGTH_OFFS 12
++#define SDRAM_PRE_DRIVER_STRENGTH_MASK (3 << SDRAM_PRE_DRIVER_STRENGTH_OFFS)
++#define SDRAM_TUNE_EN BIT16
++#define SDRAM_LOCK_OFFS 17
++#define SDRAM_LOCK_MAKS (0x1F << SDRAM_LOCK_OFFS)
++#define SDRAM_LOCKN_OFFS 17
++#define SDRAM_LOCKN_MAKS (0x3F << SDRAM_LOCKN_OFFS)
++#define SDRAM_LOCKP_OFFS 23
++#define SDRAM_LOCKP_MAKS (0x3F << SDRAM_LOCKP_OFFS)
++#define SDRAM_WR_EN (1 << 31)
++
++/* DDR2 SDRAM ODT Control (Low) Register (DSOCLR) */
++#define DDR2_SDRAM_ODT_CTRL_LOW_REG 0x1494
++#define DSOCLR_ODT_RD_OFFS(odtNum) (odtNum * 4)
++#define DSOCLR_ODT_RD_MASK(odtNum) (0xf << DSOCLR_ODT_RD_OFFS(odtNum))
++#define DSOCLR_ODT_RD(odtNum, bank) ((1 << bank) << DSOCLR_ODT_RD_OFFS(odtNum))
++#define DSOCLR_ODT_WR_OFFS(odtNum) (16 + (odtNum * 4))
++#define DSOCLR_ODT_WR_MASK(odtNum) (0xf << DSOCLR_ODT_WR_OFFS(odtNum))
++#define DSOCLR_ODT_WD(odtNum, bank) ((1 << bank) << DSOCLR_ODT_WR_OFFS(odtNum))
++
++/* DDR2 SDRAM ODT Control (High) Register (DSOCHR) */
++#define DDR2_SDRAM_ODT_CTRL_HIGH_REG 0x1498
++/* Optional control values to DSOCHR_ODT_EN macro */
++#define DDR2_ODT_CTRL_DUNIT 0
++#define DDR2_ODT_CTRL_NEVER 1
++#define DDR2_ODT_CTRL_ALWAYS 3
++#define DSOCHR_ODT_EN_OFFS(odtNum) (odtNum * 2)
++#define DSOCHR_ODT_EN_MASK(odtNum) (0x3 << DSOCHR_ODT_EN_OFFS(odtNum))
++#define DSOCHR_ODT_EN(odtNum, ctrl) ((1 << ctrl) << DSOCHR_ODT_RD_OFFS(odtNum))
++
++/* DDR2 Dunit ODT Control Register (DDOCR)*/
++#define DDR2_DUNIT_ODT_CONTROL_REG 0x149c
++#define DDOCR_ODT_RD_OFFS 0
++#define DDOCR_ODT_RD_MASK (0xf << DDOCR_ODT_RD_OFFS)
++#define DDOCR_ODT_RD(bank) ((1 << bank) << DDOCR_ODT_RD_OFFS)
++#define DDOCR_ODT_WR_OFFS 4
++#define DDOCR_ODT_WR_MASK (0xf << DDOCR_ODT_WR_OFFS)
++#define DDOCR_ODT_WR(bank) ((1 << bank) << DDOCR_ODT_WR_OFFS)
++#define DSOCR_ODT_EN_OFFS 8
++#define DSOCR_ODT_EN_MASK (0x3 << DSOCR_ODT_EN_OFFS)
++#define DSOCR_ODT_EN(ctrl) ((1 << ctrl) << DSOCR_ODT_EN_OFFS)
++#define DSOCR_ODT_SEL_OFFS 10
++#define DSOCR_ODT_SEL_MASK (0x3 << DSOCR_ODT_SEL_OFFS)
++
++/* DDR SDRAM Initialization Control Register (DSICR) */
++#define DDR_SDRAM_INIT_CTRL_REG 0x1480
++#define DSICR_INIT_EN (1 << 0)
++
++#endif /* __INCmvDramIfRegsh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.c 2010-11-09 20:28:10.812495401 +0100
+@@ -0,0 +1,1855 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++
++/* includes */
++#include "ddr2/mvDramIf.h"
++#include "ctrlEnv/sys/mvCpuIf.h"
++
++#include "ddr2/mvDramIfStaticInit.h"
++
++/* #define MV_DEBUG */
++#ifdef MV_DEBUG
++#define DB(x) x
++#else
++#define DB(x)
++#endif
++
++/* DRAM bank presence encoding */
++#define BANK_PRESENT_CS0 0x1
++#define BANK_PRESENT_CS0_CS1 0x3
++#define BANK_PRESENT_CS0_CS2 0x5
++#define BANK_PRESENT_CS0_CS1_CS2 0x7
++#define BANK_PRESENT_CS0_CS2_CS3 0xd
++#define BANK_PRESENT_CS0_CS2_CS3_CS4 0xf
++
++/* locals */
++#ifndef MV_STATIC_DRAM_ON_BOARD
++static void sdramDDr2OdtConfig(MV_DRAM_BANK_INFO *pBankInfo);
++static MV_U32 dunitCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 minCas, MV_U32 busClk, MV_STATUS TTmode );
++static MV_U32 dunitCtrlHighRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk);
++static MV_U32 sdramModeRegCalc(MV_U32 minCas);
++static MV_U32 sdramExtModeRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk);
++static MV_U32 sdramAddrCtrlRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_DRAM_BANK_INFO *pBankInfoDIMM1);
++static MV_U32 sdramConfigRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_DRAM_BANK_INFO *pBankInfo2, MV_U32 busClk);
++static MV_U32 minCasCalc(MV_DRAM_BANK_INFO *pBankInfo,MV_DRAM_BANK_INFO *pBankInfo2, MV_U32 busClk, MV_U32 forcedCl);
++static MV_U32 sdramTimeCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 minCas, MV_U32 busClk);
++static MV_U32 sdramTimeCtrlHighRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk);
++static MV_U32 sdramDdr2TimeLoRegCalc(MV_U32 minCas);
++static MV_U32 sdramDdr2TimeHiRegCalc(MV_U32 minCas);
++#endif
++MV_32 DRAM_CS_Order[MV_DRAM_MAX_CS] = {N_A
++
++#ifdef MV_INCLUDE_SDRAM_CS1
++ ,N_A
++#endif
++#ifdef MV_INCLUDE_SDRAM_CS2
++ ,N_A
++#endif
++#ifdef MV_INCLUDE_SDRAM_CS3
++ ,N_A
++#endif
++ };
++/* Get DRAM size of CS num */
++MV_U32 mvDramCsSizeGet(MV_U32 csNum)
++{
++ MV_DRAM_BANK_INFO bankInfo;
++ MV_U32 size, deviceW, dimmW;
++#ifdef MV78XX0
++ MV_U32 temp;
++#endif
++
++ if(MV_OK == mvDramBankInfoGet(csNum, &bankInfo))
++ {
++ if (0 == bankInfo.size)
++ return 0;
++
++ /* Note that the Dimm width might be different then the device DRAM width */
++#ifdef MV78XX0
++ temp = MV_REG_READ(SDRAM_CONFIG_REG);
++ deviceW = ((temp & SDRAM_DWIDTH_MASK) == SDRAM_DWIDTH_32BIT )? 32 : 64;
++#else
++ deviceW = 16 /* KW family */;
++#endif
++ dimmW = bankInfo.dataWidth - (bankInfo.dataWidth % 16);
++ size = ((bankInfo.size << 20) / (dimmW/deviceW));
++ return size;
++ }
++ else
++ return 0;
++}
++/*******************************************************************************
++* mvDramIfDetect - Prepare DRAM interface configuration values.
++*
++* DESCRIPTION:
++* This function implements the full DRAM detection and timing
++* configuration for best system performance.
++* Since this routine runs from a ROM device (Boot Flash), its stack
++* resides on RAM, that might be the system DRAM. Changing DRAM
++* configuration values while keeping vital data in DRAM is risky. That
++* is why the function does not preform the configuration setting but
++* prepare those in predefined 32bit registers (in this case IDMA
++* registers are used) for other routine to perform the settings.
++* The function will call for board DRAM SPD information for each DRAM
++* chip select. The function will then analyze those SPD parameters of
++* all DRAM banks in order to decide on DRAM configuration compatible
++* for all DRAM banks.
++* The function will set the CPU DRAM address decode registers.
++* Note: This routine prepares values that will overide configuration of
++* mvDramBasicAsmInit().
++*
++* INPUT:
++* forcedCl - Forced CAL Latency. If equal to zero, do not force.
++* eccDisable - Force down the ECC.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvDramIfDetect(MV_U32 forcedCl, MV_BOOL eccDisable)
++{
++ MV_32 MV_DRAM_CS_order[MV_DRAM_MAX_CS] = {
++ SDRAM_CS0
++#ifdef MV_INCLUDE_SDRAM_CS1
++ ,SDRAM_CS1
++#endif
++#ifdef MV_INCLUDE_SDRAM_CS2
++ ,SDRAM_CS2
++#endif
++#ifdef MV_INCLUDE_SDRAM_CS3
++ ,SDRAM_CS3
++#endif
++ };
++ MV_U32 busClk, deviceW, dimmW;
++ MV_U32 numOfAllDevices = 0;
++ MV_STATUS TTMode;
++#ifndef MV_STATIC_DRAM_ON_BOARD
++ MV_DRAM_BANK_INFO bankInfo[MV_DRAM_MAX_CS];
++ MV_U32 size, base = 0, i, j, temp, busClkPs;
++ MV_U8 minCas;
++ MV_CPU_DEC_WIN dramDecWin;
++ dramDecWin.addrWin.baseHigh = 0;
++#endif
++
++ busClk = mvBoardSysClkGet();
++
++ if (0 == busClk)
++ {
++ mvOsPrintf("Dram: ERR. Can't detect system clock! \n");
++ return MV_ERROR;
++ }
++
++#ifndef MV_STATIC_DRAM_ON_BOARD
++
++ busClkPs = 1000000000 / (busClk / 1000); /* in ps units */
++ /* we will use bank 0 as the representative of the all the DRAM banks, */
++ /* since bank 0 must exist. */
++ for(i = 0; i < MV_DRAM_MAX_CS; i++)
++ {
++ /* if Bank exist */
++ if(MV_OK == mvDramBankInfoGet(i, &bankInfo[i]))
++ {
++ DB(mvOsPrintf("Dram: Find bank %d\n", i));
++ /* check it isn't SDRAM */
++ if(bankInfo[i].memoryType != MEM_TYPE_DDR2)
++ {
++ mvOsOutput("Dram: ERR. SDRAM type not supported !!!\n");
++ return MV_ERROR;
++ }
++
++ /* All banks must support the Mclk freqency */
++ if(bankInfo[i].minCycleTimeAtMaxCasLatPs > busClkPs)
++ {
++ mvOsOutput("Dram: ERR. Bank %d doesn't support memory clock!!!\n", i);
++ return MV_ERROR;
++ }
++
++ /* All banks must support registry in order to activate it */
++ if(bankInfo[i].registeredAddrAndControlInputs !=
++ bankInfo[0].registeredAddrAndControlInputs)
++ {
++ mvOsOutput("Dram: ERR. different Registered settings !!!\n");
++ return MV_ERROR;
++ }
++
++ /* All banks must support same ECC mode */
++ if(bankInfo[i].errorCheckType !=
++ bankInfo[0].errorCheckType)
++ {
++ mvOsOutput("Dram: ERR. different ECC settings !!!\n");
++ return MV_ERROR;
++ }
++
++ }
++ else
++ {
++ if( i == 0 ) /* bank 0 doesn't exist */
++ {
++ mvOsOutput("Dram: ERR. Fail to detect bank 0 !!!\n");
++ return MV_ERROR;
++ }
++ else
++ {
++ DB(mvOsPrintf("Dram: Could not find bank %d\n", i));
++ bankInfo[i].size = 0; /* Mark this bank as non exist */
++ }
++ }
++ }
++
++#ifdef MV_INCLUDE_SDRAM_CS2
++ if (bankInfo[SDRAM_CS0].size < bankInfo[SDRAM_CS2].size)
++ {
++ MV_DRAM_CS_order[0] = SDRAM_CS2;
++ MV_DRAM_CS_order[1] = SDRAM_CS3;
++ MV_DRAM_CS_order[2] = SDRAM_CS0;
++ MV_DRAM_CS_order[3] = SDRAM_CS1;
++ DRAM_CS_Order[0] = SDRAM_CS2;
++ DRAM_CS_Order[1] = SDRAM_CS3;
++ DRAM_CS_Order[2] = SDRAM_CS0;
++ DRAM_CS_Order[3] = SDRAM_CS1;
++
++ }
++ else
++#endif
++ {
++ MV_DRAM_CS_order[0] = SDRAM_CS0;
++ MV_DRAM_CS_order[1] = SDRAM_CS1;
++ DRAM_CS_Order[0] = SDRAM_CS0;
++ DRAM_CS_Order[1] = SDRAM_CS1;
++#ifdef MV_INCLUDE_SDRAM_CS2
++ MV_DRAM_CS_order[2] = SDRAM_CS2;
++ MV_DRAM_CS_order[3] = SDRAM_CS3;
++ DRAM_CS_Order[2] = SDRAM_CS2;
++ DRAM_CS_Order[3] = SDRAM_CS3;
++#endif
++ }
++
++ for(j = 0; j < MV_DRAM_MAX_CS; j++)
++ {
++ i = MV_DRAM_CS_order[j];
++
++ if (0 == bankInfo[i].size)
++ continue;
++
++ /* Init the CPU window decode */
++ /* Note that the Dimm width might be different then the device DRAM width */
++#ifdef MV78XX0
++ temp = MV_REG_READ(SDRAM_CONFIG_REG);
++ deviceW = ((temp & SDRAM_DWIDTH_MASK) == SDRAM_DWIDTH_32BIT )? 32 : 64;
++#else
++ deviceW = 16 /* KW family */;
++#endif
++ dimmW = bankInfo[0].dataWidth - (bankInfo[0].dataWidth % 16);
++ size = ((bankInfo[i].size << 20) / (dimmW/deviceW));
++
++ /* We can not change DRAM window settings while excecuting */
++ /* code from it. That is why we skip the DRAM CS[0], saving */
++ /* it to the ROM configuration routine */
++
++ numOfAllDevices += bankInfo[i].numberOfDevices;
++ if (i == MV_DRAM_CS_order[0])
++ {
++ MV_U32 sizeToReg;
++ /* Translate the given window size to register format */
++ sizeToReg = ctrlSizeToReg(size, SCSR_SIZE_ALIGNMENT);
++ /* Size parameter validity check. */
++ if (-1 == sizeToReg)
++ {
++ mvOsOutput("DRAM: mvCtrlAddrDecToReg: ERR. Win %d size invalid.\n"
++ ,i);
++ return MV_BAD_PARAM;
++ }
++
++ DB(mvOsPrintf("Dram: Bank 0 Size - %x\n",sizeToReg);)
++ sizeToReg = (sizeToReg << SCSR_SIZE_OFFS);
++ sizeToReg |= SCSR_WIN_EN;
++ MV_REG_WRITE(DRAM_BUF_REG0, sizeToReg);
++ }
++ else
++ {
++ dramDecWin.addrWin.baseLow = base;
++ dramDecWin.addrWin.size = size;
++ dramDecWin.enable = MV_TRUE;
++ DB(mvOsPrintf("Dram: Enable window %d base 0x%x, size=0x%x\n",i, base, size));
++
++ /* Check if the DRAM size is more then 3GByte */
++ if (base < 0xC0000000)
++ {
++ DB(mvOsPrintf("Dram: Enable window %d base 0x%x, size=0x%x\n",i, base, size));
++ if (MV_OK != mvCpuIfTargetWinSet(i, &dramDecWin))
++ {
++ mvOsPrintf("Dram: ERR. Fail to set bank %d!!!\n", SDRAM_CS0 + i);
++ return MV_ERROR;
++ }
++ }
++ }
++
++ base += size;
++
++ /* update the suportedCasLatencies mask */
++ bankInfo[0].suportedCasLatencies &= bankInfo[i].suportedCasLatencies;
++ }
++
++ /* calculate minimum CAS */
++ minCas = minCasCalc(&bankInfo[0], &bankInfo[2], busClk, forcedCl);
++ if (0 == minCas)
++ {
++ mvOsOutput("Dram: Warn: Could not find CAS compatible to SysClk %dMhz\n",
++ (busClk / 1000000));
++
++ minCas = DDR2_CL_4; /* Continue with this CAS */
++ mvOsOutput("Set default CAS latency 4\n");
++ }
++
++ /* calc SDRAM_CONFIG_REG and save it to temp register */
++ temp = sdramConfigRegCalc(&bankInfo[0],&bankInfo[2], busClk);
++ if(-1 == temp)
++ {
++ mvOsOutput("Dram: ERR. sdramConfigRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++
++ /* check if ECC is enabled by the user */
++ if(eccDisable)
++ {
++ /* turn off ECC*/
++ temp &= ~BIT18;
++ }
++ DB(mvOsPrintf("Dram: sdramConfigRegCalc - %x\n",temp);)
++ MV_REG_WRITE(DRAM_BUF_REG1, temp);
++
++ /* calc SDRAM_MODE_REG and save it to temp register */
++ temp = sdramModeRegCalc(minCas);
++ if(-1 == temp)
++ {
++ mvOsOutput("Dram: ERR. sdramModeRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Dram: sdramModeRegCalc - %x\n",temp);)
++ MV_REG_WRITE(DRAM_BUF_REG2, temp);
++
++ /* calc SDRAM_EXTENDED_MODE_REG and save it to temp register */
++ temp = sdramExtModeRegCalc(&bankInfo[0], busClk);
++ if(-1 == temp)
++ {
++ mvOsOutput("Dram: ERR. sdramExtModeRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Dram: sdramExtModeRegCalc - %x\n",temp);)
++ MV_REG_WRITE(DRAM_BUF_REG10, temp);
++
++ /* calc D_UNIT_CONTROL_LOW and save it to temp register */
++ TTMode = MV_FALSE;
++ DB(mvOsPrintf("Dram: numOfAllDevices = %x\n",numOfAllDevices);)
++ if( (numOfAllDevices > 9) && (bankInfo[0].registeredAddrAndControlInputs == MV_FALSE) )
++ {
++ if ( ( (numOfAllDevices > 9) && (busClk > MV_BOARD_SYSCLK_200MHZ) ) ||
++ (numOfAllDevices > 18) )
++ {
++ mvOsOutput("Enable 2T ");
++ TTMode = MV_TRUE;
++ }
++ }
++
++ temp = dunitCtrlLowRegCalc(&bankInfo[0], minCas, busClk, TTMode );
++ if(-1 == temp)
++ {
++ mvOsOutput("Dram: ERR. dunitCtrlLowRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Dram: dunitCtrlLowRegCalc - %x\n",temp);)
++ MV_REG_WRITE(DRAM_BUF_REG3, temp);
++
++ /* calc D_UNIT_CONTROL_HIGH and save it to temp register */
++ temp = dunitCtrlHighRegCalc(&bankInfo[0], busClk);
++ if(-1 == temp)
++ {
++ mvOsOutput("Dram: ERR. dunitCtrlHighRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Dram: dunitCtrlHighRegCalc - %x\n",temp);)
++ /* check if ECC is enabled by the user */
++ if(eccDisable)
++ {
++ /* turn off sample stage if no ecc */
++ temp &= ~SDRAM__D2P_EN;;
++ }
++ MV_REG_WRITE(DRAM_BUF_REG13, temp);
++
++ /* calc SDRAM_ADDR_CTRL_REG and save it to temp register */
++ temp = sdramAddrCtrlRegCalc(&bankInfo[0],&bankInfo[2]);
++ if(-1 == temp)
++ {
++ mvOsOutput("Dram: ERR. sdramAddrCtrlRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Dram: sdramAddrCtrlRegCalc - %x\n",temp);)
++ MV_REG_WRITE(DRAM_BUF_REG4, temp);
++
++ /* calc SDRAM_TIMING_CTRL_LOW_REG and save it to temp register */
++ temp = sdramTimeCtrlLowRegCalc(&bankInfo[0], minCas, busClk);
++ if(-1 == temp)
++ {
++ mvOsOutput("Dram: ERR. sdramTimeCtrlLowRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Dram: sdramTimeCtrlLowRegCalc - %x\n",temp);)
++ MV_REG_WRITE(DRAM_BUF_REG5, temp);
++
++ /* calc SDRAM_TIMING_CTRL_HIGH_REG and save it to temp register */
++ temp = sdramTimeCtrlHighRegCalc(&bankInfo[0], busClk);
++ if(-1 == temp)
++ {
++ mvOsOutput("Dram: ERR. sdramTimeCtrlHighRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Dram: sdramTimeCtrlHighRegCalc - %x\n",temp);)
++ MV_REG_WRITE(DRAM_BUF_REG6, temp);
++
++ sdramDDr2OdtConfig(bankInfo);
++
++ /* calc DDR2_SDRAM_TIMING_LOW_REG and save it to temp register */
++ temp = sdramDdr2TimeLoRegCalc(minCas);
++ if(-1 == temp)
++ {
++ mvOsOutput("Dram: ERR. sdramDdr2TimeLoRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Dram: sdramDdr2TimeLoRegCalc - %x\n",temp);)
++ MV_REG_WRITE(DRAM_BUF_REG11, temp);
++
++ /* calc DDR2_SDRAM_TIMING_HIGH_REG and save it to temp register */
++ temp = sdramDdr2TimeHiRegCalc(minCas);
++ if(-1 == temp)
++ {
++ mvOsOutput("Dram: ERR. sdramDdr2TimeHiRegCalc failed !!!\n");
++ return MV_ERROR;
++ }
++ DB(mvOsPrintf("Dram: sdramDdr2TimeHiRegCalc - %x\n",temp);)
++ MV_REG_WRITE(DRAM_BUF_REG12, temp);
++#endif
++
++ /* Note that DDR SDRAM Address/Control and Data pad calibration */
++ /* settings is done in mvSdramIfConfig.s */
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvDramIfBankBaseGet - Get DRAM interface bank base.
++*
++* DESCRIPTION:
++* This function returns the 32 bit base address of a given DRAM bank.
++*
++* INPUT:
++* bankNum - Bank number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* DRAM bank size. If bank is disabled or paramter is invalid, the
++* function returns -1.
++*
++*******************************************************************************/
++MV_U32 mvDramIfBankBaseGet(MV_U32 bankNum)
++{
++ DB(mvOsPrintf("Dram: mvDramIfBankBaseGet Bank %d base addr is %x \n",
++ bankNum, mvCpuIfTargetWinBaseLowGet(SDRAM_CS0 + bankNum)));
++ return mvCpuIfTargetWinBaseLowGet(SDRAM_CS0 + bankNum);
++}
++
++/*******************************************************************************
++* mvDramIfBankSizeGet - Get DRAM interface bank size.
++*
++* DESCRIPTION:
++* This function returns the size of a given DRAM bank.
++*
++* INPUT:
++* bankNum - Bank number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* DRAM bank size. If bank is disabled the function return '0'. In case
++* or paramter is invalid, the function returns -1.
++*
++*******************************************************************************/
++MV_U32 mvDramIfBankSizeGet(MV_U32 bankNum)
++{
++ DB(mvOsPrintf("Dram: mvDramIfBankSizeGet Bank %d size is %x \n",
++ bankNum, mvCpuIfTargetWinSizeGet(SDRAM_CS0 + bankNum)));
++ return mvCpuIfTargetWinSizeGet(SDRAM_CS0 + bankNum);
++}
++
++
++/*******************************************************************************
++* mvDramIfSizeGet - Get DRAM interface total size.
++*
++* DESCRIPTION:
++* This function get the DRAM total size.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* DRAM total size. In case or paramter is invalid, the function
++* returns -1.
++*
++*******************************************************************************/
++MV_U32 mvDramIfSizeGet(MV_VOID)
++{
++ MV_U32 size = 0, i;
++
++ for(i = 0; i < MV_DRAM_MAX_CS; i++)
++ size += mvDramIfBankSizeGet(i);
++
++ DB(mvOsPrintf("Dram: mvDramIfSizeGet size is %x \n",size));
++ return size;
++}
++
++/*******************************************************************************
++* mvDramIfSingleBitErrThresholdSet - Set single bit ECC threshold.
++*
++* DESCRIPTION:
++* The ECC single bit error threshold is the number of single bit
++* errors to happen before the Dunit generates an interrupt.
++* This function set single bit ECC threshold.
++*
++* INPUT:
++* threshold - threshold.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM if threshold is to big, MV_OK otherwise.
++*
++*******************************************************************************/
++MV_STATUS mvDramIfSingleBitErrThresholdSet(MV_U32 threshold)
++{
++ MV_U32 regVal;
++
++ if (threshold > SECR_THRECC_MAX)
++ {
++ return MV_BAD_PARAM;
++ }
++
++ regVal = MV_REG_READ(SDRAM_ECC_CONTROL_REG);
++ regVal &= ~SECR_THRECC_MASK;
++ regVal |= ((SECR_THRECC(threshold) & SECR_THRECC_MASK));
++ MV_REG_WRITE(SDRAM_ECC_CONTROL_REG, regVal);
++
++ return MV_OK;
++}
++
++#ifndef MV_STATIC_DRAM_ON_BOARD
++/*******************************************************************************
++* minCasCalc - Calculate the Minimum CAS latency which can be used.
++*
++* DESCRIPTION:
++* Calculate the minimum CAS latency that can be used, base on the DRAM
++* parameters and the SDRAM bus Clock freq.
++*
++* INPUT:
++* busClk - the DRAM bus Clock.
++* pBankInfo - bank info parameters.
++* forcedCl - Forced CAS Latency multiplied by 10. If equal to zero, do not force.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* The minimum CAS Latency. The function returns 0 if max CAS latency
++* supported by banks is incompatible with system bus clock frequancy.
++*
++*******************************************************************************/
++
++static MV_U32 minCasCalc(MV_DRAM_BANK_INFO *pBankInfo,MV_DRAM_BANK_INFO *pBankInfo2, MV_U32 busClk, MV_U32 forcedCl)
++{
++ MV_U32 count = 1, j;
++ MV_U32 busClkPs = 1000000000 / (busClk / 1000); /* in ps units */
++ MV_U32 startBit, stopBit;
++ MV_U32 minCas0 = 0, minCas2 = 0;
++
++
++ /* DDR 2:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD *
++ Disco VI= * TBD | TBD | 5 | 4 | 3 | TBD | TBD | TBD *
++ Disco Duo= * TBD | 6 | 5 | 4 | 3 | TBD | TBD | TBD *
++ *********************************************************/
++
++
++ /* If we are asked to use the forced CAL we change the suported CAL to be forcedCl only */
++ if (forcedCl)
++ {
++ mvOsOutput("DRAM: Using forced CL %d.%d\n", (forcedCl / 10), (forcedCl % 10));
++
++ if (forcedCl == 30)
++ pBankInfo->suportedCasLatencies = 0x08;
++ else if (forcedCl == 40)
++ pBankInfo->suportedCasLatencies = 0x10;
++ else if (forcedCl == 50)
++ pBankInfo->suportedCasLatencies = 0x20;
++ else if (forcedCl == 60)
++ pBankInfo->suportedCasLatencies = 0x40;
++ else
++ {
++ mvOsPrintf("Forced CL %d.%d not supported. Set default CL 4\n",
++ (forcedCl / 10), (forcedCl % 10));
++ pBankInfo->suportedCasLatencies = 0x10;
++ }
++
++ return pBankInfo->suportedCasLatencies;
++ }
++
++ /* go over the supported cas mask from Max Cas down and check if the */
++ /* SysClk stands in its time requirments. */
++
++ DB(mvOsPrintf("Dram: minCasCalc supported mask = %x busClkPs = %x \n",
++ pBankInfo->suportedCasLatencies,busClkPs ));
++ count = 1;
++ for(j = 7; j > 0; j--)
++ {
++ if((pBankInfo->suportedCasLatencies >> j) & BIT0 )
++ {
++ /* Reset the bits for CL incompatible for the sysClk */
++ switch (count)
++ {
++ case 1:
++ if (pBankInfo->minCycleTimeAtMaxCasLatPs > busClkPs)
++ pBankInfo->suportedCasLatencies &= ~(BIT0 << j);
++ count++;
++ break;
++ case 2:
++ if (pBankInfo->minCycleTimeAtMaxCasLatMinus1Ps > busClkPs)
++ pBankInfo->suportedCasLatencies &= ~(BIT0 << j);
++ count++;
++ break;
++ case 3:
++ if (pBankInfo->minCycleTimeAtMaxCasLatMinus2Ps > busClkPs)
++ pBankInfo->suportedCasLatencies &= ~(BIT0 << j);
++ count++;
++ break;
++ default:
++ pBankInfo->suportedCasLatencies &= ~(BIT0 << j);
++ break;
++ }
++ }
++ }
++
++ DB(mvOsPrintf("Dram: minCasCalc support = %x (after SysCC calc)\n",
++ pBankInfo->suportedCasLatencies ));
++
++ count = 1;
++ DB(mvOsPrintf("Dram2: minCasCalc supported mask = %x busClkPs = %x \n",
++ pBankInfo2->suportedCasLatencies,busClkPs ));
++ for(j = 7; j > 0; j--)
++ {
++ if((pBankInfo2->suportedCasLatencies >> j) & BIT0 )
++ {
++ /* Reset the bits for CL incompatible for the sysClk */
++ switch (count)
++ {
++ case 1:
++ if (pBankInfo2->minCycleTimeAtMaxCasLatPs > busClkPs)
++ pBankInfo2->suportedCasLatencies &= ~(BIT0 << j);
++ count++;
++ break;
++ case 2:
++ if (pBankInfo2->minCycleTimeAtMaxCasLatMinus1Ps > busClkPs)
++ pBankInfo2->suportedCasLatencies &= ~(BIT0 << j);
++ count++;
++ break;
++ case 3:
++ if (pBankInfo2->minCycleTimeAtMaxCasLatMinus2Ps > busClkPs)
++ pBankInfo2->suportedCasLatencies &= ~(BIT0 << j);
++ count++;
++ break;
++ default:
++ pBankInfo2->suportedCasLatencies &= ~(BIT0 << j);
++ break;
++ }
++ }
++ }
++
++ DB(mvOsPrintf("Dram2: minCasCalc support = %x (after SysCC calc)\n",
++ pBankInfo2->suportedCasLatencies ));
++
++ startBit = 3; /* DDR2 support CL start with CL3 (bit 3) */
++ stopBit = 6; /* DDR2 support CL stops with CL6 (bit 6) */
++
++ for(j = startBit; j <= stopBit ; j++)
++ {
++ if((pBankInfo->suportedCasLatencies >> j) & BIT0 )
++ {
++ DB(mvOsPrintf("Dram: minCasCalc choose CAS %x \n",(BIT0 << j)));
++ minCas0 = (BIT0 << j);
++ break;
++ }
++ }
++
++ for(j = startBit; j <= stopBit ; j++)
++ {
++ if((pBankInfo2->suportedCasLatencies >> j) & BIT0 )
++ {
++ DB(mvOsPrintf("Dram: minCasCalc choose CAS %x \n",(BIT0 << j)));
++ minCas2 = (BIT0 << j);
++ break;
++ }
++ }
++
++ if (minCas2 > minCas0)
++ return minCas2;
++ else
++ return minCas0;
++
++ return 0;
++}
++
++/*******************************************************************************
++* sdramConfigRegCalc - Calculate sdram config register
++*
++* DESCRIPTION: Calculate sdram config register optimized value based
++* on the bank info parameters.
++*
++* INPUT:
++* busClk - the DRAM bus Clock.
++* pBankInfo - sdram bank parameters
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram config reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramConfigRegCalc(MV_DRAM_BANK_INFO *pBankInfo,MV_DRAM_BANK_INFO *pBankInfo2, MV_U32 busClk)
++{
++ MV_U32 sdramConfig = 0;
++ MV_U32 refreshPeriod;
++
++ busClk /= 1000000; /* we work with busClk in MHz */
++
++ sdramConfig = MV_REG_READ(SDRAM_CONFIG_REG);
++
++ /* figure out the memory refresh internal */
++ switch (pBankInfo->refreshInterval & 0xf)
++ {
++ case 0x0: /* refresh period is 15.625 usec */
++ refreshPeriod = 15625;
++ break;
++ case 0x1: /* refresh period is 3.9 usec */
++ refreshPeriod = 3900;
++ break;
++ case 0x2: /* refresh period is 7.8 usec */
++ refreshPeriod = 7800;
++ break;
++ case 0x3: /* refresh period is 31.3 usec */
++ refreshPeriod = 31300;
++ break;
++ case 0x4: /* refresh period is 62.5 usec */
++ refreshPeriod = 62500;
++ break;
++ case 0x5: /* refresh period is 125 usec */
++ refreshPeriod = 125000;
++ break;
++ default: /* refresh period undefined */
++ mvOsPrintf("Dram: ERR. DRAM refresh period is unknown!\n");
++ return -1;
++ }
++
++ /* Now the refreshPeriod is in register format value */
++ refreshPeriod = (busClk * refreshPeriod) / 1000;
++
++ DB(mvOsPrintf("Dram: sdramConfigRegCalc calculated refresh interval %0x\n",
++ refreshPeriod));
++
++ /* make sure the refresh value is only 14 bits */
++ if(refreshPeriod > SDRAM_REFRESH_MAX)
++ {
++ refreshPeriod = SDRAM_REFRESH_MAX;
++ DB(mvOsPrintf("Dram: sdramConfigRegCalc adjusted refresh interval %0x\n",
++ refreshPeriod));
++ }
++
++ /* Clear the refresh field */
++ sdramConfig &= ~SDRAM_REFRESH_MASK;
++
++ /* Set new value to refresh field */
++ sdramConfig |= (refreshPeriod & SDRAM_REFRESH_MASK);
++
++ /* registered DRAM ? */
++ if ( pBankInfo->registeredAddrAndControlInputs )
++ {
++ /* it's registered DRAM, so set the reg. DRAM bit */
++ sdramConfig |= SDRAM_REGISTERED;
++ DB(mvOsPrintf("DRAM Attribute: Registered address and control inputs.\n");)
++ }
++
++ /* ECC and IERR support */
++ sdramConfig &= ~SDRAM_ECC_MASK; /* Clear ECC field */
++ sdramConfig &= ~SDRAM_IERR_MASK; /* Clear IErr field */
++
++ if ( pBankInfo->errorCheckType )
++ {
++ sdramConfig |= SDRAM_ECC_EN;
++ sdramConfig |= SDRAM_IERR_REPORTE;
++ DB(mvOsPrintf("Dram: mvDramIfDetect Enabling ECC\n"));
++ }
++ else
++ {
++ sdramConfig |= SDRAM_ECC_DIS;
++ sdramConfig |= SDRAM_IERR_IGNORE;
++ DB(mvOsPrintf("Dram: mvDramIfDetect Disabling ECC!\n"));
++ }
++ /* Set static default settings */
++ sdramConfig |= SDRAM_CONFIG_DV;
++
++ DB(mvOsPrintf("Dram: sdramConfigRegCalc set sdramConfig to 0x%x\n",
++ sdramConfig));
++
++ return sdramConfig;
++}
++
++/*******************************************************************************
++* sdramModeRegCalc - Calculate sdram mode register
++*
++* DESCRIPTION: Calculate sdram mode register optimized value based
++* on the bank info parameters and the minCas.
++*
++* INPUT:
++* minCas - minimum CAS supported.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram mode reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramModeRegCalc(MV_U32 minCas)
++{
++ MV_U32 sdramMode;
++
++ sdramMode = MV_REG_READ(SDRAM_MODE_REG);
++
++ /* Clear CAS Latency field */
++ sdramMode &= ~SDRAM_CL_MASK;
++
++ DB(mvOsPrintf("DRAM CAS Latency ");)
++
++ switch (minCas)
++ {
++ case DDR2_CL_3:
++ sdramMode |= SDRAM_DDR2_CL_3;
++ DB(mvOsPrintf("3.\n");)
++ break;
++ case DDR2_CL_4:
++ sdramMode |= SDRAM_DDR2_CL_4;
++ DB(mvOsPrintf("4.\n");)
++ break;
++ case DDR2_CL_5:
++ sdramMode |= SDRAM_DDR2_CL_5;
++ DB(mvOsPrintf("5.\n");)
++ break;
++ case DDR2_CL_6:
++ sdramMode |= SDRAM_DDR2_CL_6;
++ DB(mvOsPrintf("6.\n");)
++ break;
++ default:
++ mvOsOutput("\nsdramModeRegCalc ERROR: Max. CL out of range\n");
++ return -1;
++ }
++
++ DB(mvOsPrintf("\nsdramModeRegCalc register 0x%x\n", sdramMode ));
++
++ return sdramMode;
++}
++/*******************************************************************************
++* sdramExtModeRegCalc - Calculate sdram Extended mode register
++*
++* DESCRIPTION:
++* Return sdram Extended mode register value based
++* on the bank info parameters and bank presence.
++*
++* INPUT:
++* pBankInfo - sdram bank parameters
++* busClk - DRAM frequency
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram Extended mode reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramExtModeRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk)
++{
++ MV_U32 populateBanks = 0;
++ int bankNum;
++
++ /* Represent the populate banks in binary form */
++ for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ {
++ if (0 != pBankInfo[bankNum].size)
++ {
++ populateBanks |= (1 << bankNum);
++ }
++ }
++
++ switch(populateBanks)
++ {
++ case(BANK_PRESENT_CS0):
++ case(BANK_PRESENT_CS0_CS1):
++ return DDR_SDRAM_EXT_MODE_CS0_CS1_DV;
++
++ case(BANK_PRESENT_CS0_CS2):
++ case(BANK_PRESENT_CS0_CS1_CS2):
++ case(BANK_PRESENT_CS0_CS2_CS3):
++ case(BANK_PRESENT_CS0_CS2_CS3_CS4):
++ if (busClk >= MV_BOARD_SYSCLK_267MHZ)
++ return DDR_SDRAM_EXT_MODE_FAST_CS0_CS1_CS2_CS3_DV;
++ else
++ return DDR_SDRAM_EXT_MODE_CS0_CS1_CS2_CS3_DV;
++
++ default:
++ mvOsOutput("sdramExtModeRegCalc: Invalid DRAM bank presence\n");
++ return -1;
++ }
++ return 0;
++}
++
++/*******************************************************************************
++* dunitCtrlLowRegCalc - Calculate sdram dunit control low register
++*
++* DESCRIPTION: Calculate sdram dunit control low register optimized value based
++* on the bank info parameters and the minCas.
++*
++* INPUT:
++* pBankInfo - sdram bank parameters
++* minCas - minimum CAS supported.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram dunit control low reg value.
++*
++*******************************************************************************/
++static MV_U32 dunitCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 minCas, MV_U32 busClk, MV_STATUS TTMode)
++{
++ MV_U32 dunitCtrlLow, cl;
++ MV_U32 sbOutR[4]={3,5,7,9} ;
++ MV_U32 sbOutU[4]={1,3,5,7} ;
++
++ dunitCtrlLow = MV_REG_READ(SDRAM_DUNIT_CTRL_REG);
++
++ DB(mvOsPrintf("Dram: dunitCtrlLowRegCalc\n"));
++
++ /* Clear StBurstOutDel field */
++ dunitCtrlLow &= ~SDRAM_SB_OUT_MASK;
++
++ /* Clear StBurstInDel field */
++ dunitCtrlLow &= ~SDRAM_SB_IN_MASK;
++
++ /* Clear CtrlPos field */
++ dunitCtrlLow &= ~SDRAM_CTRL_POS_MASK;
++
++ /* Clear 2T field */
++ dunitCtrlLow &= ~SDRAM_2T_MASK;
++ if (TTMode == MV_TRUE)
++ {
++ dunitCtrlLow |= SDRAM_2T_MODE;
++ }
++
++ /* For proper sample of read data set the Dunit Control register's */
++ /* stBurstInDel bits [27:24] */
++ /* 200MHz - 267MHz None reg = CL + 1 */
++ /* 200MHz - 267MHz reg = CL + 2 */
++ /* > 267MHz None reg = CL + 2 */
++ /* > 267MHz reg = CL + 3 */
++
++ /* For proper sample of read data set the Dunit Control register's */
++ /* stBurstOutDel bits [23:20] */
++ /********-********-********-********-
++ * CL=3 | CL=4 | CL=5 | CL=6 |
++ *********-********-********-********-
++ Not Reg. * 0001 | 0011 | 0101 | 0111 |
++ *********-********-********-********-
++ Registered * 0011 | 0101 | 0111 | 1001 |
++ *********-********-********-********/
++
++ /* Set Dunit Control low default value */
++ dunitCtrlLow |= SDRAM_DUNIT_CTRL_LOW_DDR2_DV;
++
++ switch (minCas)
++ {
++ case DDR2_CL_3: cl = 3; break;
++ case DDR2_CL_4: cl = 4; break;
++ case DDR2_CL_5: cl = 5; break;
++ case DDR2_CL_6: cl = 6; break;
++ default:
++ mvOsOutput("Dram: dunitCtrlLowRegCalc Max. CL out of range %d\n", minCas);
++ return -1;
++ }
++
++ /* registerd DDR SDRAM? */
++ if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE)
++ {
++ dunitCtrlLow |= (sbOutR[cl-3]) << SDRAM_SB_OUT_DEL_OFFS;
++ }
++ else
++ {
++ dunitCtrlLow |= (sbOutU[cl-3]) << SDRAM_SB_OUT_DEL_OFFS;
++ }
++
++ DB(mvOsPrintf("\n\ndunitCtrlLowRegCalc: CL = %d, frequencies=%d\n", cl, busClk));
++
++ if (busClk <= MV_BOARD_SYSCLK_267MHZ)
++ {
++ if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE)
++ cl = cl + 2;
++ else
++ cl = cl + 1;
++ }
++ else
++ {
++ if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE)
++ cl = cl + 3;
++ else
++ cl = cl + 2;
++ }
++
++ DB(mvOsPrintf("dunitCtrlLowRegCalc: SDRAM_SB_IN_DEL_OFFS = %d \n", cl));
++ dunitCtrlLow |= cl << SDRAM_SB_IN_DEL_OFFS;
++
++ DB(mvOsPrintf("Dram: Reg dunit control low = %x\n", dunitCtrlLow ));
++
++ return dunitCtrlLow;
++}
++
++/*******************************************************************************
++* dunitCtrlHighRegCalc - Calculate sdram dunit control high register
++*
++* DESCRIPTION: Calculate sdram dunit control high register optimized value based
++* on the bus clock.
++*
++* INPUT:
++* busClk - DRAM frequency.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram dunit control high reg value.
++*
++*******************************************************************************/
++static MV_U32 dunitCtrlHighRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk)
++{
++ MV_U32 dunitCtrlHigh;
++ dunitCtrlHigh = MV_REG_READ(SDRAM_DUNIT_CTRL_HI_REG);
++ if(busClk > MV_BOARD_SYSCLK_300MHZ)
++ dunitCtrlHigh |= SDRAM__P2D_EN;
++ else
++ dunitCtrlHigh &= ~SDRAM__P2D_EN;
++
++ if(busClk > MV_BOARD_SYSCLK_267MHZ)
++ dunitCtrlHigh |= (SDRAM__WR_MESH_DELAY_EN | SDRAM__PUP_ZERO_SKEW_EN | SDRAM__ADD_HALF_FCC_EN);
++
++ /* If ECC support we turn on D2P sample */
++ dunitCtrlHigh &= ~SDRAM__D2P_EN; /* Clear D2P bit */
++ if (( pBankInfo->errorCheckType ) && (busClk > MV_BOARD_SYSCLK_267MHZ))
++ dunitCtrlHigh |= SDRAM__D2P_EN;
++
++ return dunitCtrlHigh;
++}
++
++/*******************************************************************************
++* sdramAddrCtrlRegCalc - Calculate sdram address control register
++*
++* DESCRIPTION: Calculate sdram address control register optimized value based
++* on the bank info parameters and the minCas.
++*
++* INPUT:
++* pBankInfo - sdram bank parameters
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram address control reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramAddrCtrlRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_DRAM_BANK_INFO *pBankInfoDIMM1)
++{
++ MV_U32 addrCtrl = 0;
++
++ if (pBankInfoDIMM1->size)
++ {
++ switch (pBankInfoDIMM1->sdramWidth)
++ {
++ case 4: /* memory is x4 */
++ mvOsOutput("sdramAddrCtrlRegCalc: Error - x4 not supported!\n");
++ return -1;
++ break;
++ case 8: /* memory is x8 */
++ addrCtrl |= SDRAM_ADDRSEL_X8(2) | SDRAM_ADDRSEL_X8(3);
++ DB(mvOsPrintf("sdramAddrCtrlRegCalc: sdramAddrCtrlRegCalc SDRAM device DIMM2 width x8\n"));
++ break;
++ case 16:
++ addrCtrl |= SDRAM_ADDRSEL_X16(2) | SDRAM_ADDRSEL_X16(3);
++ DB(mvOsPrintf("sdramAddrCtrlRegCalc: sdramAddrCtrlRegCalc SDRAM device DIMM2 width x16\n"));
++ break;
++ default: /* memory width unsupported */
++ mvOsOutput("sdramAddrCtrlRegCalc: ERR. DRAM chip width is unknown!\n");
++ return -1;
++ }
++ }
++
++ switch (pBankInfo->sdramWidth)
++ {
++ case 4: /* memory is x4 */
++ mvOsOutput("sdramAddrCtrlRegCalc: Error - x4 not supported!\n");
++ return -1;
++ break;
++ case 8: /* memory is x8 */
++ addrCtrl |= SDRAM_ADDRSEL_X8(0) | SDRAM_ADDRSEL_X8(1);
++ DB(mvOsPrintf("sdramAddrCtrlRegCalc: sdramAddrCtrlRegCalc SDRAM device width x8\n"));
++ break;
++ case 16:
++ addrCtrl |= SDRAM_ADDRSEL_X16(0) | SDRAM_ADDRSEL_X16(1);
++ DB(mvOsPrintf("sdramAddrCtrlRegCalc: sdramAddrCtrlRegCalc SDRAM device width x16\n"));
++ break;
++ default: /* memory width unsupported */
++ mvOsOutput("sdramAddrCtrlRegCalc: ERR. DRAM chip width is unknown!\n");
++ return -1;
++ }
++
++ /* Note that density is in MB units */
++ switch (pBankInfo->deviceDensity)
++ {
++ case 256: /* 256 Mbit */
++ DB(mvOsPrintf("DRAM Device Density 256Mbit\n"));
++ addrCtrl |= SDRAM_DSIZE_256Mb(0) | SDRAM_DSIZE_256Mb(1);
++ break;
++ case 512: /* 512 Mbit */
++ DB(mvOsPrintf("DRAM Device Density 512Mbit\n"));
++ addrCtrl |= SDRAM_DSIZE_512Mb(0) | SDRAM_DSIZE_512Mb(1);
++ break;
++ case 1024: /* 1 Gbit */
++ DB(mvOsPrintf("DRAM Device Density 1Gbit\n"));
++ addrCtrl |= SDRAM_DSIZE_1Gb(0) | SDRAM_DSIZE_1Gb(1);
++ break;
++ case 2048: /* 2 Gbit */
++ DB(mvOsPrintf("DRAM Device Density 2Gbit\n"));
++ addrCtrl |= SDRAM_DSIZE_2Gb(0) | SDRAM_DSIZE_2Gb(1);
++ break;
++ default:
++ mvOsOutput("Dram: sdramAddrCtrl unsupported RAM-Device size %d\n",
++ pBankInfo->deviceDensity);
++ return -1;
++ }
++
++ if (pBankInfoDIMM1->size)
++ {
++ switch (pBankInfoDIMM1->deviceDensity)
++ {
++ case 256: /* 256 Mbit */
++ DB(mvOsPrintf("DIMM2: DRAM Device Density 256Mbit\n"));
++ addrCtrl |= SDRAM_DSIZE_256Mb(2) | SDRAM_DSIZE_256Mb(3);
++ break;
++ case 512: /* 512 Mbit */
++ DB(mvOsPrintf("DIMM2: DRAM Device Density 512Mbit\n"));
++ addrCtrl |= SDRAM_DSIZE_512Mb(2) | SDRAM_DSIZE_512Mb(3);
++ break;
++ case 1024: /* 1 Gbit */
++ DB(mvOsPrintf("DIMM2: DRAM Device Density 1Gbit\n"));
++ addrCtrl |= SDRAM_DSIZE_1Gb(2) | SDRAM_DSIZE_1Gb(3);
++ break;
++ case 2048: /* 2 Gbit */
++ DB(mvOsPrintf("DIMM2: DRAM Device Density 2Gbit\n"));
++ addrCtrl |= SDRAM_DSIZE_2Gb(2) | SDRAM_DSIZE_2Gb(3);
++ break;
++ default:
++ mvOsOutput("DIMM2: Dram: sdramAddrCtrl unsupported RAM-Device size %d\n",
++ pBankInfoDIMM1->deviceDensity);
++ return -1;
++ }
++ }
++ /* SDRAM address control */
++ DB(mvOsPrintf("Dram: setting sdram address control with: %x \n", addrCtrl));
++
++ return addrCtrl;
++}
++
++/*******************************************************************************
++* sdramTimeCtrlLowRegCalc - Calculate sdram timing control low register
++*
++* DESCRIPTION:
++* This function calculates sdram timing control low register
++* optimized value based on the bank info parameters and the minCas.
++*
++* INPUT:
++* pBankInfo - sdram bank parameters
++* minCas - minimum CAS supported.
++* busClk - Bus clock
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram timing control low reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramTimeCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 minCas, MV_U32 busClk)
++{
++ MV_U32 tRp = 0;
++ MV_U32 tRrd = 0;
++ MV_U32 tRcd = 0;
++ MV_U32 tRas = 0;
++ MV_U32 tWr = 0;
++ MV_U32 tWtr = 0;
++ MV_U32 tRtp = 0;
++ MV_U32 timeCtrlLow = 0;
++
++ MV_U32 bankNum;
++
++ busClk = busClk / 1000000; /* In MHz */
++
++ /* Scan all DRAM banks to find maximum timing values */
++ for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ {
++ tRp = MV_MAX(tRp, pBankInfo[bankNum].minRowPrechargeTime);
++ tRrd = MV_MAX(tRrd, pBankInfo[bankNum].minRowActiveToRowActive);
++ tRcd = MV_MAX(tRcd, pBankInfo[bankNum].minRasToCasDelay);
++ tRas = MV_MAX(tRas, pBankInfo[bankNum].minRasPulseWidth);
++ }
++
++ /* Extract timing (in ns) from SPD value. We ignore the tenth ns part. */
++ /* by shifting the data two bits right. */
++ tRp = tRp >> 2; /* For example 0x50 -> 20ns */
++ tRrd = tRrd >> 2;
++ tRcd = tRcd >> 2;
++
++ /* Extract clock cycles from time parameter. We need to round up */
++ tRp = ((busClk * tRp) / 1000) + (((busClk * tRp) % 1000) ? 1 : 0);
++ DB(mvOsPrintf("Dram Timing Low: tRp = %d ", tRp));
++ tRrd = ((busClk * tRrd) / 1000) + (((busClk * tRrd) % 1000) ? 1 : 0);
++ /* JEDEC min reqeirments tRrd = 2 */
++ if (tRrd < 2)
++ tRrd = 2;
++ DB(mvOsPrintf("tRrd = %d ", tRrd));
++ tRcd = ((busClk * tRcd) / 1000) + (((busClk * tRcd) % 1000) ? 1 : 0);
++ DB(mvOsPrintf("tRcd = %d ", tRcd));
++ tRas = ((busClk * tRas) / 1000) + (((busClk * tRas) % 1000) ? 1 : 0);
++ DB(mvOsPrintf("tRas = %d ", tRas));
++
++ /* tWr and tWtr is different for DDR1 and DDR2. tRtp is only for DDR2 */
++ /* Scan all DRAM banks to find maximum timing values */
++ for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ {
++ tWr = MV_MAX(tWr, pBankInfo[bankNum].minWriteRecoveryTime);
++ tWtr = MV_MAX(tWtr, pBankInfo[bankNum].minWriteToReadCmdDelay);
++ tRtp = MV_MAX(tRtp, pBankInfo[bankNum].minReadToPrechCmdDelay);
++ }
++
++ /* Extract timing (in ns) from SPD value. We ignore the tenth ns */
++ /* part by shifting the data two bits right. */
++ tWr = tWr >> 2; /* For example 0x50 -> 20ns */
++ tWtr = tWtr >> 2;
++ tRtp = tRtp >> 2;
++ /* Extract clock cycles from time parameter. We need to round up */
++ tWr = ((busClk * tWr) / 1000) + (((busClk * tWr) % 1000) ? 1 : 0);
++ DB(mvOsPrintf("tWr = %d ", tWr));
++ tWtr = ((busClk * tWtr) / 1000) + (((busClk * tWtr) % 1000) ? 1 : 0);
++ /* JEDEC min reqeirments tWtr = 2 */
++ if (tWtr < 2)
++ tWtr = 2;
++ DB(mvOsPrintf("tWtr = %d ", tWtr));
++ tRtp = ((busClk * tRtp) / 1000) + (((busClk * tRtp) % 1000) ? 1 : 0);
++ /* JEDEC min reqeirments tRtp = 2 */
++ if (tRtp < 2)
++ tRtp = 2;
++ DB(mvOsPrintf("tRtp = %d ", tRtp));
++
++ /* Note: value of 0 in register means one cycle, 1 means two and so on */
++ timeCtrlLow = (((tRp - 1) << SDRAM_TRP_OFFS) |
++ ((tRrd - 1) << SDRAM_TRRD_OFFS) |
++ ((tRcd - 1) << SDRAM_TRCD_OFFS) |
++ (((tRas - 1) << SDRAM_TRAS_OFFS) & SDRAM_TRAS_MASK)|
++ ((tWr - 1) << SDRAM_TWR_OFFS) |
++ ((tWtr - 1) << SDRAM_TWTR_OFFS) |
++ ((tRtp - 1) << SDRAM_TRTP_OFFS));
++
++ /* Check extended tRas bit */
++ if ((tRas - 1) & BIT4)
++ timeCtrlLow |= (1 << SDRAM_EXT_TRAS_OFFS);
++
++ return timeCtrlLow;
++}
++
++/*******************************************************************************
++* sdramTimeCtrlHighRegCalc - Calculate sdram timing control high register
++*
++* DESCRIPTION:
++* This function calculates sdram timing control high register
++* optimized value based on the bank info parameters and the bus clock.
++*
++* INPUT:
++* pBankInfo - sdram bank parameters
++* busClk - Bus clock
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* sdram timing control high reg value.
++*
++*******************************************************************************/
++static MV_U32 sdramTimeCtrlHighRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk)
++{
++ MV_U32 tRfc;
++ MV_U32 timingHigh;
++ MV_U32 timeNs = 0;
++ MV_U32 bankNum;
++
++ busClk = busClk / 1000000; /* In MHz */
++
++ /* Set DDR timing high register static configuration bits */
++ timingHigh = MV_REG_READ(SDRAM_TIMING_CTRL_HIGH_REG);
++
++ /* Set DDR timing high register default value */
++ timingHigh |= SDRAM_TIMING_CTRL_HIGH_REG_DV;
++
++ /* Clear tRfc field */
++ timingHigh &= ~SDRAM_TRFC_MASK;
++
++ /* Scan all DRAM banks to find maximum timing values */
++ for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ {
++ timeNs = MV_MAX(timeNs, pBankInfo[bankNum].minRefreshToActiveCmd);
++ DB(mvOsPrintf("Dram: Timing High: minRefreshToActiveCmd = %d\n",
++ pBankInfo[bankNum].minRefreshToActiveCmd));
++ }
++ if(busClk >= 333 && mvCtrlModelGet() == MV_78XX0_A1_REV)
++ {
++ timingHigh |= 0x1 << SDRAM_TR2W_W2R_OFFS;
++ }
++
++ tRfc = ((busClk * timeNs) / 1000) + (((busClk * timeNs) % 1000) ? 1 : 0);
++ /* Note: value of 0 in register means one cycle, 1 means two and so on */
++ DB(mvOsPrintf("Dram: Timing High: tRfc = %d\n", tRfc));
++ timingHigh |= (((tRfc - 1) & SDRAM_TRFC_MASK) << SDRAM_TRFC_OFFS);
++ DB(mvOsPrintf("Dram: Timing High: tRfc = %d\n", tRfc));
++
++ /* SDRAM timing high */
++ DB(mvOsPrintf("Dram: setting timing high with: %x \n", timingHigh));
++
++ return timingHigh;
++}
++/*******************************************************************************
++* sdramDDr2OdtConfig - Set DRAM DDR2 On Die Termination registers.
++*
++* DESCRIPTION:
++* This function config DDR2 On Die Termination (ODT) registers.
++*
++* INPUT:
++* pBankInfo - bank info parameters.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* None
++*******************************************************************************/
++static void sdramDDr2OdtConfig(MV_DRAM_BANK_INFO *pBankInfo)
++{
++ MV_U32 populateBanks = 0;
++ MV_U32 odtCtrlLow, odtCtrlHigh, dunitOdtCtrl;
++ int bankNum;
++
++ /* Represent the populate banks in binary form */
++ for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++)
++ {
++ if (0 != pBankInfo[bankNum].size)
++ {
++ populateBanks |= (1 << bankNum);
++ }
++ }
++
++ switch(populateBanks)
++ {
++ case(BANK_PRESENT_CS0):
++ case(BANK_PRESENT_CS0_CS1):
++ odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS1_DV;
++ odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS1_DV;
++ dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS1_DV;
++ break;
++ case(BANK_PRESENT_CS0_CS2):
++ case(BANK_PRESENT_CS0_CS1_CS2):
++ case(BANK_PRESENT_CS0_CS2_CS3):
++ case(BANK_PRESENT_CS0_CS2_CS3_CS4):
++ odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS1_CS2_CS3_DV;
++ odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS1_CS2_CS3_DV;
++ dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS1_CS2_CS3_DV;
++ break;
++ default:
++ DB(mvOsPrintf("sdramDDr2OdtConfig: Invalid DRAM bank presence\n"));
++ return;
++ }
++ /* DDR2 SDRAM ODT ctrl low */
++ DB(mvOsPrintf("Dram: DDR2 setting ODT ctrl low with: %x \n", odtCtrlLow));
++ MV_REG_WRITE(DRAM_BUF_REG7, odtCtrlLow);
++
++ /* DDR2 SDRAM ODT ctrl high */
++ DB(mvOsPrintf("Dram: DDR2 setting ODT ctrl high with: %x \n", odtCtrlHigh));
++ MV_REG_WRITE(DRAM_BUF_REG8, odtCtrlHigh);
++
++ /* DDR2 DUNIT ODT ctrl */
++ if ( ((mvCtrlModelGet() == MV_78XX0_DEV_ID) && (mvCtrlRevGet() == MV_78XX0_Y0_REV)) ||
++ (mvCtrlModelGet() == MV_76100_DEV_ID) ||
++ (mvCtrlModelGet() == MV_78100_DEV_ID) ||
++ (mvCtrlModelGet() == MV_78200_DEV_ID) )
++ dunitOdtCtrl &= ~(BIT9|BIT8); /* Clear ODT always on */
++
++ DB(mvOsPrintf("DUNIT: DDR2 setting ODT ctrl with: %x \n", dunitOdtCtrl));
++ MV_REG_WRITE(DRAM_BUF_REG9, dunitOdtCtrl);
++ return;
++}
++/*******************************************************************************
++* sdramDdr2TimeLoRegCalc - Set DDR2 DRAM Timing Low registers.
++*
++* DESCRIPTION:
++* This function config DDR2 DRAM Timing low registers.
++*
++* INPUT:
++* minCas - minimum CAS supported.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* DDR2 sdram timing low reg value.
++*******************************************************************************/
++static MV_U32 sdramDdr2TimeLoRegCalc(MV_U32 minCas)
++{
++ MV_U8 cl = -1;
++ MV_U32 ddr2TimeLoReg;
++
++ /* read and clear the feilds we are going to set */
++ ddr2TimeLoReg = MV_REG_READ(SDRAM_DDR2_TIMING_LO_REG);
++ ddr2TimeLoReg &= ~(SD2TLR_TODT_ON_RD_MASK |
++ SD2TLR_TODT_OFF_RD_MASK |
++ SD2TLR_TODT_ON_CTRL_RD_MASK |
++ SD2TLR_TODT_OFF_CTRL_RD_MASK);
++
++ if( minCas == DDR2_CL_3 )
++ {
++ cl = 3;
++ }
++ else if( minCas == DDR2_CL_4 )
++ {
++ cl = 4;
++ }
++ else if( minCas == DDR2_CL_5 )
++ {
++ cl = 5;
++ }
++ else if( minCas == DDR2_CL_6 )
++ {
++ cl = 6;
++ }
++ else
++ {
++ DB(mvOsPrintf("sdramDdr2TimeLoRegCalc: CAS latency %d unsupported. using CAS latency 4\n",
++ minCas));
++ cl = 4;
++ }
++
++ ddr2TimeLoReg |= ((cl-3) << SD2TLR_TODT_ON_RD_OFFS);
++ ddr2TimeLoReg |= ( cl << SD2TLR_TODT_OFF_RD_OFFS);
++ ddr2TimeLoReg |= ( cl << SD2TLR_TODT_ON_CTRL_RD_OFFS);
++ ddr2TimeLoReg |= ((cl+3) << SD2TLR_TODT_OFF_CTRL_RD_OFFS);
++
++ /* DDR2 SDRAM timing low */
++ DB(mvOsPrintf("Dram: DDR2 setting timing low with: %x \n", ddr2TimeLoReg));
++
++ return ddr2TimeLoReg;
++}
++
++/*******************************************************************************
++* sdramDdr2TimeHiRegCalc - Set DDR2 DRAM Timing High registers.
++*
++* DESCRIPTION:
++* This function config DDR2 DRAM Timing high registers.
++*
++* INPUT:
++* minCas - minimum CAS supported.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* DDR2 sdram timing high reg value.
++*******************************************************************************/
++static MV_U32 sdramDdr2TimeHiRegCalc(MV_U32 minCas)
++{
++ MV_U8 cl = -1;
++ MV_U32 ddr2TimeHiReg;
++
++ /* read and clear the feilds we are going to set */
++ ddr2TimeHiReg = MV_REG_READ(SDRAM_DDR2_TIMING_HI_REG);
++ ddr2TimeHiReg &= ~(SD2THR_TODT_ON_WR_MASK |
++ SD2THR_TODT_OFF_WR_MASK |
++ SD2THR_TODT_ON_CTRL_WR_MASK |
++ SD2THR_TODT_OFF_CTRL_WR_MASK);
++
++ if( minCas == DDR2_CL_3 )
++ {
++ cl = 3;
++ }
++ else if( minCas == DDR2_CL_4 )
++ {
++ cl = 4;
++ }
++ else if( minCas == DDR2_CL_5 )
++ {
++ cl = 5;
++ }
++ else if( minCas == DDR2_CL_6 )
++ {
++ cl = 6;
++ }
++ else
++ {
++ mvOsOutput("sdramDdr2TimeHiRegCalc: CAS latency %d unsupported. using CAS latency 4\n",
++ minCas);
++ cl = 4;
++ }
++
++ ddr2TimeHiReg |= ((cl-3) << SD2THR_TODT_ON_WR_OFFS);
++ ddr2TimeHiReg |= ( cl << SD2THR_TODT_OFF_WR_OFFS);
++ ddr2TimeHiReg |= ( cl << SD2THR_TODT_ON_CTRL_WR_OFFS);
++ ddr2TimeHiReg |= ((cl+3) << SD2THR_TODT_OFF_CTRL_WR_OFFS);
++
++ /* DDR2 SDRAM timin high */
++ DB(mvOsPrintf("Dram: DDR2 setting timing high with: %x \n", ddr2TimeHiReg));
++
++ return ddr2TimeHiReg;
++}
++#endif
++
++/*******************************************************************************
++* mvDramIfCalGet - Get CAS Latency
++*
++* DESCRIPTION:
++* This function get the CAS Latency.
++*
++* INPUT:
++* None
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* CAS latency times 10 (to avoid using floating point).
++*
++*******************************************************************************/
++MV_U32 mvDramIfCalGet(void)
++{
++ MV_U32 sdramCasLat, casLatMask;
++
++ casLatMask = (MV_REG_READ(SDRAM_MODE_REG) & SDRAM_CL_MASK);
++
++ switch (casLatMask)
++ {
++ case SDRAM_DDR2_CL_3:
++ sdramCasLat = 30;
++ break;
++ case SDRAM_DDR2_CL_4:
++ sdramCasLat = 40;
++ break;
++ case SDRAM_DDR2_CL_5:
++ sdramCasLat = 50;
++ break;
++ case SDRAM_DDR2_CL_6:
++ sdramCasLat = 60;
++ break;
++ default:
++ mvOsOutput("mvDramIfCalGet: Err, unknown DDR2 CAL\n");
++ return -1;
++ }
++
++ return sdramCasLat;
++}
++
++
++/*******************************************************************************
++* mvDramIfSelfRefreshSet - Put the dram in self refresh mode -
++*
++* DESCRIPTION:
++* add support in power management.
++*
++*
++* INPUT:
++* None
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* None
++*
++*******************************************************************************/
++
++MV_VOID mvDramIfSelfRefreshSet()
++{
++ MV_U32 operReg;
++
++ operReg = MV_REG_READ(SDRAM_OPERATION_REG);
++ MV_REG_WRITE(SDRAM_OPERATION_REG ,operReg |SDRAM_CMD_SLF_RFRSH);
++ /* Read until register is reset to 0 */
++ while(MV_REG_READ(SDRAM_OPERATION_REG));
++}
++/*******************************************************************************
++* mvDramIfDimGetSPDversion - return DIMM SPD version.
++*
++* DESCRIPTION:
++* This function prints the DRAM controller information.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++static void mvDramIfDimGetSPDversion(MV_U32 *pMajor, MV_U32 *pMinor, MV_U32 bankNum)
++{
++ MV_DIMM_INFO dimmInfo;
++ if (bankNum >= MV_DRAM_MAX_CS )
++ {
++ DB(mvOsPrintf("Dram: mvDramIfDimGetSPDversion bad params \n"));
++ return ;
++ }
++ memset(&dimmInfo,0,sizeof(dimmInfo));
++ if ( MV_OK != dimmSpdGet((MV_U32)(bankNum/2), &dimmInfo))
++ {
++ DB(mvOsPrintf("Dram: ERR dimmSpdGet failed to get dimm info \n"));
++ return ;
++ }
++ *pMajor = dimmInfo.spdRawData[DIMM_SPD_VERSION]/10;
++ *pMinor = dimmInfo.spdRawData[DIMM_SPD_VERSION]%10;
++}
++/*******************************************************************************
++* mvDramIfShow - Show DRAM controller information.
++*
++* DESCRIPTION:
++* This function prints the DRAM controller information.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++void mvDramIfShow(void)
++{
++ int i, sdramCasLat, sdramCsSize;
++ MV_U32 Major=0, Minor=0;
++
++ mvOsOutput("DRAM Controller info:\n");
++
++ mvOsOutput("Total DRAM ");
++ mvSizePrint(mvDramIfSizeGet());
++ mvOsOutput("\n");
++
++ for(i = 0; i < MV_DRAM_MAX_CS; i++)
++ {
++ sdramCsSize = mvDramIfBankSizeGet(i);
++ if (sdramCsSize)
++ {
++ if (0 == (i & 1))
++ {
++ mvDramIfDimGetSPDversion(&Major, &Minor,i);
++ mvOsOutput("DIMM %d version %d.%d\n", i/2, Major, Minor);
++ }
++ mvOsOutput("\tDRAM CS[%d] ", i);
++ mvSizePrint(sdramCsSize);
++ mvOsOutput("\n");
++ }
++ }
++ sdramCasLat = mvDramIfCalGet();
++
++ if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_ECC_EN)
++ {
++ mvOsOutput("ECC enabled, ");
++ }
++ else
++ {
++ mvOsOutput("ECC Disabled, ");
++ }
++
++ if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_REGISTERED)
++ {
++ mvOsOutput("Registered DIMM\n");
++ }
++ else
++ {
++ mvOsOutput("Non registered DIMM\n");
++ }
++
++ mvOsOutput("Configured CAS Latency %d.%d\n", sdramCasLat/10, sdramCasLat%10);
++}
++/*******************************************************************************
++* mvDramIfGetFirstCS - find the DRAM bank on the lower address
++*
++*
++* DESCRIPTION:
++* This function return the fisrt CS on address 0
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* SDRAM_CS0 or SDRAM_CS2
++*
++*******************************************************************************/
++MV_U32 mvDramIfGetFirstCS(void)
++{
++ MV_DRAM_BANK_INFO bankInfo[MV_DRAM_MAX_CS];
++
++ if (DRAM_CS_Order[0] == N_A)
++ {
++ mvDramBankInfoGet(SDRAM_CS0, &bankInfo[SDRAM_CS0]);
++#ifdef MV_INCLUDE_SDRAM_CS2
++ mvDramBankInfoGet(SDRAM_CS2, &bankInfo[SDRAM_CS2]);
++#endif
++
++#ifdef MV_INCLUDE_SDRAM_CS2
++ if (bankInfo[SDRAM_CS0].size < bankInfo[SDRAM_CS2].size)
++ {
++ DRAM_CS_Order[0] = SDRAM_CS2;
++ DRAM_CS_Order[1] = SDRAM_CS3;
++ DRAM_CS_Order[2] = SDRAM_CS0;
++ DRAM_CS_Order[3] = SDRAM_CS1;
++
++ return SDRAM_CS2;
++ }
++#endif
++ DRAM_CS_Order[0] = SDRAM_CS0;
++ DRAM_CS_Order[1] = SDRAM_CS1;
++#ifdef MV_INCLUDE_SDRAM_CS2
++ DRAM_CS_Order[2] = SDRAM_CS2;
++ DRAM_CS_Order[3] = SDRAM_CS3;
++#endif
++ return SDRAM_CS0;
++ }
++ return DRAM_CS_Order[0];
++}
++/*******************************************************************************
++* mvDramIfGetCSorder -
++*
++*
++* DESCRIPTION:
++* This function return the fisrt CS on address 0
++*
++* INPUT:
++* CS number.
++*
++* OUTPUT:
++* CS order.
++*
++* RETURN:
++* SDRAM_CS0 or SDRAM_CS2
++*
++* NOTE: mvDramIfGetFirstCS must be caled before this subroutine
++*******************************************************************************/
++MV_U32 mvDramIfGetCSorder(MV_U32 csOrder )
++{
++ return DRAM_CS_Order[csOrder];
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.h 2010-11-09 20:28:10.852495382 +0100
+@@ -0,0 +1,157 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDramIfConfigh
++#define __INCmvDramIfConfigh
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/* includes */
++
++/* defines */
++
++/* registers defaults values */
++
++#define SDRAM_CONFIG_DV (SDRAM_SRMODE_DRAM | BIT25 | BIT30)
++
++#define SDRAM_DUNIT_CTRL_LOW_DDR2_DV \
++ (SDRAM_SRCLK_KEPT | \
++ SDRAM_CLK1DRV_NORMAL | \
++ (BIT28 | BIT29))
++
++#define SDRAM_ADDR_CTRL_DV 2
++
++#define SDRAM_TIMING_CTRL_LOW_REG_DV \
++ ((0x2 << SDRAM_TRCD_OFFS) | \
++ (0x2 << SDRAM_TRP_OFFS) | \
++ (0x1 << SDRAM_TWR_OFFS) | \
++ (0x0 << SDRAM_TWTR_OFFS) | \
++ (0x5 << SDRAM_TRAS_OFFS) | \
++ (0x1 << SDRAM_TRRD_OFFS))
++
++/* Note: value of 0 in register means one cycle, 1 means two and so on */
++#define SDRAM_TIMING_CTRL_HIGH_REG_DV \
++ ((0x0 << SDRAM_TR2R_OFFS) | \
++ (0x0 << SDRAM_TR2W_W2R_OFFS) | \
++ (0x1 << SDRAM_TW2W_OFFS))
++
++#define SDRAM_OPEN_PAGES_CTRL_REG_DV SDRAM_OPEN_PAGE_EN
++
++/* Presence Ctrl Low Ctrl High Dunit Ctrl Ext Mode */
++/* CS0 0x84210000 0x00000000 0x0000780F 0x00000440 */
++/* CS0+CS1 0x84210000 0x00000000 0x0000780F 0x00000440 */
++/* CS0+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404 */
++/* CS0+CS1+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404 */
++/* CS0+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404 */
++/* CS0+CS1+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404 */
++
++#define DDR2_ODT_CTRL_LOW_CS0_CS1_DV 0x84210000
++#define DDR2_ODT_CTRL_HIGH_CS0_CS1_DV 0x00000000
++#define DDR2_DUNIT_ODT_CTRL_CS0_CS1_DV 0x0000E80F
++#ifdef MV78XX0
++#define DDR_SDRAM_EXT_MODE_CS0_CS1_DV 0x00000040
++#else
++#define DDR_SDRAM_EXT_MODE_CS0_CS1_DV 0x00000440
++#endif
++
++#define DDR2_ODT_CTRL_LOW_CS0_CS1_CS2_CS3_DV 0x030C030C
++#define DDR2_ODT_CTRL_HIGH_CS0_CS1_CS2_CS3_DV 0x00000000
++#define DDR2_DUNIT_ODT_CTRL_CS0_CS1_CS2_CS3_DV 0x0000F40F
++#ifdef MV78XX0
++#define DDR_SDRAM_EXT_MODE_CS0_CS1_CS2_CS3_DV 0x00000004
++#define DDR_SDRAM_EXT_MODE_FAST_CS0_CS1_CS2_CS3_DV 0x00000044
++#else
++#define DDR_SDRAM_EXT_MODE_CS0_CS1_CS2_CS3_DV 0x00000404
++#define DDR_SDRAM_EXT_MODE_FAST_CS0_CS1_CS2_CS3_DV 0x00000444
++#endif
++
++/* DDR SDRAM Adderss/Control and Data Pads Calibration default values */
++#define DDR2_ADDR_CTRL_PAD_STRENGTH_TYPICAL_DV \
++ (3 << SDRAM_PRE_DRIVER_STRENGTH_OFFS)
++
++#define DDR2_DATA_PAD_STRENGTH_TYPICAL_DV \
++ (3 << SDRAM_PRE_DRIVER_STRENGTH_OFFS)
++
++/* DDR SDRAM Mode Register default value */
++#define DDR2_MODE_REG_DV (SDRAM_BURST_LEN_4 | SDRAM_WR_3_CYC)
++/* DDR SDRAM Timing parameter default values */
++#define SDRAM_TIMING_CTRL_LOW_REG_DEFAULT 0x33136552
++#define SDRAM_TRFC_DEFAULT_VALUE 0x34
++#define SDRAM_TRFC_DEFAULT SDRAM_TRFC_DEFAULT_VALUE
++#define SDRAM_TW2W_DEFALT (0x1 << SDRAM_TW2W_OFFS)
++
++#define SDRAM_TIMING_CTRL_HIGH_REG_DEFAULT (SDRAM_TRFC_DEFAULT | SDRAM_TW2W_DEFALT)
++
++#define SDRAM_FTDLL_REG_DEFAULT_LEFT 0x88C800
++#define SDRAM_FTDLL_REG_DEFAULT_RIGHT 0x88C800
++#define SDRAM_FTDLL_REG_DEFAULT_UP 0x88C800
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __INCmvDramIfh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.h 2010-11-09 20:28:10.882495421 +0100
+@@ -0,0 +1,172 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDramIfh
++#define __INCmvDramIfh
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/* includes */
++#include "ddr2/mvDramIfRegs.h"
++#include "ddr2/mvDramIfConfig.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++
++/* defines */
++/* DRAM Timing parameters */
++#define SDRAM_TWR 15 /* ns tWr */
++#define SDRAM_TRFC_64_512M_AT_200MHZ 70 /* ns tRfc for dens 64-512 @ 200MHz */
++#define SDRAM_TRFC_64_512M 75 /* ns tRfc for dens 64-512 */
++#define SDRAM_TRFC_1G 120 /* ns tRfc for dens 1GB */
++#define SDRAM_TR2R_CYC 1 /* cycle for tR2r */
++
++#define CAL_AUTO_DETECT 0 /* Do not force CAS latancy (mvDramIfDetect) */
++#define ECC_DISABLE 1 /* Force ECC to Disable */
++#define ECC_ENABLE 0 /* Force ECC to ENABLE */
++/* typedefs */
++
++/* enumeration for memory types */
++typedef enum _mvMemoryType
++{
++ MEM_TYPE_SDRAM,
++ MEM_TYPE_DDR1,
++ MEM_TYPE_DDR2
++}MV_MEMORY_TYPE;
++
++/* enumeration for DDR2 supported CAS Latencies */
++typedef enum _mvDimmDdr2Cas
++{
++ DDR2_CL_3 = 0x08,
++ DDR2_CL_4 = 0x10,
++ DDR2_CL_5 = 0x20,
++ DDR2_CL_6 = 0x40,
++ DDR2_CL_FAULT
++} MV_DIMM_DDR2_CAS;
++
++
++typedef struct _mvDramBankInfo
++{
++ MV_MEMORY_TYPE memoryType; /* DDR1, DDR2 or SDRAM */
++
++ /* DIMM dimensions */
++ MV_U32 numOfRowAddr;
++ MV_U32 numOfColAddr;
++ MV_U32 dataWidth;
++ MV_U32 errorCheckType; /* ECC , PARITY..*/
++ MV_U32 sdramWidth; /* 4,8,16 or 32 */
++ MV_U32 errorCheckDataWidth; /* 0 - no, 1 - Yes */
++ MV_U32 burstLengthSupported;
++ MV_U32 numOfBanksOnEachDevice;
++ MV_U32 suportedCasLatencies;
++ MV_U32 refreshInterval;
++
++ /* DIMM timing parameters */
++ MV_U32 minCycleTimeAtMaxCasLatPs;
++ MV_U32 minCycleTimeAtMaxCasLatMinus1Ps;
++ MV_U32 minCycleTimeAtMaxCasLatMinus2Ps;
++ MV_U32 minRowPrechargeTime;
++ MV_U32 minRowActiveToRowActive;
++ MV_U32 minRasToCasDelay;
++ MV_U32 minRasPulseWidth;
++ MV_U32 minWriteRecoveryTime; /* DDR2 only */
++ MV_U32 minWriteToReadCmdDelay; /* DDR2 only */
++ MV_U32 minReadToPrechCmdDelay; /* DDR2 only */
++ MV_U32 minRefreshToActiveCmd; /* DDR2 only */
++
++ /* Parameters calculated from the extracted DIMM information */
++ MV_U32 size;
++ MV_U32 deviceDensity; /* 16,64,128,256 or 512 Mbit */
++ MV_U32 numberOfDevices;
++
++ /* DIMM attributes (MV_TRUE for yes) */
++ MV_BOOL registeredAddrAndControlInputs;
++ MV_BOOL registeredDQMBinputs;
++
++}MV_DRAM_BANK_INFO;
++
++#include "ddr2/spd/mvSpd.h"
++
++/* mvDramIf.h API list */
++MV_VOID mvDramIfBasicAsmInit(MV_VOID);
++MV_STATUS mvDramIfDetect(MV_U32 forcedCl, MV_BOOL eccDisable);
++MV_VOID _mvDramIfConfig(int entryNum);
++
++MV_U32 mvDramIfBankSizeGet(MV_U32 bankNum);
++MV_U32 mvDramIfBankBaseGet(MV_U32 bankNum);
++MV_U32 mvDramIfSizeGet(MV_VOID);
++MV_U32 mvDramIfCalGet(void);
++MV_STATUS mvDramIfSingleBitErrThresholdSet(MV_U32 threshold);
++MV_VOID mvDramIfSelfRefreshSet(void);
++void mvDramIfShow(void);
++MV_U32 mvDramIfGetFirstCS(void);
++MV_U32 mvDramIfGetCSorder(MV_U32 csOrder );
++MV_U32 mvDramCsSizeGet(MV_U32 csNum);
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __INCmvDramIfh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfRegs.h 2010-11-09 20:28:10.921244571 +0100
+@@ -0,0 +1,423 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDramIfRegsh
++#define __INCmvDramIfRegsh
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/* DDR SDRAM Controller Address Decode Registers */
++ /* SDRAM CSn Base Address Register (SCBAR) */
++#define SDRAM_BASE_ADDR_REG(cpu,csNum) (0x1500 + ((csNum) * 8) + ((cpu) * 0x70))
++#define SCBAR_BASE_OFFS 16
++#define SCBAR_BASE_MASK (0xffff << SCBAR_BASE_OFFS)
++#define SCBAR_BASE_ALIGNMENT 0x10000
++
++/* SDRAM CSn Size Register (SCSR) */
++#define SDRAM_SIZE_REG(cpu,csNum) (0x1504 + ((csNum) * 8) + ((cpu) * 0x70))
++#define SCSR_SIZE_OFFS 24
++#define SCSR_SIZE_MASK (0xff << SCSR_SIZE_OFFS)
++#define SCSR_SIZE_ALIGNMENT 0x1000000
++#define SCSR_WIN_EN BIT0
++
++/* configuration register */
++#define SDRAM_CONFIG_REG (DRAM_BASE + 0x1400)
++#define SDRAM_REFRESH_OFFS 0
++#define SDRAM_REFRESH_MAX 0x3FFF
++#define SDRAM_REFRESH_MASK (SDRAM_REFRESH_MAX << SDRAM_REFRESH_OFFS)
++#define SDRAM_DWIDTH_OFFS 15
++#define SDRAM_DWIDTH_MASK (1 << SDRAM_DWIDTH_OFFS)
++#define SDRAM_DWIDTH_32BIT (0 << SDRAM_DWIDTH_OFFS)
++#define SDRAM_DWIDTH_64BIT (1 << SDRAM_DWIDTH_OFFS)
++#define SDRAM_REGISTERED (1 << 17)
++#define SDRAM_ECC_OFFS 18
++#define SDRAM_ECC_MASK (1 << SDRAM_ECC_OFFS)
++#define SDRAM_ECC_DIS (0 << SDRAM_ECC_OFFS)
++#define SDRAM_ECC_EN (1 << SDRAM_ECC_OFFS)
++#define SDRAM_IERR_OFFS 19
++#define SDRAM_IERR_MASK (1 << SDRAM_IERR_OFFS)
++#define SDRAM_IERR_REPORTE (0 << SDRAM_IERR_OFFS)
++#define SDRAM_IERR_IGNORE (1 << SDRAM_IERR_OFFS)
++#define SDRAM_SRMODE_OFFS 24
++#define SDRAM_SRMODE_MASK (1 << SDRAM_SRMODE_OFFS)
++#define SDRAM_SRMODE_POWER (0 << SDRAM_SRMODE_OFFS)
++#define SDRAM_SRMODE_DRAM (1 << SDRAM_SRMODE_OFFS)
++
++/* dunit control low register */
++#define SDRAM_DUNIT_CTRL_REG (DRAM_BASE + 0x1404)
++#define SDRAM_2T_OFFS 4
++#define SDRAM_2T_MASK (1 << SDRAM_2T_OFFS)
++#define SDRAM_2T_MODE (1 << SDRAM_2T_OFFS)
++
++#define SDRAM_SRCLK_OFFS 5
++#define SDRAM_SRCLK_MASK (1 << SDRAM_SRCLK_OFFS)
++#define SDRAM_SRCLK_KEPT (0 << SDRAM_SRCLK_OFFS)
++#define SDRAM_SRCLK_GATED (1 << SDRAM_SRCLK_OFFS)
++#define SDRAM_CTRL_POS_OFFS 6
++#define SDRAM_CTRL_POS_MASK (1 << SDRAM_CTRL_POS_OFFS)
++#define SDRAM_CTRL_POS_FALL (0 << SDRAM_CTRL_POS_OFFS)
++#define SDRAM_CTRL_POS_RISE (1 << SDRAM_CTRL_POS_OFFS)
++#define SDRAM_CLK1DRV_OFFS 12
++#define SDRAM_CLK1DRV_MASK (1 << SDRAM_CLK1DRV_OFFS)
++#define SDRAM_CLK1DRV_HIGH_Z (0 << SDRAM_CLK1DRV_OFFS)
++#define SDRAM_CLK1DRV_NORMAL (1 << SDRAM_CLK1DRV_OFFS)
++#define SDRAM_CLK2DRV_OFFS 13
++#define SDRAM_CLK2DRV_MASK (1 << SDRAM_CLK2DRV_OFFS)
++#define SDRAM_CLK2DRV_HIGH_Z (0 << SDRAM_CLK2DRV_OFFS)
++#define SDRAM_CLK2DRV_NORMAL (1 << SDRAM_CLK2DRV_OFFS)
++#define SDRAM_SB_OUT_DEL_OFFS 20
++#define SDRAM_SB_OUT_DEL_MAX 0xf
++#define SDRAM_SB_OUT_MASK (SDRAM_SB_OUT_DEL_MAX<<SDRAM_SB_OUT_DEL_OFFS)
++#define SDRAM_SB_IN_DEL_OFFS 24
++#define SDRAM_SB_IN_DEL_MAX 0xf
++#define SDRAM_SB_IN_MASK (SDRAM_SB_IN_DEL_MAX<<SDRAM_SB_IN_DEL_OFFS)
++
++/* dunit control hight register */
++#define SDRAM_DUNIT_CTRL_HI_REG (DRAM_BASE + 0x1424)
++#define SDRAM__D2P_OFFS 7
++#define SDRAM__D2P_EN (1 << SDRAM__D2P_OFFS)
++#define SDRAM__P2D_OFFS 8
++#define SDRAM__P2D_EN (1 << SDRAM__P2D_OFFS)
++#define SDRAM__ADD_HALF_FCC_OFFS 9
++#define SDRAM__ADD_HALF_FCC_EN (1 << SDRAM__ADD_HALF_FCC_OFFS)
++#define SDRAM__PUP_ZERO_SKEW_OFFS 10
++#define SDRAM__PUP_ZERO_SKEW_EN (1 << SDRAM__PUP_ZERO_SKEW_OFFS)
++#define SDRAM__WR_MESH_DELAY_OFFS 11
++#define SDRAM__WR_MESH_DELAY_EN (1 << SDRAM__WR_MESH_DELAY_OFFS)
++
++/* sdram timing control low register */
++#define SDRAM_TIMING_CTRL_LOW_REG (DRAM_BASE + 0x1408)
++#define SDRAM_TRCD_OFFS 4
++#define SDRAM_TRCD_MASK (0xF << SDRAM_TRCD_OFFS)
++#define SDRAM_TRP_OFFS 8
++#define SDRAM_TRP_MASK (0xF << SDRAM_TRP_OFFS)
++#define SDRAM_TWR_OFFS 12
++#define SDRAM_TWR_MASK (0xF << SDRAM_TWR_OFFS)
++#define SDRAM_TWTR_OFFS 16
++#define SDRAM_TWTR_MASK (0xF << SDRAM_TWTR_OFFS)
++#define SDRAM_TRAS_OFFS 0
++#define SDRAM_TRAS_MASK (0xF << SDRAM_TRAS_OFFS)
++#define SDRAM_EXT_TRAS_OFFS 20
++#define SDRAM_EXT_TRAS_MASK (0x1 << SDRAM_EXT_TRAS_OFFS)
++#define SDRAM_TRRD_OFFS 24
++#define SDRAM_TRRD_MASK (0xF << SDRAM_TRRD_OFFS)
++#define SDRAM_TRTP_OFFS 28
++#define SDRAM_TRTP_MASK (0xF << SDRAM_TRTP_OFFS)
++#define SDRAM_TRTP_DDR1 (0x1 << SDRAM_TRTP_OFFS)
++
++/* sdram timing control high register */
++#define SDRAM_TIMING_CTRL_HIGH_REG (DRAM_BASE + 0x140c)
++#define SDRAM_TRFC_OFFS 0
++#define SDRAM_TRFC_MASK (0x3F << SDRAM_TRFC_OFFS)
++#define SDRAM_TR2R_OFFS 7
++#define SDRAM_TR2R_MASK (0x3 << SDRAM_TR2R_OFFS)
++#define SDRAM_TR2W_W2R_OFFS 9
++#define SDRAM_TR2W_W2R_MASK (0x3 << SDRAM_TR2W_W2R_OFFS)
++#define SDRAM_TW2W_OFFS 11
++#define SDRAM_TW2W_MASK (0x3 << SDRAM_TW2W_OFFS)
++
++/* sdram DDR2 timing low register (SD2TLR) */
++#define SDRAM_DDR2_TIMING_LO_REG (DRAM_BASE + 0x1428)
++#define SD2TLR_TODT_ON_RD_OFFS 4
++#define SD2TLR_TODT_ON_RD_MASK (0xF << SD2TLR_TODT_ON_RD_OFFS)
++#define SD2TLR_TODT_OFF_RD_OFFS 8
++#define SD2TLR_TODT_OFF_RD_MASK (0xF << SD2TLR_TODT_OFF_RD_OFFS)
++#define SD2TLR_TODT_ON_CTRL_RD_OFFS 12
++#define SD2TLR_TODT_ON_CTRL_RD_MASK (0xF << SD2TLR_TODT_ON_CTRL_RD_OFFS)
++#define SD2TLR_TODT_OFF_CTRL_RD_OFFS 16
++#define SD2TLR_TODT_OFF_CTRL_RD_MASK (0xF << SD2TLR_TODT_OFF_CTRL_RD_OFFS)
++
++/* sdram DDR2 timing high register (SD2TLR) */
++#define SDRAM_DDR2_TIMING_HI_REG (DRAM_BASE + 0x147C)
++#define SD2THR_TODT_ON_WR_OFFS 0
++#define SD2THR_TODT_ON_WR_MASK (0xF << SD2THR_TODT_ON_WR_OFFS)
++#define SD2THR_TODT_OFF_WR_OFFS 4
++#define SD2THR_TODT_OFF_WR_MASK (0xF << SD2THR_TODT_OFF_WR_OFFS)
++#define SD2THR_TODT_ON_CTRL_WR_OFFS 8
++#define SD2THR_TODT_ON_CTRL_WR_MASK (0xF << SD2THR_TODT_ON_CTRL_WR_OFFS)
++#define SD2THR_TODT_OFF_CTRL_WR_OFFS 12
++#define SD2THR_TODT_OFF_CTRL_WR_MASK (0xF << SD2THR_TODT_OFF_CTRL_WR_OFFS)
++
++/* address control register */
++#define SDRAM_ADDR_CTRL_REG (DRAM_BASE + 0x1410)
++#define SDRAM_ADDRSEL_OFFS(cs) (4 * (cs))
++#define SDRAM_ADDRSEL_MASK(cs) (0x3 << SDRAM_ADDRSEL_OFFS(cs))
++#define SDRAM_ADDRSEL_X8(cs) (0x0 << SDRAM_ADDRSEL_OFFS(cs))
++#define SDRAM_ADDRSEL_X16(cs) (0x1 << SDRAM_ADDRSEL_OFFS(cs))
++#define SDRAM_DSIZE_OFFS(cs) (2 + 4 * (cs))
++#define SDRAM_DSIZE_MASK(cs) (0x3 << SDRAM_DSIZE_OFFS(cs))
++#define SDRAM_DSIZE_256Mb(cs) (0x1 << SDRAM_DSIZE_OFFS(cs))
++#define SDRAM_DSIZE_512Mb(cs) (0x2 << SDRAM_DSIZE_OFFS(cs))
++#define SDRAM_DSIZE_1Gb(cs) (0x3 << SDRAM_DSIZE_OFFS(cs))
++#define SDRAM_DSIZE_2Gb(cs) (0x0 << SDRAM_DSIZE_OFFS(cs))
++
++/* SDRAM Open Pages Control registers */
++#define SDRAM_OPEN_PAGE_CTRL_REG (DRAM_BASE + 0x1414)
++#define SDRAM_OPEN_PAGE_EN (0 << 0)
++#define SDRAM_OPEN_PAGE_DIS (1 << 0)
++
++/* sdram opertion register */
++#define SDRAM_OPERATION_REG (DRAM_BASE + 0x1418)
++#define SDRAM_CMD_OFFS 0
++#define SDRAM_CMD_MASK (0xF << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_NORMAL (0x0 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_PRECHARGE_ALL (0x1 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_REFRESH_ALL (0x2 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_REG_SET_CMD (0x3 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_EXT_MODE_SET (0x4 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_NOP (0x5 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_SLF_RFRSH (0x7 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_EMRS2_CMD (0x8 << SDRAM_CMD_OFFS)
++#define SDRAM_CMD_EMRS3_CMD (0x9 << SDRAM_CMD_OFFS)
++
++/* sdram mode register */
++#define SDRAM_MODE_REG (DRAM_BASE + 0x141c)
++#define SDRAM_BURST_LEN_OFFS 0
++#define SDRAM_BURST_LEN_MASK (0x7 << SDRAM_BURST_LEN_OFFS)
++#define SDRAM_BURST_LEN_4 (0x2 << SDRAM_BURST_LEN_OFFS)
++#define SDRAM_CL_OFFS 4
++#define SDRAM_CL_MASK (0x7 << SDRAM_CL_OFFS)
++#define SDRAM_DDR2_CL_3 (0x3 << SDRAM_CL_OFFS)
++#define SDRAM_DDR2_CL_4 (0x4 << SDRAM_CL_OFFS)
++#define SDRAM_DDR2_CL_5 (0x5 << SDRAM_CL_OFFS)
++#define SDRAM_DDR2_CL_6 (0x6 << SDRAM_CL_OFFS)
++
++#define SDRAM_TM_OFFS 7
++#define SDRAM_TM_MASK (1 << SDRAM_TM_OFFS)
++#define SDRAM_TM_NORMAL (0 << SDRAM_TM_OFFS)
++#define SDRAM_TM_TEST_MODE (1 << SDRAM_TM_OFFS)
++#define SDRAM_DLL_OFFS 8
++#define SDRAM_DLL_MASK (1 << SDRAM_DLL_OFFS)
++#define SDRAM_DLL_NORMAL (0 << SDRAM_DLL_OFFS)
++#define SDRAM_DLL_RESET (1 << SDRAM_DLL_OFFS)
++#define SDRAM_WR_OFFS 9
++#define SDRAM_WR_MAX 7
++#define SDRAM_WR_MASK (SDRAM_WR_MAX << SDRAM_WR_OFFS)
++#define SDRAM_WR_2_CYC (1 << SDRAM_WR_OFFS)
++#define SDRAM_WR_3_CYC (2 << SDRAM_WR_OFFS)
++#define SDRAM_WR_4_CYC (3 << SDRAM_WR_OFFS)
++#define SDRAM_WR_5_CYC (4 << SDRAM_WR_OFFS)
++#define SDRAM_WR_6_CYC (5 << SDRAM_WR_OFFS)
++#define SDRAM_PD_OFFS 12
++#define SDRAM_PD_MASK (1 << SDRAM_PD_OFFS)
++#define SDRAM_PD_FAST_EXIT (0 << SDRAM_PD_OFFS)
++#define SDRAM_PD_SLOW_EXIT (1 << SDRAM_PD_OFFS)
++
++/* DDR SDRAM Extended Mode register (DSEMR) */
++#define SDRAM_EXTENDED_MODE_REG (DRAM_BASE + 0x1420)
++#define DSEMR_DLL_ENABLE 0
++#define DSEMR_DLL_DISABLE 1
++#define DSEMR_DS_OFFS 1
++#define DSEMR_DS_MASK (1 << DSEMR_DS_OFFS)
++#define DSEMR_DS_NORMAL (0 << DSEMR_DS_OFFS)
++#define DSEMR_DS_REDUCED (1 << DSEMR_DS_OFFS)
++#define DSEMR_QOFF_OUTPUT_BUFF_EN (0 << 12)
++#define DSEMR_RTT0_OFFS 2
++#define DSEMR_RTT1_OFFS 6
++#define DSEMR_RTT_ODT_DISABLE ((0 << DSEMR_RTT0_OFFS)||(0 << DSEMR_RTT1_OFFS))
++#define DSEMR_RTT_ODT_75_OHM ((1 << DSEMR_RTT0_OFFS)||(0 << DSEMR_RTT1_OFFS))
++#define DSEMR_RTT_ODT_150_OHM ((0 << DSEMR_RTT0_OFFS)||(1 << DSEMR_RTT1_OFFS))
++#define DSEMR_RTT_ODT_50_OHM ((1 << DSEMR_RTT0_OFFS)||(1 << DSEMR_RTT1_OFFS))
++#define DSEMR_DQS_OFFS 10
++#define DSEMR_DQS_MASK (1 << DSEMR_DQS_OFFS)
++#define DSEMR_DQS_DIFFERENTIAL (0 << DSEMR_DQS_OFFS)
++#define DSEMR_DQS_SINGLE_ENDED (1 << DSEMR_DQS_OFFS)
++#define DSEMR_RDQS_ENABLE (1 << 11)
++#define DSEMR_QOFF_OUTPUT_BUFF_EN (0 << 12)
++#define DSEMR_QOFF_OUTPUT_BUFF_DIS (1 << 12)
++
++/* DDR SDRAM Operation Control Register */
++#define SDRAM_OPERATION_CTRL_REG (DRAM_BASE + 0x142c)
++
++/* Dunit FTDLL Configuration Register */
++#define SDRAM_FTDLL_CONFIG_LEFT_REG (DRAM_BASE + 0x1484)
++#define SDRAM_FTDLL_CONFIG_RIGHT_REG (DRAM_BASE + 0x161C)
++#define SDRAM_FTDLL_CONFIG_UP_REG (DRAM_BASE + 0x1620)
++
++/* Pads Calibration register */
++#define SDRAM_ADDR_CTRL_PADS_CAL_REG (DRAM_BASE + 0x14c0)
++#define SDRAM_DATA_PADS_CAL_REG (DRAM_BASE + 0x14c4)
++#define SDRAM_DRVN_OFFS 0
++#define SDRAM_DRVN_MASK (0x3F << SDRAM_DRVN_OFFS)
++#define SDRAM_DRVP_OFFS 6
++#define SDRAM_DRVP_MASK (0x3F << SDRAM_DRVP_OFFS)
++#define SDRAM_PRE_DRIVER_STRENGTH_OFFS 12
++#define SDRAM_PRE_DRIVER_STRENGTH_MASK (3 << SDRAM_PRE_DRIVER_STRENGTH_OFFS)
++#define SDRAM_TUNE_EN BIT16
++#define SDRAM_LOCKN_OFFS 17
++#define SDRAM_LOCKN_MAKS (0x3F << SDRAM_LOCKN_OFFS)
++#define SDRAM_LOCKP_OFFS 23
++#define SDRAM_LOCKP_MAKS (0x3F << SDRAM_LOCKP_OFFS)
++#define SDRAM_WR_EN (1 << 31)
++
++/* DDR2 SDRAM ODT Control (Low) Register (DSOCLR) */
++#define DDR2_SDRAM_ODT_CTRL_LOW_REG (DRAM_BASE + 0x1494)
++#define DSOCLR_ODT_RD_OFFS(odtNum) (odtNum * 4)
++#define DSOCLR_ODT_RD_MASK(odtNum) (0xf << DSOCLR_ODT_RD_OFFS(odtNum))
++#define DSOCLR_ODT_RD(odtNum, bank) ((1 << bank) << DSOCLR_ODT_RD_OFFS(odtNum))
++#define DSOCLR_ODT_WR_OFFS(odtNum) (16 + (odtNum * 4))
++#define DSOCLR_ODT_WR_MASK(odtNum) (0xf << DSOCLR_ODT_WR_OFFS(odtNum))
++#define DSOCLR_ODT_WR(odtNum, bank) ((1 << bank) << DSOCLR_ODT_WR_OFFS(odtNum))
++
++/* DDR2 SDRAM ODT Control (High) Register (DSOCHR) */
++#define DDR2_SDRAM_ODT_CTRL_HIGH_REG (DRAM_BASE + 0x1498)
++/* Optional control values to DSOCHR_ODT_EN macro */
++#define DDR2_ODT_CTRL_DUNIT 0
++#define DDR2_ODT_CTRL_NEVER 1
++#define DDR2_ODT_CTRL_ALWAYS 3
++#define DSOCHR_ODT_EN_OFFS(odtNum) (odtNum * 2)
++#define DSOCHR_ODT_EN_MASK(odtNum) (0x3 << DSOCHR_ODT_EN_OFFS(odtNum))
++#define DSOCHR_ODT_EN(odtNum, ctrl) (ctrl << DSOCHR_ODT_EN_OFFS(odtNum))
++
++/* DDR2 Dunit ODT Control Register (DDOCR)*/
++#define DDR2_DUNIT_ODT_CONTROL_REG (DRAM_BASE + 0x149c)
++#define DDOCR_ODT_RD_OFFS 0
++#define DDOCR_ODT_RD_MASK (0xf << DDOCR_ODT_RD_OFFS)
++#define DDOCR_ODT_RD(bank) ((1 << bank) << DDOCR_ODT_RD_OFFS)
++#define DDOCR_ODT_WR_OFFS 4
++#define DDOCR_ODT_WR_MASK (0xf << DDOCR_ODT_WR_OFFS)
++#define DDOCR_ODT_WR(bank) ((1 << bank) << DDOCR_ODT_WR_OFFS)
++#define DSOCR_ODT_EN_OFFS 8
++#define DSOCR_ODT_EN_MASK (0x3 << DSOCR_ODT_EN_OFFS)
++/* For ctrl parameters see DDR2 SDRAM ODT Control (High) Register (0x1498) above. */
++#define DSOCR_ODT_EN(ctrl) (ctrl << DSOCR_ODT_EN_OFFS)
++#define DSOCR_ODT_SEL_DISABLE 0
++#define DSOCR_ODT_SEL_75_OHM 2
++#define DSOCR_ODT_SEL_150_OHM 1
++#define DSOCR_ODT_SEL_50_OHM 3
++#define DSOCR_DQ_ODT_SEL_OFFS 10
++#define DSOCR_DQ_ODT_SEL_MASK (0x3 << DSOCR_DQ_ODT_SEL_OFFS)
++#define DSOCR_DQ_ODT_SEL(odtSel) (odtSel << DSOCR_DQ_ODT_SEL_OFFS)
++#define DSOCR_ST_ODT_SEL_OFFS 12
++#define DSOCR_ST_ODT_SEL_MASK (0x3 << DSOCR_ST_ODT_SEL_OFFS)
++#define DSOCR_ST_ODT_SEL(odtSel) (odtSel << DSOCR_ST_ODT_SEL_OFFS)
++#define DSOCR_ST_ODT_EN (1 << 14)
++
++/* DDR SDRAM Initialization Control Register (DSICR) */
++#define DDR_SDRAM_INIT_CTRL_REG (DRAM_BASE + 0x1480)
++#define DSICR_INIT_EN (1 << 0)
++#define DSICR_T200_SET (1 << 8)
++
++/* sdram extended mode2 register (SEM2R) */
++#define SDRAM_EXTENDED_MODE2_REG (DRAM_BASE + 0x148C)
++#define SEM2R_EMRS2_DDR2_OFFS 0
++#define SEM2R_EMRS2_DDR2_MASK (0x7FFF << SEM2R_EMRS2_DDR2_OFFS)
++
++/* sdram extended mode3 register (SEM3R) */
++#define SDRAM_EXTENDED_MODE3_REG (DRAM_BASE + 0x1490)
++#define SEM3R_EMRS3_DDR2_OFFS 0
++#define SEM3R_EMRS3_DDR2_MASK (0x7FFF << SEM3R_EMRS3_DDR2_OFFS)
++
++/* sdram error registers */
++#define SDRAM_ERROR_CAUSE_REG (DRAM_BASE + 0x14d0)
++#define SDRAM_ERROR_MASK_REG (DRAM_BASE + 0x14d4)
++#define SDRAM_ERROR_DATA_LOW_REG (DRAM_BASE + 0x1444)
++#define SDRAM_ERROR_DATA_HIGH_REG (DRAM_BASE + 0x1440)
++#define SDRAM_ERROR_ADDR_REG (DRAM_BASE + 0x1450)
++#define SDRAM_ERROR_ECC_REG (DRAM_BASE + 0x1448)
++#define SDRAM_CALC_ECC_REG (DRAM_BASE + 0x144c)
++#define SDRAM_ECC_CONTROL_REG (DRAM_BASE + 0x1454)
++#define SDRAM_SINGLE_BIT_ERR_CNTR_REG (DRAM_BASE + 0x1458)
++#define SDRAM_DOUBLE_BIT_ERR_CNTR_REG (DRAM_BASE + 0x145c)
++
++/* SDRAM Error Cause Register (SECR) */
++#define SECR_SINGLE_BIT_ERR BIT0
++#define SECR_DOUBLE_BIT_ERR BIT1
++#define SECR_DATA_PATH_PARITY_ERR BIT2
++/* SDRAM Error Address Register (SEAR) */
++#define SEAR_ERR_TYPE_OFFS 0
++#define SEAR_ERR_TYPE_MASK (1 << SEAR_ERR_TYPE_OFFS)
++#define SEAR_ERR_TYPE_SINGLE 0
++#define SEAR_ERR_TYPE_DOUBLE (1 << SEAR_ERR_TYPE_OFFS)
++#define SEAR_ERR_CS_OFFS 1
++#define SEAR_ERR_CS_MASK (3 << SEAR_ERR_CS_OFFS)
++#define SEAR_ERR_CS(csNum) (csNum << SEAR_ERR_CS_OFFS)
++#define SEAR_ERR_ADDR_OFFS 3
++#define SEAR_ERR_ADDR_MASK (0x1FFFFFFF << SEAR_ERR_ADDR_OFFS)
++
++/* SDRAM ECC Control Register (SECR) */
++#define SECR_FORCEECC_OFFS 0
++#define SECR_FORCEECC_MASK (0xFF << SECR_FORCEECC_OFFS)
++#define SECR_FORCEEN_OFFS 8
++#define SECR_FORCEEN_MASK (1 << SECR_FORCEEN_OFFS)
++#define SECR_ECC_CALC_MASK (0 << SECR_FORCEEN_OFFS)
++#define SECR_ECC_USER_MASK (1 << SECR_FORCEEN_OFFS)
++#define SECR_PERRPROP_EN BIT9
++#define SECR_CNTMODE_OFFS 10
++#define SECR_CNTMODE_MASK (1 << SECR_CNTMODE_OFFS)
++#define SECR_ALL_IN_CS0 (0 << SECR_CNTMODE_OFFS)
++#define SECR_NORMAL_COUNTER (1 << SECR_CNTMODE_OFFS)
++#define SECR_THRECC_OFFS 16
++#define SECR_THRECC_MAX 0xFF
++#define SECR_THRECC_MASK (SECR_THRECC_MAX << SECR_THRECC_OFFS)
++#define SECR_THRECC(threshold) (threshold << SECR_THRECC_OFFS)
++
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __INCmvDramIfRegsh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfStaticInit.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfStaticInit.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfStaticInit.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfStaticInit.h 2010-11-09 20:28:10.962495352 +0100
+@@ -0,0 +1,179 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDramIfStaticInith
++#define __INCmvDramIfStaticInith
++
++#ifdef MV_STATIC_DRAM_ON_BOARD
++#define STATIC_DRAM_BANK_1
++#undef STATIC_DRAM_BANK_2
++#undef STATIC_DRAM_BANK_3
++#undef STATIC_DRAM_BANK_4
++
++
++#ifdef MV_DIMM_TS256MLQ72V5U
++#define STATIC_DRAM_BANK_2
++#define STATIC_DRAM_BANK_3
++#undef STATIC_DRAM_BANK_4
++
++#define STATIC_SDRAM_CONFIG_REG 0x4724481A /* offset 0x1400 - DMA reg-0xf1000814 */
++#define STATIC_SDRAM_DUNIT_CTRL_REG 0x37707450 /* offset 0x1404 - DMA reg-0xf100081c */
++#define STATIC_SDRAM_TIMING_CTRL_LOW_REG 0x11A13330 /* offset 0x1408 - DMA reg-0xf1000824 */
++#define STATIC_SDRAM_TIMING_CTRL_HIGH_REG 0x00000601 /* offset 0x140c - DMA reg-0xf1000828 */
++#define STATIC_SDRAM_ADDR_CTRL_REG 0x00001CB2 /* offset 0x1410 - DMA reg-0xf1000820 */
++#define STATIC_SDRAM_MODE_REG 0x00000642 /* offset 0x141c - DMA reg-0xf1000818 */
++#define STATIC_SDRAM_ODT_CTRL_LOW 0x030C030C /* 0x1494 */
++#define STATIC_SDRAM_ODT_CTRL_HI 0x00000000 /* 0x1498 */
++#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0000740F /* 0x149c */
++#define STATIC_SDRAM_EXT_MODE 0x00000404 /* 0x1420 */
++#define STATIC_SDRAM_DDR2_TIMING_LO 0x00074410 /* 0x1428 */
++#define STATIC_SDRAM_DDR2_TIMING_HI 0x00007441 /* 0x147C */
++
++#define STATIC_SDRAM_RANK0_SIZE_DIMM0 0x3FFF /* size bank0 dimm0 - DMA reg-0xf1000810 */
++#define STATIC_SDRAM_RANK1_SIZE_DIMM0 0x3FFF /* size bank1 dimm0 */
++#define STATIC_SDRAM_RANK0_SIZE_DIMM1 0x3FFF /* size bank0 dimm1 */
++#define STATIC_SDRAM_RANK1_SIZE_DIMM1 0x0 /* size bank1 dimm1 */
++
++#endif /* TS256MLQ72V5U */
++
++
++#ifdef MV_MT9VDDT3272AG
++/* one DIMM 256M */
++#define STATIC_SDRAM_CONFIG_REG 0x5820040d /* offset 0x1400 - DMA reg-0xf1000814 */
++#define STATIC_SDRAM_DUNIT_CTRL_REG 0xC4000540 /* offset 0x1404 - DMA reg-0xf100081c */
++#define STATIC_SDRAM_TIMING_CTRL_LOW_REG 0x01602220 /* offset 0x1408 - DMA reg-0xf1000824 */
++#define STATIC_SDRAM_TIMING_CTRL_HIGH_REG 0x0000000b /* offset 0x140c - DMA reg-0xf1000828 */
++#define STATIC_SDRAM_ADDR_CTRL_REG 0x00000012 /* offset 0x1410 - DMA reg-0xf1000820 */
++#define STATIC_SDRAM_MODE_REG 0x00000062 /* offset 0x141c - DMA reg-0xf1000818 */
++#define STATIC_SDRAM_RANK0_SIZE_DIMM0 0x0fff /* size bank0 dimm0 - DMA reg-0xf1000810 */
++#define STATIC_SDRAM_RANK0_SIZE_DIMM1 0x0 /* size bank0 dimm1 */
++
++#endif /* MV_MT9VDDT3272AG */
++
++
++
++#ifdef MV_D27RB12P
++/*
++Two DIMM 512M + ECC enabled, Registered DIMM CAS Latency 2.5
++*/
++
++#define STATIC_SDRAM_CONFIG_REG 0x6826081E /* offset 0x1400 - DMA reg-0xf1000814 */
++#define STATIC_SDRAM_DUNIT_CTRL_REG 0xC5000540 /* offset 0x1404 - DMA reg-0xf100081c */
++#define STATIC_SDRAM_TIMING_CTRL_LOW_REG 0x01501220 /* offset 0x1408 - DMA reg-0xf1000824 */
++#define STATIC_SDRAM_TIMING_CTRL_HIGH_REG 0x00000009 /* offset 0x140c - DMA reg-0xf1000828 */
++#define STATIC_SDRAM_ADDR_CTRL_REG 0x00000012 /* offset 0x1410 - DMA reg-0xf1000820 */
++#define STATIC_SDRAM_MODE_REG 0x00000062 /* offset 0x141c - DMA reg-0xf1000818 */
++#define STATIC_SDRAM_RANK0_SIZE_DIMM0 0x0FFF /* size bank0 dimm0 - DMA reg-0xf1000810 */
++#define STATIC_SDRAM_RANK0_SIZE_DIMM1 0x0FFF /* size bank0 dimm1 */
++
++#define STATIC_DRAM_BANK_2
++
++#define STATIC_DRAM_BANK_3
++#define STATIC_DRAM_BANK_4
++
++#endif /* mv_D27RB12P */
++
++#ifdef RD_MV645XX
++
++#define STATIC_MEM_TYPE MEM_TYPE_DDR2
++#define STATIC_DIMM_INFO_BANK0_SIZE 256
++/* DDR2 boards 256 MB*/
++
++#define STATIC_SDRAM_RANK0_SIZE_DIMM0 0x00000fff /* size bank0 dimm0 - DMA reg-0xf1000810 */
++#define STATIC_SDRAM_CONFIG_REG 0x07190618
++#define STATIC_SDRAM_MODE_REG 0x00000432
++#define STATIC_SDRAM_DUNIT_CTRL_REG 0xf4a03440
++#define STATIC_SDRAM_ADDR_CTRL_REG 0x00000022
++#define STATIC_SDRAM_TIMING_CTRL_LOW_REG 0x11712220
++#define STATIC_SDRAM_TIMING_CTRL_HIGH_REG 0x00000504
++#define STATIC_SDRAM_ODT_CTRL_LOW 0x84210000
++#define STATIC_SDRAM_ODT_CTRL_HI 0x00000000
++#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0000780f
++#define STATIC_SDRAM_EXT_MODE 0x00000440
++#define STATIC_SDRAM_DDR2_TIMING_LO 0x00063300
++#define STATIC_SDRAM_DDR2_TIMING_HI 0x00006330
++#endif /* RD_MV645XX */
++
++#if MV_DIMM_M3783354CZ3_CE6
++
++#define STATIC_SDRAM_RANK0_SIZE_DIMM0 0x00000FFF /* 0x2010 size bank0 dimm0 - DMA reg-0xf1000810 */
++#define STATIC_SDRAM_CONFIG_REG 0x07190618 /* 0x1400 */
++#define STATIC_SDRAM_MODE_REG 0x00000432 /* 0x141c */
++#define STATIC_SDRAM_DUNIT_CTRL_REG 0xf4a03440 /* 0x1404 */
++#define STATIC_SDRAM_ADDR_CTRL_REG 0x00000022 /* 0x1410 */
++#define STATIC_SDRAM_TIMING_CTRL_LOW_REG 0x11712220 /* 0x1408 */
++#define STATIC_SDRAM_TIMING_CTRL_HIGH_REG 0x00000504 /* 0x140c */
++#define STATIC_SDRAM_ODT_CTRL_LOW 0x84210000 /* 0x1494 */
++#define STATIC_SDRAM_ODT_CTRL_HI 0x00000000 /* 0x1498 */
++#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0000780f /* 0x149c */
++#define STATIC_SDRAM_EXT_MODE 0x00000440 /* 0x1420 */
++#define STATIC_SDRAM_DDR2_TIMING_LO 0x00063300 /* 0x1428 */
++#define STATIC_SDRAM_DDR2_TIMING_HI 0x00006330 /* 0x147C */
++
++#endif /* MV_DIMM_M3783354CZ3_CE6 */
++
++#endif /* MV_STATIC_DRAM_ON_BOARD */
++#endif /* __INCmvDramIfStaticInith */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.c 2010-11-09 20:28:11.002495540 +0100
+@@ -0,0 +1,1474 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "ddr2/spd/mvSpd.h"
++#include "boardEnv/mvBoardEnvLib.h"
++
++/* #define MV_DEBUG */
++#ifdef MV_DEBUG
++#define DB(x) x
++#else
++#define DB(x)
++#endif
++
++static MV_VOID cpyDimm2BankInfo(MV_DIMM_INFO *pDimmInfo,
++ MV_DRAM_BANK_INFO *pBankInfo);
++static MV_U32 cas2ps(MV_U8 spd_byte);
++/*******************************************************************************
++* mvDramBankGet - Get the DRAM bank paramters.
++*
++* DESCRIPTION:
++* This function retrieves DRAM bank parameters as described in
++* DRAM_BANK_INFO struct to the controller DRAM unit. In case the board
++* has its DRAM on DIMMs it will use its EEPROM to extract SPD data
++* from it. Otherwise, if the DRAM is soldered on board, the function
++* should insert its bank information into MV_DRAM_BANK_INFO struct.
++*
++* INPUT:
++* bankNum - Board DRAM bank number.
++*
++* OUTPUT:
++* pBankInfo - DRAM bank information struct.
++*
++* RETURN:
++* MV_FAIL - Bank parameters could not be read.
++*
++*******************************************************************************/
++MV_STATUS mvDramBankInfoGet(MV_U32 bankNum, MV_DRAM_BANK_INFO *pBankInfo)
++{
++ MV_DIMM_INFO dimmInfo;
++
++ DB(mvOsPrintf("Dram: mvDramBankInfoGet bank %d\n", bankNum));
++ /* zero pBankInfo structure */
++
++ if((NULL == pBankInfo) || (bankNum >= MV_DRAM_MAX_CS ))
++ {
++ DB(mvOsPrintf("Dram: mvDramBankInfoGet bad params \n"));
++ return MV_BAD_PARAM;
++ }
++ memset(pBankInfo, 0, sizeof(*pBankInfo));
++
++ if ( MV_OK != dimmSpdGet((MV_U32)(bankNum/2), &dimmInfo))
++ {
++ DB(mvOsPrintf("Dram: ERR dimmSpdGet failed to get dimm info \n"));
++ return MV_FAIL;
++ }
++ if ((dimmInfo.numOfModuleBanks == 1) && ((bankNum % 2) == 1))
++ {
++ DB(mvOsPrintf("Dram: ERR dimmSpdGet. Can't find DIMM bank 2 \n"));
++ return MV_FAIL;
++ }
++ /* convert Dimm info to Bank info */
++ cpyDimm2BankInfo(&dimmInfo, pBankInfo);
++ return MV_OK;
++}
++
++/*******************************************************************************
++* cpyDimm2BankInfo - Convert a Dimm info struct into a bank info struct.
++*
++* DESCRIPTION:
++* Convert a Dimm info struct into a bank info struct.
++*
++* INPUT:
++* pDimmInfo - DIMM information structure.
++*
++* OUTPUT:
++* pBankInfo - DRAM bank information struct.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++static MV_VOID cpyDimm2BankInfo(MV_DIMM_INFO *pDimmInfo,
++ MV_DRAM_BANK_INFO *pBankInfo)
++{
++ pBankInfo->memoryType = pDimmInfo->memoryType;
++
++ /* DIMM dimensions */
++ pBankInfo->numOfRowAddr = pDimmInfo->numOfRowAddr;
++ pBankInfo->numOfColAddr = pDimmInfo->numOfColAddr;
++ pBankInfo->dataWidth = pDimmInfo->dataWidth;
++ pBankInfo->errorCheckType = pDimmInfo->errorCheckType;
++ pBankInfo->sdramWidth = pDimmInfo->sdramWidth;
++ pBankInfo->errorCheckDataWidth = pDimmInfo->errorCheckDataWidth;
++ pBankInfo->numOfBanksOnEachDevice = pDimmInfo->numOfBanksOnEachDevice;
++ pBankInfo->suportedCasLatencies = pDimmInfo->suportedCasLatencies;
++ pBankInfo->refreshInterval = pDimmInfo->refreshInterval;
++
++ /* DIMM timing parameters */
++ pBankInfo->minCycleTimeAtMaxCasLatPs = pDimmInfo->minCycleTimeAtMaxCasLatPs;
++ pBankInfo->minCycleTimeAtMaxCasLatMinus1Ps =
++ pDimmInfo->minCycleTimeAtMaxCasLatMinus1Ps;
++ pBankInfo->minCycleTimeAtMaxCasLatMinus2Ps =
++ pDimmInfo->minCycleTimeAtMaxCasLatMinus2Ps;
++
++ pBankInfo->minRowPrechargeTime = pDimmInfo->minRowPrechargeTime;
++ pBankInfo->minRowActiveToRowActive = pDimmInfo->minRowActiveToRowActive;
++ pBankInfo->minRasToCasDelay = pDimmInfo->minRasToCasDelay;
++ pBankInfo->minRasPulseWidth = pDimmInfo->minRasPulseWidth;
++ pBankInfo->minWriteRecoveryTime = pDimmInfo->minWriteRecoveryTime;
++ pBankInfo->minWriteToReadCmdDelay = pDimmInfo->minWriteToReadCmdDelay;
++ pBankInfo->minReadToPrechCmdDelay = pDimmInfo->minReadToPrechCmdDelay;
++ pBankInfo->minRefreshToActiveCmd = pDimmInfo->minRefreshToActiveCmd;
++
++ /* Parameters calculated from the extracted DIMM information */
++ pBankInfo->size = pDimmInfo->size/pDimmInfo->numOfModuleBanks;
++ pBankInfo->deviceDensity = pDimmInfo->deviceDensity;
++ pBankInfo->numberOfDevices = pDimmInfo->numberOfDevices /
++ pDimmInfo->numOfModuleBanks;
++
++ /* DIMM attributes (MV_TRUE for yes) */
++
++ if ((pDimmInfo->memoryType == MEM_TYPE_SDRAM) ||
++ (pDimmInfo->memoryType == MEM_TYPE_DDR1) )
++ {
++ if (pDimmInfo->dimmAttributes & BIT1)
++ pBankInfo->registeredAddrAndControlInputs = MV_TRUE;
++ else
++ pBankInfo->registeredAddrAndControlInputs = MV_FALSE;
++ }
++ else /* pDimmInfo->memoryType == MEM_TYPE_DDR2 */
++ {
++ if (pDimmInfo->dimmTypeInfo & (BIT0 | BIT4))
++ pBankInfo->registeredAddrAndControlInputs = MV_TRUE;
++ else
++ pBankInfo->registeredAddrAndControlInputs = MV_FALSE;
++ }
++
++ return;
++}
++/*******************************************************************************
++* dimmSpdCpy - Cpy SPD parameters from dimm 0 to dimm 1.
++*
++* DESCRIPTION:
++* Read the DIMM SPD parameters from dimm 0 into dimm 1 SPD.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE if function could read DIMM parameters, MV_FALSE otherwise.
++*
++*******************************************************************************/
++MV_STATUS dimmSpdCpy(MV_VOID)
++{
++ MV_U32 i;
++ MV_U32 spdChecksum;
++
++ MV_TWSI_SLAVE twsiSlave;
++ MV_U8 data[SPD_SIZE];
++
++ /* zero dimmInfo structure */
++ memset(data, 0, SPD_SIZE);
++
++ /* read the dimm eeprom */
++ DB(mvOsPrintf("DRAM: Read Dimm eeprom\n"));
++ twsiSlave.slaveAddr.address = MV_BOARD_DIMM0_I2C_ADDR;
++ twsiSlave.slaveAddr.type = ADDR7_BIT;
++ twsiSlave.validOffset = MV_TRUE;
++ twsiSlave.offset = 0;
++ twsiSlave.moreThen256 = MV_FALSE;
++
++ if( MV_OK != mvTwsiRead (MV_BOARD_DIMM_I2C_CHANNEL, &twsiSlave, data, SPD_SIZE) )
++ {
++ DB(mvOsPrintf("DRAM: ERR. no DIMM in dimmNum 0\n"));
++ return MV_FAIL;
++ }
++ DB(puts("DRAM: Reading dimm info succeded.\n"));
++
++ /* calculate SPD checksum */
++ spdChecksum = 0;
++
++ for(i = 0 ; i <= 62 ; i++)
++ {
++ spdChecksum += data[i];
++ }
++
++ if ((spdChecksum & 0xff) != data[63])
++ {
++ DB(mvOsPrintf("DRAM: Warning. Wrong SPD Checksum %2x, expValue=%2x\n",
++ (MV_U32)(spdChecksum & 0xff), data[63]));
++ }
++ else
++ {
++ DB(mvOsPrintf("DRAM: SPD Checksum ok!\n"));
++ }
++
++ /* copy the SPD content 1:1 into the DIMM 1 SPD */
++ twsiSlave.slaveAddr.address = MV_BOARD_DIMM1_I2C_ADDR;
++ twsiSlave.slaveAddr.type = ADDR7_BIT;
++ twsiSlave.validOffset = MV_TRUE;
++ twsiSlave.offset = 0;
++ twsiSlave.moreThen256 = MV_FALSE;
++
++ for(i = 0 ; i < SPD_SIZE ; i++)
++ {
++ twsiSlave.offset = i;
++ if( MV_OK != mvTwsiWrite (MV_BOARD_DIMM_I2C_CHANNEL, &twsiSlave, &data[i], 1) )
++ {
++ mvOsPrintf("DRAM: ERR. no DIMM in dimmNum 1 byte %d \n",i);
++ return MV_FAIL;
++ }
++ mvOsDelay(5);
++ }
++
++ DB(puts("DRAM: Reading dimm info succeded.\n"));
++ return MV_OK;
++}
++
++/*******************************************************************************
++* dimmSpdGet - Get the SPD parameters.
++*
++* DESCRIPTION:
++* Read the DIMM SPD parameters into given struct parameter.
++*
++* INPUT:
++* dimmNum - DIMM number. See MV_BOARD_DIMM_NUM enumerator.
++*
++* OUTPUT:
++* pDimmInfo - DIMM information structure.
++*
++* RETURN:
++* MV_TRUE if function could read DIMM parameters, MV_FALSE otherwise.
++*
++*******************************************************************************/
++MV_STATUS dimmSpdGet(MV_U32 dimmNum, MV_DIMM_INFO *pDimmInfo)
++{
++ MV_U32 i;
++ MV_U32 density = 1;
++ MV_U32 spdChecksum;
++
++ MV_TWSI_SLAVE twsiSlave;
++ MV_U8 data[SPD_SIZE];
++
++ if((NULL == pDimmInfo)|| (dimmNum >= MAX_DIMM_NUM))
++ {
++ DB(mvOsPrintf("Dram: mvDramBankInfoGet bad params \n"));
++ return MV_BAD_PARAM;
++ }
++
++ /* zero dimmInfo structure */
++ memset(data, 0, SPD_SIZE);
++
++ /* read the dimm eeprom */
++ DB(mvOsPrintf("DRAM: Read Dimm eeprom\n"));
++ twsiSlave.slaveAddr.address = (dimmNum == 0) ?
++ MV_BOARD_DIMM0_I2C_ADDR : MV_BOARD_DIMM1_I2C_ADDR;
++ twsiSlave.slaveAddr.type = ADDR7_BIT;
++ twsiSlave.validOffset = MV_TRUE;
++ twsiSlave.offset = 0;
++ twsiSlave.moreThen256 = MV_FALSE;
++
++ if( MV_OK != mvTwsiRead (MV_BOARD_DIMM_I2C_CHANNEL, &twsiSlave, data, SPD_SIZE) )
++ {
++ DB(mvOsPrintf("DRAM: ERR. no DIMM in dimmNum %d \n", dimmNum));
++ return MV_FAIL;
++ }
++ DB(puts("DRAM: Reading dimm info succeded.\n"));
++
++ /* calculate SPD checksum */
++ spdChecksum = 0;
++
++ for(i = 0 ; i <= 62 ; i++)
++ {
++ spdChecksum += data[i];
++ }
++
++ if ((spdChecksum & 0xff) != data[63])
++ {
++ DB(mvOsPrintf("DRAM: Warning. Wrong SPD Checksum %2x, expValue=%2x\n",
++ (MV_U32)(spdChecksum & 0xff), data[63]));
++ }
++ else
++ {
++ DB(mvOsPrintf("DRAM: SPD Checksum ok!\n"));
++ }
++
++ /* copy the SPD content 1:1 into the dimmInfo structure*/
++ for(i = 0 ; i < SPD_SIZE ; i++)
++ {
++ pDimmInfo->spdRawData[i] = data[i];
++ DB(mvOsPrintf("SPD-EEPROM Byte %3d = %3x (%3d)\n",i, data[i], data[i]));
++ }
++
++ DB(mvOsPrintf("DRAM SPD Information:\n"));
++
++ /* Memory type (DDR / SDRAM) */
++ switch (data[DIMM_MEM_TYPE])
++ {
++ case (DIMM_MEM_TYPE_SDRAM):
++ pDimmInfo->memoryType = MEM_TYPE_SDRAM;
++ DB(mvOsPrintf("DRAM Memeory type SDRAM\n"));
++ break;
++ case (DIMM_MEM_TYPE_DDR1):
++ pDimmInfo->memoryType = MEM_TYPE_DDR1;
++ DB(mvOsPrintf("DRAM Memeory type DDR1\n"));
++ break;
++ case (DIMM_MEM_TYPE_DDR2):
++ pDimmInfo->memoryType = MEM_TYPE_DDR2;
++ DB(mvOsPrintf("DRAM Memeory type DDR2\n"));
++ break;
++ default:
++ mvOsPrintf("ERROR: Undefined memory type!\n");
++ return MV_ERROR;
++ }
++
++
++ /* Number Of Row Addresses */
++ pDimmInfo->numOfRowAddr = data[DIMM_ROW_NUM];
++ DB(mvOsPrintf("DRAM numOfRowAddr[3] %d\n",pDimmInfo->numOfRowAddr));
++
++ /* Number Of Column Addresses */
++ pDimmInfo->numOfColAddr = data[DIMM_COL_NUM];
++ DB(mvOsPrintf("DRAM numOfColAddr[4] %d\n",pDimmInfo->numOfColAddr));
++
++ /* Number Of Module Banks */
++ pDimmInfo->numOfModuleBanks = data[DIMM_MODULE_BANK_NUM];
++ DB(mvOsPrintf("DRAM numOfModuleBanks[5] 0x%x\n",
++ pDimmInfo->numOfModuleBanks));
++
++ /* Number of module banks encoded differently for DDR2 */
++ if (pDimmInfo->memoryType == MEM_TYPE_DDR2)
++ pDimmInfo->numOfModuleBanks = (pDimmInfo->numOfModuleBanks & 0x7)+1;
++
++ /* Data Width */
++ pDimmInfo->dataWidth = data[DIMM_DATA_WIDTH];
++ DB(mvOsPrintf("DRAM dataWidth[6] 0x%x\n", pDimmInfo->dataWidth));
++
++ /* Minimum Cycle Time At Max CasLatancy */
++ pDimmInfo->minCycleTimeAtMaxCasLatPs = cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS]);
++
++ /* Error Check Type */
++ pDimmInfo->errorCheckType = data[DIMM_ERR_CHECK_TYPE];
++ DB(mvOsPrintf("DRAM errorCheckType[11] 0x%x\n",
++ pDimmInfo->errorCheckType));
++
++ /* Refresh Interval */
++ pDimmInfo->refreshInterval = data[DIMM_REFRESH_INTERVAL];
++ DB(mvOsPrintf("DRAM refreshInterval[12] 0x%x\n",
++ pDimmInfo->refreshInterval));
++
++ /* Sdram Width */
++ pDimmInfo->sdramWidth = data[DIMM_SDRAM_WIDTH];
++ DB(mvOsPrintf("DRAM sdramWidth[13] 0x%x\n",pDimmInfo->sdramWidth));
++
++ /* Error Check Data Width */
++ pDimmInfo->errorCheckDataWidth = data[DIMM_ERR_CHECK_DATA_WIDTH];
++ DB(mvOsPrintf("DRAM errorCheckDataWidth[14] 0x%x\n",
++ pDimmInfo->errorCheckDataWidth));
++
++ /* Burst Length Supported */
++ /* SDRAM/DDR1:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ burst length = * Page | TBD | TBD | TBD | 8 | 4 | 2 | 1 *
++ *********************************************************/
++ /* DDR2:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ burst length = * Page | TBD | TBD | TBD | 8 | 4 | TBD | TBD *
++ *********************************************************/
++
++ pDimmInfo->burstLengthSupported = data[DIMM_BURST_LEN_SUP];
++ DB(mvOsPrintf("DRAM burstLengthSupported[16] 0x%x\n",
++ pDimmInfo->burstLengthSupported));
++
++ /* Number Of Banks On Each Device */
++ pDimmInfo->numOfBanksOnEachDevice = data[DIMM_DEV_BANK_NUM];
++ DB(mvOsPrintf("DRAM numOfBanksOnEachDevice[17] 0x%x\n",
++ pDimmInfo->numOfBanksOnEachDevice));
++
++ /* Suported Cas Latencies */
++
++ /* SDRAM:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | 7 | 6 | 5 | 4 | 3 | 2 | 1 *
++ ********************************************************/
++
++ /* DDR 1:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 *
++ *********************************************************/
++
++ /* DDR 2:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD *
++ *********************************************************/
++
++ pDimmInfo->suportedCasLatencies = data[DIMM_SUP_CAL];
++ DB(mvOsPrintf("DRAM suportedCasLatencies[18] 0x%x\n",
++ pDimmInfo->suportedCasLatencies));
++
++ /* For DDR2 only, get the DIMM type information */
++ if (pDimmInfo->memoryType == MEM_TYPE_DDR2)
++ {
++ pDimmInfo->dimmTypeInfo = data[DIMM_DDR2_TYPE_INFORMATION];
++ DB(mvOsPrintf("DRAM dimmTypeInfo[20] (DDR2) 0x%x\n",
++ pDimmInfo->dimmTypeInfo));
++ }
++
++ /* SDRAM Modules Attributes */
++ pDimmInfo->dimmAttributes = data[DIMM_BUF_ADDR_CONT_IN];
++ DB(mvOsPrintf("DRAM dimmAttributes[21] 0x%x\n",
++ pDimmInfo->dimmAttributes));
++
++ /* Minimum Cycle Time At Max CasLatancy Minus 1*/
++ pDimmInfo->minCycleTimeAtMaxCasLatMinus1Ps =
++ cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS_MINUS1]);
++
++ /* Minimum Cycle Time At Max CasLatancy Minus 2*/
++ pDimmInfo->minCycleTimeAtMaxCasLatMinus2Ps =
++ cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS_MINUS2]);
++
++ pDimmInfo->minRowPrechargeTime = data[DIMM_MIN_ROW_PRECHARGE_TIME];
++ DB(mvOsPrintf("DRAM minRowPrechargeTime[27] 0x%x\n",
++ pDimmInfo->minRowPrechargeTime));
++ pDimmInfo->minRowActiveToRowActive = data[DIMM_MIN_ROW_ACTIVE_TO_ROW_ACTIVE];
++ DB(mvOsPrintf("DRAM minRowActiveToRowActive[28] 0x%x\n",
++ pDimmInfo->minRowActiveToRowActive));
++ pDimmInfo->minRasToCasDelay = data[DIMM_MIN_RAS_TO_CAS_DELAY];
++ DB(mvOsPrintf("DRAM minRasToCasDelay[29] 0x%x\n",
++ pDimmInfo->minRasToCasDelay));
++ pDimmInfo->minRasPulseWidth = data[DIMM_MIN_RAS_PULSE_WIDTH];
++ DB(mvOsPrintf("DRAM minRasPulseWidth[30] 0x%x\n",
++ pDimmInfo->minRasPulseWidth));
++
++ /* DIMM Bank Density */
++ pDimmInfo->dimmBankDensity = data[DIMM_BANK_DENSITY];
++ DB(mvOsPrintf("DRAM dimmBankDensity[31] 0x%x\n",
++ pDimmInfo->dimmBankDensity));
++
++ /* Only DDR2 includes Write Recovery Time field. Other SDRAM ignore */
++ pDimmInfo->minWriteRecoveryTime = data[DIMM_MIN_WRITE_RECOVERY_TIME];
++ DB(mvOsPrintf("DRAM minWriteRecoveryTime[36] 0x%x\n",
++ pDimmInfo->minWriteRecoveryTime));
++
++ /* Only DDR2 includes Internal Write To Read Command Delay field. */
++ pDimmInfo->minWriteToReadCmdDelay = data[DIMM_MIN_WRITE_TO_READ_CMD_DELAY];
++ DB(mvOsPrintf("DRAM minWriteToReadCmdDelay[37] 0x%x\n",
++ pDimmInfo->minWriteToReadCmdDelay));
++
++ /* Only DDR2 includes Internal Read To Precharge Command Delay field. */
++ pDimmInfo->minReadToPrechCmdDelay = data[DIMM_MIN_READ_TO_PRECH_CMD_DELAY];
++ DB(mvOsPrintf("DRAM minReadToPrechCmdDelay[38] 0x%x\n",
++ pDimmInfo->minReadToPrechCmdDelay));
++
++ /* Only DDR2 includes Minimum Refresh to Activate/Refresh Command field */
++ pDimmInfo->minRefreshToActiveCmd = data[DIMM_MIN_REFRESH_TO_ACTIVATE_CMD];
++ DB(mvOsPrintf("DRAM minRefreshToActiveCmd[42] 0x%x\n",
++ pDimmInfo->minRefreshToActiveCmd));
++
++ /* calculating the sdram density. Representing device density from */
++ /* bit 20 to allow representation of 4GB and above. */
++ /* For example, if density is 512Mbit 0x20000000, will be represent in */
++ /* deviceDensity by 0x20000000 >> 16 --> 0x00000200. Another example */
++ /* is density 8GB 0x200000000 >> 16 --> 0x00002000. */
++ density = (1 << ((pDimmInfo->numOfRowAddr + pDimmInfo->numOfColAddr) - 20));
++ pDimmInfo->deviceDensity = density *
++ pDimmInfo->numOfBanksOnEachDevice *
++ pDimmInfo->sdramWidth;
++ DB(mvOsPrintf("DRAM deviceDensity %d\n",pDimmInfo->deviceDensity));
++
++ /* Number of devices includeing Error correction */
++ pDimmInfo->numberOfDevices = (pDimmInfo->dataWidth/pDimmInfo->sdramWidth) *
++ pDimmInfo->numOfModuleBanks;
++ DB(mvOsPrintf("DRAM numberOfDevices %d\n",
++ pDimmInfo->numberOfDevices));
++
++ pDimmInfo->size = 0;
++
++ /* Note that pDimmInfo->size is in MB units */
++ if (pDimmInfo->memoryType == MEM_TYPE_SDRAM)
++ {
++ if (pDimmInfo->dimmBankDensity & BIT0)
++ pDimmInfo->size += 1024; /* Equal to 1GB */
++ else if (pDimmInfo->dimmBankDensity & BIT1)
++ pDimmInfo->size += 8; /* Equal to 8MB */
++ else if (pDimmInfo->dimmBankDensity & BIT2)
++ pDimmInfo->size += 16; /* Equal to 16MB */
++ else if (pDimmInfo->dimmBankDensity & BIT3)
++ pDimmInfo->size += 32; /* Equal to 32MB */
++ else if (pDimmInfo->dimmBankDensity & BIT4)
++ pDimmInfo->size += 64; /* Equal to 64MB */
++ else if (pDimmInfo->dimmBankDensity & BIT5)
++ pDimmInfo->size += 128; /* Equal to 128MB */
++ else if (pDimmInfo->dimmBankDensity & BIT6)
++ pDimmInfo->size += 256; /* Equal to 256MB */
++ else if (pDimmInfo->dimmBankDensity & BIT7)
++ pDimmInfo->size += 512; /* Equal to 512MB */
++ }
++ else if (pDimmInfo->memoryType == MEM_TYPE_DDR1)
++ {
++ if (pDimmInfo->dimmBankDensity & BIT0)
++ pDimmInfo->size += 1024; /* Equal to 1GB */
++ else if (pDimmInfo->dimmBankDensity & BIT1)
++ pDimmInfo->size += 2048; /* Equal to 2GB */
++ else if (pDimmInfo->dimmBankDensity & BIT2)
++ pDimmInfo->size += 16; /* Equal to 16MB */
++ else if (pDimmInfo->dimmBankDensity & BIT3)
++ pDimmInfo->size += 32; /* Equal to 32MB */
++ else if (pDimmInfo->dimmBankDensity & BIT4)
++ pDimmInfo->size += 64; /* Equal to 64MB */
++ else if (pDimmInfo->dimmBankDensity & BIT5)
++ pDimmInfo->size += 128; /* Equal to 128MB */
++ else if (pDimmInfo->dimmBankDensity & BIT6)
++ pDimmInfo->size += 256; /* Equal to 256MB */
++ else if (pDimmInfo->dimmBankDensity & BIT7)
++ pDimmInfo->size += 512; /* Equal to 512MB */
++ }
++ else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */
++ {
++ if (pDimmInfo->dimmBankDensity & BIT0)
++ pDimmInfo->size += 1024; /* Equal to 1GB */
++ else if (pDimmInfo->dimmBankDensity & BIT1)
++ pDimmInfo->size += 2048; /* Equal to 2GB */
++ else if (pDimmInfo->dimmBankDensity & BIT2)
++ pDimmInfo->size += 4096; /* Equal to 4GB */
++ else if (pDimmInfo->dimmBankDensity & BIT3)
++ pDimmInfo->size += 8192; /* Equal to 8GB */
++ else if (pDimmInfo->dimmBankDensity & BIT4)
++ pDimmInfo->size += 16384; /* Equal to 16GB */
++ else if (pDimmInfo->dimmBankDensity & BIT5)
++ pDimmInfo->size += 128; /* Equal to 128MB */
++ else if (pDimmInfo->dimmBankDensity & BIT6)
++ pDimmInfo->size += 256; /* Equal to 256MB */
++ else if (pDimmInfo->dimmBankDensity & BIT7)
++ pDimmInfo->size += 512; /* Equal to 512MB */
++ }
++
++ pDimmInfo->size *= pDimmInfo->numOfModuleBanks;
++
++ DB(mvOsPrintf("Dram: dimm size %dMB \n",pDimmInfo->size));
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* dimmSpdPrint - Print the SPD parameters.
++*
++* DESCRIPTION:
++* Print the Dimm SPD parameters.
++*
++* INPUT:
++* pDimmInfo - DIMM information structure.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_VOID dimmSpdPrint(MV_U32 dimmNum)
++{
++ MV_DIMM_INFO dimmInfo;
++ MV_U32 i, temp = 0;
++ MV_U32 k, maskLeftOfPoint = 0, maskRightOfPoint = 0;
++ MV_U32 rightOfPoint = 0,leftOfPoint = 0, div, time_tmp, shift;
++ MV_U32 busClkPs;
++ MV_U8 trp_clocks=0, trcd_clocks, tras_clocks, trrd_clocks,
++ temp_buf[40], *spdRawData;
++
++ busClkPs = 1000000000 / (mvBoardSysClkGet() / 100); /* in 10 ps units */
++
++ spdRawData = dimmInfo.spdRawData;
++
++ if(MV_OK != dimmSpdGet(dimmNum, &dimmInfo))
++ {
++ mvOsOutput("ERROR: Could not read SPD information!\n");
++ return;
++ }
++
++ /* find Manufactura of Dimm Module */
++ mvOsOutput("\nManufacturer's JEDEC ID Code: ");
++ for(i = 0 ; i < DIMM_MODULE_MANU_SIZE ; i++)
++ {
++ mvOsOutput("%x",spdRawData[DIMM_MODULE_MANU_OFFS + i]);
++ }
++ mvOsOutput("\n");
++
++ /* Manufacturer's Specific Data */
++ for(i = 0 ; i < DIMM_MODULE_ID_SIZE ; i++)
++ {
++ temp_buf[i] = spdRawData[DIMM_MODULE_ID_OFFS + i];
++ }
++ mvOsOutput("Manufacturer's Specific Data: %s\n", temp_buf);
++
++ /* Module Part Number */
++ for(i = 0 ; i < DIMM_MODULE_VEN_SIZE ; i++)
++ {
++ temp_buf[i] = spdRawData[DIMM_MODULE_VEN_OFFS + i];
++ }
++ mvOsOutput("Module Part Number: %s\n", temp_buf);
++
++ /* Module Serial Number */
++ for(i = 0; i < sizeof(MV_U32); i++)
++ {
++ temp |= spdRawData[95+i] << 8*i;
++ }
++ mvOsOutput("DIMM Serial No. %ld (%lx)\n", (long)temp,
++ (long)temp);
++
++ /* find Manufac-Data of Dimm Module */
++ mvOsOutput("Manufactoring Date: Year 20%d%d/ ww %d%d\n",
++ ((spdRawData[93] & 0xf0) >> 4), (spdRawData[93] & 0xf),
++ ((spdRawData[94] & 0xf0) >> 4), (spdRawData[94] & 0xf));
++ /* find modul_revision of Dimm Module */
++ mvOsOutput("Module Revision: %d.%d\n",
++ spdRawData[62]/10, spdRawData[62]%10);
++
++ /* find manufac_place of Dimm Module */
++ mvOsOutput("manufac_place: %d\n", spdRawData[72]);
++
++ /* go over the first 35 I2C data bytes */
++ for(i = 2 ; i <= 35 ; i++)
++ switch(i)
++ {
++ case 2: /* Memory type (DDR1/2 / SDRAM) */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ mvOsOutput("Dram Type is: SDRAM\n");
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR1)
++ mvOsOutput("Dram Type is: SDRAM DDR1\n");
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR2)
++ mvOsOutput("Dram Type is: SDRAM DDR2\n");
++ else
++ mvOsOutput("Dram Type unknown\n");
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 3: /* Number Of Row Addresses */
++ mvOsOutput("Module Number of row addresses: %d\n",
++ dimmInfo.numOfRowAddr);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 4: /* Number Of Column Addresses */
++ mvOsOutput("Module Number of col addresses: %d\n",
++ dimmInfo.numOfColAddr);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 5: /* Number Of Module Banks */
++ mvOsOutput("Number of Banks on Mod.: %d\n",
++ dimmInfo.numOfModuleBanks);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 6: /* Data Width */
++ mvOsOutput("Module Data Width: %d bit\n",
++ dimmInfo.dataWidth);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 8: /* Voltage Interface */
++ switch(spdRawData[i])
++ {
++ case 0x0:
++ mvOsOutput("Module is TTL_5V_TOLERANT\n");
++ break;
++ case 0x1:
++ mvOsOutput("Module is LVTTL\n");
++ break;
++ case 0x2:
++ mvOsOutput("Module is HSTL_1_5V\n");
++ break;
++ case 0x3:
++ mvOsOutput("Module is SSTL_3_3V\n");
++ break;
++ case 0x4:
++ mvOsOutput("Module is SSTL_2_5V\n");
++ break;
++ case 0x5:
++ if (dimmInfo.memoryType != MEM_TYPE_SDRAM)
++ {
++ mvOsOutput("Module is SSTL_1_8V\n");
++ break;
++ }
++ default:
++ mvOsOutput("Module is VOLTAGE_UNKNOWN\n");
++ break;
++ }
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 9: /* Minimum Cycle Time At Max CasLatancy */
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ rightOfPoint = (spdRawData[i] & 0x0f) * 10;
++
++ /* DDR2 addition of right of point */
++ if ((spdRawData[i] & 0x0f) == 0xA)
++ {
++ rightOfPoint = 25;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xB)
++ {
++ rightOfPoint = 33;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xC)
++ {
++ rightOfPoint = 66;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xD)
++ {
++ rightOfPoint = 75;
++ }
++ mvOsOutput("Minimum Cycle Time At Max CL: %d.%d [ns]\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 10: /* Clock To Data Out */
++ div = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 10:100;
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / div;
++ rightOfPoint = time_tmp % div;
++ mvOsOutput("Clock To Data Out: %d.%d [ns]\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 11: /* Error Check Type */
++ mvOsOutput("Error Check Type (0=NONE): %d\n",
++ dimmInfo.errorCheckType);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 12: /* Refresh Interval */
++ mvOsOutput("Refresh Rate: %x\n",
++ dimmInfo.refreshInterval);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 13: /* Sdram Width */
++ mvOsOutput("Sdram Width: %d bits\n",
++ dimmInfo.sdramWidth);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 14: /* Error Check Data Width */
++ mvOsOutput("Error Check Data Width: %d bits\n",
++ dimmInfo.errorCheckDataWidth);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 15: /* Minimum Clock Delay is unsupported */
++ if ((dimmInfo.memoryType == MEM_TYPE_SDRAM) ||
++ (dimmInfo.memoryType == MEM_TYPE_DDR1))
++ {
++ mvOsOutput("Minimum Clk Delay back to back: %d\n",
++ spdRawData[i]);
++ }
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 16: /* Burst Length Supported */
++ /* SDRAM/DDR1:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ burst length = * Page | TBD | TBD | TBD | 8 | 4 | 2 | 1 *
++ *********************************************************/
++ /* DDR2:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ burst length = * Page | TBD | TBD | TBD | 8 | 4 | TBD | TBD *
++ *********************************************************/
++ mvOsOutput("Burst Length Supported: ");
++ if ((dimmInfo.memoryType == MEM_TYPE_SDRAM) ||
++ (dimmInfo.memoryType == MEM_TYPE_DDR1))
++ {
++ if (dimmInfo.burstLengthSupported & BIT0)
++ mvOsOutput("1, ");
++ if (dimmInfo.burstLengthSupported & BIT1)
++ mvOsOutput("2, ");
++ }
++ if (dimmInfo.burstLengthSupported & BIT2)
++ mvOsOutput("4, ");
++ if (dimmInfo.burstLengthSupported & BIT3)
++ mvOsOutput("8, ");
++
++ mvOsOutput(" Bit \n");
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 17: /* Number Of Banks On Each Device */
++ mvOsOutput("Number Of Banks On Each Chip: %d\n",
++ dimmInfo.numOfBanksOnEachDevice);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 18: /* Suported Cas Latencies */
++
++ /* SDRAM:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | 7 | 6 | 5 | 4 | 3 | 2 | 1 *
++ ********************************************************/
++
++ /* DDR 1:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 *
++ *********************************************************/
++
++ /* DDR 2:
++ *******-******-******-******-******-******-******-*******
++ * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 *
++ *******-******-******-******-******-******-******-*******
++ CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD *
++ *********************************************************/
++
++ mvOsOutput("Suported Cas Latencies: (CL) ");
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ for (k = 0; k <=7; k++)
++ {
++ if (dimmInfo.suportedCasLatencies & (1 << k))
++ mvOsOutput("%d, ", k+1);
++ }
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR1)
++ {
++ if (dimmInfo.suportedCasLatencies & BIT0)
++ mvOsOutput("1, ");
++ if (dimmInfo.suportedCasLatencies & BIT1)
++ mvOsOutput("1.5, ");
++ if (dimmInfo.suportedCasLatencies & BIT2)
++ mvOsOutput("2, ");
++ if (dimmInfo.suportedCasLatencies & BIT3)
++ mvOsOutput("2.5, ");
++ if (dimmInfo.suportedCasLatencies & BIT4)
++ mvOsOutput("3, ");
++ if (dimmInfo.suportedCasLatencies & BIT5)
++ mvOsOutput("3.5, ");
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR2)
++ {
++ if (dimmInfo.suportedCasLatencies & BIT2)
++ mvOsOutput("2, ");
++ if (dimmInfo.suportedCasLatencies & BIT3)
++ mvOsOutput("3, ");
++ if (dimmInfo.suportedCasLatencies & BIT4)
++ mvOsOutput("4, ");
++ if (dimmInfo.suportedCasLatencies & BIT5)
++ mvOsOutput("5, ");
++ }
++ else
++ mvOsOutput("?.?, ");
++ mvOsOutput("\n");
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 20: /* DDR2 DIMM type info */
++ if (dimmInfo.memoryType == MEM_TYPE_DDR2)
++ {
++ if (dimmInfo.dimmTypeInfo & (BIT0 | BIT4))
++ mvOsOutput("Registered DIMM (RDIMM)\n");
++ else if (dimmInfo.dimmTypeInfo & (BIT1 | BIT5))
++ mvOsOutput("Unbuffered DIMM (UDIMM)\n");
++ else
++ mvOsOutput("Unknown DIMM type.\n");
++ }
++
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 21: /* SDRAM Modules Attributes */
++ mvOsOutput("\nModule Attributes (SPD Byte 21): \n");
++
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ if (dimmInfo.dimmAttributes & BIT0)
++ mvOsOutput(" Buffered Addr/Control Input: Yes\n");
++ else
++ mvOsOutput(" Buffered Addr/Control Input: No\n");
++
++ if (dimmInfo.dimmAttributes & BIT1)
++ mvOsOutput(" Registered Addr/Control Input: Yes\n");
++ else
++ mvOsOutput(" Registered Addr/Control Input: No\n");
++
++ if (dimmInfo.dimmAttributes & BIT2)
++ mvOsOutput(" On-Card PLL (clock): Yes \n");
++ else
++ mvOsOutput(" On-Card PLL (clock): No \n");
++
++ if (dimmInfo.dimmAttributes & BIT3)
++ mvOsOutput(" Bufferd DQMB Input: Yes \n");
++ else
++ mvOsOutput(" Bufferd DQMB Inputs: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT4)
++ mvOsOutput(" Registered DQMB Inputs: Yes \n");
++ else
++ mvOsOutput(" Registered DQMB Inputs: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT5)
++ mvOsOutput(" Differential Clock Input: Yes \n");
++ else
++ mvOsOutput(" Differential Clock Input: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT6)
++ mvOsOutput(" redundant Row Addressing: Yes \n");
++ else
++ mvOsOutput(" redundant Row Addressing: No \n");
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR1)
++ {
++ if (dimmInfo.dimmAttributes & BIT0)
++ mvOsOutput(" Buffered Addr/Control Input: Yes\n");
++ else
++ mvOsOutput(" Buffered Addr/Control Input: No\n");
++
++ if (dimmInfo.dimmAttributes & BIT1)
++ mvOsOutput(" Registered Addr/Control Input: Yes\n");
++ else
++ mvOsOutput(" Registered Addr/Control Input: No\n");
++
++ if (dimmInfo.dimmAttributes & BIT2)
++ mvOsOutput(" On-Card PLL (clock): Yes \n");
++ else
++ mvOsOutput(" On-Card PLL (clock): No \n");
++
++ if (dimmInfo.dimmAttributes & BIT3)
++ mvOsOutput(" FET Switch On-Card Enabled: Yes \n");
++ else
++ mvOsOutput(" FET Switch On-Card Enabled: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT4)
++ mvOsOutput(" FET Switch External Enabled: Yes \n");
++ else
++ mvOsOutput(" FET Switch External Enabled: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT5)
++ mvOsOutput(" Differential Clock Input: Yes \n");
++ else
++ mvOsOutput(" Differential Clock Input: No \n");
++ }
++ else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */
++ {
++ mvOsOutput(" Number of Active Registers on the DIMM: %d\n",
++ (dimmInfo.dimmAttributes & 0x3) + 1);
++
++ mvOsOutput(" Number of PLLs on the DIMM: %d\n",
++ ((dimmInfo.dimmAttributes) >> 2) & 0x3);
++
++ if (dimmInfo.dimmAttributes & BIT4)
++ mvOsOutput(" FET Switch External Enabled: Yes \n");
++ else
++ mvOsOutput(" FET Switch External Enabled: No \n");
++
++ if (dimmInfo.dimmAttributes & BIT6)
++ mvOsOutput(" Analysis probe installed: Yes \n");
++ else
++ mvOsOutput(" Analysis probe installed: No \n");
++ }
++
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 22: /* Suported AutoPreCharge */
++ mvOsOutput("\nModul Attributes (SPD Byte 22): \n");
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ if ( spdRawData[i] & BIT0 )
++ mvOsOutput(" Early Ras Precharge: Yes \n");
++ else
++ mvOsOutput(" Early Ras Precharge: No \n");
++
++ if ( spdRawData[i] & BIT1 )
++ mvOsOutput(" AutoPreCharge: Yes \n");
++ else
++ mvOsOutput(" AutoPreCharge: No \n");
++
++ if ( spdRawData[i] & BIT2 )
++ mvOsOutput(" Precharge All: Yes \n");
++ else
++ mvOsOutput(" Precharge All: No \n");
++
++ if ( spdRawData[i] & BIT3 )
++ mvOsOutput(" Write 1/ReadBurst: Yes \n");
++ else
++ mvOsOutput(" Write 1/ReadBurst: No \n");
++
++ if ( spdRawData[i] & BIT4 )
++ mvOsOutput(" lower VCC tolerance: 5%%\n");
++ else
++ mvOsOutput(" lower VCC tolerance: 10%%\n");
++
++ if ( spdRawData[i] & BIT5 )
++ mvOsOutput(" upper VCC tolerance: 5%%\n");
++ else
++ mvOsOutput(" upper VCC tolerance: 10%%\n");
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR1)
++ {
++ if ( spdRawData[i] & BIT0 )
++ mvOsOutput(" Supports Weak Driver: Yes \n");
++ else
++ mvOsOutput(" Supports Weak Driver: No \n");
++
++ if ( !(spdRawData[i] & BIT4) )
++ mvOsOutput(" lower VCC tolerance: 0.2V\n");
++
++ if ( !(spdRawData[i] & BIT5) )
++ mvOsOutput(" upper VCC tolerance: 0.2V\n");
++
++ if ( spdRawData[i] & BIT6 )
++ mvOsOutput(" Concurrent Auto Preharge: Yes \n");
++ else
++ mvOsOutput(" Concurrent Auto Preharge: No \n");
++
++ if ( spdRawData[i] & BIT7 )
++ mvOsOutput(" Supports Fast AP: Yes \n");
++ else
++ mvOsOutput(" Supports Fast AP: No \n");
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR2)
++ {
++ if ( spdRawData[i] & BIT0 )
++ mvOsOutput(" Supports Weak Driver: Yes \n");
++ else
++ mvOsOutput(" Supports Weak Driver: No \n");
++ }
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 23:
++ /* Minimum Cycle Time At Maximum Cas Latancy Minus 1 (2nd highest CL) */
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ rightOfPoint = (spdRawData[i] & 0x0f) * 10;
++
++ /* DDR2 addition of right of point */
++ if ((spdRawData[i] & 0x0f) == 0xA)
++ {
++ rightOfPoint = 25;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xB)
++ {
++ rightOfPoint = 33;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xC)
++ {
++ rightOfPoint = 66;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xD)
++ {
++ rightOfPoint = 75;
++ }
++
++ mvOsOutput("Minimum Cycle Time At 2nd highest CasLatancy"
++ "(0 = Not supported): %d.%d [ns]\n",
++ leftOfPoint, rightOfPoint );
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 24: /* Clock To Data Out 2nd highest Cas Latency Value*/
++ div = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 10:100;
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / div;
++ rightOfPoint = time_tmp % div;
++ mvOsOutput("Clock To Data Out (2nd CL value): %d.%d [ns]\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 25:
++ /* Minimum Cycle Time At Maximum Cas Latancy Minus 2 (3rd highest CL) */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ leftOfPoint = (spdRawData[i] & 0xfc) >> 2;
++ rightOfPoint = (spdRawData[i] & 0x3) * 25;
++ }
++ else /* DDR1 or DDR2 */
++ {
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ rightOfPoint = (spdRawData[i] & 0x0f) * 10;
++
++ /* DDR2 addition of right of point */
++ if ((spdRawData[i] & 0x0f) == 0xA)
++ {
++ rightOfPoint = 25;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xB)
++ {
++ rightOfPoint = 33;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xC)
++ {
++ rightOfPoint = 66;
++ }
++ if ((spdRawData[i] & 0x0f) == 0xD)
++ {
++ rightOfPoint = 75;
++ }
++ }
++ mvOsOutput("Minimum Cycle Time At 3rd highest CasLatancy"
++ "(0 = Not supported): %d.%d [ns]\n",
++ leftOfPoint, rightOfPoint );
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 26: /* Clock To Data Out 3rd highest Cas Latency Value*/
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ leftOfPoint = (spdRawData[i] & 0xfc) >> 2;
++ rightOfPoint = (spdRawData[i] & 0x3) * 25;
++ }
++ else /* DDR1 or DDR2 */
++ {
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = 0;
++ rightOfPoint = time_tmp;
++ }
++ mvOsOutput("Clock To Data Out (3rd CL value): %d.%2d[ns]\n",
++ leftOfPoint, rightOfPoint );
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 27: /* Minimum Row Precharge Time */
++ shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2;
++ maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0xff : 0xfc;
++ maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0x00 : 0x03;
++ leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift);
++ rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25;
++ temp = ((leftOfPoint*100) + rightOfPoint);/* in 10ps Intervals*/
++ trp_clocks = (temp + (busClkPs-1)) / busClkPs;
++ mvOsOutput("Minimum Row Precharge Time [ns]: %d.%d = "
++ "in Clk cycles %d\n",
++ leftOfPoint, rightOfPoint, trp_clocks);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 28: /* Minimum Row Active to Row Active Time */
++ shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2;
++ maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0xff : 0xfc;
++ maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0x00 : 0x03;
++ leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift);
++ rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25;
++ temp = ((leftOfPoint*100) + rightOfPoint);/* in 100ns Interval*/
++ trrd_clocks = (temp + (busClkPs-1)) / busClkPs;
++ mvOsOutput("Minimum Row Active -To- Row Active Delay [ns]: "
++ "%d.%d = in Clk cycles %d\n",
++ leftOfPoint, rightOfPoint, trp_clocks);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 29: /* Minimum Ras-To-Cas Delay */
++ shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2;
++ maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0xff : 0xfc;
++ maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ?
++ 0x00 : 0x03;
++ leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift);
++ rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25;
++ temp = ((leftOfPoint*100) + rightOfPoint);/* in 100ns Interval*/
++ trcd_clocks = (temp + (busClkPs-1) )/ busClkPs;
++ mvOsOutput("Minimum Ras-To-Cas Delay [ns]: %d.%d = "
++ "in Clk cycles %d\n",
++ leftOfPoint, rightOfPoint, trp_clocks);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 30: /* Minimum Ras Pulse Width */
++ tras_clocks = (cas2ps(spdRawData[i])+(busClkPs-1)) / busClkPs;
++ mvOsOutput("Minimum Ras Pulse Width [ns]: %d = "
++ "in Clk cycles %d\n", spdRawData[i], tras_clocks);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 31: /* Module Bank Density */
++ mvOsOutput("Module Bank Density (more than 1= Multisize-Module):");
++
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ if (dimmInfo.dimmBankDensity & BIT0)
++ mvOsOutput("1GB, ");
++ if (dimmInfo.dimmBankDensity & BIT1)
++ mvOsOutput("8MB, ");
++ if (dimmInfo.dimmBankDensity & BIT2)
++ mvOsOutput("16MB, ");
++ if (dimmInfo.dimmBankDensity & BIT3)
++ mvOsOutput("32MB, ");
++ if (dimmInfo.dimmBankDensity & BIT4)
++ mvOsOutput("64MB, ");
++ if (dimmInfo.dimmBankDensity & BIT5)
++ mvOsOutput("128MB, ");
++ if (dimmInfo.dimmBankDensity & BIT6)
++ mvOsOutput("256MB, ");
++ if (dimmInfo.dimmBankDensity & BIT7)
++ mvOsOutput("512MB, ");
++ }
++ else if (dimmInfo.memoryType == MEM_TYPE_DDR1)
++ {
++ if (dimmInfo.dimmBankDensity & BIT0)
++ mvOsOutput("1GB, ");
++ if (dimmInfo.dimmBankDensity & BIT1)
++ mvOsOutput("2GB, ");
++ if (dimmInfo.dimmBankDensity & BIT2)
++ mvOsOutput("16MB, ");
++ if (dimmInfo.dimmBankDensity & BIT3)
++ mvOsOutput("32MB, ");
++ if (dimmInfo.dimmBankDensity & BIT4)
++ mvOsOutput("64MB, ");
++ if (dimmInfo.dimmBankDensity & BIT5)
++ mvOsOutput("128MB, ");
++ if (dimmInfo.dimmBankDensity & BIT6)
++ mvOsOutput("256MB, ");
++ if (dimmInfo.dimmBankDensity & BIT7)
++ mvOsOutput("512MB, ");
++ }
++ else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */
++ {
++ if (dimmInfo.dimmBankDensity & BIT0)
++ mvOsOutput("1GB, ");
++ if (dimmInfo.dimmBankDensity & BIT1)
++ mvOsOutput("2GB, ");
++ if (dimmInfo.dimmBankDensity & BIT2)
++ mvOsOutput("4GB, ");
++ if (dimmInfo.dimmBankDensity & BIT3)
++ mvOsOutput("8GB, ");
++ if (dimmInfo.dimmBankDensity & BIT4)
++ mvOsOutput("16GB, ");
++ if (dimmInfo.dimmBankDensity & BIT5)
++ mvOsOutput("128MB, ");
++ if (dimmInfo.dimmBankDensity & BIT6)
++ mvOsOutput("256MB, ");
++ if (dimmInfo.dimmBankDensity & BIT7)
++ mvOsOutput("512MB, ");
++ }
++ mvOsOutput("\n");
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 32: /* Address And Command Setup Time (measured in ns/1000) */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ rightOfPoint = (spdRawData[i] & 0x0f);
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ if(leftOfPoint > 7)
++ {
++ leftOfPoint *= -1;
++ }
++ }
++ else /* DDR1 or DDR2 */
++ {
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / 100;
++ rightOfPoint = time_tmp % 100;
++ }
++ mvOsOutput("Address And Command Setup Time [ns]: %d.%d\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 33: /* Address And Command Hold Time */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ rightOfPoint = (spdRawData[i] & 0x0f);
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ if(leftOfPoint > 7)
++ {
++ leftOfPoint *= -1;
++ }
++ }
++ else /* DDR1 or DDR2 */
++ {
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / 100;
++ rightOfPoint = time_tmp % 100;
++ }
++ mvOsOutput("Address And Command Hold Time [ns]: %d.%d\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 34: /* Data Input Setup Time */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ rightOfPoint = (spdRawData[i] & 0x0f);
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ if(leftOfPoint > 7)
++ {
++ leftOfPoint *= -1;
++ }
++ }
++ else /* DDR1 or DDR2 */
++ {
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / 100;
++ rightOfPoint = time_tmp % 100;
++ }
++ mvOsOutput("Data Input Setup Time [ns]: %d.%d\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 35: /* Data Input Hold Time */
++ if (dimmInfo.memoryType == MEM_TYPE_SDRAM)
++ {
++ rightOfPoint = (spdRawData[i] & 0x0f);
++ leftOfPoint = (spdRawData[i] & 0xf0) >> 4;
++ if(leftOfPoint > 7)
++ {
++ leftOfPoint *= -1;
++ }
++ }
++ else /* DDR1 or DDR2 */
++ {
++ time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) +
++ ((spdRawData[i] & 0x0f));
++ leftOfPoint = time_tmp / 100;
++ rightOfPoint = time_tmp % 100;
++ }
++ mvOsOutput("Data Input Hold Time [ns]: %d.%d\n\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++
++ case 36: /* Relevant for DDR2 only: Write Recovery Time */
++ leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> 2);
++ rightOfPoint = (spdRawData[i] & maskRightOfPoint) * 25;
++ mvOsOutput("Write Recovery Time [ns]: %d.%d\n",
++ leftOfPoint, rightOfPoint);
++ break;
++/*----------------------------------------------------------------------------*/
++ }
++
++}
++
++
++/*
++ * translate ns.ns/10 coding of SPD timing values
++ * into ps unit values
++ */
++/*******************************************************************************
++* cas2ps - Translate x.y ns parameter to pico-seconds values
++*
++* DESCRIPTION:
++* This function translates x.y nano seconds to its value in pico seconds.
++* For example 3.75ns will return 3750.
++*
++* INPUT:
++* spd_byte - DIMM SPD byte.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* value in pico seconds.
++*
++*******************************************************************************/
++static MV_U32 cas2ps(MV_U8 spd_byte)
++{
++ MV_U32 ns, ns10;
++
++ /* isolate upper nibble */
++ ns = (spd_byte >> 4) & 0x0F;
++ /* isolate lower nibble */
++ ns10 = (spd_byte & 0x0F);
++
++ if( ns10 < 10 ) {
++ ns10 *= 10;
++ }
++ else if( ns10 == 10 )
++ ns10 = 25;
++ else if( ns10 == 11 )
++ ns10 = 33;
++ else if( ns10 == 12 )
++ ns10 = 66;
++ else if( ns10 == 13 )
++ ns10 = 75;
++ else
++ {
++ mvOsOutput("cas2ps Err. unsupported cycle time.\n");
++ }
++
++ return (ns*1000 + ns10*10);
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.h 2010-11-09 20:28:11.032495447 +0100
+@@ -0,0 +1,192 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvDram
++#define __INCmvDram
++
++#include "ddr2/mvDramIf.h"
++#include "twsi/mvTwsi.h"
++
++#define MAX_DIMM_NUM 2
++#define SPD_SIZE 128
++
++/* Dimm spd offsets */
++#define DIMM_MEM_TYPE 2
++#define DIMM_ROW_NUM 3
++#define DIMM_COL_NUM 4
++#define DIMM_MODULE_BANK_NUM 5
++#define DIMM_DATA_WIDTH 6
++#define DIMM_VOLT_IF 8
++#define DIMM_MIN_CC_AT_MAX_CAS 9
++#define DIMM_ERR_CHECK_TYPE 11
++#define DIMM_REFRESH_INTERVAL 12
++#define DIMM_SDRAM_WIDTH 13
++#define DIMM_ERR_CHECK_DATA_WIDTH 14
++#define DIMM_MIN_CLK_DEL 15
++#define DIMM_BURST_LEN_SUP 16
++#define DIMM_DEV_BANK_NUM 17
++#define DIMM_SUP_CAL 18
++#define DIMM_DDR2_TYPE_INFORMATION 20 /* DDR2 only */
++#define DIMM_BUF_ADDR_CONT_IN 21
++#define DIMM_MIN_CC_AT_MAX_CAS_MINUS1 23
++#define DIMM_MIN_CC_AT_MAX_CAS_MINUS2 25
++#define DIMM_MIN_ROW_PRECHARGE_TIME 27
++#define DIMM_MIN_ROW_ACTIVE_TO_ROW_ACTIVE 28
++#define DIMM_MIN_RAS_TO_CAS_DELAY 29
++#define DIMM_MIN_RAS_PULSE_WIDTH 30
++#define DIMM_BANK_DENSITY 31
++#define DIMM_MIN_WRITE_RECOVERY_TIME 36
++#define DIMM_MIN_WRITE_TO_READ_CMD_DELAY 37
++#define DIMM_MIN_READ_TO_PRECH_CMD_DELAY 38
++#define DIMM_MIN_REFRESH_TO_ACTIVATE_CMD 42
++#define DIMM_SPD_VERSION 62
++
++/* Dimm Memory Type values */
++#define DIMM_MEM_TYPE_SDRAM 0x4
++#define DIMM_MEM_TYPE_DDR1 0x7
++#define DIMM_MEM_TYPE_DDR2 0x8
++
++#define DIMM_MODULE_MANU_OFFS 64
++#define DIMM_MODULE_MANU_SIZE 8
++#define DIMM_MODULE_VEN_OFFS 73
++#define DIMM_MODULE_VEN_SIZE 25
++#define DIMM_MODULE_ID_OFFS 99
++#define DIMM_MODULE_ID_SIZE 18
++
++/* enumeration for voltage levels. */
++typedef enum _mvDimmVoltageIf
++{
++ TTL_5V_TOLERANT,
++ LVTTL,
++ HSTL_1_5V,
++ SSTL_3_3V,
++ SSTL_2_5V,
++ VOLTAGE_UNKNOWN,
++} MV_DIMM_VOLTAGE_IF;
++
++
++/* enumaration for SDRAM CAS Latencies. */
++typedef enum _mvDimmSdramCas
++{
++ SD_CL_1 =1,
++ SD_CL_2,
++ SD_CL_3,
++ SD_CL_4,
++ SD_CL_5,
++ SD_CL_6,
++ SD_CL_7,
++ SD_FAULT
++}MV_DIMM_SDRAM_CAS;
++
++
++/* DIMM information structure */
++typedef struct _mvDimmInfo
++{
++ MV_MEMORY_TYPE memoryType; /* DDR or SDRAM */
++
++ MV_U8 spdRawData[SPD_SIZE]; /* Content of SPD-EEPROM copied 1:1 */
++
++ /* DIMM dimensions */
++ MV_U32 numOfRowAddr;
++ MV_U32 numOfColAddr;
++ MV_U32 numOfModuleBanks;
++ MV_U32 dataWidth;
++ MV_U32 errorCheckType; /* ECC , PARITY..*/
++ MV_U32 sdramWidth; /* 4,8,16 or 32 */
++ MV_U32 errorCheckDataWidth; /* 0 - no, 1 - Yes */
++ MV_U32 burstLengthSupported;
++ MV_U32 numOfBanksOnEachDevice;
++ MV_U32 suportedCasLatencies;
++ MV_U32 refreshInterval;
++ MV_U32 dimmBankDensity;
++ MV_U32 dimmTypeInfo; /* DDR2 only */
++ MV_U32 dimmAttributes;
++
++ /* DIMM timing parameters */
++ MV_U32 minCycleTimeAtMaxCasLatPs;
++ MV_U32 minCycleTimeAtMaxCasLatMinus1Ps;
++ MV_U32 minCycleTimeAtMaxCasLatMinus2Ps;
++ MV_U32 minRowPrechargeTime;
++ MV_U32 minRowActiveToRowActive;
++ MV_U32 minRasToCasDelay;
++ MV_U32 minRasPulseWidth;
++ MV_U32 minWriteRecoveryTime; /* DDR2 only */
++ MV_U32 minWriteToReadCmdDelay; /* DDR2 only */
++ MV_U32 minReadToPrechCmdDelay; /* DDR2 only */
++ MV_U32 minRefreshToActiveCmd; /* DDR2 only */
++
++ /* Parameters calculated from the extracted DIMM information */
++ MV_U32 size; /* 16,64,128,256 or 512 MByte in MB units */
++ MV_U32 deviceDensity; /* 16,64,128,256 or 512 Mbit in MB units */
++ MV_U32 numberOfDevices;
++
++} MV_DIMM_INFO;
++
++
++MV_STATUS mvDramBankInfoGet(MV_U32 bankNum, MV_DRAM_BANK_INFO *pBankInfo);
++MV_STATUS dimmSpdGet(MV_U32 dimmNum, MV_DIMM_INFO *pDimmInfo);
++MV_VOID dimmSpdPrint(MV_U32 dimmNum);
++MV_STATUS dimmSpdCpy(MV_VOID);
++
++#endif /* __INCmvDram */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEth.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEth.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEth.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEth.c 2010-11-09 20:28:11.042495489 +0100
+@@ -0,0 +1,2952 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++/*******************************************************************************
++* mvEth.c - Marvell's Gigabit Ethernet controller low level driver
++*
++* DESCRIPTION:
++* This file introduce OS independent APIs to Marvell's Gigabit Ethernet
++* controller. This Gigabit Ethernet Controller driver API controls
++* 1) Operations (i.e. port Init, Finish, Up, Down, PhyReset etc').
++* 2) Data flow (i.e. port Send, Receive etc').
++* 3) MAC Filtering functions (ethSetMcastAddr, ethSetRxFilterMode, etc.)
++* 4) MIB counters support (ethReadMibCounter)
++* 5) Debug functions (ethPortRegs, ethPortCounters, ethPortQueues, etc.)
++* Each Gigabit Ethernet port is controlled via ETH_PORT_CTRL struct.
++* This struct includes configuration information as well as driver
++* internal data needed for its operations.
++*
++* Supported Features:
++* - OS independent. All required OS services are implemented via external
++* OS dependent components (like osLayer or ethOsg)
++* - The user is free from Rx/Tx queue managing.
++* - Simple Gigabit Ethernet port operation API.
++* - Simple Gigabit Ethernet port data flow API.
++* - Data flow and operation API support per queue functionality.
++* - Support cached descriptors for better performance.
++* - PHY access and control API.
++* - Port Configuration API.
++* - Full control over Special and Other Multicast MAC tables.
++*
++*******************************************************************************/
++/* includes */
++#include "mvTypes.h"
++#include "mv802_3.h"
++#include "mvDebug.h"
++#include "mvCommon.h"
++#include "mvOs.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "eth-phy/mvEthPhy.h"
++#include "eth/mvEth.h"
++#include "eth/gbe/mvEthGbe.h"
++#include "cpu/mvCpu.h"
++
++#ifdef INCLUDE_SYNC_BARR
++#include "sys/mvCpuIf.h"
++#endif
++
++#ifdef MV_RT_DEBUG
++# define ETH_DEBUG
++#endif
++
++
++/* locals */
++MV_BOOL ethDescInSram;
++MV_BOOL ethDescSwCoher;
++
++/* This array holds the control structure of each port */
++ETH_PORT_CTRL* ethPortCtrl[MV_ETH_MAX_PORTS];
++
++/* Ethernet Port Local routines */
++
++static void ethInitRxDescRing(ETH_PORT_CTRL* pPortCtrl, int queue);
++
++static void ethInitTxDescRing(ETH_PORT_CTRL* pPortCtrl, int queue);
++
++static void ethSetUcastTable(int portNo, int queue);
++
++static MV_BOOL ethSetUcastAddr (int ethPortNum, MV_U8 lastNibble, int queue);
++static MV_BOOL ethSetSpecialMcastAddr(int ethPortNum, MV_U8 lastByte, int queue);
++static MV_BOOL ethSetOtherMcastAddr(int ethPortNum, MV_U8 crc8, int queue);
++
++static void ethFreeDescrMemory(ETH_PORT_CTRL* pEthPortCtrl, MV_BUF_INFO* pDescBuf);
++static MV_U8* ethAllocDescrMemory(ETH_PORT_CTRL* pEthPortCtrl, int size,
++ MV_ULONG* pPhysAddr, MV_U32 *memHandle);
++
++static MV_U32 mvEthMruGet(MV_U32 maxRxPktSize);
++
++static void mvEthPortSgmiiConfig(int port);
++
++
++
++/******************************************************************************/
++/* EthDrv Initialization functions */
++/******************************************************************************/
++
++/*******************************************************************************
++* mvEthHalInit - Initialize the Giga Ethernet unit
++*
++* DESCRIPTION:
++* This function initialize the Giga Ethernet unit.
++* 1) Configure Address decode windows of the unit
++* 2) Set registers to HW default values.
++* 3) Clear and Disable interrupts
++*
++* INPUT: NONE
++*
++* RETURN: NONE
++*
++* NOTE: this function is called once in the boot process.
++*******************************************************************************/
++void mvEthHalInit(void)
++{
++ int port;
++
++ /* Init static data structures */
++ for (port=0; port<MV_ETH_MAX_PORTS; port++)
++ {
++ ethPortCtrl[port] = NULL;
++ }
++ /* Power down all existing ports */
++ for(port=0; port<mvCtrlEthMaxPortGet(); port++)
++ {
++
++#if defined (MV78200)
++ /* Skip ports mapped to another CPU*/
++ if (MV_FALSE == mvSocUnitIsMappedToThisCpu(GIGA0+port))
++ {
++ continue;
++ }
++#endif
++
++ /* Skip power down ports */
++ if (MV_FALSE == mvCtrlPwrClckGet(ETH_GIG_UNIT_ID, port)) continue;
++
++ /* Disable Giga Ethernet Unit interrupts */
++ MV_REG_WRITE(ETH_UNIT_INTR_MASK_REG(port), 0);
++
++ /* Clear ETH_UNIT_INTR_CAUSE_REG register */
++ MV_REG_WRITE(ETH_UNIT_INTR_CAUSE_REG(port), 0);
++
++ }
++
++ mvEthMemAttrGet(&ethDescInSram, &ethDescSwCoher);
++
++#if defined(ETH_DESCR_IN_SRAM)
++ if(ethDescInSram == MV_FALSE)
++ {
++ mvOsPrintf("ethDrv: WARNING! Descriptors will be allocated in DRAM instead of SRAM.\n");
++ }
++#endif /* ETH_DESCR_IN_SRAM */
++}
++
++/*******************************************************************************
++* mvEthMemAttrGet - Define properties (SRAM/DRAM, SW_COHER / HW_COHER / UNCACHED)
++* of of memory location for RX and TX descriptors.
++*
++* DESCRIPTION:
++* This function allocates memory for RX and TX descriptors.
++* - If ETH_DESCR_IN_SRAM defined, allocate from SRAM memory.
++* - If ETH_DESCR_IN_SDRAM defined, allocate from SDRAM memory.
++*
++* INPUT:
++* MV_BOOL* pIsSram - place of descriptors:
++* MV_TRUE - in SRAM
++* MV_FALSE - in DRAM
++* MV_BOOL* pIsSwCoher - cache coherency of descriptors:
++* MV_TRUE - driver is responsible for cache coherency
++* MV_FALSE - driver is not responsible for cache coherency
++*
++* RETURN:
++*
++*******************************************************************************/
++void mvEthMemAttrGet(MV_BOOL* pIsSram, MV_BOOL* pIsSwCoher)
++{
++ MV_BOOL isSram, isSwCoher;
++
++ isSram = MV_FALSE;
++#if (ETHER_DRAM_COHER == MV_CACHE_COHER_SW)
++ isSwCoher = MV_TRUE;
++#else
++ isSwCoher = MV_FALSE;
++#endif
++
++#if defined(ETH_DESCR_IN_SRAM)
++ if( mvCtrlSramSizeGet() > 0)
++ {
++ isSram = MV_TRUE;
++ #if (INTEG_SRAM_COHER == MV_CACHE_COHER_SW)
++ isSwCoher = MV_TRUE;
++ #else
++ isSwCoher = MV_FALSE;
++ #endif
++ }
++#endif /* ETH_DESCR_IN_SRAM */
++
++ if(pIsSram != NULL)
++ *pIsSram = isSram;
++
++ if(pIsSwCoher != NULL)
++ *pIsSwCoher = isSwCoher;
++}
++
++
++
++/******************************************************************************/
++/* Port Initialization functions */
++/******************************************************************************/
++
++/*******************************************************************************
++* mvEthPortInit - Initialize the Ethernet port driver
++*
++* DESCRIPTION:
++* This function initialize the ethernet port.
++* 1) Allocate and initialize internal port Control structure.
++* 2) Create RX and TX descriptor rings for default RX and TX queues
++* 3) Disable RX and TX operations, clear cause registers and
++* mask all interrupts.
++* 4) Set all registers to default values and clean all MAC tables.
++*
++* INPUT:
++* int portNo - Ethernet port number
++* ETH_PORT_INIT *pEthPortInit - Ethernet port init structure
++*
++* RETURN:
++* void* - ethernet port handler, that should be passed to the most other
++* functions dealing with this port.
++*
++* NOTE: This function is called once per port when loading the eth module.
++*******************************************************************************/
++void* mvEthPortInit(int portNo, MV_ETH_PORT_INIT *pEthPortInit)
++{
++ int queue, descSize;
++ ETH_PORT_CTRL* pPortCtrl;
++
++ /* Check validity of parameters */
++ if( (portNo >= (int)mvCtrlEthMaxPortGet()) ||
++ (pEthPortInit->rxDefQ >= MV_ETH_RX_Q_NUM) ||
++ (pEthPortInit->maxRxPktSize < 1518) )
++ {
++ mvOsPrintf("EthPort #%d: Bad initialization parameters\n", portNo);
++ return NULL;
++ }
++ if( (pEthPortInit->rxDescrNum[pEthPortInit->rxDefQ]) == 0)
++ {
++ mvOsPrintf("EthPort #%d: rxDefQ (%d) must be created\n",
++ portNo, pEthPortInit->rxDefQ);
++ return NULL;
++ }
++
++ pPortCtrl = (ETH_PORT_CTRL*)mvOsMalloc( sizeof(ETH_PORT_CTRL) );
++ if(pPortCtrl == NULL)
++ {
++ mvOsPrintf("EthDrv: Can't allocate %dB for port #%d control structure!\n",
++ (int)sizeof(ETH_PORT_CTRL), portNo);
++ return NULL;
++ }
++
++ memset(pPortCtrl, 0, sizeof(ETH_PORT_CTRL) );
++ ethPortCtrl[portNo] = pPortCtrl;
++
++ pPortCtrl->portState = MV_UNDEFINED_STATE;
++
++ pPortCtrl->portNo = portNo;
++
++ pPortCtrl->osHandle = pEthPortInit->osHandle;
++
++ /* Copy Configuration parameters */
++ pPortCtrl->portConfig.maxRxPktSize = pEthPortInit->maxRxPktSize;
++ pPortCtrl->portConfig.rxDefQ = pEthPortInit->rxDefQ;
++ pPortCtrl->portConfig.ejpMode = 0;
++
++ for( queue=0; queue<MV_ETH_RX_Q_NUM; queue++ )
++ {
++ pPortCtrl->rxQueueConfig[queue].descrNum = pEthPortInit->rxDescrNum[queue];
++ }
++ for( queue=0; queue<MV_ETH_TX_Q_NUM; queue++ )
++ {
++ pPortCtrl->txQueueConfig[queue].descrNum = pEthPortInit->txDescrNum[queue];
++ }
++
++ mvEthPortDisable(pPortCtrl);
++
++ /* Set the board information regarding PHY address */
++ mvEthPhyAddrSet(pPortCtrl, mvBoardPhyAddrGet(portNo) );
++
++ /* Create all requested RX queues */
++ for(queue=0; queue<MV_ETH_RX_Q_NUM; queue++)
++ {
++ if(pPortCtrl->rxQueueConfig[queue].descrNum == 0)
++ continue;
++
++ /* Allocate memory for RX descriptors */
++ descSize = ((pPortCtrl->rxQueueConfig[queue].descrNum * ETH_RX_DESC_ALIGNED_SIZE) +
++ CPU_D_CACHE_LINE_SIZE);
++
++ pPortCtrl->rxQueue[queue].descBuf.bufVirtPtr =
++ ethAllocDescrMemory(pPortCtrl, descSize,
++ &pPortCtrl->rxQueue[queue].descBuf.bufPhysAddr,
++ &pPortCtrl->rxQueue[queue].descBuf.memHandle);
++ pPortCtrl->rxQueue[queue].descBuf.bufSize = descSize;
++ if(pPortCtrl->rxQueue[queue].descBuf.bufVirtPtr == NULL)
++ {
++ mvOsPrintf("EthPort #%d, rxQ=%d: Can't allocate %d bytes in %s for %d RX descr\n",
++ pPortCtrl->portNo, queue, descSize,
++ ethDescInSram ? "SRAM" : "DRAM",
++ pPortCtrl->rxQueueConfig[queue].descrNum);
++ return NULL;
++ }
++
++ ethInitRxDescRing(pPortCtrl, queue);
++ }
++ /* Create TX queues */
++ for(queue=0; queue<MV_ETH_TX_Q_NUM; queue++)
++ {
++ if(pPortCtrl->txQueueConfig[queue].descrNum == 0)
++ continue;
++
++ /* Allocate memory for TX descriptors */
++ descSize = ((pPortCtrl->txQueueConfig[queue].descrNum * ETH_TX_DESC_ALIGNED_SIZE) +
++ CPU_D_CACHE_LINE_SIZE);
++
++ pPortCtrl->txQueue[queue].descBuf.bufVirtPtr =
++ ethAllocDescrMemory(pPortCtrl, descSize,
++ &pPortCtrl->txQueue[queue].descBuf.bufPhysAddr,
++ &pPortCtrl->txQueue[queue].descBuf.memHandle);
++ pPortCtrl->txQueue[queue].descBuf.bufSize = descSize;
++ if(pPortCtrl->txQueue[queue].descBuf.bufVirtPtr == NULL)
++ {
++ mvOsPrintf("EthPort #%d, txQ=%d: Can't allocate %d bytes in %s for %d TX descr\n",
++ pPortCtrl->portNo, queue, descSize, ethDescInSram ? "SRAM" : "DRAM",
++ pPortCtrl->txQueueConfig[queue].descrNum);
++ return NULL;
++ }
++
++ ethInitTxDescRing(pPortCtrl, queue);
++ }
++ mvEthDefaultsSet(pPortCtrl);
++
++ pPortCtrl->portState = MV_IDLE;
++ return pPortCtrl;
++}
++
++/*******************************************************************************
++* ethPortFinish - Finish the Ethernet port driver
++*
++* DESCRIPTION:
++* This function finish the ethernet port.
++* 1) Down ethernet port if needed.
++* 2) Delete RX and TX descriptor rings for all created RX and TX queues
++* 3) Free internal port Control structure.
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet port handler
++*
++* RETURN: NONE.
++*
++*******************************************************************************/
++void mvEthPortFinish(void* pPortHndl)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++ int queue, portNo = pPortCtrl->portNo;
++
++ if(pPortCtrl->portState == MV_ACTIVE)
++ {
++ mvOsPrintf("ethPort #%d: Warning !!! Finish port in Active state\n",
++ portNo);
++ mvEthPortDisable(pPortHndl);
++ }
++
++ /* Free all allocated RX queues */
++ for(queue=0; queue<MV_ETH_RX_Q_NUM; queue++)
++ {
++ ethFreeDescrMemory(pPortCtrl, &pPortCtrl->rxQueue[queue].descBuf);
++ }
++
++ /* Free all allocated TX queues */
++ for(queue=0; queue<MV_ETH_TX_Q_NUM; queue++)
++ {
++ ethFreeDescrMemory(pPortCtrl, &pPortCtrl->txQueue[queue].descBuf);
++ }
++
++ /* Free port control structure */
++ mvOsFree(pPortCtrl);
++
++ ethPortCtrl[portNo] = NULL;
++}
++
++/*******************************************************************************
++* mvEthDefaultsSet - Set defaults to the ethernet port
++*
++* DESCRIPTION:
++* This function set default values to the ethernet port.
++* 1) Clear Cause registers and Mask all interrupts
++* 2) Clear all MAC tables
++* 3) Set defaults to all registers
++* 4) Reset all created RX and TX descriptors ring
++* 5) Reset PHY
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet port handler
++*
++* RETURN: MV_STATUS
++* MV_OK - Success, Others - Failure
++* NOTE:
++* This function update all the port configuration except those set
++* Initialy by the OsGlue by MV_ETH_PORT_INIT.
++* This function can be called after portDown to return the port setting
++* to defaults.
++*******************************************************************************/
++MV_STATUS mvEthDefaultsSet(void* pPortHndl)
++{
++ int ethPortNo, queue;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++ ETH_QUEUE_CTRL* pQueueCtrl;
++ MV_U32 txPrio;
++ MV_U32 portCfgReg, portCfgExtReg, portSerialCtrlReg, portSerialCtrl1Reg, portSdmaCfgReg;
++ MV_BOARD_MAC_SPEED boardMacCfg;
++
++ ethPortNo = pPortCtrl->portNo;
++
++ /* Clear Cause registers */
++ MV_REG_WRITE(ETH_INTR_CAUSE_REG(ethPortNo),0);
++ MV_REG_WRITE(ETH_INTR_CAUSE_EXT_REG(ethPortNo),0);
++
++ /* Mask all interrupts */
++ MV_REG_WRITE(ETH_INTR_MASK_REG(ethPortNo),0);
++ MV_REG_WRITE(ETH_INTR_MASK_EXT_REG(ethPortNo),0);
++
++ portCfgReg = PORT_CONFIG_VALUE;
++ portCfgExtReg = PORT_CONFIG_EXTEND_VALUE;
++
++ boardMacCfg = mvBoardMacSpeedGet(ethPortNo);
++
++ if(boardMacCfg == BOARD_MAC_SPEED_100M)
++ {
++ portSerialCtrlReg = PORT_SERIAL_CONTROL_100MB_FORCE_VALUE;
++ }
++ else if(boardMacCfg == BOARD_MAC_SPEED_1000M)
++ {
++ portSerialCtrlReg = PORT_SERIAL_CONTROL_1000MB_FORCE_VALUE;
++ }
++ else
++ {
++ portSerialCtrlReg = PORT_SERIAL_CONTROL_VALUE;
++ }
++
++ /* build PORT_SDMA_CONFIG_REG */
++ portSdmaCfgReg = ETH_TX_INTR_COAL_MASK(0);
++ portSdmaCfgReg |= ETH_TX_BURST_SIZE_MASK(ETH_BURST_SIZE_16_64BIT_VALUE);
++
++#if ( (ETHER_DRAM_COHER == MV_CACHE_COHER_HW_WB) || \
++ (ETHER_DRAM_COHER == MV_CACHE_COHER_HW_WT) )
++ /* some devices have restricted RX burst size when using HW coherency */
++ portSdmaCfgReg |= ETH_RX_BURST_SIZE_MASK(ETH_BURST_SIZE_4_64BIT_VALUE);
++#else
++ portSdmaCfgReg |= ETH_RX_BURST_SIZE_MASK(ETH_BURST_SIZE_16_64BIT_VALUE);
++#endif
++
++#if defined(MV_CPU_BE)
++ /* big endian */
++# if defined(MV_ARM)
++ portSdmaCfgReg |= (ETH_RX_NO_DATA_SWAP_MASK |
++ ETH_TX_NO_DATA_SWAP_MASK |
++ ETH_DESC_SWAP_MASK);
++# elif defined(MV_PPC)
++ portSdmaCfgReg |= (ETH_RX_DATA_SWAP_MASK |
++ ETH_TX_DATA_SWAP_MASK |
++ ETH_NO_DESC_SWAP_MASK);
++# else
++# error "Giga Ethernet Swap policy is not defined for the CPU_ARCH"
++# endif /* MV_ARM / MV_PPC */
++
++#else /* MV_CPU_LE */
++ /* little endian */
++ portSdmaCfgReg |= (ETH_RX_NO_DATA_SWAP_MASK |
++ ETH_TX_NO_DATA_SWAP_MASK |
++ ETH_NO_DESC_SWAP_MASK);
++#endif /* MV_CPU_BE / MV_CPU_LE */
++
++ pPortCtrl->portRxQueueCmdReg = 0;
++ pPortCtrl->portTxQueueCmdReg = 0;
++
++#if (MV_ETH_VERSION >= 4)
++ if(pPortCtrl->portConfig.ejpMode == MV_TRUE)
++ {
++ MV_REG_WRITE(ETH_TXQ_CMD_1_REG(ethPortNo), ETH_TX_EJP_ENABLE_MASK);
++ }
++ else
++ {
++ MV_REG_WRITE(ETH_TXQ_CMD_1_REG(ethPortNo), 0)
++ }
++#endif /* (MV_ETH_VERSION >= 4) */
++
++ ethSetUcastTable(ethPortNo, -1);
++ mvEthSetSpecialMcastTable(ethPortNo, -1);
++ mvEthSetOtherMcastTable(ethPortNo, -1);
++
++ portSerialCtrlReg &= ~ETH_MAX_RX_PACKET_SIZE_MASK;
++
++ portSerialCtrlReg |= mvEthMruGet(pPortCtrl->portConfig.maxRxPktSize);
++
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(ethPortNo), portSerialCtrlReg);
++
++ /* Update value of PortConfig register accordingly with all RxQueue types */
++ pPortCtrl->portConfig.rxArpQ = pPortCtrl->portConfig.rxDefQ;
++ pPortCtrl->portConfig.rxBpduQ = pPortCtrl->portConfig.rxDefQ;
++ pPortCtrl->portConfig.rxTcpQ = pPortCtrl->portConfig.rxDefQ;
++ pPortCtrl->portConfig.rxUdpQ = pPortCtrl->portConfig.rxDefQ;
++
++ portCfgReg &= ~ETH_DEF_RX_QUEUE_ALL_MASK;
++ portCfgReg |= ETH_DEF_RX_QUEUE_MASK(pPortCtrl->portConfig.rxDefQ);
++
++ portCfgReg &= ~ETH_DEF_RX_ARP_QUEUE_ALL_MASK;
++ portCfgReg |= ETH_DEF_RX_ARP_QUEUE_MASK(pPortCtrl->portConfig.rxArpQ);
++
++ portCfgReg &= ~ETH_DEF_RX_BPDU_QUEUE_ALL_MASK;
++ portCfgReg |= ETH_DEF_RX_BPDU_QUEUE_MASK(pPortCtrl->portConfig.rxBpduQ);
++
++ portCfgReg &= ~ETH_DEF_RX_TCP_QUEUE_ALL_MASK;
++ portCfgReg |= ETH_DEF_RX_TCP_QUEUE_MASK(pPortCtrl->portConfig.rxTcpQ);
++
++ portCfgReg &= ~ETH_DEF_RX_UDP_QUEUE_ALL_MASK;
++ portCfgReg |= ETH_DEF_RX_UDP_QUEUE_MASK(pPortCtrl->portConfig.rxUdpQ);
++
++ /* Assignment of Tx CTRP of given queue */
++ txPrio = 0;
++
++ for(queue=0; queue<MV_ETH_TX_Q_NUM; queue++)
++ {
++ pQueueCtrl = &pPortCtrl->txQueue[queue];
++
++ if(pQueueCtrl->pFirstDescr != NULL)
++ {
++ ethResetTxDescRing(pPortCtrl, queue);
++
++ MV_REG_WRITE(ETH_TXQ_TOKEN_COUNT_REG(ethPortNo, queue),
++ 0x3fffffff);
++ MV_REG_WRITE(ETH_TXQ_TOKEN_CFG_REG(ethPortNo, queue),
++ 0x03ffffff);
++ }
++ else
++ {
++ MV_REG_WRITE(ETH_TXQ_TOKEN_COUNT_REG(ethPortNo, queue), 0x0);
++ MV_REG_WRITE(ETH_TXQ_TOKEN_CFG_REG(ethPortNo, queue), 0x0);
++ }
++ }
++
++ /* Assignment of Rx CRDP of given queue */
++ for(queue=0; queue<MV_ETH_RX_Q_NUM; queue++)
++ {
++ ethResetRxDescRing(pPortCtrl, queue);
++ }
++
++ /* Allow receiving packes with odd number of preamble nibbles */
++ portSerialCtrl1Reg = MV_REG_READ(ETH_PORT_SERIAL_CTRL_1_REG(ethPortNo));
++ portSerialCtrl1Reg |= ETH_EN_MII_ODD_PRE_MASK;
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_1_REG(ethPortNo), portSerialCtrl1Reg);
++
++ /* Assign port configuration and command. */
++ MV_REG_WRITE(ETH_PORT_CONFIG_REG(ethPortNo), portCfgReg);
++
++ MV_REG_WRITE(ETH_PORT_CONFIG_EXTEND_REG(ethPortNo), portCfgExtReg);
++
++ /* Assign port SDMA configuration */
++ MV_REG_WRITE(ETH_SDMA_CONFIG_REG(ethPortNo), portSdmaCfgReg);
++
++ /* Turn off the port/queue bandwidth limitation */
++ MV_REG_WRITE(ETH_MAX_TRANSMIT_UNIT_REG(ethPortNo), 0x0);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* ethPortUp - Start the Ethernet port RX and TX activity.
++*
++* DESCRIPTION:
++* This routine start Rx and Tx activity:
++*
++* Note: Each Rx and Tx queue descriptor's list must be initialized prior
++* to calling this function (use etherInitTxDescRing for Tx queues and
++* etherInitRxDescRing for Rx queues).
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet port handler
++*
++* RETURN: MV_STATUS
++* MV_OK - Success, Others - Failure.
++*
++* NOTE : used for port link up.
++*******************************************************************************/
++MV_STATUS mvEthPortUp(void* pEthPortHndl)
++{
++ int ethPortNo;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++
++ ethPortNo = pPortCtrl->portNo;
++
++ if( (pPortCtrl->portState != MV_ACTIVE) &&
++ (pPortCtrl->portState != MV_PAUSED) )
++ {
++ mvOsPrintf("ethDrv port%d: Unexpected port state %d\n",
++ ethPortNo, pPortCtrl->portState);
++ return MV_BAD_STATE;
++ }
++
++ ethPortNo = pPortCtrl->portNo;
++
++ /* Enable port RX. */
++ MV_REG_WRITE(ETH_RX_QUEUE_COMMAND_REG(ethPortNo), pPortCtrl->portRxQueueCmdReg);
++
++ /* Enable port TX. */
++ MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(ethPortNo)) = pPortCtrl->portTxQueueCmdReg;
++
++ pPortCtrl->portState = MV_ACTIVE;
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* ethPortDown - Stop the Ethernet port activity.
++*
++* DESCRIPTION:
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet port handler
++*
++* RETURN: MV_STATUS
++* MV_OK - Success, Others - Failure.
++*
++* NOTE : used for port link down.
++*******************************************************************************/
++MV_STATUS mvEthPortDown(void* pEthPortHndl)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++ int ethPortNum = pPortCtrl->portNo;
++ unsigned int regData;
++ volatile int uDelay, mDelay;
++
++ /* Stop Rx port activity. Check port Rx activity. */
++ regData = (MV_REG_READ(ETH_RX_QUEUE_COMMAND_REG(ethPortNum))) & ETH_RXQ_ENABLE_MASK;
++ if(regData != 0)
++ {
++ /* Issue stop command for active channels only */
++ MV_REG_WRITE(ETH_RX_QUEUE_COMMAND_REG(ethPortNum), (regData << ETH_RXQ_DISABLE_OFFSET));
++ }
++
++ /* Stop Tx port activity. Check port Tx activity. */
++ regData = (MV_REG_READ(ETH_TX_QUEUE_COMMAND_REG(ethPortNum))) & ETH_TXQ_ENABLE_MASK;
++ if(regData != 0)
++ {
++ /* Issue stop command for active channels only */
++ MV_REG_WRITE(ETH_TX_QUEUE_COMMAND_REG(ethPortNum),
++ (regData << ETH_TXQ_DISABLE_OFFSET) );
++ }
++
++ /* Force link down */
++/*
++ regData = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(ethPortNum));
++ regData &= ~(ETH_DO_NOT_FORCE_LINK_FAIL_MASK);
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(ethPortNum), regData);
++*/
++ /* Wait for all Rx activity to terminate. */
++ mDelay = 0;
++ do
++ {
++ if(mDelay >= RX_DISABLE_TIMEOUT_MSEC)
++ {
++ mvOsPrintf("ethPort_%d: TIMEOUT for RX stopped !!! rxQueueCmd - 0x08%x\n",
++ ethPortNum, regData);
++ break;
++ }
++ mvOsDelay(1);
++ mDelay++;
++
++ /* Check port RX Command register that all Rx queues are stopped */
++ regData = MV_REG_READ(ETH_RX_QUEUE_COMMAND_REG(ethPortNum));
++ }
++ while(regData & 0xFF);
++
++ /* Wait for all Tx activity to terminate. */
++ mDelay = 0;
++ do
++ {
++ if(mDelay >= TX_DISABLE_TIMEOUT_MSEC)
++ {
++ mvOsPrintf("ethPort_%d: TIMEOUT for TX stoped !!! txQueueCmd - 0x08%x\n",
++ ethPortNum, regData);
++ break;
++ }
++ mvOsDelay(1);
++ mDelay++;
++
++ /* Check port TX Command register that all Tx queues are stopped */
++ regData = MV_REG_READ(ETH_TX_QUEUE_COMMAND_REG(ethPortNum));
++ }
++ while(regData & 0xFF);
++
++ /* Double check to Verify that TX FIFO is Empty */
++ mDelay = 0;
++ while(MV_TRUE)
++ {
++ do
++ {
++ if(mDelay >= TX_FIFO_EMPTY_TIMEOUT_MSEC)
++ {
++ mvOsPrintf("\n ethPort_%d: TIMEOUT for TX FIFO empty !!! portStatus - 0x08%x\n",
++ ethPortNum, regData);
++ break;
++ }
++ mvOsDelay(1);
++ mDelay++;
++
++ regData = MV_REG_READ(ETH_PORT_STATUS_REG(ethPortNum));
++ }
++ while( ((regData & ETH_TX_FIFO_EMPTY_MASK) == 0) ||
++ ((regData & ETH_TX_IN_PROGRESS_MASK) != 0) );
++
++ if(mDelay >= TX_FIFO_EMPTY_TIMEOUT_MSEC)
++ break;
++
++ /* Double check */
++ regData = MV_REG_READ(ETH_PORT_STATUS_REG(ethPortNum));
++ if( ((regData & ETH_TX_FIFO_EMPTY_MASK) != 0) &&
++ ((regData & ETH_TX_IN_PROGRESS_MASK) == 0) )
++ {
++ break;
++ }
++ else
++ mvOsPrintf("ethPort_%d: TX FIFO Empty double check failed. %d msec, portStatus=0x%x\n",
++ ethPortNum, mDelay, regData);
++ }
++
++ /* Do NOT force link down */
++/*
++ regData = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(ethPortNum));
++ regData |= (ETH_DO_NOT_FORCE_LINK_FAIL_MASK);
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(ethPortNum), regData);
++*/
++ /* Wait about 2500 tclk cycles */
++ uDelay = (PORT_DISABLE_WAIT_TCLOCKS/(mvBoardTclkGet()/1000000));
++ mvOsUDelay(uDelay);
++
++ pPortCtrl->portState = MV_PAUSED;
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* ethPortEnable - Enable the Ethernet port and Start RX and TX.
++*
++* DESCRIPTION:
++* This routine enable the Ethernet port and Rx and Tx activity:
++*
++* Note: Each Rx and Tx queue descriptor's list must be initialized prior
++* to calling this function (use etherInitTxDescRing for Tx queues and
++* etherInitRxDescRing for Rx queues).
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet port handler
++*
++* RETURN: MV_STATUS
++* MV_OK - Success, Others - Failure.
++*
++* NOTE: main usage is to enable the port after ifconfig up.
++*******************************************************************************/
++MV_STATUS mvEthPortEnable(void* pEthPortHndl)
++{
++ int ethPortNo;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++ MV_U32 portSerialCtrlReg;
++
++ ethPortNo = pPortCtrl->portNo;
++
++ /* Enable port */
++ portSerialCtrlReg = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(ethPortNo));
++ portSerialCtrlReg |= (ETH_DO_NOT_FORCE_LINK_FAIL_MASK | ETH_PORT_ENABLE_MASK);
++
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(ethPortNo), portSerialCtrlReg);
++
++ mvEthMibCountersClear(pEthPortHndl);
++
++ pPortCtrl->portState = MV_PAUSED;
++
++ /* If Link is UP, Start RX and TX traffic */
++ if( MV_REG_READ( ETH_PORT_STATUS_REG(ethPortNo) ) & ETH_LINK_UP_MASK)
++ return( mvEthPortUp(pEthPortHndl) );
++
++ return MV_NOT_READY;
++}
++
++
++/*******************************************************************************
++* mvEthPortDisable - Stop RX and TX activities and Disable the Ethernet port.
++*
++* DESCRIPTION:
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet port handler
++*
++* RETURN: MV_STATUS
++* MV_OK - Success, Others - Failure.
++*
++* NOTE: main usage is to disable the port after ifconfig down.
++*******************************************************************************/
++MV_STATUS mvEthPortDisable(void* pEthPortHndl)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++ int ethPortNum = pPortCtrl->portNo;
++ unsigned int regData;
++ volatile int mvDelay;
++
++ if(pPortCtrl->portState == MV_ACTIVE)
++ {
++ /* Stop RX and TX activities */
++ mvEthPortDown(pEthPortHndl);
++ }
++
++ /* Reset the Enable bit in the Serial Control Register */
++ regData = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(ethPortNum));
++ regData &= ~(ETH_PORT_ENABLE_MASK);
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(ethPortNum), regData);
++
++ /* Wait about 2500 tclk cycles */
++ mvDelay = (PORT_DISABLE_WAIT_TCLOCKS*(mvCpuPclkGet()/mvBoardTclkGet()));
++ for(mvDelay; mvDelay>0; mvDelay--);
++
++ pPortCtrl->portState = MV_IDLE;
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthPortForceTxDone - Get next buffer from TX queue in spite of buffer ownership.
++*
++* DESCRIPTION:
++* This routine used to free buffers attached to the Tx ring and should
++* be called only when Giga Ethernet port is Down
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet Port handler.
++* int txQueue - Number of TX queue.
++*
++* OUTPUT:
++* MV_PKT_INFO *pPktInfo - Pointer to packet was sent.
++*
++* RETURN:
++* MV_EMPTY - There is no more buffers in this queue.
++* MV_OK - Buffer detached from the queue and pPktInfo structure
++* filled with relevant information.
++*
++*******************************************************************************/
++MV_PKT_INFO* mvEthPortForceTxDone(void* pEthPortHndl, int txQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++ ETH_QUEUE_CTRL* pQueueCtrl;
++ MV_PKT_INFO* pPktInfo;
++ ETH_TX_DESC* pTxDesc;
++ int port = pPortCtrl->portNo;
++
++ pQueueCtrl = &pPortCtrl->txQueue[txQueue];
++
++ while( (pQueueCtrl->pUsedDescr != pQueueCtrl->pCurrentDescr) ||
++ (pQueueCtrl->resource == 0) )
++ {
++ /* Free next descriptor */
++ pQueueCtrl->resource++;
++ pTxDesc = (ETH_TX_DESC*)pQueueCtrl->pUsedDescr;
++
++ /* pPktInfo is available only in descriptors which are last descriptors */
++ pPktInfo = (MV_PKT_INFO*)pTxDesc->returnInfo;
++ if (pPktInfo)
++ pPktInfo->status = pTxDesc->cmdSts;
++
++ pTxDesc->cmdSts = 0x0;
++ pTxDesc->returnInfo = 0x0;
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pTxDesc);
++
++ pQueueCtrl->pUsedDescr = TX_NEXT_DESC_PTR(pTxDesc, pQueueCtrl);
++
++ if (pPktInfo)
++ if (pPktInfo->status & ETH_TX_LAST_DESC_MASK)
++ return pPktInfo;
++ }
++ MV_REG_WRITE( ETH_TX_CUR_DESC_PTR_REG(port, txQueue),
++ (MV_U32)ethDescVirtToPhy(pQueueCtrl, pQueueCtrl->pCurrentDescr) );
++ return NULL;
++}
++
++
++
++/*******************************************************************************
++* mvEthPortForceRx - Get next buffer from RX queue in spite of buffer ownership.
++*
++* DESCRIPTION:
++* This routine used to free buffers attached to the Rx ring and should
++* be called only when Giga Ethernet port is Down
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet Port handler.
++* int rxQueue - Number of Rx queue.
++*
++* OUTPUT:
++* MV_PKT_INFO *pPktInfo - Pointer to received packet.
++*
++* RETURN:
++* MV_EMPTY - There is no more buffers in this queue.
++* MV_OK - Buffer detached from the queue and pBufInfo structure
++* filled with relevant information.
++*
++*******************************************************************************/
++MV_PKT_INFO* mvEthPortForceRx(void* pEthPortHndl, int rxQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++ ETH_QUEUE_CTRL* pQueueCtrl;
++ ETH_RX_DESC* pRxDesc;
++ MV_PKT_INFO* pPktInfo;
++ int port = pPortCtrl->portNo;
++
++ pQueueCtrl = &pPortCtrl->rxQueue[rxQueue];
++
++ if(pQueueCtrl->resource == 0)
++ {
++ MV_REG_WRITE( ETH_RX_CUR_DESC_PTR_REG(port, rxQueue),
++ (MV_U32)ethDescVirtToPhy(pQueueCtrl, pQueueCtrl->pCurrentDescr) );
++
++ return NULL;
++ }
++ /* Free next descriptor */
++ pQueueCtrl->resource--;
++ pRxDesc = (ETH_RX_DESC*)pQueueCtrl->pCurrentDescr;
++ pPktInfo = (MV_PKT_INFO*)pRxDesc->returnInfo;
++
++ pPktInfo->status = pRxDesc->cmdSts;
++ pRxDesc->cmdSts = 0x0;
++ pRxDesc->returnInfo = 0x0;
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pRxDesc);
++
++ pQueueCtrl->pCurrentDescr = RX_NEXT_DESC_PTR(pRxDesc, pQueueCtrl);
++ return pPktInfo;
++}
++
++
++/******************************************************************************/
++/* Port Configuration functions */
++/******************************************************************************/
++/*******************************************************************************
++* mvEthMruGet - Get MRU configuration for Max Rx packet size.
++*
++* INPUT:
++* MV_U32 maxRxPktSize - max packet size.
++*
++* RETURN: MV_U32 - MRU configuration.
++*
++*******************************************************************************/
++static MV_U32 mvEthMruGet(MV_U32 maxRxPktSize)
++{
++ MV_U32 portSerialCtrlReg = 0;
++
++ if(maxRxPktSize > 9192)
++ portSerialCtrlReg |= ETH_MAX_RX_PACKET_9700BYTE;
++ else if(maxRxPktSize > 9022)
++ portSerialCtrlReg |= ETH_MAX_RX_PACKET_9192BYTE;
++ else if(maxRxPktSize > 1552)
++ portSerialCtrlReg |= ETH_MAX_RX_PACKET_9022BYTE;
++ else if(maxRxPktSize > 1522)
++ portSerialCtrlReg |= ETH_MAX_RX_PACKET_1552BYTE;
++ else if(maxRxPktSize > 1518)
++ portSerialCtrlReg |= ETH_MAX_RX_PACKET_1522BYTE;
++ else
++ portSerialCtrlReg |= ETH_MAX_RX_PACKET_1518BYTE;
++
++ return portSerialCtrlReg;
++}
++
++/*******************************************************************************
++* mvEthRxCoalSet - Sets coalescing interrupt mechanism on RX path
++*
++* DESCRIPTION:
++* This routine sets the RX coalescing interrupt mechanism parameter.
++* This parameter is a timeout counter, that counts in 64 tClk
++* chunks, that when timeout event occurs a maskable interrupt occurs.
++* The parameter is calculated using the tCLK frequency of the
++* MV-64xxx chip, and the required number is in micro seconds.
++*
++* INPUT:
++* void* pPortHndl - Ethernet Port handler.
++* MV_U32 uSec - Number of micro seconds between
++* RX interrupts
++*
++* RETURN:
++* None.
++*
++* COMMENT:
++* 1 sec - TCLK_RATE clocks
++* 1 uSec - TCLK_RATE / 1,000,000 clocks
++*
++* Register Value for N micro seconds - ((N * ( (TCLK_RATE / 1,000,000)) / 64)
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_U32 mvEthRxCoalSet (void* pPortHndl, MV_U32 uSec)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++ MV_U32 coal = ((uSec * (mvBoardTclkGet() / 1000000)) / 64);
++ MV_U32 portSdmaCfgReg;
++
++ portSdmaCfgReg = MV_REG_READ(ETH_SDMA_CONFIG_REG(pPortCtrl->portNo));
++ portSdmaCfgReg &= ~ETH_RX_INTR_COAL_ALL_MASK;
++
++ portSdmaCfgReg |= ETH_RX_INTR_COAL_MASK(coal);
++
++#if (MV_ETH_VERSION >= 2)
++ /* Set additional bit if needed ETH_RX_INTR_COAL_MSB_BIT (25) */
++ if(ETH_RX_INTR_COAL_MASK(coal) > ETH_RX_INTR_COAL_ALL_MASK)
++ portSdmaCfgReg |= ETH_RX_INTR_COAL_MSB_MASK;
++#endif /* MV_ETH_VERSION >= 2 */
++
++ MV_REG_WRITE (ETH_SDMA_CONFIG_REG(pPortCtrl->portNo), portSdmaCfgReg);
++ return coal;
++}
++
++/*******************************************************************************
++* mvEthTxCoalSet - Sets coalescing interrupt mechanism on TX path
++*
++* DESCRIPTION:
++* This routine sets the TX coalescing interrupt mechanism parameter.
++* This parameter is a timeout counter, that counts in 64 tClk
++* chunks, that when timeout event occurs a maskable interrupt
++* occurs.
++* The parameter is calculated using the tCLK frequency of the
++* MV-64xxx chip, and the required number is in micro seconds.
++*
++* INPUT:
++* void* pPortHndl - Ethernet Port handler.
++* MV_U32 uSec - Number of micro seconds between
++* RX interrupts
++*
++* RETURN:
++* None.
++*
++* COMMENT:
++* 1 sec - TCLK_RATE clocks
++* 1 uSec - TCLK_RATE / 1,000,000 clocks
++*
++* Register Value for N micro seconds - ((N * ( (TCLK_RATE / 1,000,000)) / 64)
++*
++*******************************************************************************/
++MV_U32 mvEthTxCoalSet(void* pPortHndl, MV_U32 uSec)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++ MV_U32 coal = ((uSec * (mvBoardTclkGet() / 1000000)) / 64);
++ MV_U32 regVal;
++
++ regVal = MV_REG_READ(ETH_TX_FIFO_URGENT_THRESH_REG(pPortCtrl->portNo));
++ regVal &= ~ETH_TX_INTR_COAL_ALL_MASK;
++ regVal |= ETH_TX_INTR_COAL_MASK(coal);
++
++ /* Set TX Coalescing mechanism */
++ MV_REG_WRITE (ETH_TX_FIFO_URGENT_THRESH_REG(pPortCtrl->portNo), regVal);
++ return coal;
++}
++
++/*******************************************************************************
++* mvEthCoalGet - Gets RX and TX coalescing values in micro seconds
++*
++* DESCRIPTION:
++* This routine gets the RX and TX coalescing interrupt values.
++* The parameter is calculated using the tCLK frequency of the
++* MV-64xxx chip, and the returned numbers are in micro seconds.
++*
++* INPUTs:
++* void* pPortHndl - Ethernet Port handler.
++*
++* OUTPUTs:
++* MV_U32* pRxCoal - Number of micro seconds between RX interrupts
++* MV_U32* pTxCoal - Number of micro seconds between TX interrupts
++*
++* RETURN:
++* MV_STATUS MV_OK - success
++* Others - failure.
++*
++* COMMENT:
++* 1 sec - TCLK_RATE clocks
++* 1 uSec - TCLK_RATE / 1,000,000 clocks
++*
++* Register Value for N micro seconds - ((N * ( (TCLK_RATE / 1,000,000)) / 64)
++*
++*******************************************************************************/
++MV_STATUS mvEthCoalGet(void* pPortHndl, MV_U32* pRxCoal, MV_U32* pTxCoal)
++{
++ MV_U32 regVal, coal, usec;
++
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++
++ /* get TX Coalescing */
++ regVal = MV_REG_READ (ETH_TX_FIFO_URGENT_THRESH_REG(pPortCtrl->portNo));
++ coal = ((regVal & ETH_TX_INTR_COAL_ALL_MASK) >> ETH_TX_INTR_COAL_OFFSET);
++
++ usec = (coal * 64) / (mvBoardTclkGet() / 1000000);
++ if(pTxCoal != NULL)
++ *pTxCoal = usec;
++
++ /* Get RX Coalescing */
++ regVal = MV_REG_READ(ETH_SDMA_CONFIG_REG(pPortCtrl->portNo));
++ coal = ((regVal & ETH_RX_INTR_COAL_ALL_MASK) >> ETH_RX_INTR_COAL_OFFSET);
++
++#if (MV_ETH_VERSION >= 2)
++ if(regVal & ETH_RX_INTR_COAL_MSB_MASK)
++ {
++ /* Add MSB */
++ coal |= (ETH_RX_INTR_COAL_ALL_MASK + 1);
++ }
++#endif /* MV_ETH_VERSION >= 2 */
++
++ usec = (coal * 64) / (mvBoardTclkGet() / 1000000);
++ if(pRxCoal != NULL)
++ *pRxCoal = usec;
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthMaxRxSizeSet -
++*
++* DESCRIPTION:
++* Change maximum receive size of the port. This configuration will take place
++* after next call of ethPortSetDefaults() function.
++*
++* INPUT:
++*
++* RETURN:
++*******************************************************************************/
++MV_STATUS mvEthMaxRxSizeSet(void* pPortHndl, int maxRxSize)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++ MV_U32 portSerialCtrlReg;
++
++ if((maxRxSize < 1518) || (maxRxSize & ~ETH_RX_BUFFER_MASK))
++ return MV_BAD_PARAM;
++
++ pPortCtrl->portConfig.maxRxPktSize = maxRxSize;
++
++ portSerialCtrlReg = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(pPortCtrl->portNo));
++ portSerialCtrlReg &= ~ETH_MAX_RX_PACKET_SIZE_MASK;
++ portSerialCtrlReg |= mvEthMruGet(pPortCtrl->portConfig.maxRxPktSize);
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(pPortCtrl->portNo), portSerialCtrlReg);
++
++ return MV_OK;
++}
++
++
++/******************************************************************************/
++/* MAC Filtering functions */
++/******************************************************************************/
++
++/*******************************************************************************
++* mvEthRxFilterModeSet - Configure Fitering mode of Ethernet port
++*
++* DESCRIPTION:
++* This routine used to free buffers attached to the Rx ring and should
++* be called only when Giga Ethernet port is Down
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet Port handler.
++* MV_BOOL isPromisc - Promiscous mode
++* MV_TRUE - accept all Broadcast, Multicast
++* and Unicast packets
++* MV_FALSE - accept all Broadcast,
++* specially added Multicast and
++* single Unicast packets
++*
++* RETURN: MV_STATUS MV_OK - Success, Other - Failure
++*
++*******************************************************************************/
++MV_STATUS mvEthRxFilterModeSet(void* pEthPortHndl, MV_BOOL isPromisc)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++ int queue;
++ MV_U32 portCfgReg;
++
++ portCfgReg = MV_REG_READ(ETH_PORT_CONFIG_REG(pPortCtrl->portNo));
++ /* Set / Clear UPM bit in port configuration register */
++ if(isPromisc)
++ {
++ /* Accept all multicast packets to RX default queue */
++ queue = pPortCtrl->portConfig.rxDefQ;
++ portCfgReg |= ETH_UNICAST_PROMISCUOUS_MODE_MASK;
++ memset(pPortCtrl->mcastCount, 1, sizeof(pPortCtrl->mcastCount));
++ MV_REG_WRITE(ETH_MAC_ADDR_LOW_REG(pPortCtrl->portNo),0xFFFF);
++ MV_REG_WRITE(ETH_MAC_ADDR_HIGH_REG(pPortCtrl->portNo),0xFFFFFFFF);
++ }
++ else
++ {
++ /* Reject all Multicast addresses */
++ queue = -1;
++ portCfgReg &= ~ETH_UNICAST_PROMISCUOUS_MODE_MASK;
++ /* Clear all mcastCount */
++ memset(pPortCtrl->mcastCount, 0, sizeof(pPortCtrl->mcastCount));
++ }
++ MV_REG_WRITE(ETH_PORT_CONFIG_REG(pPortCtrl->portNo), portCfgReg);
++
++ /* Set Special Multicast and Other Multicast tables */
++ mvEthSetSpecialMcastTable(pPortCtrl->portNo, queue);
++ mvEthSetOtherMcastTable(pPortCtrl->portNo, queue);
++ ethSetUcastTable(pPortCtrl->portNo, queue);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthMacAddrSet - This function Set the port Unicast address.
++*
++* DESCRIPTION:
++* This function Set the port Ethernet MAC address. This address
++* will be used to send Pause frames if enabled. Packets with this
++* address will be accepted and dispatched to default RX queue
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet port handler.
++* char* pAddr - Address to be set
++*
++* RETURN: MV_STATUS
++* MV_OK - Success, Other - Faulure
++*
++*******************************************************************************/
++MV_STATUS mvEthMacAddrSet(void* pPortHndl, unsigned char *pAddr, int queue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++ unsigned int macH;
++ unsigned int macL;
++
++ if(queue >= MV_ETH_RX_Q_NUM)
++ {
++ mvOsPrintf("ethDrv: RX queue #%d is out of range\n", queue);
++ return MV_BAD_PARAM;
++ }
++
++ if(queue != -1)
++ {
++ macL = (pAddr[4] << 8) | (pAddr[5]);
++ macH = (pAddr[0] << 24)| (pAddr[1] << 16) |
++ (pAddr[2] << 8) | (pAddr[3] << 0);
++
++ MV_REG_WRITE(ETH_MAC_ADDR_LOW_REG(pPortCtrl->portNo), macL);
++ MV_REG_WRITE(ETH_MAC_ADDR_HIGH_REG(pPortCtrl->portNo), macH);
++ }
++
++ /* Accept frames of this address */
++ ethSetUcastAddr(pPortCtrl->portNo, pAddr[5], queue);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthMacAddrGet - This function returns the port Unicast address.
++*
++* DESCRIPTION:
++* This function returns the port Ethernet MAC address.
++*
++* INPUT:
++* int portNo - Ethernet port number.
++* char* pAddr - Pointer where address will be written to
++*
++* RETURN: MV_STATUS
++* MV_OK - Success, Other - Faulure
++*
++*******************************************************************************/
++MV_STATUS mvEthMacAddrGet(int portNo, unsigned char *pAddr)
++{
++ unsigned int macH;
++ unsigned int macL;
++
++ if(pAddr == NULL)
++ {
++ mvOsPrintf("mvEthMacAddrGet: NULL pointer.\n");
++ return MV_BAD_PARAM;
++ }
++
++ macH = MV_REG_READ(ETH_MAC_ADDR_HIGH_REG(portNo));
++ macL = MV_REG_READ(ETH_MAC_ADDR_LOW_REG(portNo));
++ pAddr[0] = (macH >> 24) & 0xff;
++ pAddr[1] = (macH >> 16) & 0xff;
++ pAddr[2] = (macH >> 8) & 0xff;
++ pAddr[3] = macH & 0xff;
++ pAddr[4] = (macL >> 8) & 0xff;
++ pAddr[5] = macL & 0xff;
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthMcastCrc8Get - Calculate CRC8 of MAC address.
++*
++* DESCRIPTION:
++*
++* INPUT:
++* MV_U8* pAddr - Address to calculate CRC-8
++*
++* RETURN: MV_U8 - CRC-8 of this MAC address
++*
++*******************************************************************************/
++MV_U8 mvEthMcastCrc8Get(MV_U8* pAddr)
++{
++ unsigned int macH;
++ unsigned int macL;
++ int macArray[48];
++ int crc[8];
++ int i;
++ unsigned char crcResult = 0;
++
++ /* Calculate CRC-8 out of the given address */
++ macH = (pAddr[0] << 8) | (pAddr[1]);
++ macL = (pAddr[2] << 24)| (pAddr[3] << 16) |
++ (pAddr[4] << 8) | (pAddr[5] << 0);
++
++ for(i=0; i<32; i++)
++ macArray[i] = (macL >> i) & 0x1;
++
++ for(i=32; i<48; i++)
++ macArray[i] = (macH >> (i - 32)) & 0x1;
++
++ crc[0] = macArray[45] ^ macArray[43] ^ macArray[40] ^ macArray[39] ^
++ macArray[35] ^ macArray[34] ^ macArray[31] ^ macArray[30] ^
++ macArray[28] ^ macArray[23] ^ macArray[21] ^ macArray[19] ^
++ macArray[18] ^ macArray[16] ^ macArray[14] ^ macArray[12] ^
++ macArray[8] ^ macArray[7] ^ macArray[6] ^ macArray[0];
++
++ crc[1] = macArray[46] ^ macArray[45] ^ macArray[44] ^ macArray[43] ^
++ macArray[41] ^ macArray[39] ^ macArray[36] ^ macArray[34] ^
++ macArray[32] ^ macArray[30] ^ macArray[29] ^ macArray[28] ^
++ macArray[24] ^ macArray[23] ^ macArray[22] ^ macArray[21] ^
++ macArray[20] ^ macArray[18] ^ macArray[17] ^ macArray[16] ^
++ macArray[15] ^ macArray[14] ^ macArray[13] ^ macArray[12] ^
++ macArray[9] ^ macArray[6] ^ macArray[1] ^ macArray[0];
++
++ crc[2] = macArray[47] ^ macArray[46] ^ macArray[44] ^ macArray[43] ^
++ macArray[42] ^ macArray[39] ^ macArray[37] ^ macArray[34] ^
++ macArray[33] ^ macArray[29] ^ macArray[28] ^ macArray[25] ^
++ macArray[24] ^ macArray[22] ^ macArray[17] ^ macArray[15] ^
++ macArray[13] ^ macArray[12] ^ macArray[10] ^ macArray[8] ^
++ macArray[6] ^ macArray[2] ^ macArray[1] ^ macArray[0];
++
++ crc[3] = macArray[47] ^ macArray[45] ^ macArray[44] ^ macArray[43] ^
++ macArray[40] ^ macArray[38] ^ macArray[35] ^ macArray[34] ^
++ macArray[30] ^ macArray[29] ^ macArray[26] ^ macArray[25] ^
++ macArray[23] ^ macArray[18] ^ macArray[16] ^ macArray[14] ^
++ macArray[13] ^ macArray[11] ^ macArray[9] ^ macArray[7] ^
++ macArray[3] ^ macArray[2] ^ macArray[1];
++
++ crc[4] = macArray[46] ^ macArray[45] ^ macArray[44] ^ macArray[41] ^
++ macArray[39] ^ macArray[36] ^ macArray[35] ^ macArray[31] ^
++ macArray[30] ^ macArray[27] ^ macArray[26] ^ macArray[24] ^
++ macArray[19] ^ macArray[17] ^ macArray[15] ^ macArray[14] ^
++ macArray[12] ^ macArray[10] ^ macArray[8] ^ macArray[4] ^
++ macArray[3] ^ macArray[2];
++
++ crc[5] = macArray[47] ^ macArray[46] ^ macArray[45] ^ macArray[42] ^
++ macArray[40] ^ macArray[37] ^ macArray[36] ^ macArray[32] ^
++ macArray[31] ^ macArray[28] ^ macArray[27] ^ macArray[25] ^
++ macArray[20] ^ macArray[18] ^ macArray[16] ^ macArray[15] ^
++ macArray[13] ^ macArray[11] ^ macArray[9] ^ macArray[5] ^
++ macArray[4] ^ macArray[3];
++
++ crc[6] = macArray[47] ^ macArray[46] ^ macArray[43] ^ macArray[41] ^
++ macArray[38] ^ macArray[37] ^ macArray[33] ^ macArray[32] ^
++ macArray[29] ^ macArray[28] ^ macArray[26] ^ macArray[21] ^
++ macArray[19] ^ macArray[17] ^ macArray[16] ^ macArray[14] ^
++ macArray[12] ^ macArray[10] ^ macArray[6] ^ macArray[5] ^
++ macArray[4];
++
++ crc[7] = macArray[47] ^ macArray[44] ^ macArray[42] ^ macArray[39] ^
++ macArray[38] ^ macArray[34] ^ macArray[33] ^ macArray[30] ^
++ macArray[29] ^ macArray[27] ^ macArray[22] ^ macArray[20] ^
++ macArray[18] ^ macArray[17] ^ macArray[15] ^ macArray[13] ^
++ macArray[11] ^ macArray[7] ^ macArray[6] ^ macArray[5];
++
++ for(i=0; i<8; i++)
++ crcResult = crcResult | (crc[i] << i);
++
++ return crcResult;
++}
++/*******************************************************************************
++* mvEthMcastAddrSet - Multicast address settings.
++*
++* DESCRIPTION:
++* This API controls the MV device MAC multicast support.
++* The MV device supports multicast using two tables:
++* 1) Special Multicast Table for MAC addresses of the form
++* 0x01-00-5E-00-00-XX (where XX is between 0x00 and 0xFF).
++* The MAC DA[7:0] bits are used as a pointer to the Special Multicast
++* Table entries in the DA-Filter table.
++* In this case, the function calls ethPortSmcAddr() routine to set the
++* Special Multicast Table.
++* 2) Other Multicast Table for multicast of another type. A CRC-8bit
++* is used as an index to the Other Multicast Table entries in the
++* DA-Filter table.
++* In this case, the function calculates the CRC-8bit value and calls
++* ethPortOmcAddr() routine to set the Other Multicast Table.
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet port handler.
++* MV_U8* pAddr - Address to be set
++* int queue - RX queue to capture all packets with this
++* Multicast MAC address.
++* -1 means delete this Multicast address.
++*
++* RETURN: MV_STATUS
++* MV_TRUE - Success, Other - Failure
++*
++*******************************************************************************/
++MV_STATUS mvEthMcastAddrSet(void* pPortHndl, MV_U8 *pAddr, int queue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++ unsigned char crcResult = 0;
++
++ if(queue >= MV_ETH_RX_Q_NUM)
++ {
++ mvOsPrintf("ethPort %d: RX queue #%d is out of range\n",
++ pPortCtrl->portNo, queue);
++ return MV_BAD_PARAM;
++ }
++
++ if((pAddr[0] == 0x01) &&
++ (pAddr[1] == 0x00) &&
++ (pAddr[2] == 0x5E) &&
++ (pAddr[3] == 0x00) &&
++ (pAddr[4] == 0x00))
++ {
++ ethSetSpecialMcastAddr(pPortCtrl->portNo, pAddr[5], queue);
++ }
++ else
++ {
++ crcResult = mvEthMcastCrc8Get(pAddr);
++
++ /* Check Add counter for this CRC value */
++ if(queue == -1)
++ {
++ if(pPortCtrl->mcastCount[crcResult] == 0)
++ {
++ mvOsPrintf("ethPort #%d: No valid Mcast for crc8=0x%02x\n",
++ pPortCtrl->portNo, (unsigned)crcResult);
++ return MV_NO_SUCH;
++ }
++
++ pPortCtrl->mcastCount[crcResult]--;
++ if(pPortCtrl->mcastCount[crcResult] != 0)
++ {
++ mvOsPrintf("ethPort #%d: After delete there are %d valid Mcast for crc8=0x%02x\n",
++ pPortCtrl->portNo, pPortCtrl->mcastCount[crcResult],
++ (unsigned)crcResult);
++ return MV_NO_CHANGE;
++ }
++ }
++ else
++ {
++ pPortCtrl->mcastCount[crcResult]++;
++ if(pPortCtrl->mcastCount[crcResult] > 1)
++ {
++ mvOsPrintf("ethPort #%d: Valid Mcast for crc8=0x%02x already exists\n",
++ pPortCtrl->portNo, (unsigned)crcResult);
++ return MV_NO_CHANGE;
++ }
++ }
++ ethSetOtherMcastAddr(pPortCtrl->portNo, crcResult, queue);
++ }
++ return MV_OK;
++}
++
++/*******************************************************************************
++* ethSetUcastTable - Unicast address settings.
++*
++* DESCRIPTION:
++* Set all entries in the Unicast MAC Table queue==-1 means reject all
++* INPUT:
++*
++* RETURN:
++*
++*******************************************************************************/
++static void ethSetUcastTable(int portNo, int queue)
++{
++ int offset;
++ MV_U32 regValue;
++
++ if(queue == -1)
++ {
++ regValue = 0;
++ }
++ else
++ {
++ regValue = (((0x01 | (queue<<1)) << 0) |
++ ((0x01 | (queue<<1)) << 8) |
++ ((0x01 | (queue<<1)) << 16) |
++ ((0x01 | (queue<<1)) << 24));
++ }
++
++ for (offset=0; offset<=0xC; offset+=4)
++ MV_REG_WRITE((ETH_DA_FILTER_UCAST_BASE(portNo) + offset), regValue);
++}
++
++/*******************************************************************************
++* mvEthSetSpecialMcastTable - Special Multicast address settings.
++*
++* DESCRIPTION:
++* Set all entries to the Special Multicast MAC Table. queue==-1 means reject all
++* INPUT:
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_VOID mvEthSetSpecialMcastTable(int portNo, int queue)
++{
++ int offset;
++ MV_U32 regValue;
++
++ if(queue == -1)
++ {
++ regValue = 0;
++ }
++ else
++ {
++ regValue = (((0x01 | (queue<<1)) << 0) |
++ ((0x01 | (queue<<1)) << 8) |
++ ((0x01 | (queue<<1)) << 16) |
++ ((0x01 | (queue<<1)) << 24));
++ }
++
++ for (offset=0; offset<=0xFC; offset+=4)
++ {
++ MV_REG_WRITE((ETH_DA_FILTER_SPEC_MCAST_BASE(portNo) +
++ offset), regValue);
++ }
++}
++
++/*******************************************************************************
++* mvEthSetOtherMcastTable - Other Multicast address settings.
++*
++* DESCRIPTION:
++* Set all entries to the Other Multicast MAC Table. queue==-1 means reject all
++* INPUT:
++*
++* RETURN:
++*
++*******************************************************************************/
++MV_VOID mvEthSetOtherMcastTable(int portNo, int queue)
++{
++ int offset;
++ MV_U32 regValue;
++
++ if(queue == -1)
++ {
++ regValue = 0;
++ }
++ else
++ {
++ regValue = (((0x01 | (queue<<1)) << 0) |
++ ((0x01 | (queue<<1)) << 8) |
++ ((0x01 | (queue<<1)) << 16) |
++ ((0x01 | (queue<<1)) << 24));
++ }
++
++ for (offset=0; offset<=0xFC; offset+=4)
++ {
++ MV_REG_WRITE((ETH_DA_FILTER_OTH_MCAST_BASE(portNo) +
++ offset), regValue);
++ }
++}
++
++/*******************************************************************************
++* ethSetUcastAddr - This function Set the port unicast address table
++*
++* DESCRIPTION:
++* This function locates the proper entry in the Unicast table for the
++* specified MAC nibble and sets its properties according to function
++* parameters.
++*
++* INPUT:
++* int ethPortNum - Port number.
++* MV_U8 lastNibble - Unicast MAC Address last nibble.
++* int queue - Rx queue number for this MAC address.
++* value "-1" means remove address
++*
++* OUTPUT:
++* This function add/removes MAC addresses from the port unicast address
++* table.
++*
++* RETURN:
++* MV_TRUE is output succeeded.
++* MV_FALSE if option parameter is invalid.
++*
++*******************************************************************************/
++static MV_BOOL ethSetUcastAddr(int portNo, MV_U8 lastNibble, int queue)
++{
++ unsigned int unicastReg;
++ unsigned int tblOffset;
++ unsigned int regOffset;
++
++ /* Locate the Unicast table entry */
++ lastNibble = (0xf & lastNibble);
++ tblOffset = (lastNibble / 4) * 4; /* Register offset from unicast table base*/
++ regOffset = lastNibble % 4; /* Entry offset within the above register */
++
++
++ unicastReg = MV_REG_READ( (ETH_DA_FILTER_UCAST_BASE(portNo) +
++ tblOffset));
++
++
++ if(queue == -1)
++ {
++ /* Clear accepts frame bit at specified unicast DA table entry */
++ unicastReg &= ~(0xFF << (8*regOffset));
++ }
++ else
++ {
++ unicastReg &= ~(0xFF << (8*regOffset));
++ unicastReg |= ((0x01 | (queue<<1)) << (8*regOffset));
++ }
++ MV_REG_WRITE( (ETH_DA_FILTER_UCAST_BASE(portNo) + tblOffset),
++ unicastReg);
++
++ return MV_TRUE;
++}
++
++/*******************************************************************************
++* ethSetSpecialMcastAddr - Special Multicast address settings.
++*
++* DESCRIPTION:
++* This routine controls the MV device special MAC multicast support.
++* The Special Multicast Table for MAC addresses supports MAC of the form
++* 0x01-00-5E-00-00-XX (where XX is between 0x00 and 0xFF).
++* The MAC DA[7:0] bits are used as a pointer to the Special Multicast
++* Table entries in the DA-Filter table.
++* This function set the Special Multicast Table appropriate entry
++* according to the argument given.
++*
++* INPUT:
++* int ethPortNum Port number.
++* unsigned char mcByte Multicast addr last byte (MAC DA[7:0] bits).
++* int queue Rx queue number for this MAC address.
++* int option 0 = Add, 1 = remove address.
++*
++* OUTPUT:
++* See description.
++*
++* RETURN:
++* MV_TRUE is output succeeded.
++* MV_FALSE if option parameter is invalid.
++*
++*******************************************************************************/
++static MV_BOOL ethSetSpecialMcastAddr(int ethPortNum, MV_U8 lastByte, int queue)
++{
++ unsigned int smcTableReg;
++ unsigned int tblOffset;
++ unsigned int regOffset;
++
++ /* Locate the SMC table entry */
++ tblOffset = (lastByte / 4); /* Register offset from SMC table base */
++ regOffset = lastByte % 4; /* Entry offset within the above register */
++
++ smcTableReg = MV_REG_READ((ETH_DA_FILTER_SPEC_MCAST_BASE(ethPortNum) + tblOffset*4));
++
++ if(queue == -1)
++ {
++ /* Clear accepts frame bit at specified Special DA table entry */
++ smcTableReg &= ~(0xFF << (8 * regOffset));
++ }
++ else
++ {
++ smcTableReg &= ~(0xFF << (8 * regOffset));
++ smcTableReg |= ((0x01 | (queue<<1)) << (8 * regOffset));
++ }
++ MV_REG_WRITE((ETH_DA_FILTER_SPEC_MCAST_BASE(ethPortNum) +
++ tblOffset*4), smcTableReg);
++
++ return MV_TRUE;
++}
++
++/*******************************************************************************
++* ethSetOtherMcastAddr - Multicast address settings.
++*
++* DESCRIPTION:
++* This routine controls the MV device Other MAC multicast support.
++* The Other Multicast Table is used for multicast of another type.
++* A CRC-8bit is used as an index to the Other Multicast Table entries
++* in the DA-Filter table.
++* The function gets the CRC-8bit value from the calling routine and
++* set the Other Multicast Table appropriate entry according to the
++* CRC-8 argument given.
++*
++* INPUT:
++* int ethPortNum Port number.
++* MV_U8 crc8 A CRC-8bit (Polynomial: x^8+x^2+x^1+1).
++* int queue Rx queue number for this MAC address.
++*
++* OUTPUT:
++* See description.
++*
++* RETURN:
++* MV_TRUE is output succeeded.
++* MV_FALSE if option parameter is invalid.
++*
++*******************************************************************************/
++static MV_BOOL ethSetOtherMcastAddr(int ethPortNum, MV_U8 crc8, int queue)
++{
++ unsigned int omcTableReg;
++ unsigned int tblOffset;
++ unsigned int regOffset;
++
++ /* Locate the OMC table entry */
++ tblOffset = (crc8 / 4) * 4; /* Register offset from OMC table base */
++ regOffset = crc8 % 4; /* Entry offset within the above register */
++
++ omcTableReg = MV_REG_READ(
++ (ETH_DA_FILTER_OTH_MCAST_BASE(ethPortNum) + tblOffset));
++
++ if(queue == -1)
++ {
++ /* Clear accepts frame bit at specified Other DA table entry */
++ omcTableReg &= ~(0xFF << (8 * regOffset));
++ }
++ else
++ {
++ omcTableReg &= ~(0xFF << (8 * regOffset));
++ omcTableReg |= ((0x01 | (queue<<1)) << (8 * regOffset));
++ }
++
++ MV_REG_WRITE((ETH_DA_FILTER_OTH_MCAST_BASE(ethPortNum) + tblOffset),
++ omcTableReg);
++
++ return MV_TRUE;
++}
++
++
++/******************************************************************************/
++/* MIB Counters functions */
++/******************************************************************************/
++
++
++/*******************************************************************************
++* mvEthMibCounterRead - Read a MIB counter
++*
++* DESCRIPTION:
++* This function reads a MIB counter of a specific ethernet port.
++* NOTE - Read from ETH_MIB_GOOD_OCTETS_RECEIVED_LOW or
++* ETH_MIB_GOOD_OCTETS_SENT_LOW counters will return 64 bits value,
++* so pHigh32 pointer should not be NULL in this case.
++*
++* INPUT:
++* int ethPortNum - Ethernet Port number.
++* unsigned int mibOffset - MIB counter offset.
++*
++* OUTPUT:
++* MV_U32* pHigh32 - pointer to place where 32 most significant bits
++* of the counter will be stored.
++*
++* RETURN:
++* 32 low sgnificant bits of MIB counter value.
++*
++*******************************************************************************/
++MV_U32 mvEthMibCounterRead(void* pPortHandle, unsigned int mibOffset,
++ MV_U32* pHigh32)
++{
++ int portNo;
++ MV_U32 valLow32, valHigh32;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++
++ portNo = pPortCtrl->portNo;
++
++ valLow32 = MV_REG_READ(ETH_MIB_COUNTERS_BASE(portNo) + mibOffset);
++
++ /* Implement FEr ETH. Erroneous Value when Reading the Upper 32-bits */
++ /* of a 64-bit MIB Counter. */
++ if( (mibOffset == ETH_MIB_GOOD_OCTETS_RECEIVED_LOW) ||
++ (mibOffset == ETH_MIB_GOOD_OCTETS_SENT_LOW) )
++ {
++ valHigh32 = MV_REG_READ(ETH_MIB_COUNTERS_BASE(portNo) + mibOffset + 4);
++ if(pHigh32 != NULL)
++ *pHigh32 = valHigh32;
++ }
++ return valLow32;
++}
++
++/*******************************************************************************
++* mvEthMibCountersClear - Clear all MIB counters
++*
++* DESCRIPTION:
++* This function clears all MIB counters
++*
++* INPUT:
++* int ethPortNum - Ethernet Port number.
++*
++*
++* RETURN: void
++*
++*******************************************************************************/
++void mvEthMibCountersClear(void* pPortHandle)
++{
++ int i, portNo;
++ unsigned int dummy;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++
++ portNo = pPortCtrl->portNo;
++
++ /* Perform dummy reads from MIB counters */
++ for(i=ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i<ETH_MIB_LATE_COLLISION; i+=4)
++ dummy = MV_REG_READ((ETH_MIB_COUNTERS_BASE(portNo) + i));
++}
++
++
++/******************************************************************************/
++/* RX Dispatching configuration routines */
++/******************************************************************************/
++
++int mvEthTosToRxqGet(void* pPortHandle, int tos)
++{
++ MV_U32 regValue;
++ int regIdx, regOffs, rxq;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++
++ if(tos > 0xFF)
++ {
++ mvOsPrintf("eth_%d: tos=0x%x is out of range\n", pPortCtrl->portNo, tos);
++ return -1;
++ }
++ regIdx = mvOsDivide(tos>>2, 10);
++ regOffs = mvOsReminder(tos>>2, 10);
++
++ regValue = MV_REG_READ(ETH_DIFF_SERV_PRIO_REG(pPortCtrl->portNo, regIdx) );
++ rxq = (regValue >> (regOffs*3));
++ rxq &= 0x7;
++
++ return rxq;
++}
++
++/*******************************************************************************
++* mvEthTosToRxqSet - Map packets with special TOS value to special RX queue
++*
++* DESCRIPTION:
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++* int tos - TOS value in the IP header of the packet
++* int rxq - RX Queue for packets with the configured TOS value
++* Negative value (-1) means no special processing for these packets,
++* so they will be processed as regular packets.
++*
++* RETURN: MV_STATUS
++*******************************************************************************/
++MV_STATUS mvEthTosToRxqSet(void* pPortHandle, int tos, int rxq)
++{
++ MV_U32 regValue;
++ int regIdx, regOffs;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++
++ if( (rxq < 0) || (rxq >= MV_ETH_RX_Q_NUM) )
++ {
++ mvOsPrintf("eth_%d: RX queue #%d is out of range\n", pPortCtrl->portNo, rxq);
++ return MV_BAD_PARAM;
++ }
++ if(tos > 0xFF)
++ {
++ mvOsPrintf("eth_%d: tos=0x%x is out of range\n", pPortCtrl->portNo, tos);
++ return MV_BAD_PARAM;
++ }
++ regIdx = mvOsDivide(tos>>2, 10);
++ regOffs = mvOsReminder(tos>>2, 10);
++
++ regValue = MV_REG_READ(ETH_DIFF_SERV_PRIO_REG(pPortCtrl->portNo, regIdx) );
++ regValue &= ~(0x7 << (regOffs*3));
++ regValue |= (rxq << (regOffs*3));
++
++ MV_REG_WRITE(ETH_DIFF_SERV_PRIO_REG(pPortCtrl->portNo, regIdx), regValue);
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthVlanPrioRxQueue - Configure RX queue to capture VLAN tagged packets with
++* special priority bits [0-2]
++*
++* DESCRIPTION:
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++* int bpduQueue - Special queue to capture VLAN tagged packets with special
++* priority.
++* Negative value (-1) means no special processing for these packets,
++* so they will be processed as regular packets.
++*
++* RETURN: MV_STATUS
++* MV_OK - Success
++* MV_FAIL - Failed.
++*
++*******************************************************************************/
++MV_STATUS mvEthVlanPrioRxQueue(void* pPortHandle, int vlanPrio, int vlanPrioQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ MV_U32 vlanPrioReg;
++
++ if(vlanPrioQueue >= MV_ETH_RX_Q_NUM)
++ {
++ mvOsPrintf("ethDrv: RX queue #%d is out of range\n", vlanPrioQueue);
++ return MV_BAD_PARAM;
++ }
++ if(vlanPrio >= 8)
++ {
++ mvOsPrintf("ethDrv: vlanPrio=%d is out of range\n", vlanPrio);
++ return MV_BAD_PARAM;
++ }
++
++ vlanPrioReg = MV_REG_READ(ETH_VLAN_TAG_TO_PRIO_REG(pPortCtrl->portNo));
++ vlanPrioReg &= ~(0x7 << (vlanPrio*3));
++ vlanPrioReg |= (vlanPrioQueue << (vlanPrio*3));
++ MV_REG_WRITE(ETH_VLAN_TAG_TO_PRIO_REG(pPortCtrl->portNo), vlanPrioReg);
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvEthBpduRxQueue - Configure RX queue to capture BPDU packets.
++*
++* DESCRIPTION:
++* This function defines processing of BPDU packets.
++* BPDU packets can be accepted and captured to one of RX queues
++* or can be processing as regular Multicast packets.
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++* int bpduQueue - Special queue to capture BPDU packets (DA is equal to
++* 01-80-C2-00-00-00 through 01-80-C2-00-00-FF,
++* except for the Flow-Control Pause packets).
++* Negative value (-1) means no special processing for BPDU,
++* packets so they will be processed as regular Multicast packets.
++*
++* RETURN: MV_STATUS
++* MV_OK - Success
++* MV_FAIL - Failed.
++*
++*******************************************************************************/
++MV_STATUS mvEthBpduRxQueue(void* pPortHandle, int bpduQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ MV_U32 portCfgReg;
++ MV_U32 portCfgExtReg;
++
++ if(bpduQueue >= MV_ETH_RX_Q_NUM)
++ {
++ mvOsPrintf("ethDrv: RX queue #%d is out of range\n", bpduQueue);
++ return MV_BAD_PARAM;
++ }
++
++ portCfgExtReg = MV_REG_READ(ETH_PORT_CONFIG_EXTEND_REG(pPortCtrl->portNo));
++
++ portCfgReg = MV_REG_READ(ETH_PORT_CONFIG_REG(pPortCtrl->portNo));
++ if(bpduQueue >= 0)
++ {
++ pPortCtrl->portConfig.rxBpduQ = bpduQueue;
++
++ portCfgReg &= ~ETH_DEF_RX_BPDU_QUEUE_ALL_MASK;
++ portCfgReg |= ETH_DEF_RX_BPDU_QUEUE_MASK(pPortCtrl->portConfig.rxBpduQ);
++
++ MV_REG_WRITE(ETH_PORT_CONFIG_REG(pPortCtrl->portNo), portCfgReg);
++
++ portCfgExtReg |= ETH_CAPTURE_SPAN_BPDU_ENABLE_MASK;
++ }
++ else
++ {
++ pPortCtrl->portConfig.rxBpduQ = -1;
++ /* no special processing for BPDU packets */
++ portCfgExtReg &= (~ETH_CAPTURE_SPAN_BPDU_ENABLE_MASK);
++ }
++
++ MV_REG_WRITE(ETH_PORT_CONFIG_EXTEND_REG(pPortCtrl->portNo), portCfgExtReg);
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvEthArpRxQueue - Configure RX queue to capture ARP packets.
++*
++* DESCRIPTION:
++* This function defines processing of ARP (type=0x0806) packets.
++* ARP packets can be accepted and captured to one of RX queues
++* or can be processed as other Broadcast packets.
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++* int arpQueue - Special queue to capture ARP packets (type=0x806).
++* Negative value (-1) means discard ARP packets
++*
++* RETURN: MV_STATUS
++* MV_OK - Success
++* MV_FAIL - Failed.
++*
++*******************************************************************************/
++MV_STATUS mvEthArpRxQueue(void* pPortHandle, int arpQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ MV_U32 portCfgReg;
++
++ if(arpQueue >= MV_ETH_RX_Q_NUM)
++ {
++ mvOsPrintf("ethDrv: RX queue #%d is out of range\n", arpQueue);
++ return MV_BAD_PARAM;
++ }
++
++ portCfgReg = MV_REG_READ(ETH_PORT_CONFIG_REG(pPortCtrl->portNo));
++
++ if(arpQueue >= 0)
++ {
++ pPortCtrl->portConfig.rxArpQ = arpQueue;
++ portCfgReg &= ~ETH_DEF_RX_ARP_QUEUE_ALL_MASK;
++ portCfgReg |= ETH_DEF_RX_ARP_QUEUE_MASK(pPortCtrl->portConfig.rxArpQ);
++
++ portCfgReg &= (~ETH_REJECT_ARP_BCAST_MASK);
++ }
++ else
++ {
++ pPortCtrl->portConfig.rxArpQ = -1;
++ portCfgReg |= ETH_REJECT_ARP_BCAST_MASK;
++ }
++
++ MV_REG_WRITE(ETH_PORT_CONFIG_REG(pPortCtrl->portNo), portCfgReg);
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvEthTcpRxQueue - Configure RX queue to capture TCP packets.
++*
++* DESCRIPTION:
++* This function defines processing of TCP packets.
++* TCP packets can be accepted and captured to one of RX queues
++* or can be processed as regular Unicast packets.
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++* int tcpQueue - Special queue to capture TCP packets. Value "-1"
++* means no special processing for TCP packets,
++* so they will be processed as regular
++*
++* RETURN: MV_STATUS
++* MV_OK - Success
++* MV_FAIL - Failed.
++*
++*******************************************************************************/
++MV_STATUS mvEthTcpRxQueue(void* pPortHandle, int tcpQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ MV_U32 portCfgReg;
++
++ if(tcpQueue >= MV_ETH_RX_Q_NUM)
++ {
++ mvOsPrintf("ethDrv: RX queue #%d is out of range\n", tcpQueue);
++ return MV_BAD_PARAM;
++ }
++ portCfgReg = MV_REG_READ(ETH_PORT_CONFIG_REG(pPortCtrl->portNo));
++
++ if(tcpQueue >= 0)
++ {
++ pPortCtrl->portConfig.rxTcpQ = tcpQueue;
++ portCfgReg &= ~ETH_DEF_RX_TCP_QUEUE_ALL_MASK;
++ portCfgReg |= ETH_DEF_RX_TCP_QUEUE_MASK(pPortCtrl->portConfig.rxTcpQ);
++
++ portCfgReg |= ETH_CAPTURE_TCP_FRAMES_ENABLE_MASK;
++ }
++ else
++ {
++ pPortCtrl->portConfig.rxTcpQ = -1;
++ portCfgReg &= (~ETH_CAPTURE_TCP_FRAMES_ENABLE_MASK);
++ }
++
++ MV_REG_WRITE(ETH_PORT_CONFIG_REG(pPortCtrl->portNo), portCfgReg);
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvEthUdpRxQueue - Configure RX queue to capture UDP packets.
++*
++* DESCRIPTION:
++* This function defines processing of UDP packets.
++* TCP packets can be accepted and captured to one of RX queues
++* or can be processed as regular Unicast packets.
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++* int udpQueue - Special queue to capture UDP packets. Value "-1"
++* means no special processing for UDP packets,
++* so they will be processed as regular
++*
++* RETURN: MV_STATUS
++* MV_OK - Success
++* MV_FAIL - Failed.
++*
++*******************************************************************************/
++MV_STATUS mvEthUdpRxQueue(void* pPortHandle, int udpQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ MV_U32 portCfgReg;
++
++ if(udpQueue >= MV_ETH_RX_Q_NUM)
++ {
++ mvOsPrintf("ethDrv: RX queue #%d is out of range\n", udpQueue);
++ return MV_BAD_PARAM;
++ }
++
++ portCfgReg = MV_REG_READ(ETH_PORT_CONFIG_REG(pPortCtrl->portNo));
++
++ if(udpQueue >= 0)
++ {
++ pPortCtrl->portConfig.rxUdpQ = udpQueue;
++ portCfgReg &= ~ETH_DEF_RX_UDP_QUEUE_ALL_MASK;
++ portCfgReg |= ETH_DEF_RX_UDP_QUEUE_MASK(pPortCtrl->portConfig.rxUdpQ);
++
++ portCfgReg |= ETH_CAPTURE_UDP_FRAMES_ENABLE_MASK;
++ }
++ else
++ {
++ pPortCtrl->portConfig.rxUdpQ = -1;
++ portCfgReg &= ~ETH_CAPTURE_UDP_FRAMES_ENABLE_MASK;
++ }
++
++ MV_REG_WRITE(ETH_PORT_CONFIG_REG(pPortCtrl->portNo), portCfgReg);
++
++ return MV_OK;
++}
++
++
++/******************************************************************************/
++/* Speed, Duplex, FlowControl routines */
++/******************************************************************************/
++
++/*******************************************************************************
++* mvEthSpeedDuplexSet - Set Speed and Duplex of the port.
++*
++* DESCRIPTION:
++* This function configure the port to work with desirable Duplex and Speed.
++* Changing of these parameters are allowed only when port is disabled.
++* This function disable the port if was enabled, change duplex and speed
++* and, enable the port back if needed.
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++* ETH_PORT_SPEED speed - Speed of the port.
++* ETH_PORT_SPEED duplex - Duplex of the port.
++*
++* RETURN: MV_STATUS
++* MV_OK - Success
++* MV_OUT_OF_RANGE - Failed. Port is out of valid range
++* MV_NOT_FOUND - Failed. Port is not initialized.
++* MV_BAD_PARAM - Input parameters (speed/duplex) in conflict.
++* MV_BAD_VALUE - Value of one of input parameters (speed, duplex)
++* is not valid
++*
++*******************************************************************************/
++MV_STATUS mvEthSpeedDuplexSet(void* pPortHandle, MV_ETH_PORT_SPEED speed,
++ MV_ETH_PORT_DUPLEX duplex)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ int port = pPortCtrl->portNo;
++ MV_U32 portSerialCtrlReg;
++
++ if( (port < 0) || (port >= (int)mvCtrlEthMaxPortGet()) )
++ return MV_OUT_OF_RANGE;
++
++ pPortCtrl = ethPortCtrl[port];
++ if(pPortCtrl == NULL)
++ return MV_NOT_FOUND;
++
++ /* Check validity */
++ if( (speed == MV_ETH_SPEED_1000) && (duplex == MV_ETH_DUPLEX_HALF) )
++ return MV_BAD_PARAM;
++
++ portSerialCtrlReg = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(port));
++ /* Set Speed */
++ switch(speed)
++ {
++ case MV_ETH_SPEED_AN:
++ portSerialCtrlReg &= ~ETH_DISABLE_SPEED_AUTO_NEG_MASK;
++ break;
++
++ case MV_ETH_SPEED_10:
++ portSerialCtrlReg |= ETH_DISABLE_SPEED_AUTO_NEG_MASK;
++ portSerialCtrlReg &= ~ETH_SET_GMII_SPEED_1000_MASK;
++ portSerialCtrlReg &= ~ETH_SET_MII_SPEED_100_MASK;
++ break;
++
++ case MV_ETH_SPEED_100:
++ portSerialCtrlReg |= ETH_DISABLE_SPEED_AUTO_NEG_MASK;
++ portSerialCtrlReg &= ~ETH_SET_GMII_SPEED_1000_MASK;
++ portSerialCtrlReg |= ETH_SET_MII_SPEED_100_MASK;
++ break;
++
++ case MV_ETH_SPEED_1000:
++ portSerialCtrlReg |= ETH_DISABLE_SPEED_AUTO_NEG_MASK;
++ portSerialCtrlReg |= ETH_SET_GMII_SPEED_1000_MASK;
++ break;
++
++ default:
++ mvOsPrintf("ethDrv: Unexpected Speed value %d\n", speed);
++ return MV_BAD_VALUE;
++ }
++ /* Set duplex */
++ switch(duplex)
++ {
++ case MV_ETH_DUPLEX_AN:
++ portSerialCtrlReg &= ~ETH_DISABLE_DUPLEX_AUTO_NEG_MASK;
++ break;
++
++ case MV_ETH_DUPLEX_HALF:
++ portSerialCtrlReg |= ETH_DISABLE_DUPLEX_AUTO_NEG_MASK;
++ portSerialCtrlReg &= ~ETH_SET_FULL_DUPLEX_MASK;
++ break;
++
++ case MV_ETH_DUPLEX_FULL:
++ portSerialCtrlReg |= ETH_DISABLE_DUPLEX_AUTO_NEG_MASK;
++ portSerialCtrlReg |= ETH_SET_FULL_DUPLEX_MASK;
++ break;
++
++ default:
++ mvOsPrintf("ethDrv: Unexpected Duplex value %d\n", duplex);
++ return MV_BAD_VALUE;
++ }
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(port), portSerialCtrlReg);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthFlowCtrlSet - Set Flow Control of the port.
++*
++* DESCRIPTION:
++* This function configure the port to work with desirable Duplex and
++* Speed. Changing of these parameters are allowed only when port is
++* disabled. This function disable the port if was enabled, change
++* duplex and speed and, enable the port back if needed.
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++* MV_ETH_PORT_FC flowControl - Flow control of the port.
++*
++* RETURN: MV_STATUS
++* MV_OK - Success
++* MV_OUT_OF_RANGE - Failed. Port is out of valid range
++* MV_NOT_FOUND - Failed. Port is not initialized.
++* MV_BAD_VALUE - Value flowControl parameters is not valid
++*
++*******************************************************************************/
++MV_STATUS mvEthFlowCtrlSet(void* pPortHandle, MV_ETH_PORT_FC flowControl)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ int port = pPortCtrl->portNo;
++ MV_U32 portSerialCtrlReg;
++
++ if( (port < 0) || (port >= (int)mvCtrlEthMaxPortGet() ) )
++ return MV_OUT_OF_RANGE;
++
++ pPortCtrl = ethPortCtrl[port];
++ if(pPortCtrl == NULL)
++ return MV_NOT_FOUND;
++
++ portSerialCtrlReg = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(port));
++ switch(flowControl)
++ {
++ case MV_ETH_FC_AN_ADV_DIS:
++ portSerialCtrlReg &= ~ETH_DISABLE_FC_AUTO_NEG_MASK;
++ portSerialCtrlReg &= ~ETH_ADVERTISE_SYM_FC_MASK;
++ break;
++
++ case MV_ETH_FC_AN_ADV_SYM:
++ portSerialCtrlReg &= ~ETH_DISABLE_FC_AUTO_NEG_MASK;
++ portSerialCtrlReg |= ETH_ADVERTISE_SYM_FC_MASK;
++ break;
++
++ case MV_ETH_FC_DISABLE:
++ portSerialCtrlReg |= ETH_DISABLE_FC_AUTO_NEG_MASK;
++ portSerialCtrlReg &= ~ETH_SET_FLOW_CTRL_MASK;
++ break;
++
++ case MV_ETH_FC_ENABLE:
++ portSerialCtrlReg |= ETH_DISABLE_FC_AUTO_NEG_MASK;
++ portSerialCtrlReg |= ETH_SET_FLOW_CTRL_MASK;
++ break;
++
++ default:
++ mvOsPrintf("ethDrv: Unexpected FlowControl value %d\n", flowControl);
++ return MV_BAD_VALUE;
++ }
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(port), portSerialCtrlReg);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthHeaderModeSet - Set port header mode.
++*
++* DESCRIPTION:
++* This function configures the port to work in Marvell-Header mode.
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++* MV_ETH_HEADER_MODE headerMode - The header mode to set the port in.
++*
++* RETURN: MV_STATUS
++* MV_OK - Success
++* MV_NOT_SUPPORTED- Feature not supported.
++* MV_OUT_OF_RANGE - Failed. Port is out of valid range
++* MV_NOT_FOUND - Failed. Port is not initialized.
++* MV_BAD_VALUE - Value of headerMode or numRxQueue parameter is not valid.
++*
++*******************************************************************************/
++MV_STATUS mvEthHeaderModeSet(void* pPortHandle, MV_ETH_HEADER_MODE headerMode)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ int port = pPortCtrl->portNo;
++ MV_U32 mvHeaderReg;
++ MV_U32 numRxQ = MV_ETH_RX_Q_NUM;
++
++ if((port < 0) || (port >= mvCtrlEthMaxPortGet()))
++ return MV_OUT_OF_RANGE;
++
++ pPortCtrl = ethPortCtrl[port];
++ if(pPortCtrl == NULL)
++ return MV_NOT_FOUND;
++
++ mvHeaderReg = MV_REG_READ(ETH_PORT_MARVELL_HEADER_REG(port));
++ /* Disable header mode. */
++ mvHeaderReg &= ~ETH_MVHDR_EN_MASK;
++
++ if(headerMode != MV_ETH_DISABLE_HEADER_MODE)
++ {
++ /* Enable Header mode. */
++ mvHeaderReg |= ETH_MVHDR_EN_MASK;
++
++ /* Clear DA-Prefix & MHMask fields.*/
++ mvHeaderReg &= ~(ETH_MVHDR_DAPREFIX_MASK | ETH_MVHDR_MHMASK_MASK);
++
++ if(numRxQ > 1)
++ {
++ switch (headerMode)
++ {
++ case(MV_ETH_ENABLE_HEADER_MODE_PRI_2_1):
++ mvHeaderReg |= ETH_MVHDR_DAPREFIX_PRI_1_2;
++ break;
++ case(MV_ETH_ENABLE_HEADER_MODE_PRI_DBNUM):
++ mvHeaderReg |= ETH_MVHDR_DAPREFIX_DBNUM_PRI;
++ break;
++ case(MV_ETH_ENABLE_HEADER_MODE_PRI_SPID):
++ mvHeaderReg |= ETH_MVHDR_DAPREFIX_SPID_PRI;
++ break;
++ default:
++ break;
++ }
++
++ switch (numRxQ)
++ {
++ case (4):
++ mvHeaderReg |= ETH_MVHDR_MHMASK_4_QUEUE;
++ break;
++ case (8):
++ mvHeaderReg |= ETH_MVHDR_MHMASK_8_QUEUE;
++ break;
++ default:
++ break;
++ }
++ }
++ }
++
++ MV_REG_WRITE(ETH_PORT_MARVELL_HEADER_REG(port), mvHeaderReg);
++
++ return MV_OK;
++}
++
++#if (MV_ETH_VERSION >= 4)
++/*******************************************************************************
++* mvEthEjpModeSet - Enable / Disable EJP policy for TX.
++*
++* DESCRIPTION:
++* This function
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++* MV_BOOL TRUE - enable EJP mode
++* FALSE - disable EJP mode
++*
++* OUTPUT: MV_STATUS
++* MV_OK - Success
++* Other - Failure
++*
++* RETURN: None.
++*
++*******************************************************************************/
++MV_STATUS mvEthEjpModeSet(void* pPortHandle, int mode)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ int port = pPortCtrl->portNo;
++
++ if((port < 0) || (port >= mvCtrlEthMaxPortGet()))
++ return MV_OUT_OF_RANGE;
++
++ pPortCtrl = ethPortCtrl[port];
++ if(pPortCtrl == NULL)
++ return MV_NOT_FOUND;
++
++ pPortCtrl->portConfig.ejpMode = mode;
++ if(mode)
++ {
++ /* EJP enabled */
++ MV_REG_WRITE(ETH_TXQ_CMD_1_REG(port), ETH_TX_EJP_ENABLE_MASK);
++ }
++ else
++ {
++ /* EJP disabled */
++ MV_REG_WRITE(ETH_TXQ_CMD_1_REG(port), 0);
++ }
++ mvOsPrintf("eth_%d: EJP %s - ETH_TXQ_CMD_1_REG: 0x%x = 0x%08x\n",
++ port, mode ? "Enabled" : "Disabled", ETH_TXQ_CMD_1_REG(port),
++ MV_REG_READ(ETH_TXQ_CMD_1_REG(port)));
++
++ return MV_OK;
++}
++#endif /* MV_ETH_VERSION >= 4 */
++
++/*******************************************************************************
++* mvEthStatusGet - Get major properties of the port .
++*
++* DESCRIPTION:
++* This function get major properties of the port (link, speed, duplex,
++* flowControl, etc) and return them using the single structure.
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++*
++* OUTPUT:
++* MV_ETH_PORT_STATUS* pStatus - Pointer to structure, were port status
++* will be placed.
++*
++* RETURN: None.
++*
++*******************************************************************************/
++void mvEthStatusGet(void* pPortHandle, MV_ETH_PORT_STATUS* pStatus)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ int port = pPortCtrl->portNo;
++
++ MV_U32 regValue;
++
++ regValue = MV_REG_READ( ETH_PORT_STATUS_REG(port) );
++
++ if(regValue & ETH_GMII_SPEED_1000_MASK)
++ pStatus->speed = MV_ETH_SPEED_1000;
++ else if(regValue & ETH_MII_SPEED_100_MASK)
++ pStatus->speed = MV_ETH_SPEED_100;
++ else
++ pStatus->speed = MV_ETH_SPEED_10;
++
++ if(regValue & ETH_LINK_UP_MASK)
++ pStatus->isLinkUp = MV_TRUE;
++ else
++ pStatus->isLinkUp = MV_FALSE;
++
++ if(regValue & ETH_FULL_DUPLEX_MASK)
++ pStatus->duplex = MV_ETH_DUPLEX_FULL;
++ else
++ pStatus->duplex = MV_ETH_DUPLEX_HALF;
++
++
++ if(regValue & ETH_ENABLE_RCV_FLOW_CTRL_MASK)
++ pStatus->flowControl = MV_ETH_FC_ENABLE;
++ else
++ pStatus->flowControl = MV_ETH_FC_DISABLE;
++}
++
++
++/******************************************************************************/
++/* PHY Control Functions */
++/******************************************************************************/
++
++
++/*******************************************************************************
++* mvEthPhyAddrSet - Set the ethernet port PHY address.
++*
++* DESCRIPTION:
++* This routine set the ethernet port PHY address according to given
++* parameter.
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++* int phyAddr - PHY address
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++void mvEthPhyAddrSet(void* pPortHandle, int phyAddr)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ int port = pPortCtrl->portNo;
++ unsigned int regData;
++
++ regData = MV_REG_READ(ETH_PHY_ADDR_REG(port));
++
++ regData &= ~ETH_PHY_ADDR_MASK;
++ regData |= phyAddr;
++
++ MV_REG_WRITE(ETH_PHY_ADDR_REG(port), regData);
++
++ return;
++}
++
++/*******************************************************************************
++* mvEthPhyAddrGet - Get the ethernet port PHY address.
++*
++* DESCRIPTION:
++* This routine returns the given ethernet port PHY address.
++*
++* INPUT:
++* void* pPortHandle - Pointer to port specific handler;
++*
++*
++* RETURN: int - PHY address.
++*
++*******************************************************************************/
++int mvEthPhyAddrGet(void* pPortHandle)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle;
++ int port = pPortCtrl->portNo;
++ unsigned int regData;
++
++ regData = MV_REG_READ(ETH_PHY_ADDR_REG(port));
++
++ return ((regData >> (5 * port)) & 0x1f);
++}
++
++/******************************************************************************/
++/* Descriptor handling Functions */
++/******************************************************************************/
++
++/*******************************************************************************
++* etherInitRxDescRing - Curve a Rx chain desc list and buffer in memory.
++*
++* DESCRIPTION:
++* This function prepares a Rx chained list of descriptors and packet
++* buffers in a form of a ring. The routine must be called after port
++* initialization routine and before port start routine.
++* The Ethernet SDMA engine uses CPU bus addresses to access the various
++* devices in the system (i.e. DRAM). This function uses the ethernet
++* struct 'virtual to physical' routine (set by the user) to set the ring
++* with physical addresses.
++*
++* INPUT:
++* ETH_QUEUE_CTRL *pEthPortCtrl Ethernet Port Control srtuct.
++* int rxQueue Number of Rx queue.
++* int rxDescNum Number of Rx descriptors
++* MV_U8* rxDescBaseAddr Rx descriptors memory area base addr.
++*
++* OUTPUT:
++* The routine updates the Ethernet port control struct with information
++* regarding the Rx descriptors and buffers.
++*
++* RETURN: None
++*
++*******************************************************************************/
++static void ethInitRxDescRing(ETH_PORT_CTRL* pPortCtrl, int queue)
++{
++ ETH_RX_DESC *pRxDescBase, *pRxDesc, *pRxPrevDesc;
++ int ix, rxDescNum = pPortCtrl->rxQueueConfig[queue].descrNum;
++ ETH_QUEUE_CTRL *pQueueCtrl = &pPortCtrl->rxQueue[queue];
++
++ /* Make sure descriptor address is cache line size aligned */
++ pRxDescBase = (ETH_RX_DESC*)MV_ALIGN_UP((MV_ULONG)pQueueCtrl->descBuf.bufVirtPtr,
++ CPU_D_CACHE_LINE_SIZE);
++
++ pRxDesc = (ETH_RX_DESC*)pRxDescBase;
++ pRxPrevDesc = pRxDesc;
++
++ /* initialize the Rx descriptors ring */
++ for (ix=0; ix<rxDescNum; ix++)
++ {
++ pRxDesc->bufSize = 0x0;
++ pRxDesc->byteCnt = 0x0;
++ pRxDesc->cmdSts = ETH_BUFFER_OWNED_BY_HOST;
++ pRxDesc->bufPtr = 0x0;
++ pRxDesc->returnInfo = 0x0;
++ pRxPrevDesc = pRxDesc;
++ if(ix == (rxDescNum-1))
++ {
++ /* Closing Rx descriptors ring */
++ pRxPrevDesc->nextDescPtr = (MV_U32)ethDescVirtToPhy(pQueueCtrl, (void*)pRxDescBase);
++ }
++ else
++ {
++ pRxDesc = (ETH_RX_DESC*)((MV_ULONG)pRxDesc + ETH_RX_DESC_ALIGNED_SIZE);
++ pRxPrevDesc->nextDescPtr = (MV_U32)ethDescVirtToPhy(pQueueCtrl, (void*)pRxDesc);
++ }
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pRxPrevDesc);
++ }
++
++ pQueueCtrl->pCurrentDescr = pRxDescBase;
++ pQueueCtrl->pUsedDescr = pRxDescBase;
++
++ pQueueCtrl->pFirstDescr = pRxDescBase;
++ pQueueCtrl->pLastDescr = pRxDesc;
++ pQueueCtrl->resource = 0;
++}
++
++void ethResetRxDescRing(void* pPortHndl, int queue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++ ETH_QUEUE_CTRL* pQueueCtrl = &pPortCtrl->rxQueue[queue];
++ ETH_RX_DESC* pRxDesc = (ETH_RX_DESC*)pQueueCtrl->pFirstDescr;
++
++ pQueueCtrl->resource = 0;
++ if(pQueueCtrl->pFirstDescr != NULL)
++ {
++ while(MV_TRUE)
++ {
++ pRxDesc->bufSize = 0x0;
++ pRxDesc->byteCnt = 0x0;
++ pRxDesc->cmdSts = ETH_BUFFER_OWNED_BY_HOST;
++ pRxDesc->bufPtr = 0x0;
++ pRxDesc->returnInfo = 0x0;
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pRxDesc);
++ if( (void*)pRxDesc == pQueueCtrl->pLastDescr)
++ break;
++ pRxDesc = RX_NEXT_DESC_PTR(pRxDesc, pQueueCtrl);
++ }
++ pQueueCtrl->pCurrentDescr = pQueueCtrl->pFirstDescr;
++ pQueueCtrl->pUsedDescr = pQueueCtrl->pFirstDescr;
++
++ /* Update RX Command register */
++ pPortCtrl->portRxQueueCmdReg |= (1 << queue);
++
++ /* update HW */
++ MV_REG_WRITE( ETH_RX_CUR_DESC_PTR_REG(pPortCtrl->portNo, queue),
++ (MV_U32)ethDescVirtToPhy(pQueueCtrl, pQueueCtrl->pCurrentDescr) );
++ }
++ else
++ {
++ /* Update RX Command register */
++ pPortCtrl->portRxQueueCmdReg &= ~(1 << queue);
++
++ /* update HW */
++ MV_REG_WRITE( ETH_RX_CUR_DESC_PTR_REG(pPortCtrl->portNo, queue), 0);
++ }
++}
++
++/*******************************************************************************
++* etherInitTxDescRing - Curve a Tx chain desc list and buffer in memory.
++*
++* DESCRIPTION:
++* This function prepares a Tx chained list of descriptors and packet
++* buffers in a form of a ring. The routine must be called after port
++* initialization routine and before port start routine.
++* The Ethernet SDMA engine uses CPU bus addresses to access the various
++* devices in the system (i.e. DRAM). This function uses the ethernet
++* struct 'virtual to physical' routine (set by the user) to set the ring
++* with physical addresses.
++*
++* INPUT:
++* ETH_PORT_CTRL *pEthPortCtrl Ethernet Port Control srtuct.
++* int txQueue Number of Tx queue.
++* int txDescNum Number of Tx descriptors
++* int txBuffSize Size of Tx buffer
++* MV_U8* pTxDescBase Tx descriptors memory area base addr.
++*
++* OUTPUT:
++* The routine updates the Ethernet port control struct with information
++* regarding the Tx descriptors and buffers.
++*
++* RETURN: None.
++*
++*******************************************************************************/
++static void ethInitTxDescRing(ETH_PORT_CTRL* pPortCtrl, int queue)
++{
++ ETH_TX_DESC *pTxDescBase, *pTxDesc, *pTxPrevDesc;
++ int ix, txDescNum = pPortCtrl->txQueueConfig[queue].descrNum;
++ ETH_QUEUE_CTRL *pQueueCtrl = &pPortCtrl->txQueue[queue];
++
++ /* Make sure descriptor address is cache line size aligned */
++ pTxDescBase = (ETH_TX_DESC*)MV_ALIGN_UP((MV_ULONG)pQueueCtrl->descBuf.bufVirtPtr,
++ CPU_D_CACHE_LINE_SIZE);
++
++ pTxDesc = (ETH_TX_DESC*)pTxDescBase;
++ pTxPrevDesc = pTxDesc;
++
++ /* initialize the Tx descriptors ring */
++ for (ix=0; ix<txDescNum; ix++)
++ {
++ pTxDesc->byteCnt = 0x0000;
++ pTxDesc->L4iChk = 0x0000;
++ pTxDesc->cmdSts = ETH_BUFFER_OWNED_BY_HOST;
++ pTxDesc->bufPtr = 0x0;
++ pTxDesc->returnInfo = 0x0;
++
++ pTxPrevDesc = pTxDesc;
++
++ if(ix == (txDescNum-1))
++ {
++ /* Closing Tx descriptors ring */
++ pTxPrevDesc->nextDescPtr = (MV_U32)ethDescVirtToPhy(pQueueCtrl, (void*)pTxDescBase);
++ }
++ else
++ {
++ pTxDesc = (ETH_TX_DESC*)((MV_ULONG)pTxDesc + ETH_TX_DESC_ALIGNED_SIZE);
++ pTxPrevDesc->nextDescPtr = (MV_U32)ethDescVirtToPhy(pQueueCtrl, (void*)pTxDesc);
++ }
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pTxPrevDesc);
++ }
++
++ pQueueCtrl->pCurrentDescr = pTxDescBase;
++ pQueueCtrl->pUsedDescr = pTxDescBase;
++
++ pQueueCtrl->pFirstDescr = pTxDescBase;
++ pQueueCtrl->pLastDescr = pTxDesc;
++ /* Leave one TX descriptor out of use */
++ pQueueCtrl->resource = txDescNum - 1;
++}
++
++void ethResetTxDescRing(void* pPortHndl, int queue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++ ETH_QUEUE_CTRL* pQueueCtrl = &pPortCtrl->txQueue[queue];
++ ETH_TX_DESC* pTxDesc = (ETH_TX_DESC*)pQueueCtrl->pFirstDescr;
++
++ pQueueCtrl->resource = 0;
++ if(pQueueCtrl->pFirstDescr != NULL)
++ {
++ while(MV_TRUE)
++ {
++ pTxDesc->byteCnt = 0x0000;
++ pTxDesc->L4iChk = 0x0000;
++ pTxDesc->cmdSts = ETH_BUFFER_OWNED_BY_HOST;
++ pTxDesc->bufPtr = 0x0;
++ pTxDesc->returnInfo = 0x0;
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pTxDesc);
++ pQueueCtrl->resource++;
++ if( (void*)pTxDesc == pQueueCtrl->pLastDescr)
++ break;
++ pTxDesc = TX_NEXT_DESC_PTR(pTxDesc, pQueueCtrl);
++ }
++ /* Leave one TX descriptor out of use */
++ pQueueCtrl->resource--;
++ pQueueCtrl->pCurrentDescr = pQueueCtrl->pFirstDescr;
++ pQueueCtrl->pUsedDescr = pQueueCtrl->pFirstDescr;
++
++ /* Update TX Command register */
++ pPortCtrl->portTxQueueCmdReg |= MV_32BIT_LE_FAST(1 << queue);
++ /* update HW */
++ MV_REG_WRITE( ETH_TX_CUR_DESC_PTR_REG(pPortCtrl->portNo, queue),
++ (MV_U32)ethDescVirtToPhy(pQueueCtrl, pQueueCtrl->pCurrentDescr) );
++ }
++ else
++ {
++ /* Update TX Command register */
++ pPortCtrl->portTxQueueCmdReg &= MV_32BIT_LE_FAST(~(1 << queue));
++ /* update HW */
++ MV_REG_WRITE( ETH_TX_CUR_DESC_PTR_REG(pPortCtrl->portNo, queue), 0 );
++ }
++}
++
++/*******************************************************************************
++* ethAllocDescrMemory - Free memory allocated for RX and TX descriptors.
++*
++* DESCRIPTION:
++* This function allocates memory for RX and TX descriptors.
++* - If ETH_DESCR_IN_SRAM defined, allocate memory from SRAM.
++* - If ETH_DESCR_IN_SDRAM defined, allocate memory in SDRAM.
++*
++* INPUT:
++* int size - size of memory should be allocated.
++*
++* RETURN: None
++*
++*******************************************************************************/
++static MV_U8* ethAllocDescrMemory(ETH_PORT_CTRL* pPortCtrl, int descSize,
++ MV_ULONG* pPhysAddr, MV_U32 *memHandle)
++{
++ MV_U8* pVirt;
++
++#if defined(ETH_DESCR_IN_SRAM)
++ if(ethDescInSram == MV_TRUE)
++ pVirt = (char*)mvSramMalloc(descSize, pPhysAddr);
++ else
++#endif /* ETH_DESCR_IN_SRAM */
++ {
++#ifdef ETH_DESCR_UNCACHED
++ pVirt = (MV_U8*)mvOsIoUncachedMalloc(pPortCtrl->osHandle, descSize,
++ pPhysAddr,memHandle);
++#else
++ pVirt = (MV_U8*)mvOsIoCachedMalloc(pPortCtrl->osHandle, descSize,
++ pPhysAddr, memHandle);
++#endif /* ETH_DESCR_UNCACHED */
++ }
++ memset(pVirt, 0, descSize);
++
++ return pVirt;
++}
++
++/*******************************************************************************
++* ethFreeDescrMemory - Free memory allocated for RX and TX descriptors.
++*
++* DESCRIPTION:
++* This function frees memory allocated for RX and TX descriptors.
++* - If ETH_DESCR_IN_SRAM defined, free memory using gtSramFree() function.
++* - If ETH_DESCR_IN_SDRAM defined, free memory using mvOsFree() function.
++*
++* INPUT:
++* void* pVirtAddr - virtual pointer to memory allocated for RX and TX
++* desriptors.
++*
++* RETURN: None
++*
++*******************************************************************************/
++void ethFreeDescrMemory(ETH_PORT_CTRL* pPortCtrl, MV_BUF_INFO* pDescBuf)
++{
++ if( (pDescBuf == NULL) || (pDescBuf->bufVirtPtr == NULL) )
++ return;
++
++#if defined(ETH_DESCR_IN_SRAM)
++ if( ethDescInSram )
++ {
++ mvSramFree(pDescBuf->bufSize, pDescBuf->bufPhysAddr, pDescBuf->bufVirtPtr);
++ return;
++ }
++#endif /* ETH_DESCR_IN_SRAM */
++
++#ifdef ETH_DESCR_UNCACHED
++ mvOsIoUncachedFree(pPortCtrl->osHandle, pDescBuf->bufSize, pDescBuf->bufPhysAddr,
++ pDescBuf->bufVirtPtr,pDescBuf->memHandle);
++#else
++ mvOsIoCachedFree(pPortCtrl->osHandle, pDescBuf->bufSize, pDescBuf->bufPhysAddr,
++ pDescBuf->bufVirtPtr,pDescBuf->memHandle);
++#endif /* ETH_DESCR_UNCACHED */
++}
++
++/******************************************************************************/
++/* Other Functions */
++/******************************************************************************/
++
++void mvEthPortPowerUp(int port)
++{
++ MV_U32 regVal;
++
++ /* MAC Cause register should be cleared */
++ MV_REG_WRITE(ETH_UNIT_INTR_CAUSE_REG(port), 0);
++
++ if (mvBoardIsPortInSgmii(port))
++ mvEthPortSgmiiConfig(port);
++
++ /* Cancel Port Reset */
++ regVal = MV_REG_READ(ETH_PORT_SERIAL_CTRL_1_REG(port));
++ regVal &= (~ETH_PORT_RESET_MASK);
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_1_REG(port), regVal);
++ while( (MV_REG_READ(ETH_PORT_SERIAL_CTRL_1_REG(port)) & ETH_PORT_RESET_MASK) != 0);
++}
++
++void mvEthPortPowerDown(int port)
++{
++ MV_U32 regVal;
++
++ /* Port must be DISABLED */
++ regVal = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(port));
++ if( (regVal & ETH_PORT_ENABLE_MASK) != 0)
++ {
++ mvOsPrintf("ethPort #%d: PowerDown - port must be Disabled (PSC=0x%x)\n",
++ port, regVal);
++ return;
++ }
++
++ /* Port Reset (Read after write the register as a precaution) */
++ regVal = MV_REG_READ(ETH_PORT_SERIAL_CTRL_1_REG(port));
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_1_REG(port), regVal | ETH_PORT_RESET_MASK);
++ while((MV_REG_READ(ETH_PORT_SERIAL_CTRL_1_REG(port)) & ETH_PORT_RESET_MASK) == 0);
++}
++
++static void mvEthPortSgmiiConfig(int port)
++{
++ MV_U32 regVal;
++
++ regVal = MV_REG_READ(ETH_PORT_SERIAL_CTRL_1_REG(port));
++
++ regVal |= (ETH_SGMII_MODE_MASK /*| ETH_INBAND_AUTO_NEG_ENABLE_MASK */);
++ regVal &= (~ETH_INBAND_AUTO_NEG_BYPASS_MASK);
++
++ MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_1_REG(port), regVal);
++}
++
++
++
++
++
++
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.c 2010-11-09 20:28:11.072495491 +0100
+@@ -0,0 +1,748 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++/*******************************************************************************
++* mvEthDebug.c - Source file for user friendly debug functions
++*
++* DESCRIPTION:
++*
++* DEPENDENCIES:
++* None.
++*
++*******************************************************************************/
++
++#include "mvOs.h"
++#include "mvCommon.h"
++#include "mvTypes.h"
++#include "mv802_3.h"
++#include "mvDebug.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "eth-phy/mvEthPhy.h"
++#include "eth/mvEth.h"
++#include "eth/gbe/mvEthDebug.h"
++
++/* #define mvOsPrintf printf */
++
++void mvEthPortShow(void* pHndl);
++void mvEthQueuesShow(void* pHndl, int rxQueue, int txQueue, int mode);
++
++/******************************************************************************/
++/* Debug functions */
++/******************************************************************************/
++void ethRxCoal(int port, int usec)
++{
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ {
++ mvEthRxCoalSet(pHndl, usec);
++ }
++}
++
++void ethTxCoal(int port, int usec)
++{
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ {
++ mvEthTxCoalSet(pHndl, usec);
++ }
++}
++
++#if (MV_ETH_VERSION >= 4)
++void ethEjpModeSet(int port, int mode)
++{
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ {
++ mvEthEjpModeSet(pHndl, mode);
++ }
++}
++#endif /* (MV_ETH_VERSION >= 4) */
++
++void ethBpduRxQ(int port, int bpduQueue)
++{
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ {
++ mvEthBpduRxQueue(pHndl, bpduQueue);
++ }
++}
++
++void ethArpRxQ(int port, int arpQueue)
++{
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ {
++ mvEthArpRxQueue(pHndl, arpQueue);
++ }
++}
++
++void ethTcpRxQ(int port, int tcpQueue)
++{
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ {
++ mvEthTcpRxQueue(pHndl, tcpQueue);
++ }
++}
++
++void ethUdpRxQ(int port, int udpQueue)
++{
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ {
++ mvEthUdpRxQueue(pHndl, udpQueue);
++ }
++}
++
++void ethTxPolicyRegs(int port)
++{
++ int queue;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)mvEthPortHndlGet(port);
++
++ if(pPortCtrl == NULL)
++ {
++ return;
++ }
++ mvOsPrintf("Port #%d TX Policy: EJP=%d, TXQs: ",
++ port, pPortCtrl->portConfig.ejpMode);
++ for(queue=0; queue<MV_ETH_TX_Q_NUM; queue++)
++ {
++ if(pPortCtrl->txQueueConfig[queue].descrNum > 0)
++ mvOsPrintf("%d, ", queue);
++ }
++ mvOsPrintf("\n");
++
++ mvOsPrintf("\n\t TX policy Port #%d configuration registers\n", port);
++
++ mvOsPrintf("ETH_TX_QUEUE_COMMAND_REG : 0x%X = 0x%08x\n",
++ ETH_TX_QUEUE_COMMAND_REG(port),
++ MV_REG_READ( ETH_TX_QUEUE_COMMAND_REG(port) ) );
++
++ mvOsPrintf("ETH_TX_FIXED_PRIO_CFG_REG : 0x%X = 0x%08x\n",
++ ETH_TX_FIXED_PRIO_CFG_REG(port),
++ MV_REG_READ( ETH_TX_FIXED_PRIO_CFG_REG(port) ) );
++
++ mvOsPrintf("ETH_TX_TOKEN_RATE_CFG_REG : 0x%X = 0x%08x\n",
++ ETH_TX_TOKEN_RATE_CFG_REG(port),
++ MV_REG_READ( ETH_TX_TOKEN_RATE_CFG_REG(port) ) );
++
++ mvOsPrintf("ETH_MAX_TRANSMIT_UNIT_REG : 0x%X = 0x%08x\n",
++ ETH_MAX_TRANSMIT_UNIT_REG(port),
++ MV_REG_READ( ETH_MAX_TRANSMIT_UNIT_REG(port) ) );
++
++ mvOsPrintf("ETH_TX_TOKEN_BUCKET_SIZE_REG : 0x%X = 0x%08x\n",
++ ETH_TX_TOKEN_BUCKET_SIZE_REG(port),
++ MV_REG_READ( ETH_TX_TOKEN_BUCKET_SIZE_REG(port) ) );
++
++ mvOsPrintf("ETH_TX_TOKEN_BUCKET_COUNT_REG : 0x%X = 0x%08x\n",
++ ETH_TX_TOKEN_BUCKET_COUNT_REG(port),
++ MV_REG_READ( ETH_TX_TOKEN_BUCKET_COUNT_REG(port) ) );
++
++ for(queue=0; queue<MV_ETH_MAX_TXQ; queue++)
++ {
++ mvOsPrintf("\n\t TX policy Port #%d, Queue #%d configuration registers\n", port, queue);
++
++ mvOsPrintf("ETH_TXQ_TOKEN_COUNT_REG : 0x%X = 0x%08x\n",
++ ETH_TXQ_TOKEN_COUNT_REG(port, queue),
++ MV_REG_READ( ETH_TXQ_TOKEN_COUNT_REG(port, queue) ) );
++
++ mvOsPrintf("ETH_TXQ_TOKEN_CFG_REG : 0x%X = 0x%08x\n",
++ ETH_TXQ_TOKEN_CFG_REG(port, queue),
++ MV_REG_READ( ETH_TXQ_TOKEN_CFG_REG(port, queue) ) );
++
++ mvOsPrintf("ETH_TXQ_ARBITER_CFG_REG : 0x%X = 0x%08x\n",
++ ETH_TXQ_ARBITER_CFG_REG(port, queue),
++ MV_REG_READ( ETH_TXQ_ARBITER_CFG_REG(port, queue) ) );
++ }
++ mvOsPrintf("\n");
++}
++
++/* Print important registers of Ethernet port */
++void ethPortRegs(int port)
++{
++ mvOsPrintf("\n\t ethGiga #%d port Registers:\n", port);
++
++ mvOsPrintf("ETH_PORT_STATUS_REG : 0x%X = 0x%08x\n",
++ ETH_PORT_STATUS_REG(port),
++ MV_REG_READ( ETH_PORT_STATUS_REG(port) ) );
++
++ mvOsPrintf("ETH_PORT_SERIAL_CTRL_REG : 0x%X = 0x%08x\n",
++ ETH_PORT_SERIAL_CTRL_REG(port),
++ MV_REG_READ( ETH_PORT_SERIAL_CTRL_REG(port) ) );
++
++ mvOsPrintf("ETH_PORT_CONFIG_REG : 0x%X = 0x%08x\n",
++ ETH_PORT_CONFIG_REG(port),
++ MV_REG_READ( ETH_PORT_CONFIG_REG(port) ) );
++
++ mvOsPrintf("ETH_PORT_CONFIG_EXTEND_REG : 0x%X = 0x%08x\n",
++ ETH_PORT_CONFIG_EXTEND_REG(port),
++ MV_REG_READ( ETH_PORT_CONFIG_EXTEND_REG(port) ) );
++
++ mvOsPrintf("ETH_SDMA_CONFIG_REG : 0x%X = 0x%08x\n",
++ ETH_SDMA_CONFIG_REG(port),
++ MV_REG_READ( ETH_SDMA_CONFIG_REG(port) ) );
++
++ mvOsPrintf("ETH_TX_FIFO_URGENT_THRESH_REG : 0x%X = 0x%08x\n",
++ ETH_TX_FIFO_URGENT_THRESH_REG(port),
++ MV_REG_READ( ETH_TX_FIFO_URGENT_THRESH_REG(port) ) );
++
++ mvOsPrintf("ETH_RX_QUEUE_COMMAND_REG : 0x%X = 0x%08x\n",
++ ETH_RX_QUEUE_COMMAND_REG(port),
++ MV_REG_READ( ETH_RX_QUEUE_COMMAND_REG(port) ) );
++
++ mvOsPrintf("ETH_TX_QUEUE_COMMAND_REG : 0x%X = 0x%08x\n",
++ ETH_TX_QUEUE_COMMAND_REG(port),
++ MV_REG_READ( ETH_TX_QUEUE_COMMAND_REG(port) ) );
++
++ mvOsPrintf("ETH_INTR_CAUSE_REG : 0x%X = 0x%08x\n",
++ ETH_INTR_CAUSE_REG(port),
++ MV_REG_READ( ETH_INTR_CAUSE_REG(port) ) );
++
++ mvOsPrintf("ETH_INTR_EXTEND_CAUSE_REG : 0x%X = 0x%08x\n",
++ ETH_INTR_CAUSE_EXT_REG(port),
++ MV_REG_READ( ETH_INTR_CAUSE_EXT_REG(port) ) );
++
++ mvOsPrintf("ETH_INTR_MASK_REG : 0x%X = 0x%08x\n",
++ ETH_INTR_MASK_REG(port),
++ MV_REG_READ( ETH_INTR_MASK_REG(port) ) );
++
++ mvOsPrintf("ETH_INTR_EXTEND_MASK_REG : 0x%X = 0x%08x\n",
++ ETH_INTR_MASK_EXT_REG(port),
++ MV_REG_READ( ETH_INTR_MASK_EXT_REG(port) ) );
++
++ mvOsPrintf("ETH_RX_DESCR_STAT_CMD_REG : 0x%X = 0x%08x\n",
++ ETH_RX_DESCR_STAT_CMD_REG(port, 0),
++ MV_REG_READ( ETH_RX_DESCR_STAT_CMD_REG(port, 0) ) );
++
++ mvOsPrintf("ETH_RX_BYTE_COUNT_REG : 0x%X = 0x%08x\n",
++ ETH_RX_BYTE_COUNT_REG(port, 0),
++ MV_REG_READ( ETH_RX_BYTE_COUNT_REG(port, 0) ) );
++
++ mvOsPrintf("ETH_RX_BUF_PTR_REG : 0x%X = 0x%08x\n",
++ ETH_RX_BUF_PTR_REG(port, 0),
++ MV_REG_READ( ETH_RX_BUF_PTR_REG(port, 0) ) );
++
++ mvOsPrintf("ETH_RX_CUR_DESC_PTR_REG : 0x%X = 0x%08x\n",
++ ETH_RX_CUR_DESC_PTR_REG(port, 0),
++ MV_REG_READ( ETH_RX_CUR_DESC_PTR_REG(port, 0) ) );
++}
++
++
++/* Print Giga Ethernet UNIT registers */
++void ethRegs(int port)
++{
++ mvOsPrintf("ETH_PHY_ADDR_REG : 0x%X = 0x%08x\n",
++ ETH_PHY_ADDR_REG(port),
++ MV_REG_READ(ETH_PHY_ADDR_REG(port)) );
++
++ mvOsPrintf("ETH_UNIT_INTR_CAUSE_REG : 0x%X = 0x%08x\n",
++ ETH_UNIT_INTR_CAUSE_REG(port),
++ MV_REG_READ( ETH_UNIT_INTR_CAUSE_REG(port)) );
++
++ mvOsPrintf("ETH_UNIT_INTR_MASK_REG : 0x%X = 0x%08x\n",
++ ETH_UNIT_INTR_MASK_REG(port),
++ MV_REG_READ( ETH_UNIT_INTR_MASK_REG(port)) );
++
++ mvOsPrintf("ETH_UNIT_ERROR_ADDR_REG : 0x%X = 0x%08x\n",
++ ETH_UNIT_ERROR_ADDR_REG(port),
++ MV_REG_READ(ETH_UNIT_ERROR_ADDR_REG(port)) );
++
++ mvOsPrintf("ETH_UNIT_INT_ADDR_ERROR_REG : 0x%X = 0x%08x\n",
++ ETH_UNIT_INT_ADDR_ERROR_REG(port),
++ MV_REG_READ(ETH_UNIT_INT_ADDR_ERROR_REG(port)) );
++
++}
++
++/******************************************************************************/
++/* MIB Counters functions */
++/******************************************************************************/
++
++/*******************************************************************************
++* ethClearMibCounters - Clear all MIB counters
++*
++* DESCRIPTION:
++* This function clears all MIB counters of a specific ethernet port.
++* A read from the MIB counter will reset the counter.
++*
++* INPUT:
++* int port - Ethernet Port number.
++*
++* RETURN: None
++*
++*******************************************************************************/
++void ethClearCounters(int port)
++{
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ mvEthMibCountersClear(pHndl);
++
++ return;
++}
++
++
++/* Print counters of the Ethernet port */
++void ethPortCounters(int port)
++{
++ MV_U32 regValue, regValHigh;
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl == NULL)
++ return;
++
++ mvOsPrintf("\n\t Port #%d MIB Counters\n\n", port);
++
++ mvOsPrintf("GoodFramesReceived = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_GOOD_FRAMES_RECEIVED, NULL));
++ mvOsPrintf("BadFramesReceived = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_BAD_FRAMES_RECEIVED, NULL));
++ mvOsPrintf("BroadcastFramesReceived = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_BROADCAST_FRAMES_RECEIVED, NULL));
++ mvOsPrintf("MulticastFramesReceived = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_MULTICAST_FRAMES_RECEIVED, NULL));
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_GOOD_OCTETS_RECEIVED_LOW,
++ &regValHigh);
++ mvOsPrintf("GoodOctetsReceived = 0x%08x%08x\n",
++ regValHigh, regValue);
++
++ mvOsPrintf("\n");
++ mvOsPrintf("GoodFramesSent = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_GOOD_FRAMES_SENT, NULL));
++ mvOsPrintf("BroadcastFramesSent = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_BROADCAST_FRAMES_SENT, NULL));
++ mvOsPrintf("MulticastFramesSent = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_MULTICAST_FRAMES_SENT, NULL));
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_GOOD_OCTETS_SENT_LOW,
++ &regValHigh);
++ mvOsPrintf("GoodOctetsSent = 0x%08x%08x\n", regValHigh, regValue);
++
++
++ mvOsPrintf("\n\t FC Control Counters\n");
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_UNREC_MAC_CONTROL_RECEIVED, NULL);
++ mvOsPrintf("UnrecogMacControlReceived = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_GOOD_FC_RECEIVED, NULL);
++ mvOsPrintf("GoodFCFramesReceived = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_BAD_FC_RECEIVED, NULL);
++ mvOsPrintf("BadFCFramesReceived = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_FC_SENT, NULL);
++ mvOsPrintf("FCFramesSent = %u\n", regValue);
++
++
++ mvOsPrintf("\n\t RX Errors\n");
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_BAD_OCTETS_RECEIVED, NULL);
++ mvOsPrintf("BadOctetsReceived = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_UNDERSIZE_RECEIVED, NULL);
++ mvOsPrintf("UndersizeFramesReceived = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_FRAGMENTS_RECEIVED, NULL);
++ mvOsPrintf("FragmentsReceived = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_OVERSIZE_RECEIVED, NULL);
++ mvOsPrintf("OversizeFramesReceived = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_JABBER_RECEIVED, NULL);
++ mvOsPrintf("JabbersReceived = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_MAC_RECEIVE_ERROR, NULL);
++ mvOsPrintf("MacReceiveErrors = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_BAD_CRC_EVENT, NULL);
++ mvOsPrintf("BadCrcReceived = %u\n", regValue);
++
++ mvOsPrintf("\n\t TX Errors\n");
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR, NULL);
++ mvOsPrintf("TxMacErrors = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_EXCESSIVE_COLLISION, NULL);
++ mvOsPrintf("TxExcessiveCollisions = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_COLLISION, NULL);
++ mvOsPrintf("TxCollisions = %u\n", regValue);
++
++ regValue = mvEthMibCounterRead(pHndl, ETH_MIB_LATE_COLLISION, NULL);
++ mvOsPrintf("TxLateCollisions = %u\n", regValue);
++
++
++ mvOsPrintf("\n");
++ regValue = MV_REG_READ( ETH_RX_DISCARD_PKTS_CNTR_REG(port));
++ mvOsPrintf("Rx Discard packets counter = %u\n", regValue);
++
++ regValue = MV_REG_READ(ETH_RX_OVERRUN_PKTS_CNTR_REG(port));
++ mvOsPrintf("Rx Overrun packets counter = %u\n", regValue);
++}
++
++/* Print RMON counters of the Ethernet port */
++void ethPortRmonCounters(int port)
++{
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl == NULL)
++ return;
++
++ mvOsPrintf("\n\t Port #%d RMON MIB Counters\n\n", port);
++
++ mvOsPrintf("64 ByteFramesReceived = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_FRAMES_64_OCTETS, NULL));
++ mvOsPrintf("65...127 ByteFramesReceived = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_FRAMES_65_TO_127_OCTETS, NULL));
++ mvOsPrintf("128...255 ByteFramesReceived = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_FRAMES_128_TO_255_OCTETS, NULL));
++ mvOsPrintf("256...511 ByteFramesReceived = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_FRAMES_256_TO_511_OCTETS, NULL));
++ mvOsPrintf("512...1023 ByteFramesReceived = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_FRAMES_512_TO_1023_OCTETS, NULL));
++ mvOsPrintf("1024...Max ByteFramesReceived = %u\n",
++ mvEthMibCounterRead(pHndl, ETH_MIB_FRAMES_1024_TO_MAX_OCTETS, NULL));
++}
++
++/* Print port information */
++void ethPortStatus(int port)
++{
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ {
++ mvEthPortShow(pHndl);
++ }
++}
++
++/* Print port queues information */
++void ethPortQueues(int port, int rxQueue, int txQueue, int mode)
++{
++ void* pHndl;
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ {
++ mvEthQueuesShow(pHndl, rxQueue, txQueue, mode);
++ }
++}
++
++void ethUcastSet(int port, char* macStr, int queue)
++{
++ void* pHndl;
++ MV_U8 macAddr[MV_MAC_ADDR_SIZE];
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ {
++ mvMacStrToHex(macStr, macAddr);
++ mvEthMacAddrSet(pHndl, macAddr, queue);
++ }
++}
++
++
++void ethPortUcastShow(int port)
++{
++ MV_U32 unicastReg, macL, macH;
++ int i, j;
++
++ macL = MV_REG_READ(ETH_MAC_ADDR_LOW_REG(port));
++ macH = MV_REG_READ(ETH_MAC_ADDR_HIGH_REG(port));
++
++ mvOsPrintf("\n\t Port #%d Unicast MAC table: %02x:%02x:%02x:%02x:%02x:%02x\n\n",
++ port, ((macH >> 24) & 0xff), ((macH >> 16) & 0xff),
++ ((macH >> 8) & 0xff), (macH & 0xff),
++ ((macL >> 8) & 0xff), (macL & 0xff) );
++
++ for (i=0; i<4; i++)
++ {
++ unicastReg = MV_REG_READ( (ETH_DA_FILTER_UCAST_BASE(port) + i*4));
++ for(j=0; j<4; j++)
++ {
++ MV_U8 macEntry = (unicastReg >> (8*j)) & 0xFF;
++
++ mvOsPrintf("%X: %8s, Q = %d\n", i*4+j,
++ (macEntry & BIT0) ? "Accept" : "Reject", (macEntry >> 1) & 0x7);
++ }
++ }
++}
++
++void ethMcastAdd(int port, char* macStr, int queue)
++{
++ void* pHndl;
++ MV_U8 macAddr[MV_MAC_ADDR_SIZE];
++
++ pHndl = mvEthPortHndlGet(port);
++ if(pHndl != NULL)
++ {
++ mvMacStrToHex(macStr, macAddr);
++ mvEthMcastAddrSet(pHndl, macAddr, queue);
++ }
++}
++
++void ethPortMcast(int port)
++{
++ int tblIdx, regIdx;
++ MV_U32 regVal;
++
++ mvOsPrintf("\n\t Port #%d Special (IP) Multicast table: 01:00:5E:00:00:XX\n\n",
++ port);
++
++ for(tblIdx=0; tblIdx<(256/4); tblIdx++)
++ {
++ regVal = MV_REG_READ((ETH_DA_FILTER_SPEC_MCAST_BASE(port) + tblIdx*4));
++ for(regIdx=0; regIdx<4; regIdx++)
++ {
++ if((regVal & (0x01 << (regIdx*8))) != 0)
++ {
++ mvOsPrintf("0x%02X: Accepted, rxQ = %d\n",
++ tblIdx*4+regIdx, ((regVal >> (regIdx*8+1)) & 0x07));
++ }
++ }
++ }
++ mvOsPrintf("\n\t Port #%d Other Multicast table\n\n", port);
++ for(tblIdx=0; tblIdx<(256/4); tblIdx++)
++ {
++ regVal = MV_REG_READ((ETH_DA_FILTER_OTH_MCAST_BASE(port) + tblIdx*4));
++ for(regIdx=0; regIdx<4; regIdx++)
++ {
++ if((regVal & (0x01 << (regIdx*8))) != 0)
++ {
++ mvOsPrintf("Crc8=0x%02X: Accepted, rxQ = %d\n",
++ tblIdx*4+regIdx, ((regVal >> (regIdx*8+1)) & 0x07));
++ }
++ }
++ }
++}
++
++
++/* Print status of Ethernet port */
++void mvEthPortShow(void* pHndl)
++{
++ MV_U32 regValue, rxCoal, txCoal;
++ int speed, queue, port;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pHndl;
++
++ port = pPortCtrl->portNo;
++
++ regValue = MV_REG_READ( ETH_PORT_STATUS_REG(port) );
++
++ mvOsPrintf("\n\t ethGiga #%d port Status: 0x%04x = 0x%08x\n\n",
++ port, ETH_PORT_STATUS_REG(port), regValue);
++
++ mvOsPrintf("descInSram=%d, descSwCoher=%d\n",
++ ethDescInSram, ethDescSwCoher);
++
++ if(regValue & ETH_GMII_SPEED_1000_MASK)
++ speed = 1000;
++ else if(regValue & ETH_MII_SPEED_100_MASK)
++ speed = 100;
++ else
++ speed = 10;
++
++ mvEthCoalGet(pPortCtrl, &rxCoal, &txCoal);
++
++ /* Link, Speed, Duplex, FlowControl */
++ mvOsPrintf("Link=%s, Speed=%d, Duplex=%s, RxFlowControl=%s",
++ (regValue & ETH_LINK_UP_MASK) ? "UP" : "DOWN",
++ speed,
++ (regValue & ETH_FULL_DUPLEX_MASK) ? "FULL" : "HALF",
++ (regValue & ETH_ENABLE_RCV_FLOW_CTRL_MASK) ? "ENABLE" : "DISABLE");
++
++ mvOsPrintf("\n");
++
++ mvOsPrintf("RxCoal = %d usec, TxCoal = %d usec\n",
++ rxCoal, txCoal);
++
++ mvOsPrintf("rxDefQ=%d, arpQ=%d, bpduQ=%d, tcpQ=%d, udpQ=%d\n\n",
++ pPortCtrl->portConfig.rxDefQ, pPortCtrl->portConfig.rxArpQ,
++ pPortCtrl->portConfig.rxBpduQ,
++ pPortCtrl->portConfig.rxTcpQ, pPortCtrl->portConfig.rxUdpQ);
++
++ /* Print all RX and TX queues */
++ for(queue=0; queue<MV_ETH_RX_Q_NUM; queue++)
++ {
++ mvOsPrintf("RX Queue #%d: base=0x%lx, free=%d\n",
++ queue, (MV_ULONG)pPortCtrl->rxQueue[queue].pFirstDescr,
++ mvEthRxResourceGet(pPortCtrl, queue) );
++ }
++ mvOsPrintf("\n");
++ for(queue=0; queue<MV_ETH_TX_Q_NUM; queue++)
++ {
++ mvOsPrintf("TX Queue #%d: base=0x%lx, free=%d\n",
++ queue, (MV_ULONG)pPortCtrl->txQueue[queue].pFirstDescr,
++ mvEthTxResourceGet(pPortCtrl, queue) );
++ }
++}
++
++/* Print RX and TX queue of the Ethernet port */
++void mvEthQueuesShow(void* pHndl, int rxQueue, int txQueue, int mode)
++{
++ ETH_PORT_CTRL *pPortCtrl = (ETH_PORT_CTRL*)pHndl;
++ ETH_QUEUE_CTRL *pQueueCtrl;
++ MV_U32 regValue;
++ ETH_RX_DESC *pRxDescr;
++ ETH_TX_DESC *pTxDescr;
++ int i, port = pPortCtrl->portNo;
++
++ if( (rxQueue >=0) && (rxQueue < MV_ETH_RX_Q_NUM) )
++ {
++ pQueueCtrl = &(pPortCtrl->rxQueue[rxQueue]);
++ mvOsPrintf("Port #%d, RX Queue #%d\n\n", port, rxQueue);
++
++ mvOsPrintf("CURR_RX_DESC_PTR : 0x%X = 0x%08x\n",
++ ETH_RX_CUR_DESC_PTR_REG(port, rxQueue),
++ MV_REG_READ( ETH_RX_CUR_DESC_PTR_REG(port, rxQueue)));
++
++
++ if(pQueueCtrl->pFirstDescr != NULL)
++ {
++ mvOsPrintf("pFirstDescr=0x%lx, pLastDescr=0x%lx, numOfResources=%d\n",
++ (MV_ULONG)pQueueCtrl->pFirstDescr, (MV_ULONG)pQueueCtrl->pLastDescr,
++ pQueueCtrl->resource);
++ mvOsPrintf("pCurrDescr: 0x%lx, pUsedDescr: 0x%lx\n",
++ (MV_ULONG)pQueueCtrl->pCurrentDescr,
++ (MV_ULONG)pQueueCtrl->pUsedDescr);
++
++ if(mode == 1)
++ {
++ pRxDescr = (ETH_RX_DESC*)pQueueCtrl->pFirstDescr;
++ i = 0;
++ do
++ {
++ mvOsPrintf("%3d. desc=%08x (%08x), cmd=%08x, data=%4d, buf=%4d, buf=%08x, pkt=%lx, os=%lx\n",
++ i, (MV_U32)pRxDescr, (MV_U32)ethDescVirtToPhy(pQueueCtrl, (MV_U8*)pRxDescr),
++ pRxDescr->cmdSts, pRxDescr->byteCnt, (MV_U32)pRxDescr->bufSize,
++ (unsigned int)pRxDescr->bufPtr, (MV_ULONG)pRxDescr->returnInfo,
++ ((MV_PKT_INFO*)pRxDescr->returnInfo)->osInfo);
++
++ ETH_DESCR_INV(pPortCtrl, pRxDescr);
++ pRxDescr = RX_NEXT_DESC_PTR(pRxDescr, pQueueCtrl);
++ i++;
++ } while (pRxDescr != pQueueCtrl->pFirstDescr);
++ }
++ }
++ else
++ mvOsPrintf("RX Queue #%d is NOT CREATED\n", rxQueue);
++ }
++
++ if( (txQueue >=0) && (txQueue < MV_ETH_TX_Q_NUM) )
++ {
++ pQueueCtrl = &(pPortCtrl->txQueue[txQueue]);
++ mvOsPrintf("Port #%d, TX Queue #%d\n\n", port, txQueue);
++
++ regValue = MV_REG_READ( ETH_TX_CUR_DESC_PTR_REG(port, txQueue));
++ mvOsPrintf("CURR_TX_DESC_PTR : 0x%X = 0x%08x\n",
++ ETH_TX_CUR_DESC_PTR_REG(port, txQueue), regValue);
++
++ if(pQueueCtrl->pFirstDescr != NULL)
++ {
++ mvOsPrintf("pFirstDescr=0x%lx, pLastDescr=0x%lx, numOfResources=%d\n",
++ (MV_ULONG)pQueueCtrl->pFirstDescr,
++ (MV_ULONG)pQueueCtrl->pLastDescr,
++ pQueueCtrl->resource);
++ mvOsPrintf("pCurrDescr: 0x%lx, pUsedDescr: 0x%lx\n",
++ (MV_ULONG)pQueueCtrl->pCurrentDescr,
++ (MV_ULONG)pQueueCtrl->pUsedDescr);
++
++ if(mode == 1)
++ {
++ pTxDescr = (ETH_TX_DESC*)pQueueCtrl->pFirstDescr;
++ i = 0;
++ do
++ {
++ mvOsPrintf("%3d. desc=%08x (%08x), cmd=%08x, data=%4d, buf=%08x, pkt=%lx, os=%lx\n",
++ i, (MV_U32)pTxDescr, (MV_U32)ethDescVirtToPhy(pQueueCtrl, (MV_U8*)pTxDescr),
++ pTxDescr->cmdSts, pTxDescr->byteCnt,
++ (MV_U32)pTxDescr->bufPtr, (MV_ULONG)pTxDescr->returnInfo,
++ pTxDescr->returnInfo ? (((MV_PKT_INFO*)pTxDescr->returnInfo)->osInfo) : 0x0);
++
++ ETH_DESCR_INV(pPortCtrl, pTxDescr);
++ pTxDescr = TX_NEXT_DESC_PTR(pTxDescr, pQueueCtrl);
++ i++;
++ } while (pTxDescr != pQueueCtrl->pFirstDescr);
++ }
++ }
++ else
++ mvOsPrintf("TX Queue #%d is NOT CREATED\n", txQueue);
++ }
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.h 2010-11-09 20:28:11.112495471 +0100
+@@ -0,0 +1,146 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __MV_ETH_DEBUG_H__
++#define __MV_ETH_DEBUG_H__
++
++#if 0
++/*
++ ** Externs
++ */
++void ethBpduRxQ(int port, int bpduQueue);
++void ethArpRxQ(int port, int bpduQueue);
++void ethTcpRxQ(int port, int bpduQueue);
++void ethUdpRxQ(int port, int bpduQueue);
++void ethMcastAdd(int port, char* macStr, int queue);
++
++#ifdef INCLUDE_MULTI_QUEUE
++void ethRxPolicy( int port);
++void ethTxPolicy( int port);
++void ethTxPolDA(int port, char* macStr, int txQ, char* headerHexStr);
++void ethRxPolMode(int port, MV_ETH_PRIO_MODE prioMode);
++void ethRxPolQ(int port, int rxQueue, int rxQuota);
++#endif /* INCLUDE_MULTI_QUEUE */
++
++void print_egiga_stat(void *sc, unsigned int port);
++void ethPortStatus (int port);
++void ethPortQueues( int port, int rxQueue, int txQueue, int mode);
++void ethPortMcast(int port);
++void ethPortRegs(int port);
++void ethPortCounters(int port);
++void ethPortRmonCounters(int port);
++void ethRxCoal(int port, int usec);
++void ethTxCoal(int port, int usec);
++
++void ethRegs(int port);
++void ethClearCounters(int port);
++void ethUcastSet(int port, char* macStr, int queue);
++void ethPortUcastShow(int port);
++
++#ifdef CONFIG_MV_ETH_HEADER
++void run_com_header(const char *buffer);
++#endif
++
++#ifdef INCLUDE_MULTI_QUEUE
++void ethRxPolMode(int port, MV_ETH_PRIO_MODE prioMode);
++void ethRxPolQ(int port, int queue, int quota);
++void ethRxPolicy(int port);
++void ethTxPolDef(int port, int txQ, char* headerHexStr);
++void ethTxPolDA(int port, char* macStr, int txQ, char* headerHexStr);
++void ethTxPolicy(int port);
++#endif /* INCLUDE_MULTI_QUEUE */
++
++#if (MV_ETH_VERSION >= 4)
++void ethEjpModeSet(int port, int mode)
++#endif
++#endif /* 0 */
++
++
++
++
++void ethRxCoal(int port, int usec);
++void ethTxCoal(int port, int usec);
++#if (MV_ETH_VERSION >= 4)
++void ethEjpModeSet(int port, int mode);
++#endif /* (MV_ETH_VERSION >= 4) */
++
++void ethBpduRxQ(int port, int bpduQueue);
++void ethArpRxQ(int port, int arpQueue);
++void ethTcpRxQ(int port, int tcpQueue);
++void ethUdpRxQ(int port, int udpQueue);
++void ethTxPolicyRegs(int port);
++void ethPortRegs(int port);
++void ethRegs(int port);
++void ethClearCounters(int port);
++void ethPortCounters(int port);
++void ethPortRmonCounters(int port);
++void ethPortStatus(int port);
++void ethPortQueues(int port, int rxQueue, int txQueue, int mode);
++void ethUcastSet(int port, char* macStr, int queue);
++void ethPortUcastShow(int port);
++void ethMcastAdd(int port, char* macStr, int queue);
++void ethPortMcast(int port);
++void mvEthPortShow(void* pHndl);
++void mvEthQueuesShow(void* pHndl, int rxQueue, int txQueue, int mode);
++
++#endif
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthGbe.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthGbe.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthGbe.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthGbe.h 2010-11-09 20:28:11.152495442 +0100
+@@ -0,0 +1,751 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++/*******************************************************************************
++* mvEth.h - Header File for : Marvell Gigabit Ethernet Controller
++*
++* DESCRIPTION:
++* This header file contains macros typedefs and function declaration specific to
++* the Marvell Gigabit Ethernet Controller.
++*
++* DEPENDENCIES:
++* None.
++*
++*******************************************************************************/
++
++#ifndef __mvEthGbe_h__
++#define __mvEthGbe_h__
++
++extern MV_BOOL ethDescInSram;
++extern MV_BOOL ethDescSwCoher;
++extern ETH_PORT_CTRL* ethPortCtrl[];
++
++static INLINE MV_ULONG ethDescVirtToPhy(ETH_QUEUE_CTRL* pQueueCtrl, MV_U8* pDesc)
++{
++#if defined (ETH_DESCR_IN_SRAM)
++ if( ethDescInSram )
++ return mvSramVirtToPhy(pDesc);
++ else
++#endif /* ETH_DESCR_IN_SRAM */
++ return (pQueueCtrl->descBuf.bufPhysAddr + (pDesc - pQueueCtrl->descBuf.bufVirtPtr));
++}
++/* Return port handler */
++#define mvEthPortHndlGet(port) ethPortCtrl[port]
++
++/* Used as WA for HW/SW race on TX */
++static INLINE int mvEthPortTxEnable(void* pPortHndl, int queue, int max_deep)
++{
++ int deep = 0;
++ MV_U32 txCurrReg, txEnReg;
++ ETH_TX_DESC* pTxLastDesc;
++ ETH_QUEUE_CTRL* pQueueCtrl;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++
++ txEnReg = MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo));
++ if( (txEnReg & MV_32BIT_LE_FAST(ETH_TXQ_ENABLE_MASK)) == 0)
++ {
++ MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo)) = pPortCtrl->portTxQueueCmdReg;
++ return 0;
++ }
++
++ pQueueCtrl = &pPortCtrl->txQueue[queue];
++ pTxLastDesc = pQueueCtrl->pCurrentDescr;
++ txCurrReg = MV_REG_READ(ETH_TX_CUR_DESC_PTR_REG(pPortCtrl->portNo, queue));
++ if(ethDescVirtToPhy(pQueueCtrl, (MV_U8*)pTxLastDesc) == txCurrReg)
++ {
++ /* All descriptors are processed, no chance for race */
++ return 0;
++ }
++
++ /* Check distance betwee HW and SW location: */
++ /* If distance between HW and SW pointers is less than max_deep descriptors */
++ /* Race condition is possible, so wait end of TX and restart TXQ */
++ while(deep < max_deep)
++ {
++ pTxLastDesc = TX_PREV_DESC_PTR(pTxLastDesc, pQueueCtrl);
++ if(ethDescVirtToPhy(pQueueCtrl, (MV_U8*)pTxLastDesc) == txCurrReg)
++ {
++ int count = 0;
++
++ while( (txEnReg & MV_32BIT_LE_FAST(ETH_TXQ_ENABLE_MASK)) != 0)
++ {
++ count++;
++ if(count > 10000)
++ {
++ mvOsPrintf("mvEthPortTxEnable: timeout - TXQ_CMD=0x%08x\n",
++ MV_REG_READ(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo)) );
++ break;
++ }
++ txEnReg = MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo));
++ }
++
++ MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo)) = pPortCtrl->portTxQueueCmdReg;
++ return count;
++ }
++ deep++;
++ }
++ /* Distance between HW and SW pointers is more than max_deep descriptors, */
++ /* So NO race condition - do nothing */
++ return -1;
++}
++
++
++/* defines */
++#define ETH_CSUM_MIN_BYTE_COUNT 72
++
++/* Tailgate and Kirwood have only 2K TX FIFO */
++#if (MV_ETH_VERSION == 2) || (MV_ETH_VERSION == 4)
++#define ETH_CSUM_MAX_BYTE_COUNT 1600
++#else
++#define ETH_CSUM_MAX_BYTE_COUNT 9*1024
++#endif /* MV_ETH_VERSION */
++
++#define ETH_MV_HEADER_SIZE 2
++#define ETH_MV_TX_EN
++
++/* An offest in Tx descriptors to store data for buffers less than 8 Bytes */
++#define MIN_TX_BUFF_LOAD 8
++#define TX_BUF_OFFSET_IN_DESC (ETH_TX_DESC_ALIGNED_SIZE - MIN_TX_BUFF_LOAD)
++
++/* Default port configuration value */
++#define PORT_CONFIG_VALUE \
++ ETH_DEF_RX_QUEUE_MASK(0) | \
++ ETH_DEF_RX_ARP_QUEUE_MASK(0) | \
++ ETH_DEF_RX_TCP_QUEUE_MASK(0) | \
++ ETH_DEF_RX_UDP_QUEUE_MASK(0) | \
++ ETH_DEF_RX_BPDU_QUEUE_MASK(0) | \
++ ETH_RX_CHECKSUM_WITH_PSEUDO_HDR
++
++/* Default port extend configuration value */
++#define PORT_CONFIG_EXTEND_VALUE 0
++
++#define PORT_SERIAL_CONTROL_VALUE \
++ ETH_DISABLE_FC_AUTO_NEG_MASK | \
++ BIT9 | \
++ ETH_DO_NOT_FORCE_LINK_FAIL_MASK | \
++ ETH_MAX_RX_PACKET_1552BYTE | \
++ ETH_SET_FULL_DUPLEX_MASK
++
++#define PORT_SERIAL_CONTROL_100MB_FORCE_VALUE \
++ ETH_FORCE_LINK_PASS_MASK | \
++ ETH_DISABLE_DUPLEX_AUTO_NEG_MASK | \
++ ETH_DISABLE_FC_AUTO_NEG_MASK | \
++ BIT9 | \
++ ETH_DO_NOT_FORCE_LINK_FAIL_MASK | \
++ ETH_DISABLE_SPEED_AUTO_NEG_MASK | \
++ ETH_SET_FULL_DUPLEX_MASK | \
++ ETH_SET_MII_SPEED_100_MASK | \
++ ETH_MAX_RX_PACKET_1552BYTE
++
++
++#define PORT_SERIAL_CONTROL_1000MB_FORCE_VALUE \
++ ETH_FORCE_LINK_PASS_MASK | \
++ ETH_DISABLE_DUPLEX_AUTO_NEG_MASK | \
++ ETH_DISABLE_FC_AUTO_NEG_MASK | \
++ BIT9 | \
++ ETH_DO_NOT_FORCE_LINK_FAIL_MASK | \
++ ETH_DISABLE_SPEED_AUTO_NEG_MASK | \
++ ETH_SET_FULL_DUPLEX_MASK | \
++ ETH_SET_GMII_SPEED_1000_MASK | \
++ ETH_MAX_RX_PACKET_1552BYTE
++
++#define PORT_SERIAL_CONTROL_SGMII_IBAN_VALUE \
++ ETH_DISABLE_FC_AUTO_NEG_MASK | \
++ BIT9 | \
++ ETH_IN_BAND_AN_EN_MASK | \
++ ETH_DO_NOT_FORCE_LINK_FAIL_MASK | \
++ ETH_MAX_RX_PACKET_1552BYTE
++
++/* Function headers: */
++MV_VOID mvEthSetSpecialMcastTable(int portNo, int queue);
++MV_STATUS mvEthArpRxQueue(void* pPortHandle, int arpQueue);
++MV_STATUS mvEthUdpRxQueue(void* pPortHandle, int udpQueue);
++MV_STATUS mvEthTcpRxQueue(void* pPortHandle, int tcpQueue);
++MV_STATUS mvEthMacAddrGet(int portNo, unsigned char *pAddr);
++MV_VOID mvEthSetOtherMcastTable(int portNo, int queue);
++MV_STATUS mvEthHeaderModeSet(void* pPortHandle, MV_ETH_HEADER_MODE headerMode);
++/* Interrupt Coalesting functions */
++MV_U32 mvEthRxCoalSet(void* pPortHndl, MV_U32 uSec);
++MV_U32 mvEthTxCoalSet(void* pPortHndl, MV_U32 uSec);
++MV_STATUS mvEthCoalGet(void* pPortHndl, MV_U32* pRxCoal, MV_U32* pTxCoal);
++
++/******************************************************************************/
++/* Data Flow functions */
++/******************************************************************************/
++static INLINE void mvEthPortTxRestart(void* pPortHndl)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++
++ MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo)) = pPortCtrl->portTxQueueCmdReg;
++}
++
++/* Get number of Free resources in specific TX queue */
++static INLINE int mvEthTxResourceGet(void* pPortHndl, int txQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++
++ return (pPortCtrl->txQueue[txQueue].resource);
++}
++
++/* Get number of Free resources in specific RX queue */
++static INLINE int mvEthRxResourceGet(void* pPortHndl, int rxQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++
++ return (pPortCtrl->rxQueue[rxQueue].resource);
++}
++
++static INLINE int mvEthTxQueueIsFull(void* pPortHndl, int txQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++
++ if(pPortCtrl->txQueue[txQueue].resource == 0)
++ return MV_TRUE;
++
++ return MV_FALSE;
++}
++
++/* Get number of Free resources in specific RX queue */
++static INLINE int mvEthRxQueueIsFull(void* pPortHndl, int rxQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++ ETH_QUEUE_CTRL* pQueueCtrl = &pPortCtrl->rxQueue[rxQueue];
++
++ if( (pQueueCtrl->pUsedDescr == pQueueCtrl->pCurrentDescr) &&
++ (pQueueCtrl->resource != 0) )
++ return MV_TRUE;
++
++ return MV_FALSE;
++}
++
++static INLINE int mvEthTxQueueIsEmpty(void* pPortHndl, int txQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++ ETH_QUEUE_CTRL* pQueueCtrl = &pPortCtrl->txQueue[txQueue];
++
++ if( (pQueueCtrl->pUsedDescr == pQueueCtrl->pCurrentDescr) &&
++ (pQueueCtrl->resource != 0) )
++ {
++ return MV_TRUE;
++ }
++ return MV_FALSE;
++}
++
++/* Get number of Free resources in specific RX queue */
++static INLINE int mvEthRxQueueIsEmpty(void* pPortHndl, int rxQueue)
++{
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl;
++
++ if(pPortCtrl->rxQueue[rxQueue].resource == 0)
++ return MV_TRUE;
++
++ return MV_FALSE;
++}
++
++/*******************************************************************************
++* mvEthPortTx - Send an Ethernet packet
++*
++* DESCRIPTION:
++* This routine send a given packet described by pPktInfo parameter.
++* Single buffer only.
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet Port handler.
++* int txQueue - Number of Tx queue.
++* MV_PKT_INFO *pPktInfo - User packet to send.
++*
++* RETURN:
++* MV_NO_RESOURCE - No enough resources to send this packet.
++* MV_ERROR - Unexpected Fatal error.
++* MV_OK - Packet send successfully.
++*
++*******************************************************************************/
++static INLINE MV_STATUS mvEthPortTx(void* pEthPortHndl, int txQueue, MV_PKT_INFO* pPktInfo)
++{
++ ETH_TX_DESC* pTxCurrDesc;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++ ETH_QUEUE_CTRL* pQueueCtrl;
++ int portNo;
++ MV_BUF_INFO* pBufInfo = pPktInfo->pFrags;
++
++#ifdef ETH_DEBUG
++ if(pPortCtrl->portState != MV_ACTIVE)
++ return MV_BAD_STATE;
++#endif /* ETH_DEBUG */
++
++ portNo = pPortCtrl->portNo;
++ pQueueCtrl = &pPortCtrl->txQueue[txQueue];
++
++ /* Get the Tx Desc ring indexes */
++ pTxCurrDesc = pQueueCtrl->pCurrentDescr;
++
++ /* Check if there is enough resources to send the packet */
++ if(pQueueCtrl->resource == 0)
++ return MV_NO_RESOURCE;
++
++ pTxCurrDesc->byteCnt = pBufInfo->dataSize;
++
++ /* Flash Buffer */
++ if(pPktInfo->pktSize != 0)
++ {
++#ifdef MV_NETBSD
++ pTxCurrDesc->bufPtr = pBufInfo->bufPhysAddr;
++ ETH_PACKET_CACHE_FLUSH(pBufInfo->bufVirtPtr, pPktInfo->pktSize);
++#else
++ pTxCurrDesc->bufPtr = ETH_PACKET_CACHE_FLUSH(pBufInfo->bufVirtPtr, pPktInfo->pktSize);
++#endif
++ pPktInfo->pktSize = 0;
++ }
++ else
++ pTxCurrDesc->bufPtr = pBufInfo->bufPhysAddr;
++
++ pTxCurrDesc->returnInfo = (MV_ULONG)pPktInfo;
++
++ /* There is only one buffer in the packet */
++ /* The OSG might set some bits for checksum offload, so add them to first descriptor */
++ pTxCurrDesc->cmdSts = pPktInfo->status |
++ ETH_BUFFER_OWNED_BY_DMA |
++ ETH_TX_GENERATE_CRC_MASK |
++ ETH_TX_ENABLE_INTERRUPT_MASK |
++ ETH_TX_ZERO_PADDING_MASK |
++ ETH_TX_FIRST_DESC_MASK |
++ ETH_TX_LAST_DESC_MASK;
++
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pTxCurrDesc);
++
++ pQueueCtrl->resource--;
++ pQueueCtrl->pCurrentDescr = TX_NEXT_DESC_PTR(pTxCurrDesc, pQueueCtrl);
++
++ /* Apply send command */
++ MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(portNo)) = pPortCtrl->portTxQueueCmdReg;
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvEthPortSgTx - Send an Ethernet packet
++*
++* DESCRIPTION:
++* This routine send a given packet described by pBufInfo parameter. It
++* supports transmitting of a packet spaned over multiple buffers.
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet Port handler.
++* int txQueue - Number of Tx queue.
++* MV_PKT_INFO *pPktInfo - User packet to send.
++*
++* RETURN:
++* MV_NO_RESOURCE - No enough resources to send this packet.
++* MV_ERROR - Unexpected Fatal error.
++* MV_OK - Packet send successfully.
++*
++*******************************************************************************/
++static INLINE MV_STATUS mvEthPortSgTx(void* pEthPortHndl, int txQueue, MV_PKT_INFO* pPktInfo)
++{
++ ETH_TX_DESC* pTxFirstDesc;
++ ETH_TX_DESC* pTxCurrDesc;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++ ETH_QUEUE_CTRL* pQueueCtrl;
++ int portNo, bufCount;
++ MV_BUF_INFO* pBufInfo = pPktInfo->pFrags;
++ MV_U8* pTxBuf;
++
++#ifdef ETH_DEBUG
++ if(pPortCtrl->portState != MV_ACTIVE)
++ return MV_BAD_STATE;
++#endif /* ETH_DEBUG */
++
++ portNo = pPortCtrl->portNo;
++ pQueueCtrl = &pPortCtrl->txQueue[txQueue];
++
++ /* Get the Tx Desc ring indexes */
++ pTxCurrDesc = pQueueCtrl->pCurrentDescr;
++
++ /* Check if there is enough resources to send the packet */
++ if(pQueueCtrl->resource < pPktInfo->numFrags)
++ return MV_NO_RESOURCE;
++
++ /* Remember first desc */
++ pTxFirstDesc = pTxCurrDesc;
++
++ bufCount = 0;
++ while(MV_TRUE)
++ {
++ if(pBufInfo[bufCount].dataSize <= MIN_TX_BUFF_LOAD)
++ {
++ /* Buffers with a payload smaller than MIN_TX_BUFF_LOAD (8 bytes) must be aligned */
++ /* to 64-bit boundary. Two options here: */
++ /* 1) Usually, copy the payload to the reserved 8 bytes inside descriptor. */
++ /* 2) In the Half duplex workaround, the reserved 8 bytes inside descriptor are used */
++ /* as a pointer to the aligned buffer, copy the small payload to this buffer. */
++ pTxBuf = ((MV_U8*)pTxCurrDesc)+TX_BUF_OFFSET_IN_DESC;
++ mvOsBCopy(pBufInfo[bufCount].bufVirtPtr, pTxBuf, pBufInfo[bufCount].dataSize);
++ pTxCurrDesc->bufPtr = ethDescVirtToPhy(pQueueCtrl, pTxBuf);
++ }
++ else
++ {
++ /* Flash Buffer */
++#ifdef MV_NETBSD
++ pTxCurrDesc->bufPtr = pBufInfo[bufCount].bufPhysAddr;
++ ETH_PACKET_CACHE_FLUSH(pBufInfo[bufCount].bufVirtPtr, pBufInfo[bufCount].dataSize);
++#else
++ pTxCurrDesc->bufPtr = ETH_PACKET_CACHE_FLUSH(pBufInfo[bufCount].bufVirtPtr, pBufInfo[bufCount].dataSize);
++#endif
++ }
++
++ pTxCurrDesc->byteCnt = pBufInfo[bufCount].dataSize;
++ bufCount++;
++
++ if(bufCount >= pPktInfo->numFrags)
++ break;
++
++ if(bufCount > 1)
++ {
++ /* There is middle buffer of the packet Not First and Not Last */
++ pTxCurrDesc->cmdSts = ETH_BUFFER_OWNED_BY_DMA;
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pTxCurrDesc);
++ }
++ /* Go to next descriptor and next buffer */
++ pTxCurrDesc = TX_NEXT_DESC_PTR(pTxCurrDesc, pQueueCtrl);
++ }
++ /* Set last desc with DMA ownership and interrupt enable. */
++ pTxCurrDesc->returnInfo = (MV_ULONG)pPktInfo;
++ if(bufCount == 1)
++ {
++ /* There is only one buffer in the packet */
++ /* The OSG might set some bits for checksum offload, so add them to first descriptor */
++ pTxCurrDesc->cmdSts = pPktInfo->status |
++ ETH_BUFFER_OWNED_BY_DMA |
++ ETH_TX_GENERATE_CRC_MASK |
++ ETH_TX_ENABLE_INTERRUPT_MASK |
++ ETH_TX_ZERO_PADDING_MASK |
++ ETH_TX_FIRST_DESC_MASK |
++ ETH_TX_LAST_DESC_MASK;
++
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pTxCurrDesc);
++ }
++ else
++ {
++ /* Last but not First */
++ pTxCurrDesc->cmdSts = ETH_BUFFER_OWNED_BY_DMA |
++ ETH_TX_ENABLE_INTERRUPT_MASK |
++ ETH_TX_ZERO_PADDING_MASK |
++ ETH_TX_LAST_DESC_MASK;
++
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pTxCurrDesc);
++
++ /* Update First when more than one buffer in the packet */
++ /* The OSG might set some bits for checksum offload, so add them to first descriptor */
++ pTxFirstDesc->cmdSts = pPktInfo->status |
++ ETH_BUFFER_OWNED_BY_DMA |
++ ETH_TX_GENERATE_CRC_MASK |
++ ETH_TX_FIRST_DESC_MASK;
++
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pTxFirstDesc);
++ }
++ /* Update txQueue state */
++ pQueueCtrl->resource -= bufCount;
++ pQueueCtrl->pCurrentDescr = TX_NEXT_DESC_PTR(pTxCurrDesc, pQueueCtrl);
++
++ /* Apply send command */
++ MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(portNo)) = pPortCtrl->portTxQueueCmdReg;
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvEthPortTxDone - Free all used Tx descriptors and mBlks.
++*
++* DESCRIPTION:
++* This routine returns the transmitted packet information to the caller.
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet Port handler.
++* int txQueue - Number of Tx queue.
++*
++* OUTPUT:
++* MV_PKT_INFO *pPktInfo - Pointer to packet was sent.
++*
++* RETURN:
++* MV_NOT_FOUND - No transmitted packets to return. Transmit in progress.
++* MV_EMPTY - No transmitted packets to return. TX Queue is empty.
++* MV_ERROR - Unexpected Fatal error.
++* MV_OK - There is transmitted packet in the queue,
++* 'pPktInfo' filled with relevant information.
++*
++*******************************************************************************/
++static INLINE MV_PKT_INFO* mvEthPortTxDone(void* pEthPortHndl, int txQueue)
++{
++ ETH_TX_DESC* pTxCurrDesc;
++ ETH_TX_DESC* pTxUsedDesc;
++ ETH_QUEUE_CTRL* pQueueCtrl;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++ MV_PKT_INFO* pPktInfo;
++ MV_U32 commandStatus;
++
++ pQueueCtrl = &pPortCtrl->txQueue[txQueue];
++
++ pTxUsedDesc = pQueueCtrl->pUsedDescr;
++ pTxCurrDesc = pQueueCtrl->pCurrentDescr;
++
++ while(MV_TRUE)
++ {
++ /* No more used descriptors */
++ commandStatus = pTxUsedDesc->cmdSts;
++ if (commandStatus & (ETH_BUFFER_OWNED_BY_DMA))
++ {
++ ETH_DESCR_INV(pPortCtrl, pTxUsedDesc);
++ return NULL;
++ }
++ if( (pTxUsedDesc == pTxCurrDesc) &&
++ (pQueueCtrl->resource != 0) )
++ {
++ return NULL;
++ }
++ pQueueCtrl->resource++;
++ pQueueCtrl->pUsedDescr = TX_NEXT_DESC_PTR(pTxUsedDesc, pQueueCtrl);
++ if(commandStatus & (ETH_TX_LAST_DESC_MASK))
++ {
++ pPktInfo = (MV_PKT_INFO*)pTxUsedDesc->returnInfo;
++ pPktInfo->status = commandStatus;
++ return pPktInfo;
++ }
++ pTxUsedDesc = pQueueCtrl->pUsedDescr;
++ }
++}
++
++/*******************************************************************************
++* mvEthPortRx - Get new received packets from Rx queue.
++*
++* DESCRIPTION:
++* This routine returns the received data to the caller. There is no
++* data copying during routine operation. All information is returned
++* using pointer to packet information struct passed from the caller.
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet Port handler.
++* int rxQueue - Number of Rx queue.
++*
++* OUTPUT:
++* MV_PKT_INFO *pPktInfo - Pointer to received packet.
++*
++* RETURN:
++* MV_NO_RESOURCE - No free resources in RX queue.
++* MV_ERROR - Unexpected Fatal error.
++* MV_OK - New packet received and 'pBufInfo' structure filled
++* with relevant information.
++*
++*******************************************************************************/
++static INLINE MV_PKT_INFO* mvEthPortRx(void* pEthPortHndl, int rxQueue)
++{
++ ETH_RX_DESC *pRxCurrDesc;
++ MV_U32 commandStatus;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++ ETH_QUEUE_CTRL* pQueueCtrl;
++ MV_PKT_INFO* pPktInfo;
++
++ pQueueCtrl = &(pPortCtrl->rxQueue[rxQueue]);
++
++ /* Check resources */
++ if(pQueueCtrl->resource == 0)
++ {
++ mvOsPrintf("ethPortRx: no more resources\n");
++ return NULL;
++ }
++ while(MV_TRUE)
++ {
++ /* Get the Rx Desc ring 'curr and 'used' indexes */
++ pRxCurrDesc = pQueueCtrl->pCurrentDescr;
++
++ commandStatus = pRxCurrDesc->cmdSts;
++ if (commandStatus & (ETH_BUFFER_OWNED_BY_DMA))
++ {
++ /* Nothing to receive... */
++ ETH_DESCR_INV(pPortCtrl, pRxCurrDesc);
++ return NULL;
++ }
++
++ /* Valid RX only if FIRST and LAST bits are set */
++ if( (commandStatus & (ETH_RX_LAST_DESC_MASK | ETH_RX_FIRST_DESC_MASK)) ==
++ (ETH_RX_LAST_DESC_MASK | ETH_RX_FIRST_DESC_MASK) )
++ {
++ pPktInfo = (MV_PKT_INFO*)pRxCurrDesc->returnInfo;
++ pPktInfo->pFrags->dataSize = pRxCurrDesc->byteCnt - 4;
++ pPktInfo->status = commandStatus;
++ pPktInfo->fragIP = pRxCurrDesc->bufSize & ETH_RX_IP_FRAGMENTED_FRAME_MASK;
++
++ pQueueCtrl->resource--;
++ /* Update 'curr' in data structure */
++ pQueueCtrl->pCurrentDescr = RX_NEXT_DESC_PTR(pRxCurrDesc, pQueueCtrl);
++
++#ifdef INCLUDE_SYNC_BARR
++ mvCpuIfSyncBarr(DRAM_TARGET);
++#endif
++ return pPktInfo;
++ }
++ else
++ {
++ ETH_RX_DESC* pRxUsedDesc = pQueueCtrl->pUsedDescr;
++
++#ifdef ETH_DEBUG
++ mvOsPrintf("ethDrv: Unexpected Jumbo frame: "
++ "status=0x%08x, byteCnt=%d, pData=0x%x\n",
++ commandStatus, pRxCurrDesc->byteCnt, pRxCurrDesc->bufPtr);
++#endif /* ETH_DEBUG */
++
++ /* move buffer from pCurrentDescr position to pUsedDescr position */
++ pRxUsedDesc->bufPtr = pRxCurrDesc->bufPtr;
++ pRxUsedDesc->returnInfo = pRxCurrDesc->returnInfo;
++ pRxUsedDesc->bufSize = pRxCurrDesc->bufSize & ETH_RX_BUFFER_MASK;
++
++ /* Return the descriptor to DMA ownership */
++ pRxUsedDesc->cmdSts = ETH_BUFFER_OWNED_BY_DMA |
++ ETH_RX_ENABLE_INTERRUPT_MASK;
++
++ /* Flush descriptor and CPU pipe */
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pRxUsedDesc);
++
++ /* Move the used descriptor pointer to the next descriptor */
++ pQueueCtrl->pUsedDescr = RX_NEXT_DESC_PTR(pRxUsedDesc, pQueueCtrl);
++ pQueueCtrl->pCurrentDescr = RX_NEXT_DESC_PTR(pRxCurrDesc, pQueueCtrl);
++ }
++ }
++}
++
++/*******************************************************************************
++* mvEthPortRxDone - Returns a Rx buffer back to the Rx ring.
++*
++* DESCRIPTION:
++* This routine returns a Rx buffer back to the Rx ring.
++*
++* INPUT:
++* void* pEthPortHndl - Ethernet Port handler.
++* int rxQueue - Number of Rx queue.
++* MV_PKT_INFO *pPktInfo - Pointer to received packet.
++*
++* RETURN:
++* MV_ERROR - Unexpected Fatal error.
++* MV_OUT_OF_RANGE - RX queue is already FULL, so this buffer can't be
++* returned to this queue.
++* MV_FULL - Buffer returned successfully and RX queue became full.
++* More buffers should not be returned at the time.
++* MV_OK - Buffer returned successfully and there are more free
++* places in the queue.
++*
++*******************************************************************************/
++static INLINE MV_STATUS mvEthPortRxDone(void* pEthPortHndl, int rxQueue, MV_PKT_INFO *pPktInfo)
++{
++ ETH_RX_DESC* pRxUsedDesc;
++ ETH_QUEUE_CTRL* pQueueCtrl;
++ ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl;
++
++ pQueueCtrl = &pPortCtrl->rxQueue[rxQueue];
++
++ /* Get 'used' Rx descriptor */
++ pRxUsedDesc = pQueueCtrl->pUsedDescr;
++
++ /* Check that ring is not FULL */
++ if( (pQueueCtrl->pUsedDescr == pQueueCtrl->pCurrentDescr) &&
++ (pQueueCtrl->resource != 0) )
++ {
++ mvOsPrintf("%s %d: out of range Error resource=%d, curr=%p, used=%p\n",
++ __FUNCTION__, pPortCtrl->portNo, pQueueCtrl->resource,
++ pQueueCtrl->pCurrentDescr, pQueueCtrl->pUsedDescr);
++ return MV_OUT_OF_RANGE;
++ }
++
++ pRxUsedDesc->bufPtr = pPktInfo->pFrags->bufPhysAddr;
++ pRxUsedDesc->returnInfo = (MV_ULONG)pPktInfo;
++ pRxUsedDesc->bufSize = pPktInfo->pFrags->bufSize & ETH_RX_BUFFER_MASK;
++
++ /* Invalidate data buffer accordingly with pktSize */
++ if(pPktInfo->pktSize != 0)
++ {
++ ETH_PACKET_CACHE_INVALIDATE(pPktInfo->pFrags->bufVirtPtr, pPktInfo->pktSize);
++ pPktInfo->pktSize = 0;
++ }
++
++ /* Return the descriptor to DMA ownership */
++ pRxUsedDesc->cmdSts = ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT_MASK;
++
++ /* Flush descriptor and CPU pipe */
++ ETH_DESCR_FLUSH_INV(pPortCtrl, pRxUsedDesc);
++
++ pQueueCtrl->resource++;
++
++ /* Move the used descriptor pointer to the next descriptor */
++ pQueueCtrl->pUsedDescr = RX_NEXT_DESC_PTR(pRxUsedDesc, pQueueCtrl);
++
++ /* If ring became Full return MV_FULL */
++ if(pQueueCtrl->pUsedDescr == pQueueCtrl->pCurrentDescr)
++ return MV_FULL;
++
++ return MV_OK;
++}
++
++
++#endif /* __mvEthGbe_h__ */
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthRegs.h 2010-11-09 20:28:11.192495435 +0100
+@@ -0,0 +1,700 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvEthRegsh
++#define __INCmvEthRegsh
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++
++/****************************************/
++/* Ethernet Unit Registers */
++/****************************************/
++#define ETH_REG_BASE MV_ETH_REG_BASE
++
++#define ETH_PHY_ADDR_REG(port) (ETH_REG_BASE(port) + 0x000)
++#define ETH_SMI_REG(port) (ETH_REG_BASE(port) + 0x004)
++#define ETH_UNIT_DEF_ADDR_REG(port) (ETH_REG_BASE(port) + 0x008)
++#define ETH_UNIT_DEF_ID_REG(port) (ETH_REG_BASE(port) + 0x00c)
++#define ETH_UNIT_RESERVED(port) (ETH_REG_BASE(port) + 0x014)
++#define ETH_UNIT_INTR_CAUSE_REG(port) (ETH_REG_BASE(port) + 0x080)
++#define ETH_UNIT_INTR_MASK_REG(port) (ETH_REG_BASE(port) + 0x084)
++
++
++#define ETH_UNIT_ERROR_ADDR_REG(port) (ETH_REG_BASE(port) + 0x094)
++#define ETH_UNIT_INT_ADDR_ERROR_REG(port) (ETH_REG_BASE(port) + 0x098)
++#define ETH_UNIT_CONTROL_REG(port) (ETH_REG_BASE(port) + 0x0B0)
++
++#define ETH_PORT_CONFIG_REG(port) (ETH_REG_BASE(port) + 0x400)
++#define ETH_PORT_CONFIG_EXTEND_REG(port) (ETH_REG_BASE(port) + 0x404)
++#define ETH_MII_SERIAL_PARAM_REG(port) (ETH_REG_BASE(port) + 0x408)
++#define ETH_GMII_SERIAL_PARAM_REG(port) (ETH_REG_BASE(port) + 0x40c)
++#define ETH_VLAN_ETHER_TYPE_REG(port) (ETH_REG_BASE(port) + 0x410)
++#define ETH_MAC_ADDR_LOW_REG(port) (ETH_REG_BASE(port) + 0x414)
++#define ETH_MAC_ADDR_HIGH_REG(port) (ETH_REG_BASE(port) + 0x418)
++#define ETH_SDMA_CONFIG_REG(port) (ETH_REG_BASE(port) + 0x41c)
++#define ETH_DIFF_SERV_PRIO_REG(port, code) (ETH_REG_BASE(port) + 0x420 + ((code)<<2))
++#define ETH_PORT_SERIAL_CTRL_REG(port) (ETH_REG_BASE(port) + 0x43c)
++#define ETH_VLAN_TAG_TO_PRIO_REG(port) (ETH_REG_BASE(port) + 0x440)
++#define ETH_PORT_STATUS_REG(port) (ETH_REG_BASE(port) + 0x444)
++
++#define ETH_RX_QUEUE_COMMAND_REG(port) (ETH_REG_BASE(port) + 0x680)
++#define ETH_TX_QUEUE_COMMAND_REG(port) (ETH_REG_BASE(port) + 0x448)
++
++#define ETH_PORT_SERIAL_CTRL_1_REG(port) (ETH_REG_BASE(port) + 0x44c)
++#define ETH_PORT_STATUS_1_REG(port) (ETH_REG_BASE(port) + 0x450)
++#define ETH_PORT_MARVELL_HEADER_REG(port) (ETH_REG_BASE(port) + 0x454)
++#define ETH_PORT_FIFO_PARAMS_REG(port) (ETH_REG_BASE(port) + 0x458)
++#define ETH_MAX_TOKEN_BUCKET_SIZE_REG(port) (ETH_REG_BASE(port) + 0x45c)
++#define ETH_INTR_CAUSE_REG(port) (ETH_REG_BASE(port) + 0x460)
++#define ETH_INTR_CAUSE_EXT_REG(port) (ETH_REG_BASE(port) + 0x464)
++#define ETH_INTR_MASK_REG(port) (ETH_REG_BASE(port) + 0x468)
++#define ETH_INTR_MASK_EXT_REG(port) (ETH_REG_BASE(port) + 0x46c)
++#define ETH_TX_FIFO_URGENT_THRESH_REG(port) (ETH_REG_BASE(port) + 0x474)
++#define ETH_RX_MINIMAL_FRAME_SIZE_REG(port) (ETH_REG_BASE(port) + 0x47c)
++#define ETH_RX_DISCARD_PKTS_CNTR_REG(port) (ETH_REG_BASE(port) + 0x484)
++#define ETH_RX_OVERRUN_PKTS_CNTR_REG(port) (ETH_REG_BASE(port) + 0x488)
++#define ETH_INTERNAL_ADDR_ERROR_REG(port) (ETH_REG_BASE(port) + 0x494)
++#define ETH_TX_FIXED_PRIO_CFG_REG(port) (ETH_REG_BASE(port) + 0x4dc)
++#define ETH_TX_TOKEN_RATE_CFG_REG(port) (ETH_REG_BASE(port) + 0x4e0)
++#define ETH_TX_QUEUE_COMMAND1_REG(port) (ETH_REG_BASE(port) + 0x4e4)
++#define ETH_MAX_TRANSMIT_UNIT_REG(port) (ETH_REG_BASE(port) + 0x4e8)
++#define ETH_TX_TOKEN_BUCKET_SIZE_REG(port) (ETH_REG_BASE(port) + 0x4ec)
++#define ETH_TX_TOKEN_BUCKET_COUNT_REG(port) (ETH_REG_BASE(port) + 0x780)
++#define ETH_RX_DESCR_STAT_CMD_REG(port, q) (ETH_REG_BASE(port) + 0x600 + ((q)<<4))
++#define ETH_RX_BYTE_COUNT_REG(port, q) (ETH_REG_BASE(port) + 0x604 + ((q)<<4))
++#define ETH_RX_BUF_PTR_REG(port, q) (ETH_REG_BASE(port) + 0x608 + ((q)<<4))
++#define ETH_RX_CUR_DESC_PTR_REG(port, q) (ETH_REG_BASE(port) + 0x60c + ((q)<<4))
++#define ETH_TX_CUR_DESC_PTR_REG(port, q) (ETH_REG_BASE(port) + 0x6c0 + ((q)<<2))
++
++#define ETH_TXQ_TOKEN_COUNT_REG(port, q) (ETH_REG_BASE(port) + 0x700 + ((q)<<4))
++#define ETH_TXQ_TOKEN_CFG_REG(port, q) (ETH_REG_BASE(port) + 0x704 + ((q)<<4))
++#define ETH_TXQ_ARBITER_CFG_REG(port, q) (ETH_REG_BASE(port) + 0x708 + ((q)<<4))
++
++#if (MV_ETH_VERSION >= 4)
++#define ETH_TXQ_CMD_1_REG(port) (ETH_REG_BASE(port) + 0x4E4)
++#define ETH_EJP_TX_HI_IPG_REG(port) (ETH_REG_BASE(port) + 0x7A8)
++#define ETH_EJP_TX_LO_IPG_REG(port) (ETH_REG_BASE(port) + 0x7B8)
++#define ETH_EJP_HI_TKN_LO_PKT_REG(port) (ETH_REG_BASE(port) + 0x7C0)
++#define ETH_EJP_HI_TKN_ASYNC_PKT_REG(port) (ETH_REG_BASE(port) + 0x7C4)
++#define ETH_EJP_LO_TKN_ASYNC_PKT_REG(port) (ETH_REG_BASE(port) + 0x7C8)
++#define ETH_EJP_TX_SPEED_REG(port) (ETH_REG_BASE(port) + 0x7D0)
++#endif /* MV_ETH_VERSION >= 4 */
++
++#define ETH_MIB_COUNTERS_BASE(port) (ETH_REG_BASE(port) + 0x1000)
++#define ETH_DA_FILTER_SPEC_MCAST_BASE(port) (ETH_REG_BASE(port) + 0x1400)
++#define ETH_DA_FILTER_OTH_MCAST_BASE(port) (ETH_REG_BASE(port) + 0x1500)
++#define ETH_DA_FILTER_UCAST_BASE(port) (ETH_REG_BASE(port) + 0x1600)
++
++/* Phy address register definitions */
++#define ETH_PHY_ADDR_OFFS 0
++#define ETH_PHY_ADDR_MASK (0x1f <<ETH_PHY_ADDR_OFFS)
++
++/* MIB Counters register definitions */
++#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW 0x0
++#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH 0x4
++#define ETH_MIB_BAD_OCTETS_RECEIVED 0x8
++#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR 0xc
++#define ETH_MIB_GOOD_FRAMES_RECEIVED 0x10
++#define ETH_MIB_BAD_FRAMES_RECEIVED 0x14
++#define ETH_MIB_BROADCAST_FRAMES_RECEIVED 0x18
++#define ETH_MIB_MULTICAST_FRAMES_RECEIVED 0x1c
++#define ETH_MIB_FRAMES_64_OCTETS 0x20
++#define ETH_MIB_FRAMES_65_TO_127_OCTETS 0x24
++#define ETH_MIB_FRAMES_128_TO_255_OCTETS 0x28
++#define ETH_MIB_FRAMES_256_TO_511_OCTETS 0x2c
++#define ETH_MIB_FRAMES_512_TO_1023_OCTETS 0x30
++#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS 0x34
++#define ETH_MIB_GOOD_OCTETS_SENT_LOW 0x38
++#define ETH_MIB_GOOD_OCTETS_SENT_HIGH 0x3c
++#define ETH_MIB_GOOD_FRAMES_SENT 0x40
++#define ETH_MIB_EXCESSIVE_COLLISION 0x44
++#define ETH_MIB_MULTICAST_FRAMES_SENT 0x48
++#define ETH_MIB_BROADCAST_FRAMES_SENT 0x4c
++#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50
++#define ETH_MIB_FC_SENT 0x54
++#define ETH_MIB_GOOD_FC_RECEIVED 0x58
++#define ETH_MIB_BAD_FC_RECEIVED 0x5c
++#define ETH_MIB_UNDERSIZE_RECEIVED 0x60
++#define ETH_MIB_FRAGMENTS_RECEIVED 0x64
++#define ETH_MIB_OVERSIZE_RECEIVED 0x68
++#define ETH_MIB_JABBER_RECEIVED 0x6c
++#define ETH_MIB_MAC_RECEIVE_ERROR 0x70
++#define ETH_MIB_BAD_CRC_EVENT 0x74
++#define ETH_MIB_COLLISION 0x78
++#define ETH_MIB_LATE_COLLISION 0x7c
++
++
++/****************************************/
++/* Ethernet Unit Register BITs */
++/****************************************/
++
++#define ETH_RXQ_ENABLE_OFFSET 0
++#define ETH_RXQ_ENABLE_MASK (0x000000FF << ETH_RXQ_ENABLE_OFFSET)
++
++#define ETH_RXQ_DISABLE_OFFSET 8
++#define ETH_RXQ_DISABLE_MASK (0x000000FF << ETH_RXQ_DISABLE_OFFSET)
++
++/***** BITs of Transmit Queue Command (TQC) register *****/
++#define ETH_TXQ_ENABLE_OFFSET 0
++#define ETH_TXQ_ENABLE_MASK (0x000000FF << ETH_TXQ_ENABLE_OFFSET)
++
++#define ETH_TXQ_DISABLE_OFFSET 8
++#define ETH_TXQ_DISABLE_MASK (0x000000FF << ETH_TXQ_DISABLE_OFFSET)
++
++#if (MV_ETH_VERSION >= 4)
++#define ETH_TX_EJP_RESET_BIT 0
++#define ETH_TX_EJP_RESET_MASK (1 << ETH_TX_EJP_RESET_BIT)
++
++#define ETH_TX_EJP_ENABLE_BIT 2
++#define ETH_TX_EJP_ENABLE_MASK (1 << ETH_TX_EJP_ENABLE_BIT)
++
++#define ETH_TX_LEGACY_WRR_BIT 3
++#define ETH_TX_LEGACY_WRR_MASK (1 << ETH_TX_LEGACY_WRR_BIT)
++#endif /* (MV_ETH_VERSION >= 4) */
++
++/***** BITs of Ethernet Port Status reg (PSR) *****/
++#define ETH_LINK_UP_BIT 1
++#define ETH_LINK_UP_MASK (1<<ETH_LINK_UP_BIT)
++
++#define ETH_FULL_DUPLEX_BIT 2
++#define ETH_FULL_DUPLEX_MASK (1<<ETH_FULL_DUPLEX_BIT)
++
++#define ETH_ENABLE_RCV_FLOW_CTRL_BIT 3
++#define ETH_ENABLE_RCV_FLOW_CTRL_MASK (1<<ETH_ENABLE_RCV_FLOW_CTRL_BIT)
++
++#define ETH_GMII_SPEED_1000_BIT 4
++#define ETH_GMII_SPEED_1000_MASK (1<<ETH_GMII_SPEED_1000_BIT)
++
++#define ETH_MII_SPEED_100_BIT 5
++#define ETH_MII_SPEED_100_MASK (1<<ETH_MII_SPEED_100_BIT)
++
++#define ETH_TX_IN_PROGRESS_BIT 7
++#define ETH_TX_IN_PROGRESS_MASK (1<<ETH_TX_IN_PROGRESS_BIT)
++
++#define ETH_TX_FIFO_EMPTY_BIT 10
++#define ETH_TX_FIFO_EMPTY_MASK (1<<ETH_TX_FIFO_EMPTY_BIT)
++
++/***** BITs of Ethernet Port Status 1 reg (PS1R) *****/
++#define ETH_AUTO_NEG_DONE_BIT 4
++#define ETH_AUTO_NEG_DONE_MASK (1<<ETH_AUTO_NEG_DONE_BIT)
++
++#define ETH_SERDES_PLL_LOCKED_BIT 6
++#define ETH_SERDES_PLL_LOCKED_MASK (1<<ETH_SERDES_PLL_LOCKED_BIT)
++
++/***** BITs of Port Configuration reg (PxCR) *****/
++#define ETH_UNICAST_PROMISCUOUS_MODE_BIT 0
++#define ETH_UNICAST_PROMISCUOUS_MODE_MASK (1<<ETH_UNICAST_PROMISCUOUS_MODE_BIT)
++
++#define ETH_DEF_RX_QUEUE_OFFSET 1
++#define ETH_DEF_RX_QUEUE_ALL_MASK (0x7<<ETH_DEF_RX_QUEUE_OFFSET)
++#define ETH_DEF_RX_QUEUE_MASK(queue) ((queue)<<ETH_DEF_RX_QUEUE_OFFSET)
++
++#define ETH_DEF_RX_ARP_QUEUE_OFFSET 4
++#define ETH_DEF_RX_ARP_QUEUE_ALL_MASK (0x7<<ETH_DEF_RX_ARP_QUEUE_OFFSET)
++#define ETH_DEF_RX_ARP_QUEUE_MASK(queue) ((queue)<<ETH_DEF_RX_ARP_QUEUE_OFFSET)
++
++#define ETH_REJECT_NOT_IP_ARP_BCAST_BIT 7
++#define ETH_REJECT_NOT_IP_ARP_BCAST_MASK (1<<ETH_REJECT_NOT_IP_ARP_BCAST_BIT)
++
++#define ETH_REJECT_IP_BCAST_BIT 8
++#define ETH_REJECT_IP_BCAST_MASK (1<<ETH_REJECT_IP_BCAST_BIT)
++
++#define ETH_REJECT_ARP_BCAST_BIT 9
++#define ETH_REJECT_ARP_BCAST_MASK (1<<ETH_REJECT_ARP_BCAST_BIT)
++
++#define ETH_TX_NO_SET_ERROR_SUMMARY_BIT 12
++#define ETH_TX_NO_SET_ERROR_SUMMARY_MASK (1<<ETH_TX_NO_SET_ERROR_SUMMARY_BIT)
++
++#define ETH_CAPTURE_TCP_FRAMES_ENABLE_BIT 14
++#define ETH_CAPTURE_TCP_FRAMES_ENABLE_MASK (1<<ETH_CAPTURE_TCP_FRAMES_ENABLE_BIT)
++
++#define ETH_CAPTURE_UDP_FRAMES_ENABLE_BIT 15
++#define ETH_CAPTURE_UDP_FRAMES_ENABLE_MASK (1<<ETH_CAPTURE_UDP_FRAMES_ENABLE_BIT)
++
++#define ETH_DEF_RX_TCP_QUEUE_OFFSET 16
++#define ETH_DEF_RX_TCP_QUEUE_ALL_MASK (0x7<<ETH_DEF_RX_TCP_QUEUE_OFFSET)
++#define ETH_DEF_RX_TCP_QUEUE_MASK(queue) ((queue)<<ETH_DEF_RX_TCP_QUEUE_OFFSET)
++
++#define ETH_DEF_RX_UDP_QUEUE_OFFSET 19
++#define ETH_DEF_RX_UDP_QUEUE_ALL_MASK (0x7<<ETH_DEF_RX_UDP_QUEUE_OFFSET)
++#define ETH_DEF_RX_UDP_QUEUE_MASK(queue) ((queue)<<ETH_DEF_RX_UDP_QUEUE_OFFSET)
++
++#define ETH_DEF_RX_BPDU_QUEUE_OFFSET 22
++#define ETH_DEF_RX_BPDU_QUEUE_ALL_MASK (0x7<<ETH_DEF_RX_BPDU_QUEUE_OFFSET)
++#define ETH_DEF_RX_BPDU_QUEUE_MASK(queue) ((queue)<<ETH_DEF_RX_BPDU_QUEUE_OFFSET)
++
++#define ETH_RX_CHECKSUM_MODE_OFFSET 25
++#define ETH_RX_CHECKSUM_NO_PSEUDO_HDR (0<<ETH_RX_CHECKSUM_MODE_OFFSET)
++#define ETH_RX_CHECKSUM_WITH_PSEUDO_HDR (1<<ETH_RX_CHECKSUM_MODE_OFFSET)
++
++/***** BITs of Port Configuration Extend reg (PxCXR) *****/
++#define ETH_CAPTURE_SPAN_BPDU_ENABLE_BIT 1
++#define ETH_CAPTURE_SPAN_BPDU_ENABLE_MASK (1<<ETH_CAPTURE_SPAN_BPDU_ENABLE_BIT)
++
++#define ETH_TX_DISABLE_GEN_CRC_BIT 3
++#define ETH_TX_DISABLE_GEN_CRC_MASK (1<<ETH_TX_DISABLE_GEN_CRC_BIT)
++
++/***** BITs of Tx/Rx queue command reg (RQCR/TQCR) *****/
++#define ETH_QUEUE_ENABLE_OFFSET 0
++#define ETH_QUEUE_ENABLE_ALL_MASK (0xFF<<ETH_QUEUE_ENABLE_OFFSET)
++#define ETH_QUEUE_ENABLE_MASK(queue) (1<<((queue)+ETH_QUEUE_ENABLE_OFFSET))
++
++#define ETH_QUEUE_DISABLE_OFFSET 8
++#define ETH_QUEUE_DISABLE_ALL_MASK (0xFF<<ETH_QUEUE_DISABLE_OFFSET)
++#define ETH_QUEUE_DISABLE_MASK(queue) (1<<((queue)+ETH_QUEUE_DISABLE_OFFSET))
++
++
++/***** BITs of Port Sdma Configuration reg (SDCR) *****/
++#define ETH_RX_FRAME_INTERRUPT_BIT 0
++#define ETH_RX_FRAME_INTERRUPT_MASK (1<<ETH_RX_FRAME_INTERRUPT_BIT)
++
++#define ETH_BURST_SIZE_1_64BIT_VALUE 0
++#define ETH_BURST_SIZE_2_64BIT_VALUE 1
++#define ETH_BURST_SIZE_4_64BIT_VALUE 2
++#define ETH_BURST_SIZE_8_64BIT_VALUE 3
++#define ETH_BURST_SIZE_16_64BIT_VALUE 4
++
++#define ETH_RX_BURST_SIZE_OFFSET 1
++#define ETH_RX_BURST_SIZE_ALL_MASK (0x7<<ETH_RX_BURST_SIZE_OFFSET)
++#define ETH_RX_BURST_SIZE_MASK(burst) ((burst)<<ETH_RX_BURST_SIZE_OFFSET)
++
++#define ETH_RX_NO_DATA_SWAP_BIT 4
++#define ETH_RX_NO_DATA_SWAP_MASK (1<<ETH_RX_NO_DATA_SWAP_BIT)
++#define ETH_RX_DATA_SWAP_MASK (0<<ETH_RX_NO_DATA_SWAP_BIT)
++
++#define ETH_TX_NO_DATA_SWAP_BIT 5
++#define ETH_TX_NO_DATA_SWAP_MASK (1<<ETH_TX_NO_DATA_SWAP_BIT)
++#define ETH_TX_DATA_SWAP_MASK (0<<ETH_TX_NO_DATA_SWAP_BIT)
++
++#define ETH_DESC_SWAP_BIT 6
++#define ETH_DESC_SWAP_MASK (1<<ETH_DESC_SWAP_BIT)
++#define ETH_NO_DESC_SWAP_MASK (0<<ETH_DESC_SWAP_BIT)
++
++#define ETH_RX_INTR_COAL_OFFSET 7
++#define ETH_RX_INTR_COAL_ALL_MASK (0x3fff<<ETH_RX_INTR_COAL_OFFSET)
++#define ETH_RX_INTR_COAL_MASK(value) (((value)<<ETH_RX_INTR_COAL_OFFSET) \
++ & ETH_RX_INTR_COAL_ALL_MASK)
++
++#define ETH_TX_BURST_SIZE_OFFSET 22
++#define ETH_TX_BURST_SIZE_ALL_MASK (0x7<<ETH_TX_BURST_SIZE_OFFSET)
++#define ETH_TX_BURST_SIZE_MASK(burst) ((burst)<<ETH_TX_BURST_SIZE_OFFSET)
++
++#define ETH_RX_INTR_COAL_MSB_BIT 25
++#define ETH_RX_INTR_COAL_MSB_MASK (1<<ETH_RX_INTR_COAL_MSB_BIT)
++
++/* BITs Port #x Tx FIFO Urgent Threshold (PxTFUT) */
++#define ETH_TX_INTR_COAL_OFFSET 4
++#define ETH_TX_INTR_COAL_ALL_MASK (0x3fff << ETH_TX_INTR_COAL_OFFSET)
++#define ETH_TX_INTR_COAL_MASK(value) (((value) << ETH_TX_INTR_COAL_OFFSET) \
++ & ETH_TX_INTR_COAL_ALL_MASK)
++
++/* BITs of Port Serial Control reg (PSCR) */
++#define ETH_PORT_ENABLE_BIT 0
++#define ETH_PORT_ENABLE_MASK (1<<ETH_PORT_ENABLE_BIT)
++
++#define ETH_FORCE_LINK_PASS_BIT 1
++#define ETH_FORCE_LINK_PASS_MASK (1<<ETH_FORCE_LINK_PASS_BIT)
++
++#define ETH_DISABLE_DUPLEX_AUTO_NEG_BIT 2
++#define ETH_DISABLE_DUPLEX_AUTO_NEG_MASK (1<<ETH_DISABLE_DUPLEX_AUTO_NEG_BIT)
++
++#define ETH_DISABLE_FC_AUTO_NEG_BIT 3
++#define ETH_DISABLE_FC_AUTO_NEG_MASK (1<<ETH_DISABLE_FC_AUTO_NEG_BIT)
++
++#define ETH_ADVERTISE_SYM_FC_BIT 4
++#define ETH_ADVERTISE_SYM_FC_MASK (1<<ETH_ADVERTISE_SYM_FC_BIT)
++
++#define ETH_TX_FC_MODE_OFFSET 5
++#define ETH_TX_FC_MODE_MASK (3<<ETH_TX_FC_MODE_OFFSET)
++#define ETH_TX_FC_NO_PAUSE (0<<ETH_TX_FC_MODE_OFFSET)
++#define ETH_TX_FC_SEND_PAUSE (1<<ETH_TX_FC_MODE_OFFSET)
++
++#define ETH_TX_BP_MODE_OFFSET 7
++#define ETH_TX_BP_MODE_MASK (3<<ETH_TX_BP_MODE_OFFSET)
++#define ETH_TX_BP_NO_JAM (0<<ETH_TX_BP_MODE_OFFSET)
++#define ETH_TX_BP_SEND_JAM (1<<ETH_TX_BP_MODE_OFFSET)
++
++#define ETH_DO_NOT_FORCE_LINK_FAIL_BIT 10
++#define ETH_DO_NOT_FORCE_LINK_FAIL_MASK (1<<ETH_DO_NOT_FORCE_LINK_FAIL_BIT)
++
++#define ETH_RETRANSMIT_FOREVER_BIT 11
++#define ETH_RETRANSMIT_FOREVER_MASK (1<<ETH_RETRANSMIT_FOREVER_BIT)
++
++#define ETH_DISABLE_SPEED_AUTO_NEG_BIT 13
++#define ETH_DISABLE_SPEED_AUTO_NEG_MASK (1<<ETH_DISABLE_SPEED_AUTO_NEG_BIT)
++
++#define ETH_DTE_ADVERT_BIT 14
++#define ETH_DTE_ADVERT_MASK (1<<ETH_DTE_ADVERT_BIT)
++
++#define ETH_MII_PHY_MODE_BIT 15
++#define ETH_MII_PHY_MODE_MAC (0<<ETH_MII_PHY_MODE_BIT)
++#define ETH_MII_PHY_MODE_PHY (1<<ETH_MII_PHY_MODE_BIT)
++
++#define ETH_MII_SOURCE_SYNCH_BIT 16
++#define ETH_MII_STANDARD_SYNCH (0<<ETH_MII_SOURCE_SYNCH_BIT)
++#define ETH_MII_400Mbps_SYNCH (1<<ETH_MII_SOURCE_CLK_BIT)
++
++#define ETH_MAX_RX_PACKET_SIZE_OFFSET 17
++#define ETH_MAX_RX_PACKET_SIZE_MASK (7<<ETH_MAX_RX_PACKET_SIZE_OFFSET)
++#define ETH_MAX_RX_PACKET_1518BYTE (0<<ETH_MAX_RX_PACKET_SIZE_OFFSET)
++#define ETH_MAX_RX_PACKET_1522BYTE (1<<ETH_MAX_RX_PACKET_SIZE_OFFSET)
++#define ETH_MAX_RX_PACKET_1552BYTE (2<<ETH_MAX_RX_PACKET_SIZE_OFFSET)
++#define ETH_MAX_RX_PACKET_9022BYTE (3<<ETH_MAX_RX_PACKET_SIZE_OFFSET)
++#define ETH_MAX_RX_PACKET_9192BYTE (4<<ETH_MAX_RX_PACKET_SIZE_OFFSET)
++#define ETH_MAX_RX_PACKET_9700BYTE (5<<ETH_MAX_RX_PACKET_SIZE_OFFSET)
++
++#define ETH_SET_FULL_DUPLEX_BIT 21
++#define ETH_SET_FULL_DUPLEX_MASK (1<<ETH_SET_FULL_DUPLEX_BIT)
++
++#define ETH_SET_FLOW_CTRL_BIT 22
++#define ETH_SET_FLOW_CTRL_MASK (1<<ETH_SET_FLOW_CTRL_BIT)
++
++#define ETH_SET_GMII_SPEED_1000_BIT 23
++#define ETH_SET_GMII_SPEED_1000_MASK (1<<ETH_SET_GMII_SPEED_1000_BIT)
++
++#define ETH_SET_MII_SPEED_100_BIT 24
++#define ETH_SET_MII_SPEED_100_MASK (1<<ETH_SET_MII_SPEED_100_BIT)
++
++/* BITs of Port Serial Control 1 reg (PSC1R) */
++#define ETH_PSC_ENABLE_BIT 2
++#define ETH_PSC_ENABLE_MASK (1<<ETH_PSC_ENABLE_BIT)
++
++#define ETH_RGMII_ENABLE_BIT 3
++#define ETH_RGMII_ENABLE_MASK (1<<ETH_RGMII_ENABLE_BIT)
++
++#define ETH_PORT_RESET_BIT 4
++#define ETH_PORT_RESET_MASK (1<<ETH_PORT_RESET_BIT)
++
++#define ETH_INBAND_AUTO_NEG_ENABLE_BIT 6
++#define ETH_INBAND_AUTO_NEG_ENABLE_MASK (1<<ETH_INBAND_AUTO_NEG_ENABLE_BIT)
++
++#define ETH_INBAND_AUTO_NEG_BYPASS_BIT 7
++#define ETH_INBAND_AUTO_NEG_BYPASS_MASK (1<<ETH_INBAND_AUTO_NEG_BYPASS_BIT)
++
++#define ETH_INBAND_AUTO_NEG_START_BIT 8
++#define ETH_INBAND_AUTO_NEG_START_MASK (1<<ETH_INBAND_AUTO_NEG_START_BIT)
++
++#define ETH_PORT_TYPE_BIT 11
++#define ETH_PORT_TYPE_1000BasedX_MASK (1<<ETH_PORT_TYPE_BIT)
++
++#define ETH_SGMII_MODE_BIT 12
++#define ETH_1000BaseX_MODE_MASK (0<<ETH_SGMII_MODE_BIT)
++#define ETH_SGMII_MODE_MASK (1<<ETH_SGMII_MODE_BIT)
++
++#define ETH_MGMII_MODE_BIT 13
++
++#define ETH_EN_MII_ODD_PRE_BIT 22
++#define ETH_EN_MII_ODD_PRE_MASK (1<<ETH_EN_MII_ODD_PRE_BIT)
++
++/* BITs of SDMA Descriptor Command/Status field */
++#if defined(MV_CPU_BE)
++typedef struct _ethRxDesc
++{
++ MV_U16 byteCnt ; /* Descriptor buffer byte count */
++ MV_U16 bufSize ; /* Buffer size */
++ MV_U32 cmdSts ; /* Descriptor command status */
++ MV_U32 nextDescPtr; /* Next descriptor pointer */
++ MV_U32 bufPtr ; /* Descriptor buffer pointer */
++ MV_ULONG returnInfo ; /* User resource return information */
++} ETH_RX_DESC;
++
++typedef struct _ethTxDesc
++{
++ MV_U16 byteCnt ; /* Descriptor buffer byte count */
++ MV_U16 L4iChk ; /* CPU provided TCP Checksum */
++ MV_U32 cmdSts ; /* Descriptor command status */
++ MV_U32 nextDescPtr; /* Next descriptor pointer */
++ MV_U32 bufPtr ; /* Descriptor buffer pointer */
++ MV_ULONG returnInfo ; /* User resource return information */
++ MV_U8* alignBufPtr; /* Pointer to 8 byte aligned buffer */
++} ETH_TX_DESC;
++
++#elif defined(MV_CPU_LE)
++
++typedef struct _ethRxDesc
++{
++ MV_U32 cmdSts ; /* Descriptor command status */
++ MV_U16 bufSize ; /* Buffer size */
++ MV_U16 byteCnt ; /* Descriptor buffer byte count */
++ MV_U32 bufPtr ; /* Descriptor buffer pointer */
++ MV_U32 nextDescPtr; /* Next descriptor pointer */
++ MV_ULONG returnInfo ; /* User resource return information */
++} ETH_RX_DESC;
++
++typedef struct _ethTxDesc
++{
++ MV_U32 cmdSts ; /* Descriptor command status */
++ MV_U16 L4iChk ; /* CPU provided TCP Checksum */
++ MV_U16 byteCnt ; /* Descriptor buffer byte count */
++ MV_U32 bufPtr ; /* Descriptor buffer pointer */
++ MV_U32 nextDescPtr; /* Next descriptor pointer */
++ MV_ULONG returnInfo ; /* User resource return information */
++ MV_U8* alignBufPtr; /* Pointer to 32 byte aligned buffer */
++} ETH_TX_DESC;
++
++#else
++#error "MV_CPU_BE or MV_CPU_LE must be defined"
++#endif /* MV_CPU_BE || MV_CPU_LE */
++
++/* Buffer offset from buffer pointer */
++#define ETH_RX_BUF_OFFSET 0x2
++
++
++/* Tx & Rx descriptor bits */
++#define ETH_ERROR_SUMMARY_BIT 0
++#define ETH_ERROR_SUMMARY_MASK (1<<ETH_ERROR_SUMMARY_BIT)
++
++#define ETH_BUFFER_OWNER_BIT 31
++#define ETH_BUFFER_OWNED_BY_DMA (1<<ETH_BUFFER_OWNER_BIT)
++#define ETH_BUFFER_OWNED_BY_HOST (0<<ETH_BUFFER_OWNER_BIT)
++
++/* Tx descriptor bits */
++#define ETH_TX_ERROR_CODE_OFFSET 1
++#define ETH_TX_ERROR_CODE_MASK (3<<ETH_TX_ERROR_CODE_OFFSET)
++#define ETH_TX_LATE_COLLISION_ERROR (0<<ETH_TX_ERROR_CODE_OFFSET)
++#define ETH_TX_UNDERRUN_ERROR (1<<ETH_TX_ERROR_CODE_OFFSET)
++#define ETH_TX_EXCESSIVE_COLLISION_ERROR (2<<ETH_TX_ERROR_CODE_OFFSET)
++
++#define ETH_TX_LLC_SNAP_FORMAT_BIT 9
++#define ETH_TX_LLC_SNAP_FORMAT_MASK (1<<ETH_TX_LLC_SNAP_FORMAT_BIT)
++
++#define ETH_TX_IP_FRAG_BIT 10
++#define ETH_TX_IP_FRAG_MASK (1<<ETH_TX_IP_FRAG_BIT)
++#define ETH_TX_IP_FRAG (0<<ETH_TX_IP_FRAG_BIT)
++#define ETH_TX_IP_NO_FRAG (1<<ETH_TX_IP_FRAG_BIT)
++
++#define ETH_TX_IP_HEADER_LEN_OFFSET 11
++#define ETH_TX_IP_HEADER_LEN_ALL_MASK (0xF<<ETH_TX_IP_HEADER_LEN_OFFSET)
++#define ETH_TX_IP_HEADER_LEN_MASK(len) ((len)<<ETH_TX_IP_HEADER_LEN_OFFSET)
++
++#define ETH_TX_VLAN_TAGGED_FRAME_BIT 15
++#define ETH_TX_VLAN_TAGGED_FRAME_MASK (1<<ETH_TX_VLAN_TAGGED_FRAME_BIT)
++
++#define ETH_TX_L4_TYPE_BIT 16
++#define ETH_TX_L4_TCP_TYPE (0<<ETH_TX_L4_TYPE_BIT)
++#define ETH_TX_L4_UDP_TYPE (1<<ETH_TX_L4_TYPE_BIT)
++
++#define ETH_TX_GENERATE_L4_CHKSUM_BIT 17
++#define ETH_TX_GENERATE_L4_CHKSUM_MASK (1<<ETH_TX_GENERATE_L4_CHKSUM_BIT)
++
++#define ETH_TX_GENERATE_IP_CHKSUM_BIT 18
++#define ETH_TX_GENERATE_IP_CHKSUM_MASK (1<<ETH_TX_GENERATE_IP_CHKSUM_BIT)
++
++#define ETH_TX_ZERO_PADDING_BIT 19
++#define ETH_TX_ZERO_PADDING_MASK (1<<ETH_TX_ZERO_PADDING_BIT)
++
++#define ETH_TX_LAST_DESC_BIT 20
++#define ETH_TX_LAST_DESC_MASK (1<<ETH_TX_LAST_DESC_BIT)
++
++#define ETH_TX_FIRST_DESC_BIT 21
++#define ETH_TX_FIRST_DESC_MASK (1<<ETH_TX_FIRST_DESC_BIT)
++
++#define ETH_TX_GENERATE_CRC_BIT 22
++#define ETH_TX_GENERATE_CRC_MASK (1<<ETH_TX_GENERATE_CRC_BIT)
++
++#define ETH_TX_ENABLE_INTERRUPT_BIT 23
++#define ETH_TX_ENABLE_INTERRUPT_MASK (1<<ETH_TX_ENABLE_INTERRUPT_BIT)
++
++#define ETH_TX_AUTO_MODE_BIT 30
++#define ETH_TX_AUTO_MODE_MASK (1<<ETH_TX_AUTO_MODE_BIT)
++
++
++/* Rx descriptor bits */
++#define ETH_RX_ERROR_CODE_OFFSET 1
++#define ETH_RX_ERROR_CODE_MASK (3<<ETH_RX_ERROR_CODE_OFFSET)
++#define ETH_RX_CRC_ERROR (0<<ETH_RX_ERROR_CODE_OFFSET)
++#define ETH_RX_OVERRUN_ERROR (1<<ETH_RX_ERROR_CODE_OFFSET)
++#define ETH_RX_MAX_FRAME_LEN_ERROR (2<<ETH_RX_ERROR_CODE_OFFSET)
++#define ETH_RX_RESOURCE_ERROR (3<<ETH_RX_ERROR_CODE_OFFSET)
++
++#define ETH_RX_L4_CHECKSUM_OFFSET 3
++#define ETH_RX_L4_CHECKSUM_MASK (0xffff<<ETH_RX_L4_CHECKSUM_OFFSET)
++
++#define ETH_RX_VLAN_TAGGED_FRAME_BIT 19
++#define ETH_RX_VLAN_TAGGED_FRAME_MASK (1<<ETH_RX_VLAN_TAGGED_FRAME_BIT)
++
++#define ETH_RX_BPDU_FRAME_BIT 20
++#define ETH_RX_BPDU_FRAME_MASK (1<<ETH_RX_BPDU_FRAME_BIT)
++
++#define ETH_RX_L4_TYPE_OFFSET 21
++#define ETH_RX_L4_TYPE_MASK (3<<ETH_RX_L4_TYPE_OFFSET)
++#define ETH_RX_L4_TCP_TYPE (0<<ETH_RX_L4_TYPE_OFFSET)
++#define ETH_RX_L4_UDP_TYPE (1<<ETH_RX_L4_TYPE_OFFSET)
++#define ETH_RX_L4_OTHER_TYPE (2<<ETH_RX_L4_TYPE_OFFSET)
++
++#define ETH_RX_NOT_LLC_SNAP_FORMAT_BIT 23
++#define ETH_RX_NOT_LLC_SNAP_FORMAT_MASK (1<<ETH_RX_NOT_LLC_SNAP_FORMAT_BIT)
++
++#define ETH_RX_IP_FRAME_TYPE_BIT 24
++#define ETH_RX_IP_FRAME_TYPE_MASK (1<<ETH_RX_IP_FRAME_TYPE_BIT)
++
++#define ETH_RX_IP_HEADER_OK_BIT 25
++#define ETH_RX_IP_HEADER_OK_MASK (1<<ETH_RX_IP_HEADER_OK_BIT)
++
++#define ETH_RX_LAST_DESC_BIT 26
++#define ETH_RX_LAST_DESC_MASK (1<<ETH_RX_LAST_DESC_BIT)
++
++#define ETH_RX_FIRST_DESC_BIT 27
++#define ETH_RX_FIRST_DESC_MASK (1<<ETH_RX_FIRST_DESC_BIT)
++
++#define ETH_RX_UNKNOWN_DA_BIT 28
++#define ETH_RX_UNKNOWN_DA_MASK (1<<ETH_RX_UNKNOWN_DA_BIT)
++
++#define ETH_RX_ENABLE_INTERRUPT_BIT 29
++#define ETH_RX_ENABLE_INTERRUPT_MASK (1<<ETH_RX_ENABLE_INTERRUPT_BIT)
++
++#define ETH_RX_L4_CHECKSUM_OK_BIT 30
++#define ETH_RX_L4_CHECKSUM_OK_MASK (1<<ETH_RX_L4_CHECKSUM_OK_BIT)
++
++/* Rx descriptor bufSize field */
++#define ETH_RX_IP_FRAGMENTED_FRAME_BIT 2
++#define ETH_RX_IP_FRAGMENTED_FRAME_MASK (1<<ETH_RX_IP_FRAGMENTED_FRAME_BIT)
++
++#define ETH_RX_BUFFER_MASK 0xFFF8
++
++
++/* Ethernet Cause Register BITs */
++#define ETH_CAUSE_RX_READY_SUM_BIT 0
++#define ETH_CAUSE_EXTEND_BIT 1
++
++#define ETH_CAUSE_RX_READY_OFFSET 2
++#define ETH_CAUSE_RX_READY_BIT(queue) (ETH_CAUSE_RX_READY_OFFSET + (queue))
++#define ETH_CAUSE_RX_READY_MASK(queue) (1 << (ETH_CAUSE_RX_READY_BIT(queue)))
++
++#define ETH_CAUSE_RX_ERROR_SUM_BIT 10
++#define ETH_CAUSE_RX_ERROR_OFFSET 11
++#define ETH_CAUSE_RX_ERROR_BIT(queue) (ETH_CAUSE_RX_ERROR_OFFSET + (queue))
++#define ETH_CAUSE_RX_ERROR_MASK(queue) (1 << (ETH_CAUSE_RX_ERROR_BIT(queue)))
++
++#define ETH_CAUSE_TX_END_BIT 19
++#define ETH_CAUSE_SUM_BIT 31
++
++/* Ethernet Cause Extended Register BITs */
++#define ETH_CAUSE_TX_BUF_OFFSET 0
++#define ETH_CAUSE_TX_BUF_BIT(queue) (ETH_CAUSE_TX_BUF_OFFSET + (queue))
++#define ETH_CAUSE_TX_BUF_MASK(queue) (1 << (ETH_CAUSE_TX_BUF_BIT(queue)))
++
++#define ETH_CAUSE_TX_ERROR_OFFSET 8
++#define ETH_CAUSE_TX_ERROR_BIT(queue) (ETH_CAUSE_TX_ERROR_OFFSET + (queue))
++#define ETH_CAUSE_TX_ERROR_MASK(queue) (1 << (ETH_CAUSE_TX_ERROR_BIT(queue)))
++
++#define ETH_CAUSE_PHY_STATUS_CHANGE_BIT 16
++#define ETH_CAUSE_RX_OVERRUN_BIT 18
++#define ETH_CAUSE_TX_UNDERRUN_BIT 19
++#define ETH_CAUSE_LINK_STATE_CHANGE_BIT 20
++#define ETH_CAUSE_INTERNAL_ADDR_ERR_BIT 23
++#define ETH_CAUSE_EXTEND_SUM_BIT 31
++
++/* Marvell Header Register */
++/* Marvell Header register bits */
++#define ETH_MVHDR_EN_BIT 0
++#define ETH_MVHDR_EN_MASK (1 << ETH_MVHDR_EN_BIT)
++
++#define ETH_MVHDR_DAPREFIX_BIT 1
++#define ETH_MVHDR_DAPREFIX_MASK (0x3 << ETH_MVHDR_DAPREFIX_BIT)
++#define ETH_MVHDR_DAPREFIX_PRI_1_2 (0x1 << ETH_MVHDR_DAPREFIX_BIT)
++#define ETH_MVHDR_DAPREFIX_DBNUM_PRI (0x2 << ETH_MVHDR_DAPREFIX_BIT)
++#define ETH_MVHDR_DAPREFIX_SPID_PRI (0x3 << ETH_MVHDR_DAPREFIX_BIT)
++
++#define ETH_MVHDR_MHMASK_BIT 8
++#define ETH_MVHDR_MHMASK_MASK (0x3 << ETH_MVHDR_MHMASK_BIT)
++#define ETH_MVHDR_MHMASK_8_QUEUE (0x0 << ETH_MVHDR_MHMASK_BIT)
++#define ETH_MVHDR_MHMASK_4_QUEUE (0x1 << ETH_MVHDR_MHMASK_BIT)
++#define ETH_MVHDR_MHMASK_2_QUEUE (0x3 << ETH_MVHDR_MHMASK_BIT)
++
++
++/* Relevant for 6183 ONLY */
++#define ETH_UNIT_PORTS_PADS_CALIB_0_REG (MV_ETH_REG_BASE(0) + 0x0A0)
++#define ETH_UNIT_PORTS_PADS_CALIB_1_REG (MV_ETH_REG_BASE(0) + 0x0A4)
++#define ETH_UNIT_PORTS_PADS_CALIB_2_REG (MV_ETH_REG_BASE(0) + 0x0A8)
++/* Ethernet Unit Ports Pads Calibration_REG (ETH_UNIT_PORTS_PADS_CALIB_x_REG) */
++#define ETH_ETHERNET_PAD_CLIB_DRVN_OFFS 0
++#define ETH_ETHERNET_PAD_CLIB_DRVN_MASK (0x1F << ETH_ETHERNET_PAD_CLIB_DRVN_OFFS)
++
++#define ETH_ETHERNET_PAD_CLIB_DRVP_OFFS 5
++#define ETH_ETHERNET_PAD_CLIB_DRVP_MASK (0x1F << ETH_ETHERNET_PAD_CLIB_DRVP_OFFS)
++
++#define ETH_ETHERNET_PAD_CLIB_TUNEEN_OFFS 16
++#define ETH_ETHERNET_PAD_CLIB_TUNEEN_MASK (0x1 << ETH_ETHERNET_PAD_CLIB_TUNEEN_OFFS)
++
++#define ETH_ETHERNET_PAD_CLIB_LOCKN_OFFS 17
++#define ETH_ETHERNET_PAD_CLIB_LOCKN_MASK (0x1F << ETH_ETHERNET_PAD_CLIB_LOCKN_OFFS)
++
++#define ETH_ETHERNET_PAD_CLIB_OFFST_OFFS 24
++#define ETH_ETHERNET_PAD_CLIB_OFFST_MASK (0x1F << ETH_ETHERNET_PAD_CLIB_OFFST_OFFS)
++
++#define ETH_ETHERNET_PAD_CLIB_WR_EN_OFFS 31
++#define ETH_ETHERNET_PAD_CLIB_WR_EN_MASK (0x1 << ETH_ETHERNET_PAD_CLIB_WR_EN_OFFS)
++
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __INCmvEthRegsh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/mvEth.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/mvEth.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/eth/mvEth.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/eth/mvEth.h 2010-11-09 20:28:11.222495438 +0100
+@@ -0,0 +1,356 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++/*******************************************************************************
++* mvEth.h - Header File for : Ethernet Controller
++*
++* DESCRIPTION:
++* This header file contains macros typedefs and function declaration for
++* Marvell Gigabit Ethernet Controllers.
++*
++* DEPENDENCIES:
++* None.
++*
++*******************************************************************************/
++
++#ifndef __mvEth_h__
++#define __mvEth_h__
++
++/* includes */
++#include "mvTypes.h"
++#include "mv802_3.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/mvCtrlEnvAddrDec.h"
++#include "eth/gbe/mvEthRegs.h"
++#include "mvSysHwConfig.h"
++
++/* defines */
++
++#define MV_ETH_EXTRA_FRAGS_NUM 2
++
++
++typedef enum
++{
++ MV_ETH_SPEED_AN,
++ MV_ETH_SPEED_10,
++ MV_ETH_SPEED_100,
++ MV_ETH_SPEED_1000
++
++} MV_ETH_PORT_SPEED;
++
++typedef enum
++{
++ MV_ETH_DUPLEX_AN,
++ MV_ETH_DUPLEX_HALF,
++ MV_ETH_DUPLEX_FULL
++
++} MV_ETH_PORT_DUPLEX;
++
++typedef enum
++{
++ MV_ETH_FC_AN_ADV_DIS,
++ MV_ETH_FC_AN_ADV_SYM,
++ MV_ETH_FC_DISABLE,
++ MV_ETH_FC_ENABLE
++
++} MV_ETH_PORT_FC;
++
++typedef enum
++{
++ MV_ETH_PRIO_FIXED = 0, /* Fixed priority mode */
++ MV_ETH_PRIO_WRR = 1 /* Weighted round robin priority mode */
++} MV_ETH_PRIO_MODE;
++
++/* Ethernet port specific infomation */
++typedef struct
++{
++ int maxRxPktSize;
++ int rxDefQ;
++ int rxBpduQ;
++ int rxArpQ;
++ int rxTcpQ;
++ int rxUdpQ;
++ int ejpMode;
++} MV_ETH_PORT_CFG;
++
++typedef struct
++{
++ int descrNum;
++} MV_ETH_RX_Q_CFG;
++
++typedef struct
++{
++ int descrNum;
++ MV_ETH_PRIO_MODE prioMode;
++ int quota;
++} MV_ETH_TX_Q_CFG;
++
++typedef struct
++{
++ int maxRxPktSize;
++ int rxDefQ;
++ int txDescrNum[MV_ETH_TX_Q_NUM];
++ int rxDescrNum[MV_ETH_RX_Q_NUM];
++ void *osHandle;
++} MV_ETH_PORT_INIT;
++
++typedef struct
++{
++ MV_BOOL isLinkUp;
++ MV_ETH_PORT_SPEED speed;
++ MV_ETH_PORT_DUPLEX duplex;
++ MV_ETH_PORT_FC flowControl;
++
++} MV_ETH_PORT_STATUS;
++
++typedef enum
++{
++ MV_ETH_DISABLE_HEADER_MODE = 0,
++ MV_ETH_ENABLE_HEADER_MODE_PRI_2_1 = 1,
++ MV_ETH_ENABLE_HEADER_MODE_PRI_DBNUM = 2,
++ MV_ETH_ENABLE_HEADER_MODE_PRI_SPID = 3
++} MV_ETH_HEADER_MODE;
++
++
++/* ethernet.h API list */
++void mvEthHalInit(void);
++void mvEthMemAttrGet(MV_BOOL* pIsSram, MV_BOOL* pIsSwCoher);
++
++/* Port Initalization routines */
++void* mvEthPortInit (int port, MV_ETH_PORT_INIT *pPortInit);
++void ethResetTxDescRing(void* pPortHndl, int queue);
++void ethResetRxDescRing(void* pPortHndl, int queue);
++
++void* mvEthPortHndlGet(int port);
++
++void mvEthPortFinish(void* pEthPortHndl);
++MV_STATUS mvEthPortDown(void* pEthPortHndl);
++MV_STATUS mvEthPortDisable(void* pEthPortHndl);
++MV_STATUS mvEthPortUp(void* pEthPortHndl);
++MV_STATUS mvEthPortEnable(void* pEthPortHndl);
++
++/* Port data flow routines */
++MV_PKT_INFO *mvEthPortForceTxDone(void* pEthPortHndl, int txQueue);
++MV_PKT_INFO *mvEthPortForceRx(void* pEthPortHndl, int rxQueue);
++
++/* Port Configuration routines */
++MV_STATUS mvEthDefaultsSet(void* pEthPortHndl);
++MV_STATUS mvEthMaxRxSizeSet(void* pPortHndl, int maxRxSize);
++
++/* Port RX MAC Filtering control routines */
++MV_U8 mvEthMcastCrc8Get(MV_U8* pAddr);
++MV_STATUS mvEthRxFilterModeSet(void* pPortHndl, MV_BOOL isPromisc);
++MV_STATUS mvEthMacAddrSet(void* pPortHandle, MV_U8* pMacAddr, int queue);
++MV_STATUS mvEthMcastAddrSet(void* pPortHandle, MV_U8 *pAddr, int queue);
++
++/* MIB Counters APIs */
++MV_U32 mvEthMibCounterRead(void* pPortHndl, unsigned int mibOffset,
++ MV_U32* pHigh32);
++void mvEthMibCountersClear(void* pPortHandle);
++
++/* TX Scheduling configuration routines */
++MV_STATUS mvEthTxQueueConfig(void* pPortHandle, int txQueue,
++ MV_ETH_PRIO_MODE txPrioMode, int txQuota);
++
++/* RX Dispatching configuration routines */
++MV_STATUS mvEthBpduRxQueue(void* pPortHandle, int bpduQueue);
++MV_STATUS mvEthVlanPrioRxQueue(void* pPortHandle, int vlanPrio, int vlanPrioQueue);
++MV_STATUS mvEthTosToRxqSet(void* pPortHandle, int tos, int rxq);
++int mvEthTosToRxqGet(void* pPortHandle, int tos);
++
++/* Speed, Duplex, FlowControl routines */
++MV_STATUS mvEthSpeedDuplexSet(void* pPortHandle, MV_ETH_PORT_SPEED speed,
++ MV_ETH_PORT_DUPLEX duplex);
++
++MV_STATUS mvEthFlowCtrlSet(void* pPortHandle, MV_ETH_PORT_FC flowControl);
++
++#if (MV_ETH_VERSION >= 4)
++MV_STATUS mvEthEjpModeSet(void* pPortHandle, int mode);
++#endif /* (MV_ETH_VERSION >= 4) */
++
++void mvEthStatusGet(void* pPortHandle, MV_ETH_PORT_STATUS* pStatus);
++
++/* Marvell Header control */
++MV_STATUS mvEthHeaderModeSet(void* pPortHandle, MV_ETH_HEADER_MODE headerMode);
++
++/* PHY routines */
++void mvEthPhyAddrSet(void* pPortHandle, int phyAddr);
++int mvEthPhyAddrGet(void* pPortHandle);
++
++/* Power management routines */
++void mvEthPortPowerDown(int port);
++void mvEthPortPowerUp(int port);
++
++/******************** ETH PRIVATE ************************/
++
++/*#define UNCACHED_TX_BUFFERS*/
++/*#define UNCACHED_RX_BUFFERS*/
++
++
++/* Port attributes */
++/* Size of a Tx/Rx descriptor used in chain list data structure */
++#define ETH_RX_DESC_ALIGNED_SIZE 32
++#define ETH_TX_DESC_ALIGNED_SIZE 32
++
++#define TX_DISABLE_TIMEOUT_MSEC 1000
++#define RX_DISABLE_TIMEOUT_MSEC 1000
++#define TX_FIFO_EMPTY_TIMEOUT_MSEC 10000
++#define PORT_DISABLE_WAIT_TCLOCKS 5000
++
++/* Macros that save access to desc in order to find next desc pointer */
++#define RX_NEXT_DESC_PTR(pRxDescr, pQueueCtrl) \
++ ((pRxDescr) == (pQueueCtrl)->pLastDescr) ? \
++ (ETH_RX_DESC*)((pQueueCtrl)->pFirstDescr) : \
++ (ETH_RX_DESC*)(((MV_ULONG)(pRxDescr)) + ETH_RX_DESC_ALIGNED_SIZE)
++
++#define TX_NEXT_DESC_PTR(pTxDescr, pQueueCtrl) \
++ ((pTxDescr) == (pQueueCtrl)->pLastDescr) ? \
++ (ETH_TX_DESC*)((pQueueCtrl)->pFirstDescr) : \
++ (ETH_TX_DESC*)(((MV_ULONG)(pTxDescr)) + ETH_TX_DESC_ALIGNED_SIZE)
++
++#define RX_PREV_DESC_PTR(pRxDescr, pQueueCtrl) \
++ ((pRxDescr) == (pQueueCtrl)->pFirstDescr) ? \
++ (ETH_RX_DESC*)((pQueueCtrl)->pLastDescr) : \
++ (ETH_RX_DESC*)(((MV_ULONG)(pRxDescr)) - ETH_RX_DESC_ALIGNED_SIZE)
++
++#define TX_PREV_DESC_PTR(pTxDescr, pQueueCtrl) \
++ ((pTxDescr) == (pQueueCtrl)->pFirstDescr) ? \
++ (ETH_TX_DESC*)((pQueueCtrl)->pLastDescr) : \
++ (ETH_TX_DESC*)(((MV_ULONG)(pTxDescr)) - ETH_TX_DESC_ALIGNED_SIZE)
++
++
++/* Queue specific information */
++typedef struct
++{
++ void* pFirstDescr;
++ void* pLastDescr;
++ void* pCurrentDescr;
++ void* pUsedDescr;
++ int resource;
++ MV_BUF_INFO descBuf;
++} ETH_QUEUE_CTRL;
++
++
++/* Ethernet port specific infomation */
++typedef struct _ethPortCtrl
++{
++ int portNo;
++ ETH_QUEUE_CTRL rxQueue[MV_ETH_RX_Q_NUM]; /* Rx ring resource */
++ ETH_QUEUE_CTRL txQueue[MV_ETH_TX_Q_NUM]; /* Tx ring resource */
++
++ MV_ETH_PORT_CFG portConfig;
++ MV_ETH_RX_Q_CFG rxQueueConfig[MV_ETH_RX_Q_NUM];
++ MV_ETH_TX_Q_CFG txQueueConfig[MV_ETH_TX_Q_NUM];
++
++ /* Register images - For DP */
++ MV_U32 portTxQueueCmdReg; /* Port active Tx queues summary */
++ MV_U32 portRxQueueCmdReg; /* Port active Rx queues summary */
++
++ MV_STATE portState;
++
++ MV_U8 mcastCount[256];
++ MV_U32* hashPtr;
++ void *osHandle;
++} ETH_PORT_CTRL;
++
++/************** MACROs ****************/
++
++/* MACROs to Flush / Invalidate TX / RX Buffers */
++#if (ETHER_DRAM_COHER == MV_CACHE_COHER_SW) && !defined(UNCACHED_TX_BUFFERS)
++# define ETH_PACKET_CACHE_FLUSH(pAddr, size) \
++ mvOsCacheClear(NULL, (pAddr), (size)); \
++ /*CPU_PIPE_FLUSH;*/
++#else
++# define ETH_PACKET_CACHE_FLUSH(pAddr, size) \
++ mvOsIoVirtToPhy(NULL, (pAddr));
++#endif /* ETHER_DRAM_COHER == MV_CACHE_COHER_SW */
++
++#if ( (ETHER_DRAM_COHER == MV_CACHE_COHER_SW) && !defined(UNCACHED_RX_BUFFERS) )
++# define ETH_PACKET_CACHE_INVALIDATE(pAddr, size) \
++ mvOsCacheInvalidate (NULL, (pAddr), (size)); \
++ /*CPU_PIPE_FLUSH;*/
++#else
++# define ETH_PACKET_CACHE_INVALIDATE(pAddr, size)
++#endif /* ETHER_DRAM_COHER == MV_CACHE_COHER_SW && !UNCACHED_RX_BUFFERS */
++
++#ifdef ETH_DESCR_UNCACHED
++
++#define ETH_DESCR_FLUSH_INV(pPortCtrl, pDescr)
++#define ETH_DESCR_INV(pPortCtrl, pDescr)
++
++#else
++
++#define ETH_DESCR_FLUSH_INV(pPortCtrl, pDescr) \
++ mvOsCacheLineFlushInv(pPortCtrl->osHandle, (MV_ULONG)(pDescr))
++
++#define ETH_DESCR_INV(pPortCtrl, pDescr) \
++ mvOsCacheLineInv(pPortCtrl->osHandle, (MV_ULONG)(pDescr))
++
++#endif /* ETH_DESCR_UNCACHED */
++
++#include "eth/gbe/mvEthGbe.h"
++
++#endif /* __mvEth_h__ */
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.c 2010-11-09 20:28:11.262495582 +0100
+@@ -0,0 +1,362 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "gpp/mvGpp.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++static MV_VOID gppRegSet(MV_U32 group, MV_U32 regOffs,MV_U32 mask,MV_U32 value);
++
++/*******************************************************************************
++* mvGppTypeSet - Enable a GPP (OUT) pin
++*
++* DESCRIPTION:
++*
++* INPUT:
++* group - GPP group number
++* mask - 32bit mask value. Each set bit in the mask means that the type
++* of corresponding GPP will be set. Other GPPs are ignored.
++* value - 32bit value that describes GPP type per pin.
++*
++* OUTPUT:
++* None.
++*
++* EXAMPLE:
++* Set GPP8 to input and GPP15 to output.
++* mvGppTypeSet(0, (GPP8 | GPP15),
++* ((MV_GPP_IN & GPP8) | (MV_GPP_OUT & GPP15)) );
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvGppTypeSet(MV_U32 group, MV_U32 mask, MV_U32 value)
++{
++ if (group >= MV_GPP_MAX_GROUP)
++ {
++ DB(mvOsPrintf("mvGppTypeSet: ERR. invalid group number \n"));
++ return MV_BAD_PARAM;
++ }
++
++ gppRegSet(group, GPP_DATA_OUT_EN_REG(group), mask, value);
++
++ /* Workaround for Erratum FE-MISC-70*/
++ if(mvCtrlRevGet()==MV_88F6XXX_A0_REV && (group == 1))
++ {
++ mask &= 0x2;
++ gppRegSet(0, GPP_DATA_OUT_EN_REG(0), mask, value);
++ } /*End of WA*/
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvGppBlinkEn - Set a GPP (IN) Pin list to blink every ~100ms
++*
++* DESCRIPTION:
++*
++* INPUT:
++* group - GPP group number
++* mask - 32bit mask value. Each set bit in the mask means that the type
++* of corresponding GPP will be set. Other GPPs are ignored.
++* value - 32bit value that describes GPP blink per pin.
++*
++* OUTPUT:
++* None.
++*
++* EXAMPLE:
++* Set GPP8 to be static and GPP15 to be blinking.
++* mvGppBlinkEn(0, (GPP8 | GPP15),
++* ((MV_GPP_OUT_STATIC & GPP8) | (MV_GPP_OUT_BLINK & GPP15)) );
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvGppBlinkEn(MV_U32 group, MV_U32 mask, MV_U32 value)
++{
++ if (group >= MV_GPP_MAX_GROUP)
++ {
++ DB(mvOsPrintf("mvGppBlinkEn: ERR. invalid group number \n"));
++ return MV_BAD_PARAM;
++ }
++
++ gppRegSet(group, GPP_BLINK_EN_REG(group), mask, value);
++
++ return MV_OK;
++
++}
++/*******************************************************************************
++* mvGppPolaritySet - Set a GPP (IN) Pin list Polarity mode
++*
++* DESCRIPTION:
++*
++* INPUT:
++* group - GPP group number
++* mask - 32bit mask value. Each set bit in the mask means that the type
++* of corresponding GPP will be set. Other GPPs are ignored.
++* value - 32bit value that describes GPP polarity per pin.
++*
++* OUTPUT:
++* None.
++*
++* EXAMPLE:
++* Set GPP8 to the actual pin value and GPP15 to be inverted.
++* mvGppPolaritySet(0, (GPP8 | GPP15),
++* ((MV_GPP_IN_ORIGIN & GPP8) | (MV_GPP_IN_INVERT & GPP15)) );
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvGppPolaritySet(MV_U32 group, MV_U32 mask, MV_U32 value)
++{
++ if (group >= MV_GPP_MAX_GROUP)
++ {
++ DB(mvOsPrintf("mvGppPolaritySet: ERR. invalid group number \n"));
++ return MV_BAD_PARAM;
++ }
++
++ gppRegSet(group, GPP_DATA_IN_POL_REG(group), mask, value);
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvGppPolarityGet - Get a value of relevant bits from GPP Polarity register.
++*
++* DESCRIPTION:
++*
++* INPUT:
++* group - GPP group number
++* mask - 32bit mask value. Each set bit in the mask means that the
++* returned value is valid for it.
++*
++* OUTPUT:
++* None.
++*
++* EXAMPLE:
++* Get GPP8 and GPP15 value.
++* mvGppPolarityGet(0, (GPP8 | GPP15));
++*
++* RETURN:
++* 32bit value that describes GPP polatity mode per pin.
++*
++*******************************************************************************/
++MV_U32 mvGppPolarityGet(MV_U32 group, MV_U32 mask)
++{
++ MV_U32 regVal;
++
++ if (group >= MV_GPP_MAX_GROUP)
++ {
++ DB(mvOsPrintf("mvGppActiveSet: Error invalid group number \n"));
++ return MV_ERROR;
++ }
++ regVal = MV_REG_READ(GPP_DATA_IN_POL_REG(group));
++
++ return (regVal & mask);
++}
++
++/*******************************************************************************
++* mvGppValueGet - Get a GPP Pin list value.
++*
++* DESCRIPTION:
++* This function get GPP value.
++*
++* INPUT:
++* group - GPP group number
++* mask - 32bit mask value. Each set bit in the mask means that the
++* returned value is valid for it.
++*
++* OUTPUT:
++* None.
++*
++* EXAMPLE:
++* Get GPP8 and GPP15 value.
++* mvGppValueGet(0, (GPP8 | GPP15));
++*
++* RETURN:
++* 32bit value that describes GPP activity mode per pin.
++*
++*******************************************************************************/
++MV_U32 mvGppValueGet(MV_U32 group, MV_U32 mask)
++{
++ MV_U32 gppData;
++
++ gppData = MV_REG_READ(GPP_DATA_IN_REG(group));
++
++ gppData &= mask;
++
++ return gppData;
++
++}
++
++/*******************************************************************************
++* mvGppValueSet - Set a GPP Pin list value.
++*
++* DESCRIPTION:
++* This function set value for given GPP pin list.
++*
++* INPUT:
++* group - GPP group number
++* mask - 32bit mask value. Each set bit in the mask means that the
++* value of corresponding GPP will be set accordingly. Other GPP
++* are not affected.
++* value - 32bit value that describes GPP value per pin.
++*
++* OUTPUT:
++* None.
++*
++* EXAMPLE:
++* Set GPP8 value of '0' and GPP15 value of '1'.
++* mvGppActiveSet(0, (GPP8 | GPP15), ((0 & GPP8) | (GPP15)) );
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvGppValueSet (MV_U32 group, MV_U32 mask, MV_U32 value)
++{
++ MV_U32 outEnable, tmp;
++ MV_U32 i;
++
++ if (group >= MV_GPP_MAX_GROUP)
++ {
++ DB(mvOsPrintf("mvGppValueSet: Error invalid group number \n"));
++ return MV_BAD_PARAM;
++ }
++
++ /* verify that the gpp pin is configured as output */
++ /* Note that in the register out enabled -> bit = '0'. */
++ outEnable = ~MV_REG_READ(GPP_DATA_OUT_EN_REG(group));
++
++ /* Workaround for Erratum FE-MISC-70*/
++ if(mvCtrlRevGet()==MV_88F6XXX_A0_REV && (group == 1))
++ {
++ tmp = ~MV_REG_READ(GPP_DATA_OUT_EN_REG(0));
++ outEnable &= 0xfffffffd;
++ outEnable |= (tmp & 0x2);
++ } /*End of WA*/
++
++ for (i = 0 ; i < 32 ;i++)
++ {
++ if (((mask & (1 << i)) & (outEnable & (1 << i))) != (mask & (1 << i)))
++ {
++ mvOsPrintf("mvGppValueSet: Err. An attempt to set output "\
++ "value to GPP %d in input mode.\n", i);
++ return MV_ERROR;
++ }
++ }
++
++ gppRegSet(group, GPP_DATA_OUT_REG(group), mask, value);
++
++ return MV_OK;
++
++}
++/*******************************************************************************
++* gppRegSet - Set a specific GPP pin on a specific GPP register
++*
++* DESCRIPTION:
++* This function set a specific GPP pin on a specific GPP register
++*
++* INPUT:
++* regOffs - GPP Register offset
++* group - GPP group number
++* mask - 32bit mask value. Each set bit in the mask means that the
++* value of corresponding GPP will be set accordingly. Other GPP
++* are not affected.
++* value - 32bit value that describes GPP value per pin.
++*
++* OUTPUT:
++* None.
++*
++* EXAMPLE:
++* Set GPP8 value of '0' and GPP15 value of '1'.
++* mvGppActiveSet(0, (GPP8 | GPP15), ((0 & GPP8) | (1 & GPP15)) );
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++static MV_VOID gppRegSet (MV_U32 group, MV_U32 regOffs,MV_U32 mask,MV_U32 value)
++{
++ MV_U32 gppData;
++
++ gppData = MV_REG_READ(regOffs);
++
++ gppData &= ~mask;
++
++ gppData |= (value & mask);
++
++ MV_REG_WRITE(regOffs, gppData);
++}
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.h 2010-11-09 20:28:11.302495429 +0100
+@@ -0,0 +1,118 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvGppH
++#define __INCmvGppH
++
++#include "mvCommon.h"
++#include "mvOs.h"
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++#include "gpp/mvGppRegs.h"
++
++/* These macros describes the GPP type. Each of the GPPs pins can */
++/* be assigned to act as a general purpose input or output pin. */
++#define MV_GPP_IN 0xFFFFFFFF /* GPP input */
++#define MV_GPP_OUT 0 /* GPP output */
++
++
++/* These macros describes the GPP Out Enable. */
++#define MV_GPP_OUT_DIS 0xFFFFFFFF /* Out pin disabled*/
++#define MV_GPP_OUT_EN 0 /* Out pin enabled*/
++
++/* These macros describes the GPP Out Blinking. */
++/* When set and the corresponding bit in GPIO Data Out Enable Control */
++/* Register is enabled, the GPIO pin blinks every ~100 ms (a period of */
++/* 2^24 TCLK clocks). */
++#define MV_GPP_OUT_BLINK 0xFFFFFFFF /* Out pin blinking*/
++#define MV_GPP_OUT_STATIC 0 /* Out pin static*/
++
++
++/* These macros describes the GPP Polarity. */
++/* When set to 1 GPIO Data In Register reflects the inverted value of the */
++/* corresponding pin. */
++
++#define MV_GPP_IN_INVERT 0xFFFFFFFF /* Inverted value is got*/
++#define MV_GPP_IN_ORIGIN 0 /* original value is got*/
++
++/* mvGppTypeSet - Set PP pin mode (IN or OUT) */
++MV_STATUS mvGppTypeSet(MV_U32 group, MV_U32 mask, MV_U32 value);
++
++/* mvGppBlinkEn - Set a GPP (IN) Pin list to blink every ~100ms */
++MV_STATUS mvGppBlinkEn(MV_U32 group, MV_U32 mask, MV_U32 value);
++
++/* mvGppPolaritySet - Set a GPP (IN) Pin list Polarity mode. */
++MV_STATUS mvGppPolaritySet(MV_U32 group, MV_U32 mask, MV_U32 value);
++
++/* mvGppPolarityGet - Get the Polarity of a GPP Pin */
++MV_U32 mvGppPolarityGet(MV_U32 group, MV_U32 mask);
++
++/* mvGppValueGet - Get a GPP Pin list value.*/
++MV_U32 mvGppValueGet(MV_U32 group, MV_U32 mask);
++
++
++/* mvGppValueSet - Set a GPP Pin list value. */
++MV_STATUS mvGppValueSet (MV_U32 group, MV_U32 mask, MV_U32 value);
++
++#endif /* #ifndef __INCmvGppH */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGppRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGppRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGppRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGppRegs.h 2010-11-09 20:28:11.342495467 +0100
+@@ -0,0 +1,116 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvGppRegsH
++#define __INCmvGppRegsH
++
++#define MV_GPP0 BIT0
++#define MV_GPP1 BIT1
++#define MV_GPP2 BIT2
++#define MV_GPP3 BIT3
++#define MV_GPP4 BIT4
++#define MV_GPP5 BIT5
++#define MV_GPP6 BIT6
++#define MV_GPP7 BIT7
++#define MV_GPP8 BIT8
++#define MV_GPP9 BIT9
++#define MV_GPP10 BIT10
++#define MV_GPP11 BIT11
++#define MV_GPP12 BIT12
++#define MV_GPP13 BIT13
++#define MV_GPP14 BIT14
++#define MV_GPP15 BIT15
++#define MV_GPP16 BIT16
++#define MV_GPP17 BIT17
++#define MV_GPP18 BIT18
++#define MV_GPP19 BIT19
++#define MV_GPP20 BIT20
++#define MV_GPP21 BIT21
++#define MV_GPP22 BIT22
++#define MV_GPP23 BIT23
++#define MV_GPP24 BIT24
++#define MV_GPP25 BIT25
++#define MV_GPP26 BIT26
++#define MV_GPP27 BIT27
++#define MV_GPP28 BIT28
++#define MV_GPP29 BIT29
++#define MV_GPP30 BIT30
++#define MV_GPP31 BIT31
++
++
++/* registers offsets */
++
++#define GPP_DATA_OUT_REG(grp) ((grp == 0) ? 0x10100 : 0x10140)
++#define GPP_DATA_OUT_EN_REG(grp) ((grp == 0) ? 0x10104 : 0x10144)
++#define GPP_BLINK_EN_REG(grp) ((grp == 0) ? 0x10108 : 0x10148)
++#define GPP_DATA_IN_POL_REG(grp) ((grp == 0) ? 0x1010C : 0x1014c)
++#define GPP_DATA_IN_REG(grp) ((grp == 0) ? 0x10110 : 0x10150)
++#define GPP_INT_CAUSE_REG(grp) ((grp == 0) ? 0x10114 : 0x10154)
++#define GPP_INT_MASK_REG(grp) ((grp == 0) ? 0x10118 : 0x10158)
++#define GPP_INT_LVL_REG(grp) ((grp == 0) ? 0x1011c : 0x1015c)
++
++#define GPP_DATA_OUT_SET_REG 0x10120
++#define GPP_DATA_OUT_CLEAR_REG 0x10124
++
++#endif /* #ifndef __INCmvGppRegsH */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.c 2010-11-09 20:28:11.372495482 +0100
+@@ -0,0 +1,1047 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "pci/mvPci.h"
++
++#include "ctrlEnv/mvCtrlEnvLib.h"
++
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++
++
++MV_VOID mvPciHalInit(MV_U32 pciIf, MV_PCI_MOD pciIfmod)
++{
++ if (MV_PCI_MOD_HOST == pciIfmod)
++ {
++
++ mvPciLocalBusNumSet(pciIf, PCI_HOST_BUS_NUM(pciIf));
++ mvPciLocalDevNumSet(pciIf, PCI_HOST_DEV_NUM(pciIf));
++
++ /* Local device master Enable */
++ mvPciMasterEnable(pciIf, MV_TRUE);
++
++ /* Local device slave Enable */
++ mvPciSlaveEnable(pciIf, mvPciLocalBusNumGet(pciIf),
++ mvPciLocalDevNumGet(pciIf), MV_TRUE);
++ }
++ /* enable CPU-2-PCI ordering */
++ MV_REG_BIT_SET(PCI_CMD_REG(0), PCR_CPU_TO_PCI_ORDER_EN);
++}
++
++/*******************************************************************************
++* mvPciCommandSet - Set PCI comman register value.
++*
++* DESCRIPTION:
++* This function sets a given PCI interface with its command register
++* value.
++*
++* INPUT:
++* pciIf - PCI interface number.
++* command - 32bit value to be written to comamnd register.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM if pciIf is not in range otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciCommandSet(MV_U32 pciIf, MV_U32 command)
++{
++ MV_U32 locBusNum, locDevNum, regVal;
++
++ locBusNum = mvPciLocalBusNumGet(pciIf);
++ locDevNum = mvPciLocalDevNumGet(pciIf);
++
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciCommandSet: ERR. Invalid PCI IF num %d\n", pciIf);
++ return MV_BAD_PARAM;
++ }
++
++ /* Set command register */
++ MV_REG_WRITE(PCI_CMD_REG(pciIf), command);
++
++ /* Upodate device max outstanding split tarnsaction */
++ if ((command & PCR_CPU_TO_PCI_ORDER_EN) &&
++ (command & PCR_PCI_TO_CPU_ORDER_EN))
++ {
++ /* Read PCI-X command register */
++ regVal = mvPciConfigRead (pciIf, locBusNum, locDevNum, 0, PCIX_COMMAND);
++
++ /* clear bits 22:20 */
++ regVal &= 0xff8fffff;
++
++ /* set reset value */
++ regVal |= (0x3 << 20);
++
++ /* Write back the value */
++ mvPciConfigWrite (pciIf, locBusNum, locDevNum, 0, PCIX_COMMAND, regVal);
++ }
++
++ return MV_OK;
++
++
++}
++
++
++/*******************************************************************************
++* mvPciModeGet - Get PCI interface mode.
++*
++* DESCRIPTION:
++* This function returns the given PCI interface mode.
++*
++* INPUT:
++* pciIf - PCI interface number.
++*
++* OUTPUT:
++* pPciMode - Pointer to PCI mode structure.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciModeGet(MV_U32 pciIf, MV_PCI_MODE *pPciMode)
++{
++ MV_U32 pciMode;
++
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciModeGet: ERR. Invalid PCI interface %d\n", pciIf);
++ return MV_BAD_PARAM;
++ }
++ if (NULL == pPciMode)
++ {
++ mvOsPrintf("mvPciModeGet: ERR. pPciMode = NULL \n");
++ return MV_BAD_PARAM;
++ }
++
++ /* Read pci mode register */
++ pciMode = MV_REG_READ(PCI_MODE_REG(pciIf));
++
++ switch (pciMode & PMR_PCI_MODE_MASK)
++ {
++ case PMR_PCI_MODE_CONV:
++ pPciMode->pciType = MV_PCI_CONV;
++
++ if (MV_REG_READ(PCI_DLL_CTRL_REG(pciIf)) & PDC_DLL_EN)
++ {
++ pPciMode->pciSpeed = 66000000; /* 66MHZ */
++ }
++ else
++ {
++ pPciMode->pciSpeed = 33000000; /* 33MHZ */
++ }
++
++ break;
++
++ case PMR_PCI_MODE_PCIX_66MHZ:
++ pPciMode->pciType = MV_PCIX;
++ pPciMode->pciSpeed = 66000000; /* 66MHZ */
++ break;
++
++ case PMR_PCI_MODE_PCIX_100MHZ:
++ pPciMode->pciType = MV_PCIX;
++ pPciMode->pciSpeed = 100000000; /* 100MHZ */
++ break;
++
++ case PMR_PCI_MODE_PCIX_133MHZ:
++ pPciMode->pciType = MV_PCIX;
++ pPciMode->pciSpeed = 133000000; /* 133MHZ */
++ break;
++
++ default:
++ {
++ mvOsPrintf("mvPciModeGet: ERR. Non existing mode !!\n");
++ return MV_ERROR;
++ }
++ }
++
++ switch (pciMode & PMR_PCI_64_MASK)
++ {
++ case PMR_PCI_64_64BIT:
++ pPciMode->pciWidth = MV_PCI_64;
++ break;
++
++ case PMR_PCI_64_32BIT:
++ pPciMode->pciWidth = MV_PCI_32;
++ break;
++
++ default:
++ {
++ mvOsPrintf("mvPciModeGet: ERR. Non existing mode !!\n");
++ return MV_ERROR;
++ }
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvPciRetrySet - Set PCI retry counters
++*
++* DESCRIPTION:
++* This function specifies the number of times the PCI controller
++* retries a transaction before it quits.
++* Applies to the PCI Master when acting as a requester.
++* Applies to the PCI slave when acting as a completer (PCI-X mode).
++* A 0x00 value means a "retry forever".
++*
++* INPUT:
++* pciIf - PCI interface number.
++* counter - Number of times PCI controller retry. Use counter value
++* up to PRR_RETRY_CNTR_MAX.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciRetrySet(MV_U32 pciIf, MV_U32 counter)
++{
++ MV_U32 pciRetry;
++
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciRetrySet: ERR. Invalid PCI interface %d\n", pciIf);
++ return MV_BAD_PARAM;
++ }
++
++ if (counter >= PRR_RETRY_CNTR_MAX)
++ {
++ mvOsPrintf("mvPciRetrySet: ERR. Invalid counter: %d\n", counter);
++ return MV_BAD_PARAM;
++
++ }
++
++ /* Reading PCI retry register */
++ pciRetry = MV_REG_READ(PCI_RETRY_REG(pciIf));
++
++ pciRetry &= ~PRR_RETRY_CNTR_MASK;
++
++ pciRetry |= (counter << PRR_RETRY_CNTR_OFFS);
++
++ /* write new value */
++ MV_REG_WRITE(PCI_RETRY_REG(pciIf), pciRetry);
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvPciDiscardTimerSet - Set PCI discard timer
++*
++* DESCRIPTION:
++* This function set PCI discard timer.
++* In conventional PCI mode:
++* Specifies the number of PCLK cycles the PCI slave keeps a non-accessed
++* read buffers (non-completed delayed read) before invalidate the buffer.
++* Set to '0' to disable the timer. The PCI slave waits for delayed
++* read completion forever.
++* In PCI-X mode:
++* Specifies the number of PCLK cycles the PCI master waits for split
++* completion transaction, before it invalidates the pre-allocated read
++* buffer.
++* Set to '0' to disable the timer. The PCI master waits for split
++* completion forever.
++* NOTE: Must be set to a number greater than MV_PCI_MAX_DISCARD_CLK,
++* unless using the "wait for ever" setting 0x0.
++* NOTE: Must not be updated while there are pending read requests.
++*
++* INPUT:
++* pciIf - PCI interface number.
++* pClkCycles - Number of PCI clock cycles.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciDiscardTimerSet(MV_U32 pciIf, MV_U32 pClkCycles)
++{
++ MV_U32 pciDiscardTimer;
++
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciDiscardTimerSet: ERR. Invalid PCI interface %d\n",
++ pciIf);
++ return MV_BAD_PARAM;
++ }
++
++ if (pClkCycles >= PDTR_TIMER_MIN)
++ {
++ mvOsPrintf("mvPciDiscardTimerSet: ERR. Invalid Clk value: %d\n",
++ pClkCycles);
++ return MV_BAD_PARAM;
++
++ }
++
++ /* Read PCI Discard Timer */
++ pciDiscardTimer = MV_REG_READ(PCI_DISCARD_TIMER_REG(pciIf));
++
++ pciDiscardTimer &= ~PDTR_TIMER_MASK;
++
++ pciDiscardTimer |= (pClkCycles << PDTR_TIMER_OFFS);
++
++ /* Write new value */
++ MV_REG_WRITE(PCI_DISCARD_TIMER_REG(pciIf), pciDiscardTimer);
++
++ return MV_OK;
++
++}
++
++/* PCI Arbiter routines */
++
++/*******************************************************************************
++* mvPciArbEnable - PCI arbiter enable/disable
++*
++* DESCRIPTION:
++* This fuction enable/disables a given PCI interface arbiter.
++* NOTE: Arbiter setting can not be changed while in work. It should only
++* be set once.
++* INPUT:
++* pciIf - PCI interface number.
++* enable - Enable/disable parameter. If enable = MV_TRUE then enable.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvPciArbEnable(MV_U32 pciIf, MV_BOOL enable)
++{
++ MV_U32 regVal;
++
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciArbEnable: ERR. Invalid PCI interface %d\n", pciIf);
++ return MV_ERROR;
++ }
++
++ /* Set PCI Arbiter Control register according to default configuration */
++ regVal = MV_REG_READ(PCI_ARBITER_CTRL_REG(pciIf));
++
++ /* Make sure arbiter disabled before changing its values */
++ MV_REG_BIT_RESET(PCI_ARBITER_CTRL_REG(pciIf), PACR_ARB_ENABLE);
++
++ regVal &= ~PCI_ARBITER_CTRL_DEFAULT_MASK;
++
++ regVal |= PCI_ARBITER_CTRL_DEFAULT; /* Set default configuration */
++
++ if (MV_TRUE == enable)
++ {
++ regVal |= PACR_ARB_ENABLE;
++ }
++ else
++ {
++ regVal &= ~PACR_ARB_ENABLE;
++ }
++
++ /* Write to register */
++ MV_REG_WRITE(PCI_ARBITER_CTRL_REG(pciIf), regVal);
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvPciArbParkDis - Disable arbiter parking on agent
++*
++* DESCRIPTION:
++* This function disables the PCI arbiter from parking on the given agent
++* list.
++*
++* INPUT:
++* pciIf - PCI interface number.
++* pciAgentMask - When a bit in the mask is set to '1', parking on
++* the associated PCI master is disabled. Mask bit
++* refers to bit 0 - 6. For example disable parking on PCI
++* agent 3 set pciAgentMask 0x4 (bit 3 is set).
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++MV_STATUS mvPciArbParkDis(MV_U32 pciIf, MV_U32 pciAgentMask)
++{
++ MV_U32 pciArbiterCtrl;
++
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciArbParkDis: ERR. Invalid PCI interface %d\n", pciIf);
++ return MV_ERROR;
++ }
++
++ /* Reading Arbiter Control register */
++ pciArbiterCtrl = MV_REG_READ(PCI_ARBITER_CTRL_REG(pciIf));
++
++ /* Arbiter must be disabled before changing parking */
++ MV_REG_BIT_RESET(PCI_ARBITER_CTRL_REG(pciIf), PACR_ARB_ENABLE);
++
++ /* do the change */
++ pciArbiterCtrl &= ~PACR_PARK_DIS_MASK;
++ pciArbiterCtrl |= (pciAgentMask << PACR_PARK_DIS_OFFS);
++
++ /* writing new value ( if th earbiter was enabled before the change */
++ /* here it will be reenabled */
++ MV_REG_WRITE(PCI_ARBITER_CTRL_REG(pciIf), pciArbiterCtrl);
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvPciArbBrokDetectSet - Set PCI arbiter broken detection
++*
++* DESCRIPTION:
++* This function sets the maximum number of cycles that the arbiter
++* waits for a PCI master to respond to its grant assertion. If a
++* PCI agent fails to respond within this time, the PCI arbiter aborts
++* the transaction and performs a new arbitration cycle.
++* NOTE: Value must be greater than '1' for conventional PCI and
++* greater than '5' for PCI-X.
++*
++* INPUT:
++* pciIf - PCI interface number.
++* pClkCycles - Number of PCI clock cycles. If equal to '0' the broken
++* master detection is disabled.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciArbBrokDetectSet(MV_U32 pciIf, MV_U32 pClkCycles)
++{
++ MV_U32 pciArbiterCtrl;
++ MV_U32 pciMode;
++
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciArbBrokDetectSet: ERR. Invalid PCI interface %d\n",
++ pciIf);
++ return MV_BAD_PARAM;
++ }
++
++ /* Checking PCI mode and if pClkCycles is legal value */
++ pciMode = MV_REG_READ(PCI_MODE_REG(pciIf));
++ pciMode &= PMR_PCI_MODE_MASK;
++
++ if (PMR_PCI_MODE_CONV == pciMode)
++ {
++ if (pClkCycles < PACR_BROKEN_VAL_CONV_MIN)
++ return MV_ERROR;
++ }
++ else
++ {
++ if (pClkCycles < PACR_BROKEN_VAL_PCIX_MIN)
++ return MV_ERROR;
++ }
++
++ pClkCycles <<= PACR_BROKEN_VAL_OFFS;
++
++ /* Reading Arbiter Control register */
++ pciArbiterCtrl = MV_REG_READ(PCI_ARBITER_CTRL_REG(pciIf));
++ pciArbiterCtrl &= ~PACR_BROKEN_VAL_MASK;
++ pciArbiterCtrl |= pClkCycles;
++
++ /* Arbiter must be disabled before changing broken detection */
++ MV_REG_BIT_RESET(PCI_ARBITER_CTRL_REG(pciIf), PACR_ARB_ENABLE);
++
++ /* writing new value ( if th earbiter was enabled before the change */
++ /* here it will be reenabled */
++
++ MV_REG_WRITE(PCI_ARBITER_CTRL_REG(pciIf), pciArbiterCtrl);
++
++ return MV_OK;
++}
++
++/* PCI configuration space read write */
++
++/*******************************************************************************
++* mvPciConfigRead - Read from configuration space
++*
++* DESCRIPTION:
++* This function performs a 32 bit read from PCI configuration space.
++* It supports both type 0 and type 1 of Configuration Transactions
++* (local and over bridge). In order to read from local bus segment, use
++* bus number retrieved from mvPciLocalBusNumGet(). Other bus numbers
++* will result configuration transaction of type 1 (over bridge).
++*
++* INPUT:
++* pciIf - PCI interface number.
++* bus - PCI segment bus number.
++* dev - PCI device number.
++* func - Function number.
++* regOffs - Register offset.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit register data, 0xffffffff on error
++*
++*******************************************************************************/
++MV_U32 mvPciConfigRead (MV_U32 pciIf, MV_U32 bus, MV_U32 dev, MV_U32 func,
++ MV_U32 regOff)
++{
++ MV_U32 pciData = 0;
++
++ /* Parameter checking */
++ if (PCI_DEFAULT_IF != pciIf)
++ {
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciConfigRead: ERR. Invalid PCI interface %d\n",pciIf);
++ return 0xFFFFFFFF;
++ }
++ }
++
++ if (dev >= MAX_PCI_DEVICES)
++ {
++ DB(mvOsPrintf("mvPciConfigRead: ERR. device number illigal %d\n", dev));
++ return 0xFFFFFFFF;
++ }
++
++ if (func >= MAX_PCI_FUNCS)
++ {
++ DB(mvOsPrintf("mvPciConfigRead: ERR. function number illigal %d\n", func));
++ return 0xFFFFFFFF;
++ }
++
++ if (bus >= MAX_PCI_BUSSES)
++ {
++ DB(mvOsPrintf("mvPciConfigRead: ERR. bus number illigal %d\n", bus));
++ return MV_ERROR;
++ }
++
++
++ /* Creating PCI address to be passed */
++ pciData |= (bus << PCAR_BUS_NUM_OFFS);
++ pciData |= (dev << PCAR_DEVICE_NUM_OFFS);
++ pciData |= (func << PCAR_FUNC_NUM_OFFS);
++ pciData |= (regOff & PCAR_REG_NUM_MASK);
++
++ pciData |= PCAR_CONFIG_EN;
++
++ /* Write the address to the PCI configuration address register */
++ MV_REG_WRITE(PCI_CONFIG_ADDR_REG(pciIf), pciData);
++
++ /* In order to let the PCI controller absorbed the address of the read */
++ /* transaction we perform a validity check that the address was written */
++ if(pciData != MV_REG_READ(PCI_CONFIG_ADDR_REG(pciIf)))
++ {
++ return MV_ERROR;
++ }
++ /* Read the Data returned in the PCI Data register */
++ pciData = MV_REG_READ(PCI_CONFIG_DATA_REG(pciIf));
++
++ return pciData;
++}
++
++/*******************************************************************************
++* mvPciConfigWrite - Write to configuration space
++*
++* DESCRIPTION:
++* This function performs a 32 bit write to PCI configuration space.
++* It supports both type 0 and type 1 of Configuration Transactions
++* (local and over bridge). In order to write to local bus segment, use
++* bus number retrieved from mvPciLocalBusNumGet(). Other bus numbers
++* will result configuration transaction of type 1 (over bridge).
++*
++* INPUT:
++* pciIf - PCI interface number.
++* bus - PCI segment bus number.
++* dev - PCI device number.
++* func - Function number.
++* regOffs - Register offset.
++* data - 32bit data.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciConfigWrite(MV_U32 pciIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func, MV_U32 regOff, MV_U32 data)
++{
++ MV_U32 pciData = 0;
++
++ /* Parameter checking */
++ if (PCI_DEFAULT_IF != pciIf)
++ {
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciConfigWrite: ERR. Invalid PCI interface %d\n",
++ pciIf);
++ return 0xFFFFFFFF;
++ }
++ }
++
++ if (dev >= MAX_PCI_DEVICES)
++ {
++ mvOsPrintf("mvPciConfigWrite: ERR. device number illigal %d\n",dev);
++ return MV_BAD_PARAM;
++ }
++
++ if (func >= MAX_PCI_FUNCS)
++ {
++ mvOsPrintf("mvPciConfigWrite: ERR. function number illigal %d\n", func);
++ return MV_ERROR;
++ }
++
++ if (bus >= MAX_PCI_BUSSES)
++ {
++ mvOsPrintf("mvPciConfigWrite: ERR. bus number illigal %d\n", bus);
++ return MV_ERROR;
++ }
++
++ /* Creating PCI address to be passed */
++ pciData |= (bus << PCAR_BUS_NUM_OFFS);
++ pciData |= (dev << PCAR_DEVICE_NUM_OFFS);
++ pciData |= (func << PCAR_FUNC_NUM_OFFS);
++ pciData |= (regOff & PCAR_REG_NUM_MASK);
++
++ pciData |= PCAR_CONFIG_EN;
++
++ /* Write the address to the PCI configuration address register */
++ MV_REG_WRITE(PCI_CONFIG_ADDR_REG(pciIf), pciData);
++
++ /* In order to let the PCI controller absorbed the address of the read */
++ /* transaction we perform a validity check that the address was written */
++ if(pciData != MV_REG_READ(PCI_CONFIG_ADDR_REG(pciIf)))
++ {
++ return MV_ERROR;
++ }
++
++ /* Write the Data passed to the PCI Data register */
++ MV_REG_WRITE(PCI_CONFIG_DATA_REG(pciIf), data);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvPciMasterEnable - Enable/disale PCI interface master transactions.
++*
++* DESCRIPTION:
++* This function performs read modified write to PCI command status
++* (offset 0x4) to set/reset bit 2. After this bit is set, the PCI
++* master is allowed to gain ownership on the bus, otherwise it is
++* incapable to do so.
++*
++* INPUT:
++* pciIf - PCI interface number.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciMasterEnable(MV_U32 pciIf, MV_BOOL enable)
++{
++ MV_U32 pciCommandStatus;
++ MV_U32 RegOffs;
++ MV_U32 localBus;
++ MV_U32 localDev;
++
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciMasterEnable: ERR. Invalid PCI interface %d\n", pciIf);
++ return MV_ERROR;
++ }
++
++ localBus = mvPciLocalBusNumGet(pciIf);
++ localDev = mvPciLocalDevNumGet(pciIf);
++
++ RegOffs = PCI_STATUS_AND_COMMAND;
++
++ pciCommandStatus = mvPciConfigRead(pciIf, localBus, localDev, 0, RegOffs);
++
++ if (MV_TRUE == enable)
++ {
++ pciCommandStatus |= PSCR_MASTER_EN;
++ }
++ else
++ {
++ pciCommandStatus &= ~PSCR_MASTER_EN;
++ }
++
++ mvPciConfigWrite(pciIf, localBus, localDev, 0, RegOffs, pciCommandStatus);
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvPciSlaveEnable - Enable/disale PCI interface slave transactions.
++*
++* DESCRIPTION:
++* This function performs read modified write to PCI command status
++* (offset 0x4) to set/reset bit 0 and 1. After those bits are set,
++* the PCI slave is allowed to respond to PCI IO space access (bit 0)
++* and PCI memory space access (bit 1).
++*
++* INPUT:
++* pciIf - PCI interface number.
++* dev - PCI device number.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciSlaveEnable(MV_U32 pciIf, MV_U32 bus, MV_U32 dev, MV_BOOL enable)
++{
++ MV_U32 pciCommandStatus;
++ MV_U32 RegOffs;
++
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciSlaveEnable: ERR. Invalid PCI interface %d\n", pciIf);
++ return MV_BAD_PARAM;
++ }
++ if (dev >= MAX_PCI_DEVICES)
++ {
++ mvOsPrintf("mvPciLocalDevNumSet: ERR. device number illigal %d\n", dev);
++ return MV_BAD_PARAM;
++
++ }
++
++ RegOffs = PCI_STATUS_AND_COMMAND;
++
++ pciCommandStatus=mvPciConfigRead(pciIf, bus, dev, 0, RegOffs);
++
++ if (MV_TRUE == enable)
++ {
++ pciCommandStatus |= (PSCR_IO_EN | PSCR_MEM_EN);
++ }
++ else
++ {
++ pciCommandStatus &= ~(PSCR_IO_EN | PSCR_MEM_EN);
++ }
++
++ mvPciConfigWrite(pciIf, bus, dev, 0, RegOffs, pciCommandStatus);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvPciLocalBusNumSet - Set PCI interface local bus number.
++*
++* DESCRIPTION:
++* This function sets given PCI interface its local bus number.
++* Note: In case the PCI interface is PCI-X, the information is read-only.
++*
++* INPUT:
++* pciIf - PCI interface number.
++* busNum - Bus number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_NOT_ALLOWED in case PCI interface is PCI-X.
++* MV_BAD_PARAM on bad parameters ,
++* otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciLocalBusNumSet(MV_U32 pciIf, MV_U32 busNum)
++{
++ MV_U32 pciP2PConfig;
++ MV_PCI_MODE pciMode;
++ MV_U32 localBus;
++ MV_U32 localDev;
++
++
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciLocalBusNumSet: ERR. Invalid PCI interface %d\n",pciIf);
++ return MV_BAD_PARAM;
++ }
++ if (busNum >= MAX_PCI_BUSSES)
++ {
++ mvOsPrintf("mvPciLocalBusNumSet: ERR. bus number illigal %d\n", busNum);
++ return MV_ERROR;
++
++ }
++
++ localBus = mvPciLocalBusNumGet(pciIf);
++ localDev = mvPciLocalDevNumGet(pciIf);
++
++
++ /* PCI interface mode */
++ mvPciModeGet(pciIf, &pciMode);
++
++ /* if PCI type is PCI-X then it is not allowed to change the dev number */
++ if (MV_PCIX == pciMode.pciType)
++ {
++ pciP2PConfig = mvPciConfigRead(pciIf, localBus, localDev, 0, PCIX_STATUS );
++
++ pciP2PConfig &= ~PXS_BN_MASK;
++
++ pciP2PConfig |= (busNum << PXS_BN_OFFS) & PXS_BN_MASK;
++
++ mvPciConfigWrite(pciIf, localBus, localDev, 0, PCIX_STATUS,pciP2PConfig );
++
++ }
++ else
++ {
++ pciP2PConfig = MV_REG_READ(PCI_P2P_CONFIG_REG(pciIf));
++
++ pciP2PConfig &= ~PPCR_BUS_NUM_MASK;
++
++ pciP2PConfig |= (busNum << PPCR_BUS_NUM_OFFS) & PPCR_BUS_NUM_MASK;
++
++ MV_REG_WRITE(PCI_P2P_CONFIG_REG(pciIf), pciP2PConfig);
++
++ }
++
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvPciLocalBusNumGet - Get PCI interface local bus number.
++*
++* DESCRIPTION:
++* This function gets the local bus number of a given PCI interface.
++*
++* INPUT:
++* pciIf - PCI interface number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Local bus number.0xffffffff on Error
++*
++*******************************************************************************/
++MV_U32 mvPciLocalBusNumGet(MV_U32 pciIf)
++{
++ MV_U32 pciP2PConfig;
++
++ /* Parameter checking */
++ if (PCI_DEFAULT_IF != pciIf)
++ {
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciLocalBusNumGet: ERR. Invalid PCI interface %d\n",
++ pciIf);
++ return 0xFFFFFFFF;
++ }
++ }
++
++ pciP2PConfig = MV_REG_READ(PCI_P2P_CONFIG_REG(pciIf));
++ pciP2PConfig &= PPCR_BUS_NUM_MASK;
++ return (pciP2PConfig >> PPCR_BUS_NUM_OFFS);
++}
++
++
++/*******************************************************************************
++* mvPciLocalDevNumSet - Set PCI interface local device number.
++*
++* DESCRIPTION:
++* This function sets given PCI interface its local device number.
++* Note: In case the PCI interface is PCI-X, the information is read-only.
++*
++* INPUT:
++* pciIf - PCI interface number.
++* devNum - Device number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_NOT_ALLOWED in case PCI interface is PCI-X. MV_BAD_PARAM on bad parameters ,
++* otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciLocalDevNumSet(MV_U32 pciIf, MV_U32 devNum)
++{
++ MV_U32 pciP2PConfig;
++ MV_PCI_MODE pciMode;
++ MV_U32 localBus;
++ MV_U32 localDev;
++
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciLocalDevNumSet: ERR. Invalid PCI interface %d\n",pciIf);
++ return MV_BAD_PARAM;
++ }
++ if (devNum >= MAX_PCI_DEVICES)
++ {
++ mvOsPrintf("mvPciLocalDevNumSet: ERR. device number illigal %d\n",
++ devNum);
++ return MV_BAD_PARAM;
++
++ }
++
++ localBus = mvPciLocalBusNumGet(pciIf);
++ localDev = mvPciLocalDevNumGet(pciIf);
++
++ /* PCI interface mode */
++ mvPciModeGet(pciIf, &pciMode);
++
++ /* if PCI type is PCIX then it is not allowed to change the dev number */
++ if (MV_PCIX == pciMode.pciType)
++ {
++ pciP2PConfig = mvPciConfigRead(pciIf, localBus, localDev, 0, PCIX_STATUS );
++
++ pciP2PConfig &= ~PXS_DN_MASK;
++
++ pciP2PConfig |= (devNum << PXS_DN_OFFS) & PXS_DN_MASK;
++
++ mvPciConfigWrite(pciIf,localBus, localDev, 0, PCIX_STATUS,pciP2PConfig );
++ }
++ else
++ {
++ pciP2PConfig = MV_REG_READ(PCI_P2P_CONFIG_REG(pciIf));
++
++ pciP2PConfig &= ~PPCR_DEV_NUM_MASK;
++
++ pciP2PConfig |= (devNum << PPCR_DEV_NUM_OFFS) & PPCR_DEV_NUM_MASK;
++
++ MV_REG_WRITE(PCI_P2P_CONFIG_REG(pciIf), pciP2PConfig);
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvPciLocalDevNumGet - Get PCI interface local device number.
++*
++* DESCRIPTION:
++* This function gets the local device number of a given PCI interface.
++*
++* INPUT:
++* pciIf - PCI interface number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Local device number. 0xffffffff on Error
++*
++*******************************************************************************/
++MV_U32 mvPciLocalDevNumGet(MV_U32 pciIf)
++{
++ MV_U32 pciP2PConfig;
++
++ /* Parameter checking */
++
++ if (PCI_DEFAULT_IF != pciIf)
++ {
++ if (pciIf >= mvCtrlPciMaxIfGet())
++ {
++ mvOsPrintf("mvPciLocalDevNumGet: ERR. Invalid PCI interface %d\n",
++ pciIf);
++ return 0xFFFFFFFF;
++ }
++ }
++
++ pciP2PConfig = MV_REG_READ(PCI_P2P_CONFIG_REG(pciIf));
++
++ pciP2PConfig &= PPCR_DEV_NUM_MASK;
++
++ return (pciP2PConfig >> PPCR_DEV_NUM_OFFS);
++}
++
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.h 2010-11-09 20:28:11.412495457 +0100
+@@ -0,0 +1,185 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCPCIH
++#define __INCPCIH
++
++#include "mvCommon.h"
++#include "mvOs.h"
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++#include "pci/mvPciRegs.h"
++
++
++/* NOTE not supported in this driver:
++
++ Built In Self Test (BIST)
++ Vital Product Data (VPD)
++ Message Signaled Interrupt (MSI)
++ Power Management
++ Compact PCI Hot Swap
++ Header retarget
++
++Registers not supported:
++1) PCI DLL Status and Control (PCI0 0x1D20, PCI1 0x1DA0)
++2) PCI/MPP Pads Calibration (CI0/MPP[31:16] 0x1D1C, PCI1/MPP[15:0] 0X1D9C)
++*/
++
++/* defines */
++/* The number of supported PCI interfaces depend on Marvell controller */
++/* device number. This device number ID is located on the PCI unit */
++/* configuration header. This creates a loop where calling PCI */
++/* configuration read/write routine results a call to get PCI configuration */
++/* information etc. This macro defines a default PCI interface. This PCI */
++/* interface is sure to exist. */
++#define PCI_DEFAULT_IF 0
++
++
++/* typedefs */
++/* The Marvell controller supports both conventional PCI and PCI-X. */
++/* This enumeration describes the PCI type. */
++typedef enum _mvPciType
++{
++ MV_PCI_CONV, /* Conventional PCI */
++ MV_PCIX /* PCI-X */
++}MV_PCI_TYPE;
++
++typedef enum _mvPciMod
++{
++ MV_PCI_MOD_HOST,
++ MV_PCI_MOD_DEVICE
++}MV_PCI_MOD;
++
++
++/* The Marvell controller supports both PCI width of 32 and 64 bit. */
++/* This enumerator describes PCI width */
++typedef enum _mvPciWidth
++{
++ MV_PCI_32, /* PCI width 32bit */
++ MV_PCI_64 /* PCI width 64bit */
++}MV_PCI_WIDTH;
++
++/* This structure describes the PCI unit configured type, speed and width. */
++typedef struct _mvPciMode
++{
++ MV_PCI_TYPE pciType; /* PCI type */
++ MV_U32 pciSpeed; /* Assuming PCI base clock on board is 33MHz */
++ MV_PCI_WIDTH pciWidth; /* PCI bus width */
++}MV_PCI_MODE;
++
++/* mvPciInit - Initialize PCI interfaces*/
++MV_VOID mvPciHalInit(MV_U32 pciIf, MV_PCI_MOD pciIfmod);
++
++/* mvPciCommandSet - Set PCI comman register value.*/
++MV_STATUS mvPciCommandSet(MV_U32 pciIf, MV_U32 command);
++
++/* mvPciModeGet - Get PCI interface mode.*/
++MV_STATUS mvPciModeGet(MV_U32 pciIf, MV_PCI_MODE *pPciMode);
++
++/* mvPciRetrySet - Set PCI retry counters*/
++MV_STATUS mvPciRetrySet(MV_U32 pciIf, MV_U32 counter);
++
++/* mvPciDiscardTimerSet - Set PCI discard timer*/
++MV_STATUS mvPciDiscardTimerSet(MV_U32 pciIf, MV_U32 pClkCycles);
++
++/* mvPciArbEnable - PCI arbiter enable/disable*/
++MV_STATUS mvPciArbEnable(MV_U32 pciIf, MV_BOOL enable);
++
++/* mvPciArbParkDis - Disable arbiter parking on agent */
++MV_STATUS mvPciArbParkDis(MV_U32 pciIf, MV_U32 pciAgentMask);
++
++/* mvPciArbBrokDetectSet - Set PCI arbiter broken detection */
++MV_STATUS mvPciArbBrokDetectSet(MV_U32 pciIf, MV_U32 pClkCycles);
++
++/* mvPciConfigRead - Read from configuration space */
++MV_U32 mvPciConfigRead (MV_U32 pciIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func,MV_U32 regOff);
++
++/* mvPciConfigWrite - Write to configuration space */
++MV_STATUS mvPciConfigWrite(MV_U32 pciIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func, MV_U32 regOff, MV_U32 data);
++
++/* mvPciMasterEnable - Enable/disale PCI interface master transactions.*/
++MV_STATUS mvPciMasterEnable(MV_U32 pciIf, MV_BOOL enable);
++
++/* mvPciSlaveEnable - Enable/disale PCI interface slave transactions.*/
++MV_STATUS mvPciSlaveEnable(MV_U32 pciIf, MV_U32 bus, MV_U32 dev,MV_BOOL enable);
++
++/* mvPciLocalBusNumSet - Set PCI interface local bus number.*/
++MV_STATUS mvPciLocalBusNumSet(MV_U32 pciIf, MV_U32 busNum);
++
++/* mvPciLocalBusNumGet - Get PCI interface local bus number.*/
++MV_U32 mvPciLocalBusNumGet(MV_U32 pciIf);
++
++/* mvPciLocalDevNumSet - Set PCI interface local device number.*/
++MV_STATUS mvPciLocalDevNumSet(MV_U32 pciIf, MV_U32 devNum);
++
++/* mvPciLocalDevNumGet - Get PCI interface local device number.*/
++MV_U32 mvPciLocalDevNumGet(MV_U32 pciIf);
++
++
++#endif /* #ifndef __INCPCIH */
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPciRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPciRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPciRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPciRegs.h 2010-11-09 20:28:11.452495500 +0100
+@@ -0,0 +1,411 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCPCIREGSH
++#define __INCPCIREGSH
++
++
++#include "pci-if/mvPciIfRegs.h"
++/* defines */
++#define MAX_PCI_DEVICES 32
++#define MAX_PCI_FUNCS 8
++#define MAX_PCI_BUSSES 128
++
++/* enumerators */
++
++/* This enumerator described the possible PCI slave targets. */
++/* PCI slave targets are designated memory/IO address spaces that the */
++/* PCI slave targets can access. They are also refered as "targets" */
++/* this enumeratoe order is determined by the content of :
++ PCI_BASE_ADDR_ENABLE_REG */
++
++
++/* registers offsetes defines */
++
++
++
++/*************************/
++/* PCI control registers */
++/*************************/
++/* maen : should add new registers */
++#define PCI_CMD_REG(pciIf) (0x30c00 + ((pciIf) * 0x80))
++#define PCI_MODE_REG(pciIf) (0x30d00 + ((pciIf) * 0x80))
++#define PCI_RETRY_REG(pciIf) (0x30c04 + ((pciIf) * 0x80))
++#define PCI_DISCARD_TIMER_REG(pciIf) (0x30d04 + ((pciIf) * 0x80))
++#define PCI_ARBITER_CTRL_REG(pciIf) (0x31d00 + ((pciIf) * 0x80))
++#define PCI_P2P_CONFIG_REG(pciIf) (0x31d14 + ((pciIf) * 0x80))
++#define PCI_ACCESS_CTRL_BASEL_REG(pciIf, targetWin) \
++ (0x31e00 + ((pciIf) * 0x80) + ((targetWin) * 0x10))
++#define PCI_ACCESS_CTRL_BASEH_REG(pciIf, targetWin) \
++ (0x31e04 + ((pciIf) * 0x80) + ((targetWin) * 0x10))
++#define PCI_ACCESS_CTRL_SIZE_REG(pciIf, targetWin) \
++ (0x31e08 + ((pciIf) * 0x80) + ((targetWin) * 0x10))
++
++#define PCI_DLL_CTRL_REG(pciIf) (0x31d20 + ((pciIf) * 0x80))
++
++/* PCI Dll Control (PDC)*/
++#define PDC_DLL_EN BIT0
++
++
++/* PCI Command Register (PCR) */
++#define PCR_MASTER_BYTE_SWAP_EN BIT0
++#define PCR_MASTER_WR_COMBINE_EN BIT4
++#define PCR_MASTER_RD_COMBINE_EN BIT5
++#define PCR_MASTER_WR_TRIG_WHOLE BIT6
++#define PCR_MASTER_RD_TRIG_WHOLE BIT7
++#define PCR_MASTER_MEM_RD_LINE_EN BIT8
++#define PCR_MASTER_MEM_RD_MULT_EN BIT9
++#define PCR_MASTER_WORD_SWAP_EN BIT10
++#define PCR_SLAVE_WORD_SWAP_EN BIT11
++#define PCR_NS_ACCORDING_RCV_TRANS BIT14
++#define PCR_MASTER_PCIX_REQ64N_EN BIT15
++#define PCR_SLAVE_BYTE_SWAP_EN BIT16
++#define PCR_MASTER_DAC_EN BIT17
++#define PCR_MASTER_M64_ALLIGN BIT18
++#define PCR_ERRORS_PROPAGATION_EN BIT19
++#define PCR_SLAVE_SWAP_ENABLE BIT20
++#define PCR_MASTER_SWAP_ENABLE BIT21
++#define PCR_MASTER_INT_SWAP_EN BIT22
++#define PCR_LOOP_BACK_ENABLE BIT23
++#define PCR_SLAVE_INTREG_SWAP_OFFS 24
++#define PCR_SLAVE_INTREG_SWAP_MASK 0x3
++#define PCR_SLAVE_INTREG_BYTE_SWAP \
++ (MV_BYTE_SWAP << PCR_SLAVE_INT_REG_SWAP_MASK)
++#define PCR_SLAVE_INTREG_NO_SWAP \
++ (MV_NO_SWAP << PCR_SLAVE_INT_REG_SWAP_MASK)
++#define PCR_SLAVE_INTREG_BYTE_WORD \
++ (MV_BYTE_WORD_SWAP << PCR_SLAVE_INT_REG_SWAP_MASK)
++#define PCR_SLAVE_INTREG_WORD_SWAP \
++ (MV_WORD_SWAP << PCR_SLAVE_INT_REG_SWAP_MASK)
++#define PCR_RESET_REASSERTION_EN BIT26
++#define PCR_PCI_TO_CPU_REG_ORDER_EN BIT28
++#define PCR_CPU_TO_PCI_ORDER_EN BIT29
++#define PCR_PCI_TO_CPU_ORDER_EN BIT30
++
++/* PCI Mode Register (PMR) */
++#define PMR_PCI_ID_OFFS 0 /* PCI Interface ID */
++#define PMR_PCI_ID_MASK (0x1 << PMR_PCI_ID_OFFS)
++#define PMR_PCI_ID_PCI(pciNum) ((pciNum) << PCI_MODE_PCIID_OFFS)
++
++#define PMR_PCI_64_OFFS 2 /* 64-bit PCI Interface */
++#define PMR_PCI_64_MASK (0x1 << PMR_PCI_64_OFFS)
++#define PMR_PCI_64_64BIT (0x1 << PMR_PCI_64_OFFS)
++#define PMR_PCI_64_32BIT (0x0 << PMR_PCI_64_OFFS)
++
++#define PMR_PCI_MODE_OFFS 4 /* PCI interface mode of operation */
++#define PMR_PCI_MODE_MASK (0x3 << PMR_PCI_MODE_OFFS)
++#define PMR_PCI_MODE_CONV (0x0 << PMR_PCI_MODE_OFFS)
++#define PMR_PCI_MODE_PCIX_66MHZ (0x1 << PMR_PCI_MODE_OFFS)
++#define PMR_PCI_MODE_PCIX_100MHZ (0x2 << PMR_PCI_MODE_OFFS)
++#define PMR_PCI_MODE_PCIX_133MHZ (0x3 << PMR_PCI_MODE_OFFS)
++
++#define PMR_EXP_ROM_SUPPORT BIT8 /* Expansion ROM Active */
++
++#define PMR_PCI_RESET_OFFS 31 /* PCI Interface Reset Indication */
++#define PMR_PCI_RESET_MASK (0x1 << PMR_PCI_RESET_OFFS)
++#define PMR_PCI_RESET_PCIXRST (0x0 << PMR_PCI_RESET_OFFS)
++
++
++/* PCI Retry Register (PRR) */
++#define PRR_RETRY_CNTR_OFFS 16 /* Retry Counter */
++#define PRR_RETRY_CNTR_MAX 0xff
++#define PRR_RETRY_CNTR_MASK (PRR_RETRY_CNTR_MAX << PRR_RETRY_CNTR_OFFS)
++
++
++/* PCI Discard Timer Register (PDTR) */
++#define PDTR_TIMER_OFFS 0 /* Timer */
++#define PDTR_TIMER_MAX 0xffff
++#define PDTR_TIMER_MIN 0x7F
++#define PDTR_TIMER_MASK (PDTR_TIMER_MAX << PDTR_TIMER_OFFS)
++
++
++/* PCI Arbiter Control Register (PACR) */
++#define PACR_BROKEN_DETECT_EN BIT1 /* Broken Detection Enable */
++
++#define PACR_BROKEN_VAL_OFFS 3 /* Broken Value */
++#define PACR_BROKEN_VAL_MASK (0xf << PACR_BROKEN_VAL_OFFS)
++#define PACR_BROKEN_VAL_CONV_MIN 0x2
++#define PACR_BROKEN_VAL_PCIX_MIN 0x6
++
++#define PACR_PARK_DIS_OFFS 14 /* Parking Disable */
++#define PACR_PARK_DIS_MAX_AGENT 0x3f
++#define PACR_PARK_DIS_MASK (PACR_PARK_DIS_MAX_AGENT<<PACR_PARK_DIS_OFFS)
++#define PACR_PARK_DIS(agent) ((1 << (agent)) << PACR_PARK_DIS_OFFS)
++
++#define PACR_ARB_ENABLE BIT31 /* Enable Internal Arbiter */
++
++
++/* PCI P2P Configuration Register (PPCR) */
++#define PPCR_2ND_BUS_L_OFFS 0 /* 2nd PCI Interface Bus Range Lower */
++#define PPCR_2ND_BUS_L_MASK (0xff << PPCR_2ND_BUS_L_OFFS)
++
++#define PPCR_2ND_BUS_H_OFFS 8 /* 2nd PCI Interface Bus Range Upper */
++#define PPCR_2ND_BUS_H_MASK (0xff << PPCR_2ND_BUS_H_OFFS)
++
++#define PPCR_BUS_NUM_OFFS 16 /* The PCI interface's Bus number */
++#define PPCR_BUS_NUM_MASK (0xff << PPCR_BUS_NUM_OFFS)
++
++#define PPCR_DEV_NUM_OFFS 24 /* The PCI interface’s Device number */
++#define PPCR_DEV_NUM_MASK (0xff << PPCR_DEV_NUM_OFFS)
++
++
++/* PCI Access Control Base Low Register (PACBLR) */
++#define PACBLR_EN BIT0 /* Access control window enable */
++
++#define PACBLR_ACCPROT BIT4 /* Access Protect */
++#define PACBLR_WRPROT BIT5 /* Write Protect */
++
++#define PACBLR_PCISWAP_OFFS 6 /* PCI slave Data Swap Control */
++#define PACBLR_PCISWAP_MASK (0x3 << PACBLR_PCISWAP_OFFS)
++#define PACBLR_PCISWAP_BYTE (0x0 << PACBLR_PCISWAP_OFFS)
++#define PACBLR_PCISWAP_NO_SWAP (0x1 << PACBLR_PCISWAP_OFFS)
++#define PACBLR_PCISWAP_BYTE_WORD (0x2 << PACBLR_PCISWAP_OFFS)
++#define PACBLR_PCISWAP_WORD (0x3 << PACBLR_PCISWAP_OFFS)
++
++#define PACBLR_RDMBURST_OFFS 8 /* Read Max Burst */
++#define PACBLR_RDMBURST_MASK (0x3 << PACBLR_RDMBURST_OFFS)
++#define PACBLR_RDMBURST_32BYTE (0x0 << PACBLR_RDMBURST_OFFS)
++#define PACBLR_RDMBURST_64BYTE (0x1 << PACBLR_RDMBURST_OFFS)
++#define PACBLR_RDMBURST_128BYTE (0x2 << PACBLR_RDMBURST_OFFS)
++
++#define PACBLR_RDSIZE_OFFS 10 /* Typical PCI read transaction Size. */
++#define PACBLR_RDSIZE_MASK (0x3 << PACBLR_RDSIZE_OFFS)
++#define PACBLR_RDSIZE_32BYTE (0x0 << PACBLR_RDSIZE_OFFS)
++#define PACBLR_RDSIZE_64BYTE (0x1 << PACBLR_RDSIZE_OFFS)
++#define PACBLR_RDSIZE_128BYTE (0x2 << PACBLR_RDSIZE_OFFS)
++#define PACBLR_RDSIZE_256BYTE (0x3 << PACBLR_RDSIZE_OFFS)
++
++#define PACBLR_BASE_L_OFFS 12 /* Corresponds to address bits [31:12] */
++#define PACBLR_BASE_L_MASK (0xfffff << PACBLR_BASE_L_OFFS)
++#define PACBLR_BASE_L_ALIGNMENT (1 << PACBLR_BASE_L_OFFS)
++#define PACBLR_BASE_ALIGN_UP(base) \
++ ((base+PACBLR_BASE_L_ALIGNMENT)&PACBLR_BASE_L_MASK)
++#define PACBLR_BASE_ALIGN_DOWN(base) (base & PACBLR_BASE_L_MASK)
++
++
++/* PCI Access Control Base High Register (PACBHR) */
++#define PACBHR_BASE_H_OFFS 0 /* Corresponds to address bits [63:32] */
++#define PACBHR_CTRL_BASE_H_MASK (0xffffffff << PACBHR_BASE_H_OFFS)
++
++/* PCI Access Control Size Register (PACSR) */
++#define PACSR_WRMBURST_OFFS 8 /* Write Max Burst */
++#define PACSR_WRMBURST_MASK (0x3 << PACSR_WRMBURST_OFFS)
++#define PACSR_WRMBURST_32BYTE (0x0 << PACSR_WRMBURST_OFFS)
++#define PACSR_WRMBURST_64BYTE (0x1 << PACSR_WRMBURST_OFFS)
++#define PACSR_WRMBURST_128BYTE (0x2 << PACSR_WRMBURST_OFFS)
++
++#define PACSR_PCI_ORDERING BIT11 /* PCI Ordering required */
++
++#define PACSR_SIZE_OFFS 12 /* PCI access window size */
++#define PACSR_SIZE_MASK (0xfffff << PACSR_SIZE_OFFS)
++#define PACSR_SIZE_ALIGNMENT (1 << PACSR_SIZE_OFFS)
++#define PACSR_SIZE_ALIGN_UP(size) \
++ ((size+PACSR_SIZE_ALIGNMENT)&PACSR_SIZE_MASK)
++#define PACSR_SIZE_ALIGN_DOWN(size) (size & PACSR_SIZE_MASK)
++
++
++/***************************************/
++/* PCI Configuration Access Registers */
++/***************************************/
++
++#define PCI_CONFIG_ADDR_REG(pciIf) (0x30C78 - ((pciIf) * 0x80) )
++#define PCI_CONFIG_DATA_REG(pciIf) (0x30C7C - ((pciIf) * 0x80) )
++#define PCI_INT_ACK_REG(pciIf) (0x30C34 + ((pciIf) * 0x80) )
++
++/* PCI Configuration Address Register (PCAR) */
++#define PCAR_REG_NUM_OFFS 2
++#define PCAR_REG_NUM_MASK (0x3F << PCAR_REG_NUM_OFFS)
++
++#define PCAR_FUNC_NUM_OFFS 8
++#define PCAR_FUNC_NUM_MASK (0x7 << PCAR_FUNC_NUM_OFFS)
++
++#define PCAR_DEVICE_NUM_OFFS 11
++#define PCAR_DEVICE_NUM_MASK (0x1F << PCAR_DEVICE_NUM_OFFS)
++
++#define PCAR_BUS_NUM_OFFS 16
++#define PCAR_BUS_NUM_MASK (0xFF << PCAR_BUS_NUM_OFFS)
++
++#define PCAR_CONFIG_EN BIT31
++
++
++/***************************************/
++/* PCI Configuration registers */
++/***************************************/
++
++/*********************************************/
++/* PCI Configuration, Function 0, Registers */
++/*********************************************/
++
++/* Marvell Specific */
++#define PCI_SCS0_BASE_ADDR_LOW 0x010
++#define PCI_SCS0_BASE_ADDR_HIGH 0x014
++#define PCI_SCS1_BASE_ADDR_LOW 0x018
++#define PCI_SCS1_BASE_ADDR_HIGH 0x01C
++#define PCI_INTER_REG_MEM_MAPPED_BASE_ADDR_L 0x020
++#define PCI_INTER_REG_MEM_MAPPED_BASE_ADDR_H 0x024
++
++/* capability list */
++#define PCI_POWER_MNG_CAPABILITY 0x040
++#define PCI_POWER_MNG_STATUS_CONTROL 0x044
++#define PCI_VPD_ADDRESS_REG 0x048
++#define PCI_VPD_DATA_REG 0x04c
++#define PCI_MSI_MESSAGE_CONTROL 0x050
++#define PCI_MSI_MESSAGE_ADDR 0x054
++#define PCI_MSI_MESSAGE_UPPER_ADDR 0x058
++#define PCI_MSI_MESSAGE_DATA 0x05c
++#define PCIX_COMMAND 0x060
++#define PCIX_STATUS 0x064
++#define PCI_COMPACT_PCI_HOT_SWAP 0x068
++
++
++/*********************************************/
++/* PCI Configuration, Function 1, Registers */
++/*********************************************/
++
++#define PCI_SCS2_BASE_ADDR_LOW 0x10
++#define PCI_SCS2_BASE_ADDR_HIGH 0x14
++#define PCI_SCS3_BASE_ADDR_LOW 0x18
++#define PCI_SCS3_BASE_ADDR_HIGH 0x1c
++
++
++/***********************************************/
++/* PCI Configuration, Function 2, Registers */
++/***********************************************/
++
++#define PCI_DEVCS0_BASE_ADDR_LOW 0x10
++#define PCI_DEVCS0_BASE_ADDR_HIGH 0x14
++#define PCI_DEVCS1_BASE_ADDR_LOW 0x18
++#define PCI_DEVCS1_BASE_ADDR_HIGH 0x1c
++#define PCI_DEVCS2_BASE_ADDR_LOW 0x20
++#define PCI_DEVCS2_BASE_ADDR_HIGH 0x24
++
++/***********************************************/
++/* PCI Configuration, Function 3, Registers */
++/***********************************************/
++
++#define PCI_BOOTCS_BASE_ADDR_LOW 0x18
++#define PCI_BOOTCS_BASE_ADDR_HIGH 0x1c
++
++/***********************************************/
++/* PCI Configuration, Function 4, Registers */
++/***********************************************/
++
++#define PCI_P2P_MEM0_BASE_ADDR_LOW 0x10
++#define PCI_P2P_MEM0_BASE_ADDR_HIGH 0x14
++#define PCI_P2P_IO_BASE_ADDR 0x20
++#define PCI_INTER_REGS_IO_MAPPED_BASE_ADDR 0x24
++
++/* PCIX_STATUS register fields (PXS) */
++
++#define PXS_FN_OFFS 0 /* Description Number */
++#define PXS_FN_MASK (0x7 << PXS_FN_OFFS)
++
++#define PXS_DN_OFFS 3 /* Device Number */
++#define PXS_DN_MASK (0x1f << PXS_DN_OFFS)
++
++#define PXS_BN_OFFS 8 /* Bus Number */
++#define PXS_BN_MASK (0xff << PXS_BN_OFFS)
++
++
++/* PCI Error Report Register Map */
++#define PCI_SERRN_MASK_REG(pciIf) (0x30c28 + (pciIf * 0x80))
++#define PCI_CAUSE_REG(pciIf) (0x31d58 + (pciIf * 0x80))
++#define PCI_MASK_REG(pciIf) (0x31d5C + (pciIf * 0x80))
++#define PCI_ERROR_ADDR_LOW_REG(pciIf) (0x31d40 + (pciIf * 0x80))
++#define PCI_ERROR_ADDR_HIGH_REG(pciIf) (0x31d44 + (pciIf * 0x80))
++#define PCI_ERROR_ATTRIBUTE_REG(pciIf) (0x31d48 + (pciIf * 0x80))
++#define PCI_ERROR_COMMAND_REG(pciIf) (0x31d50 + (pciIf * 0x80))
++
++/* PCI Interrupt Cause Register (PICR) */
++#define PICR_ERR_SEL_OFFS 27
++#define PICR_ERR_SEL_MASK (0x1f << PICR_ERR_SEL_OFFS)
++
++/* PCI Error Command Register (PECR) */
++#define PECR_ERR_CMD_OFFS 0
++#define PECR_ERR_CMD_MASK (0xf << PECR_ERR_CMD_OFFS)
++#define PECR_DAC BIT4
++
++
++/* defaults */
++/* Set bits means value is about to change according to new value */
++#define PCI_COMMAND_DEFAULT_MASK 0xffffdff1
++#define PCI_COMMAND_DEFAULT \
++ (PCR_MASTER_WR_TRIG_WHOLE | \
++ PCR_MASTER_RD_TRIG_WHOLE | \
++ PCR_MASTER_MEM_RD_LINE_EN | \
++ PCR_MASTER_MEM_RD_MULT_EN | \
++ PCR_NS_ACCORDING_RCV_TRANS | \
++ PCR_MASTER_PCIX_REQ64N_EN | \
++ PCR_MASTER_DAC_EN | \
++ PCR_MASTER_M64_ALLIGN | \
++ PCR_ERRORS_PROPAGATION_EN)
++
++
++#define PCI_ARBITER_CTRL_DEFAULT_MASK 0x801fc07a
++#define PCI_ARBITER_CTRL_DEFAULT \
++ (PACR_BROKEN_VAL_PCIX_MIN << PACR_BROKEN_VAL_OFFS)
++
++
++#endif /* #ifndef __INCPCIREGSH */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.c 2010-11-09 20:28:11.512532816 +0100
+@@ -0,0 +1,669 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvPciIf.h"
++#include "ctrlEnv/sys/mvSysPex.h"
++
++#if defined(MV_INCLUDE_PCI)
++#include "ctrlEnv/sys/mvSysPci.h"
++#endif
++
++
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++
++/*******************************************************************************
++* mvPciInit - Initialize PCI interfaces
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_OK if function success otherwise MV_ERROR or MV_BAD_PARAM
++*
++*******************************************************************************/
++
++
++MV_STATUS mvPciIfInit(MV_U32 pciIf, PCI_IF_MODE pciIfmode)
++{
++ PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf);
++
++ if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PCI)
++
++ MV_PCI_MOD pciMod;
++
++ if (PCI_IF_MODE_HOST == pciIfmode)
++ {
++ pciMod = MV_PCI_MOD_HOST;
++ }
++ else if (PCI_IF_MODE_DEVICE == pciIfmode)
++ {
++ pciMod = MV_PCI_MOD_DEVICE;
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Bus %d mode %d neither host nor device!\n",
++ __FUNCTION__, pciIf, pciIfmode);
++ return MV_FAIL;
++ }
++
++ return mvPciInit(pciIf - MV_PCI_START_IF, pciMod);
++ #else
++ return MV_OK;
++ #endif
++ }
++ else if (PCI_IF_TYPE_PEX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PEX)
++
++ MV_PEX_TYPE pexType;
++
++ if (PCI_IF_MODE_HOST == pciIfmode)
++ {
++ pexType = MV_PEX_ROOT_COMPLEX;
++ }
++ else if (PCI_IF_MODE_DEVICE == pciIfmode)
++ {
++ pexType = MV_PEX_END_POINT;
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Bus %d type %d neither root complex nor" \
++ " end point\n", __FUNCTION__, pciIf, pciIfmode);
++ return MV_FAIL;
++ }
++ return mvPexInit(pciIf - MV_PEX_START_IF, pexType);
++
++ #else
++ return MV_OK;
++ #endif
++
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf);
++ }
++
++ return MV_FAIL;
++
++}
++
++/* PCI configuration space read write */
++
++/*******************************************************************************
++* mvPciConfigRead - Read from configuration space
++*
++* DESCRIPTION:
++* This function performs a 32 bit read from PCI configuration space.
++* It supports both type 0 and type 1 of Configuration Transactions
++* (local and over bridge). In order to read from local bus segment, use
++* bus number retrieved from mvPciLocalBusNumGet(). Other bus numbers
++* will result configuration transaction of type 1 (over bridge).
++*
++* INPUT:
++* pciIf - PCI interface number.
++* bus - PCI segment bus number.
++* dev - PCI device number.
++* func - Function number.
++* regOffs - Register offset.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit register data, 0xffffffff on error
++*
++*******************************************************************************/
++MV_U32 mvPciIfConfigRead (MV_U32 pciIf, MV_U32 bus, MV_U32 dev, MV_U32 func,
++ MV_U32 regOff)
++{
++ PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf);
++
++ if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PCI)
++ return mvPciConfigRead(pciIf - MV_PCI_START_IF,
++ bus,
++ dev,
++ func,
++ regOff);
++ #else
++ return 0xffffffff;
++ #endif
++ }
++ else if (PCI_IF_TYPE_PEX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PEX)
++ return mvPexConfigRead(pciIf - MV_PEX_START_IF,
++ bus,
++ dev,
++ func,
++ regOff);
++ #else
++ return 0xffffffff;
++ #endif
++
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf);
++ }
++
++ return 0;
++
++}
++
++/*******************************************************************************
++* mvPciConfigWrite - Write to configuration space
++*
++* DESCRIPTION:
++* This function performs a 32 bit write to PCI configuration space.
++* It supports both type 0 and type 1 of Configuration Transactions
++* (local and over bridge). In order to write to local bus segment, use
++* bus number retrieved from mvPciLocalBusNumGet(). Other bus numbers
++* will result configuration transaction of type 1 (over bridge).
++*
++* INPUT:
++* pciIf - PCI interface number.
++* bus - PCI segment bus number.
++* dev - PCI device number.
++* func - Function number.
++* regOffs - Register offset.
++* data - 32bit data.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciIfConfigWrite(MV_U32 pciIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func, MV_U32 regOff, MV_U32 data)
++{
++ PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf);
++
++ if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PCI)
++ return mvPciConfigWrite(pciIf - MV_PCI_START_IF,
++ bus,
++ dev,
++ func,
++ regOff,
++ data);
++ #else
++ return MV_OK;
++ #endif
++ }
++ else if (PCI_IF_TYPE_PEX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PEX)
++ return mvPexConfigWrite(pciIf - MV_PEX_START_IF,
++ bus,
++ dev,
++ func,
++ regOff,
++ data);
++ #else
++ return MV_OK;
++ #endif
++
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf);
++ }
++
++ return MV_FAIL;
++
++}
++
++/*******************************************************************************
++* mvPciMasterEnable - Enable/disale PCI interface master transactions.
++*
++* DESCRIPTION:
++* This function performs read modified write to PCI command status
++* (offset 0x4) to set/reset bit 2. After this bit is set, the PCI
++* master is allowed to gain ownership on the bus, otherwise it is
++* incapable to do so.
++*
++* INPUT:
++* pciIf - PCI interface number.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciIfMasterEnable(MV_U32 pciIf, MV_BOOL enable)
++{
++
++ PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf);
++
++ if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PCI)
++ return mvPciMasterEnable(pciIf - MV_PCI_START_IF,
++ enable);
++ #else
++ return MV_OK;
++ #endif
++ }
++ else if (PCI_IF_TYPE_PEX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PEX)
++ return mvPexMasterEnable(pciIf - MV_PEX_START_IF,
++ enable);
++ #else
++ return MV_OK;
++ #endif
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf);
++ }
++
++ return MV_FAIL;
++
++}
++
++
++/*******************************************************************************
++* mvPciSlaveEnable - Enable/disale PCI interface slave transactions.
++*
++* DESCRIPTION:
++* This function performs read modified write to PCI command status
++* (offset 0x4) to set/reset bit 0 and 1. After those bits are set,
++* the PCI slave is allowed to respond to PCI IO space access (bit 0)
++* and PCI memory space access (bit 1).
++*
++* INPUT:
++* pciIf - PCI interface number.
++* dev - PCI device number.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciIfSlaveEnable(MV_U32 pciIf,MV_U32 bus, MV_U32 dev, MV_BOOL enable)
++{
++
++ PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf);
++
++ if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PCI)
++ return mvPciSlaveEnable(pciIf - MV_PCI_START_IF,bus,dev,
++ enable);
++ #else
++ return MV_OK;
++ #endif
++ }
++ else if (PCI_IF_TYPE_PEX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PEX)
++ return mvPexSlaveEnable(pciIf - MV_PEX_START_IF,bus,dev,
++ enable);
++ #else
++ return MV_OK;
++ #endif
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf);
++ }
++
++ return MV_FAIL;
++
++}
++
++/*******************************************************************************
++* mvPciLocalBusNumSet - Set PCI interface local bus number.
++*
++* DESCRIPTION:
++* This function sets given PCI interface its local bus number.
++* Note: In case the PCI interface is PCI-X, the information is read-only.
++*
++* INPUT:
++* pciIf - PCI interface number.
++* busNum - Bus number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_NOT_ALLOWED in case PCI interface is PCI-X.
++* MV_BAD_PARAM on bad parameters ,
++* otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciIfLocalBusNumSet(MV_U32 pciIf, MV_U32 busNum)
++{
++ PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf);
++
++ if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PCI)
++ return mvPciLocalBusNumSet(pciIf - MV_PCI_START_IF,
++ busNum);
++ #else
++ return MV_OK;
++ #endif
++ }
++ else if (PCI_IF_TYPE_PEX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PEX)
++ return mvPexLocalBusNumSet(pciIf - MV_PEX_START_IF,
++ busNum);
++ #else
++ return MV_OK;
++ #endif
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf);
++ }
++
++ return MV_FAIL;
++
++}
++
++/*******************************************************************************
++* mvPciLocalBusNumGet - Get PCI interface local bus number.
++*
++* DESCRIPTION:
++* This function gets the local bus number of a given PCI interface.
++*
++* INPUT:
++* pciIf - PCI interface number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Local bus number.0xffffffff on Error
++*
++*******************************************************************************/
++MV_U32 mvPciIfLocalBusNumGet(MV_U32 pciIf)
++{
++ PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf);
++
++ if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PCI)
++ return mvPciLocalBusNumGet(pciIf - MV_PCI_START_IF);
++ #else
++ return 0xFFFFFFFF;
++ #endif
++ }
++ else if (PCI_IF_TYPE_PEX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PEX)
++ return mvPexLocalBusNumGet(pciIf - MV_PEX_START_IF);
++ #else
++ return 0xFFFFFFFF;
++ #endif
++
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n",__FUNCTION__, pciIf);
++ }
++
++ return 0;
++
++}
++
++
++/*******************************************************************************
++* mvPciLocalDevNumSet - Set PCI interface local device number.
++*
++* DESCRIPTION:
++* This function sets given PCI interface its local device number.
++* Note: In case the PCI interface is PCI-X, the information is read-only.
++*
++* INPUT:
++* pciIf - PCI interface number.
++* devNum - Device number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_NOT_ALLOWED in case PCI interface is PCI-X. MV_BAD_PARAM on bad parameters ,
++* otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciIfLocalDevNumSet(MV_U32 pciIf, MV_U32 devNum)
++{
++ PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf);
++
++ if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PCI)
++ return mvPciLocalDevNumSet(pciIf - MV_PCI_START_IF,
++ devNum);
++ #else
++ return MV_OK;
++ #endif
++ }
++ else if (PCI_IF_TYPE_PEX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PEX)
++ return mvPexLocalDevNumSet(pciIf - MV_PEX_START_IF,
++ devNum);
++ #else
++ return MV_OK;
++ #endif
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf);
++ }
++
++ return MV_FAIL;
++
++}
++
++/*******************************************************************************
++* mvPciLocalDevNumGet - Get PCI interface local device number.
++*
++* DESCRIPTION:
++* This function gets the local device number of a given PCI interface.
++*
++* INPUT:
++* pciIf - PCI interface number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Local device number. 0xffffffff on Error
++*
++*******************************************************************************/
++MV_U32 mvPciIfLocalDevNumGet(MV_U32 pciIf)
++{
++ PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf);
++
++ if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PCI)
++ return mvPciLocalDevNumGet(pciIf - MV_PCI_START_IF);
++ #else
++ return 0xFFFFFFFF;
++ #endif
++ }
++ else if (PCI_IF_TYPE_PEX == pciIfType)
++ {
++ #if defined(MV_INCLUDE_PEX)
++ return mvPexLocalDevNumGet(pciIf - MV_PEX_START_IF);
++ #else
++ return 0xFFFFFFFF;
++ #endif
++
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf);
++ }
++
++ return 0;
++
++}
++
++/*******************************************************************************
++* mvPciIfTypeGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*******************************************************************************/
++
++PCI_IF_TYPE mvPciIfTypeGet(MV_U32 pciIf)
++{
++
++ if ((pciIf >= MV_PCI_START_IF)&&(pciIf < MV_PCI_MAX_IF + MV_PCI_START_IF))
++ {
++ return PCI_IF_TYPE_CONVEN_PCIX;
++ }
++ else if ((pciIf >= MV_PEX_START_IF) &&
++ (pciIf < MV_PEX_MAX_IF + MV_PEX_START_IF))
++ {
++ return PCI_IF_TYPE_PEX;
++
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf);
++ }
++
++ return 0xffffffff;
++
++}
++
++/*******************************************************************************
++* mvPciIfTypeGet -
++*
++* DESCRIPTION:
++*
++* INPUT:
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++*
++*******************************************************************************/
++
++MV_U32 mvPciRealIfNumGet(MV_U32 pciIf)
++{
++
++ PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf);
++
++ if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType)
++ {
++ return (pciIf - MV_PCI_START_IF);
++ }
++ else if (PCI_IF_TYPE_PEX == pciIfType)
++ {
++ return (pciIf - MV_PEX_START_IF);
++
++ }
++ else
++ {
++ mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf);
++ }
++
++ return 0xffffffff;
++
++}
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.h 2010-11-09 20:28:11.552495455 +0100
+@@ -0,0 +1,134 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCPCIIFH
++#define __INCPCIIFH
++
++#include "mvSysHwConfig.h"
++#include "pci-if/mvPciIfRegs.h"
++#if defined(MV_INCLUDE_PEX)
++#include "pex/mvPex.h"
++#endif
++#if defined(MV_INCLUDE_PCI)
++#include "pci/mvPci.h"
++#endif
++#include "ctrlEnv/mvCtrlEnvLib.h"
++#include "ctrlEnv/mvCtrlEnvAddrDec.h"
++
++typedef enum _mvPCIIfType
++{
++ PCI_IF_TYPE_CONVEN_PCIX,
++ PCI_IF_TYPE_PEX
++
++}PCI_IF_TYPE;
++
++typedef enum _mvPCIIfMode
++{
++ PCI_IF_MODE_HOST,
++ PCI_IF_MODE_DEVICE
++}PCI_IF_MODE;
++
++
++/* Global Functions prototypes */
++
++/* mvPciIfInit - Initialize PCI interfaces*/
++MV_STATUS mvPciIfInit(MV_U32 pciIf, PCI_IF_MODE pciIfmode);
++
++/* mvPciIfConfigRead - Read from configuration space */
++MV_U32 mvPciIfConfigRead (MV_U32 pciIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func,MV_U32 regOff);
++
++/* mvPciIfConfigWrite - Write to configuration space */
++MV_STATUS mvPciIfConfigWrite(MV_U32 pciIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func, MV_U32 regOff, MV_U32 data);
++
++/* mvPciIfMasterEnable - Enable/disale PCI interface master transactions.*/
++MV_STATUS mvPciIfMasterEnable(MV_U32 pciIf, MV_BOOL enable);
++
++/* mvPciIfSlaveEnable - Enable/disale PCI interface slave transactions.*/
++MV_STATUS mvPciIfSlaveEnable(MV_U32 pciIf,MV_U32 bus, MV_U32 dev,
++ MV_BOOL enable);
++
++/* mvPciIfLocalBusNumSet - Set PCI interface local bus number.*/
++MV_STATUS mvPciIfLocalBusNumSet(MV_U32 pciIf, MV_U32 busNum);
++
++/* mvPciIfLocalBusNumGet - Get PCI interface local bus number.*/
++MV_U32 mvPciIfLocalBusNumGet(MV_U32 pciIf);
++
++/* mvPciIfLocalDevNumSet - Set PCI interface local device number.*/
++MV_STATUS mvPciIfLocalDevNumSet(MV_U32 pciIf, MV_U32 devNum);
++
++/* mvPciIfLocalDevNumGet - Get PCI interface local device number.*/
++MV_U32 mvPciIfLocalDevNumGet(MV_U32 pciIf);
++
++/* mvPciIfTypeGet - Get PCI If type*/
++PCI_IF_TYPE mvPciIfTypeGet(MV_U32 pciIf);
++
++MV_U32 mvPciRealIfNumGet(MV_U32 pciIf);
++
++/* mvPciIfAddrDecShow - Display address decode windows attributes */
++MV_VOID mvPciIfAddrDecShow(MV_VOID);
++
++#endif /* #ifndef __INCPCIIFH */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIfRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIfRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIfRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIfRegs.h 2010-11-09 20:28:11.592495403 +0100
+@@ -0,0 +1,245 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCPCIIFREGSH
++#define __INCPCIIFREGSH
++
++
++/* defines */
++#define MAX_PCI_DEVICES 32
++#define MAX_PCI_FUNCS 8
++#define MAX_PCI_BUSSES 128
++
++/***************************************/
++/* PCI Configuration registers */
++/***************************************/
++
++/*********************************************/
++/* PCI Configuration, Function 0, Registers */
++/*********************************************/
++
++
++/* Standard registers */
++#define PCI_DEVICE_AND_VENDOR_ID 0x000
++#define PCI_STATUS_AND_COMMAND 0x004
++#define PCI_CLASS_CODE_AND_REVISION_ID 0x008
++#define PCI_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE 0x00C
++#define PCI_MEMORY_BAR_BASE_ADDR(barNum) (0x010 + ((barNum) << 2))
++#define PCI_SUBSYS_ID_AND_SUBSYS_VENDOR_ID 0x02C
++#define PCI_EXPANSION_ROM_BASE_ADDR_REG 0x030
++#define PCI_CAPABILTY_LIST_POINTER 0x034
++#define PCI_INTERRUPT_PIN_AND_LINE 0x03C
++
++
++/* PCI Device and Vendor ID Register (PDVIR) */
++#define PDVIR_VEN_ID_OFFS 0 /* Vendor ID */
++#define PDVIR_VEN_ID_MASK (0xffff << PDVIR_VEN_ID_OFFS)
++
++#define PDVIR_DEV_ID_OFFS 16 /* Device ID */
++#define PDVIR_DEV_ID_MASK (0xffff << PDVIR_DEV_ID_OFFS)
++
++/* PCI Status and Command Register (PSCR) */
++#define PSCR_IO_EN BIT0 /* IO Enable */
++#define PSCR_MEM_EN BIT1 /* Memory Enable */
++#define PSCR_MASTER_EN BIT2 /* Master Enable */
++#define PSCR_SPECIAL_EN BIT3 /* Special Cycle Enable */
++#define PSCR_MEM_WRI_INV BIT4 /* Memory Write and Invalidate Enable */
++#define PSCR_VGA BIT5 /* VGA Palette Snoops */
++#define PSCR_PERR_EN BIT6 /* Parity Errors Respond Enable */
++#define PSCR_ADDR_STEP BIT7 /* Address Stepping Enable (Wait Cycle En)*/
++#define PSCR_SERR_EN BIT8 /* Ability to assert SERR# line */
++#define PSCR_FAST_BTB_EN BIT9 /* generate fast back-to-back transactions*/
++#define PSCR_CAP_LIST BIT20 /* Capability List Support */
++#define PSCR_66MHZ_EN BIT21 /* 66 MHz Capable */
++#define PSCR_UDF_EN BIT22 /* User definable features */
++#define PSCR_TAR_FAST_BB BIT23 /* fast back-to-back transactions capable */
++#define PSCR_DATA_PERR BIT24 /* Data Parity reported */
++
++#define PSCR_DEVSEL_TIM_OFFS 25 /* DEVSEL timing */
++#define PSCR_DEVSEL_TIM_MASK (0x3 << PSCR_DEVSEL_TIM_OFFS)
++#define PSCR_DEVSEL_TIM_FAST (0x0 << PSCR_DEVSEL_TIM_OFFS)
++#define PSCR_DEVSEL_TIM_MED (0x1 << PSCR_DEVSEL_TIM_OFFS)
++#define PSCR_DEVSEL_TIM_SLOW (0x2 << PSCR_DEVSEL_TIM_OFFS)
++
++#define PSCR_SLAVE_TABORT BIT27 /* Signalled Target Abort */
++#define PSCR_MASTER_TABORT BIT28 /* Recieved Target Abort */
++#define PSCR_MABORT BIT29 /* Recieved Master Abort */
++#define PSCR_SYSERR BIT30 /* Signalled system error */
++#define PSCR_DET_PARERR BIT31 /* Detect Parity Error */
++
++/* PCI configuration register offset=0x08 fields
++ (PCI_CLASS_CODE_AND_REVISION_ID)(PCCRI) */
++
++#define PCCRIR_REVID_OFFS 0 /* Revision ID */
++#define PCCRIR_REVID_MASK (0xff << PCCRIR_REVID_OFFS)
++
++#define PCCRIR_FULL_CLASS_OFFS 8 /* Full Class Code */
++#define PCCRIR_FULL_CLASS_MASK (0xffffff << PCCRIR_FULL_CLASS_OFFS)
++
++#define PCCRIR_PROGIF_OFFS 8 /* Prog .I/F*/
++#define PCCRIR_PROGIF_MASK (0xff << PCCRIR_PROGIF_OFFS)
++
++#define PCCRIR_SUB_CLASS_OFFS 16 /* Sub Class*/
++#define PCCRIR_SUB_CLASS_MASK (0xff << PCCRIR_SUB_CLASS_OFFS)
++
++#define PCCRIR_BASE_CLASS_OFFS 24 /* Base Class*/
++#define PCCRIR_BASE_CLASS_MASK (0xff << PCCRIR_BASE_CLASS_OFFS)
++
++/* PCI configuration register offset=0x0C fields
++ (PCI_BIST_HEADER_TYPE_LATENCY_TIMER_CACHE_LINE)(PBHTLTCL) */
++
++#define PBHTLTCLR_CACHELINE_OFFS 0 /* Specifies the cache line size */
++#define PBHTLTCLR_CACHELINE_MASK (0xff << PBHTLTCLR_CACHELINE_OFFS)
++
++#define PBHTLTCLR_LATTIMER_OFFS 8 /* latency timer */
++#define PBHTLTCLR_LATTIMER_MASK (0xff << PBHTLTCLR_LATTIMER_OFFS)
++
++#define PBHTLTCLR_HEADTYPE_FULL_OFFS 16 /* Full Header Type */
++#define PBHTLTCLR_HEADTYPE_FULL_MASK (0xff << PBHTLTCLR_HEADTYPE_FULL_OFFS)
++
++#define PBHTLTCLR_MULTI_FUNC BIT23 /* Multi/Single function */
++
++#define PBHTLTCLR_HEADER_OFFS 16 /* Header type */
++#define PBHTLTCLR_HEADER_MASK (0x7f << PBHTLTCLR_HEADER_OFFS)
++#define PBHTLTCLR_HEADER_STANDARD (0x0 << PBHTLTCLR_HEADER_OFFS)
++#define PBHTLTCLR_HEADER_PCI2PCI_BRIDGE (0x1 << PBHTLTCLR_HEADER_OFFS)
++
++
++#define PBHTLTCLR_BISTCOMP_OFFS 24 /* BIST Completion Code */
++#define PBHTLTCLR_BISTCOMP_MASK (0xf << PBHTLTCLR_BISTCOMP_OFFS)
++
++#define PBHTLTCLR_BISTACT BIT30 /* BIST Activate bit */
++#define PBHTLTCLR_BISTCAP BIT31 /* BIST Capable Bit */
++
++
++/* PCI Bar Base Low Register (PBBLR) */
++#define PBBLR_IOSPACE BIT0 /* Memory Space Indicator */
++
++#define PBBLR_TYPE_OFFS 1 /* BAR Type/Init Val. */
++#define PBBLR_TYPE_MASK (0x3 << PBBLR_TYPE_OFFS)
++#define PBBLR_TYPE_32BIT_ADDR (0x0 << PBBLR_TYPE_OFFS)
++#define PBBLR_TYPE_64BIT_ADDR (0x2 << PBBLR_TYPE_OFFS)
++
++#define PBBLR_PREFETCH_EN BIT3 /* Prefetch Enable */
++
++
++#define PBBLR_MEM_BASE_OFFS 4 /* Memory Bar Base address. Corresponds to
++ address bits [31:4] */
++#define PBBLR_MEM_BASE_MASK (0xfffffff << PBBLR_MEM_BASE_OFFS)
++
++#define PBBLR_IO_BASE_OFFS 2 /* IO Bar Base address. Corresponds to
++ address bits [31:2] */
++#define PBBLR_IO_BASE_MASK (0x3fffffff << PBBLR_IO_BASE_OFFS)
++
++
++#define PBBLR_BASE_OFFS 12 /* Base address. Address bits [31:12] */
++#define PBBLR_BASE_MASK (0xfffff << PBBLR_BASE_OFFS)
++#define PBBLR_BASE_ALIGNMET (1 << PBBLR_BASE_OFFS)
++
++
++/* PCI Bar Base High Fegister (PBBHR) */
++#define PBBHR_BASE_OFFS 0 /* Base address. Address bits [31:12] */
++#define PBBHR_BASE_MASK (0xffffffff << PBBHR_BASE_OFFS)
++
++
++/* PCI configuration register offset=0x2C fields
++ (PCI_SUBSYSTEM_ID_AND_SUBSYSTEM_VENDOR_ID)(PSISVI) */
++
++#define PSISVIR_VENID_OFFS 0 /* Subsystem Manufacturer Vendor ID Number */
++#define PSISVIR_VENID_MASK (0xffff << PSISVIR_VENID_OFFS)
++
++#define PSISVIR_DEVID_OFFS 16 /* Subsystem Device ID Number */
++#define PSISVIR_DEVID_MASK (0xffff << PSISVIR_DEVID_OFFS)
++
++/* PCI configuration register offset=0x30 fields
++ (PCI_EXPANSION_ROM_BASE_ADDR_REG)(PERBA) */
++
++#define PERBAR_EXPROMEN BIT0 /* Expansion ROM Enable */
++
++#define PERBAR_BASE_OFFS 12 /* Expansion ROM Base Address */
++#define PERBAR_BASE_MASK (0xfffff << PERBAR_BASE_OFFS)
++
++/* PCI configuration register offset=0x34 fields
++ (PCI_CAPABILTY_LIST_POINTER)(PCLP) */
++
++#define PCLPR_CAPPTR_OFFS 0 /* Capability List Pointer */
++#define PCLPR_CAPPTR_MASK (0xff << PCLPR_CAPPTR_OFFS)
++
++/* PCI configuration register offset=0x3C fields
++ (PCI_INTERRUPT_PIN_AND_LINE)(PIPL) */
++
++#define PIPLR_INTLINE_OFFS 0 /* Interrupt line (IRQ) */
++#define PIPLR_INTLINE_MASK (0xff << PIPLR_INTLINE_OFFS)
++
++#define PIPLR_INTPIN_OFFS 8 /* interrupt pin (A,B,C,D) */
++#define PIPLR_INTPIN_MASK (0xff << PIPLR_INTPIN_OFFS)
++
++#define PIPLR_MINGRANT_OFFS 16 /* Minimum Grant on 250 nano seconds units */
++#define PIPLR_MINGRANT_MASK (0xff << PIPLR_MINGRANT_OFFS)
++
++#define PIPLR_MAXLATEN_OFFS 24 /* Maximum latency on 250 nano seconds units */
++#define PIPLR_MAXLATEN_MASK (0xff << PIPLR_MAXLATEN_OFFS)
++
++#endif /* #ifndef __INCPCIIFREGSH */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.c 2010-11-09 20:28:11.632495445 +0100
+@@ -0,0 +1,1006 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++
++/* includes */
++#include "mvPciUtils.h"
++
++#include "ctrlEnv/mvCtrlEnvLib.h"
++
++/* #define MV_DEBUG */
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++ #define mvOsPrintf printf
++#else
++ #define DB(x)
++#endif
++
++/*
++This module only support scanning of Header type 00h of pci devices
++There is no suppotr for Header type 01h of pci devices ( PCI bridges )
++*/
++
++
++static MV_STATUS pciDetectDevice(MV_U32 pciIf,
++ MV_U32 bus,
++ MV_U32 dev,
++ MV_U32 func,
++ MV_PCI_DEVICE *pPciAgent);
++
++static MV_U32 pciDetectDeviceBars(MV_U32 pciIf,
++ MV_U32 bus,
++ MV_U32 dev,
++ MV_U32 func,
++ MV_PCI_DEVICE *pPciAgent);
++
++
++
++
++
++
++/*******************************************************************************
++* mvPciScan - Scan a PCI interface bus
++*
++* DESCRIPTION:
++* Performs a full scan on a PCI interface and returns all possible details
++* on the agents found on the bus.
++*
++* INPUT:
++* pciIf - PCI Interface
++* pPciAgents - Pointer to an Array of the pci agents to be detected
++* pPciAgentsNum - pPciAgents array maximum number of elements
++*
++* OUTPUT:
++* pPciAgents - Array of the pci agents detected on the bus
++* pPciAgentsNum - Number of pci agents detected on the bus
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++
++MV_STATUS mvPciScan(MV_U32 pciIf,
++ MV_PCI_DEVICE *pPciAgents,
++ MV_U32 *pPciAgentsNum)
++{
++
++ MV_U32 devIndex,funcIndex=0,busIndex=0,detectedDevNum=0;
++ MV_U32 localBus=mvPciIfLocalBusNumGet(pciIf);
++ MV_PCI_DEVICE *pPciDevice;
++ MV_PCI_DEVICE *pMainDevice;
++
++ DB(mvOsPrintf("mvPciScan: PCI interface num %d\n", pciIf));
++ /* Parameter checking */
++ if (pciIf >= mvCtrlPexMaxIfGet())
++ {
++ DB(mvOsPrintf("mvPciScan: ERR. Invalid PCI interface num %d\n", pciIf));
++ return MV_BAD_PARAM;
++ }
++ if (NULL == pPciAgents)
++ {
++ DB(mvOsPrintf("mvPciScan: ERR. pPciAgents=NULL \n"));
++ return MV_BAD_PARAM;
++ }
++ if (NULL == pPciAgentsNum)
++ {
++ DB(mvOsPrintf("mvPciScan: ERR. pPciAgentsNum=NULL \n"));
++ return MV_BAD_PARAM;
++ }
++
++
++ DB(mvOsPrintf("mvPciScan: PCI interface num %d mvPciMasterEnable\n", pciIf));
++ /* Master enable the MV PCI master */
++ if (MV_OK != mvPciIfMasterEnable(pciIf,MV_TRUE))
++ {
++ DB(mvOsPrintf("mvPciScan: ERR. mvPciMasterEnable failed \n"));
++ return MV_ERROR;
++
++ }
++
++ DB(mvOsPrintf("mvPciScan: PCI interface num scan%d\n", pciIf));
++
++ /* go through all busses */
++ for (busIndex=localBus ; busIndex < MAX_PCI_BUSSES ; busIndex++)
++ {
++ /* go through all possible devices on the local bus */
++ for (devIndex=0 ; devIndex < MAX_PCI_DEVICES ; devIndex++)
++ {
++ /* always start with function equal to zero */
++ funcIndex=0;
++
++ pPciDevice=&pPciAgents[detectedDevNum];
++ DB(mvOsPrintf("mvPciScan: PCI interface num scan%d:%d\n", busIndex, devIndex));
++
++ if (MV_ERROR == pciDetectDevice(pciIf,
++ busIndex,
++ devIndex,
++ funcIndex,
++ pPciDevice))
++ {
++ /* no device detected , try the next address */
++ continue;
++ }
++
++ /* We are here ! means we have detected a device*/
++ /* always we start with only one function per device */
++ pMainDevice = pPciDevice;
++ pPciDevice->funtionsNum = 1;
++
++
++ /* move on */
++ detectedDevNum++;
++
++
++ /* check if we have no more room for a new device */
++ if (detectedDevNum == *pPciAgentsNum)
++ {
++ DB(mvOsPrintf("mvPciScan: ERR. array passed too small \n"));
++ return MV_ERROR;
++ }
++
++ /* check the detected device if it is a multi functional device then
++ scan all device functions*/
++ if (pPciDevice->isMultiFunction == MV_TRUE)
++ {
++ /* start with function number 1 because we have already detected
++ function 0 */
++ for (funcIndex=1; funcIndex<MAX_PCI_FUNCS ; funcIndex++)
++ {
++ pPciDevice=&pPciAgents[detectedDevNum];
++
++ if (MV_ERROR == pciDetectDevice(pciIf,
++ busIndex,
++ devIndex,
++ funcIndex,
++ pPciDevice))
++ {
++ /* no device detected means no more functions !*/
++ continue;
++ }
++ /* We are here ! means we have detected a device */
++
++ /* move on */
++ pMainDevice->funtionsNum++;
++ detectedDevNum++;
++
++ /* check if we have no more room for a new device */
++ if (detectedDevNum == *pPciAgentsNum)
++ {
++ DB(mvOsPrintf("mvPciScan: ERR. Array too small\n"));
++ return MV_ERROR;
++ }
++
++
++ }
++ }
++
++ }
++
++ }
++
++ /* return the number of devices actually detected on the bus ! */
++ *pPciAgentsNum = detectedDevNum;
++
++ return MV_OK;
++
++}
++
++
++/*******************************************************************************
++* pciDetectDevice - Detect a pci device parameters
++*
++* DESCRIPTION:
++* This function detect if a pci agent exist on certain address !
++* and if exists then it fills all possible information on the
++* agent
++*
++* INPUT:
++* pciIf - PCI Interface
++* bus - Bus number
++* dev - Device number
++* func - Function number
++*
++*
++*
++* OUTPUT:
++* pPciAgent - pointer to the pci agent filled with its information
++*
++* RETURN:
++* MV_ERROR if no device , MV_OK otherwise
++*
++*******************************************************************************/
++
++static MV_STATUS pciDetectDevice(MV_U32 pciIf,
++ MV_U32 bus,
++ MV_U32 dev,
++ MV_U32 func,
++ MV_PCI_DEVICE *pPciAgent)
++{
++ MV_U32 pciData;
++
++ /* no Parameters checking ! because it is static function and it is assumed
++ that all parameters were checked in the calling function */
++
++
++ /* Try read the PCI Vendor ID and Device ID */
++
++ /* We will scan only ourselves and the PCI slots that exist on the
++ board, because we may have a case that we have one slot that has
++ a Cardbus connector, and because CardBus answers all IDsels we want
++ to scan only this slot and ourseleves.
++
++ */
++ #if defined(MV_INCLUDE_PCI)
++ if ((PCI_IF_TYPE_CONVEN_PCIX == mvPciIfTypeGet(pciIf)) &&
++ (DB_88F5181_DDR1_PRPMC != mvBoardIdGet()) &&
++ (DB_88F5181_DDR1_PEXPCI != mvBoardIdGet()) &&
++ (DB_88F5181_DDR1_MNG != mvBoardIdGet()))
++ {
++
++ if (mvBoardIsOurPciSlot(bus, dev) == MV_FALSE)
++ {
++ return MV_ERROR;
++ }
++ }
++ #endif /* defined(MV_INCLUDE_PCI) */
++
++ pciData = mvPciIfConfigRead(pciIf, bus,dev,func, PCI_DEVICE_AND_VENDOR_ID);
++
++ if (PCI_ERROR_CODE == pciData)
++ {
++ /* no device exist */
++ return MV_ERROR;
++ }
++
++ /* we are here ! means a device is detected */
++
++ /* fill basic information */
++ pPciAgent->busNumber=bus;
++ pPciAgent->deviceNum=dev;
++ pPciAgent->function=func;
++
++ /* Fill the PCI Vendor ID and Device ID */
++
++ pPciAgent->venID = (pciData & PDVIR_VEN_ID_MASK) >> PDVIR_VEN_ID_OFFS;
++ pPciAgent->deviceID = (pciData & PDVIR_DEV_ID_MASK) >> PDVIR_DEV_ID_OFFS;
++
++ /* Read Status and command */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_STATUS_AND_COMMAND);
++
++
++ /* Fill related Status and Command information*/
++
++ if (pciData & PSCR_TAR_FAST_BB)
++ {
++ pPciAgent->isFastB2BCapable = MV_TRUE;
++ }
++ else
++ {
++ pPciAgent->isFastB2BCapable = MV_FALSE;
++ }
++
++ if (pciData & PSCR_CAP_LIST)
++ {
++ pPciAgent->isCapListSupport=MV_TRUE;
++ }
++ else
++ {
++ pPciAgent->isCapListSupport=MV_FALSE;
++ }
++
++ if (pciData & PSCR_66MHZ_EN)
++ {
++ pPciAgent->is66MHZCapable=MV_TRUE;
++ }
++ else
++ {
++ pPciAgent->is66MHZCapable=MV_FALSE;
++ }
++
++ /* Read Class Code and Revision */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_CLASS_CODE_AND_REVISION_ID);
++
++
++ pPciAgent->baseClassCode =
++ (pciData & PCCRIR_BASE_CLASS_MASK) >> PCCRIR_BASE_CLASS_OFFS;
++
++ pPciAgent->subClassCode =
++ (pciData & PCCRIR_SUB_CLASS_MASK) >> PCCRIR_SUB_CLASS_OFFS;
++
++ pPciAgent->progIf =
++ (pciData & PCCRIR_PROGIF_MASK) >> PCCRIR_PROGIF_OFFS;
++
++ pPciAgent->revisionID =
++ (pciData & PCCRIR_REVID_MASK) >> PCCRIR_REVID_OFFS;
++
++ /* Read PCI_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE);
++
++
++
++ pPciAgent->pciCacheLine=
++ (pciData & PBHTLTCLR_CACHELINE_MASK ) >> PBHTLTCLR_CACHELINE_OFFS;
++ pPciAgent->pciLatencyTimer=
++ (pciData & PBHTLTCLR_LATTIMER_MASK) >> PBHTLTCLR_LATTIMER_OFFS;
++
++ switch (pciData & PBHTLTCLR_HEADER_MASK)
++ {
++ case PBHTLTCLR_HEADER_STANDARD:
++
++ pPciAgent->pciHeader=MV_PCI_STANDARD;
++ break;
++ case PBHTLTCLR_HEADER_PCI2PCI_BRIDGE:
++
++ pPciAgent->pciHeader=MV_PCI_PCI2PCI_BRIDGE;
++ break;
++
++ }
++
++ if (pciData & PBHTLTCLR_MULTI_FUNC)
++ {
++ pPciAgent->isMultiFunction=MV_TRUE;
++ }
++ else
++ {
++ pPciAgent->isMultiFunction=MV_FALSE;
++ }
++
++ if (pciData & PBHTLTCLR_BISTCAP)
++ {
++ pPciAgent->isBISTCapable=MV_TRUE;
++ }
++ else
++ {
++ pPciAgent->isBISTCapable=MV_FALSE;
++ }
++
++
++ /* read this device pci bars */
++
++ pciDetectDeviceBars(pciIf,
++ bus,dev,func,
++ pPciAgent);
++
++
++ /* check if we are bridge*/
++ if ((pPciAgent->baseClassCode == PCI_BRIDGE_CLASS)&&
++ (pPciAgent->subClassCode == P2P_BRIDGE_SUB_CLASS_CODE))
++ {
++
++ /* Read P2P_BUSSES_NUM */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ P2P_BUSSES_NUM);
++
++ pPciAgent->p2pPrimBusNum =
++ (pciData & PBM_PRIME_BUS_NUM_MASK) >> PBM_PRIME_BUS_NUM_OFFS;
++
++ pPciAgent->p2pSecBusNum =
++ (pciData & PBM_SEC_BUS_NUM_MASK) >> PBM_SEC_BUS_NUM_OFFS;
++
++ pPciAgent->p2pSubBusNum =
++ (pciData & PBM_SUB_BUS_NUM_MASK) >> PBM_SUB_BUS_NUM_OFFS;
++
++ pPciAgent->p2pSecLatencyTimer =
++ (pciData & PBM_SEC_LAT_TMR_MASK) >> PBM_SEC_LAT_TMR_OFFS;
++
++ /* Read P2P_IO_BASE_LIMIT_SEC_STATUS */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ P2P_IO_BASE_LIMIT_SEC_STATUS);
++
++ pPciAgent->p2pSecStatus =
++ (pciData & PIBLSS_SEC_STATUS_MASK) >> PIBLSS_SEC_STATUS_OFFS;
++
++
++ pPciAgent->p2pIObase =
++ (pciData & PIBLSS_IO_BASE_MASK) << PIBLSS_IO_LIMIT_OFFS;
++
++ /* clear low address (should be zero)*/
++ pPciAgent->p2pIObase &= PIBLSS_HIGH_ADDR_MASK;
++
++ pPciAgent->p2pIOLimit =
++ (pciData & PIBLSS_IO_LIMIT_MASK);
++
++ /* fill low address with 0xfff */
++ pPciAgent->p2pIOLimit |= PIBLSS_LOW_ADDR_MASK;
++
++
++ switch ((pciData & PIBLSS_ADD_CAP_MASK) >> PIBLSS_ADD_CAP_OFFS)
++ {
++ case PIBLSS_ADD_CAP_16BIT:
++
++ pPciAgent->bIO32 = MV_FALSE;
++
++ break;
++ case PIBLSS_ADD_CAP_32BIT:
++
++ pPciAgent->bIO32 = MV_TRUE;
++
++ /* Read P2P_IO_BASE_LIMIT_UPPER_16 */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ P2P_IO_BASE_LIMIT_UPPER_16);
++
++ pPciAgent->p2pIObase |=
++ (pciData & PRBU_IO_UPP_BASE_MASK) << PRBU_IO_UPP_LIMIT_OFFS;
++
++
++ pPciAgent->p2pIOLimit |=
++ (pciData & PRBU_IO_UPP_LIMIT_MASK);
++
++ break;
++
++ }
++
++
++ /* Read P2P_MEM_BASE_LIMIT */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ P2P_MEM_BASE_LIMIT);
++
++ pPciAgent->p2pMemBase =
++ (pciData & PMBL_MEM_BASE_MASK) << PMBL_MEM_LIMIT_OFFS;
++
++ /* clear low address */
++ pPciAgent->p2pMemBase &= PMBL_HIGH_ADDR_MASK;
++
++ pPciAgent->p2pMemLimit =
++ (pciData & PMBL_MEM_LIMIT_MASK);
++
++ /* add 0xfffff */
++ pPciAgent->p2pMemLimit |= PMBL_LOW_ADDR_MASK;
++
++
++ /* Read P2P_PREF_MEM_BASE_LIMIT */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ P2P_PREF_MEM_BASE_LIMIT);
++
++
++ pPciAgent->p2pPrefMemBase =
++ (pciData & PRMBL_PREF_MEM_BASE_MASK) << PRMBL_PREF_MEM_LIMIT_OFFS;
++
++ /* get high address only */
++ pPciAgent->p2pPrefMemBase &= PRMBL_HIGH_ADDR_MASK;
++
++
++
++ pPciAgent->p2pPrefMemLimit =
++ (pciData & PRMBL_PREF_MEM_LIMIT_MASK);
++
++ /* add 0xfffff */
++ pPciAgent->p2pPrefMemLimit |= PRMBL_LOW_ADDR_MASK;
++
++ switch (pciData & PRMBL_ADD_CAP_MASK)
++ {
++ case PRMBL_ADD_CAP_32BIT:
++
++ pPciAgent->bPrefMem64 = MV_FALSE;
++
++ /* Read P2P_PREF_BASE_UPPER_32 */
++ pPciAgent->p2pPrefBaseUpper32Bits = 0;
++
++ /* Read P2P_PREF_LIMIT_UPPER_32 */
++ pPciAgent->p2pPrefLimitUpper32Bits = 0;
++
++ break;
++ case PRMBL_ADD_CAP_64BIT:
++
++ pPciAgent->bPrefMem64 = MV_TRUE;
++
++ /* Read P2P_PREF_BASE_UPPER_32 */
++ pPciAgent->p2pPrefBaseUpper32Bits = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ P2P_PREF_BASE_UPPER_32);
++
++ /* Read P2P_PREF_LIMIT_UPPER_32 */
++ pPciAgent->p2pPrefLimitUpper32Bits = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ P2P_PREF_LIMIT_UPPER_32);
++
++ break;
++
++ }
++
++ }
++ else /* no bridge */
++ {
++ /* Read PCI_SUBSYS_ID_AND_SUBSYS_VENDOR_ID */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_SUBSYS_ID_AND_SUBSYS_VENDOR_ID);
++
++
++ pPciAgent->subSysVenID =
++ (pciData & PSISVIR_VENID_MASK) >> PSISVIR_VENID_OFFS;
++ pPciAgent->subSysID =
++ (pciData & PSISVIR_DEVID_MASK) >> PSISVIR_DEVID_OFFS;
++
++
++ /* Read PCI_EXPANSION_ROM_BASE_ADDR_REG */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_EXPANSION_ROM_BASE_ADDR_REG);
++
++
++ if (pciData & PERBAR_EXPROMEN)
++ {
++ pPciAgent->isExpRom = MV_TRUE;
++ }
++ else
++ {
++ pPciAgent->isExpRom = MV_FALSE;
++ }
++
++ pPciAgent->expRomAddr =
++ (pciData & PERBAR_BASE_MASK) >> PERBAR_BASE_OFFS;
++
++ }
++
++
++ if (MV_TRUE == pPciAgent->isCapListSupport)
++ {
++ /* Read PCI_CAPABILTY_LIST_POINTER */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_CAPABILTY_LIST_POINTER);
++
++ pPciAgent->capListPointer =
++ (pciData & PCLPR_CAPPTR_MASK) >> PCLPR_CAPPTR_OFFS;
++
++ }
++
++ /* Read PCI_INTERRUPT_PIN_AND_LINE */
++ pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_INTERRUPT_PIN_AND_LINE);
++
++
++ pPciAgent->irqLine=
++ (pciData & PIPLR_INTLINE_MASK) >> PIPLR_INTLINE_OFFS;
++
++ pPciAgent->intPin=
++ (MV_PCI_INT_PIN)(pciData & PIPLR_INTPIN_MASK) >> PIPLR_INTPIN_OFFS;
++
++ pPciAgent->minGrant=
++ (pciData & PIPLR_MINGRANT_MASK) >> PIPLR_MINGRANT_OFFS;
++ pPciAgent->maxLatency=
++ (pciData & PIPLR_MAXLATEN_MASK) >> PIPLR_MAXLATEN_OFFS;
++
++ mvPciClassNameGet(pPciAgent->baseClassCode,
++ (MV_8 *)pPciAgent->type);
++
++ return MV_OK;
++
++
++}
++
++/*******************************************************************************
++* pciDetectDeviceBars - Detect a pci device bars
++*
++* DESCRIPTION:
++* This function detects all pci agent bars
++*
++* INPUT:
++* pciIf - PCI Interface
++* bus - Bus number
++* dev - Device number
++* func - Function number
++*
++*
++*
++* OUTPUT:
++* pPciAgent - pointer to the pci agent filled with its information
++*
++* RETURN:
++* detected bars number
++*
++*******************************************************************************/
++static MV_U32 pciDetectDeviceBars(MV_U32 pciIf,
++ MV_U32 bus,
++ MV_U32 dev,
++ MV_U32 func,
++ MV_PCI_DEVICE *pPciAgent)
++{
++ MV_U32 pciData,barIndex,detectedBar=0;
++ MV_U32 tmpBaseHigh=0,tmpBaseLow=0;
++ MV_U32 pciMaxBars=0;
++
++ pPciAgent->barsNum=0;
++
++ /* check if we are bridge*/
++ if ((pPciAgent->baseClassCode == PCI_BRIDGE_CLASS)&&
++ (pPciAgent->subClassCode == P2P_BRIDGE_SUB_CLASS_CODE))
++ {
++ pciMaxBars = 2;
++ }
++ else /* no bridge */
++ {
++ pciMaxBars = 6;
++ }
++
++ /* read this device pci bars */
++ for (barIndex = 0 ; barIndex < pciMaxBars ; barIndex++ )
++ {
++ /* Read PCI_MEMORY_BAR_BASE_ADDR */
++ tmpBaseLow = pciData = mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex));
++
++ pPciAgent->pciBar[detectedBar].barOffset =
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex);
++
++ /* check if the bar is 32bit or 64bit bar */
++ switch (pciData & PBBLR_TYPE_MASK)
++ {
++ case PBBLR_TYPE_32BIT_ADDR:
++ pPciAgent->pciBar[detectedBar].barType = PCI_32BIT_BAR;
++ break;
++ case PBBLR_TYPE_64BIT_ADDR:
++ pPciAgent->pciBar[detectedBar].barType = PCI_64BIT_BAR;
++ break;
++
++ }
++
++ /* check if it is memory or IO bar */
++ if (pciData & PBBLR_IOSPACE)
++ {
++ pPciAgent->pciBar[detectedBar].barMapping=PCI_IO_BAR;
++ }
++ else
++ {
++ pPciAgent->pciBar[detectedBar].barMapping=PCI_MEMORY_BAR;
++ }
++
++ /* if it is memory bar then check if it is prefetchable */
++ if (PCI_MEMORY_BAR == pPciAgent->pciBar[detectedBar].barMapping)
++ {
++ if (pciData & PBBLR_PREFETCH_EN)
++ {
++ pPciAgent->pciBar[detectedBar].isPrefetchable = MV_TRUE;
++ }
++ else
++ {
++ pPciAgent->pciBar[detectedBar].isPrefetchable = MV_FALSE;
++ }
++
++ pPciAgent->pciBar[detectedBar].barBaseLow =
++ pciData & PBBLR_MEM_BASE_MASK;
++
++
++ }
++ else /* IO Bar */
++ {
++ pPciAgent->pciBar[detectedBar].barBaseLow =
++ pciData & PBBLR_IO_BASE_MASK;
++
++ }
++
++ pPciAgent->pciBar[detectedBar].barBaseHigh=0;
++
++ if (PCI_64BIT_BAR == pPciAgent->pciBar[detectedBar].barType)
++ {
++ barIndex++;
++
++ tmpBaseHigh = pPciAgent->pciBar[detectedBar].barBaseHigh =
++ mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex));
++
++
++ }
++
++ /* calculating full base address (64bit) */
++ pPciAgent->pciBar[detectedBar].barBaseAddr =
++ (MV_U64)pPciAgent->pciBar[detectedBar].barBaseHigh;
++
++ pPciAgent->pciBar[detectedBar].barBaseAddr <<= 32;
++
++ pPciAgent->pciBar[detectedBar].barBaseAddr |=
++ (MV_U64)pPciAgent->pciBar[detectedBar].barBaseLow;
++
++
++
++ /* get the sizes of the the bar */
++
++ pPciAgent->pciBar[detectedBar].barSizeHigh=0;
++
++ if ((PCI_64BIT_BAR == pPciAgent->pciBar[detectedBar].barType) &&
++ (PCI_MEMORY_BAR == pPciAgent->pciBar[detectedBar].barMapping))
++
++ {
++ /* write oxffffffff to the bar to get the size */
++ /* start with sizelow ( original value was saved in tmpBaseLow ) */
++ mvPciIfConfigWrite(pciIf,
++ bus,dev,func,
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex-1),
++ 0xffffffff);
++
++ /* read size */
++ pPciAgent->pciBar[detectedBar].barSizeLow =
++ mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex-1));
++
++
++
++ /* restore original value */
++ mvPciIfConfigWrite(pciIf,
++ bus,dev,func,
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex-1),
++ tmpBaseLow);
++
++
++ /* now do the same for BaseHigh */
++
++ /* write oxffffffff to the bar to get the size */
++ mvPciIfConfigWrite(pciIf,
++ bus,dev,func,
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex),
++ 0xffffffff);
++
++ /* read size */
++ pPciAgent->pciBar[detectedBar].barSizeHigh =
++ mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex));
++
++ /* restore original value */
++ mvPciIfConfigWrite(pciIf,
++ bus,dev,func,
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex),
++ tmpBaseHigh);
++
++ if ((0 == pPciAgent->pciBar[detectedBar].barSizeLow)&&
++ (0 == pPciAgent->pciBar[detectedBar].barSizeHigh))
++ {
++ /* this bar is not applicable for this device,
++ ignore all previous settings and check the next bar*/
++
++ /* we though this was a 64bit bar , and it seems this
++ was wrong ! so decrement barIndex */
++ barIndex--;
++ continue;
++ }
++
++ /* calculate the full 64 bit size */
++
++ if (0 != pPciAgent->pciBar[detectedBar].barSizeHigh)
++ {
++ pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_MEM_BASE_MASK;
++
++ pPciAgent->pciBar[detectedBar].barSizeLow =
++ ~pPciAgent->pciBar[detectedBar].barSizeLow + 1;
++
++ pPciAgent->pciBar[detectedBar].barSizeHigh = 0;
++
++ }
++ else
++ {
++
++ pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_MEM_BASE_MASK;
++
++ pPciAgent->pciBar[detectedBar].barSizeLow =
++ ~pPciAgent->pciBar[detectedBar].barSizeLow + 1;
++
++ pPciAgent->pciBar[detectedBar].barSizeHigh = 0;
++
++ }
++
++
++
++ }
++ else /* 32bit bar */
++ {
++ /* write oxffffffff to the bar to get the size */
++ mvPciIfConfigWrite(pciIf,
++ bus,dev,func,
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex),
++ 0xffffffff);
++
++ /* read size */
++ pPciAgent->pciBar[detectedBar].barSizeLow =
++ mvPciIfConfigRead(pciIf,
++ bus,dev,func,
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex));
++
++ if (0 == pPciAgent->pciBar[detectedBar].barSizeLow)
++ {
++ /* this bar is not applicable for this device,
++ ignore all previous settings and check the next bar*/
++ continue;
++ }
++
++
++ /* restore original value */
++ mvPciIfConfigWrite(pciIf,
++ bus,dev,func,
++ PCI_MEMORY_BAR_BASE_ADDR(barIndex),
++ tmpBaseLow);
++
++ /* calculate size low */
++
++ if (PCI_MEMORY_BAR == pPciAgent->pciBar[detectedBar].barMapping)
++ {
++ pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_MEM_BASE_MASK;
++ }
++ else
++ {
++ pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_IO_BASE_MASK;
++ }
++
++ pPciAgent->pciBar[detectedBar].barSizeLow =
++ ~pPciAgent->pciBar[detectedBar].barSizeLow + 1;
++
++ pPciAgent->pciBar[detectedBar].barSizeHigh = 0;
++ pPciAgent->pciBar[detectedBar].barSize =
++ (MV_U64)pPciAgent->pciBar[detectedBar].barSizeLow;
++
++
++ }
++
++ /* we are here ! this means we have already detected a bar for
++ this device , now move on */
++
++ detectedBar++;
++ pPciAgent->barsNum++;
++ }
++
++ return detectedBar;
++}
++
++
++/*******************************************************************************
++* mvPciClassNameGet - get PCI class name
++*
++* DESCRIPTION:
++* This function returns the PCI class name
++*
++* INPUT:
++* baseClassCode - Base Class Code.
++*
++* OUTPUT:
++* pType - the class name
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPciClassNameGet(MV_U32 baseClassCode, MV_8 *pType)
++{
++
++ switch(baseClassCode)
++ {
++ case 0x0:
++ strcpy(pType,"Old generation device");
++ break;
++ case 0x1:
++ strcpy(pType,"Mass storage controller");
++ break;
++ case 0x2:
++ strcpy(pType,"Network controller");
++ break;
++ case 0x3:
++ strcpy(pType,"Display controller");
++ break;
++ case 0x4:
++ strcpy(pType,"Multimedia device");
++ break;
++ case 0x5:
++ strcpy(pType,"Memory controller");
++ break;
++ case 0x6:
++ strcpy(pType,"Bridge Device");
++ break;
++ case 0x7:
++ strcpy(pType,"Simple Communication controllers");
++ break;
++ case 0x8:
++ strcpy(pType,"Base system peripherals");
++ break;
++ case 0x9:
++ strcpy(pType,"Input Devices");
++ break;
++ case 0xa:
++ strcpy(pType,"Docking stations");
++ break;
++ case 0xb:
++ strcpy(pType,"Processors");
++ break;
++ case 0xc:
++ strcpy(pType,"Serial bus controllers");
++ break;
++ case 0xd:
++ strcpy(pType,"Wireless controllers");
++ break;
++ case 0xe:
++ strcpy(pType,"Intelligent I/O controllers");
++ break;
++ case 0xf:
++ strcpy(pType,"Satellite communication controllers");
++ break;
++ case 0x10:
++ strcpy(pType,"Encryption/Decryption controllers");
++ break;
++ case 0x11:
++ strcpy(pType,"Data acquisition and signal processing controllers");
++ break;
++ default:
++ strcpy(pType,"Unknown device");
++ break;
++ }
++
++ return MV_OK;
++
++}
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.h 2010-11-09 20:28:11.662495451 +0100
+@@ -0,0 +1,323 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvPciUtilsh
++#define __INCmvPciUtilsh
++
++/*
++This module only support scanning of Header type 00h of pci devices
++There is no suppotr for Header type 01h of pci devices ( PCI bridges )
++*/
++
++/* includes */
++#include "mvSysHwConfig.h"
++#include "pci-if/mvPciIf.h"
++#include "pci/mvPciRegs.h"
++
++
++
++/* PCI base address low bar mask */
++#define PCI_ERROR_CODE 0xffffffff
++
++#define PCI_BRIDGE_CLASS 0x6
++#define P2P_BRIDGE_SUB_CLASS_CODE 0x4
++
++
++#define P2P_BUSSES_NUM 0x18
++#define P2P_IO_BASE_LIMIT_SEC_STATUS 0x1C
++#define P2P_MEM_BASE_LIMIT 0x20
++#define P2P_PREF_MEM_BASE_LIMIT 0x24
++#define P2P_PREF_BASE_UPPER_32 0x28
++#define P2P_PREF_LIMIT_UPPER_32 0x2C
++#define P2P_IO_BASE_LIMIT_UPPER_16 0x30
++#define P2P_EXP_ROM 0x38
++
++/* P2P_BUSSES_NUM (PBM) */
++
++#define PBM_PRIME_BUS_NUM_OFFS 0
++#define PBM_PRIME_BUS_NUM_MASK (0xff << PBM_PRIME_BUS_NUM_OFFS)
++
++#define PBM_SEC_BUS_NUM_OFFS 8
++#define PBM_SEC_BUS_NUM_MASK (0xff << PBM_SEC_BUS_NUM_OFFS)
++
++#define PBM_SUB_BUS_NUM_OFFS 16
++#define PBM_SUB_BUS_NUM_MASK (0xff << PBM_SUB_BUS_NUM_OFFS)
++
++#define PBM_SEC_LAT_TMR_OFFS 24
++#define PBM_SEC_LAT_TMR_MASK (0xff << PBM_SEC_LAT_TMR_OFFS)
++
++/* P2P_IO_BASE_LIMIT_SEC_STATUS (PIBLSS) */
++
++#define PIBLSS_IO_BASE_OFFS 0
++#define PIBLSS_IO_BASE_MASK (0xff << PIBLSS_IO_BASE_OFFS)
++
++#define PIBLSS_ADD_CAP_OFFS 0
++#define PIBLSS_ADD_CAP_MASK (0x3 << PIBLSS_ADD_CAP_OFFS)
++#define PIBLSS_ADD_CAP_16BIT (0x0 << PIBLSS_ADD_CAP_OFFS)
++#define PIBLSS_ADD_CAP_32BIT (0x1 << PIBLSS_ADD_CAP_OFFS)
++
++#define PIBLSS_LOW_ADDR_OFFS 0
++#define PIBLSS_LOW_ADDR_MASK (0xFFF << PIBLSS_LOW_ADDR_OFFS)
++
++#define PIBLSS_HIGH_ADDR_OFFS 12
++#define PIBLSS_HIGH_ADDR_MASK (0xF << PIBLSS_HIGH_ADDR_OFFS)
++
++#define PIBLSS_IO_LIMIT_OFFS 8
++#define PIBLSS_IO_LIMIT_MASK (0xff << PIBLSS_IO_LIMIT_OFFS)
++
++#define PIBLSS_SEC_STATUS_OFFS 16
++#define PIBLSS_SEC_STATUS_MASK (0xffff << PIBLSS_SEC_STATUS_OFFS)
++
++
++/* P2P_MEM_BASE_LIMIT (PMBL)*/
++
++#define PMBL_MEM_BASE_OFFS 0
++#define PMBL_MEM_BASE_MASK (0xffff << PMBL_MEM_BASE_OFFS)
++
++#define PMBL_MEM_LIMIT_OFFS 16
++#define PMBL_MEM_LIMIT_MASK (0xffff << PMBL_MEM_LIMIT_OFFS)
++
++
++#define PMBL_LOW_ADDR_OFFS 0
++#define PMBL_LOW_ADDR_MASK (0xFFFFF << PMBL_LOW_ADDR_OFFS)
++
++#define PMBL_HIGH_ADDR_OFFS 20
++#define PMBL_HIGH_ADDR_MASK (0xFFF << PMBL_HIGH_ADDR_OFFS)
++
++
++/* P2P_PREF_MEM_BASE_LIMIT (PRMBL) */
++
++#define PRMBL_PREF_MEM_BASE_OFFS 0
++#define PRMBL_PREF_MEM_BASE_MASK (0xffff << PRMBL_PREF_MEM_BASE_OFFS)
++
++#define PRMBL_PREF_MEM_LIMIT_OFFS 16
++#define PRMBL_PREF_MEM_LIMIT_MASK (0xffff<<PRMBL_PREF_MEM_LIMIT_OFFS)
++
++#define PRMBL_LOW_ADDR_OFFS 0
++#define PRMBL_LOW_ADDR_MASK (0xFFFFF << PRMBL_LOW_ADDR_OFFS)
++
++#define PRMBL_HIGH_ADDR_OFFS 20
++#define PRMBL_HIGH_ADDR_MASK (0xFFF << PRMBL_HIGH_ADDR_OFFS)
++
++#define PRMBL_ADD_CAP_OFFS 0
++#define PRMBL_ADD_CAP_MASK (0xf << PRMBL_ADD_CAP_OFFS)
++#define PRMBL_ADD_CAP_32BIT (0x0 << PRMBL_ADD_CAP_OFFS)
++#define PRMBL_ADD_CAP_64BIT (0x1 << PRMBL_ADD_CAP_OFFS)
++
++/* P2P_IO_BASE_LIMIT_UPPER_16 (PIBLU) */
++
++#define PRBU_IO_UPP_BASE_OFFS 0
++#define PRBU_IO_UPP_BASE_MASK (0xffff << PRBU_IO_UPP_BASE_OFFS)
++
++#define PRBU_IO_UPP_LIMIT_OFFS 16
++#define PRBU_IO_UPP_LIMIT_MASK (0xffff << PRBU_IO_UPP_LIMIT_OFFS)
++
++
++/* typedefs */
++
++typedef enum _mvPciBarMapping
++{
++ PCI_MEMORY_BAR,
++ PCI_IO_BAR,
++ PCI_NO_MAPPING
++}MV_PCI_BAR_MAPPING;
++
++typedef enum _mvPciBarType
++{
++ PCI_32BIT_BAR,
++ PCI_64BIT_BAR
++}MV_PCI_BAR_TYPE;
++
++typedef enum _mvPciIntPin
++{
++ MV_PCI_INTA = 1,
++ MV_PCI_INTB = 2,
++ MV_PCI_INTC = 3,
++ MV_PCI_INTD = 4
++}MV_PCI_INT_PIN;
++
++typedef enum _mvPciHeader
++{
++ MV_PCI_STANDARD,
++ MV_PCI_PCI2PCI_BRIDGE
++
++}MV_PCI_HEADER;
++
++
++/* BAR structure */
++typedef struct _pciBar
++{
++ MV_U32 barOffset;
++ MV_U32 barBaseLow;
++ MV_U32 barBaseHigh;
++ MV_U32 barSizeLow;
++ MV_U32 barSizeHigh;
++ /* The 'barBaseAddr' is a 64-bit variable
++ that will contain the TOTAL base address
++ value achived by combining both the 'barBaseLow'
++ and the 'barBaseHigh' parameters as follows:
++
++ BIT: 63 31 0
++ | | |
++ barBaseHigh barBaseLow */
++ MV_U64 barBaseAddr;
++ /* The 'barSize' is a 64-bit variable
++ that will contain the TOTAL size achived
++ by combining both the 'barSizeLow' and
++ the 'barSizeHigh' parameters as follows:
++
++ BIT: 63 31 0
++ | | |
++ barSizeHigh barSizeLow
++
++ NOTE: The total size described above
++ is AFTER the size calculation as
++ described in PCI spec rev2.2 */
++ MV_U64 barSize;
++ MV_BOOL isPrefetchable;
++ MV_PCI_BAR_TYPE barType;
++ MV_PCI_BAR_MAPPING barMapping;
++
++
++} PCI_BAR;
++
++/* Device information structure */
++typedef struct _mvPciDevice
++{
++ /* Device specific information */
++ MV_U32 busNumber; /* Pci agent bus number */
++ MV_U32 deviceNum; /* Pci agent device number */
++ MV_U32 function; /* Pci agent function number */
++
++ MV_U32 venID; /* Pci agent Vendor ID */
++ MV_U32 deviceID; /* Pci agent Device ID */
++
++ MV_BOOL isFastB2BCapable; /* Capability of Fast Back to Back
++ transactions */
++ MV_BOOL isCapListSupport; /* Support of Capability list */
++ MV_BOOL is66MHZCapable; /* 66MHZ support */
++
++ MV_U32 baseClassCode; /* Pci agent base Class Code */
++ MV_U32 subClassCode; /* Pci agent sub Class Code */
++ MV_U32 progIf; /* Pci agent Programing interface */
++ MV_U32 revisionID;
++
++ PCI_BAR pciBar[6]; /* Pci agent bar list */
++
++ MV_U32 p2pPrimBusNum; /* P2P Primary Bus number*/
++ MV_U32 p2pSecBusNum; /* P2P Secondary Bus Number*/
++ MV_U32 p2pSubBusNum; /* P2P Subordinate bus Number */
++ MV_U32 p2pSecLatencyTimer; /* P2P Econdary Latency Timer*/
++ MV_U32 p2pIObase; /* P2P IO Base */
++ MV_U32 p2pIOLimit; /* P2P IO Linit */
++ MV_BOOL bIO32;
++ MV_U32 p2pSecStatus; /* P2P Secondary Status */
++ MV_U32 p2pMemBase; /* P2P Memory Space */
++ MV_U32 p2pMemLimit; /* P2P Memory Limit*/
++ MV_U32 p2pPrefMemBase; /* P2P Prefetchable Mem Base*/
++ MV_U32 p2pPrefMemLimit; /* P2P Prefetchable Memory Limit*/
++ MV_BOOL bPrefMem64;
++ MV_U32 p2pPrefBaseUpper32Bits;/* P2P Prefetchable upper 32 bits*/
++ MV_U32 p2pPrefLimitUpper32Bits;/* P2P prefetchable limit upper 32*/
++
++
++ MV_U32 pciCacheLine; /* Pci agent cache line */
++ MV_U32 pciLatencyTimer; /* Pci agent Latency timer */
++ MV_PCI_HEADER pciHeader; /* Pci agent header type*/
++ MV_BOOL isMultiFunction; /* Multi function support */
++ MV_BOOL isBISTCapable; /* Self test capable */
++
++ MV_U32 subSysID; /* Sub System ID */
++ MV_U32 subSysVenID; /* Sub System Vendor ID */
++
++ MV_BOOL isExpRom; /* Expantion Rom support */
++ MV_U32 expRomAddr; /* Expantion Rom pointer */
++
++ MV_U32 capListPointer; /* Capability list pointer */
++
++ MV_U32 irqLine; /* IRQ line */
++ MV_PCI_INT_PIN intPin; /* Interrupt pin */
++ MV_U32 minGrant; /* Minimum grant*/
++ MV_U32 maxLatency; /* Maximum latency*/
++
++ MV_U32 funtionsNum; /* pci agent total functions number */
++
++ MV_U32 barsNum;
++ MV_U8 type[60]; /* class name of the pci agent */
++
++
++} MV_PCI_DEVICE;
++
++/* PCI gloabl functions */
++MV_STATUS mvPciClassNameGet(MV_U32 classCode, MV_8 *pType);
++
++
++/* Performs a full scan on both PCIs and returns all possible details on the
++ agents found on the bus. */
++MV_STATUS mvPciScan(MV_U32 pciIf,
++ MV_PCI_DEVICE *pPciAgents,
++ MV_U32 *pPciAgentsNum);
++
++
++#endif /* #ifndef __INCmvPciUtilsh */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.c 2010-11-09 20:28:11.702495387 +0100
+@@ -0,0 +1,1143 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "pex/mvPex.h"
++
++#include "ctrlEnv/mvCtrlEnvLib.h"
++
++/* defines */
++#ifdef MV_DEBUG
++#define DB(x) x
++#else
++#define DB(x)
++#endif
++
++MV_STATUS mvPexHalInit(MV_U32 pexIf, MV_PEX_TYPE pexType)
++{
++ MV_PEX_MODE pexMode;
++ MV_U32 regVal;
++ MV_U32 status;
++
++ /* First implement Guideline (GL# PCI Express-2) Wrong Default Value */
++ /* to Transmitter Output Current (TXAMP) Relevant for: 88F5181-A1/B0/B1 */
++ /* and 88F5281-B0 and above, 88F5182, 88F5082, 88F5181L, 88F6082/L */
++
++ if ((mvCtrlModelGet() != MV_1281_DEV_ID) &&
++ (mvCtrlModelGet() != MV_6281_DEV_ID) &&
++ (mvCtrlModelGet() != MV_6192_DEV_ID) &&
++ (mvCtrlModelGet() != MV_6190_DEV_ID) &&
++ (mvCtrlModelGet() != MV_6180_DEV_ID) &&
++ (mvCtrlModelGet() != MV_6183_DEV_ID) &&
++ (mvCtrlModelGet() != MV_6183L_DEV_ID) &&
++ (mvCtrlModelGet() != MV_78100_DEV_ID) &&
++ (mvCtrlModelGet() != MV_78200_DEV_ID) &&
++ (mvCtrlModelGet() != MV_76100_DEV_ID) &&
++ (mvCtrlModelGet() != MV_78XX0_DEV_ID))
++ {
++
++ /* Read current value of TXAMP */
++ MV_REG_WRITE(0x41b00, 0x80820000); /* Write the read command */
++
++ regVal = MV_REG_READ(0x41b00); /* Extract the data */
++
++ /* Prepare new data for write */
++ regVal &= ~0x7; /* Clear bits [2:0] */
++ regVal |= 0x4; /* Set the new value */
++ regVal &= ~0x80000000; /* Set "write" command */
++ MV_REG_WRITE(0x41b00, regVal); /* Write the write command */
++
++ }
++ else
++ {
++ /* Implement 1.0V termination GL for 88F1281 device only */
++ /* BIT0 - Common mode feedback */
++ /* BIT3 - TxBuf, extra drive for 1.0V termination */
++ if (mvCtrlModelGet() == MV_1281_DEV_ID)
++ {
++ MV_REG_WRITE(0x41b00, 0x80860000); /* Write the read command */
++ regVal = MV_REG_READ(0x41b00); /* Extract the data */
++ regVal |= (BIT0 | BIT3);
++ regVal &= ~0x80000000; /* Set "write" command */
++ MV_REG_WRITE(0x41b00, regVal); /* Write the write command */
++
++ MV_REG_WRITE(0x31b00, 0x80860000); /* Write the read command */
++ regVal = MV_REG_READ(0x31b00); /* Extract the data */
++ regVal |= (BIT0 | BIT3);
++ regVal &= ~0x80000000; /* Set "write" command */
++ MV_REG_WRITE(0x31b00, regVal); /* Write the write command */
++ }
++ }
++
++ if( mvPexModeGet(pexIf, &pexMode) != MV_OK)
++ {
++ mvOsPrintf("PEX init ERR. mvPexModeGet failed (pexType=%d)\n",pexMode.pexType);
++ return MV_ERROR;
++ }
++
++ /* Check that required PEX type is the one set in reset time */
++ if (pexType != pexMode.pexType)
++ {
++ /* No Link. Shut down the Phy */
++ mvPexPowerDown(pexIf);
++ mvOsPrintf("PEX init ERR. PEX type sampled mismatch (%d,%d)\n",pexType,pexMode.pexType);
++ return MV_ERROR;
++ }
++
++ if (MV_PEX_ROOT_COMPLEX == pexType)
++ {
++ mvPexLocalBusNumSet(pexIf, PEX_HOST_BUS_NUM(pexIf));
++ mvPexLocalDevNumSet(pexIf, PEX_HOST_DEV_NUM(pexIf));
++
++ /* Local device master Enable */
++ mvPexMasterEnable(pexIf, MV_TRUE);
++
++ /* Local device slave Enable */
++ mvPexSlaveEnable(pexIf, mvPexLocalBusNumGet(pexIf),
++ mvPexLocalDevNumGet(pexIf), MV_TRUE);
++ /* Interrupt disable */
++ status = MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_STATUS_AND_COMMAND));
++ status |= PXSAC_INT_DIS;
++ MV_REG_WRITE(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_STATUS_AND_COMMAND), status);
++ }
++
++ /* now wait 500 ms to be sure the link is valid (spec compliant) */
++ mvOsDelay(500);
++ /* Check if we have link */
++ if (MV_REG_READ(PEX_STATUS_REG(pexIf)) & PXSR_DL_DOWN)
++ {
++ mvOsPrintf("PEX%d interface detected no Link.\n",pexIf);
++ return MV_NO_SUCH;
++ }
++
++ if (MV_PEX_WITDH_X1 == pexMode.pexWidth)
++ {
++ mvOsPrintf("PEX%d interface detected Link X1\n",pexIf);
++ }
++ else
++ {
++ mvOsPrintf("PEX%d interface detected Link X4\n",pexIf);
++ }
++
++#ifdef PCIE_VIRTUAL_BRIDGE_SUPPORT
++ mvPexVrtBrgInit(pexIf);
++#endif
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvPexModeGet - Get Pex Mode
++*
++* DESCRIPTION:
++*
++* INPUT:
++* pexIf - PEX interface number.
++*
++* OUTPUT:
++* pexMode - Pex mode structure
++*
++* RETURN:
++* MV_OK on success , MV_ERROR otherwise
++*
++*******************************************************************************/
++MV_U32 mvPexModeGet(MV_U32 pexIf,MV_PEX_MODE *pexMode)
++{
++ MV_U32 pexData;
++
++ /* Parameter checking */
++ if (PEX_DEFAULT_IF != pexIf)
++ {
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexModeGet: ERR. Invalid PEX interface %d\n",pexIf);
++ return MV_ERROR;
++ }
++ }
++
++ pexData = MV_REG_READ(PEX_CTRL_REG(pexIf));
++
++ switch (pexData & PXCR_DEV_TYPE_CTRL_MASK)
++ {
++ case PXCR_DEV_TYPE_CTRL_CMPLX:
++ pexMode->pexType = MV_PEX_ROOT_COMPLEX;
++ break;
++ case PXCR_DEV_TYPE_CTRL_POINT:
++ pexMode->pexType = MV_PEX_END_POINT;
++ break;
++
++ }
++
++ /* Check if we have link */
++ if (MV_REG_READ(PEX_STATUS_REG(pexIf)) & PXSR_DL_DOWN)
++ {
++ pexMode->pexLinkUp = MV_FALSE;
++
++ /* If there is no link, the auto negotiation data is worthless */
++ pexMode->pexWidth = MV_PEX_WITDH_INVALID;
++ }
++ else
++ {
++ pexMode->pexLinkUp = MV_TRUE;
++
++ /* We have link. The link width is now valid */
++ pexData = MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_LINK_CTRL_STAT_REG));
++ pexMode->pexWidth = ((pexData & PXLCSR_NEG_LNK_WDTH_MASK) >>
++ PXLCSR_NEG_LNK_WDTH_OFFS);
++ }
++
++ return MV_OK;
++}
++
++
++/* PEX configuration space read write */
++
++/*******************************************************************************
++* mvPexConfigRead - Read from configuration space
++*
++* DESCRIPTION:
++* This function performs a 32 bit read from PEX configuration space.
++* It supports both type 0 and type 1 of Configuration Transactions
++* (local and over bridge). In order to read from local bus segment, use
++* bus number retrieved from mvPexLocalBusNumGet(). Other bus numbers
++* will result configuration transaction of type 1 (over bridge).
++*
++* INPUT:
++* pexIf - PEX interface number.
++* bus - PEX segment bus number.
++* dev - PEX device number.
++* func - Function number.
++* regOffs - Register offset.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* 32bit register data, 0xffffffff on error
++*
++*******************************************************************************/
++MV_U32 mvPexConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func,
++ MV_U32 regOff)
++{
++#if defined(PCIE_VIRTUAL_BRIDGE_SUPPORT)
++ return mvPexVrtBrgConfigRead (pexIf, bus, dev, func, regOff);
++}
++
++MV_U32 mvPexHwConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func,
++ MV_U32 regOff)
++{
++#endif
++ MV_U32 pexData = 0;
++ MV_U32 localDev,localBus;
++
++ /* Parameter checking */
++ if (PEX_DEFAULT_IF != pexIf)
++ {
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexConfigRead: ERR. Invalid PEX interface %d\n",pexIf);
++ return 0xFFFFFFFF;
++ }
++ }
++
++ if (dev >= MAX_PEX_DEVICES)
++ {
++ DB(mvOsPrintf("mvPexConfigRead: ERR. device number illigal %d\n", dev));
++ return 0xFFFFFFFF;
++ }
++
++ if (func >= MAX_PEX_FUNCS)
++ {
++ DB(mvOsPrintf("mvPexConfigRead: ERR. function num illigal %d\n", func));
++ return 0xFFFFFFFF;
++ }
++
++ if (bus >= MAX_PEX_BUSSES)
++ {
++ DB(mvOsPrintf("mvPexConfigRead: ERR. bus number illigal %d\n", bus));
++ return MV_ERROR;
++ }
++
++ DB(mvOsPrintf("mvPexConfigRead: pexIf %d, bus %d, dev %d, func %d, regOff 0x%x\n",
++ pexIf, bus, dev, func, regOff));
++
++ localDev = mvPexLocalDevNumGet(pexIf);
++ localBus = mvPexLocalBusNumGet(pexIf);
++
++ /* Speed up the process. In case on no link, return MV_ERROR */
++ if ((dev != localDev) || (bus != localBus))
++ {
++ pexData = MV_REG_READ(PEX_STATUS_REG(pexIf));
++
++ if ((pexData & PXSR_DL_DOWN))
++ {
++ return MV_ERROR;
++ }
++ }
++
++ /* in PCI Express we have only one device number */
++ /* and this number is the first number we encounter
++ else that the localDev*/
++ /* spec pex define return on config read/write on any device */
++ if (bus == localBus)
++ {
++ if (localDev == 0)
++ {
++ /* if local dev is 0 then the first number we encounter
++ after 0 is 1 */
++ if ((dev != 1)&&(dev != localDev))
++ {
++ return MV_ERROR;
++ }
++ }
++ else
++ {
++ /* if local dev is not 0 then the first number we encounter
++ is 0 */
++
++ if ((dev != 0)&&(dev != localDev))
++ {
++ return MV_ERROR;
++ }
++ }
++ if(func != 0 ) /* i.e bridge */
++ {
++ return MV_ERROR;
++ }
++ }
++
++
++ /* Creating PEX address to be passed */
++ pexData = (bus << PXCAR_BUS_NUM_OFFS);
++ pexData |= (dev << PXCAR_DEVICE_NUM_OFFS);
++ pexData |= (func << PXCAR_FUNC_NUM_OFFS);
++ pexData |= (regOff & PXCAR_REG_NUM_MASK); /* lgacy register space */
++ /* extended register space */
++ pexData |=(((regOff & PXCAR_REAL_EXT_REG_NUM_MASK) >>
++ PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS);
++
++ pexData |= PXCAR_CONFIG_EN;
++
++ /* Write the address to the PEX configuration address register */
++ MV_REG_WRITE(PEX_CFG_ADDR_REG(pexIf), pexData);
++
++ DB(mvOsPrintf("mvPexConfigRead:address pexData=%x ",pexData));
++
++
++ /* In order to let the PEX controller absorbed the address of the read */
++ /* transaction we perform a validity check that the address was written */
++ if(pexData != MV_REG_READ(PEX_CFG_ADDR_REG(pexIf)))
++ {
++ return MV_ERROR;
++ }
++
++ /* cleaning Master Abort */
++ MV_REG_BIT_SET(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_STATUS_AND_COMMAND),
++ PXSAC_MABORT);
++#if 0
++ /* Guideline (GL# PCI Express-1) Erroneous Read Data on Configuration */
++ /* This guideline is relevant for all devices except of the following devices:
++ 88F5281-BO and above, 88F5181L-A0 and above, 88F1281 A0 and above
++ 88F6183 A0 and above, 88F6183L */
++ if ( ( (dev != localDev) || (bus != localBus) ) &&
++ (
++ !(MV_5281_DEV_ID == mvCtrlModelGet())&&
++ !((MV_5181_DEV_ID == mvCtrlModelGet())&& (mvCtrlRevGet() >= MV_5181L_A0_REV))&&
++ !(MV_1281_DEV_ID == mvCtrlModelGet())&&
++ !(MV_6183_DEV_ID == mvCtrlModelGet())&&
++ !(MV_6183L_DEV_ID == mvCtrlModelGet())&&
++ !(MV_6281_DEV_ID == mvCtrlModelGet())&&
++ !(MV_6192_DEV_ID == mvCtrlModelGet())&&
++ !(MV_6190_DEV_ID == mvCtrlModelGet())&&
++ !(MV_6180_DEV_ID == mvCtrlModelGet())&&
++ !(MV_78XX0_DEV_ID == mvCtrlModelGet())
++ ))
++ {
++
++ /* PCI-Express configuration read work-around */
++
++ /* we will use one of the Punit (AHBToMbus) windows to access the xbar
++ and read the data from there */
++ /*
++ Need to configure the 2 free Punit (AHB to MBus bridge)
++ address decoding windows:
++ Configure the flash Window to handle Configuration space requests
++ for PEX0/1:
++ 1. write 0x7931/0x7941 to the flash window and the size,
++ 79-xbar attr (pci cfg), 3/4-xbar target (pex0/1), 1-WinEn
++ 2. write base to flash window
++
++ Configuration transactions from the CPU should write/read the data
++ to/from address of the form:
++ addr[31:28] = 0x5 (for PEX0) or 0x6 (for PEX1)
++ addr[27:24] = extended register number
++ addr[23:16] = bus number
++ addr[15:11] = device number
++ addr[10:8] = function number
++ addr[7:0] = register number
++ */
++
++ #include "ctrlEnv/sys/mvAhbToMbus.h"
++ {
++ MV_U32 winNum;
++ MV_AHB_TO_MBUS_DEC_WIN originWin;
++ MV_U32 pciAddr=0;
++ MV_U32 remapLow=0,remapHigh=0;
++
++ /*
++ We will use DEV_CS2\Flash window for this workarround
++ */
++
++ winNum = mvAhbToMbusWinTargetGet(PEX_CONFIG_RW_WA_TARGET);
++
++ /* save remap values if exist */
++ if ((1 == winNum)||(0 == winNum))
++ {
++ remapLow = MV_REG_READ(AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum));
++ remapHigh = MV_REG_READ(AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum));
++
++ }
++
++
++ /* save the original window values */
++ mvAhbToMbusWinGet(winNum,&originWin);
++
++ if (PEX_CONFIG_RW_WA_USE_ORIGINAL_WIN_VALUES)
++ {
++ /* set the window as xbar window */
++ if (pexIf)
++ {
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_CTRL_REG(winNum),
++ (0x7931 | (((originWin.addrWin.size >> 16)-1) ) << 16));
++ }
++ else
++ {
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_CTRL_REG(winNum),
++ (0x7941 | (((originWin.addrWin.size >> 16)-1) ) << 16));
++ }
++
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_BASE_REG(winNum),
++ originWin.addrWin.baseLow);
++
++ /*pciAddr = originWin.addrWin.baseLow;*/
++ pciAddr = (MV_U32)CPU_MEMIO_UNCACHED_ADDR(
++ (MV_U32)originWin.addrWin.baseLow);
++
++ }
++ else
++ {
++ /* set the window as xbar window */
++ if (pexIf)
++ {
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_CTRL_REG(winNum),
++ (0x7931 | (((PEX_CONFIG_RW_WA_SIZE >> 16)-1) ) << 16));
++ }
++ else
++ {
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_CTRL_REG(winNum),
++ (0x7941 | (((PEX_CONFIG_RW_WA_SIZE >> 16)-1) ) << 16));
++ }
++
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_BASE_REG(winNum),
++ PEX_CONFIG_RW_WA_BASE);
++
++ pciAddr = (MV_U32)CPU_MEMIO_UNCACHED_ADDR(PEX_CONFIG_RW_WA_BASE);
++ }
++
++
++ /* remap should be as base */
++ if ((1 == winNum)||(0 == winNum))
++ {
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum),pciAddr);
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum),0);
++
++ }
++
++ /* extended register space */
++ pciAddr |= (bus << 16);
++ pciAddr |= (dev << 11);
++ pciAddr |= (func << 8);
++ pciAddr |= (regOff & PXCAR_REG_NUM_MASK); /* lgacy register space */
++
++ pexData = *(MV_U32*)pciAddr;
++ pexData = MV_32BIT_LE(pexData); /* Data always in LE */
++
++ /* restore the original window values */
++ mvAhbToMbusWinSet(winNum,&originWin);
++
++ /* restore original remap values*/
++ if ((1 == winNum)||(0 == winNum))
++ {
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum),remapLow);
++ MV_REG_WRITE(AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum),remapHigh);
++
++ }
++ }
++ }
++ else
++#endif
++ {
++ /* Read the Data returned in the PEX Data register */
++ pexData = MV_REG_READ(PEX_CFG_DATA_REG(pexIf));
++
++ }
++
++ DB(mvOsPrintf("mvPexConfigRead: got : %x \n",pexData));
++
++ return pexData;
++
++}
++
++/*******************************************************************************
++* mvPexConfigWrite - Write to configuration space
++*
++* DESCRIPTION:
++* This function performs a 32 bit write to PEX configuration space.
++* It supports both type 0 and type 1 of Configuration Transactions
++* (local and over bridge). In order to write to local bus segment, use
++* bus number retrieved from mvPexLocalBusNumGet(). Other bus numbers
++* will result configuration transaction of type 1 (over bridge).
++*
++* INPUT:
++* pexIf - PEX interface number.
++* bus - PEX segment bus number.
++* dev - PEX device number.
++* func - Function number.
++* regOffs - Register offset.
++* data - 32bit data.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPexConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func, MV_U32 regOff, MV_U32 data)
++{
++#if defined(PCIE_VIRTUAL_BRIDGE_SUPPORT)
++ return mvPexVrtBrgConfigWrite (pexIf, bus, dev, func, regOff, data);
++}
++
++MV_STATUS mvPexHwConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func, MV_U32 regOff, MV_U32 data)
++{
++#endif
++ MV_U32 pexData = 0;
++ MV_U32 localDev,localBus;
++
++ /* Parameter checking */
++ if (PEX_DEFAULT_IF != pexIf)
++ {
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexConfigWrite: ERR. Invalid PEX interface %d\n",
++ pexIf);
++ return MV_ERROR;
++ }
++ }
++
++ if (dev >= MAX_PEX_DEVICES)
++ {
++ mvOsPrintf("mvPexConfigWrite: ERR. device number illigal %d\n",dev);
++ return MV_BAD_PARAM;
++ }
++
++ if (func >= MAX_PEX_FUNCS)
++ {
++ mvOsPrintf("mvPexConfigWrite: ERR. function number illigal %d\n", func);
++ return MV_ERROR;
++ }
++
++ if (bus >= MAX_PEX_BUSSES)
++ {
++ mvOsPrintf("mvPexConfigWrite: ERR. bus number illigal %d\n", bus);
++ return MV_ERROR;
++ }
++
++
++
++ localDev = mvPexLocalDevNumGet(pexIf);
++ localBus = mvPexLocalBusNumGet(pexIf);
++
++
++ /* in PCI Express we have only one device number other than ourselves*/
++ /* and this number is the first number we encounter
++ else than the localDev that can be any valid dev number*/
++ /* pex spec define return on config read/write on any device */
++ if (bus == localBus)
++ {
++
++ if (localDev == 0)
++ {
++ /* if local dev is 0 then the first number we encounter
++ after 0 is 1 */
++ if ((dev != 1)&&(dev != localDev))
++ {
++ return MV_ERROR;
++ }
++
++ }
++ else
++ {
++ /* if local dev is not 0 then the first number we encounter
++ is 0 */
++
++ if ((dev != 0)&&(dev != localDev))
++ {
++ return MV_ERROR;
++ }
++ }
++
++
++ }
++
++ /* if we are not accessing ourselves , then check the link */
++ if ((dev != localDev) || (bus != localBus) )
++ {
++ /* workarround */
++ /* when no link return MV_ERROR */
++
++ pexData = MV_REG_READ(PEX_STATUS_REG(pexIf));
++
++ if ((pexData & PXSR_DL_DOWN))
++ {
++ return MV_ERROR;
++ }
++
++ }
++
++ pexData =0;
++
++ /* Creating PEX address to be passed */
++ pexData |= (bus << PXCAR_BUS_NUM_OFFS);
++ pexData |= (dev << PXCAR_DEVICE_NUM_OFFS);
++ pexData |= (func << PXCAR_FUNC_NUM_OFFS);
++ pexData |= (regOff & PXCAR_REG_NUM_MASK); /* lgacy register space */
++ /* extended register space */
++ pexData |=(((regOff & PXCAR_REAL_EXT_REG_NUM_MASK) >>
++ PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS);
++ pexData |= PXCAR_CONFIG_EN;
++
++ DB(mvOsPrintf("mvPexConfigWrite: If=%x bus=%x func=%x dev=%x regOff=%x data=%x \n",
++ pexIf,bus,func,dev,regOff,data,pexData) );
++
++ /* Write the address to the PEX configuration address register */
++ MV_REG_WRITE(PEX_CFG_ADDR_REG(pexIf), pexData);
++
++ /* Clear CPU pipe. Important where CPU can perform OOO execution */
++ CPU_PIPE_FLUSH;
++
++ /* In order to let the PEX controller absorbed the address of the read */
++ /* transaction we perform a validity check that the address was written */
++ if(pexData != MV_REG_READ(PEX_CFG_ADDR_REG(pexIf)))
++ {
++ return MV_ERROR;
++ }
++
++ /* Write the Data passed to the PEX Data register */
++ MV_REG_WRITE(PEX_CFG_DATA_REG(pexIf), data);
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvPexMasterEnable - Enable/disale PEX interface master transactions.
++*
++* DESCRIPTION:
++* This function performs read modified write to PEX command status
++* (offset 0x4) to set/reset bit 2. After this bit is set, the PEX
++* master is allowed to gain ownership on the bus, otherwise it is
++* incapable to do so.
++*
++* INPUT:
++* pexIf - PEX interface number.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPexMasterEnable(MV_U32 pexIf, MV_BOOL enable)
++{
++ MV_U32 pexCommandStatus;
++ MV_U32 localBus;
++ MV_U32 localDev;
++
++ /* Parameter checking */
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexMasterEnable: ERR. Invalid PEX interface %d\n", pexIf);
++ return MV_ERROR;
++ }
++
++ localBus = mvPexLocalBusNumGet(pexIf);
++ localDev = mvPexLocalDevNumGet(pexIf);
++
++ pexCommandStatus = MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf,
++ PEX_STATUS_AND_COMMAND));
++
++
++ if (MV_TRUE == enable)
++ {
++ pexCommandStatus |= PXSAC_MASTER_EN;
++ }
++ else
++ {
++ pexCommandStatus &= ~PXSAC_MASTER_EN;
++ }
++
++
++ MV_REG_WRITE(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_STATUS_AND_COMMAND),
++ pexCommandStatus);
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvPexSlaveEnable - Enable/disale PEX interface slave transactions.
++*
++* DESCRIPTION:
++* This function performs read modified write to PEX command status
++* (offset 0x4) to set/reset bit 0 and 1. After those bits are set,
++* the PEX slave is allowed to respond to PEX IO space access (bit 0)
++* and PEX memory space access (bit 1).
++*
++* INPUT:
++* pexIf - PEX interface number.
++* dev - PEX device number.
++* enable - Enable/disable parameter.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPexSlaveEnable(MV_U32 pexIf, MV_U32 bus,MV_U32 dev, MV_BOOL enable)
++{
++ MV_U32 pexCommandStatus;
++ MV_U32 RegOffs;
++
++ /* Parameter checking */
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexSlaveEnable: ERR. Invalid PEX interface %d\n", pexIf);
++ return MV_BAD_PARAM;
++ }
++ if (dev >= MAX_PEX_DEVICES)
++ {
++ mvOsPrintf("mvPexLocalDevNumSet: ERR. device number illigal %d\n", dev);
++ return MV_BAD_PARAM;
++
++ }
++
++
++ RegOffs = PEX_STATUS_AND_COMMAND;
++
++ pexCommandStatus = mvPexConfigRead(pexIf, bus, dev, 0, RegOffs);
++
++ if (MV_TRUE == enable)
++ {
++ pexCommandStatus |= (PXSAC_IO_EN | PXSAC_MEM_EN);
++ }
++ else
++ {
++ pexCommandStatus &= ~(PXSAC_IO_EN | PXSAC_MEM_EN);
++ }
++
++ mvPexConfigWrite(pexIf, bus, dev, 0, RegOffs, pexCommandStatus);
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvPexLocalBusNumSet - Set PEX interface local bus number.
++*
++* DESCRIPTION:
++* This function sets given PEX interface its local bus number.
++* Note: In case the PEX interface is PEX-X, the information is read-only.
++*
++* INPUT:
++* pexIf - PEX interface number.
++* busNum - Bus number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_NOT_ALLOWED in case PEX interface is PEX-X.
++* MV_BAD_PARAM on bad parameters ,
++* otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPexLocalBusNumSet(MV_U32 pexIf, MV_U32 busNum)
++{
++ MV_U32 pexStatus;
++ MV_U32 localBus;
++ MV_U32 localDev;
++
++
++ /* Parameter checking */
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexLocalBusNumSet: ERR. Invalid PEX interface %d\n",pexIf);
++ return MV_BAD_PARAM;
++ }
++ if (busNum >= MAX_PEX_BUSSES)
++ {
++ mvOsPrintf("mvPexLocalBusNumSet: ERR. bus number illigal %d\n", busNum);
++ return MV_ERROR;
++
++ }
++
++ localBus = mvPexLocalBusNumGet(pexIf);
++ localDev = mvPexLocalDevNumGet(pexIf);
++
++
++
++ pexStatus = MV_REG_READ(PEX_STATUS_REG(pexIf));
++
++ pexStatus &= ~PXSR_PEX_BUS_NUM_MASK;
++
++ pexStatus |= (busNum << PXSR_PEX_BUS_NUM_OFFS) & PXSR_PEX_BUS_NUM_MASK;
++
++ MV_REG_WRITE(PEX_STATUS_REG(pexIf), pexStatus);
++
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvPexLocalBusNumGet - Get PEX interface local bus number.
++*
++* DESCRIPTION:
++* This function gets the local bus number of a given PEX interface.
++*
++* INPUT:
++* pexIf - PEX interface number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Local bus number.0xffffffff on Error
++*
++*******************************************************************************/
++MV_U32 mvPexLocalBusNumGet(MV_U32 pexIf)
++{
++ MV_U32 pexStatus;
++
++ /* Parameter checking */
++ if (PEX_DEFAULT_IF != pexIf)
++ {
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexLocalBusNumGet: ERR. Invalid PEX interface %d\n",pexIf);
++ return 0xFFFFFFFF;
++ }
++ }
++
++
++ pexStatus = MV_REG_READ(PEX_STATUS_REG(pexIf));
++
++ pexStatus &= PXSR_PEX_BUS_NUM_MASK;
++
++ return (pexStatus >> PXSR_PEX_BUS_NUM_OFFS);
++
++}
++
++
++/*******************************************************************************
++* mvPexLocalDevNumSet - Set PEX interface local device number.
++*
++* DESCRIPTION:
++* This function sets given PEX interface its local device number.
++* Note: In case the PEX interface is PEX-X, the information is read-only.
++*
++* INPUT:
++* pexIf - PEX interface number.
++* devNum - Device number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_NOT_ALLOWED in case PEX interface is PEX-X.
++* MV_BAD_PARAM on bad parameters ,
++* otherwise MV_OK
++*
++*******************************************************************************/
++MV_STATUS mvPexLocalDevNumSet(MV_U32 pexIf, MV_U32 devNum)
++{
++ MV_U32 pexStatus;
++ MV_U32 localBus;
++ MV_U32 localDev;
++
++ /* Parameter checking */
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexLocalDevNumSet: ERR. Invalid PEX interface %d\n",pexIf);
++ return MV_BAD_PARAM;
++ }
++ if (devNum >= MAX_PEX_DEVICES)
++ {
++ mvOsPrintf("mvPexLocalDevNumSet: ERR. device number illigal %d\n",
++ devNum);
++ return MV_BAD_PARAM;
++
++ }
++
++ localBus = mvPexLocalBusNumGet(pexIf);
++ localDev = mvPexLocalDevNumGet(pexIf);
++
++
++ pexStatus = MV_REG_READ(PEX_STATUS_REG(pexIf));
++
++ pexStatus &= ~PXSR_PEX_DEV_NUM_MASK;
++
++ pexStatus |= (devNum << PXSR_PEX_DEV_NUM_OFFS) & PXSR_PEX_DEV_NUM_MASK;
++
++ MV_REG_WRITE(PEX_STATUS_REG(pexIf), pexStatus);
++
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvPexLocalDevNumGet - Get PEX interface local device number.
++*
++* DESCRIPTION:
++* This function gets the local device number of a given PEX interface.
++*
++* INPUT:
++* pexIf - PEX interface number.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Local device number. 0xffffffff on Error
++*
++*******************************************************************************/
++MV_U32 mvPexLocalDevNumGet(MV_U32 pexIf)
++{
++ MV_U32 pexStatus;
++
++ /* Parameter checking */
++
++ if (PEX_DEFAULT_IF != pexIf)
++ {
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexLocalDevNumGet: ERR. Invalid PEX interface %d\n",
++ pexIf);
++ return 0xFFFFFFFF;
++ }
++ }
++
++ pexStatus = MV_REG_READ(PEX_STATUS_REG(pexIf));
++
++ pexStatus &= PXSR_PEX_DEV_NUM_MASK;
++
++ return (pexStatus >> PXSR_PEX_DEV_NUM_OFFS);
++}
++
++MV_VOID mvPexPhyRegRead(MV_U32 pexIf, MV_U32 regOffset, MV_U16 *value)
++{
++
++ MV_U32 regAddr;
++ if (pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexPhyRegRead: ERR. Invalid PEX interface %d\n", pexIf);
++ return;
++ }
++ regAddr = (BIT31 | ((regOffset & 0x3fff) << 16));
++ MV_REG_WRITE(PEX_PHY_ACCESS_REG(pexIf), regAddr);
++ *value = MV_REG_READ(PEX_PHY_ACCESS_REG(pexIf));
++}
++
++
++MV_VOID mvPexPhyRegWrite(MV_U32 pexIf, MV_U32 regOffset, MV_U16 value)
++{
++
++ MV_U32 regAddr;
++ if(pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexPhyRegWrite: ERR. Invalid PEX interface %d\n", pexIf);
++ return;
++ }
++ regAddr = (((regOffset & 0x3fff) << 16) | value);
++ MV_REG_WRITE(PEX_PHY_ACCESS_REG(pexIf), regAddr);
++}
++
++/*******************************************************************************
++* mvPexActiveStateLinkPMEnable
++*
++* DESCRIPTION:
++* Enable Active Link State Power Management
++*
++* INPUT:
++* pexIf - PEX interface number.
++* enable - MV_TRUE to enable ASPM, MV_FALSE to disable.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* MV_OK on success , MV_ERROR otherwise
++*
++*******************************************************************************/
++MV_STATUS mvPexActiveStateLinkPMEnable(MV_U32 pexIf, MV_BOOL enable)
++{
++ MV_U32 reg;
++
++ if(pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexActiveStateLinkPMEnable: ERR. Invalid PEX interface %d\n", pexIf);
++ return MV_ERROR;
++ }
++
++ reg = MV_REG_READ(PEX_PWR_MNG_EXT_REG(pexIf)) & ~PXPMER_L1_ASPM_EN_MASK;
++ if(enable == MV_TRUE)
++ reg |= PXPMER_L1_ASPM_EN_MASK;
++ MV_REG_WRITE(PEX_PWR_MNG_EXT_REG(pexIf), reg);
++
++ /* Enable / Disable L0/1 entry */
++ reg = MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_LINK_CTRL_STAT_REG))
++ & ~PXLCSR_ASPM_CNT_MASK;
++ if(enable == MV_TRUE)
++ reg |= PXLCSR_ASPM_CNT_L0S_L1S_ENT_SUPP;
++ MV_REG_WRITE(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_LINK_CTRL_STAT_REG), reg);
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvPexForceX1
++*
++* DESCRIPTION:
++* shut down lanes 1-3 if recognize that attached to an x1 end-point
++* INPUT:
++* pexIf - PEX interface number.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* MV_OK on success , MV_ERROR otherwise
++*
++*******************************************************************************/
++MV_U32 mvPexForceX1(MV_U32 pexIf)
++{
++ MV_U32 regData = 0;
++ if(pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexForceX1: ERR. Invalid PEX interface %d\n", pexIf);
++ return MV_BAD_PARAM;
++ }
++
++ regData = MV_REG_READ(PEX_CTRL_REG(pexIf)) & ~(PXCR_CONF_LINK_MASK) ;
++ regData |= PXCR_CONF_LINK_X1;
++
++ MV_REG_WRITE(PEX_CTRL_REG(pexIf), regData);
++ return MV_OK;
++}
++
++MV_BOOL mvPexIsPowerUp(MV_U32 pexIf)
++{
++ if(pexIf >= mvCtrlPexMaxIfGet())
++ {
++ mvOsPrintf("mvPexIsPowerUp: ERR. Invalid PEX interface %d\n", pexIf);
++ return MV_FALSE;
++ }
++ return mvCtrlPwrClckGet(PEX_UNIT_ID, pexIf);
++}
++
++
++MV_VOID mvPexPowerDown(MV_U32 pexIf)
++{
++ if ( (mvCtrlModelGet() == MV_78XX0_DEV_ID) ||
++ (mvCtrlModelGet() == MV_76100_DEV_ID) ||
++ (mvCtrlModelGet() == MV_78100_DEV_ID) ||
++ (mvCtrlModelGet() == MV_78200_DEV_ID) )
++ {
++ mvCtrlPwrClckSet(PEX_UNIT_ID, pexIf, MV_FALSE);
++ }
++ else
++ {
++ MV_REG_WRITE((0x41B00 -(pexIf)*0x10000), 0x20800087);
++ }
++}
++
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.h 2010-11-09 20:28:11.742495415 +0100
+@@ -0,0 +1,168 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCPEXH
++#define __INCPEXH
++
++#include "mvCommon.h"
++#include "mvOs.h"
++#include "pex/mvPexRegs.h"
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++
++
++
++/* NOTE not supported in this driver:*/
++
++
++/* defines */
++/* The number of supported PEX interfaces depend on Marvell controller */
++/* device number. This device number ID is located on the PEX unit */
++/* configuration header. This creates a loop where calling PEX */
++/* configuration read/write routine results a call to get PEX configuration */
++/* information etc. This macro defines a default PEX interface. This PEX */
++/* interface is sure to exist. */
++#define PEX_DEFAULT_IF 0
++
++
++/* typedefs */
++/* The Marvell controller supports both root complex and end point devices */
++/* This enumeration describes the PEX type. */
++typedef enum _mvPexType
++{
++ MV_PEX_ROOT_COMPLEX, /* root complex device */
++ MV_PEX_END_POINT /* end point device */
++}MV_PEX_TYPE;
++
++typedef enum _mvPexWidth
++{
++ MV_PEX_WITDH_X1 = 1,
++ MV_PEX_WITDH_X2,
++ MV_PEX_WITDH_X3,
++ MV_PEX_WITDH_X4,
++ MV_PEX_WITDH_INVALID
++}MV_PEX_WIDTH;
++
++/* PEX Bar attributes */
++typedef struct _mvPexMode
++{
++ MV_PEX_TYPE pexType;
++ MV_PEX_WIDTH pexWidth;
++ MV_BOOL pexLinkUp;
++}MV_PEX_MODE;
++
++
++
++/* Global Functions prototypes */
++/* mvPexInit - Initialize PEX interfaces*/
++MV_STATUS mvPexHalInit(MV_U32 pexIf, MV_PEX_TYPE pexType);
++
++/* mvPexModeGet - Get Pex If mode */
++MV_U32 mvPexModeGet(MV_U32 pexIf,MV_PEX_MODE *pexMode);
++
++/* mvPexConfigRead - Read from configuration space */
++MV_U32 mvPexConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func,MV_U32 regOff);
++
++/* mvPexConfigWrite - Write to configuration space */
++MV_STATUS mvPexConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func, MV_U32 regOff, MV_U32 data);
++
++/* mvPexMasterEnable - Enable/disale PEX interface master transactions.*/
++MV_STATUS mvPexMasterEnable(MV_U32 pexIf, MV_BOOL enable);
++
++/* mvPexSlaveEnable - Enable/disale PEX interface slave transactions.*/
++MV_STATUS mvPexSlaveEnable(MV_U32 pexIf, MV_U32 bus,MV_U32 dev, MV_BOOL enable);
++
++/* mvPexLocalBusNumSet - Set PEX interface local bus number.*/
++MV_STATUS mvPexLocalBusNumSet(MV_U32 pexIf, MV_U32 busNum);
++
++/* mvPexLocalBusNumGet - Get PEX interface local bus number.*/
++MV_U32 mvPexLocalBusNumGet(MV_U32 pexIf);
++
++/* mvPexLocalDevNumSet - Set PEX interface local device number.*/
++MV_STATUS mvPexLocalDevNumSet(MV_U32 pexIf, MV_U32 devNum);
++
++/* mvPexLocalDevNumGet - Get PEX interface local device number.*/
++MV_U32 mvPexLocalDevNumGet(MV_U32 pexIf);
++/* mvPexForceX1 - Force PEX interface to X1 mode. */
++MV_U32 mvPexForceX1(MV_U32 pexIf);
++
++/* mvPexIsPowerUp - Is PEX interface Power up? */
++MV_BOOL mvPexIsPowerUp(MV_U32 pexIf);
++
++/* mvPexPowerDown - Power Down */
++MV_VOID mvPexPowerDown(MV_U32 pexIf);
++
++/* mvPexPowerUp - Power Up */
++MV_VOID mvPexPowerUp(MV_U32 pexIf);
++
++/* mvPexPhyRegRead - Pex phy read */
++MV_VOID mvPexPhyRegRead(MV_U32 pexIf, MV_U32 regOffset, MV_U16 *value);
++
++/* mvPexPhyRegWrite - Pex phy write */
++MV_VOID mvPexPhyRegWrite(MV_U32 pexIf, MV_U32 regOffset, MV_U16 value);
++
++MV_STATUS mvPexActiveStateLinkPMEnable(MV_U32 pexIf, MV_BOOL enable);
++
++#endif /* #ifndef __INCPEXH */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPexRegs.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPexRegs.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPexRegs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPexRegs.h 2010-11-09 20:28:11.782495900 +0100
+@@ -0,0 +1,751 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCPEXREGSH
++#define __INCPEXREGSH
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/* defines */
++#define MAX_PEX_DEVICES 32
++#define MAX_PEX_FUNCS 8
++#define MAX_PEX_BUSSES 256
++
++
++
++/*********************************************************/
++/* PCI Express Configuration Cycles Generation Registers */
++/*********************************************************/
++
++#define PEX_CFG_ADDR_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x18F8)
++#define PEX_CFG_DATA_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x18FC)
++#define PEX_PHY_ACCESS_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1B00)
++/* PCI Express Configuration Address Register */
++/* PEX_CFG_ADDR_REG (PXCAR)*/
++
++#define PXCAR_REG_NUM_OFFS 2
++#define PXCAR_REG_NUM_MAX 0x3F
++#define PXCAR_REG_NUM_MASK (PXCAR_REG_NUM_MAX << PXCAR_REG_NUM_OFFS)
++#define PXCAR_FUNC_NUM_OFFS 8
++#define PXCAR_FUNC_NUM_MAX 0x7
++#define PXCAR_FUNC_NUM_MASK (PXCAR_FUNC_NUM_MAX << PXCAR_FUNC_NUM_OFFS)
++#define PXCAR_DEVICE_NUM_OFFS 11
++#define PXCAR_DEVICE_NUM_MAX 0x1F
++#define PXCAR_DEVICE_NUM_MASK (PXCAR_DEVICE_NUM_MAX << PXCAR_DEVICE_NUM_OFFS)
++#define PXCAR_BUS_NUM_OFFS 16
++#define PXCAR_BUS_NUM_MAX 0xFF
++#define PXCAR_BUS_NUM_MASK (PXCAR_BUS_NUM_MAX << PXCAR_BUS_NUM_OFFS)
++#define PXCAR_EXT_REG_NUM_OFFS 24
++#define PXCAR_EXT_REG_NUM_MAX 0xF
++
++/* in pci express register address is now the legacy register address (8 bits)
++with the new extended register address (more 4 bits) , below is the mask of
++the upper 4 bits of the full register address */
++
++#define PXCAR_REAL_EXT_REG_NUM_OFFS 8
++#define PXCAR_EXT_REG_NUM_MASK (PXCAR_EXT_REG_NUM_MAX << PXCAR_EXT_REG_NUM_OFFS)
++#define PXCAR_CONFIG_EN BIT31
++
++#define PXCAR_REAL_EXT_REG_NUM_OFFS 8
++#define PXCAR_REAL_EXT_REG_NUM_MASK (0xF << PXCAR_REAL_EXT_REG_NUM_OFFS)
++
++/* The traditional PCI spec defined 6-bit field to describe register offset.*/
++/* The new PCI Express extend the register offset by an extra 4-bits. */
++/* The below macro assign 10-bit register offset into the apprpreate */
++/* fields in the CFG_ADDR_REG */
++#define PXCAR_REG_OFFS_SET(regOffs) \
++ ( (regOff & PXCAR_REG_NUM_MASK) | \
++ ( ((regOff & PXCAR_REAL_EXT_REG_NUM_MASK) >> PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS) )
++
++/***********************************/
++/* PCI Express Interrupt registers */
++/***********************************/
++#define PEX_CAUSE_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1900)
++#define PEX_MASK_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1910)
++
++#define PXICR_TX_REQ_IN_DLDOWN_ERR BIT0 /* Transmit request while field */
++ /* <DLDown> of the PCI Express */
++/* PCI Express Interrupt Cause */
++/* PEX_INT_CAUSE_REG (PXICR)*/
++/* PEX_INT_MASK_REG*/
++/*
++NOTE:All bits except bits[27:24] are Read/Write Clear only. A cause bit sets
++upon an error event occurrence. A write of 0 clears the bit. A write of 1 has
++no affect. Bits[24:27} are set and cleared upon reception of interrupt
++emulation messages.
++
++Mask bit per cause bit. If a bit is set to 1, the corresponding event is
++enabled. Mask does not affect setting of the Interrupt Cause register bits;
++it only affects the assertion of the interrupt .*/
++
++
++#define PXICR_MDIS_CAUSE BIT1 /* Attempt to generate PCI transaction
++ while master is disabled */
++#define PXICR_ERR_WRTO_REG_CAUSE BIT3 /* Erroneous write attempt to
++ PCI Express internal register*/
++#define PXICR_HIT_DFLT_WIN_ERR BIT4 /* Hit Default Window Error */
++#define PXICR_RX_RAM_PAR_ERR BIT6 /* Rx RAM Parity Error */
++#define PXICR_TX_RAM_PAR_ERR BIT7 /* Tx RAM Parity Error */
++#define PXICR_COR_ERR_DET BIT8 /* Correctable Error Detected*/
++#define PXICR_NF_ERR_DET BIT9 /* Non-Fatal Error Detected*/
++#define PXICR_FERR_DET BIT10 /* Fatal Error Detected*/
++#define PXICR_DSTATE_CHANGE BIT11 /* Dstate Change Indication*/
++#define PXICR_BIST BIT12 /* PCI-Express BIST activated*/
++#define PXICR_FLW_CTRL_PROT BIT14 /* Flow Control Protocol Error */
++
++#define PXICR_RCV_UR_CA_ERR BIT15 /* Received UR or CA status. */
++#define PXICR_RCV_ERR_FATAL BIT16 /* Received ERR_FATAL message.*/
++#define PXICR_RCV_ERR_NON_FATAL BIT17 /* Received ERR_NONFATAL message*/
++#define PXICR_RCV_ERR_COR BIT18 /* Received ERR_COR message.*/
++#define PXICR_RCV_CRS BIT19 /* Received CRS completion status*/
++#define PXICR_SLV_HOT_RESET BIT20 /* Received Hot Reset Indication*/
++#define PXICR_SLV_DIS_LINK BIT21 /* Slave Disable Link Indication*/
++#define PXICR_SLV_LB BIT22 /* Slave Loopback Indication*/
++#define PXICR_LINK_FAIL BIT23 /* Link Failure indication.*/
++#define PXICR_RCV_INTA BIT24 /* IntA status.*/
++#define PXICR_RCV_INTB BIT25 /* IntB status.*/
++#define PXICR_RCV_INTC BIT26 /* IntC status.*/
++#define PXICR_RCV_INTD BIT27 /* IntD status.*/
++#define PXICR_RCV_PM_PME BIT28 /* Received PM_PME message. */
++
++
++/********************************************/
++/* PCI Express Control and Status Registers */
++/********************************************/
++#define PEX_CTRL_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A00)
++#define PEX_STATUS_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A04)
++#define PEX_COMPLT_TMEOUT_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A10)
++#define PEX_PWR_MNG_EXT_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A18)
++#define PEX_FLOW_CTRL_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A20)
++#define PEX_ACK_TMR_4X_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A30)
++#define PEX_ACK_TMR_1X_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A40)
++#define PEX_TL_CTRL_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1AB0)
++
++
++#define PEX_RAM_PARITY_CTRL_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A50)
++/* PCI Express Control Register */
++/* PEX_CTRL_REG (PXCR) */
++
++#define PXCR_CONF_LINK_OFFS 0
++#define PXCR_CONF_LINK_MASK (1 << PXCR_CONF_LINK_OFFS)
++#define PXCR_CONF_LINK_X4 (0 << PXCR_CONF_LINK_OFFS)
++#define PXCR_CONF_LINK_X1 (1 << PXCR_CONF_LINK_OFFS)
++#define PXCR_DEV_TYPE_CTRL_OFFS 1 /*PCI ExpressDevice Type Control*/
++#define PXCR_DEV_TYPE_CTRL_MASK BIT1
++#define PXCR_DEV_TYPE_CTRL_CMPLX (1 << PXCR_DEV_TYPE_CTRL_OFFS)
++#define PXCR_DEV_TYPE_CTRL_POINT (0 << PXCR_DEV_TYPE_CTRL_OFFS)
++#define PXCR_CFG_MAP_TO_MEM_EN BIT2 /* Configuration Header Mapping
++ to Memory Space Enable */
++
++#define PXCR_CFG_MAP_TO_MEM_EN BIT2 /* Configuration Header Mapping
++ to Memory Space Enable*/
++
++#define PXCR_RSRV1_OFFS 5
++#define PXCR_RSRV1_MASK (0x7 << PXCR_RSRV1_OFFS)
++#define PXCR_RSRV1_VAL (0x0 << PXCR_RSRV1_OFFS)
++
++#define PXCR_CONF_MAX_OUTSTND_OFFS 8 /*Maximum outstanding NP requests as a master*/
++#define PXCR_CONF_MAX_OUTSTND_MASK (0x3 << PXCR_CONF_MAX_OUTSTND_OFFS)
++
++
++#define PXCR_CONF_NFTS_OFFS 16 /*number of FTS Ordered-Sets*/
++#define PXCR_CONF_NFTS_MASK (0xff << PXCR_CONF_NFTS_OFFS)
++
++#define PXCR_CONF_MSTR_HOT_RESET BIT24 /*Master Hot-Reset.*/
++#define PXCR_CONF_MSTR_LB BIT26 /* Master Loopback */
++#define PXCR_CONF_MSTR_DIS_SCRMB BIT27 /* Master Disable Scrambling*/
++#define PXCR_CONF_DIRECT_DIS_SCRMB BIT28 /* Direct Disable Scrambling*/
++
++/* PCI Express Status Register */
++/* PEX_STATUS_REG (PXSR) */
++
++#define PXSR_DL_DOWN BIT0 /* DL_Down indication.*/
++
++#define PXSR_PEX_BUS_NUM_OFFS 8 /* Bus Number Indication */
++#define PXSR_PEX_BUS_NUM_MASK (0xff << PXSR_PEX_BUS_NUM_OFFS)
++
++#define PXSR_PEX_DEV_NUM_OFFS 16 /* Device Number Indication */
++#define PXSR_PEX_DEV_NUM_MASK (0x1f << PXSR_PEX_DEV_NUM_OFFS)
++
++#define PXSR_PEX_SLV_HOT_RESET BIT24 /* Slave Hot Reset Indication*/
++#define PXSR_PEX_SLV_DIS_LINK BIT25 /* Slave Disable Link Indication*/
++#define PXSR_PEX_SLV_LB BIT26 /* Slave Loopback Indication*/
++#define PXSR_PEX_SLV_DIS_SCRMB BIT27 /* Slave Disable Scrambling Indication*/
++
++
++/* PCI Express Completion Timeout Register */
++/* PEX_COMPLT_TMEOUT_REG (PXCTR)*/
++
++#define PXCTR_CMP_TO_THRSHLD_OFFS 0 /* Completion Timeout Threshold */
++#define PXCTR_CMP_TO_THRSHLD_MASK (0xffff << PXCTR_CMP_TO_THRSHLD_OFFS)
++
++/* PCI Express Power Management Extended Register */
++/* PEX_PWR_MNG_EXT_REG (PXPMER) */
++
++#define PXPMER_L1_ASPM_EN_OFFS 1
++#define PXPMER_L1_ASPM_EN_MASK (0x1 << PXPMER_L1_ASPM_EN_OFFS)
++
++/* PCI Express Flow Control Register */
++/* PEX_FLOW_CTRL_REG (PXFCR)*/
++
++#define PXFCR_PH_INIT_FC_OFFS 0 /*Posted Headers Flow Control Credit
++ Initial Value.*/
++#define PXFCR_PH_INIT_FC_MASK (0xff << PXFCR_PH_INIT_FC_OFFS)
++
++
++#define PXFCR_NPH_INIT_FC_OFFS 8 /* Classified Non-Posted Headers
++ Flow Control Credit Initial Value*/
++#define PXFCR_NPH_INIT_FC_MASK (0xff << PXFCR_NPH_INIT_FC_OFFS)
++
++#define PXFCR_CH_INIT_FC_OFFS 16 /* Completion Headers Flow Control
++ Credit Initial Value Infinite*/
++
++#define PXFCR_CH_INIT_FC_MASK (0xff << PXFCR_CH_INIT_FC_OFFS)
++
++#define PXFCR_FC_UPDATE_TO_OFFS 24 /* Flow Control Update Timeout */
++#define PXFCR_FC_UPDATE_TO_MASK (0xff << PXFCR_FC_UPDATE_TO_OFFS)
++
++/* PCI Express Acknowledge Timers (4X) Register */
++/* PEX_ACK_TMR_4X_REG (PXAT4R) */
++#define PXAT1R_ACK_LAT_TOX4_OFFS 0 /* Ack Latency Timer Timeout Value */
++#define PXAT1R_ACK_LAT_TOX4_MASK (0xffff << PXAT4R_ACK_LAT_TOX1_OFFS)
++#define PXAT1R_ACK_RPLY_TOX4_OFFS 16 /* Ack Replay Timer Timeout Value */
++#define PXAT1R_ACK_RPLY_TOX4_MASK (0xffff << PXAT1R_ACK_RPLY_TOX1_OFFS)
++
++/* PCI Express Acknowledge Timers (1X) Register */
++/* PEX_ACK_TMR_1X_REG (PXAT1R) */
++
++#define PXAT1R_ACK_LAT_TOX1_OFFS 0 /* Acknowledge Latency Timer Timeout
++ Value for 1X Link*/
++#define PXAT1R_ACK_LAT_TOX1_MASK (0xffff << PXAT1R_ACK_LAT_TOX1_OFFS)
++
++#define PXAT1R_ACK_RPLY_TOX1_OFFS 16 /* Acknowledge Replay Timer Timeout
++ Value for 1X*/
++#define PXAT1R_ACK_RPLY_TOX1_MASK (0xffff << PXAT1R_ACK_RPLY_TOX1_OFFS)
++
++
++/* PCI Express TL Control Register */
++/* PEX_TL_CTRL_REG (PXTCR) */
++
++#define PXTCR_TX_CMP_BUFF_NO_OFFS 8 /*Number of completion buffers in Tx*/
++#define PXTCR_TX_CMP_BUFF_NO_MASK (0xf << PXTCR_TX_CMP_BUFF_NO_OFFS)
++
++/* PCI Express Debug MAC Control Register */
++/* PEX_DEBUG_MAC_CTRL_REG (PXDMCR) */
++
++#define PXDMCR_LINKUP BIT4
++
++
++
++/**********************************************/
++/* PCI Express Configuration Header Registers */
++/**********************************************/
++#define PEX_CFG_DIRECT_ACCESS(pexIf,cfgReg) ((PEX_IF_BASE(pexIf)) + (cfgReg))
++
++#define PEX_DEVICE_AND_VENDOR_ID 0x000
++#define PEX_STATUS_AND_COMMAND 0x004
++#define PEX_CLASS_CODE_AND_REVISION_ID 0x008
++#define PEX_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE 0x00C
++#define PEX_MEMORY_BAR_BASE_ADDR(barNum) (0x010 + ((barNum) << 2))
++#define PEX_MV_BAR_BASE(barNum) (0x010 + (barNum) * 8)
++#define PEX_MV_BAR_BASE_HIGH(barNum) (0x014 + (barNum) * 8)
++#define PEX_BAR0_INTER_REG 0x010
++#define PEX_BAR0_INTER_REG_HIGH 0x014
++#define PEX_BAR1_REG 0x018
++#define PEX_BAR1_REG_HIGH 0x01C
++#define PEX_BAR2_REG 0x020
++#define PEX_BAR2_REG_HIGH 0x024
++
++#define PEX_SUBSYS_ID_AND_SUBSYS_VENDOR_ID 0x02C
++#define PEX_EXPANSION_ROM_BASE_ADDR_REG 0x030
++#define PEX_CAPABILTY_LIST_POINTER 0x034
++#define PEX_INTERRUPT_PIN_AND_LINE 0x03C
++
++/* capability list */
++#define PEX_POWER_MNG_CAPABILITY 0x040
++#define PEX_POWER_MNG_STATUS_CONTROL 0x044
++
++#define PEX_MSI_MESSAGE_CONTROL 0x050
++#define PEX_MSI_MESSAGE_ADDR 0x054
++#define PEX_MSI_MESSAGE_HIGH_ADDR 0x058
++#define PEX_MSI_MESSAGE_DATA 0x05C
++
++#define PEX_CAPABILITY_REG 0x60
++#define PEX_DEV_CAPABILITY_REG 0x64
++#define PEX_DEV_CTRL_STAT_REG 0x68
++#define PEX_LINK_CAPABILITY_REG 0x6C
++#define PEX_LINK_CTRL_STAT_REG 0x70
++
++#define PEX_ADV_ERR_RPRT_HDR_TRGT_REG 0x100
++#define PEX_UNCORRECT_ERR_STAT_REG 0x104
++#define PEX_UNCORRECT_ERR_MASK_REG 0x108
++#define PEX_UNCORRECT_ERR_SERVITY_REG 0x10C
++#define PEX_CORRECT_ERR_STAT_REG 0x110
++#define PEX_CORRECT_ERR_MASK_REG 0x114
++#define PEX_ADV_ERR_CAPABILITY_CTRL_REG 0x118
++#define PEX_HDR_LOG_FIRST_DWORD_REG 0x11C
++#define PEX_HDR_LOG_SECOND_DWORD_REG 0x120
++#define PEX_HDR_LOG_THIRD_DWORD_REG 0x124
++#define PEX_HDR_LOG_FOURTH_DWORD_REG 0x128
++
++
++
++/* PCI Express Device and Vendor ID Register*/
++/*PEX_DEVICE_AND_VENDOR_ID (PXDAVI)*/
++
++#define PXDAVI_VEN_ID_OFFS 0 /* Vendor ID */
++#define PXDAVI_VEN_ID_MASK (0xffff << PXDAVI_VEN_ID_OFFS)
++
++#define PXDAVI_DEV_ID_OFFS 16 /* Device ID */
++#define PXDAVI_DEV_ID_MASK (0xffff << PXDAVI_DEV_ID_OFFS)
++
++
++/* PCI Express Command and Status Register*/
++/*PEX_STATUS_AND_COMMAND (PXSAC)*/
++
++#define PXSAC_IO_EN BIT0 /* IO Enable */
++#define PXSAC_MEM_EN BIT1 /* Memory Enable */
++#define PXSAC_MASTER_EN BIT2 /* Master Enable */
++#define PXSAC_PERR_EN BIT6 /* Parity Errors Respond Enable */
++#define PXSAC_SERR_EN BIT8 /* Ability to assert SERR# line */
++#define PXSAC_INT_DIS BIT10 /* Interrupt Disable */
++#define PXSAC_INT_STAT BIT19 /* Interrupt Status */
++#define PXSAC_CAP_LIST BIT20 /* Capability List Support */
++#define PXSAC_MAS_DATA_PERR BIT24 /* Master Data Parity Error */
++#define PXSAC_SLAVE_TABORT BIT27 /* Signalled Target Abort */
++#define PXSAC_RT_ABORT BIT28 /* Recieved Target Abort */
++#define PXSAC_MABORT BIT29 /* Recieved Master Abort */
++#define PXSAC_SYSERR BIT30 /* Signalled system error */
++#define PXSAC_DET_PARERR BIT31 /* Detect Parity Error */
++
++
++/* PCI Express Class Code and Revision ID Register*/
++/*PEX_CLASS_CODE_AND_REVISION_ID (PXCCARI)*/
++
++#define PXCCARI_REVID_OFFS 0 /* Revision ID */
++#define PXCCARI_REVID_MASK (0xff << PXCCARI_REVID_OFFS)
++
++#define PXCCARI_FULL_CLASS_OFFS 8 /* Full Class Code */
++#define PXCCARI_FULL_CLASS_MASK (0xffffff << PXCCARI_FULL_CLASS_OFFS)
++
++#define PXCCARI_PROGIF_OFFS 8 /* Prog .I/F*/
++#define PXCCARI_PROGIF_MASK (0xff << PXCCARI_PROGIF_OFFS)
++
++#define PXCCARI_SUB_CLASS_OFFS 16 /* Sub Class*/
++#define PXCCARI_SUB_CLASS_MASK (0xff << PXCCARI_SUB_CLASS_OFFS)
++
++#define PXCCARI_BASE_CLASS_OFFS 24 /* Base Class*/
++#define PXCCARI_BASE_CLASS_MASK (0xff << PXCCARI_BASE_CLASS_OFFS)
++
++
++/* PCI Express BIST, Header Type and Cache Line Size Register*/
++/*PEX_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE (PXBHTLTCL)*/
++
++#define PXBHTLTCL_CACHELINE_OFFS 0 /* Specifies the cache line size */
++#define PXBHTLTCL_CACHELINE_MASK (0xff << PXBHTLTCL_CACHELINE_OFFS)
++
++#define PXBHTLTCL_HEADTYPE_FULL_OFFS 16 /* Full Header Type */
++#define PXBHTLTCL_HEADTYPE_FULL_MASK (0xff << PXBHTLTCL_HEADTYPE_FULL_OFFS)
++
++#define PXBHTLTCL_MULTI_FUNC BIT23 /* Multi/Single function */
++
++#define PXBHTLTCL_HEADER_OFFS 16 /* Header type */
++#define PXBHTLTCL_HEADER_MASK (0x7f << PXBHTLTCL_HEADER_OFFS)
++#define PXBHTLTCL_HEADER_STANDARD (0x0 << PXBHTLTCL_HEADER_OFFS)
++#define PXBHTLTCL_HEADER_PCI2PCI_BRIDGE (0x1 << PXBHTLTCL_HEADER_OFFS)
++
++
++#define PXBHTLTCL_BISTCOMP_OFFS 24 /* BIST Completion Code */
++#define PXBHTLTCL_BISTCOMP_MASK (0xf << PXBHTLTCL_BISTCOMP_OFFS)
++
++#define PXBHTLTCL_BISTACT BIT30 /* BIST Activate bit */
++#define PXBHTLTCL_BISTCAP BIT31 /* BIST Capable Bit */
++#define PXBHTLTCL_BISTCAP_OFFS 31
++#define PXBHTLTCL_BISTCAP_MASK BIT31
++#define PXBHTLTCL_BISTCAP_VAL 0
++
++
++/* PCI Express Subsystem Device and Vendor ID */
++/*PEX_SUBSYS_ID_AND_SUBSYS_VENDOR_ID (PXSIASVI)*/
++
++#define PXSIASVI_VENID_OFFS 0 /* Subsystem Manufacturer Vendor ID Number */
++#define PXSIASVI_VENID_MASK (0xffff << PXSIASVI_VENID_OFFS)
++
++#define PXSIASVI_DEVID_OFFS 16 /* Subsystem Device ID Number */
++#define PXSIASVI_DEVID_MASK (0xffff << PXSIASVI_DEVID_OFFS)
++
++
++/* PCI Express Capability List Pointer Register*/
++/*PEX_CAPABILTY_LIST_POINTER (PXCLP)*/
++
++#define PXCLP_CAPPTR_OFFS 0 /* Capability List Pointer */
++#define PXCLP_CAPPTR_MASK (0xff << PXCLP_CAPPTR_OFFS)
++
++/* PCI Express Interrupt Pin and Line Register */
++/*PEX_INTERRUPT_PIN_AND_LINE (PXIPAL)*/
++
++#define PXIPAL_INTLINE_OFFS 0 /* Interrupt line (IRQ) */
++#define PXIPAL_INTLINE_MASK (0xff << PXIPAL_INTLINE_OFFS)
++
++#define PXIPAL_INTPIN_OFFS 8 /* interrupt pin (A,B,C,D) */
++#define PXIPAL_INTPIN_MASK (0xff << PXIPAL_INTPIN_OFFS)
++
++
++/* PCI Express Power Management Capability Header Register*/
++/*PEX_POWER_MNG_CAPABILITY (PXPMC)*/
++
++#define PXPMC_CAP_ID_OFFS 0 /* Capability ID */
++#define PXPMC_CAP_ID_MASK (0xff << PXPMC_CAP_ID_OFFS)
++
++#define PXPMC_NEXT_PTR_OFFS 8 /* Next Item Pointer */
++#define PXPMC_NEXT_PTR_MASK (0xff << PXPMC_NEXT_PTR_OFFS)
++
++#define PXPMC_PMC_VER_OFFS 16 /* PCI Power Management Capability Version*/
++#define PXPMC_PMC_VER_MASK (0x7 << PXPMC_PMC_VER_OFFS)
++
++#define PXPMC_DSI BIT21/* Device Specific Initialization */
++
++#define PXPMC_AUX_CUR_OFFS 22 /* Auxiliary Current Requirements */
++#define PXPMC_AUX_CUR_MASK (0x7 << PXPMC_AUX_CUR_OFFS)
++
++#define PXPMC_D1_SUP BIT25 /* D1 Power Management support*/
++
++#define PXPMC_D2_SUP BIT26 /* D2 Power Management support*/
++
++#define PXPMC_PME_SUP_OFFS 27 /* PM Event generation support*/
++#define PXPMC_PME_SUP_MASK (0x1f << PXPMC_PME_SUP_OFFS)
++
++/* PCI Express Power Management Control and Status Register*/
++/*PEX_POWER_MNG_STATUS_CONTROL (PXPMSC)*/
++
++#define PXPMSC_PM_STATE_OFFS 0 /* Power State */
++#define PXPMSC_PM_STATE_MASK (0x3 << PXPMSC_PM_STATE_OFFS)
++#define PXPMSC_PM_STATE_D0 (0x0 << PXPMSC_PM_STATE_OFFS)
++#define PXPMSC_PM_STATE_D1 (0x1 << PXPMSC_PM_STATE_OFFS)
++#define PXPMSC_PM_STATE_D2 (0x2 << PXPMSC_PM_STATE_OFFS)
++#define PXPMSC_PM_STATE_D3 (0x3 << PXPMSC_PM_STATE_OFFS)
++
++#define PXPMSC_PME_EN BIT8/* PM_PME Message Generation Enable */
++
++#define PXPMSC_PM_DATA_SEL_OFFS 9 /* Data Select*/
++#define PXPMSC_PM_DATA_SEL_MASK (0xf << PXPMSC_PM_DATA_SEL_OFFS)
++
++#define PXPMSC_PM_DATA_SCALE_OFFS 13 /* Data Scale */
++#define PXPMSC_PM_DATA_SCALE_MASK (0x3 << PXPMSC_PM_DATA_SCALE_OFFS)
++
++#define PXPMSC_PME_STAT BIT15/* PME Status */
++
++#define PXPMSC_PM_DATA_OFFS 24 /* State Data */
++#define PXPMSC_PM_DATA_MASK (0xff << PXPMSC_PM_DATA_OFFS)
++
++
++/* PCI Express MSI Message Control Register*/
++/*PEX_MSI_MESSAGE_CONTROL (PXMMC)*/
++
++#define PXMMC_CAP_ID_OFFS 0 /* Capability ID */
++#define PXMMC_CAP_ID_MASK (0xff << PXMMC_CAP_ID_OFFS)
++
++#define PXMMC_NEXT_PTR_OFFS 8 /* Next Item Pointer */
++#define PXMMC_NEXT_PTR_MASK (0xff << PXMMC_NEXT_PTR_OFFS)
++
++#define PXMMC_MSI_EN BIT18 /* MSI Enable */
++
++#define PXMMC_MULTI_CAP_OFFS 17 /* Multiple Message Capable */
++#define PXMMC_MULTI_CAP_MASK (0x7 << PXMMC_MULTI_CAP_OFFS)
++
++#define PXMMC_MULTI_EN_OFFS 20 /* Multiple Messages Enable */
++#define PXMMC_MULTI_EN_MASK (0x7 << PXMMC_MULTI_EN_OFFS)
++
++#define PXMMC_ADDR64 BIT23 /* 64-bit Addressing Capable */
++
++
++/* PCI Express MSI Message Address Register*/
++/*PEX_MSI_MESSAGE_ADDR (PXMMA)*/
++
++#define PXMMA_MSI_ADDR_OFFS 2 /* Message Address corresponds to
++ Address[31:2] of the MSI MWr TLP*/
++#define PXMMA_MSI_ADDR_MASK (0x3fffffff << PXMMA_MSI_ADDR_OFFS)
++
++
++/* PCI Express MSI Message Address (High) Register */
++/*PEX_MSI_MESSAGE_HIGH_ADDR (PXMMHA)*/
++
++#define PXMMA_MSI_ADDR_H_OFFS 0 /* Message Upper Address corresponds to
++ Address[63:32] of the MSI MWr TLP*/
++#define PXMMA_MSI_ADDR_H_MASK (0xffffffff << PXMMA_MSI_ADDR_H_OFFS )
++
++
++/* PCI Express MSI Message Data Register*/
++/*PEX_MSI_MESSAGE_DATA (PXMMD)*/
++
++#define PXMMD_MSI_DATA_OFFS 0 /* Message Data */
++#define PXMMD_MSI_DATA_MASK (0xffff << PXMMD_MSI_DATA_OFFS )
++
++
++/* PCI Express Capability Register*/
++/*PEX_CAPABILITY_REG (PXCR)*/
++
++#define PXCR_CAP_ID_OFFS 0 /* Capability ID*/
++#define PXCR_CAP_ID_MASK (0xff << PXCR_CAP_ID_OFFS)
++
++#define PXCR_NEXT_PTR_OFFS 8 /* Next Item Pointer*/
++#define PXCR_NEXT_PTR_MASK (0xff << PXCR_NEXT_PTR_OFFS)
++
++#define PXCR_CAP_VER_OFFS 16 /* Capability Version*/
++#define PXCR_CAP_VER_MASK (0xf << PXCR_CAP_VER_OFFS)
++
++#define PXCR_DEV_TYPE_OFFS 20 /* Device/Port Type*/
++#define PXCR_DEV_TYPE_MASK (0xf << PXCR_DEV_TYPE_OFFS)
++
++#define PXCR_SLOT_IMP BIT24 /* Slot Implemented*/
++
++#define PXCR_INT_MSG_NUM_OFFS 25 /* Interrupt Message Number*/
++#define PXCR_INT_MSG_NUM_MASK (0x1f << PXCR_INT_MSG_NUM_OFFS)
++
++
++/* PCI Express Device Capabilities Register */
++/*PEX_DEV_CAPABILITY_REG (PXDCR)*/
++
++#define PXDCR_MAX_PLD_SIZE_SUP_OFFS 0 /* Maximum Payload Size Supported*/
++#define PXDCR_MAX_PLD_SIZE_SUP_MASK (0x7 << PXDCR_MAX_PLD_SIZE_SUP_OFFS)
++
++#define PXDCR_EP_L0S_ACC_LAT_OFFS 6/* Endpoint L0s Acceptable Latency*/
++#define PXDCR_EP_L0S_ACC_LAT_MASK (0x7 << PXDCR_EP_L0S_ACC_LAT_OFFS)
++#define PXDCR_EP_L0S_ACC_LAT_64NS_LESS (0x0 << PXDCR_EP_L0S_ACC_LAT_OFFS)
++#define PXDCR_EP_L0S_ACC_LAT_64NS_128NS (0x1 << PXDCR_EP_L0S_ACC_LAT_OFFS)
++#define PXDCR_EP_L0S_ACC_LAT_128NS_256NS (0x2 << PXDCR_EP_L0S_ACC_LAT_OFFS)
++#define PXDCR_EP_L0S_ACC_LAT_256NS_512NS (0x3 << PXDCR_EP_L0S_ACC_LAT_OFFS)
++#define PXDCR_EP_L0S_ACC_LAT_512NS_1US (0x4 << PXDCR_EP_L0S_ACC_LAT_OFFS)
++#define PXDCR_EP_L0S_ACC_LAT_1US_2US (0x5 << PXDCR_EP_L0S_ACC_LAT_OFFS)
++#define PXDCR_EP_L0S_ACC_LAT_2US_4US (0x6 << PXDCR_EP_L0S_ACC_LAT_OFFS)
++#define PXDCR_EP_L0S_ACC_LAT_4US_MORE (0x7 << PXDCR_EP_L0S_ACC_LAT_OFFS)
++
++#define PXDCR_EP_L1_ACC_LAT_OFFS 9 /* Endpoint L1 Acceptable Latency*/
++#define PXDCR_EP_L1_ACC_LAT_MASK (0x7 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXDCR_EP_L1_ACC_LAT_64NS_LESS (0x0 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXDCR_EP_L1_ACC_LAT_64NS_128NS (0x1 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXDCR_EP_L1_ACC_LAT_128NS_256NS (0x2 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXDCR_EP_L1_ACC_LAT_256NS_512NS (0x3 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXDCR_EP_L1_ACC_LAT_512NS_1US (0x4 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXDCR_EP_L1_ACC_LAT_1US_2US (0x5 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXDCR_EP_L1_ACC_LAT_2US_4US (0x6 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXDCR_EP_L1_ACC_LAT_4US_MORE (0x7 << PXDCR_EP_L1_ACC_LAT_OFFS)
++
++
++#define PXDCR_ATT_BUT_PRS_OFFS 12 /* Attention Button Present*/
++#define PXDCR_ATT_BUT_PRS_MASK BIT12
++#define PXDCR_ATT_BUT_PRS_IMPLEMENTED BIT12
++
++#define PXDCR_ATT_IND_PRS_OFFS 13 /* Attention Indicator Present*/
++#define PXDCR_ATT_IND_PRS_MASK BIT13
++#define PXDCR_ATT_IND_PRS_IMPLEMENTED BIT13
++
++#define PXDCR_PWR_IND_PRS_OFFS 14/* Power Indicator Present*/
++#define PXDCR_PWR_IND_PRS_MASK BIT14
++#define PXDCR_PWR_IND_PRS_IMPLEMENTED BIT14
++
++#define PXDCR_CAP_SPL_VAL_OFFS 18 /*Captured Slot Power Limit
++ Value*/
++#define PXDCR_CAP_SPL_VAL_MASK (0xff << PXDCR_CAP_SPL_VAL_OFFS)
++
++#define PXDCR_CAP_SP_LSCL_OFFS 26 /* Captured Slot Power Limit
++ Scale */
++#define PXDCR_CAP_SP_LSCL_MASK (0x3 << PXDCR_CAP_SP_LSCL_OFFS)
++
++/* PCI Express Device Control Status Register */
++/*PEX_DEV_CTRL_STAT_REG (PXDCSR)*/
++
++#define PXDCSR_COR_ERR_REP_EN BIT0 /* Correctable Error Reporting Enable*/
++#define PXDCSR_NF_ERR_REP_EN BIT1 /* Non-Fatal Error Reporting Enable*/
++#define PXDCSR_F_ERR_REP_EN BIT2 /* Fatal Error Reporting Enable*/
++#define PXDCSR_UR_REP_EN BIT3 /* Unsupported Request (UR)
++ Reporting Enable*/
++#define PXDCSR_EN_RO BIT4 /* Enable Relaxed Ordering*/
++
++#define PXDCSR_MAX_PLD_SZ_OFFS 5 /* Maximum Payload Size*/
++#define PXDCSR_MAX_PLD_SZ_MASK (0x7 << PXDCSR_MAX_PLD_SZ_OFFS)
++#define PXDCSR_MAX_PLD_SZ_128B (0x0 << PXDCSR_MAX_PLD_SZ_OFFS)
++#define PXDCSR_EN_NS BIT11 /* Enable No Snoop*/
++
++#define PXDCSR_MAX_RD_RQ_SZ_OFFS 12 /* Maximum Read Request Size*/
++#define PXDCSR_MAX_RD_RQ_SZ_MASK (0x7 << PXDCSR_MAX_RD_RQ_SZ_OFFS)
++#define PXDCSR_MAX_RD_RQ_SZ_128B (0x0 << PXDCSR_MAX_RD_RQ_SZ_OFFS)
++#define PXDCSR_MAX_RD_RQ_SZ_256B (0x1 << PXDCSR_MAX_RD_RQ_SZ_OFFS)
++#define PXDCSR_MAX_RD_RQ_SZ_512B (0x2 << PXDCSR_MAX_RD_RQ_SZ_OFFS)
++#define PXDCSR_MAX_RD_RQ_SZ_1KB (0x3 << PXDCSR_MAX_RD_RQ_SZ_OFFS)
++#define PXDCSR_MAX_RD_RQ_SZ_2KB (0x4 << PXDCSR_MAX_RD_RQ_SZ_OFFS)
++#define PXDCSR_MAX_RD_RQ_SZ_4KB (0x5 << PXDCSR_MAX_RD_RQ_SZ_OFFS)
++
++#define PXDCSR_COR_ERR_DET BIT16 /* Correctable Error Detected*/
++#define PXDCSR_NF_ERR_DET BIT17 /* Non-Fatal Error Detected.*/
++#define PXDCSR_F_ERR_DET BIT18 /* Fatal Error Detected.*/
++#define PXDCSR_UR_DET BIT19 /* Unsupported Request Detected */
++#define PXDCSR_AUX_PWR_DET BIT20 /* Reserved*/
++
++#define PXDCSR_TRANS_PEND_OFFS 21 /* Transactions Pending*/
++#define PXDCSR_TRANS_PEND_MASK BIT21
++#define PXDCSR_TRANS_PEND_NOT_COMPLETED (0x1 << PXDCSR_TRANS_PEND_OFFS)
++
++
++/* PCI Express Link Capabilities Register*/
++/*PEX_LINK_CAPABILITY_REG (PXLCR)*/
++
++#define PXLCR_MAX_LINK_SPD_OFFS 0 /* Maximum Link Speed*/
++#define PXLCR_MAX_LINK_SPD_MASK (0xf << PXLCR_MAX_LINK_SPD_OFFS)
++
++#define PXLCR_MAX_LNK_WDTH_OFFS 3 /* Maximum Link Width*/
++#define PXLCR_MAX_LNK_WDTH_MASK (0x3f << PXLCR_MAX_LNK_WDTH_OFFS)
++
++#define PXLCR_ASPM_SUP_OFFS 10 /* Active State Link PM Support*/
++#define PXLCR_ASPM_SUP_MASK (0x3 << PXLCR_ASPM_SUP_OFFS)
++
++#define PXLCR_L0S_EXT_LAT_OFFS 12 /* L0s Exit Latency*/
++#define PXLCR_L0S_EXT_LAT_MASK (0x7 << PXLCR_L0S_EXT_LAT_OFFS)
++#define PXLCR_L0S_EXT_LAT_64NS_LESS (0x0 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXLCR_L0S_EXT_LAT_64NS_128NS (0x1 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXLCR_L0S_EXT_LAT_128NS_256NS (0x2 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXLCR_L0S_EXT_LAT_256NS_512NS (0x3 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXLCR_L0S_EXT_LAT_512NS_1US (0x4 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXLCR_L0S_EXT_LAT_1US_2US (0x5 << PXDCR_EP_L1_ACC_LAT_OFFS)
++#define PXLCR_L0S_EXT_LAT_2US_4US (0x6 << PXDCR_EP_L1_ACC_LAT_OFFS)
++
++#define PXLCR_POR_TNUM_OFFS 24 /* Port Number */
++#define PXLCR_POR_TNUM_MASK (0xff << PXLCR_POR_TNUM_OFFS)
++
++/* PCI Express Link Control Status Register */
++/*PEX_LINK_CTRL_STAT_REG (PXLCSR)*/
++
++#define PXLCSR_ASPM_CNT_OFFS 0 /* Active State Link PM Control */
++#define PXLCSR_ASPM_CNT_MASK (0x3 << PXLCSR_ASPM_CNT_OFFS)
++#define PXLCSR_ASPM_CNT_DISABLED (0x0 << PXLCSR_ASPM_CNT_OFFS)
++#define PXLCSR_ASPM_CNT_L0S_ENT_SUPP (0x1 << PXLCSR_ASPM_CNT_OFFS)
++#define PXLCSR_ASPM_CNT_L1S_ENT_SUPP (0x2 << PXLCSR_ASPM_CNT_OFFS)
++#define PXLCSR_ASPM_CNT_L0S_L1S_ENT_SUPP (0x3 << PXLCSR_ASPM_CNT_OFFS)
++
++#define PXLCSR_RCB_OFFS 3 /* Read Completion Boundary */
++#define PXLCSR_RCB_MASK BIT3
++#define PXLCSR_RCB_64B (0 << PXLCSR_RCB_OFFS)
++#define PXLCSR_RCB_128B (1 << PXLCSR_RCB_OFFS)
++
++#define PXLCSR_LNK_DIS BIT4 /* Link Disable */
++#define PXLCSR_RETRN_LNK BIT5 /* Retrain Link */
++#define PXLCSR_CMN_CLK_CFG BIT6 /* Common Clock Configuration */
++#define PXLCSR_EXTD_SNC BIT7 /* Extended Sync */
++
++#define PXLCSR_LNK_SPD_OFFS 16 /* Link Speed */
++#define PXLCSR_LNK_SPD_MASK (0xf << PXLCSR_LNK_SPD_OFFS)
++
++#define PXLCSR_NEG_LNK_WDTH_OFFS 20 /* Negotiated Link Width */
++#define PXLCSR_NEG_LNK_WDTH_MASK (0x3f << PXLCSR_NEG_LNK_WDTH_OFFS)
++#define PXLCSR_NEG_LNK_WDTH_X1 (0x1 << PXLCSR_NEG_LNK_WDTH_OFFS)
++
++#define PXLCSR_LNK_TRN BIT27 /* Link Training */
++
++#define PXLCSR_SLT_CLK_CFG_OFFS 28 /* Slot Clock Configuration */
++#define PXLCSR_SLT_CLK_CFG_MASK BIT28
++#define PXLCSR_SLT_CLK_CFG_INDPNT (0x0 << PXLCSR_SLT_CLK_CFG_OFFS)
++#define PXLCSR_SLT_CLK_CFG_REF (0x1 << PXLCSR_SLT_CLK_CFG_OFFS)
++
++/* PCI Express Advanced Error Report Header Register */
++/*PEX_ADV_ERR_RPRT_HDR_TRGT_REG (PXAERHTR)*/
++
++/* PCI Express Uncorrectable Error Status Register*/
++/*PEX_UNCORRECT_ERR_STAT_REG (PXUESR)*/
++
++/* PCI Express Uncorrectable Error Mask Register */
++/*PEX_UNCORRECT_ERR_MASK_REG (PXUEMR)*/
++
++/* PCI Express Uncorrectable Error Severity Register */
++/*PEX_UNCORRECT_ERR_SERVITY_REG (PXUESR)*/
++
++/* PCI Express Correctable Error Status Register */
++/*PEX_CORRECT_ERR_STAT_REG (PXCESR)*/
++
++/* PCI Express Correctable Error Mask Register */
++/*PEX_CORRECT_ERR_MASK_REG (PXCEMR)*/
++
++/* PCI Express Advanced Error Capability and Control Register*/
++/*PEX_ADV_ERR_CAPABILITY_CTRL_REG (PXAECCR)*/
++
++/* PCI Express Header Log First DWORD Register*/
++/*PEX_HDR_LOG_FIRST_DWORD_REG (PXHLFDR)*/
++
++/* PCI Express Header Log Second DWORD Register*/
++/*PEX_HDR_LOG_SECOND_DWORD_REG (PXHLSDR)*/
++
++/* PCI Express Header Log Third DWORD Register*/
++/*PEX_HDR_LOG_THIRD_DWORD_REG (PXHLTDR)*/
++
++/* PCI Express Header Log Fourth DWORD Register*/
++/*PEX_HDR_LOG_FOURTH_DWORD_REG (PXHLFDR)*/
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* #ifndef __INCPEXREGSH */
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.c 2010-11-09 20:28:11.822495468 +0100
+@@ -0,0 +1,313 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvPex.h"
++
++//#define MV_DEBUG
++/* defines */
++#ifdef MV_DEBUG
++ #define DB(x) x
++#else
++ #define DB(x)
++#endif
++
++/* locals */
++typedef struct
++{
++ MV_U32 data;
++ MV_U32 mask;
++}PEX_HEADER_DATA;
++
++/* local function forwad decleration */
++MV_U32 mvPexHwConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func,
++ MV_U32 regOff);
++MV_STATUS mvPexHwConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func, MV_U32 regOff, MV_U32 data);
++void resetPexConfig(MV_U32 pexIf, MV_U32 bus, MV_U32 dev);
++
++
++PEX_HEADER_DATA configHdr[16] =
++{
++{0x888811ab, 0x00000000}, /*[device ID, vendor ID] */
++{0x00100007, 0x0000ffff}, /*[status register, command register] */
++{0x0604000e, 0x00000000}, /*[programming interface, sub class code, class code, revision ID] */
++{0x00010008, 0x00000000}, /*[BIST, header type, latency time, cache line] */
++{0x00000000, 0x00000000}, /*[base address 0] */
++{0x00000000, 0x00000000}, /*[base address 1] */
++{0x00000000, 0x00ffffff}, /*[secondary latency timersubordinate bus number, secondary bus number, primary bus number] */
++{0x0000f101, 0x00000000}, /*[secondary status ,IO limit, IO base] */
++{0x9ff0a000, 0x00000000}, /*[memory limit, memory base] */
++{0x0001fff1, 0x00000000}, /*[prefetch memory limit, prefetch memory base] */
++{0xffffffff, 0x00000000}, /*[prefetch memory base upper] */
++{0x00000000, 0x00000000}, /*[prefetch memory limit upper] */
++{0xeffff000, 0x00000000}, /*[IO limit upper 16 bits, IO base upper 16 bits] */
++{0x00000000, 0x00000000}, /*[reserved, capability pointer] */
++{0x00000000, 0x00000000}, /*[expansion ROM base address] */
++{0x00000000, 0x000000FF}, /*[bridge control, interrupt pin, interrupt line] */
++};
++
++
++#define HEADER_WRITE(data, offset) configHdr[offset/4].data = ((configHdr[offset/4].data & ~configHdr[offset/4].mask) | \
++ (data & configHdr[offset/4].mask))
++#define HEADER_READ(offset) configHdr[offset/4].data
++
++/*******************************************************************************
++* mvVrtBrgPexInit - Initialize PEX interfaces
++*
++* DESCRIPTION:
++*
++* This function is responsible of intialization of the Pex Interface , It
++* configure the Pex Bars and Windows in the following manner:
++*
++* Assumptions :
++* Bar0 is always internal registers bar
++* Bar1 is always the DRAM bar
++* Bar2 is always the Device bar
++*
++* 1) Sets the Internal registers bar base by obtaining the base from
++* the CPU Interface
++* 2) Sets the DRAM bar base and size by getting the base and size from
++* the CPU Interface when the size is the sum of all enabled DRAM
++* chip selects and the base is the base of CS0 .
++* 3) Sets the Device bar base and size by getting these values from the
++* CPU Interface when the base is the base of the lowest base of the
++* Device chip selects, and the
++*
++*
++* INPUT:
++*
++* pexIf - PEX interface number.
++*
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_OK if function success otherwise MV_ERROR or MV_BAD_PARAM
++*
++*******************************************************************************/
++MV_STATUS mvPexVrtBrgInit(MV_U32 pexIf)
++{
++ /* reset PEX tree to recover previous U-boot/Boot configurations */
++ MV_U32 localBus = mvPexLocalBusNumGet(pexIf);
++
++
++ resetPexConfig(pexIf, localBus, 1);
++ return MV_OK;
++}
++
++
++MV_U32 mvPexVrtBrgConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func,
++ MV_U32 regOff)
++{
++
++ MV_U32 localBus = mvPexLocalBusNumGet(pexIf);
++ MV_U32 localDev = mvPexLocalDevNumGet(pexIf);
++ MV_U32 val;
++ if(bus == localBus)
++ {
++ if(dev > 1)
++ {
++/* on the local device allow only device #0 & #1 */
++ return 0xffffffff;
++ }
++ else
++ if (dev == localDev)
++ {
++ /* read the memory controller registers */
++ return mvPexHwConfigRead (pexIf, bus, dev, func, regOff);
++ }
++ else
++ {
++ /* access the virtual brg header */
++ return HEADER_READ(regOff);
++ }
++ }
++ else
++ if(bus == (localBus + 1))
++ {
++ /* access the device behind the virtual bridge */
++ if((dev == localDev) || (dev > 1))
++ {
++ return 0xffffffff;
++ }
++ else
++ {
++ /* access the device behind the virtual bridge, in this case
++ * change the bus number to the local bus number in order to
++ * generate type 0 config cycle
++ */
++ mvPexLocalBusNumSet(pexIf, bus);
++ mvPexLocalDevNumSet(pexIf, 1);
++ val = mvPexHwConfigRead (pexIf, bus, 0, func, regOff);
++ mvPexLocalBusNumSet(pexIf, localBus);
++ mvPexLocalDevNumSet(pexIf, localDev);
++ return val;
++ }
++ }
++ /* for all other devices use the HW function to get the
++ * requested registers
++ */
++ mvPexLocalDevNumSet(pexIf, 1);
++ val = mvPexHwConfigRead (pexIf, bus, dev, func, regOff);
++ mvPexLocalDevNumSet(pexIf, localDev);
++ return val;
++}
++
++
++MV_STATUS mvPexVrtBrgConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func, MV_U32 regOff, MV_U32 data)
++{
++ MV_U32 localBus = mvPexLocalBusNumGet(pexIf);
++ MV_U32 localDev = mvPexLocalDevNumGet(pexIf);
++ MV_STATUS status;
++
++ if(bus == localBus)
++ {
++ if(dev > 1)
++ {
++ /* on the local device allow only device #0 & #1 */
++ return MV_ERROR;
++ }
++ else
++ if (dev == localDev)
++ {
++ /* read the memory controller registers */
++ return mvPexHwConfigWrite (pexIf, bus, dev, func, regOff, data);
++ }
++ else
++ {
++ /* access the virtual brg header */
++ HEADER_WRITE(data, regOff);
++ return MV_OK;
++ }
++ }
++ else
++ if(bus == (localBus + 1))
++ {
++ /* access the device behind the virtual bridge */
++ if((dev == localDev) || (dev > 1))
++ {
++ return MV_ERROR;
++ }
++ else
++ {
++ /* access the device behind the virtual bridge, in this case
++ * change the bus number to the local bus number in order to
++ * generate type 0 config cycle
++ */
++ //return mvPexHwConfigWrite (pexIf, localBus, dev, func, regOff, data);
++ mvPexLocalBusNumSet(pexIf, bus);
++ mvPexLocalDevNumSet(pexIf, 1);
++ status = mvPexHwConfigWrite (pexIf, bus, 0, func, regOff, data);
++ mvPexLocalBusNumSet(pexIf, localBus);
++ mvPexLocalDevNumSet(pexIf, localDev);
++ return status;
++
++ }
++ }
++ /* for all other devices use the HW function to get the
++ * requested registers
++ */
++ mvPexLocalDevNumSet(pexIf, 1);
++ status = mvPexHwConfigWrite (pexIf, bus, dev, func, regOff, data);
++ mvPexLocalDevNumSet(pexIf, localDev);
++ return status;
++}
++
++
++
++
++void resetPexConfig(MV_U32 pexIf, MV_U32 bus, MV_U32 dev)
++{
++ MV_U32 tData;
++ MV_U32 i;
++
++ /* restore the PEX configuration to initialization state */
++ /* in case PEX P2P call recursive and reset config */
++ tData = mvPexHwConfigRead (pexIf, bus, dev, 0x0, 0x0);
++ if(tData != 0xffffffff)
++ {
++ /* agent had been found - check whether P2P */
++ tData = mvPexHwConfigRead (pexIf, bus, dev, 0x0, 0x8);
++ if((tData & 0xffff0000) == 0x06040000)
++ {/* P2P */
++ /* get the sec bus and the subordinate */
++ MV_U32 secBus;
++ tData = mvPexHwConfigRead (pexIf, bus, dev, 0x0, 0x18);
++ secBus = ((tData >> 8) & 0xff);
++ /* now scan on sec bus */
++ for(i = 0;i < 0xff;i++)
++ {
++ resetPexConfig(pexIf, secBus, i);
++ }
++ /* now reset this device */
++ DB(mvOsPrintf("Reset bus %d dev %d\n", bus, dev));
++ mvPexHwConfigWrite(pexIf, bus, dev, 0x0, 0x18, 0x0);
++ DB(mvOsPrintf("Reset bus %d dev %d\n", bus, dev));
++ }
++ }
++}
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.h 2010-11-09 20:28:11.861239834 +0100
+@@ -0,0 +1,82 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCVRTBRGPEXH
++#define __INCVRTBRGPEXH
++
++
++/* Global Functions prototypes */
++/* mvPexInit - Initialize PEX interfaces*/
++MV_STATUS mvPexVrtBrgInit(MV_U32 pexIf);
++
++/* mvPexConfigRead - Read from configuration space */
++MV_U32 mvPexVrtBrgConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func,MV_U32 regOff);
++
++/* mvPexConfigWrite - Write to configuration space */
++MV_STATUS mvPexVrtBrgConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev,
++ MV_U32 func, MV_U32 regOff, MV_U32 data);
++
++
++#endif /* #ifndef __INCPEXH */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.c 2010-11-09 20:28:11.901246212 +0100
+@@ -0,0 +1,1522 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvOs.h"
++#include "sflash/mvSFlash.h"
++#include "sflash/mvSFlashSpec.h"
++#include "spi/mvSpi.h"
++#include "spi/mvSpiCmnd.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++
++/*#define MV_DEBUG*/
++#ifdef MV_DEBUG
++#define DB(x) x
++#else
++#define DB(x)
++#endif
++
++/* Globals */
++static MV_SFLASH_DEVICE_PARAMS sflash[] = {
++ /* ST M25P32 SPI flash, 4MB, 64 sectors of 64K each */
++ {
++ MV_M25P_WREN_CMND_OPCD,
++ MV_M25P_WRDI_CMND_OPCD,
++ MV_M25P_RDID_CMND_OPCD,
++ MV_M25P_RDSR_CMND_OPCD,
++ MV_M25P_WRSR_CMND_OPCD,
++ MV_M25P_READ_CMND_OPCD,
++ MV_M25P_FAST_RD_CMND_OPCD,
++ MV_M25P_PP_CMND_OPCD,
++ MV_M25P_SE_CMND_OPCD,
++ MV_M25P_BE_CMND_OPCD,
++ MV_M25P_RES_CMND_OPCD,
++ MV_SFLASH_NO_SPECIFIC_OPCD, /* power save not supported */
++ MV_M25P32_SECTOR_SIZE,
++ MV_M25P32_SECTOR_NUMBER,
++ MV_M25P_PAGE_SIZE,
++ "ST M25P32",
++ MV_M25PXXX_ST_MANF_ID,
++ MV_M25P32_DEVICE_ID,
++ MV_M25P32_MAX_SPI_FREQ,
++ MV_M25P32_MAX_FAST_SPI_FREQ,
++ MV_M25P32_FAST_READ_DUMMY_BYTES
++ },
++ /* ST M25P64 SPI flash, 8MB, 128 sectors of 64K each */
++ {
++ MV_M25P_WREN_CMND_OPCD,
++ MV_M25P_WRDI_CMND_OPCD,
++ MV_M25P_RDID_CMND_OPCD,
++ MV_M25P_RDSR_CMND_OPCD,
++ MV_M25P_WRSR_CMND_OPCD,
++ MV_M25P_READ_CMND_OPCD,
++ MV_M25P_FAST_RD_CMND_OPCD,
++ MV_M25P_PP_CMND_OPCD,
++ MV_M25P_SE_CMND_OPCD,
++ MV_M25P_BE_CMND_OPCD,
++ MV_M25P_RES_CMND_OPCD,
++ MV_SFLASH_NO_SPECIFIC_OPCD, /* power save not supported */
++ MV_M25P64_SECTOR_SIZE,
++ MV_M25P64_SECTOR_NUMBER,
++ MV_M25P_PAGE_SIZE,
++ "ST M25P64",
++ MV_M25PXXX_ST_MANF_ID,
++ MV_M25P64_DEVICE_ID,
++ MV_M25P64_MAX_SPI_FREQ,
++ MV_M25P64_MAX_FAST_SPI_FREQ,
++ MV_M25P64_FAST_READ_DUMMY_BYTES
++ },
++ /* ST M25P128 SPI flash, 16MB, 64 sectors of 256K each */
++ {
++ MV_M25P_WREN_CMND_OPCD,
++ MV_M25P_WRDI_CMND_OPCD,
++ MV_M25P_RDID_CMND_OPCD,
++ MV_M25P_RDSR_CMND_OPCD,
++ MV_M25P_WRSR_CMND_OPCD,
++ MV_M25P_READ_CMND_OPCD,
++ MV_M25P_FAST_RD_CMND_OPCD,
++ MV_M25P_PP_CMND_OPCD,
++ MV_M25P_SE_CMND_OPCD,
++ MV_M25P_BE_CMND_OPCD,
++ MV_M25P_RES_CMND_OPCD,
++ MV_SFLASH_NO_SPECIFIC_OPCD, /* power save not supported */
++ MV_M25P128_SECTOR_SIZE,
++ MV_M25P128_SECTOR_NUMBER,
++ MV_M25P_PAGE_SIZE,
++ "ST M25P128",
++ MV_M25PXXX_ST_MANF_ID,
++ MV_M25P128_DEVICE_ID,
++ MV_M25P128_MAX_SPI_FREQ,
++ MV_M25P128_MAX_FAST_SPI_FREQ,
++ MV_M25P128_FAST_READ_DUMMY_BYTES
++ },
++ /* Macronix MXIC MX25L6405 SPI flash, 8MB, 128 sectors of 64K each */
++ {
++ MV_MX25L_WREN_CMND_OPCD,
++ MV_MX25L_WRDI_CMND_OPCD,
++ MV_MX25L_RDID_CMND_OPCD,
++ MV_MX25L_RDSR_CMND_OPCD,
++ MV_MX25L_WRSR_CMND_OPCD,
++ MV_MX25L_READ_CMND_OPCD,
++ MV_MX25L_FAST_RD_CMND_OPCD,
++ MV_MX25L_PP_CMND_OPCD,
++ MV_MX25L_SE_CMND_OPCD,
++ MV_MX25L_BE_CMND_OPCD,
++ MV_MX25L_RES_CMND_OPCD,
++ MV_MX25L_DP_CMND_OPCD,
++ MV_MX25L6405_SECTOR_SIZE,
++ MV_MX25L6405_SECTOR_NUMBER,
++ MV_MXIC_PAGE_SIZE,
++ "MXIC MX25L6405",
++ MV_MXIC_MANF_ID,
++ MV_MX25L6405_DEVICE_ID,
++ MV_MX25L6405_MAX_SPI_FREQ,
++ MV_MX25L6405_MAX_FAST_SPI_FREQ,
++ MV_MX25L6405_FAST_READ_DUMMY_BYTES
++ },
++ /* SPANSION S25FL128P SPI flash, 16MB, 64 sectors of 256K each */
++ {
++ MV_S25FL_WREN_CMND_OPCD,
++ MV_S25FL_WRDI_CMND_OPCD,
++ MV_S25FL_RDID_CMND_OPCD,
++ MV_S25FL_RDSR_CMND_OPCD,
++ MV_S25FL_WRSR_CMND_OPCD,
++ MV_S25FL_READ_CMND_OPCD,
++ MV_S25FL_FAST_RD_CMND_OPCD,
++ MV_S25FL_PP_CMND_OPCD,
++ MV_S25FL_SE_CMND_OPCD,
++ MV_S25FL_BE_CMND_OPCD,
++ MV_S25FL_RES_CMND_OPCD,
++ MV_S25FL_DP_CMND_OPCD,
++ MV_S25FL128_SECTOR_SIZE,
++ MV_S25FL128_SECTOR_NUMBER,
++ MV_S25FL_PAGE_SIZE,
++ "SPANSION S25FL128",
++ MV_SPANSION_MANF_ID,
++ MV_S25FL128_DEVICE_ID,
++ MV_S25FL128_MAX_SPI_FREQ,
++ MV_M25P128_MAX_FAST_SPI_FREQ,
++ MV_M25P128_FAST_READ_DUMMY_BYTES
++ }
++};
++
++/* Static Functions */
++static MV_STATUS mvWriteEnable (MV_SFLASH_INFO * pFlinfo);
++static MV_STATUS mvStatusRegGet (MV_SFLASH_INFO * pFlinfo, MV_U8 * pStatReg);
++static MV_STATUS mvStatusRegSet (MV_SFLASH_INFO * pFlinfo, MV_U8 sr);
++static MV_STATUS mvWaitOnWipClear(MV_SFLASH_INFO * pFlinfo);
++static MV_STATUS mvSFlashPageWr (MV_SFLASH_INFO * pFlinfo, MV_U32 offset, \
++ MV_U8* pPageBuff, MV_U32 buffSize);
++static MV_STATUS mvSFlashWithDefaultsIdGet (MV_SFLASH_INFO * pFlinfo, \
++ MV_U8* manId, MV_U16* devId);
++
++/*******************************************************************************
++* mvWriteEnable - serialize the write enable sequence
++*
++* DESCRIPTION:
++* transmit the sequence for write enable
++*
++********************************************************************************/
++static MV_STATUS mvWriteEnable(MV_SFLASH_INFO * pFlinfo)
++{
++ MV_U8 cmd[MV_SFLASH_WREN_CMND_LENGTH];
++
++
++ cmd[0] = sflash[pFlinfo->index].opcdWREN;
++
++ return mvSpiWriteThenRead(cmd, MV_SFLASH_WREN_CMND_LENGTH, NULL, 0, 0);
++}
++
++/*******************************************************************************
++* mvStatusRegGet - Retrieve the value of the status register
++*
++* DESCRIPTION:
++* perform the RDSR sequence to get the 8bit status register
++*
++********************************************************************************/
++static MV_STATUS mvStatusRegGet(MV_SFLASH_INFO * pFlinfo, MV_U8 * pStatReg)
++{
++ MV_STATUS ret;
++ MV_U8 cmd[MV_SFLASH_RDSR_CMND_LENGTH];
++ MV_U8 sr[MV_SFLASH_RDSR_REPLY_LENGTH];
++
++
++
++
++ cmd[0] = sflash[pFlinfo->index].opcdRDSR;
++
++ if ((ret = mvSpiWriteThenRead(cmd, MV_SFLASH_RDSR_CMND_LENGTH, sr,
++ MV_SFLASH_RDSR_REPLY_LENGTH,0)) != MV_OK)
++ return ret;
++
++ *pStatReg = sr[0];
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvWaitOnWipClear - Block waiting for the WIP (write in progress) to be cleared
++*
++* DESCRIPTION:
++* Block waiting for the WIP (write in progress) to be cleared
++*
++********************************************************************************/
++static MV_STATUS mvWaitOnWipClear(MV_SFLASH_INFO * pFlinfo)
++{
++ MV_STATUS ret;
++ MV_U32 i;
++ MV_U8 stat;
++
++ for (i=0; i<MV_SFLASH_MAX_WAIT_LOOP; i++)
++ {
++ if ((ret = mvStatusRegGet(pFlinfo, &stat)) != MV_OK)
++ return ret;
++
++ if ((stat & MV_SFLASH_STATUS_REG_WIP_MASK) == 0)
++ return MV_OK;
++ }
++
++ DB(mvOsPrintf("%s WARNING: Write Timeout!\n", __FUNCTION__);)
++ return MV_TIMEOUT;
++}
++
++/*******************************************************************************
++* mvWaitOnChipEraseDone - Block waiting for the WIP (write in progress) to be
++* cleared after a chip erase command which is supposed
++* to take about 2:30 minutes
++*
++* DESCRIPTION:
++* Block waiting for the WIP (write in progress) to be cleared
++*
++********************************************************************************/
++static MV_STATUS mvWaitOnChipEraseDone(MV_SFLASH_INFO * pFlinfo)
++{
++ MV_STATUS ret;
++ MV_U32 i;
++ MV_U8 stat;
++
++ for (i=0; i<MV_SFLASH_CHIP_ERASE_MAX_WAIT_LOOP; i++)
++ {
++ if ((ret = mvStatusRegGet(pFlinfo, &stat)) != MV_OK)
++ return ret;
++
++ if ((stat & MV_SFLASH_STATUS_REG_WIP_MASK) == 0)
++ return MV_OK;
++ }
++
++ DB(mvOsPrintf("%s WARNING: Write Timeout!\n", __FUNCTION__);)
++ return MV_TIMEOUT;
++}
++
++/*******************************************************************************
++* mvStatusRegSet - Set the value of the 8bit status register
++*
++* DESCRIPTION:
++* Set the value of the 8bit status register
++*
++********************************************************************************/
++static MV_STATUS mvStatusRegSet(MV_SFLASH_INFO * pFlinfo, MV_U8 sr)
++{
++ MV_STATUS ret;
++ MV_U8 cmd[MV_SFLASH_WRSR_CMND_LENGTH];
++
++
++ /* Issue the Write enable command prior the WRSR command */
++ if ((ret = mvWriteEnable(pFlinfo)) != MV_OK)
++ return ret;
++
++ /* Write the SR with the new values */
++ cmd[0] = sflash[pFlinfo->index].opcdWRSR;
++ cmd[1] = sr;
++
++ if ((ret = mvSpiWriteThenRead(cmd, MV_SFLASH_WRSR_CMND_LENGTH, NULL, 0, 0)) != MV_OK)
++ return ret;
++
++ if ((ret = mvWaitOnWipClear(pFlinfo)) != MV_OK)
++ return ret;
++
++ mvOsDelay(1);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSFlashPageWr - Write up to 256 Bytes in the same page
++*
++* DESCRIPTION:
++* Write a buffer up to the page size in length provided that the whole address
++* range is within the same page (alligned to page bounderies)
++*
++*******************************************************************************/
++static MV_STATUS mvSFlashPageWr (MV_SFLASH_INFO * pFlinfo, MV_U32 offset,
++ MV_U8* pPageBuff, MV_U32 buffSize)
++{
++ MV_STATUS ret;
++ MV_U8 cmd[MV_SFLASH_PP_CMND_LENGTH];
++
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invalid parameter device index!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ /* check that we do not cross the page bounderies */
++ if (((offset & (sflash[pFlinfo->index].pageSize - 1)) + buffSize) >
++ sflash[pFlinfo->index].pageSize)
++ {
++ DB(mvOsPrintf("%s WARNING: Page allignment problem!\n", __FUNCTION__);)
++ return MV_OUT_OF_RANGE;
++ }
++
++ /* Issue the Write enable command prior the page program command */
++ if ((ret = mvWriteEnable(pFlinfo)) != MV_OK)
++ return ret;
++
++ cmd[0] = sflash[pFlinfo->index].opcdPP;
++ cmd[1] = ((offset >> 16) & 0xFF);
++ cmd[2] = ((offset >> 8) & 0xFF);
++ cmd[3] = (offset & 0xFF);
++
++ if ((ret = mvSpiWriteThenWrite(cmd, MV_SFLASH_PP_CMND_LENGTH, pPageBuff, buffSize)) != MV_OK)
++ return ret;
++
++ if ((ret = mvWaitOnWipClear(pFlinfo)) != MV_OK)
++ return ret;
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSFlashWithDefaultsIdGet - Try to read the manufacturer and Device IDs from
++* the device using the default RDID opcode and the default WREN opcode.
++*
++* DESCRIPTION:
++* This is used to detect a generic device that uses the default opcodes
++* for the WREN and RDID.
++*
++********************************************************************************/
++static MV_STATUS mvSFlashWithDefaultsIdGet (MV_SFLASH_INFO * pFlinfo, MV_U8* manId, MV_U16* devId)
++{
++ MV_STATUS ret;
++ MV_U8 cmdRDID[MV_SFLASH_RDID_CMND_LENGTH];
++ MV_U8 id[MV_SFLASH_RDID_REPLY_LENGTH];
++
++
++
++ /* Use the default RDID opcode to read the IDs */
++ cmdRDID[0] = MV_SFLASH_DEFAULT_RDID_OPCD; /* unknown model try default */
++ if ((ret = mvSpiWriteThenRead(cmdRDID, MV_SFLASH_RDID_CMND_LENGTH, id, MV_SFLASH_RDID_REPLY_LENGTH, 0)) != MV_OK)
++ return ret;
++
++ *manId = id[0];
++ *devId = 0;
++ *devId |= (id[1] << 8);
++ *devId |= id[2];
++
++ return MV_OK;
++}
++
++/*
++#####################################################################################
++#####################################################################################
++*/
++
++/*******************************************************************************
++* mvSFlashInit - Initialize the serial flash device
++*
++* DESCRIPTION:
++* Perform the neccessary initialization and configuration
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++* pFlinfo->baseAddr: base address in fast mode.
++* pFlinfo->index: Index of the flash in the sflash tabel. If the SPI
++* flash device does not support read Id command with
++* the standard opcode, then the user should supply this
++* as an input to skip the autodetection process!!!!
++*
++* OUTPUT:
++* pFlinfo: pointer to the Flash information structure after detection
++* pFlinfo->manufacturerId: Manufacturer ID
++* pFlinfo->deviceId: Device ID
++* pFlinfo->sectorSize: size of the sector (all sectors are the same).
++* pFlinfo->sectorNumber: number of sectors.
++* pFlinfo->pageSize: size of the page.
++* pFlinfo->index: Index of the detected flash in the sflash tabel
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashInit (MV_SFLASH_INFO * pFlinfo)
++{
++ MV_STATUS ret;
++ MV_U8 manf;
++ MV_U16 dev;
++ MV_U32 indx;
++ MV_BOOL detectFlag = MV_FALSE;
++
++ /* check for NULL pointer */
++ if (pFlinfo == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Initialize the SPI interface with low frequency to make sure that the read ID succeeds */
++ if ((ret = mvSpiInit(MV_SFLASH_BASIC_SPI_FREQ)) != MV_OK)
++ {
++ mvOsPrintf("%s ERROR: Failed to initialize the SPI interface!\n", __FUNCTION__);
++ return ret;
++ }
++
++ /* First try to read the Manufacturer and Device IDs */
++ if ((ret = mvSFlashIdGet(pFlinfo, &manf, &dev)) != MV_OK)
++ {
++ mvOsPrintf("%s ERROR: Failed to get the SFlash ID!\n", __FUNCTION__);
++ return ret;
++ }
++
++ /* loop over the whole table and look for the appropriate SFLASH */
++ for (indx=0; indx<MV_ARRAY_SIZE(sflash); indx++)
++ {
++ if ((manf == sflash[indx].manufacturerId) && (dev == sflash[indx].deviceId))
++ {
++ pFlinfo->manufacturerId = manf;
++ pFlinfo->deviceId = dev;
++ pFlinfo->index = indx;
++ detectFlag = MV_TRUE;
++ }
++ }
++
++ if(!detectFlag)
++ {
++ mvOsPrintf("%s ERROR: Unknown SPI flash device!\n", __FUNCTION__);
++ return MV_FAIL;
++ }
++
++ /* fill the info based on the model detected */
++ pFlinfo->sectorSize = sflash[pFlinfo->index].sectorSize;
++ pFlinfo->sectorNumber = sflash[pFlinfo->index].sectorNumber;
++ pFlinfo->pageSize = sflash[pFlinfo->index].pageSize;
++
++ /* Set the SPI frequency to the MAX allowed for the device for best performance */
++ if ((ret = mvSpiBaudRateSet(sflash[pFlinfo->index].spiMaxFreq)) != MV_OK)
++ {
++ mvOsPrintf("%s ERROR: Failed to set the SPI frequency!\n", __FUNCTION__);
++ return ret;
++ }
++
++ /* As default lock the SR */
++ if ((ret = mvSFlashStatRegLock(pFlinfo, MV_TRUE)) != MV_OK)
++ return ret;
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSFlashSectorErase - Erasse a single sector of the serial flash
++*
++* DESCRIPTION:
++* Issue the erase sector command and address
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++* secNumber: sector Number to erase (0 -> (sectorNumber-1))
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashSectorErase (MV_SFLASH_INFO * pFlinfo, MV_U32 secNumber)
++{
++ MV_STATUS ret;
++ MV_U8 cmd[MV_SFLASH_SE_CMND_LENGTH];
++
++ MV_U32 secAddr = (secNumber * pFlinfo->sectorSize);
++#if 0
++ MV_U32 i;
++ MV_U32 * pW = (MV_U32*) (secAddr + pFlinfo->baseAddr);
++ MV_U32 erasedWord = 0xFFFFFFFF;
++ MV_U32 wordsPerSector = (pFlinfo->sectorSize / sizeof(MV_U32));
++ MV_BOOL eraseNeeded = MV_FALSE;
++#endif
++ /* check for NULL pointer */
++ if (pFlinfo == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ /* check that the sector number is valid */
++ if (secNumber >= pFlinfo->sectorNumber)
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter sector number!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ /* we don't want to access SPI in direct mode from in-direct API,
++ becasue of timing issue between CS asserts. */
++#if 0
++ /* First compare to FF and check if erase is needed */
++ for (i=0; i<wordsPerSector; i++)
++ {
++ if (memcmp(pW, &erasedWord, sizeof(MV_U32)) != 0)
++ {
++ eraseNeeded = MV_TRUE;
++ break;
++ }
++
++ ++pW;
++ }
++ if (!eraseNeeded)
++ return MV_OK;
++#endif
++
++ cmd[0] = sflash[pFlinfo->index].opcdSE;
++ cmd[1] = ((secAddr >> 16) & 0xFF);
++ cmd[2] = ((secAddr >> 8) & 0xFF);
++ cmd[3] = (secAddr & 0xFF);
++
++ /* Issue the Write enable command prior the sector erase command */
++ if ((ret = mvWriteEnable(pFlinfo)) != MV_OK)
++ return ret;
++
++ if ((ret = mvSpiWriteThenWrite(cmd, MV_SFLASH_SE_CMND_LENGTH, NULL, 0)) != MV_OK)
++ return ret;
++
++ if ((ret = mvWaitOnWipClear(pFlinfo)) != MV_OK)
++ return ret;
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSFlashChipErase - Erasse the whole serial flash
++*
++* DESCRIPTION:
++* Issue the bulk (chip) erase command
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashChipErase (MV_SFLASH_INFO * pFlinfo)
++{
++ MV_STATUS ret;
++ MV_U8 cmd[MV_SFLASH_BE_CMND_LENGTH];
++
++
++ /* check for NULL pointer */
++ if (pFlinfo == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ cmd[0] = sflash[pFlinfo->index].opcdBE;
++
++ /* Issue the Write enable command prior the Bulk erase command */
++ if ((ret = mvWriteEnable(pFlinfo)) != MV_OK)
++ return ret;
++
++ if ((ret = mvSpiWriteThenWrite(cmd, MV_SFLASH_BE_CMND_LENGTH, NULL, 0)) != MV_OK)
++ return ret;
++
++ if ((ret = mvWaitOnChipEraseDone(pFlinfo)) != MV_OK)
++ return ret;
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSFlashBlockRd - Read from the serial flash
++*
++* DESCRIPTION:
++* Issue the read command and address then perfom the needed read
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++* offset: byte offset with the flash to start reading from
++* pReadBuff: pointer to the buffer to read the data in
++* buffSize: size of the buffer to read.
++*
++* OUTPUT:
++* pReadBuff: pointer to the buffer containing the read data
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashBlockRd (MV_SFLASH_INFO * pFlinfo, MV_U32 offset,
++ MV_U8* pReadBuff, MV_U32 buffSize)
++{
++ MV_U8 cmd[MV_SFLASH_READ_CMND_LENGTH];
++
++
++ /* check for NULL pointer */
++ if ((pFlinfo == NULL) || (pReadBuff == NULL))
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ cmd[0] = sflash[pFlinfo->index].opcdREAD;
++ cmd[1] = ((offset >> 16) & 0xFF);
++ cmd[2] = ((offset >> 8) & 0xFF);
++ cmd[3] = (offset & 0xFF);
++
++ return mvSpiWriteThenRead(cmd, MV_SFLASH_READ_CMND_LENGTH, pReadBuff, buffSize, 0);
++}
++
++/*******************************************************************************
++* mvSFlashFastBlockRd - Fast read from the serial flash
++*
++* DESCRIPTION:
++* Issue the fast read command and address then perfom the needed read
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++* offset: byte offset with the flash to start reading from
++* pReadBuff: pointer to the buffer to read the data in
++* buffSize: size of the buffer to read.
++*
++* OUTPUT:
++* pReadBuff: pointer to the buffer containing the read data
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashFastBlockRd (MV_SFLASH_INFO * pFlinfo, MV_U32 offset,
++ MV_U8* pReadBuff, MV_U32 buffSize)
++{
++ MV_U8 cmd[MV_SFLASH_READ_CMND_LENGTH];
++ MV_STATUS ret;
++
++ /* check for NULL pointer */
++ if ((pFlinfo == NULL) || (pReadBuff == NULL))
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ /* Set the SPI frequency to the MAX allowed for fast-read operations */
++ mvOsPrintf("Setting freq to %d.\n",sflash[pFlinfo->index].spiMaxFastFreq);
++ if ((ret = mvSpiBaudRateSet(sflash[pFlinfo->index].spiMaxFastFreq)) != MV_OK)
++ {
++ mvOsPrintf("%s ERROR: Failed to set the SPI fast frequency!\n", __FUNCTION__);
++ return ret;
++ }
++
++ cmd[0] = sflash[pFlinfo->index].opcdFSTRD;
++ cmd[1] = ((offset >> 16) & 0xFF);
++ cmd[2] = ((offset >> 8) & 0xFF);
++ cmd[3] = (offset & 0xFF);
++
++
++ ret = mvSpiWriteThenRead(cmd, MV_SFLASH_READ_CMND_LENGTH, pReadBuff, buffSize,
++ sflash[pFlinfo->index].spiFastRdDummyBytes);
++
++ /* Reset the SPI frequency to the MAX allowed for the device for best performance */
++ if ((ret = mvSpiBaudRateSet(sflash[pFlinfo->index].spiMaxFreq)) != MV_OK)
++ {
++ mvOsPrintf("%s ERROR: Failed to set the SPI frequency!\n", __FUNCTION__);
++ return ret;
++ }
++
++ return ret;
++}
++
++
++/*******************************************************************************
++* mvSFlashBlockWr - Write a buffer with any size
++*
++* DESCRIPTION:
++* write regardless of the page boundaries and size limit per Page
++* program command
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++* offset: byte offset within the flash region
++* pWriteBuff: pointer to the buffer holding the data to program
++* buffSize: size of the buffer to write
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashBlockWr (MV_SFLASH_INFO * pFlinfo, MV_U32 offset,
++ MV_U8* pWriteBuff, MV_U32 buffSize)
++{
++ MV_STATUS ret;
++ MV_U32 data2write = buffSize;
++ MV_U32 preAllOffset = (offset & MV_SFLASH_PAGE_ALLIGN_MASK(MV_M25P_PAGE_SIZE));
++ MV_U32 preAllSz = (preAllOffset ? (MV_M25P_PAGE_SIZE - preAllOffset) : 0);
++ MV_U32 writeOffset = offset;
++
++ /* check for NULL pointer */
++#ifndef CONFIG_MARVELL
++ if(NULL == pWriteBuff)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++#endif
++
++ if (pFlinfo == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ /* check that the buffer size does not exceed the flash size */
++ if ((offset + buffSize) > mvSFlashSizeGet(pFlinfo))
++ {
++ DB(mvOsPrintf("%s WARNING: Write exceeds flash size!\n", __FUNCTION__);)
++ return MV_OUT_OF_RANGE;
++ }
++
++ /* check if the total block size is less than the first chunk remainder */
++ if (data2write < preAllSz)
++ preAllSz = data2write;
++
++ /* check if programing does not start at a 64byte alligned offset */
++ if (preAllSz)
++ {
++ if ((ret = mvSFlashPageWr(pFlinfo, writeOffset, pWriteBuff, preAllSz)) != MV_OK)
++ return ret;
++
++ /* increment pointers and counters */
++ writeOffset += preAllSz;
++ data2write -= preAllSz;
++ pWriteBuff += preAllSz;
++ }
++
++ /* program the data that fits in complete page chunks */
++ while (data2write >= sflash[pFlinfo->index].pageSize)
++ {
++ if ((ret = mvSFlashPageWr(pFlinfo, writeOffset, pWriteBuff, sflash[pFlinfo->index].pageSize)) != MV_OK)
++ return ret;
++
++ /* increment pointers and counters */
++ writeOffset += sflash[pFlinfo->index].pageSize;
++ data2write -= sflash[pFlinfo->index].pageSize;
++ pWriteBuff += sflash[pFlinfo->index].pageSize;
++ }
++
++ /* program the last partial chunk */
++ if (data2write)
++ {
++ if ((ret = mvSFlashPageWr(pFlinfo, writeOffset, pWriteBuff, data2write)) != MV_OK)
++ return ret;
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSFlashIdGet - Get the manufacturer and device IDs.
++*
++* DESCRIPTION:
++* Get the Manufacturer and device IDs from the serial flash through
++* writing the RDID command then reading 3 bytes of data. In case that
++* this command was called for the first time in order to detect the
++* manufacturer and device IDs, then the default RDID opcode will be used
++* unless the device index is indicated by the user (in case the SPI flash
++* does not use the default RDID opcode).
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++* pManId: pointer to the 8bit variable to hold the manufacturing ID
++* pDevId: pointer to the 16bit variable to hold the device ID
++*
++* OUTPUT:
++* pManId: pointer to the 8bit variable holding the manufacturing ID
++* pDevId: pointer to the 16bit variable holding the device ID
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashIdGet (MV_SFLASH_INFO * pFlinfo, MV_U8* pManId, MV_U16* pDevId)
++{
++ MV_STATUS ret;
++ MV_U8 cmd[MV_SFLASH_RDID_CMND_LENGTH];
++ MV_U8 id[MV_SFLASH_RDID_REPLY_LENGTH];
++
++
++
++ /* check for NULL pointer */
++ if ((pFlinfo == NULL) || (pManId == NULL) || (pDevId == NULL))
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ return mvSFlashWithDefaultsIdGet(pFlinfo, pManId, pDevId);
++ else
++ cmd[0] = sflash[pFlinfo->index].opcdRDID;
++
++ if ((ret = mvSpiWriteThenRead(cmd, MV_SFLASH_RDID_CMND_LENGTH, id, MV_SFLASH_RDID_REPLY_LENGTH, 0)) != MV_OK)
++ return ret;
++
++ *pManId = id[0];
++ *pDevId = 0;
++ *pDevId |= (id[1] << 8);
++ *pDevId |= id[2];
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSFlashWpRegionSet - Set the Write-Protected region
++*
++* DESCRIPTION:
++* Set the Write-Protected region
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++* wpRegion: which region will be protected
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashWpRegionSet (MV_SFLASH_INFO * pFlinfo, MV_SFLASH_WP_REGION wpRegion)
++{
++ MV_U8 wpMask;
++
++ /* check for NULL pointer */
++ if (pFlinfo == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ /* Check if the chip is an ST flash; then WP supports only 3 bits */
++ if (pFlinfo->manufacturerId == MV_M25PXXX_ST_MANF_ID)
++ {
++ switch (wpRegion)
++ {
++ case MV_WP_NONE:
++ wpMask = MV_M25P_STATUS_BP_NONE;
++ break;
++
++ case MV_WP_UPR_1OF128:
++ DB(mvOsPrintf("%s WARNING: Invaild option for this flash chip!\n", __FUNCTION__);)
++ return MV_NOT_SUPPORTED;
++
++ case MV_WP_UPR_1OF64:
++ wpMask = MV_M25P_STATUS_BP_1_OF_64;
++ break;
++
++ case MV_WP_UPR_1OF32:
++ wpMask = MV_M25P_STATUS_BP_1_OF_32;
++ break;
++
++ case MV_WP_UPR_1OF16:
++ wpMask = MV_M25P_STATUS_BP_1_OF_16;
++ break;
++
++ case MV_WP_UPR_1OF8:
++ wpMask = MV_M25P_STATUS_BP_1_OF_8;
++ break;
++
++ case MV_WP_UPR_1OF4:
++ wpMask = MV_M25P_STATUS_BP_1_OF_4;
++ break;
++
++ case MV_WP_UPR_1OF2:
++ wpMask = MV_M25P_STATUS_BP_1_OF_2;
++ break;
++
++ case MV_WP_ALL:
++ wpMask = MV_M25P_STATUS_BP_ALL;
++ break;
++
++ default:
++ DB(mvOsPrintf("%s WARNING: Invaild parameter WP region!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++ }
++ /* check if the manufacturer is MXIC then the WP is 4bits */
++ else if (pFlinfo->manufacturerId == MV_MXIC_MANF_ID)
++ {
++ switch (wpRegion)
++ {
++ case MV_WP_NONE:
++ wpMask = MV_MX25L_STATUS_BP_NONE;
++ break;
++
++ case MV_WP_UPR_1OF128:
++ wpMask = MV_MX25L_STATUS_BP_1_OF_128;
++ break;
++
++ case MV_WP_UPR_1OF64:
++ wpMask = MV_MX25L_STATUS_BP_1_OF_64;
++ break;
++
++ case MV_WP_UPR_1OF32:
++ wpMask = MV_MX25L_STATUS_BP_1_OF_32;
++ break;
++
++ case MV_WP_UPR_1OF16:
++ wpMask = MV_MX25L_STATUS_BP_1_OF_16;
++ break;
++
++ case MV_WP_UPR_1OF8:
++ wpMask = MV_MX25L_STATUS_BP_1_OF_8;
++ break;
++
++ case MV_WP_UPR_1OF4:
++ wpMask = MV_MX25L_STATUS_BP_1_OF_4;
++ break;
++
++ case MV_WP_UPR_1OF2:
++ wpMask = MV_MX25L_STATUS_BP_1_OF_2;
++ break;
++
++ case MV_WP_ALL:
++ wpMask = MV_MX25L_STATUS_BP_ALL;
++ break;
++
++ default:
++ DB(mvOsPrintf("%s WARNING: Invaild parameter WP region!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++ }
++ /* check if the manufacturer is SPANSION then the WP is 4bits */
++ else if (pFlinfo->manufacturerId == MV_SPANSION_MANF_ID)
++ {
++ switch (wpRegion)
++ {
++ case MV_WP_NONE:
++ wpMask = MV_S25FL_STATUS_BP_NONE;
++ break;
++
++ case MV_WP_UPR_1OF128:
++ DB(mvOsPrintf("%s WARNING: Invaild option for this flash chip!\n", __FUNCTION__);)
++ return MV_NOT_SUPPORTED;
++
++ case MV_WP_UPR_1OF64:
++ wpMask = MV_S25FL_STATUS_BP_1_OF_64;
++ break;
++
++ case MV_WP_UPR_1OF32:
++ wpMask = MV_S25FL_STATUS_BP_1_OF_32;
++ break;
++
++ case MV_WP_UPR_1OF16:
++ wpMask = MV_S25FL_STATUS_BP_1_OF_16;
++ break;
++
++ case MV_WP_UPR_1OF8:
++ wpMask = MV_S25FL_STATUS_BP_1_OF_8;
++ break;
++
++ case MV_WP_UPR_1OF4:
++ wpMask = MV_S25FL_STATUS_BP_1_OF_4;
++ break;
++
++ case MV_WP_UPR_1OF2:
++ wpMask = MV_S25FL_STATUS_BP_1_OF_2;
++ break;
++
++ case MV_WP_ALL:
++ wpMask = MV_S25FL_STATUS_BP_ALL;
++ break;
++
++
++ default:
++ DB(mvOsPrintf("%s WARNING: Invaild parameter WP region!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++ }
++ else
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter Manufacturer ID!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ /* Verify that the SRWD bit is always set - register is s/w locked */
++ wpMask |= MV_SFLASH_STATUS_REG_SRWD_MASK;
++
++ return mvStatusRegSet(pFlinfo, wpMask);
++}
++
++/*******************************************************************************
++* mvSFlashWpRegionGet - Get the Write-Protected region configured
++*
++* DESCRIPTION:
++* Get from the chip the Write-Protected region configured
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++* pWpRegion: pointer to the variable to return the WP region in
++*
++* OUTPUT:
++* wpRegion: pointer to the variable holding the WP region configured
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashWpRegionGet (MV_SFLASH_INFO * pFlinfo, MV_SFLASH_WP_REGION * pWpRegion)
++{
++ MV_STATUS ret;
++ MV_U8 reg;
++
++ /* check for NULL pointer */
++ if ((pFlinfo == NULL) || (pWpRegion == NULL))
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ if ((ret = mvStatusRegGet(pFlinfo, &reg)) != MV_OK)
++ return ret;
++
++ /* Check if the chip is an ST flash; then WP supports only 3 bits */
++ if (pFlinfo->manufacturerId == MV_M25PXXX_ST_MANF_ID)
++ {
++ switch ((reg & MV_M25P_STATUS_REG_WP_MASK))
++ {
++ case MV_M25P_STATUS_BP_NONE:
++ *pWpRegion = MV_WP_NONE;
++ break;
++
++ case MV_M25P_STATUS_BP_1_OF_64:
++ *pWpRegion = MV_WP_UPR_1OF64;
++ break;
++
++ case MV_M25P_STATUS_BP_1_OF_32:
++ *pWpRegion = MV_WP_UPR_1OF32;
++ break;
++
++ case MV_M25P_STATUS_BP_1_OF_16:
++ *pWpRegion = MV_WP_UPR_1OF16;
++ break;
++
++ case MV_M25P_STATUS_BP_1_OF_8:
++ *pWpRegion = MV_WP_UPR_1OF8;
++ break;
++
++ case MV_M25P_STATUS_BP_1_OF_4:
++ *pWpRegion = MV_WP_UPR_1OF4;
++ break;
++
++ case MV_M25P_STATUS_BP_1_OF_2:
++ *pWpRegion = MV_WP_UPR_1OF2;
++ break;
++
++ case MV_M25P_STATUS_BP_ALL:
++ *pWpRegion = MV_WP_ALL;
++ break;
++
++ default:
++ DB(mvOsPrintf("%s WARNING: Unidentified WP region in h/w!\n", __FUNCTION__);)
++ return MV_BAD_VALUE;
++ }
++ }
++ /* check if the manufacturer is MXIC then the WP is 4bits */
++ else if (pFlinfo->manufacturerId == MV_MXIC_MANF_ID)
++ {
++ switch ((reg & MV_MX25L_STATUS_REG_WP_MASK))
++ {
++ case MV_MX25L_STATUS_BP_NONE:
++ *pWpRegion = MV_WP_NONE;
++ break;
++
++ case MV_MX25L_STATUS_BP_1_OF_128:
++ *pWpRegion = MV_WP_UPR_1OF128;
++ break;
++
++ case MV_MX25L_STATUS_BP_1_OF_64:
++ *pWpRegion = MV_WP_UPR_1OF64;
++ break;
++
++ case MV_MX25L_STATUS_BP_1_OF_32:
++ *pWpRegion = MV_WP_UPR_1OF32;
++ break;
++
++ case MV_MX25L_STATUS_BP_1_OF_16:
++ *pWpRegion = MV_WP_UPR_1OF16;
++ break;
++
++ case MV_MX25L_STATUS_BP_1_OF_8:
++ *pWpRegion = MV_WP_UPR_1OF8;
++ break;
++
++ case MV_MX25L_STATUS_BP_1_OF_4:
++ *pWpRegion = MV_WP_UPR_1OF4;
++ break;
++
++ case MV_MX25L_STATUS_BP_1_OF_2:
++ *pWpRegion = MV_WP_UPR_1OF2;
++ break;
++
++ case MV_MX25L_STATUS_BP_ALL:
++ *pWpRegion = MV_WP_ALL;
++ break;
++
++ default:
++ DB(mvOsPrintf("%s WARNING: Unidentified WP region in h/w!\n", __FUNCTION__);)
++ return MV_BAD_VALUE;
++ }
++ }
++ /* Check if the chip is an SPANSION flash; then WP supports only 3 bits */
++ else if (pFlinfo->manufacturerId == MV_SPANSION_MANF_ID)
++ {
++ switch ((reg & MV_S25FL_STATUS_REG_WP_MASK))
++ {
++ case MV_S25FL_STATUS_BP_NONE:
++ *pWpRegion = MV_WP_NONE;
++ break;
++
++ case MV_S25FL_STATUS_BP_1_OF_64:
++ *pWpRegion = MV_WP_UPR_1OF64;
++ break;
++
++ case MV_S25FL_STATUS_BP_1_OF_32:
++ *pWpRegion = MV_WP_UPR_1OF32;
++ break;
++
++ case MV_S25FL_STATUS_BP_1_OF_16:
++ *pWpRegion = MV_WP_UPR_1OF16;
++ break;
++
++ case MV_S25FL_STATUS_BP_1_OF_8:
++ *pWpRegion = MV_WP_UPR_1OF8;
++ break;
++
++ case MV_S25FL_STATUS_BP_1_OF_4:
++ *pWpRegion = MV_WP_UPR_1OF4;
++ break;
++
++ case MV_S25FL_STATUS_BP_1_OF_2:
++ *pWpRegion = MV_WP_UPR_1OF2;
++ break;
++
++ case MV_S25FL_STATUS_BP_ALL:
++ *pWpRegion = MV_WP_ALL;
++ break;
++
++ default:
++ DB(mvOsPrintf("%s WARNING: Unidentified WP region in h/w!\n", __FUNCTION__);)
++ return MV_BAD_VALUE;
++ }
++ }
++ else
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter Manufacturer ID!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSFlashStatRegLock - Lock the status register for writing - W/Vpp
++* pin should be low to take effect
++*
++* DESCRIPTION:
++* Lock the access to the Status Register for writing. This will
++* cause the flash to enter the hardware protection mode if the W/Vpp
++* is low. If the W/Vpp is hi, the chip will be in soft protection mode, but
++* the register will continue to be writable if WREN sequence was used.
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++* srLock: enable/disable (MV_TRUE/MV_FALSE) status registor lock mechanism
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashStatRegLock (MV_SFLASH_INFO * pFlinfo, MV_BOOL srLock)
++{
++ MV_STATUS ret;
++ MV_U8 reg;
++
++ /* check for NULL pointer */
++ if (pFlinfo == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ if ((ret = mvStatusRegGet(pFlinfo, &reg)) != MV_OK)
++ return ret;
++
++ if (srLock)
++ reg |= MV_SFLASH_STATUS_REG_SRWD_MASK;
++ else
++ reg &= ~MV_SFLASH_STATUS_REG_SRWD_MASK;
++
++ return mvStatusRegSet(pFlinfo, reg);
++}
++
++/*******************************************************************************
++* mvSFlashSizeGet - Get the size of the SPI flash
++*
++* DESCRIPTION:
++* based on the sector number and size of each sector calculate the total
++* size of the flash memory.
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Size of the flash in bytes.
++*
++*
++*******************************************************************************/
++MV_U32 mvSFlashSizeGet (MV_SFLASH_INFO * pFlinfo)
++{
++ /* check for NULL pointer */
++ if (pFlinfo == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return 0;
++ }
++
++ return (pFlinfo->sectorSize * pFlinfo->sectorNumber);
++}
++
++/*******************************************************************************
++* mvSFlashPowerSaveEnter - Cause the falsh device to go into power save mode
++*
++* DESCRIPTION:
++* Enter a special power save mode.
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Size of the flash in bytes.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashPowerSaveEnter(MV_SFLASH_INFO * pFlinfo)
++{
++ MV_STATUS ret;
++ MV_U8 cmd[MV_SFLASH_DP_CMND_LENGTH];
++
++
++ /* check for NULL pointer */
++ if (pFlinfo == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return 0;
++ }
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ /* check that power save mode is supported in the specific device */
++ if (sflash[pFlinfo->index].opcdPwrSave == MV_SFLASH_NO_SPECIFIC_OPCD)
++ {
++ DB(mvOsPrintf("%s WARNING: Power save not supported for this device!\n", __FUNCTION__);)
++ return MV_NOT_SUPPORTED;
++ }
++
++ cmd[0] = sflash[pFlinfo->index].opcdPwrSave;
++
++ if ((ret = mvSpiWriteThenWrite(cmd, MV_SFLASH_DP_CMND_LENGTH, NULL, 0)) != MV_OK)
++ return ret;
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvSFlashPowerSaveExit - Cause the falsh device to exit the power save mode
++*
++* DESCRIPTION:
++* Exit the deep power save mode.
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Size of the flash in bytes.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSFlashPowerSaveExit (MV_SFLASH_INFO * pFlinfo)
++{
++ MV_STATUS ret;
++ MV_U8 cmd[MV_SFLASH_RES_CMND_LENGTH];
++
++
++ /* check for NULL pointer */
++ if (pFlinfo == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return 0;
++ }
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);)
++ return MV_BAD_PARAM;
++ }
++
++ /* check that power save mode is supported in the specific device */
++ if (sflash[pFlinfo->index].opcdRES == MV_SFLASH_NO_SPECIFIC_OPCD)
++ {
++ DB(mvOsPrintf("%s WARNING: Read Electronic Signature not supported for this device!\n", __FUNCTION__);)
++ return MV_NOT_SUPPORTED;
++ }
++
++ cmd[0] = sflash[pFlinfo->index].opcdRES;
++
++ if ((ret = mvSpiWriteThenWrite(cmd, MV_SFLASH_RES_CMND_LENGTH, NULL, 0)) != MV_OK)
++ return ret;
++
++ /* add the delay needed for the device to wake up */
++ mvOsDelay(MV_MXIC_DP_EXIT_DELAY); /* 30 ms */
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvSFlashModelGet - Retreive the string with the device manufacturer and model
++*
++* DESCRIPTION:
++* Retreive the string with the device manufacturer and model
++*
++* INPUT:
++* pFlinfo: pointer to the Flash information structure
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* pointer to the string indicating the device manufacturer and model
++*
++*
++*******************************************************************************/
++const MV_8 * mvSFlashModelGet (MV_SFLASH_INFO * pFlinfo)
++{
++ static const MV_8 * unknModel = (const MV_8 *)"Unknown";
++
++ /* check for NULL pointer */
++ if (pFlinfo == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return 0;
++ }
++
++ /* Protection - check if the model was detected */
++ if (pFlinfo->index >= MV_ARRAY_SIZE(sflash))
++ {
++ DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);)
++ return unknModel;
++ }
++
++ return sflash[pFlinfo->index].deviceModel;
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.h 2010-11-09 20:28:11.941246441 +0100
+@@ -0,0 +1,166 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvSFlashH
++#define __INCmvSFlashH
++
++#include "mvTypes.h"
++
++/* MCAROS */
++#define MV_SFLASH_PAGE_ALLIGN_MASK(pgSz) (pgSz-1)
++#define MV_ARRAY_SIZE(a) ((sizeof(a)) / (sizeof(a[0])))
++
++/* Constants */
++#define MV_INVALID_DEVICE_NUMBER 0xFFFFFFFF
++/* 10 MHz is the minimum possible SPI frequency when tclk is set 200MHz*/
++#define MV_SFLASH_BASIC_SPI_FREQ 10000000
++/* enumerations */
++typedef enum
++{
++ MV_WP_NONE, /* Unprotect the whole chip */
++ MV_WP_UPR_1OF128, /* Write protect the upper 1/128 part */
++ MV_WP_UPR_1OF64, /* Write protect the upper 1/64 part */
++ MV_WP_UPR_1OF32, /* Write protect the upper 1/32 part */
++ MV_WP_UPR_1OF16, /* Write protect the upper 1/16 part */
++ MV_WP_UPR_1OF8, /* Write protect the upper 1/8 part */
++ MV_WP_UPR_1OF4, /* Write protect the upper 1/4 part */
++ MV_WP_UPR_1OF2, /* Write protect the upper 1/2 part */
++ MV_WP_ALL /* Write protect the whole chip */
++} MV_SFLASH_WP_REGION;
++
++/* Type Definitions */
++typedef struct
++{
++ MV_U8 opcdWREN; /* Write enable opcode */
++ MV_U8 opcdWRDI; /* Write disable opcode */
++ MV_U8 opcdRDID; /* Read ID opcode */
++ MV_U8 opcdRDSR; /* Read Status Register opcode */
++ MV_U8 opcdWRSR; /* Write Status register opcode */
++ MV_U8 opcdREAD; /* Read opcode */
++ MV_U8 opcdFSTRD; /* Fast Read opcode */
++ MV_U8 opcdPP; /* Page program opcode */
++ MV_U8 opcdSE; /* Sector erase opcode */
++ MV_U8 opcdBE; /* Bulk erase opcode */
++ MV_U8 opcdRES; /* Read electronic signature */
++ MV_U8 opcdPwrSave; /* Go into power save mode */
++ MV_U32 sectorSize; /* Size of each sector */
++ MV_U32 sectorNumber; /* Number of sectors */
++ MV_U32 pageSize; /* size of each page */
++ const char * deviceModel; /* string with the device model */
++ MV_U32 manufacturerId; /* The manufacturer ID */
++ MV_U32 deviceId; /* Device ID */
++ MV_U32 spiMaxFreq; /* The MAX frequency that can be used with the device */
++ MV_U32 spiMaxFastFreq; /* The MAX frequency that can be used with the device for fast reads */
++ MV_U32 spiFastRdDummyBytes; /* Number of dumy bytes to read before real data when working in fast read mode. */
++} MV_SFLASH_DEVICE_PARAMS;
++
++typedef struct
++{
++ MV_U32 baseAddr; /* Flash Base Address used in fast mode */
++ MV_U8 manufacturerId; /* Manufacturer ID */
++ MV_U16 deviceId; /* Device ID */
++ MV_U32 sectorSize; /* Size of each sector - all the same */
++ MV_U32 sectorNumber; /* Number of sectors */
++ MV_U32 pageSize; /* Page size - affect allignment */
++ MV_U32 index; /* index of the device in the sflash table (internal parameter) */
++} MV_SFLASH_INFO;
++
++/* Function Prototypes */
++/* Init */
++MV_STATUS mvSFlashInit (MV_SFLASH_INFO * pFlinfo);
++
++/* erase */
++MV_STATUS mvSFlashSectorErase (MV_SFLASH_INFO * pFlinfo, MV_U32 secNumber);
++MV_STATUS mvSFlashChipErase (MV_SFLASH_INFO * pFlinfo);
++
++/* Read */
++MV_STATUS mvSFlashBlockRd (MV_SFLASH_INFO * pFlinfo, MV_U32 offset,
++ MV_U8* pReadBuff, MV_U32 buffSize);
++MV_STATUS mvSFlashFastBlockRd (MV_SFLASH_INFO * pFlinfo, MV_U32 offset,
++ MV_U8* pReadBuff, MV_U32 buffSize);
++
++/* write regardless of the page boundaries and size limit per Page program command */
++MV_STATUS mvSFlashBlockWr (MV_SFLASH_INFO * pFlinfo, MV_U32 offset,
++ MV_U8* pWriteBuff, MV_U32 buffSize);
++/* Get IDs */
++MV_STATUS mvSFlashIdGet (MV_SFLASH_INFO * pFlinfo, MV_U8* pManId, MV_U16* pDevId);
++
++/* Set and Get the Write Protection region - if the Status register is not locked */
++MV_STATUS mvSFlashWpRegionSet (MV_SFLASH_INFO * pFlinfo, MV_SFLASH_WP_REGION wpRegion);
++MV_STATUS mvSFlashWpRegionGet (MV_SFLASH_INFO * pFlinfo, MV_SFLASH_WP_REGION * pWpRegion);
++
++/* Lock the status register for writing - W/Vpp pin should be low to take effect */
++MV_STATUS mvSFlashStatRegLock (MV_SFLASH_INFO * pFlinfo, MV_BOOL srLock);
++
++/* Get the regions sizes */
++MV_U32 mvSFlashSizeGet (MV_SFLASH_INFO * pFlinfo);
++
++/* Cause the falsh device to go into power save mode */
++MV_STATUS mvSFlashPowerSaveEnter(MV_SFLASH_INFO * pFlinfo);
++MV_STATUS mvSFlashPowerSaveExit (MV_SFLASH_INFO * pFlinfo);
++
++/* Retreive the string with the device manufacturer and model */
++const MV_8 * mvSFlashModelGet (MV_SFLASH_INFO * pFlinfo);
++
++#endif /* __INCmvSFlashH */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlashSpec.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlashSpec.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlashSpec.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlashSpec.h 2010-11-09 20:28:11.981246772 +0100
+@@ -0,0 +1,233 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvSFlashSpecH
++#define __INCmvSFlashSpecH
++
++/* Constants */
++#define MV_SFLASH_READ_CMND_LENGTH 4 /* 1B opcode + 3B address */
++#define MV_SFLASH_SE_CMND_LENGTH 4 /* 1B opcode + 3B address */
++#define MV_SFLASH_BE_CMND_LENGTH 1 /* 1B opcode */
++#define MV_SFLASH_PP_CMND_LENGTH 4 /* 1B opcode + 3B address */
++#define MV_SFLASH_WREN_CMND_LENGTH 1 /* 1B opcode */
++#define MV_SFLASH_WRDI_CMND_LENGTH 1 /* 1B opcode */
++#define MV_SFLASH_RDID_CMND_LENGTH 1 /* 1B opcode */
++#define MV_SFLASH_RDID_REPLY_LENGTH 3 /* 1B manf ID and 2B device ID */
++#define MV_SFLASH_RDSR_CMND_LENGTH 1 /* 1B opcode */
++#define MV_SFLASH_RDSR_REPLY_LENGTH 1 /* 1B status */
++#define MV_SFLASH_WRSR_CMND_LENGTH 2 /* 1B opcode + 1B status value */
++#define MV_SFLASH_DP_CMND_LENGTH 1 /* 1B opcode */
++#define MV_SFLASH_RES_CMND_LENGTH 1 /* 1B opcode */
++
++/* Status Register Bit Masks */
++#define MV_SFLASH_STATUS_REG_WIP_OFFSET 0 /* bit 0; write in progress */
++#define MV_SFLASH_STATUS_REG_WP_OFFSET 2 /* bit 2-4; write protect option */
++#define MV_SFLASH_STATUS_REG_SRWD_OFFSET 7 /* bit 7; lock status register write */
++#define MV_SFLASH_STATUS_REG_WIP_MASK (0x1 << MV_SFLASH_STATUS_REG_WIP_OFFSET)
++#define MV_SFLASH_STATUS_REG_SRWD_MASK (0x1 << MV_SFLASH_STATUS_REG_SRWD_OFFSET)
++
++#define MV_SFLASH_MAX_WAIT_LOOP 1000000
++#define MV_SFLASH_CHIP_ERASE_MAX_WAIT_LOOP 0x50000000
++
++#define MV_SFLASH_DEFAULT_RDID_OPCD 0x9F /* Default Read ID */
++#define MV_SFLASH_DEFAULT_WREN_OPCD 0x06 /* Default Write Enable */
++#define MV_SFLASH_NO_SPECIFIC_OPCD 0x00
++
++/********************************/
++/* ST M25Pxxx Device Specific */
++/********************************/
++
++/* Manufacturer IDs and Device IDs for SFLASHs supported by the driver */
++#define MV_M25PXXX_ST_MANF_ID 0x20
++#define MV_M25P32_DEVICE_ID 0x2016
++#define MV_M25P32_MAX_SPI_FREQ 20000000 /* 20MHz */
++#define MV_M25P32_MAX_FAST_SPI_FREQ 50000000 /* 50MHz */
++#define MV_M25P32_FAST_READ_DUMMY_BYTES 1
++#define MV_M25P64_DEVICE_ID 0x2017
++#define MV_M25P64_MAX_SPI_FREQ 20000000 /* 20MHz */
++#define MV_M25P64_MAX_FAST_SPI_FREQ 50000000 /* 50MHz */
++#define MV_M25P64_FAST_READ_DUMMY_BYTES 1
++#define MV_M25P128_DEVICE_ID 0x2018
++#define MV_M25P128_MAX_SPI_FREQ 20000000 /* 20MHz */
++#define MV_M25P128_MAX_FAST_SPI_FREQ 50000000 /* 50MHz */
++#define MV_M25P128_FAST_READ_DUMMY_BYTES 1
++
++
++/* Sector Sizes and population per device model*/
++#define MV_M25P32_SECTOR_SIZE 0x10000 /* 64K */
++#define MV_M25P64_SECTOR_SIZE 0x10000 /* 64K */
++#define MV_M25P128_SECTOR_SIZE 0x40000 /* 256K */
++#define MV_M25P32_SECTOR_NUMBER 64
++#define MV_M25P64_SECTOR_NUMBER 128
++#define MV_M25P128_SECTOR_NUMBER 64
++#define MV_M25P_PAGE_SIZE 0x100 /* 256 byte */
++
++#define MV_M25P_WREN_CMND_OPCD 0x06 /* Write Enable */
++#define MV_M25P_WRDI_CMND_OPCD 0x04 /* Write Disable */
++#define MV_M25P_RDID_CMND_OPCD 0x9F /* Read ID */
++#define MV_M25P_RDSR_CMND_OPCD 0x05 /* Read Status Register */
++#define MV_M25P_WRSR_CMND_OPCD 0x01 /* Write Status Register */
++#define MV_M25P_READ_CMND_OPCD 0x03 /* Sequential Read */
++#define MV_M25P_FAST_RD_CMND_OPCD 0x0B /* Fast Read */
++#define MV_M25P_PP_CMND_OPCD 0x02 /* Page Program */
++#define MV_M25P_SE_CMND_OPCD 0xD8 /* Sector Erase */
++#define MV_M25P_BE_CMND_OPCD 0xC7 /* Bulk Erase */
++#define MV_M25P_RES_CMND_OPCD 0xAB /* Read Electronic Signature */
++
++/* Status Register Write Protect Bit Masks - 3bits */
++#define MV_M25P_STATUS_REG_WP_MASK (0x07 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_M25P_STATUS_BP_NONE (0x00 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_M25P_STATUS_BP_1_OF_64 (0x01 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_M25P_STATUS_BP_1_OF_32 (0x02 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_M25P_STATUS_BP_1_OF_16 (0x03 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_M25P_STATUS_BP_1_OF_8 (0x04 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_M25P_STATUS_BP_1_OF_4 (0x05 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_M25P_STATUS_BP_1_OF_2 (0x06 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_M25P_STATUS_BP_ALL (0x07 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++
++/************************************/
++/* MXIC MX25L6405 Device Specific */
++/************************************/
++
++/* Manufacturer IDs and Device IDs for SFLASHs supported by the driver */
++#define MV_MXIC_MANF_ID 0xC2
++#define MV_MX25L6405_DEVICE_ID 0x2017
++#define MV_MX25L6405_MAX_SPI_FREQ 20000000 /* 20MHz */
++#define MV_MX25L6405_MAX_FAST_SPI_FREQ 50000000 /* 50MHz */
++#define MV_MX25L6405_FAST_READ_DUMMY_BYTES 1
++#define MV_MXIC_DP_EXIT_DELAY 30 /* 30 ms */
++
++/* Sector Sizes and population per device model*/
++#define MV_MX25L6405_SECTOR_SIZE 0x10000 /* 64K */
++#define MV_MX25L6405_SECTOR_NUMBER 128
++#define MV_MXIC_PAGE_SIZE 0x100 /* 256 byte */
++
++#define MV_MX25L_WREN_CMND_OPCD 0x06 /* Write Enable */
++#define MV_MX25L_WRDI_CMND_OPCD 0x04 /* Write Disable */
++#define MV_MX25L_RDID_CMND_OPCD 0x9F /* Read ID */
++#define MV_MX25L_RDSR_CMND_OPCD 0x05 /* Read Status Register */
++#define MV_MX25L_WRSR_CMND_OPCD 0x01 /* Write Status Register */
++#define MV_MX25L_READ_CMND_OPCD 0x03 /* Sequential Read */
++#define MV_MX25L_FAST_RD_CMND_OPCD 0x0B /* Fast Read */
++#define MV_MX25L_PP_CMND_OPCD 0x02 /* Page Program */
++#define MV_MX25L_SE_CMND_OPCD 0xD8 /* Sector Erase */
++#define MV_MX25L_BE_CMND_OPCD 0xC7 /* Bulk Erase */
++#define MV_MX25L_DP_CMND_OPCD 0xB9 /* Deep Power Down */
++#define MV_MX25L_RES_CMND_OPCD 0xAB /* Read Electronic Signature */
++
++/* Status Register Write Protect Bit Masks - 4bits */
++#define MV_MX25L_STATUS_REG_WP_MASK (0x0F << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_MX25L_STATUS_BP_NONE (0x00 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_MX25L_STATUS_BP_1_OF_128 (0x01 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_MX25L_STATUS_BP_1_OF_64 (0x02 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_MX25L_STATUS_BP_1_OF_32 (0x03 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_MX25L_STATUS_BP_1_OF_16 (0x04 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_MX25L_STATUS_BP_1_OF_8 (0x05 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_MX25L_STATUS_BP_1_OF_4 (0x06 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_MX25L_STATUS_BP_1_OF_2 (0x07 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_MX25L_STATUS_BP_ALL (0x0F << MV_SFLASH_STATUS_REG_WP_OFFSET)
++
++/************************************/
++/* SPANSION S25FL128P Device Specific */
++/************************************/
++
++/* Manufacturer IDs and Device IDs for SFLASHs supported by the driver */
++#define MV_SPANSION_MANF_ID 0x01
++#define MV_S25FL128_DEVICE_ID 0x2018
++#define MV_S25FL128_MAX_SPI_FREQ 33000000 /* 33MHz */
++#define MV_S25FL128_MAX_FAST_SPI_FREQ 104000000 /* 104MHz */
++#define MV_S25FL128_FAST_READ_DUMMY_BYTES 1
++
++/* Sector Sizes and population per device model*/
++#define MV_S25FL128_SECTOR_SIZE 0x40000 /* 256K */
++#define MV_S25FL128_SECTOR_NUMBER 64
++#define MV_S25FL_PAGE_SIZE 0x100 /* 256 byte */
++
++#define MV_S25FL_WREN_CMND_OPCD 0x06 /* Write Enable */
++#define MV_S25FL_WRDI_CMND_OPCD 0x04 /* Write Disable */
++#define MV_S25FL_RDID_CMND_OPCD 0x9F /* Read ID */
++#define MV_S25FL_RDSR_CMND_OPCD 0x05 /* Read Status Register */
++#define MV_S25FL_WRSR_CMND_OPCD 0x01 /* Write Status Register */
++#define MV_S25FL_READ_CMND_OPCD 0x03 /* Sequential Read */
++#define MV_S25FL_FAST_RD_CMND_OPCD 0x0B /* Fast Read */
++#define MV_S25FL_PP_CMND_OPCD 0x02 /* Page Program */
++#define MV_S25FL_SE_CMND_OPCD 0xD8 /* Sector Erase */
++#define MV_S25FL_BE_CMND_OPCD 0xC7 /* Bulk Erase */
++#define MV_S25FL_DP_CMND_OPCD 0xB9 /* Deep Power Down */
++#define MV_S25FL_RES_CMND_OPCD 0xAB /* Read Electronic Signature */
++
++/* Status Register Write Protect Bit Masks - 4bits */
++#define MV_S25FL_STATUS_REG_WP_MASK (0x0F << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_S25FL_STATUS_BP_NONE (0x00 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_S25FL_STATUS_BP_1_OF_128 (0x01 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_S25FL_STATUS_BP_1_OF_64 (0x02 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_S25FL_STATUS_BP_1_OF_32 (0x03 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_S25FL_STATUS_BP_1_OF_16 (0x04 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_S25FL_STATUS_BP_1_OF_8 (0x05 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_S25FL_STATUS_BP_1_OF_4 (0x06 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_S25FL_STATUS_BP_1_OF_2 (0x07 << MV_SFLASH_STATUS_REG_WP_OFFSET)
++#define MV_S25FL_STATUS_BP_ALL (0x0F << MV_SFLASH_STATUS_REG_WP_OFFSET)
++
++#endif /* __INCmvSFlashSpecH */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.c 2010-11-09 20:28:12.022495595 +0100
+@@ -0,0 +1,576 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "spi/mvSpi.h"
++#include "spi/mvSpiSpec.h"
++
++#include "ctrlEnv/mvCtrlEnvLib.h"
++
++/* #define MV_DEBUG */
++#ifdef MV_DEBUG
++#define DB(x) x
++#define mvOsPrintf printf
++#else
++#define DB(x)
++#endif
++
++
++/*******************************************************************************
++* mvSpi16bitDataTxRx - Transmt and receive data
++*
++* DESCRIPTION:
++* Tx data and block waiting for data to be transmitted
++*
++********************************************************************************/
++static MV_STATUS mvSpi16bitDataTxRx (MV_U16 txData, MV_U16 * pRxData)
++{
++ MV_U32 i;
++ MV_BOOL ready = MV_FALSE;
++
++ /* First clear the bit in the interrupt cause register */
++ MV_REG_WRITE(MV_SPI_INT_CAUSE_REG, 0x0);
++
++ /* Transmit data */
++ MV_REG_WRITE(MV_SPI_DATA_OUT_REG, MV_16BIT_LE(txData));
++
++ /* wait with timeout for memory ready */
++ for (i=0; i<MV_SPI_WAIT_RDY_MAX_LOOP; i++)
++ {
++ if (MV_REG_READ(MV_SPI_INT_CAUSE_REG))
++ {
++ ready = MV_TRUE;
++ break;
++ }
++#ifdef MV_SPI_SLEEP_ON_WAIT
++ mvOsSleep(1);
++#endif /* MV_SPI_SLEEP_ON_WAIT */
++ }
++
++ if (!ready)
++ return MV_TIMEOUT;
++
++ /* check that the RX data is needed */
++ if (pRxData)
++ {
++ if ((MV_U32)pRxData & 0x1) /* check if address is not alligned to 16bit */
++ {
++#if defined(MV_CPU_LE)
++ /* perform the data write to the buffer in two stages with 8bit each */
++ MV_U8 * bptr = (MV_U8*)pRxData;
++ MV_U16 data = MV_16BIT_LE(MV_REG_READ(MV_SPI_DATA_IN_REG));
++ *bptr = (data & 0xFF);
++ ++bptr;
++ *bptr = ((data >> 8) & 0xFF);
++
++#elif defined(MV_CPU_BE)
++
++ /* perform the data write to the buffer in two stages with 8bit each */
++ MV_U8 * bptr = (MV_U8 *)pRxData;
++ MV_U16 data = MV_16BIT_LE(MV_REG_READ(MV_SPI_DATA_IN_REG));
++ *bptr = ((data >> 8) & 0xFF);
++ ++bptr;
++ *bptr = (data & 0xFF);
++
++#else
++ #error "CPU endianess isn't defined!\n"
++#endif
++
++ }
++ else
++ *pRxData = MV_16BIT_LE(MV_REG_READ(MV_SPI_DATA_IN_REG));
++ }
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvSpi8bitDataTxRx - Transmt and receive data (8bits)
++*
++* DESCRIPTION:
++* Tx data and block waiting for data to be transmitted
++*
++********************************************************************************/
++static MV_STATUS mvSpi8bitDataTxRx (MV_U8 txData, MV_U8 * pRxData)
++{
++ MV_U32 i;
++ MV_BOOL ready = MV_FALSE;
++
++ /* First clear the bit in the interrupt cause register */
++ MV_REG_WRITE(MV_SPI_INT_CAUSE_REG, 0x0);
++
++ /* Transmit data */
++ MV_REG_WRITE(MV_SPI_DATA_OUT_REG, txData);
++
++ /* wait with timeout for memory ready */
++ for (i=0; i<MV_SPI_WAIT_RDY_MAX_LOOP; i++)
++ {
++ if (MV_REG_READ(MV_SPI_INT_CAUSE_REG))
++ {
++ ready = MV_TRUE;
++ break;
++ }
++#ifdef MV_SPI_SLEEP_ON_WAIT
++ mvOsSleep(1);
++#endif /* MV_SPI_SLEEP_ON_WAIT */
++ }
++
++ if (!ready)
++ return MV_TIMEOUT;
++
++ /* check that the RX data is needed */
++ if (pRxData)
++ *pRxData = MV_REG_READ(MV_SPI_DATA_IN_REG);
++
++ return MV_OK;
++}
++
++/*
++#####################################################################################
++#####################################################################################
++*/
++
++/*******************************************************************************
++* mvSpiInit - Initialize the SPI controller
++*
++* DESCRIPTION:
++* Perform the neccessary initialization in order to be able to send an
++* receive over the SPI interface.
++*
++* INPUT:
++* serialBaudRate: Baud rate (SPI clock frequency)
++* use16BitMode: Whether to use 2bytes (MV_TRUE) or 1bytes (MV_FALSE)
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSpiInit (MV_U32 serialBaudRate)
++{
++ MV_STATUS ret;
++
++ /* Set the serial clock */
++ if ((ret = mvSpiBaudRateSet(serialBaudRate)) != MV_OK)
++ return ret;
++
++ /* For devices in which the SPI is muxed on the MPP with other interfaces*/
++ mvMPPConfigToSPI();
++
++ /* Configure the default SPI mode to be 16bit */
++ MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
++
++ /* Fix ac timing on SPI in 6183, 6183L and 78x00 only */
++ if ( (mvCtrlModelGet() == MV_6183_DEV_ID) ||
++ (mvCtrlModelGet() == MV_6183L_DEV_ID) ||
++ (mvCtrlModelGet() == MV_78100_DEV_ID) ||
++ (mvCtrlModelGet() == MV_78200_DEV_ID) ||
++ (mvCtrlModelGet() == MV_76100_DEV_ID))
++ MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, BIT14);
++
++ /* Verify that the CS is deasserted */
++ mvSpiCsDeassert();
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSpiBaudRateSet - Set the Frequency of the SPI clock
++*
++* DESCRIPTION:
++* Set the Prescale bits to adapt to the requested baud rate (the clock
++* used for thr SPI).
++*
++* INPUT:
++* serialBaudRate: Baud rate (SPI clock frequency)
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSpiBaudRateSet (MV_U32 serialBaudRate)
++{
++ MV_U8 i;
++ /* MV_U8 preScale[32] = {1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
++ 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30};
++ */
++ MV_U8 preScale[14] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30};
++ MV_U8 bestPrescaleIndx = 100;
++ MV_U32 minBaudOffset = 0xFFFFFFFF;
++ MV_U32 cpuClk = mvBoardTclkGet(); /*mvCpuPclkGet();*/
++ MV_U32 tempReg;
++
++ /* Find the best prescale configuration - less or equal */
++ for (i=0; i<14; i++)
++ {
++ /* check for higher - irrelevent */
++ if ((cpuClk / preScale[i]) > serialBaudRate)
++ continue;
++
++ /* check for exact fit */
++ if ((cpuClk / preScale[i]) == serialBaudRate)
++ {
++ bestPrescaleIndx = i;
++ break;
++ }
++
++ /* check if this is better than the previous one */
++ if ((serialBaudRate - (cpuClk / preScale[i])) < minBaudOffset)
++ {
++ minBaudOffset = (serialBaudRate - (cpuClk / preScale[i]));
++ bestPrescaleIndx = i;
++ }
++ }
++
++ if (bestPrescaleIndx > 14)
++ {
++ mvOsPrintf("%s ERROR: SPI baud rate prescale error!\n", __FUNCTION__);
++ return MV_OUT_OF_RANGE;
++ }
++
++ /* configure the Prescale */
++ tempReg = MV_REG_READ(MV_SPI_IF_CONFIG_REG);
++ tempReg = ((tempReg & ~MV_SPI_CLK_PRESCALE_MASK) | (bestPrescaleIndx + 0x12));
++ MV_REG_WRITE(MV_SPI_IF_CONFIG_REG, tempReg);
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSpiCsAssert - Assert the Chip Select pin indicating a new transfer
++*
++* DESCRIPTION:
++* Assert The chip select - used to select an external SPI device
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Success or Error code.
++*
++********************************************************************************/
++MV_VOID mvSpiCsAssert(MV_VOID)
++{
++ /* For devices in which the SPI is muxed on the MPP with other interfaces*/
++ mvMPPConfigToSPI();
++ mvOsUDelay(1);
++ MV_REG_BIT_SET(MV_SPI_IF_CTRL_REG, MV_SPI_CS_ENABLE_MASK);
++}
++
++/*******************************************************************************
++* mvSpiCsDeassert - DeAssert the Chip Select pin indicating the end of a
++* SPI transfer sequence
++*
++* DESCRIPTION:
++* DeAssert the chip select pin
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Success or Error code.
++*
++********************************************************************************/
++MV_VOID mvSpiCsDeassert(MV_VOID)
++{
++ MV_REG_BIT_RESET(MV_SPI_IF_CTRL_REG, MV_SPI_CS_ENABLE_MASK);
++
++ /* For devices in which the SPI is muxed on the MPP with other interfaces*/
++ mvMPPConfigToDefault();
++}
++
++/*******************************************************************************
++* mvSpiRead - Read a buffer over the SPI interface
++*
++* DESCRIPTION:
++* Receive (read) a buffer over the SPI interface in 16bit chunks. If the
++* buffer size is odd, then the last chunk will be 8bits. Chip select is not
++* handled at this level.
++*
++* INPUT:
++* pRxBuff: Pointer to the buffer to hold the received data
++* buffSize: length of the pRxBuff
++*
++* OUTPUT:
++* pRxBuff: Pointer to the buffer with the received data
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSpiRead (MV_U8* pRxBuff, MV_U32 buffSize)
++{
++ MV_STATUS ret;
++ MV_U32 bytesLeft = buffSize;
++ MV_U16* rxPtr = (MV_U16*)pRxBuff;
++
++ /* check for null parameters */
++ if (pRxBuff == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check that the buffer pointer and the buffer size are 16bit aligned */
++ if ((((MV_U32)buffSize & 1) == 0) && (((MV_U32)pRxBuff & 1) == 0))
++ {
++ /* Verify that the SPI mode is in 16bit mode */
++ MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
++
++ /* TX/RX as long we have complete 16bit chunks */
++ while (bytesLeft >= MV_SPI_16_BIT_CHUNK_SIZE)
++ {
++ /* Transmitted and wait for the transfer to be completed */
++ if ((ret = mvSpi16bitDataTxRx(MV_SPI_DUMMY_WRITE_16BITS, rxPtr)) != MV_OK)
++ return ret;
++
++ /* increment the pointers */
++ rxPtr++;
++ bytesLeft -= MV_SPI_16_BIT_CHUNK_SIZE;
++ }
++
++ }
++ else
++ {
++ /* Verify that the SPI mode is in 8bit mode */
++ MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
++
++ /* TX/RX in 8bit chanks */
++ while (bytesLeft > 0)
++ {
++ /* Transmitted and wait for the transfer to be completed */
++ if ((ret = mvSpi8bitDataTxRx(MV_SPI_DUMMY_WRITE_8BITS, pRxBuff)) != MV_OK)
++ return ret;
++ /* increment the pointers */
++ pRxBuff++;
++ bytesLeft--;
++ }
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvSpiWrite - Transmit a buffer over the SPI interface
++*
++* DESCRIPTION:
++* Transmit a buffer over the SPI interface in 16bit chunks. If the
++* buffer size is odd, then the last chunk will be 8bits. No chip select
++* action is taken.
++*
++* INPUT:
++* pTxBuff: Pointer to the buffer holding the TX data
++* buffSize: length of the pTxBuff
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSpiWrite(MV_U8* pTxBuff, MV_U32 buffSize)
++{
++ MV_STATUS ret;
++ MV_U32 bytesLeft = buffSize;
++ MV_U16* txPtr = (MV_U16*)pTxBuff;
++
++ /* check for null parameters */
++ if (pTxBuff == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check that the buffer pointer and the buffer size are 16bit aligned */
++ if ((((MV_U32)buffSize & 1) == 0) && (((MV_U32)pTxBuff & 1) == 0))
++ {
++ /* Verify that the SPI mode is in 16bit mode */
++ MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
++
++ /* TX/RX as long we have complete 16bit chunks */
++ while (bytesLeft >= MV_SPI_16_BIT_CHUNK_SIZE)
++ {
++ /* Transmitted and wait for the transfer to be completed */
++ if ((ret = mvSpi16bitDataTxRx(*txPtr, NULL)) != MV_OK)
++ return ret;
++
++ /* increment the pointers */
++ txPtr++;
++ bytesLeft -= MV_SPI_16_BIT_CHUNK_SIZE;
++ }
++ }
++ else
++ {
++
++ /* Verify that the SPI mode is in 8bit mode */
++ MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
++
++ /* TX/RX in 8bit chanks */
++ while (bytesLeft > 0)
++ {
++ /* Transmitted and wait for the transfer to be completed */
++ if ((ret = mvSpi8bitDataTxRx(*pTxBuff, NULL)) != MV_OK)
++ return ret;
++
++ /* increment the pointers */
++ pTxBuff++;
++ bytesLeft--;
++ }
++ }
++
++ return MV_OK;
++}
++
++
++/*******************************************************************************
++* mvSpiReadWrite - Read and Write a buffer simultanuosely
++*
++* DESCRIPTION:
++* Transmit and receive a buffer over the SPI in 16bit chunks. If the
++* buffer size is odd, then the last chunk will be 8bits. The SPI chip
++* select is not handled implicitely.
++*
++* INPUT:
++* pRxBuff: Pointer to the buffer to write the RX info in
++* pTxBuff: Pointer to the buffer holding the TX info
++* buffSize: length of both the pTxBuff and pRxBuff
++*
++* OUTPUT:
++* pRxBuff: Pointer of the buffer holding the RX data
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSpiReadWrite(MV_U8* pRxBuff, MV_U8* pTxBuff, MV_U32 buffSize)
++{
++ MV_STATUS ret;
++ MV_U32 bytesLeft = buffSize;
++ MV_U16* txPtr = (MV_U16*)pTxBuff;
++ MV_U16* rxPtr = (MV_U16*)pRxBuff;
++
++ /* check for null parameters */
++ if ((pRxBuff == NULL) || (pTxBuff == NULL))
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* Check that the buffer pointer and the buffer size are 16bit aligned */
++ if ((((MV_U32)buffSize & 1) == 0) && (((MV_U32)pTxBuff & 1) == 0) && (((MV_U32)pRxBuff & 1) == 0))
++ {
++ /* Verify that the SPI mode is in 16bit mode */
++ MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
++
++ /* TX/RX as long we have complete 16bit chunks */
++ while (bytesLeft >= MV_SPI_16_BIT_CHUNK_SIZE)
++ {
++ /* Transmitted and wait for the transfer to be completed */
++ if ((ret = mvSpi16bitDataTxRx(*txPtr, rxPtr)) != MV_OK)
++ return ret;
++
++ /* increment the pointers */
++ txPtr++;
++ rxPtr++;
++ bytesLeft -= MV_SPI_16_BIT_CHUNK_SIZE;
++ }
++ }
++ else
++ {
++ /* Verify that the SPI mode is in 8bit mode */
++ MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK);
++
++ /* TX/RX in 8bit chanks */
++ while (bytesLeft > 0)
++ {
++ /* Transmitted and wait for the transfer to be completed */
++ if ( (ret = mvSpi8bitDataTxRx(*pTxBuff, pRxBuff) ) != MV_OK)
++ return ret;
++ pRxBuff++;
++ pTxBuff++;
++ bytesLeft--;
++ }
++ }
++
++ return MV_OK;
++}
++
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.c 2010-11-09 20:28:12.052495353 +0100
+@@ -0,0 +1,249 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "spi/mvSpi.h"
++#include "spi/mvSpiSpec.h"
++
++/*#define MV_DEBUG*/
++#ifdef MV_DEBUG
++#define DB(x) x
++#else
++#define DB(x)
++#endif
++
++
++/*******************************************************************************
++* mvSpiReadAndWrite - Read and Write a buffer simultanuousely
++*
++* DESCRIPTION:
++* Transmit and receive a buffer over the SPI in 16bit chunks. If the
++* buffer size is odd, then the last chunk will be 8bits.
++*
++* INPUT:
++* pRxBuff: Pointer to the buffer to write the RX info in
++* pTxBuff: Pointer to the buffer holding the TX info
++* buffSize: length of both the pTxBuff and pRxBuff
++*
++* OUTPUT:
++* pRxBuff: Pointer of the buffer holding the RX data
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSpiReadAndWrite(MV_U8* pRxBuff, MV_U8* pTxBuff, MV_U32 buffSize)
++{
++ MV_STATUS ret;
++
++ /* check for null parameters */
++ if ((pRxBuff == NULL) || (pTxBuff == NULL) || (buffSize == 0))
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* First assert the chip select */
++ mvSpiCsAssert();
++
++ ret = mvSpiReadWrite(pRxBuff, pTxBuff, buffSize);
++
++ /* Finally deassert the chip select */
++ mvSpiCsDeassert();
++
++ return ret;
++}
++
++/*******************************************************************************
++* mvSpiWriteThenWrite - Serialize a command followed by the data over the TX line
++*
++* DESCRIPTION:
++* Assert the chip select line. Transmit the command buffer followed by
++* the data buffer. Then deassert the CS line.
++*
++* INPUT:
++* pCmndBuff: Pointer to the command buffer to transmit
++* cmndSize: length of the command size
++* pTxDataBuff: Pointer to the data buffer to transmit
++* txDataSize: length of the data buffer
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSpiWriteThenWrite (MV_U8* pCmndBuff, MV_U32 cmndSize, MV_U8* pTxDataBuff,
++ MV_U32 txDataSize)
++{
++ MV_STATUS ret = MV_OK, tempRet;
++
++ /* check for null parameters */
++#ifndef CONFIG_MARVELL
++ if(NULL == pTxDataBuff)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++#endif
++
++ if (pCmndBuff == NULL)
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* First assert the chip select */
++ mvSpiCsAssert();
++
++ /* first write the command */
++ if ((cmndSize) && (pCmndBuff != NULL))
++ {
++ if ((tempRet = mvSpiWrite(pCmndBuff, cmndSize)) != MV_OK)
++ ret = tempRet;
++ }
++
++ /* Then write the data buffer */
++#ifndef CONFIG_MARVELL
++ if (txDataSize)
++#else
++ if ((txDataSize) && (pTxDataBuff != NULL))
++#endif
++ {
++ if ((tempRet = mvSpiWrite(pTxDataBuff, txDataSize)) != MV_OK)
++ ret = tempRet;
++ }
++
++ /* Finally deassert the chip select */
++ mvSpiCsDeassert();
++
++ return ret;
++}
++
++/*******************************************************************************
++* mvSpiWriteThenRead - Serialize a command then read a data buffer
++*
++* DESCRIPTION:
++* Assert the chip select line. Transmit the command buffer then read
++* the data buffer. Then deassert the CS line.
++*
++* INPUT:
++* pCmndBuff: Pointer to the command buffer to transmit
++* cmndSize: length of the command size
++* pRxDataBuff: Pointer to the buffer to read the data in
++* txDataSize: length of the data buffer
++*
++* OUTPUT:
++* pRxDataBuff: Pointer to the buffer holding the data
++*
++* RETURN:
++* Success or Error code.
++*
++*
++*******************************************************************************/
++MV_STATUS mvSpiWriteThenRead (MV_U8* pCmndBuff, MV_U32 cmndSize, MV_U8* pRxDataBuff,
++ MV_U32 rxDataSize,MV_U32 dummyBytesToRead)
++{
++ MV_STATUS ret = MV_OK, tempRet;
++ MV_U8 dummyByte;
++
++ /* check for null parameters */
++ if ((pCmndBuff == NULL) && (pRxDataBuff == NULL))
++ {
++ mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__);
++ return MV_BAD_PARAM;
++ }
++
++ /* First assert the chip select */
++ mvSpiCsAssert();
++
++ /* first write the command */
++ if ((cmndSize) && (pCmndBuff != NULL))
++ {
++ if ((tempRet = mvSpiWrite(pCmndBuff, cmndSize)) != MV_OK)
++ ret = tempRet;
++ }
++
++ /* Read dummy bytes before real data. */
++ while(dummyBytesToRead)
++ {
++ mvSpiRead(&dummyByte,1);
++ dummyBytesToRead--;
++ }
++
++ /* Then write the data buffer */
++ if ((rxDataSize) && (pRxDataBuff != NULL))
++ {
++ if ((tempRet = mvSpiRead(pRxDataBuff, rxDataSize)) != MV_OK)
++ ret = tempRet;
++ }
++
++ /* Finally deassert the chip select */
++ mvSpiCsDeassert();
++
++ return ret;
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.h 2010-11-09 20:28:12.082495364 +0100
+@@ -0,0 +1,82 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvSpiCmndhH
++#define __INCmvSpiCmndhH
++
++#include "mvTypes.h"
++
++/* Function Prototypes */
++
++/* Simultanuous Read and write */
++MV_STATUS mvSpiReadAndWrite (MV_U8* pRxBuff, MV_U8* pTxBuff, MV_U32 buffSize);
++
++/* write command - write a command and then write data */
++MV_STATUS mvSpiWriteThenWrite (MV_U8* pCmndBuff, MV_U32 cmndSize, MV_U8* pTxDataBuff, MV_U32 txDataSize);
++
++/* read command - write a command and then read data by writing dummy data */
++MV_STATUS mvSpiWriteThenRead (MV_U8* pCmndBuff, MV_U32 cmndSize, MV_U8* pRxDataBuff,
++ MV_U32 rxDataSize,MV_U32 dummyBytesToRead);
++
++#endif /* __INCmvSpiCmndhH */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.h 2010-11-09 20:28:12.121243940 +0100
+@@ -0,0 +1,94 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvSpihH
++#define __INCmvSpihH
++
++#include "mvCommon.h"
++#include "mvOs.h"
++#include "ctrlEnv/mvCtrlEnvSpec.h"
++
++/* Function Prototypes */
++/* Init */
++MV_STATUS mvSpiInit (MV_U32 serialBaudRate);
++
++/* Set the Frequency of the Spi clock */
++MV_STATUS mvSpiBaudRateSet(MV_U32 serialBaudRate);
++
++/* Assert the SPI chip select */
++MV_VOID mvSpiCsAssert (MV_VOID);
++
++/* De-assert the SPI chip select */
++MV_VOID mvSpiCsDeassert (MV_VOID);
++
++/* Simultanuous Read and write */
++MV_STATUS mvSpiReadWrite (MV_U8* pRxBuff, MV_U8* pTxBuff, MV_U32 buffSize);
++
++/* serialize a buffer on the TX line - Rx is ignored */
++MV_STATUS mvSpiWrite (MV_U8* pTxBuff, MV_U32 buffSize);
++
++/* read from the RX line by writing dummy values to the TX line */
++MV_STATUS mvSpiRead (MV_U8* pRxBuff, MV_U32 buffSize);
++
++#endif /* __INCmvSpihH */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiSpec.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiSpec.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiSpec.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiSpec.h 2010-11-09 20:28:12.162495430 +0100
+@@ -0,0 +1,98 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvSpiSpecH
++#define __INCmvSpiSpecH
++
++/* Constants */
++#define MV_SPI_WAIT_RDY_MAX_LOOP 100000
++#define MV_SPI_16_BIT_CHUNK_SIZE 2
++#define MV_SPI_DUMMY_WRITE_16BITS 0xFFFF
++#define MV_SPI_DUMMY_WRITE_8BITS 0xFF
++
++/* Marvell Flash Device Controller Registers */
++#define MV_SPI_CTRLR_OFST 0x10600
++#define MV_SPI_IF_CTRL_REG (MV_SPI_CTRLR_OFST + 0x00)
++#define MV_SPI_IF_CONFIG_REG (MV_SPI_CTRLR_OFST + 0x04)
++#define MV_SPI_DATA_OUT_REG (MV_SPI_CTRLR_OFST + 0x08)
++#define MV_SPI_DATA_IN_REG (MV_SPI_CTRLR_OFST + 0x0c)
++#define MV_SPI_INT_CAUSE_REG (MV_SPI_CTRLR_OFST + 0x10)
++#define MV_SPI_INT_CAUSE_MASK_REG (MV_SPI_CTRLR_OFST + 0x14)
++
++/* Serial Memory Interface Control Register Masks */
++#define MV_SPI_CS_ENABLE_OFFSET 0 /* bit 0 */
++#define MV_SPI_MEMORY_READY_OFFSET 1 /* bit 1 */
++#define MV_SPI_CS_ENABLE_MASK (0x1 << MV_SPI_CS_ENABLE_OFFSET)
++#define MV_SPI_MEMORY_READY_MASK (0x1 << MV_SPI_MEMORY_READY_OFFSET)
++
++/* Serial Memory Interface Configuration Register Masks */
++#define MV_SPI_CLK_PRESCALE_OFFSET 0 /* bit 0-4 */
++#define MV_SPI_BYTE_LENGTH_OFFSET 5 /* bit 5 */
++#define MV_SPI_ADDRESS_BURST_LENGTH_OFFSET 8 /* bit 8-9 */
++#define MV_SPI_CLK_PRESCALE_MASK (0x1F << MV_SPI_CLK_PRESCALE_OFFSET)
++#define MV_SPI_BYTE_LENGTH_MASK (0x1 << MV_SPI_BYTE_LENGTH_OFFSET)
++#define MV_SPI_ADDRESS_BURST_LENGTH_MASK (0x3 << MV_SPI_ADDRESS_BURST_LENGTH_OFFSET)
++
++#endif /* __INCmvSpiSpecH */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.c linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.c
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.c 2010-11-09 20:28:12.192495512 +0100
+@@ -0,0 +1,1023 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "mvTwsi.h"
++#include "mvTwsiSpec.h"
++#include "cpu/mvCpu.h"
++
++
++/*#define MV_DEBUG*/
++#ifdef MV_DEBUG
++#define DB(x) x
++#else
++#define DB(x)
++#endif
++
++static MV_VOID twsiIntFlgClr(MV_U8 chanNum);
++static MV_BOOL twsiMainIntGet(MV_U8 chanNum);
++static MV_VOID twsiAckBitSet(MV_U8 chanNum);
++static MV_U32 twsiStsGet(MV_U8 chanNum);
++static MV_VOID twsiReset(MV_U8 chanNum);
++static MV_STATUS twsiAddr7BitSet(MV_U8 chanNum, MV_U32 deviceAddress,MV_TWSI_CMD command);
++static MV_STATUS twsiAddr10BitSet(MV_U8 chanNum, MV_U32 deviceAddress,MV_TWSI_CMD command);
++static MV_STATUS twsiDataTransmit(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize);
++static MV_STATUS twsiDataReceive(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize);
++static MV_STATUS twsiTargetOffsSet(MV_U8 chanNum, MV_U32 offset,MV_BOOL moreThen256);
++
++
++static MV_BOOL twsiTimeoutChk(MV_U32 timeout, const MV_8 *pString)
++{
++ if(timeout >= TWSI_TIMEOUT_VALUE)
++ {
++ DB(mvOsPrintf("%s",pString));
++ return MV_TRUE;
++ }
++ return MV_FALSE;
++
++}
++/*******************************************************************************
++* mvTwsiStartBitSet - Set start bit on the bus
++*
++* DESCRIPTION:
++* This routine sets the start bit on the TWSI bus.
++* The routine first checks for interrupt flag condition, then it sets
++* the start bit in the TWSI Control register.
++* If the interrupt flag condition check previously was set, the function
++* will clear it.
++* The function then wait for the start bit to be cleared by the HW.
++* Then it waits for the interrupt flag to be set and eventually, the
++* TWSI status is checked to be 0x8 or 0x10(repeated start bit).
++*
++* INPUT:
++* chanNum - TWSI channel.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_OK is start bit was set successfuly on the bus.
++* MV_FAIL if interrupt flag was set before setting start bit.
++*
++*******************************************************************************/
++MV_STATUS mvTwsiStartBitSet(MV_U8 chanNum)
++{
++ MV_BOOL isIntFlag = MV_FALSE;
++ MV_U32 timeout, temp;
++
++ DB(mvOsPrintf("TWSI: mvTwsiStartBitSet \n"));
++ /* check Int flag */
++ if(twsiMainIntGet(chanNum))
++ isIntFlag = MV_TRUE;
++ /* set start Bit */
++ temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum));
++ MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp | TWSI_CONTROL_START_BIT);
++
++ /* in case that the int flag was set before i.e. repeated start bit */
++ if(isIntFlag){
++ DB(mvOsPrintf("TWSI: mvTwsiStartBitSet repeated start Bit\n"));
++ twsiIntFlgClr(chanNum);
++ }
++
++ /* wait for interrupt */
++ timeout = 0;
++ while(!twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE));
++
++ /* check for timeout */
++ if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: mvTwsiStartBitSet ERROR - Start Clear bit TimeOut .\n"))
++ return MV_TIMEOUT;
++
++
++ /* check that start bit went down */
++ if((MV_REG_READ(TWSI_CONTROL_REG(chanNum)) & TWSI_CONTROL_START_BIT) != 0)
++ {
++ mvOsPrintf("TWSI: mvTwsiStartBitSet ERROR - start bit didn't went down\n");
++ return MV_FAIL;
++ }
++
++ /* check the status */
++ temp = twsiStsGet(chanNum);
++ if(( temp != TWSI_START_CON_TRA ) && ( temp != TWSI_REPEATED_START_CON_TRA ))
++ {
++ mvOsPrintf("TWSI: mvTwsiStartBitSet ERROR - status %x after Set Start Bit. \n",temp);
++ return MV_FAIL;
++ }
++
++ return MV_OK;
++
++}
++
++/*******************************************************************************
++* mvTwsiStopBitSet - Set stop bit on the bus
++*
++* DESCRIPTION:
++* This routine set the stop bit on the TWSI bus.
++* The function then wait for the stop bit to be cleared by the HW.
++* Finally the function checks for status of 0xF8.
++*
++* INPUT:
++* chanNum - TWSI channel
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE is stop bit was set successfuly on the bus.
++*
++*******************************************************************************/
++MV_STATUS mvTwsiStopBitSet(MV_U8 chanNum)
++{
++ MV_U32 timeout, temp;
++
++ /* Generate stop bit */
++ temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum));
++ MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp | TWSI_CONTROL_STOP_BIT);
++
++ twsiIntFlgClr(chanNum);
++
++ /* wait for stop bit to come down */
++ timeout = 0;
++ while( ((MV_REG_READ(TWSI_CONTROL_REG(chanNum)) & TWSI_CONTROL_STOP_BIT) != 0) && (timeout++ < TWSI_TIMEOUT_VALUE));
++
++ /* check for timeout */
++ if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: mvTwsiStopBitSet ERROR - Stop bit TimeOut .\n"))
++ return MV_TIMEOUT;
++
++ /* check that the stop bit went down */
++ if((MV_REG_READ(TWSI_CONTROL_REG(chanNum)) & TWSI_CONTROL_STOP_BIT) != 0)
++ {
++ mvOsPrintf("TWSI: mvTwsiStopBitSet ERROR - stop bit didn't went down. \n");
++ return MV_FAIL;
++ }
++
++ /* check the status */
++ temp = twsiStsGet(chanNum);
++ if( temp != TWSI_NO_REL_STS_INT_FLAG_IS_KEPT_0){
++ mvOsPrintf("TWSI: mvTwsiStopBitSet ERROR - status %x after Stop Bit. \n", temp);
++ return MV_FAIL;
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* twsiMainIntGet - Get twsi bit from main Interrupt cause.
++*
++* DESCRIPTION:
++* This routine returns the twsi interrupt flag value.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_TRUE is interrupt flag is set, MV_FALSE otherwise.
++*
++*******************************************************************************/
++static MV_BOOL twsiMainIntGet(MV_U8 chanNum)
++{
++ MV_U32 temp;
++
++ /* get the int flag bit */
++
++ temp = MV_REG_READ(TWSI_CPU_MAIN_INT_CAUSE_REG);
++ if (temp & (TWSI0_CPU_MAIN_INT_BIT << chanNum))
++ return MV_TRUE;
++
++ return MV_FALSE;
++}
++/*******************************************************************************
++* twsiIntFlgClr - Clear Interrupt flag.
++*
++* DESCRIPTION:
++* This routine clears the interrupt flag. It does NOT poll the interrupt
++* to make sure the clear. After clearing the interrupt, it waits for at
++* least 1 miliseconds.
++*
++* INPUT:
++* chanNum - TWSI channel
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++static MV_VOID twsiIntFlgClr(MV_U8 chanNum)
++{
++ MV_U32 temp;
++
++ /* wait for 1 mili to prevent TWSI register write after write problems */
++ mvOsDelay(1);
++ /* clear the int flag bit */
++ temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum));
++ MV_REG_WRITE(TWSI_CONTROL_REG(chanNum),temp & ~(TWSI_CONTROL_INT_FLAG_SET));
++
++ /* wait for 1 mili sec for the clear to take effect */
++ mvOsDelay(1);
++
++ return;
++}
++
++
++/*******************************************************************************
++* twsiAckBitSet - Set acknowledge bit on the bus
++*
++* DESCRIPTION:
++* This routine set the acknowledge bit on the TWSI bus.
++*
++* INPUT:
++* None.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None.
++*
++*******************************************************************************/
++static MV_VOID twsiAckBitSet(MV_U8 chanNum)
++{
++ MV_U32 temp;
++
++ /*Set the Ack bit */
++ temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum));
++ MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp | TWSI_CONTROL_ACK);
++
++ /* Add delay of 1ms */
++ mvOsDelay(1);
++ return;
++}
++
++
++/*******************************************************************************
++* twsiInit - Initialize TWSI interface
++*
++* DESCRIPTION:
++* This routine:
++* -Reset the TWSI.
++* -Initialize the TWSI clock baud rate according to given frequancy
++* parameter based on Tclk frequancy and enables TWSI slave.
++* -Set the ack bit.
++* -Assign the TWSI slave address according to the TWSI address Type.
++*
++*
++* INPUT:
++* chanNum - TWSI channel
++* frequancy - TWSI frequancy in KHz. (up to 100KHZ)
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* Actual frequancy.
++*
++*******************************************************************************/
++MV_U32 mvTwsiInit(MV_U8 chanNum, MV_HZ frequancy, MV_U32 Tclk, MV_TWSI_ADDR *pTwsiAddr, MV_BOOL generalCallEnable)
++{
++ MV_U32 n,m,freq,margin,minMargin = 0xffffffff;
++ MV_U32 power;
++ MV_U32 actualFreq = 0,actualN = 0,actualM = 0,val;
++
++ if(frequancy > 100000)
++ {
++ mvOsPrintf("Warning TWSI frequancy is too high, please use up tp 100Khz. \n");
++ }
++
++ DB(mvOsPrintf("TWSI: mvTwsiInit - Tclk = %d freq = %d\n",Tclk,frequancy));
++ /* Calucalte N and M for the TWSI clock baud rate */
++ for(n = 0 ; n < 8 ; n++)
++ {
++ for(m = 0 ; m < 16 ; m++)
++ {
++ power = 2 << n; /* power = 2^(n+1) */
++ freq = Tclk/(10*(m+1)*power);
++ margin = MV_ABS(frequancy - freq);
++ if(margin < minMargin)
++ {
++ minMargin = margin;
++ actualFreq = freq;
++ actualN = n;
++ actualM = m;
++ }
++ }
++ }
++ DB(mvOsPrintf("TWSI: mvTwsiInit - actN %d actM %d actFreq %d\n",actualN , actualM, actualFreq));
++ /* Reset the TWSI logic */
++ twsiReset(chanNum);
++
++ /* Set the baud rate */
++ val = ((actualM<< TWSI_BAUD_RATE_M_OFFS) | actualN << TWSI_BAUD_RATE_N_OFFS);
++ MV_REG_WRITE(TWSI_STATUS_BAUDE_RATE_REG(chanNum),val);
++
++ /* Enable the TWSI and slave */
++ MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), TWSI_CONTROL_ENA | TWSI_CONTROL_ACK);
++
++ /* set the TWSI slave address */
++ if( pTwsiAddr->type == ADDR10_BIT )/* 10 Bit deviceAddress */
++ {
++ /* writing the 2 most significant bits of the 10 bit address*/
++ val = ((pTwsiAddr->address & TWSI_SLAVE_ADDR_10BIT_MASK) >> TWSI_SLAVE_ADDR_10BIT_OFFS );
++ /* bits 7:3 must be 0x11110 */
++ val |= TWSI_SLAVE_ADDR_10BIT_CONST;
++ /* set GCE bit */
++ if(generalCallEnable)
++ val |= TWSI_SLAVE_ADDR_GCE_ENA;
++ /* write slave address */
++ MV_REG_WRITE(TWSI_SLAVE_ADDR_REG(chanNum),val);
++
++ /* writing the 8 least significant bits of the 10 bit address*/
++ val = (pTwsiAddr->address << TWSI_EXTENDED_SLAVE_OFFS) & TWSI_EXTENDED_SLAVE_MASK;
++ MV_REG_WRITE(TWSI_EXTENDED_SLAVE_ADDR_REG(chanNum), val);
++ }
++ else /*7 bit address*/
++ {
++ /* set the 7 Bits address */
++ MV_REG_WRITE(TWSI_EXTENDED_SLAVE_ADDR_REG(chanNum),0x0);
++ val = (pTwsiAddr->address << TWSI_SLAVE_ADDR_7BIT_OFFS) & TWSI_SLAVE_ADDR_7BIT_MASK;
++ MV_REG_WRITE(TWSI_SLAVE_ADDR_REG(chanNum), val);
++ }
++
++ /* unmask twsi int */
++ val = MV_REG_READ(TWSI_CONTROL_REG(chanNum));
++ MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), val | TWSI_CONTROL_INT_ENA);
++ /* Add delay of 1ms */
++ mvOsDelay(1);
++
++ return actualFreq;
++}
++
++
++/*******************************************************************************
++* twsiStsGet - Get the TWSI status value.
++*
++* DESCRIPTION:
++* This routine returns the TWSI status value.
++*
++* INPUT:
++* chanNum - TWSI channel
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_U32 - the TWSI status.
++*
++*******************************************************************************/
++static MV_U32 twsiStsGet(MV_U8 chanNum)
++{
++ return MV_REG_READ(TWSI_STATUS_BAUDE_RATE_REG(chanNum));
++
++}
++
++/*******************************************************************************
++* twsiReset - Reset the TWSI.
++*
++* DESCRIPTION:
++* Resets the TWSI logic and sets all TWSI registers to their reset values.
++*
++* INPUT:
++* chanNum - TWSI channel
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* None
++*
++*******************************************************************************/
++static MV_VOID twsiReset(MV_U8 chanNum)
++{
++ /* Reset the TWSI logic */
++ MV_REG_WRITE(TWSI_SOFT_RESET_REG(chanNum),0);
++
++ /* wait for 2 mili sec */
++ mvOsDelay(2);
++
++ return;
++}
++
++
++
++
++/******************************* POLICY ****************************************/
++
++
++
++/*******************************************************************************
++* mvTwsiAddrSet - Set address on TWSI bus.
++*
++* DESCRIPTION:
++* This function Set address (7 or 10 Bit address) on the Twsi Bus.
++*
++* INPUT:
++* chanNum - TWSI channel
++* pTwsiAddr - twsi address.
++* command - read / write .
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_OK - if setting the address completed succesfully.
++* MV_FAIL otherwmise.
++*
++*******************************************************************************/
++MV_STATUS mvTwsiAddrSet(MV_U8 chanNum, MV_TWSI_ADDR *pTwsiAddr, MV_TWSI_CMD command)
++{
++ DB(mvOsPrintf("TWSI: mvTwsiAddr7BitSet addr %x , type %d, cmd is %s\n",pTwsiAddr->address,\
++ pTwsiAddr->type, ((command==MV_TWSI_WRITE)?"Write":"Read") ));
++ /* 10 Bit address */
++ if(pTwsiAddr->type == ADDR10_BIT)
++ {
++ return twsiAddr10BitSet(chanNum, pTwsiAddr->address,command);
++ }
++ /* 7 Bit address */
++ else
++ {
++ return twsiAddr7BitSet(chanNum, pTwsiAddr->address,command);
++ }
++
++}
++
++/*******************************************************************************
++* twsiAddr10BitSet - Set 10 Bit address on TWSI bus.
++*
++* DESCRIPTION:
++* There are two address phases:
++* 1) Write '11110' to data register bits [7:3] and 10-bit address MSB
++* (bits [9:8]) to data register bits [2:1] plus a write(0) or read(1) bit
++* to the Data register. Then it clears interrupt flag which drive
++* the address on the TWSI bus. The function then waits for interrupt
++* flag to be active and status 0x18 (write) or 0x40 (read) to be set.
++* 2) write the rest of 10-bit address to data register and clears
++* interrupt flag which drive the address on the TWSI bus. The
++* function then waits for interrupt flag to be active and status
++* 0xD0 (write) or 0xE0 (read) to be set.
++*
++* INPUT:
++* chanNum - TWSI channel
++* deviceAddress - twsi address.
++* command - read / write .
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_OK - if setting the address completed succesfully.
++* MV_FAIL otherwmise.
++*
++*******************************************************************************/
++static MV_STATUS twsiAddr10BitSet(MV_U8 chanNum, MV_U32 deviceAddress,MV_TWSI_CMD command)
++{
++ MV_U32 val,timeout;
++
++ /* writing the 2 most significant bits of the 10 bit address*/
++ val = ((deviceAddress & TWSI_DATA_ADDR_10BIT_MASK) >> TWSI_DATA_ADDR_10BIT_OFFS );
++ /* bits 7:3 must be 0x11110 */
++ val |= TWSI_DATA_ADDR_10BIT_CONST;
++ /* set command */
++ val |= command;
++ MV_REG_WRITE(TWSI_DATA_REG(chanNum), val);
++ /* WA add a delay */
++ mvOsDelay(1);
++
++ /* clear Int flag */
++ twsiIntFlgClr(chanNum);
++
++ /* wait for Int to be Set */
++ timeout = 0;
++ while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE));
++
++ /* check for timeout */
++ if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiAddr10BitSet ERROR - 1st addr (10Bit) Int TimeOut.\n"))
++ return MV_TIMEOUT;
++
++ /* check the status */
++ val = twsiStsGet(chanNum);
++ if(( (val != TWSI_AD_PLS_RD_BIT_TRA_ACK_REC) && (command == MV_TWSI_READ ) ) ||
++ ( (val != TWSI_AD_PLS_WR_BIT_TRA_ACK_REC) && (command == MV_TWSI_WRITE) ))
++ {
++ mvOsPrintf("TWSI: twsiAddr10BitSet ERROR - status %x 1st addr (10 Bit) in %s mode.\n"\
++ ,val, ((command==MV_TWSI_WRITE)?"Write":"Read") );
++ return MV_FAIL;
++ }
++
++ /* set 8 LSB of the address */
++ val = (deviceAddress << TWSI_DATA_ADDR_7BIT_OFFS) & TWSI_DATA_ADDR_7BIT_MASK;
++ MV_REG_WRITE(TWSI_DATA_REG(chanNum), val);
++
++ /* clear Int flag */
++ twsiIntFlgClr(chanNum);
++
++ /* wait for Int to be Set */
++ timeout = 0;
++ while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE));
++
++ /* check for timeout */
++ if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiAddr10BitSet ERROR - 2nd (10 Bit) Int TimOut.\n"))
++ return MV_TIMEOUT;
++
++ /* check the status */
++ val = twsiStsGet(chanNum);
++ if(( (val != TWSI_SEC_AD_PLS_RD_BIT_TRA_ACK_REC) && (command == MV_TWSI_READ ) ) ||
++ ( (val != TWSI_SEC_AD_PLS_WR_BIT_TRA_ACK_REC) && (command == MV_TWSI_WRITE) ))
++ {
++ mvOsPrintf("TWSI: twsiAddr10BitSet ERROR - status %x 2nd addr(10 Bit) in %s mode.\n"\
++ ,val, ((command==MV_TWSI_WRITE)?"Write":"Read") );
++ return MV_FAIL;
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* twsiAddr7BitSet - Set 7 Bit address on TWSI bus.
++*
++* DESCRIPTION:
++* This function writes 7 bit address plus a write or read bit to the
++* Data register. Then it clears interrupt flag which drive the address on
++* the TWSI bus. The function then waits for interrupt flag to be active
++* and status 0x18 (write) or 0x40 (read) to be set.
++*
++* INPUT:
++* chanNum - TWSI channel
++* deviceAddress - twsi address.
++* command - read / write .
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_OK - if setting the address completed succesfully.
++* MV_FAIL otherwmise.
++*
++*******************************************************************************/
++static MV_STATUS twsiAddr7BitSet(MV_U8 chanNum, MV_U32 deviceAddress,MV_TWSI_CMD command)
++{
++ MV_U32 val,timeout;
++
++ /* set the address */
++ val = (deviceAddress << TWSI_DATA_ADDR_7BIT_OFFS) & TWSI_DATA_ADDR_7BIT_MASK;
++ /* set command */
++ val |= command;
++ MV_REG_WRITE(TWSI_DATA_REG(chanNum), val);
++ /* WA add a delay */
++ mvOsDelay(1);
++
++ /* clear Int flag */
++ twsiIntFlgClr(chanNum);
++
++ /* wait for Int to be Set */
++ timeout = 0;
++ while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE));
++
++ /* check for timeout */
++ if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiAddr7BitSet ERROR - Addr (7 Bit) int TimeOut.\n"))
++ return MV_TIMEOUT;
++
++ /* check the status */
++ val = twsiStsGet(chanNum);
++ if(( (val != TWSI_AD_PLS_RD_BIT_TRA_ACK_REC) && (command == MV_TWSI_READ ) ) ||
++ ( (val != TWSI_AD_PLS_WR_BIT_TRA_ACK_REC) && (command == MV_TWSI_WRITE) ))
++ {
++ /* only in debug, since in boot we try to read the SPD of both DRAM, and we don't
++ want error messeges in case DIMM doesn't exist. */
++ DB(mvOsPrintf("TWSI: twsiAddr7BitSet ERROR - status %x addr (7 Bit) in %s mode.\n"\
++ ,val,((command==MV_TWSI_WRITE)?"Write":"Read") ));
++ return MV_FAIL;
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* twsiDataWrite - Trnasmit a data block over TWSI bus.
++*
++* DESCRIPTION:
++* This function writes a given data block to TWSI bus in 8 bit granularity.
++* first The function waits for interrupt flag to be active then
++* For each 8-bit data:
++* The function writes data to data register. It then clears
++* interrupt flag which drives the data on the TWSI bus.
++* The function then waits for interrupt flag to be active and status
++* 0x28 to be set.
++*
++*
++* INPUT:
++* chanNum - TWSI channel
++* pBlock - Data block.
++* blockSize - number of chars in pBlock.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_OK - if transmiting the block completed succesfully,
++* MV_BAD_PARAM - if pBlock is NULL,
++* MV_FAIL otherwmise.
++*
++*******************************************************************************/
++static MV_STATUS twsiDataTransmit(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize)
++{
++ MV_U32 timeout, temp, blockSizeWr = blockSize;
++
++ if(NULL == pBlock)
++ return MV_BAD_PARAM;
++
++ /* wait for Int to be Set */
++ timeout = 0;
++ while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE));
++
++ /* check for timeout */
++ if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiDataTransmit ERROR - Read Data Int TimeOut.\n"))
++ return MV_TIMEOUT;
++
++ while(blockSizeWr)
++ {
++ /* write the data*/
++ MV_REG_WRITE(TWSI_DATA_REG(chanNum),(MV_U32)*pBlock);
++ DB(mvOsPrintf("TWSI: twsiDataTransmit place = %d write %x \n",\
++ blockSize - blockSizeWr, *pBlock));
++ pBlock++;
++ blockSizeWr--;
++
++ twsiIntFlgClr(chanNum);
++
++ /* wait for Int to be Set */
++ timeout = 0;
++ while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE));
++
++ /* check for timeout */
++ if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiDataTransmit ERROR - Read Data Int TimeOut.\n"))
++ return MV_TIMEOUT;
++
++ /* check the status */
++ temp = twsiStsGet(chanNum);
++ if(temp != TWSI_M_TRAN_DATA_BYTE_ACK_REC)
++ {
++ mvOsPrintf("TWSI: twsiDataTransmit ERROR - status %x in write trans\n",temp);
++ return MV_FAIL;
++ }
++
++ }
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* twsiDataReceive - Receive data block from TWSI bus.
++*
++* DESCRIPTION:
++* This function receive data block from TWSI bus in 8bit granularity
++* into pBlock buffer.
++* first The function waits for interrupt flag to be active then
++* For each 8-bit data:
++* It clears the interrupt flag which allows the next data to be
++* received from TWSI bus.
++* The function waits for interrupt flag to be active,
++* and status reg is 0x50.
++* Then the function reads data from data register, and copies it to
++* the given buffer.
++*
++* INPUT:
++* chanNum - TWSI channel
++* blockSize - number of bytes to read.
++*
++* OUTPUT:
++* pBlock - Data block.
++*
++* RETURN:
++* MV_OK - if receive transaction completed succesfully,
++* MV_BAD_PARAM - if pBlock is NULL,
++* MV_FAIL otherwmise.
++*
++*******************************************************************************/
++static MV_STATUS twsiDataReceive(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize)
++{
++ MV_U32 timeout, temp, blockSizeRd = blockSize;
++ if(NULL == pBlock)
++ return MV_BAD_PARAM;
++
++ /* wait for Int to be Set */
++ timeout = 0;
++ while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE));
++
++ /* check for timeout */
++ if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiDataReceive ERROR - Read Data int Time out .\n"))
++ return MV_TIMEOUT;
++
++ while(blockSizeRd)
++ {
++ if(blockSizeRd == 1)
++ {
++ /* clear ack and Int flag */
++ temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum));
++ temp &= ~(TWSI_CONTROL_ACK);
++ MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp);
++ }
++ twsiIntFlgClr(chanNum);
++ /* wait for Int to be Set */
++ timeout = 0;
++ while( (!twsiMainIntGet(chanNum)) && (timeout++ < TWSI_TIMEOUT_VALUE));
++
++ /* check for timeout */
++ if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiDataReceive ERROR - Read Data Int Time out .\n"))
++ return MV_TIMEOUT;
++
++ /* check the status */
++ temp = twsiStsGet(chanNum);
++ if((temp != TWSI_M_REC_RD_DATA_ACK_TRA) && (blockSizeRd !=1))
++ {
++ mvOsPrintf("TWSI: twsiDataReceive ERROR - status %x in read trans \n",temp);
++ return MV_FAIL;
++ }
++ else if((temp != TWSI_M_REC_RD_DATA_ACK_NOT_TRA) && (blockSizeRd ==1))
++ {
++ mvOsPrintf("TWSI: twsiDataReceive ERROR - status %x in Rd Terminate\n",temp);
++ return MV_FAIL;
++ }
++
++ /* read the data*/
++ *pBlock = (MV_U8)MV_REG_READ(TWSI_DATA_REG(chanNum));
++ DB(mvOsPrintf("TWSI: twsiDataReceive place %d read %x \n",\
++ blockSize - blockSizeRd,*pBlock));
++ pBlock++;
++ blockSizeRd--;
++ }
++
++ return MV_OK;
++}
++
++
++
++/*******************************************************************************
++* twsiTargetOffsSet - Set TWST target offset on TWSI bus.
++*
++* DESCRIPTION:
++* The function support TWSI targets that have inside address space (for
++* example EEPROMs). The function:
++* 1) Convert the given offset into pBlock and size.
++* in case the offset should be set to a TWSI slave which support
++* more then 256 bytes offset, the offset setting will be done
++* in 2 transactions.
++* 2) Use twsiDataTransmit to place those on the bus.
++*
++* INPUT:
++* chanNum - TWSI channel
++* offset - offset to be set on the EEPROM device.
++* moreThen256 - whether the EEPROM device support more then 256 byte offset.
++*
++* OUTPUT:
++* None.
++*
++* RETURN:
++* MV_OK - if setting the offset completed succesfully.
++* MV_FAIL otherwmise.
++*
++*******************************************************************************/
++static MV_STATUS twsiTargetOffsSet(MV_U8 chanNum, MV_U32 offset, MV_BOOL moreThen256)
++{
++ MV_U8 offBlock[2];
++ MV_U32 offSize;
++
++ if(moreThen256 == MV_TRUE)
++ {
++ offBlock[0] = (offset >> 8) & 0xff;
++ offBlock[1] = offset & 0xff;
++ offSize = 2;
++ }
++ else
++ {
++ offBlock[0] = offset & 0xff;
++ offSize = 1;
++ }
++ DB(mvOsPrintf("TWSI: twsiTargetOffsSet offSize = %x addr1 = %x addr2 = %x\n",\
++ offSize,offBlock[0],offBlock[1]));
++ return twsiDataTransmit(chanNum, offBlock, offSize);
++
++}
++
++/*******************************************************************************
++* mvTwsiRead - Read data block from a TWSI Slave.
++*
++* DESCRIPTION:
++* The function calls the following functions:
++* -) mvTwsiStartBitSet();
++* if(EEPROM device)
++* -) mvTwsiAddrSet(w);
++* -) twsiTargetOffsSet();
++* -) mvTwsiStartBitSet();
++* -) mvTwsiAddrSet(r);
++* -) twsiDataReceive();
++* -) mvTwsiStopBitSet();
++*
++* INPUT:
++* chanNum - TWSI channel
++* pTwsiSlave - Twsi Slave structure.
++* blockSize - number of bytes to read.
++*
++* OUTPUT:
++* pBlock - Data block.
++*
++* RETURN:
++* MV_OK - if EEPROM read transaction completed succesfully,
++* MV_BAD_PARAM - if pBlock is NULL,
++* MV_FAIL otherwmise.
++*
++*******************************************************************************/
++MV_STATUS mvTwsiRead(MV_U8 chanNum, MV_TWSI_SLAVE *pTwsiSlave, MV_U8 *pBlock, MV_U32 blockSize)
++{
++ if((NULL == pBlock) || (NULL == pTwsiSlave))
++ return MV_BAD_PARAM;
++ if(MV_OK != mvTwsiStartBitSet(chanNum))
++ {
++ mvTwsiStopBitSet(chanNum);
++ return MV_FAIL;
++ }
++
++ DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiStartBitSet\n"));
++
++ /* in case offset exsist (i.e. eeprom ) */
++ if(MV_TRUE == pTwsiSlave->validOffset)
++ {
++ if(MV_OK != mvTwsiAddrSet(chanNum, &(pTwsiSlave->slaveAddr), MV_TWSI_WRITE))
++ {
++ mvTwsiStopBitSet(chanNum);
++ return MV_FAIL;
++ }
++ DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiAddrSet\n"));
++ if(MV_OK != twsiTargetOffsSet(chanNum, pTwsiSlave->offset, pTwsiSlave->moreThen256))
++ {
++ mvTwsiStopBitSet(chanNum);
++ return MV_FAIL;
++ }
++ DB(mvOsPrintf("TWSI: mvTwsiEepromRead after twsiTargetOffsSet\n"));
++ if(MV_OK != mvTwsiStartBitSet(chanNum))
++ {
++ mvTwsiStopBitSet(chanNum);
++ return MV_FAIL;
++ }
++ DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiStartBitSet\n"));
++ }
++ if(MV_OK != mvTwsiAddrSet(chanNum, &(pTwsiSlave->slaveAddr), MV_TWSI_READ))
++ {
++ mvTwsiStopBitSet(chanNum);
++ return MV_FAIL;
++ }
++ DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiAddrSet\n"));
++ if(MV_OK != twsiDataReceive(chanNum, pBlock, blockSize))
++ {
++ mvTwsiStopBitSet(chanNum);
++ return MV_FAIL;
++ }
++ DB(mvOsPrintf("TWSI: mvTwsiEepromRead after twsiDataReceive\n"));
++
++ if(MV_OK != mvTwsiStopBitSet(chanNum))
++ {
++ return MV_FAIL;
++ }
++
++ twsiAckBitSet(chanNum);
++
++ DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiStopBitSet\n"));
++
++ return MV_OK;
++}
++
++/*******************************************************************************
++* mvTwsiWrite - Write data block to a TWSI Slave.
++*
++* DESCRIPTION:
++* The function calls the following functions:
++* -) mvTwsiStartBitSet();
++* -) mvTwsiAddrSet();
++* -)if(EEPROM device)
++* -) twsiTargetOffsSet();
++* -) twsiDataTransmit();
++* -) mvTwsiStopBitSet();
++*
++* INPUT:
++* chanNum - TWSI channel
++* eepromAddress - eeprom address.
++* blockSize - number of bytes to write.
++* pBlock - Data block.
++*
++* OUTPUT:
++* None
++*
++* RETURN:
++* MV_OK - if EEPROM read transaction completed succesfully.
++* MV_BAD_PARAM - if pBlock is NULL,
++* MV_FAIL otherwmise.
++*
++* NOTE: Part of the EEPROM, required that the offset will be aligned to the
++* max write burst supported.
++*******************************************************************************/
++MV_STATUS mvTwsiWrite(MV_U8 chanNum, MV_TWSI_SLAVE *pTwsiSlave, MV_U8 *pBlock, MV_U32 blockSize)
++{
++ if((NULL == pBlock) || (NULL == pTwsiSlave))
++ return MV_BAD_PARAM;
++
++ if(MV_OK != mvTwsiStartBitSet(chanNum))
++ {
++ mvTwsiStopBitSet(chanNum);
++ return MV_FAIL;
++ }
++
++ DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after mvTwsiStartBitSet\n"));
++ if(MV_OK != mvTwsiAddrSet(chanNum, &(pTwsiSlave->slaveAddr), MV_TWSI_WRITE))
++ {
++ mvTwsiStopBitSet(chanNum);
++ return MV_FAIL;
++ }
++ DB(mvOsPrintf("TWSI :mvTwsiEepromWrite after mvTwsiAddrSet\n"));
++
++ /* in case offset exsist (i.e. eeprom ) */
++ if(MV_TRUE == pTwsiSlave->validOffset)
++ {
++ if(MV_OK != twsiTargetOffsSet(chanNum, pTwsiSlave->offset, pTwsiSlave->moreThen256))
++ {
++ mvTwsiStopBitSet(chanNum);
++ return MV_FAIL;
++ }
++ DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after twsiTargetOffsSet\n"));
++ }
++ if(MV_OK != twsiDataTransmit(chanNum, pBlock, blockSize))
++ {
++ mvTwsiStopBitSet(chanNum);
++ return MV_FAIL;
++ }
++ DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after twsiDataTransmit\n"));
++ if(MV_OK != mvTwsiStopBitSet(chanNum))
++ {
++ return MV_FAIL;
++ }
++ DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after mvTwsiStopBitSet\n"));
++
++ return MV_OK;
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.h 2010-11-09 20:28:12.231824496 +0100
+@@ -0,0 +1,121 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 __INCmvTwsiH
++#define __INCmvTwsiH
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/* need to update this includes */
++#include "twsi/mvTwsiSpec.h"
++#include "ctrlEnv/mvCtrlEnvLib.h"
++
++
++/* The TWSI interface supports both 7-bit and 10-bit addressing. */
++/* This enumerator describes addressing type. */
++typedef enum _mvTwsiAddrType
++{
++ ADDR7_BIT, /* 7 bit address */
++ ADDR10_BIT /* 10 bit address */
++}MV_TWSI_ADDR_TYPE;
++
++/* This structure describes TWSI address. */
++typedef struct _mvTwsiAddr
++{
++ MV_U32 address; /* address */
++ MV_TWSI_ADDR_TYPE type; /* Address type */
++}MV_TWSI_ADDR;
++
++/* This structure describes a TWSI slave. */
++typedef struct _mvTwsiSlave
++{
++ MV_TWSI_ADDR slaveAddr;
++ MV_BOOL validOffset; /* whether the slave has offset (i.e. Eeprom etc.) */
++ MV_U32 offset; /* offset in the slave. */
++ MV_BOOL moreThen256; /* whether the ofset is bigger then 256 */
++}MV_TWSI_SLAVE;
++
++/* This enumerator describes TWSI protocol commands. */
++typedef enum _mvTwsiCmd
++{
++ MV_TWSI_WRITE, /* TWSI write command - 0 according to spec */
++ MV_TWSI_READ /* TWSI read command - 1 according to spec */
++}MV_TWSI_CMD;
++
++MV_STATUS mvTwsiStartBitSet(MV_U8 chanNum);
++MV_STATUS mvTwsiStopBitSet(MV_U8 chanNum);
++MV_STATUS mvTwsiAddrSet(MV_U8 chanNum, MV_TWSI_ADDR *twsiAddr, MV_TWSI_CMD command);
++
++MV_U32 mvTwsiInit(MV_U8 chanNum, MV_KHZ frequancy, MV_U32 Tclk, MV_TWSI_ADDR *twsiAddr, MV_BOOL generalCallEnable);
++MV_STATUS mvTwsiRead (MV_U8 chanNum, MV_TWSI_SLAVE *twsiSlave, MV_U8 *pBlock, MV_U32 blockSize);
++MV_STATUS mvTwsiWrite(MV_U8 chanNum, MV_TWSI_SLAVE *twsiSlave, MV_U8 *pBlock, MV_U32 blockSize);
++
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __INCmvTwsiH */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiSpec.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiSpec.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiSpec.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiSpec.h 2010-11-09 20:28:12.272374071 +0100
+@@ -0,0 +1,160 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++This software file (the "File") is owned and distributed by Marvell
++International Ltd. and/or its affiliates ("Marvell") under the following
++alternative licensing terms. Once you have made an election to distribute the
++File under one of the following license alternatives, please (i) delete this
++introductory statement regarding license alternatives, (ii) delete the two
++license alternatives that you have not elected to use and (iii) preserve the
++Marvell copyright notice above.
++
++********************************************************************************
++Marvell Commercial License Option
++
++If you received this File from Marvell and you have entered into a commercial
++license agreement (a "Commercial License") with Marvell, the File is licensed
++to you under the terms of the applicable Commercial License.
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++********************************************************************************
++Marvell BSD License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File under the following licensing terms.
++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 Marvell 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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.
++
++*******************************************************************************/
++/****************************************/
++/* TWSI Registers */
++/****************************************/
++#ifndef __INCmvTwsiSpech
++#define __INCmvTwsiSpech
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++/* defines */
++#define TWSI_SLAVE_ADDR_REG(chanNum) (TWSI_SLAVE_BASE(chanNum)+ 0x00)
++
++#define TWSI_SLAVE_ADDR_GCE_ENA BIT0
++#define TWSI_SLAVE_ADDR_7BIT_OFFS 0x1
++#define TWSI_SLAVE_ADDR_7BIT_MASK (0xFF << TWSI_SLAVE_ADDR_7BIT_OFFS)
++#define TWSI_SLAVE_ADDR_10BIT_OFFS 0x7
++#define TWSI_SLAVE_ADDR_10BIT_MASK 0x300
++#define TWSI_SLAVE_ADDR_10BIT_CONST 0xF0
++
++
++#define TWSI_EXTENDED_SLAVE_ADDR_REG(chanNum) (TWSI_SLAVE_BASE(chanNum) + 0x10)
++#define TWSI_EXTENDED_SLAVE_OFFS 0
++#define TWSI_EXTENDED_SLAVE_MASK (0xFF << TWSI_EXTENDED_SLAVE_OFFS)
++
++
++#define TWSI_DATA_REG(chanNum) (TWSI_SLAVE_BASE(chanNum) + 0x04)
++#define TWSI_DATA_COMMAND_OFFS 0x0
++#define TWSI_DATA_COMMAND_MASK (0x1 << TWSI_DATA_COMMAND_OFFS)
++#define TWSI_DATA_COMMAND_WR (0x1 << TWSI_DATA_COMMAND_OFFS)
++#define TWSI_DATA_COMMAND_RD (0x0 << TWSI_DATA_COMMAND_OFFS)
++#define TWSI_DATA_ADDR_7BIT_OFFS 0x1
++#define TWSI_DATA_ADDR_7BIT_MASK (0xFF << TWSI_DATA_ADDR_7BIT_OFFS)
++#define TWSI_DATA_ADDR_10BIT_OFFS 0x7
++#define TWSI_DATA_ADDR_10BIT_MASK 0x300
++#define TWSI_DATA_ADDR_10BIT_CONST 0xF0
++
++
++#define TWSI_CONTROL_REG(chanNum) (TWSI_SLAVE_BASE(chanNum) + 0x08)
++#define TWSI_CONTROL_ACK BIT2
++#define TWSI_CONTROL_INT_FLAG_SET BIT3
++#define TWSI_CONTROL_STOP_BIT BIT4
++#define TWSI_CONTROL_START_BIT BIT5
++#define TWSI_CONTROL_ENA BIT6
++#define TWSI_CONTROL_INT_ENA BIT7
++
++
++#define TWSI_STATUS_BAUDE_RATE_REG(chanNum) (TWSI_SLAVE_BASE(chanNum) + 0x0c)
++#define TWSI_BAUD_RATE_N_OFFS 0
++#define TWSI_BAUD_RATE_N_MASK (0x7 << TWSI_BAUD_RATE_N_OFFS)
++#define TWSI_BAUD_RATE_M_OFFS 3
++#define TWSI_BAUD_RATE_M_MASK (0xF << TWSI_BAUD_RATE_M_OFFS)
++
++#define TWSI_SOFT_RESET_REG(chanNum) (TWSI_SLAVE_BASE(chanNum) + 0x1c)
++
++/* defines */
++#define TWSI_TIMEOUT_VALUE 0x500
++
++/* TWSI status codes */
++#define TWSI_BUS_ERROR 0x00
++#define TWSI_START_CON_TRA 0x08
++#define TWSI_REPEATED_START_CON_TRA 0x10
++#define TWSI_AD_PLS_WR_BIT_TRA_ACK_REC 0x18
++#define TWSI_AD_PLS_WR_BIT_TRA_ACK_NOT_REC 0x20
++#define TWSI_M_TRAN_DATA_BYTE_ACK_REC 0x28
++#define TWSI_M_TRAN_DATA_BYTE_ACK_NOT_REC 0x30
++#define TWSI_M_LOST_ARB_DUR_AD_OR_DATA_TRA 0x38
++#define TWSI_AD_PLS_RD_BIT_TRA_ACK_REC 0x40
++#define TWSI_AD_PLS_RD_BIT_TRA_ACK_NOT_REC 0x48
++#define TWSI_M_REC_RD_DATA_ACK_TRA 0x50
++#define TWSI_M_REC_RD_DATA_ACK_NOT_TRA 0x58
++#define TWSI_SLA_REC_AD_PLS_WR_BIT_ACK_TRA 0x60
++#define TWSI_M_LOST_ARB_DUR_AD_TRA_AD_IS_TRGT_TO_SLA_ACK_TRA_W 0x68
++#define TWSI_GNL_CALL_REC_ACK_TRA 0x70
++#define TWSI_M_LOST_ARB_DUR_AD_TRA_GNL_CALL_AD_REC_ACK_TRA 0x78
++#define TWSI_SLA_REC_WR_DATA_AF_REC_SLA_AD_ACK_TRAN 0x80
++#define TWSI_SLA_REC_WR_DATA_AF_REC_SLA_AD_ACK_NOT_TRAN 0x88
++#define TWSI_SLA_REC_WR_DATA_AF_REC_GNL_CALL_ACK_TRAN 0x90
++#define TWSI_SLA_REC_WR_DATA_AF_REC_GNL_CALL_ACK_NOT_TRAN 0x98
++#define TWSI_SLA_REC_STOP_OR_REPEATED_STRT_CON 0xA0
++#define TWSI_SLA_REC_AD_PLS_RD_BIT_ACK_TRA 0xA8
++#define TWSI_M_LOST_ARB_DUR_AD_TRA_AD_IS_TRGT_TO_SLA_ACK_TRA_R 0xB0
++#define TWSI_SLA_TRA_RD_DATA_ACK_REC 0xB8
++#define TWSI_SLA_TRA_RD_DATA_ACK_NOT_REC 0xC0
++#define TWSI_SLA_TRA_LAST_RD_DATA_ACK_REC 0xC8
++#define TWSI_SEC_AD_PLS_WR_BIT_TRA_ACK_REC 0xD0
++#define TWSI_SEC_AD_PLS_WR_BIT_TRA_ACK_NOT_REC 0xD8
++#define TWSI_SEC_AD_PLS_RD_BIT_TRA_ACK_REC 0xE0
++#define TWSI_SEC_AD_PLS_RD_BIT_TRA_ACK_NOT_REC 0xE8
++#define TWSI_NO_REL_STS_INT_FLAG_IS_KEPT_0 0xF8
++
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif /* __INCmvTwsiSpech */
+diff -Nur linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mvSysHwConfig.h linux-2.6.36/crypto/ocf/kirkwood/mvHal/mvSysHwConfig.h
+--- linux-2.6.36.orig/crypto/ocf/kirkwood/mvHal/mvSysHwConfig.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/kirkwood/mvHal/mvSysHwConfig.h 2010-11-09 20:28:12.322486315 +0100
+@@ -0,0 +1,375 @@
++/*******************************************************************************
++Copyright (C) Marvell International Ltd. and its affiliates
++
++********************************************************************************
++Marvell GPL License Option
++
++If you received this File from Marvell, you may opt to use, redistribute and/or
++modify this File in accordance with the terms and conditions of the General
++Public License Version 2, June 1991 (the "GPL License"), a copy of which is
++available along with the File in the license.txt file or by writing to the Free
++Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
++on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
++
++THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
++WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
++DISCLAIMED. The GPL License provides additional details about this warranty
++disclaimer.
++
++*******************************************************************************/
++/*******************************************************************************
++* mvSysHwCfg.h - Marvell system HW configuration file
++*
++* DESCRIPTION:
++* None.
++*
++* DEPENDENCIES:
++* None.
++*
++*******************************************************************************/
++
++#ifndef __INCmvSysHwConfigh
++#define __INCmvSysHwConfigh
++
++#include "../../../../include/linux/autoconf.h"
++
++#define CONFIG_MARVELL 1
++
++/* includes */
++#define _1K 0x00000400
++#define _4K 0x00001000
++#define _8K 0x00002000
++#define _16K 0x00004000
++#define _32K 0x00008000
++#define _64K 0x00010000
++#define _128K 0x00020000
++#define _256K 0x00040000
++#define _512K 0x00080000
++
++#define _1M 0x00100000
++#define _2M 0x00200000
++#define _4M 0x00400000
++#define _8M 0x00800000
++#define _16M 0x01000000
++#define _32M 0x02000000
++#define _64M 0x04000000
++#define _128M 0x08000000
++#define _256M 0x10000000
++#define _512M 0x20000000
++
++#define _1G 0x40000000
++#define _2G 0x80000000
++
++/****************************************/
++/* Soc supporeted Units definitions */
++/****************************************/
++
++#ifdef CONFIG_MV_INCLUDE_PEX
++#define MV_INCLUDE_PEX
++#endif
++#ifdef CONFIG_MV_INCLUDE_TWSI
++#define MV_INCLUDE_TWSI
++#endif
++#ifdef CONFIG_MV_INCLUDE_CESA
++#define MV_INCLUDE_CESA
++#endif
++#ifdef CONFIG_MV_INCLUDE_GIG_ETH
++#define MV_INCLUDE_GIG_ETH
++#endif
++#ifdef CONFIG_MV_INCLUDE_INTEG_SATA
++#define MV_INCLUDE_INTEG_SATA
++#define MV_INCLUDE_SATA
++#endif
++#ifdef CONFIG_MV_INCLUDE_USB
++#define MV_INCLUDE_USB
++#define MV_USB_VOLTAGE_FIX
++#endif
++#ifdef CONFIG_MV_INCLUDE_NAND
++#define MV_INCLUDE_NAND
++#endif
++#ifdef CONFIG_MV_INCLUDE_TDM
++#define MV_INCLUDE_TDM
++#endif
++#ifdef CONFIG_MV_INCLUDE_XOR
++#define MV_INCLUDE_XOR
++#endif
++#ifdef CONFIG_MV_INCLUDE_TWSI
++#define MV_INCLUDE_TWSI
++#endif
++#ifdef CONFIG_MV_INCLUDE_UART
++#define MV_INCLUDE_UART
++#endif
++#ifdef CONFIG_MV_INCLUDE_SPI
++#define MV_INCLUDE_SPI
++#endif
++#ifdef CONFIG_MV_INCLUDE_SFLASH_MTD
++#define MV_INCLUDE_SFLASH_MTD
++#endif
++#ifdef CONFIG_MV_INCLUDE_AUDIO
++#define MV_INCLUDE_AUDIO
++#endif
++#ifdef CONFIG_MV_INCLUDE_TS
++#define MV_INCLUDE_TS
++#endif
++#ifdef CONFIG_MV_INCLUDE_SDIO
++#define MV_INCLUDE_SDIO
++#endif
++
++
++/* NAND flash stuff */
++#ifdef CONFIG_MV_NAND_BOOT
++#define MV_NAND_BOOT
++#endif
++#ifdef CONFIG_MV_NAND
++#define MV_NAND
++#endif
++
++/* SPI flash stuff */
++#ifdef CONFIG_MV_SPI_BOOT
++#define MV_SPI_BOOT
++#endif
++
++
++/****************************************************************/
++/************* General configuration ********************/
++/****************************************************************/
++
++/* Enable Clock Power Control */
++#define MV_INCLUDE_CLK_PWR_CNTRL
++
++/* Disable the DEVICE BAR in the PEX */
++#define MV_DISABLE_PEX_DEVICE_BAR
++
++/* Allow the usage of early printings during initialization */
++#define MV_INCLUDE_EARLY_PRINTK
++
++/****************************************************************/
++/************* NFP configuration ********************************/
++/****************************************************************/
++#define MV_NFP_SEC_Q_SIZE 64
++#define MV_NFP_SEC_REQ_Q_SIZE 1000
++
++
++
++/****************************************************************/
++/************* CESA configuration ********************/
++/****************************************************************/
++
++#ifdef MV_INCLUDE_CESA
++
++#define MV_CESA_MAX_CHAN 4
++
++/* Use 2K of SRAM */
++#define MV_CESA_MAX_BUF_SIZE 1600
++
++#endif /* MV_INCLUDE_CESA */
++
++#if defined(CONFIG_MV_INCLUDE_GIG_ETH)
++
++#ifdef CONFIG_MV_NFP_STATS
++#define MV_FP_STATISTICS
++#else
++#undef MV_FP_STATISTICS
++#endif
++/* Default configuration for SKB_REUSE: 0 - Disabled, 1 - Enabled */
++#define MV_ETH_SKB_REUSE_DEFAULT 1
++/* Default configuration for TX_EN workaround: 0 - Disabled, 1 - Enabled */
++#define MV_ETH_TX_EN_DEFAULT 0
++
++/* un-comment if you want to perform tx_done from within the poll function */
++/* #define ETH_TX_DONE_ISR */
++
++/* put descriptors in uncached memory */
++/* #define ETH_DESCR_UNCACHED */
++
++/* Descriptors location: DRAM/internal-SRAM */
++#define ETH_DESCR_IN_SDRAM
++#undef ETH_DESCR_IN_SRAM /* No integrated SRAM in 88Fxx81 devices */
++
++#if defined(ETH_DESCR_IN_SRAM)
++#if defined(ETH_DESCR_UNCACHED)
++ #define ETH_DESCR_CONFIG_STR "Uncached descriptors in integrated SRAM"
++#else
++ #define ETH_DESCR_CONFIG_STR "Cached descriptors in integrated SRAM"
++#endif
++#elif defined(ETH_DESCR_IN_SDRAM)
++#if defined(ETH_DESCR_UNCACHED)
++ #define ETH_DESCR_CONFIG_STR "Uncached descriptors in DRAM"
++#else
++ #define ETH_DESCR_CONFIG_STR "Cached descriptors in DRAM"
++#endif
++#else
++ #error "Ethernet descriptors location undefined"
++#endif /* ETH_DESCR_IN_SRAM or ETH_DESCR_IN_SDRAM*/
++
++/* SW Sync-Barrier: not relevant for 88fxx81*/
++/* Reasnable to define this macro when descriptors in SRAM and buffers in DRAM */
++/* In RX the CPU theoretically might see himself as the descriptor owner, */
++/* although the buffer hadn't been written to DRAM yet. Performance cost. */
++/* #define INCLUDE_SYNC_BARR */
++
++/* Buffers cache coherency method (buffers in DRAM) */
++#ifndef MV_CACHE_COHER_SW
++/* Taken from mvCommon.h */
++/* Memory uncached, HW or SW cache coherency is not needed */
++#define MV_UNCACHED 0
++/* Memory cached, HW cache coherency supported in WriteThrough mode */
++#define MV_CACHE_COHER_HW_WT 1
++/* Memory cached, HW cache coherency supported in WriteBack mode */
++#define MV_CACHE_COHER_HW_WB 2
++/* Memory cached, No HW cache coherency, Cache coherency must be in SW */
++#define MV_CACHE_COHER_SW 3
++
++#endif
++
++/* DRAM cache coherency configuration */
++#define MV_CACHE_COHERENCY MV_CACHE_COHER_SW
++
++
++#define ETHER_DRAM_COHER MV_CACHE_COHER_SW /* No HW coherency in 88Fxx81 devices */
++
++#if (ETHER_DRAM_COHER == MV_CACHE_COHER_HW_WB)
++ #define ETH_SDRAM_CONFIG_STR "DRAM HW cache coherency (write-back)"
++#elif (ETHER_DRAM_COHER == MV_CACHE_COHER_HW_WT)
++ #define ETH_SDRAM_CONFIG_STR "DRAM HW cache coherency (write-through)"
++#elif (ETHER_DRAM_COHER == MV_CACHE_COHER_SW)
++ #define ETH_SDRAM_CONFIG_STR "DRAM SW cache-coherency"
++#elif (ETHER_DRAM_COHER == MV_UNCACHED)
++# define ETH_SDRAM_CONFIG_STR "DRAM uncached"
++#else
++ #error "Ethernet-DRAM undefined"
++#endif /* ETHER_DRAM_COHER */
++
++
++/****************************************************************/
++/************* Ethernet driver configuration ********************/
++/****************************************************************/
++
++/* port's default queueus */
++#define ETH_DEF_TXQ 0
++#define ETH_DEF_RXQ 0
++
++#define MV_ETH_RX_Q_NUM CONFIG_MV_ETH_RX_Q_NUM
++#define MV_ETH_TX_Q_NUM CONFIG_MV_ETH_TX_Q_NUM
++
++/* interrupt coalescing setting */
++#define ETH_TX_COAL 200
++#define ETH_RX_COAL 200
++
++/* Checksum offloading */
++#define TX_CSUM_OFFLOAD
++#define RX_CSUM_OFFLOAD
++
++#endif /* CONFIG_MV_INCLUDE_GIG_ETH */
++
++/****************************************************************/
++/*************** Telephony configuration ************************/
++/****************************************************************/
++#if defined(CONFIG_MV_TDM_LINEAR_MODE)
++ #define MV_TDM_LINEAR_MODE
++#elif defined(CONFIG_MV_TDM_ULAW_MODE)
++ #define MV_TDM_ULAW_MODE
++#endif
++
++#if defined(CONFIG_MV_TDM_5CHANNELS)
++ #define MV_TDM_5CHANNELS
++#endif
++
++#if defined(CONFIG_MV_TDM_USE_EXTERNAL_PCLK_SOURCE)
++ #define MV_TDM_USE_EXTERNAL_PCLK_SOURCE
++#endif
++
++/* We use the following registers to store DRAM interface pre configuration */
++/* auto-detection results */
++/* IMPORTANT: We are using mask register for that purpose. Before writing */
++/* to units mask register, make sure main maks register is set to disable */
++/* all interrupts. */
++#define DRAM_BUF_REG0 0x30810 /* sdram bank 0 size */
++#define DRAM_BUF_REG1 0x30820 /* sdram config */
++#define DRAM_BUF_REG2 0x30830 /* sdram mode */
++#define DRAM_BUF_REG3 0x308c4 /* dunit control low */
++#define DRAM_BUF_REG4 0x60a90 /* sdram address control */
++#define DRAM_BUF_REG5 0x60a94 /* sdram timing control low */
++#define DRAM_BUF_REG6 0x60a98 /* sdram timing control high */
++#define DRAM_BUF_REG7 0x60a9c /* sdram ODT control low */
++#define DRAM_BUF_REG8 0x60b90 /* sdram ODT control high */
++#define DRAM_BUF_REG9 0x60b94 /* sdram Dunit ODT control */
++#define DRAM_BUF_REG10 0x60b98 /* sdram Extended Mode */
++#define DRAM_BUF_REG11 0x60b9c /* sdram Ddr2 Time Low Reg */
++#define DRAM_BUF_REG12 0x60a00 /* sdram Ddr2 Time High Reg */
++#define DRAM_BUF_REG13 0x60a04 /* dunit Ctrl High */
++#define DRAM_BUF_REG14 0x60b00 /* sdram second DIMM exist */
++
++/* Following the pre-configuration registers default values restored after */
++/* auto-detection is done */
++#define DRAM_BUF_REG_DV 0
++
++/* System Mapping */
++#define SDRAM_CS0_BASE 0x00000000
++#define SDRAM_CS0_SIZE _256M
++
++#define SDRAM_CS1_BASE 0x10000000
++#define SDRAM_CS1_SIZE _256M
++
++#define SDRAM_CS2_BASE 0x20000000
++#define SDRAM_CS2_SIZE _256M
++
++#define SDRAM_CS3_BASE 0x30000000
++#define SDRAM_CS3_SIZE _256M
++
++/* PEX */
++#define PEX0_MEM_BASE 0xe8000000
++#define PEX0_MEM_SIZE _128M
++
++#define PEX0_IO_BASE 0xf2000000
++#define PEX0_IO_SIZE _1M
++
++/* Device Chip Selects */
++#define NFLASH_CS_BASE 0xfa000000
++#define NFLASH_CS_SIZE _2M
++
++#define SPI_CS_BASE 0xf4000000
++#define SPI_CS_SIZE _16M
++
++#define CRYPT_ENG_BASE 0xf0000000
++#define CRYPT_ENG_SIZE _2M
++
++#define BOOTDEV_CS_BASE 0xff800000
++#define BOOTDEV_CS_SIZE _8M
++
++/* CS2 - BOOTROM */
++#define DEVICE_CS2_BASE 0xff900000
++#define DEVICE_CS2_SIZE _1M
++
++/* PEX Work arround */
++/* the target we will use for the workarround */
++#define PEX_CONFIG_RW_WA_TARGET PEX0_MEM
++/*a flag that indicates if we are going to use the
++size and base of the target we using for the workarround
++window */
++#define PEX_CONFIG_RW_WA_USE_ORIGINAL_WIN_VALUES 1
++/* if the above flag is 0 then the following values
++will be used for the workarround window base and size,
++otherwise the following defines will be ignored */
++#define PEX_CONFIG_RW_WA_BASE 0xF3000000
++#define PEX_CONFIG_RW_WA_SIZE _16M
++
++/* Internal registers: size is defined in Controllerenvironment */
++#define INTER_REGS_BASE 0xFEE00000
++
++/* DRAM detection stuff */
++#define MV_DRAM_AUTO_SIZE
++
++/* Board clock detection */
++#define TCLK_AUTO_DETECT /* Use Tclk auto detection */
++#define SYSCLK_AUTO_DETECT /* Use SysClk auto detection */
++#define PCLCK_AUTO_DETECT /* Use PClk auto detection */
++#define L2CLK_AUTO_DETECT /* Use L2Clk auto detection */
++
++/* PEX-PCI\PCI-PCI Bridge*/
++#define PCI0_IF_PTP 0 /* Bridge exist on pciIf0*/
++
++
++
++#endif /* __INCmvSysHwConfigh */
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/Makefile linux-2.6.36/crypto/ocf/Makefile
+--- linux-2.6.36.orig/crypto/ocf/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/Makefile 2010-11-09 20:28:12.342495369 +0100
+@@ -0,0 +1,124 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++OCF_OBJS = crypto.o criov.o
++
++ifdef CONFIG_OCF_RANDOMHARVEST
++ OCF_OBJS += random.o
++endif
++
++ifdef CONFIG_OCF_FIPS
++ OCF_OBJS += rndtest.o
++endif
++
++# Add in autoconf.h to get #defines for CONFIG_xxx
++AUTOCONF_H=$(ROOTDIR)/modules/autoconf.h
++ifeq ($(AUTOCONF_H), $(wildcard $(AUTOCONF_H)))
++ EXTRA_CFLAGS += -include $(AUTOCONF_H)
++ export EXTRA_CFLAGS
++endif
++
++ifndef obj
++ obj ?= .
++ _obj = subdir
++ mod-subdirs := safe hifn ixp4xx talitos ocfnull
++ export-objs += crypto.o criov.o random.o
++ list-multi += ocf.o
++ _slash :=
++else
++ _obj = obj
++ _slash := /
++endif
++
++EXTRA_CFLAGS += -I$(obj)/.
++
++obj-$(CONFIG_OCF_OCF) += ocf.o
++obj-$(CONFIG_OCF_CRYPTODEV) += cryptodev.o
++obj-$(CONFIG_OCF_CRYPTOSOFT) += cryptosoft.o
++obj-$(CONFIG_OCF_BENCH) += ocf-bench.o
++
++$(_obj)-$(CONFIG_OCF_SAFE) += safe$(_slash)
++$(_obj)-$(CONFIG_OCF_HIFN) += hifn$(_slash)
++$(_obj)-$(CONFIG_OCF_IXP4XX) += ixp4xx$(_slash)
++$(_obj)-$(CONFIG_OCF_TALITOS) += talitos$(_slash)
++$(_obj)-$(CONFIG_OCF_PASEMI) += pasemi$(_slash)
++$(_obj)-$(CONFIG_OCF_EP80579) += ep80579$(_slash)
++$(_obj)-$(CONFIG_OCF_CRYPTOCTEON) += cryptocteon$(_slash)
++$(_obj)-$(CONFIG_OCF_KIRKWOOD) += kirkwood$(_slash)
++$(_obj)-$(CONFIG_OCF_OCFNULL) += ocfnull$(_slash)
++$(_obj)-$(CONFIG_OCF_C7108) += c7108$(_slash)
++
++ocf-objs := $(OCF_OBJS)
++
++$(list-multi) dummy1: $(ocf-objs)
++ $(LD) -r -o $@ $(ocf-objs)
++
++.PHONY:
++clean:
++ rm -f *.o *.ko .*.o.flags .*.ko.cmd .*.o.cmd .*.mod.o.cmd *.mod.c
++ rm -f */*.o */*.ko */.*.o.cmd */.*.ko.cmd */.*.mod.o.cmd */*.mod.c */.*.o.flags
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
++#
++# release gen targets
++#
++
++.PHONY: patch
++patch:
++ REL=`date +%Y%m%d`; \
++ patch=ocf-linux-$$REL.patch; \
++ patch24=ocf-linux-24-$$REL.patch; \
++ patch26=ocf-linux-26-$$REL.patch; \
++ ( \
++ find . -name Makefile; \
++ find . -name Config.in; \
++ find . -name Kconfig; \
++ find . -name README; \
++ find . -name '*.[ch]' | grep -v '.mod.c'; \
++ ) | while read t; do \
++ diff -Nau /dev/null $$t | sed 's?^+++ \./?+++ linux/crypto/ocf/?'; \
++ done > $$patch; \
++ cat patches/linux-2.4.35-ocf.patch $$patch > $$patch24; \
++ cat patches/linux-2.6.33-ocf.patch $$patch > $$patch26
++
++.PHONY: tarball
++tarball:
++ REL=`date +%Y%m%d`; RELDIR=/tmp/ocf-linux-$$REL; \
++ CURDIR=`pwd`; \
++ rm -rf /tmp/ocf-linux-$$REL*; \
++ mkdir -p $$RELDIR/tools; \
++ cp README* $$RELDIR; \
++ cp patches/openss*.patch $$RELDIR; \
++ cp patches/crypto-tools.patch $$RELDIR; \
++ cp tools/[!C]* $$RELDIR/tools; \
++ cd ..; \
++ tar cvf $$RELDIR/ocf-linux.tar \
++ --exclude=CVS \
++ --exclude=.* \
++ --exclude=*.o \
++ --exclude=*.ko \
++ --exclude=*.mod.* \
++ --exclude=README* \
++ --exclude=ocf-*.patch \
++ --exclude=ocf/patches/openss*.patch \
++ --exclude=ocf/patches/crypto-tools.patch \
++ --exclude=ocf/tools \
++ ocf; \
++ gzip -9 $$RELDIR/ocf-linux.tar; \
++ cd /tmp; \
++ tar cvf ocf-linux-$$REL.tar ocf-linux-$$REL; \
++ gzip -9 ocf-linux-$$REL.tar; \
++ cd $$CURDIR/../../user; \
++ rm -rf /tmp/crypto-tools-$$REL*; \
++ tar cvf /tmp/crypto-tools-$$REL.tar \
++ --exclude=CVS \
++ --exclude=.* \
++ --exclude=*.o \
++ --exclude=cryptotest \
++ --exclude=cryptokeytest \
++ crypto-tools; \
++ gzip -9 /tmp/crypto-tools-$$REL.tar
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/ocf-bench.c linux-2.6.36/crypto/ocf/ocf-bench.c
+--- linux-2.6.36.orig/crypto/ocf/ocf-bench.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/ocf-bench.c 2010-11-09 20:28:12.381251524 +0100
+@@ -0,0 +1,436 @@
++/*
++ * A loadable module that benchmarks the OCF crypto speed from kernel space.
++ *
++ * Copyright (C) 2004-2010 David McCullough <david_mccullough@mcafee.com>
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ * 1. distributions of this source code include the above copyright
++ * notice, this list of conditions and the following disclaimer;
++ *
++ * 2. distributions in binary form include the above copyright
++ * notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other associated materials;
++ *
++ * 3. the copyright holder's name is not used to endorse products
++ * built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ */
++
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/version.h>
++#include <linux/interrupt.h>
++#include <cryptodev.h>
++
++#ifdef I_HAVE_AN_XSCALE_WITH_INTEL_SDK
++#define BENCH_IXP_ACCESS_LIB 1
++#endif
++#ifdef BENCH_IXP_ACCESS_LIB
++#include <IxTypes.h>
++#include <IxOsBuffMgt.h>
++#include <IxNpeDl.h>
++#include <IxCryptoAcc.h>
++#include <IxQMgr.h>
++#include <IxOsServices.h>
++#include <IxOsCacheMMU.h>
++#endif
++
++/*
++ * support for access lib version 1.4
++ */
++#ifndef IX_MBUF_PRIV
++#define IX_MBUF_PRIV(x) ((x)->priv)
++#endif
++
++/*
++ * the number of simultaneously active requests
++ */
++static int request_q_len = 20;
++module_param(request_q_len, int, 0);
++MODULE_PARM_DESC(request_q_len, "Number of outstanding requests");
++/*
++ * how many requests we want to have processed
++ */
++static int request_num = 1024;
++module_param(request_num, int, 0);
++MODULE_PARM_DESC(request_num, "run for at least this many requests");
++/*
++ * the size of each request
++ */
++static int request_size = 1500;
++module_param(request_size, int, 0);
++MODULE_PARM_DESC(request_size, "size of each request");
++
++/*
++ * a structure for each request
++ */
++typedef struct {
++ struct work_struct work;
++#ifdef BENCH_IXP_ACCESS_LIB
++ IX_MBUF mbuf;
++#endif
++ unsigned char *buffer;
++} request_t;
++
++static request_t *requests;
++
++static int outstanding;
++static int total;
++
++/*************************************************************************/
++/*
++ * OCF benchmark routines
++ */
++
++static uint64_t ocf_cryptoid;
++static int ocf_init(void);
++static int ocf_cb(struct cryptop *crp);
++static void ocf_request(void *arg);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void ocf_request_wq(struct work_struct *work);
++#endif
++
++static int
++ocf_init(void)
++{
++ int error;
++ struct cryptoini crie, cria;
++ struct cryptodesc crda, crde;
++
++ memset(&crie, 0, sizeof(crie));
++ memset(&cria, 0, sizeof(cria));
++ memset(&crde, 0, sizeof(crde));
++ memset(&crda, 0, sizeof(crda));
++
++ cria.cri_alg = CRYPTO_SHA1_HMAC;
++ cria.cri_klen = 20 * 8;
++ cria.cri_key = "0123456789abcdefghij";
++
++ crie.cri_alg = CRYPTO_3DES_CBC;
++ crie.cri_klen = 24 * 8;
++ crie.cri_key = "0123456789abcdefghijklmn";
++
++ crie.cri_next = &cria;
++
++ error = crypto_newsession(&ocf_cryptoid, &crie, 0);
++ if (error) {
++ printk("crypto_newsession failed %d\n", error);
++ return -1;
++ }
++ return 0;
++}
++
++static int
++ocf_cb(struct cryptop *crp)
++{
++ request_t *r = (request_t *) crp->crp_opaque;
++
++ if (crp->crp_etype)
++ printk("Error in OCF processing: %d\n", crp->crp_etype);
++ total++;
++ crypto_freereq(crp);
++ crp = NULL;
++
++ if (total > request_num) {
++ outstanding--;
++ return 0;
++ }
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++ INIT_WORK(&r->work, ocf_request_wq);
++#else
++ INIT_WORK(&r->work, ocf_request, r);
++#endif
++ schedule_work(&r->work);
++ return 0;
++}
++
++
++static void
++ocf_request(void *arg)
++{
++ request_t *r = arg;
++ struct cryptop *crp = crypto_getreq(2);
++ struct cryptodesc *crde, *crda;
++
++ if (!crp) {
++ outstanding--;
++ return;
++ }
++
++ crde = crp->crp_desc;
++ crda = crde->crd_next;
++
++ crda->crd_skip = 0;
++ crda->crd_flags = 0;
++ crda->crd_len = request_size;
++ crda->crd_inject = request_size;
++ crda->crd_alg = CRYPTO_SHA1_HMAC;
++ crda->crd_key = "0123456789abcdefghij";
++ crda->crd_klen = 20 * 8;
++
++ crde->crd_skip = 0;
++ crde->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_ENCRYPT;
++ crde->crd_len = request_size;
++ crde->crd_inject = request_size;
++ crde->crd_alg = CRYPTO_3DES_CBC;
++ crde->crd_key = "0123456789abcdefghijklmn";
++ crde->crd_klen = 24 * 8;
++
++ crp->crp_ilen = request_size + 64;
++ crp->crp_flags = CRYPTO_F_CBIMM;
++ crp->crp_buf = (caddr_t) r->buffer;
++ crp->crp_callback = ocf_cb;
++ crp->crp_sid = ocf_cryptoid;
++ crp->crp_opaque = (caddr_t) r;
++ crypto_dispatch(crp);
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void
++ocf_request_wq(struct work_struct *work)
++{
++ request_t *r = container_of(work, request_t, work);
++ ocf_request(r);
++}
++#endif
++
++/*************************************************************************/
++#ifdef BENCH_IXP_ACCESS_LIB
++/*************************************************************************/
++/*
++ * CryptoAcc benchmark routines
++ */
++
++static IxCryptoAccCtx ixp_ctx;
++static UINT32 ixp_ctx_id;
++static IX_MBUF ixp_pri;
++static IX_MBUF ixp_sec;
++static int ixp_registered = 0;
++
++static void ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp,
++ IxCryptoAccStatus status);
++static void ixp_perform_cb(UINT32 ctx_id, IX_MBUF *sbufp, IX_MBUF *dbufp,
++ IxCryptoAccStatus status);
++static void ixp_request(void *arg);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void ixp_request_wq(struct work_struct *work);
++#endif
++
++static int
++ixp_init(void)
++{
++ IxCryptoAccStatus status;
++
++ ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES;
++ ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC;
++ ixp_ctx.cipherCtx.cipherKeyLen = 24;
++ ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64;
++ ixp_ctx.cipherCtx.cipherInitialVectorLen = IX_CRYPTO_ACC_DES_IV_64;
++ memcpy(ixp_ctx.cipherCtx.key.cipherKey, "0123456789abcdefghijklmn", 24);
++
++ ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1;
++ ixp_ctx.authCtx.authDigestLen = 12;
++ ixp_ctx.authCtx.aadLen = 0;
++ ixp_ctx.authCtx.authKeyLen = 20;
++ memcpy(ixp_ctx.authCtx.key.authKey, "0123456789abcdefghij", 20);
++
++ ixp_ctx.useDifferentSrcAndDestMbufs = 0;
++ ixp_ctx.operation = IX_CRYPTO_ACC_OP_ENCRYPT_AUTH ;
++
++ IX_MBUF_MLEN(&ixp_pri) = IX_MBUF_PKT_LEN(&ixp_pri) = 128;
++ IX_MBUF_MDATA(&ixp_pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC);
++ IX_MBUF_MLEN(&ixp_sec) = IX_MBUF_PKT_LEN(&ixp_sec) = 128;
++ IX_MBUF_MDATA(&ixp_sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC);
++
++ status = ixCryptoAccCtxRegister(&ixp_ctx, &ixp_pri, &ixp_sec,
++ ixp_register_cb, ixp_perform_cb, &ixp_ctx_id);
++
++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) {
++ while (!ixp_registered)
++ schedule();
++ return ixp_registered < 0 ? -1 : 0;
++ }
++
++ printk("ixp: ixCryptoAccCtxRegister failed %d\n", status);
++ return -1;
++}
++
++static void
++ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status)
++{
++ if (bufp) {
++ IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0;
++ kfree(IX_MBUF_MDATA(bufp));
++ IX_MBUF_MDATA(bufp) = NULL;
++ }
++
++ if (IX_CRYPTO_ACC_STATUS_WAIT == status)
++ return;
++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status)
++ ixp_registered = 1;
++ else
++ ixp_registered = -1;
++}
++
++static void
++ixp_perform_cb(
++ UINT32 ctx_id,
++ IX_MBUF *sbufp,
++ IX_MBUF *dbufp,
++ IxCryptoAccStatus status)
++{
++ request_t *r = NULL;
++
++ total++;
++ if (total > request_num) {
++ outstanding--;
++ return;
++ }
++
++ if (!sbufp || !(r = IX_MBUF_PRIV(sbufp))) {
++ printk("crappo %p %p\n", sbufp, r);
++ outstanding--;
++ return;
++ }
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++ INIT_WORK(&r->work, ixp_request_wq);
++#else
++ INIT_WORK(&r->work, ixp_request, r);
++#endif
++ schedule_work(&r->work);
++}
++
++static void
++ixp_request(void *arg)
++{
++ request_t *r = arg;
++ IxCryptoAccStatus status;
++
++ memset(&r->mbuf, 0, sizeof(r->mbuf));
++ IX_MBUF_MLEN(&r->mbuf) = IX_MBUF_PKT_LEN(&r->mbuf) = request_size + 64;
++ IX_MBUF_MDATA(&r->mbuf) = r->buffer;
++ IX_MBUF_PRIV(&r->mbuf) = r;
++ status = ixCryptoAccAuthCryptPerform(ixp_ctx_id, &r->mbuf, NULL,
++ 0, request_size, 0, request_size, request_size, r->buffer);
++ if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) {
++ printk("status1 = %d\n", status);
++ outstanding--;
++ return;
++ }
++ return;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void
++ixp_request_wq(struct work_struct *work)
++{
++ request_t *r = container_of(work, request_t, work);
++ ixp_request(r);
++}
++#endif
++
++/*************************************************************************/
++#endif /* BENCH_IXP_ACCESS_LIB */
++/*************************************************************************/
++
++int
++ocfbench_init(void)
++{
++ int i, jstart, jstop;
++
++ printk("Crypto Speed tests\n");
++
++ requests = kmalloc(sizeof(request_t) * request_q_len, GFP_KERNEL);
++ if (!requests) {
++ printk("malloc failed\n");
++ return -EINVAL;
++ }
++
++ for (i = 0; i < request_q_len; i++) {
++ /* +64 for return data */
++ requests[i].buffer = kmalloc(request_size + 128, GFP_DMA);
++ if (!requests[i].buffer) {
++ printk("malloc failed\n");
++ return -EINVAL;
++ }
++ memset(requests[i].buffer, '0' + i, request_size + 128);
++ }
++
++ /*
++ * OCF benchmark
++ */
++ printk("OCF: testing ...\n");
++ ocf_init();
++ total = outstanding = 0;
++ jstart = jiffies;
++ for (i = 0; i < request_q_len; i++) {
++ outstanding++;
++ ocf_request(&requests[i]);
++ }
++ while (outstanding > 0)
++ schedule();
++ jstop = jiffies;
++
++ printk("OCF: %d requests of %d bytes in %d jiffies\n", total, request_size,
++ jstop - jstart);
++
++#ifdef BENCH_IXP_ACCESS_LIB
++ /*
++ * IXP benchmark
++ */
++ printk("IXP: testing ...\n");
++ ixp_init();
++ total = outstanding = 0;
++ jstart = jiffies;
++ for (i = 0; i < request_q_len; i++) {
++ outstanding++;
++ ixp_request(&requests[i]);
++ }
++ while (outstanding > 0)
++ schedule();
++ jstop = jiffies;
++
++ printk("IXP: %d requests of %d bytes in %d jiffies\n", total, request_size,
++ jstop - jstart);
++#endif /* BENCH_IXP_ACCESS_LIB */
++
++ for (i = 0; i < request_q_len; i++)
++ kfree(requests[i].buffer);
++ kfree(requests);
++ return -EINVAL; /* always fail to load so it can be re-run quickly ;-) */
++}
++
++static void __exit ocfbench_exit(void)
++{
++}
++
++module_init(ocfbench_init);
++module_exit(ocfbench_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
++MODULE_DESCRIPTION("Benchmark various in-kernel crypto speeds");
+diff -Nur linux-2.6.36.orig/crypto/ocf/ocf-compat.h linux-2.6.36/crypto/ocf/ocf-compat.h
+--- linux-2.6.36.orig/crypto/ocf/ocf-compat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/ocf-compat.h 2010-11-09 20:28:12.422358492 +0100
+@@ -0,0 +1,294 @@
++#ifndef _BSD_COMPAT_H_
++#define _BSD_COMPAT_H_ 1
++/****************************************************************************/
++/*
++ * Provide compat routines for older linux kernels and BSD kernels
++ *
++ * Written by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2010 David McCullough <david_mccullough@mcafee.com>
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ * 1. distributions of this source code include the above copyright
++ * notice, this list of conditions and the following disclaimer;
++ *
++ * 2. distributions in binary form include the above copyright
++ * notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other associated materials;
++ *
++ * 3. the copyright holder's name is not used to endorse products
++ * built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this file
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ */
++/****************************************************************************/
++#ifdef __KERNEL__
++/*
++ * fake some BSD driver interface stuff specifically for OCF use
++ */
++
++typedef struct ocf_device *device_t;
++
++typedef struct {
++ int (*cryptodev_newsession)(device_t dev, u_int32_t *sidp, struct cryptoini *cri);
++ int (*cryptodev_freesession)(device_t dev, u_int64_t tid);
++ int (*cryptodev_process)(device_t dev, struct cryptop *crp, int hint);
++ int (*cryptodev_kprocess)(device_t dev, struct cryptkop *krp, int hint);
++} device_method_t;
++#define DEVMETHOD(id, func) id: func
++
++struct ocf_device {
++ char name[32]; /* the driver name */
++ char nameunit[32]; /* the driver name + HW instance */
++ int unit;
++ device_method_t methods;
++ void *softc;
++};
++
++#define CRYPTODEV_NEWSESSION(dev, sid, cri) \
++ ((*(dev)->methods.cryptodev_newsession)(dev,sid,cri))
++#define CRYPTODEV_FREESESSION(dev, sid) \
++ ((*(dev)->methods.cryptodev_freesession)(dev, sid))
++#define CRYPTODEV_PROCESS(dev, crp, hint) \
++ ((*(dev)->methods.cryptodev_process)(dev, crp, hint))
++#define CRYPTODEV_KPROCESS(dev, krp, hint) \
++ ((*(dev)->methods.cryptodev_kprocess)(dev, krp, hint))
++
++#define device_get_name(dev) ((dev)->name)
++#define device_get_nameunit(dev) ((dev)->nameunit)
++#define device_get_unit(dev) ((dev)->unit)
++#define device_get_softc(dev) ((dev)->softc)
++
++#define softc_device_decl \
++ struct ocf_device _device; \
++ device_t
++
++#define softc_device_init(_sc, _name, _unit, _methods) \
++ if (1) {\
++ strncpy((_sc)->_device.name, _name, sizeof((_sc)->_device.name) - 1); \
++ snprintf((_sc)->_device.nameunit, sizeof((_sc)->_device.name), "%s%d", _name, _unit); \
++ (_sc)->_device.unit = _unit; \
++ (_sc)->_device.methods = _methods; \
++ (_sc)->_device.softc = (void *) _sc; \
++ *(device_t *)((softc_get_device(_sc))+1) = &(_sc)->_device; \
++ } else
++
++#define softc_get_device(_sc) (&(_sc)->_device)
++
++/*
++ * iomem support for 2.4 and 2.6 kernels
++ */
++#include <linux/version.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++#define ocf_iomem_t unsigned long
++
++/*
++ * implement simple workqueue like support for older kernels
++ */
++
++#include <linux/tqueue.h>
++
++#define work_struct tq_struct
++
++#define INIT_WORK(wp, fp, ap) \
++ do { \
++ (wp)->sync = 0; \
++ (wp)->routine = (fp); \
++ (wp)->data = (ap); \
++ } while (0)
++
++#define schedule_work(wp) \
++ do { \
++ queue_task((wp), &tq_immediate); \
++ mark_bh(IMMEDIATE_BH); \
++ } while (0)
++
++#define flush_scheduled_work() run_task_queue(&tq_immediate)
++
++#else
++#define ocf_iomem_t void __iomem *
++
++#include <linux/workqueue.h>
++
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
++#include <linux/fdtable.h>
++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
++#define files_fdtable(files) (files)
++#endif
++
++#ifdef MODULE_PARM
++#undef module_param /* just in case */
++#define module_param(a,b,c) MODULE_PARM(a,"i")
++#endif
++
++#define bzero(s,l) memset(s,0,l)
++#define bcopy(s,d,l) memcpy(d,s,l)
++#define bcmp(x, y, l) memcmp(x,y,l)
++
++#define MIN(x,y) ((x) < (y) ? (x) : (y))
++
++#define device_printf(dev, a...) ({ \
++ printk("%s: ", device_get_nameunit(dev)); printk(a); \
++ })
++
++#undef printf
++#define printf(fmt...) printk(fmt)
++
++#define KASSERT(c,p) if (!(c)) { printk p ; } else
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++#define ocf_daemonize(str) \
++ daemonize(); \
++ spin_lock_irq(&current->sigmask_lock); \
++ sigemptyset(&current->blocked); \
++ recalc_sigpending(current); \
++ spin_unlock_irq(&current->sigmask_lock); \
++ sprintf(current->comm, str);
++#else
++#define ocf_daemonize(str) daemonize(str);
++#endif
++
++#define TAILQ_INSERT_TAIL(q,d,m) list_add_tail(&(d)->m, (q))
++#define TAILQ_EMPTY(q) list_empty(q)
++#define TAILQ_FOREACH(v, q, m) list_for_each_entry(v, q, m)
++
++#define read_random(p,l) get_random_bytes(p,l)
++
++#define DELAY(x) ((x) > 2000 ? mdelay((x)/1000) : udelay(x))
++#define strtoul simple_strtoul
++
++#define pci_get_vendor(dev) ((dev)->vendor)
++#define pci_get_device(dev) ((dev)->device)
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++#define pci_set_consistent_dma_mask(dev, mask) (0)
++#endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
++#define pci_dma_sync_single_for_cpu pci_dma_sync_single
++#endif
++
++#ifndef DMA_32BIT_MASK
++#define DMA_32BIT_MASK 0x00000000ffffffffULL
++#endif
++
++#ifndef htole32
++#define htole32(x) cpu_to_le32(x)
++#endif
++#ifndef htobe32
++#define htobe32(x) cpu_to_be32(x)
++#endif
++#ifndef htole16
++#define htole16(x) cpu_to_le16(x)
++#endif
++#ifndef htobe16
++#define htobe16(x) cpu_to_be16(x)
++#endif
++
++/* older kernels don't have these */
++
++#include <asm/irq.h>
++#if !defined(IRQ_NONE) && !defined(IRQ_RETVAL)
++#define IRQ_NONE
++#define IRQ_HANDLED
++#define IRQ_WAKE_THREAD
++#define IRQ_RETVAL
++#define irqreturn_t void
++typedef irqreturn_t (*irq_handler_t)(int irq, void *arg, struct pt_regs *regs);
++#endif
++#ifndef IRQF_SHARED
++#define IRQF_SHARED SA_SHIRQ
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++# define strlcpy(dest,src,len) \
++ ({strncpy(dest,src,(len)-1); ((char *)dest)[(len)-1] = '\0'; })
++#endif
++
++#ifndef MAX_ERRNO
++#define MAX_ERRNO 4095
++#endif
++#ifndef IS_ERR_VALUE
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,5)
++#include <linux/err.h>
++#endif
++#ifndef IS_ERR_VALUE
++#define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO)
++#endif
++#endif
++
++/*
++ * common debug for all
++ */
++#if 1
++#define dprintk(a...) do { if (debug) printk(a); } while(0)
++#else
++#define dprintk(a...)
++#endif
++
++#ifndef SLAB_ATOMIC
++/* Changed in 2.6.20, must use GFP_ATOMIC now */
++#define SLAB_ATOMIC GFP_ATOMIC
++#endif
++
++/*
++ * need some additional support for older kernels */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,2)
++#define pci_register_driver_compat(driver, rc) \
++ do { \
++ if ((rc) > 0) { \
++ (rc) = 0; \
++ } else if (rc == 0) { \
++ (rc) = -ENODEV; \
++ } else { \
++ pci_unregister_driver(driver); \
++ } \
++ } while (0)
++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
++#define pci_register_driver_compat(driver,rc) ((rc) = (rc) < 0 ? (rc) : 0)
++#else
++#define pci_register_driver_compat(driver,rc)
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
++
++#include <linux/mm.h>
++#include <asm/scatterlist.h>
++
++static inline void sg_set_page(struct scatterlist *sg, struct page *page,
++ unsigned int len, unsigned int offset)
++{
++ sg->page = page;
++ sg->offset = offset;
++ sg->length = len;
++}
++
++static inline void *sg_virt(struct scatterlist *sg)
++{
++ return page_address(sg->page) + sg->offset;
++}
++
++#define sg_init_table(sg, n)
++
++#endif
++
++#ifndef late_initcall
++#define late_initcall(init) module_init(init)
++#endif
++
++#endif /* __KERNEL__ */
++
++/****************************************************************************/
++#endif /* _BSD_COMPAT_H_ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/ocfnull/Makefile linux-2.6.36/crypto/ocf/ocfnull/Makefile
+--- linux-2.6.36.orig/crypto/ocf/ocfnull/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/ocfnull/Makefile 2010-11-09 20:28:12.462495574 +0100
+@@ -0,0 +1,12 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_OCFNULL) += ocfnull.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/..
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/ocfnull/ocfnull.c linux-2.6.36/crypto/ocf/ocfnull/ocfnull.c
+--- linux-2.6.36.orig/crypto/ocf/ocfnull/ocfnull.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/ocfnull/ocfnull.c 2010-11-09 20:28:12.501251038 +0100
+@@ -0,0 +1,203 @@
++/*
++ * An OCF module for determining the cost of crypto versus the cost of
++ * IPSec processing outside of OCF. This modules gives us the effect of
++ * zero cost encryption, of course you will need to run it at both ends
++ * since it does no crypto at all.
++ *
++ * Written by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ * 1. distributions of this source code include the above copyright
++ * notice, this list of conditions and the following disclaimer;
++ *
++ * 2. distributions in binary form include the above copyright
++ * notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other associated materials;
++ *
++ * 3. the copyright holder's name is not used to endorse products
++ * built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/crypto.h>
++#include <linux/interrupt.h>
++
++#include <cryptodev.h>
++#include <uio.h>
++
++static int32_t null_id = -1;
++static u_int32_t null_sesnum = 0;
++
++static int null_process(device_t, struct cryptop *, int);
++static int null_newsession(device_t, u_int32_t *, struct cryptoini *);
++static int null_freesession(device_t, u_int64_t);
++
++#define debug ocfnull_debug
++int ocfnull_debug = 0;
++module_param(ocfnull_debug, int, 0644);
++MODULE_PARM_DESC(ocfnull_debug, "Enable debug");
++
++/*
++ * dummy device structure
++ */
++
++static struct {
++ softc_device_decl sc_dev;
++} nulldev;
++
++static device_method_t null_methods = {
++ /* crypto device methods */
++ DEVMETHOD(cryptodev_newsession, null_newsession),
++ DEVMETHOD(cryptodev_freesession,null_freesession),
++ DEVMETHOD(cryptodev_process, null_process),
++};
++
++/*
++ * Generate a new software session.
++ */
++static int
++null_newsession(device_t arg, u_int32_t *sid, struct cryptoini *cri)
++{
++ dprintk("%s()\n", __FUNCTION__);
++ if (sid == NULL || cri == NULL) {
++ dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ if (null_sesnum == 0)
++ null_sesnum++;
++ *sid = null_sesnum++;
++ return 0;
++}
++
++
++/*
++ * Free a session.
++ */
++static int
++null_freesession(device_t arg, u_int64_t tid)
++{
++ u_int32_t sid = CRYPTO_SESID2LID(tid);
++
++ dprintk("%s()\n", __FUNCTION__);
++ if (sid > null_sesnum) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ /* Silently accept and return */
++ if (sid == 0)
++ return 0;
++ return 0;
++}
++
++
++/*
++ * Process a request.
++ */
++static int
++null_process(device_t arg, struct cryptop *crp, int hint)
++{
++ unsigned int lid;
++
++ dprintk("%s()\n", __FUNCTION__);
++
++ /* Sanity check */
++ if (crp == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++
++ crp->crp_etype = 0;
++
++ if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++ crp->crp_etype = EINVAL;
++ goto done;
++ }
++
++ /*
++ * find the session we are using
++ */
++
++ lid = crp->crp_sid & 0xffffffff;
++ if (lid >= null_sesnum || lid == 0) {
++ crp->crp_etype = ENOENT;
++ dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);
++ goto done;
++ }
++
++done:
++ crypto_done(crp);
++ return 0;
++}
++
++
++/*
++ * our driver startup and shutdown routines
++ */
++
++static int
++null_init(void)
++{
++ dprintk("%s(%p)\n", __FUNCTION__, null_init);
++
++ memset(&nulldev, 0, sizeof(nulldev));
++ softc_device_init(&nulldev, "ocfnull", 0, null_methods);
++
++ null_id = crypto_get_driverid(softc_get_device(&nulldev),
++ CRYPTOCAP_F_HARDWARE);
++ if (null_id < 0)
++ panic("ocfnull: crypto device cannot initialize!");
++
++#define REGISTER(alg) \
++ crypto_register(null_id,alg,0,0)
++ REGISTER(CRYPTO_DES_CBC);
++ REGISTER(CRYPTO_3DES_CBC);
++ REGISTER(CRYPTO_RIJNDAEL128_CBC);
++ REGISTER(CRYPTO_MD5);
++ REGISTER(CRYPTO_SHA1);
++ REGISTER(CRYPTO_MD5_HMAC);
++ REGISTER(CRYPTO_SHA1_HMAC);
++#undef REGISTER
++
++ return 0;
++}
++
++static void
++null_exit(void)
++{
++ dprintk("%s()\n", __FUNCTION__);
++ crypto_unregister_all(null_id);
++ null_id = -1;
++}
++
++module_init(null_init);
++module_exit(null_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
++MODULE_DESCRIPTION("ocfnull - claims a lot but does nothing");
+diff -Nur linux-2.6.36.orig/crypto/ocf/pasemi/Makefile linux-2.6.36/crypto/ocf/pasemi/Makefile
+--- linux-2.6.36.orig/crypto/ocf/pasemi/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/pasemi/Makefile 2010-11-09 20:28:12.532495480 +0100
+@@ -0,0 +1,12 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_PASEMI) += pasemi.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/pasemi/pasemi.c linux-2.6.36/crypto/ocf/pasemi/pasemi.c
+--- linux-2.6.36.orig/crypto/ocf/pasemi/pasemi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/pasemi/pasemi.c 2010-11-09 20:28:12.572495531 +0100
+@@ -0,0 +1,1009 @@
++/*
++ * Copyright (C) 2007 PA Semi, Inc
++ *
++ * Driver for the PA Semi PWRficient DMA Crypto Engine
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/timer.h>
++#include <linux/random.h>
++#include <linux/skbuff.h>
++#include <asm/scatterlist.h>
++#include <linux/moduleparam.h>
++#include <linux/pci.h>
++#include <cryptodev.h>
++#include <uio.h>
++#include "pasemi_fnu.h"
++
++#define DRV_NAME "pasemi"
++
++#define TIMER_INTERVAL 1000
++
++static void __devexit pasemi_dma_remove(struct pci_dev *pdev);
++static struct pasdma_status volatile * dma_status;
++
++static int debug;
++module_param(debug, int, 0644);
++MODULE_PARM_DESC(debug, "Enable debug");
++
++static void pasemi_desc_start(struct pasemi_desc *desc, u64 hdr)
++{
++ desc->postop = 0;
++ desc->quad[0] = hdr;
++ desc->quad_cnt = 1;
++ desc->size = 1;
++}
++
++static void pasemi_desc_build(struct pasemi_desc *desc, u64 val)
++{
++ desc->quad[desc->quad_cnt++] = val;
++ desc->size = (desc->quad_cnt + 1) / 2;
++}
++
++static void pasemi_desc_hdr(struct pasemi_desc *desc, u64 hdr)
++{
++ desc->quad[0] |= hdr;
++}
++
++static int pasemi_desc_size(struct pasemi_desc *desc)
++{
++ return desc->size;
++}
++
++static void pasemi_ring_add_desc(
++ struct pasemi_fnu_txring *ring,
++ struct pasemi_desc *desc,
++ struct cryptop *crp) {
++ int i;
++ int ring_index = 2 * (ring->next_to_fill & (TX_RING_SIZE-1));
++
++ TX_DESC_INFO(ring, ring->next_to_fill).desc_size = desc->size;
++ TX_DESC_INFO(ring, ring->next_to_fill).desc_postop = desc->postop;
++ TX_DESC_INFO(ring, ring->next_to_fill).cf_crp = crp;
++
++ for (i = 0; i < desc->quad_cnt; i += 2) {
++ ring_index = 2 * (ring->next_to_fill & (TX_RING_SIZE-1));
++ ring->desc[ring_index] = desc->quad[i];
++ ring->desc[ring_index + 1] = desc->quad[i + 1];
++ ring->next_to_fill++;
++ }
++
++ if (desc->quad_cnt & 1)
++ ring->desc[ring_index + 1] = 0;
++}
++
++static void pasemi_ring_incr(struct pasemi_softc *sc, int chan_index, int incr)
++{
++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_INCR(sc->base_chan + chan_index),
++ incr);
++}
++
++/*
++ * Generate a new software session.
++ */
++static int
++pasemi_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
++{
++ struct cryptoini *c, *encini = NULL, *macini = NULL;
++ struct pasemi_softc *sc = device_get_softc(dev);
++ struct pasemi_session *ses = NULL, **sespp;
++ int sesn, blksz = 0;
++ u64 ccmd = 0;
++ unsigned long flags;
++ struct pasemi_desc init_desc;
++ struct pasemi_fnu_txring *txring;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++ if (sidp == NULL || cri == NULL || sc == NULL) {
++ DPRINTF("%s,%d - EINVAL\n", __FILE__, __LINE__);
++ return -EINVAL;
++ }
++ for (c = cri; c != NULL; c = c->cri_next) {
++ if (ALG_IS_SIG(c->cri_alg)) {
++ if (macini)
++ return -EINVAL;
++ macini = c;
++ } else if (ALG_IS_CIPHER(c->cri_alg)) {
++ if (encini)
++ return -EINVAL;
++ encini = c;
++ } else {
++ DPRINTF("UNKNOWN c->cri_alg %d\n", c->cri_alg);
++ return -EINVAL;
++ }
++ }
++ if (encini == NULL && macini == NULL)
++ return -EINVAL;
++ if (encini) {
++ /* validate key length */
++ switch (encini->cri_alg) {
++ case CRYPTO_DES_CBC:
++ if (encini->cri_klen != 64)
++ return -EINVAL;
++ ccmd = DMA_CALGO_DES;
++ break;
++ case CRYPTO_3DES_CBC:
++ if (encini->cri_klen != 192)
++ return -EINVAL;
++ ccmd = DMA_CALGO_3DES;
++ break;
++ case CRYPTO_AES_CBC:
++ if (encini->cri_klen != 128 &&
++ encini->cri_klen != 192 &&
++ encini->cri_klen != 256)
++ return -EINVAL;
++ ccmd = DMA_CALGO_AES;
++ break;
++ case CRYPTO_ARC4:
++ if (encini->cri_klen != 128)
++ return -EINVAL;
++ ccmd = DMA_CALGO_ARC;
++ break;
++ default:
++ DPRINTF("UNKNOWN encini->cri_alg %d\n",
++ encini->cri_alg);
++ return -EINVAL;
++ }
++ }
++
++ if (macini) {
++ switch (macini->cri_alg) {
++ case CRYPTO_MD5:
++ case CRYPTO_MD5_HMAC:
++ blksz = 16;
++ break;
++ case CRYPTO_SHA1:
++ case CRYPTO_SHA1_HMAC:
++ blksz = 20;
++ break;
++ default:
++ DPRINTF("UNKNOWN macini->cri_alg %d\n",
++ macini->cri_alg);
++ return -EINVAL;
++ }
++ if (((macini->cri_klen + 7) / 8) > blksz) {
++ DPRINTF("key length %d bigger than blksize %d not supported\n",
++ ((macini->cri_klen + 7) / 8), blksz);
++ return -EINVAL;
++ }
++ }
++
++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
++ if (sc->sc_sessions[sesn] == NULL) {
++ sc->sc_sessions[sesn] = (struct pasemi_session *)
++ kzalloc(sizeof(struct pasemi_session), GFP_ATOMIC);
++ ses = sc->sc_sessions[sesn];
++ break;
++ } else if (sc->sc_sessions[sesn]->used == 0) {
++ ses = sc->sc_sessions[sesn];
++ break;
++ }
++ }
++
++ if (ses == NULL) {
++ sespp = (struct pasemi_session **)
++ kzalloc(sc->sc_nsessions * 2 *
++ sizeof(struct pasemi_session *), GFP_ATOMIC);
++ if (sespp == NULL)
++ return -ENOMEM;
++ memcpy(sespp, sc->sc_sessions,
++ sc->sc_nsessions * sizeof(struct pasemi_session *));
++ kfree(sc->sc_sessions);
++ sc->sc_sessions = sespp;
++ sesn = sc->sc_nsessions;
++ ses = sc->sc_sessions[sesn] = (struct pasemi_session *)
++ kzalloc(sizeof(struct pasemi_session), GFP_ATOMIC);
++ if (ses == NULL)
++ return -ENOMEM;
++ sc->sc_nsessions *= 2;
++ }
++
++ ses->used = 1;
++
++ ses->dma_addr = pci_map_single(sc->dma_pdev, (void *) ses->civ,
++ sizeof(struct pasemi_session), DMA_TO_DEVICE);
++
++ /* enter the channel scheduler */
++ spin_lock_irqsave(&sc->sc_chnlock, flags);
++
++ /* ARC4 has to be processed by the even channel */
++ if (encini && (encini->cri_alg == CRYPTO_ARC4))
++ ses->chan = sc->sc_lastchn & ~1;
++ else
++ ses->chan = sc->sc_lastchn;
++ sc->sc_lastchn = (sc->sc_lastchn + 1) % sc->sc_num_channels;
++
++ spin_unlock_irqrestore(&sc->sc_chnlock, flags);
++
++ txring = &sc->tx[ses->chan];
++
++ if (encini) {
++ ses->ccmd = ccmd;
++
++ /* get an IV */
++ /* XXX may read fewer than requested */
++ get_random_bytes(ses->civ, sizeof(ses->civ));
++
++ ses->keysz = (encini->cri_klen - 63) / 64;
++ memcpy(ses->key, encini->cri_key, (ses->keysz + 1) * 8);
++
++ pasemi_desc_start(&init_desc,
++ XCT_CTRL_HDR(ses->chan, (encini && macini) ? 0x68 : 0x40, DMA_FN_CIV0));
++ pasemi_desc_build(&init_desc,
++ XCT_FUN_SRC_PTR((encini && macini) ? 0x68 : 0x40, ses->dma_addr));
++ }
++ if (macini) {
++ if (macini->cri_alg == CRYPTO_MD5_HMAC ||
++ macini->cri_alg == CRYPTO_SHA1_HMAC)
++ memcpy(ses->hkey, macini->cri_key, blksz);
++ else {
++ /* Load initialization constants(RFC 1321, 3174) */
++ ses->hiv[0] = 0x67452301efcdab89ULL;
++ ses->hiv[1] = 0x98badcfe10325476ULL;
++ ses->hiv[2] = 0xc3d2e1f000000000ULL;
++ }
++ ses->hseq = 0ULL;
++ }
++
++ spin_lock_irqsave(&txring->fill_lock, flags);
++
++ if (((txring->next_to_fill + pasemi_desc_size(&init_desc)) -
++ txring->next_to_clean) > TX_RING_SIZE) {
++ spin_unlock_irqrestore(&txring->fill_lock, flags);
++ return ERESTART;
++ }
++
++ if (encini) {
++ pasemi_ring_add_desc(txring, &init_desc, NULL);
++ pasemi_ring_incr(sc, ses->chan,
++ pasemi_desc_size(&init_desc));
++ }
++
++ txring->sesn = sesn;
++ spin_unlock_irqrestore(&txring->fill_lock, flags);
++
++ *sidp = PASEMI_SID(sesn);
++ return 0;
++}
++
++/*
++ * Deallocate a session.
++ */
++static int
++pasemi_freesession(device_t dev, u_int64_t tid)
++{
++ struct pasemi_softc *sc = device_get_softc(dev);
++ int session;
++ u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ if (sc == NULL)
++ return -EINVAL;
++ session = PASEMI_SESSION(sid);
++ if (session >= sc->sc_nsessions || !sc->sc_sessions[session])
++ return -EINVAL;
++
++ pci_unmap_single(sc->dma_pdev,
++ sc->sc_sessions[session]->dma_addr,
++ sizeof(struct pasemi_session), DMA_TO_DEVICE);
++ memset(sc->sc_sessions[session], 0,
++ sizeof(struct pasemi_session));
++
++ return 0;
++}
++
++static int
++pasemi_process(device_t dev, struct cryptop *crp, int hint)
++{
++
++ int err = 0, ivsize, srclen = 0, reinit = 0, reinit_size = 0, chsel;
++ struct pasemi_softc *sc = device_get_softc(dev);
++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
++ caddr_t ivp;
++ struct pasemi_desc init_desc, work_desc;
++ struct pasemi_session *ses;
++ struct sk_buff *skb;
++ struct uio *uiop;
++ unsigned long flags;
++ struct pasemi_fnu_txring *txring;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ if (crp == NULL || crp->crp_callback == NULL || sc == NULL)
++ return -EINVAL;
++
++ crp->crp_etype = 0;
++ if (PASEMI_SESSION(crp->crp_sid) >= sc->sc_nsessions)
++ return -EINVAL;
++
++ ses = sc->sc_sessions[PASEMI_SESSION(crp->crp_sid)];
++
++ crd1 = crp->crp_desc;
++ if (crd1 == NULL) {
++ err = -EINVAL;
++ goto errout;
++ }
++ crd2 = crd1->crd_next;
++
++ if (ALG_IS_SIG(crd1->crd_alg)) {
++ maccrd = crd1;
++ if (crd2 == NULL)
++ enccrd = NULL;
++ else if (ALG_IS_CIPHER(crd2->crd_alg) &&
++ (crd2->crd_flags & CRD_F_ENCRYPT) == 0)
++ enccrd = crd2;
++ else
++ goto erralg;
++ } else if (ALG_IS_CIPHER(crd1->crd_alg)) {
++ enccrd = crd1;
++ if (crd2 == NULL)
++ maccrd = NULL;
++ else if (ALG_IS_SIG(crd2->crd_alg) &&
++ (crd1->crd_flags & CRD_F_ENCRYPT))
++ maccrd = crd2;
++ else
++ goto erralg;
++ } else
++ goto erralg;
++
++ chsel = ses->chan;
++
++ txring = &sc->tx[chsel];
++
++ if (enccrd && !maccrd) {
++ if (enccrd->crd_alg == CRYPTO_ARC4)
++ reinit = 1;
++ reinit_size = 0x40;
++ srclen = crp->crp_ilen;
++
++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I
++ | XCT_FUN_FUN(chsel));
++ if (enccrd->crd_flags & CRD_F_ENCRYPT)
++ pasemi_desc_hdr(&work_desc, XCT_FUN_CRM_ENC);
++ else
++ pasemi_desc_hdr(&work_desc, XCT_FUN_CRM_DEC);
++ } else if (enccrd && maccrd) {
++ if (enccrd->crd_alg == CRYPTO_ARC4)
++ reinit = 1;
++ reinit_size = 0x68;
++
++ if (enccrd->crd_flags & CRD_F_ENCRYPT) {
++ /* Encrypt -> Authenticate */
++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_ENC_SIG
++ | XCT_FUN_A | XCT_FUN_FUN(chsel));
++ srclen = maccrd->crd_skip + maccrd->crd_len;
++ } else {
++ /* Authenticate -> Decrypt */
++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_SIG_DEC
++ | XCT_FUN_24BRES | XCT_FUN_FUN(chsel));
++ pasemi_desc_build(&work_desc, 0);
++ pasemi_desc_build(&work_desc, 0);
++ pasemi_desc_build(&work_desc, 0);
++ work_desc.postop = PASEMI_CHECK_SIG;
++ srclen = crp->crp_ilen;
++ }
++
++ pasemi_desc_hdr(&work_desc, XCT_FUN_SHL(maccrd->crd_skip / 4));
++ pasemi_desc_hdr(&work_desc, XCT_FUN_CHL(enccrd->crd_skip - maccrd->crd_skip));
++ } else if (!enccrd && maccrd) {
++ srclen = maccrd->crd_len;
++
++ pasemi_desc_start(&init_desc,
++ XCT_CTRL_HDR(chsel, 0x58, DMA_FN_HKEY0));
++ pasemi_desc_build(&init_desc,
++ XCT_FUN_SRC_PTR(0x58, ((struct pasemi_session *)ses->dma_addr)->hkey));
++
++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_SIG
++ | XCT_FUN_A | XCT_FUN_FUN(chsel));
++ }
++
++ if (enccrd) {
++ switch (enccrd->crd_alg) {
++ case CRYPTO_3DES_CBC:
++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_3DES |
++ XCT_FUN_BCM_CBC);
++ ivsize = sizeof(u64);
++ break;
++ case CRYPTO_DES_CBC:
++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_DES |
++ XCT_FUN_BCM_CBC);
++ ivsize = sizeof(u64);
++ break;
++ case CRYPTO_AES_CBC:
++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_AES |
++ XCT_FUN_BCM_CBC);
++ ivsize = 2 * sizeof(u64);
++ break;
++ case CRYPTO_ARC4:
++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_ARC);
++ ivsize = 0;
++ break;
++ default:
++ printk(DRV_NAME ": unimplemented enccrd->crd_alg %d\n",
++ enccrd->crd_alg);
++ err = -EINVAL;
++ goto errout;
++ }
++
++ ivp = (ivsize == sizeof(u64)) ? (caddr_t) &ses->civ[1] : (caddr_t) &ses->civ[0];
++ if (enccrd->crd_flags & CRD_F_ENCRYPT) {
++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++ memcpy(ivp, enccrd->crd_iv, ivsize);
++ /* If IV is not present in the buffer already, it has to be copied there */
++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0)
++ crypto_copyback(crp->crp_flags, crp->crp_buf,
++ enccrd->crd_inject, ivsize, ivp);
++ } else {
++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++ /* IV is provided expicitly in descriptor */
++ memcpy(ivp, enccrd->crd_iv, ivsize);
++ else
++ /* IV is provided in the packet */
++ crypto_copydata(crp->crp_flags, crp->crp_buf,
++ enccrd->crd_inject, ivsize,
++ ivp);
++ }
++ }
++
++ if (maccrd) {
++ switch (maccrd->crd_alg) {
++ case CRYPTO_MD5:
++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_MD5 |
++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4));
++ break;
++ case CRYPTO_SHA1:
++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_SHA1 |
++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4));
++ break;
++ case CRYPTO_MD5_HMAC:
++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_HMAC_MD5 |
++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4));
++ break;
++ case CRYPTO_SHA1_HMAC:
++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_HMAC_SHA1 |
++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4));
++ break;
++ default:
++ printk(DRV_NAME ": unimplemented maccrd->crd_alg %d\n",
++ maccrd->crd_alg);
++ err = -EINVAL;
++ goto errout;
++ }
++ }
++
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ /* using SKB buffers */
++ skb = (struct sk_buff *)crp->crp_buf;
++ if (skb_shinfo(skb)->nr_frags) {
++ printk(DRV_NAME ": skb frags unimplemented\n");
++ err = -EINVAL;
++ goto errout;
++ }
++ pasemi_desc_build(
++ &work_desc,
++ XCT_FUN_DST_PTR(skb->len, pci_map_single(
++ sc->dma_pdev, skb->data,
++ skb->len, DMA_TO_DEVICE)));
++ pasemi_desc_build(
++ &work_desc,
++ XCT_FUN_SRC_PTR(
++ srclen, pci_map_single(
++ sc->dma_pdev, skb->data,
++ srclen, DMA_TO_DEVICE)));
++ pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen));
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ /* using IOV buffers */
++ uiop = (struct uio *)crp->crp_buf;
++ if (uiop->uio_iovcnt > 1) {
++ printk(DRV_NAME ": iov frags unimplemented\n");
++ err = -EINVAL;
++ goto errout;
++ }
++
++ /* crp_olen is never set; always use crp_ilen */
++ pasemi_desc_build(
++ &work_desc,
++ XCT_FUN_DST_PTR(crp->crp_ilen, pci_map_single(
++ sc->dma_pdev,
++ uiop->uio_iov->iov_base,
++ crp->crp_ilen, DMA_TO_DEVICE)));
++ pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen));
++
++ pasemi_desc_build(
++ &work_desc,
++ XCT_FUN_SRC_PTR(srclen, pci_map_single(
++ sc->dma_pdev,
++ uiop->uio_iov->iov_base,
++ srclen, DMA_TO_DEVICE)));
++ } else {
++ /* using contig buffers */
++ pasemi_desc_build(
++ &work_desc,
++ XCT_FUN_DST_PTR(crp->crp_ilen, pci_map_single(
++ sc->dma_pdev,
++ crp->crp_buf,
++ crp->crp_ilen, DMA_TO_DEVICE)));
++ pasemi_desc_build(
++ &work_desc,
++ XCT_FUN_SRC_PTR(srclen, pci_map_single(
++ sc->dma_pdev,
++ crp->crp_buf, srclen,
++ DMA_TO_DEVICE)));
++ pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen));
++ }
++
++ spin_lock_irqsave(&txring->fill_lock, flags);
++
++ if (txring->sesn != PASEMI_SESSION(crp->crp_sid)) {
++ txring->sesn = PASEMI_SESSION(crp->crp_sid);
++ reinit = 1;
++ }
++
++ if (enccrd) {
++ pasemi_desc_start(&init_desc,
++ XCT_CTRL_HDR(chsel, reinit ? reinit_size : 0x10, DMA_FN_CIV0));
++ pasemi_desc_build(&init_desc,
++ XCT_FUN_SRC_PTR(reinit ? reinit_size : 0x10, ses->dma_addr));
++ }
++
++ if (((txring->next_to_fill + pasemi_desc_size(&init_desc) +
++ pasemi_desc_size(&work_desc)) -
++ txring->next_to_clean) > TX_RING_SIZE) {
++ spin_unlock_irqrestore(&txring->fill_lock, flags);
++ err = ERESTART;
++ goto errout;
++ }
++
++ pasemi_ring_add_desc(txring, &init_desc, NULL);
++ pasemi_ring_add_desc(txring, &work_desc, crp);
++
++ pasemi_ring_incr(sc, chsel,
++ pasemi_desc_size(&init_desc) +
++ pasemi_desc_size(&work_desc));
++
++ spin_unlock_irqrestore(&txring->fill_lock, flags);
++
++ mod_timer(&txring->crypto_timer, jiffies + TIMER_INTERVAL);
++
++ return 0;
++
++erralg:
++ printk(DRV_NAME ": unsupported algorithm or algorithm order alg1 %d alg2 %d\n",
++ crd1->crd_alg, crd2->crd_alg);
++ err = -EINVAL;
++
++errout:
++ if (err != ERESTART) {
++ crp->crp_etype = err;
++ crypto_done(crp);
++ }
++ return err;
++}
++
++static int pasemi_clean_tx(struct pasemi_softc *sc, int chan)
++{
++ int i, j, ring_idx;
++ struct pasemi_fnu_txring *ring = &sc->tx[chan];
++ u16 delta_cnt;
++ int flags, loops = 10;
++ int desc_size;
++ struct cryptop *crp;
++
++ spin_lock_irqsave(&ring->clean_lock, flags);
++
++ while ((delta_cnt = (dma_status->tx_sta[sc->base_chan + chan]
++ & PAS_STATUS_PCNT_M) - ring->total_pktcnt)
++ && loops--) {
++
++ for (i = 0; i < delta_cnt; i++) {
++ desc_size = TX_DESC_INFO(ring, ring->next_to_clean).desc_size;
++ crp = TX_DESC_INFO(ring, ring->next_to_clean).cf_crp;
++ if (crp) {
++ ring_idx = 2 * (ring->next_to_clean & (TX_RING_SIZE-1));
++ if (TX_DESC_INFO(ring, ring->next_to_clean).desc_postop & PASEMI_CHECK_SIG) {
++ /* Need to make sure signature matched,
++ * if not - return error */
++ if (!(ring->desc[ring_idx + 1] & (1ULL << 63)))
++ crp->crp_etype = -EINVAL;
++ }
++ crypto_done(TX_DESC_INFO(ring,
++ ring->next_to_clean).cf_crp);
++ TX_DESC_INFO(ring, ring->next_to_clean).cf_crp = NULL;
++ pci_unmap_single(
++ sc->dma_pdev,
++ XCT_PTR_ADDR_LEN(ring->desc[ring_idx + 1]),
++ PCI_DMA_TODEVICE);
++
++ ring->desc[ring_idx] = ring->desc[ring_idx + 1] = 0;
++
++ ring->next_to_clean++;
++ for (j = 1; j < desc_size; j++) {
++ ring_idx = 2 *
++ (ring->next_to_clean &
++ (TX_RING_SIZE-1));
++ pci_unmap_single(
++ sc->dma_pdev,
++ XCT_PTR_ADDR_LEN(ring->desc[ring_idx]),
++ PCI_DMA_TODEVICE);
++ if (ring->desc[ring_idx + 1])
++ pci_unmap_single(
++ sc->dma_pdev,
++ XCT_PTR_ADDR_LEN(
++ ring->desc[
++ ring_idx + 1]),
++ PCI_DMA_TODEVICE);
++ ring->desc[ring_idx] =
++ ring->desc[ring_idx + 1] = 0;
++ ring->next_to_clean++;
++ }
++ } else {
++ for (j = 0; j < desc_size; j++) {
++ ring_idx = 2 * (ring->next_to_clean & (TX_RING_SIZE-1));
++ ring->desc[ring_idx] =
++ ring->desc[ring_idx + 1] = 0;
++ ring->next_to_clean++;
++ }
++ }
++ }
++
++ ring->total_pktcnt += delta_cnt;
++ }
++ spin_unlock_irqrestore(&ring->clean_lock, flags);
++
++ return 0;
++}
++
++static void sweepup_tx(struct pasemi_softc *sc)
++{
++ int i;
++
++ for (i = 0; i < sc->sc_num_channels; i++)
++ pasemi_clean_tx(sc, i);
++}
++
++static irqreturn_t pasemi_intr(int irq, void *arg, struct pt_regs *regs)
++{
++ struct pasemi_softc *sc = arg;
++ unsigned int reg;
++ int chan = irq - sc->base_irq;
++ int chan_index = sc->base_chan + chan;
++ u64 stat = dma_status->tx_sta[chan_index];
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ if (!(stat & PAS_STATUS_CAUSE_M))
++ return IRQ_NONE;
++
++ pasemi_clean_tx(sc, chan);
++
++ stat = dma_status->tx_sta[chan_index];
++
++ reg = PAS_IOB_DMA_TXCH_RESET_PINTC |
++ PAS_IOB_DMA_TXCH_RESET_PCNT(sc->tx[chan].total_pktcnt);
++
++ if (stat & PAS_STATUS_SOFT)
++ reg |= PAS_IOB_DMA_RXCH_RESET_SINTC;
++
++ out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_RESET(chan_index), reg);
++
++
++ return IRQ_HANDLED;
++}
++
++static int pasemi_dma_setup_tx_resources(struct pasemi_softc *sc, int chan)
++{
++ u32 val;
++ int chan_index = chan + sc->base_chan;
++ int ret;
++ struct pasemi_fnu_txring *ring;
++
++ ring = &sc->tx[chan];
++
++ spin_lock_init(&ring->fill_lock);
++ spin_lock_init(&ring->clean_lock);
++
++ ring->desc_info = kzalloc(sizeof(struct pasemi_desc_info) *
++ TX_RING_SIZE, GFP_KERNEL);
++ if (!ring->desc_info)
++ return -ENOMEM;
++
++ /* Allocate descriptors */
++ ring->desc = dma_alloc_coherent(&sc->dma_pdev->dev,
++ TX_RING_SIZE *
++ 2 * sizeof(u64),
++ &ring->dma, GFP_KERNEL);
++ if (!ring->desc)
++ return -ENOMEM;
++
++ memset((void *) ring->desc, 0, TX_RING_SIZE * 2 * sizeof(u64));
++
++ out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_RESET(chan_index), 0x30);
++
++ ring->total_pktcnt = 0;
++
++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEL(chan_index),
++ PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
++
++ val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
++ val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2);
++
++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEU(chan_index), val);
++
++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_CFG(chan_index),
++ PAS_DMA_TXCHAN_CFG_TY_FUNC |
++ PAS_DMA_TXCHAN_CFG_TATTR(chan) |
++ PAS_DMA_TXCHAN_CFG_WT(2));
++
++ /* enable tx channel */
++ out_le32(sc->dma_regs +
++ PAS_DMA_TXCHAN_TCMDSTA(chan_index),
++ PAS_DMA_TXCHAN_TCMDSTA_EN);
++
++ out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_CFG(chan_index),
++ PAS_IOB_DMA_TXCH_CFG_CNTTH(1000));
++
++ ring->next_to_fill = 0;
++ ring->next_to_clean = 0;
++
++ snprintf(ring->irq_name, sizeof(ring->irq_name),
++ "%s%d", "crypto", chan);
++
++ ring->irq = irq_create_mapping(NULL, sc->base_irq + chan);
++ ret = request_irq(ring->irq, (irq_handler_t)
++ pasemi_intr, IRQF_DISABLED, ring->irq_name, sc);
++ if (ret) {
++ printk(KERN_ERR DRV_NAME ": failed to hook irq %d ret %d\n",
++ ring->irq, ret);
++ ring->irq = -1;
++ return ret;
++ }
++
++ setup_timer(&ring->crypto_timer, (void *) sweepup_tx, (unsigned long) sc);
++
++ return 0;
++}
++
++static device_method_t pasemi_methods = {
++ /* crypto device methods */
++ DEVMETHOD(cryptodev_newsession, pasemi_newsession),
++ DEVMETHOD(cryptodev_freesession, pasemi_freesession),
++ DEVMETHOD(cryptodev_process, pasemi_process),
++};
++
++/* Set up the crypto device structure, private data,
++ * and anything else we need before we start */
++
++static int __devinit
++pasemi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++ struct pasemi_softc *sc;
++ int ret, i;
++
++ DPRINTF(KERN_ERR "%s()\n", __FUNCTION__);
++
++ sc = kzalloc(sizeof(*sc), GFP_KERNEL);
++ if (!sc)
++ return -ENOMEM;
++
++ softc_device_init(sc, DRV_NAME, 1, pasemi_methods);
++
++ pci_set_drvdata(pdev, sc);
++
++ spin_lock_init(&sc->sc_chnlock);
++
++ sc->sc_sessions = (struct pasemi_session **)
++ kzalloc(PASEMI_INITIAL_SESSIONS *
++ sizeof(struct pasemi_session *), GFP_ATOMIC);
++ if (sc->sc_sessions == NULL) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ sc->sc_nsessions = PASEMI_INITIAL_SESSIONS;
++ sc->sc_lastchn = 0;
++ sc->base_irq = pdev->irq + 6;
++ sc->base_chan = 6;
++ sc->sc_cid = -1;
++ sc->dma_pdev = pdev;
++
++ sc->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
++ if (!sc->iob_pdev) {
++ dev_err(&pdev->dev, "Can't find I/O Bridge\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ /* This is hardcoded and ugly, but we have some firmware versions
++ * who don't provide the register space in the device tree. Luckily
++ * they are at well-known locations so we can just do the math here.
++ */
++ sc->dma_regs =
++ ioremap(0xe0000000 + (sc->dma_pdev->devfn << 12), 0x2000);
++ sc->iob_regs =
++ ioremap(0xe0000000 + (sc->iob_pdev->devfn << 12), 0x2000);
++ if (!sc->dma_regs || !sc->iob_regs) {
++ dev_err(&pdev->dev, "Can't map registers\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dma_status = __ioremap(0xfd800000, 0x1000, 0);
++ if (!dma_status) {
++ ret = -ENODEV;
++ dev_err(&pdev->dev, "Can't map dmastatus space\n");
++ goto out;
++ }
++
++ sc->tx = (struct pasemi_fnu_txring *)
++ kzalloc(sizeof(struct pasemi_fnu_txring)
++ * 8, GFP_KERNEL);
++ if (!sc->tx) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ /* Initialize the h/w */
++ out_le32(sc->dma_regs + PAS_DMA_COM_CFG,
++ (in_le32(sc->dma_regs + PAS_DMA_COM_CFG) |
++ PAS_DMA_COM_CFG_FWF));
++ out_le32(sc->dma_regs + PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN);
++
++ for (i = 0; i < PASEMI_FNU_CHANNELS; i++) {
++ sc->sc_num_channels++;
++ ret = pasemi_dma_setup_tx_resources(sc, i);
++ if (ret)
++ goto out;
++ }
++
++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc),
++ CRYPTOCAP_F_HARDWARE);
++ if (sc->sc_cid < 0) {
++ printk(KERN_ERR DRV_NAME ": could not get crypto driver id\n");
++ ret = -ENXIO;
++ goto out;
++ }
++
++ /* register algorithms with the framework */
++ printk(DRV_NAME ":");
++
++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
++
++ return 0;
++
++out:
++ pasemi_dma_remove(pdev);
++ return ret;
++}
++
++#define MAX_RETRIES 5000
++
++static void pasemi_free_tx_resources(struct pasemi_softc *sc, int chan)
++{
++ struct pasemi_fnu_txring *ring = &sc->tx[chan];
++ int chan_index = chan + sc->base_chan;
++ int retries;
++ u32 stat;
++
++ /* Stop the channel */
++ out_le32(sc->dma_regs +
++ PAS_DMA_TXCHAN_TCMDSTA(chan_index),
++ PAS_DMA_TXCHAN_TCMDSTA_ST);
++
++ for (retries = 0; retries < MAX_RETRIES; retries++) {
++ stat = in_le32(sc->dma_regs +
++ PAS_DMA_TXCHAN_TCMDSTA(chan_index));
++ if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT))
++ break;
++ cond_resched();
++ }
++
++ if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
++ dev_err(&sc->dma_pdev->dev, "Failed to stop tx channel %d\n",
++ chan_index);
++
++ /* Disable the channel */
++ out_le32(sc->dma_regs +
++ PAS_DMA_TXCHAN_TCMDSTA(chan_index),
++ 0);
++
++ if (ring->desc_info)
++ kfree((void *) ring->desc_info);
++ if (ring->desc)
++ dma_free_coherent(&sc->dma_pdev->dev,
++ TX_RING_SIZE *
++ 2 * sizeof(u64),
++ (void *) ring->desc, ring->dma);
++ if (ring->irq != -1)
++ free_irq(ring->irq, sc);
++
++ del_timer(&ring->crypto_timer);
++}
++
++static void __devexit pasemi_dma_remove(struct pci_dev *pdev)
++{
++ struct pasemi_softc *sc = pci_get_drvdata(pdev);
++ int i;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ if (sc->sc_cid >= 0) {
++ crypto_unregister_all(sc->sc_cid);
++ }
++
++ if (sc->tx) {
++ for (i = 0; i < sc->sc_num_channels; i++)
++ pasemi_free_tx_resources(sc, i);
++
++ kfree(sc->tx);
++ }
++ if (sc->sc_sessions) {
++ for (i = 0; i < sc->sc_nsessions; i++)
++ kfree(sc->sc_sessions[i]);
++ kfree(sc->sc_sessions);
++ }
++ if (sc->iob_pdev)
++ pci_dev_put(sc->iob_pdev);
++ if (sc->dma_regs)
++ iounmap(sc->dma_regs);
++ if (sc->iob_regs)
++ iounmap(sc->iob_regs);
++ kfree(sc);
++}
++
++static struct pci_device_id pasemi_dma_pci_tbl[] = {
++ { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa007) },
++};
++
++MODULE_DEVICE_TABLE(pci, pasemi_dma_pci_tbl);
++
++static struct pci_driver pasemi_dma_driver = {
++ .name = "pasemi_dma",
++ .id_table = pasemi_dma_pci_tbl,
++ .probe = pasemi_dma_probe,
++ .remove = __devexit_p(pasemi_dma_remove),
++};
++
++static void __exit pasemi_dma_cleanup_module(void)
++{
++ pci_unregister_driver(&pasemi_dma_driver);
++ __iounmap(dma_status);
++ dma_status = NULL;
++}
++
++int pasemi_dma_init_module(void)
++{
++ return pci_register_driver(&pasemi_dma_driver);
++}
++
++module_init(pasemi_dma_init_module);
++module_exit(pasemi_dma_cleanup_module);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("Egor Martovetsky egor@pasemi.com");
++MODULE_DESCRIPTION("OCF driver for PA Semi PWRficient DMA Crypto Engine");
+diff -Nur linux-2.6.36.orig/crypto/ocf/pasemi/pasemi_fnu.h linux-2.6.36/crypto/ocf/pasemi/pasemi_fnu.h
+--- linux-2.6.36.orig/crypto/ocf/pasemi/pasemi_fnu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/pasemi/pasemi_fnu.h 2010-11-09 20:28:12.612495424 +0100
+@@ -0,0 +1,410 @@
++/*
++ * Copyright (C) 2007 PA Semi, Inc
++ *
++ * Driver for the PA Semi PWRficient DMA Crypto Engine, soft state and
++ * hardware register layouts.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef PASEMI_FNU_H
++#define PASEMI_FNU_H
++
++#include <linux/spinlock.h>
++
++#define PASEMI_SESSION(sid) ((sid) & 0xffffffff)
++#define PASEMI_SID(sesn) ((sesn) & 0xffffffff)
++#define DPRINTF(a...) if (debug) { printk(DRV_NAME ": " a); }
++
++/* Must be a power of two */
++#define RX_RING_SIZE 512
++#define TX_RING_SIZE 512
++#define TX_DESC(ring, num) ((ring)->desc[2 * (num & (TX_RING_SIZE-1))])
++#define TX_DESC_INFO(ring, num) ((ring)->desc_info[(num) & (TX_RING_SIZE-1)])
++#define MAX_DESC_SIZE 8
++#define PASEMI_INITIAL_SESSIONS 10
++#define PASEMI_FNU_CHANNELS 8
++
++/* DMA descriptor */
++struct pasemi_desc {
++ u64 quad[2*MAX_DESC_SIZE];
++ int quad_cnt;
++ int size;
++ int postop;
++};
++
++/*
++ * Holds per descriptor data
++ */
++struct pasemi_desc_info {
++ int desc_size;
++ int desc_postop;
++#define PASEMI_CHECK_SIG 0x1
++
++ struct cryptop *cf_crp;
++};
++
++/*
++ * Holds per channel data
++ */
++struct pasemi_fnu_txring {
++ volatile u64 *desc;
++ volatile struct
++ pasemi_desc_info *desc_info;
++ dma_addr_t dma;
++ struct timer_list crypto_timer;
++ spinlock_t fill_lock;
++ spinlock_t clean_lock;
++ unsigned int next_to_fill;
++ unsigned int next_to_clean;
++ u16 total_pktcnt;
++ int irq;
++ int sesn;
++ char irq_name[10];
++};
++
++/*
++ * Holds data specific to a single pasemi device.
++ */
++struct pasemi_softc {
++ softc_device_decl sc_cdev;
++ struct pci_dev *dma_pdev; /* device backpointer */
++ struct pci_dev *iob_pdev; /* device backpointer */
++ void __iomem *dma_regs;
++ void __iomem *iob_regs;
++ int base_irq;
++ int base_chan;
++ int32_t sc_cid; /* crypto tag */
++ int sc_nsessions;
++ struct pasemi_session **sc_sessions;
++ int sc_num_channels;/* number of crypto channels */
++
++ /* pointer to the array of txring datastructures, one txring per channel */
++ struct pasemi_fnu_txring *tx;
++
++ /*
++ * mutual exclusion for the channel scheduler
++ */
++ spinlock_t sc_chnlock;
++ /* last channel used, for now use round-robin to allocate channels */
++ int sc_lastchn;
++};
++
++struct pasemi_session {
++ u64 civ[2];
++ u64 keysz;
++ u64 key[4];
++ u64 ccmd;
++ u64 hkey[4];
++ u64 hseq;
++ u64 giv[2];
++ u64 hiv[4];
++
++ int used;
++ dma_addr_t dma_addr;
++ int chan;
++};
++
++/* status register layout in IOB region, at 0xfd800000 */
++struct pasdma_status {
++ u64 rx_sta[64];
++ u64 tx_sta[20];
++};
++
++#define ALG_IS_CIPHER(alg) ((alg == CRYPTO_DES_CBC) || \
++ (alg == CRYPTO_3DES_CBC) || \
++ (alg == CRYPTO_AES_CBC) || \
++ (alg == CRYPTO_ARC4) || \
++ (alg == CRYPTO_NULL_CBC))
++
++#define ALG_IS_SIG(alg) ((alg == CRYPTO_MD5) || \
++ (alg == CRYPTO_MD5_HMAC) || \
++ (alg == CRYPTO_SHA1) || \
++ (alg == CRYPTO_SHA1_HMAC) || \
++ (alg == CRYPTO_NULL_HMAC))
++
++enum {
++ PAS_DMA_COM_TXCMD = 0x100, /* Transmit Command Register */
++ PAS_DMA_COM_TXSTA = 0x104, /* Transmit Status Register */
++ PAS_DMA_COM_RXCMD = 0x108, /* Receive Command Register */
++ PAS_DMA_COM_RXSTA = 0x10c, /* Receive Status Register */
++ PAS_DMA_COM_CFG = 0x114, /* DMA Configuration Register */
++};
++
++/* All these registers live in the PCI configuration space for the DMA PCI
++ * device. Use the normal PCI config access functions for them.
++ */
++
++#define PAS_DMA_COM_CFG_FWF 0x18000000
++
++#define PAS_DMA_COM_TXCMD_EN 0x00000001 /* enable */
++#define PAS_DMA_COM_TXSTA_ACT 0x00000001 /* active */
++#define PAS_DMA_COM_RXCMD_EN 0x00000001 /* enable */
++#define PAS_DMA_COM_RXSTA_ACT 0x00000001 /* active */
++
++#define _PAS_DMA_TXCHAN_STRIDE 0x20 /* Size per channel */
++#define _PAS_DMA_TXCHAN_TCMDSTA 0x300 /* Command / Status */
++#define _PAS_DMA_TXCHAN_CFG 0x304 /* Configuration */
++#define _PAS_DMA_TXCHAN_DSCRBU 0x308 /* Descriptor BU Allocation */
++#define _PAS_DMA_TXCHAN_INCR 0x310 /* Descriptor increment */
++#define _PAS_DMA_TXCHAN_CNT 0x314 /* Descriptor count/offset */
++#define _PAS_DMA_TXCHAN_BASEL 0x318 /* Descriptor ring base (low) */
++#define _PAS_DMA_TXCHAN_BASEU 0x31c /* (high) */
++#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE)
++#define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */
++#define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */
++#define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */
++#define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
++#define PAS_DMA_TXCHAN_CFG_TY_FUNC 0x00000002 /* Type = interface */
++#define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */
++#define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c
++#define PAS_DMA_TXCHAN_CFG_TATTR_S 2
++#define PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \
++ PAS_DMA_TXCHAN_CFG_TATTR_M)
++#define PAS_DMA_TXCHAN_CFG_WT_M 0x000001c0
++#define PAS_DMA_TXCHAN_CFG_WT_S 6
++#define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
++ PAS_DMA_TXCHAN_CFG_WT_M)
++#define PAS_DMA_TXCHAN_CFG_LPSQ_FAST 0x00000400
++#define PAS_DMA_TXCHAN_CFG_LPDQ_FAST 0x00000800
++#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */
++#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */
++#define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */
++#define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
++#define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
++#define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0
++#define PAS_DMA_TXCHAN_BASEL_BRBL_S 0
++#define PAS_DMA_TXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \
++ PAS_DMA_TXCHAN_BASEL_BRBL_M)
++#define PAS_DMA_TXCHAN_BASEU(c) (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE)
++#define PAS_DMA_TXCHAN_BASEU_BRBH_M 0x00000fff
++#define PAS_DMA_TXCHAN_BASEU_BRBH_S 0
++#define PAS_DMA_TXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \
++ PAS_DMA_TXCHAN_BASEU_BRBH_M)
++/* # of cache lines worth of buffer ring */
++#define PAS_DMA_TXCHAN_BASEU_SIZ_M 0x3fff0000
++#define PAS_DMA_TXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */
++#define PAS_DMA_TXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \
++ PAS_DMA_TXCHAN_BASEU_SIZ_M)
++
++#define PAS_STATUS_PCNT_M 0x000000000000ffffull
++#define PAS_STATUS_PCNT_S 0
++#define PAS_STATUS_DCNT_M 0x00000000ffff0000ull
++#define PAS_STATUS_DCNT_S 16
++#define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull
++#define PAS_STATUS_BPCNT_S 32
++#define PAS_STATUS_CAUSE_M 0xf000000000000000ull
++#define PAS_STATUS_TIMER 0x1000000000000000ull
++#define PAS_STATUS_ERROR 0x2000000000000000ull
++#define PAS_STATUS_SOFT 0x4000000000000000ull
++#define PAS_STATUS_INT 0x8000000000000000ull
++
++#define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4)
++#define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff
++#define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0
++#define PAS_IOB_DMA_RXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \
++ PAS_IOB_DMA_RXCH_CFG_CNTTH_M)
++#define PAS_IOB_DMA_TXCH_CFG(i) (0x1200 + (i)*4)
++#define PAS_IOB_DMA_TXCH_CFG_CNTTH_M 0x00000fff
++#define PAS_IOB_DMA_TXCH_CFG_CNTTH_S 0
++#define PAS_IOB_DMA_TXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \
++ PAS_IOB_DMA_TXCH_CFG_CNTTH_M)
++#define PAS_IOB_DMA_RXCH_STAT(i) (0x1300 + (i)*4)
++#define PAS_IOB_DMA_RXCH_STAT_INTGEN 0x00001000
++#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_M 0x00000fff
++#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_S 0
++#define PAS_IOB_DMA_RXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\
++ PAS_IOB_DMA_RXCH_STAT_CNTDEL_M)
++#define PAS_IOB_DMA_TXCH_STAT(i) (0x1400 + (i)*4)
++#define PAS_IOB_DMA_TXCH_STAT_INTGEN 0x00001000
++#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_M 0x00000fff
++#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_S 0
++#define PAS_IOB_DMA_TXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\
++ PAS_IOB_DMA_TXCH_STAT_CNTDEL_M)
++#define PAS_IOB_DMA_RXCH_RESET(i) (0x1500 + (i)*4)
++#define PAS_IOB_DMA_RXCH_RESET_PCNT_M 0xffff0000
++#define PAS_IOB_DMA_RXCH_RESET_PCNT_S 16
++#define PAS_IOB_DMA_RXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \
++ PAS_IOB_DMA_RXCH_RESET_PCNT_M)
++#define PAS_IOB_DMA_RXCH_RESET_PCNTRST 0x00000020
++#define PAS_IOB_DMA_RXCH_RESET_DCNTRST 0x00000010
++#define PAS_IOB_DMA_RXCH_RESET_TINTC 0x00000008
++#define PAS_IOB_DMA_RXCH_RESET_DINTC 0x00000004
++#define PAS_IOB_DMA_RXCH_RESET_SINTC 0x00000002
++#define PAS_IOB_DMA_RXCH_RESET_PINTC 0x00000001
++#define PAS_IOB_DMA_TXCH_RESET(i) (0x1600 + (i)*4)
++#define PAS_IOB_DMA_TXCH_RESET_PCNT_M 0xffff0000
++#define PAS_IOB_DMA_TXCH_RESET_PCNT_S 16
++#define PAS_IOB_DMA_TXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \
++ PAS_IOB_DMA_TXCH_RESET_PCNT_M)
++#define PAS_IOB_DMA_TXCH_RESET_PCNTRST 0x00000020
++#define PAS_IOB_DMA_TXCH_RESET_DCNTRST 0x00000010
++#define PAS_IOB_DMA_TXCH_RESET_TINTC 0x00000008
++#define PAS_IOB_DMA_TXCH_RESET_DINTC 0x00000004
++#define PAS_IOB_DMA_TXCH_RESET_SINTC 0x00000002
++#define PAS_IOB_DMA_TXCH_RESET_PINTC 0x00000001
++
++#define PAS_IOB_DMA_COM_TIMEOUTCFG 0x1700
++#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M 0x00ffffff
++#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S 0
++#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x) (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \
++ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M)
++
++/* Transmit descriptor fields */
++#define XCT_MACTX_T 0x8000000000000000ull
++#define XCT_MACTX_ST 0x4000000000000000ull
++#define XCT_MACTX_NORES 0x0000000000000000ull
++#define XCT_MACTX_8BRES 0x1000000000000000ull
++#define XCT_MACTX_24BRES 0x2000000000000000ull
++#define XCT_MACTX_40BRES 0x3000000000000000ull
++#define XCT_MACTX_I 0x0800000000000000ull
++#define XCT_MACTX_O 0x0400000000000000ull
++#define XCT_MACTX_E 0x0200000000000000ull
++#define XCT_MACTX_VLAN_M 0x0180000000000000ull
++#define XCT_MACTX_VLAN_NOP 0x0000000000000000ull
++#define XCT_MACTX_VLAN_REMOVE 0x0080000000000000ull
++#define XCT_MACTX_VLAN_INSERT 0x0100000000000000ull
++#define XCT_MACTX_VLAN_REPLACE 0x0180000000000000ull
++#define XCT_MACTX_CRC_M 0x0060000000000000ull
++#define XCT_MACTX_CRC_NOP 0x0000000000000000ull
++#define XCT_MACTX_CRC_INSERT 0x0020000000000000ull
++#define XCT_MACTX_CRC_PAD 0x0040000000000000ull
++#define XCT_MACTX_CRC_REPLACE 0x0060000000000000ull
++#define XCT_MACTX_SS 0x0010000000000000ull
++#define XCT_MACTX_LLEN_M 0x00007fff00000000ull
++#define XCT_MACTX_LLEN_S 32ull
++#define XCT_MACTX_LLEN(x) ((((long)(x)) << XCT_MACTX_LLEN_S) & \
++ XCT_MACTX_LLEN_M)
++#define XCT_MACTX_IPH_M 0x00000000f8000000ull
++#define XCT_MACTX_IPH_S 27ull
++#define XCT_MACTX_IPH(x) ((((long)(x)) << XCT_MACTX_IPH_S) & \
++ XCT_MACTX_IPH_M)
++#define XCT_MACTX_IPO_M 0x0000000007c00000ull
++#define XCT_MACTX_IPO_S 22ull
++#define XCT_MACTX_IPO(x) ((((long)(x)) << XCT_MACTX_IPO_S) & \
++ XCT_MACTX_IPO_M)
++#define XCT_MACTX_CSUM_M 0x0000000000000060ull
++#define XCT_MACTX_CSUM_NOP 0x0000000000000000ull
++#define XCT_MACTX_CSUM_TCP 0x0000000000000040ull
++#define XCT_MACTX_CSUM_UDP 0x0000000000000060ull
++#define XCT_MACTX_V6 0x0000000000000010ull
++#define XCT_MACTX_C 0x0000000000000004ull
++#define XCT_MACTX_AL2 0x0000000000000002ull
++
++#define XCT_PTR_T 0x8000000000000000ull
++#define XCT_PTR_LEN_M 0x7ffff00000000000ull
++#define XCT_PTR_LEN_S 44
++#define XCT_PTR_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & \
++ XCT_PTR_LEN_M)
++#define XCT_PTR_ADDR_M 0x00000fffffffffffull
++#define XCT_PTR_ADDR_S 0
++#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \
++ XCT_PTR_ADDR_M)
++
++/* Function descriptor fields */
++#define XCT_FUN_T 0x8000000000000000ull
++#define XCT_FUN_ST 0x4000000000000000ull
++#define XCT_FUN_NORES 0x0000000000000000ull
++#define XCT_FUN_8BRES 0x1000000000000000ull
++#define XCT_FUN_24BRES 0x2000000000000000ull
++#define XCT_FUN_40BRES 0x3000000000000000ull
++#define XCT_FUN_I 0x0800000000000000ull
++#define XCT_FUN_O 0x0400000000000000ull
++#define XCT_FUN_E 0x0200000000000000ull
++#define XCT_FUN_FUN_S 54
++#define XCT_FUN_FUN_M 0x01c0000000000000ull
++#define XCT_FUN_FUN(num) ((((long)(num)) << XCT_FUN_FUN_S) & \
++ XCT_FUN_FUN_M)
++#define XCT_FUN_CRM_NOP 0x0000000000000000ull
++#define XCT_FUN_CRM_SIG 0x0008000000000000ull
++#define XCT_FUN_CRM_ENC 0x0010000000000000ull
++#define XCT_FUN_CRM_DEC 0x0018000000000000ull
++#define XCT_FUN_CRM_SIG_ENC 0x0020000000000000ull
++#define XCT_FUN_CRM_ENC_SIG 0x0028000000000000ull
++#define XCT_FUN_CRM_SIG_DEC 0x0030000000000000ull
++#define XCT_FUN_CRM_DEC_SIG 0x0038000000000000ull
++#define XCT_FUN_LLEN_M 0x0007ffff00000000ull
++#define XCT_FUN_LLEN_S 32ULL
++#define XCT_FUN_LLEN(x) ((((long)(x)) << XCT_FUN_LLEN_S) & \
++ XCT_FUN_LLEN_M)
++#define XCT_FUN_SHL_M 0x00000000f8000000ull
++#define XCT_FUN_SHL_S 27ull
++#define XCT_FUN_SHL(x) ((((long)(x)) << XCT_FUN_SHL_S) & \
++ XCT_FUN_SHL_M)
++#define XCT_FUN_CHL_M 0x0000000007c00000ull
++#define XCT_FUN_CHL_S 22ull
++#define XCT_FUN_CHL(x) ((((long)(x)) << XCT_FUN_CHL_S) & \
++ XCT_FUN_CHL_M)
++#define XCT_FUN_HSZ_M 0x00000000003c0000ull
++#define XCT_FUN_HSZ_S 18ull
++#define XCT_FUN_HSZ(x) ((((long)(x)) << XCT_FUN_HSZ_S) & \
++ XCT_FUN_HSZ_M)
++#define XCT_FUN_ALG_DES 0x0000000000000000ull
++#define XCT_FUN_ALG_3DES 0x0000000000008000ull
++#define XCT_FUN_ALG_AES 0x0000000000010000ull
++#define XCT_FUN_ALG_ARC 0x0000000000018000ull
++#define XCT_FUN_ALG_KASUMI 0x0000000000020000ull
++#define XCT_FUN_BCM_ECB 0x0000000000000000ull
++#define XCT_FUN_BCM_CBC 0x0000000000001000ull
++#define XCT_FUN_BCM_CFB 0x0000000000002000ull
++#define XCT_FUN_BCM_OFB 0x0000000000003000ull
++#define XCT_FUN_BCM_CNT 0x0000000000003800ull
++#define XCT_FUN_BCM_KAS_F8 0x0000000000002800ull
++#define XCT_FUN_BCM_KAS_F9 0x0000000000001800ull
++#define XCT_FUN_BCP_NO_PAD 0x0000000000000000ull
++#define XCT_FUN_BCP_ZRO 0x0000000000000200ull
++#define XCT_FUN_BCP_PL 0x0000000000000400ull
++#define XCT_FUN_BCP_INCR 0x0000000000000600ull
++#define XCT_FUN_SIG_MD5 (0ull << 4)
++#define XCT_FUN_SIG_SHA1 (2ull << 4)
++#define XCT_FUN_SIG_HMAC_MD5 (8ull << 4)
++#define XCT_FUN_SIG_HMAC_SHA1 (10ull << 4)
++#define XCT_FUN_A 0x0000000000000008ull
++#define XCT_FUN_C 0x0000000000000004ull
++#define XCT_FUN_AL2 0x0000000000000002ull
++#define XCT_FUN_SE 0x0000000000000001ull
++
++#define XCT_FUN_SRC_PTR(len, addr) (XCT_PTR_LEN(len) | XCT_PTR_ADDR(addr))
++#define XCT_FUN_DST_PTR(len, addr) (XCT_FUN_SRC_PTR(len, addr) | \
++ 0x8000000000000000ull)
++
++#define XCT_CTRL_HDR_FUN_NUM_M 0x01c0000000000000ull
++#define XCT_CTRL_HDR_FUN_NUM_S 54
++#define XCT_CTRL_HDR_LEN_M 0x0007ffff00000000ull
++#define XCT_CTRL_HDR_LEN_S 32
++#define XCT_CTRL_HDR_REG_M 0x00000000000000ffull
++#define XCT_CTRL_HDR_REG_S 0
++
++#define XCT_CTRL_HDR(funcN,len,reg) (0x9400000000000000ull | \
++ ((((long)(funcN)) << XCT_CTRL_HDR_FUN_NUM_S) \
++ & XCT_CTRL_HDR_FUN_NUM_M) | \
++ ((((long)(len)) << \
++ XCT_CTRL_HDR_LEN_S) & XCT_CTRL_HDR_LEN_M) | \
++ ((((long)(reg)) << \
++ XCT_CTRL_HDR_REG_S) & XCT_CTRL_HDR_REG_M))
++
++/* Function config command options */
++#define DMA_CALGO_DES 0x00
++#define DMA_CALGO_3DES 0x01
++#define DMA_CALGO_AES 0x02
++#define DMA_CALGO_ARC 0x03
++
++#define DMA_FN_CIV0 0x02
++#define DMA_FN_CIV1 0x03
++#define DMA_FN_HKEY0 0x0a
++
++#define XCT_PTR_ADDR_LEN(ptr) ((ptr) & XCT_PTR_ADDR_M), \
++ (((ptr) & XCT_PTR_LEN_M) >> XCT_PTR_LEN_S)
++
++#endif /* PASEMI_FNU_H */
+diff -Nur linux-2.6.36.orig/crypto/ocf/random.c linux-2.6.36/crypto/ocf/random.c
+--- linux-2.6.36.orig/crypto/ocf/random.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/random.c 2010-11-09 20:28:12.652495434 +0100
+@@ -0,0 +1,322 @@
++/*
++ * A system independant way of adding entropy to the kernels pool
++ * this way the drivers can focus on the real work and we can take
++ * care of pushing it to the appropriate place in the kernel.
++ *
++ * This should be fast and callable from timers/interrupts
++ *
++ * Written by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ * 1. distributions of this source code include the above copyright
++ * notice, this list of conditions and the following disclaimer;
++ *
++ * 2. distributions in binary form include the above copyright
++ * notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other associated materials;
++ *
++ * 3. the copyright holder's name is not used to endorse products
++ * built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/version.h>
++#include <linux/unistd.h>
++#include <linux/poll.h>
++#include <linux/random.h>
++#include <cryptodev.h>
++
++#ifdef CONFIG_OCF_FIPS
++#include "rndtest.h"
++#endif
++
++#ifndef HAS_RANDOM_INPUT_WAIT
++#error "Please do not enable OCF_RANDOMHARVEST unless you have applied patches"
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
++#include <linux/sched.h>
++#define kill_proc(p,s,v) send_sig(s,find_task_by_vpid(p),0)
++#endif
++
++/*
++ * a hack to access the debug levels from the crypto driver
++ */
++extern int crypto_debug;
++#define debug crypto_debug
++
++/*
++ * a list of all registered random providers
++ */
++static LIST_HEAD(random_ops);
++static int started = 0;
++static int initted = 0;
++
++struct random_op {
++ struct list_head random_list;
++ u_int32_t driverid;
++ int (*read_random)(void *arg, u_int32_t *buf, int len);
++ void *arg;
++};
++
++static int random_proc(void *arg);
++
++static pid_t randomproc = (pid_t) -1;
++static spinlock_t random_lock;
++
++/*
++ * just init the spin locks
++ */
++static int
++crypto_random_init(void)
++{
++ spin_lock_init(&random_lock);
++ initted = 1;
++ return(0);
++}
++
++/*
++ * Add the given random reader to our list (if not present)
++ * and start the thread (if not already started)
++ *
++ * we have to assume that driver id is ok for now
++ */
++int
++crypto_rregister(
++ u_int32_t driverid,
++ int (*read_random)(void *arg, u_int32_t *buf, int len),
++ void *arg)
++{
++ unsigned long flags;
++ int ret = 0;
++ struct random_op *rops, *tmp;
++
++ dprintk("%s,%d: %s(0x%x, %p, %p)\n", __FILE__, __LINE__,
++ __FUNCTION__, driverid, read_random, arg);
++
++ if (!initted)
++ crypto_random_init();
++
++#if 0
++ struct cryptocap *cap;
++
++ cap = crypto_checkdriver(driverid);
++ if (!cap)
++ return EINVAL;
++#endif
++
++ list_for_each_entry_safe(rops, tmp, &random_ops, random_list) {
++ if (rops->driverid == driverid && rops->read_random == read_random)
++ return EEXIST;
++ }
++
++ rops = (struct random_op *) kmalloc(sizeof(*rops), GFP_KERNEL);
++ if (!rops)
++ return ENOMEM;
++
++ rops->driverid = driverid;
++ rops->read_random = read_random;
++ rops->arg = arg;
++
++ spin_lock_irqsave(&random_lock, flags);
++ list_add_tail(&rops->random_list, &random_ops);
++ if (!started) {
++ randomproc = kernel_thread(random_proc, NULL, CLONE_FS|CLONE_FILES);
++ if (randomproc < 0) {
++ ret = randomproc;
++ printk("crypto: crypto_rregister cannot start random thread; "
++ "error %d", ret);
++ } else
++ started = 1;
++ }
++ spin_unlock_irqrestore(&random_lock, flags);
++
++ return ret;
++}
++EXPORT_SYMBOL(crypto_rregister);
++
++int
++crypto_runregister_all(u_int32_t driverid)
++{
++ struct random_op *rops, *tmp;
++ unsigned long flags;
++
++ dprintk("%s,%d: %s(0x%x)\n", __FILE__, __LINE__, __FUNCTION__, driverid);
++
++ list_for_each_entry_safe(rops, tmp, &random_ops, random_list) {
++ if (rops->driverid == driverid) {
++ list_del(&rops->random_list);
++ kfree(rops);
++ }
++ }
++
++ spin_lock_irqsave(&random_lock, flags);
++ if (list_empty(&random_ops) && started)
++ kill_proc(randomproc, SIGKILL, 1);
++ spin_unlock_irqrestore(&random_lock, flags);
++ return(0);
++}
++EXPORT_SYMBOL(crypto_runregister_all);
++
++/*
++ * while we can add entropy to random.c continue to read random data from
++ * the drivers and push it to random.
++ */
++static int
++random_proc(void *arg)
++{
++ int n;
++ int wantcnt;
++ int bufcnt = 0;
++ int retval = 0;
++ int *buf = NULL;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ daemonize();
++ spin_lock_irq(&current->sigmask_lock);
++ sigemptyset(&current->blocked);
++ recalc_sigpending(current);
++ spin_unlock_irq(&current->sigmask_lock);
++ sprintf(current->comm, "ocf-random");
++#else
++ daemonize("ocf-random");
++ allow_signal(SIGKILL);
++#endif
++
++ (void) get_fs();
++ set_fs(get_ds());
++
++#ifdef CONFIG_OCF_FIPS
++#define NUM_INT (RNDTEST_NBYTES/sizeof(int))
++#else
++#define NUM_INT 32
++#endif
++
++ /*
++ * some devices can transferr their RNG data direct into memory,
++ * so make sure it is device friendly
++ */
++ buf = kmalloc(NUM_INT * sizeof(int), GFP_DMA);
++ if (NULL == buf) {
++ printk("crypto: RNG could not allocate memory\n");
++ retval = -ENOMEM;
++ goto bad_alloc;
++ }
++
++ wantcnt = NUM_INT; /* start by adding some entropy */
++
++ /*
++ * its possible due to errors or driver removal that we no longer
++ * have anything to do, if so exit or we will consume all the CPU
++ * doing nothing
++ */
++ while (!list_empty(&random_ops)) {
++ struct random_op *rops, *tmp;
++
++#ifdef CONFIG_OCF_FIPS
++ if (wantcnt)
++ wantcnt = NUM_INT; /* FIPs mode can do 20000 bits or none */
++#endif
++
++ /* see if we can get enough entropy to make the world
++ * a better place.
++ */
++ while (bufcnt < wantcnt && bufcnt < NUM_INT) {
++ list_for_each_entry_safe(rops, tmp, &random_ops, random_list) {
++
++ n = (*rops->read_random)(rops->arg, &buf[bufcnt],
++ NUM_INT - bufcnt);
++
++ /* on failure remove the random number generator */
++ if (n == -1) {
++ list_del(&rops->random_list);
++ printk("crypto: RNG (driverid=0x%x) failed, disabling\n",
++ rops->driverid);
++ kfree(rops);
++ } else if (n > 0)
++ bufcnt += n;
++ }
++ /* give up CPU for a bit, just in case as this is a loop */
++ schedule();
++ }
++
++
++#ifdef CONFIG_OCF_FIPS
++ if (bufcnt > 0 && rndtest_buf((unsigned char *) &buf[0])) {
++ dprintk("crypto: buffer had fips errors, discarding\n");
++ bufcnt = 0;
++ }
++#endif
++
++ /*
++ * if we have a certified buffer, we can send some data
++ * to /dev/random and move along
++ */
++ if (bufcnt > 0) {
++ /* add what we have */
++ random_input_words(buf, bufcnt, bufcnt*sizeof(int)*8);
++ bufcnt = 0;
++ }
++
++ /* give up CPU for a bit so we don't hog while filling */
++ schedule();
++
++ /* wait for needing more */
++ wantcnt = random_input_wait();
++
++ if (wantcnt <= 0)
++ wantcnt = 0; /* try to get some info again */
++ else
++ /* round up to one word or we can loop forever */
++ wantcnt = (wantcnt + (sizeof(int)*8)) / (sizeof(int)*8);
++ if (wantcnt > NUM_INT) {
++ wantcnt = NUM_INT;
++ }
++
++ if (signal_pending(current)) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ spin_lock_irq(&current->sigmask_lock);
++#endif
++ flush_signals(current);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ spin_unlock_irq(&current->sigmask_lock);
++#endif
++ }
++ }
++
++ kfree(buf);
++
++bad_alloc:
++ spin_lock_irq(&random_lock);
++ randomproc = (pid_t) -1;
++ started = 0;
++ spin_unlock_irq(&random_lock);
++
++ return retval;
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/README linux-2.6.36/crypto/ocf/README
+--- linux-2.6.36.orig/crypto/ocf/README 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/README 2010-11-09 20:28:12.681240186 +0100
+@@ -0,0 +1,167 @@
++README - ocf-linux-20100325
++---------------------------
++
++This README provides instructions for getting ocf-linux compiled and
++operating in a generic linux environment. For other information you
++might like to visit the home page for this project:
++
++ http://ocf-linux.sourceforge.net/
++
++Adding OCF to linux
++-------------------
++
++ Not much in this file for now, just some notes. I usually build
++ the ocf support as modules but it can be built into the kernel as
++ well. To use it:
++
++ * mknod /dev/crypto c 10 70
++
++ * to add OCF to your kernel source, you have two options. Apply
++ the kernel specific patch:
++
++ cd linux-2.4*; gunzip < ocf-linux-24-XXXXXXXX.patch.gz | patch -p1
++ cd linux-2.6*; gunzip < ocf-linux-26-XXXXXXXX.patch.gz | patch -p1
++
++ if you do one of the above, then you can proceed to the next step,
++ or you can do the above process by hand with using the patches against
++ linux-2.4.35 and 2.6.33 to include the ocf code under crypto/ocf.
++ Here's how to add it:
++
++ for 2.4.35 (and later)
++
++ cd linux-2.4.35/crypto
++ tar xvzf ocf-linux.tar.gz
++ cd ..
++ patch -p1 < crypto/ocf/patches/linux-2.4.35-ocf.patch
++
++ for 2.6.23 (and later), find the kernel patch specific (or nearest)
++ to your kernel versions and then:
++
++ cd linux-2.6.NN/crypto
++ tar xvzf ocf-linux.tar.gz
++ cd ..
++ patch -p1 < crypto/ocf/patches/linux-2.6.NN-ocf.patch
++
++ It should be easy to take this patch and apply it to other more
++ recent versions of the kernels. The same patches should also work
++ relatively easily on kernels as old as 2.6.11 and 2.4.18.
++
++ * under 2.4 if you are on a non-x86 platform, you may need to:
++
++ cp linux-2.X.x/include/asm-i386/kmap_types.h linux-2.X.x/include/asm-YYY
++
++ so that you can build the kernel crypto support needed for the cryptosoft
++ driver.
++
++ * For simplicity you should enable all the crypto support in your kernel
++ except for the test driver. Likewise for the OCF options. Do not
++ enable OCF crypto drivers for HW that you do not have (for example
++ ixp4xx will not compile on non-Xscale systems).
++
++ * make sure that cryptodev.h (from ocf-linux.tar.gz) is installed as
++ crypto/cryptodev.h in an include directory that is used for building
++ applications for your platform. For example on a host system that
++ might be:
++
++ /usr/include/crypto/cryptodev.h
++
++ * patch your openssl-0.9.8n code with the openssl-0.9.8n.patch.
++ (NOTE: there is no longer a need to patch ssh). The patch is against:
++ openssl-0_9_8e
++
++ If you need a patch for an older version of openssl, you should look
++ to older OCF releases. This patch is unlikely to work on older
++ openssl versions.
++
++ openssl-0.9.8n.patch
++ - enables --with-cryptodev for non BSD systems
++ - adds -cpu option to openssl speed for calculating CPU load
++ under linux
++ - fixes null pointer in openssl speed multi thread output.
++ - fixes test keys to work with linux crypto's more stringent
++ key checking.
++ - adds MD5/SHA acceleration (Ronen Shitrit), only enabled
++ with the --with-cryptodev-digests option
++ - fixes bug in engine code caching.
++
++ * build crypto-tools-XXXXXXXX.tar.gz if you want to try some of the BSD
++ tools for testing OCF (ie., cryptotest).
++
++How to load the OCF drivers
++---------------------------
++
++ First insert the base modules:
++
++ insmod ocf
++ insmod cryptodev
++
++ You can then install the software OCF driver with:
++
++ insmod cryptosoft
++
++ and one or more of the OCF HW drivers with:
++
++ insmod safe
++ insmod hifn7751
++ insmod ixp4xx
++ ...
++
++ all the drivers take a debug option to enable verbose debug so that
++ you can see what is going on. For debug you load them as:
++
++ insmod ocf crypto_debug=1
++ insmod cryptodev cryptodev_debug=1
++ insmod cryptosoft swcr_debug=1
++
++ You may load more than one OCF crypto driver but then there is no guarantee
++ as to which will be used.
++
++ You can also enable debug at run time on 2.6 systems with the following:
++
++ echo 1 > /sys/module/ocf/parameters/crypto_debug
++ echo 1 > /sys/module/cryptodev/parameters/cryptodev_debug
++ echo 1 > /sys/module/cryptosoft/parameters/swcr_debug
++ echo 1 > /sys/module/hifn7751/parameters/hifn_debug
++ echo 1 > /sys/module/safe/parameters/safe_debug
++ echo 1 > /sys/module/ixp4xx/parameters/ixp_debug
++ ...
++
++Testing the OCF support
++-----------------------
++
++ run "cryptotest", it should do a short test for a couple of
++ des packets. If it does everything is working.
++
++ If this works, then ssh will use the driver when invoked as:
++
++ ssh -c 3des username@host
++
++ to see for sure that it is operating, enable debug as defined above.
++
++ To get a better idea of performance run:
++
++ cryptotest 100 4096
++
++ There are more options to cryptotest, see the help.
++
++ It is also possible to use openssl to test the speed of the crypto
++ drivers.
++
++ openssl speed -evp des -engine cryptodev -elapsed
++ openssl speed -evp des3 -engine cryptodev -elapsed
++ openssl speed -evp aes128 -engine cryptodev -elapsed
++
++ and multiple threads (10) with:
++
++ openssl speed -evp des -engine cryptodev -elapsed -multi 10
++ openssl speed -evp des3 -engine cryptodev -elapsed -multi 10
++ openssl speed -evp aes128 -engine cryptodev -elapsed -multi 10
++
++ for public key testing you can try:
++
++ cryptokeytest
++ openssl speed -engine cryptodev rsa -elapsed
++ openssl speed -engine cryptodev dsa -elapsed
++
++David McCullough
++david_mccullough@mcafee.com
+diff -Nur linux-2.6.36.orig/crypto/ocf/rndtest.c linux-2.6.36/crypto/ocf/rndtest.c
+--- linux-2.6.36.orig/crypto/ocf/rndtest.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/rndtest.c 2010-11-09 20:28:12.722495563 +0100
+@@ -0,0 +1,300 @@
++/* $OpenBSD$ */
++
++/*
++ * OCF/Linux port done by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. All advertising materials mentioning features or use of this software
++ * must display the following acknowledgement:
++ * This product includes software developed by Jason L. Wright
++ * 4. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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 AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/wait.h>
++#include <linux/time.h>
++#include <linux/version.h>
++#include <linux/unistd.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/time.h>
++#include <cryptodev.h>
++#include "rndtest.h"
++
++static struct rndtest_stats rndstats;
++
++static void rndtest_test(struct rndtest_state *);
++
++/* The tests themselves */
++static int rndtest_monobit(struct rndtest_state *);
++static int rndtest_runs(struct rndtest_state *);
++static int rndtest_longruns(struct rndtest_state *);
++static int rndtest_chi_4(struct rndtest_state *);
++
++static int rndtest_runs_check(struct rndtest_state *, int, int *);
++static void rndtest_runs_record(struct rndtest_state *, int, int *);
++
++static const struct rndtest_testfunc {
++ int (*test)(struct rndtest_state *);
++} rndtest_funcs[] = {
++ { rndtest_monobit },
++ { rndtest_runs },
++ { rndtest_chi_4 },
++ { rndtest_longruns },
++};
++
++#define RNDTEST_NTESTS (sizeof(rndtest_funcs)/sizeof(rndtest_funcs[0]))
++
++static void
++rndtest_test(struct rndtest_state *rsp)
++{
++ int i, rv = 0;
++
++ rndstats.rst_tests++;
++ for (i = 0; i < RNDTEST_NTESTS; i++)
++ rv |= (*rndtest_funcs[i].test)(rsp);
++ rsp->rs_discard = (rv != 0);
++}
++
++
++extern int crypto_debug;
++#define rndtest_verbose 2
++#define rndtest_report(rsp, failure, fmt, a...) \
++ { if (failure || crypto_debug) { printk("rng_test: " fmt "\n", a); } else; }
++
++#define RNDTEST_MONOBIT_MINONES 9725
++#define RNDTEST_MONOBIT_MAXONES 10275
++
++static int
++rndtest_monobit(struct rndtest_state *rsp)
++{
++ int i, ones = 0, j;
++ u_int8_t r;
++
++ for (i = 0; i < RNDTEST_NBYTES; i++) {
++ r = rsp->rs_buf[i];
++ for (j = 0; j < 8; j++, r <<= 1)
++ if (r & 0x80)
++ ones++;
++ }
++ if (ones > RNDTEST_MONOBIT_MINONES &&
++ ones < RNDTEST_MONOBIT_MAXONES) {
++ if (rndtest_verbose > 1)
++ rndtest_report(rsp, 0, "monobit pass (%d < %d < %d)",
++ RNDTEST_MONOBIT_MINONES, ones,
++ RNDTEST_MONOBIT_MAXONES);
++ return (0);
++ } else {
++ if (rndtest_verbose)
++ rndtest_report(rsp, 1,
++ "monobit failed (%d ones)", ones);
++ rndstats.rst_monobit++;
++ return (-1);
++ }
++}
++
++#define RNDTEST_RUNS_NINTERVAL 6
++
++static const struct rndtest_runs_tabs {
++ u_int16_t min, max;
++} rndtest_runs_tab[] = {
++ { 2343, 2657 },
++ { 1135, 1365 },
++ { 542, 708 },
++ { 251, 373 },
++ { 111, 201 },
++ { 111, 201 },
++};
++
++static int
++rndtest_runs(struct rndtest_state *rsp)
++{
++ int i, j, ones, zeros, rv = 0;
++ int onei[RNDTEST_RUNS_NINTERVAL], zeroi[RNDTEST_RUNS_NINTERVAL];
++ u_int8_t c;
++
++ bzero(onei, sizeof(onei));
++ bzero(zeroi, sizeof(zeroi));
++ ones = zeros = 0;
++ for (i = 0; i < RNDTEST_NBYTES; i++) {
++ c = rsp->rs_buf[i];
++ for (j = 0; j < 8; j++, c <<= 1) {
++ if (c & 0x80) {
++ ones++;
++ rndtest_runs_record(rsp, zeros, zeroi);
++ zeros = 0;
++ } else {
++ zeros++;
++ rndtest_runs_record(rsp, ones, onei);
++ ones = 0;
++ }
++ }
++ }
++ rndtest_runs_record(rsp, ones, onei);
++ rndtest_runs_record(rsp, zeros, zeroi);
++
++ rv |= rndtest_runs_check(rsp, 0, zeroi);
++ rv |= rndtest_runs_check(rsp, 1, onei);
++
++ if (rv)
++ rndstats.rst_runs++;
++
++ return (rv);
++}
++
++static void
++rndtest_runs_record(struct rndtest_state *rsp, int len, int *intrv)
++{
++ if (len == 0)
++ return;
++ if (len > RNDTEST_RUNS_NINTERVAL)
++ len = RNDTEST_RUNS_NINTERVAL;
++ len -= 1;
++ intrv[len]++;
++}
++
++static int
++rndtest_runs_check(struct rndtest_state *rsp, int val, int *src)
++{
++ int i, rv = 0;
++
++ for (i = 0; i < RNDTEST_RUNS_NINTERVAL; i++) {
++ if (src[i] < rndtest_runs_tab[i].min ||
++ src[i] > rndtest_runs_tab[i].max) {
++ rndtest_report(rsp, 1,
++ "%s interval %d failed (%d, %d-%d)",
++ val ? "ones" : "zeros",
++ i + 1, src[i], rndtest_runs_tab[i].min,
++ rndtest_runs_tab[i].max);
++ rv = -1;
++ } else {
++ rndtest_report(rsp, 0,
++ "runs pass %s interval %d (%d < %d < %d)",
++ val ? "ones" : "zeros",
++ i + 1, rndtest_runs_tab[i].min, src[i],
++ rndtest_runs_tab[i].max);
++ }
++ }
++ return (rv);
++}
++
++static int
++rndtest_longruns(struct rndtest_state *rsp)
++{
++ int i, j, ones = 0, zeros = 0, maxones = 0, maxzeros = 0;
++ u_int8_t c;
++
++ for (i = 0; i < RNDTEST_NBYTES; i++) {
++ c = rsp->rs_buf[i];
++ for (j = 0; j < 8; j++, c <<= 1) {
++ if (c & 0x80) {
++ zeros = 0;
++ ones++;
++ if (ones > maxones)
++ maxones = ones;
++ } else {
++ ones = 0;
++ zeros++;
++ if (zeros > maxzeros)
++ maxzeros = zeros;
++ }
++ }
++ }
++
++ if (maxones < 26 && maxzeros < 26) {
++ rndtest_report(rsp, 0, "longruns pass (%d ones, %d zeros)",
++ maxones, maxzeros);
++ return (0);
++ } else {
++ rndtest_report(rsp, 1, "longruns fail (%d ones, %d zeros)",
++ maxones, maxzeros);
++ rndstats.rst_longruns++;
++ return (-1);
++ }
++}
++
++/*
++ * chi^2 test over 4 bits: (this is called the poker test in FIPS 140-2,
++ * but it is really the chi^2 test over 4 bits (the poker test as described
++ * by Knuth vol 2 is something different, and I take him as authoritative
++ * on nomenclature over NIST).
++ */
++#define RNDTEST_CHI4_K 16
++#define RNDTEST_CHI4_K_MASK (RNDTEST_CHI4_K - 1)
++
++/*
++ * The unnormalized values are used so that we don't have to worry about
++ * fractional precision. The "real" value is found by:
++ * (V - 1562500) * (16 / 5000) = Vn (where V is the unnormalized value)
++ */
++#define RNDTEST_CHI4_VMIN 1563181 /* 2.1792 */
++#define RNDTEST_CHI4_VMAX 1576929 /* 46.1728 */
++
++static int
++rndtest_chi_4(struct rndtest_state *rsp)
++{
++ unsigned int freq[RNDTEST_CHI4_K], i, sum;
++
++ for (i = 0; i < RNDTEST_CHI4_K; i++)
++ freq[i] = 0;
++
++ /* Get number of occurances of each 4 bit pattern */
++ for (i = 0; i < RNDTEST_NBYTES; i++) {
++ freq[(rsp->rs_buf[i] >> 4) & RNDTEST_CHI4_K_MASK]++;
++ freq[(rsp->rs_buf[i] >> 0) & RNDTEST_CHI4_K_MASK]++;
++ }
++
++ for (i = 0, sum = 0; i < RNDTEST_CHI4_K; i++)
++ sum += freq[i] * freq[i];
++
++ if (sum >= 1563181 && sum <= 1576929) {
++ rndtest_report(rsp, 0, "chi^2(4): pass (sum %u)", sum);
++ return (0);
++ } else {
++ rndtest_report(rsp, 1, "chi^2(4): failed (sum %u)", sum);
++ rndstats.rst_chi++;
++ return (-1);
++ }
++}
++
++int
++rndtest_buf(unsigned char *buf)
++{
++ struct rndtest_state rsp;
++
++ memset(&rsp, 0, sizeof(rsp));
++ rsp.rs_buf = buf;
++ rndtest_test(&rsp);
++ return(rsp.rs_discard);
++}
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/rndtest.h linux-2.6.36/crypto/ocf/rndtest.h
+--- linux-2.6.36.orig/crypto/ocf/rndtest.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/rndtest.h 2010-11-09 20:28:12.762495556 +0100
+@@ -0,0 +1,54 @@
++/* $FreeBSD: src/sys/dev/rndtest/rndtest.h,v 1.1 2003/03/11 22:54:44 sam Exp $ */
++/* $OpenBSD$ */
++
++/*
++ * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. All advertising materials mentioning features or use of this software
++ * must display the following acknowledgement:
++ * This product includes software developed by Jason L. Wright
++ * 4. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
++ */
++
++
++/* Some of the tests depend on these values */
++#define RNDTEST_NBYTES 2500
++#define RNDTEST_NBITS (8 * RNDTEST_NBYTES)
++
++struct rndtest_state {
++ int rs_discard; /* discard/accept random data */
++ u_int8_t *rs_buf;
++};
++
++struct rndtest_stats {
++ u_int32_t rst_discard; /* number of bytes discarded */
++ u_int32_t rst_tests; /* number of test runs */
++ u_int32_t rst_monobit; /* monobit test failures */
++ u_int32_t rst_runs; /* 0/1 runs failures */
++ u_int32_t rst_longruns; /* longruns failures */
++ u_int32_t rst_chi; /* chi^2 failures */
++};
++
++extern int rndtest_buf(unsigned char *buf);
+diff -Nur linux-2.6.36.orig/crypto/ocf/safe/Makefile linux-2.6.36/crypto/ocf/safe/Makefile
+--- linux-2.6.36.orig/crypto/ocf/safe/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/safe/Makefile 2010-11-09 20:28:12.805576889 +0100
+@@ -0,0 +1,12 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_SAFE) += safe.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/safe/md5.c linux-2.6.36/crypto/ocf/safe/md5.c
+--- linux-2.6.36.orig/crypto/ocf/safe/md5.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/safe/md5.c 2010-11-09 20:28:12.842495449 +0100
+@@ -0,0 +1,308 @@
++/* $KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */
++/*
++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. Neither the name of the project 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 BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT 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 0
++#include <sys/cdefs.h>
++__FBSDID("$FreeBSD: src/sys/crypto/md5.c,v 1.9 2004/01/27 19:49:19 des Exp $");
++
++#include <sys/types.h>
++#include <sys/cdefs.h>
++#include <sys/time.h>
++#include <sys/systm.h>
++#include <crypto/md5.h>
++#endif
++
++#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s))))
++
++#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
++#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
++#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
++#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))
++
++#define ROUND1(a, b, c, d, k, s, i) { \
++ (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
++ (a) = SHIFT((a), (s)); \
++ (a) = (b) + (a); \
++}
++
++#define ROUND2(a, b, c, d, k, s, i) { \
++ (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
++ (a) = SHIFT((a), (s)); \
++ (a) = (b) + (a); \
++}
++
++#define ROUND3(a, b, c, d, k, s, i) { \
++ (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
++ (a) = SHIFT((a), (s)); \
++ (a) = (b) + (a); \
++}
++
++#define ROUND4(a, b, c, d, k, s, i) { \
++ (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
++ (a) = SHIFT((a), (s)); \
++ (a) = (b) + (a); \
++}
++
++#define Sa 7
++#define Sb 12
++#define Sc 17
++#define Sd 22
++
++#define Se 5
++#define Sf 9
++#define Sg 14
++#define Sh 20
++
++#define Si 4
++#define Sj 11
++#define Sk 16
++#define Sl 23
++
++#define Sm 6
++#define Sn 10
++#define So 15
++#define Sp 21
++
++#define MD5_A0 0x67452301
++#define MD5_B0 0xefcdab89
++#define MD5_C0 0x98badcfe
++#define MD5_D0 0x10325476
++
++/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
++static const u_int32_t T[65] = {
++ 0,
++ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
++ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
++ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
++ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
++
++ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
++ 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
++ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
++ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
++
++ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
++ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
++ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
++ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
++
++ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
++ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
++ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
++ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
++};
++
++static const u_int8_t md5_paddat[MD5_BUFLEN] = {
++ 0x80, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++};
++
++static void md5_calc(u_int8_t *, md5_ctxt *);
++
++void md5_init(ctxt)
++ md5_ctxt *ctxt;
++{
++ ctxt->md5_n = 0;
++ ctxt->md5_i = 0;
++ ctxt->md5_sta = MD5_A0;
++ ctxt->md5_stb = MD5_B0;
++ ctxt->md5_stc = MD5_C0;
++ ctxt->md5_std = MD5_D0;
++ bzero(ctxt->md5_buf, sizeof(ctxt->md5_buf));
++}
++
++void md5_loop(ctxt, input, len)
++ md5_ctxt *ctxt;
++ u_int8_t *input;
++ u_int len; /* number of bytes */
++{
++ u_int gap, i;
++
++ ctxt->md5_n += len * 8; /* byte to bit */
++ gap = MD5_BUFLEN - ctxt->md5_i;
++
++ if (len >= gap) {
++ bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
++ gap);
++ md5_calc(ctxt->md5_buf, ctxt);
++
++ for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
++ md5_calc((u_int8_t *)(input + i), ctxt);
++ }
++
++ ctxt->md5_i = len - i;
++ bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
++ } else {
++ bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
++ len);
++ ctxt->md5_i += len;
++ }
++}
++
++void md5_pad(ctxt)
++ md5_ctxt *ctxt;
++{
++ u_int gap;
++
++ /* Don't count up padding. Keep md5_n. */
++ gap = MD5_BUFLEN - ctxt->md5_i;
++ if (gap > 8) {
++ bcopy(md5_paddat,
++ (void *)(ctxt->md5_buf + ctxt->md5_i),
++ gap - sizeof(ctxt->md5_n));
++ } else {
++ /* including gap == 8 */
++ bcopy(md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
++ gap);
++ md5_calc(ctxt->md5_buf, ctxt);
++ bcopy((md5_paddat + gap),
++ (void *)ctxt->md5_buf,
++ MD5_BUFLEN - sizeof(ctxt->md5_n));
++ }
++
++ /* 8 byte word */
++#if BYTE_ORDER == LITTLE_ENDIAN
++ bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
++#endif
++#if BYTE_ORDER == BIG_ENDIAN
++ ctxt->md5_buf[56] = ctxt->md5_n8[7];
++ ctxt->md5_buf[57] = ctxt->md5_n8[6];
++ ctxt->md5_buf[58] = ctxt->md5_n8[5];
++ ctxt->md5_buf[59] = ctxt->md5_n8[4];
++ ctxt->md5_buf[60] = ctxt->md5_n8[3];
++ ctxt->md5_buf[61] = ctxt->md5_n8[2];
++ ctxt->md5_buf[62] = ctxt->md5_n8[1];
++ ctxt->md5_buf[63] = ctxt->md5_n8[0];
++#endif
++
++ md5_calc(ctxt->md5_buf, ctxt);
++}
++
++void md5_result(digest, ctxt)
++ u_int8_t *digest;
++ md5_ctxt *ctxt;
++{
++ /* 4 byte words */
++#if BYTE_ORDER == LITTLE_ENDIAN
++ bcopy(&ctxt->md5_st8[0], digest, 16);
++#endif
++#if BYTE_ORDER == BIG_ENDIAN
++ digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2];
++ digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0];
++ digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6];
++ digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4];
++ digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10];
++ digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8];
++ digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14];
++ digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12];
++#endif
++}
++
++static void md5_calc(b64, ctxt)
++ u_int8_t *b64;
++ md5_ctxt *ctxt;
++{
++ u_int32_t A = ctxt->md5_sta;
++ u_int32_t B = ctxt->md5_stb;
++ u_int32_t C = ctxt->md5_stc;
++ u_int32_t D = ctxt->md5_std;
++#if BYTE_ORDER == LITTLE_ENDIAN
++ u_int32_t *X = (u_int32_t *)b64;
++#endif
++#if BYTE_ORDER == BIG_ENDIAN
++ /* 4 byte words */
++ /* what a brute force but fast! */
++ u_int32_t X[16];
++ u_int8_t *y = (u_int8_t *)X;
++ y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0];
++ y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4];
++ y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8];
++ y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12];
++ y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16];
++ y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20];
++ y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24];
++ y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28];
++ y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32];
++ y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36];
++ y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40];
++ y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44];
++ y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48];
++ y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52];
++ y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56];
++ y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60];
++#endif
++
++ ROUND1(A, B, C, D, 0, Sa, 1); ROUND1(D, A, B, C, 1, Sb, 2);
++ ROUND1(C, D, A, B, 2, Sc, 3); ROUND1(B, C, D, A, 3, Sd, 4);
++ ROUND1(A, B, C, D, 4, Sa, 5); ROUND1(D, A, B, C, 5, Sb, 6);
++ ROUND1(C, D, A, B, 6, Sc, 7); ROUND1(B, C, D, A, 7, Sd, 8);
++ ROUND1(A, B, C, D, 8, Sa, 9); ROUND1(D, A, B, C, 9, Sb, 10);
++ ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12);
++ ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14);
++ ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16);
++
++ ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18);
++ ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20);
++ ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22);
++ ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A, 4, Sh, 24);
++ ROUND2(A, B, C, D, 9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26);
++ ROUND2(C, D, A, B, 3, Sg, 27); ROUND2(B, C, D, A, 8, Sh, 28);
++ ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C, 2, Sf, 30);
++ ROUND2(C, D, A, B, 7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32);
++
++ ROUND3(A, B, C, D, 5, Si, 33); ROUND3(D, A, B, C, 8, Sj, 34);
++ ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36);
++ ROUND3(A, B, C, D, 1, Si, 37); ROUND3(D, A, B, C, 4, Sj, 38);
++ ROUND3(C, D, A, B, 7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40);
++ ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C, 0, Sj, 42);
++ ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44);
++ ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46);
++ ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48);
++
++ ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50);
++ ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52);
++ ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54);
++ ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56);
++ ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58);
++ ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60);
++ ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62);
++ ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64);
++
++ ctxt->md5_sta += A;
++ ctxt->md5_stb += B;
++ ctxt->md5_stc += C;
++ ctxt->md5_std += D;
++}
+diff -Nur linux-2.6.36.orig/crypto/ocf/safe/md5.h linux-2.6.36/crypto/ocf/safe/md5.h
+--- linux-2.6.36.orig/crypto/ocf/safe/md5.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/safe/md5.h 2010-11-09 20:28:12.881683669 +0100
+@@ -0,0 +1,76 @@
++/* $FreeBSD: src/sys/crypto/md5.h,v 1.4 2002/03/20 05:13:50 alfred Exp $ */
++/* $KAME: md5.h,v 1.4 2000/03/27 04:36:22 sumikawa Exp $ */
++
++/*
++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. Neither the name of the project 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 BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT 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 _NETINET6_MD5_H_
++#define _NETINET6_MD5_H_
++
++#define MD5_BUFLEN 64
++
++typedef struct {
++ union {
++ u_int32_t md5_state32[4];
++ u_int8_t md5_state8[16];
++ } md5_st;
++
++#define md5_sta md5_st.md5_state32[0]
++#define md5_stb md5_st.md5_state32[1]
++#define md5_stc md5_st.md5_state32[2]
++#define md5_std md5_st.md5_state32[3]
++#define md5_st8 md5_st.md5_state8
++
++ union {
++ u_int64_t md5_count64;
++ u_int8_t md5_count8[8];
++ } md5_count;
++#define md5_n md5_count.md5_count64
++#define md5_n8 md5_count.md5_count8
++
++ u_int md5_i;
++ u_int8_t md5_buf[MD5_BUFLEN];
++} md5_ctxt;
++
++extern void md5_init(md5_ctxt *);
++extern void md5_loop(md5_ctxt *, u_int8_t *, u_int);
++extern void md5_pad(md5_ctxt *);
++extern void md5_result(u_int8_t *, md5_ctxt *);
++
++/* compatibility */
++#define MD5_CTX md5_ctxt
++#define MD5Init(x) md5_init((x))
++#define MD5Update(x, y, z) md5_loop((x), (y), (z))
++#define MD5Final(x, y) \
++do { \
++ md5_pad((y)); \
++ md5_result((x), (y)); \
++} while (0)
++
++#endif /* ! _NETINET6_MD5_H_*/
+diff -Nur linux-2.6.36.orig/crypto/ocf/safe/safe.c linux-2.6.36/crypto/ocf/safe/safe.c
+--- linux-2.6.36.orig/crypto/ocf/safe/safe.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/safe/safe.c 2010-11-09 20:28:12.922204086 +0100
+@@ -0,0 +1,2288 @@
++/*-
++ * Linux port done by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2004-2010 David McCullough
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 2003 Sam Leffler, Errno Consulting
++ * Copyright (c) 2003 Global Technology Associates, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
++ *
++__FBSDID("$FreeBSD: src/sys/dev/safe/safe.c,v 1.18 2007/03/21 03:42:50 sam Exp $");
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/random.h>
++#include <linux/version.h>
++#include <linux/skbuff.h>
++#include <asm/io.h>
++
++/*
++ * SafeNet SafeXcel-1141 hardware crypto accelerator
++ */
++
++#include <cryptodev.h>
++#include <uio.h>
++#include <safe/safereg.h>
++#include <safe/safevar.h>
++
++#if 1
++#define DPRINTF(a) do { \
++ if (debug) { \
++ printk("%s: ", sc ? \
++ device_get_nameunit(sc->sc_dev) : "safe"); \
++ printk a; \
++ } \
++ } while (0)
++#else
++#define DPRINTF(a)
++#endif
++
++/*
++ * until we find a cleaner way, include the BSD md5/sha1 code
++ * here
++ */
++#define HMAC_HACK 1
++#ifdef HMAC_HACK
++#define LITTLE_ENDIAN 1234
++#define BIG_ENDIAN 4321
++#ifdef __LITTLE_ENDIAN
++#define BYTE_ORDER LITTLE_ENDIAN
++#endif
++#ifdef __BIG_ENDIAN
++#define BYTE_ORDER BIG_ENDIAN
++#endif
++#include <safe/md5.h>
++#include <safe/md5.c>
++#include <safe/sha1.h>
++#include <safe/sha1.c>
++
++u_int8_t hmac_ipad_buffer[64] = {
++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
++};
++
++u_int8_t hmac_opad_buffer[64] = {
++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C
++};
++#endif /* HMAC_HACK */
++
++/* add proc entry for this */
++struct safe_stats safestats;
++
++#define debug safe_debug
++int safe_debug = 0;
++module_param(safe_debug, int, 0644);
++MODULE_PARM_DESC(safe_debug, "Enable debug");
++
++static void safe_callback(struct safe_softc *, struct safe_ringentry *);
++static void safe_feed(struct safe_softc *, struct safe_ringentry *);
++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG)
++static void safe_rng_init(struct safe_softc *);
++int safe_rngbufsize = 8; /* 32 bytes each read */
++module_param(safe_rngbufsize, int, 0644);
++MODULE_PARM_DESC(safe_rngbufsize, "RNG polling buffer size (32-bit words)");
++int safe_rngmaxalarm = 8; /* max alarms before reset */
++module_param(safe_rngmaxalarm, int, 0644);
++MODULE_PARM_DESC(safe_rngmaxalarm, "RNG max alarms before reset");
++#endif /* SAFE_NO_RNG */
++
++static void safe_totalreset(struct safe_softc *sc);
++static int safe_dmamap_aligned(struct safe_softc *sc, const struct safe_operand *op);
++static int safe_dmamap_uniform(struct safe_softc *sc, const struct safe_operand *op);
++static int safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re);
++static int safe_kprocess(device_t dev, struct cryptkop *krp, int hint);
++static int safe_kstart(struct safe_softc *sc);
++static int safe_ksigbits(struct safe_softc *sc, struct crparam *cr);
++static void safe_kfeed(struct safe_softc *sc);
++static void safe_kpoll(unsigned long arg);
++static void safe_kload_reg(struct safe_softc *sc, u_int32_t off,
++ u_int32_t len, struct crparam *n);
++
++static int safe_newsession(device_t, u_int32_t *, struct cryptoini *);
++static int safe_freesession(device_t, u_int64_t);
++static int safe_process(device_t, struct cryptop *, int);
++
++static device_method_t safe_methods = {
++ /* crypto device methods */
++ DEVMETHOD(cryptodev_newsession, safe_newsession),
++ DEVMETHOD(cryptodev_freesession,safe_freesession),
++ DEVMETHOD(cryptodev_process, safe_process),
++ DEVMETHOD(cryptodev_kprocess, safe_kprocess),
++};
++
++#define READ_REG(sc,r) readl((sc)->sc_base_addr + (r))
++#define WRITE_REG(sc,r,val) writel((val), (sc)->sc_base_addr + (r))
++
++#define SAFE_MAX_CHIPS 8
++static struct safe_softc *safe_chip_idx[SAFE_MAX_CHIPS];
++
++/*
++ * split our buffers up into safe DMAable byte fragments to avoid lockup
++ * bug in 1141 HW on rev 1.0.
++ */
++
++static int
++pci_map_linear(
++ struct safe_softc *sc,
++ struct safe_operand *buf,
++ void *addr,
++ int len)
++{
++ dma_addr_t tmp;
++ int chunk, tlen = len;
++
++ tmp = pci_map_single(sc->sc_pcidev, addr, len, PCI_DMA_BIDIRECTIONAL);
++
++ buf->mapsize += len;
++ while (len > 0) {
++ chunk = (len > sc->sc_max_dsize) ? sc->sc_max_dsize : len;
++ buf->segs[buf->nsegs].ds_addr = tmp;
++ buf->segs[buf->nsegs].ds_len = chunk;
++ buf->segs[buf->nsegs].ds_tlen = tlen;
++ buf->nsegs++;
++ tmp += chunk;
++ len -= chunk;
++ tlen = 0;
++ }
++ return 0;
++}
++
++/*
++ * map in a given uio buffer (great on some arches :-)
++ */
++
++static int
++pci_map_uio(struct safe_softc *sc, struct safe_operand *buf, struct uio *uio)
++{
++ struct iovec *iov = uio->uio_iov;
++ int n;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ buf->mapsize = 0;
++ buf->nsegs = 0;
++
++ for (n = 0; n < uio->uio_iovcnt; n++) {
++ pci_map_linear(sc, buf, iov->iov_base, iov->iov_len);
++ iov++;
++ }
++
++ /* identify this buffer by the first segment */
++ buf->map = (void *) buf->segs[0].ds_addr;
++ return(0);
++}
++
++/*
++ * map in a given sk_buff
++ */
++
++static int
++pci_map_skb(struct safe_softc *sc,struct safe_operand *buf,struct sk_buff *skb)
++{
++ int i;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ buf->mapsize = 0;
++ buf->nsegs = 0;
++
++ pci_map_linear(sc, buf, skb->data, skb_headlen(skb));
++
++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
++ pci_map_linear(sc, buf,
++ page_address(skb_shinfo(skb)->frags[i].page) +
++ skb_shinfo(skb)->frags[i].page_offset,
++ skb_shinfo(skb)->frags[i].size);
++ }
++
++ /* identify this buffer by the first segment */
++ buf->map = (void *) buf->segs[0].ds_addr;
++ return(0);
++}
++
++
++#if 0 /* not needed at this time */
++static void
++pci_sync_operand(struct safe_softc *sc, struct safe_operand *buf)
++{
++ int i;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++ for (i = 0; i < buf->nsegs; i++)
++ pci_dma_sync_single_for_cpu(sc->sc_pcidev, buf->segs[i].ds_addr,
++ buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL);
++}
++#endif
++
++static void
++pci_unmap_operand(struct safe_softc *sc, struct safe_operand *buf)
++{
++ int i;
++ DPRINTF(("%s()\n", __FUNCTION__));
++ for (i = 0; i < buf->nsegs; i++) {
++ if (buf->segs[i].ds_tlen) {
++ DPRINTF(("%s - unmap %d 0x%x %d\n", __FUNCTION__, i, buf->segs[i].ds_addr, buf->segs[i].ds_tlen));
++ pci_unmap_single(sc->sc_pcidev, buf->segs[i].ds_addr,
++ buf->segs[i].ds_tlen, PCI_DMA_BIDIRECTIONAL);
++ DPRINTF(("%s - unmap %d 0x%x %d done\n", __FUNCTION__, i, buf->segs[i].ds_addr, buf->segs[i].ds_tlen));
++ }
++ buf->segs[i].ds_addr = 0;
++ buf->segs[i].ds_len = 0;
++ buf->segs[i].ds_tlen = 0;
++ }
++ buf->nsegs = 0;
++ buf->mapsize = 0;
++ buf->map = 0;
++}
++
++
++/*
++ * SafeXcel Interrupt routine
++ */
++static irqreturn_t
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++safe_intr(int irq, void *arg)
++#else
++safe_intr(int irq, void *arg, struct pt_regs *regs)
++#endif
++{
++ struct safe_softc *sc = arg;
++ int stat;
++ unsigned long flags;
++
++ stat = READ_REG(sc, SAFE_HM_STAT);
++
++ DPRINTF(("%s(stat=0x%x)\n", __FUNCTION__, stat));
++
++ if (stat == 0) /* shared irq, not for us */
++ return IRQ_NONE;
++
++ WRITE_REG(sc, SAFE_HI_CLR, stat); /* IACK */
++
++ if ((stat & SAFE_INT_PE_DDONE)) {
++ /*
++ * Descriptor(s) done; scan the ring and
++ * process completed operations.
++ */
++ spin_lock_irqsave(&sc->sc_ringmtx, flags);
++ while (sc->sc_back != sc->sc_front) {
++ struct safe_ringentry *re = sc->sc_back;
++
++#ifdef SAFE_DEBUG
++ if (debug) {
++ safe_dump_ringstate(sc, __func__);
++ safe_dump_request(sc, __func__, re);
++ }
++#endif
++ /*
++ * safe_process marks ring entries that were allocated
++ * but not used with a csr of zero. This insures the
++ * ring front pointer never needs to be set backwards
++ * in the event that an entry is allocated but not used
++ * because of a setup error.
++ */
++ DPRINTF(("%s re->re_desc.d_csr=0x%x\n", __FUNCTION__, re->re_desc.d_csr));
++ if (re->re_desc.d_csr != 0) {
++ if (!SAFE_PE_CSR_IS_DONE(re->re_desc.d_csr)) {
++ DPRINTF(("%s !CSR_IS_DONE\n", __FUNCTION__));
++ break;
++ }
++ if (!SAFE_PE_LEN_IS_DONE(re->re_desc.d_len)) {
++ DPRINTF(("%s !LEN_IS_DONE\n", __FUNCTION__));
++ break;
++ }
++ sc->sc_nqchip--;
++ safe_callback(sc, re);
++ }
++ if (++(sc->sc_back) == sc->sc_ringtop)
++ sc->sc_back = sc->sc_ring;
++ }
++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags);
++ }
++
++ /*
++ * Check to see if we got any DMA Error
++ */
++ if (stat & SAFE_INT_PE_ERROR) {
++ printk("%s: dmaerr dmastat %08x\n", device_get_nameunit(sc->sc_dev),
++ (int)READ_REG(sc, SAFE_PE_DMASTAT));
++ safestats.st_dmaerr++;
++ safe_totalreset(sc);
++#if 0
++ safe_feed(sc);
++#endif
++ }
++
++ if (sc->sc_needwakeup) { /* XXX check high watermark */
++ int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ);
++ DPRINTF(("%s: wakeup crypto %x\n", __func__,
++ sc->sc_needwakeup));
++ sc->sc_needwakeup &= ~wakeup;
++ crypto_unblock(sc->sc_cid, wakeup);
++ }
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * safe_feed() - post a request to chip
++ */
++static void
++safe_feed(struct safe_softc *sc, struct safe_ringentry *re)
++{
++ DPRINTF(("%s()\n", __FUNCTION__));
++#ifdef SAFE_DEBUG
++ if (debug) {
++ safe_dump_ringstate(sc, __func__);
++ safe_dump_request(sc, __func__, re);
++ }
++#endif
++ sc->sc_nqchip++;
++ if (sc->sc_nqchip > safestats.st_maxqchip)
++ safestats.st_maxqchip = sc->sc_nqchip;
++ /* poke h/w to check descriptor ring, any value can be written */
++ WRITE_REG(sc, SAFE_HI_RD_DESCR, 0);
++}
++
++#define N(a) (sizeof(a) / sizeof (a[0]))
++static void
++safe_setup_enckey(struct safe_session *ses, caddr_t key)
++{
++ int i;
++
++ bcopy(key, ses->ses_key, ses->ses_klen / 8);
++
++ /* PE is little-endian, insure proper byte order */
++ for (i = 0; i < N(ses->ses_key); i++)
++ ses->ses_key[i] = htole32(ses->ses_key[i]);
++}
++
++static void
++safe_setup_mackey(struct safe_session *ses, int algo, caddr_t key, int klen)
++{
++#ifdef HMAC_HACK
++ MD5_CTX md5ctx;
++ SHA1_CTX sha1ctx;
++ int i;
++
++
++ for (i = 0; i < klen; i++)
++ key[i] ^= HMAC_IPAD_VAL;
++
++ if (algo == CRYPTO_MD5_HMAC) {
++ MD5Init(&md5ctx);
++ MD5Update(&md5ctx, key, klen);
++ MD5Update(&md5ctx, hmac_ipad_buffer, MD5_HMAC_BLOCK_LEN - klen);
++ bcopy(md5ctx.md5_st8, ses->ses_hminner, sizeof(md5ctx.md5_st8));
++ } else {
++ SHA1Init(&sha1ctx);
++ SHA1Update(&sha1ctx, key, klen);
++ SHA1Update(&sha1ctx, hmac_ipad_buffer,
++ SHA1_HMAC_BLOCK_LEN - klen);
++ bcopy(sha1ctx.h.b32, ses->ses_hminner, sizeof(sha1ctx.h.b32));
++ }
++
++ for (i = 0; i < klen; i++)
++ key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
++
++ if (algo == CRYPTO_MD5_HMAC) {
++ MD5Init(&md5ctx);
++ MD5Update(&md5ctx, key, klen);
++ MD5Update(&md5ctx, hmac_opad_buffer, MD5_HMAC_BLOCK_LEN - klen);
++ bcopy(md5ctx.md5_st8, ses->ses_hmouter, sizeof(md5ctx.md5_st8));
++ } else {
++ SHA1Init(&sha1ctx);
++ SHA1Update(&sha1ctx, key, klen);
++ SHA1Update(&sha1ctx, hmac_opad_buffer,
++ SHA1_HMAC_BLOCK_LEN - klen);
++ bcopy(sha1ctx.h.b32, ses->ses_hmouter, sizeof(sha1ctx.h.b32));
++ }
++
++ for (i = 0; i < klen; i++)
++ key[i] ^= HMAC_OPAD_VAL;
++
++#if 0
++ /*
++ * this code prevents SHA working on a BE host,
++ * so it is obviously wrong. I think the byte
++ * swap setup we do with the chip fixes this for us
++ */
++
++ /* PE is little-endian, insure proper byte order */
++ for (i = 0; i < N(ses->ses_hminner); i++) {
++ ses->ses_hminner[i] = htole32(ses->ses_hminner[i]);
++ ses->ses_hmouter[i] = htole32(ses->ses_hmouter[i]);
++ }
++#endif
++#else /* HMAC_HACK */
++ printk("safe: md5/sha not implemented\n");
++#endif /* HMAC_HACK */
++}
++#undef N
++
++/*
++ * Allocate a new 'session' and return an encoded session id. 'sidp'
++ * contains our registration id, and should contain an encoded session
++ * id on successful allocation.
++ */
++static int
++safe_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
++{
++ struct safe_softc *sc = device_get_softc(dev);
++ struct cryptoini *c, *encini = NULL, *macini = NULL;
++ struct safe_session *ses = NULL;
++ int sesn;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ if (sidp == NULL || cri == NULL || sc == NULL)
++ return (EINVAL);
++
++ for (c = cri; c != NULL; c = c->cri_next) {
++ if (c->cri_alg == CRYPTO_MD5_HMAC ||
++ c->cri_alg == CRYPTO_SHA1_HMAC ||
++ c->cri_alg == CRYPTO_NULL_HMAC) {
++ if (macini)
++ return (EINVAL);
++ macini = c;
++ } else if (c->cri_alg == CRYPTO_DES_CBC ||
++ c->cri_alg == CRYPTO_3DES_CBC ||
++ c->cri_alg == CRYPTO_AES_CBC ||
++ c->cri_alg == CRYPTO_NULL_CBC) {
++ if (encini)
++ return (EINVAL);
++ encini = c;
++ } else
++ return (EINVAL);
++ }
++ if (encini == NULL && macini == NULL)
++ return (EINVAL);
++ if (encini) { /* validate key length */
++ switch (encini->cri_alg) {
++ case CRYPTO_DES_CBC:
++ if (encini->cri_klen != 64)
++ return (EINVAL);
++ break;
++ case CRYPTO_3DES_CBC:
++ if (encini->cri_klen != 192)
++ return (EINVAL);
++ break;
++ case CRYPTO_AES_CBC:
++ if (encini->cri_klen != 128 &&
++ encini->cri_klen != 192 &&
++ encini->cri_klen != 256)
++ return (EINVAL);
++ break;
++ }
++ }
++
++ if (sc->sc_sessions == NULL) {
++ ses = sc->sc_sessions = (struct safe_session *)
++ kmalloc(sizeof(struct safe_session), SLAB_ATOMIC);
++ if (ses == NULL)
++ return (ENOMEM);
++ memset(ses, 0, sizeof(struct safe_session));
++ sesn = 0;
++ sc->sc_nsessions = 1;
++ } else {
++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
++ if (sc->sc_sessions[sesn].ses_used == 0) {
++ ses = &sc->sc_sessions[sesn];
++ break;
++ }
++ }
++
++ if (ses == NULL) {
++ sesn = sc->sc_nsessions;
++ ses = (struct safe_session *)
++ kmalloc((sesn + 1) * sizeof(struct safe_session), SLAB_ATOMIC);
++ if (ses == NULL)
++ return (ENOMEM);
++ memset(ses, 0, (sesn + 1) * sizeof(struct safe_session));
++ bcopy(sc->sc_sessions, ses, sesn *
++ sizeof(struct safe_session));
++ bzero(sc->sc_sessions, sesn *
++ sizeof(struct safe_session));
++ kfree(sc->sc_sessions);
++ sc->sc_sessions = ses;
++ ses = &sc->sc_sessions[sesn];
++ sc->sc_nsessions++;
++ }
++ }
++
++ bzero(ses, sizeof(struct safe_session));
++ ses->ses_used = 1;
++
++ if (encini) {
++ /* get an IV */
++ /* XXX may read fewer than requested */
++ read_random(ses->ses_iv, sizeof(ses->ses_iv));
++
++ ses->ses_klen = encini->cri_klen;
++ if (encini->cri_key != NULL)
++ safe_setup_enckey(ses, encini->cri_key);
++ }
++
++ if (macini) {
++ ses->ses_mlen = macini->cri_mlen;
++ if (ses->ses_mlen == 0) {
++ if (macini->cri_alg == CRYPTO_MD5_HMAC)
++ ses->ses_mlen = MD5_HASH_LEN;
++ else
++ ses->ses_mlen = SHA1_HASH_LEN;
++ }
++
++ if (macini->cri_key != NULL) {
++ safe_setup_mackey(ses, macini->cri_alg, macini->cri_key,
++ macini->cri_klen / 8);
++ }
++ }
++
++ *sidp = SAFE_SID(device_get_unit(sc->sc_dev), sesn);
++ return (0);
++}
++
++/*
++ * Deallocate a session.
++ */
++static int
++safe_freesession(device_t dev, u_int64_t tid)
++{
++ struct safe_softc *sc = device_get_softc(dev);
++ int session, ret;
++ u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ if (sc == NULL)
++ return (EINVAL);
++
++ session = SAFE_SESSION(sid);
++ if (session < sc->sc_nsessions) {
++ bzero(&sc->sc_sessions[session], sizeof(sc->sc_sessions[session]));
++ ret = 0;
++ } else
++ ret = EINVAL;
++ return (ret);
++}
++
++
++static int
++safe_process(device_t dev, struct cryptop *crp, int hint)
++{
++ struct safe_softc *sc = device_get_softc(dev);
++ int err = 0, i, nicealign, uniform;
++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
++ int bypass, oplen, ivsize;
++ caddr_t iv;
++ int16_t coffset;
++ struct safe_session *ses;
++ struct safe_ringentry *re;
++ struct safe_sarec *sa;
++ struct safe_pdesc *pd;
++ u_int32_t cmd0, cmd1, staterec;
++ unsigned long flags;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ if (crp == NULL || crp->crp_callback == NULL || sc == NULL) {
++ safestats.st_invalid++;
++ return (EINVAL);
++ }
++ if (SAFE_SESSION(crp->crp_sid) >= sc->sc_nsessions) {
++ safestats.st_badsession++;
++ return (EINVAL);
++ }
++
++ spin_lock_irqsave(&sc->sc_ringmtx, flags);
++ if (sc->sc_front == sc->sc_back && sc->sc_nqchip != 0) {
++ safestats.st_ringfull++;
++ sc->sc_needwakeup |= CRYPTO_SYMQ;
++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags);
++ return (ERESTART);
++ }
++ re = sc->sc_front;
++
++ staterec = re->re_sa.sa_staterec; /* save */
++ /* NB: zero everything but the PE descriptor */
++ bzero(&re->re_sa, sizeof(struct safe_ringentry) - sizeof(re->re_desc));
++ re->re_sa.sa_staterec = staterec; /* restore */
++
++ re->re_crp = crp;
++ re->re_sesn = SAFE_SESSION(crp->crp_sid);
++
++ re->re_src.nsegs = 0;
++ re->re_dst.nsegs = 0;
++
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ re->re_src_skb = (struct sk_buff *)crp->crp_buf;
++ re->re_dst_skb = (struct sk_buff *)crp->crp_buf;
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ re->re_src_io = (struct uio *)crp->crp_buf;
++ re->re_dst_io = (struct uio *)crp->crp_buf;
++ } else {
++ safestats.st_badflags++;
++ err = EINVAL;
++ goto errout; /* XXX we don't handle contiguous blocks! */
++ }
++
++ sa = &re->re_sa;
++ ses = &sc->sc_sessions[re->re_sesn];
++
++ crd1 = crp->crp_desc;
++ if (crd1 == NULL) {
++ safestats.st_nodesc++;
++ err = EINVAL;
++ goto errout;
++ }
++ crd2 = crd1->crd_next;
++
++ cmd0 = SAFE_SA_CMD0_BASIC; /* basic group operation */
++ cmd1 = 0;
++ if (crd2 == NULL) {
++ if (crd1->crd_alg == CRYPTO_MD5_HMAC ||
++ crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++ crd1->crd_alg == CRYPTO_NULL_HMAC) {
++ maccrd = crd1;
++ enccrd = NULL;
++ cmd0 |= SAFE_SA_CMD0_OP_HASH;
++ } else if (crd1->crd_alg == CRYPTO_DES_CBC ||
++ crd1->crd_alg == CRYPTO_3DES_CBC ||
++ crd1->crd_alg == CRYPTO_AES_CBC ||
++ crd1->crd_alg == CRYPTO_NULL_CBC) {
++ maccrd = NULL;
++ enccrd = crd1;
++ cmd0 |= SAFE_SA_CMD0_OP_CRYPT;
++ } else {
++ safestats.st_badalg++;
++ err = EINVAL;
++ goto errout;
++ }
++ } else {
++ if ((crd1->crd_alg == CRYPTO_MD5_HMAC ||
++ crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++ crd1->crd_alg == CRYPTO_NULL_HMAC) &&
++ (crd2->crd_alg == CRYPTO_DES_CBC ||
++ crd2->crd_alg == CRYPTO_3DES_CBC ||
++ crd2->crd_alg == CRYPTO_AES_CBC ||
++ crd2->crd_alg == CRYPTO_NULL_CBC) &&
++ ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) {
++ maccrd = crd1;
++ enccrd = crd2;
++ } else if ((crd1->crd_alg == CRYPTO_DES_CBC ||
++ crd1->crd_alg == CRYPTO_3DES_CBC ||
++ crd1->crd_alg == CRYPTO_AES_CBC ||
++ crd1->crd_alg == CRYPTO_NULL_CBC) &&
++ (crd2->crd_alg == CRYPTO_MD5_HMAC ||
++ crd2->crd_alg == CRYPTO_SHA1_HMAC ||
++ crd2->crd_alg == CRYPTO_NULL_HMAC) &&
++ (crd1->crd_flags & CRD_F_ENCRYPT)) {
++ enccrd = crd1;
++ maccrd = crd2;
++ } else {
++ safestats.st_badalg++;
++ err = EINVAL;
++ goto errout;
++ }
++ cmd0 |= SAFE_SA_CMD0_OP_BOTH;
++ }
++
++ if (enccrd) {
++ if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT)
++ safe_setup_enckey(ses, enccrd->crd_key);
++
++ if (enccrd->crd_alg == CRYPTO_DES_CBC) {
++ cmd0 |= SAFE_SA_CMD0_DES;
++ cmd1 |= SAFE_SA_CMD1_CBC;
++ ivsize = 2*sizeof(u_int32_t);
++ } else if (enccrd->crd_alg == CRYPTO_3DES_CBC) {
++ cmd0 |= SAFE_SA_CMD0_3DES;
++ cmd1 |= SAFE_SA_CMD1_CBC;
++ ivsize = 2*sizeof(u_int32_t);
++ } else if (enccrd->crd_alg == CRYPTO_AES_CBC) {
++ cmd0 |= SAFE_SA_CMD0_AES;
++ cmd1 |= SAFE_SA_CMD1_CBC;
++ if (ses->ses_klen == 128)
++ cmd1 |= SAFE_SA_CMD1_AES128;
++ else if (ses->ses_klen == 192)
++ cmd1 |= SAFE_SA_CMD1_AES192;
++ else
++ cmd1 |= SAFE_SA_CMD1_AES256;
++ ivsize = 4*sizeof(u_int32_t);
++ } else {
++ cmd0 |= SAFE_SA_CMD0_CRYPT_NULL;
++ ivsize = 0;
++ }
++
++ /*
++ * Setup encrypt/decrypt state. When using basic ops
++ * we can't use an inline IV because hash/crypt offset
++ * must be from the end of the IV to the start of the
++ * crypt data and this leaves out the preceding header
++ * from the hash calculation. Instead we place the IV
++ * in the state record and set the hash/crypt offset to
++ * copy both the header+IV.
++ */
++ if (enccrd->crd_flags & CRD_F_ENCRYPT) {
++ cmd0 |= SAFE_SA_CMD0_OUTBOUND;
++
++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++ iv = enccrd->crd_iv;
++ else
++ iv = (caddr_t) ses->ses_iv;
++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++ crypto_copyback(crp->crp_flags, crp->crp_buf,
++ enccrd->crd_inject, ivsize, iv);
++ }
++ bcopy(iv, re->re_sastate.sa_saved_iv, ivsize);
++ /* make iv LE */
++ for (i = 0; i < ivsize/sizeof(re->re_sastate.sa_saved_iv[0]); i++)
++ re->re_sastate.sa_saved_iv[i] =
++ cpu_to_le32(re->re_sastate.sa_saved_iv[i]);
++ cmd0 |= SAFE_SA_CMD0_IVLD_STATE | SAFE_SA_CMD0_SAVEIV;
++ re->re_flags |= SAFE_QFLAGS_COPYOUTIV;
++ } else {
++ cmd0 |= SAFE_SA_CMD0_INBOUND;
++
++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) {
++ bcopy(enccrd->crd_iv,
++ re->re_sastate.sa_saved_iv, ivsize);
++ } else {
++ crypto_copydata(crp->crp_flags, crp->crp_buf,
++ enccrd->crd_inject, ivsize,
++ (caddr_t)re->re_sastate.sa_saved_iv);
++ }
++ /* make iv LE */
++ for (i = 0; i < ivsize/sizeof(re->re_sastate.sa_saved_iv[0]); i++)
++ re->re_sastate.sa_saved_iv[i] =
++ cpu_to_le32(re->re_sastate.sa_saved_iv[i]);
++ cmd0 |= SAFE_SA_CMD0_IVLD_STATE;
++ }
++ /*
++ * For basic encryption use the zero pad algorithm.
++ * This pads results to an 8-byte boundary and
++ * suppresses padding verification for inbound (i.e.
++ * decrypt) operations.
++ *
++ * NB: Not sure if the 8-byte pad boundary is a problem.
++ */
++ cmd0 |= SAFE_SA_CMD0_PAD_ZERO;
++
++ /* XXX assert key bufs have the same size */
++ bcopy(ses->ses_key, sa->sa_key, sizeof(sa->sa_key));
++ }
++
++ if (maccrd) {
++ if (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
++ safe_setup_mackey(ses, maccrd->crd_alg,
++ maccrd->crd_key, maccrd->crd_klen / 8);
++ }
++
++ if (maccrd->crd_alg == CRYPTO_MD5_HMAC) {
++ cmd0 |= SAFE_SA_CMD0_MD5;
++ cmd1 |= SAFE_SA_CMD1_HMAC; /* NB: enable HMAC */
++ } else if (maccrd->crd_alg == CRYPTO_SHA1_HMAC) {
++ cmd0 |= SAFE_SA_CMD0_SHA1;
++ cmd1 |= SAFE_SA_CMD1_HMAC; /* NB: enable HMAC */
++ } else {
++ cmd0 |= SAFE_SA_CMD0_HASH_NULL;
++ }
++ /*
++ * Digest data is loaded from the SA and the hash
++ * result is saved to the state block where we
++ * retrieve it for return to the caller.
++ */
++ /* XXX assert digest bufs have the same size */
++ bcopy(ses->ses_hminner, sa->sa_indigest,
++ sizeof(sa->sa_indigest));
++ bcopy(ses->ses_hmouter, sa->sa_outdigest,
++ sizeof(sa->sa_outdigest));
++
++ cmd0 |= SAFE_SA_CMD0_HSLD_SA | SAFE_SA_CMD0_SAVEHASH;
++ re->re_flags |= SAFE_QFLAGS_COPYOUTICV;
++ }
++
++ if (enccrd && maccrd) {
++ /*
++ * The offset from hash data to the start of
++ * crypt data is the difference in the skips.
++ */
++ bypass = maccrd->crd_skip;
++ coffset = enccrd->crd_skip - maccrd->crd_skip;
++ if (coffset < 0) {
++ DPRINTF(("%s: hash does not precede crypt; "
++ "mac skip %u enc skip %u\n",
++ __func__, maccrd->crd_skip, enccrd->crd_skip));
++ safestats.st_skipmismatch++;
++ err = EINVAL;
++ goto errout;
++ }
++ oplen = enccrd->crd_skip + enccrd->crd_len;
++ if (maccrd->crd_skip + maccrd->crd_len != oplen) {
++ DPRINTF(("%s: hash amount %u != crypt amount %u\n",
++ __func__, maccrd->crd_skip + maccrd->crd_len,
++ oplen));
++ safestats.st_lenmismatch++;
++ err = EINVAL;
++ goto errout;
++ }
++#ifdef SAFE_DEBUG
++ if (debug) {
++ printf("mac: skip %d, len %d, inject %d\n",
++ maccrd->crd_skip, maccrd->crd_len,
++ maccrd->crd_inject);
++ printf("enc: skip %d, len %d, inject %d\n",
++ enccrd->crd_skip, enccrd->crd_len,
++ enccrd->crd_inject);
++ printf("bypass %d coffset %d oplen %d\n",
++ bypass, coffset, oplen);
++ }
++#endif
++ if (coffset & 3) { /* offset must be 32-bit aligned */
++ DPRINTF(("%s: coffset %u misaligned\n",
++ __func__, coffset));
++ safestats.st_coffmisaligned++;
++ err = EINVAL;
++ goto errout;
++ }
++ coffset >>= 2;
++ if (coffset > 255) { /* offset must be <256 dwords */
++ DPRINTF(("%s: coffset %u too big\n",
++ __func__, coffset));
++ safestats.st_cofftoobig++;
++ err = EINVAL;
++ goto errout;
++ }
++ /*
++ * Tell the hardware to copy the header to the output.
++ * The header is defined as the data from the end of
++ * the bypass to the start of data to be encrypted.
++ * Typically this is the inline IV. Note that you need
++ * to do this even if src+dst are the same; it appears
++ * that w/o this bit the crypted data is written
++ * immediately after the bypass data.
++ */
++ cmd1 |= SAFE_SA_CMD1_HDRCOPY;
++ /*
++ * Disable IP header mutable bit handling. This is
++ * needed to get correct HMAC calculations.
++ */
++ cmd1 |= SAFE_SA_CMD1_MUTABLE;
++ } else {
++ if (enccrd) {
++ bypass = enccrd->crd_skip;
++ oplen = bypass + enccrd->crd_len;
++ } else {
++ bypass = maccrd->crd_skip;
++ oplen = bypass + maccrd->crd_len;
++ }
++ coffset = 0;
++ }
++ /* XXX verify multiple of 4 when using s/g */
++ if (bypass > 96) { /* bypass offset must be <= 96 bytes */
++ DPRINTF(("%s: bypass %u too big\n", __func__, bypass));
++ safestats.st_bypasstoobig++;
++ err = EINVAL;
++ goto errout;
++ }
++
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ if (pci_map_skb(sc, &re->re_src, re->re_src_skb)) {
++ safestats.st_noload++;
++ err = ENOMEM;
++ goto errout;
++ }
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ if (pci_map_uio(sc, &re->re_src, re->re_src_io)) {
++ safestats.st_noload++;
++ err = ENOMEM;
++ goto errout;
++ }
++ }
++ nicealign = safe_dmamap_aligned(sc, &re->re_src);
++ uniform = safe_dmamap_uniform(sc, &re->re_src);
++
++ DPRINTF(("src nicealign %u uniform %u nsegs %u\n",
++ nicealign, uniform, re->re_src.nsegs));
++ if (re->re_src.nsegs > 1) {
++ re->re_desc.d_src = sc->sc_spalloc.dma_paddr +
++ ((caddr_t) sc->sc_spfree - (caddr_t) sc->sc_spring);
++ for (i = 0; i < re->re_src_nsegs; i++) {
++ /* NB: no need to check if there's space */
++ pd = sc->sc_spfree;
++ if (++(sc->sc_spfree) == sc->sc_springtop)
++ sc->sc_spfree = sc->sc_spring;
++
++ KASSERT((pd->pd_flags&3) == 0 ||
++ (pd->pd_flags&3) == SAFE_PD_DONE,
++ ("bogus source particle descriptor; flags %x",
++ pd->pd_flags));
++ pd->pd_addr = re->re_src_segs[i].ds_addr;
++ pd->pd_size = re->re_src_segs[i].ds_len;
++ pd->pd_flags = SAFE_PD_READY;
++ }
++ cmd0 |= SAFE_SA_CMD0_IGATHER;
++ } else {
++ /*
++ * No need for gather, reference the operand directly.
++ */
++ re->re_desc.d_src = re->re_src_segs[0].ds_addr;
++ }
++
++ if (enccrd == NULL && maccrd != NULL) {
++ /*
++ * Hash op; no destination needed.
++ */
++ } else {
++ if (crp->crp_flags & (CRYPTO_F_IOV|CRYPTO_F_SKBUF)) {
++ if (!nicealign) {
++ safestats.st_iovmisaligned++;
++ err = EINVAL;
++ goto errout;
++ }
++ if (uniform != 1) {
++ device_printf(sc->sc_dev, "!uniform source\n");
++ if (!uniform) {
++ /*
++ * There's no way to handle the DMA
++ * requirements with this uio. We
++ * could create a separate DMA area for
++ * the result and then copy it back,
++ * but for now we just bail and return
++ * an error. Note that uio requests
++ * > SAFE_MAX_DSIZE are handled because
++ * the DMA map and segment list for the
++ * destination wil result in a
++ * destination particle list that does
++ * the necessary scatter DMA.
++ */
++ safestats.st_iovnotuniform++;
++ err = EINVAL;
++ goto errout;
++ }
++ } else
++ re->re_dst = re->re_src;
++ } else {
++ safestats.st_badflags++;
++ err = EINVAL;
++ goto errout;
++ }
++
++ if (re->re_dst.nsegs > 1) {
++ re->re_desc.d_dst = sc->sc_dpalloc.dma_paddr +
++ ((caddr_t) sc->sc_dpfree - (caddr_t) sc->sc_dpring);
++ for (i = 0; i < re->re_dst_nsegs; i++) {
++ pd = sc->sc_dpfree;
++ KASSERT((pd->pd_flags&3) == 0 ||
++ (pd->pd_flags&3) == SAFE_PD_DONE,
++ ("bogus dest particle descriptor; flags %x",
++ pd->pd_flags));
++ if (++(sc->sc_dpfree) == sc->sc_dpringtop)
++ sc->sc_dpfree = sc->sc_dpring;
++ pd->pd_addr = re->re_dst_segs[i].ds_addr;
++ pd->pd_flags = SAFE_PD_READY;
++ }
++ cmd0 |= SAFE_SA_CMD0_OSCATTER;
++ } else {
++ /*
++ * No need for scatter, reference the operand directly.
++ */
++ re->re_desc.d_dst = re->re_dst_segs[0].ds_addr;
++ }
++ }
++
++ /*
++ * All done with setup; fillin the SA command words
++ * and the packet engine descriptor. The operation
++ * is now ready for submission to the hardware.
++ */
++ sa->sa_cmd0 = cmd0 | SAFE_SA_CMD0_IPCI | SAFE_SA_CMD0_OPCI;
++ sa->sa_cmd1 = cmd1
++ | (coffset << SAFE_SA_CMD1_OFFSET_S)
++ | SAFE_SA_CMD1_SAREV1 /* Rev 1 SA data structure */
++ | SAFE_SA_CMD1_SRPCI
++ ;
++ /*
++ * NB: the order of writes is important here. In case the
++ * chip is scanning the ring because of an outstanding request
++ * it might nab this one too. In that case we need to make
++ * sure the setup is complete before we write the length
++ * field of the descriptor as it signals the descriptor is
++ * ready for processing.
++ */
++ re->re_desc.d_csr = SAFE_PE_CSR_READY | SAFE_PE_CSR_SAPCI;
++ if (maccrd)
++ re->re_desc.d_csr |= SAFE_PE_CSR_LOADSA | SAFE_PE_CSR_HASHFINAL;
++ wmb();
++ re->re_desc.d_len = oplen
++ | SAFE_PE_LEN_READY
++ | (bypass << SAFE_PE_LEN_BYPASS_S)
++ ;
++
++ safestats.st_ipackets++;
++ safestats.st_ibytes += oplen;
++
++ if (++(sc->sc_front) == sc->sc_ringtop)
++ sc->sc_front = sc->sc_ring;
++
++ /* XXX honor batching */
++ safe_feed(sc, re);
++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags);
++ return (0);
++
++errout:
++ if (re->re_src.map != re->re_dst.map)
++ pci_unmap_operand(sc, &re->re_dst);
++ if (re->re_src.map)
++ pci_unmap_operand(sc, &re->re_src);
++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags);
++ if (err != ERESTART) {
++ crp->crp_etype = err;
++ crypto_done(crp);
++ } else {
++ sc->sc_needwakeup |= CRYPTO_SYMQ;
++ }
++ return (err);
++}
++
++static void
++safe_callback(struct safe_softc *sc, struct safe_ringentry *re)
++{
++ struct cryptop *crp = (struct cryptop *)re->re_crp;
++ struct cryptodesc *crd;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ safestats.st_opackets++;
++ safestats.st_obytes += re->re_dst.mapsize;
++
++ if (re->re_desc.d_csr & SAFE_PE_CSR_STATUS) {
++ device_printf(sc->sc_dev, "csr 0x%x cmd0 0x%x cmd1 0x%x\n",
++ re->re_desc.d_csr,
++ re->re_sa.sa_cmd0, re->re_sa.sa_cmd1);
++ safestats.st_peoperr++;
++ crp->crp_etype = EIO; /* something more meaningful? */
++ }
++
++ if (re->re_dst.map != NULL && re->re_dst.map != re->re_src.map)
++ pci_unmap_operand(sc, &re->re_dst);
++ pci_unmap_operand(sc, &re->re_src);
++
++ /*
++ * If result was written to a differet mbuf chain, swap
++ * it in as the return value and reclaim the original.
++ */
++ if ((crp->crp_flags & CRYPTO_F_SKBUF) && re->re_src_skb != re->re_dst_skb) {
++ device_printf(sc->sc_dev, "no CRYPTO_F_SKBUF swapping support\n");
++ /* kfree_skb(skb) */
++ /* crp->crp_buf = (caddr_t)re->re_dst_skb */
++ return;
++ }
++
++ if (re->re_flags & SAFE_QFLAGS_COPYOUTIV) {
++ /* copy out IV for future use */
++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
++ int i;
++ int ivsize;
++
++ if (crd->crd_alg == CRYPTO_DES_CBC ||
++ crd->crd_alg == CRYPTO_3DES_CBC) {
++ ivsize = 2*sizeof(u_int32_t);
++ } else if (crd->crd_alg == CRYPTO_AES_CBC) {
++ ivsize = 4*sizeof(u_int32_t);
++ } else
++ continue;
++ crypto_copydata(crp->crp_flags, crp->crp_buf,
++ crd->crd_skip + crd->crd_len - ivsize, ivsize,
++ (caddr_t)sc->sc_sessions[re->re_sesn].ses_iv);
++ for (i = 0;
++ i < ivsize/sizeof(sc->sc_sessions[re->re_sesn].ses_iv[0]);
++ i++)
++ sc->sc_sessions[re->re_sesn].ses_iv[i] =
++ cpu_to_le32(sc->sc_sessions[re->re_sesn].ses_iv[i]);
++ break;
++ }
++ }
++
++ if (re->re_flags & SAFE_QFLAGS_COPYOUTICV) {
++ /* copy out ICV result */
++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
++ if (!(crd->crd_alg == CRYPTO_MD5_HMAC ||
++ crd->crd_alg == CRYPTO_SHA1_HMAC ||
++ crd->crd_alg == CRYPTO_NULL_HMAC))
++ continue;
++ if (crd->crd_alg == CRYPTO_SHA1_HMAC) {
++ /*
++ * SHA-1 ICV's are byte-swapped; fix 'em up
++ * before copy them to their destination.
++ */
++ re->re_sastate.sa_saved_indigest[0] =
++ cpu_to_be32(re->re_sastate.sa_saved_indigest[0]);
++ re->re_sastate.sa_saved_indigest[1] =
++ cpu_to_be32(re->re_sastate.sa_saved_indigest[1]);
++ re->re_sastate.sa_saved_indigest[2] =
++ cpu_to_be32(re->re_sastate.sa_saved_indigest[2]);
++ } else {
++ re->re_sastate.sa_saved_indigest[0] =
++ cpu_to_le32(re->re_sastate.sa_saved_indigest[0]);
++ re->re_sastate.sa_saved_indigest[1] =
++ cpu_to_le32(re->re_sastate.sa_saved_indigest[1]);
++ re->re_sastate.sa_saved_indigest[2] =
++ cpu_to_le32(re->re_sastate.sa_saved_indigest[2]);
++ }
++ crypto_copyback(crp->crp_flags, crp->crp_buf,
++ crd->crd_inject,
++ sc->sc_sessions[re->re_sesn].ses_mlen,
++ (caddr_t)re->re_sastate.sa_saved_indigest);
++ break;
++ }
++ }
++ crypto_done(crp);
++}
++
++
++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG)
++#define SAFE_RNG_MAXWAIT 1000
++
++static void
++safe_rng_init(struct safe_softc *sc)
++{
++ u_int32_t w, v;
++ int i;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ WRITE_REG(sc, SAFE_RNG_CTRL, 0);
++ /* use default value according to the manual */
++ WRITE_REG(sc, SAFE_RNG_CNFG, 0x834); /* magic from SafeNet */
++ WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0);
++
++ /*
++ * There is a bug in rev 1.0 of the 1140 that when the RNG
++ * is brought out of reset the ready status flag does not
++ * work until the RNG has finished its internal initialization.
++ *
++ * So in order to determine the device is through its
++ * initialization we must read the data register, using the
++ * status reg in the read in case it is initialized. Then read
++ * the data register until it changes from the first read.
++ * Once it changes read the data register until it changes
++ * again. At this time the RNG is considered initialized.
++ * This could take between 750ms - 1000ms in time.
++ */
++ i = 0;
++ w = READ_REG(sc, SAFE_RNG_OUT);
++ do {
++ v = READ_REG(sc, SAFE_RNG_OUT);
++ if (v != w) {
++ w = v;
++ break;
++ }
++ DELAY(10);
++ } while (++i < SAFE_RNG_MAXWAIT);
++
++ /* Wait Until data changes again */
++ i = 0;
++ do {
++ v = READ_REG(sc, SAFE_RNG_OUT);
++ if (v != w)
++ break;
++ DELAY(10);
++ } while (++i < SAFE_RNG_MAXWAIT);
++}
++
++static __inline void
++safe_rng_disable_short_cycle(struct safe_softc *sc)
++{
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ WRITE_REG(sc, SAFE_RNG_CTRL,
++ READ_REG(sc, SAFE_RNG_CTRL) &~ SAFE_RNG_CTRL_SHORTEN);
++}
++
++static __inline void
++safe_rng_enable_short_cycle(struct safe_softc *sc)
++{
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ WRITE_REG(sc, SAFE_RNG_CTRL,
++ READ_REG(sc, SAFE_RNG_CTRL) | SAFE_RNG_CTRL_SHORTEN);
++}
++
++static __inline u_int32_t
++safe_rng_read(struct safe_softc *sc)
++{
++ int i;
++
++ i = 0;
++ while (READ_REG(sc, SAFE_RNG_STAT) != 0 && ++i < SAFE_RNG_MAXWAIT)
++ ;
++ return READ_REG(sc, SAFE_RNG_OUT);
++}
++
++static int
++safe_read_random(void *arg, u_int32_t *buf, int maxwords)
++{
++ struct safe_softc *sc = (struct safe_softc *) arg;
++ int i, rc;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ safestats.st_rng++;
++ /*
++ * Fetch the next block of data.
++ */
++ if (maxwords > safe_rngbufsize)
++ maxwords = safe_rngbufsize;
++ if (maxwords > SAFE_RNG_MAXBUFSIZ)
++ maxwords = SAFE_RNG_MAXBUFSIZ;
++retry:
++ /* read as much as we can */
++ for (rc = 0; rc < maxwords; rc++) {
++ if (READ_REG(sc, SAFE_RNG_STAT) != 0)
++ break;
++ buf[rc] = READ_REG(sc, SAFE_RNG_OUT);
++ }
++ if (rc == 0)
++ return 0;
++ /*
++ * Check the comparator alarm count and reset the h/w if
++ * it exceeds our threshold. This guards against the
++ * hardware oscillators resonating with external signals.
++ */
++ if (READ_REG(sc, SAFE_RNG_ALM_CNT) > safe_rngmaxalarm) {
++ u_int32_t freq_inc, w;
++
++ DPRINTF(("%s: alarm count %u exceeds threshold %u\n", __func__,
++ (unsigned)READ_REG(sc, SAFE_RNG_ALM_CNT), safe_rngmaxalarm));
++ safestats.st_rngalarm++;
++ safe_rng_enable_short_cycle(sc);
++ freq_inc = 18;
++ for (i = 0; i < 64; i++) {
++ w = READ_REG(sc, SAFE_RNG_CNFG);
++ freq_inc = ((w + freq_inc) & 0x3fL);
++ w = ((w & ~0x3fL) | freq_inc);
++ WRITE_REG(sc, SAFE_RNG_CNFG, w);
++
++ WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0);
++
++ (void) safe_rng_read(sc);
++ DELAY(25);
++
++ if (READ_REG(sc, SAFE_RNG_ALM_CNT) == 0) {
++ safe_rng_disable_short_cycle(sc);
++ goto retry;
++ }
++ freq_inc = 1;
++ }
++ safe_rng_disable_short_cycle(sc);
++ } else
++ WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0);
++
++ return(rc);
++}
++#endif /* defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) */
++
++
++/*
++ * Resets the board. Values in the regesters are left as is
++ * from the reset (i.e. initial values are assigned elsewhere).
++ */
++static void
++safe_reset_board(struct safe_softc *sc)
++{
++ u_int32_t v;
++ /*
++ * Reset the device. The manual says no delay
++ * is needed between marking and clearing reset.
++ */
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ v = READ_REG(sc, SAFE_PE_DMACFG) &~
++ (SAFE_PE_DMACFG_PERESET | SAFE_PE_DMACFG_PDRRESET |
++ SAFE_PE_DMACFG_SGRESET);
++ WRITE_REG(sc, SAFE_PE_DMACFG, v
++ | SAFE_PE_DMACFG_PERESET
++ | SAFE_PE_DMACFG_PDRRESET
++ | SAFE_PE_DMACFG_SGRESET);
++ WRITE_REG(sc, SAFE_PE_DMACFG, v);
++}
++
++/*
++ * Initialize registers we need to touch only once.
++ */
++static void
++safe_init_board(struct safe_softc *sc)
++{
++ u_int32_t v, dwords;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ v = READ_REG(sc, SAFE_PE_DMACFG);
++ v &=~ ( SAFE_PE_DMACFG_PEMODE
++ | SAFE_PE_DMACFG_FSENA /* failsafe enable */
++ | SAFE_PE_DMACFG_GPRPCI /* gather ring on PCI */
++ | SAFE_PE_DMACFG_SPRPCI /* scatter ring on PCI */
++ | SAFE_PE_DMACFG_ESDESC /* endian-swap descriptors */
++ | SAFE_PE_DMACFG_ESPDESC /* endian-swap part. desc's */
++ | SAFE_PE_DMACFG_ESSA /* endian-swap SA's */
++ | SAFE_PE_DMACFG_ESPACKET /* swap the packet data */
++ );
++ v |= SAFE_PE_DMACFG_FSENA /* failsafe enable */
++ | SAFE_PE_DMACFG_GPRPCI /* gather ring on PCI */
++ | SAFE_PE_DMACFG_SPRPCI /* scatter ring on PCI */
++ | SAFE_PE_DMACFG_ESDESC /* endian-swap descriptors */
++ | SAFE_PE_DMACFG_ESPDESC /* endian-swap part. desc's */
++ | SAFE_PE_DMACFG_ESSA /* endian-swap SA's */
++#if 0
++ | SAFE_PE_DMACFG_ESPACKET /* swap the packet data */
++#endif
++ ;
++ WRITE_REG(sc, SAFE_PE_DMACFG, v);
++
++#ifdef __BIG_ENDIAN
++ /* tell the safenet that we are 4321 and not 1234 */
++ WRITE_REG(sc, SAFE_ENDIAN, 0xe4e41b1b);
++#endif
++
++ if (sc->sc_chiprev == SAFE_REV(1,0)) {
++ /*
++ * Avoid large PCI DMA transfers. Rev 1.0 has a bug where
++ * "target mode transfers" done while the chip is DMA'ing
++ * >1020 bytes cause the hardware to lockup. To avoid this
++ * we reduce the max PCI transfer size and use small source
++ * particle descriptors (<= 256 bytes).
++ */
++ WRITE_REG(sc, SAFE_DMA_CFG, 256);
++ device_printf(sc->sc_dev,
++ "Reduce max DMA size to %u words for rev %u.%u WAR\n",
++ (unsigned) ((READ_REG(sc, SAFE_DMA_CFG)>>2) & 0xff),
++ (unsigned) SAFE_REV_MAJ(sc->sc_chiprev),
++ (unsigned) SAFE_REV_MIN(sc->sc_chiprev));
++ sc->sc_max_dsize = 256;
++ } else {
++ sc->sc_max_dsize = SAFE_MAX_DSIZE;
++ }
++
++ /* NB: operands+results are overlaid */
++ WRITE_REG(sc, SAFE_PE_PDRBASE, sc->sc_ringalloc.dma_paddr);
++ WRITE_REG(sc, SAFE_PE_RDRBASE, sc->sc_ringalloc.dma_paddr);
++ /*
++ * Configure ring entry size and number of items in the ring.
++ */
++ KASSERT((sizeof(struct safe_ringentry) % sizeof(u_int32_t)) == 0,
++ ("PE ring entry not 32-bit aligned!"));
++ dwords = sizeof(struct safe_ringentry) / sizeof(u_int32_t);
++ WRITE_REG(sc, SAFE_PE_RINGCFG,
++ (dwords << SAFE_PE_RINGCFG_OFFSET_S) | SAFE_MAX_NQUEUE);
++ WRITE_REG(sc, SAFE_PE_RINGPOLL, 0); /* disable polling */
++
++ WRITE_REG(sc, SAFE_PE_GRNGBASE, sc->sc_spalloc.dma_paddr);
++ WRITE_REG(sc, SAFE_PE_SRNGBASE, sc->sc_dpalloc.dma_paddr);
++ WRITE_REG(sc, SAFE_PE_PARTSIZE,
++ (SAFE_TOTAL_DPART<<16) | SAFE_TOTAL_SPART);
++ /*
++ * NB: destination particles are fixed size. We use
++ * an mbuf cluster and require all results go to
++ * clusters or smaller.
++ */
++ WRITE_REG(sc, SAFE_PE_PARTCFG, sc->sc_max_dsize);
++
++ /* it's now safe to enable PE mode, do it */
++ WRITE_REG(sc, SAFE_PE_DMACFG, v | SAFE_PE_DMACFG_PEMODE);
++
++ /*
++ * Configure hardware to use level-triggered interrupts and
++ * to interrupt after each descriptor is processed.
++ */
++ WRITE_REG(sc, SAFE_HI_CFG, SAFE_HI_CFG_LEVEL);
++ WRITE_REG(sc, SAFE_HI_CLR, 0xffffffff);
++ WRITE_REG(sc, SAFE_HI_DESC_CNT, 1);
++ WRITE_REG(sc, SAFE_HI_MASK, SAFE_INT_PE_DDONE | SAFE_INT_PE_ERROR);
++}
++
++
++/*
++ * Clean up after a chip crash.
++ * It is assumed that the caller in splimp()
++ */
++static void
++safe_cleanchip(struct safe_softc *sc)
++{
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ if (sc->sc_nqchip != 0) {
++ struct safe_ringentry *re = sc->sc_back;
++
++ while (re != sc->sc_front) {
++ if (re->re_desc.d_csr != 0)
++ safe_free_entry(sc, re);
++ if (++re == sc->sc_ringtop)
++ re = sc->sc_ring;
++ }
++ sc->sc_back = re;
++ sc->sc_nqchip = 0;
++ }
++}
++
++/*
++ * free a safe_q
++ * It is assumed that the caller is within splimp().
++ */
++static int
++safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re)
++{
++ struct cryptop *crp;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ /*
++ * Free header MCR
++ */
++ if ((re->re_dst_skb != NULL) && (re->re_src_skb != re->re_dst_skb))
++#ifdef NOTYET
++ m_freem(re->re_dst_m);
++#else
++ printk("%s,%d: SKB not supported\n", __FILE__, __LINE__);
++#endif
++
++ crp = (struct cryptop *)re->re_crp;
++
++ re->re_desc.d_csr = 0;
++
++ crp->crp_etype = EFAULT;
++ crypto_done(crp);
++ return(0);
++}
++
++/*
++ * Routine to reset the chip and clean up.
++ * It is assumed that the caller is in splimp()
++ */
++static void
++safe_totalreset(struct safe_softc *sc)
++{
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ safe_reset_board(sc);
++ safe_init_board(sc);
++ safe_cleanchip(sc);
++}
++
++/*
++ * Is the operand suitable aligned for direct DMA. Each
++ * segment must be aligned on a 32-bit boundary and all
++ * but the last segment must be a multiple of 4 bytes.
++ */
++static int
++safe_dmamap_aligned(struct safe_softc *sc, const struct safe_operand *op)
++{
++ int i;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ for (i = 0; i < op->nsegs; i++) {
++ if (op->segs[i].ds_addr & 3)
++ return (0);
++ if (i != (op->nsegs - 1) && (op->segs[i].ds_len & 3))
++ return (0);
++ }
++ return (1);
++}
++
++/*
++ * Is the operand suitable for direct DMA as the destination
++ * of an operation. The hardware requires that each ``particle''
++ * but the last in an operation result have the same size. We
++ * fix that size at SAFE_MAX_DSIZE bytes. This routine returns
++ * 0 if some segment is not a multiple of of this size, 1 if all
++ * segments are exactly this size, or 2 if segments are at worst
++ * a multple of this size.
++ */
++static int
++safe_dmamap_uniform(struct safe_softc *sc, const struct safe_operand *op)
++{
++ int result = 1;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ if (op->nsegs > 0) {
++ int i;
++
++ for (i = 0; i < op->nsegs-1; i++) {
++ if (op->segs[i].ds_len % sc->sc_max_dsize)
++ return (0);
++ if (op->segs[i].ds_len != sc->sc_max_dsize)
++ result = 2;
++ }
++ }
++ return (result);
++}
++
++static int
++safe_kprocess(device_t dev, struct cryptkop *krp, int hint)
++{
++ struct safe_softc *sc = device_get_softc(dev);
++ struct safe_pkq *q;
++ unsigned long flags;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ if (sc == NULL) {
++ krp->krp_status = EINVAL;
++ goto err;
++ }
++
++ if (krp->krp_op != CRK_MOD_EXP) {
++ krp->krp_status = EOPNOTSUPP;
++ goto err;
++ }
++
++ q = (struct safe_pkq *) kmalloc(sizeof(*q), GFP_KERNEL);
++ if (q == NULL) {
++ krp->krp_status = ENOMEM;
++ goto err;
++ }
++ memset(q, 0, sizeof(*q));
++ q->pkq_krp = krp;
++ INIT_LIST_HEAD(&q->pkq_list);
++
++ spin_lock_irqsave(&sc->sc_pkmtx, flags);
++ list_add_tail(&q->pkq_list, &sc->sc_pkq);
++ safe_kfeed(sc);
++ spin_unlock_irqrestore(&sc->sc_pkmtx, flags);
++ return (0);
++
++err:
++ crypto_kdone(krp);
++ return (0);
++}
++
++#define SAFE_CRK_PARAM_BASE 0
++#define SAFE_CRK_PARAM_EXP 1
++#define SAFE_CRK_PARAM_MOD 2
++
++static int
++safe_kstart(struct safe_softc *sc)
++{
++ struct cryptkop *krp = sc->sc_pkq_cur->pkq_krp;
++ int exp_bits, mod_bits, base_bits;
++ u_int32_t op, a_off, b_off, c_off, d_off;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ if (krp->krp_iparams < 3 || krp->krp_oparams != 1) {
++ krp->krp_status = EINVAL;
++ return (1);
++ }
++
++ base_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_BASE]);
++ if (base_bits > 2048)
++ goto too_big;
++ if (base_bits <= 0) /* 5. base not zero */
++ goto too_small;
++
++ exp_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_EXP]);
++ if (exp_bits > 2048)
++ goto too_big;
++ if (exp_bits <= 0) /* 1. exponent word length > 0 */
++ goto too_small; /* 4. exponent not zero */
++
++ mod_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_MOD]);
++ if (mod_bits > 2048)
++ goto too_big;
++ if (mod_bits <= 32) /* 2. modulus word length > 1 */
++ goto too_small; /* 8. MSW of modulus != zero */
++ if (mod_bits < exp_bits) /* 3 modulus len >= exponent len */
++ goto too_small;
++ if ((krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p[0] & 1) == 0)
++ goto bad_domain; /* 6. modulus is odd */
++ if (mod_bits > krp->krp_param[krp->krp_iparams].crp_nbits)
++ goto too_small; /* make sure result will fit */
++
++ /* 7. modulus > base */
++ if (mod_bits < base_bits)
++ goto too_small;
++ if (mod_bits == base_bits) {
++ u_int8_t *basep, *modp;
++ int i;
++
++ basep = krp->krp_param[SAFE_CRK_PARAM_BASE].crp_p +
++ ((base_bits + 7) / 8) - 1;
++ modp = krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p +
++ ((mod_bits + 7) / 8) - 1;
++
++ for (i = 0; i < (mod_bits + 7) / 8; i++, basep--, modp--) {
++ if (*modp < *basep)
++ goto too_small;
++ if (*modp > *basep)
++ break;
++ }
++ }
++
++ /* And on the 9th step, he rested. */
++
++ WRITE_REG(sc, SAFE_PK_A_LEN, (exp_bits + 31) / 32);
++ WRITE_REG(sc, SAFE_PK_B_LEN, (mod_bits + 31) / 32);
++ if (mod_bits > 1024) {
++ op = SAFE_PK_FUNC_EXP4;
++ a_off = 0x000;
++ b_off = 0x100;
++ c_off = 0x200;
++ d_off = 0x300;
++ } else {
++ op = SAFE_PK_FUNC_EXP16;
++ a_off = 0x000;
++ b_off = 0x080;
++ c_off = 0x100;
++ d_off = 0x180;
++ }
++ sc->sc_pk_reslen = b_off - a_off;
++ sc->sc_pk_resoff = d_off;
++
++ /* A is exponent, B is modulus, C is base, D is result */
++ safe_kload_reg(sc, a_off, b_off - a_off,
++ &krp->krp_param[SAFE_CRK_PARAM_EXP]);
++ WRITE_REG(sc, SAFE_PK_A_ADDR, a_off >> 2);
++ safe_kload_reg(sc, b_off, b_off - a_off,
++ &krp->krp_param[SAFE_CRK_PARAM_MOD]);
++ WRITE_REG(sc, SAFE_PK_B_ADDR, b_off >> 2);
++ safe_kload_reg(sc, c_off, b_off - a_off,
++ &krp->krp_param[SAFE_CRK_PARAM_BASE]);
++ WRITE_REG(sc, SAFE_PK_C_ADDR, c_off >> 2);
++ WRITE_REG(sc, SAFE_PK_D_ADDR, d_off >> 2);
++
++ WRITE_REG(sc, SAFE_PK_FUNC, op | SAFE_PK_FUNC_RUN);
++
++ return (0);
++
++too_big:
++ krp->krp_status = E2BIG;
++ return (1);
++too_small:
++ krp->krp_status = ERANGE;
++ return (1);
++bad_domain:
++ krp->krp_status = EDOM;
++ return (1);
++}
++
++static int
++safe_ksigbits(struct safe_softc *sc, struct crparam *cr)
++{
++ u_int plen = (cr->crp_nbits + 7) / 8;
++ int i, sig = plen * 8;
++ u_int8_t c, *p = cr->crp_p;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ for (i = plen - 1; i >= 0; i--) {
++ c = p[i];
++ if (c != 0) {
++ while ((c & 0x80) == 0) {
++ sig--;
++ c <<= 1;
++ }
++ break;
++ }
++ sig -= 8;
++ }
++ return (sig);
++}
++
++static void
++safe_kfeed(struct safe_softc *sc)
++{
++ struct safe_pkq *q, *tmp;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ if (list_empty(&sc->sc_pkq) && sc->sc_pkq_cur == NULL)
++ return;
++ if (sc->sc_pkq_cur != NULL)
++ return;
++ list_for_each_entry_safe(q, tmp, &sc->sc_pkq, pkq_list) {
++ sc->sc_pkq_cur = q;
++ list_del(&q->pkq_list);
++ if (safe_kstart(sc) != 0) {
++ crypto_kdone(q->pkq_krp);
++ kfree(q);
++ sc->sc_pkq_cur = NULL;
++ } else {
++ /* op started, start polling */
++ mod_timer(&sc->sc_pkto, jiffies + 1);
++ break;
++ }
++ }
++}
++
++static void
++safe_kpoll(unsigned long arg)
++{
++ struct safe_softc *sc = NULL;
++ struct safe_pkq *q;
++ struct crparam *res;
++ int i;
++ u_int32_t buf[64];
++ unsigned long flags;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ if (arg >= SAFE_MAX_CHIPS)
++ return;
++ sc = safe_chip_idx[arg];
++ if (!sc) {
++ DPRINTF(("%s() - bad callback\n", __FUNCTION__));
++ return;
++ }
++
++ spin_lock_irqsave(&sc->sc_pkmtx, flags);
++ if (sc->sc_pkq_cur == NULL)
++ goto out;
++ if (READ_REG(sc, SAFE_PK_FUNC) & SAFE_PK_FUNC_RUN) {
++ /* still running, check back later */
++ mod_timer(&sc->sc_pkto, jiffies + 1);
++ goto out;
++ }
++
++ q = sc->sc_pkq_cur;
++ res = &q->pkq_krp->krp_param[q->pkq_krp->krp_iparams];
++ bzero(buf, sizeof(buf));
++ bzero(res->crp_p, (res->crp_nbits + 7) / 8);
++ for (i = 0; i < sc->sc_pk_reslen >> 2; i++)
++ buf[i] = le32_to_cpu(READ_REG(sc, SAFE_PK_RAM_START +
++ sc->sc_pk_resoff + (i << 2)));
++ bcopy(buf, res->crp_p, (res->crp_nbits + 7) / 8);
++ /*
++ * reduce the bits that need copying if possible
++ */
++ res->crp_nbits = min(res->crp_nbits,sc->sc_pk_reslen * 8);
++ res->crp_nbits = safe_ksigbits(sc, res);
++
++ for (i = SAFE_PK_RAM_START; i < SAFE_PK_RAM_END; i += 4)
++ WRITE_REG(sc, i, 0);
++
++ crypto_kdone(q->pkq_krp);
++ kfree(q);
++ sc->sc_pkq_cur = NULL;
++
++ safe_kfeed(sc);
++out:
++ spin_unlock_irqrestore(&sc->sc_pkmtx, flags);
++}
++
++static void
++safe_kload_reg(struct safe_softc *sc, u_int32_t off, u_int32_t len,
++ struct crparam *n)
++{
++ u_int32_t buf[64], i;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ bzero(buf, sizeof(buf));
++ bcopy(n->crp_p, buf, (n->crp_nbits + 7) / 8);
++
++ for (i = 0; i < len >> 2; i++)
++ WRITE_REG(sc, SAFE_PK_RAM_START + off + (i << 2),
++ cpu_to_le32(buf[i]));
++}
++
++#ifdef SAFE_DEBUG
++static void
++safe_dump_dmastatus(struct safe_softc *sc, const char *tag)
++{
++ printf("%s: ENDIAN 0x%x SRC 0x%x DST 0x%x STAT 0x%x\n"
++ , tag
++ , READ_REG(sc, SAFE_DMA_ENDIAN)
++ , READ_REG(sc, SAFE_DMA_SRCADDR)
++ , READ_REG(sc, SAFE_DMA_DSTADDR)
++ , READ_REG(sc, SAFE_DMA_STAT)
++ );
++}
++
++static void
++safe_dump_intrstate(struct safe_softc *sc, const char *tag)
++{
++ printf("%s: HI_CFG 0x%x HI_MASK 0x%x HI_DESC_CNT 0x%x HU_STAT 0x%x HM_STAT 0x%x\n"
++ , tag
++ , READ_REG(sc, SAFE_HI_CFG)
++ , READ_REG(sc, SAFE_HI_MASK)
++ , READ_REG(sc, SAFE_HI_DESC_CNT)
++ , READ_REG(sc, SAFE_HU_STAT)
++ , READ_REG(sc, SAFE_HM_STAT)
++ );
++}
++
++static void
++safe_dump_ringstate(struct safe_softc *sc, const char *tag)
++{
++ u_int32_t estat = READ_REG(sc, SAFE_PE_ERNGSTAT);
++
++ /* NB: assume caller has lock on ring */
++ printf("%s: ERNGSTAT %x (next %u) back %lu front %lu\n",
++ tag,
++ estat, (estat >> SAFE_PE_ERNGSTAT_NEXT_S),
++ (unsigned long)(sc->sc_back - sc->sc_ring),
++ (unsigned long)(sc->sc_front - sc->sc_ring));
++}
++
++static void
++safe_dump_request(struct safe_softc *sc, const char* tag, struct safe_ringentry *re)
++{
++ int ix, nsegs;
++
++ ix = re - sc->sc_ring;
++ printf("%s: %p (%u): csr %x src %x dst %x sa %x len %x\n"
++ , tag
++ , re, ix
++ , re->re_desc.d_csr
++ , re->re_desc.d_src
++ , re->re_desc.d_dst
++ , re->re_desc.d_sa
++ , re->re_desc.d_len
++ );
++ if (re->re_src.nsegs > 1) {
++ ix = (re->re_desc.d_src - sc->sc_spalloc.dma_paddr) /
++ sizeof(struct safe_pdesc);
++ for (nsegs = re->re_src.nsegs; nsegs; nsegs--) {
++ printf(" spd[%u] %p: %p size %u flags %x"
++ , ix, &sc->sc_spring[ix]
++ , (caddr_t)(uintptr_t) sc->sc_spring[ix].pd_addr
++ , sc->sc_spring[ix].pd_size
++ , sc->sc_spring[ix].pd_flags
++ );
++ if (sc->sc_spring[ix].pd_size == 0)
++ printf(" (zero!)");
++ printf("\n");
++ if (++ix == SAFE_TOTAL_SPART)
++ ix = 0;
++ }
++ }
++ if (re->re_dst.nsegs > 1) {
++ ix = (re->re_desc.d_dst - sc->sc_dpalloc.dma_paddr) /
++ sizeof(struct safe_pdesc);
++ for (nsegs = re->re_dst.nsegs; nsegs; nsegs--) {
++ printf(" dpd[%u] %p: %p flags %x\n"
++ , ix, &sc->sc_dpring[ix]
++ , (caddr_t)(uintptr_t) sc->sc_dpring[ix].pd_addr
++ , sc->sc_dpring[ix].pd_flags
++ );
++ if (++ix == SAFE_TOTAL_DPART)
++ ix = 0;
++ }
++ }
++ printf("sa: cmd0 %08x cmd1 %08x staterec %x\n",
++ re->re_sa.sa_cmd0, re->re_sa.sa_cmd1, re->re_sa.sa_staterec);
++ printf("sa: key %x %x %x %x %x %x %x %x\n"
++ , re->re_sa.sa_key[0]
++ , re->re_sa.sa_key[1]
++ , re->re_sa.sa_key[2]
++ , re->re_sa.sa_key[3]
++ , re->re_sa.sa_key[4]
++ , re->re_sa.sa_key[5]
++ , re->re_sa.sa_key[6]
++ , re->re_sa.sa_key[7]
++ );
++ printf("sa: indigest %x %x %x %x %x\n"
++ , re->re_sa.sa_indigest[0]
++ , re->re_sa.sa_indigest[1]
++ , re->re_sa.sa_indigest[2]
++ , re->re_sa.sa_indigest[3]
++ , re->re_sa.sa_indigest[4]
++ );
++ printf("sa: outdigest %x %x %x %x %x\n"
++ , re->re_sa.sa_outdigest[0]
++ , re->re_sa.sa_outdigest[1]
++ , re->re_sa.sa_outdigest[2]
++ , re->re_sa.sa_outdigest[3]
++ , re->re_sa.sa_outdigest[4]
++ );
++ printf("sr: iv %x %x %x %x\n"
++ , re->re_sastate.sa_saved_iv[0]
++ , re->re_sastate.sa_saved_iv[1]
++ , re->re_sastate.sa_saved_iv[2]
++ , re->re_sastate.sa_saved_iv[3]
++ );
++ printf("sr: hashbc %u indigest %x %x %x %x %x\n"
++ , re->re_sastate.sa_saved_hashbc
++ , re->re_sastate.sa_saved_indigest[0]
++ , re->re_sastate.sa_saved_indigest[1]
++ , re->re_sastate.sa_saved_indigest[2]
++ , re->re_sastate.sa_saved_indigest[3]
++ , re->re_sastate.sa_saved_indigest[4]
++ );
++}
++
++static void
++safe_dump_ring(struct safe_softc *sc, const char *tag)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&sc->sc_ringmtx, flags);
++ printf("\nSafeNet Ring State:\n");
++ safe_dump_intrstate(sc, tag);
++ safe_dump_dmastatus(sc, tag);
++ safe_dump_ringstate(sc, tag);
++ if (sc->sc_nqchip) {
++ struct safe_ringentry *re = sc->sc_back;
++ do {
++ safe_dump_request(sc, tag, re);
++ if (++re == sc->sc_ringtop)
++ re = sc->sc_ring;
++ } while (re != sc->sc_front);
++ }
++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags);
++}
++#endif /* SAFE_DEBUG */
++
++
++static int safe_probe(struct pci_dev *dev, const struct pci_device_id *ent)
++{
++ struct safe_softc *sc = NULL;
++ u32 mem_start, mem_len, cmd;
++ int i, rc, devinfo;
++ dma_addr_t raddr;
++ static int num_chips = 0;
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ if (pci_enable_device(dev) < 0)
++ return(-ENODEV);
++
++ if (!dev->irq) {
++ printk("safe: found device with no IRQ assigned. check BIOS settings!");
++ pci_disable_device(dev);
++ return(-ENODEV);
++ }
++
++ if (pci_set_mwi(dev)) {
++ printk("safe: pci_set_mwi failed!");
++ return(-ENODEV);
++ }
++
++ sc = (struct safe_softc *) kmalloc(sizeof(*sc), GFP_KERNEL);
++ if (!sc)
++ return(-ENOMEM);
++ memset(sc, 0, sizeof(*sc));
++
++ softc_device_init(sc, "safe", num_chips, safe_methods);
++
++ sc->sc_irq = -1;
++ sc->sc_cid = -1;
++ sc->sc_pcidev = dev;
++ if (num_chips < SAFE_MAX_CHIPS) {
++ safe_chip_idx[device_get_unit(sc->sc_dev)] = sc;
++ num_chips++;
++ }
++
++ INIT_LIST_HEAD(&sc->sc_pkq);
++ spin_lock_init(&sc->sc_pkmtx);
++
++ pci_set_drvdata(sc->sc_pcidev, sc);
++
++ /* we read its hardware registers as memory */
++ mem_start = pci_resource_start(sc->sc_pcidev, 0);
++ mem_len = pci_resource_len(sc->sc_pcidev, 0);
++
++ sc->sc_base_addr = (ocf_iomem_t) ioremap(mem_start, mem_len);
++ if (!sc->sc_base_addr) {
++ device_printf(sc->sc_dev, "failed to ioremap 0x%x-0x%x\n",
++ mem_start, mem_start + mem_len - 1);
++ goto out;
++ }
++
++ /* fix up the bus size */
++ if (pci_set_dma_mask(sc->sc_pcidev, DMA_32BIT_MASK)) {
++ device_printf(sc->sc_dev, "No usable DMA configuration, aborting.\n");
++ goto out;
++ }
++ if (pci_set_consistent_dma_mask(sc->sc_pcidev, DMA_32BIT_MASK)) {
++ device_printf(sc->sc_dev, "No usable consistent DMA configuration, aborting.\n");
++ goto out;
++ }
++
++ pci_set_master(sc->sc_pcidev);
++
++ pci_read_config_dword(sc->sc_pcidev, PCI_COMMAND, &cmd);
++
++ if (!(cmd & PCI_COMMAND_MEMORY)) {
++ device_printf(sc->sc_dev, "failed to enable memory mapping\n");
++ goto out;
++ }
++
++ if (!(cmd & PCI_COMMAND_MASTER)) {
++ device_printf(sc->sc_dev, "failed to enable bus mastering\n");
++ goto out;
++ }
++
++ rc = request_irq(dev->irq, safe_intr, IRQF_SHARED, "safe", sc);
++ if (rc) {
++ device_printf(sc->sc_dev, "failed to hook irq %d\n", sc->sc_irq);
++ goto out;
++ }
++ sc->sc_irq = dev->irq;
++
++ sc->sc_chiprev = READ_REG(sc, SAFE_DEVINFO) &
++ (SAFE_DEVINFO_REV_MAJ | SAFE_DEVINFO_REV_MIN);
++
++ /*
++ * Allocate packet engine descriptors.
++ */
++ sc->sc_ringalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev,
++ SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry),
++ &sc->sc_ringalloc.dma_paddr);
++ if (!sc->sc_ringalloc.dma_vaddr) {
++ device_printf(sc->sc_dev, "cannot allocate PE descriptor ring\n");
++ goto out;
++ }
++
++ /*
++ * Hookup the static portion of all our data structures.
++ */
++ sc->sc_ring = (struct safe_ringentry *) sc->sc_ringalloc.dma_vaddr;
++ sc->sc_ringtop = sc->sc_ring + SAFE_MAX_NQUEUE;
++ sc->sc_front = sc->sc_ring;
++ sc->sc_back = sc->sc_ring;
++ raddr = sc->sc_ringalloc.dma_paddr;
++ bzero(sc->sc_ring, SAFE_MAX_NQUEUE * sizeof(struct safe_ringentry));
++ for (i = 0; i < SAFE_MAX_NQUEUE; i++) {
++ struct safe_ringentry *re = &sc->sc_ring[i];
++
++ re->re_desc.d_sa = raddr +
++ offsetof(struct safe_ringentry, re_sa);
++ re->re_sa.sa_staterec = raddr +
++ offsetof(struct safe_ringentry, re_sastate);
++
++ raddr += sizeof (struct safe_ringentry);
++ }
++ spin_lock_init(&sc->sc_ringmtx);
++
++ /*
++ * Allocate scatter and gather particle descriptors.
++ */
++ sc->sc_spalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev,
++ SAFE_TOTAL_SPART * sizeof (struct safe_pdesc),
++ &sc->sc_spalloc.dma_paddr);
++ if (!sc->sc_spalloc.dma_vaddr) {
++ device_printf(sc->sc_dev, "cannot allocate source particle descriptor ring\n");
++ goto out;
++ }
++ sc->sc_spring = (struct safe_pdesc *) sc->sc_spalloc.dma_vaddr;
++ sc->sc_springtop = sc->sc_spring + SAFE_TOTAL_SPART;
++ sc->sc_spfree = sc->sc_spring;
++ bzero(sc->sc_spring, SAFE_TOTAL_SPART * sizeof(struct safe_pdesc));
++
++ sc->sc_dpalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev,
++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc),
++ &sc->sc_dpalloc.dma_paddr);
++ if (!sc->sc_dpalloc.dma_vaddr) {
++ device_printf(sc->sc_dev, "cannot allocate destination particle descriptor ring\n");
++ goto out;
++ }
++ sc->sc_dpring = (struct safe_pdesc *) sc->sc_dpalloc.dma_vaddr;
++ sc->sc_dpringtop = sc->sc_dpring + SAFE_TOTAL_DPART;
++ sc->sc_dpfree = sc->sc_dpring;
++ bzero(sc->sc_dpring, SAFE_TOTAL_DPART * sizeof(struct safe_pdesc));
++
++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc), CRYPTOCAP_F_HARDWARE);
++ if (sc->sc_cid < 0) {
++ device_printf(sc->sc_dev, "could not get crypto driver id\n");
++ goto out;
++ }
++
++ printf("%s:", device_get_nameunit(sc->sc_dev));
++
++ devinfo = READ_REG(sc, SAFE_DEVINFO);
++ if (devinfo & SAFE_DEVINFO_RNG) {
++ sc->sc_flags |= SAFE_FLAGS_RNG;
++ printf(" rng");
++ }
++ if (devinfo & SAFE_DEVINFO_PKEY) {
++ printf(" key");
++ sc->sc_flags |= SAFE_FLAGS_KEY;
++ crypto_kregister(sc->sc_cid, CRK_MOD_EXP, 0);
++#if 0
++ crypto_kregister(sc->sc_cid, CRK_MOD_EXP_CRT, 0);
++#endif
++ init_timer(&sc->sc_pkto);
++ sc->sc_pkto.function = safe_kpoll;
++ sc->sc_pkto.data = (unsigned long) device_get_unit(sc->sc_dev);
++ }
++ if (devinfo & SAFE_DEVINFO_DES) {
++ printf(" des/3des");
++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
++ }
++ if (devinfo & SAFE_DEVINFO_AES) {
++ printf(" aes");
++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
++ }
++ if (devinfo & SAFE_DEVINFO_MD5) {
++ printf(" md5");
++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
++ }
++ if (devinfo & SAFE_DEVINFO_SHA1) {
++ printf(" sha1");
++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
++ }
++ printf(" null");
++ crypto_register(sc->sc_cid, CRYPTO_NULL_CBC, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_NULL_HMAC, 0, 0);
++ /* XXX other supported algorithms */
++ printf("\n");
++
++ safe_reset_board(sc); /* reset h/w */
++ safe_init_board(sc); /* init h/w */
++
++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG)
++ if (sc->sc_flags & SAFE_FLAGS_RNG) {
++ safe_rng_init(sc);
++ crypto_rregister(sc->sc_cid, safe_read_random, sc);
++ }
++#endif /* SAFE_NO_RNG */
++
++ return (0);
++
++out:
++ if (sc->sc_cid >= 0)
++ crypto_unregister_all(sc->sc_cid);
++ if (sc->sc_irq != -1)
++ free_irq(sc->sc_irq, sc);
++ if (sc->sc_ringalloc.dma_vaddr)
++ pci_free_consistent(sc->sc_pcidev,
++ SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry),
++ sc->sc_ringalloc.dma_vaddr, sc->sc_ringalloc.dma_paddr);
++ if (sc->sc_spalloc.dma_vaddr)
++ pci_free_consistent(sc->sc_pcidev,
++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc),
++ sc->sc_spalloc.dma_vaddr, sc->sc_spalloc.dma_paddr);
++ if (sc->sc_dpalloc.dma_vaddr)
++ pci_free_consistent(sc->sc_pcidev,
++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc),
++ sc->sc_dpalloc.dma_vaddr, sc->sc_dpalloc.dma_paddr);
++ kfree(sc);
++ return(-ENODEV);
++}
++
++static void safe_remove(struct pci_dev *dev)
++{
++ struct safe_softc *sc = pci_get_drvdata(dev);
++
++ DPRINTF(("%s()\n", __FUNCTION__));
++
++ /* XXX wait/abort active ops */
++
++ WRITE_REG(sc, SAFE_HI_MASK, 0); /* disable interrupts */
++
++ del_timer_sync(&sc->sc_pkto);
++
++ crypto_unregister_all(sc->sc_cid);
++
++ safe_cleanchip(sc);
++
++ if (sc->sc_irq != -1)
++ free_irq(sc->sc_irq, sc);
++ if (sc->sc_ringalloc.dma_vaddr)
++ pci_free_consistent(sc->sc_pcidev,
++ SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry),
++ sc->sc_ringalloc.dma_vaddr, sc->sc_ringalloc.dma_paddr);
++ if (sc->sc_spalloc.dma_vaddr)
++ pci_free_consistent(sc->sc_pcidev,
++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc),
++ sc->sc_spalloc.dma_vaddr, sc->sc_spalloc.dma_paddr);
++ if (sc->sc_dpalloc.dma_vaddr)
++ pci_free_consistent(sc->sc_pcidev,
++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc),
++ sc->sc_dpalloc.dma_vaddr, sc->sc_dpalloc.dma_paddr);
++ sc->sc_irq = -1;
++ sc->sc_ringalloc.dma_vaddr = NULL;
++ sc->sc_spalloc.dma_vaddr = NULL;
++ sc->sc_dpalloc.dma_vaddr = NULL;
++}
++
++static struct pci_device_id safe_pci_tbl[] = {
++ { PCI_VENDOR_SAFENET, PCI_PRODUCT_SAFEXCEL,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
++ { },
++};
++MODULE_DEVICE_TABLE(pci, safe_pci_tbl);
++
++static struct pci_driver safe_driver = {
++ .name = "safe",
++ .id_table = safe_pci_tbl,
++ .probe = safe_probe,
++ .remove = safe_remove,
++ /* add PM stuff here one day */
++};
++
++static int __init safe_init (void)
++{
++ struct safe_softc *sc = NULL;
++ int rc;
++
++ DPRINTF(("%s(%p)\n", __FUNCTION__, safe_init));
++
++ rc = pci_register_driver(&safe_driver);
++ pci_register_driver_compat(&safe_driver, rc);
++
++ return rc;
++}
++
++static void __exit safe_exit (void)
++{
++ pci_unregister_driver(&safe_driver);
++}
++
++module_init(safe_init);
++module_exit(safe_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
++MODULE_DESCRIPTION("OCF driver for safenet PCI crypto devices");
+diff -Nur linux-2.6.36.orig/crypto/ocf/safe/safereg.h linux-2.6.36/crypto/ocf/safe/safereg.h
+--- linux-2.6.36.orig/crypto/ocf/safe/safereg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/safe/safereg.h 2010-11-09 20:28:12.962495464 +0100
+@@ -0,0 +1,421 @@
++/*-
++ * Copyright (c) 2003 Sam Leffler, Errno Consulting
++ * Copyright (c) 2003 Global Technology Associates, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * $FreeBSD: src/sys/dev/safe/safereg.h,v 1.1 2003/07/21 21:46:07 sam Exp $
++ */
++#ifndef _SAFE_SAFEREG_H_
++#define _SAFE_SAFEREG_H_
++
++/*
++ * Register definitions for SafeNet SafeXcel-1141 crypto device.
++ * Definitions from revision 1.3 (Nov 6 2002) of the User's Manual.
++ */
++
++#define BS_BAR 0x10 /* DMA base address register */
++#define BS_TRDY_TIMEOUT 0x40 /* TRDY timeout */
++#define BS_RETRY_TIMEOUT 0x41 /* DMA retry timeout */
++
++#define PCI_VENDOR_SAFENET 0x16ae /* SafeNet, Inc. */
++
++/* SafeNet */
++#define PCI_PRODUCT_SAFEXCEL 0x1141 /* 1141 */
++
++#define SAFE_PE_CSR 0x0000 /* Packet Enginge Ctrl/Status */
++#define SAFE_PE_SRC 0x0004 /* Packet Engine Source */
++#define SAFE_PE_DST 0x0008 /* Packet Engine Destination */
++#define SAFE_PE_SA 0x000c /* Packet Engine SA */
++#define SAFE_PE_LEN 0x0010 /* Packet Engine Length */
++#define SAFE_PE_DMACFG 0x0040 /* Packet Engine DMA Configuration */
++#define SAFE_PE_DMASTAT 0x0044 /* Packet Engine DMA Status */
++#define SAFE_PE_PDRBASE 0x0048 /* Packet Engine Descriptor Ring Base */
++#define SAFE_PE_RDRBASE 0x004c /* Packet Engine Result Ring Base */
++#define SAFE_PE_RINGCFG 0x0050 /* Packet Engine Ring Configuration */
++#define SAFE_PE_RINGPOLL 0x0054 /* Packet Engine Ring Poll */
++#define SAFE_PE_IRNGSTAT 0x0058 /* Packet Engine Internal Ring Status */
++#define SAFE_PE_ERNGSTAT 0x005c /* Packet Engine External Ring Status */
++#define SAFE_PE_IOTHRESH 0x0060 /* Packet Engine I/O Threshold */
++#define SAFE_PE_GRNGBASE 0x0064 /* Packet Engine Gather Ring Base */
++#define SAFE_PE_SRNGBASE 0x0068 /* Packet Engine Scatter Ring Base */
++#define SAFE_PE_PARTSIZE 0x006c /* Packet Engine Particlar Ring Size */
++#define SAFE_PE_PARTCFG 0x0070 /* Packet Engine Particle Ring Config */
++#define SAFE_CRYPTO_CTRL 0x0080 /* Crypto Control */
++#define SAFE_DEVID 0x0084 /* Device ID */
++#define SAFE_DEVINFO 0x0088 /* Device Info */
++#define SAFE_HU_STAT 0x00a0 /* Host Unmasked Status */
++#define SAFE_HM_STAT 0x00a4 /* Host Masked Status (read-only) */
++#define SAFE_HI_CLR 0x00a4 /* Host Clear Interrupt (write-only) */
++#define SAFE_HI_MASK 0x00a8 /* Host Mask Control */
++#define SAFE_HI_CFG 0x00ac /* Interrupt Configuration */
++#define SAFE_HI_RD_DESCR 0x00b4 /* Force Descriptor Read */
++#define SAFE_HI_DESC_CNT 0x00b8 /* Host Descriptor Done Count */
++#define SAFE_DMA_ENDIAN 0x00c0 /* Master Endian Status */
++#define SAFE_DMA_SRCADDR 0x00c4 /* DMA Source Address Status */
++#define SAFE_DMA_DSTADDR 0x00c8 /* DMA Destination Address Status */
++#define SAFE_DMA_STAT 0x00cc /* DMA Current Status */
++#define SAFE_DMA_CFG 0x00d4 /* DMA Configuration/Status */
++#define SAFE_ENDIAN 0x00e0 /* Endian Configuration */
++#define SAFE_PK_A_ADDR 0x0800 /* Public Key A Address */
++#define SAFE_PK_B_ADDR 0x0804 /* Public Key B Address */
++#define SAFE_PK_C_ADDR 0x0808 /* Public Key C Address */
++#define SAFE_PK_D_ADDR 0x080c /* Public Key D Address */
++#define SAFE_PK_A_LEN 0x0810 /* Public Key A Length */
++#define SAFE_PK_B_LEN 0x0814 /* Public Key B Length */
++#define SAFE_PK_SHIFT 0x0818 /* Public Key Shift */
++#define SAFE_PK_FUNC 0x081c /* Public Key Function */
++#define SAFE_PK_RAM_START 0x1000 /* Public Key RAM start address */
++#define SAFE_PK_RAM_END 0x1fff /* Public Key RAM end address */
++
++#define SAFE_RNG_OUT 0x0100 /* RNG Output */
++#define SAFE_RNG_STAT 0x0104 /* RNG Status */
++#define SAFE_RNG_CTRL 0x0108 /* RNG Control */
++#define SAFE_RNG_A 0x010c /* RNG A */
++#define SAFE_RNG_B 0x0110 /* RNG B */
++#define SAFE_RNG_X_LO 0x0114 /* RNG X [31:0] */
++#define SAFE_RNG_X_MID 0x0118 /* RNG X [63:32] */
++#define SAFE_RNG_X_HI 0x011c /* RNG X [80:64] */
++#define SAFE_RNG_X_CNTR 0x0120 /* RNG Counter */
++#define SAFE_RNG_ALM_CNT 0x0124 /* RNG Alarm Count */
++#define SAFE_RNG_CNFG 0x0128 /* RNG Configuration */
++#define SAFE_RNG_LFSR1_LO 0x012c /* RNG LFSR1 [31:0] */
++#define SAFE_RNG_LFSR1_HI 0x0130 /* RNG LFSR1 [47:32] */
++#define SAFE_RNG_LFSR2_LO 0x0134 /* RNG LFSR1 [31:0] */
++#define SAFE_RNG_LFSR2_HI 0x0138 /* RNG LFSR1 [47:32] */
++
++#define SAFE_PE_CSR_READY 0x00000001 /* ready for processing */
++#define SAFE_PE_CSR_DONE 0x00000002 /* h/w completed processing */
++#define SAFE_PE_CSR_LOADSA 0x00000004 /* load SA digests */
++#define SAFE_PE_CSR_HASHFINAL 0x00000010 /* do hash pad & write result */
++#define SAFE_PE_CSR_SABUSID 0x000000c0 /* bus id for SA */
++#define SAFE_PE_CSR_SAPCI 0x00000040 /* PCI bus id for SA */
++#define SAFE_PE_CSR_NXTHDR 0x0000ff00 /* next hdr value for IPsec */
++#define SAFE_PE_CSR_FPAD 0x0000ff00 /* fixed pad for basic ops */
++#define SAFE_PE_CSR_STATUS 0x00ff0000 /* operation result status */
++#define SAFE_PE_CSR_AUTH_FAIL 0x00010000 /* ICV mismatch (inbound) */
++#define SAFE_PE_CSR_PAD_FAIL 0x00020000 /* pad verify fail (inbound) */
++#define SAFE_PE_CSR_SEQ_FAIL 0x00040000 /* sequence number (inbound) */
++#define SAFE_PE_CSR_XERROR 0x00080000 /* extended error follows */
++#define SAFE_PE_CSR_XECODE 0x00f00000 /* extended error code */
++#define SAFE_PE_CSR_XECODE_S 20
++#define SAFE_PE_CSR_XECODE_BADCMD 0 /* invalid command */
++#define SAFE_PE_CSR_XECODE_BADALG 1 /* invalid algorithm */
++#define SAFE_PE_CSR_XECODE_ALGDIS 2 /* algorithm disabled */
++#define SAFE_PE_CSR_XECODE_ZEROLEN 3 /* zero packet length */
++#define SAFE_PE_CSR_XECODE_DMAERR 4 /* bus DMA error */
++#define SAFE_PE_CSR_XECODE_PIPEABORT 5 /* secondary bus DMA error */
++#define SAFE_PE_CSR_XECODE_BADSPI 6 /* IPsec SPI mismatch */
++#define SAFE_PE_CSR_XECODE_TIMEOUT 10 /* failsafe timeout */
++#define SAFE_PE_CSR_PAD 0xff000000 /* ESP padding control/status */
++#define SAFE_PE_CSR_PAD_MIN 0x00000000 /* minimum IPsec padding */
++#define SAFE_PE_CSR_PAD_16 0x08000000 /* pad to 16-byte boundary */
++#define SAFE_PE_CSR_PAD_32 0x10000000 /* pad to 32-byte boundary */
++#define SAFE_PE_CSR_PAD_64 0x20000000 /* pad to 64-byte boundary */
++#define SAFE_PE_CSR_PAD_128 0x40000000 /* pad to 128-byte boundary */
++#define SAFE_PE_CSR_PAD_256 0x80000000 /* pad to 256-byte boundary */
++
++/*
++ * Check the CSR to see if the PE has returned ownership to
++ * the host. Note that before processing a descriptor this
++ * must be done followed by a check of the SAFE_PE_LEN register
++ * status bits to avoid premature processing of a descriptor
++ * on its way back to the host.
++ */
++#define SAFE_PE_CSR_IS_DONE(_csr) \
++ (((_csr) & (SAFE_PE_CSR_READY | SAFE_PE_CSR_DONE)) == SAFE_PE_CSR_DONE)
++
++#define SAFE_PE_LEN_LENGTH 0x000fffff /* total length (bytes) */
++#define SAFE_PE_LEN_READY 0x00400000 /* ready for processing */
++#define SAFE_PE_LEN_DONE 0x00800000 /* h/w completed processing */
++#define SAFE_PE_LEN_BYPASS 0xff000000 /* bypass offset (bytes) */
++#define SAFE_PE_LEN_BYPASS_S 24
++
++#define SAFE_PE_LEN_IS_DONE(_len) \
++ (((_len) & (SAFE_PE_LEN_READY | SAFE_PE_LEN_DONE)) == SAFE_PE_LEN_DONE)
++
++/* NB: these apply to HU_STAT, HM_STAT, HI_CLR, and HI_MASK */
++#define SAFE_INT_PE_CDONE 0x00000002 /* PE context done */
++#define SAFE_INT_PE_DDONE 0x00000008 /* PE descriptor done */
++#define SAFE_INT_PE_ERROR 0x00000010 /* PE error */
++#define SAFE_INT_PE_ODONE 0x00000020 /* PE operation done */
++
++#define SAFE_HI_CFG_PULSE 0x00000001 /* use pulse interrupt */
++#define SAFE_HI_CFG_LEVEL 0x00000000 /* use level interrupt */
++#define SAFE_HI_CFG_AUTOCLR 0x00000002 /* auto-clear pulse interrupt */
++
++#define SAFE_ENDIAN_PASS 0x000000e4 /* straight pass-thru */
++#define SAFE_ENDIAN_SWAB 0x0000001b /* swap bytes in 32-bit word */
++
++#define SAFE_PE_DMACFG_PERESET 0x00000001 /* reset packet engine */
++#define SAFE_PE_DMACFG_PDRRESET 0x00000002 /* reset PDR counters/ptrs */
++#define SAFE_PE_DMACFG_SGRESET 0x00000004 /* reset scatter/gather cache */
++#define SAFE_PE_DMACFG_FSENA 0x00000008 /* enable failsafe reset */
++#define SAFE_PE_DMACFG_PEMODE 0x00000100 /* packet engine mode */
++#define SAFE_PE_DMACFG_SAPREC 0x00000200 /* SA precedes packet */
++#define SAFE_PE_DMACFG_PKFOLL 0x00000400 /* packet follows descriptor */
++#define SAFE_PE_DMACFG_GPRBID 0x00003000 /* gather particle ring busid */
++#define SAFE_PE_DMACFG_GPRPCI 0x00001000 /* PCI gather particle ring */
++#define SAFE_PE_DMACFG_SPRBID 0x0000c000 /* scatter part. ring busid */
++#define SAFE_PE_DMACFG_SPRPCI 0x00004000 /* PCI scatter part. ring */
++#define SAFE_PE_DMACFG_ESDESC 0x00010000 /* endian swap descriptors */
++#define SAFE_PE_DMACFG_ESSA 0x00020000 /* endian swap SA data */
++#define SAFE_PE_DMACFG_ESPACKET 0x00040000 /* endian swap packet data */
++#define SAFE_PE_DMACFG_ESPDESC 0x00080000 /* endian swap particle desc. */
++#define SAFE_PE_DMACFG_NOPDRUP 0x00100000 /* supp. PDR ownership update */
++#define SAFE_PD_EDMACFG_PCIMODE 0x01000000 /* PCI target mode */
++
++#define SAFE_PE_DMASTAT_PEIDONE 0x00000001 /* PE core input done */
++#define SAFE_PE_DMASTAT_PEODONE 0x00000002 /* PE core output done */
++#define SAFE_PE_DMASTAT_ENCDONE 0x00000004 /* encryption done */
++#define SAFE_PE_DMASTAT_IHDONE 0x00000008 /* inner hash done */
++#define SAFE_PE_DMASTAT_OHDONE 0x00000010 /* outer hash (HMAC) done */
++#define SAFE_PE_DMASTAT_PADFLT 0x00000020 /* crypto pad fault */
++#define SAFE_PE_DMASTAT_ICVFLT 0x00000040 /* ICV fault */
++#define SAFE_PE_DMASTAT_SPIMIS 0x00000080 /* SPI mismatch */
++#define SAFE_PE_DMASTAT_CRYPTO 0x00000100 /* crypto engine timeout */
++#define SAFE_PE_DMASTAT_CQACT 0x00000200 /* command queue active */
++#define SAFE_PE_DMASTAT_IRACT 0x00000400 /* input request active */
++#define SAFE_PE_DMASTAT_ORACT 0x00000800 /* output request active */
++#define SAFE_PE_DMASTAT_PEISIZE 0x003ff000 /* PE input size:32-bit words */
++#define SAFE_PE_DMASTAT_PEOSIZE 0xffc00000 /* PE out. size:32-bit words */
++
++#define SAFE_PE_RINGCFG_SIZE 0x000003ff /* ring size (descriptors) */
++#define SAFE_PE_RINGCFG_OFFSET 0xffff0000 /* offset btw desc's (dwords) */
++#define SAFE_PE_RINGCFG_OFFSET_S 16
++
++#define SAFE_PE_RINGPOLL_POLL 0x00000fff /* polling frequency/divisor */
++#define SAFE_PE_RINGPOLL_RETRY 0x03ff0000 /* polling frequency/divisor */
++#define SAFE_PE_RINGPOLL_CONT 0x80000000 /* continuously poll */
++
++#define SAFE_PE_IRNGSTAT_CQAVAIL 0x00000001 /* command queue available */
++
++#define SAFE_PE_ERNGSTAT_NEXT 0x03ff0000 /* index of next packet desc. */
++#define SAFE_PE_ERNGSTAT_NEXT_S 16
++
++#define SAFE_PE_IOTHRESH_INPUT 0x000003ff /* input threshold (dwords) */
++#define SAFE_PE_IOTHRESH_OUTPUT 0x03ff0000 /* output threshold (dwords) */
++
++#define SAFE_PE_PARTCFG_SIZE 0x0000ffff /* scatter particle size */
++#define SAFE_PE_PARTCFG_GBURST 0x00030000 /* gather particle burst */
++#define SAFE_PE_PARTCFG_GBURST_2 0x00000000
++#define SAFE_PE_PARTCFG_GBURST_4 0x00010000
++#define SAFE_PE_PARTCFG_GBURST_8 0x00020000
++#define SAFE_PE_PARTCFG_GBURST_16 0x00030000
++#define SAFE_PE_PARTCFG_SBURST 0x000c0000 /* scatter particle burst */
++#define SAFE_PE_PARTCFG_SBURST_2 0x00000000
++#define SAFE_PE_PARTCFG_SBURST_4 0x00040000
++#define SAFE_PE_PARTCFG_SBURST_8 0x00080000
++#define SAFE_PE_PARTCFG_SBURST_16 0x000c0000
++
++#define SAFE_PE_PARTSIZE_SCAT 0xffff0000 /* scatter particle ring size */
++#define SAFE_PE_PARTSIZE_GATH 0x0000ffff /* gather particle ring size */
++
++#define SAFE_CRYPTO_CTRL_3DES 0x00000001 /* enable 3DES support */
++#define SAFE_CRYPTO_CTRL_PKEY 0x00010000 /* enable public key support */
++#define SAFE_CRYPTO_CTRL_RNG 0x00020000 /* enable RNG support */
++
++#define SAFE_DEVINFO_REV_MIN 0x0000000f /* minor rev for chip */
++#define SAFE_DEVINFO_REV_MAJ 0x000000f0 /* major rev for chip */
++#define SAFE_DEVINFO_REV_MAJ_S 4
++#define SAFE_DEVINFO_DES 0x00000100 /* DES/3DES support present */
++#define SAFE_DEVINFO_ARC4 0x00000200 /* ARC4 support present */
++#define SAFE_DEVINFO_AES 0x00000400 /* AES support present */
++#define SAFE_DEVINFO_MD5 0x00001000 /* MD5 support present */
++#define SAFE_DEVINFO_SHA1 0x00002000 /* SHA-1 support present */
++#define SAFE_DEVINFO_RIPEMD 0x00004000 /* RIPEMD support present */
++#define SAFE_DEVINFO_DEFLATE 0x00010000 /* Deflate support present */
++#define SAFE_DEVINFO_SARAM 0x00100000 /* on-chip SA RAM present */
++#define SAFE_DEVINFO_EMIBUS 0x00200000 /* EMI bus present */
++#define SAFE_DEVINFO_PKEY 0x00400000 /* public key support present */
++#define SAFE_DEVINFO_RNG 0x00800000 /* RNG present */
++
++#define SAFE_REV(_maj, _min) (((_maj) << SAFE_DEVINFO_REV_MAJ_S) | (_min))
++#define SAFE_REV_MAJ(_chiprev) \
++ (((_chiprev) & SAFE_DEVINFO_REV_MAJ) >> SAFE_DEVINFO_REV_MAJ_S)
++#define SAFE_REV_MIN(_chiprev) ((_chiprev) & SAFE_DEVINFO_REV_MIN)
++
++#define SAFE_PK_FUNC_MULT 0x00000001 /* Multiply function */
++#define SAFE_PK_FUNC_SQUARE 0x00000004 /* Square function */
++#define SAFE_PK_FUNC_ADD 0x00000010 /* Add function */
++#define SAFE_PK_FUNC_SUB 0x00000020 /* Subtract function */
++#define SAFE_PK_FUNC_LSHIFT 0x00000040 /* Left-shift function */
++#define SAFE_PK_FUNC_RSHIFT 0x00000080 /* Right-shift function */
++#define SAFE_PK_FUNC_DIV 0x00000100 /* Divide function */
++#define SAFE_PK_FUNC_CMP 0x00000400 /* Compare function */
++#define SAFE_PK_FUNC_COPY 0x00000800 /* Copy function */
++#define SAFE_PK_FUNC_EXP16 0x00002000 /* Exponentiate (4-bit ACT) */
++#define SAFE_PK_FUNC_EXP4 0x00004000 /* Exponentiate (2-bit ACT) */
++#define SAFE_PK_FUNC_RUN 0x00008000 /* start/status */
++
++#define SAFE_RNG_STAT_BUSY 0x00000001 /* busy, data not valid */
++
++#define SAFE_RNG_CTRL_PRE_LFSR 0x00000001 /* enable output pre-LFSR */
++#define SAFE_RNG_CTRL_TST_MODE 0x00000002 /* enable test mode */
++#define SAFE_RNG_CTRL_TST_RUN 0x00000004 /* start test state machine */
++#define SAFE_RNG_CTRL_ENA_RING1 0x00000008 /* test entropy oscillator #1 */
++#define SAFE_RNG_CTRL_ENA_RING2 0x00000010 /* test entropy oscillator #2 */
++#define SAFE_RNG_CTRL_DIS_ALARM 0x00000020 /* disable RNG alarm reports */
++#define SAFE_RNG_CTRL_TST_CLOCK 0x00000040 /* enable test clock */
++#define SAFE_RNG_CTRL_SHORTEN 0x00000080 /* shorten state timers */
++#define SAFE_RNG_CTRL_TST_ALARM 0x00000100 /* simulate alarm state */
++#define SAFE_RNG_CTRL_RST_LFSR 0x00000200 /* reset LFSR */
++
++/*
++ * Packet engine descriptor. Note that d_csr is a copy of the
++ * SAFE_PE_CSR register and all definitions apply, and d_len
++ * is a copy of the SAFE_PE_LEN register and all definitions apply.
++ * d_src and d_len may point directly to contiguous data or to a
++ * list of ``particle descriptors'' when using scatter/gather i/o.
++ */
++struct safe_desc {
++ u_int32_t d_csr; /* per-packet control/status */
++ u_int32_t d_src; /* source address */
++ u_int32_t d_dst; /* destination address */
++ u_int32_t d_sa; /* SA address */
++ u_int32_t d_len; /* length, bypass, status */
++};
++
++/*
++ * Scatter/Gather particle descriptor.
++ *
++ * NB: scatter descriptors do not specify a size; this is fixed
++ * by the setting of the SAFE_PE_PARTCFG register.
++ */
++struct safe_pdesc {
++ u_int32_t pd_addr; /* particle address */
++#ifdef __BIG_ENDIAN
++ u_int16_t pd_flags; /* control word */
++ u_int16_t pd_size; /* particle size (bytes) */
++#else
++ u_int16_t pd_flags; /* control word */
++ u_int16_t pd_size; /* particle size (bytes) */
++#endif
++};
++
++#define SAFE_PD_READY 0x0001 /* ready for processing */
++#define SAFE_PD_DONE 0x0002 /* h/w completed processing */
++
++/*
++ * Security Association (SA) Record (Rev 1). One of these is
++ * required for each operation processed by the packet engine.
++ */
++struct safe_sarec {
++ u_int32_t sa_cmd0;
++ u_int32_t sa_cmd1;
++ u_int32_t sa_resv0;
++ u_int32_t sa_resv1;
++ u_int32_t sa_key[8]; /* DES/3DES/AES key */
++ u_int32_t sa_indigest[5]; /* inner digest */
++ u_int32_t sa_outdigest[5]; /* outer digest */
++ u_int32_t sa_spi; /* SPI */
++ u_int32_t sa_seqnum; /* sequence number */
++ u_int32_t sa_seqmask[2]; /* sequence number mask */
++ u_int32_t sa_resv2;
++ u_int32_t sa_staterec; /* address of state record */
++ u_int32_t sa_resv3[2];
++ u_int32_t sa_samgmt0; /* SA management field 0 */
++ u_int32_t sa_samgmt1; /* SA management field 0 */
++};
++
++#define SAFE_SA_CMD0_OP 0x00000007 /* operation code */
++#define SAFE_SA_CMD0_OP_CRYPT 0x00000000 /* encrypt/decrypt (basic) */
++#define SAFE_SA_CMD0_OP_BOTH 0x00000001 /* encrypt-hash/hash-decrypto */
++#define SAFE_SA_CMD0_OP_HASH 0x00000003 /* hash (outbound-only) */
++#define SAFE_SA_CMD0_OP_ESP 0x00000000 /* ESP in/out (proto) */
++#define SAFE_SA_CMD0_OP_AH 0x00000001 /* AH in/out (proto) */
++#define SAFE_SA_CMD0_INBOUND 0x00000008 /* inbound operation */
++#define SAFE_SA_CMD0_OUTBOUND 0x00000000 /* outbound operation */
++#define SAFE_SA_CMD0_GROUP 0x00000030 /* operation group */
++#define SAFE_SA_CMD0_BASIC 0x00000000 /* basic operation */
++#define SAFE_SA_CMD0_PROTO 0x00000010 /* protocol/packet operation */
++#define SAFE_SA_CMD0_BUNDLE 0x00000020 /* bundled operation (resvd) */
++#define SAFE_SA_CMD0_PAD 0x000000c0 /* crypto pad method */
++#define SAFE_SA_CMD0_PAD_IPSEC 0x00000000 /* IPsec padding */
++#define SAFE_SA_CMD0_PAD_PKCS7 0x00000040 /* PKCS#7 padding */
++#define SAFE_SA_CMD0_PAD_CONS 0x00000080 /* constant padding */
++#define SAFE_SA_CMD0_PAD_ZERO 0x000000c0 /* zero padding */
++#define SAFE_SA_CMD0_CRYPT_ALG 0x00000f00 /* symmetric crypto algorithm */
++#define SAFE_SA_CMD0_DES 0x00000000 /* DES crypto algorithm */
++#define SAFE_SA_CMD0_3DES 0x00000100 /* 3DES crypto algorithm */
++#define SAFE_SA_CMD0_AES 0x00000300 /* AES crypto algorithm */
++#define SAFE_SA_CMD0_CRYPT_NULL 0x00000f00 /* null crypto algorithm */
++#define SAFE_SA_CMD0_HASH_ALG 0x0000f000 /* hash algorithm */
++#define SAFE_SA_CMD0_MD5 0x00000000 /* MD5 hash algorithm */
++#define SAFE_SA_CMD0_SHA1 0x00001000 /* SHA-1 hash algorithm */
++#define SAFE_SA_CMD0_HASH_NULL 0x0000f000 /* null hash algorithm */
++#define SAFE_SA_CMD0_HDR_PROC 0x00080000 /* header processing */
++#define SAFE_SA_CMD0_IBUSID 0x00300000 /* input bus id */
++#define SAFE_SA_CMD0_IPCI 0x00100000 /* PCI input bus id */
++#define SAFE_SA_CMD0_OBUSID 0x00c00000 /* output bus id */
++#define SAFE_SA_CMD0_OPCI 0x00400000 /* PCI output bus id */
++#define SAFE_SA_CMD0_IVLD 0x03000000 /* IV loading */
++#define SAFE_SA_CMD0_IVLD_NONE 0x00000000 /* IV no load (reuse) */
++#define SAFE_SA_CMD0_IVLD_IBUF 0x01000000 /* IV load from input buffer */
++#define SAFE_SA_CMD0_IVLD_STATE 0x02000000 /* IV load from state */
++#define SAFE_SA_CMD0_HSLD 0x0c000000 /* hash state loading */
++#define SAFE_SA_CMD0_HSLD_SA 0x00000000 /* hash state load from SA */
++#define SAFE_SA_CMD0_HSLD_STATE 0x08000000 /* hash state load from state */
++#define SAFE_SA_CMD0_HSLD_NONE 0x0c000000 /* hash state no load */
++#define SAFE_SA_CMD0_SAVEIV 0x10000000 /* save IV */
++#define SAFE_SA_CMD0_SAVEHASH 0x20000000 /* save hash state */
++#define SAFE_SA_CMD0_IGATHER 0x40000000 /* input gather */
++#define SAFE_SA_CMD0_OSCATTER 0x80000000 /* output scatter */
++
++#define SAFE_SA_CMD1_HDRCOPY 0x00000002 /* copy header to output */
++#define SAFE_SA_CMD1_PAYCOPY 0x00000004 /* copy payload to output */
++#define SAFE_SA_CMD1_PADCOPY 0x00000008 /* copy pad to output */
++#define SAFE_SA_CMD1_IPV4 0x00000000 /* IPv4 protocol */
++#define SAFE_SA_CMD1_IPV6 0x00000010 /* IPv6 protocol */
++#define SAFE_SA_CMD1_MUTABLE 0x00000020 /* mutable bit processing */
++#define SAFE_SA_CMD1_SRBUSID 0x000000c0 /* state record bus id */
++#define SAFE_SA_CMD1_SRPCI 0x00000040 /* state record from PCI */
++#define SAFE_SA_CMD1_CRMODE 0x00000300 /* crypto mode */
++#define SAFE_SA_CMD1_ECB 0x00000000 /* ECB crypto mode */
++#define SAFE_SA_CMD1_CBC 0x00000100 /* CBC crypto mode */
++#define SAFE_SA_CMD1_OFB 0x00000200 /* OFB crypto mode */
++#define SAFE_SA_CMD1_CFB 0x00000300 /* CFB crypto mode */
++#define SAFE_SA_CMD1_CRFEEDBACK 0x00000c00 /* crypto feedback mode */
++#define SAFE_SA_CMD1_64BIT 0x00000000 /* 64-bit crypto feedback */
++#define SAFE_SA_CMD1_8BIT 0x00000400 /* 8-bit crypto feedback */
++#define SAFE_SA_CMD1_1BIT 0x00000800 /* 1-bit crypto feedback */
++#define SAFE_SA_CMD1_128BIT 0x00000c00 /* 128-bit crypto feedback */
++#define SAFE_SA_CMD1_OPTIONS 0x00001000 /* HMAC/options mutable bit */
++#define SAFE_SA_CMD1_HMAC SAFE_SA_CMD1_OPTIONS
++#define SAFE_SA_CMD1_SAREV1 0x00008000 /* SA Revision 1 */
++#define SAFE_SA_CMD1_OFFSET 0x00ff0000 /* hash/crypto offset(dwords) */
++#define SAFE_SA_CMD1_OFFSET_S 16
++#define SAFE_SA_CMD1_AESKEYLEN 0x0f000000 /* AES key length */
++#define SAFE_SA_CMD1_AES128 0x02000000 /* 128-bit AES key */
++#define SAFE_SA_CMD1_AES192 0x03000000 /* 192-bit AES key */
++#define SAFE_SA_CMD1_AES256 0x04000000 /* 256-bit AES key */
++
++/*
++ * Security Associate State Record (Rev 1).
++ */
++struct safe_sastate {
++ u_int32_t sa_saved_iv[4]; /* saved IV (DES/3DES/AES) */
++ u_int32_t sa_saved_hashbc; /* saved hash byte count */
++ u_int32_t sa_saved_indigest[5]; /* saved inner digest */
++};
++#endif /* _SAFE_SAFEREG_H_ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/safe/safevar.h linux-2.6.36/crypto/ocf/safe/safevar.h
+--- linux-2.6.36.orig/crypto/ocf/safe/safevar.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/safe/safevar.h 2010-11-09 20:28:13.022495375 +0100
+@@ -0,0 +1,230 @@
++/*-
++ * The linux port of this code done by David McCullough
++ * Copyright (C) 2004-2010 David McCullough <david_mccullough@mcafee.com>
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 2003 Sam Leffler, Errno Consulting
++ * Copyright (c) 2003 Global Technology Associates, Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * $FreeBSD: src/sys/dev/safe/safevar.h,v 1.2 2006/05/17 18:34:26 pjd Exp $
++ */
++#ifndef _SAFE_SAFEVAR_H_
++#define _SAFE_SAFEVAR_H_
++
++/* Maximum queue length */
++#ifndef SAFE_MAX_NQUEUE
++#define SAFE_MAX_NQUEUE 60
++#endif
++
++#define SAFE_MAX_PART 64 /* Maximum scatter/gather depth */
++#define SAFE_DMA_BOUNDARY 0 /* No boundary for source DMA ops */
++#define SAFE_MAX_DSIZE 2048 /* MCLBYTES Fixed scatter particle size */
++#define SAFE_MAX_SSIZE 0x0ffff /* Maximum gather particle size */
++#define SAFE_MAX_DMA 0xfffff /* Maximum PE operand size (20 bits) */
++/* total src+dst particle descriptors */
++#define SAFE_TOTAL_DPART (SAFE_MAX_NQUEUE * SAFE_MAX_PART)
++#define SAFE_TOTAL_SPART (SAFE_MAX_NQUEUE * SAFE_MAX_PART)
++
++#define SAFE_RNG_MAXBUFSIZ 128 /* 32-bit words */
++
++#define SAFE_CARD(sid) (((sid) & 0xf0000000) >> 28)
++#define SAFE_SESSION(sid) ( (sid) & 0x0fffffff)
++#define SAFE_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff))
++
++#define SAFE_DEF_RTY 0xff /* PCI Retry Timeout */
++#define SAFE_DEF_TOUT 0xff /* PCI TRDY Timeout */
++#define SAFE_DEF_CACHELINE 0x01 /* Cache Line setting */
++
++#ifdef __KERNEL__
++/*
++ * State associated with the allocation of each chunk
++ * of memory setup for DMA.
++ */
++struct safe_dma_alloc {
++ dma_addr_t dma_paddr;
++ void *dma_vaddr;
++};
++
++/*
++ * Cryptographic operand state. One of these exists for each
++ * source and destination operand passed in from the crypto
++ * subsystem. When possible source and destination operands
++ * refer to the same memory. More often they are distinct.
++ * We track the virtual address of each operand as well as
++ * where each is mapped for DMA.
++ */
++struct safe_operand {
++ union {
++ struct sk_buff *skb;
++ struct uio *io;
++ } u;
++ void *map;
++ int mapsize; /* total number of bytes in segs */
++ struct {
++ dma_addr_t ds_addr;
++ int ds_len;
++ int ds_tlen;
++ } segs[SAFE_MAX_PART];
++ int nsegs;
++};
++
++/*
++ * Packet engine ring entry and cryptographic operation state.
++ * The packet engine requires a ring of descriptors that contain
++ * pointers to various cryptographic state. However the ring
++ * configuration register allows you to specify an arbitrary size
++ * for ring entries. We use this feature to collect most of the
++ * state for each cryptographic request into one spot. Other than
++ * ring entries only the ``particle descriptors'' (scatter/gather
++ * lists) and the actual operand data are kept separate. The
++ * particle descriptors must also be organized in rings. The
++ * operand data can be located aribtrarily (modulo alignment constraints).
++ *
++ * Note that the descriptor ring is mapped onto the PCI bus so
++ * the hardware can DMA data. This means the entire ring must be
++ * contiguous.
++ */
++struct safe_ringentry {
++ struct safe_desc re_desc; /* command descriptor */
++ struct safe_sarec re_sa; /* SA record */
++ struct safe_sastate re_sastate; /* SA state record */
++
++ struct cryptop *re_crp; /* crypto operation */
++
++ struct safe_operand re_src; /* source operand */
++ struct safe_operand re_dst; /* destination operand */
++
++ int re_sesn; /* crypto session ID */
++ int re_flags;
++#define SAFE_QFLAGS_COPYOUTIV 0x1 /* copy back on completion */
++#define SAFE_QFLAGS_COPYOUTICV 0x2 /* copy back on completion */
++};
++
++#define re_src_skb re_src.u.skb
++#define re_src_io re_src.u.io
++#define re_src_map re_src.map
++#define re_src_nsegs re_src.nsegs
++#define re_src_segs re_src.segs
++#define re_src_mapsize re_src.mapsize
++
++#define re_dst_skb re_dst.u.skb
++#define re_dst_io re_dst.u.io
++#define re_dst_map re_dst.map
++#define re_dst_nsegs re_dst.nsegs
++#define re_dst_segs re_dst.segs
++#define re_dst_mapsize re_dst.mapsize
++
++struct rndstate_test;
++
++struct safe_session {
++ u_int32_t ses_used;
++ u_int32_t ses_klen; /* key length in bits */
++ u_int32_t ses_key[8]; /* DES/3DES/AES key */
++ u_int32_t ses_mlen; /* hmac length in bytes */
++ u_int32_t ses_hminner[5]; /* hmac inner state */
++ u_int32_t ses_hmouter[5]; /* hmac outer state */
++ u_int32_t ses_iv[4]; /* DES/3DES/AES iv */
++};
++
++struct safe_pkq {
++ struct list_head pkq_list;
++ struct cryptkop *pkq_krp;
++};
++
++struct safe_softc {
++ softc_device_decl sc_dev;
++ u32 sc_irq;
++
++ struct pci_dev *sc_pcidev;
++ ocf_iomem_t sc_base_addr;
++
++ u_int sc_chiprev; /* major/minor chip revision */
++ int sc_flags; /* device specific flags */
++#define SAFE_FLAGS_KEY 0x01 /* has key accelerator */
++#define SAFE_FLAGS_RNG 0x02 /* hardware rng */
++ int sc_suspended;
++ int sc_needwakeup; /* notify crypto layer */
++ int32_t sc_cid; /* crypto tag */
++
++ struct safe_dma_alloc sc_ringalloc; /* PE ring allocation state */
++ struct safe_ringentry *sc_ring; /* PE ring */
++ struct safe_ringentry *sc_ringtop; /* PE ring top */
++ struct safe_ringentry *sc_front; /* next free entry */
++ struct safe_ringentry *sc_back; /* next pending entry */
++ int sc_nqchip; /* # passed to chip */
++ spinlock_t sc_ringmtx; /* PE ring lock */
++ struct safe_pdesc *sc_spring; /* src particle ring */
++ struct safe_pdesc *sc_springtop; /* src particle ring top */
++ struct safe_pdesc *sc_spfree; /* next free src particle */
++ struct safe_dma_alloc sc_spalloc; /* src particle ring state */
++ struct safe_pdesc *sc_dpring; /* dest particle ring */
++ struct safe_pdesc *sc_dpringtop; /* dest particle ring top */
++ struct safe_pdesc *sc_dpfree; /* next free dest particle */
++ struct safe_dma_alloc sc_dpalloc; /* dst particle ring state */
++ int sc_nsessions; /* # of sessions */
++ struct safe_session *sc_sessions; /* sessions */
++
++ struct timer_list sc_pkto; /* PK polling */
++ spinlock_t sc_pkmtx; /* PK lock */
++ struct list_head sc_pkq; /* queue of PK requests */
++ struct safe_pkq *sc_pkq_cur; /* current processing request */
++ u_int32_t sc_pk_reslen, sc_pk_resoff;
++
++ int sc_max_dsize; /* maximum safe DMA size */
++};
++#endif /* __KERNEL__ */
++
++struct safe_stats {
++ u_int64_t st_ibytes;
++ u_int64_t st_obytes;
++ u_int32_t st_ipackets;
++ u_int32_t st_opackets;
++ u_int32_t st_invalid; /* invalid argument */
++ u_int32_t st_badsession; /* invalid session id */
++ u_int32_t st_badflags; /* flags indicate !(mbuf | uio) */
++ u_int32_t st_nodesc; /* op submitted w/o descriptors */
++ u_int32_t st_badalg; /* unsupported algorithm */
++ u_int32_t st_ringfull; /* PE descriptor ring full */
++ u_int32_t st_peoperr; /* PE marked error */
++ u_int32_t st_dmaerr; /* PE DMA error */
++ u_int32_t st_bypasstoobig; /* bypass > 96 bytes */
++ u_int32_t st_skipmismatch; /* enc part begins before auth part */
++ u_int32_t st_lenmismatch; /* enc length different auth length */
++ u_int32_t st_coffmisaligned; /* crypto offset not 32-bit aligned */
++ u_int32_t st_cofftoobig; /* crypto offset > 255 words */
++ u_int32_t st_iovmisaligned; /* iov op not aligned */
++ u_int32_t st_iovnotuniform; /* iov op not suitable */
++ u_int32_t st_unaligned; /* unaligned src caused copy */
++ u_int32_t st_notuniform; /* non-uniform src caused copy */
++ u_int32_t st_nomap; /* bus_dmamap_create failed */
++ u_int32_t st_noload; /* bus_dmamap_load_* failed */
++ u_int32_t st_nombuf; /* MGET* failed */
++ u_int32_t st_nomcl; /* MCLGET* failed */
++ u_int32_t st_maxqchip; /* max mcr1 ops out for processing */
++ u_int32_t st_rng; /* RNG requests */
++ u_int32_t st_rngalarm; /* RNG alarm requests */
++ u_int32_t st_noicvcopy; /* ICV data copies suppressed */
++};
++#endif /* _SAFE_SAFEVAR_H_ */
+diff -Nur linux-2.6.36.orig/crypto/ocf/safe/sha1.c linux-2.6.36/crypto/ocf/safe/sha1.c
+--- linux-2.6.36.orig/crypto/ocf/safe/sha1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/safe/sha1.c 2010-11-09 20:28:13.072495484 +0100
+@@ -0,0 +1,279 @@
++/* $KAME: sha1.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */
++/*
++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. Neither the name of the project 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 BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT 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.
++ */
++
++/*
++ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1)
++ * based on: http://csrc.nist.gov/fips/fip180-1.txt
++ * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>
++ */
++
++#if 0
++#include <sys/cdefs.h>
++__FBSDID("$FreeBSD: src/sys/crypto/sha1.c,v 1.9 2003/06/10 21:36:57 obrien Exp $");
++
++#include <sys/types.h>
++#include <sys/cdefs.h>
++#include <sys/time.h>
++#include <sys/systm.h>
++
++#include <crypto/sha1.h>
++#endif
++
++/* sanity check */
++#if BYTE_ORDER != BIG_ENDIAN
++# if BYTE_ORDER != LITTLE_ENDIAN
++# define unsupported 1
++# endif
++#endif
++
++#ifndef unsupported
++
++/* constant table */
++static u_int32_t _K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
++#define K(t) _K[(t) / 20]
++
++#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d)))
++#define F1(b, c, d) (((b) ^ (c)) ^ (d))
++#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
++#define F3(b, c, d) (((b) ^ (c)) ^ (d))
++
++#define S(n, x) (((x) << (n)) | ((x) >> (32 - n)))
++
++#undef H
++#define H(n) (ctxt->h.b32[(n)])
++#define COUNT (ctxt->count)
++#define BCOUNT (ctxt->c.b64[0] / 8)
++#define W(n) (ctxt->m.b32[(n)])
++
++#define PUTBYTE(x) { \
++ ctxt->m.b8[(COUNT % 64)] = (x); \
++ COUNT++; \
++ COUNT %= 64; \
++ ctxt->c.b64[0] += 8; \
++ if (COUNT % 64 == 0) \
++ sha1_step(ctxt); \
++ }
++
++#define PUTPAD(x) { \
++ ctxt->m.b8[(COUNT % 64)] = (x); \
++ COUNT++; \
++ COUNT %= 64; \
++ if (COUNT % 64 == 0) \
++ sha1_step(ctxt); \
++ }
++
++static void sha1_step(struct sha1_ctxt *);
++
++static void
++sha1_step(ctxt)
++ struct sha1_ctxt *ctxt;
++{
++ u_int32_t a, b, c, d, e;
++ size_t t, s;
++ u_int32_t tmp;
++
++#if BYTE_ORDER == LITTLE_ENDIAN
++ struct sha1_ctxt tctxt;
++ bcopy(&ctxt->m.b8[0], &tctxt.m.b8[0], 64);
++ ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2];
++ ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0];
++ ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6];
++ ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4];
++ ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10];
++ ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8];
++ ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14];
++ ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12];
++ ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18];
++ ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16];
++ ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22];
++ ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20];
++ ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26];
++ ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24];
++ ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30];
++ ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28];
++ ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34];
++ ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32];
++ ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38];
++ ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36];
++ ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42];
++ ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40];
++ ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46];
++ ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44];
++ ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50];
++ ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48];
++ ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54];
++ ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52];
++ ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58];
++ ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56];
++ ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62];
++ ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60];
++#endif
++
++ a = H(0); b = H(1); c = H(2); d = H(3); e = H(4);
++
++ for (t = 0; t < 20; t++) {
++ s = t & 0x0f;
++ if (t >= 16) {
++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
++ }
++ tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t);
++ e = d; d = c; c = S(30, b); b = a; a = tmp;
++ }
++ for (t = 20; t < 40; t++) {
++ s = t & 0x0f;
++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
++ tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t);
++ e = d; d = c; c = S(30, b); b = a; a = tmp;
++ }
++ for (t = 40; t < 60; t++) {
++ s = t & 0x0f;
++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
++ tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t);
++ e = d; d = c; c = S(30, b); b = a; a = tmp;
++ }
++ for (t = 60; t < 80; t++) {
++ s = t & 0x0f;
++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
++ tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t);
++ e = d; d = c; c = S(30, b); b = a; a = tmp;
++ }
++
++ H(0) = H(0) + a;
++ H(1) = H(1) + b;
++ H(2) = H(2) + c;
++ H(3) = H(3) + d;
++ H(4) = H(4) + e;
++
++ bzero(&ctxt->m.b8[0], 64);
++}
++
++/*------------------------------------------------------------*/
++
++void
++sha1_init(ctxt)
++ struct sha1_ctxt *ctxt;
++{
++ bzero(ctxt, sizeof(struct sha1_ctxt));
++ H(0) = 0x67452301;
++ H(1) = 0xefcdab89;
++ H(2) = 0x98badcfe;
++ H(3) = 0x10325476;
++ H(4) = 0xc3d2e1f0;
++}
++
++void
++sha1_pad(ctxt)
++ struct sha1_ctxt *ctxt;
++{
++ size_t padlen; /*pad length in bytes*/
++ size_t padstart;
++
++ PUTPAD(0x80);
++
++ padstart = COUNT % 64;
++ padlen = 64 - padstart;
++ if (padlen < 8) {
++ bzero(&ctxt->m.b8[padstart], padlen);
++ COUNT += padlen;
++ COUNT %= 64;
++ sha1_step(ctxt);
++ padstart = COUNT % 64; /* should be 0 */
++ padlen = 64 - padstart; /* should be 64 */
++ }
++ bzero(&ctxt->m.b8[padstart], padlen - 8);
++ COUNT += (padlen - 8);
++ COUNT %= 64;
++#if BYTE_ORDER == BIG_ENDIAN
++ PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]);
++ PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]);
++ PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]);
++ PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]);
++#else
++ PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]);
++ PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]);
++ PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]);
++ PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]);
++#endif
++}
++
++void
++sha1_loop(ctxt, input, len)
++ struct sha1_ctxt *ctxt;
++ const u_int8_t *input;
++ size_t len;
++{
++ size_t gaplen;
++ size_t gapstart;
++ size_t off;
++ size_t copysiz;
++
++ off = 0;
++
++ while (off < len) {
++ gapstart = COUNT % 64;
++ gaplen = 64 - gapstart;
++
++ copysiz = (gaplen < len - off) ? gaplen : len - off;
++ bcopy(&input[off], &ctxt->m.b8[gapstart], copysiz);
++ COUNT += copysiz;
++ COUNT %= 64;
++ ctxt->c.b64[0] += copysiz * 8;
++ if (COUNT % 64 == 0)
++ sha1_step(ctxt);
++ off += copysiz;
++ }
++}
++
++void
++sha1_result(ctxt, digest0)
++ struct sha1_ctxt *ctxt;
++ caddr_t digest0;
++{
++ u_int8_t *digest;
++
++ digest = (u_int8_t *)digest0;
++ sha1_pad(ctxt);
++#if BYTE_ORDER == BIG_ENDIAN
++ bcopy(&ctxt->h.b8[0], digest, 20);
++#else
++ digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2];
++ digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0];
++ digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6];
++ digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4];
++ digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10];
++ digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8];
++ digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14];
++ digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12];
++ digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18];
++ digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16];
++#endif
++}
++
++#endif /*unsupported*/
+diff -Nur linux-2.6.36.orig/crypto/ocf/safe/sha1.h linux-2.6.36/crypto/ocf/safe/sha1.h
+--- linux-2.6.36.orig/crypto/ocf/safe/sha1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/safe/sha1.h 2010-11-09 20:28:13.112495423 +0100
+@@ -0,0 +1,72 @@
++/* $FreeBSD: src/sys/crypto/sha1.h,v 1.8 2002/03/20 05:13:50 alfred Exp $ */
++/* $KAME: sha1.h,v 1.5 2000/03/27 04:36:23 sumikawa Exp $ */
++
++/*
++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. Neither the name of the project 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 BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT 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.
++ */
++/*
++ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1)
++ * based on: http://csrc.nist.gov/fips/fip180-1.txt
++ * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>
++ */
++
++#ifndef _NETINET6_SHA1_H_
++#define _NETINET6_SHA1_H_
++
++struct sha1_ctxt {
++ union {
++ u_int8_t b8[20];
++ u_int32_t b32[5];
++ } h;
++ union {
++ u_int8_t b8[8];
++ u_int64_t b64[1];
++ } c;
++ union {
++ u_int8_t b8[64];
++ u_int32_t b32[16];
++ } m;
++ u_int8_t count;
++};
++
++#ifdef __KERNEL__
++extern void sha1_init(struct sha1_ctxt *);
++extern void sha1_pad(struct sha1_ctxt *);
++extern void sha1_loop(struct sha1_ctxt *, const u_int8_t *, size_t);
++extern void sha1_result(struct sha1_ctxt *, caddr_t);
++
++/* compatibilty with other SHA1 source codes */
++typedef struct sha1_ctxt SHA1_CTX;
++#define SHA1Init(x) sha1_init((x))
++#define SHA1Update(x, y, z) sha1_loop((x), (y), (z))
++#define SHA1Final(x, y) sha1_result((y), (x))
++#endif /* __KERNEL__ */
++
++#define SHA1_RESULTLEN (160/8)
++
++#endif /*_NETINET6_SHA1_H_*/
+diff -Nur linux-2.6.36.orig/crypto/ocf/talitos/Makefile linux-2.6.36/crypto/ocf/talitos/Makefile
+--- linux-2.6.36.orig/crypto/ocf/talitos/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/talitos/Makefile 2010-11-09 20:28:13.155214387 +0100
+@@ -0,0 +1,12 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++obj-$(CONFIG_OCF_TALITOS) += talitos.o
++
++obj ?= .
++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
+diff -Nur linux-2.6.36.orig/crypto/ocf/talitos/talitos.c linux-2.6.36/crypto/ocf/talitos/talitos.c
+--- linux-2.6.36.orig/crypto/ocf/talitos/talitos.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/talitos/talitos.c 2010-11-09 20:28:13.192104548 +0100
+@@ -0,0 +1,1359 @@
++/*
++ * crypto/ocf/talitos/talitos.c
++ *
++ * An OCF-Linux module that uses Freescale's SEC to do the crypto.
++ * Based on crypto/ocf/hifn and crypto/ocf/safe OCF drivers
++ *
++ * Copyright (c) 2006 Freescale Semiconductor, Inc.
++ *
++ * This code written by Kim A. B. Phillips <kim.phillips@freescale.com>
++ * some code copied from files with the following:
++ * Copyright (C) 2004-2007 David McCullough <david_mccullough@mcafee.com>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ * ---------------------------------------------------------------------------
++ *
++ * NOTES:
++ *
++ * The Freescale SEC (also known as 'talitos') resides on the
++ * internal bus, and runs asynchronous to the processor core. It has
++ * a wide gamut of cryptographic acceleration features, including single-
++ * pass IPsec (also known as algorithm chaining). To properly utilize
++ * all of the SEC's performance enhancing features, further reworking
++ * of higher level code (framework, applications) will be necessary.
++ *
++ * The following table shows which SEC version is present in which devices:
++ *
++ * Devices SEC version
++ *
++ * 8272, 8248 SEC 1.0
++ * 885, 875 SEC 1.2
++ * 8555E, 8541E SEC 2.0
++ * 8349E SEC 2.01
++ * 8548E SEC 2.1
++ *
++ * The following table shows the features offered by each SEC version:
++ *
++ * Max. chan-
++ * version Bus I/F Clock nels DEU AESU AFEU MDEU PKEU RNG KEU
++ *
++ * SEC 1.0 internal 64b 100MHz 4 1 1 1 1 1 1 0
++ * SEC 1.2 internal 32b 66MHz 1 1 1 0 1 0 0 0
++ * SEC 2.0 internal 64b 166MHz 4 1 1 1 1 1 1 0
++ * SEC 2.01 internal 64b 166MHz 4 1 1 1 1 1 1 0
++ * SEC 2.1 internal 64b 333MHz 4 1 1 1 1 1 1 1
++ *
++ * Each execution unit in the SEC has two modes of execution; channel and
++ * slave/debug. This driver employs the channel infrastructure in the
++ * device for convenience. Only the RNG is directly accessed due to the
++ * convenience of its random fifo pool. The relationship between the
++ * channels and execution units is depicted in the following diagram:
++ *
++ * ------- ------------
++ * ---| ch0 |---| |
++ * ------- | |
++ * | |------+-------+-------+-------+------------
++ * ------- | | | | | | |
++ * ---| ch1 |---| | | | | | |
++ * ------- | | ------ ------ ------ ------ ------
++ * |controller| |DEU | |AESU| |MDEU| |PKEU| ... |RNG |
++ * ------- | | ------ ------ ------ ------ ------
++ * ---| ch2 |---| | | | | | |
++ * ------- | | | | | | |
++ * | |------+-------+-------+-------+------------
++ * ------- | |
++ * ---| ch3 |---| |
++ * ------- ------------
++ *
++ * Channel ch0 may drive an aes operation to the aes unit (AESU),
++ * and, at the same time, ch1 may drive a message digest operation
++ * to the mdeu. Each channel has an input descriptor FIFO, and the
++ * FIFO can contain, e.g. on the 8541E, up to 24 entries, before a
++ * a buffer overrun error is triggered. The controller is responsible
++ * for fetching the data from descriptor pointers, and passing the
++ * data to the appropriate EUs. The controller also writes the
++ * cryptographic operation's result to memory. The SEC notifies
++ * completion by triggering an interrupt and/or setting the 1st byte
++ * of the hdr field to 0xff.
++ *
++ * TODO:
++ * o support more algorithms
++ * o support more versions of the SEC
++ * o add support for linux 2.4
++ * o scatter-gather (sg) support
++ * o add support for public key ops (PKEU)
++ * o add statistics
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/random.h>
++#include <linux/skbuff.h>
++#include <asm/scatterlist.h>
++#include <linux/dma-mapping.h> /* dma_map_single() */
++#include <linux/moduleparam.h>
++
++#include <linux/version.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
++#include <linux/platform_device.h>
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++#include <linux/of_platform.h>
++#endif
++
++#include <cryptodev.h>
++#include <uio.h>
++
++#define DRV_NAME "talitos"
++
++#include "talitos_dev.h"
++#include "talitos_soft.h"
++
++#define read_random(p,l) get_random_bytes(p,l)
++
++const char talitos_driver_name[] = "Talitos OCF";
++const char talitos_driver_version[] = "0.2";
++
++static int talitos_newsession(device_t dev, u_int32_t *sidp,
++ struct cryptoini *cri);
++static int talitos_freesession(device_t dev, u_int64_t tid);
++static int talitos_process(device_t dev, struct cryptop *crp, int hint);
++static void dump_talitos_status(struct talitos_softc *sc);
++static int talitos_submit(struct talitos_softc *sc, struct talitos_desc *td,
++ int chsel);
++static void talitos_doneprocessing(struct talitos_softc *sc);
++static void talitos_init_device(struct talitos_softc *sc);
++static void talitos_reset_device_master(struct talitos_softc *sc);
++static void talitos_reset_device(struct talitos_softc *sc);
++static void talitos_errorprocessing(struct talitos_softc *sc);
++#ifdef CONFIG_PPC_MERGE
++static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match);
++static int talitos_remove(struct of_device *ofdev);
++#else
++static int talitos_probe(struct platform_device *pdev);
++static int talitos_remove(struct platform_device *pdev);
++#endif
++#ifdef CONFIG_OCF_RANDOMHARVEST
++static int talitos_read_random(void *arg, u_int32_t *buf, int maxwords);
++static void talitos_rng_init(struct talitos_softc *sc);
++#endif
++
++static device_method_t talitos_methods = {
++ /* crypto device methods */
++ DEVMETHOD(cryptodev_newsession, talitos_newsession),
++ DEVMETHOD(cryptodev_freesession,talitos_freesession),
++ DEVMETHOD(cryptodev_process, talitos_process),
++};
++
++#define debug talitos_debug
++int talitos_debug = 0;
++module_param(talitos_debug, int, 0644);
++MODULE_PARM_DESC(talitos_debug, "Enable debug");
++
++static inline void talitos_write(volatile unsigned *addr, u32 val)
++{
++ out_be32(addr, val);
++}
++
++static inline u32 talitos_read(volatile unsigned *addr)
++{
++ u32 val;
++ val = in_be32(addr);
++ return val;
++}
++
++static void dump_talitos_status(struct talitos_softc *sc)
++{
++ unsigned int v, v_hi, i, *ptr;
++ v = talitos_read(sc->sc_base_addr + TALITOS_MCR);
++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_MCR_HI);
++ printk(KERN_INFO "%s: MCR 0x%08x_%08x\n",
++ device_get_nameunit(sc->sc_cdev), v, v_hi);
++ v = talitos_read(sc->sc_base_addr + TALITOS_IMR);
++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI);
++ printk(KERN_INFO "%s: IMR 0x%08x_%08x\n",
++ device_get_nameunit(sc->sc_cdev), v, v_hi);
++ v = talitos_read(sc->sc_base_addr + TALITOS_ISR);
++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI);
++ printk(KERN_INFO "%s: ISR 0x%08x_%08x\n",
++ device_get_nameunit(sc->sc_cdev), v, v_hi);
++ for (i = 0; i < sc->sc_num_channels; i++) {
++ v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
++ TALITOS_CH_CDPR);
++ v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
++ TALITOS_CH_CDPR_HI);
++ printk(KERN_INFO "%s: CDPR ch%d 0x%08x_%08x\n",
++ device_get_nameunit(sc->sc_cdev), i, v, v_hi);
++ }
++ for (i = 0; i < sc->sc_num_channels; i++) {
++ v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
++ TALITOS_CH_CCPSR);
++ v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
++ TALITOS_CH_CCPSR_HI);
++ printk(KERN_INFO "%s: CCPSR ch%d 0x%08x_%08x\n",
++ device_get_nameunit(sc->sc_cdev), i, v, v_hi);
++ }
++ ptr = sc->sc_base_addr + TALITOS_CH_DESCBUF;
++ for (i = 0; i < 16; i++) {
++ v = talitos_read(ptr++); v_hi = talitos_read(ptr++);
++ printk(KERN_INFO "%s: DESCBUF ch0 0x%08x_%08x (tdp%02d)\n",
++ device_get_nameunit(sc->sc_cdev), v, v_hi, i);
++ }
++ return;
++}
++
++
++#ifdef CONFIG_OCF_RANDOMHARVEST
++/*
++ * pull random numbers off the RNG FIFO, not exceeding amount available
++ */
++static int
++talitos_read_random(void *arg, u_int32_t *buf, int maxwords)
++{
++ struct talitos_softc *sc = (struct talitos_softc *) arg;
++ int rc;
++ u_int32_t v;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ /* check for things like FIFO underflow */
++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI);
++ if (unlikely(v)) {
++ printk(KERN_ERR "%s: RNGISR_HI error %08x\n",
++ device_get_nameunit(sc->sc_cdev), v);
++ return 0;
++ }
++ /*
++ * OFL is number of available 64-bit words,
++ * shift and convert to a 32-bit word count
++ */
++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI);
++ v = (v & TALITOS_RNGSR_HI_OFL) >> (16 - 1);
++ if (maxwords > v)
++ maxwords = v;
++ for (rc = 0; rc < maxwords; rc++) {
++ buf[rc] = talitos_read(sc->sc_base_addr +
++ TALITOS_RNG_FIFO + rc*sizeof(u_int32_t));
++ }
++ if (maxwords & 1) {
++ /*
++ * RNG will complain with an AE in the RNGISR
++ * if we don't complete the pairs of 32-bit reads
++ * to its 64-bit register based FIFO
++ */
++ v = talitos_read(sc->sc_base_addr +
++ TALITOS_RNG_FIFO + rc*sizeof(u_int32_t));
++ }
++
++ return rc;
++}
++
++static void
++talitos_rng_init(struct talitos_softc *sc)
++{
++ u_int32_t v;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++ /* reset RNG EU */
++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGRCR_HI);
++ v |= TALITOS_RNGRCR_HI_SR;
++ talitos_write(sc->sc_base_addr + TALITOS_RNGRCR_HI, v);
++ while ((talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI)
++ & TALITOS_RNGSR_HI_RD) == 0)
++ cpu_relax();
++ /*
++ * we tell the RNG to start filling the RNG FIFO
++ * by writing the RNGDSR
++ */
++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGDSR_HI);
++ talitos_write(sc->sc_base_addr + TALITOS_RNGDSR_HI, v);
++ /*
++ * 64 bits of data will be pushed onto the FIFO every
++ * 256 SEC cycles until the FIFO is full. The RNG then
++ * attempts to keep the FIFO full.
++ */
++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI);
++ if (v) {
++ printk(KERN_ERR "%s: RNGISR_HI error %08x\n",
++ device_get_nameunit(sc->sc_cdev), v);
++ return;
++ }
++ /*
++ * n.b. we need to add a FIPS test here - if the RNG is going
++ * to fail, it's going to fail at reset time
++ */
++ return;
++}
++#endif /* CONFIG_OCF_RANDOMHARVEST */
++
++/*
++ * Generate a new software session.
++ */
++static int
++talitos_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
++{
++ struct cryptoini *c, *encini = NULL, *macini = NULL;
++ struct talitos_softc *sc = device_get_softc(dev);
++ struct talitos_session *ses = NULL;
++ int sesn;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++ if (sidp == NULL || cri == NULL || sc == NULL) {
++ DPRINTF("%s,%d - EINVAL\n", __FILE__, __LINE__);
++ return EINVAL;
++ }
++ for (c = cri; c != NULL; c = c->cri_next) {
++ if (c->cri_alg == CRYPTO_MD5 ||
++ c->cri_alg == CRYPTO_MD5_HMAC ||
++ c->cri_alg == CRYPTO_SHA1 ||
++ c->cri_alg == CRYPTO_SHA1_HMAC ||
++ c->cri_alg == CRYPTO_NULL_HMAC) {
++ if (macini)
++ return EINVAL;
++ macini = c;
++ } else if (c->cri_alg == CRYPTO_DES_CBC ||
++ c->cri_alg == CRYPTO_3DES_CBC ||
++ c->cri_alg == CRYPTO_AES_CBC ||
++ c->cri_alg == CRYPTO_NULL_CBC) {
++ if (encini)
++ return EINVAL;
++ encini = c;
++ } else {
++ DPRINTF("UNKNOWN c->cri_alg %d\n", encini->cri_alg);
++ return EINVAL;
++ }
++ }
++ if (encini == NULL && macini == NULL)
++ return EINVAL;
++ if (encini) {
++ /* validate key length */
++ switch (encini->cri_alg) {
++ case CRYPTO_DES_CBC:
++ if (encini->cri_klen != 64)
++ return EINVAL;
++ break;
++ case CRYPTO_3DES_CBC:
++ if (encini->cri_klen != 192) {
++ return EINVAL;
++ }
++ break;
++ case CRYPTO_AES_CBC:
++ if (encini->cri_klen != 128 &&
++ encini->cri_klen != 192 &&
++ encini->cri_klen != 256)
++ return EINVAL;
++ break;
++ default:
++ DPRINTF("UNKNOWN encini->cri_alg %d\n",
++ encini->cri_alg);
++ return EINVAL;
++ }
++ }
++
++ if (sc->sc_sessions == NULL) {
++ ses = sc->sc_sessions = (struct talitos_session *)
++ kmalloc(sizeof(struct talitos_session), SLAB_ATOMIC);
++ if (ses == NULL)
++ return ENOMEM;
++ memset(ses, 0, sizeof(struct talitos_session));
++ sesn = 0;
++ sc->sc_nsessions = 1;
++ } else {
++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
++ if (sc->sc_sessions[sesn].ses_used == 0) {
++ ses = &sc->sc_sessions[sesn];
++ break;
++ }
++ }
++
++ if (ses == NULL) {
++ /* allocating session */
++ sesn = sc->sc_nsessions;
++ ses = (struct talitos_session *) kmalloc(
++ (sesn + 1) * sizeof(struct talitos_session),
++ SLAB_ATOMIC);
++ if (ses == NULL)
++ return ENOMEM;
++ memset(ses, 0,
++ (sesn + 1) * sizeof(struct talitos_session));
++ memcpy(ses, sc->sc_sessions,
++ sesn * sizeof(struct talitos_session));
++ memset(sc->sc_sessions, 0,
++ sesn * sizeof(struct talitos_session));
++ kfree(sc->sc_sessions);
++ sc->sc_sessions = ses;
++ ses = &sc->sc_sessions[sesn];
++ sc->sc_nsessions++;
++ }
++ }
++
++ ses->ses_used = 1;
++
++ if (encini) {
++ /* get an IV */
++ /* XXX may read fewer than requested */
++ read_random(ses->ses_iv, sizeof(ses->ses_iv));
++
++ ses->ses_klen = (encini->cri_klen + 7) / 8;
++ memcpy(ses->ses_key, encini->cri_key, ses->ses_klen);
++ if (macini) {
++ /* doing hash on top of cipher */
++ ses->ses_hmac_len = (macini->cri_klen + 7) / 8;
++ memcpy(ses->ses_hmac, macini->cri_key,
++ ses->ses_hmac_len);
++ }
++ } else if (macini) {
++ /* doing hash */
++ ses->ses_klen = (macini->cri_klen + 7) / 8;
++ memcpy(ses->ses_key, macini->cri_key, ses->ses_klen);
++ }
++
++ /* back compat way of determining MSC result len */
++ if (macini) {
++ ses->ses_mlen = macini->cri_mlen;
++ if (ses->ses_mlen == 0) {
++ if (macini->cri_alg == CRYPTO_MD5_HMAC)
++ ses->ses_mlen = MD5_HASH_LEN;
++ else
++ ses->ses_mlen = SHA1_HASH_LEN;
++ }
++ }
++
++ /* really should make up a template td here,
++ * and only fill things like i/o and direction in process() */
++
++ /* assign session ID */
++ *sidp = TALITOS_SID(sc->sc_num, sesn);
++ return 0;
++}
++
++/*
++ * Deallocate a session.
++ */
++static int
++talitos_freesession(device_t dev, u_int64_t tid)
++{
++ struct talitos_softc *sc = device_get_softc(dev);
++ int session, ret;
++ u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
++
++ if (sc == NULL)
++ return EINVAL;
++ session = TALITOS_SESSION(sid);
++ if (session < sc->sc_nsessions) {
++ memset(&sc->sc_sessions[session], 0,
++ sizeof(sc->sc_sessions[session]));
++ ret = 0;
++ } else
++ ret = EINVAL;
++ return ret;
++}
++
++/*
++ * launch device processing - it will come back with done notification
++ * in the form of an interrupt and/or HDR_DONE_BITS in header
++ */
++static int
++talitos_submit(
++ struct talitos_softc *sc,
++ struct talitos_desc *td,
++ int chsel)
++{
++ u_int32_t v;
++
++ v = dma_map_single(NULL, td, sizeof(*td), DMA_TO_DEVICE);
++ talitos_write(sc->sc_base_addr +
++ chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF, 0);
++ talitos_write(sc->sc_base_addr +
++ chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF_HI, v);
++ return 0;
++}
++
++static int
++talitos_process(device_t dev, struct cryptop *crp, int hint)
++{
++ int i, err = 0, ivsize;
++ struct talitos_softc *sc = device_get_softc(dev);
++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
++ caddr_t iv;
++ struct talitos_session *ses;
++ struct talitos_desc *td;
++ unsigned long flags;
++ /* descriptor mappings */
++ int hmac_key, hmac_data, cipher_iv, cipher_key,
++ in_fifo, out_fifo, cipher_iv_out;
++ static int chsel = -1;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ if (crp == NULL || crp->crp_callback == NULL || sc == NULL) {
++ return EINVAL;
++ }
++ crp->crp_etype = 0;
++ if (TALITOS_SESSION(crp->crp_sid) >= sc->sc_nsessions) {
++ return EINVAL;
++ }
++
++ ses = &sc->sc_sessions[TALITOS_SESSION(crp->crp_sid)];
++
++ /* enter the channel scheduler */
++ spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
++
++ /* reuse channel that already had/has requests for the required EU */
++ for (i = 0; i < sc->sc_num_channels; i++) {
++ if (sc->sc_chnlastalg[i] == crp->crp_desc->crd_alg)
++ break;
++ }
++ if (i == sc->sc_num_channels) {
++ /*
++ * haven't seen this algo the last sc_num_channels or more
++ * use round robin in this case
++ * nb: sc->sc_num_channels must be power of 2
++ */
++ chsel = (chsel + 1) & (sc->sc_num_channels - 1);
++ } else {
++ /*
++ * matches channel with same target execution unit;
++ * use same channel in this case
++ */
++ chsel = i;
++ }
++ sc->sc_chnlastalg[chsel] = crp->crp_desc->crd_alg;
++
++ /* release the channel scheduler lock */
++ spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
++
++ /* acquire the selected channel fifo lock */
++ spin_lock_irqsave(&sc->sc_chnfifolock[chsel], flags);
++
++ /* find and reserve next available descriptor-cryptop pair */
++ for (i = 0; i < sc->sc_chfifo_len; i++) {
++ if (sc->sc_chnfifo[chsel][i].cf_desc.hdr == 0) {
++ /*
++ * ensure correct descriptor formation by
++ * avoiding inadvertently setting "optional" entries
++ * e.g. not using "optional" dptr2 for MD/HMAC descs
++ */
++ memset(&sc->sc_chnfifo[chsel][i].cf_desc,
++ 0, sizeof(*td));
++ /* reserve it with done notification request bit */
++ sc->sc_chnfifo[chsel][i].cf_desc.hdr |=
++ TALITOS_DONE_NOTIFY;
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&sc->sc_chnfifolock[chsel], flags);
++
++ if (i == sc->sc_chfifo_len) {
++ /* fifo full */
++ err = ERESTART;
++ goto errout;
++ }
++
++ td = &sc->sc_chnfifo[chsel][i].cf_desc;
++ sc->sc_chnfifo[chsel][i].cf_crp = crp;
++
++ crd1 = crp->crp_desc;
++ if (crd1 == NULL) {
++ err = EINVAL;
++ goto errout;
++ }
++ crd2 = crd1->crd_next;
++ /* prevent compiler warning */
++ hmac_key = 0;
++ hmac_data = 0;
++ if (crd2 == NULL) {
++ td->hdr |= TD_TYPE_COMMON_NONSNOOP_NO_AFEU;
++ /* assign descriptor dword ptr mappings for this desc. type */
++ cipher_iv = 1;
++ cipher_key = 2;
++ in_fifo = 3;
++ cipher_iv_out = 5;
++ if (crd1->crd_alg == CRYPTO_MD5_HMAC ||
++ crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++ crd1->crd_alg == CRYPTO_SHA1 ||
++ crd1->crd_alg == CRYPTO_MD5) {
++ out_fifo = 5;
++ maccrd = crd1;
++ enccrd = NULL;
++ } else if (crd1->crd_alg == CRYPTO_DES_CBC ||
++ crd1->crd_alg == CRYPTO_3DES_CBC ||
++ crd1->crd_alg == CRYPTO_AES_CBC ||
++ crd1->crd_alg == CRYPTO_ARC4) {
++ out_fifo = 4;
++ maccrd = NULL;
++ enccrd = crd1;
++ } else {
++ DPRINTF("UNKNOWN crd1->crd_alg %d\n", crd1->crd_alg);
++ err = EINVAL;
++ goto errout;
++ }
++ } else {
++ if (sc->sc_desc_types & TALITOS_HAS_DT_IPSEC_ESP) {
++ td->hdr |= TD_TYPE_IPSEC_ESP;
++ } else {
++ DPRINTF("unimplemented: multiple descriptor ipsec\n");
++ err = EINVAL;
++ goto errout;
++ }
++ /* assign descriptor dword ptr mappings for this desc. type */
++ hmac_key = 0;
++ hmac_data = 1;
++ cipher_iv = 2;
++ cipher_key = 3;
++ in_fifo = 4;
++ out_fifo = 5;
++ cipher_iv_out = 6;
++ if ((crd1->crd_alg == CRYPTO_MD5_HMAC ||
++ crd1->crd_alg == CRYPTO_SHA1_HMAC ||
++ crd1->crd_alg == CRYPTO_MD5 ||
++ crd1->crd_alg == CRYPTO_SHA1) &&
++ (crd2->crd_alg == CRYPTO_DES_CBC ||
++ crd2->crd_alg == CRYPTO_3DES_CBC ||
++ crd2->crd_alg == CRYPTO_AES_CBC ||
++ crd2->crd_alg == CRYPTO_ARC4) &&
++ ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) {
++ maccrd = crd1;
++ enccrd = crd2;
++ } else if ((crd1->crd_alg == CRYPTO_DES_CBC ||
++ crd1->crd_alg == CRYPTO_ARC4 ||
++ crd1->crd_alg == CRYPTO_3DES_CBC ||
++ crd1->crd_alg == CRYPTO_AES_CBC) &&
++ (crd2->crd_alg == CRYPTO_MD5_HMAC ||
++ crd2->crd_alg == CRYPTO_SHA1_HMAC ||
++ crd2->crd_alg == CRYPTO_MD5 ||
++ crd2->crd_alg == CRYPTO_SHA1) &&
++ (crd1->crd_flags & CRD_F_ENCRYPT)) {
++ enccrd = crd1;
++ maccrd = crd2;
++ } else {
++ /* We cannot order the SEC as requested */
++ printk("%s: cannot do the order\n",
++ device_get_nameunit(sc->sc_cdev));
++ err = EINVAL;
++ goto errout;
++ }
++ }
++ /* assign in_fifo and out_fifo based on input/output struct type */
++ if (crp->crp_flags & CRYPTO_F_SKBUF) {
++ /* using SKB buffers */
++ struct sk_buff *skb = (struct sk_buff *)crp->crp_buf;
++ if (skb_shinfo(skb)->nr_frags) {
++ printk("%s: skb frags unimplemented\n",
++ device_get_nameunit(sc->sc_cdev));
++ err = EINVAL;
++ goto errout;
++ }
++ td->ptr[in_fifo].ptr = dma_map_single(NULL, skb->data,
++ skb->len, DMA_TO_DEVICE);
++ td->ptr[in_fifo].len = skb->len;
++ td->ptr[out_fifo].ptr = dma_map_single(NULL, skb->data,
++ skb->len, DMA_TO_DEVICE);
++ td->ptr[out_fifo].len = skb->len;
++ td->ptr[hmac_data].ptr = dma_map_single(NULL, skb->data,
++ skb->len, DMA_TO_DEVICE);
++ } else if (crp->crp_flags & CRYPTO_F_IOV) {
++ /* using IOV buffers */
++ struct uio *uiop = (struct uio *)crp->crp_buf;
++ if (uiop->uio_iovcnt > 1) {
++ printk("%s: iov frags unimplemented\n",
++ device_get_nameunit(sc->sc_cdev));
++ err = EINVAL;
++ goto errout;
++ }
++ td->ptr[in_fifo].ptr = dma_map_single(NULL,
++ uiop->uio_iov->iov_base, crp->crp_ilen, DMA_TO_DEVICE);
++ td->ptr[in_fifo].len = crp->crp_ilen;
++ /* crp_olen is never set; always use crp_ilen */
++ td->ptr[out_fifo].ptr = dma_map_single(NULL,
++ uiop->uio_iov->iov_base,
++ crp->crp_ilen, DMA_TO_DEVICE);
++ td->ptr[out_fifo].len = crp->crp_ilen;
++ } else {
++ /* using contig buffers */
++ td->ptr[in_fifo].ptr = dma_map_single(NULL,
++ crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE);
++ td->ptr[in_fifo].len = crp->crp_ilen;
++ td->ptr[out_fifo].ptr = dma_map_single(NULL,
++ crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE);
++ td->ptr[out_fifo].len = crp->crp_ilen;
++ }
++ if (enccrd) {
++ switch (enccrd->crd_alg) {
++ case CRYPTO_3DES_CBC:
++ td->hdr |= TALITOS_MODE0_DEU_3DES;
++ /* FALLTHROUGH */
++ case CRYPTO_DES_CBC:
++ td->hdr |= TALITOS_SEL0_DEU
++ | TALITOS_MODE0_DEU_CBC;
++ if (enccrd->crd_flags & CRD_F_ENCRYPT)
++ td->hdr |= TALITOS_MODE0_DEU_ENC;
++ ivsize = 2*sizeof(u_int32_t);
++ DPRINTF("%cDES ses %d ch %d len %d\n",
++ (td->hdr & TALITOS_MODE0_DEU_3DES)?'3':'1',
++ (u32)TALITOS_SESSION(crp->crp_sid),
++ chsel, td->ptr[in_fifo].len);
++ break;
++ case CRYPTO_AES_CBC:
++ td->hdr |= TALITOS_SEL0_AESU
++ | TALITOS_MODE0_AESU_CBC;
++ if (enccrd->crd_flags & CRD_F_ENCRYPT)
++ td->hdr |= TALITOS_MODE0_AESU_ENC;
++ ivsize = 4*sizeof(u_int32_t);
++ DPRINTF("AES ses %d ch %d len %d\n",
++ (u32)TALITOS_SESSION(crp->crp_sid),
++ chsel, td->ptr[in_fifo].len);
++ break;
++ default:
++ printk("%s: unimplemented enccrd->crd_alg %d\n",
++ device_get_nameunit(sc->sc_cdev), enccrd->crd_alg);
++ err = EINVAL;
++ goto errout;
++ }
++ /*
++ * Setup encrypt/decrypt state. When using basic ops
++ * we can't use an inline IV because hash/crypt offset
++ * must be from the end of the IV to the start of the
++ * crypt data and this leaves out the preceding header
++ * from the hash calculation. Instead we place the IV
++ * in the state record and set the hash/crypt offset to
++ * copy both the header+IV.
++ */
++ if (enccrd->crd_flags & CRD_F_ENCRYPT) {
++ td->hdr |= TALITOS_DIR_OUTBOUND;
++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
++ iv = enccrd->crd_iv;
++ else
++ iv = (caddr_t) ses->ses_iv;
++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++ crypto_copyback(crp->crp_flags, crp->crp_buf,
++ enccrd->crd_inject, ivsize, iv);
++ }
++ } else {
++ td->hdr |= TALITOS_DIR_INBOUND;
++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) {
++ iv = enccrd->crd_iv;
++ bcopy(enccrd->crd_iv, iv, ivsize);
++ } else {
++ iv = (caddr_t) ses->ses_iv;
++ crypto_copydata(crp->crp_flags, crp->crp_buf,
++ enccrd->crd_inject, ivsize, iv);
++ }
++ }
++ td->ptr[cipher_iv].ptr = dma_map_single(NULL, iv, ivsize,
++ DMA_TO_DEVICE);
++ td->ptr[cipher_iv].len = ivsize;
++ /*
++ * we don't need the cipher iv out length/pointer
++ * field to do ESP IPsec. Therefore we set the len field as 0,
++ * which tells the SEC not to do anything with this len/ptr
++ * field. Previously, when length/pointer as pointing to iv,
++ * it gave us corruption of packets.
++ */
++ td->ptr[cipher_iv_out].len = 0;
++ }
++ if (enccrd && maccrd) {
++ /* this is ipsec only for now */
++ td->hdr |= TALITOS_SEL1_MDEU
++ | TALITOS_MODE1_MDEU_INIT
++ | TALITOS_MODE1_MDEU_PAD;
++ switch (maccrd->crd_alg) {
++ case CRYPTO_MD5:
++ td->hdr |= TALITOS_MODE1_MDEU_MD5;
++ break;
++ case CRYPTO_MD5_HMAC:
++ td->hdr |= TALITOS_MODE1_MDEU_MD5_HMAC;
++ break;
++ case CRYPTO_SHA1:
++ td->hdr |= TALITOS_MODE1_MDEU_SHA1;
++ break;
++ case CRYPTO_SHA1_HMAC:
++ td->hdr |= TALITOS_MODE1_MDEU_SHA1_HMAC;
++ break;
++ default:
++ /* We cannot order the SEC as requested */
++ printk("%s: cannot do the order\n",
++ device_get_nameunit(sc->sc_cdev));
++ err = EINVAL;
++ goto errout;
++ }
++ if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) ||
++ (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) {
++ /*
++ * The offset from hash data to the start of
++ * crypt data is the difference in the skips.
++ */
++ /* ipsec only for now */
++ td->ptr[hmac_key].ptr = dma_map_single(NULL,
++ ses->ses_hmac, ses->ses_hmac_len, DMA_TO_DEVICE);
++ td->ptr[hmac_key].len = ses->ses_hmac_len;
++ td->ptr[in_fifo].ptr += enccrd->crd_skip;
++ td->ptr[in_fifo].len = enccrd->crd_len;
++ td->ptr[out_fifo].ptr += enccrd->crd_skip;
++ td->ptr[out_fifo].len = enccrd->crd_len;
++ /* bytes of HMAC to postpend to ciphertext */
++ td->ptr[out_fifo].extent = ses->ses_mlen;
++ td->ptr[hmac_data].ptr += maccrd->crd_skip;
++ td->ptr[hmac_data].len = enccrd->crd_skip - maccrd->crd_skip;
++ }
++ if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
++ printk("%s: CRD_F_KEY_EXPLICIT unimplemented\n",
++ device_get_nameunit(sc->sc_cdev));
++ }
++ }
++ if (!enccrd && maccrd) {
++ /* single MD5 or SHA */
++ td->hdr |= TALITOS_SEL0_MDEU
++ | TALITOS_MODE0_MDEU_INIT
++ | TALITOS_MODE0_MDEU_PAD;
++ switch (maccrd->crd_alg) {
++ case CRYPTO_MD5:
++ td->hdr |= TALITOS_MODE0_MDEU_MD5;
++ DPRINTF("MD5 ses %d ch %d len %d\n",
++ (u32)TALITOS_SESSION(crp->crp_sid),
++ chsel, td->ptr[in_fifo].len);
++ break;
++ case CRYPTO_MD5_HMAC:
++ td->hdr |= TALITOS_MODE0_MDEU_MD5_HMAC;
++ break;
++ case CRYPTO_SHA1:
++ td->hdr |= TALITOS_MODE0_MDEU_SHA1;
++ DPRINTF("SHA1 ses %d ch %d len %d\n",
++ (u32)TALITOS_SESSION(crp->crp_sid),
++ chsel, td->ptr[in_fifo].len);
++ break;
++ case CRYPTO_SHA1_HMAC:
++ td->hdr |= TALITOS_MODE0_MDEU_SHA1_HMAC;
++ break;
++ default:
++ /* We cannot order the SEC as requested */
++ DPRINTF("cannot do the order\n");
++ err = EINVAL;
++ goto errout;
++ }
++
++ if (crp->crp_flags & CRYPTO_F_IOV)
++ td->ptr[out_fifo].ptr += maccrd->crd_inject;
++
++ if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) ||
++ (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) {
++ td->ptr[hmac_key].ptr = dma_map_single(NULL,
++ ses->ses_hmac, ses->ses_hmac_len,
++ DMA_TO_DEVICE);
++ td->ptr[hmac_key].len = ses->ses_hmac_len;
++ }
++ }
++ else {
++ /* using process key (session data has duplicate) */
++ td->ptr[cipher_key].ptr = dma_map_single(NULL,
++ enccrd->crd_key, (enccrd->crd_klen + 7) / 8,
++ DMA_TO_DEVICE);
++ td->ptr[cipher_key].len = (enccrd->crd_klen + 7) / 8;
++ }
++ /* descriptor complete - GO! */
++ return talitos_submit(sc, td, chsel);
++
++errout:
++ if (err != ERESTART) {
++ crp->crp_etype = err;
++ crypto_done(crp);
++ }
++ return err;
++}
++
++/* go through all channels descriptors, notifying OCF what has
++ * _and_hasn't_ successfully completed and reset the device
++ * (otherwise it's up to decoding desc hdrs!)
++ */
++static void talitos_errorprocessing(struct talitos_softc *sc)
++{
++ unsigned long flags;
++ int i, j;
++
++ /* disable further scheduling until under control */
++ spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
++
++ if (debug) dump_talitos_status(sc);
++ /* go through descriptors, try and salvage those successfully done,
++ * and EIO those that weren't
++ */
++ for (i = 0; i < sc->sc_num_channels; i++) {
++ spin_lock_irqsave(&sc->sc_chnfifolock[i], flags);
++ for (j = 0; j < sc->sc_chfifo_len; j++) {
++ if (sc->sc_chnfifo[i][j].cf_desc.hdr) {
++ if ((sc->sc_chnfifo[i][j].cf_desc.hdr
++ & TALITOS_HDR_DONE_BITS)
++ != TALITOS_HDR_DONE_BITS) {
++ /* this one didn't finish */
++ /* signify in crp->etype */
++ sc->sc_chnfifo[i][j].cf_crp->crp_etype
++ = EIO;
++ }
++ } else
++ continue; /* free entry */
++ /* either way, notify ocf */
++ crypto_done(sc->sc_chnfifo[i][j].cf_crp);
++ /* and tag it available again
++ *
++ * memset to ensure correct descriptor formation by
++ * avoiding inadvertently setting "optional" entries
++ * e.g. not using "optional" dptr2 MD/HMAC processing
++ */
++ memset(&sc->sc_chnfifo[i][j].cf_desc,
++ 0, sizeof(struct talitos_desc));
++ }
++ spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags);
++ }
++ /* reset and initialize the SEC h/w device */
++ talitos_reset_device(sc);
++ talitos_init_device(sc);
++#ifdef CONFIG_OCF_RANDOMHARVEST
++ if (sc->sc_exec_units & TALITOS_HAS_EU_RNG)
++ talitos_rng_init(sc);
++#endif
++
++ /* Okay. Stand by. */
++ spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
++
++ return;
++}
++
++/* go through all channels descriptors, notifying OCF what's been done */
++static void talitos_doneprocessing(struct talitos_softc *sc)
++{
++ unsigned long flags;
++ int i, j;
++
++ /* go through descriptors looking for done bits */
++ for (i = 0; i < sc->sc_num_channels; i++) {
++ spin_lock_irqsave(&sc->sc_chnfifolock[i], flags);
++ for (j = 0; j < sc->sc_chfifo_len; j++) {
++ /* descriptor has done bits set? */
++ if ((sc->sc_chnfifo[i][j].cf_desc.hdr
++ & TALITOS_HDR_DONE_BITS)
++ == TALITOS_HDR_DONE_BITS) {
++ /* notify ocf */
++ crypto_done(sc->sc_chnfifo[i][j].cf_crp);
++ /* and tag it available again
++ *
++ * memset to ensure correct descriptor formation by
++ * avoiding inadvertently setting "optional" entries
++ * e.g. not using "optional" dptr2 MD/HMAC processing
++ */
++ memset(&sc->sc_chnfifo[i][j].cf_desc,
++ 0, sizeof(struct talitos_desc));
++ }
++ }
++ spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags);
++ }
++ return;
++}
++
++static irqreturn_t
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++talitos_intr(int irq, void *arg)
++#else
++talitos_intr(int irq, void *arg, struct pt_regs *regs)
++#endif
++{
++ struct talitos_softc *sc = arg;
++ u_int32_t v, v_hi;
++
++ /* ack */
++ v = talitos_read(sc->sc_base_addr + TALITOS_ISR);
++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI);
++ talitos_write(sc->sc_base_addr + TALITOS_ICR, v);
++ talitos_write(sc->sc_base_addr + TALITOS_ICR_HI, v_hi);
++
++ if (unlikely(v & TALITOS_ISR_ERROR)) {
++ /* Okay, Houston, we've had a problem here. */
++ printk(KERN_DEBUG "%s: got error interrupt - ISR 0x%08x_%08x\n",
++ device_get_nameunit(sc->sc_cdev), v, v_hi);
++ talitos_errorprocessing(sc);
++ } else
++ if (likely(v & TALITOS_ISR_DONE)) {
++ talitos_doneprocessing(sc);
++ }
++ return IRQ_HANDLED;
++}
++
++/*
++ * Initialize registers we need to touch only once.
++ */
++static void
++talitos_init_device(struct talitos_softc *sc)
++{
++ u_int32_t v;
++ int i;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ /* init all channels */
++ for (i = 0; i < sc->sc_num_channels; i++) {
++ v = talitos_read(sc->sc_base_addr +
++ i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI);
++ v |= TALITOS_CH_CCCR_HI_CDWE
++ | TALITOS_CH_CCCR_HI_CDIE; /* invoke interrupt if done */
++ talitos_write(sc->sc_base_addr +
++ i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI, v);
++ }
++ /* enable all interrupts */
++ v = talitos_read(sc->sc_base_addr + TALITOS_IMR);
++ v |= TALITOS_IMR_ALL;
++ talitos_write(sc->sc_base_addr + TALITOS_IMR, v);
++ v = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI);
++ v |= TALITOS_IMR_HI_ERRONLY;
++ talitos_write(sc->sc_base_addr + TALITOS_IMR_HI, v);
++ return;
++}
++
++/*
++ * set the master reset bit on the device.
++ */
++static void
++talitos_reset_device_master(struct talitos_softc *sc)
++{
++ u_int32_t v;
++
++ /* Reset the device by writing 1 to MCR:SWR and waiting 'til cleared */
++ v = talitos_read(sc->sc_base_addr + TALITOS_MCR);
++ talitos_write(sc->sc_base_addr + TALITOS_MCR, v | TALITOS_MCR_SWR);
++
++ while (talitos_read(sc->sc_base_addr + TALITOS_MCR) & TALITOS_MCR_SWR)
++ cpu_relax();
++
++ return;
++}
++
++/*
++ * Resets the device. Values in the registers are left as is
++ * from the reset (i.e. initial values are assigned elsewhere).
++ */
++static void
++talitos_reset_device(struct talitos_softc *sc)
++{
++ u_int32_t v;
++ int i;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ /*
++ * Master reset
++ * errata documentation: warning: certain SEC interrupts
++ * are not fully cleared by writing the MCR:SWR bit,
++ * set bit twice to completely reset
++ */
++ talitos_reset_device_master(sc); /* once */
++ talitos_reset_device_master(sc); /* and once again */
++
++ /* reset all channels */
++ for (i = 0; i < sc->sc_num_channels; i++) {
++ v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
++ TALITOS_CH_CCCR);
++ talitos_write(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
++ TALITOS_CH_CCCR, v | TALITOS_CH_CCCR_RESET);
++ }
++}
++
++/* Set up the crypto device structure, private data,
++ * and anything else we need before we start */
++#ifdef CONFIG_PPC_MERGE
++static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match)
++#else
++static int talitos_probe(struct platform_device *pdev)
++#endif
++{
++ struct talitos_softc *sc = NULL;
++ struct resource *r;
++#ifdef CONFIG_PPC_MERGE
++ struct device *device = &ofdev->dev;
++ struct device_node *np = ofdev->node;
++ const unsigned int *prop;
++ int err;
++ struct resource res;
++#endif
++ static int num_chips = 0;
++ int rc;
++ int i;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++
++ sc = (struct talitos_softc *) kmalloc(sizeof(*sc), GFP_KERNEL);
++ if (!sc)
++ return -ENOMEM;
++ memset(sc, 0, sizeof(*sc));
++
++ softc_device_init(sc, DRV_NAME, num_chips, talitos_methods);
++
++ sc->sc_irq = -1;
++ sc->sc_cid = -1;
++#ifndef CONFIG_PPC_MERGE
++ sc->sc_dev = pdev;
++#endif
++ sc->sc_num = num_chips++;
++
++#ifdef CONFIG_PPC_MERGE
++ dev_set_drvdata(device, sc);
++#else
++ platform_set_drvdata(sc->sc_dev, sc);
++#endif
++
++ /* get the irq line */
++#ifdef CONFIG_PPC_MERGE
++ err = of_address_to_resource(np, 0, &res);
++ if (err)
++ return -EINVAL;
++ r = &res;
++
++ sc->sc_irq = irq_of_parse_and_map(np, 0);
++#else
++ /* get a pointer to the register memory */
++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++ sc->sc_irq = platform_get_irq(pdev, 0);
++#endif
++ rc = request_irq(sc->sc_irq, talitos_intr, 0,
++ device_get_nameunit(sc->sc_cdev), sc);
++ if (rc) {
++ printk(KERN_ERR "%s: failed to hook irq %d\n",
++ device_get_nameunit(sc->sc_cdev), sc->sc_irq);
++ sc->sc_irq = -1;
++ goto out;
++ }
++
++ sc->sc_base_addr = (ocf_iomem_t) ioremap(r->start, (r->end - r->start));
++ if (!sc->sc_base_addr) {
++ printk(KERN_ERR "%s: failed to ioremap\n",
++ device_get_nameunit(sc->sc_cdev));
++ goto out;
++ }
++
++ /* figure out our SEC's properties and capabilities */
++ sc->sc_chiprev = (u64)talitos_read(sc->sc_base_addr + TALITOS_ID) << 32
++ | talitos_read(sc->sc_base_addr + TALITOS_ID_HI);
++ DPRINTF("sec id 0x%llx\n", sc->sc_chiprev);
++
++#ifdef CONFIG_PPC_MERGE
++ /* get SEC properties from device tree, defaulting to SEC 2.0 */
++
++ prop = of_get_property(np, "num-channels", NULL);
++ sc->sc_num_channels = prop ? *prop : TALITOS_NCHANNELS_SEC_2_0;
++
++ prop = of_get_property(np, "channel-fifo-len", NULL);
++ sc->sc_chfifo_len = prop ? *prop : TALITOS_CHFIFOLEN_SEC_2_0;
++
++ prop = of_get_property(np, "exec-units-mask", NULL);
++ sc->sc_exec_units = prop ? *prop : TALITOS_HAS_EUS_SEC_2_0;
++
++ prop = of_get_property(np, "descriptor-types-mask", NULL);
++ sc->sc_desc_types = prop ? *prop : TALITOS_HAS_DESCTYPES_SEC_2_0;
++#else
++ /* bulk should go away with openfirmware flat device tree support */
++ if (sc->sc_chiprev & TALITOS_ID_SEC_2_0) {
++ sc->sc_num_channels = TALITOS_NCHANNELS_SEC_2_0;
++ sc->sc_chfifo_len = TALITOS_CHFIFOLEN_SEC_2_0;
++ sc->sc_exec_units = TALITOS_HAS_EUS_SEC_2_0;
++ sc->sc_desc_types = TALITOS_HAS_DESCTYPES_SEC_2_0;
++ } else {
++ printk(KERN_ERR "%s: failed to id device\n",
++ device_get_nameunit(sc->sc_cdev));
++ goto out;
++ }
++#endif
++
++ /* + 1 is for the meta-channel lock used by the channel scheduler */
++ sc->sc_chnfifolock = (spinlock_t *) kmalloc(
++ (sc->sc_num_channels + 1) * sizeof(spinlock_t), GFP_KERNEL);
++ if (!sc->sc_chnfifolock)
++ goto out;
++ for (i = 0; i < sc->sc_num_channels + 1; i++) {
++ spin_lock_init(&sc->sc_chnfifolock[i]);
++ }
++
++ sc->sc_chnlastalg = (int *) kmalloc(
++ sc->sc_num_channels * sizeof(int), GFP_KERNEL);
++ if (!sc->sc_chnlastalg)
++ goto out;
++ memset(sc->sc_chnlastalg, 0, sc->sc_num_channels * sizeof(int));
++
++ sc->sc_chnfifo = (struct desc_cryptop_pair **) kmalloc(
++ sc->sc_num_channels * sizeof(struct desc_cryptop_pair *),
++ GFP_KERNEL);
++ if (!sc->sc_chnfifo)
++ goto out;
++ for (i = 0; i < sc->sc_num_channels; i++) {
++ sc->sc_chnfifo[i] = (struct desc_cryptop_pair *) kmalloc(
++ sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair),
++ GFP_KERNEL);
++ if (!sc->sc_chnfifo[i])
++ goto out;
++ memset(sc->sc_chnfifo[i], 0,
++ sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair));
++ }
++
++ /* reset and initialize the SEC h/w device */
++ talitos_reset_device(sc);
++ talitos_init_device(sc);
++
++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE);
++ if (sc->sc_cid < 0) {
++ printk(KERN_ERR "%s: could not get crypto driver id\n",
++ device_get_nameunit(sc->sc_cdev));
++ goto out;
++ }
++
++ /* register algorithms with the framework */
++ printk("%s:", device_get_nameunit(sc->sc_cdev));
++
++ if (sc->sc_exec_units & TALITOS_HAS_EU_RNG) {
++ printk(" rng");
++#ifdef CONFIG_OCF_RANDOMHARVEST
++ talitos_rng_init(sc);
++ crypto_rregister(sc->sc_cid, talitos_read_random, sc);
++#endif
++ }
++ if (sc->sc_exec_units & TALITOS_HAS_EU_DEU) {
++ printk(" des/3des");
++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
++ }
++ if (sc->sc_exec_units & TALITOS_HAS_EU_AESU) {
++ printk(" aes");
++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
++ }
++ if (sc->sc_exec_units & TALITOS_HAS_EU_MDEU) {
++ printk(" md5");
++ crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0);
++ /* HMAC support only with IPsec for now */
++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
++ printk(" sha1");
++ crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0);
++ /* HMAC support only with IPsec for now */
++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
++ }
++ printk("\n");
++ return 0;
++
++out:
++#ifndef CONFIG_PPC_MERGE
++ talitos_remove(pdev);
++#endif
++ return -ENOMEM;
++}
++
++#ifdef CONFIG_PPC_MERGE
++static int talitos_remove(struct of_device *ofdev)
++#else
++static int talitos_remove(struct platform_device *pdev)
++#endif
++{
++#ifdef CONFIG_PPC_MERGE
++ struct talitos_softc *sc = dev_get_drvdata(&ofdev->dev);
++#else
++ struct talitos_softc *sc = platform_get_drvdata(pdev);
++#endif
++ int i;
++
++ DPRINTF("%s()\n", __FUNCTION__);
++ if (sc->sc_cid >= 0)
++ crypto_unregister_all(sc->sc_cid);
++ if (sc->sc_chnfifo) {
++ for (i = 0; i < sc->sc_num_channels; i++)
++ if (sc->sc_chnfifo[i])
++ kfree(sc->sc_chnfifo[i]);
++ kfree(sc->sc_chnfifo);
++ }
++ if (sc->sc_chnlastalg)
++ kfree(sc->sc_chnlastalg);
++ if (sc->sc_chnfifolock)
++ kfree(sc->sc_chnfifolock);
++ if (sc->sc_irq != -1)
++ free_irq(sc->sc_irq, sc);
++ if (sc->sc_base_addr)
++ iounmap((void *) sc->sc_base_addr);
++ kfree(sc);
++ return 0;
++}
++
++#ifdef CONFIG_PPC_MERGE
++static struct of_device_id talitos_match[] = {
++ {
++ .type = "crypto",
++ .compatible = "talitos",
++ },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, talitos_match);
++
++static struct of_platform_driver talitos_driver = {
++ .name = DRV_NAME,
++ .match_table = talitos_match,
++ .probe = talitos_probe,
++ .remove = talitos_remove,
++};
++
++static int __init talitos_init(void)
++{
++ return of_register_platform_driver(&talitos_driver);
++}
++
++static void __exit talitos_exit(void)
++{
++ of_unregister_platform_driver(&talitos_driver);
++}
++#else
++/* Structure for a platform device driver */
++static struct platform_driver talitos_driver = {
++ .probe = talitos_probe,
++ .remove = talitos_remove,
++ .driver = {
++ .name = "fsl-sec2",
++ }
++};
++
++static int __init talitos_init(void)
++{
++ return platform_driver_register(&talitos_driver);
++}
++
++static void __exit talitos_exit(void)
++{
++ platform_driver_unregister(&talitos_driver);
++}
++#endif
++
++module_init(talitos_init);
++module_exit(talitos_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("kim.phillips@freescale.com");
++MODULE_DESCRIPTION("OCF driver for Freescale SEC (talitos)");
+diff -Nur linux-2.6.36.orig/crypto/ocf/talitos/talitos_dev.h linux-2.6.36/crypto/ocf/talitos/talitos_dev.h
+--- linux-2.6.36.orig/crypto/ocf/talitos/talitos_dev.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/talitos/talitos_dev.h 2010-11-09 20:28:13.232495491 +0100
+@@ -0,0 +1,277 @@
++/*
++ * Freescale SEC (talitos) device dependent data structures
++ *
++ * Copyright (c) 2006 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ *
++ */
++
++/* device ID register values */
++#define TALITOS_ID_SEC_2_0 0x40
++#define TALITOS_ID_SEC_2_1 0x40 /* cross ref with IP block revision reg */
++
++/*
++ * following num_channels, channel-fifo-depth, exec-unit-mask, and
++ * descriptor-types-mask are for forward-compatibility with openfirmware
++ * flat device trees
++ */
++
++/*
++ * num_channels : the number of channels available in each SEC version.
++ */
++
++/* n.b. this driver requires these values be a power of 2 */
++#define TALITOS_NCHANNELS_SEC_1_0 4
++#define TALITOS_NCHANNELS_SEC_1_2 1
++#define TALITOS_NCHANNELS_SEC_2_0 4
++#define TALITOS_NCHANNELS_SEC_2_01 4
++#define TALITOS_NCHANNELS_SEC_2_1 4
++#define TALITOS_NCHANNELS_SEC_2_4 4
++
++/*
++ * channel-fifo-depth : The number of descriptor
++ * pointers a channel fetch fifo can hold.
++ */
++#define TALITOS_CHFIFOLEN_SEC_1_0 1
++#define TALITOS_CHFIFOLEN_SEC_1_2 1
++#define TALITOS_CHFIFOLEN_SEC_2_0 24
++#define TALITOS_CHFIFOLEN_SEC_2_01 24
++#define TALITOS_CHFIFOLEN_SEC_2_1 24
++#define TALITOS_CHFIFOLEN_SEC_2_4 24
++
++/*
++ * exec-unit-mask : The bitmask representing what Execution Units (EUs)
++ * are available. EU information should be encoded following the SEC's
++ * EU_SEL0 bitfield documentation, i.e. as follows:
++ *
++ * bit 31 = set if SEC permits no-EU selection (should be always set)
++ * bit 30 = set if SEC has the ARC4 EU (AFEU)
++ * bit 29 = set if SEC has the des/3des EU (DEU)
++ * bit 28 = set if SEC has the message digest EU (MDEU)
++ * bit 27 = set if SEC has the random number generator EU (RNG)
++ * bit 26 = set if SEC has the public key EU (PKEU)
++ * bit 25 = set if SEC has the aes EU (AESU)
++ * bit 24 = set if SEC has the Kasumi EU (KEU)
++ *
++ */
++#define TALITOS_HAS_EU_NONE (1<<0)
++#define TALITOS_HAS_EU_AFEU (1<<1)
++#define TALITOS_HAS_EU_DEU (1<<2)
++#define TALITOS_HAS_EU_MDEU (1<<3)
++#define TALITOS_HAS_EU_RNG (1<<4)
++#define TALITOS_HAS_EU_PKEU (1<<5)
++#define TALITOS_HAS_EU_AESU (1<<6)
++#define TALITOS_HAS_EU_KEU (1<<7)
++
++/* the corresponding masks for each SEC version */
++#define TALITOS_HAS_EUS_SEC_1_0 0x7f
++#define TALITOS_HAS_EUS_SEC_1_2 0x4d
++#define TALITOS_HAS_EUS_SEC_2_0 0x7f
++#define TALITOS_HAS_EUS_SEC_2_01 0x7f
++#define TALITOS_HAS_EUS_SEC_2_1 0xff
++#define TALITOS_HAS_EUS_SEC_2_4 0x7f
++
++/*
++ * descriptor-types-mask : The bitmask representing what descriptors
++ * are available. Descriptor type information should be encoded
++ * following the SEC's Descriptor Header Dword DESC_TYPE field
++ * documentation, i.e. as follows:
++ *
++ * bit 0 = set if SEC supports the aesu_ctr_nonsnoop desc. type
++ * bit 1 = set if SEC supports the ipsec_esp descriptor type
++ * bit 2 = set if SEC supports the common_nonsnoop desc. type
++ * bit 3 = set if SEC supports the 802.11i AES ccmp desc. type
++ * bit 4 = set if SEC supports the hmac_snoop_no_afeu desc. type
++ * bit 5 = set if SEC supports the srtp descriptor type
++ * bit 6 = set if SEC supports the non_hmac_snoop_no_afeu desc.type
++ * bit 7 = set if SEC supports the pkeu_assemble descriptor type
++ * bit 8 = set if SEC supports the aesu_key_expand_output desc.type
++ * bit 9 = set if SEC supports the pkeu_ptmul descriptor type
++ * bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type
++ * bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type
++ *
++ * ..and so on and so forth.
++ */
++#define TALITOS_HAS_DT_AESU_CTR_NONSNOOP (1<<0)
++#define TALITOS_HAS_DT_IPSEC_ESP (1<<1)
++#define TALITOS_HAS_DT_COMMON_NONSNOOP (1<<2)
++
++/* the corresponding masks for each SEC version */
++#define TALITOS_HAS_DESCTYPES_SEC_2_0 0x01010ebf
++#define TALITOS_HAS_DESCTYPES_SEC_2_1 0x012b0ebf
++
++/*
++ * a TALITOS_xxx_HI address points to the low data bits (32-63) of the register
++ */
++
++/* global register offset addresses */
++#define TALITOS_ID 0x1020
++#define TALITOS_ID_HI 0x1024
++#define TALITOS_MCR 0x1030 /* master control register */
++#define TALITOS_MCR_HI 0x1038 /* master control register */
++#define TALITOS_MCR_SWR 0x1
++#define TALITOS_IMR 0x1008 /* interrupt mask register */
++#define TALITOS_IMR_ALL 0x00010fff /* enable all interrupts mask */
++#define TALITOS_IMR_ERRONLY 0x00010aaa /* enable error interrupts */
++#define TALITOS_IMR_HI 0x100C /* interrupt mask register */
++#define TALITOS_IMR_HI_ALL 0x00323333 /* enable all interrupts mask */
++#define TALITOS_IMR_HI_ERRONLY 0x00222222 /* enable error interrupts */
++#define TALITOS_ISR 0x1010 /* interrupt status register */
++#define TALITOS_ISR_ERROR 0x00010faa /* errors mask */
++#define TALITOS_ISR_DONE 0x00000055 /* channel(s) done mask */
++#define TALITOS_ISR_HI 0x1014 /* interrupt status register */
++#define TALITOS_ICR 0x1018 /* interrupt clear register */
++#define TALITOS_ICR_HI 0x101C /* interrupt clear register */
++
++/* channel register address stride */
++#define TALITOS_CH_OFFSET 0x100
++
++/* channel register offset addresses and bits */
++#define TALITOS_CH_CCCR 0x1108 /* Crypto-Channel Config Register */
++#define TALITOS_CH_CCCR_RESET 0x1 /* Channel Reset bit */
++#define TALITOS_CH_CCCR_HI 0x110c /* Crypto-Channel Config Register */
++#define TALITOS_CH_CCCR_HI_CDWE 0x10 /* Channel done writeback enable bit */
++#define TALITOS_CH_CCCR_HI_NT 0x4 /* Notification type bit */
++#define TALITOS_CH_CCCR_HI_CDIE 0x2 /* Channel Done Interrupt Enable bit */
++#define TALITOS_CH_CCPSR 0x1110 /* Crypto-Channel Pointer Status Reg */
++#define TALITOS_CH_CCPSR_HI 0x1114 /* Crypto-Channel Pointer Status Reg */
++#define TALITOS_CH_FF 0x1148 /* Fetch FIFO */
++#define TALITOS_CH_FF_HI 0x114c /* Fetch FIFO's FETCH_ADRS */
++#define TALITOS_CH_CDPR 0x1140 /* Crypto-Channel Pointer Status Reg */
++#define TALITOS_CH_CDPR_HI 0x1144 /* Crypto-Channel Pointer Status Reg */
++#define TALITOS_CH_DESCBUF 0x1180 /* (thru 11bf) Crypto-Channel
++ * Descriptor Buffer (debug) */
++
++/* execution unit register offset addresses and bits */
++#define TALITOS_DEUSR 0x2028 /* DEU status register */
++#define TALITOS_DEUSR_HI 0x202c /* DEU status register */
++#define TALITOS_DEUISR 0x2030 /* DEU interrupt status register */
++#define TALITOS_DEUISR_HI 0x2034 /* DEU interrupt status register */
++#define TALITOS_DEUICR 0x2038 /* DEU interrupt control register */
++#define TALITOS_DEUICR_HI 0x203c /* DEU interrupt control register */
++#define TALITOS_AESUISR 0x4030 /* AESU interrupt status register */
++#define TALITOS_AESUISR_HI 0x4034 /* AESU interrupt status register */
++#define TALITOS_AESUICR 0x4038 /* AESU interrupt control register */
++#define TALITOS_AESUICR_HI 0x403c /* AESU interrupt control register */
++#define TALITOS_MDEUISR 0x6030 /* MDEU interrupt status register */
++#define TALITOS_MDEUISR_HI 0x6034 /* MDEU interrupt status register */
++#define TALITOS_RNGSR 0xa028 /* RNG status register */
++#define TALITOS_RNGSR_HI 0xa02c /* RNG status register */
++#define TALITOS_RNGSR_HI_RD 0x1 /* RNG Reset done */
++#define TALITOS_RNGSR_HI_OFL 0xff0000/* number of dwords in RNG output FIFO*/
++#define TALITOS_RNGDSR 0xa010 /* RNG data size register */
++#define TALITOS_RNGDSR_HI 0xa014 /* RNG data size register */
++#define TALITOS_RNG_FIFO 0xa800 /* RNG FIFO - pool of random numbers */
++#define TALITOS_RNGISR 0xa030 /* RNG Interrupt status register */
++#define TALITOS_RNGISR_HI 0xa034 /* RNG Interrupt status register */
++#define TALITOS_RNGRCR 0xa018 /* RNG Reset control register */
++#define TALITOS_RNGRCR_HI 0xa01c /* RNG Reset control register */
++#define TALITOS_RNGRCR_HI_SR 0x1 /* RNG RNGRCR:Software Reset */
++
++/* descriptor pointer entry */
++struct talitos_desc_ptr {
++ u16 len; /* length */
++ u8 extent; /* jump (to s/g link table) and extent */
++ u8 res; /* reserved */
++ u32 ptr; /* pointer */
++};
++
++/* descriptor */
++struct talitos_desc {
++ u32 hdr; /* header */
++ u32 res; /* reserved */
++ struct talitos_desc_ptr ptr[7]; /* ptr/len pair array */
++};
++
++/* talitos descriptor header (hdr) bits */
++
++/* primary execution unit select */
++#define TALITOS_SEL0_AFEU 0x10000000
++#define TALITOS_SEL0_DEU 0x20000000
++#define TALITOS_SEL0_MDEU 0x30000000
++#define TALITOS_SEL0_RNG 0x40000000
++#define TALITOS_SEL0_PKEU 0x50000000
++#define TALITOS_SEL0_AESU 0x60000000
++
++/* primary execution unit mode (MODE0) and derivatives */
++#define TALITOS_MODE0_AESU_CBC 0x00200000
++#define TALITOS_MODE0_AESU_ENC 0x00100000
++#define TALITOS_MODE0_DEU_CBC 0x00400000
++#define TALITOS_MODE0_DEU_3DES 0x00200000
++#define TALITOS_MODE0_DEU_ENC 0x00100000
++#define TALITOS_MODE0_MDEU_INIT 0x01000000 /* init starting regs */
++#define TALITOS_MODE0_MDEU_HMAC 0x00800000
++#define TALITOS_MODE0_MDEU_PAD 0x00400000 /* PD */
++#define TALITOS_MODE0_MDEU_MD5 0x00200000
++#define TALITOS_MODE0_MDEU_SHA256 0x00100000
++#define TALITOS_MODE0_MDEU_SHA1 0x00000000 /* SHA-160 */
++#define TALITOS_MODE0_MDEU_MD5_HMAC \
++ (TALITOS_MODE0_MDEU_MD5 | TALITOS_MODE0_MDEU_HMAC)
++#define TALITOS_MODE0_MDEU_SHA256_HMAC \
++ (TALITOS_MODE0_MDEU_SHA256 | TALITOS_MODE0_MDEU_HMAC)
++#define TALITOS_MODE0_MDEU_SHA1_HMAC \
++ (TALITOS_MODE0_MDEU_SHA1 | TALITOS_MODE0_MDEU_HMAC)
++
++/* secondary execution unit select (SEL1) */
++/* it's MDEU or nothing */
++#define TALITOS_SEL1_MDEU 0x00030000
++
++/* secondary execution unit mode (MODE1) and derivatives */
++#define TALITOS_MODE1_MDEU_INIT 0x00001000 /* init starting regs */
++#define TALITOS_MODE1_MDEU_HMAC 0x00000800
++#define TALITOS_MODE1_MDEU_PAD 0x00000400 /* PD */
++#define TALITOS_MODE1_MDEU_MD5 0x00000200
++#define TALITOS_MODE1_MDEU_SHA256 0x00000100
++#define TALITOS_MODE1_MDEU_SHA1 0x00000000 /* SHA-160 */
++#define TALITOS_MODE1_MDEU_MD5_HMAC \
++ (TALITOS_MODE1_MDEU_MD5 | TALITOS_MODE1_MDEU_HMAC)
++#define TALITOS_MODE1_MDEU_SHA256_HMAC \
++ (TALITOS_MODE1_MDEU_SHA256 | TALITOS_MODE1_MDEU_HMAC)
++#define TALITOS_MODE1_MDEU_SHA1_HMAC \
++ (TALITOS_MODE1_MDEU_SHA1 | TALITOS_MODE1_MDEU_HMAC)
++
++/* direction of overall data flow (DIR) */
++#define TALITOS_DIR_OUTBOUND 0x00000000
++#define TALITOS_DIR_INBOUND 0x00000002
++
++/* done notification (DN) */
++#define TALITOS_DONE_NOTIFY 0x00000001
++
++/* descriptor types */
++/* odd numbers here are valid on SEC2 and greater only (e.g. ipsec_esp) */
++#define TD_TYPE_AESU_CTR_NONSNOOP (0 << 3)
++#define TD_TYPE_IPSEC_ESP (1 << 3)
++#define TD_TYPE_COMMON_NONSNOOP_NO_AFEU (2 << 3)
++#define TD_TYPE_HMAC_SNOOP_NO_AFEU (4 << 3)
++
++#define TALITOS_HDR_DONE_BITS 0xff000000
++
++#define DPRINTF(a...) do { \
++ if (debug) { \
++ printk("%s: ", sc ? \
++ device_get_nameunit(sc->sc_cdev) : "talitos"); \
++ printk(a); \
++ } \
++ } while (0)
+diff -Nur linux-2.6.36.orig/crypto/ocf/talitos/talitos_soft.h linux-2.6.36/crypto/ocf/talitos/talitos_soft.h
+--- linux-2.6.36.orig/crypto/ocf/talitos/talitos_soft.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/talitos/talitos_soft.h 2010-11-09 20:28:13.272495451 +0100
+@@ -0,0 +1,77 @@
++/*
++ * Freescale SEC data structures for integration with ocf-linux
++ *
++ * Copyright (c) 2006 Freescale Semiconductor, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. 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.
++ * 3. The name of the author may not be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR 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.
++ */
++
++/*
++ * paired descriptor and associated crypto operation
++ */
++struct desc_cryptop_pair {
++ struct talitos_desc cf_desc; /* descriptor ptr */
++ struct cryptop *cf_crp; /* cryptop ptr */
++};
++
++/*
++ * Holds data specific to a single talitos device.
++ */
++struct talitos_softc {
++ softc_device_decl sc_cdev;
++ struct platform_device *sc_dev; /* device backpointer */
++ ocf_iomem_t sc_base_addr;
++ int sc_irq;
++ int sc_num; /* if we have multiple chips */
++ int32_t sc_cid; /* crypto tag */
++ u64 sc_chiprev; /* major/minor chip revision */
++ int sc_nsessions;
++ struct talitos_session *sc_sessions;
++ int sc_num_channels;/* number of crypto channels */
++ int sc_chfifo_len; /* channel fetch fifo len */
++ int sc_exec_units; /* execution units mask */
++ int sc_desc_types; /* descriptor types mask */
++ /*
++ * mutual exclusion for intra-channel resources, e.g. fetch fifos
++ * the last entry is a meta-channel lock used by the channel scheduler
++ */
++ spinlock_t *sc_chnfifolock;
++ /* sc_chnlastalgo contains last algorithm for that channel */
++ int *sc_chnlastalg;
++ /* sc_chnfifo holds pending descriptor--crypto operation pairs */
++ struct desc_cryptop_pair **sc_chnfifo;
++};
++
++struct talitos_session {
++ u_int32_t ses_used;
++ u_int32_t ses_klen; /* key length in bits */
++ u_int32_t ses_key[8]; /* DES/3DES/AES key */
++ u_int32_t ses_hmac[5]; /* hmac inner state */
++ u_int32_t ses_hmac_len; /* hmac length */
++ u_int32_t ses_iv[4]; /* DES/3DES/AES iv */
++ u_int32_t ses_mlen; /* desired hash result len (12=ipsec or 16) */
++};
++
++#define TALITOS_SESSION(sid) ((sid) & 0x0fffffff)
++#define TALITOS_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff))
+diff -Nur linux-2.6.36.orig/crypto/ocf/uio.h linux-2.6.36/crypto/ocf/uio.h
+--- linux-2.6.36.orig/crypto/ocf/uio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/crypto/ocf/uio.h 2010-11-09 20:28:13.313482727 +0100
+@@ -0,0 +1,54 @@
++#ifndef _OCF_UIO_H_
++#define _OCF_UIO_H_
++
++#include <linux/uio.h>
++
++/*
++ * The linux uio.h doesn't have all we need. To be fully api compatible
++ * with the BSD cryptodev, we need to keep this around. Perhaps this can
++ * be moved back into the linux/uio.h
++ *
++ * Linux port done by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ * 1. distributions of this source code include the above copyright
++ * notice, this list of conditions and the following disclaimer;
++ *
++ * 2. distributions in binary form include the above copyright
++ * notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other associated materials;
++ *
++ * 3. the copyright holder's name is not used to endorse products
++ * built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ * ---------------------------------------------------------------------------
++ */
++
++struct uio {
++ struct iovec *uio_iov;
++ int uio_iovcnt;
++ off_t uio_offset;
++ int uio_resid;
++#if 0
++ enum uio_seg uio_segflg;
++ enum uio_rw uio_rw;
++ struct thread *uio_td;
++#endif
++};
++
++#endif
+diff -Nur linux-2.6.36.orig/drivers/char/random.c linux-2.6.36/drivers/char/random.c
+--- linux-2.6.36.orig/drivers/char/random.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/char/random.c 2010-11-09 20:28:13.352495461 +0100
+@@ -129,6 +129,9 @@
+ * unsigned int value);
+ * void add_interrupt_randomness(int irq);
+ *
++ * void random_input_words(__u32 *buf, size_t wordcount, int ent_count)
++ * int random_input_wait(void);
++ *
+ * add_input_randomness() uses the input layer interrupt timing, as well as
+ * the event type information from the hardware.
+ *
+@@ -140,6 +143,13 @@
+ * a better measure, since the timing of the disk interrupts are more
+ * unpredictable.
+ *
++ * random_input_words() just provides a raw block of entropy to the input
++ * pool, such as from a hardware entropy generator.
++ *
++ * random_input_wait() suspends the caller until such time as the
++ * entropy pool falls below the write threshold, and returns a count of how
++ * much entropy (in bits) is needed to sustain the pool.
++ *
+ * All of these routines try to estimate how many bits of randomness a
+ * particular randomness source. They do this by keeping track of the
+ * first and second order deltas of the event timings.
+@@ -259,6 +269,7 @@
+ #define SEC_XFER_SIZE 512
+ #define EXTRACT_SIZE 10
+
++
+ /*
+ * The minimum number of bits of entropy before we wake up a read on
+ * /dev/random. Should be enough to do a significant reseed.
+@@ -552,6 +563,60 @@
+ spin_unlock_irqrestore(&r->lock, flags);
+ }
+
++/*
++ * random_input_words - add bulk entropy to pool
++ *
++ * @buf: buffer to add
++ * @wordcount: number of __u32 words to add
++ * @ent_count: total amount of entropy (in bits) to credit
++ *
++ * this provides bulk input of entropy to the input pool
++ *
++ */
++void random_input_words(__u32 *buf, size_t wordcount, int ent_count)
++{
++ mix_pool_bytes(&input_pool, buf, wordcount*4);
++
++ credit_entropy_bits(&input_pool, ent_count);
++
++ DEBUG_ENT("crediting %d bits => %d\n",
++ ent_count, input_pool.entropy_count);
++ /*
++ * Wake up waiting processes if we have enough
++ * entropy.
++ */
++ if (input_pool.entropy_count >= random_read_wakeup_thresh)
++ wake_up_interruptible(&random_read_wait);
++}
++EXPORT_SYMBOL(random_input_words);
++
++/*
++ * random_input_wait - wait until random needs entropy
++ *
++ * this function sleeps until the /dev/random subsystem actually
++ * needs more entropy, and then return the amount of entropy
++ * that it would be nice to have added to the system.
++ */
++int random_input_wait(void)
++{
++ int count;
++
++ wait_event_interruptible(random_write_wait,
++ input_pool.entropy_count < random_write_wakeup_thresh);
++
++ count = random_write_wakeup_thresh - input_pool.entropy_count;
++
++ /* likely we got woken up due to a signal */
++ if (count <= 0) count = random_read_wakeup_thresh;
++
++ DEBUG_ENT("requesting %d bits from input_wait()er %d<%d\n",
++ count,
++ input_pool.entropy_count, random_write_wakeup_thresh);
++
++ return count;
++}
++EXPORT_SYMBOL(random_input_wait);
++
+ /*********************************************************************
+ *
+ * Entropy input management
+diff -Nur linux-2.6.36.orig/fs/fcntl.c linux-2.6.36/fs/fcntl.c
+--- linux-2.6.36.orig/fs/fcntl.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/fs/fcntl.c 2010-11-09 20:28:13.392495458 +0100
+@@ -142,6 +142,7 @@
+ }
+ return ret;
+ }
++EXPORT_SYMBOL(sys_dup);
+
+ #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
+
+diff -Nur linux-2.6.36.orig/include/linux/miscdevice.h linux-2.6.36/include/linux/miscdevice.h
+--- linux-2.6.36.orig/include/linux/miscdevice.h 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/include/linux/miscdevice.h 2010-11-09 20:28:13.432495492 +0100
+@@ -18,6 +18,7 @@
+ #define APOLLO_MOUSE_MINOR 7
+ #define PC110PAD_MINOR 9
+ /*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */
++#define CRYPTODEV_MINOR 70 /* /dev/crypto */
+ #define WATCHDOG_MINOR 130 /* Watchdog timer */
+ #define TEMP_MINOR 131 /* Temperature Sensor */
+ #define RTC_MINOR 135
+diff -Nur linux-2.6.36.orig/include/linux/random.h linux-2.6.36/include/linux/random.h
+--- linux-2.6.36.orig/include/linux/random.h 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/include/linux/random.h 2010-11-09 20:28:13.597270121 +0100
+@@ -9,6 +9,7 @@
+
+ #include <linux/types.h>
+ #include <linux/ioctl.h>
++#include <linux/types.h> /* for __u32 in user space */
+ #include <linux/irqnr.h>
+
+ /* ioctl()'s for the random number generator */
+@@ -34,6 +35,30 @@
+ /* Clear the entropy pool and associated counters. (Superuser only.) */
+ #define RNDCLEARPOOL _IO( 'R', 0x06 )
+
++#ifdef CONFIG_FIPS_RNG
++
++/* Size of seed value - equal to AES blocksize */
++#define AES_BLOCK_SIZE_BYTES 16
++#define SEED_SIZE_BYTES AES_BLOCK_SIZE_BYTES
++/* Size of AES key */
++#define KEY_SIZE_BYTES 16
++
++/* ioctl() structure used by FIPS 140-2 Tests */
++struct rand_fips_test {
++ unsigned char key[KEY_SIZE_BYTES]; /* Input */
++ unsigned char datetime[SEED_SIZE_BYTES]; /* Input */
++ unsigned char seed[SEED_SIZE_BYTES]; /* Input */
++ unsigned char result[SEED_SIZE_BYTES]; /* Output */
++};
++
++/* FIPS 140-2 RNG Variable Seed Test. (Superuser only.) */
++#define RNDFIPSVST _IOWR('R', 0x10, struct rand_fips_test)
++
++/* FIPS 140-2 RNG Monte Carlo Test. (Superuser only.) */
++#define RNDFIPSMCT _IOWR('R', 0x11, struct rand_fips_test)
++
++#endif /* #ifdef CONFIG_FIPS_RNG */
++
+ struct rand_pool_info {
+ int entropy_count;
+ int buf_size;
+@@ -54,6 +79,10 @@
+ unsigned int value);
+ extern void add_interrupt_randomness(int irq);
+
++extern void random_input_words(__u32 *buf, size_t wordcount, int ent_count);
++extern int random_input_wait(void);
++#define HAS_RANDOM_INPUT_WAIT 1
++
+ extern void get_random_bytes(void *buf, int nbytes);
+ void generate_random_uuid(unsigned char uuid_out[16]);
+
diff --git a/target/linux/patches/2.6.37/rb532.patch b/target/linux/patches/2.6.37/rb532.patch
new file mode 100644
index 000000000..be68c65f0
--- /dev/null
+++ b/target/linux/patches/2.6.37/rb532.patch
@@ -0,0 +1,18 @@
+diff -Nur linux-2.6.36.orig/arch/mips/rb532/devices.c linux-2.6.36/arch/mips/rb532/devices.c
+--- linux-2.6.36.orig/arch/mips/rb532/devices.c 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/mips/rb532/devices.c 2010-12-21 20:26:05.000000000 +0100
+@@ -190,8 +190,12 @@
+ }, {
+ .name = "rootfs",
+ .offset = MTDPART_OFS_NXTBLK,
+- .size = MTDPART_SIZ_FULL,
+- }
++ .size = 0x8000000 - 0x400000 - 0x400000,
++ }, {
++ .name = "cfgfs",
++ .offset = 0x8000000 - 0x400000,
++ .size = 0x400000,
++ },
+ };
+
+ static struct platform_device rb532_led = {
diff --git a/target/linux/patches/2.6.37/startup.patch b/target/linux/patches/2.6.37/startup.patch
new file mode 100644
index 000000000..68e8987b0
--- /dev/null
+++ b/target/linux/patches/2.6.37/startup.patch
@@ -0,0 +1,20 @@
+diff -Nur linux-2.6.34.orig/init/main.c linux-2.6.34/init/main.c
+--- linux-2.6.34.orig/init/main.c 2010-05-16 23:17:36.000000000 +0200
++++ linux-2.6.34/init/main.c 2010-05-20 20:13:26.321613615 +0200
+@@ -842,6 +842,7 @@
+ printk(KERN_WARNING "Failed to execute %s. Attempting "
+ "defaults...\n", execute_command);
+ }
++ run_init_process("/init");
+ run_init_process("/sbin/init");
+ run_init_process("/etc/init");
+ run_init_process("/bin/init");
+@@ -889,6 +890,8 @@
+ if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
+ printk(KERN_WARNING "Warning: unable to open an initial console.\n");
+
++ printk(KERN_WARNING "Starting Linux (built with OpenADK).\n");
++
+ (void) sys_dup(0);
+ (void) sys_dup(0);
+ /*
diff --git a/target/linux/patches/2.6.37/uuid.patch b/target/linux/patches/2.6.37/uuid.patch
new file mode 100644
index 000000000..cf2869ed2
--- /dev/null
+++ b/target/linux/patches/2.6.37/uuid.patch
@@ -0,0 +1,261 @@
+# DP: Add support for specifying the root device using UUIDs on the
+# DP: kernel command line like this without the need for an initrd:
+# DP: linux ... root=UUID=ce40d6b2-18eb-4a75-aefe-7ddb0995ce63
+# DP: Note: debugging code is kept in, commented out “//†style.
+# DP:
+# DP: Written © 2010 by Thorsten Glaser <tg@debian.org>
+# DP: Idea from 1999 by David Balazic <david.balazic@uni-mb.si>
+
+--- linux-2.6.36/block/genhd.c~ Wed Oct 20 22:30:22 2010
++++ linux-2.6.36/block/genhd.c Sat Nov 20 23:14:03 2010
+@@ -35,7 +35,7 @@ struct kobject *block_depr;
+ static DEFINE_MUTEX(ext_devt_mutex);
+ static DEFINE_IDR(ext_devt_idr);
+
+-static struct device_type disk_type;
++struct device_type disk_type;
+
+ /**
+ * disk_get_part - get partition
+@@ -1019,7 +1019,7 @@ static char *block_devnode(struct device *dev, mode_t
+ return NULL;
+ }
+
+-static struct device_type disk_type = {
++struct device_type disk_type = {
+ .name = "disk",
+ .groups = disk_attr_groups,
+ .release = disk_release,
+--- linux-2.6.36/init/do_mounts.c~ Wed Oct 20 20:29:58 2010
++++ linux-2.6.36/init/do_mounts.c Sun Nov 21 18:37:36 2010
+@@ -32,6 +32,132 @@ static int __initdata root_wait;
+
+ dev_t ROOT_DEV;
+
++#ifdef CONFIG_EXT2_FS
++/* support for root=UUID=ce40d6b2-18eb-4a75-aefe-7ddb0995ce63 bootargs */
++
++#include <linux/ext2_fs.h>
++
++__u8 root_dev_uuid[16];
++int root_dev_type; /* 0 = normal (/dev/hda1, 0301); 1 = UUID; 3 = bad */
++
++/* imported from block/genhd.c after removing its static qualifier */
++extern struct device_type disk_type;
++
++/* helper function */
++static __u8 __init fromhex(char c)
++{
++ if (c >= '0' && c <= '9')
++ return (c - '0');
++ c &= ~32;
++ if (c >= 'A' && c <= 'F')
++ return (c - 'A' + 10);
++ return (0xFF);
++}
++
++static void __init parse_uuid(const char *s)
++{
++ int i;
++ __u8 j, k;
++
++ if (strlen(s) != 36 || s[8] != '-' || s[13] != '-' ||
++ s[18] != '-' || s[23] != '-')
++ goto bad_uuid;
++ for (i = 0; i < 16; i++) {
++ if (*s == '-')
++ ++s;
++ j = fromhex(*s++);
++ k = fromhex(*s++);
++ if (j == 0xFF || k == 0xFF)
++ goto bad_uuid;
++ root_dev_uuid[i] = (j << 4) | k;
++ }
++ return;
++ bad_uuid:
++ /* we cannot panic here, defer */
++ root_dev_type = 3;
++}
++
++/* from drivers/md/md.c */
++static void __init initcode_bi_complete(struct bio *bio, int error)
++{
++ complete((struct completion*)bio->bi_private);
++}
++
++static int __init initcode_sync_page_read(struct block_device *bdev,
++ sector_t sector, int size, struct page *page)
++{
++ struct bio *bio = bio_alloc(GFP_NOIO, 1);
++ struct completion event;
++ int ret, rw = READ;
++
++ rw |= REQ_SYNC | REQ_UNPLUG;
++
++ bio->bi_bdev = bdev;
++ bio->bi_sector = sector;
++ bio_add_page(bio, page, size, 0);
++ init_completion(&event);
++ bio->bi_private = &event;
++ bio->bi_end_io = initcode_bi_complete;
++ submit_bio(rw, bio);
++ wait_for_completion(&event);
++
++ ret = test_bit(BIO_UPTODATE, &bio->bi_flags);
++ bio_put(bio);
++ /* 0 = failure */
++ return ret;
++}
++
++/* most of this taken from fs/ext2/super.c */
++static int __init check_dev(struct gendisk *thedisk, dev_t devt,
++ int blocksize, struct page *page)
++{
++ struct ext2_super_block * es;
++ struct block_device *bdev;
++ unsigned long sb_block = 1;
++ unsigned long logic_sb_block;
++ unsigned long offset = 0;
++ int rv = /* not found */ 0;
++ char bff[22];
++
++ bdev = bdget(devt);
++ if (blkdev_get(bdev, FMODE_READ)) {
++ printk(KERN_ERR "VFS: opening block device %s failed!\n",
++ format_dev_t(bff, devt));
++ return (0);
++ }
++
++ if (blocksize != BLOCK_SIZE) {
++ logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
++ offset = (sb_block*BLOCK_SIZE) % blocksize;
++ } else {
++ logic_sb_block = sb_block;
++ }
++
++// printk(KERN_ERR "D: attempting to read %d @%lu from "
++// "bdev %p devt %08X %s\n", blocksize, logic_sb_block,
++// bdev, devt, format_dev_t(bff, devt));
++ if (!initcode_sync_page_read(bdev, logic_sb_block, blocksize, page)) {
++// printk(KERN_ERR "D: failed!\n");
++ goto out;
++ }
++ es = (struct ext2_super_block *)(((char *)page_address(page)) + offset);
++ if (le16_to_cpu(es->s_magic) == EXT2_SUPER_MAGIC) {
++// printk(KERN_ERR "D: has uuid "
++// "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
++// es->s_uuid[0], es->s_uuid[1], es->s_uuid[2], es->s_uuid[3],
++// es->s_uuid[4], es->s_uuid[5], es->s_uuid[6], es->s_uuid[7],
++// es->s_uuid[8], es->s_uuid[9], es->s_uuid[10], es->s_uuid[11],
++// es->s_uuid[12], es->s_uuid[13], es->s_uuid[14], es->s_uuid[15]);
++ if (!memcmp(es->s_uuid, root_dev_uuid, 16))
++ rv = /* found */ 1;
++ }
++// else printk(KERN_ERR "D: bad ext2fs magic\n");
++ out:
++ blkdev_put(bdev, FMODE_READ);
++ return (rv);
++}
++#endif /* CONFIG_EXT2_FS for UUID support */
++
+ static int __init load_ramdisk(char *str)
+ {
+ rd_doload = simple_strtol(str,NULL,0) & 3;
+@@ -148,6 +274,13 @@ done:
+ static int __init root_dev_setup(char *line)
+ {
+ strlcpy(saved_root_name, line, sizeof(saved_root_name));
++#ifdef CONFIG_EXT2_FS
++ root_dev_type = 0;
++ if (!strncmp(line, "UUID=", 5)) {
++ root_dev_type = 1;
++ parse_uuid(line + 5);
++ }
++#endif /* CONFIG_EXT2_FS for UUID support */
+ return 1;
+ }
+
+@@ -333,6 +466,83 @@ void __init change_floppy(char *fmt, ...
+
+ void __init mount_root(void)
+ {
++#ifdef CONFIG_EXT2_FS
++ /* UUID support */
++// printk_all_partitions();
++ if (root_dev_type == 1) {
++ int blocksize;
++
++ /* from block/genhd.c printk_all_partitions */
++ struct class_dev_iter iter;
++ struct device *dev;
++
++ /* from drivers/md/md.c */
++ struct page *sb_page;
++
++ if (!(sb_page = alloc_page(GFP_KERNEL))) {
++ printk(KERN_ERR "VFS: no memory for bio page\n");
++ goto nomemforbio;
++ }
++
++// printk(KERN_ERR "D: root is: "
++// "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
++// root_dev_uuid[0], root_dev_uuid[1], root_dev_uuid[2], root_dev_uuid[3],
++// root_dev_uuid[4], root_dev_uuid[5], root_dev_uuid[6], root_dev_uuid[7],
++// root_dev_uuid[8], root_dev_uuid[9], root_dev_uuid[10], root_dev_uuid[11],
++// root_dev_uuid[12], root_dev_uuid[13], root_dev_uuid[14], root_dev_uuid[15]);
++ /* from block/genhd.c printk_all_partitions */
++// printk(KERN_ERR "D: begin iter\n");
++ class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
++ while (root_dev_type && (dev = class_dev_iter_next(&iter))) {
++// char bff[22];
++ struct gendisk *disk = dev_to_disk(dev);
++ struct disk_part_iter piter;
++ struct hd_struct *part;
++ if (get_capacity(disk) == 0 ||
++ (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) {
++// printk(KERN_ERR "D: ignoring\n");
++ continue;
++ }
++ blocksize = queue_logical_block_size(disk->queue);
++// printk(KERN_ERR "D: gendisk, blocksize %d "
++// "name '%s' devt %08X %s #part %d\n", blocksize,
++// disk->disk_name, dev->devt,
++// format_dev_t(bff, dev->devt),
++// disk_max_parts(disk));
++ disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
++ while (root_dev_type && (part = disk_part_iter_next(&piter))) {
++ /* avoid empty or too small partitions */
++// printk(KERN_ERR "D: part #%d start %llu "
++// "nr %llu\n", part->partno,
++// (__u64)part->start_sect,
++// (__u64)part->nr_sects);
++ if (part->nr_sects < 8)
++ continue;
++ if (check_dev(disk, MKDEV(MAJOR(dev->devt),
++ MINOR(dev->devt) + part->partno),
++ blocksize, sb_page)) {
++ ROOT_DEV = part_devt(part);
++// printk(KERN_ERR "D: got match!\n");
++ // comment out below for debugging
++ root_dev_type = 0;
++ }
++ }
++ disk_part_iter_exit(&piter);
++ }
++// printk(KERN_ERR "D: end iter\n");
++ class_dev_iter_exit(&iter);
++ put_page(sb_page);
++ }
++ nomemforbio:
++ if (root_dev_type == 1)
++ printk(KERN_ERR "VFS: Unable to find root by UUID %s.\n",
++ saved_root_name + 5);
++ else if (root_dev_type == 3)
++ /* execute deferred panic from parse_uuid */
++ panic("Badly formatted UUID %s was supplied as kernel "
++ "parameter root", saved_root_name + 5);
++#endif /* CONFIG_EXT2_FS for UUID support */
++
+ #ifdef CONFIG_ROOT_NFS
+ if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
+ if (mount_nfs_root())
diff --git a/target/linux/patches/2.6.37/yaffs2.patch b/target/linux/patches/2.6.37/yaffs2.patch
new file mode 100644
index 000000000..4a52d3f10
--- /dev/null
+++ b/target/linux/patches/2.6.37/yaffs2.patch
@@ -0,0 +1,16912 @@
+diff -Nur linux-2.6.36.orig/fs/Kconfig linux-2.6.36/fs/Kconfig
+--- linux-2.6.36.orig/fs/Kconfig 2011-01-10 19:28:45.000000000 +0100
++++ linux-2.6.36/fs/Kconfig 2011-01-10 19:29:29.000000000 +0100
+@@ -174,6 +174,7 @@
+ source "fs/befs/Kconfig"
+ source "fs/bfs/Kconfig"
+ source "fs/efs/Kconfig"
++source "fs/yaffs2/Kconfig"
+ source "fs/jffs2/Kconfig"
+ # UBIFS File system configuration
+ source "fs/ubifs/Kconfig"
+diff -Nur linux-2.6.36.orig/fs/Makefile linux-2.6.36/fs/Makefile
+--- linux-2.6.36.orig/fs/Makefile 2011-01-10 19:28:45.000000000 +0100
++++ linux-2.6.36/fs/Makefile 2011-01-10 19:30:04.000000000 +0100
+@@ -124,6 +124,7 @@
+ obj-$(CONFIG_OCFS2_FS) += ocfs2/
+ obj-$(CONFIG_BTRFS_FS) += btrfs/
+ obj-$(CONFIG_GFS2_FS) += gfs2/
++obj-$(CONFIG_YAFFS_FS) += yaffs2/
+ obj-$(CONFIG_EXOFS_FS) += exofs/
+ obj-$(CONFIG_CEPH_FS) += ceph/
+ obj-$(CONFIG_AUFS_FS) += aufs/
+diff -Nur linux-2.6.36.orig/fs/yaffs2/Kconfig linux-2.6.36/fs/yaffs2/Kconfig
+--- linux-2.6.36.orig/fs/yaffs2/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/Kconfig 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,161 @@
++#
++# YAFFS file system configurations
++#
++
++config YAFFS_FS
++ tristate "YAFFS2 file system support"
++ default n
++ depends on MTD_BLOCK
++ select YAFFS_YAFFS1
++ select YAFFS_YAFFS2
++ help
++ YAFFS2, or Yet Another Flash Filing System, is a filing system
++ optimised for NAND Flash chips.
++
++ To compile the YAFFS2 file system support as a module, choose M
++ here: the module will be called yaffs2.
++
++ If unsure, say N.
++
++ Further information on YAFFS2 is available at
++ <http://www.aleph1.co.uk/yaffs/>.
++
++config YAFFS_YAFFS1
++ bool "512 byte / page devices"
++ depends on YAFFS_FS
++ default y
++ help
++ Enable YAFFS1 support -- yaffs for 512 byte / page devices
++
++ Not needed for 2K-page devices.
++
++ If unsure, say Y.
++
++config YAFFS_9BYTE_TAGS
++ bool "Use older-style on-NAND data format with pageStatus byte"
++ depends on YAFFS_YAFFS1
++ default n
++ help
++
++ Older-style on-NAND data format has a "pageStatus" byte to record
++ chunk/page state. This byte is zero when the page is discarded.
++ Choose this option if you have existing on-NAND data using this
++ format that you need to continue to support. New data written
++ also uses the older-style format. Note: Use of this option
++ generally requires that MTD's oob layout be adjusted to use the
++ older-style format. See notes on tags formats and MTD versions
++ in yaffs_mtdif1.c.
++
++ If unsure, say N.
++
++config YAFFS_DOES_ECC
++ bool "Lets Yaffs do its own ECC"
++ depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
++ default n
++ help
++ This enables Yaffs to use its own ECC functions instead of using
++ the ones from the generic MTD-NAND driver.
++
++ If unsure, say N.
++
++config YAFFS_ECC_WRONG_ORDER
++ bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
++ depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
++ default n
++ help
++ This makes yaffs_ecc.c use the same ecc byte order as Steven
++ Hill's nand_ecc.c. If not set, then you get the same ecc byte
++ order as SmartMedia.
++
++ If unsure, say N.
++
++config YAFFS_YAFFS2
++ bool "2048 byte (or larger) / page devices"
++ depends on YAFFS_FS
++ default y
++ help
++ Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
++
++ If unsure, say Y.
++
++config YAFFS_AUTO_YAFFS2
++ bool "Autoselect yaffs2 format"
++ depends on YAFFS_YAFFS2
++ default y
++ help
++ Without this, you need to explicitely use yaffs2 as the file
++ system type. With this, you can say "yaffs" and yaffs or yaffs2
++ will be used depending on the device page size (yaffs on
++ 512-byte page devices, yaffs2 on 2K page devices).
++
++ If unsure, say Y.
++
++config YAFFS_DISABLE_TAGS_ECC
++ bool "Disable YAFFS from doing ECC on tags by default"
++ depends on YAFFS_FS && YAFFS_YAFFS2
++ default n
++ help
++ This defaults Yaffs to using its own ECC calculations on tags instead of
++ just relying on the MTD.
++ This behavior can also be overridden with tags_ecc_on and
++ tags_ecc_off mount options.
++
++ If unsure, say N.
++
++config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
++ bool "Force chunk erase check"
++ depends on YAFFS_FS
++ default n
++ help
++ Normally YAFFS only checks chunks before writing until an erased
++ chunk is found. This helps to detect any partially written
++ chunks that might have happened due to power loss.
++
++ Enabling this forces on the test that chunks are erased in flash
++ before writing to them. This takes more time but is potentially
++ a bit more secure.
++
++ Suggest setting Y during development and ironing out driver
++ issues etc. Suggest setting to N if you want faster writing.
++
++ If unsure, say Y.
++
++config YAFFS_EMPTY_LOST_AND_FOUND
++ bool "Empty lost and found on boot"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is enabled then the contents of lost and found is
++ automatically dumped at mount.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BLOCK_REFRESHING
++ bool "Disable yaffs2 block refreshing"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is set, then block refreshing is disabled.
++ Block refreshing infrequently refreshes the oldest block in
++ a yaffs2 file system. This mechanism helps to refresh flash to
++ mitigate against data loss. This is particularly useful for MLC.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_BACKGROUND
++ bool "Disable yaffs2 background processing"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is set, then background processing is disabled.
++ Background processing makes many foreground activities faster.
++
++ If unsure, say N.
++
++config YAFFS_XATTR
++ bool "Enable yaffs2 xattr support"
++ depends on YAFFS_FS
++ default y
++ help
++ If this is set then yaffs2 will provide xattr support.
++ If unsure, say Y.
+diff -Nur linux-2.6.36.orig/fs/yaffs2/Makefile linux-2.6.36/fs/yaffs2/Makefile
+--- linux-2.6.36.orig/fs/yaffs2/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/Makefile 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,17 @@
++#
++# Makefile for the linux YAFFS filesystem routines.
++#
++
++obj-$(CONFIG_YAFFS_FS) += yaffs.o
++
++yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
++yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
++yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
++yaffs-y += yaffs_nameval.o yaffs_attribs.o
++yaffs-y += yaffs_allocator.o
++yaffs-y += yaffs_yaffs1.o
++yaffs-y += yaffs_yaffs2.o
++yaffs-y += yaffs_bitmap.o
++yaffs-y += yaffs_verify.o
++
+diff -Nur linux-2.6.36.orig/fs/yaffs2/moduleconfig.h linux-2.6.36/fs/yaffs2/moduleconfig.h
+--- linux-2.6.36.orig/fs/yaffs2/moduleconfig.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/moduleconfig.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,81 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Martin Fouts <Martin.Fouts@palmsource.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_CONFIG_H__
++#define __YAFFS_CONFIG_H__
++
++#ifdef YAFFS_OUT_OF_TREE
++
++/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
++#define CONFIG_YAFFS_FS
++#define CONFIG_YAFFS_YAFFS1
++#define CONFIG_YAFFS_YAFFS2
++
++/* These options are independent of each other. Select those that matter. */
++
++/* Default: Not selected */
++/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
++/* #define CONFIG_YAFFS_DOES_ECC */
++
++/* Default: Selected */
++/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
++#define CONFIG_YAFFS_DOES_TAGS_ECC
++
++/* Default: Not selected */
++/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
++/* CONFIG_YAFFS_DOES_ECC is set */
++/* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
++
++/* Default: Not selected */
++/* Meaning: Always test whether chunks are erased before writing to them.
++ Use during mtd debugging and init. */
++/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */
++
++/* Default: Not Selected */
++/* Meaning: At mount automatically empty all files from lost and found. */
++/* This is done to fix an old problem where rmdir was not checking for an */
++/* empty directory. This can also be achieved with a mount option. */
++#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
++
++/* Default: Unselected */
++/* Meaning: Select to disable block refreshing. */
++/* Block Refreshing periodically rewrites the oldest block. */
++/* #define CONFIG_DISABLE_BLOCK_REFRESHING */
++
++/* Default: Unselected */
++/* Meaning: Select to disable background processing */
++/* #define CONFIG_DISABLE_BACKGROUND */
++
++/* Default: Selected */
++/* Meaning: Enable XATTR support */
++#define CONFIG_YAFFS_XATTR
++
++/*
++Older-style on-NAND data format has a "page_status" byte to record
++chunk/page state. This byte is zeroed when the page is discarded.
++Choose this option if you have existing on-NAND data in this format
++that you need to continue to support. New data written also uses the
++older-style format.
++Note: Use of this option generally requires that MTD's oob layout be
++adjusted to use the older-style format. See notes on tags formats and
++MTD versions in yaffs_mtdif1.c.
++*/
++/* Default: Not selected */
++/* Meaning: Use older-style on-NAND data format with page_status byte */
++/* #define CONFIG_YAFFS_9BYTE_TAGS */
++
++#endif /* YAFFS_OUT_OF_TREE */
++
++#endif /* __YAFFS_CONFIG_H__ */
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_allocator.c linux-2.6.36/fs/yaffs2/yaffs_allocator.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_allocator.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_allocator.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,397 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_allocator.h"
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yportenv.h"
++
++#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
++
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ dev = dev;
++}
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ dev = dev;
++}
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
++{
++ return (struct yaffs_tnode *)YMALLOC(dev->tnode_size);
++}
++
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++ dev = dev;
++ YFREE(tn);
++}
++
++void yaffs_init_raw_objs(struct yaffs_dev *dev)
++{
++ dev = dev;
++}
++
++void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
++{
++ dev = dev;
++}
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
++{
++ dev = dev;
++ return (struct yaffs_obj *)YMALLOC(sizeof(struct yaffs_obj));
++}
++
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++
++ dev = dev;
++ YFREE(obj);
++}
++
++#else
++
++struct yaffs_tnode_list {
++ struct yaffs_tnode_list *next;
++ struct yaffs_tnode *tnodes;
++};
++
++struct yaffs_obj_list {
++ struct yaffs_obj_list *next;
++ struct yaffs_obj *objects;
++};
++
++struct yaffs_allocator {
++ int n_tnodes_created;
++ struct yaffs_tnode *free_tnodes;
++ int n_free_tnodes;
++ struct yaffs_tnode_list *alloc_tnode_list;
++
++ int n_obj_created;
++ struct yaffs_obj *free_objs;
++ int n_free_objects;
++
++ struct yaffs_obj_list *allocated_obj_list;
++};
++
++static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
++{
++
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++
++ struct yaffs_tnode_list *tmp;
++
++ if (!allocator) {
++ YBUG();
++ return;
++ }
++
++ while (allocator->alloc_tnode_list) {
++ tmp = allocator->alloc_tnode_list->next;
++
++ YFREE(allocator->alloc_tnode_list->tnodes);
++ YFREE(allocator->alloc_tnode_list);
++ allocator->alloc_tnode_list = tmp;
++
++ }
++
++ allocator->free_tnodes = NULL;
++ allocator->n_free_tnodes = 0;
++ allocator->n_tnodes_created = 0;
++}
++
++static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (allocator) {
++ allocator->alloc_tnode_list = NULL;
++ allocator->free_tnodes = NULL;
++ allocator->n_free_tnodes = 0;
++ allocator->n_tnodes_created = 0;
++ } else {
++ YBUG();
++ }
++}
++
++static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ int i;
++ struct yaffs_tnode *new_tnodes;
++ u8 *mem;
++ struct yaffs_tnode *curr;
++ struct yaffs_tnode *next;
++ struct yaffs_tnode_list *tnl;
++
++ if (!allocator) {
++ YBUG();
++ return YAFFS_FAIL;
++ }
++
++ if (n_tnodes < 1)
++ return YAFFS_OK;
++
++ /* make these things */
++
++ new_tnodes = YMALLOC(n_tnodes * dev->tnode_size);
++ mem = (u8 *) new_tnodes;
++
++ if (!new_tnodes) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ /* New hookup for wide tnodes */
++ for (i = 0; i < n_tnodes - 1; i++) {
++ curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
++ next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
++ curr->internal[0] = next;
++ }
++
++ curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
++ curr->internal[0] = allocator->free_tnodes;
++ allocator->free_tnodes = (struct yaffs_tnode *)mem;
++
++ allocator->n_free_tnodes += n_tnodes;
++ allocator->n_tnodes_created += n_tnodes;
++
++ /* Now add this bunch of tnodes to a list for freeing up.
++ * NB If we can't add this to the management list it isn't fatal
++ * but it just means we can't free this bunch of tnodes later.
++ */
++
++ tnl = YMALLOC(sizeof(struct yaffs_tnode_list));
++ if (!tnl) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs: Could not add tnodes to management list" TENDSTR)));
++ return YAFFS_FAIL;
++ } else {
++ tnl->tnodes = new_tnodes;
++ tnl->next = allocator->alloc_tnode_list;
++ allocator->alloc_tnode_list = tnl;
++ }
++
++ T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
++
++ return YAFFS_OK;
++}
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator =
++ (struct yaffs_allocator *)dev->allocator;
++ struct yaffs_tnode *tn = NULL;
++
++ if (!allocator) {
++ YBUG();
++ return NULL;
++ }
++
++ /* If there are none left make more */
++ if (!allocator->free_tnodes)
++ yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
++
++ if (allocator->free_tnodes) {
++ tn = allocator->free_tnodes;
++ allocator->free_tnodes = allocator->free_tnodes->internal[0];
++ allocator->n_free_tnodes--;
++ }
++
++ return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ YBUG();
++ return;
++ }
++
++ if (tn) {
++ tn->internal[0] = allocator->free_tnodes;
++ allocator->free_tnodes = tn;
++ allocator->n_free_tnodes++;
++ }
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++static void yaffs_init_raw_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (allocator) {
++ allocator->allocated_obj_list = NULL;
++ allocator->free_objs = NULL;
++ allocator->n_free_objects = 0;
++ } else {
++ YBUG();
++ }
++}
++
++static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++ struct yaffs_obj_list *tmp;
++
++ if (!allocator) {
++ YBUG();
++ return;
++ }
++
++ while (allocator->allocated_obj_list) {
++ tmp = allocator->allocated_obj_list->next;
++ YFREE(allocator->allocated_obj_list->objects);
++ YFREE(allocator->allocated_obj_list);
++
++ allocator->allocated_obj_list = tmp;
++ }
++
++ allocator->free_objs = NULL;
++ allocator->n_free_objects = 0;
++ allocator->n_obj_created = 0;
++}
++
++static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
++{
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ int i;
++ struct yaffs_obj *new_objs;
++ struct yaffs_obj_list *list;
++
++ if (!allocator) {
++ YBUG();
++ return YAFFS_FAIL;
++ }
++
++ if (n_obj < 1)
++ return YAFFS_OK;
++
++ /* make these things */
++ new_objs = YMALLOC(n_obj * sizeof(struct yaffs_obj));
++ list = YMALLOC(sizeof(struct yaffs_obj_list));
++
++ if (!new_objs || !list) {
++ if (new_objs) {
++ YFREE(new_objs);
++ new_objs = NULL;
++ }
++ if (list) {
++ YFREE(list);
++ list = NULL;
++ }
++ T(YAFFS_TRACE_ALLOCATE,
++ (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ /* Hook them into the free list */
++ for (i = 0; i < n_obj - 1; i++) {
++ new_objs[i].siblings.next =
++ (struct list_head *)(&new_objs[i + 1]);
++ }
++
++ new_objs[n_obj - 1].siblings.next = (void *)allocator->free_objs;
++ allocator->free_objs = new_objs;
++ allocator->n_free_objects += n_obj;
++ allocator->n_obj_created += n_obj;
++
++ /* Now add this bunch of Objects to a list for freeing up. */
++
++ list->objects = new_objs;
++ list->next = allocator->allocated_obj_list;
++ allocator->allocated_obj_list = list;
++
++ return YAFFS_OK;
++}
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator) {
++ YBUG();
++ return obj;
++ }
++
++ /* If there are none left make more */
++ if (!allocator->free_objs)
++ yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
++
++ if (allocator->free_objs) {
++ obj = allocator->free_objs;
++ allocator->free_objs =
++ (struct yaffs_obj *)(allocator->free_objs->siblings.next);
++ allocator->n_free_objects--;
++ }
++
++ return obj;
++}
++
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++
++ struct yaffs_allocator *allocator = dev->allocator;
++
++ if (!allocator)
++ YBUG();
++ else {
++ /* Link into the free list. */
++ obj->siblings.next = (struct list_head *)(allocator->free_objs);
++ allocator->free_objs = obj;
++ allocator->n_free_objects++;
++ }
++}
++
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ if (dev->allocator) {
++ yaffs_deinit_raw_tnodes(dev);
++ yaffs_deinit_raw_objs(dev);
++
++ YFREE(dev->allocator);
++ dev->allocator = NULL;
++ } else {
++ YBUG();
++ }
++}
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_allocator *allocator;
++
++ if (!dev->allocator) {
++ allocator = YMALLOC(sizeof(struct yaffs_allocator));
++ if (allocator) {
++ dev->allocator = allocator;
++ yaffs_init_raw_tnodes(dev);
++ yaffs_init_raw_objs(dev);
++ }
++ } else {
++ YBUG();
++ }
++}
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_allocator.h linux-2.6.36/fs/yaffs2/yaffs_allocator.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_allocator.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_allocator.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,30 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ALLOCATOR_H__
++#define __YAFFS_ALLOCATOR_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_attribs.c linux-2.6.36/fs/yaffs2/yaffs_attribs.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_attribs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_attribs.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,124 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
++{
++ obj->yst_uid = oh->yst_uid;
++ obj->yst_gid = oh->yst_gid;
++ obj->yst_atime = oh->yst_atime;
++ obj->yst_mtime = oh->yst_mtime;
++ obj->yst_ctime = oh->yst_ctime;
++ obj->yst_rdev = oh->yst_rdev;
++}
++
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
++{
++ oh->yst_uid = obj->yst_uid;
++ oh->yst_gid = obj->yst_gid;
++ oh->yst_atime = obj->yst_atime;
++ oh->yst_mtime = obj->yst_mtime;
++ oh->yst_ctime = obj->yst_ctime;
++ oh->yst_rdev = obj->yst_rdev;
++
++}
++
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
++{
++ obj->yst_mtime = Y_CURRENT_TIME;
++ if (do_a)
++ obj->yst_atime = obj->yst_atime;
++ if (do_c)
++ obj->yst_ctime = obj->yst_atime;
++}
++
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
++{
++ yaffs_load_current_time(obj, 1, 1);
++ obj->yst_rdev = rdev;
++ obj->yst_uid = uid;
++ obj->yst_gid = gid;
++}
++
++loff_t yaffs_get_file_size(struct yaffs_obj *obj)
++{
++ YCHAR *alias = NULL;
++ obj = yaffs_get_equivalent_obj(obj);
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return obj->variant.file_variant.file_size;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = obj->variant.symlink_variant.alias;
++ if (!alias)
++ return 0;
++ return yaffs_strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
++ default:
++ return 0;
++ }
++}
++
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++ unsigned int valid = attr->ia_valid;
++
++ if (valid & ATTR_MODE)
++ obj->yst_mode = attr->ia_mode;
++ if (valid & ATTR_UID)
++ obj->yst_uid = attr->ia_uid;
++ if (valid & ATTR_GID)
++ obj->yst_gid = attr->ia_gid;
++
++ if (valid & ATTR_ATIME)
++ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
++ if (valid & ATTR_CTIME)
++ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
++ if (valid & ATTR_MTIME)
++ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
++
++ if (valid & ATTR_SIZE)
++ yaffs_resize_file(obj, attr->ia_size);
++
++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++ return YAFFS_OK;
++
++}
++
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++ unsigned int valid = 0;
++
++ attr->ia_mode = obj->yst_mode;
++ valid |= ATTR_MODE;
++ attr->ia_uid = obj->yst_uid;
++ valid |= ATTR_UID;
++ attr->ia_gid = obj->yst_gid;
++ valid |= ATTR_GID;
++
++ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
++ valid |= ATTR_ATIME;
++ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
++ valid |= ATTR_CTIME;
++ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
++ valid |= ATTR_MTIME;
++
++ attr->ia_size = yaffs_get_file_size(obj);
++ valid |= ATTR_SIZE;
++
++ attr->ia_valid = valid;
++
++ return YAFFS_OK;
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_attribs.h linux-2.6.36/fs/yaffs2/yaffs_attribs.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_attribs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_attribs.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ATTRIBS_H__
++#define __YAFFS_ATTRIBS_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_bitmap.c linux-2.6.36/fs/yaffs2/yaffs_bitmap.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_bitmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_bitmap.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,104 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_bitmap.h"
++#include "yaffs_trace.h"
++/*
++ * Chunk bitmap manipulations
++ */
++
++static Y_INLINE u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
++ blk));
++ YBUG();
++ }
++ return dev->chunk_bits +
++ (dev->chunk_bit_stride * (blk - dev->internal_start_block));
++}
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
++ chunk < 0 || chunk >= dev->param.chunks_per_block) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid" TENDSTR),
++ blk, chunk));
++ YBUG();
++ }
++}
++
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ memset(blk_bits, 0, dev->chunk_bit_stride);
++}
++
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++
++ blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
++}
++
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++
++ blk_bits[chunk / 8] |= (1 << (chunk & 7));
++}
++
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++ yaffs_verify_chunk_bit_id(dev, blk, chunk);
++
++ return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
++}
++
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++ int i;
++ for (i = 0; i < dev->chunk_bit_stride; i++) {
++ if (*blk_bits)
++ return 1;
++ blk_bits++;
++ }
++ return 0;
++}
++
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++ u8 *blk_bits = yaffs_block_bits(dev, blk);
++ int i;
++ int n = 0;
++ for (i = 0; i < dev->chunk_bit_stride; i++) {
++ u8 x = *blk_bits;
++ while (x) {
++ if (x & 1)
++ n++;
++ x >>= 1;
++ }
++
++ blk_bits++;
++ }
++ return n;
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_bitmap.h linux-2.6.36/fs/yaffs2/yaffs_bitmap.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_bitmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_bitmap.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * Chunk bitmap manipulations
++ */
++
++#ifndef __YAFFS_BITMAP_H__
++#define __YAFFS_BITMAP_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_checkptrw.c linux-2.6.36/fs/yaffs2/yaffs_checkptrw.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_checkptrw.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,420 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_checkptrw.h"
++#include "yaffs_getblockinfo.h"
++
++static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
++{
++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("checkpt blocks available = %d" TENDSTR), blocks_avail));
++
++ return (blocks_avail <= 0) ? 0 : 1;
++}
++
++static int yaffs_checkpt_erase(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (!dev->param.erase_fn)
++ return 0;
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d" TENDSTR),
++ dev->internal_start_block,
++ dev->internal_end_block));
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("erasing checkpt block %d" TENDSTR), i));
++
++ dev->n_erasures++;
++
++ if (dev->param.
++ erase_fn(dev,
++ i - dev->block_offset /* realign */ )) {
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ dev->n_free_chunks +=
++ dev->param.chunks_per_block;
++ } else {
++ dev->param.bad_block_fn(dev, i);
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++ }
++ }
++ }
++
++ dev->blocks_in_checkpt = 0;
++
++ return 1;
++}
++
++static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
++{
++ int i;
++ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR
++ ("allocating checkpt block: erased %d reserved %d avail %d next %d "
++ TENDSTR), dev->n_erased_blocks, dev->param.n_reserved_blocks,
++ blocks_avail, dev->checkpt_next_block));
++
++ if (dev->checkpt_next_block >= 0 &&
++ dev->checkpt_next_block <= dev->internal_end_block &&
++ blocks_avail > 0) {
++
++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++ i++) {
++ struct yaffs_block_info *bi =
++ yaffs_get_block_info(dev, i);
++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ dev->checkpt_next_block = i + 1;
++ dev->checkpt_cur_block = i;
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("allocating checkpt block %d" TENDSTR),
++ i));
++ return;
++ }
++ }
++ }
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks" TENDSTR)));
++
++ dev->checkpt_next_block = -1;
++ dev->checkpt_cur_block = -1;
++}
++
++static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
++{
++ int i;
++ struct yaffs_ext_tags tags;
++
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
++ dev->blocks_in_checkpt, dev->checkpt_next_block));
++
++ if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
++ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++ i++) {
++ int chunk = i * dev->param.chunks_per_block;
++ int realigned_chunk = chunk - dev->chunk_offset;
++
++ dev->param.read_chunk_tags_fn(dev, realigned_chunk,
++ NULL, &tags);
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR
++ ("find next checkpt block: search: block %d oid %d seq %d eccr %d"
++ TENDSTR), i, tags.obj_id, tags.seq_number,
++ tags.ecc_result));
++
++ if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
++ /* Right kind of block */
++ dev->checkpt_next_block = tags.obj_id;
++ dev->checkpt_cur_block = i;
++ dev->checkpt_block_list[dev->
++ blocks_in_checkpt] = i;
++ dev->blocks_in_checkpt++;
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("found checkpt block %d" TENDSTR), i));
++ return;
++ }
++ }
++
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("found no more checkpt blocks" TENDSTR)));
++
++ dev->checkpt_next_block = -1;
++ dev->checkpt_cur_block = -1;
++}
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
++{
++
++ dev->checkpt_open_write = writing;
++
++ /* Got the functions we need? */
++ if (!dev->param.write_chunk_tags_fn ||
++ !dev->param.read_chunk_tags_fn ||
++ !dev->param.erase_fn || !dev->param.bad_block_fn)
++ return 0;
++
++ if (writing && !yaffs2_checkpt_space_ok(dev))
++ return 0;
++
++ if (!dev->checkpt_buffer)
++ dev->checkpt_buffer =
++ YMALLOC_DMA(dev->param.total_bytes_per_chunk);
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ dev->checkpt_page_seq = 0;
++ dev->checkpt_byte_count = 0;
++ dev->checkpt_sum = 0;
++ dev->checkpt_xor = 0;
++ dev->checkpt_cur_block = -1;
++ dev->checkpt_cur_chunk = -1;
++ dev->checkpt_next_block = dev->internal_start_block;
++
++ /* Erase all the blocks in the checkpoint area */
++ if (writing) {
++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++ dev->checkpt_byte_offs = 0;
++ return yaffs_checkpt_erase(dev);
++ } else {
++ int i;
++ /* Set to a value that will kick off a read */
++ dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
++ /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
++ * going to be way more than we need */
++ dev->blocks_in_checkpt = 0;
++ dev->checkpt_max_blocks =
++ (dev->internal_end_block - dev->internal_start_block) / 16 +
++ 2;
++ dev->checkpt_block_list =
++ YMALLOC(sizeof(int) * dev->checkpt_max_blocks);
++ if (!dev->checkpt_block_list)
++ return 0;
++
++ for (i = 0; i < dev->checkpt_max_blocks; i++)
++ dev->checkpt_block_list[i] = -1;
++ }
++
++ return 1;
++}
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
++{
++ u32 composite_sum;
++ composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF);
++ *sum = composite_sum;
++ return 1;
++}
++
++static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
++{
++ int chunk;
++ int realigned_chunk;
++
++ struct yaffs_ext_tags tags;
++
++ if (dev->checkpt_cur_block < 0) {
++ yaffs2_checkpt_find_erased_block(dev);
++ dev->checkpt_cur_chunk = 0;
++ }
++
++ if (dev->checkpt_cur_block < 0)
++ return 0;
++
++ tags.is_deleted = 0;
++ tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
++ tags.chunk_id = dev->checkpt_page_seq + 1;
++ tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
++ tags.n_bytes = dev->data_bytes_per_chunk;
++ if (dev->checkpt_cur_chunk == 0) {
++ /* First chunk we write for the block? Set block state to
++ checkpoint */
++ struct yaffs_block_info *bi =
++ yaffs_get_block_info(dev, dev->checkpt_cur_block);
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ dev->blocks_in_checkpt++;
++ }
++
++ chunk =
++ dev->checkpt_cur_block * dev->param.chunks_per_block +
++ dev->checkpt_cur_chunk;
++
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR
++ ("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
++ chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, tags.obj_id,
++ tags.chunk_id));
++
++ realigned_chunk = chunk - dev->chunk_offset;
++
++ dev->n_page_writes++;
++
++ dev->param.write_chunk_tags_fn(dev, realigned_chunk,
++ dev->checkpt_buffer, &tags);
++ dev->checkpt_byte_offs = 0;
++ dev->checkpt_page_seq++;
++ dev->checkpt_cur_chunk++;
++ if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
++ dev->checkpt_cur_chunk = 0;
++ dev->checkpt_cur_block = -1;
++ }
++ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++
++ return 1;
++}
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
++{
++ int i = 0;
++ int ok = 1;
++
++ u8 *data_bytes = (u8 *) data;
++
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ if (!dev->checkpt_open_write)
++ return -1;
++
++ while (i < n_bytes && ok) {
++ dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
++ dev->checkpt_sum += *data_bytes;
++ dev->checkpt_xor ^= *data_bytes;
++
++ dev->checkpt_byte_offs++;
++ i++;
++ data_bytes++;
++ dev->checkpt_byte_count++;
++
++ if (dev->checkpt_byte_offs < 0 ||
++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
++ ok = yaffs2_checkpt_flush_buffer(dev);
++ }
++
++ return i;
++}
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
++{
++ int i = 0;
++ int ok = 1;
++ struct yaffs_ext_tags tags;
++
++ int chunk;
++ int realigned_chunk;
++
++ u8 *data_bytes = (u8 *) data;
++
++ if (!dev->checkpt_buffer)
++ return 0;
++
++ if (dev->checkpt_open_write)
++ return -1;
++
++ while (i < n_bytes && ok) {
++
++ if (dev->checkpt_byte_offs < 0 ||
++ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
++
++ if (dev->checkpt_cur_block < 0) {
++ yaffs2_checkpt_find_block(dev);
++ dev->checkpt_cur_chunk = 0;
++ }
++
++ if (dev->checkpt_cur_block < 0)
++ ok = 0;
++ else {
++ chunk = dev->checkpt_cur_block *
++ dev->param.chunks_per_block +
++ dev->checkpt_cur_chunk;
++
++ realigned_chunk = chunk - dev->chunk_offset;
++
++ dev->n_page_reads++;
++
++ /* read in the next chunk */
++ dev->param.read_chunk_tags_fn(dev,
++ realigned_chunk,
++ dev->
++ checkpt_buffer,
++ &tags);
++
++ if (tags.chunk_id != (dev->checkpt_page_seq + 1)
++ || tags.ecc_result > YAFFS_ECC_RESULT_FIXED
++ || tags.seq_number !=
++ YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ ok = 0;
++
++ dev->checkpt_byte_offs = 0;
++ dev->checkpt_page_seq++;
++ dev->checkpt_cur_chunk++;
++
++ if (dev->checkpt_cur_chunk >=
++ dev->param.chunks_per_block)
++ dev->checkpt_cur_block = -1;
++ }
++ }
++
++ if (ok) {
++ *data_bytes =
++ dev->checkpt_buffer[dev->checkpt_byte_offs];
++ dev->checkpt_sum += *data_bytes;
++ dev->checkpt_xor ^= *data_bytes;
++ dev->checkpt_byte_offs++;
++ i++;
++ data_bytes++;
++ dev->checkpt_byte_count++;
++ }
++ }
++
++ return i;
++}
++
++int yaffs_checkpt_close(struct yaffs_dev *dev)
++{
++
++ if (dev->checkpt_open_write) {
++ if (dev->checkpt_byte_offs != 0)
++ yaffs2_checkpt_flush_buffer(dev);
++ } else if (dev->checkpt_block_list) {
++ int i;
++ for (i = 0;
++ i < dev->blocks_in_checkpt
++ && dev->checkpt_block_list[i] >= 0; i++) {
++ int blk = dev->checkpt_block_list[i];
++ struct yaffs_block_info *bi = NULL;
++ if (dev->internal_start_block <= blk
++ && blk <= dev->internal_end_block)
++ bi = yaffs_get_block_info(dev, blk);
++ if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
++ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ else {
++ /* Todo this looks odd... */
++ }
++ }
++ YFREE(dev->checkpt_block_list);
++ dev->checkpt_block_list = NULL;
++ }
++
++ dev->n_free_chunks -=
++ dev->blocks_in_checkpt * dev->param.chunks_per_block;
++ dev->n_erased_blocks -= dev->blocks_in_checkpt;
++
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR),
++ dev->checkpt_byte_count));
++
++ if (dev->checkpt_buffer) {
++ /* free the buffer */
++ YFREE(dev->checkpt_buffer);
++ dev->checkpt_buffer = NULL;
++ return 1;
++ } else {
++ return 0;
++ }
++}
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
++{
++ /* Erase the checkpoint data */
++
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("checkpoint invalidate of %d blocks" TENDSTR),
++ dev->blocks_in_checkpt));
++
++ return yaffs_checkpt_erase(dev);
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_checkptrw.h linux-2.6.36/fs/yaffs2/yaffs_checkptrw.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_checkptrw.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_CHECKPTRW_H__
++#define __YAFFS_CHECKPTRW_H__
++
++#include "yaffs_guts.h"
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
++
++int yaffs_checkpt_close(struct yaffs_dev *dev);
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_ecc.c linux-2.6.36/fs/yaffs2/yaffs_ecc.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_ecc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_ecc.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,322 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
++ * blocks are used on a 512-byte NAND page.
++ *
++ */
++
++/* Table generated by gen-ecc.c
++ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
++ * for each byte of data. These are instead provided in a table in bits7..2.
++ * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
++ * this bytes influence on the line parity.
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_ecc.h"
++
++static const unsigned char column_parity_table[] = {
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++};
++
++/* Count the bits in an unsigned char or a U32 */
++
++static int yaffs_count_bits(unsigned char x)
++{
++ int r = 0;
++ while (x) {
++ if (x & 1)
++ r++;
++ x >>= 1;
++ }
++ return r;
++}
++
++static int yaffs_count_bits32(unsigned x)
++{
++ int r = 0;
++ while (x) {
++ if (x & 1)
++ r++;
++ x >>= 1;
++ }
++ return r;
++}
++
++/* Calculate the ECC for a 256-byte block of data */
++void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc)
++{
++ unsigned int i;
++
++ unsigned char col_parity = 0;
++ unsigned char line_parity = 0;
++ unsigned char line_parity_prime = 0;
++ unsigned char t;
++ unsigned char b;
++
++ for (i = 0; i < 256; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) { /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++ }
++
++ ecc[2] = (~col_parity) | 0x03;
++
++ t = 0;
++ if (line_parity & 0x80)
++ t |= 0x80;
++ if (line_parity_prime & 0x80)
++ t |= 0x40;
++ if (line_parity & 0x40)
++ t |= 0x20;
++ if (line_parity_prime & 0x40)
++ t |= 0x10;
++ if (line_parity & 0x20)
++ t |= 0x08;
++ if (line_parity_prime & 0x20)
++ t |= 0x04;
++ if (line_parity & 0x10)
++ t |= 0x02;
++ if (line_parity_prime & 0x10)
++ t |= 0x01;
++ ecc[1] = ~t;
++
++ t = 0;
++ if (line_parity & 0x08)
++ t |= 0x80;
++ if (line_parity_prime & 0x08)
++ t |= 0x40;
++ if (line_parity & 0x04)
++ t |= 0x20;
++ if (line_parity_prime & 0x04)
++ t |= 0x10;
++ if (line_parity & 0x02)
++ t |= 0x08;
++ if (line_parity_prime & 0x02)
++ t |= 0x04;
++ if (line_parity & 0x01)
++ t |= 0x02;
++ if (line_parity_prime & 0x01)
++ t |= 0x01;
++ ecc[0] = ~t;
++
++#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
++ /* Swap the bytes into the wrong order */
++ t = ecc[0];
++ ecc[0] = ecc[1];
++ ecc[1] = t;
++#endif
++}
++
++/* Correct the ECC on a 256 byte block of data */
++
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc)
++{
++ unsigned char d0, d1, d2; /* deltas */
++
++ d0 = read_ecc[0] ^ test_ecc[0];
++ d1 = read_ecc[1] ^ test_ecc[1];
++ d2 = read_ecc[2] ^ test_ecc[2];
++
++ if ((d0 | d1 | d2) == 0)
++ return 0; /* no error */
++
++ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
++ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
++ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
++ /* Single bit (recoverable) error in data */
++
++ unsigned byte;
++ unsigned bit;
++
++#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
++ /* swap the bytes to correct for the wrong order */
++ unsigned char t;
++
++ t = d0;
++ d0 = d1;
++ d1 = t;
++#endif
++
++ bit = byte = 0;
++
++ if (d1 & 0x80)
++ byte |= 0x80;
++ if (d1 & 0x20)
++ byte |= 0x40;
++ if (d1 & 0x08)
++ byte |= 0x20;
++ if (d1 & 0x02)
++ byte |= 0x10;
++ if (d0 & 0x80)
++ byte |= 0x08;
++ if (d0 & 0x20)
++ byte |= 0x04;
++ if (d0 & 0x08)
++ byte |= 0x02;
++ if (d0 & 0x02)
++ byte |= 0x01;
++
++ if (d2 & 0x80)
++ bit |= 0x04;
++ if (d2 & 0x20)
++ bit |= 0x02;
++ if (d2 & 0x08)
++ bit |= 0x01;
++
++ data[byte] ^= (1 << bit);
++
++ return 1; /* Corrected the error */
++ }
++
++ if ((yaffs_count_bits(d0) +
++ yaffs_count_bits(d1) + yaffs_count_bits(d2)) == 1) {
++ /* Reccoverable error in ecc */
++
++ read_ecc[0] = test_ecc[0];
++ read_ecc[1] = test_ecc[1];
++ read_ecc[2] = test_ecc[2];
++
++ return 1; /* Corrected the error */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++
++}
++
++/*
++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
++ */
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *ecc_other)
++{
++ unsigned int i;
++
++ unsigned char col_parity = 0;
++ unsigned line_parity = 0;
++ unsigned line_parity_prime = 0;
++ unsigned char b;
++
++ for (i = 0; i < n_bytes; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) {
++ /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++
++ }
++
++ ecc_other->col_parity = (col_parity >> 2) & 0x3f;
++ ecc_other->line_parity = line_parity;
++ ecc_other->line_parity_prime = line_parity_prime;
++}
++
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *read_ecc,
++ const struct yaffs_ecc_other *test_ecc)
++{
++ unsigned char delta_col; /* column parity delta */
++ unsigned delta_line; /* line parity delta */
++ unsigned delta_line_prime; /* line parity delta */
++ unsigned bit;
++
++ delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
++ delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
++ delta_line_prime =
++ read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
++
++ if ((delta_col | delta_line | delta_line_prime) == 0)
++ return 0; /* no error */
++
++ if (delta_line == ~delta_line_prime &&
++ (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
++ /* Single bit (recoverable) error in data */
++
++ bit = 0;
++
++ if (delta_col & 0x20)
++ bit |= 0x04;
++ if (delta_col & 0x08)
++ bit |= 0x02;
++ if (delta_col & 0x02)
++ bit |= 0x01;
++
++ if (delta_line >= n_bytes)
++ return -1;
++
++ data[delta_line] ^= (1 << bit);
++
++ return 1; /* corrected */
++ }
++
++ if ((yaffs_count_bits32(delta_line) +
++ yaffs_count_bits32(delta_line_prime) +
++ yaffs_count_bits(delta_col)) == 1) {
++ /* Reccoverable error in ecc */
++
++ *read_ecc = *test_ecc;
++ return 1; /* corrected */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_ecc.h linux-2.6.36/fs/yaffs2/yaffs_ecc.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_ecc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_ecc.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
++ * blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#ifndef __YAFFS_ECC_H__
++#define __YAFFS_ECC_H__
++
++struct yaffs_ecc_other {
++ unsigned char col_parity;
++ unsigned line_parity;
++ unsigned line_parity_prime;
++};
++
++void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc);
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc);
++
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *ecc);
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++ struct yaffs_ecc_other *read_ecc,
++ const struct yaffs_ecc_other *test_ecc);
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_getblockinfo.h linux-2.6.36/fs/yaffs2/yaffs_getblockinfo.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_getblockinfo.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,36 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GETBLOCKINFO_H__
++#define __YAFFS_GETBLOCKINFO_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++
++/* Function to manipulate block info */
++static Y_INLINE struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
++ *dev, int blk)
++{
++ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>> yaffs: get_block_info block %d is not valid" TENDSTR),
++ blk));
++ YBUG();
++ }
++ return &dev->block_info[blk - dev->internal_start_block];
++}
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_guts.c linux-2.6.36/fs/yaffs2/yaffs_guts.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_guts.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_guts.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,5227 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++#include "yaffs_guts.h"
++#include "yaffs_tagsvalidity.h"
++#include "yaffs_getblockinfo.h"
++
++#include "yaffs_tagscompat.h"
++
++#include "yaffs_nand.h"
++
++#include "yaffs_yaffs1.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_verify.h"
++
++#include "yaffs_nand.h"
++#include "yaffs_packedtags2.h"
++
++#include "yaffs_nameval.h"
++#include "yaffs_allocator.h"
++
++#include "yaffs_attribs.h"
++
++/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
++#define YAFFS_GC_GOOD_ENOUGH 2
++#define YAFFS_GC_PASSIVE_THRESHOLD 4
++
++#include "yaffs_ecc.h"
++
++/* Robustification (if it ever comes about...) */
++static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block);
++static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
++ int erased_ok);
++static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
++ const u8 * data,
++ const struct yaffs_ext_tags *tags);
++static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
++ const struct yaffs_ext_tags *tags);
++
++/* Other local prototypes */
++static void yaffs_update_parent(struct yaffs_obj *obj);
++static int yaffs_unlink_obj(struct yaffs_obj *obj);
++static int yaffs_obj_cache_dirty(struct yaffs_obj *obj);
++
++static int yaffs_write_new_chunk(struct yaffs_dev *dev,
++ const u8 * buffer,
++ struct yaffs_ext_tags *tags, int use_reserver);
++
++static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
++ enum yaffs_obj_type type);
++
++static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
++ struct yaffs_xattr_mod *xmod);
++
++static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj);
++static int yaffs_generic_obj_del(struct yaffs_obj *in);
++
++static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk);
++
++static int yaffs_unlink_worker(struct yaffs_obj *obj);
++
++static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
++ int chunk_obj);
++
++static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
++ struct yaffs_block_info **block_ptr);
++
++static void yaffs_check_obj_details_loaded(struct yaffs_obj *in);
++
++static void yaffs_invalidate_whole_cache(struct yaffs_obj *in);
++static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object,
++ int chunk_id);
++
++static int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags);
++
++static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 * data,
++ struct yaffs_ext_tags *tags);
++
++static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR * name,
++ const YCHAR * oh_name, int buff_size);
++static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR * oh_name,
++ const YCHAR * name);
++
++/* Function to calculate chunk and offset */
++
++static void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++ int *chunk_out, u32 * offset_out)
++{
++ int chunk;
++ u32 offset;
++
++ chunk = (u32) (addr >> dev->chunk_shift);
++
++ if (dev->chunk_div == 1) {
++ /* easy power of 2 case */
++ offset = (u32) (addr & dev->chunk_mask);
++ } else {
++ /* Non power-of-2 case */
++
++ loff_t chunk_base;
++
++ chunk /= dev->chunk_div;
++
++ chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
++ offset = (u32) (addr - chunk_base);
++ }
++
++ *chunk_out = chunk;
++ *offset_out = offset;
++}
++
++/* Function to return the number of shifts for a power of 2 greater than or
++ * equal to the given number
++ * Note we don't try to cater for all possible numbers and this does not have to
++ * be hellishly efficient.
++ */
++
++static u32 calc_shifts_ceiling(u32 x)
++{
++ int extra_bits;
++ int shifts;
++
++ shifts = extra_bits = 0;
++
++ while (x > 1) {
++ if (x & 1)
++ extra_bits++;
++ x >>= 1;
++ shifts++;
++ }
++
++ if (extra_bits)
++ shifts++;
++
++ return shifts;
++}
++
++/* Function to return the number of shifts to get a 1 in bit 0
++ */
++
++static u32 calc_shifts(u32 x)
++{
++ u32 shifts;
++
++ shifts = 0;
++
++ if (!x)
++ return 0;
++
++ while (!(x & 1)) {
++ x >>= 1;
++ shifts++;
++ }
++
++ return shifts;
++}
++
++/*
++ * Temporary buffer manipulations.
++ */
++
++static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
++{
++ int i;
++ u8 *buf = (u8 *) 1;
++
++ memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
++
++ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
++ dev->temp_buffer[i].line = 0; /* not in use */
++ dev->temp_buffer[i].buffer = buf =
++ YMALLOC_DMA(dev->param.total_bytes_per_chunk);
++ }
++
++ return buf ? YAFFS_OK : YAFFS_FAIL;
++}
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev, int line_no)
++{
++ int i, j;
++
++ dev->temp_in_use++;
++ if (dev->temp_in_use > dev->max_temp)
++ dev->max_temp = dev->temp_in_use;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->temp_buffer[i].line == 0) {
++ dev->temp_buffer[i].line = line_no;
++ if ((i + 1) > dev->max_temp) {
++ dev->max_temp = i + 1;
++ for (j = 0; j <= i; j++)
++ dev->temp_buffer[j].max_line =
++ dev->temp_buffer[j].line;
++ }
++
++ return dev->temp_buffer[i].buffer;
++ }
++ }
++
++ T(YAFFS_TRACE_BUFFERS,
++ (TSTR("Out of temp buffers at line %d, other held by lines:"),
++ line_no));
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
++ T(YAFFS_TRACE_BUFFERS,
++ (TSTR(" %d "), dev->temp_buffer[i].line));
++
++ T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));
++
++ /*
++ * If we got here then we have to allocate an unmanaged one
++ * This is not good.
++ */
++
++ dev->unmanaged_buffer_allocs++;
++ return YMALLOC(dev->data_bytes_per_chunk);
++
++}
++
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 * buffer, int line_no)
++{
++ int i;
++
++ dev->temp_in_use--;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->temp_buffer[i].buffer == buffer) {
++ dev->temp_buffer[i].line = 0;
++ return;
++ }
++ }
++
++ if (buffer) {
++ /* assume it is an unmanaged one. */
++ T(YAFFS_TRACE_BUFFERS,
++ (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),
++ line_no));
++ YFREE(buffer);
++ dev->unmanaged_buffer_deallocs++;
++ }
++
++}
++
++/*
++ * Determine if we have a managed buffer.
++ */
++int yaffs_is_managed_tmp_buffer(struct yaffs_dev *dev, const u8 * buffer)
++{
++ int i;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->temp_buffer[i].buffer == buffer)
++ return 1;
++ }
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].data == buffer)
++ return 1;
++ }
++
++ if (buffer == dev->checkpt_buffer)
++ return 1;
++
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR)));
++ return 0;
++}
++
++/*
++ * Verification code
++ */
++
++/*
++ * Simple hash function. Needs to have a reasonable spread
++ */
++
++static Y_INLINE int yaffs_hash_fn(int n)
++{
++ n = abs(n);
++ return n % YAFFS_NOBJECT_BUCKETS;
++}
++
++/*
++ * Access functions to useful fake objects.
++ * Note that root might have a presence in NAND if permissions are set.
++ */
++
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
++{
++ return dev->root_dir;
++}
++
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
++{
++ return dev->lost_n_found;
++}
++
++/*
++ * Erased NAND checking functions
++ */
++
++int yaffs_check_ff(u8 * buffer, int n_bytes)
++{
++ /* Horrible, slow implementation */
++ while (n_bytes--) {
++ if (*buffer != 0xFF)
++ return 0;
++ buffer++;
++ }
++ return 1;
++}
++
++static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
++{
++ int retval = YAFFS_OK;
++ u8 *data = yaffs_get_temp_buffer(dev, __LINE__);
++ struct yaffs_ext_tags tags;
++ int result;
++
++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
++
++ if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
++ retval = YAFFS_FAIL;
++
++ if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || tags.chunk_used) {
++ T(YAFFS_TRACE_NANDACCESS,
++ (TSTR("Chunk %d not erased" TENDSTR), nand_chunk));
++ retval = YAFFS_FAIL;
++ }
++
++ yaffs_release_temp_buffer(dev, data, __LINE__);
++
++ return retval;
++
++}
++
++static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 * data,
++ struct yaffs_ext_tags *tags)
++{
++ int retval = YAFFS_OK;
++ struct yaffs_ext_tags temp_tags;
++ u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
++ int result;
++
++ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
++ if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
++ temp_tags.obj_id != tags->obj_id ||
++ temp_tags.chunk_id != tags->chunk_id ||
++ temp_tags.n_bytes != tags->n_bytes)
++ retval = YAFFS_FAIL;
++
++ yaffs_release_temp_buffer(dev, buffer, __LINE__);
++
++ return retval;
++}
++
++static int yaffs_write_new_chunk(struct yaffs_dev *dev,
++ const u8 * data,
++ struct yaffs_ext_tags *tags, int use_reserver)
++{
++ int attempts = 0;
++ int write_ok = 0;
++ int chunk;
++
++ yaffs2_checkpt_invalidate(dev);
++
++ do {
++ struct yaffs_block_info *bi = 0;
++ int erased_ok = 0;
++
++ chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
++ if (chunk < 0) {
++ /* no space */
++ break;
++ }
++
++ /* First check this chunk is erased, if it needs
++ * checking. The checking policy (unless forced
++ * always on) is as follows:
++ *
++ * Check the first page we try to write in a block.
++ * If the check passes then we don't need to check any
++ * more. If the check fails, we check again...
++ * If the block has been erased, we don't need to check.
++ *
++ * However, if the block has been prioritised for gc,
++ * then we think there might be something odd about
++ * this block and stop using it.
++ *
++ * Rationale: We should only ever see chunks that have
++ * not been erased if there was a partially written
++ * chunk due to power loss. This checking policy should
++ * catch that case with very few checks and thus save a
++ * lot of checks that are most likely not needed.
++ *
++ * Mods to the above
++ * If an erase check fails or the write fails we skip the
++ * rest of the block.
++ */
++
++ /* let's give it a try */
++ attempts++;
++
++ if (dev->param.always_check_erased)
++ bi->skip_erased_check = 0;
++
++ if (!bi->skip_erased_check) {
++ erased_ok = yaffs_check_chunk_erased(dev, chunk);
++ if (erased_ok != YAFFS_OK) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("**>> yaffs chunk %d was not erased"
++ TENDSTR), chunk));
++
++ /* If not erased, delete this one,
++ * skip rest of block and
++ * try another chunk */
++ yaffs_chunk_del(dev, chunk, 1, __LINE__);
++ yaffs_skip_rest_of_block(dev);
++ continue;
++ }
++ }
++
++ write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
++
++ if (!bi->skip_erased_check)
++ write_ok =
++ yaffs_verify_chunk_written(dev, chunk, data, tags);
++
++ if (write_ok != YAFFS_OK) {
++ /* Clean up aborted write, skip to next block and
++ * try another chunk */
++ yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
++ continue;
++ }
++
++ bi->skip_erased_check = 1;
++
++ /* Copy the data into the robustification buffer */
++ yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
++
++ } while (write_ok != YAFFS_OK &&
++ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
++
++ if (!write_ok)
++ chunk = -1;
++
++ if (attempts > 1) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("**>> yaffs write required %d attempts" TENDSTR),
++ attempts));
++
++ dev->n_retired_writes += (attempts - 1);
++ }
++
++ return chunk;
++}
++
++/*
++ * Block retiring for handling a broken block.
++ */
++
++static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++ yaffs2_checkpt_invalidate(dev);
++
++ yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++ if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
++ if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("yaffs: Failed to mark bad and erase block %d"
++ TENDSTR), flash_block));
++ } else {
++ struct yaffs_ext_tags tags;
++ int chunk_id =
++ flash_block * dev->param.chunks_per_block;
++
++ u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
++
++ memset(buffer, 0xff, dev->data_bytes_per_chunk);
++ yaffs_init_tags(&tags);
++ tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
++ if (dev->param.write_chunk_tags_fn(dev, chunk_id -
++ dev->chunk_offset,
++ buffer,
++ &tags) != YAFFS_OK)
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("yaffs: Failed to "
++ TCONT("write bad block marker to block %d")
++ TENDSTR), flash_block));
++
++ yaffs_release_temp_buffer(dev, buffer, __LINE__);
++ }
++ }
++
++ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++ bi->gc_prioritise = 0;
++ bi->needs_retiring = 0;
++
++ dev->n_retired_blocks++;
++}
++
++/*
++ * Functions for robustisizing TODO
++ *
++ */
++
++static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
++ const u8 * data,
++ const struct yaffs_ext_tags *tags)
++{
++ dev = dev;
++ nand_chunk = nand_chunk;
++ data = data;
++ tags = tags;
++}
++
++static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
++ const struct yaffs_ext_tags *tags)
++{
++ dev = dev;
++ nand_chunk = nand_chunk;
++ tags = tags;
++}
++
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi)
++{
++ if (!bi->gc_prioritise) {
++ bi->gc_prioritise = 1;
++ dev->has_pending_prioritised_gc = 1;
++ bi->chunk_error_strikes++;
++
++ if (bi->chunk_error_strikes > 3) {
++ bi->needs_retiring = 1; /* Too many stikes, so retire this */
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: Block struck out" TENDSTR)));
++
++ }
++ }
++}
++
++static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
++ int erased_ok)
++{
++ int flash_block = nand_chunk / dev->param.chunks_per_block;
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++ yaffs_handle_chunk_error(dev, bi);
++
++ if (erased_ok) {
++ /* Was an actual write failure, so mark the block for retirement */
++ bi->needs_retiring = 1;
++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("**>> Block %d needs retiring" TENDSTR), flash_block));
++ }
++
++ /* Delete the chunk */
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ yaffs_skip_rest_of_block(dev);
++}
++
++/*---------------- Name handling functions ------------*/
++
++static u16 yaffs_calc_name_sum(const YCHAR * name)
++{
++ u16 sum = 0;
++ u16 i = 1;
++
++ const YUCHAR *bname = (const YUCHAR *)name;
++ if (bname) {
++ while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH / 2))) {
++
++ /* 0x1f mask is case insensitive */
++ sum += ((*bname) & 0x1f) * i;
++ i++;
++ bname++;
++ }
++ }
++ return sum;
++}
++
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
++{
++#ifndef CONFIG_YAFFS_NO_SHORT_NAMES
++ memset(obj->short_name, 0, sizeof(obj->short_name));
++ if (name &&
++ yaffs_strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
++ YAFFS_SHORT_NAME_LENGTH)
++ yaffs_strcpy(obj->short_name, name);
++ else
++ obj->short_name[0] = _Y('\0');
++#endif
++ obj->sum = yaffs_calc_name_sum(name);
++}
++
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++ const struct yaffs_obj_hdr *oh)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
++ memset(tmp_name, 0, sizeof(tmp_name));
++ yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ yaffs_set_obj_name(obj, tmp_name);
++#else
++ yaffs_set_obj_name(obj, oh->name);
++#endif
++}
++
++/*-------------------- TNODES -------------------
++
++ * List of spare tnodes
++ * The list is hooked together using the first pointer
++ * in the tnode.
++ */
++
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
++{
++ struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
++ if (tn) {
++ memset(tn, 0, dev->tnode_size);
++ dev->n_tnodes++;
++ }
++
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++
++ return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++ yaffs_free_raw_tnode(dev, tn);
++ dev->n_tnodes--;
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ yaffs_deinit_raw_tnodes_and_objs(dev);
++ dev->n_obj = 0;
++ dev->n_tnodes = 0;
++}
++
++void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos, unsigned val)
++{
++ u32 *map = (u32 *) tn;
++ u32 bit_in_map;
++ u32 bit_in_word;
++ u32 word_in_map;
++ u32 mask;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++ val >>= dev->chunk_grp_bits;
++
++ bit_in_map = pos * dev->tnode_width;
++ word_in_map = bit_in_map / 32;
++ bit_in_word = bit_in_map & (32 - 1);
++
++ mask = dev->tnode_mask << bit_in_word;
++
++ map[word_in_map] &= ~mask;
++ map[word_in_map] |= (mask & (val << bit_in_word));
++
++ if (dev->tnode_width > (32 - bit_in_word)) {
++ bit_in_word = (32 - bit_in_word);
++ word_in_map++;;
++ mask =
++ dev->tnode_mask >> ( /*dev->tnode_width - */ bit_in_word);
++ map[word_in_map] &= ~mask;
++ map[word_in_map] |= (mask & (val >> bit_in_word));
++ }
++}
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos)
++{
++ u32 *map = (u32 *) tn;
++ u32 bit_in_map;
++ u32 bit_in_word;
++ u32 word_in_map;
++ u32 val;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++
++ bit_in_map = pos * dev->tnode_width;
++ word_in_map = bit_in_map / 32;
++ bit_in_word = bit_in_map & (32 - 1);
++
++ val = map[word_in_map] >> bit_in_word;
++
++ if (dev->tnode_width > (32 - bit_in_word)) {
++ bit_in_word = (32 - bit_in_word);
++ word_in_map++;;
++ val |= (map[word_in_map] << bit_in_word);
++ }
++
++ val &= dev->tnode_mask;
++ val <<= dev->chunk_grp_bits;
++
++ return val;
++}
++
++/* ------------------- End of individual tnode manipulation -----------------*/
++
++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
++ * The look up tree is represented by the top tnode and the number of top_level
++ * in the tree. 0 means only the level 0 tnode is in the tree.
++ */
++
++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id)
++{
++ struct yaffs_tnode *tn = file_struct->top;
++ u32 i;
++ int required_depth;
++ int level = file_struct->top_level;
++
++ dev = dev;
++
++ /* Check sane level and chunk Id */
++ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunk_id > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough top_level) */
++
++ i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (i) {
++ i >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ if (required_depth > file_struct->top_level)
++ return NULL; /* Not tall enough, so we can't find it */
++
++ /* Traverse down to level 0 */
++ while (level > 0 && tn) {
++ tn = tn->internal[(chunk_id >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (level - 1) *
++ YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK];
++ level--;
++ }
++
++ return tn;
++}
++
++/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
++ * This happens in two steps:
++ * 1. If the tree isn't tall enough, then make it taller.
++ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
++ *
++ * Used when modifying the tree.
++ *
++ * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
++ * be plugged into the ttree.
++ */
++
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id,
++ struct yaffs_tnode *passed_tn)
++{
++ int required_depth;
++ int i;
++ int l;
++ struct yaffs_tnode *tn;
++
++ u32 x;
++
++ /* Check sane level and page Id */
++ if (file_struct->top_level < 0
++ || file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunk_id > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough top_level) */
++
++ x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (x) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ if (required_depth > file_struct->top_level) {
++ /* Not tall enough, gotta make the tree taller */
++ for (i = file_struct->top_level; i < required_depth; i++) {
++
++ tn = yaffs_get_tnode(dev);
++
++ if (tn) {
++ tn->internal[0] = file_struct->top;
++ file_struct->top = tn;
++ file_struct->top_level++;
++ } else {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("yaffs: no more tnodes" TENDSTR)));
++ return NULL;
++ }
++ }
++ }
++
++ /* Traverse down to level 0, adding anything we need */
++
++ l = file_struct->top_level;
++ tn = file_struct->top;
++
++ if (l > 0) {
++ while (l > 0 && tn) {
++ x = (chunk_id >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK;
++
++ if ((l > 1) && !tn->internal[x]) {
++ /* Add missing non-level-zero tnode */
++ tn->internal[x] = yaffs_get_tnode(dev);
++ if (!tn->internal[x])
++ return NULL;
++ } else if (l == 1) {
++ /* Looking from level 1 at level 0 */
++ if (passed_tn) {
++ /* If we already have one, then release it. */
++ if (tn->internal[x])
++ yaffs_free_tnode(dev,
++ tn->
++ internal[x]);
++ tn->internal[x] = passed_tn;
++
++ } else if (!tn->internal[x]) {
++ /* Don't have one, none passed in */
++ tn->internal[x] = yaffs_get_tnode(dev);
++ if (!tn->internal[x])
++ return NULL;
++ }
++ }
++
++ tn = tn->internal[x];
++ l--;
++ }
++ } else {
++ /* top is level 0 */
++ if (passed_tn) {
++ memcpy(tn, passed_tn,
++ (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
++ yaffs_free_tnode(dev, passed_tn);
++ }
++ }
++
++ return tn;
++}
++
++static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
++ struct yaffs_ext_tags *tags, int obj_id,
++ int inode_chunk)
++{
++ int j;
++
++ for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
++ if (yaffs_check_chunk_bit
++ (dev, the_chunk / dev->param.chunks_per_block,
++ the_chunk % dev->param.chunks_per_block)) {
++
++ if (dev->chunk_grp_size == 1)
++ return the_chunk;
++ else {
++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++ tags);
++ if (yaffs_tags_match(tags, obj_id, inode_chunk)) {
++ /* found it; */
++ return the_chunk;
++ }
++ }
++ }
++ the_chunk++;
++ }
++ return -1;
++}
++
++static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
++{
++ struct yaffs_block_info *the_block;
++ unsigned block_no;
++
++ T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
++
++ block_no = chunk / dev->param.chunks_per_block;
++ the_block = yaffs_get_block_info(dev, block_no);
++ if (the_block) {
++ the_block->soft_del_pages++;
++ dev->n_free_chunks++;
++ yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
++ }
++}
++
++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
++ * All soft deleting does is increment the block's softdelete count and pulls the chunk out
++ * of the tnode.
++ * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
++ */
++
++static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
++ u32 level, int chunk_offset)
++{
++ int i;
++ int the_chunk;
++ int all_done = 1;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (tn) {
++ if (level > 0) {
++
++ for (i = YAFFS_NTNODES_INTERNAL - 1; all_done && i >= 0;
++ i--) {
++ if (tn->internal[i]) {
++ all_done =
++ yaffs_soft_del_worker(in,
++ tn->internal
++ [i],
++ level - 1,
++ (chunk_offset
++ <<
++ YAFFS_TNODES_INTERNAL_BITS)
++ + i);
++ if (all_done) {
++ yaffs_free_tnode(dev,
++ tn->internal
++ [i]);
++ tn->internal[i] = NULL;
++ } else {
++ /* Hoosterman... how could this happen? */
++ }
++ }
++ }
++ return (all_done) ? 1 : 0;
++ } else if (level == 0) {
++
++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
++ the_chunk = yaffs_get_group_base(dev, tn, i);
++ if (the_chunk) {
++ /* Note this does not find the real chunk, only the chunk group.
++ * We make an assumption that a chunk group is not larger than
++ * a block.
++ */
++ yaffs_soft_del_chunk(dev, the_chunk);
++ yaffs_load_tnode_0(dev, tn, i, 0);
++ }
++
++ }
++ return 1;
++
++ }
++
++ }
++
++ return 1;
++
++}
++
++static void yaffs_soft_del_file(struct yaffs_obj *obj)
++{
++ if (obj->deleted &&
++ obj->variant_type == YAFFS_OBJECT_TYPE_FILE && !obj->soft_del) {
++ if (obj->n_data_chunks <= 0) {
++ /* Empty file with no duplicate object headers, just delete it immediately */
++ yaffs_free_tnode(obj->my_dev,
++ obj->variant.file_variant.top);
++ obj->variant.file_variant.top = NULL;
++ T(YAFFS_TRACE_TRACING,
++ (TSTR("yaffs: Deleting empty file %d" TENDSTR),
++ obj->obj_id));
++ yaffs_generic_obj_del(obj);
++ } else {
++ yaffs_soft_del_worker(obj,
++ obj->variant.file_variant.top,
++ obj->variant.
++ file_variant.top_level, 0);
++ obj->soft_del = 1;
++ }
++ }
++}
++
++/* Pruning removes any part of the file structure tree that is beyond the
++ * bounds of the file (ie that does not point to chunks).
++ *
++ * A file should only get pruned when its size is reduced.
++ *
++ * Before pruning, the chunks must be pulled from the tree and the
++ * level 0 tnode entries must be zeroed out.
++ * Could also use this for file deletion, but that's probably better handled
++ * by a special case.
++ *
++ * This function is recursive. For levels > 0 the function is called again on
++ * any sub-tree. For level == 0 we just check if the sub-tree has data.
++ * If there is no data in a subtree then it is pruned.
++ */
++
++static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
++ struct yaffs_tnode *tn, u32 level,
++ int del0)
++{
++ int i;
++ int has_data;
++
++ if (tn) {
++ has_data = 0;
++
++ if (level > 0) {
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i]) {
++ tn->internal[i] =
++ yaffs_prune_worker(dev,
++ tn->internal[i],
++ level - 1,
++ (i ==
++ 0) ? del0 : 1);
++ }
++
++ if (tn->internal[i])
++ has_data++;
++ }
++ } else {
++ int tnode_size_u32 = dev->tnode_size / sizeof(u32);
++ u32 *map = (u32 *) tn;
++
++ for (i = 0; !has_data && i < tnode_size_u32; i++) {
++ if (map[i])
++ has_data++;
++ }
++ }
++
++ if (has_data == 0 && del0) {
++ /* Free and return NULL */
++
++ yaffs_free_tnode(dev, tn);
++ tn = NULL;
++ }
++
++ }
++
++ return tn;
++
++}
++
++static int yaffs_prune_tree(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct)
++{
++ int i;
++ int has_data;
++ int done = 0;
++ struct yaffs_tnode *tn;
++
++ if (file_struct->top_level > 0) {
++ file_struct->top =
++ yaffs_prune_worker(dev, file_struct->top,
++ file_struct->top_level, 0);
++
++ /* Now we have a tree with all the non-zero branches NULL but the height
++ * is the same as it was.
++ * Let's see if we can trim internal tnodes to shorten the tree.
++ * We can do this if only the 0th element in the tnode is in use
++ * (ie all the non-zero are NULL)
++ */
++
++ while (file_struct->top_level && !done) {
++ tn = file_struct->top;
++
++ has_data = 0;
++ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i])
++ has_data++;
++ }
++
++ if (!has_data) {
++ file_struct->top = tn->internal[0];
++ file_struct->top_level--;
++ yaffs_free_tnode(dev, tn);
++ } else {
++ done = 1;
++ }
++ }
++ }
++
++ return YAFFS_OK;
++}
++
++/*-------------------- End of File Structure functions.-------------------*/
++
++/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
++static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
++
++ if (obj) {
++ dev->n_obj++;
++
++ /* Now sweeten it up... */
++
++ memset(obj, 0, sizeof(struct yaffs_obj));
++ obj->being_created = 1;
++
++ obj->my_dev = dev;
++ obj->hdr_chunk = 0;
++ obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
++ INIT_LIST_HEAD(&(obj->hard_links));
++ INIT_LIST_HEAD(&(obj->hash_link));
++ INIT_LIST_HEAD(&obj->siblings);
++
++ /* Now make the directory sane */
++ if (dev->root_dir) {
++ obj->parent = dev->root_dir;
++ list_add(&(obj->siblings),
++ &dev->root_dir->variant.dir_variant.children);
++ }
++
++ /* Add it to the lost and found directory.
++ * NB Can't put root or lost-n-found in lost-n-found so
++ * check if lost-n-found exists first
++ */
++ if (dev->lost_n_found)
++ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
++
++ obj->being_created = 0;
++ }
++
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++
++ return obj;
++}
++
++static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
++ int number, u32 mode)
++{
++
++ struct yaffs_obj *obj =
++ yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
++ if (obj) {
++ obj->fake = 1; /* it is fake so it might have no NAND presence... */
++ obj->rename_allowed = 0; /* ... and we're not allowed to rename it... */
++ obj->unlink_allowed = 0; /* ... or unlink it */
++ obj->deleted = 0;
++ obj->unlinked = 0;
++ obj->yst_mode = mode;
++ obj->my_dev = dev;
++ obj->hdr_chunk = 0; /* Not a valid chunk. */
++ }
++
++ return obj;
++
++}
++
++static void yaffs_unhash_obj(struct yaffs_obj *obj)
++{
++ int bucket;
++ struct yaffs_dev *dev = obj->my_dev;
++
++ /* If it is still linked into the bucket list, free from the list */
++ if (!list_empty(&obj->hash_link)) {
++ list_del_init(&obj->hash_link);
++ bucket = yaffs_hash_fn(obj->obj_id);
++ dev->obj_bucket[bucket].count--;
++ }
++}
++
++/* FreeObject frees up a Object and puts it back on the free list */
++static void yaffs_free_obj(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("FreeObject %p inode %p" TENDSTR), obj, obj->my_inode));
++
++ if (!obj)
++ YBUG();
++ if (obj->parent)
++ YBUG();
++ if (!list_empty(&obj->siblings))
++ YBUG();
++
++ if (obj->my_inode) {
++ /* We're still hooked up to a cached inode.
++ * Don't delete now, but mark for later deletion
++ */
++ obj->defered_free = 1;
++ return;
++ }
++
++ yaffs_unhash_obj(obj);
++
++ yaffs_free_raw_obj(dev, obj);
++ dev->n_obj--;
++ dev->checkpoint_blocks_required = 0; /* force recalculation */
++}
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj)
++{
++ if (obj->defered_free)
++ yaffs_free_obj(obj);
++}
++
++static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
++{
++ int i;
++
++ dev->n_obj = 0;
++ dev->n_tnodes = 0;
++
++ yaffs_init_raw_tnodes_and_objs(dev);
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ INIT_LIST_HEAD(&dev->obj_bucket[i].list);
++ dev->obj_bucket[i].count = 0;
++ }
++}
++
++static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
++{
++ int i;
++ int l = 999;
++ int lowest = 999999;
++
++ /* Search for the shortest list or one that
++ * isn't too long.
++ */
++
++ for (i = 0; i < 10 && lowest > 4; i++) {
++ dev->bucket_finder++;
++ dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
++ if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
++ lowest = dev->obj_bucket[dev->bucket_finder].count;
++ l = dev->bucket_finder;
++ }
++
++ }
++
++ return l;
++}
++
++static int yaffs_new_obj_id(struct yaffs_dev *dev)
++{
++ int bucket = yaffs_find_nice_bucket(dev);
++
++ /* Now find an object value that has not already been taken
++ * by scanning the list.
++ */
++
++ int found = 0;
++ struct list_head *i;
++
++ u32 n = (u32) bucket;
++
++ /* yaffs_check_obj_hash_sane(); */
++
++ while (!found) {
++ found = 1;
++ n += YAFFS_NOBJECT_BUCKETS;
++ if (1 || dev->obj_bucket[bucket].count > 0) {
++ list_for_each(i, &dev->obj_bucket[bucket].list) {
++ /* If there is already one in the list */
++ if (i && list_entry(i, struct yaffs_obj,
++ hash_link)->obj_id == n) {
++ found = 0;
++ }
++ }
++ }
++ }
++
++ return n;
++}
++
++static void yaffs_hash_obj(struct yaffs_obj *in)
++{
++ int bucket = yaffs_hash_fn(in->obj_id);
++ struct yaffs_dev *dev = in->my_dev;
++
++ list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
++ dev->obj_bucket[bucket].count++;
++}
++
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
++{
++ int bucket = yaffs_hash_fn(number);
++ struct list_head *i;
++ struct yaffs_obj *in;
++
++ list_for_each(i, &dev->obj_bucket[bucket].list) {
++ /* Look if it is in the list */
++ if (i) {
++ in = list_entry(i, struct yaffs_obj, hash_link);
++ if (in->obj_id == number) {
++
++ /* Don't tell the VFS about this one if it is defered free */
++ if (in->defered_free)
++ return NULL;
++
++ return in;
++ }
++ }
++ }
++
++ return NULL;
++}
++
++struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
++ enum yaffs_obj_type type)
++{
++ struct yaffs_obj *the_obj = NULL;
++ struct yaffs_tnode *tn = NULL;
++
++ if (number < 0)
++ number = yaffs_new_obj_id(dev);
++
++ if (type == YAFFS_OBJECT_TYPE_FILE) {
++ tn = yaffs_get_tnode(dev);
++ if (!tn)
++ return NULL;
++ }
++
++ the_obj = yaffs_alloc_empty_obj(dev);
++ if (!the_obj) {
++ if (tn)
++ yaffs_free_tnode(dev, tn);
++ return NULL;
++ }
++
++ if (the_obj) {
++ the_obj->fake = 0;
++ the_obj->rename_allowed = 1;
++ the_obj->unlink_allowed = 1;
++ the_obj->obj_id = number;
++ yaffs_hash_obj(the_obj);
++ the_obj->variant_type = type;
++ yaffs_load_current_time(the_obj, 1, 1);
++
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ the_obj->variant.file_variant.file_size = 0;
++ the_obj->variant.file_variant.scanned_size = 0;
++ the_obj->variant.file_variant.shrink_size = ~0; /* max */
++ the_obj->variant.file_variant.top_level = 0;
++ the_obj->variant.file_variant.top = tn;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
++ INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* No action required */
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* todo this should not happen */
++ break;
++ }
++ }
++
++ return the_obj;
++}
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++ int number,
++ enum yaffs_obj_type type)
++{
++ struct yaffs_obj *the_obj = NULL;
++
++ if (number > 0)
++ the_obj = yaffs_find_by_number(dev, number);
++
++ if (!the_obj)
++ the_obj = yaffs_new_obj(dev, number, type);
++
++ return the_obj;
++
++}
++
++YCHAR *yaffs_clone_str(const YCHAR * str)
++{
++ YCHAR *new_str = NULL;
++ int len;
++
++ if (!str)
++ str = _Y("");
++
++ len = yaffs_strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
++ new_str = YMALLOC((len + 1) * sizeof(YCHAR));
++ if (new_str) {
++ yaffs_strncpy(new_str, str, len);
++ new_str[len] = 0;
++ }
++ return new_str;
++
++}
++
++/*
++ * Mknod (create) a new object.
++ * equiv_obj only has meaning for a hard link;
++ * alias_str only has meaning for a symlink.
++ * rdev only has meaning for devices (a subset of special objects)
++ */
++
++static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
++ struct yaffs_obj *parent,
++ const YCHAR * name,
++ u32 mode,
++ u32 uid,
++ u32 gid,
++ struct yaffs_obj *equiv_obj,
++ const YCHAR * alias_str, u32 rdev)
++{
++ struct yaffs_obj *in;
++ YCHAR *str = NULL;
++
++ struct yaffs_dev *dev = parent->my_dev;
++
++ /* Check if the entry exists. If it does then fail the call since we don't want a dup. */
++ if (yaffs_find_by_name(parent, name))
++ return NULL;
++
++ if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ str = yaffs_clone_str(alias_str);
++ if (!str)
++ return NULL;
++ }
++
++ in = yaffs_new_obj(dev, -1, type);
++
++ if (!in) {
++ if (str)
++ YFREE(str);
++ return NULL;
++ }
++
++ if (in) {
++ in->hdr_chunk = 0;
++ in->valid = 1;
++ in->variant_type = type;
++
++ in->yst_mode = mode;
++
++ yaffs_attribs_init(in, gid, uid, rdev);
++
++ in->n_data_chunks = 0;
++
++ yaffs_set_obj_name(in, name);
++ in->dirty = 1;
++
++ yaffs_add_obj_to_dir(parent, in);
++
++ in->my_dev = parent->my_dev;
++
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symlink_variant.alias = str;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.hardlink_variant.equiv_obj = equiv_obj;
++ in->variant.hardlink_variant.equiv_id =
++ equiv_obj->obj_id;
++ list_add(&in->hard_links, &equiv_obj->hard_links);
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* do nothing */
++ break;
++ }
++
++ if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
++ /* Could not create the object header, fail the creation */
++ yaffs_del_obj(in);
++ in = NULL;
++ }
++
++ yaffs_update_parent(parent);
++ }
++
++ return in;
++}
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++ const YCHAR * name, u32 mode, u32 uid,
++ u32 gid)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
++ uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR * name,
++ u32 mode, u32 uid, u32 gid)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
++ mode, uid, gid, NULL, NULL, 0);
++}
++
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++ const YCHAR * name, u32 mode, u32 uid,
++ u32 gid, u32 rdev)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
++ uid, gid, NULL, NULL, rdev);
++}
++
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++ const YCHAR * name, u32 mode, u32 uid,
++ u32 gid, const YCHAR * alias)
++{
++ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
++ uid, gid, NULL, alias, 0);
++}
++
++/* yaffs_link_obj returns the object id of the equivalent object.*/
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
++ struct yaffs_obj *equiv_obj)
++{
++ /* Get the real object in case we were fed a hard link as an equivalent object */
++ equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
++
++ if (yaffs_create_obj
++ (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
++ equiv_obj, NULL, 0)) {
++ return equiv_obj;
++ } else {
++ return NULL;
++ }
++
++}
++
++static int yaffs_change_obj_name(struct yaffs_obj *obj,
++ struct yaffs_obj *new_dir,
++ const YCHAR * new_name, int force, int shadows)
++{
++ int unlink_op;
++ int del_op;
++
++ struct yaffs_obj *existing_target;
++
++ if (new_dir == NULL)
++ new_dir = obj->parent; /* use the old directory */
++
++ if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("tragedy: yaffs_change_obj_name: new_dir is not a directory"
++ TENDSTR)));
++ YBUG();
++ }
++
++ /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
++ if (obj->my_dev->param.is_yaffs2)
++ unlink_op = (new_dir == obj->my_dev->unlinked_dir);
++ else
++ unlink_op = (new_dir == obj->my_dev->unlinked_dir
++ && obj->variant_type == YAFFS_OBJECT_TYPE_FILE);
++
++ del_op = (new_dir == obj->my_dev->del_dir);
++
++ existing_target = yaffs_find_by_name(new_dir, new_name);
++
++ /* If the object is a file going into the unlinked directory,
++ * then it is OK to just stuff it in since duplicate names are allowed.
++ * else only proceed if the new name does not exist and if we're putting
++ * it into a directory.
++ */
++ if ((unlink_op ||
++ del_op ||
++ force ||
++ (shadows > 0) ||
++ !existing_target) &&
++ new_dir->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_set_obj_name(obj, new_name);
++ obj->dirty = 1;
++
++ yaffs_add_obj_to_dir(new_dir, obj);
++
++ if (unlink_op)
++ obj->unlinked = 1;
++
++ /* If it is a deletion then we mark it as a shrink for gc purposes. */
++ if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >=
++ 0)
++ return YAFFS_OK;
++ }
++
++ return YAFFS_FAIL;
++}
++
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
++ struct yaffs_obj *new_dir, const YCHAR * new_name)
++{
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_obj *existing_target = NULL;
++ int force = 0;
++ int result;
++ struct yaffs_dev *dev;
++
++ if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++ YBUG();
++ if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++ YBUG();
++
++ dev = old_dir->my_dev;
++
++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
++ /* Special case for case insemsitive systems.
++ * While look-up is case insensitive, the name isn't.
++ * Therefore we might want to change x.txt to X.txt
++ */
++ if (old_dir == new_dir && yaffs_strcmp(old_name, new_name) == 0)
++ force = 1;
++#endif
++
++ if (yaffs_strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
++ YAFFS_MAX_NAME_LENGTH)
++ /* ENAMETOOLONG */
++ return YAFFS_FAIL;
++
++ obj = yaffs_find_by_name(old_dir, old_name);
++
++ if (obj && obj->rename_allowed) {
++
++ /* Now do the handling for an existing target, if there is one */
++
++ existing_target = yaffs_find_by_name(new_dir, new_name);
++ if (existing_target &&
++ existing_target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY
++ && !list_empty(&existing_target->variant.dir_variant.
++ children)) {
++ /* There is a target that is a non-empty directory, so we fail */
++ return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
++ } else if (existing_target && existing_target != obj) {
++ /* Nuke the target first, using shadowing,
++ * but only if it isn't the same object.
++ *
++ * Note we must disable gc otherwise it can mess up the shadowing.
++ *
++ */
++ dev->gc_disable = 1;
++ yaffs_change_obj_name(obj, new_dir, new_name, force,
++ existing_target->obj_id);
++ existing_target->is_shadowed = 1;
++ yaffs_unlink_obj(existing_target);
++ dev->gc_disable = 0;
++ }
++
++ result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
++
++ yaffs_update_parent(old_dir);
++ if (new_dir != old_dir)
++ yaffs_update_parent(new_dir);
++
++ return result;
++ }
++ return YAFFS_FAIL;
++}
++
++/*------------------------- Block Management and Page Allocation ----------------*/
++
++static int yaffs_init_blocks(struct yaffs_dev *dev)
++{
++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++ dev->block_info = NULL;
++ dev->chunk_bits = NULL;
++
++ dev->alloc_block = -1; /* force it to get a new one */
++
++ /* If the first allocation strategy fails, thry the alternate one */
++ dev->block_info = YMALLOC(n_blocks * sizeof(struct yaffs_block_info));
++ if (!dev->block_info) {
++ dev->block_info =
++ YMALLOC_ALT(n_blocks * sizeof(struct yaffs_block_info));
++ dev->block_info_alt = 1;
++ } else {
++ dev->block_info_alt = 0;
++ }
++
++ if (dev->block_info) {
++ /* Set up dynamic blockinfo stuff. */
++ dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; /* round up bytes */
++ dev->chunk_bits = YMALLOC(dev->chunk_bit_stride * n_blocks);
++ if (!dev->chunk_bits) {
++ dev->chunk_bits =
++ YMALLOC_ALT(dev->chunk_bit_stride * n_blocks);
++ dev->chunk_bits_alt = 1;
++ } else {
++ dev->chunk_bits_alt = 0;
++ }
++ }
++
++ if (dev->block_info && dev->chunk_bits) {
++ memset(dev->block_info, 0,
++ n_blocks * sizeof(struct yaffs_block_info));
++ memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
++ return YAFFS_OK;
++ }
++
++ return YAFFS_FAIL;
++}
++
++static void yaffs_deinit_blocks(struct yaffs_dev *dev)
++{
++ if (dev->block_info_alt && dev->block_info)
++ YFREE_ALT(dev->block_info);
++ else if (dev->block_info)
++ YFREE(dev->block_info);
++
++ dev->block_info_alt = 0;
++
++ dev->block_info = NULL;
++
++ if (dev->chunk_bits_alt && dev->chunk_bits)
++ YFREE_ALT(dev->chunk_bits);
++ else if (dev->chunk_bits)
++ YFREE(dev->chunk_bits);
++ dev->chunk_bits_alt = 0;
++ dev->chunk_bits = NULL;
++}
++
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
++{
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
++
++ int erased_ok = 0;
++
++ /* If the block is still healthy erase it and mark as clean.
++ * If the block has had a data failure, then retire it.
++ */
++
++ T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
++ (TSTR("yaffs_block_became_dirty block %d state %d %s" TENDSTR),
++ block_no, bi->block_state,
++ (bi->needs_retiring) ? "needs retiring" : ""));
++
++ yaffs2_clear_oldest_dirty_seq(dev, bi);
++
++ bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
++
++ /* If this is the block being garbage collected then stop gc'ing this block */
++ if (block_no == dev->gc_block)
++ dev->gc_block = 0;
++
++ /* If this block is currently the best candidate for gc then drop as a candidate */
++ if (block_no == dev->gc_dirtiest) {
++ dev->gc_dirtiest = 0;
++ dev->gc_pages_in_use = 0;
++ }
++
++ if (!bi->needs_retiring) {
++ yaffs2_checkpt_invalidate(dev);
++ erased_ok = yaffs_erase_block(dev, block_no);
++ if (!erased_ok) {
++ dev->n_erase_failures++;
++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("**>> Erasure failed %d" TENDSTR), block_no));
++ }
++ }
++
++ if (erased_ok &&
++ ((yaffs_trace_mask & YAFFS_TRACE_ERASE)
++ || !yaffs_skip_verification(dev))) {
++ int i;
++ for (i = 0; i < dev->param.chunks_per_block; i++) {
++ if (!yaffs_check_chunk_erased
++ (dev, block_no * dev->param.chunks_per_block + i)) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ (">>Block %d erasure supposedly OK, but chunk %d not erased"
++ TENDSTR), block_no, i));
++ }
++ }
++ }
++
++ if (erased_ok) {
++ /* Clean it up... */
++ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++ bi->seq_number = 0;
++ dev->n_erased_blocks++;
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++ bi->has_shrink_hdr = 0;
++ bi->skip_erased_check = 1; /* This is clean, so no need to check */
++ bi->gc_prioritise = 0;
++ yaffs_clear_chunk_bits(dev, block_no);
++
++ T(YAFFS_TRACE_ERASE,
++ (TSTR("Erased block %d" TENDSTR), block_no));
++ } else {
++ dev->n_free_chunks -= dev->param.chunks_per_block; /* We lost a block of free space */
++
++ yaffs_retire_block(dev, block_no);
++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("**>> Block %d retired" TENDSTR), block_no));
++ }
++}
++
++static int yaffs_find_alloc_block(struct yaffs_dev *dev)
++{
++ int i;
++
++ struct yaffs_block_info *bi;
++
++ if (dev->n_erased_blocks < 1) {
++ /* Hoosterman we've got a problem.
++ * Can't get space to gc
++ */
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
++
++ return -1;
++ }
++
++ /* Find an empty block. */
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ dev->alloc_block_finder++;
++ if (dev->alloc_block_finder < dev->internal_start_block
++ || dev->alloc_block_finder > dev->internal_end_block) {
++ dev->alloc_block_finder = dev->internal_start_block;
++ }
++
++ bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++ bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->seq_number++;
++ bi->seq_number = dev->seq_number;
++ dev->n_erased_blocks--;
++ T(YAFFS_TRACE_ALLOCATE,
++ (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
++ dev->alloc_block_finder, dev->seq_number,
++ dev->n_erased_blocks));
++ return dev->alloc_block_finder;
++ }
++ }
++
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("yaffs tragedy: no more erased blocks, but there should have been %d"
++ TENDSTR), dev->n_erased_blocks));
++
++ return -1;
++}
++
++/*
++ * Check if there's space to allocate...
++ * Thinks.... do we need top make this ths same as yaffs_get_free_chunks()?
++ */
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
++{
++ int reserved_chunks;
++ int reserved_blocks = dev->param.n_reserved_blocks;
++ int checkpt_blocks;
++
++ checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
++
++ reserved_chunks =
++ ((reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block);
++
++ return (dev->n_free_chunks > (reserved_chunks + n_chunks));
++}
++
++static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
++ struct yaffs_block_info **block_ptr)
++{
++ int ret_val;
++ struct yaffs_block_info *bi;
++
++ if (dev->alloc_block < 0) {
++ /* Get next block to allocate off */
++ dev->alloc_block = yaffs_find_alloc_block(dev);
++ dev->alloc_page = 0;
++ }
++
++ if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
++ /* Not enough space to allocate unless we're allowed to use the reserve. */
++ return -1;
++ }
++
++ if (dev->n_erased_blocks < dev->param.n_reserved_blocks
++ && dev->alloc_page == 0) {
++ T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
++ }
++
++ /* Next page please.... */
++ if (dev->alloc_block >= 0) {
++ bi = yaffs_get_block_info(dev, dev->alloc_block);
++
++ ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
++ dev->alloc_page;
++ bi->pages_in_use++;
++ yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
++
++ dev->alloc_page++;
++
++ dev->n_free_chunks--;
++
++ /* If the block is full set the state to full */
++ if (dev->alloc_page >= dev->param.chunks_per_block) {
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++
++ if (block_ptr)
++ *block_ptr = bi;
++
++ return ret_val;
++ }
++
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
++
++ return -1;
++}
++
++static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
++{
++ int n;
++
++ n = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ if (dev->alloc_block > 0)
++ n += (dev->param.chunks_per_block - dev->alloc_page);
++
++ return n;
++
++}
++
++/*
++ * yaffs_skip_rest_of_block() skips over the rest of the allocation block
++ * if we don't want to write to it.
++ */
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
++{
++ if (dev->alloc_block > 0) {
++ struct yaffs_block_info *bi =
++ yaffs_get_block_info(dev, dev->alloc_block);
++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++ }
++}
++
++static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
++{
++ int old_chunk;
++ int new_chunk;
++ int mark_flash;
++ int ret_val = YAFFS_OK;
++ int i;
++ int is_checkpt_block;
++ int matching_chunk;
++ int max_copies;
++
++ int chunks_before = yaffs_get_erased_chunks(dev);
++ int chunks_after;
++
++ struct yaffs_ext_tags tags;
++
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
++
++ struct yaffs_obj *object;
++
++ is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
++
++ T(YAFFS_TRACE_TRACING,
++ (TSTR
++ ("Collecting block %d, in use %d, shrink %d, whole_block %d"
++ TENDSTR), block, bi->pages_in_use, bi->has_shrink_hdr,
++ whole_block));
++
++ /*yaffs_verify_free_chunks(dev); */
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
++ bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
++
++ bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
++
++ dev->gc_disable = 1;
++
++ if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
++ T(YAFFS_TRACE_TRACING,
++ (TSTR
++ ("Collecting block %d that has no chunks in use" TENDSTR),
++ block));
++ yaffs_block_became_dirty(dev, block);
++ } else {
++
++ u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
++
++ yaffs_verify_blk(dev, bi, block);
++
++ max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
++ old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
++
++ for ( /* init already done */ ;
++ ret_val == YAFFS_OK &&
++ dev->gc_chunk < dev->param.chunks_per_block &&
++ (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
++ max_copies > 0; dev->gc_chunk++, old_chunk++) {
++ if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
++
++ /* This page is in use and might need to be copied off */
++
++ max_copies--;
++
++ mark_flash = 1;
++
++ yaffs_init_tags(&tags);
++
++ yaffs_rd_chunk_tags_nand(dev, old_chunk,
++ buffer, &tags);
++
++ object = yaffs_find_by_number(dev, tags.obj_id);
++
++ T(YAFFS_TRACE_GC_DETAIL,
++ (TSTR
++ ("Collecting chunk in block %d, %d %d %d "
++ TENDSTR), dev->gc_chunk, tags.obj_id,
++ tags.chunk_id, tags.n_bytes));
++
++ if (object && !yaffs_skip_verification(dev)) {
++ if (tags.chunk_id == 0)
++ matching_chunk =
++ object->hdr_chunk;
++ else if (object->soft_del)
++ matching_chunk = old_chunk; /* Defeat the test */
++ else
++ matching_chunk =
++ yaffs_find_chunk_in_file
++ (object, tags.chunk_id,
++ NULL);
++
++ if (old_chunk != matching_chunk)
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("gc: page in gc mismatch: %d %d %d %d"
++ TENDSTR), old_chunk,
++ matching_chunk, tags.obj_id,
++ tags.chunk_id));
++
++ }
++
++ if (!object) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("page %d in gc has no object: %d %d %d "
++ TENDSTR), old_chunk,
++ tags.obj_id, tags.chunk_id,
++ tags.n_bytes));
++ }
++
++ if (object &&
++ object->deleted &&
++ object->soft_del && tags.chunk_id != 0) {
++ /* Data chunk in a soft deleted file, throw it away
++ * It's a soft deleted data chunk,
++ * No need to copy this, just forget about it and
++ * fix up the object.
++ */
++
++ /* Free chunks already includes softdeleted chunks.
++ * How ever this chunk is going to soon be really deleted
++ * which will increment free chunks.
++ * We have to decrement free chunks so this works out properly.
++ */
++ dev->n_free_chunks--;
++ bi->soft_del_pages--;
++
++ object->n_data_chunks--;
++
++ if (object->n_data_chunks <= 0) {
++ /* remeber to clean up the object */
++ dev->gc_cleanup_list[dev->
++ n_clean_ups]
++ = tags.obj_id;
++ dev->n_clean_ups++;
++ }
++ mark_flash = 0;
++ } else if (0) {
++ /* Todo object && object->deleted && object->n_data_chunks == 0 */
++ /* Deleted object header with no data chunks.
++ * Can be discarded and the file deleted.
++ */
++ object->hdr_chunk = 0;
++ yaffs_free_tnode(object->my_dev,
++ object->
++ variant.file_variant.
++ top);
++ object->variant.file_variant.top = NULL;
++ yaffs_generic_obj_del(object);
++
++ } else if (object) {
++ /* It's either a data chunk in a live file or
++ * an ObjectHeader, so we're interested in it.
++ * NB Need to keep the ObjectHeaders of deleted files
++ * until the whole file has been deleted off
++ */
++ tags.serial_number++;
++
++ dev->n_gc_copies++;
++
++ if (tags.chunk_id == 0) {
++ /* It is an object Id,
++ * We need to nuke the shrinkheader flags first
++ * Also need to clean up shadowing.
++ * We no longer want the shrink_header flag since its work is done
++ * and if it is left in place it will mess up scanning.
++ */
++
++ struct yaffs_obj_hdr *oh;
++ oh = (struct yaffs_obj_hdr *)
++ buffer;
++
++ oh->is_shrink = 0;
++ tags.extra_is_shrink = 0;
++
++ oh->shadows_obj = 0;
++ oh->inband_shadowed_obj_id = 0;
++ tags.extra_shadows = 0;
++
++ /* Update file size */
++ if (object->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE) {
++ oh->file_size =
++ object->variant.
++ file_variant.
++ file_size;
++ tags.extra_length =
++ oh->file_size;
++ }
++
++ yaffs_verify_oh(object, oh,
++ &tags, 1);
++ new_chunk =
++ yaffs_write_new_chunk(dev,
++ (u8 *)
++ oh,
++ &tags,
++ 1);
++ } else {
++ new_chunk =
++ yaffs_write_new_chunk(dev,
++ buffer,
++ &tags,
++ 1);
++ }
++
++ if (new_chunk < 0) {
++ ret_val = YAFFS_FAIL;
++ } else {
++
++ /* Ok, now fix up the Tnodes etc. */
++
++ if (tags.chunk_id == 0) {
++ /* It's a header */
++ object->hdr_chunk =
++ new_chunk;
++ object->serial =
++ tags.serial_number;
++ } else {
++ /* It's a data chunk */
++ int ok;
++ ok = yaffs_put_chunk_in_file(object, tags.chunk_id, new_chunk, 0);
++ }
++ }
++ }
++
++ if (ret_val == YAFFS_OK)
++ yaffs_chunk_del(dev, old_chunk,
++ mark_flash, __LINE__);
++
++ }
++ }
++
++ yaffs_release_temp_buffer(dev, buffer, __LINE__);
++
++ }
++
++ yaffs_verify_collected_blk(dev, bi, block);
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++ /*
++ * The gc did not complete. Set block state back to FULL
++ * because checkpointing does not restore gc.
++ */
++ bi->block_state = YAFFS_BLOCK_STATE_FULL;
++ } else {
++ /* The gc completed. */
++ /* Do any required cleanups */
++ for (i = 0; i < dev->n_clean_ups; i++) {
++ /* Time to delete the file too */
++ object =
++ yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
++ if (object) {
++ yaffs_free_tnode(dev,
++ object->variant.
++ file_variant.top);
++ object->variant.file_variant.top = NULL;
++ T(YAFFS_TRACE_GC,
++ (TSTR
++ ("yaffs: About to finally delete object %d"
++ TENDSTR), object->obj_id));
++ yaffs_generic_obj_del(object);
++ object->my_dev->n_deleted_files--;
++ }
++
++ }
++
++ chunks_after = yaffs_get_erased_chunks(dev);
++ if (chunks_before >= chunks_after) {
++ T(YAFFS_TRACE_GC,
++ (TSTR
++ ("gc did not increase free chunks before %d after %d"
++ TENDSTR), chunks_before, chunks_after));
++ }
++ dev->gc_block = 0;
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++
++ dev->gc_disable = 0;
++
++ return ret_val;
++}
++
++/*
++ * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough)
++ * for garbage collection.
++ */
++
++static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
++ int aggressive, int background)
++{
++ int i;
++ int iterations;
++ unsigned selected = 0;
++ int prioritised = 0;
++ int prioritised_exist = 0;
++ struct yaffs_block_info *bi;
++ int threshold;
++
++ /* First let's see if we need to grab a prioritised block */
++ if (dev->has_pending_prioritised_gc && !aggressive) {
++ dev->gc_dirtiest = 0;
++ bi = dev->block_info;
++ for (i = dev->internal_start_block;
++ i <= dev->internal_end_block && !selected; i++) {
++
++ if (bi->gc_prioritise) {
++ prioritised_exist = 1;
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++ yaffs_block_ok_for_gc(dev, bi)) {
++ selected = i;
++ prioritised = 1;
++ }
++ }
++ bi++;
++ }
++
++ /*
++ * If there is a prioritised block and none was selected then
++ * this happened because there is at least one old dirty block gumming
++ * up the works. Let's gc the oldest dirty block.
++ */
++
++ if (prioritised_exist &&
++ !selected && dev->oldest_dirty_block > 0)
++ selected = dev->oldest_dirty_block;
++
++ if (!prioritised_exist) /* None found, so we can clear this */
++ dev->has_pending_prioritised_gc = 0;
++ }
++
++ /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
++ * search harder.
++ * else (we're doing a leasurely gc), then we only bother to do this if the
++ * block has only a few pages in use.
++ */
++
++ if (!selected) {
++ int pages_used;
++ int n_blocks =
++ dev->internal_end_block - dev->internal_start_block + 1;
++ if (aggressive) {
++ threshold = dev->param.chunks_per_block;
++ iterations = n_blocks;
++ } else {
++ int max_threshold;
++
++ if (background)
++ max_threshold = dev->param.chunks_per_block / 2;
++ else
++ max_threshold = dev->param.chunks_per_block / 8;
++
++ if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++ max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++
++ threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
++ if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
++ threshold = YAFFS_GC_PASSIVE_THRESHOLD;
++ if (threshold > max_threshold)
++ threshold = max_threshold;
++
++ iterations = n_blocks / 16 + 1;
++ if (iterations > 100)
++ iterations = 100;
++ }
++
++ for (i = 0;
++ i < iterations &&
++ (dev->gc_dirtiest < 1 ||
++ dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH); i++) {
++ dev->gc_block_finder++;
++ if (dev->gc_block_finder < dev->internal_start_block ||
++ dev->gc_block_finder > dev->internal_end_block)
++ dev->gc_block_finder =
++ dev->internal_start_block;
++
++ bi = yaffs_get_block_info(dev, dev->gc_block_finder);
++
++ pages_used = bi->pages_in_use - bi->soft_del_pages;
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
++ pages_used < dev->param.chunks_per_block &&
++ (dev->gc_dirtiest < 1
++ || pages_used < dev->gc_pages_in_use)
++ && yaffs_block_ok_for_gc(dev, bi)) {
++ dev->gc_dirtiest = dev->gc_block_finder;
++ dev->gc_pages_in_use = pages_used;
++ }
++ }
++
++ if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
++ selected = dev->gc_dirtiest;
++ }
++
++ /*
++ * If nothing has been selected for a while, try selecting the oldest dirty
++ * because that's gumming up the works.
++ */
++
++ if (!selected && dev->param.is_yaffs2 &&
++ dev->gc_not_done >= (background ? 10 : 20)) {
++ yaffs2_find_oldest_dirty_seq(dev);
++ if (dev->oldest_dirty_block > 0) {
++ selected = dev->oldest_dirty_block;
++ dev->gc_dirtiest = selected;
++ dev->oldest_dirty_gc_count++;
++ bi = yaffs_get_block_info(dev, selected);
++ dev->gc_pages_in_use =
++ bi->pages_in_use - bi->soft_del_pages;
++ } else {
++ dev->gc_not_done = 0;
++ }
++ }
++
++ if (selected) {
++ T(YAFFS_TRACE_GC,
++ (TSTR
++ ("GC Selected block %d with %d free, prioritised:%d"
++ TENDSTR), selected,
++ dev->param.chunks_per_block - dev->gc_pages_in_use,
++ prioritised));
++
++ dev->n_gc_blocks++;
++ if (background)
++ dev->bg_gcs++;
++
++ dev->gc_dirtiest = 0;
++ dev->gc_pages_in_use = 0;
++ dev->gc_not_done = 0;
++ if (dev->refresh_skip > 0)
++ dev->refresh_skip--;
++ } else {
++ dev->gc_not_done++;
++ T(YAFFS_TRACE_GC,
++ (TSTR
++ ("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s"
++ TENDSTR), dev->gc_block_finder, dev->gc_not_done, threshold,
++ dev->gc_dirtiest, dev->gc_pages_in_use,
++ dev->oldest_dirty_block, background ? " bg" : ""));
++ }
++
++ return selected;
++}
++
++/* New garbage collector
++ * If we're very low on erased blocks then we do aggressive garbage collection
++ * otherwise we do "leasurely" garbage collection.
++ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
++ * Passive gc only inspects smaller areas and will only accept more dirty blocks.
++ *
++ * The idea is to help clear out space in a more spread-out manner.
++ * Dunno if it really does anything useful.
++ */
++static int yaffs_check_gc(struct yaffs_dev *dev, int background)
++{
++ int aggressive = 0;
++ int gc_ok = YAFFS_OK;
++ int max_tries = 0;
++ int min_erased;
++ int erased_chunks;
++ int checkpt_block_adjust;
++
++ if (dev->param.gc_control && (dev->param.gc_control(dev) & 1) == 0)
++ return YAFFS_OK;
++
++ if (dev->gc_disable) {
++ /* Bail out so we don't get recursive gc */
++ return YAFFS_OK;
++ }
++
++ /* This loop should pass the first time.
++ * We'll only see looping here if the collection does not increase space.
++ */
++
++ do {
++ max_tries++;
++
++ checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
++
++ min_erased =
++ dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
++ erased_chunks =
++ dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ /* If we need a block soon then do aggressive gc. */
++ if (dev->n_erased_blocks < min_erased)
++ aggressive = 1;
++ else {
++ if (!background
++ && erased_chunks > (dev->n_free_chunks / 4))
++ break;
++
++ if (dev->gc_skip > 20)
++ dev->gc_skip = 20;
++ if (erased_chunks < dev->n_free_chunks / 2 ||
++ dev->gc_skip < 1 || background)
++ aggressive = 0;
++ else {
++ dev->gc_skip--;
++ break;
++ }
++ }
++
++ dev->gc_skip = 5;
++
++ /* If we don't already have a block being gc'd then see if we should start another */
++
++ if (dev->gc_block < 1 && !aggressive) {
++ dev->gc_block = yaffs2_find_refresh_block(dev);
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++ if (dev->gc_block < 1) {
++ dev->gc_block =
++ yaffs_find_gc_block(dev, aggressive, background);
++ dev->gc_chunk = 0;
++ dev->n_clean_ups = 0;
++ }
++
++ if (dev->gc_block > 0) {
++ dev->all_gcs++;
++ if (!aggressive)
++ dev->passive_gc_count++;
++
++ T(YAFFS_TRACE_GC,
++ (TSTR
++ ("yaffs: GC n_erased_blocks %d aggressive %d"
++ TENDSTR), dev->n_erased_blocks, aggressive));
++
++ gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
++ }
++
++ if (dev->n_erased_blocks < (dev->param.n_reserved_blocks)
++ && dev->gc_block > 0) {
++ T(YAFFS_TRACE_GC,
++ (TSTR
++ ("yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d"
++ TENDSTR), dev->n_erased_blocks, max_tries,
++ dev->gc_block));
++ }
++ } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
++ (dev->gc_block > 0) && (max_tries < 2));
++
++ return aggressive ? gc_ok : YAFFS_OK;
++}
++
++/*
++ * yaffs_bg_gc()
++ * Garbage collects. Intended to be called from a background thread.
++ * Returns non-zero if at least half the free chunks are erased.
++ */
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
++{
++ int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR), urgency));
++
++ yaffs_check_gc(dev, 1);
++ return erased_chunks > dev->n_free_chunks / 2;
++}
++
++/*------------------------- TAGS --------------------------------*/
++
++static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
++ int chunk_obj)
++{
++ return (tags->chunk_id == chunk_obj &&
++ tags->obj_id == obj_id && !tags->is_deleted) ? 1 : 0;
++
++}
++
++/*-------------------- Data file manipulation -----------------*/
++
++static int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags)
++{
++ /*Get the Tnode, then get the level 0 offset chunk offset */
++ struct yaffs_tnode *tn;
++ int the_chunk = -1;
++ struct yaffs_ext_tags local_tags;
++ int ret_val = -1;
++
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &local_tags;
++ }
++
++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++ if (tn) {
++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ ret_val =
++ yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++ inode_chunk);
++ }
++ return ret_val;
++}
++
++static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
++ struct yaffs_ext_tags *tags)
++{
++ /* Get the Tnode, then get the level 0 offset chunk offset */
++ struct yaffs_tnode *tn;
++ int the_chunk = -1;
++ struct yaffs_ext_tags local_tags;
++
++ struct yaffs_dev *dev = in->my_dev;
++ int ret_val = -1;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &local_tags;
++ }
++
++ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
++
++ if (tn) {
++
++ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ ret_val =
++ yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
++ inode_chunk);
++
++ /* Delete the entry in the filestructure (if found) */
++ if (ret_val != -1)
++ yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
++ }
++
++ return ret_val;
++}
++
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ int nand_chunk, int in_scan)
++{
++ /* NB in_scan is zero unless scanning.
++ * For forward scanning, in_scan is > 0;
++ * for backward scanning in_scan is < 0
++ *
++ * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
++ */
++
++ struct yaffs_tnode *tn;
++ struct yaffs_dev *dev = in->my_dev;
++ int existing_cunk;
++ struct yaffs_ext_tags existing_tags;
++ struct yaffs_ext_tags new_tags;
++ unsigned existing_serial, new_serial;
++
++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
++ /* Just ignore an attempt at putting a chunk into a non-file during scanning
++ * If it is not during Scanning then something went wrong!
++ */
++ if (!in_scan) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy:attempt to put data chunk into a non-file"
++ TENDSTR)));
++ YBUG();
++ }
++
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ return YAFFS_OK;
++ }
++
++ tn = yaffs_add_find_tnode_0(dev,
++ &in->variant.file_variant,
++ inode_chunk, NULL);
++ if (!tn)
++ return YAFFS_FAIL;
++
++ if (!nand_chunk)
++ /* Dummy insert, bail now */
++ return YAFFS_OK;
++
++ existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
++
++ if (in_scan != 0) {
++ /* If we're scanning then we need to test for duplicates
++ * NB This does not need to be efficient since it should only ever
++ * happen when the power fails during a write, then only one
++ * chunk should ever be affected.
++ *
++ * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
++ * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
++ */
++
++ if (existing_cunk > 0) {
++ /* NB Right now existing chunk will not be real chunk_id if the chunk group size > 1
++ * thus we have to do a FindChunkInFile to get the real chunk id.
++ *
++ * We have a duplicate now we need to decide which one to use:
++ *
++ * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
++ * Forward scanning YAFFS2: The new one is what we use, dump the old one.
++ * YAFFS1: Get both sets of tags and compare serial numbers.
++ */
++
++ if (in_scan > 0) {
++ /* Only do this for forward scanning */
++ yaffs_rd_chunk_tags_nand(dev,
++ nand_chunk,
++ NULL, &new_tags);
++
++ /* Do a proper find */
++ existing_cunk =
++ yaffs_find_chunk_in_file(in, inode_chunk,
++ &existing_tags);
++ }
++
++ if (existing_cunk <= 0) {
++ /*Hoosterman - how did this happen? */
++
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy: existing chunk < 0 in scan"
++ TENDSTR)));
++
++ }
++
++ /* NB The deleted flags should be false, otherwise the chunks will
++ * not be loaded during a scan
++ */
++
++ if (in_scan > 0) {
++ new_serial = new_tags.serial_number;
++ existing_serial = existing_tags.serial_number;
++ }
++
++ if ((in_scan > 0) &&
++ (existing_cunk <= 0 ||
++ ((existing_serial + 1) & 3) == new_serial)) {
++ /* Forward scanning.
++ * Use new
++ * Delete the old one and drop through to update the tnode
++ */
++ yaffs_chunk_del(dev, existing_cunk, 1,
++ __LINE__);
++ } else {
++ /* Backward scanning or we want to use the existing one
++ * Use existing.
++ * Delete the new one and return early so that the tnode isn't changed
++ */
++ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++ return YAFFS_OK;
++ }
++ }
++
++ }
++
++ if (existing_cunk == 0)
++ in->n_data_chunks++;
++
++ yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
++
++ return YAFFS_OK;
++}
++
++static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
++{
++ int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
++
++ if (nand_chunk >= 0)
++ return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
++ buffer, NULL);
++ else {
++ T(YAFFS_TRACE_NANDACCESS,
++ (TSTR("Chunk %d not found zero instead" TENDSTR),
++ nand_chunk));
++ /* get sane (zero) data if you read a hole */
++ memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
++ return 0;
++ }
++
++}
++
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++ int lyn)
++{
++ int block;
++ int page;
++ struct yaffs_ext_tags tags;
++ struct yaffs_block_info *bi;
++
++ if (chunk_id <= 0)
++ return;
++
++ dev->n_deletions++;
++ block = chunk_id / dev->param.chunks_per_block;
++ page = chunk_id % dev->param.chunks_per_block;
++
++ if (!yaffs_check_chunk_bit(dev, block, page))
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Deleting invalid chunk %d" TENDSTR), chunk_id));
++
++ bi = yaffs_get_block_info(dev, block);
++
++ yaffs2_update_oldest_dirty_seq(dev, block, bi);
++
++ T(YAFFS_TRACE_DELETION,
++ (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunk_id));
++
++ if (!dev->param.is_yaffs2 && mark_flash &&
++ bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
++
++ yaffs_init_tags(&tags);
++
++ tags.is_deleted = 1;
++
++ yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
++ yaffs_handle_chunk_update(dev, chunk_id, &tags);
++ } else {
++ dev->n_unmarked_deletions++;
++ }
++
++ /* Pull out of the management area.
++ * If the whole block became dirty, this will kick off an erasure.
++ */
++ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
++ bi->block_state == YAFFS_BLOCK_STATE_FULL ||
++ bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
++ bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
++ dev->n_free_chunks++;
++
++ yaffs_clear_chunk_bit(dev, block, page);
++
++ bi->pages_in_use--;
++
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
++ bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
++ yaffs_block_became_dirty(dev, block);
++ }
++
++ }
++
++}
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++ const u8 * buffer, int n_bytes, int use_reserve)
++{
++ /* Find old chunk Need to do this to get serial number
++ * Write new one and patch into tree.
++ * Invalidate old tags.
++ */
++
++ int prev_chunk_id;
++ struct yaffs_ext_tags prev_tags;
++
++ int new_chunk_id;
++ struct yaffs_ext_tags new_tags;
++
++ struct yaffs_dev *dev = in->my_dev;
++
++ yaffs_check_gc(dev, 0);
++
++ /* Get the previous chunk at this location in the file if it exists.
++ * If it does not exist then put a zero into the tree. This creates
++ * the tnode now, rather than later when it is harder to clean up.
++ */
++ prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
++ if (prev_chunk_id < 1 &&
++ !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
++ return 0;
++
++ /* Set up new tags */
++ yaffs_init_tags(&new_tags);
++
++ new_tags.chunk_id = inode_chunk;
++ new_tags.obj_id = in->obj_id;
++ new_tags.serial_number =
++ (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
++ new_tags.n_bytes = n_bytes;
++
++ if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR),
++ n_bytes));
++ YBUG();
++ }
++
++ new_chunk_id =
++ yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
++
++ if (new_chunk_id > 0) {
++ yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
++
++ if (prev_chunk_id > 0)
++ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
++
++ yaffs_verify_file_sane(in);
++ }
++ return new_chunk_id;
++
++}
++
++/* UpdateObjectHeader updates the header on NAND for an object.
++ * If name is not NULL, then that new name is used.
++ */
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR * name, int force,
++ int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
++{
++
++ struct yaffs_block_info *bi;
++
++ struct yaffs_dev *dev = in->my_dev;
++
++ int prev_chunk_id;
++ int ret_val = 0;
++ int result = 0;
++
++ int new_chunk_id;
++ struct yaffs_ext_tags new_tags;
++ struct yaffs_ext_tags old_tags;
++ const YCHAR *alias = NULL;
++
++ u8 *buffer = NULL;
++ YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ struct yaffs_obj_hdr *oh = NULL;
++
++ yaffs_strcpy(old_name, _Y("silly old name"));
++
++ if (!in->fake || in == dev->root_dir || /* The root_dir should also be saved */
++ force || xmod) {
++
++ yaffs_check_gc(dev, 0);
++ yaffs_check_obj_details_loaded(in);
++
++ buffer = yaffs_get_temp_buffer(in->my_dev, __LINE__);
++ oh = (struct yaffs_obj_hdr *)buffer;
++
++ prev_chunk_id = in->hdr_chunk;
++
++ if (prev_chunk_id > 0) {
++ result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
++ buffer, &old_tags);
++
++ yaffs_verify_oh(in, oh, &old_tags, 0);
++
++ memcpy(old_name, oh->name, sizeof(oh->name));
++ memset(buffer, 0xFF, sizeof(struct yaffs_obj_hdr));
++ } else {
++ memset(buffer, 0xFF, dev->data_bytes_per_chunk);
++ }
++
++ oh->type = in->variant_type;
++ oh->yst_mode = in->yst_mode;
++ oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
++
++ yaffs_load_attribs_oh(oh, in);
++
++ if (in->parent)
++ oh->parent_obj_id = in->parent->obj_id;
++ else
++ oh->parent_obj_id = 0;
++
++ if (name && *name) {
++ memset(oh->name, 0, sizeof(oh->name));
++ yaffs_load_oh_from_name(dev, oh->name, name);
++ } else if (prev_chunk_id > 0) {
++ memcpy(oh->name, old_name, sizeof(oh->name));
++ } else {
++ memset(oh->name, 0, sizeof(oh->name));
++ }
++
++ oh->is_shrink = is_shrink;
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Should not happen */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ oh->file_size =
++ (oh->parent_obj_id == YAFFS_OBJECTID_DELETED
++ || oh->parent_obj_id ==
++ YAFFS_OBJECTID_UNLINKED) ? 0 : in->
++ variant.file_variant.file_size;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ oh->equiv_id = in->variant.hardlink_variant.equiv_id;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = in->variant.symlink_variant.alias;
++ if (!alias)
++ alias = _Y("no alias");
++ yaffs_strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
++ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
++ break;
++ }
++
++ /* process any xattrib modifications */
++ if (xmod)
++ yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
++
++ /* Tags */
++ yaffs_init_tags(&new_tags);
++ in->serial++;
++ new_tags.chunk_id = 0;
++ new_tags.obj_id = in->obj_id;
++ new_tags.serial_number = in->serial;
++
++ /* Add extra info for file header */
++
++ new_tags.extra_available = 1;
++ new_tags.extra_parent_id = oh->parent_obj_id;
++ new_tags.extra_length = oh->file_size;
++ new_tags.extra_is_shrink = oh->is_shrink;
++ new_tags.extra_equiv_id = oh->equiv_id;
++ new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
++ new_tags.extra_obj_type = in->variant_type;
++
++ yaffs_verify_oh(in, oh, &new_tags, 1);
++
++ /* Create new chunk in NAND */
++ new_chunk_id =
++ yaffs_write_new_chunk(dev, buffer, &new_tags,
++ (prev_chunk_id > 0) ? 1 : 0);
++
++ if (new_chunk_id >= 0) {
++
++ in->hdr_chunk = new_chunk_id;
++
++ if (prev_chunk_id > 0) {
++ yaffs_chunk_del(dev, prev_chunk_id, 1,
++ __LINE__);
++ }
++
++ if (!yaffs_obj_cache_dirty(in))
++ in->dirty = 0;
++
++ /* If this was a shrink, then mark the block that the chunk lives on */
++ if (is_shrink) {
++ bi = yaffs_get_block_info(in->my_dev,
++ new_chunk_id /
++ in->my_dev->param.
++ chunks_per_block);
++ bi->has_shrink_hdr = 1;
++ }
++
++ }
++
++ ret_val = new_chunk_id;
++
++ }
++
++ if (buffer)
++ yaffs_release_temp_buffer(dev, buffer, __LINE__);
++
++ return ret_val;
++}
++
++/*------------------------ Short Operations Cache ----------------------------------------
++ * In many situations where there is no high level buffering a lot of
++ * reads might be short sequential reads, and a lot of writes may be short
++ * sequential writes. eg. scanning/writing a jpeg file.
++ * In these cases, a short read/write cache can provide a huge perfomance
++ * benefit with dumb-as-a-rock code.
++ * In Linux, the page cache provides read buffering and the short op cache
++ * provides write buffering.
++ *
++ * There are a limited number (~10) of cache chunks per device so that we don't
++ * need a very intelligent search.
++ */
++
++static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int i;
++ struct yaffs_cache *cache;
++ int n_caches = obj->my_dev->param.n_caches;
++
++ for (i = 0; i < n_caches; i++) {
++ cache = &dev->cache[i];
++ if (cache->object == obj && cache->dirty)
++ return 1;
++ }
++
++ return 0;
++}
++
++static void yaffs_flush_file_cache(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int lowest = -99; /* Stop compiler whining. */
++ int i;
++ struct yaffs_cache *cache;
++ int chunk_written = 0;
++ int n_caches = obj->my_dev->param.n_caches;
++
++ if (n_caches > 0) {
++ do {
++ cache = NULL;
++
++ /* Find the dirty cache for this object with the lowest chunk id. */
++ for (i = 0; i < n_caches; i++) {
++ if (dev->cache[i].object == obj &&
++ dev->cache[i].dirty) {
++ if (!cache
++ || dev->cache[i].chunk_id <
++ lowest) {
++ cache = &dev->cache[i];
++ lowest = cache->chunk_id;
++ }
++ }
++ }
++
++ if (cache && !cache->locked) {
++ /* Write it out and free it up */
++
++ chunk_written =
++ yaffs_wr_data_obj(cache->object,
++ cache->chunk_id,
++ cache->data,
++ cache->n_bytes, 1);
++ cache->dirty = 0;
++ cache->object = NULL;
++ }
++
++ } while (cache && chunk_written > 0);
++
++ if (cache) {
++ /* Hoosterman, disk full while writing cache out. */
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy: no space during cache write"
++ TENDSTR)));
++
++ }
++ }
++
++}
++
++/*yaffs_flush_whole_cache(dev)
++ *
++ *
++ */
++
++void yaffs_flush_whole_cache(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ int n_caches = dev->param.n_caches;
++ int i;
++
++ /* Find a dirty object in the cache and flush it...
++ * until there are no further dirty objects.
++ */
++ do {
++ obj = NULL;
++ for (i = 0; i < n_caches && !obj; i++) {
++ if (dev->cache[i].object && dev->cache[i].dirty)
++ obj = dev->cache[i].object;
++
++ }
++ if (obj)
++ yaffs_flush_file_cache(obj);
++
++ } while (obj);
++
++}
++
++/* Grab us a cache chunk for use.
++ * First look for an empty one.
++ * Then look for the least recently used non-dirty one.
++ * Then look for the least recently used dirty one...., flush and look again.
++ */
++static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
++{
++ int i;
++
++ if (dev->param.n_caches > 0) {
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (!dev->cache[i].object)
++ return &dev->cache[i];
++ }
++ }
++
++ return NULL;
++}
++
++static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
++{
++ struct yaffs_cache *cache;
++ struct yaffs_obj *the_obj;
++ int usage;
++ int i;
++ int pushout;
++
++ if (dev->param.n_caches > 0) {
++ /* Try find a non-dirty one... */
++
++ cache = yaffs_grab_chunk_worker(dev);
++
++ if (!cache) {
++ /* They were all dirty, find the last recently used object and flush
++ * its cache, then find again.
++ * NB what's here is not very accurate, we actually flush the object
++ * the last recently used page.
++ */
++
++ /* With locking we can't assume we can use entry zero */
++
++ the_obj = NULL;
++ usage = -1;
++ cache = NULL;
++ pushout = -1;
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object &&
++ !dev->cache[i].locked &&
++ (dev->cache[i].last_use < usage
++ || !cache)) {
++ usage = dev->cache[i].last_use;
++ the_obj = dev->cache[i].object;
++ cache = &dev->cache[i];
++ pushout = i;
++ }
++ }
++
++ if (!cache || cache->dirty) {
++ /* Flush and try again */
++ yaffs_flush_file_cache(the_obj);
++ cache = yaffs_grab_chunk_worker(dev);
++ }
++
++ }
++ return cache;
++ } else {
++ return NULL;
++ }
++}
++
++/* Find a cached chunk */
++static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
++ int chunk_id)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ int i;
++ if (dev->param.n_caches > 0) {
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object == obj &&
++ dev->cache[i].chunk_id == chunk_id) {
++ dev->cache_hits++;
++
++ return &dev->cache[i];
++ }
++ }
++ }
++ return NULL;
++}
++
++/* Mark the chunk for the least recently used algorithym */
++static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
++ int is_write)
++{
++
++ if (dev->param.n_caches > 0) {
++ if (dev->cache_last_use < 0 || dev->cache_last_use > 100000000) {
++ /* Reset the cache usages */
++ int i;
++ for (i = 1; i < dev->param.n_caches; i++)
++ dev->cache[i].last_use = 0;
++
++ dev->cache_last_use = 0;
++ }
++
++ dev->cache_last_use++;
++
++ cache->last_use = dev->cache_last_use;
++
++ if (is_write)
++ cache->dirty = 1;
++ }
++}
++
++/* Invalidate a single cache page.
++ * Do this when a whole page gets written,
++ * ie the short cache for this page is no longer valid.
++ */
++static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
++{
++ if (object->my_dev->param.n_caches > 0) {
++ struct yaffs_cache *cache =
++ yaffs_find_chunk_cache(object, chunk_id);
++
++ if (cache)
++ cache->object = NULL;
++ }
++}
++
++/* Invalidate all the cache pages associated with this object
++ * Do this whenever ther file is deleted or resized.
++ */
++static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
++{
++ int i;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (dev->param.n_caches > 0) {
++ /* Invalidate it. */
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].object == in)
++ dev->cache[i].object = NULL;
++ }
++ }
++}
++
++/*--------------------- File read/write ------------------------
++ * Read and write have very similar structures.
++ * In general the read/write has three parts to it
++ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
++ * Some complete chunks
++ * An incomplete chunk to end off with
++ *
++ * Curve-balls: the first chunk might also be the last chunk.
++ */
++
++int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
++{
++
++ int chunk;
++ u32 start;
++ int n_copy;
++ int n = n_bytes;
++ int n_done = 0;
++ struct yaffs_cache *cache;
++
++ struct yaffs_dev *dev;
++
++ dev = in->my_dev;
++
++ while (n > 0) {
++ /* chunk = offset / dev->data_bytes_per_chunk + 1; */
++ /* start = offset % dev->data_bytes_per_chunk; */
++ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++ chunk++;
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++ if ((start + n) < dev->data_bytes_per_chunk)
++ n_copy = n;
++ else
++ n_copy = dev->data_bytes_per_chunk - start;
++
++ cache = yaffs_find_chunk_cache(in, chunk);
++
++ /* If the chunk is already in the cache or it is less than a whole chunk
++ * or we're using inband tags then use the cache (if there is caching)
++ * else bypass the cache.
++ */
++ if (cache || n_copy != dev->data_bytes_per_chunk
++ || dev->param.inband_tags) {
++ if (dev->param.n_caches > 0) {
++
++ /* If we can't find the data in the cache, then load it up. */
++
++ if (!cache) {
++ cache =
++ yaffs_grab_chunk_cache(in->my_dev);
++ cache->object = in;
++ cache->chunk_id = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_rd_data_obj(in, chunk,
++ cache->data);
++ cache->n_bytes = 0;
++ }
++
++ yaffs_use_cache(dev, cache, 0);
++
++ cache->locked = 1;
++
++ memcpy(buffer, &cache->data[start], n_copy);
++
++ cache->locked = 0;
++ } else {
++ /* Read into the local buffer then copy.. */
++
++ u8 *local_buffer =
++ yaffs_get_temp_buffer(dev, __LINE__);
++ yaffs_rd_data_obj(in, chunk, local_buffer);
++
++ memcpy(buffer, &local_buffer[start], n_copy);
++
++ yaffs_release_temp_buffer(dev, local_buffer,
++ __LINE__);
++ }
++
++ } else {
++
++ /* A full chunk. Read directly into the supplied buffer. */
++ yaffs_rd_data_obj(in, chunk, buffer);
++
++ }
++
++ n -= n_copy;
++ offset += n_copy;
++ buffer += n_copy;
++ n_done += n_copy;
++
++ }
++
++ return n_done;
++}
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 * buffer, loff_t offset,
++ int n_bytes, int write_trhrough)
++{
++
++ int chunk;
++ u32 start;
++ int n_copy;
++ int n = n_bytes;
++ int n_done = 0;
++ int n_writeback;
++ int start_write = offset;
++ int chunk_written = 0;
++ u32 n_bytes_read;
++ u32 chunk_start;
++
++ struct yaffs_dev *dev;
++
++ dev = in->my_dev;
++
++ while (n > 0 && chunk_written >= 0) {
++ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
++
++ if (chunk * dev->data_bytes_per_chunk + start != offset ||
++ start >= dev->data_bytes_per_chunk) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("AddrToChunk of offset %d gives chunk %d start %d"
++ TENDSTR), (int)offset, chunk, start));
++ }
++ chunk++; /* File pos to chunk in file offset */
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++
++ if ((start + n) < dev->data_bytes_per_chunk) {
++ n_copy = n;
++
++ /* Now folks, to calculate how many bytes to write back....
++ * If we're overwriting and not writing to then end of file then
++ * we need to write back as much as was there before.
++ */
++
++ chunk_start = ((chunk - 1) * dev->data_bytes_per_chunk);
++
++ if (chunk_start > in->variant.file_variant.file_size)
++ n_bytes_read = 0; /* Past end of file */
++ else
++ n_bytes_read =
++ in->variant.file_variant.file_size -
++ chunk_start;
++
++ if (n_bytes_read > dev->data_bytes_per_chunk)
++ n_bytes_read = dev->data_bytes_per_chunk;
++
++ n_writeback =
++ (n_bytes_read >
++ (start + n)) ? n_bytes_read : (start + n);
++
++ if (n_writeback < 0
++ || n_writeback > dev->data_bytes_per_chunk)
++ YBUG();
++
++ } else {
++ n_copy = dev->data_bytes_per_chunk - start;
++ n_writeback = dev->data_bytes_per_chunk;
++ }
++
++ if (n_copy != dev->data_bytes_per_chunk
++ || dev->param.inband_tags) {
++ /* An incomplete start or end chunk (or maybe both start and end chunk),
++ * or we're using inband tags, so we want to use the cache buffers.
++ */
++ if (dev->param.n_caches > 0) {
++ struct yaffs_cache *cache;
++ /* If we can't find the data in the cache, then load the cache */
++ cache = yaffs_find_chunk_cache(in, chunk);
++
++ if (!cache
++ && yaffs_check_alloc_available(dev, 1)) {
++ cache = yaffs_grab_chunk_cache(dev);
++ cache->object = in;
++ cache->chunk_id = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_rd_data_obj(in, chunk,
++ cache->data);
++ } else if (cache &&
++ !cache->dirty &&
++ !yaffs_check_alloc_available(dev,
++ 1)) {
++ /* Drop the cache if it was a read cache item and
++ * no space check has been made for it.
++ */
++ cache = NULL;
++ }
++
++ if (cache) {
++ yaffs_use_cache(dev, cache, 1);
++ cache->locked = 1;
++
++ memcpy(&cache->data[start], buffer,
++ n_copy);
++
++ cache->locked = 0;
++ cache->n_bytes = n_writeback;
++
++ if (write_trhrough) {
++ chunk_written =
++ yaffs_wr_data_obj
++ (cache->object,
++ cache->chunk_id,
++ cache->data,
++ cache->n_bytes, 1);
++ cache->dirty = 0;
++ }
++
++ } else {
++ chunk_written = -1; /* fail the write */
++ }
++ } else {
++ /* An incomplete start or end chunk (or maybe both start and end chunk)
++ * Read into the local buffer then copy, then copy over and write back.
++ */
++
++ u8 *local_buffer =
++ yaffs_get_temp_buffer(dev, __LINE__);
++
++ yaffs_rd_data_obj(in, chunk, local_buffer);
++
++ memcpy(&local_buffer[start], buffer, n_copy);
++
++ chunk_written =
++ yaffs_wr_data_obj(in, chunk,
++ local_buffer,
++ n_writeback, 0);
++
++ yaffs_release_temp_buffer(dev, local_buffer,
++ __LINE__);
++
++ }
++
++ } else {
++ /* A full chunk. Write directly from the supplied buffer. */
++
++ chunk_written =
++ yaffs_wr_data_obj(in, chunk, buffer,
++ dev->data_bytes_per_chunk, 0);
++
++ /* Since we've overwritten the cached data, we better invalidate it. */
++ yaffs_invalidate_chunk_cache(in, chunk);
++ }
++
++ if (chunk_written >= 0) {
++ n -= n_copy;
++ offset += n_copy;
++ buffer += n_copy;
++ n_done += n_copy;
++ }
++
++ }
++
++ /* Update file object */
++
++ if ((start_write + n_done) > in->variant.file_variant.file_size)
++ in->variant.file_variant.file_size = (start_write + n_done);
++
++ in->dirty = 1;
++
++ return n_done;
++}
++
++int yaffs_wr_file(struct yaffs_obj *in, const u8 * buffer, loff_t offset,
++ int n_bytes, int write_trhrough)
++{
++ yaffs2_handle_hole(in, offset);
++ return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_trhrough);
++}
++
++/* ---------------------- File resizing stuff ------------------ */
++
++static void yaffs_prune_chunks(struct yaffs_obj *in, int new_size)
++{
++
++ struct yaffs_dev *dev = in->my_dev;
++ int old_size = in->variant.file_variant.file_size;
++
++ int last_del = 1 + (old_size - 1) / dev->data_bytes_per_chunk;
++
++ int start_del = 1 + (new_size + dev->data_bytes_per_chunk - 1) /
++ dev->data_bytes_per_chunk;
++ int i;
++ int chunk_id;
++
++ /* Delete backwards so that we don't end up with holes if
++ * power is lost part-way through the operation.
++ */
++ for (i = last_del; i >= start_del; i--) {
++ /* NB this could be optimised somewhat,
++ * eg. could retrieve the tags and write them without
++ * using yaffs_chunk_del
++ */
++
++ chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
++ if (chunk_id > 0) {
++ if (chunk_id <
++ (dev->internal_start_block *
++ dev->param.chunks_per_block)
++ || chunk_id >=
++ ((dev->internal_end_block +
++ 1) * dev->param.chunks_per_block)) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("Found daft chunk_id %d for %d" TENDSTR),
++ chunk_id, i));
++ } else {
++ in->n_data_chunks--;
++ yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
++ }
++ }
++ }
++
++}
++
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
++{
++ int new_full;
++ u32 new_partial;
++ struct yaffs_dev *dev = obj->my_dev;
++
++ yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
++
++ yaffs_prune_chunks(obj, new_size);
++
++ if (new_partial != 0) {
++ int last_chunk = 1 + new_full;
++ u8 *local_buffer = yaffs_get_temp_buffer(dev, __LINE__);
++
++ /* Got to read and rewrite the last chunk with its new size and zero pad */
++ yaffs_rd_data_obj(obj, last_chunk, local_buffer);
++ memset(local_buffer + new_partial, 0,
++ dev->data_bytes_per_chunk - new_partial);
++
++ yaffs_wr_data_obj(obj, last_chunk, local_buffer,
++ new_partial, 1);
++
++ yaffs_release_temp_buffer(dev, local_buffer, __LINE__);
++ }
++
++ obj->variant.file_variant.file_size = new_size;
++
++ yaffs_prune_tree(dev, &obj->variant.file_variant);
++}
++
++int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
++{
++ struct yaffs_dev *dev = in->my_dev;
++ int old_size = in->variant.file_variant.file_size;
++
++ yaffs_flush_file_cache(in);
++ yaffs_invalidate_whole_cache(in);
++
++ yaffs_check_gc(dev, 0);
++
++ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ if (new_size == old_size)
++ return YAFFS_OK;
++
++ if (new_size > old_size) {
++ yaffs2_handle_hole(in, new_size);
++ in->variant.file_variant.file_size = new_size;
++ } else {
++ /* new_size < old_size */
++ yaffs_resize_file_down(in, new_size);
++ }
++
++ /* Write a new object header to reflect the resize.
++ * show we've shrunk the file, if need be
++ * Do this only if the file is not in the deleted directories
++ * and is not shadowed.
++ */
++ if (in->parent &&
++ !in->is_shadowed &&
++ in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++ in->parent->obj_id != YAFFS_OBJECTID_DELETED)
++ yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
++
++ return YAFFS_OK;
++}
++
++int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
++{
++ int ret_val;
++ if (in->dirty) {
++ yaffs_flush_file_cache(in);
++ if (data_sync) /* Only sync data */
++ ret_val = YAFFS_OK;
++ else {
++ if (update_time)
++ yaffs_load_current_time(in, 0, 0);
++
++ ret_val = (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >=
++ 0) ? YAFFS_OK : YAFFS_FAIL;
++ }
++ } else {
++ ret_val = YAFFS_OK;
++ }
++
++ return ret_val;
++
++}
++
++static int yaffs_generic_obj_del(struct yaffs_obj *in)
++{
++
++ /* First off, invalidate the file's data in the cache, without flushing. */
++ yaffs_invalidate_whole_cache(in);
++
++ if (in->my_dev->param.is_yaffs2 && (in->parent != in->my_dev->del_dir)) {
++ /* Move to the unlinked directory so we have a record that it was deleted. */
++ yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
++ 0);
++
++ }
++
++ yaffs_remove_obj_from_dir(in);
++ yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
++ in->hdr_chunk = 0;
++
++ yaffs_free_obj(in);
++ return YAFFS_OK;
++
++}
++
++/* yaffs_del_file deletes the whole file data
++ * and the inode associated with the file.
++ * It does not delete the links associated with the file.
++ */
++static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
++{
++
++ int ret_val;
++ int del_now = 0;
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (!in->my_inode)
++ del_now = 1;
++
++ if (del_now) {
++ ret_val =
++ yaffs_change_obj_name(in, in->my_dev->del_dir,
++ _Y("deleted"), 0, 0);
++ T(YAFFS_TRACE_TRACING,
++ (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
++ in->obj_id));
++ in->deleted = 1;
++ in->my_dev->n_deleted_files++;
++ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++ yaffs_resize_file(in, 0);
++ yaffs_soft_del_file(in);
++ } else {
++ ret_val =
++ yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
++ _Y("unlinked"), 0, 0);
++ }
++
++ return ret_val;
++}
++
++int yaffs_del_file(struct yaffs_obj *in)
++{
++ int ret_val = YAFFS_OK;
++ int deleted; /* Need to cache value on stack if in is freed */
++ struct yaffs_dev *dev = in->my_dev;
++
++ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
++ yaffs_resize_file(in, 0);
++
++ if (in->n_data_chunks > 0) {
++ /* Use soft deletion if there is data in the file.
++ * That won't be the case if it has been resized to zero.
++ */
++ if (!in->unlinked)
++ ret_val = yaffs_unlink_file_if_needed(in);
++
++ deleted = in->deleted;
++
++ if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
++ in->deleted = 1;
++ deleted = 1;
++ in->my_dev->n_deleted_files++;
++ yaffs_soft_del_file(in);
++ }
++ return deleted ? YAFFS_OK : YAFFS_FAIL;
++ } else {
++ /* The file has no data chunks so we toss it immediately */
++ yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
++ in->variant.file_variant.top = NULL;
++ yaffs_generic_obj_del(in);
++
++ return YAFFS_OK;
++ }
++}
++
++static int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
++{
++ return (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
++ !(list_empty(&obj->variant.dir_variant.children));
++}
++
++static int yaffs_del_dir(struct yaffs_obj *obj)
++{
++ /* First check that the directory is empty. */
++ if (yaffs_is_non_empty_dir(obj))
++ return YAFFS_FAIL;
++
++ return yaffs_generic_obj_del(obj);
++}
++
++static int yaffs_del_symlink(struct yaffs_obj *in)
++{
++ if (in->variant.symlink_variant.alias)
++ YFREE(in->variant.symlink_variant.alias);
++ in->variant.symlink_variant.alias = NULL;
++
++ return yaffs_generic_obj_del(in);
++}
++
++static int yaffs_del_link(struct yaffs_obj *in)
++{
++ /* remove this hardlink from the list assocaited with the equivalent
++ * object
++ */
++ list_del_init(&in->hard_links);
++ return yaffs_generic_obj_del(in);
++}
++
++int yaffs_del_obj(struct yaffs_obj *obj)
++{
++ int ret_val = -1;
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ ret_val = yaffs_del_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ if (!list_empty(&obj->variant.dir_variant.dirty)) {
++ T(YAFFS_TRACE_BACKGROUND,
++ (TSTR
++ ("Remove object %d from dirty directories" TENDSTR),
++ obj->obj_id));
++ list_del_init(&obj->variant.dir_variant.dirty);
++ }
++ return yaffs_del_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ ret_val = yaffs_del_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ ret_val = yaffs_del_link(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ ret_val = yaffs_generic_obj_del(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ ret_val = 0;
++ break; /* should not happen. */
++ }
++
++ return ret_val;
++}
++
++static int yaffs_unlink_worker(struct yaffs_obj *obj)
++{
++
++ int del_now = 0;
++
++ if (!obj->my_inode)
++ del_now = 1;
++
++ if (obj)
++ yaffs_update_parent(obj->parent);
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++ return yaffs_del_link(obj);
++ } else if (!list_empty(&obj->hard_links)) {
++ /* Curve ball: We're unlinking an object that has a hardlink.
++ *
++ * This problem arises because we are not strictly following
++ * The Linux link/inode model.
++ *
++ * We can't really delete the object.
++ * Instead, we do the following:
++ * - Select a hardlink.
++ * - Unhook it from the hard links
++ * - Move it from its parent directory (so that the rename can work)
++ * - Rename the object to the hardlink's name.
++ * - Delete the hardlink
++ */
++
++ struct yaffs_obj *hl;
++ struct yaffs_obj *parent;
++ int ret_val;
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ hl = list_entry(obj->hard_links.next, struct yaffs_obj,
++ hard_links);
++
++ yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
++ parent = hl->parent;
++
++ list_del_init(&hl->hard_links);
++
++ yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
++
++ ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
++
++ if (ret_val == YAFFS_OK)
++ ret_val = yaffs_generic_obj_del(hl);
++
++ return ret_val;
++
++ } else if (del_now) {
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return yaffs_del_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ list_del_init(&obj->variant.dir_variant.dirty);
++ return yaffs_del_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return yaffs_del_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ return yaffs_generic_obj_del(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ return YAFFS_FAIL;
++ }
++ } else if (yaffs_is_non_empty_dir(obj)) {
++ return YAFFS_FAIL;
++ } else {
++ return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
++ _Y("unlinked"), 0, 0);
++ }
++}
++
++static int yaffs_unlink_obj(struct yaffs_obj *obj)
++{
++
++ if (obj && obj->unlink_allowed)
++ return yaffs_unlink_worker(obj);
++
++ return YAFFS_FAIL;
++
++}
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name)
++{
++ struct yaffs_obj *obj;
++
++ obj = yaffs_find_by_name(dir, name);
++ return yaffs_unlink_obj(obj);
++}
++
++/*----------------------- Initialisation Scanning ---------------------- */
++
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++ int backward_scanning)
++{
++ struct yaffs_obj *obj;
++
++ if (!backward_scanning) {
++ /* Handle YAFFS1 forward scanning case
++ * For YAFFS1 we always do the deletion
++ */
++
++ } else {
++ /* Handle YAFFS2 case (backward scanning)
++ * If the shadowed object exists then ignore.
++ */
++ obj = yaffs_find_by_number(dev, obj_id);
++ if (obj)
++ return;
++ }
++
++ /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
++ * We put it in unlinked dir to be cleaned up after the scanning
++ */
++ obj =
++ yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
++ if (!obj)
++ return;
++ obj->is_shadowed = 1;
++ yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
++ obj->variant.file_variant.shrink_size = 0;
++ obj->valid = 1; /* So that we don't read any other info for this file */
++
++}
++
++void yaffs_link_fixup(struct yaffs_dev *dev, struct yaffs_obj *hard_list)
++{
++ struct yaffs_obj *hl;
++ struct yaffs_obj *in;
++
++ while (hard_list) {
++ hl = hard_list;
++ hard_list = (struct yaffs_obj *)(hard_list->hard_links.next);
++
++ in = yaffs_find_by_number(dev,
++ hl->variant.
++ hardlink_variant.equiv_id);
++
++ if (in) {
++ /* Add the hardlink pointers */
++ hl->variant.hardlink_variant.equiv_obj = in;
++ list_add(&hl->hard_links, &in->hard_links);
++ } else {
++ /* Todo Need to report/handle this better.
++ * Got a problem... hardlink to a non-existant object
++ */
++ hl->variant.hardlink_variant.equiv_obj = NULL;
++ INIT_LIST_HEAD(&hl->hard_links);
++
++ }
++ }
++}
++
++static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
++{
++ /*
++ * Sort out state of unlinked and deleted objects after scanning.
++ */
++ struct list_head *i;
++ struct list_head *n;
++ struct yaffs_obj *l;
++
++ if (dev->read_only)
++ return;
++
++ /* Soft delete all the unlinked files */
++ list_for_each_safe(i, n,
++ &dev->unlinked_dir->variant.dir_variant.children) {
++ if (i) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++ yaffs_del_obj(l);
++ }
++ }
++
++ list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
++ if (i) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++ yaffs_del_obj(l);
++ }
++ }
++
++}
++
++/*
++ * This code iterates through all the objects making sure that they are rooted.
++ * Any unrooted objects are re-rooted in lost+found.
++ * An object needs to be in one of:
++ * - Directly under deleted, unlinked
++ * - Directly or indirectly under root.
++ *
++ * Note:
++ * This code assumes that we don't ever change the current relationships between
++ * directories:
++ * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
++ * lost-n-found->parent == root_dir
++ *
++ * This fixes the problem where directories might have inadvertently been deleted
++ * leaving the object "hanging" without being rooted in the directory tree.
++ */
++
++static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++ return (obj == dev->del_dir ||
++ obj == dev->unlinked_dir || obj == dev->root_dir);
++}
++
++static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_obj *parent;
++ int i;
++ struct list_head *lh;
++ struct list_head *n;
++ int depth_limit;
++ int hanging;
++
++ if (dev->read_only)
++ return;
++
++ /* Iterate through the objects in each hash entry,
++ * looking at each object.
++ * Make sure it is rooted.
++ */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
++ if (lh) {
++ obj =
++ list_entry(lh, struct yaffs_obj, hash_link);
++ parent = obj->parent;
++
++ if (yaffs_has_null_parent(dev, obj)) {
++ /* These directories are not hanging */
++ hanging = 0;
++ } else if (!parent
++ || parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ hanging = 1;
++ } else if (yaffs_has_null_parent(dev, parent)) {
++ hanging = 0;
++ } else {
++ /*
++ * Need to follow the parent chain to see if it is hanging.
++ */
++ hanging = 0;
++ depth_limit = 100;
++
++ while (parent != dev->root_dir &&
++ parent->parent &&
++ parent->parent->variant_type ==
++ YAFFS_OBJECT_TYPE_DIRECTORY
++ && depth_limit > 0) {
++ parent = parent->parent;
++ depth_limit--;
++ }
++ if (parent != dev->root_dir)
++ hanging = 1;
++ }
++ if (hanging) {
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ ("Hanging object %d moved to lost and found"
++ TENDSTR), obj->obj_id));
++ yaffs_add_obj_to_dir(dev->lost_n_found,
++ obj);
++ }
++ }
++ }
++ }
++}
++
++/*
++ * Delete directory contents for cleaning up lost and found.
++ */
++static void yaffs_del_dir_contents(struct yaffs_obj *dir)
++{
++ struct yaffs_obj *obj;
++ struct list_head *lh;
++ struct list_head *n;
++
++ if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
++ YBUG();
++
++ list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
++ if (lh) {
++ obj = list_entry(lh, struct yaffs_obj, siblings);
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
++ yaffs_del_dir_contents(obj);
++
++ T(YAFFS_TRACE_SCAN,
++ (TSTR("Deleting lost_found object %d" TENDSTR),
++ obj->obj_id));
++
++ /* Need to use UnlinkObject since Delete would not handle
++ * hardlinked objects correctly.
++ */
++ yaffs_unlink_obj(obj);
++ }
++ }
++
++}
++
++static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
++{
++ yaffs_del_dir_contents(dev->lost_n_found);
++}
++
++static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
++{
++ u8 *chunk_data;
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_dev *dev;
++ struct yaffs_ext_tags tags;
++ int result;
++ int alloc_failed = 0;
++
++ if (!in)
++ return;
++
++ dev = in->my_dev;
++
++ if (in->lazy_loaded && in->hdr_chunk > 0) {
++ in->lazy_loaded = 0;
++ chunk_data = yaffs_get_temp_buffer(dev, __LINE__);
++
++ result =
++ yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, chunk_data,
++ &tags);
++ oh = (struct yaffs_obj_hdr *)chunk_data;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ yaffs_set_obj_name_from_oh(in, oh);
++
++ if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ in->variant.symlink_variant.alias =
++ yaffs_clone_str(oh->alias);
++ if (!in->variant.symlink_variant.alias)
++ alloc_failed = 1; /* Not returned to caller */
++ }
++
++ yaffs_release_temp_buffer(dev, chunk_data, __LINE__);
++ }
++}
++
++/*------------------------------ Directory Functions ----------------------------- */
++
++/*
++ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
++ * link (ie. name) is created or deleted in the directory.
++ *
++ * ie.
++ * create dir/a : update dir's mtime/ctime
++ * rm dir/a: update dir's mtime/ctime
++ * modify dir/a: don't update dir's mtimme/ctime
++ *
++ * This can be handled immediately or defered. Defering helps reduce the number
++ * of updates when many files in a directory are changed within a brief period.
++ *
++ * If the directory updating is defered then yaffs_update_dirty_dirs must be
++ * called periodically.
++ */
++
++static void yaffs_update_parent(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++ if (!obj)
++ return;
++ dev = obj->my_dev;
++ obj->dirty = 1;
++ yaffs_load_current_time(obj, 0, 1);
++ if (dev->param.defered_dir_update) {
++ struct list_head *link = &obj->variant.dir_variant.dirty;
++
++ if (list_empty(link)) {
++ list_add(link, &dev->dirty_dirs);
++ T(YAFFS_TRACE_BACKGROUND,
++ (TSTR("Added object %d to dirty directories" TENDSTR),
++ obj->obj_id));
++ }
++
++ } else {
++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++ }
++}
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
++{
++ struct list_head *link;
++ struct yaffs_obj *obj;
++ struct yaffs_dir_var *d_s;
++ union yaffs_obj_var *o_v;
++
++ T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR)));
++
++ while (!list_empty(&dev->dirty_dirs)) {
++ link = dev->dirty_dirs.next;
++ list_del_init(link);
++
++ d_s = list_entry(link, struct yaffs_dir_var, dirty);
++ o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
++ obj = list_entry(o_v, struct yaffs_obj, variant);
++
++ T(YAFFS_TRACE_BACKGROUND,
++ (TSTR("Update directory %d" TENDSTR), obj->obj_id));
++
++ if (obj->dirty)
++ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
++ }
++}
++
++static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev = obj->my_dev;
++ struct yaffs_obj *parent;
++
++ yaffs_verify_obj_in_dir(obj);
++ parent = obj->parent;
++
++ yaffs_verify_dir(parent);
++
++ if (dev && dev->param.remove_obj_fn)
++ dev->param.remove_obj_fn(obj);
++
++ list_del_init(&obj->siblings);
++ obj->parent = NULL;
++
++ yaffs_verify_dir(parent);
++}
++
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
++{
++ if (!directory) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("tragedy: Trying to add an object to a null pointer directory"
++ TENDSTR)));
++ YBUG();
++ return;
++ }
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("tragedy: Trying to add an object to a non-directory"
++ TENDSTR)));
++ YBUG();
++ }
++
++ if (obj->siblings.prev == NULL) {
++ /* Not initialised */
++ YBUG();
++ }
++
++ yaffs_verify_dir(directory);
++
++ yaffs_remove_obj_from_dir(obj);
++
++ /* Now add it */
++ list_add(&obj->siblings, &directory->variant.dir_variant.children);
++ obj->parent = directory;
++
++ if (directory == obj->my_dev->unlinked_dir
++ || directory == obj->my_dev->del_dir) {
++ obj->unlinked = 1;
++ obj->my_dev->n_unlinked_files++;
++ obj->rename_allowed = 0;
++ }
++
++ yaffs_verify_dir(directory);
++ yaffs_verify_obj_in_dir(obj);
++}
++
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
++ const YCHAR * name)
++{
++ int sum;
++
++ struct list_head *i;
++ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
++
++ struct yaffs_obj *l;
++
++ if (!name)
++ return NULL;
++
++ if (!directory) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("tragedy: yaffs_find_by_name: null pointer directory"
++ TENDSTR)));
++ YBUG();
++ return NULL;
++ }
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("tragedy: yaffs_find_by_name: non-directory" TENDSTR)));
++ YBUG();
++ }
++
++ sum = yaffs_calc_name_sum(name);
++
++ list_for_each(i, &directory->variant.dir_variant.children) {
++ if (i) {
++ l = list_entry(i, struct yaffs_obj, siblings);
++
++ if (l->parent != directory)
++ YBUG();
++
++ yaffs_check_obj_details_loaded(l);
++
++ /* Special case for lost-n-found */
++ if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++ if (!yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME))
++ return l;
++ } else if (yaffs_sum_cmp(l->sum, sum)
++ || l->hdr_chunk <= 0) {
++ /* LostnFound chunk called Objxxx
++ * Do a real check
++ */
++ yaffs_get_obj_name(l, buffer,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ if (yaffs_strncmp
++ (name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
++ return l;
++ }
++ }
++ }
++
++ return NULL;
++}
++
++/* GetEquivalentObject dereferences any hard links to get to the
++ * actual object.
++ */
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
++{
++ if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
++ /* We want the object id of the equivalent object, not this one */
++ obj = obj->variant.hardlink_variant.equiv_obj;
++ yaffs_check_obj_details_loaded(obj);
++ }
++ return obj;
++}
++
++/*
++ * A note or two on object names.
++ * * If the object name is missing, we then make one up in the form objnnn
++ *
++ * * ASCII names are stored in the object header's name field from byte zero
++ * * Unicode names are historically stored starting from byte zero.
++ *
++ * Then there are automatic Unicode names...
++ * The purpose of these is to save names in a way that can be read as
++ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
++ * system to share files.
++ *
++ * These automatic unicode are stored slightly differently...
++ * - If the name can fit in the ASCII character space then they are saved as
++ * ascii names as per above.
++ * - If the name needs Unicode then the name is saved in Unicode
++ * starting at oh->name[1].
++
++ */
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR * name,
++ int buffer_size)
++{
++ /* Create an object name if we could not find one. */
++ if (yaffs_strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
++ YCHAR local_name[20];
++ YCHAR num_string[20];
++ YCHAR *x = &num_string[19];
++ unsigned v = obj->obj_id;
++ num_string[19] = 0;
++ while (v > 0) {
++ x--;
++ *x = '0' + (v % 10);
++ v /= 10;
++ }
++ /* make up a name */
++ yaffs_strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
++ yaffs_strcat(local_name, x);
++ yaffs_strncpy(name, local_name, buffer_size - 1);
++ }
++}
++
++static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR * name,
++ const YCHAR * oh_name, int buff_size)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ if (dev->param.auto_unicode) {
++ if (*oh_name) {
++ /* It is an ASCII name, so do an ASCII to unicode conversion */
++ const char *ascii_oh_name = (const char *)oh_name;
++ int n = buff_size - 1;
++ while (n > 0 && *ascii_oh_name) {
++ *name = *ascii_oh_name;
++ name++;
++ ascii_oh_name++;
++ n--;
++ }
++ } else {
++ yaffs_strncpy(name, oh_name + 1, buff_size - 1);
++ }
++ } else {
++#else
++ {
++#endif
++ yaffs_strncpy(name, oh_name, buff_size - 1);
++ }
++}
++
++static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR * oh_name,
++ const YCHAR * name)
++{
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++
++ int is_ascii;
++ YCHAR *w;
++
++ if (dev->param.auto_unicode) {
++
++ is_ascii = 1;
++ w = name;
++
++ /* Figure out if the name will fit in ascii character set */
++ while (is_ascii && *w) {
++ if ((*w) & 0xff00)
++ is_ascii = 0;
++ w++;
++ }
++
++ if (is_ascii) {
++ /* It is an ASCII name, so do a unicode to ascii conversion */
++ char *ascii_oh_name = (char *)oh_name;
++ int n = YAFFS_MAX_NAME_LENGTH - 1;
++ while (n > 0 && *name) {
++ *ascii_oh_name = *name;
++ name++;
++ ascii_oh_name++;
++ n--;
++ }
++ } else {
++ /* It is a unicode name, so save starting at the second YCHAR */
++ *oh_name = 0;
++ yaffs_strncpy(oh_name + 1, name,
++ YAFFS_MAX_NAME_LENGTH - 2);
++ }
++ } else {
++#else
++ {
++#endif
++ yaffs_strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
++ }
++
++}
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size)
++{
++ memset(name, 0, buffer_size * sizeof(YCHAR));
++
++ yaffs_check_obj_details_loaded(obj);
++
++ if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
++ yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
++ }
++#ifndef CONFIG_YAFFS_NO_SHORT_NAMES
++ else if (obj->short_name[0]) {
++ yaffs_strcpy(name, obj->short_name);
++ }
++#endif
++ else if (obj->hdr_chunk > 0) {
++ int result;
++ u8 *buffer = yaffs_get_temp_buffer(obj->my_dev, __LINE__);
++
++ struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
++
++ memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
++
++ if (obj->hdr_chunk > 0) {
++ result = yaffs_rd_chunk_tags_nand(obj->my_dev,
++ obj->hdr_chunk,
++ buffer, NULL);
++ }
++ yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
++ buffer_size);
++
++ yaffs_release_temp_buffer(obj->my_dev, buffer, __LINE__);
++ }
++
++ yaffs_fix_null_name(obj, name, buffer_size);
++
++ return yaffs_strnlen(name, YAFFS_MAX_NAME_LENGTH);
++}
++
++int yaffs_get_obj_length(struct yaffs_obj *obj)
++{
++ /* Dereference any hard linking */
++ obj = yaffs_get_equivalent_obj(obj);
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ return obj->variant.file_variant.file_size;
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ if (!obj->variant.symlink_variant.alias)
++ return 0;
++ return yaffs_strnlen(obj->variant.symlink_variant.alias,
++ YAFFS_MAX_ALIAS_LENGTH);
++ } else {
++ /* Only a directory should drop through to here */
++ return obj->my_dev->data_bytes_per_chunk;
++ }
++}
++
++int yaffs_get_obj_link_count(struct yaffs_obj *obj)
++{
++ int count = 0;
++ struct list_head *i;
++
++ if (!obj->unlinked)
++ count++; /* the object itself */
++
++ list_for_each(i, &obj->hard_links)
++ count++; /* add the hard links; */
++
++ return count;
++}
++
++int yaffs_get_obj_inode(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++
++ return obj->obj_id;
++}
++
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ return DT_DIR;
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return DT_LNK;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ if (S_ISFIFO(obj->yst_mode))
++ return DT_FIFO;
++ if (S_ISCHR(obj->yst_mode))
++ return DT_CHR;
++ if (S_ISBLK(obj->yst_mode))
++ return DT_BLK;
++ if (S_ISSOCK(obj->yst_mode))
++ return DT_SOCK;
++ default:
++ return DT_REG;
++ break;
++ }
++}
++
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
++{
++ obj = yaffs_get_equivalent_obj(obj);
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
++ return yaffs_clone_str(obj->variant.symlink_variant.alias);
++ else
++ return yaffs_clone_str(_Y(""));
++}
++
++static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
++ const YCHAR * name, const void *value, int size,
++ int flags)
++{
++ struct yaffs_xattr_mod xmod;
++
++ int result;
++
++ xmod.set = set;
++ xmod.name = name;
++ xmod.data = value;
++ xmod.size = size;
++ xmod.flags = flags;
++ xmod.result = -ENOSPC;
++
++ result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
++
++ if (result > 0)
++ return xmod.result;
++ else
++ return -ENOSPC;
++}
++
++static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
++ struct yaffs_xattr_mod *xmod)
++{
++ int retval = 0;
++ int x_offs = sizeof(struct yaffs_obj_hdr);
++ struct yaffs_dev *dev = obj->my_dev;
++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++
++ char *x_buffer = buffer + x_offs;
++
++ if (xmod->set)
++ retval =
++ nval_set(x_buffer, x_size, xmod->name, xmod->data,
++ xmod->size, xmod->flags);
++ else
++ retval = nval_del(x_buffer, x_size, xmod->name);
++
++ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++ obj->xattr_known = 1;
++
++ xmod->result = retval;
++
++ return retval;
++}
++
++static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR * name,
++ void *value, int size)
++{
++ char *buffer = NULL;
++ int result;
++ struct yaffs_ext_tags tags;
++ struct yaffs_dev *dev = obj->my_dev;
++ int x_offs = sizeof(struct yaffs_obj_hdr);
++ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
++
++ char *x_buffer;
++
++ int retval = 0;
++
++ if (obj->hdr_chunk < 1)
++ return -ENODATA;
++
++ /* If we know that the object has no xattribs then don't do all the
++ * reading and parsing.
++ */
++ if (obj->xattr_known && !obj->has_xattr) {
++ if (name)
++ return -ENODATA;
++ else
++ return 0;
++ }
++
++ buffer = (char *)yaffs_get_temp_buffer(dev, __LINE__);
++ if (!buffer)
++ return -ENOMEM;
++
++ result =
++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
++
++ if (result != YAFFS_OK)
++ retval = -ENOENT;
++ else {
++ x_buffer = buffer + x_offs;
++
++ if (!obj->xattr_known) {
++ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
++ obj->xattr_known = 1;
++ }
++
++ if (name)
++ retval = nval_get(x_buffer, x_size, name, value, size);
++ else
++ retval = nval_list(x_buffer, x_size, value, size);
++ }
++ yaffs_release_temp_buffer(dev, (u8 *) buffer, __LINE__);
++ return retval;
++}
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
++ const void *value, int size, int flags)
++{
++ return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
++}
++
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
++{
++ return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
++}
++
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
++ int size)
++{
++ return yaffs_do_xattrib_fetch(obj, name, value, size);
++}
++
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
++{
++ return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
++}
++
++/*---------------------------- Initialisation code -------------------------------------- */
++
++static int yaffs_check_dev_fns(const struct yaffs_dev *dev)
++{
++
++ /* Common functions, gotta have */
++ if (!dev->param.erase_fn || !dev->param.initialise_flash_fn)
++ return 0;
++
++#ifdef CONFIG_YAFFS_YAFFS2
++
++ /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
++ if (dev->param.write_chunk_tags_fn &&
++ dev->param.read_chunk_tags_fn &&
++ !dev->param.write_chunk_fn &&
++ !dev->param.read_chunk_fn &&
++ dev->param.bad_block_fn && dev->param.query_block_fn)
++ return 1;
++#endif
++
++ /* Can use the "spare" style interface for yaffs1 */
++ if (!dev->param.is_yaffs2 &&
++ !dev->param.write_chunk_tags_fn &&
++ !dev->param.read_chunk_tags_fn &&
++ dev->param.write_chunk_fn &&
++ dev->param.read_chunk_fn &&
++ !dev->param.bad_block_fn && !dev->param.query_block_fn)
++ return 1;
++
++ return 0; /* bad */
++}
++
++static int yaffs_create_initial_dir(struct yaffs_dev *dev)
++{
++ /* Initialise the unlinked, deleted, root and lost and found directories */
++
++ dev->lost_n_found = dev->root_dir = NULL;
++ dev->unlinked_dir = dev->del_dir = NULL;
++
++ dev->unlinked_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
++
++ dev->del_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
++
++ dev->root_dir =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
++ YAFFS_ROOT_MODE | S_IFDIR);
++ dev->lost_n_found =
++ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
++ YAFFS_LOSTNFOUND_MODE | S_IFDIR);
++
++ if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
++ && dev->del_dir) {
++ yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
++ return YAFFS_OK;
++ }
++
++ return YAFFS_FAIL;
++}
++
++int yaffs_guts_initialise(struct yaffs_dev *dev)
++{
++ int init_failed = 0;
++ unsigned x;
++ int bits;
++
++ T(YAFFS_TRACE_TRACING,
++ (TSTR("yaffs: yaffs_guts_initialise()" TENDSTR)));
++
++ /* Check stuff that must be set */
++
++ if (!dev) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ dev->internal_start_block = dev->param.start_block;
++ dev->internal_end_block = dev->param.end_block;
++ dev->block_offset = 0;
++ dev->chunk_offset = 0;
++ dev->n_free_chunks = 0;
++
++ dev->gc_block = 0;
++
++ if (dev->param.start_block == 0) {
++ dev->internal_start_block = dev->param.start_block + 1;
++ dev->internal_end_block = dev->param.end_block + 1;
++ dev->block_offset = 1;
++ dev->chunk_offset = dev->param.chunks_per_block;
++ }
++
++ /* Check geometry parameters. */
++
++ if ((!dev->param.inband_tags && dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 1024) || (!dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 512) || (dev->param.inband_tags && !dev->param.is_yaffs2) || dev->param.chunks_per_block < 2 || dev->param.n_reserved_blocks < 2 || dev->internal_start_block <= 0 || dev->internal_end_block <= 0 || dev->internal_end_block <= (dev->internal_start_block + dev->param.n_reserved_blocks + 2)) { /* otherwise it is too small */
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d "
++ TENDSTR), dev->param.total_bytes_per_chunk,
++ dev->param.is_yaffs2 ? "2" : "", dev->param.inband_tags));
++ return YAFFS_FAIL;
++ }
++
++ if (yaffs_init_nand(dev) != YAFFS_OK) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ /* Sort out space for inband tags, if required */
++ if (dev->param.inband_tags)
++ dev->data_bytes_per_chunk =
++ dev->param.total_bytes_per_chunk -
++ sizeof(struct yaffs_packed_tags2_tags_only);
++ else
++ dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
++
++ /* Got the right mix of functions? */
++ if (!yaffs_check_dev_fns(dev)) {
++ /* Function missing */
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("yaffs: device function(s) missing or wrong\n" TENDSTR)));
++
++ return YAFFS_FAIL;
++ }
++
++ if (dev->is_mounted) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: device already mounted\n" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ /* Finished with most checks. One or two more checks happen later on too. */
++
++ dev->is_mounted = 1;
++
++ /* OK now calculate a few things for the device */
++
++ /*
++ * Calculate all the chunk size manipulation numbers:
++ */
++ x = dev->data_bytes_per_chunk;
++ /* We always use dev->chunk_shift and dev->chunk_div */
++ dev->chunk_shift = calc_shifts(x);
++ x >>= dev->chunk_shift;
++ dev->chunk_div = x;
++ /* We only use chunk mask if chunk_div is 1 */
++ dev->chunk_mask = (1 << dev->chunk_shift) - 1;
++
++ /*
++ * Calculate chunk_grp_bits.
++ * We need to find the next power of 2 > than internal_end_block
++ */
++
++ x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
++
++ bits = calc_shifts_ceiling(x);
++
++ /* Set up tnode width if wide tnodes are enabled. */
++ if (!dev->param.wide_tnodes_disabled) {
++ /* bits must be even so that we end up with 32-bit words */
++ if (bits & 1)
++ bits++;
++ if (bits < 16)
++ dev->tnode_width = 16;
++ else
++ dev->tnode_width = bits;
++ } else {
++ dev->tnode_width = 16;
++ }
++
++ dev->tnode_mask = (1 << dev->tnode_width) - 1;
++
++ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
++ * so if the bitwidth of the
++ * chunk range we're using is greater than 16 we need
++ * to figure out chunk shift and chunk_grp_size
++ */
++
++ if (bits <= dev->tnode_width)
++ dev->chunk_grp_bits = 0;
++ else
++ dev->chunk_grp_bits = bits - dev->tnode_width;
++
++ dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
++ if (dev->tnode_size < sizeof(struct yaffs_tnode))
++ dev->tnode_size = sizeof(struct yaffs_tnode);
++
++ dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
++
++ if (dev->param.chunks_per_block < dev->chunk_grp_size) {
++ /* We have a problem because the soft delete won't work if
++ * the chunk group size > chunks per block.
++ * This can be remedied by using larger "virtual blocks".
++ */
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: chunk group too large\n" TENDSTR)));
++
++ return YAFFS_FAIL;
++ }
++
++ /* OK, we've finished verifying the device, lets continue with initialisation */
++
++ /* More device initialisation */
++ dev->all_gcs = 0;
++ dev->passive_gc_count = 0;
++ dev->oldest_dirty_gc_count = 0;
++ dev->bg_gcs = 0;
++ dev->gc_block_finder = 0;
++ dev->buffered_block = -1;
++ dev->doing_buffered_block_rewrite = 0;
++ dev->n_deleted_files = 0;
++ dev->n_bg_deletions = 0;
++ dev->n_unlinked_files = 0;
++ dev->n_ecc_fixed = 0;
++ dev->n_ecc_unfixed = 0;
++ dev->n_tags_ecc_fixed = 0;
++ dev->n_tags_ecc_unfixed = 0;
++ dev->n_erase_failures = 0;
++ dev->n_erased_blocks = 0;
++ dev->gc_disable = 0;
++ dev->has_pending_prioritised_gc = 1; /* Assume the worst for now, will get fixed on first GC */
++ INIT_LIST_HEAD(&dev->dirty_dirs);
++ dev->oldest_dirty_seq = 0;
++ dev->oldest_dirty_block = 0;
++
++ /* Initialise temporary buffers and caches. */
++ if (!yaffs_init_tmp_buffers(dev))
++ init_failed = 1;
++
++ dev->cache = NULL;
++ dev->gc_cleanup_list = NULL;
++
++ if (!init_failed && dev->param.n_caches > 0) {
++ int i;
++ void *buf;
++ int cache_bytes =
++ dev->param.n_caches * sizeof(struct yaffs_cache);
++
++ if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
++ dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
++
++ dev->cache = YMALLOC(cache_bytes);
++
++ buf = (u8 *) dev->cache;
++
++ if (dev->cache)
++ memset(dev->cache, 0, cache_bytes);
++
++ for (i = 0; i < dev->param.n_caches && buf; i++) {
++ dev->cache[i].object = NULL;
++ dev->cache[i].last_use = 0;
++ dev->cache[i].dirty = 0;
++ dev->cache[i].data = buf =
++ YMALLOC_DMA(dev->param.total_bytes_per_chunk);
++ }
++ if (!buf)
++ init_failed = 1;
++
++ dev->cache_last_use = 0;
++ }
++
++ dev->cache_hits = 0;
++
++ if (!init_failed) {
++ dev->gc_cleanup_list =
++ YMALLOC(dev->param.chunks_per_block * sizeof(u32));
++ if (!dev->gc_cleanup_list)
++ init_failed = 1;
++ }
++
++ if (dev->param.is_yaffs2)
++ dev->param.use_header_file_size = 1;
++
++ if (!init_failed && !yaffs_init_blocks(dev))
++ init_failed = 1;
++
++ yaffs_init_tnodes_and_objs(dev);
++
++ if (!init_failed && !yaffs_create_initial_dir(dev))
++ init_failed = 1;
++
++ if (!init_failed) {
++ /* Now scan the flash. */
++ if (dev->param.is_yaffs2) {
++ if (yaffs2_checkpt_restore(dev)) {
++ yaffs_check_obj_details_loaded(dev->root_dir);
++ T(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
++ (TSTR
++ ("yaffs: restored from checkpoint"
++ TENDSTR)));
++ } else {
++
++ /* Clean up the mess caused by an aborted checkpoint load
++ * and scan backwards.
++ */
++ yaffs_deinit_blocks(dev);
++
++ yaffs_deinit_tnodes_and_objs(dev);
++
++ dev->n_erased_blocks = 0;
++ dev->n_free_chunks = 0;
++ dev->alloc_block = -1;
++ dev->alloc_page = -1;
++ dev->n_deleted_files = 0;
++ dev->n_unlinked_files = 0;
++ dev->n_bg_deletions = 0;
++
++ if (!init_failed && !yaffs_init_blocks(dev))
++ init_failed = 1;
++
++ yaffs_init_tnodes_and_objs(dev);
++
++ if (!init_failed
++ && !yaffs_create_initial_dir(dev))
++ init_failed = 1;
++
++ if (!init_failed && !yaffs2_scan_backwards(dev))
++ init_failed = 1;
++ }
++ } else if (!yaffs1_scan(dev)) {
++ init_failed = 1;
++ }
++
++ yaffs_strip_deleted_objs(dev);
++ yaffs_fix_hanging_objs(dev);
++ if (dev->param.empty_lost_n_found)
++ yaffs_empty_l_n_f(dev);
++ }
++
++ if (init_failed) {
++ /* Clean up the mess */
++ T(YAFFS_TRACE_TRACING,
++ (TSTR("yaffs: yaffs_guts_initialise() aborted.\n" TENDSTR)));
++
++ yaffs_deinitialise(dev);
++ return YAFFS_FAIL;
++ }
++
++ /* Zero out stats */
++ dev->n_page_reads = 0;
++ dev->n_page_writes = 0;
++ dev->n_erasures = 0;
++ dev->n_gc_copies = 0;
++ dev->n_retired_writes = 0;
++
++ dev->n_retired_blocks = 0;
++
++ yaffs_verify_free_chunks(dev);
++ yaffs_verify_blocks(dev);
++
++ /* Clean up any aborted checkpoint data */
++ if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
++ yaffs2_checkpt_invalidate(dev);
++
++ T(YAFFS_TRACE_TRACING,
++ (TSTR("yaffs: yaffs_guts_initialise() done.\n" TENDSTR)));
++ return YAFFS_OK;
++
++}
++
++void yaffs_deinitialise(struct yaffs_dev *dev)
++{
++ if (dev->is_mounted) {
++ int i;
++
++ yaffs_deinit_blocks(dev);
++ yaffs_deinit_tnodes_and_objs(dev);
++ if (dev->param.n_caches > 0 && dev->cache) {
++
++ for (i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].data)
++ YFREE(dev->cache[i].data);
++ dev->cache[i].data = NULL;
++ }
++
++ YFREE(dev->cache);
++ dev->cache = NULL;
++ }
++
++ YFREE(dev->gc_cleanup_list);
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
++ YFREE(dev->temp_buffer[i].buffer);
++
++ dev->is_mounted = 0;
++
++ if (dev->param.deinitialise_flash_fn)
++ dev->param.deinitialise_flash_fn(dev);
++ }
++}
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev)
++{
++ int n_free = 0;
++ int b;
++
++ struct yaffs_block_info *blk;
++
++ blk = dev->block_info;
++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++ switch (blk->block_state) {
++ case YAFFS_BLOCK_STATE_EMPTY:
++ case YAFFS_BLOCK_STATE_ALLOCATING:
++ case YAFFS_BLOCK_STATE_COLLECTING:
++ case YAFFS_BLOCK_STATE_FULL:
++ n_free +=
++ (dev->param.chunks_per_block - blk->pages_in_use +
++ blk->soft_del_pages);
++ break;
++ default:
++ break;
++ }
++ blk++;
++ }
++
++ return n_free;
++}
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
++{
++ /* This is what we report to the outside world */
++
++ int n_free;
++ int n_dirty_caches;
++ int blocks_for_checkpt;
++ int i;
++
++ n_free = dev->n_free_chunks;
++ n_free += dev->n_deleted_files;
++
++ /* Now count the number of dirty chunks in the cache and subtract those */
++
++ for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
++ if (dev->cache[i].dirty)
++ n_dirty_caches++;
++ }
++
++ n_free -= n_dirty_caches;
++
++ n_free -=
++ ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
++
++ /* Now we figure out how much to reserve for the checkpoint and report that... */
++ blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
++
++ n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
++
++ if (n_free < 0)
++ n_free = 0;
++
++ return n_free;
++
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_guts.h linux-2.6.36/fs/yaffs2/yaffs_guts.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_guts.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_guts.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,914 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GUTS_H__
++#define __YAFFS_GUTS_H__
++
++#include "yportenv.h"
++
++#define YAFFS_OK 1
++#define YAFFS_FAIL 0
++
++/* Give us a Y=0x59,
++ * Give us an A=0x41,
++ * Give us an FF=0xFF
++ * Give us an S=0x53
++ * And what have we got...
++ */
++#define YAFFS_MAGIC 0x5941FF53
++
++#define YAFFS_NTNODES_LEVEL0 16
++#define YAFFS_TNODES_LEVEL0_BITS 4
++#define YAFFS_TNODES_LEVEL0_MASK 0xf
++
++#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
++#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
++#define YAFFS_TNODES_INTERNAL_MASK 0x7
++#define YAFFS_TNODES_MAX_LEVEL 6
++
++#ifndef CONFIG_YAFFS_NO_YAFFS1
++#define YAFFS_BYTES_PER_SPARE 16
++#define YAFFS_BYTES_PER_CHUNK 512
++#define YAFFS_CHUNK_SIZE_SHIFT 9
++#define YAFFS_CHUNKS_PER_BLOCK 32
++#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
++#endif
++
++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
++#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
++
++#define YAFFS_MAX_CHUNK_ID 0x000FFFFF
++
++#define YAFFS_ALLOCATION_NOBJECTS 100
++#define YAFFS_ALLOCATION_NTNODES 100
++#define YAFFS_ALLOCATION_NLINKS 100
++
++#define YAFFS_NOBJECT_BUCKETS 256
++
++#define YAFFS_OBJECT_SPACE 0x40000
++#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1)
++
++#define YAFFS_CHECKPOINT_VERSION 4
++
++#ifdef CONFIG_YAFFS_UNICODE
++#define YAFFS_MAX_NAME_LENGTH 127
++#define YAFFS_MAX_ALIAS_LENGTH 79
++#else
++#define YAFFS_MAX_NAME_LENGTH 255
++#define YAFFS_MAX_ALIAS_LENGTH 159
++#endif
++
++#define YAFFS_SHORT_NAME_LENGTH 15
++
++/* Some special object ids for pseudo objects */
++#define YAFFS_OBJECTID_ROOT 1
++#define YAFFS_OBJECTID_LOSTNFOUND 2
++#define YAFFS_OBJECTID_UNLINKED 3
++#define YAFFS_OBJECTID_DELETED 4
++
++/* Pseudo object ids for checkpointing */
++#define YAFFS_OBJECTID_SB_HEADER 0x10
++#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
++#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
++
++#define YAFFS_MAX_SHORT_OP_CACHES 20
++
++#define YAFFS_N_TEMP_BUFFERS 6
++
++/* We limit the number attempts at sucessfully saving a chunk of data.
++ * Small-page devices have 32 pages per block; large-page devices have 64.
++ * Default to something in the order of 5 to 10 blocks worth of chunks.
++ */
++#define YAFFS_WR_ATTEMPTS (5*64)
++
++/* Sequence numbers are used in YAFFS2 to determine block allocation order.
++ * The range is limited slightly to help distinguish bad numbers from good.
++ * This also allows us to perhaps in the future use special numbers for
++ * special purposes.
++ * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
++ * and is a larger number than the lifetime of a 2GB device.
++ */
++#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
++#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00
++
++/* Special sequence number for bad block that failed to be marked bad */
++#define YAFFS_SEQUENCE_BAD_BLOCK 0xFFFF0000
++
++/* ChunkCache is used for short read/write operations.*/
++struct yaffs_cache {
++ struct yaffs_obj *object;
++ int chunk_id;
++ int last_use;
++ int dirty;
++ int n_bytes; /* Only valid if the cache is dirty */
++ int locked; /* Can't push out or flush while locked. */
++ u8 *data;
++};
++
++/* Tags structures in RAM
++ * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
++ * the structure size will get blown out.
++ */
++
++#ifndef CONFIG_YAFFS_NO_YAFFS1
++struct yaffs_tags {
++ unsigned chunk_id:20;
++ unsigned serial_number:2;
++ unsigned n_bytes_lsb:10;
++ unsigned obj_id:18;
++ unsigned ecc:12;
++ unsigned n_bytes_msb:2;
++};
++
++union yaffs_tags_union {
++ struct yaffs_tags as_tags;
++ u8 as_bytes[8];
++};
++
++#endif
++
++/* Stuff used for extended tags in YAFFS2 */
++
++enum yaffs_ecc_result {
++ YAFFS_ECC_RESULT_UNKNOWN,
++ YAFFS_ECC_RESULT_NO_ERROR,
++ YAFFS_ECC_RESULT_FIXED,
++ YAFFS_ECC_RESULT_UNFIXED
++};
++
++enum yaffs_obj_type {
++ YAFFS_OBJECT_TYPE_UNKNOWN,
++ YAFFS_OBJECT_TYPE_FILE,
++ YAFFS_OBJECT_TYPE_SYMLINK,
++ YAFFS_OBJECT_TYPE_DIRECTORY,
++ YAFFS_OBJECT_TYPE_HARDLINK,
++ YAFFS_OBJECT_TYPE_SPECIAL
++};
++
++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
++
++struct yaffs_ext_tags {
++
++ unsigned validity0;
++ unsigned chunk_used; /* Status of the chunk: used or unused */
++ unsigned obj_id; /* If 0 then this is not part of an object (unused) */
++ unsigned chunk_id; /* If 0 then this is a header, else a data chunk */
++ unsigned n_bytes; /* Only valid for data chunks */
++
++ /* The following stuff only has meaning when we read */
++ enum yaffs_ecc_result ecc_result;
++ unsigned block_bad;
++
++ /* YAFFS 1 stuff */
++ unsigned is_deleted; /* The chunk is marked deleted */
++ unsigned serial_number; /* Yaffs1 2-bit serial number */
++
++ /* YAFFS2 stuff */
++ unsigned seq_number; /* The sequence number of this block */
++
++ /* Extra info if this is an object header (YAFFS2 only) */
++
++ unsigned extra_available; /* There is extra info available if this is not zero */
++ unsigned extra_parent_id; /* The parent object */
++ unsigned extra_is_shrink; /* Is it a shrink header? */
++ unsigned extra_shadows; /* Does this shadow another object? */
++
++ enum yaffs_obj_type extra_obj_type; /* What object type? */
++
++ unsigned extra_length; /* Length if it is a file */
++ unsigned extra_equiv_id; /* Equivalent object Id if it is a hard link */
++
++ unsigned validity1;
++
++};
++
++/* Spare structure for YAFFS1 */
++struct yaffs_spare {
++ u8 tb0;
++ u8 tb1;
++ u8 tb2;
++ u8 tb3;
++ u8 page_status; /* set to 0 to delete the chunk */
++ u8 block_status;
++ u8 tb4;
++ u8 tb5;
++ u8 ecc1[3];
++ u8 tb6;
++ u8 tb7;
++ u8 ecc2[3];
++};
++
++/*Special structure for passing through to mtd */
++struct yaffs_nand_spare {
++ struct yaffs_spare spare;
++ int eccres1;
++ int eccres2;
++};
++
++/* Block data in RAM */
++
++enum yaffs_block_state {
++ YAFFS_BLOCK_STATE_UNKNOWN = 0,
++
++ YAFFS_BLOCK_STATE_SCANNING,
++ /* Being scanned */
++
++ YAFFS_BLOCK_STATE_NEEDS_SCANNING,
++ /* The block might have something on it (ie it is allocating or full, perhaps empty)
++ * but it needs to be scanned to determine its true state.
++ * This state is only valid during scanning.
++ * NB We tolerate empty because the pre-scanner might be incapable of deciding
++ * However, if this state is returned on a YAFFS2 device, then we expect a sequence number
++ */
++
++ YAFFS_BLOCK_STATE_EMPTY,
++ /* This block is empty */
++
++ YAFFS_BLOCK_STATE_ALLOCATING,
++ /* This block is partially allocated.
++ * At least one page holds valid data.
++ * This is the one currently being used for page
++ * allocation. Should never be more than one of these.
++ * If a block is only partially allocated at mount it is treated as full.
++ */
++
++ YAFFS_BLOCK_STATE_FULL,
++ /* All the pages in this block have been allocated.
++ * If a block was only partially allocated when mounted we treat
++ * it as fully allocated.
++ */
++
++ YAFFS_BLOCK_STATE_DIRTY,
++ /* The block was full and now all chunks have been deleted.
++ * Erase me, reuse me.
++ */
++
++ YAFFS_BLOCK_STATE_CHECKPOINT,
++ /* This block is assigned to holding checkpoint data. */
++
++ YAFFS_BLOCK_STATE_COLLECTING,
++ /* This block is being garbage collected */
++
++ YAFFS_BLOCK_STATE_DEAD
++ /* This block has failed and is not in use */
++};
++
++#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
++
++struct yaffs_block_info {
++
++ int soft_del_pages:10; /* number of soft deleted pages */
++ int pages_in_use:10; /* number of pages in use */
++ unsigned block_state:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
++ u32 needs_retiring:1; /* Data has failed on this block, need to get valid data off */
++ /* and retire the block. */
++ u32 skip_erased_check:1; /* If this is set we can skip the erased check on this block */
++ u32 gc_prioritise:1; /* An ECC check or blank check has failed on this block.
++ It should be prioritised for GC */
++ u32 chunk_error_strikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
++
++#ifdef CONFIG_YAFFS_YAFFS2
++ u32 has_shrink_hdr:1; /* This block has at least one shrink object header */
++ u32 seq_number; /* block sequence number for yaffs2 */
++#endif
++
++};
++
++/* -------------------------- Object structure -------------------------------*/
++/* This is the object structure as stored on NAND */
++
++struct yaffs_obj_hdr {
++ enum yaffs_obj_type type;
++
++ /* Apply to everything */
++ int parent_obj_id;
++ u16 sum_no_longer_used; /* checksum of name. No longer used */
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ /* The following apply to directories, files, symlinks - not hard links */
++ u32 yst_mode; /* protection */
++
++ u32 yst_uid;
++ u32 yst_gid;
++ u32 yst_atime;
++ u32 yst_mtime;
++ u32 yst_ctime;
++
++ /* File size applies to files only */
++ int file_size;
++
++ /* Equivalent object id applies to hard links only. */
++ int equiv_id;
++
++ /* Alias is for symlinks only. */
++ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
++
++ u32 yst_rdev; /* device stuff for block and char devices (major/min) */
++
++ u32 win_ctime[2];
++ u32 win_atime[2];
++ u32 win_mtime[2];
++
++ u32 inband_shadowed_obj_id;
++ u32 inband_is_shrink;
++
++ u32 reserved[2];
++ int shadows_obj; /* This object header shadows the specified object if > 0 */
++
++ /* is_shrink applies to object headers written when we shrink the file (ie resize) */
++ u32 is_shrink;
++
++};
++
++/*--------------------------- Tnode -------------------------- */
++
++struct yaffs_tnode {
++ struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
++};
++
++/*------------------------ Object -----------------------------*/
++/* An object can be one of:
++ * - a directory (no data, has children links
++ * - a regular file (data.... not prunes :->).
++ * - a symlink [symbolic link] (the alias).
++ * - a hard link
++ */
++
++struct yaffs_file_var {
++ u32 file_size;
++ u32 scanned_size;
++ u32 shrink_size;
++ int top_level;
++ struct yaffs_tnode *top;
++};
++
++struct yaffs_dir_var {
++ struct list_head children; /* list of child links */
++ struct list_head dirty; /* Entry for list of dirty directories */
++};
++
++struct yaffs_symlink_var {
++ YCHAR *alias;
++};
++
++struct yaffs_hardlink_var {
++ struct yaffs_obj *equiv_obj;
++ u32 equiv_id;
++};
++
++union yaffs_obj_var {
++ struct yaffs_file_var file_variant;
++ struct yaffs_dir_var dir_variant;
++ struct yaffs_symlink_var symlink_variant;
++ struct yaffs_hardlink_var hardlink_variant;
++};
++
++struct yaffs_obj {
++ u8 deleted:1; /* This should only apply to unlinked files. */
++ u8 soft_del:1; /* it has also been soft deleted */
++ u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory. */
++ u8 fake:1; /* A fake object has no presence on NAND. */
++ u8 rename_allowed:1; /* Some objects are not allowed to be renamed. */
++ u8 unlink_allowed:1;
++ u8 dirty:1; /* the object needs to be written to flash */
++ u8 valid:1; /* When the file system is being loaded up, this
++ * object might be created before the data
++ * is available (ie. file data records appear before the header).
++ */
++ u8 lazy_loaded:1; /* This object has been lazy loaded and is missing some detail */
++
++ u8 defered_free:1; /* For Linux kernel. Object is removed from NAND, but is
++ * still in the inode cache. Free of object is defered.
++ * until the inode is released.
++ */
++ u8 being_created:1; /* This object is still being created so skip some checks. */
++ u8 is_shadowed:1; /* This object is shadowed on the way to being renamed. */
++
++ u8 xattr_known:1; /* We know if this has object has xattribs or not. */
++ u8 has_xattr:1; /* This object has xattribs. Valid if xattr_known. */
++
++ u8 serial; /* serial number of chunk in NAND. Cached here */
++ u16 sum; /* sum of the name to speed searching */
++
++ struct yaffs_dev *my_dev; /* The device I'm on */
++
++ struct list_head hash_link; /* list of objects in this hash bucket */
++
++ struct list_head hard_links; /* all the equivalent hard linked objects */
++
++ /* directory structure stuff */
++ /* also used for linking up the free list */
++ struct yaffs_obj *parent;
++ struct list_head siblings;
++
++ /* Where's my object header in NAND? */
++ int hdr_chunk;
++
++ int n_data_chunks; /* Number of data chunks attached to the file. */
++
++ u32 obj_id; /* the object id value */
++
++ u32 yst_mode;
++
++#ifndef CONFIG_YAFFS_NO_SHORT_NAMES
++ YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
++#endif
++
++#ifdef CONFIG_YAFFS_WINCE
++ u32 win_ctime[2];
++ u32 win_mtime[2];
++ u32 win_atime[2];
++#else
++ u32 yst_uid;
++ u32 yst_gid;
++ u32 yst_atime;
++ u32 yst_mtime;
++ u32 yst_ctime;
++#endif
++
++ u32 yst_rdev;
++
++ void *my_inode;
++
++ enum yaffs_obj_type variant_type;
++
++ union yaffs_obj_var variant;
++
++};
++
++struct yaffs_obj_bucket {
++ struct list_head list;
++ int count;
++};
++
++/* yaffs_checkpt_obj holds the definition of an object as dumped
++ * by checkpointing.
++ */
++
++struct yaffs_checkpt_obj {
++ int struct_type;
++ u32 obj_id;
++ u32 parent_id;
++ int hdr_chunk;
++ enum yaffs_obj_type variant_type:3;
++ u8 deleted:1;
++ u8 soft_del:1;
++ u8 unlinked:1;
++ u8 fake:1;
++ u8 rename_allowed:1;
++ u8 unlink_allowed:1;
++ u8 serial;
++ int n_data_chunks;
++ u32 size_or_equiv_obj;
++};
++
++/*--------------------- Temporary buffers ----------------
++ *
++ * These are chunk-sized working buffers. Each device has a few
++ */
++
++struct yaffs_buffer {
++ u8 *buffer;
++ int line; /* track from whence this buffer was allocated */
++ int max_line;
++};
++
++/*----------------- Device ---------------------------------*/
++
++struct yaffs_param {
++ const YCHAR *name;
++
++ /*
++ * Entry parameters set up way early. Yaffs sets up the rest.
++ * The structure should be zeroed out before use so that unused
++ * and defualt values are zero.
++ */
++
++ int inband_tags; /* Use unband tags */
++ u32 total_bytes_per_chunk; /* Should be >= 512, does not need to be a power of 2 */
++ int chunks_per_block; /* does not need to be a power of 2 */
++ int spare_bytes_per_chunk; /* spare area size */
++ int start_block; /* Start block we're allowed to use */
++ int end_block; /* End block we're allowed to use */
++ int n_reserved_blocks; /* We want this tuneable so that we can reduce */
++ /* reserved blocks on NOR and RAM. */
++
++ int n_caches; /* If <= 0, then short op caching is disabled, else
++ * the number of short op caches (don't use too many).
++ * 10 to 20 is a good bet.
++ */
++ int use_nand_ecc; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */
++ int no_tags_ecc; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */
++
++ int is_yaffs2; /* Use yaffs2 mode on this device */
++
++ int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
++
++ int refresh_period; /* How often we should check to do a block refresh */
++
++ /* Checkpoint control. Can be set before or after initialisation */
++ u8 skip_checkpt_rd;
++ u8 skip_checkpt_wr;
++
++ int enable_xattr; /* Enable xattribs */
++
++ /* NAND access functions (Must be set before calling YAFFS) */
++
++ int (*write_chunk_fn) (struct yaffs_dev * dev,
++ int nand_chunk, const u8 * data,
++ const struct yaffs_spare * spare);
++ int (*read_chunk_fn) (struct yaffs_dev * dev,
++ int nand_chunk, u8 * data,
++ struct yaffs_spare * spare);
++ int (*erase_fn) (struct yaffs_dev * dev, int flash_block);
++ int (*initialise_flash_fn) (struct yaffs_dev * dev);
++ int (*deinitialise_flash_fn) (struct yaffs_dev * dev);
++
++#ifdef CONFIG_YAFFS_YAFFS2
++ int (*write_chunk_tags_fn) (struct yaffs_dev * dev,
++ int nand_chunk, const u8 * data,
++ const struct yaffs_ext_tags * tags);
++ int (*read_chunk_tags_fn) (struct yaffs_dev * dev,
++ int nand_chunk, u8 * data,
++ struct yaffs_ext_tags * tags);
++ int (*bad_block_fn) (struct yaffs_dev * dev, int block_no);
++ int (*query_block_fn) (struct yaffs_dev * dev, int block_no,
++ enum yaffs_block_state * state,
++ u32 * seq_number);
++#endif
++
++ /* The remove_obj_fn function must be supplied by OS flavours that
++ * need it.
++ * yaffs direct uses it to implement the faster readdir.
++ * Linux uses it to protect the directory during unlocking.
++ */
++ void (*remove_obj_fn) (struct yaffs_obj * obj);
++
++ /* Callback to mark the superblock dirty */
++ void (*sb_dirty_fn) (struct yaffs_dev * dev);
++
++ /* Callback to control garbage collection. */
++ unsigned (*gc_control) (struct yaffs_dev * dev);
++
++ /* Debug control flags. Don't use unless you know what you're doing */
++ int use_header_file_size; /* Flag to determine if we should use file sizes from the header */
++ int disable_lazy_load; /* Disable lazy loading on this device */
++ int wide_tnodes_disabled; /* Set to disable wide tnodes */
++ int disable_soft_del; /* yaffs 1 only: Set to disable the use of softdeletion. */
++
++ int defered_dir_update; /* Set to defer directory updates */
++
++#ifdef CONFIG_YAFFS_AUTO_UNICODE
++ int auto_unicode;
++#endif
++ int always_check_erased; /* Force chunk erased check always on */
++};
++
++struct yaffs_dev {
++ struct yaffs_param param;
++
++ /* Context storage. Holds extra OS specific data for this device */
++
++ void *os_context;
++ void *driver_context;
++
++ struct list_head dev_list;
++
++ /* Runtime parameters. Set up by YAFFS. */
++ int data_bytes_per_chunk;
++
++ /* Non-wide tnode stuff */
++ u16 chunk_grp_bits; /* Number of bits that need to be resolved if
++ * the tnodes are not wide enough.
++ */
++ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
++
++ /* Stuff to support wide tnodes */
++ u32 tnode_width;
++ u32 tnode_mask;
++ u32 tnode_size;
++
++ /* Stuff for figuring out file offset to chunk conversions */
++ u32 chunk_shift; /* Shift value */
++ u32 chunk_div; /* Divisor after shifting: 1 for power-of-2 sizes */
++ u32 chunk_mask; /* Mask to use for power-of-2 case */
++
++ int is_mounted;
++ int read_only;
++ int is_checkpointed;
++
++ /* Stuff to support block offsetting to support start block zero */
++ int internal_start_block;
++ int internal_end_block;
++ int block_offset;
++ int chunk_offset;
++
++ /* Runtime checkpointing stuff */
++ int checkpt_page_seq; /* running sequence number of checkpoint pages */
++ int checkpt_byte_count;
++ int checkpt_byte_offs;
++ u8 *checkpt_buffer;
++ int checkpt_open_write;
++ int blocks_in_checkpt;
++ int checkpt_cur_chunk;
++ int checkpt_cur_block;
++ int checkpt_next_block;
++ int *checkpt_block_list;
++ int checkpt_max_blocks;
++ u32 checkpt_sum;
++ u32 checkpt_xor;
++
++ int checkpoint_blocks_required; /* Number of blocks needed to store current checkpoint set */
++
++ /* Block Info */
++ struct yaffs_block_info *block_info;
++ u8 *chunk_bits; /* bitmap of chunks in use */
++ unsigned block_info_alt:1; /* was allocated using alternative strategy */
++ unsigned chunk_bits_alt:1; /* was allocated using alternative strategy */
++ int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
++ * Must be consistent with chunks_per_block.
++ */
++
++ int n_erased_blocks;
++ int alloc_block; /* Current block being allocated off */
++ u32 alloc_page;
++ int alloc_block_finder; /* Used to search for next allocation block */
++
++ /* Object and Tnode memory management */
++ void *allocator;
++ int n_obj;
++ int n_tnodes;
++
++ int n_hardlinks;
++
++ struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
++ u32 bucket_finder;
++
++ int n_free_chunks;
++
++ /* Garbage collection control */
++ u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
++ u32 n_clean_ups;
++
++ unsigned has_pending_prioritised_gc; /* We think this device might have pending prioritised gcs */
++ unsigned gc_disable;
++ unsigned gc_block_finder;
++ unsigned gc_dirtiest;
++ unsigned gc_pages_in_use;
++ unsigned gc_not_done;
++ unsigned gc_block;
++ unsigned gc_chunk;
++ unsigned gc_skip;
++
++ /* Special directories */
++ struct yaffs_obj *root_dir;
++ struct yaffs_obj *lost_n_found;
++
++ /* Buffer areas for storing data to recover from write failures TODO
++ * u8 buffered_data[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
++ * struct yaffs_spare buffered_spare[YAFFS_CHUNKS_PER_BLOCK];
++ */
++
++ int buffered_block; /* Which block is buffered here? */
++ int doing_buffered_block_rewrite;
++
++ struct yaffs_cache *cache;
++ int cache_last_use;
++
++ /* Stuff for background deletion and unlinked files. */
++ struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted files live. */
++ struct yaffs_obj *del_dir; /* Directory where deleted objects are sent to disappear. */
++ struct yaffs_obj *unlinked_deletion; /* Current file being background deleted. */
++ int n_deleted_files; /* Count of files awaiting deletion; */
++ int n_unlinked_files; /* Count of unlinked files. */
++ int n_bg_deletions; /* Count of background deletions. */
++
++ /* Temporary buffer management */
++ struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
++ int max_temp;
++ int temp_in_use;
++ int unmanaged_buffer_allocs;
++ int unmanaged_buffer_deallocs;
++
++ /* yaffs2 runtime stuff */
++ unsigned seq_number; /* Sequence number of currently allocating block */
++ unsigned oldest_dirty_seq;
++ unsigned oldest_dirty_block;
++
++ /* Block refreshing */
++ int refresh_skip; /* A skip down counter. Refresh happens when this gets to zero. */
++
++ /* Dirty directory handling */
++ struct list_head dirty_dirs; /* List of dirty directories */
++
++ /* Statistcs */
++ u32 n_page_writes;
++ u32 n_page_reads;
++ u32 n_erasures;
++ u32 n_erase_failures;
++ u32 n_gc_copies;
++ u32 all_gcs;
++ u32 passive_gc_count;
++ u32 oldest_dirty_gc_count;
++ u32 n_gc_blocks;
++ u32 bg_gcs;
++ u32 n_retired_writes;
++ u32 n_retired_blocks;
++ u32 n_ecc_fixed;
++ u32 n_ecc_unfixed;
++ u32 n_tags_ecc_fixed;
++ u32 n_tags_ecc_unfixed;
++ u32 n_deletions;
++ u32 n_unmarked_deletions;
++ u32 refresh_count;
++ u32 cache_hits;
++
++};
++
++/* The CheckpointDevice structure holds the device information that changes at runtime and
++ * must be preserved over unmount/mount cycles.
++ */
++struct yaffs_checkpt_dev {
++ int struct_type;
++ int n_erased_blocks;
++ int alloc_block; /* Current block being allocated off */
++ u32 alloc_page;
++ int n_free_chunks;
++
++ int n_deleted_files; /* Count of files awaiting deletion; */
++ int n_unlinked_files; /* Count of unlinked files. */
++ int n_bg_deletions; /* Count of background deletions. */
++
++ /* yaffs2 runtime stuff */
++ unsigned seq_number; /* Sequence number of currently allocating block */
++
++};
++
++struct yaffs_checkpt_validity {
++ int struct_type;
++ u32 magic;
++ u32 version;
++ u32 head;
++};
++
++struct yaffs_shadow_fixer {
++ int obj_id;
++ int shadowed_id;
++ struct yaffs_shadow_fixer *next;
++};
++
++/* Structure for doing xattr modifications */
++struct yaffs_xattr_mod {
++ int set; /* If 0 then this is a deletion */
++ const YCHAR *name;
++ const void *data;
++ int size;
++ int flags;
++ int result;
++};
++
++/*----------------------- YAFFS Functions -----------------------*/
++
++int yaffs_guts_initialise(struct yaffs_dev *dev);
++void yaffs_deinitialise(struct yaffs_dev *dev);
++
++int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
++ struct yaffs_obj *new_dir, const YCHAR * new_name);
++
++int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
++int yaffs_del_obj(struct yaffs_obj *obj);
++
++int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
++int yaffs_get_obj_length(struct yaffs_obj *obj);
++int yaffs_get_obj_inode(struct yaffs_obj *obj);
++unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
++int yaffs_get_obj_link_count(struct yaffs_obj *obj);
++
++/* File operations */
++int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
++ int n_bytes);
++int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
++ int n_bytes, int write_trhrough);
++int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
++
++struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
++ const YCHAR * name, u32 mode, u32 uid,
++ u32 gid);
++
++int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
++
++/* Flushing and checkpointing */
++void yaffs_flush_whole_cache(struct yaffs_dev *dev);
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev);
++int yaffs_checkpoint_restore(struct yaffs_dev *dev);
++
++/* Directory operations */
++struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR * name,
++ u32 mode, u32 uid, u32 gid);
++struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
++ const YCHAR * name);
++struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
++
++/* Link operations */
++struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
++ struct yaffs_obj *equiv_obj);
++
++struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
++
++/* Symlink operations */
++struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
++ const YCHAR * name, u32 mode, u32 uid,
++ u32 gid, const YCHAR * alias);
++YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
++
++/* Special inodes (fifos, sockets and devices) */
++struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
++ const YCHAR * name, u32 mode, u32 uid,
++ u32 gid, u32 rdev);
++
++int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
++ const void *value, int size, int flags);
++int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
++ int size);
++int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
++int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name);
++
++/* Special directories */
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
++
++void yaffs_handle_defered_free(struct yaffs_obj *obj);
++
++void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
++
++int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
++
++/* Debug dump */
++int yaffs_dump_obj(struct yaffs_obj *obj);
++
++void yaffs_guts_test(struct yaffs_dev *dev);
++
++/* A few useful functions to be used within the core files*/
++void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
++ int lyn);
++int yaffs_check_ff(u8 * buffer, int n_bytes);
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi);
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev, int line_no);
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 * buffer, int line_no);
++
++struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
++ int number,
++ enum yaffs_obj_type type);
++int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
++ int nand_chunk, int in_scan);
++void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name);
++void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
++ const struct yaffs_obj_hdr *oh);
++void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
++YCHAR *yaffs_clone_str(const YCHAR * str);
++void yaffs_link_fixup(struct yaffs_dev *dev, struct yaffs_obj *hard_list);
++void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
++int yaffs_update_oh(struct yaffs_obj *in, const YCHAR * name,
++ int force, int is_shrink, int shadows,
++ struct yaffs_xattr_mod *xop);
++void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
++ int backward_scanning);
++int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
++struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
++struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id,
++ struct yaffs_tnode *passed_tn);
++
++int yaffs_do_file_wr(struct yaffs_obj *in, const u8 * buffer, loff_t offset,
++ int n_bytes, int write_trhrough);
++void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
++void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
++
++int yaffs_count_free_chunks(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
++ struct yaffs_file_var *file_struct,
++ u32 chunk_id);
++
++u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
++ unsigned pos);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_linux.h linux-2.6.36/fs/yaffs2/yaffs_linux.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_linux.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_linux.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,41 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_LINUX_H__
++#define __YAFFS_LINUX_H__
++
++#include "yportenv.h"
++
++struct yaffs_linux_context {
++ struct list_head context_list; /* List of these we have mounted */
++ struct yaffs_dev *dev;
++ struct super_block *super;
++ struct task_struct *bg_thread; /* Background thread for this device */
++ int bg_running;
++ struct mutex gross_lock; /* Gross locking mutex*/
++ u8 *spare_buffer; /* For mtdif2 use. Don't know the size of the buffer
++ * at compile time so we have to allocate it.
++ */
++ struct list_head search_contexts;
++ void (*put_super_fn) (struct super_block * sb);
++
++ struct task_struct *readdir_process;
++ unsigned mount_id;
++};
++
++#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
++#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif.c linux-2.6.36/fs/yaffs2/yaffs_mtdif.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,54 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_mtdif.h"
++
++#include "linux/mtd/mtd.h"
++#include "linux/types.h"
++#include "linux/time.h"
++#include "linux/mtd/nand.h"
++
++#include "yaffs_linux.h"
++
++int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ u32 addr =
++ ((loff_t) block_no) * dev->param.total_bytes_per_chunk
++ * dev->param.chunks_per_block;
++ struct erase_info ei;
++
++ int retval = 0;
++
++ ei.mtd = mtd;
++ ei.addr = addr;
++ ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
++ ei.time = 1000;
++ ei.retries = 2;
++ ei.callback = NULL;
++ ei.priv = (u_long) dev;
++
++ retval = mtd->erase(mtd, &ei);
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++int nandmtd_initialise(struct yaffs_dev *dev)
++{
++ return YAFFS_OK;
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif.h linux-2.6.36/fs/yaffs2/yaffs_mtdif.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,23 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_MTDIF_H__
++#define __YAFFS_MTDIF_H__
++
++#include "yaffs_guts.h"
++
++int nandmtd_erase_block(struct yaffs_dev *dev, int block_no);
++int nandmtd_initialise(struct yaffs_dev *dev);
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif1.c linux-2.6.36/fs/yaffs2/yaffs_mtdif1.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif1.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,365 @@
++/*
++ * YAFFS: Yet another FFS. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This module provides the interface between yaffs_nand.c and the
++ * MTD API. This version is used when the MTD interface supports the
++ * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
++ * and we have small-page NAND device.
++ *
++ * These functions are invoked via function pointers in yaffs_nand.c.
++ * This replaces functionality provided by functions in yaffs_mtdif.c
++ * and the yaffs_tags compatability functions in yaffs_tagscompat.c that are
++ * called in yaffs_mtdif.c when the function pointers are NULL.
++ * We assume the MTD layer is performing ECC (use_nand_ecc is true).
++ */
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_packedtags1.h"
++#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */
++#include "yaffs_linux.h"
++
++#include "linux/kernel.h"
++#include "linux/version.h"
++#include "linux/types.h"
++#include "linux/mtd/mtd.h"
++
++/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
++
++#ifndef CONFIG_YAFFS_9BYTE_TAGS
++# define YTAG1_SIZE 8
++#else
++# define YTAG1_SIZE 9
++#endif
++
++#if 0
++/* Use the following nand_ecclayout with MTD when using
++ * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
++ * If you have existing Yaffs images and the byte order differs from this,
++ * adjust 'oobfree' to match your existing Yaffs data.
++ *
++ * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
++ * page_status byte (at NAND spare offset 4) scattered/gathered from/to
++ * the 9th byte.
++ *
++ * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
++ * We have/need packed_tags1 plus page_status: T0,T1,T2,T3,T4,T5,T6,T7,P
++ * where Tn are the tag bytes, En are MTD's ECC bytes, P is the page_status
++ * byte and B is the small-page bad-block indicator byte.
++ */
++static struct nand_ecclayout nand_oob_16 = {
++ .eccbytes = 6,
++ .eccpos = {8, 9, 10, 13, 14, 15},
++ .oobavail = 9,
++ .oobfree = {{0, 4}, {6, 2}, {11, 2}, {4, 1}}
++};
++#endif
++
++/* Write a chunk (page) of data to NAND.
++ *
++ * Caller always provides ExtendedTags data which are converted to a more
++ * compact (packed) form for storage in NAND. A mini-ECC runs over the
++ * contents of the tags meta-data; used to valid the tags when read.
++ *
++ * - Pack ExtendedTags to packed_tags1 form
++ * - Compute mini-ECC for packed_tags1
++ * - Write data and packed tags to NAND.
++ *
++ * Note: Due to the use of the packed_tags1 meta-data which does not include
++ * a full sequence number (as found in the larger packed_tags2 form) it is
++ * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
++ * discarded and dirty. This is not ideal: newer NAND parts are supposed
++ * to be written just once. When Yaffs performs this operation, this
++ * function is called with a NULL data pointer -- calling MTD write_oob
++ * without data is valid usage (2.6.17).
++ *
++ * Any underlying MTD error results in YAFFS_FAIL.
++ * Returns YAFFS_OK or YAFFS_FAIL.
++ */
++int nandmtd1_write_chunk_tags(struct yaffs_dev *dev,
++ int nand_chunk, const u8 * data,
++ const struct yaffs_ext_tags *etags)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int chunk_bytes = dev->data_bytes_per_chunk;
++ loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
++ struct mtd_oob_ops ops;
++ struct yaffs_packed_tags1 pt1;
++ int retval;
++
++ /* we assume that packed_tags1 and struct yaffs_tags are compatible */
++ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
++ compile_time_assertion(sizeof(struct yaffs_tags) == 8);
++
++ yaffs_pack_tags1(&pt1, etags);
++ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
++
++ /* When deleting a chunk, the upper layer provides only skeletal
++ * etags, one with is_deleted set. However, we need to update the
++ * tags, not erase them completely. So we use the NAND write property
++ * that only zeroed-bits stick and set tag bytes to all-ones and
++ * zero just the (not) deleted bit.
++ */
++#ifndef CONFIG_YAFFS_9BYTE_TAGS
++ if (etags->is_deleted) {
++ memset(&pt1, 0xff, 8);
++ /* clear delete status bit to indicate deleted */
++ pt1.deleted = 0;
++ }
++#else
++ ((u8 *) & pt1)[8] = 0xff;
++ if (etags->is_deleted) {
++ memset(&pt1, 0xff, 8);
++ /* zero page_status byte to indicate deleted */
++ ((u8 *) & pt1)[8] = 0;
++ }
++#endif
++
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OOB_AUTO;
++ ops.len = (data) ? chunk_bytes : 0;
++ ops.ooblen = YTAG1_SIZE;
++ ops.datbuf = (u8 *) data;
++ ops.oobbuf = (u8 *) & pt1;
++
++ retval = mtd->write_oob(mtd, addr, &ops);
++ if (retval) {
++ T(YAFFS_TRACE_MTD,
++ (TSTR("write_oob failed, chunk %d, mtd error %d" TENDSTR),
++ nand_chunk, retval));
++ }
++ return retval ? YAFFS_FAIL : YAFFS_OK;
++}
++
++/* Return with empty ExtendedTags but add ecc_result.
++ */
++static int rettags(struct yaffs_ext_tags *etags, int ecc_result, int retval)
++{
++ if (etags) {
++ memset(etags, 0, sizeof(*etags));
++ etags->ecc_result = ecc_result;
++ }
++ return retval;
++}
++
++/* Read a chunk (page) from NAND.
++ *
++ * Caller expects ExtendedTags data to be usable even on error; that is,
++ * all members except ecc_result and block_bad are zeroed.
++ *
++ * - Check ECC results for data (if applicable)
++ * - Check for blank/erased block (return empty ExtendedTags if blank)
++ * - Check the packed_tags1 mini-ECC (correct if necessary/possible)
++ * - Convert packed_tags1 to ExtendedTags
++ * - Update ecc_result and block_bad members to refect state.
++ *
++ * Returns YAFFS_OK or YAFFS_FAIL.
++ */
++int nandmtd1_read_chunk_tags(struct yaffs_dev *dev,
++ int nand_chunk, u8 * data,
++ struct yaffs_ext_tags *etags)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int chunk_bytes = dev->data_bytes_per_chunk;
++ loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
++ int eccres = YAFFS_ECC_RESULT_NO_ERROR;
++ struct mtd_oob_ops ops;
++ struct yaffs_packed_tags1 pt1;
++ int retval;
++ int deleted;
++
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OOB_AUTO;
++ ops.len = (data) ? chunk_bytes : 0;
++ ops.ooblen = YTAG1_SIZE;
++ ops.datbuf = data;
++ ops.oobbuf = (u8 *) & pt1;
++
++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
++ /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
++ * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
++ */
++ ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
++#endif
++ /* Read page and oob using MTD.
++ * Check status and determine ECC result.
++ */
++ retval = mtd->read_oob(mtd, addr, &ops);
++ if (retval) {
++ T(YAFFS_TRACE_MTD,
++ (TSTR("read_oob failed, chunk %d, mtd error %d" TENDSTR),
++ nand_chunk, retval));
++ }
++
++ switch (retval) {
++ case 0:
++ /* no error */
++ break;
++
++ case -EUCLEAN:
++ /* MTD's ECC fixed the data */
++ eccres = YAFFS_ECC_RESULT_FIXED;
++ dev->n_ecc_fixed++;
++ break;
++
++ case -EBADMSG:
++ /* MTD's ECC could not fix the data */
++ dev->n_ecc_unfixed++;
++ /* fall into... */
++ default:
++ rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
++ etags->block_bad = (mtd->block_isbad) (mtd, addr);
++ return YAFFS_FAIL;
++ }
++
++ /* Check for a blank/erased chunk.
++ */
++ if (yaffs_check_ff((u8 *) & pt1, 8)) {
++ /* when blank, upper layers want ecc_result to be <= NO_ERROR */
++ return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
++ }
++#ifndef CONFIG_YAFFS_9BYTE_TAGS
++ /* Read deleted status (bit) then return it to it's non-deleted
++ * state before performing tags mini-ECC check. pt1.deleted is
++ * inverted.
++ */
++ deleted = !pt1.deleted;
++ pt1.deleted = 1;
++#else
++ deleted = (yaffs_count_bits(((u8 *) & pt1)[8]) < 7);
++#endif
++
++ /* Check the packed tags mini-ECC and correct if necessary/possible.
++ */
++ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
++ switch (retval) {
++ case 0:
++ /* no tags error, use MTD result */
++ break;
++ case 1:
++ /* recovered tags-ECC error */
++ dev->n_tags_ecc_fixed++;
++ if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
++ eccres = YAFFS_ECC_RESULT_FIXED;
++ break;
++ default:
++ /* unrecovered tags-ECC error */
++ dev->n_tags_ecc_unfixed++;
++ return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
++ }
++
++ /* Unpack the tags to extended form and set ECC result.
++ * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
++ */
++ pt1.should_be_ff = 0xFFFFFFFF;
++ yaffs_unpack_tags1(etags, &pt1);
++ etags->ecc_result = eccres;
++
++ /* Set deleted state */
++ etags->is_deleted = deleted;
++ return YAFFS_OK;
++}
++
++/* Mark a block bad.
++ *
++ * This is a persistant state.
++ * Use of this function should be rare.
++ *
++ * Returns YAFFS_OK or YAFFS_FAIL.
++ */
++int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
++ int retval;
++
++ T(YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("marking block %d bad" TENDSTR), block_no));
++
++ retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
++ return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++/* Check any MTD prerequists.
++ *
++ * Returns YAFFS_OK or YAFFS_FAIL.
++ */
++static int nandmtd1_test_prerequists(struct mtd_info *mtd)
++{
++ /* 2.6.18 has mtd->ecclayout->oobavail */
++ /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
++ int oobavail = mtd->ecclayout->oobavail;
++
++ if (oobavail < YTAG1_SIZE) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("mtd device has only %d bytes for tags, need %d" TENDSTR),
++ oobavail, YTAG1_SIZE));
++ return YAFFS_FAIL;
++ }
++ return YAFFS_OK;
++}
++
++/* Query for the current state of a specific block.
++ *
++ * Examine the tags of the first chunk of the block and return the state:
++ * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
++ * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
++ * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
++ *
++ * Always returns YAFFS_OK.
++ */
++int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state_ptr, u32 * seq_ptr)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int chunk_num = block_no * dev->param.chunks_per_block;
++ loff_t addr = (loff_t) chunk_num * dev->data_bytes_per_chunk;
++ struct yaffs_ext_tags etags;
++ int state = YAFFS_BLOCK_STATE_DEAD;
++ int seqnum = 0;
++ int retval;
++
++ /* We don't yet have a good place to test for MTD config prerequists.
++ * Do it here as we are called during the initial scan.
++ */
++ if (nandmtd1_test_prerequists(mtd) != YAFFS_OK)
++ return YAFFS_FAIL;
++
++ retval = nandmtd1_read_chunk_tags(dev, chunk_num, NULL, &etags);
++ etags.block_bad = (mtd->block_isbad) (mtd, addr);
++ if (etags.block_bad) {
++ T(YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("block %d is marked bad" TENDSTR), block_no));
++ state = YAFFS_BLOCK_STATE_DEAD;
++ } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
++ /* bad tags, need to look more closely */
++ state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
++ } else if (etags.chunk_used) {
++ state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
++ seqnum = etags.seq_number;
++ } else {
++ state = YAFFS_BLOCK_STATE_EMPTY;
++ }
++
++ *state_ptr = state;
++ *seq_ptr = seqnum;
++
++ /* query always succeeds */
++ return YAFFS_OK;
++}
++
++#endif /*MTD_VERSION */
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif1.h linux-2.6.36/fs/yaffs2/yaffs_mtdif1.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif1.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,29 @@
++/*
++ * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_MTDIF1_H__
++#define __YAFFS_MTDIF1_H__
++
++int nandmtd1_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
++ const u8 * data,
++ const struct yaffs_ext_tags *tags);
++
++int nandmtd1_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
++ u8 * data, struct yaffs_ext_tags *tags);
++
++int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no);
++
++int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state, u32 * seq_number);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif2.c linux-2.6.36/fs/yaffs2/yaffs_mtdif2.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif2.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,261 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* mtd interface for YAFFS2 */
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++#include "yaffs_mtdif2.h"
++
++#include "linux/mtd/mtd.h"
++#include "linux/types.h"
++#include "linux/time.h"
++
++#include "yaffs_packedtags2.h"
++
++#include "yaffs_linux.h"
++
++/* NB For use with inband tags....
++ * We assume that the data buffer is of size total_bytes_per_chunk so that we can also
++ * use it to load the tags.
++ */
++int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
++ const u8 * data,
++ const struct yaffs_ext_tags *tags)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
++ struct mtd_oob_ops ops;
++#else
++ size_t dummy;
++#endif
++ int retval = 0;
++
++ loff_t addr;
++
++ struct yaffs_packed_tags2 pt;
++
++ int packed_tags_size =
++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++ void *packed_tags_ptr =
++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++ T(YAFFS_TRACE_MTD,
++ (TSTR
++ ("nandmtd2_write_chunk_tags chunk %d data %p tags %p"
++ TENDSTR), nand_chunk, data, tags));
++
++ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++
++ /* For yaffs2 writing there must be both data and tags.
++ * If we're using inband tags, then the tags are stuffed into
++ * the end of the data buffer.
++ */
++ if (!data || !tags)
++ BUG();
++ else if (dev->param.inband_tags) {
++ struct yaffs_packed_tags2_tags_only *pt2tp;
++ pt2tp =
++ (struct yaffs_packed_tags2_tags_only *)(data +
++ dev->
++ data_bytes_per_chunk);
++ yaffs_pack_tags2_tags_only(pt2tp, tags);
++ } else {
++ yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
++ }
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ ops.mode = MTD_OOB_AUTO;
++ ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
++ ops.len = dev->param.total_bytes_per_chunk;
++ ops.ooboffs = 0;
++ ops.datbuf = (u8 *) data;
++ ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
++ retval = mtd->write_oob(mtd, addr, &ops);
++
++#else
++ if (!dev->param.inband_tags) {
++ retval =
++ mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
++ &dummy, data, (u8 *) packed_tags_ptr, NULL);
++ } else {
++ retval =
++ mtd->write(mtd, addr, dev->param.total_bytes_per_chunk,
++ &dummy, data);
++ }
++#endif
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
++ u8 * data, struct yaffs_ext_tags *tags)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
++ struct mtd_oob_ops ops;
++#endif
++ size_t dummy;
++ int retval = 0;
++ int local_data = 0;
++
++ loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
++
++ struct yaffs_packed_tags2 pt;
++
++ int packed_tags_size =
++ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
++ void *packed_tags_ptr =
++ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
++
++ T(YAFFS_TRACE_MTD,
++ (TSTR
++ ("nandmtd2_read_chunk_tags chunk %d data %p tags %p"
++ TENDSTR), nand_chunk, data, tags));
++
++ if (dev->param.inband_tags) {
++
++ if (!data) {
++ local_data = 1;
++ data = yaffs_get_temp_buffer(dev, __LINE__);
++ }
++
++ }
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ if (dev->param.inband_tags || (data && !tags))
++ retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
++ &dummy, data);
++ else if (tags) {
++ ops.mode = MTD_OOB_AUTO;
++ ops.ooblen = packed_tags_size;
++ ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
++ ops.ooboffs = 0;
++ ops.datbuf = data;
++ ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer;
++ retval = mtd->read_oob(mtd, addr, &ops);
++ }
++#else
++ if (!dev->param.inband_tags && data && tags) {
++
++ retval = mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
++ &dummy, data, dev->spare_buffer, NULL);
++ } else {
++ if (data)
++ retval =
++ mtd->read(mtd, addr, dev->data_bytes_per_chunk,
++ &dummy, data);
++ if (!dev->param.inband_tags && tags)
++ retval =
++ mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
++ dev->spare_buffer);
++ }
++#endif
++
++ if (dev->param.inband_tags) {
++ if (tags) {
++ struct yaffs_packed_tags2_tags_only *pt2tp;
++ pt2tp =
++ (struct yaffs_packed_tags2_tags_only *)&data[dev->
++ data_bytes_per_chunk];
++ yaffs_unpack_tags2_tags_only(tags, pt2tp);
++ }
++ } else {
++ if (tags) {
++ memcpy(packed_tags_ptr,
++ yaffs_dev_to_lc(dev)->spare_buffer,
++ packed_tags_size);
++ yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
++ }
++ }
++
++ if (local_data)
++ yaffs_release_temp_buffer(dev, data, __LINE__);
++
++ if (tags && retval == -EBADMSG
++ && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
++ tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ dev->n_ecc_unfixed++;
++ }
++ if (tags && retval == -EUCLEAN
++ && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
++ tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
++ dev->n_ecc_fixed++;
++ }
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int retval;
++ T(YAFFS_TRACE_MTD,
++ (TSTR("nandmtd2_mark_block_bad %d" TENDSTR), block_no));
++
++ retval =
++ mtd->block_markbad(mtd,
++ block_no * dev->param.chunks_per_block *
++ dev->param.total_bytes_per_chunk);
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++
++}
++
++int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state, u32 * seq_number)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
++ int retval;
++
++ T(YAFFS_TRACE_MTD, (TSTR("nandmtd2_query_block %d" TENDSTR), block_no));
++ retval =
++ mtd->block_isbad(mtd,
++ block_no * dev->param.chunks_per_block *
++ dev->param.total_bytes_per_chunk);
++
++ if (retval) {
++ T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
++
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ *seq_number = 0;
++ } else {
++ struct yaffs_ext_tags t;
++ nandmtd2_read_chunk_tags(dev, block_no *
++ dev->param.chunks_per_block, NULL, &t);
++
++ if (t.chunk_used) {
++ *seq_number = t.seq_number;
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
++ } else {
++ *seq_number = 0;
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ }
++ }
++ T(YAFFS_TRACE_MTD,
++ (TSTR("block is bad seq %d state %d" TENDSTR), *seq_number, *state));
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif2.h linux-2.6.36/fs/yaffs2/yaffs_mtdif2.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_mtdif2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_mtdif2.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,29 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_MTDIF2_H__
++#define __YAFFS_MTDIF2_H__
++
++#include "yaffs_guts.h"
++int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
++ const u8 * data,
++ const struct yaffs_ext_tags *tags);
++int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
++ u8 * data, struct yaffs_ext_tags *tags);
++int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no);
++int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
++ enum yaffs_block_state *state, u32 * seq_number);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nameval.c linux-2.6.36/fs/yaffs2/yaffs_nameval.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_nameval.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_nameval.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,201 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * This simple implementation of a name-value store assumes a small number of values and fits
++ * into a small finite buffer.
++ *
++ * Each attribute is stored as a record:
++ * sizeof(int) bytes record size.
++ * strnlen+1 bytes name null terminated.
++ * nbytes value.
++ * ----------
++ * total size stored in record size
++ *
++ * This code has not been tested with unicode yet.
++ */
++
++#include "yaffs_nameval.h"
++
++#include "yportenv.h"
++
++static int nval_find(const char *xb, int xb_size, const YCHAR * name,
++ int *exist_size)
++{
++ int pos = 0;
++ int size;
++
++ memcpy(&size, xb, sizeof(int));
++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++ if (yaffs_strncmp
++ ((YCHAR *) (xb + pos + sizeof(int)), name, size) == 0) {
++ if (exist_size)
++ *exist_size = size;
++ return pos;
++ }
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ if (exist_size)
++ *exist_size = 0;
++ return -1;
++}
++
++static int nval_used(const char *xb, int xb_size)
++{
++ int pos = 0;
++ int size;
++
++ memcpy(&size, xb + pos, sizeof(int));
++ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ return pos;
++}
++
++int nval_del(char *xb, int xb_size, const YCHAR * name)
++{
++ int pos = nval_find(xb, xb_size, name, NULL);
++ int size;
++
++ if (pos >= 0 && pos < xb_size) {
++ /* Find size, shift rest over this record, then zero out the rest of buffer */
++ memcpy(&size, xb + pos, sizeof(int));
++ memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
++ memset(xb + (xb_size - size), 0, size);
++ return 0;
++ } else {
++ return -ENODATA;
++ }
++}
++
++int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
++ int bsize, int flags)
++{
++ int pos;
++ int namelen = yaffs_strnlen(name, xb_size);
++ int reclen;
++ int size_exist = 0;
++ int space;
++ int start;
++
++ pos = nval_find(xb, xb_size, name, &size_exist);
++
++ if (flags & XATTR_CREATE && pos >= 0)
++ return -EEXIST;
++ if (flags & XATTR_REPLACE && pos < 0)
++ return -ENODATA;
++
++ start = nval_used(xb, xb_size);
++ space = xb_size - start + size_exist;
++
++ reclen = (sizeof(int) + namelen + 1 + bsize);
++
++ if (reclen > space)
++ return -ENOSPC;
++
++ if (pos >= 0) {
++ nval_del(xb, xb_size, name);
++ start = nval_used(xb, xb_size);
++ }
++
++ pos = start;
++
++ memcpy(xb + pos, &reclen, sizeof(int));
++ pos += sizeof(int);
++ yaffs_strncpy((YCHAR *) (xb + pos), name, reclen);
++ pos += (namelen + 1);
++ memcpy(xb + pos, buf, bsize);
++ return 0;
++}
++
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++ int bsize)
++{
++ int pos = nval_find(xb, xb_size, name, NULL);
++ int size;
++
++ if (pos >= 0 && pos < xb_size) {
++
++ memcpy(&size, xb + pos, sizeof(int));
++ pos += sizeof(int); /* advance past record length */
++ size -= sizeof(int);
++
++ /* Advance over name string */
++ while (xb[pos] && size > 0 && pos < xb_size) {
++ pos++;
++ size--;
++ }
++ /*Advance over NUL */
++ pos++;
++ size--;
++
++ if (size <= bsize) {
++ memcpy(buf, xb + pos, size);
++ return size;
++ }
++
++ }
++ if (pos >= 0)
++ return -ERANGE;
++ else
++ return -ENODATA;
++}
++
++int nval_list(const char *xb, int xb_size, char *buf, int bsize)
++{
++ int pos = 0;
++ int size;
++ int name_len;
++ int ncopied = 0;
++ int filled = 0;
++
++ memcpy(&size, xb + pos, sizeof(int));
++ while (size > sizeof(int) && size <= xb_size && (pos + size) < xb_size
++ && !filled) {
++ pos += sizeof(int);
++ size -= sizeof(int);
++ name_len = yaffs_strnlen((YCHAR *) (xb + pos), size);
++ if (ncopied + name_len + 1 < bsize) {
++ memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
++ buf += name_len;
++ *buf = '\0';
++ buf++;
++ if (sizeof(YCHAR) > 1) {
++ *buf = '\0';
++ buf++;
++ }
++ ncopied += (name_len + 1);
++ } else {
++ filled = 1;
++ }
++ pos += size;
++ if (pos < xb_size - sizeof(int))
++ memcpy(&size, xb + pos, sizeof(int));
++ else
++ size = 0;
++ }
++ return ncopied;
++}
++
++int nval_hasvalues(const char *xb, int xb_size)
++{
++ return nval_used(xb, xb_size) > 0;
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nameval.h linux-2.6.36/fs/yaffs2/yaffs_nameval.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_nameval.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_nameval.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __NAMEVAL_H__
++#define __NAMEVAL_H__
++
++#include "yportenv.h"
++
++int nval_del(char *xb, int xb_size, const YCHAR * name);
++int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
++ int bsize, int flags);
++int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
++ int bsize);
++int nval_list(const char *xb, int xb_size, char *buf, int bsize);
++int nval_hasvalues(const char *xb, int xb_size);
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nand.c linux-2.6.36/fs/yaffs2/yaffs_nand.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_nand.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_nand.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,128 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_nand.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_tagsvalidity.h"
++
++#include "yaffs_getblockinfo.h"
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++ u8 * buffer, struct yaffs_ext_tags *tags)
++{
++ int result;
++ struct yaffs_ext_tags local_tags;
++
++ int realigned_chunk = nand_chunk - dev->chunk_offset;
++
++ dev->n_page_reads++;
++
++ /* If there are no tags provided, use local tags to get prioritised gc working */
++ if (!tags)
++ tags = &local_tags;
++
++ if (dev->param.read_chunk_tags_fn)
++ result =
++ dev->param.read_chunk_tags_fn(dev, realigned_chunk, buffer,
++ tags);
++ else
++ result = yaffs_tags_compat_rd(dev,
++ realigned_chunk, buffer, tags);
++ if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
++
++ struct yaffs_block_info *bi;
++ bi = yaffs_get_block_info(dev,
++ nand_chunk /
++ dev->param.chunks_per_block);
++ yaffs_handle_chunk_error(dev, bi);
++ }
++
++ return result;
++}
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 * buffer, struct yaffs_ext_tags *tags)
++{
++
++ dev->n_page_writes++;
++
++ nand_chunk -= dev->chunk_offset;
++
++ if (tags) {
++ tags->seq_number = dev->seq_number;
++ tags->chunk_used = 1;
++ if (!yaffs_validate_tags(tags)) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("Writing uninitialised tags" TENDSTR)));
++ YBUG();
++ }
++ T(YAFFS_TRACE_WRITE,
++ (TSTR("Writing chunk %d tags %d %d" TENDSTR), nand_chunk,
++ tags->obj_id, tags->chunk_id));
++ } else {
++ T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
++ YBUG();
++ }
++
++ if (dev->param.write_chunk_tags_fn)
++ return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer,
++ tags);
++ else
++ return yaffs_tags_compat_wr(dev, nand_chunk, buffer, tags);
++}
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++ block_no -= dev->block_offset;
++
++ if (dev->param.bad_block_fn)
++ return dev->param.bad_block_fn(dev, block_no);
++ else
++ return yaffs_tags_compat_mark_bad(dev, block_no);
++}
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 * seq_number)
++{
++ block_no -= dev->block_offset;
++
++ if (dev->param.query_block_fn)
++ return dev->param.query_block_fn(dev, block_no, state,
++ seq_number);
++ else
++ return yaffs_tags_compat_query_block(dev, block_no,
++ state, seq_number);
++}
++
++int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
++{
++ int result;
++
++ flash_block -= dev->block_offset;
++
++ dev->n_erasures++;
++
++ result = dev->param.erase_fn(dev, flash_block);
++
++ return result;
++}
++
++int yaffs_init_nand(struct yaffs_dev *dev)
++{
++ if (dev->param.initialise_flash_fn)
++ return dev->param.initialise_flash_fn(dev);
++ return YAFFS_OK;
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_nand.h linux-2.6.36/fs/yaffs2/yaffs_nand.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_nand.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_nand.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,38 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_NAND_H__
++#define __YAFFS_NAND_H__
++#include "yaffs_guts.h"
++
++int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
++ u8 * buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 * buffer, struct yaffs_ext_tags *tags);
++
++int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
++
++int yaffs_query_init_block_state(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ unsigned *seq_number);
++
++int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
++
++int yaffs_init_nand(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags1.c linux-2.6.36/fs/yaffs2/yaffs_packedtags1.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_packedtags1.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,53 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_packedtags1.h"
++#include "yportenv.h"
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++ const struct yaffs_ext_tags *t)
++{
++ pt->chunk_id = t->chunk_id;
++ pt->serial_number = t->serial_number;
++ pt->n_bytes = t->n_bytes;
++ pt->obj_id = t->obj_id;
++ pt->ecc = 0;
++ pt->deleted = (t->is_deleted) ? 0 : 1;
++ pt->unused_stuff = 0;
++ pt->should_be_ff = 0xFFFFFFFF;
++
++}
++
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++ const struct yaffs_packed_tags1 *pt)
++{
++ static const u8 all_ff[] =
++ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++ 0xff
++ };
++
++ if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
++ t->block_bad = 0;
++ if (pt->should_be_ff != 0xFFFFFFFF)
++ t->block_bad = 1;
++ t->chunk_used = 1;
++ t->obj_id = pt->obj_id;
++ t->chunk_id = pt->chunk_id;
++ t->n_bytes = pt->n_bytes;
++ t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ t->is_deleted = (pt->deleted) ? 0 : 1;
++ t->serial_number = pt->serial_number;
++ } else {
++ memset(t, 0, sizeof(struct yaffs_ext_tags));
++ }
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags1.h linux-2.6.36/fs/yaffs2/yaffs_packedtags1.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_packedtags1.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
++
++#ifndef __YAFFS_PACKEDTAGS1_H__
++#define __YAFFS_PACKEDTAGS1_H__
++
++#include "yaffs_guts.h"
++
++struct yaffs_packed_tags1 {
++ unsigned chunk_id:20;
++ unsigned serial_number:2;
++ unsigned n_bytes:10;
++ unsigned obj_id:18;
++ unsigned ecc:12;
++ unsigned deleted:1;
++ unsigned unused_stuff:1;
++ unsigned should_be_ff;
++
++};
++
++void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
++ const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
++ const struct yaffs_packed_tags1 *pt);
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags2.c linux-2.6.36/fs/yaffs2/yaffs_packedtags2.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_packedtags2.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,197 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_packedtags2.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_tagsvalidity.h"
++
++/* This code packs a set of extended tags into a binary structure for
++ * NAND storage
++ */
++
++/* Some of the information is "extra" struff which can be packed in to
++ * speed scanning
++ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
++ */
++
++/* Extra flags applied to chunk_id */
++
++#define EXTRA_HEADER_INFO_FLAG 0x80000000
++#define EXTRA_SHRINK_FLAG 0x40000000
++#define EXTRA_SHADOWS_FLAG 0x20000000
++#define EXTRA_SPARE_FLAGS 0x10000000
++
++#define ALL_EXTRA_FLAGS 0xF0000000
++
++/* Also, the top 4 bits of the object Id are set to the object type. */
++#define EXTRA_OBJECT_TYPE_SHIFT (28)
++#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
++
++static void yaffs_dump_packed_tags2_tags_only(const struct
++ yaffs_packed_tags2_tags_only *ptt)
++{
++ T(YAFFS_TRACE_MTD,
++ (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
++ ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number));
++}
++
++static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
++{
++ yaffs_dump_packed_tags2_tags_only(&pt->t);
++}
++
++static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
++{
++ T(YAFFS_TRACE_MTD,
++ (TSTR
++ ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
++ TENDSTR), t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
++ t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
++ t->seq_number));
++
++}
++
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
++ const struct yaffs_ext_tags *t)
++{
++ ptt->chunk_id = t->chunk_id;
++ ptt->seq_number = t->seq_number;
++ ptt->n_bytes = t->n_bytes;
++ ptt->obj_id = t->obj_id;
++
++ if (t->chunk_id == 0 && t->extra_available) {
++ /* Store the extra header info instead */
++ /* We save the parent object in the chunk_id */
++ ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
++ if (t->extra_is_shrink)
++ ptt->chunk_id |= EXTRA_SHRINK_FLAG;
++ if (t->extra_shadows)
++ ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
++
++ ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++ ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
++
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ ptt->n_bytes = t->extra_equiv_id;
++ else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
++ ptt->n_bytes = t->extra_length;
++ else
++ ptt->n_bytes = 0;
++ }
++
++ yaffs_dump_packed_tags2_tags_only(ptt);
++ yaffs_dump_tags2(t);
++}
++
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++ const struct yaffs_ext_tags *t, int tags_ecc)
++{
++ yaffs_pack_tags2_tags_only(&pt->t, t);
++
++ if (tags_ecc)
++ yaffs_ecc_calc_other((unsigned char *)&pt->t,
++ sizeof(struct
++ yaffs_packed_tags2_tags_only),
++ &pt->ecc);
++}
++
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++ struct yaffs_packed_tags2_tags_only *ptt)
++{
++
++ memset(t, 0, sizeof(struct yaffs_ext_tags));
++
++ yaffs_init_tags(t);
++
++ if (ptt->seq_number != 0xFFFFFFFF) {
++ t->block_bad = 0;
++ t->chunk_used = 1;
++ t->obj_id = ptt->obj_id;
++ t->chunk_id = ptt->chunk_id;
++ t->n_bytes = ptt->n_bytes;
++ t->is_deleted = 0;
++ t->serial_number = 0;
++ t->seq_number = ptt->seq_number;
++
++ /* Do extra header info stuff */
++
++ if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
++ t->chunk_id = 0;
++ t->n_bytes = 0;
++
++ t->extra_available = 1;
++ t->extra_parent_id =
++ ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
++ t->extra_is_shrink =
++ (ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0;
++ t->extra_shadows =
++ (ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0;
++ t->extra_obj_type =
++ ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
++ t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
++
++ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ t->extra_equiv_id = ptt->n_bytes;
++ else
++ t->extra_length = ptt->n_bytes;
++ }
++ }
++
++ yaffs_dump_packed_tags2_tags_only(ptt);
++ yaffs_dump_tags2(t);
++
++}
++
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++ int tags_ecc)
++{
++
++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++ if (pt->t.seq_number != 0xFFFFFFFF && tags_ecc) {
++ /* Chunk is in use and we need to do ECC */
++
++ struct yaffs_ecc_other ecc;
++ int result;
++ yaffs_ecc_calc_other((unsigned char *)&pt->t,
++ sizeof(struct
++ yaffs_packed_tags2_tags_only),
++ &ecc);
++ result =
++ yaffs_ecc_correct_other((unsigned char *)&pt->t,
++ sizeof(struct
++ yaffs_packed_tags2_tags_only),
++ &pt->ecc, &ecc);
++ switch (result) {
++ case 0:
++ ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ break;
++ case 1:
++ ecc_result = YAFFS_ECC_RESULT_FIXED;
++ break;
++ case -1:
++ ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ break;
++ default:
++ ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++ }
++ }
++
++ yaffs_unpack_tags2_tags_only(t, &pt->t);
++
++ t->ecc_result = ecc_result;
++
++ yaffs_dump_packed_tags2(pt);
++ yaffs_dump_tags2(t);
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags2.h linux-2.6.36/fs/yaffs2/yaffs_packedtags2.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_packedtags2.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,47 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
++
++#ifndef __YAFFS_PACKEDTAGS2_H__
++#define __YAFFS_PACKEDTAGS2_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_ecc.h"
++
++struct yaffs_packed_tags2_tags_only {
++ unsigned seq_number;
++ unsigned obj_id;
++ unsigned chunk_id;
++ unsigned n_bytes;
++};
++
++struct yaffs_packed_tags2 {
++ struct yaffs_packed_tags2_tags_only t;
++ struct yaffs_ecc_other ecc;
++};
++
++/* Full packed tags with ECC, used for oob tags */
++void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
++ const struct yaffs_ext_tags *t, int tags_ecc);
++void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
++ int tags_ecc);
++
++/* Only the tags part (no ECC for use with inband tags */
++void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
++ const struct yaffs_ext_tags *t);
++void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
++ struct yaffs_packed_tags2_tags_only *pt);
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagscompat.c linux-2.6.36/fs/yaffs2/yaffs_tagscompat.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_tagscompat.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,454 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_ecc.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_trace.h"
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
++
++static const char yaffs_count_bits_table[256] = {
++ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
++};
++
++int yaffs_count_bits(u8 x)
++{
++ int ret_val;
++ ret_val = yaffs_count_bits_table[x];
++ return ret_val;
++}
++
++/********** Tags ECC calculations *********/
++
++void yaffs_calc_ecc(const u8 * data, struct yaffs_spare *spare)
++{
++ yaffs_ecc_cacl(data, spare->ecc1);
++ yaffs_ecc_cacl(&data[256], spare->ecc2);
++}
++
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
++{
++ /* Calculate an ecc */
++
++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++ unsigned i, j;
++ unsigned ecc = 0;
++ unsigned bit = 0;
++
++ tags->ecc = 0;
++
++ for (i = 0; i < 8; i++) {
++ for (j = 1; j & 0xff; j <<= 1) {
++ bit++;
++ if (b[i] & j)
++ ecc ^= bit;
++ }
++ }
++
++ tags->ecc = ecc;
++
++}
++
++int yaffs_check_tags_ecc(struct yaffs_tags *tags)
++{
++ unsigned ecc = tags->ecc;
++
++ yaffs_calc_tags_ecc(tags);
++
++ ecc ^= tags->ecc;
++
++ if (ecc && ecc <= 64) {
++ /* TODO: Handle the failure better. Retire? */
++ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
++
++ ecc--;
++
++ b[ecc / 8] ^= (1 << (ecc & 7));
++
++ /* Now recvalc the ecc */
++ yaffs_calc_tags_ecc(tags);
++
++ return 1; /* recovered error */
++ } else if (ecc) {
++ /* Wierd ecc failure value */
++ /* TODO Need to do somethiong here */
++ return -1; /* unrecovered error */
++ }
++
++ return 0;
++}
++
++/********** Tags **********/
++
++static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
++ struct yaffs_tags *tags_ptr)
++{
++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++
++ yaffs_calc_tags_ecc(tags_ptr);
++
++ spare_ptr->tb0 = tu->as_bytes[0];
++ spare_ptr->tb1 = tu->as_bytes[1];
++ spare_ptr->tb2 = tu->as_bytes[2];
++ spare_ptr->tb3 = tu->as_bytes[3];
++ spare_ptr->tb4 = tu->as_bytes[4];
++ spare_ptr->tb5 = tu->as_bytes[5];
++ spare_ptr->tb6 = tu->as_bytes[6];
++ spare_ptr->tb7 = tu->as_bytes[7];
++}
++
++static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
++ struct yaffs_spare *spare_ptr,
++ struct yaffs_tags *tags_ptr)
++{
++ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
++ int result;
++
++ tu->as_bytes[0] = spare_ptr->tb0;
++ tu->as_bytes[1] = spare_ptr->tb1;
++ tu->as_bytes[2] = spare_ptr->tb2;
++ tu->as_bytes[3] = spare_ptr->tb3;
++ tu->as_bytes[4] = spare_ptr->tb4;
++ tu->as_bytes[5] = spare_ptr->tb5;
++ tu->as_bytes[6] = spare_ptr->tb6;
++ tu->as_bytes[7] = spare_ptr->tb7;
++
++ result = yaffs_check_tags_ecc(tags_ptr);
++ if (result > 0)
++ dev->n_tags_ecc_fixed++;
++ else if (result < 0)
++ dev->n_tags_ecc_unfixed++;
++}
++
++static void yaffs_spare_init(struct yaffs_spare *spare)
++{
++ memset(spare, 0xFF, sizeof(struct yaffs_spare));
++}
++
++static int yaffs_wr_nand(struct yaffs_dev *dev,
++ int nand_chunk, const u8 * data,
++ struct yaffs_spare *spare)
++{
++ if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
++ nand_chunk));
++ return YAFFS_FAIL;
++ }
++
++ return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
++}
++
++static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 * data,
++ struct yaffs_spare *spare,
++ enum yaffs_ecc_result *ecc_result,
++ int correct_errors)
++{
++ int ret_val;
++ struct yaffs_spare local_spare;
++
++ if (!spare && data) {
++ /* If we don't have a real spare, then we use a local one. */
++ /* Need this for the calculation of the ecc */
++ spare = &local_spare;
++ }
++
++ if (!dev->param.use_nand_ecc) {
++ ret_val =
++ dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
++ if (data && correct_errors) {
++ /* Do ECC correction */
++ /* Todo handle any errors */
++ int ecc_result1, ecc_result2;
++ u8 calc_ecc[3];
++
++ yaffs_ecc_cacl(data, calc_ecc);
++ ecc_result1 =
++ yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
++ yaffs_ecc_cacl(&data[256], calc_ecc);
++ ecc_result2 =
++ yaffs_ecc_correct(&data[256], spare->ecc2,
++ calc_ecc);
++
++ if (ecc_result1 > 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>yaffs ecc error fix performed on chunk %d:0"
++ TENDSTR), nand_chunk));
++ dev->n_ecc_fixed++;
++ } else if (ecc_result1 < 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>yaffs ecc error unfixed on chunk %d:0"
++ TENDSTR), nand_chunk));
++ dev->n_ecc_unfixed++;
++ }
++
++ if (ecc_result2 > 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>yaffs ecc error fix performed on chunk %d:1"
++ TENDSTR), nand_chunk));
++ dev->n_ecc_fixed++;
++ } else if (ecc_result2 < 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>yaffs ecc error unfixed on chunk %d:1"
++ TENDSTR), nand_chunk));
++ dev->n_ecc_unfixed++;
++ }
++
++ if (ecc_result1 || ecc_result2) {
++ /* We had a data problem on this page */
++ yaffs_handle_rd_data_error(dev, nand_chunk);
++ }
++
++ if (ecc_result1 < 0 || ecc_result2 < 0)
++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ else if (ecc_result1 > 0 || ecc_result2 > 0)
++ *ecc_result = YAFFS_ECC_RESULT_FIXED;
++ else
++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++ }
++ } else {
++ /* Must allocate enough memory for spare+2*sizeof(int) */
++ /* for ecc results from device. */
++ struct yaffs_nand_spare nspare;
++
++ memset(&nspare, 0, sizeof(nspare));
++
++ ret_val = dev->param.read_chunk_fn(dev, nand_chunk, data,
++ (struct yaffs_spare *)
++ &nspare);
++ memcpy(spare, &nspare, sizeof(struct yaffs_spare));
++ if (data && correct_errors) {
++ if (nspare.eccres1 > 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>mtd ecc error fix performed on chunk %d:0"
++ TENDSTR), nand_chunk));
++ } else if (nspare.eccres1 < 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>mtd ecc error unfixed on chunk %d:0"
++ TENDSTR), nand_chunk));
++ }
++
++ if (nspare.eccres2 > 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>mtd ecc error fix performed on chunk %d:1"
++ TENDSTR), nand_chunk));
++ } else if (nspare.eccres2 < 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>mtd ecc error unfixed on chunk %d:1"
++ TENDSTR), nand_chunk));
++ }
++
++ if (nspare.eccres1 || nspare.eccres2) {
++ /* We had a data problem on this page */
++ yaffs_handle_rd_data_error(dev, nand_chunk);
++ }
++
++ if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
++ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
++ else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
++ *ecc_result = YAFFS_ECC_RESULT_FIXED;
++ else
++ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
++
++ }
++ }
++ return ret_val;
++}
++
++/*
++ * Functions for robustisizing
++ */
++
++static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
++{
++ int flash_block = nand_chunk / dev->param.chunks_per_block;
++
++ /* Mark the block for retirement */
++ yaffs_get_block_info(dev,
++ flash_block + dev->block_offset)->needs_retiring =
++ 1;
++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("**>>Block %d marked for retirement" TENDSTR), flash_block));
++
++ /* TODO:
++ * Just do a garbage collection on the affected block
++ * then retire the block
++ * NB recursion
++ */
++}
++
++int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 * data, const struct yaffs_ext_tags *ext_tags)
++{
++ struct yaffs_spare spare;
++ struct yaffs_tags tags;
++
++ yaffs_spare_init(&spare);
++
++ if (ext_tags->is_deleted)
++ spare.page_status = 0;
++ else {
++ tags.obj_id = ext_tags->obj_id;
++ tags.chunk_id = ext_tags->chunk_id;
++
++ tags.n_bytes_lsb = ext_tags->n_bytes & 0x3ff;
++
++ if (dev->data_bytes_per_chunk >= 1024)
++ tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
++ else
++ tags.n_bytes_msb = 3;
++
++ tags.serial_number = ext_tags->serial_number;
++
++ if (!dev->param.use_nand_ecc && data)
++ yaffs_calc_ecc(data, &spare);
++
++ yaffs_load_tags_to_spare(&spare, &tags);
++
++ }
++
++ return yaffs_wr_nand(dev, nand_chunk, data, &spare);
++}
++
++int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 * data, struct yaffs_ext_tags *ext_tags)
++{
++
++ struct yaffs_spare spare;
++ struct yaffs_tags tags;
++ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
++
++ static struct yaffs_spare spare_ff;
++ static int init;
++
++ if (!init) {
++ memset(&spare_ff, 0xFF, sizeof(spare_ff));
++ init = 1;
++ }
++
++ if (yaffs_rd_chunk_nand(dev, nand_chunk, data, &spare, &ecc_result, 1)) {
++ /* ext_tags may be NULL */
++ if (ext_tags) {
++
++ int deleted =
++ (yaffs_count_bits(spare.page_status) < 7) ? 1 : 0;
++
++ ext_tags->is_deleted = deleted;
++ ext_tags->ecc_result = ecc_result;
++ ext_tags->block_bad = 0; /* We're reading it */
++ /* therefore it is not a bad block */
++ ext_tags->chunk_used =
++ (memcmp(&spare_ff, &spare, sizeof(spare_ff)) !=
++ 0) ? 1 : 0;
++
++ if (ext_tags->chunk_used) {
++ yaffs_get_tags_from_spare(dev, &spare, &tags);
++
++ ext_tags->obj_id = tags.obj_id;
++ ext_tags->chunk_id = tags.chunk_id;
++ ext_tags->n_bytes = tags.n_bytes_lsb;
++
++ if (dev->data_bytes_per_chunk >= 1024)
++ ext_tags->n_bytes |=
++ (((unsigned)tags.
++ n_bytes_msb) << 10);
++
++ ext_tags->serial_number = tags.serial_number;
++ }
++ }
++
++ return YAFFS_OK;
++ } else {
++ return YAFFS_FAIL;
++ }
++}
++
++int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
++{
++
++ struct yaffs_spare spare;
++
++ memset(&spare, 0xff, sizeof(struct yaffs_spare));
++
++ spare.block_status = 'Y';
++
++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
++ &spare);
++ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
++ NULL, &spare);
++
++ return YAFFS_OK;
++
++}
++
++int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 * seq_number)
++{
++
++ struct yaffs_spare spare0, spare1;
++ static struct yaffs_spare spare_ff;
++ static int init;
++ enum yaffs_ecc_result dummy;
++
++ if (!init) {
++ memset(&spare_ff, 0xFF, sizeof(spare_ff));
++ init = 1;
++ }
++
++ *seq_number = 0;
++
++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
++ &spare0, &dummy, 1);
++ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
++ NULL, &spare1, &dummy, 1);
++
++ if (yaffs_count_bits(spare0.block_status & spare1.block_status) < 7)
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ else
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
++
++ return YAFFS_OK;
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagscompat.h linux-2.6.36/fs/yaffs2/yaffs_tagscompat.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_tagscompat.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,36 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSCOMPAT_H__
++#define __YAFFS_TAGSCOMPAT_H__
++
++#include "yaffs_guts.h"
++int yaffs_tags_compat_wr(struct yaffs_dev *dev,
++ int nand_chunk,
++ const u8 * data, const struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_rd(struct yaffs_dev *dev,
++ int nand_chunk,
++ u8 * data, struct yaffs_ext_tags *tags);
++int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
++int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++ int block_no,
++ enum yaffs_block_state *state,
++ u32 * seq_number);
++
++void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
++int yaffs_check_tags_ecc(struct yaffs_tags *tags);
++int yaffs_count_bits(u8 byte);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagsvalidity.c linux-2.6.36/fs/yaffs2/yaffs_tagsvalidity.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_tagsvalidity.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_tagsvalidity.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,27 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_tagsvalidity.h"
++
++void yaffs_init_tags(struct yaffs_ext_tags *tags)
++{
++ memset(tags, 0, sizeof(struct yaffs_ext_tags));
++ tags->validity0 = 0xAAAAAAAA;
++ tags->validity1 = 0x55555555;
++}
++
++int yaffs_validate_tags(struct yaffs_ext_tags *tags)
++{
++ return (tags->validity0 == 0xAAAAAAAA && tags->validity1 == 0x55555555);
++
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.36/fs/yaffs2/yaffs_tagsvalidity.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_tagsvalidity.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_tagsvalidity.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,23 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGS_VALIDITY_H__
++#define __YAFFS_TAGS_VALIDITY_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_init_tags(struct yaffs_ext_tags *tags);
++int yaffs_validate_tags(struct yaffs_ext_tags *tags);
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_trace.h linux-2.6.36/fs/yaffs2/yaffs_trace.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_trace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_trace.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,59 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YTRACE_H__
++#define __YTRACE_H__
++
++extern unsigned int yaffs_trace_mask;
++extern unsigned int yaffs_wr_attempts;
++
++/*
++ * Tracing flags.
++ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
++ */
++
++#define YAFFS_TRACE_OS 0x00000002
++#define YAFFS_TRACE_ALLOCATE 0x00000004
++#define YAFFS_TRACE_SCAN 0x00000008
++#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
++#define YAFFS_TRACE_ERASE 0x00000020
++#define YAFFS_TRACE_GC 0x00000040
++#define YAFFS_TRACE_WRITE 0x00000080
++#define YAFFS_TRACE_TRACING 0x00000100
++#define YAFFS_TRACE_DELETION 0x00000200
++#define YAFFS_TRACE_BUFFERS 0x00000400
++#define YAFFS_TRACE_NANDACCESS 0x00000800
++#define YAFFS_TRACE_GC_DETAIL 0x00001000
++#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
++#define YAFFS_TRACE_MTD 0x00004000
++#define YAFFS_TRACE_CHECKPOINT 0x00008000
++
++#define YAFFS_TRACE_VERIFY 0x00010000
++#define YAFFS_TRACE_VERIFY_NAND 0x00020000
++#define YAFFS_TRACE_VERIFY_FULL 0x00040000
++#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
++
++#define YAFFS_TRACE_SYNC 0x00100000
++#define YAFFS_TRACE_BACKGROUND 0x00200000
++#define YAFFS_TRACE_LOCK 0x00400000
++#define YAFFS_TRACE_MOUNT 0x00800000
++
++#define YAFFS_TRACE_ERROR 0x40000000
++#define YAFFS_TRACE_BUG 0x80000000
++#define YAFFS_TRACE_ALWAYS 0xF0000000
++
++#define T(mask, p) do { if ((mask) & (yaffs_trace_mask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_verify.c linux-2.6.36/fs/yaffs2/yaffs_verify.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_verify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_verify.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,546 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_verify.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++
++int yaffs_skip_verification(struct yaffs_dev *dev)
++{
++ dev = dev;
++ return !(yaffs_trace_mask &
++ (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_full_verification(struct yaffs_dev *dev)
++{
++ dev = dev;
++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
++{
++ dev = dev;
++ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
++}
++
++static const char *block_state_name[] = {
++ "Unknown",
++ "Needs scanning",
++ "Scanning",
++ "Empty",
++ "Allocating",
++ "Full",
++ "Dirty",
++ "Checkpoint",
++ "Collecting",
++ "Dead"
++};
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
++{
++ int actually_used;
++ int in_use;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Report illegal runtime states */
++ if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Block %d has undefined state %d" TENDSTR), n,
++ bi->block_state));
++
++ switch (bi->block_state) {
++ case YAFFS_BLOCK_STATE_UNKNOWN:
++ case YAFFS_BLOCK_STATE_SCANNING:
++ case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Block %d has bad run-state %s" TENDSTR), n,
++ block_state_name[bi->block_state]));
++ }
++
++ /* Check pages in use and soft deletions are legal */
++
++ actually_used = bi->pages_in_use - bi->soft_del_pages;
++
++ if (bi->pages_in_use < 0
++ || bi->pages_in_use > dev->param.chunks_per_block
++ || bi->soft_del_pages < 0
++ || bi->soft_del_pages > dev->param.chunks_per_block
++ || actually_used < 0 || actually_used > dev->param.chunks_per_block)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR
++ ("Block %d has illegal values pages_in_used %d soft_del_pages %d"
++ TENDSTR), n, bi->pages_in_use, bi->soft_del_pages));
++
++ /* Check chunk bitmap legal */
++ in_use = yaffs_count_chunk_bits(dev, n);
++ if (in_use != bi->pages_in_use)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR
++ ("Block %d has inconsistent values pages_in_use %d counted chunk bits %d"
++ TENDSTR), n, bi->pages_in_use, in_use));
++
++}
++
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi, int n)
++{
++ yaffs_verify_blk(dev, bi, n);
++
++ /* After collection the block should be in the erased state */
++
++ if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
++ bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("Block %d is in state %d after gc, should be erased"
++ TENDSTR), n, bi->block_state));
++ }
++}
++
++void yaffs_verify_blocks(struct yaffs_dev *dev)
++{
++ int i;
++ int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
++ int illegal_states = 0;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ memset(state_count, 0, sizeof(state_count));
++
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++ yaffs_verify_blk(dev, bi, i);
++
++ if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
++ state_count[bi->block_state]++;
++ else
++ illegal_states++;
++ }
++
++ T(YAFFS_TRACE_VERIFY, (TSTR("" TENDSTR)));
++ T(YAFFS_TRACE_VERIFY, (TSTR("Block summary" TENDSTR)));
++
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("%d blocks have illegal states" TENDSTR), illegal_states));
++ if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Too many allocating blocks" TENDSTR)));
++
++ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("%s %d blocks" TENDSTR),
++ block_state_name[i], state_count[i]));
++
++ if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Checkpoint block count wrong dev %d count %d" TENDSTR),
++ dev->blocks_in_checkpt,
++ state_count[YAFFS_BLOCK_STATE_CHECKPOINT]));
++
++ if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Erased block count wrong dev %d count %d" TENDSTR),
++ dev->n_erased_blocks, state_count[YAFFS_BLOCK_STATE_EMPTY]));
++
++ if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Too many collecting blocks %d (max is 1)" TENDSTR),
++ state_count[YAFFS_BLOCK_STATE_COLLECTING]));
++
++ T(YAFFS_TRACE_VERIFY, (TSTR("" TENDSTR)));
++
++}
++
++/*
++ * Verify the object header. oh must be valid, but obj and tags may be NULL in which
++ * case those tests will not be performed.
++ */
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++ struct yaffs_ext_tags *tags, int parent_check)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ if (!(tags && obj && oh)) {
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Verifying object header tags %p obj %p oh %p" TENDSTR),
++ tags, obj, oh));
++ return;
++ }
++
++ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
++ oh->type > YAFFS_OBJECT_TYPE_MAX)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d header type is illegal value 0x%x" TENDSTR),
++ tags->obj_id, oh->type));
++
++ if (tags->obj_id != obj->obj_id)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d header mismatch obj_id %d" TENDSTR),
++ tags->obj_id, obj->obj_id));
++
++ /*
++ * Check that the object's parent ids match if parent_check requested.
++ *
++ * Tests do not apply to the root object.
++ */
++
++ if (parent_check && tags->obj_id > 1 && !obj->parent)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR
++ ("Obj %d header mismatch parent_id %d obj->parent is NULL"
++ TENDSTR), tags->obj_id, oh->parent_obj_id));
++
++ if (parent_check && obj->parent &&
++ oh->parent_obj_id != obj->parent->obj_id &&
++ (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR
++ ("Obj %d header mismatch parent_id %d parent_obj_id %d"
++ TENDSTR), tags->obj_id, oh->parent_obj_id,
++ obj->parent->obj_id));
++
++ if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d header name is NULL" TENDSTR), obj->obj_id));
++
++ if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Trashed name */
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d header name is 0xFF" TENDSTR), obj->obj_id));
++}
++
++void yaffs_verify_file(struct yaffs_obj *obj)
++{
++ int required_depth;
++ int actual_depth;
++ u32 last_chunk;
++ u32 x;
++ u32 i;
++ struct yaffs_dev *dev;
++ struct yaffs_ext_tags tags;
++ struct yaffs_tnode *tn;
++ u32 obj_id;
++
++ if (!obj)
++ return;
++
++ if (yaffs_skip_verification(obj->my_dev))
++ return;
++
++ dev = obj->my_dev;
++ obj_id = obj->obj_id;
++
++ /* Check file size is consistent with tnode depth */
++ last_chunk =
++ obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1;
++ x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
++ required_depth = 0;
++ while (x > 0) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ required_depth++;
++ }
++
++ actual_depth = obj->variant.file_variant.top_level;
++
++ /* Check that the chunks in the tnode tree are all correct.
++ * We do this by scanning through the tnode tree and
++ * checking the tags for every chunk match.
++ */
++
++ if (yaffs_skip_nand_verification(dev))
++ return;
++
++ for (i = 1; i <= last_chunk; i++) {
++ tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
++
++ if (tn) {
++ u32 the_chunk = yaffs_get_group_base(dev, tn, i);
++ if (the_chunk > 0) {
++ /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),obj_id,i,the_chunk)); */
++ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
++ &tags);
++ if (tags.obj_id != obj_id || tags.chunk_id != i) {
++ T(~0,
++ (TSTR
++ ("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"
++ TENDSTR), obj_id, i, the_chunk,
++ tags.obj_id, tags.chunk_id));
++ }
++ }
++ }
++ }
++}
++
++void yaffs_verify_link(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ /* Verify sane equivalent object */
++}
++
++void yaffs_verify_symlink(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++
++ /* Verify symlink string */
++}
++
++void yaffs_verify_special(struct yaffs_obj *obj)
++{
++ if (obj && yaffs_skip_verification(obj->my_dev))
++ return;
++}
++
++void yaffs_verify_obj(struct yaffs_obj *obj)
++{
++ struct yaffs_dev *dev;
++
++ u32 chunk_min;
++ u32 chunk_max;
++
++ u32 chunk_id_ok;
++ u32 chunk_in_range;
++ u32 chunk_wrongly_deleted;
++ u32 chunk_valid;
++
++ if (!obj)
++ return;
++
++ if (obj->being_created)
++ return;
++
++ dev = obj->my_dev;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Check sane object header chunk */
++
++ chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
++ chunk_max =
++ (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
++
++ chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
++ ((unsigned)(obj->hdr_chunk)) <= chunk_max);
++ chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
++ chunk_valid = chunk_in_range &&
++ yaffs_check_chunk_bit(dev,
++ obj->hdr_chunk / dev->param.chunks_per_block,
++ obj->hdr_chunk % dev->param.chunks_per_block);
++ chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
++
++ if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted)) {
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d has chunk_id %d %s %s" TENDSTR),
++ obj->obj_id, obj->hdr_chunk,
++ chunk_id_ok ? "" : ",out of range",
++ chunk_wrongly_deleted ? ",marked as deleted" : ""));
++ }
++
++ if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
++ struct yaffs_ext_tags tags;
++ struct yaffs_obj_hdr *oh;
++ u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
++
++ oh = (struct yaffs_obj_hdr *)buffer;
++
++ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
++
++ yaffs_verify_oh(obj, oh, &tags, 1);
++
++ yaffs_release_temp_buffer(dev, buffer, __LINE__);
++ }
++
++ /* Verify it has a parent */
++ if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR
++ ("Obj %d has parent pointer %p which does not look like an object"
++ TENDSTR), obj->obj_id, obj->parent));
++ }
++
++ /* Verify parent is a directory */
++ if (obj->parent
++ && obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d's parent is not a directory (type %d)" TENDSTR),
++ obj->obj_id, obj->parent->variant_type));
++ }
++
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ yaffs_verify_file(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ yaffs_verify_symlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ yaffs_verify_dir(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ yaffs_verify_link(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ yaffs_verify_special(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d has illegaltype %d" TENDSTR),
++ obj->obj_id, obj->variant_type));
++ break;
++ }
++}
++
++void yaffs_verify_objects(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ int i;
++ struct list_head *lh;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ /* Iterate through the objects in each hash entry */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each(lh, &dev->obj_bucket[i].list) {
++ if (lh) {
++ obj =
++ list_entry(lh, struct yaffs_obj, hash_link);
++ yaffs_verify_obj(obj);
++ }
++ }
++ }
++}
++
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
++{
++ struct list_head *lh;
++ struct yaffs_obj *list_obj;
++
++ int count = 0;
++
++ if (!obj) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
++ YBUG();
++ return;
++ }
++
++ if (yaffs_skip_verification(obj->my_dev))
++ return;
++
++ if (!obj->parent) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("Object does not have parent" TENDSTR)));
++ YBUG();
++ return;
++ }
++
++ if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("Parent is not directory" TENDSTR)));
++ YBUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ list_for_each(lh, &obj->parent->variant.dir_variant.children) {
++ if (lh) {
++ list_obj = list_entry(lh, struct yaffs_obj, siblings);
++ yaffs_verify_obj(list_obj);
++ if (obj == list_obj)
++ count++;
++ }
++ }
++
++ if (count != 1) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("Object in directory %d times" TENDSTR), count));
++ YBUG();
++ }
++}
++
++void yaffs_verify_dir(struct yaffs_obj *directory)
++{
++ struct list_head *lh;
++ struct yaffs_obj *list_obj;
++
++ if (!directory) {
++ YBUG();
++ return;
++ }
++
++ if (yaffs_skip_full_verification(directory->my_dev))
++ return;
++
++ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("Directory has wrong type: %d" TENDSTR),
++ directory->variant_type));
++ YBUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ list_for_each(lh, &directory->variant.dir_variant.children) {
++ if (lh) {
++ list_obj = list_entry(lh, struct yaffs_obj, siblings);
++ if (list_obj->parent != directory) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("Object in directory list has wrong parent %p"
++ TENDSTR), list_obj->parent));
++ YBUG();
++ }
++ yaffs_verify_obj_in_dir(list_obj);
++ }
++ }
++}
++
++static int yaffs_free_verification_failures;
++
++void yaffs_verify_free_chunks(struct yaffs_dev *dev)
++{
++ int counted;
++ int difference;
++
++ if (yaffs_skip_verification(dev))
++ return;
++
++ counted = yaffs_count_free_chunks(dev);
++
++ difference = dev->n_free_chunks - counted;
++
++ if (difference) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
++ dev->n_free_chunks, counted, difference));
++ yaffs_free_verification_failures++;
++ }
++}
++
++int yaffs_verify_file_sane(struct yaffs_obj *in)
++{
++ in = in;
++ return YAFFS_OK;
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_verify.h linux-2.6.36/fs/yaffs2/yaffs_verify.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_verify.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_verify.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,43 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_VERIFY_H__
++#define __YAFFS_VERIFY_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
++ int n);
++void yaffs_verify_collected_blk(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi, int n);
++void yaffs_verify_blocks(struct yaffs_dev *dev);
++
++void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
++ struct yaffs_ext_tags *tags, int parent_check);
++void yaffs_verify_file(struct yaffs_obj *obj);
++void yaffs_verify_link(struct yaffs_obj *obj);
++void yaffs_verify_symlink(struct yaffs_obj *obj);
++void yaffs_verify_special(struct yaffs_obj *obj);
++void yaffs_verify_obj(struct yaffs_obj *obj);
++void yaffs_verify_objects(struct yaffs_dev *dev);
++void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
++void yaffs_verify_dir(struct yaffs_obj *directory);
++void yaffs_verify_free_chunks(struct yaffs_dev *dev);
++
++int yaffs_verify_file_sane(struct yaffs_obj *obj);
++
++int yaffs_skip_verification(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_vfs.c linux-2.6.36/fs/yaffs2/yaffs_vfs.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_vfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_vfs.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,3565 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ * Acknowledgements:
++ * Luc van OostenRyck for numerous patches.
++ * Nick Bane for numerous patches.
++ * Nick Bane for 2.5/2.6 integration.
++ * Andras Toth for mknod rdev issue.
++ * Michael Fischer for finding the problem with inode inconsistency.
++ * Some code bodily lifted from JFFS
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ *
++ * This is the file system front-end to YAFFS that hooks it up to
++ * the VFS.
++ *
++ * Special notes:
++ * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with
++ * this superblock
++ * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this
++ * superblock
++ * >> inode->u.generic_ip points to the associated struct yaffs_obj.
++ */
++
++/*
++ * There are two variants of the VFS glue code. This variant should compile
++ * for any version of Linux.
++ */
++#include <linux/version.h>
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
++#define YAFFS_COMPILE_BACKGROUND
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23))
++#define YAFFS_COMPILE_FREEZER
++#endif
++#endif
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
++#define YAFFS_COMPILE_EXPORTFS
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
++#define YAFFS_USE_SETATTR_COPY
++#define YAFFS_USE_TRUNCATE_SETSIZE
++#endif
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
++#define YAFFS_HAS_EVICT_INODE
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
++#define YAFFS_NEW_FOLLOW_LINK 1
++#else
++#define YAFFS_NEW_FOLLOW_LINK 0
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++#include <linux/config.h>
++#endif
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/proc_fs.h>
++#include <linux/smp_lock.h>
++#include <linux/pagemap.h>
++#include <linux/mtd/mtd.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++#include <linux/namei.h>
++#endif
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++#include <linux/exportfs.h>
++#endif
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#endif
++#ifdef YAFFS_COMPILE_FREEZER
++#include <linux/freezer.h>
++#endif
++
++#include <asm/div64.h>
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++#include <linux/statfs.h>
++
++#define UnlockPage(p) unlock_page(p)
++#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
++
++/* FIXME: use sb->s_id instead ? */
++#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
++
++#else
++
++#include <linux/locks.h>
++#define BDEVNAME_SIZE 0
++#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
++/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
++#define __user
++#endif
++
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
++#define YPROC_ROOT (&proc_root)
++#else
++#define YPROC_ROOT NULL
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
++#define Y_INIT_TIMER(a) init_timer(a)
++#else
++#define Y_INIT_TIMER(a) init_timer_on_stack(a)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++#define WRITE_SIZE_STR "writesize"
++#define WRITE_SIZE(mtd) ((mtd)->writesize)
++#else
++#define WRITE_SIZE_STR "oobblock"
++#define WRITE_SIZE(mtd) ((mtd)->oobblock)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
++#define YAFFS_USE_WRITE_BEGIN_END 1
++#else
++#define YAFFS_USE_WRITE_BEGIN_END 0
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
++static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
++{
++ uint64_t result = partition_size;
++ do_div(result, block_size);
++ return (uint32_t) result;
++}
++#else
++#define YCALCBLOCKS(s, b) ((s)/(b))
++#endif
++
++#include <linux/uaccess.h>
++#include <linux/mtd/mtd.h>
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#include "yaffs_linux.h"
++
++#include "yaffs_mtdif.h"
++#include "yaffs_mtdif1.h"
++#include "yaffs_mtdif2.h"
++
++unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
++unsigned int yaffs_auto_checkpoint = 1;
++unsigned int yaffs_gc_control = 1;
++unsigned int yaffs_bg_enable = 1;
++
++/* Module Parameters */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++module_param(yaffs_trace_mask, uint, 0644);
++module_param(yaffs_wr_attempts, uint, 0644);
++module_param(yaffs_auto_checkpoint, uint, 0644);
++module_param(yaffs_gc_control, uint, 0644);
++module_param(yaffs_bg_enable, uint, 0644);
++#else
++MODULE_PARM(yaffs_trace_mask, "i");
++MODULE_PARM(yaffs_wr_attempts, "i");
++MODULE_PARM(yaffs_auto_checkpoint, "i");
++MODULE_PARM(yaffs_gc_control, "i");
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++/* use iget and read_inode */
++#define Y_IGET(sb, inum) iget((sb), (inum))
++static void yaffs_read_inode(struct inode *inode);
++
++#else
++/* Call local equivalent */
++#define YAFFS_USE_OWN_IGET
++#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
++
++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
++#else
++#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip)
++#endif
++
++#define yaffs_inode_to_obj(iptr) ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
++#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info)
++#else
++#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp)
++#endif
++
++#define update_dir_time(dir) do {\
++ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
++ } while(0)
++
++static void yaffs_put_super(struct super_block *sb);
++
++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
++ loff_t * pos);
++static ssize_t yaffs_hold_space(struct file *f);
++static void yaffs_release_space(struct file *f);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_file_flush(struct file *file, fl_owner_t id);
++#else
++static int yaffs_file_flush(struct file *file);
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++static int yaffs_sync_object(struct file *file, int datasync);
++#else
++static int yaffs_sync_object(struct file *file, struct dentry *dentry,
++ int datasync);
++#endif
++
++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
++ struct nameidata *n);
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
++ struct nameidata *n);
++#else
++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
++#endif
++static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
++ struct dentry *dentry);
++static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
++static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
++ const char *symname);
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++ dev_t dev);
++#else
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++ int dev);
++#endif
++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry);
++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_sync_fs(struct super_block *sb, int wait);
++static void yaffs_write_super(struct super_block *sb);
++#else
++static int yaffs_sync_fs(struct super_block *sb);
++static int yaffs_write_super(struct super_block *sb);
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
++#else
++static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
++#endif
++
++#ifdef YAFFS_HAS_PUT_INODE
++static void yaffs_put_inode(struct inode *inode);
++#endif
++
++#ifdef YAFFS_HAS_EVICT_INODE
++static void yaffs_evict_inode(struct inode *);
++#else
++static void yaffs_delete_inode(struct inode *);
++static void yaffs_clear_inode(struct inode *);
++#endif
++
++static int yaffs_readpage(struct file *file, struct page *page);
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
++#else
++static int yaffs_writepage(struct page *page);
++#endif
++
++#ifdef CONFIG_YAFFS_XATTR
++int yaffs_setxattr(struct dentry *dentry, const char *name,
++ const void *value, size_t size, int flags);
++ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
++ size_t size);
++int yaffs_removexattr(struct dentry *dentry, const char *name);
++ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
++#endif
++
++#if (YAFFS_USE_WRITE_BEGIN_END != 0)
++static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned flags,
++ struct page **pagep, void **fsdata);
++static int yaffs_write_end(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned copied,
++ struct page *pg, void *fsdadata);
++#else
++static int yaffs_prepare_write(struct file *f, struct page *pg,
++ unsigned offset, unsigned to);
++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
++ unsigned to);
++
++#endif
++
++static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
++ int buflen);
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
++#else
++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
++#endif
++
++static void yaffs_touch_super(struct yaffs_dev *dev);
++
++static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
++
++static int yaffs_vfs_setattr(struct inode *, struct iattr *);
++
++static struct address_space_operations yaffs_file_address_operations = {
++ .readpage = yaffs_readpage,
++ .writepage = yaffs_writepage,
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++ .write_begin = yaffs_write_begin,
++ .write_end = yaffs_write_end,
++#else
++ .prepare_write = yaffs_prepare_write,
++ .commit_write = yaffs_commit_write,
++#endif
++};
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
++static const struct file_operations yaffs_file_operations = {
++ .read = do_sync_read,
++ .write = do_sync_write,
++ .aio_read = generic_file_aio_read,
++ .aio_write = generic_file_aio_write,
++ .mmap = generic_file_mmap,
++ .flush = yaffs_file_flush,
++ .fsync = yaffs_sync_object,
++ .splice_read = generic_file_splice_read,
++ .splice_write = generic_file_splice_write,
++ .llseek = generic_file_llseek,
++};
++
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++
++static const struct file_operations yaffs_file_operations = {
++ .read = do_sync_read,
++ .write = do_sync_write,
++ .aio_read = generic_file_aio_read,
++ .aio_write = generic_file_aio_write,
++ .mmap = generic_file_mmap,
++ .flush = yaffs_file_flush,
++ .fsync = yaffs_sync_object,
++ .sendfile = generic_file_sendfile,
++};
++
++#else
++
++static const struct file_operations yaffs_file_operations = {
++ .read = generic_file_read,
++ .write = generic_file_write,
++ .mmap = generic_file_mmap,
++ .flush = yaffs_file_flush,
++ .fsync = yaffs_sync_object,
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ .sendfile = generic_file_sendfile,
++#endif
++};
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
++static void zero_user_segment(struct page *page, unsigned start, unsigned end)
++{
++ void *kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr + start, 0, end - start);
++ kunmap_atomic(kaddr, KM_USER0);
++ flush_dcache_page(page);
++}
++#endif
++
++static const struct inode_operations yaffs_file_inode_operations = {
++ .setattr = yaffs_setattr,
++#ifdef CONFIG_YAFFS_XATTR
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++#endif
++};
++
++static const struct inode_operations yaffs_symlink_inode_operations = {
++ .readlink = yaffs_readlink,
++ .follow_link = yaffs_follow_link,
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++ .put_link = yaffs_put_link,
++#endif
++ .setattr = yaffs_setattr,
++#ifdef CONFIG_YAFFS_XATTR
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++#endif
++};
++
++static const struct inode_operations yaffs_dir_inode_operations = {
++ .create = yaffs_create,
++ .lookup = yaffs_lookup,
++ .link = yaffs_link,
++ .unlink = yaffs_unlink,
++ .symlink = yaffs_symlink,
++ .mkdir = yaffs_mkdir,
++ .rmdir = yaffs_unlink,
++ .mknod = yaffs_mknod,
++ .rename = yaffs_rename,
++ .setattr = yaffs_setattr,
++#ifdef CONFIG_YAFFS_XATTR
++ .setxattr = yaffs_setxattr,
++ .getxattr = yaffs_getxattr,
++ .listxattr = yaffs_listxattr,
++ .removexattr = yaffs_removexattr,
++#endif
++};
++
++static const struct file_operations yaffs_dir_operations = {
++ .read = generic_read_dir,
++ .readdir = yaffs_readdir,
++ .fsync = yaffs_sync_object,
++ .llseek = yaffs_dir_llseek,
++};
++
++static const struct super_operations yaffs_super_ops = {
++ .statfs = yaffs_statfs,
++
++#ifndef YAFFS_USE_OWN_IGET
++ .read_inode = yaffs_read_inode,
++#endif
++#ifdef YAFFS_HAS_PUT_INODE
++ .put_inode = yaffs_put_inode,
++#endif
++ .put_super = yaffs_put_super,
++#ifdef YAFFS_HAS_EVICT_INODE
++ .evict_inode = yaffs_evict_inode,
++#else
++ .delete_inode = yaffs_delete_inode,
++ .clear_inode = yaffs_clear_inode,
++#endif
++ .sync_fs = yaffs_sync_fs,
++ .write_super = yaffs_write_super,
++};
++
++static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
++{
++#ifdef YAFFS_USE_SETATTR_COPY
++ setattr_copy(inode, attr);
++ return 0;
++#else
++ return inode_setattr(inode, attr);
++#endif
++
++}
++
++static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
++{
++#ifdef YAFFS_USE_TRUNCATE_SETSIZE
++ truncate_setsize(inode, newsize);
++ return 0;
++#else
++ truncate_inode_pages(&inode->i_data, newsize);
++ return 0;
++#endif
++
++}
++
++static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
++{
++ return yaffs_gc_control;
++}
++
++static void yaffs_gross_lock(struct yaffs_dev *dev)
++{
++ T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
++ mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));
++ T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
++}
++
++static void yaffs_gross_unlock(struct yaffs_dev *dev)
++{
++ T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
++ mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));
++}
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++
++static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
++ uint32_t generation)
++{
++ return Y_IGET(sb, ino);
++}
++
++static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,
++ struct fid *fid, int fh_len,
++ int fh_type)
++{
++ return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
++ yaffs2_nfs_get_inode);
++}
++
++static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,
++ struct fid *fid, int fh_len,
++ int fh_type)
++{
++ return generic_fh_to_parent(sb, fid, fh_len, fh_type,
++ yaffs2_nfs_get_inode);
++}
++
++struct dentry *yaffs2_get_parent(struct dentry *dentry)
++{
++
++ struct super_block *sb = dentry->d_inode->i_sb;
++ struct dentry *parent = ERR_PTR(-ENOENT);
++ struct inode *inode;
++ unsigned long parent_ino;
++ struct yaffs_obj *d_obj;
++ struct yaffs_obj *parent_obj;
++
++ d_obj = yaffs_inode_to_obj(dentry->d_inode);
++
++ if (d_obj) {
++ parent_obj = d_obj->parent;
++ if (parent_obj) {
++ parent_ino = yaffs_get_obj_inode(parent_obj);
++ inode = Y_IGET(sb, parent_ino);
++
++ if (IS_ERR(inode)) {
++ parent = ERR_CAST(inode);
++ } else {
++ parent = d_obtain_alias(inode);
++ if (!IS_ERR(parent)) {
++ parent = ERR_PTR(-ENOMEM);
++ iput(inode);
++ }
++ }
++ }
++ }
++
++ return parent;
++}
++
++/* Just declare a zero structure as a NULL value implies
++ * using the default functions of exportfs.
++ */
++
++static struct export_operations yaffs_export_ops = {
++ .fh_to_dentry = yaffs2_fh_to_dentry,
++ .fh_to_parent = yaffs2_fh_to_parent,
++ .get_parent = yaffs2_get_parent,
++};
++
++#endif
++
++/*-----------------------------------------------------------------*/
++/* Directory search context allows us to unlock access to yaffs during
++ * filldir without causing problems with the directory being modified.
++ * This is similar to the tried and tested mechanism used in yaffs direct.
++ *
++ * A search context iterates along a doubly linked list of siblings in the
++ * directory. If the iterating object is deleted then this would corrupt
++ * the list iteration, likely causing a crash. The search context avoids
++ * this by using the remove_obj_fn to move the search context to the
++ * next object before the object is deleted.
++ *
++ * Many readdirs (and thus seach conexts) may be alive simulateously so
++ * each struct yaffs_dev has a list of these.
++ *
++ * A seach context lives for the duration of a readdir.
++ *
++ * All these functions must be called while yaffs is locked.
++ */
++
++struct yaffs_search_context {
++ struct yaffs_dev *dev;
++ struct yaffs_obj *dir_obj;
++ struct yaffs_obj *next_return;
++ struct list_head others;
++};
++
++/*
++ * yaffs_new_search() creates a new search context, initialises it and
++ * adds it to the device's search context list.
++ *
++ * Called at start of readdir.
++ */
++static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
++{
++ struct yaffs_dev *dev = dir->my_dev;
++ struct yaffs_search_context *sc =
++ YMALLOC(sizeof(struct yaffs_search_context));
++ if (sc) {
++ sc->dir_obj = dir;
++ sc->dev = dev;
++ if (list_empty(&sc->dir_obj->variant.dir_variant.children))
++ sc->next_return = NULL;
++ else
++ sc->next_return =
++ list_entry(dir->variant.dir_variant.children.next,
++ struct yaffs_obj, siblings);
++ INIT_LIST_HEAD(&sc->others);
++ list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
++ }
++ return sc;
++}
++
++/*
++ * yaffs_search_end() disposes of a search context and cleans up.
++ */
++static void yaffs_search_end(struct yaffs_search_context *sc)
++{
++ if (sc) {
++ list_del(&sc->others);
++ YFREE(sc);
++ }
++}
++
++/*
++ * yaffs_search_advance() moves a search context to the next object.
++ * Called when the search iterates or when an object removal causes
++ * the search context to be moved to the next object.
++ */
++static void yaffs_search_advance(struct yaffs_search_context *sc)
++{
++ if (!sc)
++ return;
++
++ if (sc->next_return == NULL ||
++ list_empty(&sc->dir_obj->variant.dir_variant.children))
++ sc->next_return = NULL;
++ else {
++ struct list_head *next = sc->next_return->siblings.next;
++
++ if (next == &sc->dir_obj->variant.dir_variant.children)
++ sc->next_return = NULL; /* end of list */
++ else
++ sc->next_return =
++ list_entry(next, struct yaffs_obj, siblings);
++ }
++}
++
++/*
++ * yaffs_remove_obj_callback() is called when an object is unlinked.
++ * We check open search contexts and advance any which are currently
++ * on the object being iterated.
++ */
++static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
++{
++
++ struct list_head *i;
++ struct yaffs_search_context *sc;
++ struct list_head *search_contexts =
++ &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
++
++ /* Iterate through the directory search contexts.
++ * If any are currently on the object being removed, then advance
++ * the search context to the next object to prevent a hanging pointer.
++ */
++ list_for_each(i, search_contexts) {
++ if (i) {
++ sc = list_entry(i, struct yaffs_search_context, others);
++ if (sc->next_return == obj)
++ yaffs_search_advance(sc);
++ }
++ }
++
++}
++
++/*-----------------------------------------------------------------*/
++
++static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
++ int buflen)
++{
++ unsigned char *alias;
++ int ret;
++
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++
++ yaffs_gross_unlock(dev);
++
++ if (!alias)
++ return -ENOMEM;
++
++ ret = vfs_readlink(dentry, buffer, buflen, alias);
++ kfree(alias);
++ return ret;
++}
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ void *ret;
++#else
++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ int ret
++#endif
++ unsigned char *alias;
++ int ret_int = 0;
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
++ yaffs_gross_unlock(dev);
++
++ if (!alias) {
++ ret_int = -ENOMEM;
++ goto out;
++ }
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++ nd_set_link(nd, alias);
++ ret = alias;
++out:
++ if (ret_int)
++ ret = ERR_PTR(ret_int);
++ return ret;
++#else
++ ret = vfs_follow_link(nd, alias);
++ kfree(alias);
++out:
++ if (ret_int)
++ ret = ret_int;
++ return ret;
++#endif
++}
++
++#if (YAFFS_NEW_FOLLOW_LINK == 1)
++void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
++{
++ kfree(alias);
++}
++#endif
++
++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
++ struct yaffs_obj *obj);
++
++/*
++ * Lookup is used to find objects in the fs
++ */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
++ struct nameidata *n)
++#else
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
++#endif
++{
++ struct yaffs_obj *obj;
++ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
++
++ struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_lock(dev);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_lookup for %d:%s\n"),
++ yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name));
++
++ obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);
++
++ obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
++
++ /* Can't hold gross lock when calling yaffs_get_inode() */
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_lookup found %d\n"), obj->obj_id));
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++
++ if (inode) {
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_loookup dentry \n")));
++/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
++ * d_add even if NULL inode */
++#if 0
++ /*dget(dentry); // try to solve directory bug */
++ d_add(dentry, inode);
++
++ /* return dentry; */
++ return NULL;
++#endif
++ }
++
++ } else {
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_lookup not found\n")));
++
++ }
++
++/* added NCB for 2.5/6 compatability - forces add even if inode is
++ * NULL which creates dentry hash */
++ d_add(dentry, inode);
++
++ return NULL;
++}
++
++#ifdef YAFFS_HAS_PUT_INODE
++
++/* For now put inode is just for debugging
++ * Put inode is called when the inode **structure** is put.
++ */
++static void yaffs_put_inode(struct inode *inode)
++{
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
++ atomic_read(&inode->i_count)));
++
++}
++#endif
++
++static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
++{
++ /* Clear the association between the inode and
++ * the struct yaffs_obj.
++ */
++ obj->my_inode = NULL;
++ yaffs_inode_to_obj_lv(inode) = NULL;
++
++ /* If the object freeing was deferred, then the real
++ * free happens now.
++ * This should fix the inode inconsistency problem.
++ */
++ yaffs_handle_defered_free(obj);
++}
++
++#ifdef YAFFS_HAS_EVICT_INODE
++/* yaffs_evict_inode combines into one operation what was previously done in
++ * yaffs_clear_inode() and yaffs_delete_inode()
++ *
++ */
++static void yaffs_evict_inode(struct inode *inode)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ int deleteme = 0;
++
++ obj = yaffs_inode_to_obj(inode);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
++ atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object"));
++
++ if (!inode->i_nlink && !is_bad_inode(inode))
++ deleteme = 1;
++ truncate_inode_pages(&inode->i_data, 0);
++ end_writeback(inode);
++
++ if (deleteme && obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_del_obj(obj);
++ yaffs_gross_unlock(dev);
++ }
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_unstitch_obj(inode, obj);
++ yaffs_gross_unlock(dev);
++ }
++
++}
++#else
++
++/* clear is called to tell the fs to release any per-inode data it holds.
++ * The object might still exist on disk and is just being thrown out of the cache
++ * or else the object has actually been deleted and we're being called via
++ * the chain
++ * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
++ */
++
++static void yaffs_clear_inode(struct inode *inode)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_inode_to_obj(inode);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
++ atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object"));
++
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_unstitch_obj(inode, obj);
++ yaffs_gross_unlock(dev);
++ }
++
++}
++
++/* delete is called when the link count is zero and the inode
++ * is put (ie. nobody wants to know about it anymore, time to
++ * delete the file).
++ * NB Must call clear_inode()
++ */
++static void yaffs_delete_inode(struct inode *inode)
++{
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++ struct yaffs_dev *dev;
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
++ atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object"));
++
++ if (obj) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ yaffs_del_obj(obj);
++ yaffs_gross_unlock(dev);
++ }
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++ truncate_inode_pages(&inode->i_data, 0);
++#endif
++ clear_inode(inode);
++}
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_file_flush(struct file *file, fl_owner_t id)
++#else
++static int yaffs_file_flush(struct file *file)
++#endif
++{
++ struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
++
++ struct yaffs_dev *dev = obj->my_dev;
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_file_flush object %d (%s)\n"), obj->obj_id,
++ obj->dirty ? "dirty" : "clean"));
++
++ yaffs_gross_lock(dev);
++
++ yaffs_flush_file(obj, 1, 0);
++
++ yaffs_gross_unlock(dev);
++
++ return 0;
++}
++
++static int yaffs_readpage_nolock(struct file *f, struct page *pg)
++{
++ /* Lifted from jffs2 */
++
++ struct yaffs_obj *obj;
++ unsigned char *pg_buf;
++ int ret;
++
++ struct yaffs_dev *dev;
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
++ (unsigned)(pg->index << PAGE_CACHE_SHIFT),
++ (unsigned)PAGE_CACHE_SIZE));
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ BUG_ON(!PageLocked(pg));
++#else
++ if (!PageLocked(pg))
++ PAGE_BUG(pg);
++#endif
++
++ pg_buf = kmap(pg);
++ /* FIXME: Can kmap fail? */
++
++ yaffs_gross_lock(dev);
++
++ ret = yaffs_file_rd(obj, pg_buf,
++ pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE);
++
++ yaffs_gross_unlock(dev);
++
++ if (ret >= 0)
++ ret = 0;
++
++ if (ret) {
++ ClearPageUptodate(pg);
++ SetPageError(pg);
++ } else {
++ SetPageUptodate(pg);
++ ClearPageError(pg);
++ }
++
++ flush_dcache_page(pg);
++ kunmap(pg);
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n")));
++ return ret;
++}
++
++static int yaffs_readpage_unlock(struct file *f, struct page *pg)
++{
++ int ret = yaffs_readpage_nolock(f, pg);
++ UnlockPage(pg);
++ return ret;
++}
++
++static int yaffs_readpage(struct file *f, struct page *pg)
++{
++ int ret;
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n")));
++ ret = yaffs_readpage_unlock(f, pg);
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n")));
++ return ret;
++}
++
++/* writepage inspired by/stolen from smbfs */
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
++#else
++static int yaffs_writepage(struct page *page)
++#endif
++{
++ struct yaffs_dev *dev;
++ struct address_space *mapping = page->mapping;
++ struct inode *inode;
++ unsigned long end_index;
++ char *buffer;
++ struct yaffs_obj *obj;
++ int n_written = 0;
++ unsigned n_bytes;
++ loff_t i_size;
++
++ if (!mapping)
++ BUG();
++ inode = mapping->host;
++ if (!inode)
++ BUG();
++ i_size = i_size_read(inode);
++
++ end_index = i_size >> PAGE_CACHE_SHIFT;
++
++ if (page->index < end_index)
++ n_bytes = PAGE_CACHE_SIZE;
++ else {
++ n_bytes = i_size & (PAGE_CACHE_SIZE - 1);
++
++ if (page->index > end_index || !n_bytes) {
++ T(YAFFS_TRACE_OS,
++ (TSTR
++ ("yaffs_writepage at %08x, inode size = %08x!!!\n"),
++ (unsigned)(page->index << PAGE_CACHE_SHIFT),
++ (unsigned)inode->i_size));
++ T(YAFFS_TRACE_OS,
++ (TSTR(" -> don't care!!\n")));
++
++ zero_user_segment(page, 0, PAGE_CACHE_SIZE);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ return 0;
++ }
++ }
++
++ if (n_bytes != PAGE_CACHE_SIZE)
++ zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);
++
++ get_page(page);
++
++ buffer = kmap(page);
++
++ obj = yaffs_inode_to_obj(inode);
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_writepage at %08x, size %08x\n"),
++ (unsigned)(page->index << PAGE_CACHE_SHIFT), n_bytes));
++ T(YAFFS_TRACE_OS,
++ (TSTR("writepag0: obj = %05x, ino = %05x\n"),
++ (int)obj->variant.file_variant.file_size, (int)inode->i_size));
++
++ n_written = yaffs_wr_file(obj, buffer,
++ page->index << PAGE_CACHE_SHIFT, n_bytes, 0);
++
++ yaffs_touch_super(dev);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("writepag1: obj = %05x, ino = %05x\n"),
++ (int)obj->variant.file_variant.file_size, (int)inode->i_size));
++
++ yaffs_gross_unlock(dev);
++
++ kunmap(page);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ put_page(page);
++
++ return (n_written == n_bytes) ? 0 : -ENOSPC;
++}
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned flags,
++ struct page **pagep, void **fsdata)
++{
++ struct page *pg = NULL;
++ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
++
++ int ret = 0;
++ int space_held = 0;
++
++ /* Get a page */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
++ pg = grab_cache_page_write_begin(mapping, index, flags);
++#else
++ pg = __grab_cache_page(mapping, index);
++#endif
++
++ *pagep = pg;
++ if (!pg) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ T(YAFFS_TRACE_OS,
++ (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"),
++ (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0));
++
++ /* Get fs space */
++ space_held = yaffs_hold_space(filp);
++
++ if (!space_held) {
++ ret = -ENOSPC;
++ goto out;
++ }
++
++ /* Update page if required */
++
++ if (!Page_Uptodate(pg))
++ ret = yaffs_readpage_nolock(filp, pg);
++
++ if (ret)
++ goto out;
++
++ /* Happy path return */
++ T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n")));
++
++ return 0;
++
++out:
++ T(YAFFS_TRACE_OS,
++ (TSTR("end yaffs_write_begin fail returning %d\n"), ret));
++ if (space_held)
++ yaffs_release_space(filp);
++ if (pg) {
++ unlock_page(pg);
++ page_cache_release(pg);
++ }
++ return ret;
++}
++
++#else
++
++static int yaffs_prepare_write(struct file *f, struct page *pg,
++ unsigned offset, unsigned to)
++{
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n")));
++
++ if (!Page_Uptodate(pg))
++ return yaffs_readpage_nolock(f, pg);
++ return 0;
++}
++#endif
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_end(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned copied,
++ struct page *pg, void *fsdadata)
++{
++ int ret = 0;
++ void *addr, *kva;
++ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
++
++ kva = kmap(pg);
++ addr = kva + offset_into_page;
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_write_end addr %p pos %x n_bytes %d\n",
++ addr, (unsigned)pos, copied));
++
++ ret = yaffs_file_write(filp, addr, copied, &pos);
++
++ if (ret != copied) {
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_write_end not same size ret %d copied %d\n"),
++ ret, copied));
++ SetPageError(pg);
++ } else {
++ /* Nothing */
++ }
++
++ kunmap(pg);
++
++ yaffs_release_space(filp);
++ unlock_page(pg);
++ page_cache_release(pg);
++ return ret;
++}
++#else
++
++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
++ unsigned to)
++{
++ void *addr, *kva;
++
++ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
++ int n_bytes = to - offset;
++ int n_written;
++
++ unsigned spos = pos;
++ unsigned saddr;
++
++ kva = kmap(pg);
++ addr = kva + offset;
++
++ saddr = (unsigned)addr;
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_commit_write addr %x pos %x n_bytes %d\n"),
++ saddr, spos, n_bytes));
++
++ n_written = yaffs_file_write(f, addr, n_bytes, &pos);
++
++ if (n_written != n_bytes) {
++ T(YAFFS_TRACE_OS,
++ (TSTR
++ ("yaffs_commit_write not same size n_written %d n_bytes %d\n"),
++ n_written, n_bytes));
++ SetPageError(pg);
++ } else {
++ /* Nothing */
++ }
++
++ kunmap(pg);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_commit_write returning %d\n"),
++ n_written == n_bytes ? 0 : n_written));
++
++ return n_written == n_bytes ? 0 : n_written;
++}
++#endif
++
++static void yaffs_fill_inode_from_obj(struct inode *inode,
++ struct yaffs_obj *obj)
++{
++ if (inode && obj) {
++
++ /* Check mode against the variant type and attempt to repair if broken. */
++ u32 mode = obj->yst_mode;
++ switch (obj->variant_type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (!S_ISREG(mode)) {
++ obj->yst_mode &= ~S_IFMT;
++ obj->yst_mode |= S_IFREG;
++ }
++
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ if (!S_ISLNK(mode)) {
++ obj->yst_mode &= ~S_IFMT;
++ obj->yst_mode |= S_IFLNK;
++ }
++
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ if (!S_ISDIR(mode)) {
++ obj->yst_mode &= ~S_IFMT;
++ obj->yst_mode |= S_IFDIR;
++ }
++
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ default:
++ /* TODO? */
++ break;
++ }
++
++ inode->i_flags |= S_NOATIME;
++
++ inode->i_ino = obj->obj_id;
++ inode->i_mode = obj->yst_mode;
++ inode->i_uid = obj->yst_uid;
++ inode->i_gid = obj->yst_gid;
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++ inode->i_blksize = inode->i_sb->s_blocksize;
++#endif
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++ inode->i_rdev = old_decode_dev(obj->yst_rdev);
++ inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
++ inode->i_atime.tv_nsec = 0;
++ inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
++ inode->i_mtime.tv_nsec = 0;
++ inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
++ inode->i_ctime.tv_nsec = 0;
++#else
++ inode->i_rdev = obj->yst_rdev;
++ inode->i_atime = obj->yst_atime;
++ inode->i_mtime = obj->yst_mtime;
++ inode->i_ctime = obj->yst_ctime;
++#endif
++ inode->i_size = yaffs_get_obj_length(obj);
++ inode->i_blocks = (inode->i_size + 511) >> 9;
++
++ inode->i_nlink = yaffs_get_obj_link_count(obj);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR
++ ("yaffs_fill_inode mode %x uid %d gid %d size %d count %d\n"),
++ inode->i_mode, inode->i_uid, inode->i_gid,
++ (int)inode->i_size, atomic_read(&inode->i_count)));
++
++ switch (obj->yst_mode & S_IFMT) {
++ default: /* fifo, device or socket */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ init_special_inode(inode, obj->yst_mode,
++ old_decode_dev(obj->yst_rdev));
++#else
++ init_special_inode(inode, obj->yst_mode,
++ (dev_t) (obj->yst_rdev));
++#endif
++ break;
++ case S_IFREG: /* file */
++ inode->i_op = &yaffs_file_inode_operations;
++ inode->i_fop = &yaffs_file_operations;
++ inode->i_mapping->a_ops =
++ &yaffs_file_address_operations;
++ break;
++ case S_IFDIR: /* directory */
++ inode->i_op = &yaffs_dir_inode_operations;
++ inode->i_fop = &yaffs_dir_operations;
++ break;
++ case S_IFLNK: /* symlink */
++ inode->i_op = &yaffs_symlink_inode_operations;
++ break;
++ }
++
++ yaffs_inode_to_obj_lv(inode) = obj;
++
++ obj->my_inode = inode;
++
++ } else {
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_fill_inode invalid parameters\n")));
++ }
++
++}
++
++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
++ struct yaffs_obj *obj)
++{
++ struct inode *inode;
++
++ if (!sb) {
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_get_inode for NULL super_block!!\n")));
++ return NULL;
++
++ }
++
++ if (!obj) {
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_get_inode for NULL object!!\n")));
++ return NULL;
++
++ }
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_get_inode for object %d\n"), obj->obj_id));
++
++ inode = Y_IGET(sb, obj->obj_id);
++ if (IS_ERR(inode))
++ return NULL;
++
++ /* NB Side effect: iget calls back to yaffs_read_inode(). */
++ /* iget also increments the inode's i_count */
++ /* NB You can't be holding gross_lock or deadlock will happen! */
++
++ return inode;
++}
++
++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
++ loff_t * pos)
++{
++ struct yaffs_obj *obj;
++ int n_written, ipos;
++ struct inode *inode;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ inode = f->f_dentry->d_inode;
++
++ if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
++ ipos = inode->i_size;
++ else
++ ipos = *pos;
++
++ if (!obj)
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_file_write: hey obj is null!\n")));
++ else
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_file_write about to write writing %u(%x) bytes"
++ "to object %d at %d(%x)\n"),
++ (unsigned)n, (unsigned)n, obj->obj_id, ipos, ipos));
++
++ n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
++
++ yaffs_touch_super(dev);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
++ (unsigned)n, (unsigned)n));
++
++ if (n_written > 0) {
++ ipos += n_written;
++ *pos = ipos;
++ if (ipos > inode->i_size) {
++ inode->i_size = ipos;
++ inode->i_blocks = (ipos + 511) >> 9;
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_file_write size updated to %d bytes, "
++ "%d blocks\n"), ipos, (int)(inode->i_blocks)));
++ }
++
++ }
++ yaffs_gross_unlock(dev);
++ return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
++}
++
++/* Space holding and freeing is done to ensure we have space available for write_begin/end */
++/* For now we just assume few parallel writes and check against a small number. */
++/* Todo: need to do this with a counter to handle parallel reads better */
++
++static ssize_t yaffs_hold_space(struct file *f)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ int n_free_chunks;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ n_free_chunks = yaffs_get_n_free_chunks(dev);
++
++ yaffs_gross_unlock(dev);
++
++ return (n_free_chunks > 20) ? 1 : 0;
++}
++
++static void yaffs_release_space(struct file *f)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_gross_unlock(dev);
++}
++
++static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
++{
++ long long retval;
++
++ lock_kernel();
++
++ switch (origin) {
++ case 2:
++ offset += i_size_read(file->f_path.dentry->d_inode);
++ break;
++ case 1:
++ offset += file->f_pos;
++ }
++ retval = -EINVAL;
++
++ if (offset >= 0) {
++ if (offset != file->f_pos)
++ file->f_pos = offset;
++
++ retval = offset;
++ }
++ unlock_kernel();
++ return retval;
++}
++
++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ struct yaffs_search_context *sc;
++ struct inode *inode = f->f_dentry->d_inode;
++ unsigned long offset, curoffs;
++ struct yaffs_obj *l;
++ int ret_val = 0;
++
++ char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ obj = yaffs_dentry_to_obj(f->f_dentry);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ yaffs_dev_to_lc(dev)->readdir_process = current;
++
++ offset = f->f_pos;
++
++ sc = yaffs_new_search(obj);
++ if (!sc) {
++ ret_val = -ENOMEM;
++ goto out;
++ }
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
++
++ if (offset == 0) {
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_readdir: entry . ino %d \n"),
++ (int)inode->i_ino));
++ yaffs_gross_unlock(dev);
++ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ f->f_pos++;
++ }
++ if (offset == 1) {
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_readdir: entry .. ino %d \n"),
++ (int)f->f_dentry->d_parent->d_inode->i_ino));
++ yaffs_gross_unlock(dev);
++ if (filldir(dirent, "..", 2, offset,
++ f->f_dentry->d_parent->d_inode->i_ino,
++ DT_DIR) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++ yaffs_gross_lock(dev);
++ offset++;
++ f->f_pos++;
++ }
++
++ curoffs = 1;
++
++ /* If the directory has changed since the open or last call to
++ readdir, rewind to after the 2 canned entries. */
++ if (f->f_version != inode->i_version) {
++ offset = 2;
++ f->f_pos = offset;
++ f->f_version = inode->i_version;
++ }
++
++ while (sc->next_return) {
++ curoffs++;
++ l = sc->next_return;
++ if (curoffs >= offset) {
++ int this_inode = yaffs_get_obj_inode(l);
++ int this_type = yaffs_get_obj_type(l);
++
++ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_readdir: %s inode %d\n"),
++ name, yaffs_get_obj_inode(l)));
++
++ yaffs_gross_unlock(dev);
++
++ if (filldir(dirent,
++ name,
++ strlen(name),
++ offset, this_inode, this_type) < 0) {
++ yaffs_gross_lock(dev);
++ goto out;
++ }
++
++ yaffs_gross_lock(dev);
++
++ offset++;
++ f->f_pos++;
++ }
++ yaffs_search_advance(sc);
++ }
++
++out:
++ yaffs_search_end(sc);
++ yaffs_dev_to_lc(dev)->readdir_process = NULL;
++ yaffs_gross_unlock(dev);
++
++ return ret_val;
++}
++
++/*
++ * File creation. Allocate an inode, and we're done..
++ */
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++#define YCRED(x) x
++#else
++#define YCRED(x) (x->cred)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++ dev_t rdev)
++#else
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++ int rdev)
++#endif
++{
++ struct inode *inode;
++
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_dev *dev;
++
++ struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
++
++ int error = -ENOSPC;
++ uid_t uid = YCRED(current)->fsuid;
++ gid_t gid =
++ (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
++
++ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
++ mode |= S_ISGID;
++
++ if (parent) {
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_mknod: parent object %d type %d\n"),
++ parent->obj_id, parent->variant_type));
++ } else {
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_mknod: could not get parent object\n")));
++ return -EPERM;
++ }
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, "
++ "mode %x dev %x\n"),
++ dentry->d_name.name, mode, rdev));
++
++ dev = parent->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ switch (mode & S_IFMT) {
++ default:
++ /* Special (socket, fifo, device...) */
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n")));
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ obj =
++ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++ gid, old_encode_dev(rdev));
++#else
++ obj =
++ yaffs_create_special(parent, dentry->d_name.name, mode, uid,
++ gid, rdev);
++#endif
++ break;
++ case S_IFREG: /* file */
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n")));
++ obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
++ gid);
++ break;
++ case S_IFDIR: /* directory */
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making directory\n")));
++ obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
++ uid, gid);
++ break;
++ case S_IFLNK: /* symlink */
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n")));
++ obj = NULL; /* Do we ever get here? */
++ break;
++ }
++
++ /* Can not call yaffs_get_inode() with gross lock held */
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_mknod created object %d count = %d\n"),
++ obj->obj_id, atomic_read(&inode->i_count)));
++ error = 0;
++ yaffs_fill_inode_from_obj(dir, parent);
++ } else {
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod failed making object\n")));
++ error = -ENOMEM;
++ }
++
++ return error;
++}
++
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++ int ret_val;
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
++ ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
++ return ret_val;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
++ struct nameidata *n)
++#else
++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
++#endif
++{
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_create\n")));
++ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
++}
++
++static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int ret_val;
++
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj;
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_unlink %d:%s\n"),
++ (int)(dir->i_ino), dentry->d_name.name));
++ obj = yaffs_inode_to_obj(dir);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ ret_val = yaffs_unlinker(obj, dentry->d_name.name);
++
++ if (ret_val == YAFFS_OK) {
++ dentry->d_inode->i_nlink--;
++ dir->i_version++;
++ yaffs_gross_unlock(dev);
++ mark_inode_dirty(dentry->d_inode);
++ update_dir_time(dir);
++ return 0;
++ }
++ yaffs_gross_unlock(dev);
++ return -ENOTEMPTY;
++}
++
++/*
++ * Create a link...
++ */
++static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
++ struct dentry *dentry)
++{
++ struct inode *inode = old_dentry->d_inode;
++ struct yaffs_obj *obj = NULL;
++ struct yaffs_obj *link = NULL;
++ struct yaffs_dev *dev;
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n")));
++
++ obj = yaffs_inode_to_obj(inode);
++ dev = obj->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
++ link =
++ yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,
++ obj);
++
++ if (link) {
++ old_dentry->d_inode->i_nlink = yaffs_get_obj_link_count(obj);
++ d_instantiate(dentry, old_dentry->d_inode);
++ atomic_inc(&old_dentry->d_inode->i_count);
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_link link count %d i_count %d\n"),
++ old_dentry->d_inode->i_nlink,
++ atomic_read(&old_dentry->d_inode->i_count)));
++ }
++
++ yaffs_gross_unlock(dev);
++
++ if (link) {
++ update_dir_time(dir);
++ return 0;
++ }
++
++ return -EPERM;
++}
++
++static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
++ const char *symname)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++ uid_t uid = YCRED(current)->fsuid;
++ gid_t gid =
++ (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
++
++ dev = yaffs_inode_to_obj(dir)->my_dev;
++ yaffs_gross_lock(dev);
++ obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
++ S_IFLNK | S_IRWXUGO, uid, gid, symname);
++ yaffs_gross_unlock(dev);
++
++ if (obj) {
++ struct inode *inode;
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n")));
++ return 0;
++ } else {
++ T(YAFFS_TRACE_OS, (TSTR("symlink not created\n")));
++ }
++
++ return -ENOMEM;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++static int yaffs_sync_object(struct file *file, int datasync)
++#else
++static int yaffs_sync_object(struct file *file, struct dentry *dentry,
++ int datasync)
++#endif
++{
++
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
++ struct dentry *dentry = file->f_path.dentry;
++#endif
++
++ obj = yaffs_dentry_to_obj(dentry);
++
++ dev = obj->my_dev;
++
++ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, (TSTR("yaffs_sync_object\n")));
++ yaffs_gross_lock(dev);
++ yaffs_flush_file(obj, 1, datasync);
++ yaffs_gross_unlock(dev);
++ return 0;
++}
++
++/*
++ * The VFS layer already does all the dentry stuff for rename.
++ *
++ * NB: POSIX says you can rename an object over an old object of the same name
++ */
++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry)
++{
++ struct yaffs_dev *dev;
++ int ret_val = YAFFS_FAIL;
++ struct yaffs_obj *target;
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n")));
++ dev = yaffs_inode_to_obj(old_dir)->my_dev;
++
++ yaffs_gross_lock(dev);
++
++ /* Check if the target is an existing directory that is not empty. */
++ target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),
++ new_dentry->d_name.name);
++
++ if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
++ !list_empty(&target->variant.dir_variant.children)) {
++
++ T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n")));
++
++ ret_val = YAFFS_FAIL;
++ } else {
++ /* Now does unlinking internally using shadowing mechanism */
++ T(YAFFS_TRACE_OS, (TSTR("calling yaffs_rename_obj\n")));
++
++ ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),
++ old_dentry->d_name.name,
++ yaffs_inode_to_obj(new_dir),
++ new_dentry->d_name.name);
++ }
++ yaffs_gross_unlock(dev);
++
++ if (ret_val == YAFFS_OK) {
++ if (target) {
++ new_dentry->d_inode->i_nlink--;
++ mark_inode_dirty(new_dentry->d_inode);
++ }
++
++ update_dir_time(old_dir);
++ if (old_dir != new_dir)
++ update_dir_time(new_dir);
++ return 0;
++ } else {
++ return -ENOTEMPTY;
++ }
++}
++
++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_setattr of object %d\n"),
++ yaffs_inode_to_obj(inode)->obj_id));
++
++ /* Fail if a requested resize >= 2GB */
++ if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
++ error = -EINVAL;
++
++ if (error == 0)
++ error = inode_change_ok(inode, attr);
++ if (error == 0) {
++ int result;
++ if (!error) {
++ error = yaffs_vfs_setattr(inode, attr);
++ T(YAFFS_TRACE_OS, (TSTR("inode_setattr called\n")));
++ if (attr->ia_valid & ATTR_SIZE) {
++ yaffs_vfs_setsize(inode, attr->ia_size);
++ inode->i_blocks = (inode->i_size + 511) >> 9;
++ }
++ }
++ dev = yaffs_inode_to_obj(inode)->my_dev;
++ if (attr->ia_valid & ATTR_SIZE) {
++ T(YAFFS_TRACE_OS, (TSTR("resize to %d(%x)\n"),
++ (int)(attr->ia_size),
++ (int)(attr->ia_size)));
++ }
++ yaffs_gross_lock(dev);
++ result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
++ if (result == YAFFS_OK) {
++ error = 0;
++ } else {
++ error = -EPERM;
++ }
++ yaffs_gross_unlock(dev);
++
++ }
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_setattr done returning %d\n"), error));
++
++ return error;
++}
++
++#ifdef CONFIG_YAFFS_XATTR
++int yaffs_setxattr(struct dentry *dentry, const char *name,
++ const void *value, size_t size, int flags)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_setxattr of object %d\n"), obj->obj_id));
++
++ if (error == 0) {
++ int result;
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ result = yaffs_set_xattrib(obj, name, value, size, flags);
++ if (result == YAFFS_OK)
++ error = 0;
++ else if (result < 0)
++ error = result;
++ yaffs_gross_unlock(dev);
++
++ }
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_setxattr done returning %d\n"), error));
++
++ return error;
++}
++
++ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, void *buff,
++ size_t size)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_getxattr \"%s\" from object %d\n"), name, obj->obj_id));
++
++ if (error == 0) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ error = yaffs_get_xattrib(obj, name, buff, size);
++ yaffs_gross_unlock(dev);
++
++ }
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_getxattr done returning %d\n"), error));
++
++ return error;
++}
++
++int yaffs_removexattr(struct dentry *dentry, const char *name)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_removexattr of object %d\n"), obj->obj_id));
++
++ if (error == 0) {
++ int result;
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ result = yaffs_remove_xattrib(obj, name);
++ if (result == YAFFS_OK)
++ error = 0;
++ else if (result < 0)
++ error = result;
++ yaffs_gross_unlock(dev);
++
++ }
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_removexattr done returning %d\n"), error));
++
++ return error;
++}
++
++ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
++{
++ struct inode *inode = dentry->d_inode;
++ int error = 0;
++ struct yaffs_dev *dev;
++ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_listxattr of object %d\n"), obj->obj_id));
++
++ if (error == 0) {
++ dev = obj->my_dev;
++ yaffs_gross_lock(dev);
++ error = yaffs_list_xattrib(obj, buff, size);
++ yaffs_gross_unlock(dev);
++
++ }
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_listxattr done returning %d\n"), error));
++
++ return error;
++}
++
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
++ struct super_block *sb = dentry->d_sb;
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#else
++static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++#endif
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n")));
++
++ yaffs_gross_lock(dev);
++
++ buf->f_type = YAFFS_MAGIC;
++ buf->f_bsize = sb->s_blocksize;
++ buf->f_namelen = 255;
++
++ if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
++ /* Do this if chunk size is not a power of 2 */
++
++ uint64_t bytes_in_dev;
++ uint64_t bytes_free;
++
++ bytes_in_dev =
++ ((uint64_t)
++ ((dev->param.end_block - dev->param.start_block +
++ 1))) * ((uint64_t) (dev->param.chunks_per_block *
++ dev->data_bytes_per_chunk));
++
++ do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */
++ buf->f_blocks = bytes_in_dev;
++
++ bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
++ ((uint64_t) (dev->data_bytes_per_chunk));
++
++ do_div(bytes_free, sb->s_blocksize);
++
++ buf->f_bfree = bytes_free;
++
++ } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
++
++ buf->f_blocks =
++ (dev->param.end_block - dev->param.start_block + 1) *
++ dev->param.chunks_per_block /
++ (sb->s_blocksize / dev->data_bytes_per_chunk);
++ buf->f_bfree =
++ yaffs_get_n_free_chunks(dev) /
++ (sb->s_blocksize / dev->data_bytes_per_chunk);
++ } else {
++ buf->f_blocks =
++ (dev->param.end_block - dev->param.start_block + 1) *
++ dev->param.chunks_per_block *
++ (dev->data_bytes_per_chunk / sb->s_blocksize);
++
++ buf->f_bfree =
++ yaffs_get_n_free_chunks(dev) *
++ (dev->data_bytes_per_chunk / sb->s_blocksize);
++ }
++
++ buf->f_files = 0;
++ buf->f_ffree = 0;
++ buf->f_bavail = buf->f_bfree;
++
++ yaffs_gross_unlock(dev);
++ return 0;
++}
++
++static void yaffs_flush_inodes(struct super_block *sb)
++{
++ struct inode *iptr;
++ struct yaffs_obj *obj;
++
++ list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
++ obj = yaffs_inode_to_obj(iptr);
++ if (obj) {
++ T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
++ obj->obj_id));
++ yaffs_flush_file(obj, 1, 0);
++ }
++ }
++}
++
++static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ if (!dev)
++ return;
++
++ yaffs_flush_inodes(sb);
++ yaffs_update_dirty_dirs(dev);
++ yaffs_flush_whole_cache(dev);
++ if (do_checkpoint)
++ yaffs_checkpoint_save(dev);
++}
++
++static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
++{
++ unsigned erased_chunks =
++ dev->n_erased_blocks * dev->param.chunks_per_block;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++ unsigned scattered = 0; /* Free chunks not in an erased block */
++
++ if (erased_chunks < dev->n_free_chunks)
++ scattered = (dev->n_free_chunks - erased_chunks);
++
++ if (!context->bg_running)
++ return 0;
++ else if (scattered < (dev->param.chunks_per_block * 2))
++ return 0;
++ else if (erased_chunks > dev->n_free_chunks / 2)
++ return 0;
++ else if (erased_chunks > dev->n_free_chunks / 4)
++ return 1;
++ else
++ return 2;
++}
++
++static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
++{
++
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++ unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
++ unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
++ int do_checkpoint;
++
++ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++ (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
++ gc_urgent,
++ sb->s_dirt ? "dirty" : "clean",
++ request_checkpoint ? "checkpoint requested" : "no checkpoint",
++ oneshot_checkpoint ? " one-shot" : ""));
++
++ yaffs_gross_lock(dev);
++ do_checkpoint = ((request_checkpoint && !gc_urgent) ||
++ oneshot_checkpoint) && !dev->is_checkpointed;
++
++ if (sb->s_dirt || do_checkpoint) {
++ yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
++ sb->s_dirt = 0;
++ if (oneshot_checkpoint)
++ yaffs_auto_checkpoint &= ~4;
++ }
++ yaffs_gross_unlock(dev);
++
++ return 0;
++}
++
++/*
++ * yaffs background thread functions .
++ * yaffs_bg_thread_fn() the thread function
++ * yaffs_bg_start() launches the background thread.
++ * yaffs_bg_stop() cleans up the background thread.
++ *
++ * NB:
++ * The thread should only run after the yaffs is initialised
++ * The thread should be stopped before yaffs is unmounted.
++ * The thread should not do any writing while the fs is in read only.
++ */
++
++#ifdef YAFFS_COMPILE_BACKGROUND
++
++void yaffs_background_waker(unsigned long data)
++{
++ wake_up_process((struct task_struct *)data);
++}
++
++static int yaffs_bg_thread_fn(void *data)
++{
++ struct yaffs_dev *dev = (struct yaffs_dev *)data;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++ unsigned long now = jiffies;
++ unsigned long next_dir_update = now;
++ unsigned long next_gc = now;
++ unsigned long expires;
++ unsigned int urgency;
++
++ int gc_result;
++ struct timer_list timer;
++
++ T(YAFFS_TRACE_BACKGROUND,
++ (TSTR("yaffs_background starting for dev %p\n"), (void *)dev));
++
++#ifdef YAFFS_COMPILE_FREEZER
++ set_freezable();
++#endif
++ while (context->bg_running) {
++ T(YAFFS_TRACE_BACKGROUND, (TSTR("yaffs_background\n")));
++
++ if (kthread_should_stop())
++ break;
++
++#ifdef YAFFS_COMPILE_FREEZER
++ if (try_to_freeze())
++ continue;
++#endif
++ yaffs_gross_lock(dev);
++
++ now = jiffies;
++
++ if (time_after(now, next_dir_update) && yaffs_bg_enable) {
++ yaffs_update_dirty_dirs(dev);
++ next_dir_update = now + HZ;
++ }
++
++ if (time_after(now, next_gc) && yaffs_bg_enable) {
++ if (!dev->is_checkpointed) {
++ urgency = yaffs_bg_gc_urgency(dev);
++ gc_result = yaffs_bg_gc(dev, urgency);
++ if (urgency > 1)
++ next_gc = now + HZ / 20 + 1;
++ else if (urgency > 0)
++ next_gc = now + HZ / 10 + 1;
++ else
++ next_gc = now + HZ * 2;
++ } else {
++ /*
++ * gc not running so set to next_dir_update
++ * to cut down on wake ups
++ */
++ next_gc = next_dir_update;
++ }
++ }
++ yaffs_gross_unlock(dev);
++#if 1
++ expires = next_dir_update;
++ if (time_before(next_gc, expires))
++ expires = next_gc;
++ if (time_before(expires, now))
++ expires = now + HZ;
++
++ Y_INIT_TIMER(&timer);
++ timer.expires = expires + 1;
++ timer.data = (unsigned long)current;
++ timer.function = yaffs_background_waker;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_timer(&timer);
++ schedule();
++ del_timer_sync(&timer);
++#else
++ msleep(10);
++#endif
++ }
++
++ return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++ int retval = 0;
++ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
++
++ if (dev->read_only)
++ return -1;
++
++ context->bg_running = 1;
++
++ context->bg_thread = kthread_run(yaffs_bg_thread_fn,
++ (void *)dev, "yaffs-bg-%d",
++ context->mount_id);
++
++ if (IS_ERR(context->bg_thread)) {
++ retval = PTR_ERR(context->bg_thread);
++ context->bg_thread = NULL;
++ context->bg_running = 0;
++ }
++ return retval;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++ struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
++
++ ctxt->bg_running = 0;
++
++ if (ctxt->bg_thread) {
++ kthread_stop(ctxt->bg_thread);
++ ctxt->bg_thread = NULL;
++ }
++}
++#else
++static int yaffs_bg_thread_fn(void *data)
++{
++ return 0;
++}
++
++static int yaffs_bg_start(struct yaffs_dev *dev)
++{
++ return 0;
++}
++
++static void yaffs_bg_stop(struct yaffs_dev *dev)
++{
++}
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static void yaffs_write_super(struct super_block *sb)
++#else
++static int yaffs_write_super(struct super_block *sb)
++#endif
++{
++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
++
++ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
++ (TSTR("yaffs_write_super%s\n"),
++ request_checkpoint ? " checkpt" : ""));
++
++ yaffs_do_sync_fs(sb, request_checkpoint);
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
++ return 0;
++#endif
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_sync_fs(struct super_block *sb, int wait)
++#else
++static int yaffs_sync_fs(struct super_block *sb)
++#endif
++{
++ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
++
++ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
++ (TSTR("yaffs_sync_fs%s\n"), request_checkpoint ? " checkpt" : ""));
++
++ yaffs_do_sync_fs(sb, request_checkpoint);
++
++ return 0;
++}
++
++#ifdef YAFFS_USE_OWN_IGET
++
++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
++{
++ struct inode *inode;
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_iget for %lu\n"), ino));
++
++ inode = iget_locked(sb, ino);
++ if (!inode)
++ return ERR_PTR(-ENOMEM);
++ if (!(inode->i_state & I_NEW))
++ return inode;
++
++ /* NB This is called as a side effect of other functions, but
++ * we had to release the lock to prevent deadlocks, so
++ * need to lock again.
++ */
++
++ yaffs_gross_lock(dev);
++
++ obj = yaffs_find_by_number(dev, inode->i_ino);
++
++ yaffs_fill_inode_from_obj(inode, obj);
++
++ yaffs_gross_unlock(dev);
++
++ unlock_new_inode(inode);
++ return inode;
++}
++
++#else
++
++static void yaffs_read_inode(struct inode *inode)
++{
++ /* NB This is called as a side effect of other functions, but
++ * we had to release the lock to prevent deadlocks, so
++ * need to lock again.
++ */
++
++ struct yaffs_obj *obj;
++ struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_lock(dev);
++
++ obj = yaffs_find_by_number(dev, inode->i_ino);
++
++ yaffs_fill_inode_from_obj(inode, obj);
++
++ if (current != yaffs_dev_to_lc(dev)->readdir_process)
++ yaffs_gross_unlock(dev);
++}
++
++#endif
++
++static LIST_HEAD(yaffs_context_list);
++struct mutex yaffs_context_lock;
++
++static void yaffs_put_super(struct super_block *sb)
++{
++ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
++
++ T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++ (TSTR("Shutting down yaffs background thread\n")));
++ yaffs_bg_stop(dev);
++ T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
++ (TSTR("yaffs background thread shut down\n")));
++
++ yaffs_gross_lock(dev);
++
++ yaffs_flush_super(sb, 1);
++
++ if (yaffs_dev_to_lc(dev)->put_super_fn)
++ yaffs_dev_to_lc(dev)->put_super_fn(sb);
++
++ yaffs_deinitialise(dev);
++
++ yaffs_gross_unlock(dev);
++
++ mutex_lock(&yaffs_context_lock);
++ list_del_init(&(yaffs_dev_to_lc(dev)->context_list));
++ mutex_unlock(&yaffs_context_lock);
++
++ if (yaffs_dev_to_lc(dev)->spare_buffer) {
++ YFREE(yaffs_dev_to_lc(dev)->spare_buffer);
++ yaffs_dev_to_lc(dev)->spare_buffer = NULL;
++ }
++
++ kfree(dev);
++}
++
++static void yaffs_mtd_put_super(struct super_block *sb)
++{
++ struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_super_to_dev(sb));
++
++ if (mtd->sync)
++ mtd->sync(mtd);
++
++ put_mtd_device(mtd);
++}
++
++static void yaffs_touch_super(struct yaffs_dev *dev)
++{
++ struct super_block *sb = yaffs_dev_to_lc(dev)->super;
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_touch_super() sb = %p\n"), sb));
++ if (sb)
++ sb->s_dirt = 1;
++}
++
++struct yaffs_options {
++ int inband_tags;
++ int skip_checkpoint_read;
++ int skip_checkpoint_write;
++ int no_cache;
++ int tags_ecc_on;
++ int tags_ecc_overridden;
++ int lazy_loading_enabled;
++ int lazy_loading_overridden;
++ int empty_lost_and_found;
++ int empty_lost_and_found_overridden;
++};
++
++#define MAX_OPT_LEN 30
++static int yaffs_parse_options(struct yaffs_options *options,
++ const char *options_str)
++{
++ char cur_opt[MAX_OPT_LEN + 1];
++ int p;
++ int error = 0;
++
++ /* Parse through the options which is a comma seperated list */
++
++ while (options_str && *options_str && !error) {
++ memset(cur_opt, 0, MAX_OPT_LEN + 1);
++ p = 0;
++
++ while (*options_str == ',')
++ options_str++;
++
++ while (*options_str && *options_str != ',') {
++ if (p < MAX_OPT_LEN) {
++ cur_opt[p] = *options_str;
++ p++;
++ }
++ options_str++;
++ }
++
++ if (!strcmp(cur_opt, "inband-tags")) {
++ options->inband_tags = 1;
++ } else if (!strcmp(cur_opt, "tags-ecc-off")) {
++ options->tags_ecc_on = 0;
++ options->tags_ecc_overridden = 1;
++ } else if (!strcmp(cur_opt, "tags-ecc-on")) {
++ options->tags_ecc_on = 1;
++ options->tags_ecc_overridden = 1;
++ } else if (!strcmp(cur_opt, "lazy-loading-off")) {
++ options->lazy_loading_enabled = 0;
++ options->lazy_loading_overridden = 1;
++ } else if (!strcmp(cur_opt, "lazy-loading-on")) {
++ options->lazy_loading_enabled = 1;
++ options->lazy_loading_overridden = 1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {
++ options->empty_lost_and_found = 0;
++ options->empty_lost_and_found_overridden = 1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {
++ options->empty_lost_and_found = 1;
++ options->empty_lost_and_found_overridden = 1;
++ } else if (!strcmp(cur_opt, "no-cache")) {
++ options->no_cache = 1;
++ } else if (!strcmp(cur_opt, "no-checkpoint-read")) {
++ options->skip_checkpoint_read = 1;
++ } else if (!strcmp(cur_opt, "no-checkpoint-write")) {
++ options->skip_checkpoint_write = 1;
++ } else if (!strcmp(cur_opt, "no-checkpoint")) {
++ options->skip_checkpoint_read = 1;
++ options->skip_checkpoint_write = 1;
++ } else {
++ printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
++ cur_opt);
++ error = 1;
++ }
++ }
++
++ return error;
++}
++
++static struct super_block *yaffs_internal_read_super(int yaffs_version,
++ struct super_block *sb,
++ void *data, int silent)
++{
++ int n_blocks;
++ struct inode *inode = NULL;
++ struct dentry *root;
++ struct yaffs_dev *dev = 0;
++ char devname_buf[BDEVNAME_SIZE + 1];
++ struct mtd_info *mtd;
++ int err;
++ char *data_str = (char *)data;
++ struct yaffs_linux_context *context = NULL;
++ struct yaffs_param *param;
++
++ int read_only = 0;
++
++ struct yaffs_options options;
++
++ unsigned mount_id;
++ int found;
++ struct yaffs_linux_context *context_iterator;
++ struct list_head *l;
++
++ sb->s_magic = YAFFS_MAGIC;
++ sb->s_op = &yaffs_super_ops;
++ sb->s_flags |= MS_NOATIME;
++
++ read_only = ((sb->s_flags & MS_RDONLY) != 0);
++
++#ifdef YAFFS_COMPILE_EXPORTFS
++ sb->s_export_op = &yaffs_export_ops;
++#endif
++
++ if (!sb)
++ printk(KERN_INFO "yaffs: sb is NULL\n");
++ else if (!sb->s_dev)
++ printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
++ else if (!yaffs_devname(sb, devname_buf))
++ printk(KERN_INFO "yaffs: devname is NULL\n");
++ else
++ printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
++ sb->s_dev,
++ yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");
++
++ if (!data_str)
++ data_str = "";
++
++ printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
++
++ memset(&options, 0, sizeof(options));
++
++ if (yaffs_parse_options(&options, data_str)) {
++ /* Option parsing failed */
++ return NULL;
++ }
++
++ sb->s_blocksize = PAGE_CACHE_SIZE;
++ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffs_version));
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_read_super: block size %d\n"), (int)(sb->s_blocksize)));
++
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
++ MAJOR(sb->s_dev), MINOR(sb->s_dev), yaffs_devname(sb, devname_buf)));
++
++ /* Check it's an mtd device..... */
++ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
++ return NULL; /* This isn't an mtd device */
++
++ /* Get the device */
++ mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
++ if (!mtd) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
++ MINOR(sb->s_dev)));
++ return NULL;
++ }
++ /* Check it's NAND */
++ if (mtd->type != MTD_NANDFLASH) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
++ mtd->type));
++ return NULL;
++ }
++
++ T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
++ T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
++ T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
++ T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob));
++ T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
++ T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
++ T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
++ T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
++ T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
++ T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++ T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
++#else
++ T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
++#endif
++
++#ifdef CONFIG_YAFFS_AUTO_YAFFS2
++
++ if (yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: auto selecting yaffs2\n")));
++ yaffs_version = 2;
++ }
++
++ /* Added NCB 26/5/2006 for completeness */
++ if (yaffs_version == 2 && !options.inband_tags
++ && WRITE_SIZE(mtd) == 512) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: auto selecting yaffs1\n")));
++ yaffs_version = 1;
++ }
++#endif
++
++ if (yaffs_version == 2) {
++ /* Check for version 2 style functions */
++ if (!mtd->erase ||
++ !mtd->block_isbad ||
++ !mtd->block_markbad || !mtd->read || !mtd->write ||
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ !mtd->read_oob || !mtd->write_oob) {
++#else
++ !mtd->write_ecc ||
++ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
++#endif
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: MTD device does not support required "
++ "functions\n")));
++ return NULL;
++ }
++
++ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
++ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
++ !options.inband_tags) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: MTD device does not have the "
++ "right page sizes\n")));
++ return NULL;
++ }
++ } else {
++ /* Check for V1 style functions */
++ if (!mtd->erase || !mtd->read || !mtd->write ||
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ !mtd->read_oob || !mtd->write_oob) {
++#else
++ !mtd->write_ecc ||
++ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
++#endif
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: MTD device does not support required "
++ "functions\n")));
++ return NULL;
++ }
++
++ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
++ mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: MTD device does not support have the "
++ "right page sizes\n")));
++ return NULL;
++ }
++ }
++
++ /* OK, so if we got here, we have an MTD that's NAND and looks
++ * like it has the right capabilities
++ * Set the struct yaffs_dev up for mtd
++ */
++
++ if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
++ read_only = 1;
++ printk(KERN_INFO
++ "yaffs: mtd is read only, setting superblock read only");
++ sb->s_flags |= MS_RDONLY;
++ }
++
++ dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);
++ context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
++
++ if (!dev || !context) {
++ if (dev)
++ kfree(dev);
++ if (context)
++ kfree(context);
++ dev = NULL;
++ context = NULL;
++ }
++
++ if (!dev) {
++ /* Deep shit could not allocate device structure */
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs_read_super: Failed trying to allocate "
++ "struct yaffs_dev. \n")));
++ return NULL;
++ }
++ memset(dev, 0, sizeof(struct yaffs_dev));
++ param = &(dev->param);
++
++ memset(context, 0, sizeof(struct yaffs_linux_context));
++ dev->os_context = context;
++ INIT_LIST_HEAD(&(context->context_list));
++ context->dev = dev;
++ context->super = sb;
++
++ dev->read_only = read_only;
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ sb->s_fs_info = dev;
++#else
++ sb->u.generic_sbp = dev;
++#endif
++
++ dev->driver_context = mtd;
++ param->name = mtd->name;
++
++ /* Set up the memory size parameters.... */
++
++ n_blocks =
++ YCALCBLOCKS(mtd->size,
++ (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
++
++ param->start_block = 0;
++ param->end_block = n_blocks - 1;
++ param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
++ param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
++ param->n_reserved_blocks = 5;
++ param->n_caches = (options.no_cache) ? 0 : 10;
++ param->inband_tags = options.inband_tags;
++
++#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
++ param->disable_lazy_load = 1;
++#endif
++#ifdef CONFIG_YAFFS_XATTR
++ param->enable_xattr = 1;
++#endif
++ if (options.lazy_loading_overridden)
++ param->disable_lazy_load = !options.lazy_loading_enabled;
++
++#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
++ param->no_tags_ecc = 1;
++#endif
++
++#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
++#else
++ param->defered_dir_update = 1;
++#endif
++
++ if (options.tags_ecc_overridden)
++ param->no_tags_ecc = !options.tags_ecc_on;
++
++#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
++ param->empty_lost_n_found = 1;
++#endif
++
++#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
++ param->refresh_period = 0;
++#else
++ param->refresh_period = 500;
++#endif
++
++#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED
++ param->always_check_erased = 1;
++#endif
++
++ if (options.empty_lost_and_found_overridden)
++ param->empty_lost_n_found = options.empty_lost_and_found;
++
++ /* ... and the functions. */
++ if (yaffs_version == 2) {
++ param->write_chunk_tags_fn = nandmtd2_write_chunk_tags;
++ param->read_chunk_tags_fn = nandmtd2_read_chunk_tags;
++ param->bad_block_fn = nandmtd2_mark_block_bad;
++ param->query_block_fn = nandmtd2_query_block;
++ yaffs_dev_to_lc(dev)->spare_buffer = YMALLOC(mtd->oobsize);
++ param->is_yaffs2 = 1;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ param->total_bytes_per_chunk = mtd->writesize;
++ param->chunks_per_block = mtd->erasesize / mtd->writesize;
++#else
++ param->total_bytes_per_chunk = mtd->oobblock;
++ param->chunks_per_block = mtd->erasesize / mtd->oobblock;
++#endif
++ n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
++
++ param->start_block = 0;
++ param->end_block = n_blocks - 1;
++ } else {
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ /* use the MTD interface in yaffs_mtdif1.c */
++ param->write_chunk_tags_fn = nandmtd1_write_chunk_tags;
++ param->read_chunk_tags_fn = nandmtd1_read_chunk_tags;
++ param->bad_block_fn = nandmtd1_mark_block_bad;
++ param->query_block_fn = nandmtd1_query_block;
++#else
++ param->write_chunk_fn = nandmtd_write_chunk;
++ param->read_chunk_fn = nandmtd_read_chunk;
++#endif
++ param->is_yaffs2 = 0;
++ }
++ /* ... and common functions */
++ param->erase_fn = nandmtd_erase_block;
++ param->initialise_flash_fn = nandmtd_initialise;
++
++ yaffs_dev_to_lc(dev)->put_super_fn = yaffs_mtd_put_super;
++
++ param->sb_dirty_fn = yaffs_touch_super;
++ param->gc_control = yaffs_gc_control_callback;
++
++ yaffs_dev_to_lc(dev)->super = sb;
++
++#ifndef CONFIG_YAFFS_DOES_ECC
++ param->use_nand_ecc = 1;
++#endif
++
++#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
++ param->wide_tnodes_disabled = 1;
++#endif
++
++ param->skip_checkpt_rd = options.skip_checkpoint_read;
++ param->skip_checkpt_wr = options.skip_checkpoint_write;
++
++ mutex_lock(&yaffs_context_lock);
++ /* Get a mount id */
++ found = 0;
++ for (mount_id = 0; !found; mount_id++) {
++ found = 1;
++ list_for_each(l, &yaffs_context_list) {
++ context_iterator =
++ list_entry(l, struct yaffs_linux_context,
++ context_list);
++ if (context_iterator->mount_id == mount_id)
++ found = 0;
++ }
++ }
++ context->mount_id = mount_id;
++
++ list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),
++ &yaffs_context_list);
++ mutex_unlock(&yaffs_context_lock);
++
++ /* Directory search handling... */
++ INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));
++ param->remove_obj_fn = yaffs_remove_obj_callback;
++
++ mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));
++
++ yaffs_gross_lock(dev);
++
++ err = yaffs_guts_initialise(dev);
++
++ T(YAFFS_TRACE_OS,
++ (TSTR("yaffs_read_super: guts initialised %s\n"),
++ (err == YAFFS_OK) ? "OK" : "FAILED"));
++
++ if (err == YAFFS_OK)
++ yaffs_bg_start(dev);
++
++ if (!context->bg_thread)
++ param->defered_dir_update = 0;
++
++ /* Release lock before yaffs_get_inode() */
++ yaffs_gross_unlock(dev);
++
++ /* Create root inode */
++ if (err == YAFFS_OK)
++ inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev));
++
++ if (!inode)
++ return NULL;
++
++ inode->i_op = &yaffs_dir_inode_operations;
++ inode->i_fop = &yaffs_dir_operations;
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
++
++ root = d_alloc_root(inode);
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
++
++ if (!root) {
++ iput(inode);
++ return NULL;
++ }
++ sb->s_root = root;
++ sb->s_dirt = !dev->is_checkpointed;
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs_read_super: is_checkpointed %d\n"),
++ dev->is_checkpointed));
++
++ T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
++ return sb;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
++ int silent)
++{
++ return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_read_super(struct file_system_type *fs,
++ int flags, const char *dev_name,
++ void *data, struct vfsmount *mnt)
++{
++
++ return get_sb_bdev(fs, flags, dev_name, data,
++ yaffs_internal_read_super_mtd, mnt);
++}
++#else
++static struct super_block *yaffs_read_super(struct file_system_type *fs,
++ int flags, const char *dev_name,
++ void *data)
++{
++
++ return get_sb_bdev(fs, flags, dev_name, data,
++ yaffs_internal_read_super_mtd);
++}
++#endif
++
++static struct file_system_type yaffs_fs_type = {
++ .owner = THIS_MODULE,
++ .name = "yaffs",
++ .get_sb = yaffs_read_super,
++ .kill_sb = kill_block_super,
++ .fs_flags = FS_REQUIRES_DEV,
++};
++#else
++static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
++ int silent)
++{
++ return yaffs_internal_read_super(1, sb, data, silent);
++}
++
++static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
++ FS_REQUIRES_DEV);
++#endif
++
++#ifdef CONFIG_YAFFS_YAFFS2
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
++ int silent)
++{
++ return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs2_read_super(struct file_system_type *fs,
++ int flags, const char *dev_name, void *data,
++ struct vfsmount *mnt)
++{
++ return get_sb_bdev(fs, flags, dev_name, data,
++ yaffs2_internal_read_super_mtd, mnt);
++}
++#else
++static struct super_block *yaffs2_read_super(struct file_system_type *fs,
++ int flags, const char *dev_name,
++ void *data)
++{
++
++ return get_sb_bdev(fs, flags, dev_name, data,
++ yaffs2_internal_read_super_mtd);
++}
++#endif
++
++static struct file_system_type yaffs2_fs_type = {
++ .owner = THIS_MODULE,
++ .name = "yaffs2",
++ .get_sb = yaffs2_read_super,
++ .kill_sb = kill_block_super,
++ .fs_flags = FS_REQUIRES_DEV,
++};
++#else
++static struct super_block *yaffs2_read_super(struct super_block *sb,
++ void *data, int silent)
++{
++ return yaffs_internal_read_super(2, sb, data, silent);
++}
++
++static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
++ FS_REQUIRES_DEV);
++#endif
++
++#endif /* CONFIG_YAFFS_YAFFS2 */
++
++static struct proc_dir_entry *my_proc_entry;
++static struct proc_dir_entry *debug_proc_entry;
++
++static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
++{
++ buf +=
++ sprintf(buf, "start_block.......... %d\n", dev->param.start_block);
++ buf += sprintf(buf, "end_block............ %d\n", dev->param.end_block);
++ buf +=
++ sprintf(buf, "total_bytes_per_chunk %d\n",
++ dev->param.total_bytes_per_chunk);
++ buf +=
++ sprintf(buf, "use_nand_ecc......... %d\n", dev->param.use_nand_ecc);
++ buf +=
++ sprintf(buf, "no_tags_ecc.......... %d\n", dev->param.no_tags_ecc);
++ buf += sprintf(buf, "is_yaffs2............ %d\n", dev->param.is_yaffs2);
++ buf +=
++ sprintf(buf, "inband_tags.......... %d\n", dev->param.inband_tags);
++ buf +=
++ sprintf(buf, "empty_lost_n_found... %d\n",
++ dev->param.empty_lost_n_found);
++ buf +=
++ sprintf(buf, "disable_lazy_load.... %d\n",
++ dev->param.disable_lazy_load);
++ buf +=
++ sprintf(buf, "refresh_period....... %d\n",
++ dev->param.refresh_period);
++ buf += sprintf(buf, "n_caches............. %d\n", dev->param.n_caches);
++ buf +=
++ sprintf(buf, "n_reserved_blocks.... %d\n",
++ dev->param.n_reserved_blocks);
++ buf +=
++ sprintf(buf, "always_check_erased.. %d\n",
++ dev->param.always_check_erased);
++
++ buf += sprintf(buf, "\n");
++
++ return buf;
++}
++
++static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
++{
++ buf +=
++ sprintf(buf, "data_bytes_per_chunk. %d\n",
++ dev->data_bytes_per_chunk);
++ buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
++ buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
++ buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
++ buf +=
++ sprintf(buf, "blocks_in_checkpt.... %d\n", dev->blocks_in_checkpt);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
++ buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
++ buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
++ buf += sprintf(buf, "\n");
++ buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
++ buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
++ buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
++ buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
++ buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
++ buf +=
++ sprintf(buf, "passive_gc_count..... %u\n", dev->passive_gc_count);
++ buf +=
++ sprintf(buf, "oldest_dirty_gc_count %u\n",
++ dev->oldest_dirty_gc_count);
++ buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
++ buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
++ buf +=
++ sprintf(buf, "n_retired_writes..... %u\n", dev->n_retired_writes);
++ buf +=
++ sprintf(buf, "n_retired_blocks..... %u\n", dev->n_retired_blocks);
++ buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
++ buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
++ buf +=
++ sprintf(buf, "n_tags_ecc_fixed..... %u\n", dev->n_tags_ecc_fixed);
++ buf +=
++ sprintf(buf, "n_tags_ecc_unfixed... %u\n", dev->n_tags_ecc_unfixed);
++ buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
++ buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
++ buf +=
++ sprintf(buf, "n_unlinked_files..... %u\n", dev->n_unlinked_files);
++ buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
++ buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
++
++ return buf;
++}
++
++static int yaffs_proc_read(char *page,
++ char **start,
++ off_t offset, int count, int *eof, void *data)
++{
++ struct list_head *item;
++ char *buf = page;
++ int step = offset;
++ int n = 0;
++
++ /* Get proc_file_read() to step 'offset' by one on each sucessive call.
++ * We use 'offset' (*ppos) to indicate where we are in dev_list.
++ * This also assumes the user has posted a read buffer large
++ * enough to hold the complete output; but that's life in /proc.
++ */
++
++ *(int *)start = 1;
++
++ /* Print header first */
++ if (step == 0)
++ buf +=
++ sprintf(buf,
++ "Multi-version YAFFS built:" __DATE__ " " __TIME__
++ "\n");
++ else if (step == 1)
++ buf += sprintf(buf, "\n");
++ else {
++ step -= 2;
++
++ mutex_lock(&yaffs_context_lock);
++
++ /* Locate and print the Nth entry. Order N-squared but N is small. */
++ list_for_each(item, &yaffs_context_list) {
++ struct yaffs_linux_context *dc =
++ list_entry(item, struct yaffs_linux_context,
++ context_list);
++ struct yaffs_dev *dev = dc->dev;
++
++ if (n < (step & ~1)) {
++ n += 2;
++ continue;
++ }
++ if ((step & 1) == 0) {
++ buf +=
++ sprintf(buf, "\nDevice %d \"%s\"\n", n,
++ dev->param.name);
++ buf = yaffs_dump_dev_part0(buf, dev);
++ } else {
++ buf = yaffs_dump_dev_part1(buf, dev);
++ }
++
++ break;
++ }
++ mutex_unlock(&yaffs_context_lock);
++ }
++
++ return buf - page < count ? buf - page : count;
++}
++
++static int yaffs_stats_proc_read(char *page,
++ char **start,
++ off_t offset, int count, int *eof, void *data)
++{
++ struct list_head *item;
++ char *buf = page;
++ int n = 0;
++
++ mutex_lock(&yaffs_context_lock);
++
++ /* Locate and print the Nth entry. Order N-squared but N is small. */
++ list_for_each(item, &yaffs_context_list) {
++ struct yaffs_linux_context *dc =
++ list_entry(item, struct yaffs_linux_context, context_list);
++ struct yaffs_dev *dev = dc->dev;
++
++ int erased_chunks;
++
++ erased_chunks =
++ dev->n_erased_blocks * dev->param.chunks_per_block;
++
++ buf += sprintf(buf, "%d, %d, %d, %u, %u, %u, %u\n",
++ n, dev->n_free_chunks, erased_chunks,
++ dev->bg_gcs, dev->oldest_dirty_gc_count,
++ dev->n_obj, dev->n_tnodes);
++ }
++ mutex_unlock(&yaffs_context_lock);
++
++ return buf - page < count ? buf - page : count;
++}
++
++/**
++ * Set the verbosity of the warnings and error messages.
++ *
++ * Note that the names can only be a..z or _ with the current code.
++ */
++
++static struct {
++ char *mask_name;
++ unsigned mask_bitfield;
++} mask_flags[] = {
++ {"allocate", YAFFS_TRACE_ALLOCATE},
++ {"always", YAFFS_TRACE_ALWAYS},
++ {"background", YAFFS_TRACE_BACKGROUND},
++ {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
++ {"buffers", YAFFS_TRACE_BUFFERS},
++ {"bug", YAFFS_TRACE_BUG},
++ {"checkpt", YAFFS_TRACE_CHECKPOINT},
++ {"deletion", YAFFS_TRACE_DELETION},
++ {"erase", YAFFS_TRACE_ERASE},
++ {"error", YAFFS_TRACE_ERROR},
++ {"gc_detail", YAFFS_TRACE_GC_DETAIL},
++ {"gc", YAFFS_TRACE_GC},
++ {"lock", YAFFS_TRACE_LOCK},
++ {"mtd", YAFFS_TRACE_MTD},
++ {"nandaccess", YAFFS_TRACE_NANDACCESS},
++ {"os", YAFFS_TRACE_OS},
++ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
++ {"scan", YAFFS_TRACE_SCAN},
++ {"mount", YAFFS_TRACE_MOUNT},
++ {"tracing", YAFFS_TRACE_TRACING},
++ {"sync", YAFFS_TRACE_SYNC},
++ {"write", YAFFS_TRACE_WRITE},
++ {"verify", YAFFS_TRACE_VERIFY},
++ {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
++ {"verify_full", YAFFS_TRACE_VERIFY_FULL},
++ {"verify_all", YAFFS_TRACE_VERIFY_ALL},
++ {"all", 0xffffffff},
++ {"none", 0},
++ {NULL, 0},
++};
++
++#define MAX_MASK_NAME_LENGTH 40
++static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++ unsigned rg = 0, mask_bitfield;
++ char *end;
++ char *mask_name;
++ const char *x;
++ char substring[MAX_MASK_NAME_LENGTH + 1];
++ int i;
++ int done = 0;
++ int add, len = 0;
++ int pos = 0;
++
++ rg = yaffs_trace_mask;
++
++ while (!done && (pos < count)) {
++ done = 1;
++ while ((pos < count) && isspace(buf[pos]))
++ pos++;
++
++ switch (buf[pos]) {
++ case '+':
++ case '-':
++ case '=':
++ add = buf[pos];
++ pos++;
++ break;
++
++ default:
++ add = ' ';
++ break;
++ }
++ mask_name = NULL;
++
++ mask_bitfield = simple_strtoul(buf + pos, &end, 0);
++
++ if (end > buf + pos) {
++ mask_name = "numeral";
++ len = end - (buf + pos);
++ pos += len;
++ done = 0;
++ } else {
++ for (x = buf + pos, i = 0;
++ (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
++ i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
++ substring[i] = *x;
++ substring[i] = '\0';
++
++ for (i = 0; mask_flags[i].mask_name != NULL; i++) {
++ if (strcmp(substring, mask_flags[i].mask_name)
++ == 0) {
++ mask_name = mask_flags[i].mask_name;
++ mask_bitfield =
++ mask_flags[i].mask_bitfield;
++ done = 0;
++ break;
++ }
++ }
++ }
++
++ if (mask_name != NULL) {
++ done = 0;
++ switch (add) {
++ case '-':
++ rg &= ~mask_bitfield;
++ break;
++ case '+':
++ rg |= mask_bitfield;
++ break;
++ case '=':
++ rg = mask_bitfield;
++ break;
++ default:
++ rg |= mask_bitfield;
++ break;
++ }
++ }
++ }
++
++ yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
++
++ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
++
++ if (rg & YAFFS_TRACE_ALWAYS) {
++ for (i = 0; mask_flags[i].mask_name != NULL; i++) {
++ char flag;
++ flag = ((rg & mask_flags[i].mask_bitfield) ==
++ mask_flags[i].mask_bitfield) ? '+' : '-';
++ printk(KERN_DEBUG "%c%s\n", flag,
++ mask_flags[i].mask_name);
++ }
++ }
++
++ return count;
++}
++
++static int yaffs_proc_write(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++ return yaffs_proc_write_trace_options(file, buf, count, data);
++}
++
++/* Stuff to handle installation of file systems */
++struct file_system_to_install {
++ struct file_system_type *fst;
++ int installed;
++};
++
++static struct file_system_to_install fs_to_install[] = {
++ {&yaffs_fs_type, 0},
++ {&yaffs2_fs_type, 0},
++ {NULL, 0}
++};
++
++static int __init init_yaffs_fs(void)
++{
++ int error = 0;
++ struct file_system_to_install *fsinst;
++
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n")));
++
++#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ (" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n")));
++#endif
++
++ mutex_init(&yaffs_context_lock);
++
++ /* Install the proc_fs entries */
++ my_proc_entry = create_proc_entry("yaffs",
++ S_IRUGO | S_IFREG, YPROC_ROOT);
++
++ if (my_proc_entry) {
++ my_proc_entry->write_proc = yaffs_proc_write;
++ my_proc_entry->read_proc = yaffs_proc_read;
++ my_proc_entry->data = NULL;
++ } else {
++ return -ENOMEM;
++ }
++
++ debug_proc_entry = create_proc_entry("yaffs_stats",
++ S_IRUGO | S_IFREG, YPROC_ROOT);
++
++ if (debug_proc_entry) {
++ debug_proc_entry->write_proc = NULL;
++ debug_proc_entry->read_proc = yaffs_stats_proc_read;
++ debug_proc_entry->data = NULL;
++ } else {
++ return -ENOMEM;
++ }
++
++ /* Now add the file system entries */
++
++ fsinst = fs_to_install;
++
++ while (fsinst->fst && !error) {
++ error = register_filesystem(fsinst->fst);
++ if (!error)
++ fsinst->installed = 1;
++ fsinst++;
++ }
++
++ /* Any errors? uninstall */
++ if (error) {
++ fsinst = fs_to_install;
++
++ while (fsinst->fst) {
++ if (fsinst->installed) {
++ unregister_filesystem(fsinst->fst);
++ fsinst->installed = 0;
++ }
++ fsinst++;
++ }
++ }
++
++ return error;
++}
++
++static void __exit exit_yaffs_fs(void)
++{
++
++ struct file_system_to_install *fsinst;
++
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
++
++ remove_proc_entry("yaffs", YPROC_ROOT);
++ remove_proc_entry("yaffs_stats", YPROC_ROOT);
++
++ fsinst = fs_to_install;
++
++ while (fsinst->fst) {
++ if (fsinst->installed) {
++ unregister_filesystem(fsinst->fst);
++ fsinst->installed = 0;
++ }
++ fsinst++;
++ }
++}
++
++module_init(init_yaffs_fs)
++ module_exit(exit_yaffs_fs)
++
++ MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
++MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs1.c linux-2.6.36/fs/yaffs2/yaffs_yaffs1.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_yaffs1.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,437 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_yaffs1.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_nand.h"
++#include "yaffs_attribs.h"
++
++int yaffs1_scan(struct yaffs_dev *dev)
++{
++ struct yaffs_ext_tags tags;
++ int blk;
++ int result;
++
++ int chunk;
++ int c;
++ int deleted;
++ enum yaffs_block_state state;
++ struct yaffs_obj *hard_list = NULL;
++ struct yaffs_block_info *bi;
++ u32 seq_number;
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_obj *in;
++ struct yaffs_obj *parent;
++
++ int alloc_failed = 0;
++
++ struct yaffs_shadow_fixer *shadow_fixers = NULL;
++
++ u8 *chunk_data;
++
++ T(YAFFS_TRACE_SCAN,
++ (TSTR("yaffs1_scan starts intstartblk %d intendblk %d..." TENDSTR),
++ dev->internal_start_block, dev->internal_end_block));
++
++ chunk_data = yaffs_get_temp_buffer(dev, __LINE__);
++
++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ /* Scan all the blocks to determine their state */
++ bi = dev->block_info;
++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++ blk++) {
++ yaffs_clear_chunk_bits(dev, blk);
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++
++ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++ bi->block_state = state;
++ bi->seq_number = seq_number;
++
++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
++
++ T(YAFFS_TRACE_SCAN_DEBUG,
++ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
++ state, seq_number));
++
++ if (state == YAFFS_BLOCK_STATE_DEAD) {
++ T(YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("block %d is bad" TENDSTR), blk));
++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
++ T(YAFFS_TRACE_SCAN_DEBUG,
++ (TSTR("Block empty " TENDSTR)));
++ dev->n_erased_blocks++;
++ dev->n_free_chunks += dev->param.chunks_per_block;
++ }
++ bi++;
++ }
++
++ /* For each block.... */
++ for (blk = dev->internal_start_block;
++ !alloc_failed && blk <= dev->internal_end_block; blk++) {
++
++ YYIELD();
++
++ bi = yaffs_get_block_info(dev, blk);
++ state = bi->block_state;
++
++ deleted = 0;
++
++ /* For each chunk in each block that needs scanning.... */
++ for (c = 0; !alloc_failed && c < dev->param.chunks_per_block &&
++ state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
++ /* Read the tags and decide what to do */
++ chunk = blk * dev->param.chunks_per_block + c;
++
++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
++ &tags);
++
++ /* Let's have a good look at this chunk... */
++
++ if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED
++ || tags.is_deleted) {
++ /* YAFFS1 only...
++ * A deleted chunk
++ */
++ deleted++;
++ dev->n_free_chunks++;
++ /*T((" %d %d deleted\n",blk,c)); */
++ } else if (!tags.chunk_used) {
++ /* An unassigned chunk in the block
++ * This means that either the block is empty or
++ * this is the one being allocated from
++ */
++
++ if (c == 0) {
++ /* We're looking at the first chunk in the block so the block is unused */
++ state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ } else {
++ /* this is the block being allocated from */
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ (" Allocating from %d %d" TENDSTR),
++ blk, c));
++ state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->alloc_block = blk;
++ dev->alloc_page = c;
++ dev->alloc_block_finder = blk;
++ /* Set block finder here to encourage the allocator to go forth from here. */
++
++ }
++
++ dev->n_free_chunks +=
++ (dev->param.chunks_per_block - c);
++ } else if (tags.chunk_id > 0) {
++ /* chunk_id > 0 so it is a data chunk... */
++ unsigned int endpos;
++
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ YAFFS_OBJECT_TYPE_FILE);
++ /* PutChunkIntoFile checks for a clash (two data chunks with
++ * the same chunk_id).
++ */
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in) {
++ if (!yaffs_put_chunk_in_file
++ (in, tags.chunk_id, chunk, 1))
++ alloc_failed = 1;
++ }
++
++ endpos =
++ (tags.chunk_id -
++ 1) * dev->data_bytes_per_chunk +
++ tags.n_bytes;
++ if (in
++ && in->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE
++ && in->variant.file_variant.scanned_size <
++ endpos) {
++ in->variant.file_variant.scanned_size =
++ endpos;
++ if (!dev->param.use_header_file_size) {
++ in->variant.
++ file_variant.file_size =
++ in->variant.
++ file_variant.scanned_size;
++ }
++
++ }
++ /* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */
++ } else {
++ /* chunk_id == 0, so it is an ObjectHeader.
++ * Thus, we read in the object header and make the object
++ */
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ result = yaffs_rd_chunk_tags_nand(dev, chunk,
++ chunk_data,
++ NULL);
++
++ oh = (struct yaffs_obj_hdr *)chunk_data;
++
++ in = yaffs_find_by_number(dev, tags.obj_id);
++ if (in && in->variant_type != oh->type) {
++ /* This should not happen, but somehow
++ * Wev'e ended up with an obj_id that has been reused but not yet
++ * deleted, and worse still it has changed type. Delete the old object.
++ */
++
++ yaffs_del_obj(in);
++
++ in = 0;
++ }
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ oh->type);
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in && oh->shadows_obj > 0) {
++
++ struct yaffs_shadow_fixer *fixer;
++ fixer =
++ YMALLOC(sizeof
++ (struct
++ yaffs_shadow_fixer));
++ if (fixer) {
++ fixer->next = shadow_fixers;
++ shadow_fixers = fixer;
++ fixer->obj_id = tags.obj_id;
++ fixer->shadowed_id =
++ oh->shadows_obj;
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ (" Shadow fixer: %d shadows %d"
++ TENDSTR), fixer->obj_id,
++ fixer->shadowed_id));
++
++ }
++
++ }
++
++ if (in && in->valid) {
++ /* We have already filled this one. We have a duplicate and need to resolve it. */
++
++ unsigned existing_serial = in->serial;
++ unsigned new_serial =
++ tags.serial_number;
++
++ if (((existing_serial + 1) & 3) ==
++ new_serial) {
++ /* Use new one - destroy the exisiting one */
++ yaffs_chunk_del(dev,
++ in->hdr_chunk,
++ 1, __LINE__);
++ in->valid = 0;
++ } else {
++ /* Use existing - destroy this one. */
++ yaffs_chunk_del(dev, chunk, 1,
++ __LINE__);
++ }
++ }
++
++ if (in && !in->valid &&
++ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id ==
++ YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle with directory structure */
++ in->valid = 1;
++ in->variant_type = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->hdr_chunk = chunk;
++ in->serial = tags.serial_number;
++
++ } else if (in && !in->valid) {
++ /* we need to load this info */
++
++ in->valid = 1;
++ in->variant_type = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->hdr_chunk = chunk;
++ in->serial = tags.serial_number;
++
++ yaffs_set_obj_name_from_oh(in, oh);
++ in->dirty = 0;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ parent =
++ yaffs_find_or_create_by_number
++ (dev, oh->parent_obj_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ if (!parent)
++ alloc_failed = 1;
++ if (parent && parent->variant_type ==
++ YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variant_type =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ INIT_LIST_HEAD(&parent->
++ variant.dir_variant.children);
++ } else if (!parent
++ || parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, another problem....
++ * We're trying to use a non-directory as a directory
++ */
++
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ TENDSTR)));
++ parent = dev->lost_n_found;
++ }
++
++ yaffs_add_obj_to_dir(parent, in);
++
++ if (0 && (parent == dev->del_dir ||
++ parent ==
++ dev->unlinked_dir)) {
++ in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
++ dev->n_deleted_files++;
++ }
++ /* Note re hardlinks.
++ * Since we might scan a hardlink before its equivalent object is scanned
++ * we put them all in a list.
++ * After scanning is complete, we should have all the objects, so we run through this
++ * list and fix up all the chains.
++ */
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (dev->param.
++ use_header_file_size)
++
++ in->variant.
++ file_variant.file_size
++ = oh->file_size;
++
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.
++ hardlink_variant.equiv_id =
++ oh->equiv_id;
++ in->hard_links.next =
++ (struct list_head *)
++ hard_list;
++ hard_list = in;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symlink_variant.
++ alias =
++ yaffs_clone_str(oh->alias);
++ if (!in->variant.
++ symlink_variant.alias)
++ alloc_failed = 1;
++ break;
++ }
++
++ }
++ }
++ }
++
++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
++ /* If we got this far while scanning, then the block is fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++ if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ /* If the block was partially allocated then treat it as fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ dev->alloc_block = -1;
++ }
++
++ bi->block_state = state;
++
++ /* Now let's see if it was dirty */
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++ yaffs_block_became_dirty(dev, blk);
++ }
++
++ }
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We should now have scanned all the objects, now it's time to add these
++ * hardlinks.
++ */
++
++ yaffs_link_fixup(dev, hard_list);
++
++ /* Fix up any shadowed objects */
++ {
++ struct yaffs_shadow_fixer *fixer;
++ struct yaffs_obj *obj;
++
++ while (shadow_fixers) {
++ fixer = shadow_fixers;
++ shadow_fixers = fixer->next;
++ /* Complete the rename transaction by deleting the shadowed object
++ * then setting the object header to unshadowed.
++ */
++ obj = yaffs_find_by_number(dev, fixer->shadowed_id);
++ if (obj)
++ yaffs_del_obj(obj);
++
++ obj = yaffs_find_by_number(dev, fixer->obj_id);
++
++ if (obj)
++ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++ YFREE(fixer);
++ }
++ }
++
++ yaffs_release_temp_buffer(dev, chunk_data, __LINE__);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_scan ends" TENDSTR)));
++
++ return YAFFS_OK;
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs1.h linux-2.6.36/fs/yaffs2/yaffs_yaffs1.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_yaffs1.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,22 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS1_H__
++#define __YAFFS_YAFFS1_H__
++
++#include "yaffs_guts.h"
++int yaffs1_scan(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs2.c linux-2.6.36/fs/yaffs2/yaffs_yaffs2.c
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_yaffs2.c 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,1620 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_checkptrw.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_nand.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_verify.h"
++#include "yaffs_attribs.h"
++
++/*
++ * Checkpoints are really no benefit on very small partitions.
++ *
++ * To save space on small partitions don't bother with checkpoints unless
++ * the partition is at least this big.
++ */
++#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
++
++#define YAFFS_SMALL_HOLE_THRESHOLD 4
++
++/*
++ * Oldest Dirty Sequence Number handling.
++ */
++
++/* yaffs_calc_oldest_dirty_seq()
++ * yaffs2_find_oldest_dirty_seq()
++ * Calculate the oldest dirty sequence number if we don't know it.
++ */
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++ int i;
++ unsigned seq;
++ unsigned block_no = 0;
++ struct yaffs_block_info *b;
++
++ if (!dev->param.is_yaffs2)
++ return;
++
++ /* Find the oldest dirty sequence number. */
++ seq = dev->seq_number + 1;
++ b = dev->block_info;
++ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++ if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
++ (b->pages_in_use - b->soft_del_pages) <
++ dev->param.chunks_per_block && b->seq_number < seq) {
++ seq = b->seq_number;
++ block_no = i;
++ }
++ b++;
++ }
++
++ if (block_no) {
++ dev->oldest_dirty_seq = seq;
++ dev->oldest_dirty_block = block_no;
++ }
++
++}
++
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!dev->oldest_dirty_seq)
++ yaffs_calc_oldest_dirty_seq(dev);
++}
++
++/*
++ * yaffs_clear_oldest_dirty_seq()
++ * Called when a block is erased or marked bad. (ie. when its seq_number
++ * becomes invalid). If the value matches the oldest then we clear
++ * dev->oldest_dirty_seq to force its recomputation.
++ */
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi)
++{
++
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
++ dev->oldest_dirty_seq = 0;
++ dev->oldest_dirty_block = 0;
++ }
++}
++
++/*
++ * yaffs2_update_oldest_dirty_seq()
++ * Update the oldest dirty sequence number whenever we dirty a block.
++ * Only do this if the oldest_dirty_seq is actually being tracked.
++ */
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++ struct yaffs_block_info *bi)
++{
++ if (!dev->param.is_yaffs2)
++ return;
++
++ if (dev->oldest_dirty_seq) {
++ if (dev->oldest_dirty_seq > bi->seq_number) {
++ dev->oldest_dirty_seq = bi->seq_number;
++ dev->oldest_dirty_block = block_no;
++ }
++ }
++}
++
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
++{
++
++ if (!dev->param.is_yaffs2)
++ return 1; /* disqualification only applies to yaffs2. */
++
++ if (!bi->has_shrink_hdr)
++ return 1; /* can gc */
++
++ yaffs2_find_oldest_dirty_seq(dev);
++
++ /* Can't do gc of this block if there are any blocks older than this one that have
++ * discarded pages.
++ */
++ return (bi->seq_number <= dev->oldest_dirty_seq);
++}
++
++/*
++ * yaffs2_find_refresh_block()
++ * periodically finds the oldest full block by sequence number for refreshing.
++ * Only for yaffs2.
++ */
++u32 yaffs2_find_refresh_block(struct yaffs_dev * dev)
++{
++ u32 b;
++
++ u32 oldest = 0;
++ u32 oldest_seq = 0;
++
++ struct yaffs_block_info *bi;
++
++ if (!dev->param.is_yaffs2)
++ return oldest;
++
++ /*
++ * If refresh period < 10 then refreshing is disabled.
++ */
++ if (dev->param.refresh_period < 10)
++ return oldest;
++
++ /*
++ * Fix broken values.
++ */
++ if (dev->refresh_skip > dev->param.refresh_period)
++ dev->refresh_skip = dev->param.refresh_period;
++
++ if (dev->refresh_skip > 0)
++ return oldest;
++
++ /*
++ * Refresh skip is now zero.
++ * We'll do a refresh this time around....
++ * Update the refresh skip and find the oldest block.
++ */
++ dev->refresh_skip = dev->param.refresh_period;
++ dev->refresh_count++;
++ bi = dev->block_info;
++ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
++
++ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++
++ if (oldest < 1 || bi->seq_number < oldest_seq) {
++ oldest = b;
++ oldest_seq = bi->seq_number;
++ }
++ }
++ bi++;
++ }
++
++ if (oldest > 0) {
++ T(YAFFS_TRACE_GC,
++ (TSTR
++ ("GC refresh count %d selected block %d with seq_number %d"
++ TENDSTR), dev->refresh_count, oldest, oldest_seq));
++ }
++
++ return oldest;
++}
++
++int yaffs2_checkpt_required(struct yaffs_dev *dev)
++{
++ int nblocks;
++
++ if (!dev->param.is_yaffs2)
++ return 0;
++
++ nblocks = dev->internal_end_block - dev->internal_start_block + 1;
++
++ return !dev->param.skip_checkpt_wr &&
++ !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
++}
++
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
++{
++ int retval;
++
++ if (!dev->param.is_yaffs2)
++ return 0;
++
++ if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
++ /* Not a valid value so recalculate */
++ int n_bytes = 0;
++ int n_blocks;
++ int dev_blocks =
++ (dev->param.end_block - dev->param.start_block + 1);
++
++ n_bytes += sizeof(struct yaffs_checkpt_validity);
++ n_bytes += sizeof(struct yaffs_checkpt_dev);
++ n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
++ n_bytes += dev_blocks * dev->chunk_bit_stride;
++ n_bytes +=
++ (sizeof(struct yaffs_checkpt_obj) +
++ sizeof(u32)) * (dev->n_obj);
++ n_bytes += (dev->tnode_size + sizeof(u32)) * (dev->n_tnodes);
++ n_bytes += sizeof(struct yaffs_checkpt_validity);
++ n_bytes += sizeof(u32); /* checksum */
++
++ /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
++
++ n_blocks =
++ (n_bytes /
++ (dev->data_bytes_per_chunk *
++ dev->param.chunks_per_block)) + 3;
++
++ dev->checkpoint_blocks_required = n_blocks;
++ }
++
++ retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
++ if (retval < 0)
++ retval = 0;
++ return retval;
++}
++
++/*--------------------- Checkpointing --------------------*/
++
++static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++ struct yaffs_checkpt_validity cp;
++
++ memset(&cp, 0, sizeof(cp));
++
++ cp.struct_type = sizeof(cp);
++ cp.magic = YAFFS_MAGIC;
++ cp.version = YAFFS_CHECKPOINT_VERSION;
++ cp.head = (head) ? 1 : 0;
++
++ return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
++{
++ struct yaffs_checkpt_validity cp;
++ int ok;
++
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ if (ok)
++ ok = (cp.struct_type == sizeof(cp)) &&
++ (cp.magic == YAFFS_MAGIC) &&
++ (cp.version == YAFFS_CHECKPOINT_VERSION) &&
++ (cp.head == ((head) ? 1 : 0));
++ return ok ? 1 : 0;
++}
++
++static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
++ struct yaffs_dev *dev)
++{
++ cp->n_erased_blocks = dev->n_erased_blocks;
++ cp->alloc_block = dev->alloc_block;
++ cp->alloc_page = dev->alloc_page;
++ cp->n_free_chunks = dev->n_free_chunks;
++
++ cp->n_deleted_files = dev->n_deleted_files;
++ cp->n_unlinked_files = dev->n_unlinked_files;
++ cp->n_bg_deletions = dev->n_bg_deletions;
++ cp->seq_number = dev->seq_number;
++
++}
++
++static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
++ struct yaffs_checkpt_dev *cp)
++{
++ dev->n_erased_blocks = cp->n_erased_blocks;
++ dev->alloc_block = cp->alloc_block;
++ dev->alloc_page = cp->alloc_page;
++ dev->n_free_chunks = cp->n_free_chunks;
++
++ dev->n_deleted_files = cp->n_deleted_files;
++ dev->n_unlinked_files = cp->n_unlinked_files;
++ dev->n_bg_deletions = cp->n_bg_deletions;
++ dev->seq_number = cp->seq_number;
++}
++
++static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_dev cp;
++ u32 n_bytes;
++ u32 n_blocks =
++ (dev->internal_end_block - dev->internal_start_block + 1);
++
++ int ok;
++
++ /* Write device runtime values */
++ yaffs2_dev_to_checkpt_dev(&cp, dev);
++ cp.struct_type = sizeof(cp);
++
++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ /* Write block info */
++ if (ok) {
++ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++ ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) ==
++ n_bytes);
++ }
++
++ /* Write chunk bits */
++ if (ok) {
++ n_bytes = n_blocks * dev->chunk_bit_stride;
++ ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) ==
++ n_bytes);
++ }
++ return ok ? 1 : 0;
++
++}
++
++static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
++{
++ struct yaffs_checkpt_dev cp;
++ u32 n_bytes;
++ u32 n_blocks =
++ (dev->internal_end_block - dev->internal_start_block + 1);
++
++ int ok;
++
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (!ok)
++ return 0;
++
++ if (cp.struct_type != sizeof(cp))
++ return 0;
++
++ yaffs_checkpt_dev_to_dev(dev, &cp);
++
++ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
++
++ ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
++
++ if (!ok)
++ return 0;
++ n_bytes = n_blocks * dev->chunk_bit_stride;
++
++ ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
++
++ return ok ? 1 : 0;
++}
++
++static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
++ struct yaffs_obj *obj)
++{
++
++ cp->obj_id = obj->obj_id;
++ cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
++ cp->hdr_chunk = obj->hdr_chunk;
++ cp->variant_type = obj->variant_type;
++ cp->deleted = obj->deleted;
++ cp->soft_del = obj->soft_del;
++ cp->unlinked = obj->unlinked;
++ cp->fake = obj->fake;
++ cp->rename_allowed = obj->rename_allowed;
++ cp->unlink_allowed = obj->unlink_allowed;
++ cp->serial = obj->serial;
++ cp->n_data_chunks = obj->n_data_chunks;
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
++}
++
++static int taffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
++ struct yaffs_checkpt_obj *cp)
++{
++
++ struct yaffs_obj *parent;
++
++ if (obj->variant_type != cp->variant_type) {
++ T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
++ TCONT
++ ("chunk %d does not match existing object type %d")
++ TENDSTR), cp->obj_id,
++ cp->variant_type, cp->hdr_chunk,
++ obj->variant_type));
++ return 0;
++ }
++
++ obj->obj_id = cp->obj_id;
++
++ if (cp->parent_id)
++ parent = yaffs_find_or_create_by_number(obj->my_dev,
++ cp->parent_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ else
++ parent = NULL;
++
++ if (parent) {
++ if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("Checkpoint read object %d parent %d type %d"
++ TCONT(" chunk %d Parent type, %d, not directory")
++ TENDSTR), cp->obj_id, cp->parent_id,
++ cp->variant_type, cp->hdr_chunk,
++ parent->variant_type));
++ return 0;
++ }
++ yaffs_add_obj_to_dir(parent, obj);
++ }
++
++ obj->hdr_chunk = cp->hdr_chunk;
++ obj->variant_type = cp->variant_type;
++ obj->deleted = cp->deleted;
++ obj->soft_del = cp->soft_del;
++ obj->unlinked = cp->unlinked;
++ obj->fake = cp->fake;
++ obj->rename_allowed = cp->rename_allowed;
++ obj->unlink_allowed = cp->unlink_allowed;
++ obj->serial = cp->serial;
++ obj->n_data_chunks = cp->n_data_chunks;
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
++ obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
++ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
++ obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
++
++ if (obj->hdr_chunk > 0)
++ obj->lazy_loaded = 1;
++ return 1;
++}
++
++static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
++ struct yaffs_tnode *tn, u32 level,
++ int chunk_offset)
++{
++ int i;
++ struct yaffs_dev *dev = in->my_dev;
++ int ok = 1;
++
++ if (tn) {
++ if (level > 0) {
++
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
++ if (tn->internal[i]) {
++ ok = yaffs2_checkpt_tnode_worker(in,
++ tn->
++ internal
++ [i],
++ level -
++ 1,
++ (chunk_offset
++ <<
++ YAFFS_TNODES_INTERNAL_BITS)
++ + i);
++ }
++ }
++ } else if (level == 0) {
++ u32 base_offset =
++ chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
++ ok = (yaffs2_checkpt_wr
++ (dev, &base_offset,
++ sizeof(base_offset)) == sizeof(base_offset));
++ if (ok)
++ ok = (yaffs2_checkpt_wr
++ (dev, tn,
++ dev->tnode_size) == dev->tnode_size);
++ }
++ }
++
++ return ok;
++
++}
++
++static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
++{
++ u32 end_marker = ~0;
++ int ok = 1;
++
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
++ ok = yaffs2_checkpt_tnode_worker(obj,
++ obj->variant.file_variant.top,
++ obj->variant.file_variant.
++ top_level, 0);
++ if (ok)
++ ok = (yaffs2_checkpt_wr
++ (obj->my_dev, &end_marker,
++ sizeof(end_marker)) == sizeof(end_marker));
++ }
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
++{
++ u32 base_chunk;
++ int ok = 1;
++ struct yaffs_dev *dev = obj->my_dev;
++ struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
++ struct yaffs_tnode *tn;
++ int nread = 0;
++
++ ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
++ sizeof(base_chunk));
++
++ while (ok && (~base_chunk)) {
++ nread++;
++ /* Read level 0 tnode */
++
++ tn = yaffs_get_tnode(dev);
++ if (tn) {
++ ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
++ dev->tnode_size);
++ } else {
++ ok = 0;
++ }
++
++ if (tn && ok)
++ ok = yaffs_add_find_tnode_0(dev,
++ file_stuct_ptr,
++ base_chunk, tn) ? 1 : 0;
++
++ if (ok)
++ ok = (yaffs2_checkpt_rd
++ (dev, &base_chunk,
++ sizeof(base_chunk)) == sizeof(base_chunk));
++
++ }
++
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
++ nread, base_chunk, ok));
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_checkpt_obj cp;
++ int i;
++ int ok = 1;
++ struct list_head *lh;
++
++ /* Iterate through the objects in each hash entry,
++ * dumping them to the checkpointing stream.
++ */
++
++ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
++ list_for_each(lh, &dev->obj_bucket[i].list) {
++ if (lh) {
++ obj =
++ list_entry(lh, struct yaffs_obj, hash_link);
++ if (!obj->defered_free) {
++ yaffs2_obj_checkpt_obj(&cp, obj);
++ cp.struct_type = sizeof(cp);
++
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR
++ ("Checkpoint write object %d parent %d type %d chunk %d obj addr %p"
++ TENDSTR), cp.obj_id, cp.parent_id,
++ cp.variant_type, cp.hdr_chunk, obj));
++
++ ok = (yaffs2_checkpt_wr
++ (dev, &cp,
++ sizeof(cp)) == sizeof(cp));
++
++ if (ok
++ && obj->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE)
++ ok = yaffs2_wr_checkpt_tnodes
++ (obj);
++ }
++ }
++ }
++ }
++
++ /* Dump end of list */
++ memset(&cp, 0xFF, sizeof(struct yaffs_checkpt_obj));
++ cp.struct_type = sizeof(cp);
++
++ if (ok)
++ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
++{
++ struct yaffs_obj *obj;
++ struct yaffs_checkpt_obj cp;
++ int ok = 1;
++ int done = 0;
++ struct yaffs_obj *hard_list = NULL;
++
++ while (ok && !done) {
++ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (cp.struct_type != sizeof(cp)) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("struct size %d instead of %d ok %d" TENDSTR),
++ cp.struct_type, (int)sizeof(cp), ok));
++ ok = 0;
++ }
++
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR
++ ("Checkpoint read object %d parent %d type %d chunk %d "
++ TENDSTR), cp.obj_id, cp.parent_id, cp.variant_type,
++ cp.hdr_chunk));
++
++ if (ok && cp.obj_id == ~0) {
++ done = 1;
++ } else if (ok) {
++ obj =
++ yaffs_find_or_create_by_number(dev, cp.obj_id,
++ cp.variant_type);
++ if (obj) {
++ ok = taffs2_checkpt_obj_to_obj(obj, &cp);
++ if (!ok)
++ break;
++ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
++ ok = yaffs2_rd_checkpt_tnodes(obj);
++ } else if (obj->variant_type ==
++ YAFFS_OBJECT_TYPE_HARDLINK) {
++ obj->hard_links.next =
++ (struct list_head *)hard_list;
++ hard_list = obj;
++ }
++ } else {
++ ok = 0;
++ }
++ }
++ }
++
++ if (ok)
++ yaffs_link_fixup(dev, hard_list);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
++{
++ u32 checkpt_sum;
++ int ok;
++
++ yaffs2_get_checkpt_sum(dev, &checkpt_sum);
++
++ ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
++ sizeof(checkpt_sum));
++
++ if (!ok)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
++{
++ u32 checkpt_sum0;
++ u32 checkpt_sum1;
++ int ok;
++
++ yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
++
++ ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
++ sizeof(checkpt_sum1));
++
++ if (!ok)
++ return 0;
++
++ if (checkpt_sum0 != checkpt_sum1)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
++{
++ int ok = 1;
++
++ if (!yaffs2_checkpt_required(dev)) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("skipping checkpoint write" TENDSTR)));
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs2_checkpt_open(dev, 1);
++
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("write checkpoint validity" TENDSTR)));
++ ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("write checkpoint device" TENDSTR)));
++ ok = yaffs2_wr_checkpt_dev(dev);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("write checkpoint objects" TENDSTR)));
++ ok = yaffs2_wr_checkpt_objs(dev);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("write checkpoint validity" TENDSTR)));
++ ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
++ }
++
++ if (ok)
++ ok = yaffs2_wr_checkpt_sum(dev);
++
++ if (!yaffs_checkpt_close(dev))
++ ok = 0;
++
++ if (ok)
++ dev->is_checkpointed = 1;
++ else
++ dev->is_checkpointed = 0;
++
++ return dev->is_checkpointed;
++}
++
++static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
++{
++ int ok = 1;
++
++ if (!dev->param.is_yaffs2)
++ ok = 0;
++
++ if (ok && dev->param.skip_checkpt_rd) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("skipping checkpoint read" TENDSTR)));
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs2_checkpt_open(dev, 0); /* open for read */
++
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("read checkpoint validity" TENDSTR)));
++ ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("read checkpoint device" TENDSTR)));
++ ok = yaffs2_rd_checkpt_dev(dev);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("read checkpoint objects" TENDSTR)));
++ ok = yaffs2_rd_checkpt_objs(dev);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("read checkpoint validity" TENDSTR)));
++ ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
++ }
++
++ if (ok) {
++ ok = yaffs2_rd_checkpt_sum(dev);
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("read checkpoint checksum %d" TENDSTR), ok));
++ }
++
++ if (!yaffs_checkpt_close(dev))
++ ok = 0;
++
++ if (ok)
++ dev->is_checkpointed = 1;
++ else
++ dev->is_checkpointed = 0;
++
++ return ok ? 1 : 0;
++
++}
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
++{
++ if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
++ dev->is_checkpointed = 0;
++ yaffs2_checkpt_invalidate_stream(dev);
++ }
++ if (dev->param.sb_dirty_fn)
++ dev->param.sb_dirty_fn(dev);
++}
++
++int yaffs_checkpoint_save(struct yaffs_dev *dev)
++{
++
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("save entry: is_checkpointed %d" TENDSTR),
++ dev->is_checkpointed));
++
++ yaffs_verify_objects(dev);
++ yaffs_verify_blocks(dev);
++ yaffs_verify_free_chunks(dev);
++
++ if (!dev->is_checkpointed) {
++ yaffs2_checkpt_invalidate(dev);
++ yaffs2_wr_checkpt_data(dev);
++ }
++
++ T(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
++ (TSTR("save exit: is_checkpointed %d" TENDSTR),
++ dev->is_checkpointed));
++
++ return dev->is_checkpointed;
++}
++
++int yaffs2_checkpt_restore(struct yaffs_dev *dev)
++{
++ int retval;
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("restore entry: is_checkpointed %d" TENDSTR),
++ dev->is_checkpointed));
++
++ retval = yaffs2_rd_checkpt_data(dev);
++
++ if (dev->is_checkpointed) {
++ yaffs_verify_objects(dev);
++ yaffs_verify_blocks(dev);
++ yaffs_verify_free_chunks(dev);
++ }
++
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("restore exit: is_checkpointed %d" TENDSTR),
++ dev->is_checkpointed));
++
++ return retval;
++}
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
++{
++ /* if new_size > old_file_size.
++ * We're going to be writing a hole.
++ * If the hole is small then write zeros otherwise write a start of hole marker.
++ */
++
++ loff_t old_file_size;
++ int increase;
++ int small_hole;
++ int result = YAFFS_OK;
++ struct yaffs_dev *dev = NULL;
++
++ u8 *local_buffer = NULL;
++
++ int small_increase_ok = 0;
++
++ if (!obj)
++ return YAFFS_FAIL;
++
++ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ dev = obj->my_dev;
++
++ /* Bail out if not yaffs2 mode */
++ if (!dev->param.is_yaffs2)
++ return YAFFS_OK;
++
++ old_file_size = obj->variant.file_variant.file_size;
++
++ if (new_size <= old_file_size)
++ return YAFFS_OK;
++
++ increase = new_size - old_file_size;
++
++ if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
++ yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
++ small_hole = 1;
++ else
++ small_hole = 0;
++
++ if (small_hole)
++ local_buffer = yaffs_get_temp_buffer(dev, __LINE__);
++
++ if (local_buffer) {
++ /* fill hole with zero bytes */
++ int pos = old_file_size;
++ int this_write;
++ int written;
++ memset(local_buffer, 0, dev->data_bytes_per_chunk);
++ small_increase_ok = 1;
++
++ while (increase > 0 && small_increase_ok) {
++ this_write = increase;
++ if (this_write > dev->data_bytes_per_chunk)
++ this_write = dev->data_bytes_per_chunk;
++ written =
++ yaffs_do_file_wr(obj, local_buffer, pos, this_write,
++ 0);
++ if (written == this_write) {
++ pos += this_write;
++ increase -= this_write;
++ } else {
++ small_increase_ok = 0;
++ }
++ }
++
++ yaffs_release_temp_buffer(dev, local_buffer, __LINE__);
++
++ /* If we were out of space then reverse any chunks we've added */
++ if (!small_increase_ok)
++ yaffs_resize_file_down(obj, old_file_size);
++ }
++
++ if (!small_increase_ok &&
++ obj->parent &&
++ obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
++ obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
++ /* Write a hole start header with the old file size */
++ yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
++ }
++
++ return result;
++
++}
++
++struct yaffs_block_index {
++ int seq;
++ int block;
++};
++
++static int yaffs2_ybicmp(const void *a, const void *b)
++{
++ int aseq = ((struct yaffs_block_index *)a)->seq;
++ int bseq = ((struct yaffs_block_index *)b)->seq;
++ int ablock = ((struct yaffs_block_index *)a)->block;
++ int bblock = ((struct yaffs_block_index *)b)->block;
++ if (aseq == bseq)
++ return ablock - bblock;
++ else
++ return aseq - bseq;
++}
++
++int yaffs2_scan_backwards(struct yaffs_dev *dev)
++{
++ struct yaffs_ext_tags tags;
++ int blk;
++ int block_iter;
++ int start_iter;
++ int end_iter;
++ int n_to_scan = 0;
++
++ int chunk;
++ int result;
++ int c;
++ int deleted;
++ enum yaffs_block_state state;
++ struct yaffs_obj *hard_list = NULL;
++ struct yaffs_block_info *bi;
++ u32 seq_number;
++ struct yaffs_obj_hdr *oh;
++ struct yaffs_obj *in;
++ struct yaffs_obj *parent;
++ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
++ int is_unlinked;
++ u8 *chunk_data;
++
++ int file_size;
++ int is_shrink;
++ int found_chunks;
++ int equiv_id;
++ int alloc_failed = 0;
++
++ struct yaffs_block_index *block_index = NULL;
++ int alt_block_index = 0;
++
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ ("yaffs2_scan_backwards starts intstartblk %d intendblk %d..."
++ TENDSTR), dev->internal_start_block, dev->internal_end_block));
++
++ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ block_index = YMALLOC(n_blocks * sizeof(struct yaffs_block_index));
++
++ if (!block_index) {
++ block_index =
++ YMALLOC_ALT(n_blocks * sizeof(struct yaffs_block_index));
++ alt_block_index = 1;
++ }
++
++ if (!block_index) {
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ ("yaffs2_scan_backwards() could not allocate block index!"
++ TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ dev->blocks_in_checkpt = 0;
++
++ chunk_data = yaffs_get_temp_buffer(dev, __LINE__);
++
++ /* Scan all the blocks to determine their state */
++ bi = dev->block_info;
++ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
++ blk++) {
++ yaffs_clear_chunk_bits(dev, blk);
++ bi->pages_in_use = 0;
++ bi->soft_del_pages = 0;
++
++ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
++
++ bi->block_state = state;
++ bi->seq_number = seq_number;
++
++ if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ bi->block_state = state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
++
++ T(YAFFS_TRACE_SCAN_DEBUG,
++ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
++ state, seq_number));
++
++ if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ dev->blocks_in_checkpt++;
++
++ } else if (state == YAFFS_BLOCK_STATE_DEAD) {
++ T(YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("block %d is bad" TENDSTR), blk));
++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
++ T(YAFFS_TRACE_SCAN_DEBUG,
++ (TSTR("Block empty " TENDSTR)));
++ dev->n_erased_blocks++;
++ dev->n_free_chunks += dev->param.chunks_per_block;
++ } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
++
++ /* Determine the highest sequence number */
++ if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
++ seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
++
++ block_index[n_to_scan].seq = seq_number;
++ block_index[n_to_scan].block = blk;
++
++ n_to_scan++;
++
++ if (seq_number >= dev->seq_number)
++ dev->seq_number = seq_number;
++ } else {
++ /* TODO: Nasty sequence number! */
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ ("Block scanning block %d has bad sequence number %d"
++ TENDSTR), blk, seq_number));
++
++ }
++ }
++ bi++;
++ }
++
++ T(YAFFS_TRACE_SCAN,
++ (TSTR("%d blocks to be sorted..." TENDSTR), n_to_scan));
++
++ YYIELD();
++
++ /* Sort the blocks by sequence number */
++ yaffs_sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
++ yaffs2_ybicmp);
++
++ YYIELD();
++
++ T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
++
++ /* Now scan the blocks looking at the data. */
++ start_iter = 0;
++ end_iter = n_to_scan - 1;
++ T(YAFFS_TRACE_SCAN_DEBUG,
++ (TSTR("%d blocks to be scanned" TENDSTR), n_to_scan));
++
++ /* For each block.... backwards */
++ for (block_iter = end_iter; !alloc_failed && block_iter >= start_iter;
++ block_iter--) {
++ /* Cooperative multitasking! This loop can run for so
++ long that watchdog timers expire. */
++ YYIELD();
++
++ /* get the block to scan in the correct order */
++ blk = block_index[block_iter].block;
++
++ bi = yaffs_get_block_info(dev, blk);
++
++ state = bi->block_state;
++
++ deleted = 0;
++
++ /* For each chunk in each block that needs scanning.... */
++ found_chunks = 0;
++ for (c = dev->param.chunks_per_block - 1;
++ !alloc_failed && c >= 0 &&
++ (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
++ state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
++ /* Scan backwards...
++ * Read the tags and decide what to do
++ */
++
++ chunk = blk * dev->param.chunks_per_block + c;
++
++ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
++ &tags);
++
++ /* Let's have a good look at this chunk... */
++
++ if (!tags.chunk_used) {
++ /* An unassigned chunk in the block.
++ * If there are used chunks after this one, then
++ * it is a chunk that was skipped due to failing the erased
++ * check. Just skip it so that it can be deleted.
++ * But, more typically, We get here when this is an unallocated
++ * chunk and his means that either the block is empty or
++ * this is the one being allocated from
++ */
++
++ if (found_chunks) {
++ /* This is a chunk that was skipped due to failing the erased check */
++ } else if (c == 0) {
++ /* We're looking at the first chunk in the block so the block is unused */
++ state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->n_erased_blocks++;
++ } else {
++ if (state ==
++ YAFFS_BLOCK_STATE_NEEDS_SCANNING
++ || state ==
++ YAFFS_BLOCK_STATE_ALLOCATING) {
++ if (dev->seq_number ==
++ bi->seq_number) {
++ /* this is the block being allocated from */
++
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ (" Allocating from %d %d"
++ TENDSTR), blk, c));
++
++ state =
++ YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->alloc_block = blk;
++ dev->alloc_page = c;
++ dev->
++ alloc_block_finder =
++ blk;
++ } else {
++ /* This is a partially written block that is not
++ * the current allocation block.
++ */
++
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ ("Partially written block %d detected"
++ TENDSTR), blk));
++ }
++ }
++ }
++
++ dev->n_free_chunks++;
++
++ } else if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ (" Unfixed ECC in chunk(%d:%d), chunk ignored"
++ TENDSTR), blk, c));
++
++ dev->n_free_chunks++;
++
++ } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
++ tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
++ (tags.chunk_id > 0
++ && tags.n_bytes > dev->data_bytes_per_chunk)
++ || tags.seq_number != bi->seq_number) {
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ ("Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored"
++ TENDSTR), blk, c, tags.obj_id,
++ tags.chunk_id, tags.n_bytes));
++
++ dev->n_free_chunks++;
++
++ } else if (tags.chunk_id > 0) {
++ /* chunk_id > 0 so it is a data chunk... */
++ unsigned int endpos;
++ u32 chunk_base =
++ (tags.chunk_id -
++ 1) * dev->data_bytes_per_chunk;
++
++ found_chunks = 1;
++
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ in = yaffs_find_or_create_by_number(dev,
++ tags.obj_id,
++ YAFFS_OBJECT_TYPE_FILE);
++ if (!in) {
++ /* Out of memory */
++ alloc_failed = 1;
++ }
++
++ if (in &&
++ in->variant_type == YAFFS_OBJECT_TYPE_FILE
++ && chunk_base <
++ in->variant.file_variant.shrink_size) {
++ /* This has not been invalidated by a resize */
++ if (!yaffs_put_chunk_in_file
++ (in, tags.chunk_id, chunk, -1)) {
++ alloc_failed = 1;
++ }
++
++ /* File size is calculated by looking at the data chunks if we have not
++ * seen an object header yet. Stop this practice once we find an object header.
++ */
++ endpos = chunk_base + tags.n_bytes;
++
++ if (!in->valid && /* have not got an object header yet */
++ in->variant.file_variant.
++ scanned_size < endpos) {
++ in->variant.file_variant.
++ scanned_size = endpos;
++ in->variant.file_variant.
++ file_size = endpos;
++ }
++
++ } else if (in) {
++ /* This chunk has been invalidated by a resize, or a past file deletion
++ * so delete the chunk*/
++ yaffs_chunk_del(dev, chunk, 1,
++ __LINE__);
++
++ }
++ } else {
++ /* chunk_id == 0, so it is an ObjectHeader.
++ * Thus, we read in the object header and make the object
++ */
++ found_chunks = 1;
++
++ yaffs_set_chunk_bit(dev, blk, c);
++ bi->pages_in_use++;
++
++ oh = NULL;
++ in = NULL;
++
++ if (tags.extra_available) {
++ in = yaffs_find_or_create_by_number(dev,
++ tags.
++ obj_id,
++ tags.
++ extra_obj_type);
++ if (!in)
++ alloc_failed = 1;
++ }
++
++ if (!in ||
++ (!in->valid && dev->param.disable_lazy_load)
++ || tags.extra_shadows || (!in->valid
++ && (tags.obj_id ==
++ YAFFS_OBJECTID_ROOT
++ || tags.
++ obj_id ==
++ YAFFS_OBJECTID_LOSTNFOUND)))
++ {
++
++ /* If we don't have valid info then we need to read the chunk
++ * TODO In future we can probably defer reading the chunk and
++ * living with invalid data until needed.
++ */
++
++ result = yaffs_rd_chunk_tags_nand(dev,
++ chunk,
++ chunk_data,
++ NULL);
++
++ oh = (struct yaffs_obj_hdr *)chunk_data;
++
++ if (dev->param.inband_tags) {
++ /* Fix up the header if they got corrupted by inband tags */
++ oh->shadows_obj =
++ oh->inband_shadowed_obj_id;
++ oh->is_shrink =
++ oh->inband_is_shrink;
++ }
++
++ if (!in) {
++ in = yaffs_find_or_create_by_number(dev, tags.obj_id, oh->type);
++ if (!in)
++ alloc_failed = 1;
++ }
++
++ }
++
++ if (!in) {
++ /* TODO Hoosterman we have a problem! */
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
++ TENDSTR), tags.obj_id, chunk));
++ continue;
++ }
++
++ if (in->valid) {
++ /* We have already filled this one.
++ * We have a duplicate that will be discarded, but
++ * we first have to suck out resize info if it is a file.
++ */
++
++ if ((in->variant_type ==
++ YAFFS_OBJECT_TYPE_FILE) && ((oh
++ &&
++ oh->
++ type
++ ==
++ YAFFS_OBJECT_TYPE_FILE)
++ ||
++ (tags.
++ extra_available
++ &&
++ tags.
++ extra_obj_type
++ ==
++ YAFFS_OBJECT_TYPE_FILE)))
++ {
++ u32 this_size =
++ (oh) ? oh->
++ file_size :
++ tags.extra_length;
++ u32 parent_obj_id =
++ (oh) ? oh->parent_obj_id :
++ tags.extra_parent_id;
++
++ is_shrink =
++ (oh) ? oh->
++ is_shrink :
++ tags.extra_is_shrink;
++
++ /* If it is deleted (unlinked at start also means deleted)
++ * we treat the file size as being zeroed at this point.
++ */
++ if (parent_obj_id ==
++ YAFFS_OBJECTID_DELETED
++ || parent_obj_id ==
++ YAFFS_OBJECTID_UNLINKED) {
++ this_size = 0;
++ is_shrink = 1;
++ }
++
++ if (is_shrink
++ && in->variant.file_variant.
++ shrink_size > this_size)
++ in->variant.
++ file_variant.
++ shrink_size =
++ this_size;
++
++ if (is_shrink)
++ bi->has_shrink_hdr = 1;
++
++ }
++ /* Use existing - destroy this one. */
++ yaffs_chunk_del(dev, chunk, 1,
++ __LINE__);
++
++ }
++
++ if (!in->valid && in->variant_type !=
++ (oh ? oh->type : tags.extra_obj_type))
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy: Bad object type, "
++ TCONT
++ ("%d != %d, for object %d at chunk ")
++ TCONT("%d during scan")
++ TENDSTR), oh ?
++ oh->type : tags.extra_obj_type,
++ in->variant_type, tags.obj_id,
++ chunk));
++
++ if (!in->valid &&
++ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
++ tags.obj_id ==
++ YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle with directory structure */
++ in->valid = 1;
++
++ if (oh) {
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++ in->lazy_loaded = 0;
++ } else {
++ in->lazy_loaded = 1;
++ }
++ in->hdr_chunk = chunk;
++
++ } else if (!in->valid) {
++ /* we need to load this info */
++
++ in->valid = 1;
++ in->hdr_chunk = chunk;
++
++ if (oh) {
++ in->variant_type = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++ yaffs_load_attribs(in, oh);
++
++ if (oh->shadows_obj > 0)
++ yaffs_handle_shadowed_obj
++ (dev,
++ oh->shadows_obj,
++ 1);
++
++ yaffs_set_obj_name_from_oh(in,
++ oh);
++ parent =
++ yaffs_find_or_create_by_number
++ (dev, oh->parent_obj_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++
++ file_size = oh->file_size;
++ is_shrink = oh->is_shrink;
++ equiv_id = oh->equiv_id;
++
++ } else {
++ in->variant_type =
++ tags.extra_obj_type;
++ parent =
++ yaffs_find_or_create_by_number
++ (dev, tags.extra_parent_id,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ file_size = tags.extra_length;
++ is_shrink =
++ tags.extra_is_shrink;
++ equiv_id = tags.extra_equiv_id;
++ in->lazy_loaded = 1;
++
++ }
++ in->dirty = 0;
++
++ if (!parent)
++ alloc_failed = 1;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ if (parent && parent->variant_type ==
++ YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variant_type =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ INIT_LIST_HEAD(&parent->
++ variant.dir_variant.children);
++ } else if (!parent
++ || parent->variant_type !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, another problem....
++ * We're trying to use a non-directory as a directory
++ */
++
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ TENDSTR)));
++ parent = dev->lost_n_found;
++ }
++
++ yaffs_add_obj_to_dir(parent, in);
++
++ is_unlinked = (parent == dev->del_dir)
++ || (parent == dev->unlinked_dir);
++
++ if (is_shrink) {
++ /* Mark the block as having a shrink header */
++ bi->has_shrink_hdr = 1;
++ }
++
++ /* Note re hardlinks.
++ * Since we might scan a hardlink before its equivalent object is scanned
++ * we put them all in a list.
++ * After scanning is complete, we should have all the objects, so we run
++ * through this list and fix up all the chains.
++ */
++
++ switch (in->variant_type) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++
++ if (in->variant.
++ file_variant.scanned_size <
++ file_size) {
++ /* This covers the case where the file size is greater
++ * than where the data is
++ * This will happen if the file is resized to be larger
++ * than its current data extents.
++ */
++ in->variant.
++ file_variant.
++ file_size =
++ file_size;
++ in->variant.
++ file_variant.
++ scanned_size =
++ file_size;
++ }
++
++ if (in->variant.file_variant.
++ shrink_size > file_size)
++ in->variant.
++ file_variant.
++ shrink_size =
++ file_size;
++
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ if (!is_unlinked) {
++ in->variant.
++ hardlink_variant.
++ equiv_id = equiv_id;
++ in->hard_links.next =
++ (struct list_head *)
++ hard_list;
++ hard_list = in;
++ }
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ if (oh) {
++ in->variant.
++ symlink_variant.
++ alias =
++ yaffs_clone_str(oh->
++ alias);
++ if (!in->variant.
++ symlink_variant.
++ alias)
++ alloc_failed =
++ 1;
++ }
++ break;
++ }
++
++ }
++
++ }
++
++ } /* End of scanning for each chunk */
++
++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
++ /* If we got this far while scanning, then the block is fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++ bi->block_state = state;
++
++ /* Now let's see if it was dirty */
++ if (bi->pages_in_use == 0 &&
++ !bi->has_shrink_hdr &&
++ bi->block_state == YAFFS_BLOCK_STATE_FULL) {
++ yaffs_block_became_dirty(dev, blk);
++ }
++
++ }
++
++ yaffs_skip_rest_of_block(dev);
++
++ if (alt_block_index)
++ YFREE_ALT(block_index);
++ else
++ YFREE(block_index);
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We should now have scanned all the objects, now it's time to add these
++ * hardlinks.
++ */
++ yaffs_link_fixup(dev, hard_list);
++
++ yaffs_release_temp_buffer(dev, chunk_data, __LINE__);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_scan_backwards ends" TENDSTR)));
++
++ return YAFFS_OK;
++}
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs2.h linux-2.6.36/fs/yaffs2/yaffs_yaffs2.h
+--- linux-2.6.36.orig/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yaffs_yaffs2.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_YAFFS2_H__
++#define __YAFFS_YAFFS2_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
++void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
++ struct yaffs_block_info *bi);
++void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
++ struct yaffs_block_info *bi);
++int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
++u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
++int yaffs2_checkpt_required(struct yaffs_dev *dev);
++int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
++
++void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
++int yaffs2_checkpt_save(struct yaffs_dev *dev);
++int yaffs2_checkpt_restore(struct yaffs_dev *dev);
++
++int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
++int yaffs2_scan_backwards(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-2.6.36.orig/fs/yaffs2/yportenv.h linux-2.6.36/fs/yaffs2/yportenv.h
+--- linux-2.6.36.orig/fs/yaffs2/yportenv.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/fs/yaffs2/yportenv.h 2011-01-10 19:29:29.000000000 +0100
+@@ -0,0 +1,339 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2010 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YPORTENV_H__
++#define __YPORTENV_H__
++
++/*
++ * Define the MTD version in terms of Linux Kernel versions
++ * This allows yaffs to be used independantly of the kernel
++ * as well as with it.
++ */
++
++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
++
++#if defined CONFIG_YAFFS_WINCE
++
++#include "ywinceenv.h"
++
++#elif defined __KERNEL__
++
++#include "moduleconfig.h"
++
++/* Linux kernel */
++
++#include <linux/version.h>
++#define MTD_VERSION_CODE LINUX_VERSION_CODE
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/xattr.h>
++#include <linux/list.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/stat.h>
++#include <linux/sort.h>
++
++#define YCHAR char
++#define YUCHAR unsigned char
++#define _Y(x) x
++#define yaffs_strcat(a, b) strcat(a, b)
++#define yaffs_strcpy(a, b) strcpy(a, b)
++#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
++#define yaffs_strncmp(a, b, c) strncmp(a, b, c)
++#define yaffs_strnlen(s,m) strnlen(s,m)
++#define yaffs_sprintf sprintf
++#define yaffs_toupper(a) toupper(a)
++#define yaffs_sort(base, n, sz, cmp_fn) sort(base, n, sz, cmp_fn, NULL)
++
++#define Y_INLINE __inline__
++
++#define YAFFS_LOSTNFOUND_NAME "lost+found"
++#define YAFFS_LOSTNFOUND_PREFIX "obj"
++
++/* #define YPRINTF(x) printk x */
++#define YMALLOC(x) kmalloc(x, GFP_NOFS)
++#define YFREE(x) kfree(x)
++#define YMALLOC_ALT(x) vmalloc(x)
++#define YFREE_ALT(x) vfree(x)
++#define YMALLOC_DMA(x) YMALLOC(x)
++
++#define YYIELD() schedule()
++#define Y_DUMP_STACK() dump_stack()
++
++#define YAFFS_ROOT_MODE 0755
++#define YAFFS_LOSTNFOUND_MODE 0700
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
++#define Y_TIME_CONVERT(x) (x).tv_sec
++#else
++#define Y_CURRENT_TIME CURRENT_TIME
++#define Y_TIME_CONVERT(x) (x)
++#endif
++
++#define yaffs_sum_cmp(x, y) ((x) == (y))
++#define yaffs_strcmp(a, b) strcmp(a, b)
++
++#define TENDSTR "\n"
++#define TSTR(x) KERN_DEBUG x
++#define TCONT(x) x
++#define TOUT(p) printk p
++
++#define compile_time_assertion(assertion) \
++ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
++
++#elif defined CONFIG_YAFFS_DIRECT
++
++#define MTD_VERSION_CODE MTD_VERSION(2, 6, 22)
++
++/* Direct interface */
++#include "ydirectenv.h"
++
++#elif defined CONFIG_YAFFS_UTIL
++
++/* Stuff for YAFFS utilities */
++
++#include "stdlib.h"
++#include "stdio.h"
++#include "string.h"
++
++#define YMALLOC(x) malloc(x)
++#define YFREE(x) free(x)
++#define YMALLOC_ALT(x) malloc(x)
++#define YFREE_ALT(x) free(x)
++
++#define YCHAR char
++#define YUCHAR unsigned char
++#define _Y(x) x
++#define yaffs_strcat(a, b) strcat(a, b)
++#define yaffs_strcpy(a, b) strcpy(a, b)
++#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
++#define yaffs_strnlen(s,m) strnlen(s,m)
++#define yaffs_sprintf sprintf
++#define yaffs_toupper(a) toupper(a)
++
++#define Y_INLINE inline
++
++/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
++/* #define YALERT(s) YINFO(s) */
++
++#define TENDSTR "\n"
++#define TSTR(x) x
++#define TOUT(p) printf p
++
++#define YAFFS_LOSTNFOUND_NAME "lost+found"
++#define YAFFS_LOSTNFOUND_PREFIX "obj"
++/* #define YPRINTF(x) printf x */
++
++#define YAFFS_ROOT_MODE 0755
++#define YAFFS_LOSTNFOUND_MODE 0700
++
++#define yaffs_sum_cmp(x, y) ((x) == (y))
++#define yaffs_strcmp(a, b) strcmp(a, b)
++
++#else
++/* Should have specified a configuration type */
++#error Unknown configuration
++
++#endif
++
++#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
++
++#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
++
++#ifndef O_RDONLY
++#define O_RDONLY 00
++#endif
++
++#ifndef O_WRONLY
++#define O_WRONLY 01
++#endif
++
++#ifndef O_RDWR
++#define O_RDWR 02
++#endif
++
++#ifndef O_CREAT
++#define O_CREAT 0100
++#endif
++
++#ifndef O_EXCL
++#define O_EXCL 0200
++#endif
++
++#ifndef O_TRUNC
++#define O_TRUNC 01000
++#endif
++
++#ifndef O_APPEND
++#define O_APPEND 02000
++#endif
++
++#ifndef SEEK_SET
++#define SEEK_SET 0
++#endif
++
++#ifndef SEEK_CUR
++#define SEEK_CUR 1
++#endif
++
++#ifndef SEEK_END
++#define SEEK_END 2
++#endif
++
++#ifndef EBUSY
++#define EBUSY 16
++#endif
++
++#ifndef ENODEV
++#define ENODEV 19
++#endif
++
++#ifndef EINVAL
++#define EINVAL 22
++#endif
++
++#ifndef ENFILE
++#define ENFILE 23
++#endif
++
++#ifndef EBADF
++#define EBADF 9
++#endif
++
++#ifndef EACCES
++#define EACCES 13
++#endif
++
++#ifndef EXDEV
++#define EXDEV 18
++#endif
++
++#ifndef ENOENT
++#define ENOENT 2
++#endif
++
++#ifndef ENOSPC
++#define ENOSPC 28
++#endif
++
++#ifndef ERANGE
++#define ERANGE 34
++#endif
++
++#ifndef ENODATA
++#define ENODATA 61
++#endif
++
++#ifndef ENOTEMPTY
++#define ENOTEMPTY 39
++#endif
++
++#ifndef ENAMETOOLONG
++#define ENAMETOOLONG 36
++#endif
++
++#ifndef ENOMEM
++#define ENOMEM 12
++#endif
++
++#ifndef EEXIST
++#define EEXIST 17
++#endif
++
++#ifndef ENOTDIR
++#define ENOTDIR 20
++#endif
++
++#ifndef EISDIR
++#define EISDIR 21
++#endif
++
++// Mode flags
++
++#ifndef S_IFMT
++#define S_IFMT 0170000
++#endif
++
++#ifndef S_IFLNK
++#define S_IFLNK 0120000
++#endif
++
++#ifndef S_IFDIR
++#define S_IFDIR 0040000
++#endif
++
++#ifndef S_IFREG
++#define S_IFREG 0100000
++#endif
++
++#ifndef S_IREAD
++#define S_IREAD 0000400
++#endif
++
++#ifndef S_IWRITE
++#define S_IWRITE 0000200
++#endif
++
++#ifndef S_IEXEC
++#define S_IEXEC 0000100
++#endif
++
++#ifndef XATTR_CREATE
++#define XATTR_CREATE 1
++#endif
++
++#ifndef XATTR_REPLACE
++#define XATTR_REPLACE 2
++#endif
++
++#ifndef R_OK
++#define R_OK 4
++#define W_OK 2
++#define X_OK 1
++#define F_OK 0
++#endif
++
++#else
++#include <errno.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#endif
++
++#endif
++
++#ifndef Y_DUMP_STACK
++#define Y_DUMP_STACK() do { } while (0)
++#endif
++
++#ifndef YBUG
++#define YBUG() do {\
++ T(YAFFS_TRACE_BUG,\
++ (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\
++ __LINE__));\
++ Y_DUMP_STACK();\
++} while (0)
++#endif
++
++#endif
diff --git a/target/mips/kernel.config b/target/mips/kernel.config
index dd4326205..ecec23854 100644
--- a/target/mips/kernel.config
+++ b/target/mips/kernel.config
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.36
-# Sun Jan 2 23:03:13 2011
+# Tue Jan 4 23:41:39 2011
#
CONFIG_MIPS=y
@@ -155,14 +155,14 @@ CONFIG_SYS_SUPPORTS_MIPS_CMP=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_CPU_SUPPORTS_HR_SCHED_CLOCK=y
# CONFIG_HZ_48 is not set
-CONFIG_HZ_100=y
+# CONFIG_HZ_100 is not set
# CONFIG_HZ_128 is not set
-# CONFIG_HZ_250 is not set
+CONFIG_HZ_250=y
# CONFIG_HZ_256 is not set
# CONFIG_HZ_1000 is not set
# CONFIG_HZ_1024 is not set
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_HZ=100
+CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
@@ -186,9 +186,9 @@ CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_BZIP2=y
CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_LZO=y
-CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_GZIP is not set
# CONFIG_KERNEL_BZIP2 is not set
-# CONFIG_KERNEL_LZMA is not set
+CONFIG_KERNEL_LZMA=y
# CONFIG_KERNEL_LZO is not set
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
@@ -219,8 +219,7 @@ CONFIG_SYSCTL=y
CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_KALLSYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -264,9 +263,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
# CONFIG_BLOCK is not set
-# CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-# CONFIG_DEFAULT_NOOP is not set
# CONFIG_INLINE_SPIN_TRYLOCK is not set
# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
# CONFIG_INLINE_SPIN_LOCK is not set
diff --git a/target/mips/patches/io_map_base.patch b/target/mips/patches/io_map_base.patch
deleted file mode 100644
index be39ffe09..000000000
--- a/target/mips/patches/io_map_base.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-diff -Nur linux-2.6.28.orig/arch/mips/include/asm/mips-boards/generic.h linux-2.6.28/arch/mips/include/asm/mips-boards/generic.h
---- linux-2.6.28.orig/arch/mips/include/asm/mips-boards/generic.h 2008-12-25 00:26:37.000000000 +0100
-+++ linux-2.6.28/arch/mips/include/asm/mips-boards/generic.h 2009-01-09 23:03:02.000000000 +0100
-@@ -92,7 +92,7 @@
- extern void mips_reboot_setup(void);
-
- #ifdef CONFIG_PCI
--extern void mips_pcibios_init(void);
-+extern int mips_pcibios_init(void);
- #else
- #define mips_pcibios_init() do { } while (0)
- #endif
-diff -Nur linux-2.6.28.orig/arch/mips/mti-malta/malta-pci.c linux-2.6.28/arch/mips/mti-malta/malta-pci.c
---- linux-2.6.28.orig/arch/mips/mti-malta/malta-pci.c 2008-12-25 00:26:37.000000000 +0100
-+++ linux-2.6.28/arch/mips/mti-malta/malta-pci.c 2009-01-09 23:02:02.000000000 +0100
-@@ -87,10 +87,11 @@
- .mem_resource = &msc_mem_resource,
- };
-
--void __init mips_pcibios_init(void)
-+int __init mips_pcibios_init(void)
- {
- struct pci_controller *controller;
- resource_size_t start, end, map, start1, end1, map1, map2, map3, mask;
-+ void __iomem *io_map_base;
-
- switch (mips_revision_sconid) {
- case MIPS_REVISION_SCON_GT64120:
-@@ -230,7 +231,7 @@
- controller = &msc_controller;
- break;
- default:
-- return;
-+ return 0;
- }
-
- if (controller->io_resource->start < 0x00001000UL) /* FIXME */
-@@ -239,5 +240,14 @@
- iomem_resource.end &= 0xfffffffffULL; /* 64 GB */
- ioport_resource.end = controller->io_resource->end;
-
-+ io_map_base = ioremap(MIPS_MSC01_PCI_REG_BASE,
-+ controller->io_resource->end - controller->io_resource->start + 1);
-+ if (!io_map_base)
-+ return -EBUSY;
-+
-+ controller->io_map_base = (unsigned long)io_map_base;
-+
- register_pci_controller(controller);
-+
-+ return 0;
- }
diff --git a/target/mips64/Makefile b/target/mips64/Makefile
index 12781b874..a242511c9 100644
--- a/target/mips64/Makefile
+++ b/target/mips64/Makefile
@@ -8,17 +8,20 @@ include $(TOPDIR)/mk/kernel-build.mk
include $(TOPDIR)/mk/image.mk
KERNEL:=$(LINUX_DIR)/vmlinux
+OSTRIP:=-R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id
-ifeq ($(FS),archive)
+ifeq ($(ADK_TARGET_FS),archive)
imageinstall: $(BIN_DIR)/$(ROOTFSTARBALL)
+ @cp $(TARGET_DIR)/boot/kernel $(BIN_DIR)/$(TARGET_KERNEL)
@echo "The RootFS tarball is: $(BIN_DIR)/$(ROOTFSTARBALL)"
@echo "Use following command to create a QEMU Image:"
@echo "sudo ./scripts/create-image.sh qemu-${CPU_ARCH}.img $(BIN_DIR)/$(ROOTFSTARBALL)"
@echo "Start qemu with following options:"
- @echo 'qemu-system-mips64 -nographic -M malta -kernel $(BIN_DIR)/${TARGET_KERNEL} -hda qemu-${CPU_ARCH}.img -append "root=/dev/hda1"'
+ @echo 'qemu-system-mips64 -nographic -M malta -kernel $(BIN_DIR)/${TARGET_KERNEL} qemu-${CPU_ARCH}.img'
endif
-ifeq ($(FS),initramfs)
+ifeq ($(ADK_TARGET_FS),initramfs)
imageinstall: $(BIN_DIR)/$(INITRAMFS)
+ @cp $(TARGET_DIR)/boot/kernel $(BIN_DIR)/$(TARGET_KERNEL)
@echo 'The kernel file is: ${BIN_DIR}/${TARGET_KERNEL}'
@echo 'The initramfs image is: ${BIN_DIR}/${INITRAMFS}'
@echo 'qemu-system-mips64 -nographic -M malta -kernel $(BIN_DIR)/${TARGET_KERNEL} -initrd ${BIN_DIR}/${INITRAMFS}'
diff --git a/target/mips64/kernel.config b/target/mips64/kernel.config
index 2cd7908a5..795027285 100644
--- a/target/mips64/kernel.config
+++ b/target/mips64/kernel.config
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc7
-# Sat May 30 17:42:51 2009
+# Linux kernel version: 2.6.36
+# Tue Jan 4 14:52:49 2011
#
CONFIG_MIPS=y
@@ -9,14 +9,17 @@ CONFIG_MIPS=y
# Machine selection
#
CONFIG_ZONE_DMA=y
-# CONFIG_MACH_ALCHEMY is not set
-# CONFIG_BASLER_EXCITE is not set
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_ATHEROS_AR71XX is not set
# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
# CONFIG_LASAT is not set
-# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MACH_LOONGSON is not set
CONFIG_MIPS_MALTA=y
# CONFIG_MIPS_SIM is not set
# CONFIG_NEC_MARKEINS is not set
@@ -27,6 +30,7 @@ CONFIG_MIPS_MALTA=y
# CONFIG_PNX8550_STB810 is not set
# CONFIG_PMC_MSP is not set
# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_POWERTV is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
# CONFIG_SGI_IP28 is not set
@@ -46,6 +50,10 @@ CONFIG_MIPS_MALTA=y
# CONFIG_WR_PPMC is not set
# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_CAVIUM_OCTEON_HELPER=y
+CONFIG_LOONGSON_UART_BASE=y
+# CONFIG_LOONGSON_MC146818 is not set
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
@@ -54,7 +62,6 @@ CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_SCHED_OMIT_FRAME_POINTER=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
@@ -65,52 +72,37 @@ CONFIG_CEVT_R4K=y
CONFIG_CSRC_R4K_LIB=y
CONFIG_CSRC_R4K=y
CONFIG_DMA_NONCOHERENT=y
-CONFIG_DMA_NEED_PCI_MAP_STATE=y
-CONFIG_EARLY_PRINTK=y
+CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
-# CONFIG_HOTPLUG_CPU is not set
CONFIG_I8259=y
CONFIG_MIPS_BONITO64=y
CONFIG_MIPS_MSC=y
+# CONFIG_MIPS_MACHINE is not set
# CONFIG_NO_IOPORT is not set
CONFIG_GENERIC_ISA_DMA=y
+CONFIG_ISA_DMA_API=y
CONFIG_CPU_BIG_ENDIAN=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
CONFIG_IRQ_CPU=y
CONFIG_IRQ_GIC=y
CONFIG_MIPS_BOARDS_GEN=y
CONFIG_PCI_GT64XXX_PCI0=y
CONFIG_SWAP_IO_SPACE=y
CONFIG_BOOT_ELF32=y
-CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_MIPS_L1_CACHE_SHIFT=6
#
# CPU selection
#
-# CONFIG_CPU_LOONGSON2 is not set
# CONFIG_CPU_MIPS32_R1 is not set
# CONFIG_CPU_MIPS32_R2 is not set
CONFIG_CPU_MIPS64_R1=y
-# CONFIG_CPU_MIPS64_R2 is not set
-# CONFIG_CPU_R3000 is not set
-# CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_VR41XX is not set
-# CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
-# CONFIG_CPU_TX49XX is not set
-# CONFIG_CPU_R5000 is not set
-# CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_R5500 is not set
-# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_NEVADA is not set
-# CONFIG_CPU_R8000 is not set
-# CONFIG_CPU_R10000 is not set
# CONFIG_CPU_RM7000 is not set
-# CONFIG_CPU_RM9000 is not set
-# CONFIG_CPU_SB1 is not set
-# CONFIG_CPU_CAVIUM_OCTEON is not set
+CONFIG_SYS_SUPPORTS_ZBOOT=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_CPU_MIPS64_R1=y
@@ -122,6 +114,7 @@ CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HUGEPAGES=y
CONFIG_HARDWARE_WATCHPOINTS=y
#
@@ -130,19 +123,17 @@ CONFIG_HARDWARE_WATCHPOINTS=y
# CONFIG_32BIT is not set
CONFIG_64BIT=y
CONFIG_PAGE_SIZE_4KB=y
-# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_16KB is not set
-# CONFIG_PAGE_SIZE_32KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_BOARD_SCACHE=y
CONFIG_MIPS_CPU_SCACHE=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMP is not set
-# CONFIG_MIPS_MT_SMTC is not set
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
# CONFIG_MIPS_VPE_LOADER is not set
-CONFIG_CPU_HAS_LLSC=y
+# CONFIG_MIPS_CMP is not set
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
# CONFIG_CPU_HAS_SMARTMIPS is not set
CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
@@ -153,21 +144,20 @@ CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-# CONFIG_UNEVICTABLE_LRU is not set
-CONFIG_HAVE_MLOCK=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_SYS_SUPPORTS_MIPS_CMP=y
# CONFIG_NO_HZ is not set
# CONFIG_HIGH_RES_TIMERS is not set
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_CPU_SUPPORTS_HR_SCHED_CLOCK=y
# CONFIG_HZ_48 is not set
CONFIG_HZ_100=y
# CONFIG_HZ_128 is not set
@@ -185,6 +175,7 @@ CONFIG_PREEMPT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -193,12 +184,21 @@ CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
# CONFIG_AUDIT is not set
@@ -206,37 +206,32 @@ CONFIG_SYSVIPC_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=64
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_GROUP_SCHED is not set
# CONFIG_CGROUPS is not set
# CONFIG_SYSFS_DEPRECATED_V2 is not set
# CONFIG_RELAY is not set
# CONFIG_NAMESPACES is not set
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_RD_GZIP=y
-# CONFIG_RD_BZIP2 is not set
-# CONFIG_RD_LZMA is not set
+# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_KALLSYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_PCSPKR_PLATFORM=y
-CONFIG_BASE_FULL=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_BASE_FULL is not set
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
@@ -244,44 +239,67 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
-CONFIG_VM_EVENT_COUNTERS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_PCI_QUIRKS=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
CONFIG_HAVE_SYSCALL_WRAPPERS=y
-# CONFIG_SLOW_WORK is not set
-# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+
+#
+# GCOV-based kernel profiling
+#
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
-CONFIG_BASE_SMALL=0
+CONFIG_BASE_SMALL=1
CONFIG_MODULES=y
# CONFIG_MODULE_FORCE_LOAD is not set
CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_BLOCK=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_BLK_DEV_INTEGRITY is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-# CONFIG_DEFAULT_AS is not set
-# CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-CONFIG_DEFAULT_NOOP=y
-CONFIG_DEFAULT_IOSCHED="noop"
-# CONFIG_PROBE_INITRD_HEADER is not set
+# CONFIG_BLOCK is not set
+# CONFIG_DEFAULT_NOOP is not set
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_UNLOCK is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_UNLOCK is not set
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_UNLOCK is not set
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
# CONFIG_FREEZER is not set
#
@@ -291,7 +309,6 @@ CONFIG_HW_HAS_PCI=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
# CONFIG_ARCH_SUPPORTS_MSI is not set
-# CONFIG_PCI_LEGACY is not set
# CONFIG_PCI_STUB is not set
# CONFIG_PCI_IOV is not set
CONFIG_MMU=y
@@ -303,7 +320,6 @@ CONFIG_I8253=y
# Executable file formats
#
CONFIG_BINFMT_ELF=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_MIPS32_COMPAT is not set
@@ -311,30 +327,27 @@ CONFIG_BINFMT_ELF=y
#
# Power management options
#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PM is not set
+CONFIG_MIPS_EXTERNAL_TIMER=y
CONFIG_NET=y
#
# Networking options
#
CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_ASK_IP_FIB_HASH is not set
# CONFIG_IP_FIB_TRIE is not set
CONFIG_IP_FIB_HASH=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_MULTIPATH=y
-# CONFIG_IP_ROUTE_VERBOSE is not set
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
@@ -346,21 +359,22 @@ CONFIG_IP_ROUTE_MULTIPATH=y
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
+# CONFIG_INET_DIAG is not set
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
# CONFIG_BRIDGE is not set
-# CONFIG_NET_DSA is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
@@ -371,6 +385,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -383,11 +398,11 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
-CONFIG_FIB_RULES=y
# CONFIG_WIRELESS is not set
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
#
# Device Drivers
@@ -397,6 +412,8 @@ CONFIG_FIB_RULES=y
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_STANDALONE is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
@@ -404,131 +421,31 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
# CONFIG_PARPORT is not set
-CONFIG_BLK_DEV=y
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-# CONFIG_BLK_DEV_HD is not set
# CONFIG_MISC_DEVICES is not set
CONFIG_HAVE_IDE=y
-CONFIG_IDE=y
-
-#
-# Please see Documentation/ide/ide.txt for help/info on IDE drives
-#
-CONFIG_IDE_XFER_MODE=y
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_IDE_GD=y
-CONFIG_IDE_GD_ATA=y
-# CONFIG_IDE_GD_ATAPI is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_PROC_FS is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_BLK_DEV_PLATFORM is not set
-CONFIG_BLK_DEV_IDEDMA_SFF=y
-
-#
-# PCI IDE chipsets support
-#
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_IDEPCI_PCIBUS_ORDER=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_BLK_DEV_GENERIC=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_JMICRON is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-CONFIG_BLK_DEV_PIIX=y
-# CONFIG_BLK_DEV_IT8172 is not set
-# CONFIG_BLK_DEV_IT8213 is not set
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_BLK_DEV_TC86C001 is not set
-CONFIG_BLK_DEV_IDEDMA=y
#
# SCSI device support
#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_DMA=y
-# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_MOD=y
+# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_NETLINK is not set
-# CONFIG_SCSI_PROC_FS is not set
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
+# CONFIG_FUSION is not set
#
-# SCSI Transports
+# IEEE 1394 (FireWire) support
#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-# CONFIG_SCSI_LOWLEVEL is not set
-# CONFIG_SCSI_DH is not set
-# CONFIG_SCSI_OSD_INITIATOR is not set
-# CONFIG_ATA is not set
-# CONFIG_MD is not set
-# CONFIG_FUSION is not set
#
-# IEEE 1394 (FireWire) support
+# You can enable one or both FireWire driver stacks.
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# The newer stack is recommended.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
+# CONFIG_FIREWIRE_NOSY is not set
# CONFIG_I2O is not set
# CONFIG_NETDEVICES is not set
# CONFIG_ISDN is not set
@@ -537,58 +454,21 @@ CONFIG_SCSI_WAIT_SCAN=m
#
# Input device support
#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
+# CONFIG_INPUT is not set
#
# Hardware I/O ports
#
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
#
# Character devices
#
-CONFIG_VT=y
-CONFIG_CONSOLE_TRANSLATIONS=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-CONFIG_DEVKMEM=y
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
# CONFIG_NOZOMI is not set
#
@@ -596,7 +476,7 @@ CONFIG_DEVKMEM=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_PCI=y
+# CONFIG_SERIAL_8250_PCI is not set
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
@@ -604,9 +484,13 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_MFD_HSU is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
@@ -614,16 +498,20 @@ CONFIG_UNIX98_PTYS=y
# CONFIG_HW_RANDOM is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
# CONFIG_WATCHDOG is not set
CONFIG_SSB_POSSIBLE=y
@@ -631,35 +519,15 @@ CONFIG_SSB_POSSIBLE=y
# Sonics Silicon Backplane
#
# CONFIG_SSB is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_SUPPORT is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
#
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
# CONFIG_DRM is not set
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
@@ -700,7 +568,6 @@ CONFIG_FB=y
# CONFIG_FB_S3 is not set
# CONFIG_FB_SAVAGE is not set
# CONFIG_FB_SIS is not set
-# CONFIG_FB_VIA is not set
# CONFIG_FB_NEOMAGIC is not set
# CONFIG_FB_KYRO is not set
# CONFIG_FB_3DFX is not set
@@ -720,31 +587,8 @@ CONFIG_FB=y
# Display device support
#
# CONFIG_DISPLAY_SUPPORT is not set
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-CONFIG_VGACON_SOFT_SCROLLBACK=y
-CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
# CONFIG_LOGO is not set
# CONFIG_SOUND is not set
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
-# CONFIG_HIDRAW is not set
-# CONFIG_HID_PID is not set
-
-#
-# Special HID drivers
-#
# CONFIG_USB_SUPPORT is not set
# CONFIG_UWB is not set
# CONFIG_MMC is not set
@@ -758,26 +602,15 @@ CONFIG_RTC_LIB=y
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
# CONFIG_STAGING is not set
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
#
# File systems
#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_EXT4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
CONFIG_FILE_LOCKING=y
-# CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_BTRFS_FS is not set
-CONFIG_DNOTIFY=y
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
+# CONFIG_FSNOTIFY is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
@@ -789,19 +622,6 @@ CONFIG_INOTIFY_USER=y
# CONFIG_FSCACHE is not set
#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
@@ -811,57 +631,11 @@ CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
# CONFIG_CONFIGFS_FS is not set
-CONFIG_MISC_FILESYSTEMS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_SQUASHFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_OMFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
-# CONFIG_NFS_FS is not set
-# CONFIG_NFSD is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_KARMA_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
# CONFIG_NLS is not set
# CONFIG_DLM is not set
@@ -874,31 +648,29 @@ CONFIG_PRINTK_TIME=y
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_FRAME_WARN=1024
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
# CONFIG_DEBUG_MEMORY_INIT is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_PREEMPT_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
-CONFIG_CMDLINE="console=ttyS0,115200 console=tty0"
+CONFIG_EARLY_PRINTK=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="init=/init"
+# CONFIG_CMDLINE_OVERRIDE is not set
#
# Security options
@@ -906,8 +678,14 @@ CONFIG_CMDLINE="console=ttyS0,115200 console=tty0"
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITYFS is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
# CONFIG_CRYPTO is not set
+
+#
+# OCF Configuration
+#
+# CONFIG_OCF_OCF is not set
# CONFIG_BINARY_PRINTF is not set
#
@@ -922,8 +700,6 @@ CONFIG_GENERIC_FIND_LAST_BIT=y
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
-CONFIG_DECOMPRESS_GZIP=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
diff --git a/target/mips64/patches/io_map_base.patch b/target/mips64/patches/io_map_base.patch
deleted file mode 100644
index be39ffe09..000000000
--- a/target/mips64/patches/io_map_base.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-diff -Nur linux-2.6.28.orig/arch/mips/include/asm/mips-boards/generic.h linux-2.6.28/arch/mips/include/asm/mips-boards/generic.h
---- linux-2.6.28.orig/arch/mips/include/asm/mips-boards/generic.h 2008-12-25 00:26:37.000000000 +0100
-+++ linux-2.6.28/arch/mips/include/asm/mips-boards/generic.h 2009-01-09 23:03:02.000000000 +0100
-@@ -92,7 +92,7 @@
- extern void mips_reboot_setup(void);
-
- #ifdef CONFIG_PCI
--extern void mips_pcibios_init(void);
-+extern int mips_pcibios_init(void);
- #else
- #define mips_pcibios_init() do { } while (0)
- #endif
-diff -Nur linux-2.6.28.orig/arch/mips/mti-malta/malta-pci.c linux-2.6.28/arch/mips/mti-malta/malta-pci.c
---- linux-2.6.28.orig/arch/mips/mti-malta/malta-pci.c 2008-12-25 00:26:37.000000000 +0100
-+++ linux-2.6.28/arch/mips/mti-malta/malta-pci.c 2009-01-09 23:02:02.000000000 +0100
-@@ -87,10 +87,11 @@
- .mem_resource = &msc_mem_resource,
- };
-
--void __init mips_pcibios_init(void)
-+int __init mips_pcibios_init(void)
- {
- struct pci_controller *controller;
- resource_size_t start, end, map, start1, end1, map1, map2, map3, mask;
-+ void __iomem *io_map_base;
-
- switch (mips_revision_sconid) {
- case MIPS_REVISION_SCON_GT64120:
-@@ -230,7 +231,7 @@
- controller = &msc_controller;
- break;
- default:
-- return;
-+ return 0;
- }
-
- if (controller->io_resource->start < 0x00001000UL) /* FIXME */
-@@ -239,5 +240,14 @@
- iomem_resource.end &= 0xfffffffffULL; /* 64 GB */
- ioport_resource.end = controller->io_resource->end;
-
-+ io_map_base = ioremap(MIPS_MSC01_PCI_REG_BASE,
-+ controller->io_resource->end - controller->io_resource->start + 1);
-+ if (!io_map_base)
-+ return -EBUSY;
-+
-+ controller->io_map_base = (unsigned long)io_map_base;
-+
- register_pci_controller(controller);
-+
-+ return 0;
- }
diff --git a/target/mips64/sys-available/qemu-mips64 b/target/mips64/sys-available/qemu-mips64
new file mode 100644
index 000000000..ff61277f1
--- /dev/null
+++ b/target/mips64/sys-available/qemu-mips64
@@ -0,0 +1,14 @@
+config ADK_TARGET_SYSTEM_QEMU_MIPS64
+ bool "Qemu Emulator"
+ select ADK_mips64
+ select ADK_qemu_mips64
+ select ADK_LINUX_64
+ select ADK_KERNEL_MIPS_MALTA
+ select ADK_HARDWARE_QEMU
+ select ADK_TARGET_WITH_VGA
+ select ADK_TARGET_WITH_INPUT
+ select ADK_TARGET_WITH_PCI
+ select ADK_TARGET_WITH_HDD
+ help
+ Qemu support for mips64 big endian architecture.
+
diff --git a/target/mips64/sys-available/toolchain-mips64 b/target/mips64/sys-available/toolchain-mips64
index e06280359..a6932a977 100644
--- a/target/mips64/sys-available/toolchain-mips64
+++ b/target/mips64/sys-available/toolchain-mips64
@@ -3,6 +3,7 @@ config ADK_TARGET_SYSTEM_TOOLCHAIN_MIPS64
select ADK_mips64
select ADK_toolchain_mips64
select ADK_TOOLCHAIN_ONLY
+ select ADK_LINUX_64
help
Build a mips64 big endian toolchain.
diff --git a/target/mips64el/Makefile b/target/mips64el/Makefile
index d9ff26f57..3c4a08f64 100644
--- a/target/mips64el/Makefile
+++ b/target/mips64el/Makefile
@@ -22,7 +22,7 @@ imageinstall: $(BIN_DIR)/$(ROOTFSTARBALL)
@echo "Use following command to create a QEMU Image:"
@echo "sudo ./scripts/create-image.sh -f $(ADK_TARGET_ROOTFS) qemu-${CPU_ARCH}.img $(BIN_DIR)/$(ROOTFSTARBALL)"
@echo "Start qemu with following options:"
- @echo 'qemu-system-mips64el -nographic -M malta -kernel $(BIN_DIR)/${TARGET_KERNEL} -hda qemu-${CPU_ARCH}.img -append "root=/dev/hda1"'
+ @echo 'qemu-system-mips64el -nographic -M malta -kernel $(BIN_DIR)/${TARGET_KERNEL} qemu-${CPU_ARCH}.img'
endif
ifeq ($(ADK_TARGET_FS),initramfs)
imageinstall: $(BIN_DIR)/$(INITRAMFS)
diff --git a/target/mips64el/kernel.config b/target/mips64el/kernel.config
index c2c1ca58a..40a48f745 100644
--- a/target/mips64el/kernel.config
+++ b/target/mips64el/kernel.config
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29.1
-# Sat May 30 13:07:12 2009
+# Linux kernel version: 2.6.36
+# Tue Jan 4 13:47:01 2011
#
CONFIG_MIPS=y
@@ -9,14 +9,17 @@ CONFIG_MIPS=y
# Machine selection
#
CONFIG_ZONE_DMA=y
-# CONFIG_MACH_ALCHEMY is not set
-# CONFIG_BASLER_EXCITE is not set
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_ATHEROS_AR71XX is not set
# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
# CONFIG_LASAT is not set
-# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MACH_LOONGSON is not set
CONFIG_MIPS_MALTA=y
# CONFIG_MIPS_SIM is not set
# CONFIG_NEC_MARKEINS is not set
@@ -27,6 +30,7 @@ CONFIG_MIPS_MALTA=y
# CONFIG_PNX8550_STB810 is not set
# CONFIG_PMC_MSP is not set
# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_POWERTV is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
# CONFIG_SGI_IP28 is not set
@@ -46,6 +50,10 @@ CONFIG_MIPS_MALTA=y
# CONFIG_WR_PPMC is not set
# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_CAVIUM_OCTEON_HELPER=y
+CONFIG_LOONGSON_UART_BASE=y
+# CONFIG_LOONGSON_MC146818 is not set
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
@@ -54,10 +62,9 @@ CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_SCHED_OMIT_FRAME_POINTER=y
-# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_BOOT_RAW=y
CONFIG_CEVT_R4K_LIB=y
@@ -65,52 +72,37 @@ CONFIG_CEVT_R4K=y
CONFIG_CSRC_R4K_LIB=y
CONFIG_CSRC_R4K=y
CONFIG_DMA_NONCOHERENT=y
-CONFIG_DMA_NEED_PCI_MAP_STATE=y
-CONFIG_EARLY_PRINTK=y
+CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
-# CONFIG_HOTPLUG_CPU is not set
CONFIG_I8259=y
CONFIG_MIPS_BONITO64=y
CONFIG_MIPS_MSC=y
+# CONFIG_MIPS_MACHINE is not set
# CONFIG_NO_IOPORT is not set
CONFIG_GENERIC_ISA_DMA=y
+CONFIG_ISA_DMA_API=y
# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
CONFIG_IRQ_CPU=y
CONFIG_IRQ_GIC=y
CONFIG_MIPS_BOARDS_GEN=y
CONFIG_PCI_GT64XXX_PCI0=y
CONFIG_SWAP_IO_SPACE=y
CONFIG_BOOT_ELF32=y
-CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_MIPS_L1_CACHE_SHIFT=6
#
# CPU selection
#
-# CONFIG_CPU_LOONGSON2 is not set
# CONFIG_CPU_MIPS32_R1 is not set
# CONFIG_CPU_MIPS32_R2 is not set
CONFIG_CPU_MIPS64_R1=y
-# CONFIG_CPU_MIPS64_R2 is not set
-# CONFIG_CPU_R3000 is not set
-# CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_VR41XX is not set
-# CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
-# CONFIG_CPU_TX49XX is not set
-# CONFIG_CPU_R5000 is not set
-# CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_R5500 is not set
-# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_NEVADA is not set
-# CONFIG_CPU_R8000 is not set
-# CONFIG_CPU_R10000 is not set
# CONFIG_CPU_RM7000 is not set
-# CONFIG_CPU_RM9000 is not set
-# CONFIG_CPU_SB1 is not set
-# CONFIG_CPU_CAVIUM_OCTEON is not set
+CONFIG_SYS_SUPPORTS_ZBOOT=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_CPU_MIPS64_R1=y
@@ -122,6 +114,7 @@ CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HUGEPAGES=y
CONFIG_HARDWARE_WATCHPOINTS=y
#
@@ -130,7 +123,6 @@ CONFIG_HARDWARE_WATCHPOINTS=y
# CONFIG_32BIT is not set
CONFIG_64BIT=y
CONFIG_PAGE_SIZE_4KB=y
-# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_16KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_BOARD_SCACHE=y
@@ -138,10 +130,10 @@ CONFIG_MIPS_CPU_SCACHE=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMP is not set
-# CONFIG_MIPS_MT_SMTC is not set
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
# CONFIG_MIPS_VPE_LOADER is not set
-CONFIG_CPU_HAS_LLSC=y
+# CONFIG_MIPS_CMP is not set
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
# CONFIG_CPU_HAS_SMARTMIPS is not set
CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
@@ -152,51 +144,60 @@ CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-# CONFIG_UNEVICTABLE_LRU is not set
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_SYS_SUPPORTS_MIPS_CMP=y
# CONFIG_NO_HZ is not set
# CONFIG_HIGH_RES_TIMERS is not set
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_CPU_SUPPORTS_HR_SCHED_CLOCK=y
# CONFIG_HZ_48 is not set
-# CONFIG_HZ_100 is not set
+CONFIG_HZ_100=y
# CONFIG_HZ_128 is not set
-CONFIG_HZ_250=y
+# CONFIG_HZ_250 is not set
# CONFIG_HZ_256 is not set
# CONFIG_HZ_1000 is not set
# CONFIG_HZ_1024 is not set
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_HZ=250
-# CONFIG_PREEMPT_NONE is not set
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
-CONFIG_PREEMPT=y
+# CONFIG_PREEMPT is not set
# CONFIG_KEXEC is not set
# CONFIG_SECCOMP is not set
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
-CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_BZIP2 is not set
+CONFIG_KERNEL_LZMA=y
+# CONFIG_KERNEL_LZO is not set
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
# CONFIG_AUDIT is not set
@@ -204,20 +205,19 @@ CONFIG_SYSVIPC_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_GROUP_SCHED is not set
# CONFIG_CGROUPS is not set
# CONFIG_SYSFS_DEPRECATED_V2 is not set
# CONFIG_RELAY is not set
# CONFIG_NAMESPACES is not set
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
CONFIG_ANON_INODES=y
@@ -228,9 +228,9 @@ CONFIG_KALLSYMS=y
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
-CONFIG_ELF_CORE=y
+# CONFIG_ELF_CORE is not set
# CONFIG_PCSPKR_PLATFORM is not set
-CONFIG_BASE_FULL=y
+# CONFIG_BASE_FULL is not set
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
@@ -238,7 +238,11 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
-CONFIG_VM_EVENT_COUNTERS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_PCI_QUIRKS=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
@@ -246,35 +250,55 @@ CONFIG_SLAB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
CONFIG_HAVE_SYSCALL_WRAPPERS=y
-# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+
+#
+# GCOV-based kernel profiling
+#
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
-CONFIG_BASE_SMALL=0
+CONFIG_BASE_SMALL=1
CONFIG_MODULES=y
# CONFIG_MODULE_FORCE_LOAD is not set
CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_BLOCK=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_BLK_DEV_INTEGRITY is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-# CONFIG_DEFAULT_AS is not set
-# CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-CONFIG_DEFAULT_NOOP=y
-CONFIG_DEFAULT_IOSCHED="noop"
-# CONFIG_PROBE_INITRD_HEADER is not set
+# CONFIG_BLOCK is not set
+# CONFIG_DEFAULT_NOOP is not set
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
# CONFIG_FREEZER is not set
#
@@ -284,8 +308,8 @@ CONFIG_HW_HAS_PCI=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
# CONFIG_ARCH_SUPPORTS_MSI is not set
-# CONFIG_PCI_LEGACY is not set
# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
CONFIG_MMU=y
CONFIG_I8253=y
# CONFIG_PCCARD is not set
@@ -295,7 +319,6 @@ CONFIG_I8253=y
# Executable file formats
#
CONFIG_BINFMT_ELF=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_MIPS32_COMPAT is not set
@@ -303,31 +326,25 @@ CONFIG_BINFMT_ELF=y
#
# Power management options
#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PM is not set
+CONFIG_MIPS_EXTERNAL_TIMER=y
CONFIG_NET=y
#
# Networking options
#
-CONFIG_COMPAT_NET_DEV_OPS=y
CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_ASK_IP_FIB_HASH=y
-# CONFIG_IP_FIB_TRIE is not set
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_MULTIPATH=y
-# CONFIG_IP_ROUTE_VERBOSE is not set
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
@@ -339,21 +356,22 @@ CONFIG_IP_ROUTE_MULTIPATH=y
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
+# CONFIG_INET_DIAG is not set
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
# CONFIG_BRIDGE is not set
-# CONFIG_NET_DSA is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
@@ -363,6 +381,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -375,12 +395,11 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-CONFIG_FIB_RULES=y
# CONFIG_WIRELESS is not set
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
#
# Device Drivers
@@ -390,6 +409,8 @@ CONFIG_FIB_RULES=y
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_STANDALONE is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
@@ -397,129 +418,31 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
# CONFIG_PARPORT is not set
-CONFIG_BLK_DEV=y
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-# CONFIG_BLK_DEV_HD is not set
# CONFIG_MISC_DEVICES is not set
CONFIG_HAVE_IDE=y
-CONFIG_IDE=y
-
-#
-# Please see Documentation/ide/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_IDE_GD=y
-CONFIG_IDE_GD_ATA=y
-# CONFIG_IDE_GD_ATAPI is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_PROC_FS is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_BLK_DEV_PLATFORM is not set
-CONFIG_BLK_DEV_IDEDMA_SFF=y
-
-#
-# PCI IDE chipsets support
-#
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_IDEPCI_PCIBUS_ORDER=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_BLK_DEV_GENERIC=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_JMICRON is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-CONFIG_BLK_DEV_PIIX=y
-# CONFIG_BLK_DEV_IT8172 is not set
-# CONFIG_BLK_DEV_IT8213 is not set
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_BLK_DEV_TC86C001 is not set
-CONFIG_BLK_DEV_IDEDMA=y
#
# SCSI device support
#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_DMA=y
-# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_MOD=y
+# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_NETLINK is not set
-# CONFIG_SCSI_PROC_FS is not set
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
+# CONFIG_FUSION is not set
#
-# SCSI Transports
+# IEEE 1394 (FireWire) support
#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-# CONFIG_SCSI_LOWLEVEL is not set
-# CONFIG_SCSI_DH is not set
-# CONFIG_ATA is not set
-# CONFIG_MD is not set
-# CONFIG_FUSION is not set
#
-# IEEE 1394 (FireWire) support
+# You can enable one or both FireWire driver stacks.
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# The newer stack is recommended.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
+# CONFIG_FIREWIRE_NOSY is not set
# CONFIG_I2O is not set
# CONFIG_NETDEVICES is not set
# CONFIG_ISDN is not set
@@ -528,58 +451,21 @@ CONFIG_SCSI_WAIT_SCAN=m
#
# Input device support
#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_STOWAWAY is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
+# CONFIG_INPUT is not set
#
# Hardware I/O ports
#
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
#
# Character devices
#
-CONFIG_VT=y
-CONFIG_CONSOLE_TRANSLATIONS=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-CONFIG_DEVKMEM=y
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
# CONFIG_NOZOMI is not set
#
@@ -587,7 +473,7 @@ CONFIG_DEVKMEM=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_PCI=y
+# CONFIG_SERIAL_8250_PCI is not set
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
@@ -595,9 +481,13 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_MFD_HSU is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
@@ -605,16 +495,20 @@ CONFIG_UNIX98_PTYS=y
# CONFIG_HW_RANDOM is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
# CONFIG_WATCHDOG is not set
CONFIG_SSB_POSSIBLE=y
@@ -622,140 +516,26 @@ CONFIG_SSB_POSSIBLE=y
# Sonics Silicon Backplane
#
# CONFIG_SSB is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_SUPPORT is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
#
+# CONFIG_VGA_ARB is not set
# CONFIG_DRM is not set
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-CONFIG_FB=y
-# CONFIG_FIRMWARE_EDID is not set
-# CONFIG_FB_DDC is not set
-# CONFIG_FB_BOOT_VESA_SUPPORT is not set
-# CONFIG_FB_CFB_FILLRECT is not set
-# CONFIG_FB_CFB_COPYAREA is not set
-# CONFIG_FB_CFB_IMAGEBLIT is not set
-# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
-# CONFIG_FB_SYS_FILLRECT is not set
-# CONFIG_FB_SYS_COPYAREA is not set
-# CONFIG_FB_SYS_IMAGEBLIT is not set
-# CONFIG_FB_FOREIGN_ENDIAN is not set
-# CONFIG_FB_SYS_FOPS is not set
-# CONFIG_FB_SVGALIB is not set
-# CONFIG_FB_MACMODES is not set
-# CONFIG_FB_BACKLIGHT is not set
-# CONFIG_FB_MODE_HELPERS is not set
-# CONFIG_FB_TILEBLITTING is not set
-
-#
-# Frame buffer hardware drivers
-#
-# CONFIG_FB_CIRRUS is not set
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_ASILIANT is not set
-# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_S1D13XXX is not set
-# CONFIG_FB_NVIDIA is not set
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_MATROX is not set
-# CONFIG_FB_RADEON is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_S3 is not set
-# CONFIG_FB_SAVAGE is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_VIA is not set
-# CONFIG_FB_NEOMAGIC is not set
-# CONFIG_FB_KYRO is not set
-# CONFIG_FB_3DFX is not set
-# CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_VT8623 is not set
-# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_ARK is not set
-# CONFIG_FB_PM3 is not set
-# CONFIG_FB_CARMINE is not set
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FB_METRONOME is not set
-# CONFIG_FB_MB862XX is not set
+# CONFIG_FB is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Display device support
#
# CONFIG_DISPLAY_SUPPORT is not set
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-CONFIG_VGACON_SOFT_SCROLLBACK=y
-CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-# CONFIG_LOGO is not set
# CONFIG_SOUND is not set
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
-# CONFIG_HIDRAW is not set
-# CONFIG_HID_PID is not set
-
-#
-# Special HID drivers
-#
-CONFIG_HID_COMPAT=y
-CONFIG_USB_SUPPORT=y
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB_ARCH_HAS_EHCI=y
-# CONFIG_USB is not set
-# CONFIG_USB_OTG_WHITELIST is not set
-# CONFIG_USB_OTG_BLACKLIST_HUB is not set
-
-#
-# Enable Host or Gadget support to see Inventra options
-#
-
-#
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# OTG and related infrastructure
-#
+# CONFIG_USB_SUPPORT is not set
# CONFIG_UWB is not set
# CONFIG_MMC is not set
# CONFIG_MEMSTICK is not set
@@ -765,45 +545,27 @@ CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_RTC_LIB=y
# CONFIG_RTC_CLASS is not set
# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
# CONFIG_STAGING is not set
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
#
# File systems
#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_EXT4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
CONFIG_FILE_LOCKING=y
-# CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_BTRFS_FS is not set
-CONFIG_DNOTIFY=y
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
+# CONFIG_FSNOTIFY is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_FUSE_FS is not set
#
-# CD-ROM/DVD Filesystems
+# Caches
#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
+# CONFIG_FSCACHE is not set
#
# Pseudo filesystems
@@ -815,56 +577,11 @@ CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
# CONFIG_CONFIGFS_FS is not set
-CONFIG_MISC_FILESYSTEMS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_SQUASHFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_OMFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
-# CONFIG_NFS_FS is not set
-# CONFIG_NFSD is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_KARMA_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
# CONFIG_NLS is not set
# CONFIG_DLM is not set
@@ -872,26 +589,34 @@ CONFIG_MSDOS_PARTITION=y
# Kernel hacking
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-# CONFIG_PRINTK_TIME is not set
+CONFIG_PRINTK_TIME=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_FRAME_WARN=1024
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
# CONFIG_DEBUG_MEMORY_INIT is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_SYSCTL_SYSCALL_CHECK is not set
-
-#
-# Tracers
-#
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
-CONFIG_CMDLINE="console=ttyS0,115200 console=tty0"
+CONFIG_EARLY_PRINTK=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="init=/init"
+# CONFIG_CMDLINE_OVERRIDE is not set
#
# Security options
@@ -899,13 +624,15 @@ CONFIG_CMDLINE="console=ttyS0,115200 console=tty0"
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITYFS is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
# CONFIG_CRYPTO is not set
#
# OCF Configuration
#
# CONFIG_OCF_OCF is not set
+# CONFIG_BINARY_PRINTF is not set
#
# Library routines
@@ -919,7 +646,7 @@ CONFIG_GENERIC_FIND_LAST_BIT=y
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
-CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/target/mips64el/sys-available/lemote-yeelong b/target/mips64el/sys-available/lemote-yeelong
index f19b36140..b1a91491e 100644
--- a/target/mips64el/sys-available/lemote-yeelong
+++ b/target/mips64el/sys-available/lemote-yeelong
@@ -2,6 +2,7 @@ config ADK_TARGET_SYSTEM_LEMOTE_YEELONG
bool "Lemote Yeelong laptop"
select ADK_mips64el
select ADK_lemote_yeelong
+ select ADK_LINUX_64
select ADK_TARGET_WITH_USB_BOOT
select ADK_TARGET_WITH_USB
select ADK_TARGET_WITH_PCI
diff --git a/target/mips64el/sys-available/qemu-mips64el b/target/mips64el/sys-available/qemu-mips64el
new file mode 100644
index 000000000..47818f392
--- /dev/null
+++ b/target/mips64el/sys-available/qemu-mips64el
@@ -0,0 +1,14 @@
+config ADK_TARGET_SYSTEM_QEMU_MIPS64EL
+ bool "Qemu Emulator"
+ select ADK_mips64el
+ select ADK_qemu_mips64el
+ select ADK_LINUX_64
+ select ADK_KERNEL_MIPS_MALTA
+ select ADK_HARDWARE_QEMU
+ select ADK_TARGET_WITH_VGA
+ select ADK_TARGET_WITH_INPUT
+ select ADK_TARGET_WITH_PCI
+ select ADK_TARGET_WITH_HDD
+ help
+ Qemu support for mips64 little endian architecture.
+
diff --git a/target/mips64el/sys-available/toolchain-mips64el b/target/mips64el/sys-available/toolchain-mips64el
index 51ae40951..a403df0cd 100644
--- a/target/mips64el/sys-available/toolchain-mips64el
+++ b/target/mips64el/sys-available/toolchain-mips64el
@@ -3,6 +3,7 @@ config ADK_TARGET_SYSTEM_TOOLCHAIN_MIPS64EL
select ADK_mips64el
select ADK_toolchain_mips64el
select ADK_TOOLCHAIN_ONLY
+ select ADK_LINUX_64
help
Build a mips64 little endian toolchain.
diff --git a/target/mipsel/Makefile b/target/mipsel/Makefile
index d0aa6e5c9..b04bc9011 100644
--- a/target/mipsel/Makefile
+++ b/target/mipsel/Makefile
@@ -5,15 +5,17 @@ include $(TOPDIR)/rules.mk
include $(TOPDIR)/mk/kernel.mk
include $(TOPDIR)/mk/modules.mk
include $(TOPDIR)/mk/kernel-build.mk
+
+ifeq (${ADK_TARGET_SYSTEM_LINKSYS_WRT54G},y)
+CUSTOM_ROOTFSSQUASHFS_BUILD=1
+endif
+
include $(TOPDIR)/mk/image.mk
KERNEL:=$(LINUX_DIR)/vmlinux
OSTRIP:=-R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id
-$(TOOLS_BUILD_DIR):
- @mkdir -p $(TOOLS_BUILD_DIR)
-
-tools-compile: $(TOOLS_BUILD_DIR)
+tools-compile:
$(MAKE) -C ../tools/trx
$(MAKE) -C ../tools/addpattern
$(MAKE) -C ../tools/srec2bin
@@ -21,9 +23,18 @@ tools-compile: $(TOOLS_BUILD_DIR)
ifeq ($(ADK_TARGET_SYSTEM_LINKSYS_WRT54G),y)
kernel-install: tools-compile
- $(TARGET_CROSS)objcopy $(OSTRIP) -S $(LINUX_DIR)/vmlinux \
- $(LINUX_DIR)/vmlinux.stripped
- @gzip -c9 $(LINUX_DIR)/vmlinux.stripped > $(BUILD_DIR)/$(TARGET_KERNEL)
+ ${TARGET_CROSS}objcopy ${OSTRIP} -S ${LINUX_DIR}/vmlinub.elf \
+ ${BUILD_DIR}/${TARGET_KERNEL}
+
+${BUILD_DIR}/${ROOTFSSQUASHFS}: ${BUILD_DIR}/root.squashfs
+ ${TARGET_CROSS}objcopy -O binary ${BUILD_DIR}/${TARGET_KERNEL} \
+ ${BUILD_DIR}/${TARGET_KERNEL}.bin
+ gzip -n9 <${BUILD_DIR}/${TARGET_KERNEL}.bin \
+ >${BUILD_DIR}/${TARGET_KERNEL}.bin.gz
+ printf '\0' >>${BUILD_DIR}/${TARGET_KERNEL}.bin.gz
+ PATH='${TARGET_PATH}' trx -o $@~ ${BUILD_DIR}/${TARGET_KERNEL}.bin.gz \
+ -a 1024 ${BUILD_DIR}/root.squashfs
+ PATH='${TARGET_PATH}' addpattern -4 -p W54G -v v4.20.6 -g -i $@~ -o $@
endif
ifeq ($(ADK_TARGET_SYSTEM_LINKSYS_AG241),y)
@@ -49,7 +60,7 @@ imageinstall: kernel-install $(BIN_DIR)/$(ROOTFSUSERTARBALL)
@echo "If you just want to update, use adkupdate."
endif
ifeq ($(ADK_TARGET_FS),squashfs)
-imageinstall: kernel-install $(BIN_DIR)/$(ROOTFSSQUASHFS)
+imageinstall: kernel-install ${BUILD_DIR}/${ROOTFSSQUASHFS}
@if [ $$(stat -f %z ${BUILD_DIR}/${ROOTFSSQUASHFS}) -gt 3801088 ];then \
echo 'Image is too big!'; \
else \
@@ -74,7 +85,7 @@ ifeq ($(ADK_TARGET_SYSTEM_LINKSYS_AG241),y)
endif
ifeq ($(ADK_TARGET_SYSTEM_LINKSYS_WRT54G),y)
@echo 'Type following on the CFE prompt to boot the kernel:'
- @echo 'CFE> boot -z -elf -tftp 192.168.1.254:$(BIN_DIR)/${TARGET_KERNEL}'
+ @echo 'CFE> boot -elf -tftp 192.168.1.254:$(BIN_DIR)/${TARGET_KERNEL}'
endif
endif
ifeq ($(ADK_TARGET_FS),archive)
diff --git a/target/mipsel/kernel.config b/target/mipsel/kernel.config
index cbb30047f..3f5539b57 100644
--- a/target/mipsel/kernel.config
+++ b/target/mipsel/kernel.config
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.36
-# Tue Dec 21 20:10:13 2010
+# Tue Jan 4 22:23:45 2011
#
CONFIG_MIPS=y
@@ -194,7 +194,8 @@ CONFIG_KERNEL_LZMA=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
# CONFIG_AUDIT is not set
diff --git a/target/mipsel/sys-available/linksys-wrt54g b/target/mipsel/sys-available/linksys-wrt54g
index e4a3fe3e4..4fbc3964f 100644
--- a/target/mipsel/sys-available/linksys-wrt54g
+++ b/target/mipsel/sys-available/linksys-wrt54g
@@ -3,6 +3,7 @@ config ADK_TARGET_SYSTEM_LINKSYS_WRT54G
select ADK_mipsel
select ADK_linksys_wrt54g
select ADK_KERNEL_BCM47XX
+ select ADK_KERNEL_KERNEL_LZMA
select ADK_TARGET_WITH_MTD
select ADK_TARGET_WITH_SSB
select ADK_TARGET_WITH_WATCHDOG
diff --git a/target/tools/squashfs/Makefile b/target/tools/squashfs/Makefile
index 3f22d8a56..cfe4a5339 100644
--- a/target/tools/squashfs/Makefile
+++ b/target/tools/squashfs/Makefile
@@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:= squashfs
PKG_VERSION:= 4.0
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= a3c23391da4ebab0ac4a75021ddabf96
PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=squashfs/}
DISTFILES:= ${PKG_NAME}${PKG_VERSION}.tar.gz
@@ -14,7 +14,7 @@ WRKDIST= ${WRKDIR}/$(PKG_NAME)${PKG_VERSION}
include ../rules.mk
$(WRKBUILD)/.compiled: ${WRKDIST}/.prepared
- $(MAKE) -C $(WRKBUILD)/squashfs-tools
+ ${MAKE} -C ${WRKBUILD}/squashfs-tools CC='${HOSTCC}'
touch $@
${STAGING_HOST_DIR}/bin/mksquashfs: $(WRKBUILD)/.compiled
diff --git a/target/tools/squashfs/patches/honour-cflags.patch b/target/tools/squashfs/patches/honour-cflags.patch
new file mode 100644
index 000000000..2ee7de909
--- /dev/null
+++ b/target/tools/squashfs/patches/honour-cflags.patch
@@ -0,0 +1,11 @@
+--- squashfs4.0/squashfs-tools/Makefile~ Sun Apr 5 02:03:12 2009
++++ squashfs4.0/squashfs-tools/Makefile Fri Jan 7 16:16:46 2011
+@@ -2,7 +2,7 @@ INSTALL_DIR = /usr/local/bin
+
+ INCLUDEDIR = .
+
+-CFLAGS := -I$(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -O2
++CFLAGS := -I$(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -O2 ${HOSTCFLAGS}
+
+ all: mksquashfs unsquashfs
+
diff --git a/target/tools/squashfs/patches/squashfs-bsd.patch b/target/tools/squashfs/patches/squashfs-bsd.patch
index 6e23ed8d6..578b9017f 100644
--- a/target/tools/squashfs/patches/squashfs-bsd.patch
+++ b/target/tools/squashfs/patches/squashfs-bsd.patch
@@ -1,26 +1,14 @@
-diff -Nur squashfs4.0.orig/squashfs-tools/mksquashfs.c squashfs4.0/squashfs-tools/mksquashfs.c
---- squashfs4.0.orig/squashfs-tools/mksquashfs.c Sun Apr 5 23:22:48 2009
-+++ squashfs4.0/squashfs-tools/mksquashfs.c Tue Dec 29 18:23:15 2009
-@@ -48,16 +48,9 @@
- #include <regex.h>
- #include <fnmatch.h>
+--- squashfs4.0~/squashfs-tools/mksquashfs.c Sun Apr 5 21:22:24 2009
++++ squashfs4.0/squashfs-tools/mksquashfs.c Fri Jan 7 20:36:08 2011
+@@ -24,6 +24,7 @@
+ #define FALSE 0
+ #define TRUE 1
--#ifndef linux
--#define __BYTE_ORDER BYTE_ORDER
--#define __BIG_ENDIAN BIG_ENDIAN
--#define __LITTLE_ENDIAN LITTLE_ENDIAN
--#include <sys/sysctl.h>
--#else
--#include <endian.h>
--#include <sys/sysinfo.h>
--#endif
+#include <sys/param.h>
-
-+
- #include "squashfs_fs.h"
- #include "squashfs_swap.h"
- #include "mksquashfs.h"
-@@ -3688,23 +3681,9 @@
+ #include <pwd.h>
+ #include <grp.h>
+ #include <time.h>
+@@ -3688,23 +3689,9 @@ void initialise_threads()
signal(SIGUSR1, sigusr1_handler);
if(processors == -1) {
@@ -46,7 +34,7 @@ diff -Nur squashfs4.0.orig/squashfs-tools/mksquashfs.c squashfs4.0/squashfs-tool
processors = get_nprocs();
#endif
}
-@@ -3974,9 +3953,15 @@
+@@ -3974,9 +3961,15 @@ int excluded(struct pathnames *paths, ch
int match = use_regex ?
regexec(path->name[i].preg, name, (size_t) 0,
NULL, 0) == 0 :
@@ -62,9 +50,36 @@ diff -Nur squashfs4.0.orig/squashfs-tools/mksquashfs.c squashfs4.0/squashfs-tool
if(match && path->name[i].paths == NULL) {
/* match on a leaf component, any subdirectories
-diff -Nur squashfs4.0.orig/squashfs-tools/pseudo.c squashfs4.0/squashfs-tools/pseudo.c
---- squashfs4.0.orig/squashfs-tools/pseudo.c Sun Apr 5 04:01:58 2009
-+++ squashfs4.0/squashfs-tools/pseudo.c Tue Dec 29 18:07:33 2009
+--- squashfs4.0~/squashfs-tools/mksquashfs.h Thu Feb 19 18:30:44 2009
++++ squashfs4.0/squashfs-tools/mksquashfs.h Fri Jan 7 20:40:01 2011
+@@ -24,7 +24,9 @@
+ *
+ */
+
+-#if __BYTE_ORDER == __BIG_ENDIAN
++#ifndef __BYTE_ORDER
++#error Which endianness? __BYTE_ORDER is not defined.
++#elif __BYTE_ORDER == __BIG_ENDIAN
+ #define SQUASHFS_SWAP_SHORTS(s, d, n) swap_le16_num(s, d, n)
+ #define SQUASHFS_SWAP_INTS(s, d, n) swap_le32_num(s, d, n)
+ #define SQUASHFS_SWAP_LONG_LONGS(s, d, n) swap_le64_num(s, d, n)
+@@ -34,11 +36,13 @@
+ #define SWAP_LE64(s, d, field) swap_le64(&((s)->field), &((d)->field))
+ #define SWAP_LES16(s, d, field) swap_le16((unsigned short *) &((s)->field), \
+ (unsigned short *) &((d)->field))
+-#else
++#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ #define SQUASHFS_MEMCPY(s, d, n) memcpy(d, s, n)
+ #define SQUASHFS_SWAP_SHORTS(s, d, n) memcpy(d, s, n * sizeof(short))
+ #define SQUASHFS_SWAP_INTS(s, d, n) memcpy(d, s, n * sizeof(int))
+ #define SQUASHFS_SWAP_LONG_LONGS(s, d, n) \
+ memcpy(d, s, n * sizeof(long long))
++#else
++#error Which endianness (PDP endian? Worse?)
+ #endif
+ #endif
+--- squashfs4.0~/squashfs-tools/pseudo.c Sun Apr 5 02:01:34 2009
++++ squashfs4.0/squashfs-tools/pseudo.c Fri Jan 7 20:35:31 2011
@@ -30,6 +30,11 @@
#include <string.h>
#include <stdlib.h>
@@ -77,9 +92,107 @@ diff -Nur squashfs4.0.orig/squashfs-tools/pseudo.c squashfs4.0/squashfs-tools/ps
#include "pseudo.h"
-diff -Nur squashfs4.0.orig/squashfs-tools/unsquashfs.c squashfs4.0/squashfs-tools/unsquashfs.c
---- squashfs4.0.orig/squashfs-tools/unsquashfs.c Sun Apr 5 23:23:06 2009
-+++ squashfs4.0/squashfs-tools/unsquashfs.c Tue Dec 29 18:25:56 2009
+--- squashfs4.0~/squashfs-tools/read_fs.h Thu Feb 19 18:28:56 2009
++++ squashfs4.0/squashfs-tools/read_fs.h Fri Jan 7 20:40:00 2011
+@@ -24,7 +24,9 @@
+ *
+ */
+
+-#if __BYTE_ORDER == __BIG_ENDIAN
++#ifndef __BYTE_ORDER
++#error Which endianness? __BYTE_ORDER is not defined.
++#elif __BYTE_ORDER == __BIG_ENDIAN
+ #define SQUASHFS_SWAP_SHORTS(d, s, n) swap_le16_num(s, d, n)
+ #define SQUASHFS_SWAP_INTS(d, s, n) swap_le32_num(s, d, n)
+ #define SQUASHFS_SWAP_LONG_LONGS(d, s, n) swap_le64_num(s, d, n)
+@@ -34,11 +36,13 @@
+ #define SWAP_LE64(d, s, field) swap_le64(&((s)->field), &((d)->field))
+ #define SWAP_LES16(d, s, field) swap_le16((unsigned short *) &((s)->field), \
+ (unsigned short *) &((d)->field))
+-#else
++#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ #define SQUASHFS_MEMCPY(d, s, n) memcpy(d, s, n)
+ #define SQUASHFS_SWAP_SHORTS(d, s, n) memcpy(d, s, n * sizeof(short))
+ #define SQUASHFS_SWAP_INTS(d, s, n) memcpy(d, s, n * sizeof(int))
+ #define SQUASHFS_SWAP_LONG_LONGS(d, s, n) \
+ memcpy(d, s, n * sizeof(long long))
++#else
++#error Which endianness (PDP endian? Worse?)
+ #endif
+ #endif
+--- squashfs4.0~/squashfs-tools/squashfs_compat.h Mon Mar 16 04:27:03 2009
++++ squashfs4.0/squashfs-tools/squashfs_compat.h Fri Jan 7 20:39:59 2011
+@@ -768,12 +768,16 @@ typedef union squashfs_inode_header_2 sq
+ * macros used to swap each structure entry, taking into account
+ * bitfields and different bitfield placing conventions on differing architectures
+ */
+-#if __BYTE_ORDER == __BIG_ENDIAN
++#ifndef __BYTE_ORDER
++#error Which endianness? __BYTE_ORDER is not defined.
++#elif __BYTE_ORDER == __BIG_ENDIAN
+ /* convert from big endian to little endian */
+ #define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos)
+-#else
++#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ /* convert from little endian to big endian */
+ #define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos)
++#else
++#error Which endianness (PDP endian? Worse?)
+ #endif
+
+ #define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
+--- squashfs4.0~/squashfs-tools/squashfs_swap.h Fri Feb 20 19:41:56 2009
++++ squashfs4.0/squashfs-tools/squashfs_swap.h Fri Jan 7 20:39:59 2011
+@@ -27,7 +27,9 @@
+ * macros to convert each stucture from big endian to little endian
+ */
+
+-#if __BYTE_ORDER == __BIG_ENDIAN
++#ifndef __BYTE_ORDER
++#error Which endianness? __BYTE_ORDER is not defined.
++#elif __BYTE_ORDER == __BIG_ENDIAN
+ extern void swap_le16(unsigned short *, unsigned short *);
+ extern void swap_le32(unsigned int *, unsigned int *);
+ extern void swap_le64(long long *, long long *);
+@@ -256,7 +258,7 @@ extern void inswap_le64_num(long long *,
+ #define SQUASHFS_INSWAP_SHORTS(s, n) inswap_le16_num(s, n)
+ #define SQUASHFS_INSWAP_INTS(s, n) inswap_le32_num(s, n)
+ #define SQUASHFS_INSWAP_LONG_LONGS(s, n) inswap_le64_num(s, n)
+-#else
++#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ #define SQUASHFS_SWAP_SUPER_BLOCK(s, d) \
+ SQUASHFS_MEMCPY(s, d, sizeof(*(s)))
+ #define SQUASHFS_SWAP_DIR_INDEX(s, d) \
+@@ -308,5 +310,7 @@ extern void inswap_le64_num(long long *,
+ #define SQUASHFS_INSWAP_SHORTS(s, n)
+ #define SQUASHFS_INSWAP_INTS(s, n)
+ #define SQUASHFS_INSWAP_LONG_LONGS(s, n)
++#else
++#error Which endianness (PDP endian? Worse?)
+ #endif
+ #endif
+--- squashfs4.0~/squashfs-tools/swap.c Thu Mar 26 04:39:52 2009
++++ squashfs4.0/squashfs-tools/swap.c Fri Jan 7 20:40:00 2011
+@@ -27,7 +27,9 @@
+ #include <endian.h>
+ #endif
+
+-#if __BYTE_ORDER == __BIG_ENDIAN
++#ifndef __BYTE_ORDER
++#error Which endianness? __BYTE_ORDER is not defined.
++#elif __BYTE_ORDER == __BIG_ENDIAN
+ void swap_le16(unsigned short *src, unsigned short *dest)
+ {
+ unsigned char *s = (unsigned char *) src;
+@@ -120,4 +122,6 @@ void inswap_le##BITS##_num(TYPE *s, int
+ INSWAP_LE_NUM(16, unsigned short)
+ INSWAP_LE_NUM(32, unsigned int)
+ INSWAP_LE_NUM(64, long long)
++#elif __BYTE_ORDER != __LITTLE_ENDIAN
++#error Which endianness (PDP endian? Worse?)
+ #endif
+--- squashfs4.0~/squashfs-tools/unsquashfs.c Sun Apr 5 21:22:42 2009
++++ squashfs4.0/squashfs-tools/unsquashfs.c Fri Jan 7 20:35:31 2011
@@ -21,6 +21,8 @@
* unsquashfs.c
*/
@@ -89,7 +202,7 @@ diff -Nur squashfs4.0.orig/squashfs-tools/unsquashfs.c squashfs4.0/squashfs-tool
#include "unsquashfs.h"
#include "squashfs_swap.h"
#include "squashfs_compat.h"
-@@ -1193,10 +1195,17 @@
+@@ -1193,10 +1195,17 @@ int matches(struct pathnames *paths, cha
struct pathname *path = paths->path[n];
for(i = 0; i < path->names; i++) {
int match = use_regex ?
@@ -107,7 +220,7 @@ diff -Nur squashfs4.0.orig/squashfs-tools/unsquashfs.c squashfs4.0/squashfs-tool
if(match && path->name[i].paths == NULL)
/*
* match on a leaf component, any subdirectories
-@@ -1795,21 +1804,7 @@
+@@ -1795,21 +1804,7 @@ void initialise_threads(int fragment_buf
if(processors == -1) {
#ifndef linux
diff --git a/toolchain/Config.in b/toolchain/Config.in
new file mode 100644
index 000000000..e86e9656f
--- /dev/null
+++ b/toolchain/Config.in
@@ -0,0 +1,45 @@
+menu "Toolchain settings"
+
+config ADK_TOOLCHAIN_GDB
+ prompt "Enable building of the GNU debugger"
+ boolean
+ default y
+
+config ADK_TOOLCHAIN_GCC_CXX
+ prompt "Enable building of G++ (C++ language support in GCC)"
+ boolean
+ default y
+
+config ADK_TOOLCHAIN_GCC_JAVA
+ prompt "Enable building of GCJ (Java language support in GCC)"
+ boolean
+ default n
+
+config ADK_TOOLCHAIN_GCC_OBJC
+ prompt "Enable building of Objective C compiler"
+ boolean
+ default n
+
+config ADK_TOOLCHAIN_GCC_SSP
+ prompt "Enable Stack Smashing Protection in GCC"
+ boolean
+ default n
+
+config ADK_TOOLCHAIN_GCC_USE_SSP
+ prompt "Use SSP for all packages"
+ boolean
+ depends on ADK_TOOLCHAIN_GCC_SSP
+ default n
+
+config ADK_TOOLCHAIN_GCC_LTO
+ prompt "Enable Link Time Optimization in GCC"
+ boolean
+ default n
+
+config ADK_TOOLCHAIN_GCC_USE_LTO
+ prompt "Use Link Time Optimization for all packages"
+ boolean
+ depends on ADK_TOOLCHAIN_GCC_LTO
+ default n
+
+endmenu
diff --git a/toolchain/Makefile b/toolchain/Makefile
index 1e36c6b5f..e3c04a85a 100644
--- a/toolchain/Makefile
+++ b/toolchain/Makefile
@@ -3,7 +3,7 @@
#
# Steps to build toolchains
# 1) build and install binutils
-# 2) build and install mpfr, mpc and gmp
+# 2) build and install mpfr, mpc, libelf and gmp
# 3) build and install gcc c compiler
# 4) install kernel-headers
# 5) install libc headers
@@ -13,7 +13,7 @@
include $(TOPDIR)/rules.mk
-TARGETS:=binutils gmp mpfr mpc gcc
+TARGETS:=binutils gmp mpfr mpc libelf gcc
ifeq ($(ADK_TARGET_LIB_GLIBC),y)
TARGETS+=glibc-ports glibc
LIBC:=glibc
@@ -26,7 +26,9 @@ ifeq ($(ADK_TARGET_LIB_UCLIBC),y)
TARGETS+=uClibc
LIBC:=uClibc
endif
+ifeq ($(ADK_TOOLCHAIN_GDB),y)
TARGETS+=gdb
+endif
DOWNLOAD:=kernel-headers-download $(patsubst %,%-download,$(TARGETS))
TARGETS_INSTALL:=$(patsubst %,%-install,$(TARGETS))
@@ -36,7 +38,7 @@ install: $(TARGETS_INSTALL)
clean: $(TARGETS_CLEAN)
download: $(DOWNLOAD)
-gcc-prepare: binutils-install gmp-install mpfr-install mpc-install
+gcc-prepare: binutils-install gmp-install mpfr-install mpc-install libelf-install
ifeq ($(ADK_TARGET_LIB_GLIBC),y)
$(LIBC)-prepare: gcc-prepare kernel-headers-prepare glibc-ports-prepare
else
@@ -52,14 +54,11 @@ $(STAGING_HOST_DIR):
@mkdir -p $(STAGING_HOST_DIR)/$(REAL_GNU_TARGET_NAME)
@ln -sf ../lib $(STAGING_HOST_DIR)/$(REAL_GNU_TARGET_NAME)/lib
-$(TOOLCHAIN_BUILD_DIR):
- @mkdir -p $(TOOLCHAIN_BUILD_DIR)
-
%-download:
$(TRACE) toolchain/$(patsubst %-download,%,$@)/download
$(MAKE) -C $(patsubst %-download,%,$@) fetch
-%-prepare: $(STAGING_HOST_DIR) $(TOOLCHAIN_BUILD_DIR)
+%-prepare: $(STAGING_HOST_DIR)
$(TRACE) toolchain/$(patsubst %-prepare,%,$@)/prepare
@if test x"$(patsubst %-prepare,%,$@)" = x"$(LIBC)"; then \
$(MAKE) -C $(patsubst %-prepare,%,$@) prepare \
diff --git a/toolchain/binutils/Makefile b/toolchain/binutils/Makefile
index 33f03c7fb..cc8c1b26a 100644
--- a/toolchain/binutils/Makefile
+++ b/toolchain/binutils/Makefile
@@ -6,6 +6,12 @@ include Makefile.inc
include ../rules.mk
include ${TOPDIR}/mk/buildhlp.mk
+ifeq ($(ADK_TOOLCHAIN_GCC_SSP),y)
+CONFOPTS+= --enable-libssp
+else
+CONFOPTS+= --disable-libssp
+endif
+
ifeq ($(ADK_LINUX_64),y)
CONFOPTS+= --enable-64-bit-bfd
endif
@@ -22,14 +28,12 @@ $(WRKBUILD)/.configured:
--build=$(GNU_HOST_NAME) \
--host=$(GNU_HOST_NAME) \
--target=$(REAL_GNU_TARGET_NAME) \
- --disable-nls \
- --with-sysroot=$(TOOLCHAIN_SYSROOT) \
--with-sysroot=$(STAGING_TARGET_DIR) \
--disable-multilib \
--disable-dependency-tracking \
--disable-libtool-lock \
+ --disable-nls \
--disable-werror \
- --disable-libssp \
${CONFOPTS} \
);
touch $@
diff --git a/toolchain/eglibc/Makefile b/toolchain/eglibc/Makefile
index a4d54bb69..c5f2a5653 100644
--- a/toolchain/eglibc/Makefile
+++ b/toolchain/eglibc/Makefile
@@ -4,7 +4,6 @@
include $(TOPDIR)/rules.mk
include ../rules.mk
include Makefile.inc
-
include ${TOPDIR}/mk/buildhlp.mk
ifneq ($(ADK_DEBUG),)
@@ -51,8 +50,8 @@ $(WRKBUILD)/.headers_configure:
(cd $(EGLIBC_BUILD_DIR_INITIAL); \
${EGLIBC_ENV} \
$(WRKBUILD)/libc/configure \
- --prefix=$(TOOLCHAIN_SYSROOT)/usr \
- --with-headers=$(TOOLCHAIN_SYSROOT)/usr/include \
+ --prefix=$(STAGING_TARGET_DIR)/usr \
+ --with-headers=$(STAGING_TARGET_DIR)/usr/include \
${EGLIBC_CONFOPTS} \
);
touch $@
@@ -62,9 +61,15 @@ $(WRKBUILD)/.headers: $(WRKBUILD)/.headers_configure
PATH='${TARGET_PATH}' \
$(MAKE) install-headers install-bootstrap-headers=yes \
);
- touch $(TOOLCHAIN_SYSROOT)/usr/include/gnu/stubs.h
+ touch $(STAGING_TARGET_DIR)/usr/include/gnu/stubs.h
touch $@
+ifeq ($(ADK_TOOLCHAIN_GCC_USE_SSP),y)
+EGLIBC_ENV+= libc_cv_ssp=yes
+else
+EGLIBC_ENV+= libc_cv_ssp=no
+endif
+
$(WRKBUILD)/.configured:
mkdir -p $(EGLIBC_BUILD_DIR_FINAL)
$(CP) ${TOPDIR}/toolchain/eglibc/eglibc.config \
@@ -79,12 +84,16 @@ $(WRKBUILD)/.configured:
);
touch $@
-$(WRKBUILD)/.compiled:
+$(EGLIBC_BUILD_DIR_FINAL)/libc.so:
+$(WRKBUILD)/.compiled: $(WRKBUILD)/.configured
${EGLIBC_ENV} $(MAKE) -C $(EGLIBC_BUILD_DIR_FINAL) all
touch $@
-$(WRKBUILD)/.installed:
+$(WRKBUILD)/.installed: $(EGLIBC_BUILD_DIR_FINAL)/libc.so
${EGLIBC_ENV} $(MAKE) -C $(EGLIBC_BUILD_DIR_FINAL) install_root=$(STAGING_TARGET_DIR) install
+ ${INSTALL_DATA} ${WRKBUILD}/libc/posix/gai.conf ${STAGING_TARGET_DIR}/etc/
+ ${INSTALL_DATA} ${WRKBUILD}/libc/nscd/nscd.conf ${STAGING_TARGET_DIR}/etc/
+ ${INSTALL_DATA} ${WRKBUILD}/libc/nss/nsswitch.conf ${STAGING_TARGET_DIR}/etc/
touch $@
include ${TOPDIR}/mk/toolchain.mk
diff --git a/toolchain/eglibc/Makefile.inc b/toolchain/eglibc/Makefile.inc
index 51fefa6d5..42e80e858 100644
--- a/toolchain/eglibc/Makefile.inc
+++ b/toolchain/eglibc/Makefile.inc
@@ -3,6 +3,6 @@
PKG_NAME:= eglibc
PKG_VERSION:= 2.12.1
-PKG_RELEASE:= 1
+PKG_RELEASE:= 2
PKG_MD5SUM:= 3668505801160785c2961df0a7ec192e
PKG_SITES:= http://openadk.org/distfiles/
diff --git a/toolchain/eglibc/patches/eglibc-cross.patch b/toolchain/eglibc/patches/eglibc-cross.patch
index 384a5c16b..6a7fb9e51 100644
--- a/toolchain/eglibc/patches/eglibc-cross.patch
+++ b/toolchain/eglibc/patches/eglibc-cross.patch
@@ -1,3 +1,5 @@
+* NOTE: This will still use a hardcoded “gcc†instead of HOSTCC
+
diff -Nur eglibc-2.12.orig/libc/sunrpc/proto.h eglibc-2.12/libc/sunrpc/proto.h
--- eglibc-2.12.orig/libc/sunrpc/proto.h 2010-09-28 19:14:26.000000000 +0200
+++ eglibc-2.12/libc/sunrpc/proto.h 2010-09-29 14:05:15.000000000 +0200
diff --git a/toolchain/gcc/Makefile b/toolchain/gcc/Makefile
index 7e806c68c..b1ce84f98 100644
--- a/toolchain/gcc/Makefile
+++ b/toolchain/gcc/Makefile
@@ -11,6 +11,7 @@ GCC_CONFOPTS= --prefix=$(STAGING_HOST_DIR) \
--target=$(REAL_GNU_TARGET_NAME) \
--with-gmp=$(STAGING_HOST_DIR) \
--with-mpfr=$(STAGING_HOST_DIR) \
+ --with-libelf=$(STAGING_HOST_DIR) \
--disable-__cxa_atexit \
--with-gnu-ld \
--disable-libmudflap \
@@ -19,7 +20,6 @@ GCC_CONFOPTS= --prefix=$(STAGING_HOST_DIR) \
--disable-decimal-float \
--disable-multilib \
--disable-sjlj-exceptions \
- --disable-libssp \
--disable-libstdcxx-pch \
--disable-ppl-version-check \
--disable-cloog-version-check \
@@ -27,6 +27,18 @@ GCC_CONFOPTS= --prefix=$(STAGING_HOST_DIR) \
--without-cloog \
--disable-nls
+ifeq ($(ADK_TOOLCHAIN_GCC_SSP),y)
+GCC_CONFOPTS+= --enable-libssp
+else
+GCC_CONFOPTS+= --disable-libssp
+endif
+
+ifeq ($(ADK_TOOLCHAIN_GCC_LTO),y)
+GCC_CONFOPTS+= --enable-lto
+else
+GCC_CONFOPTS+= --disable-lto
+endif
+
ifeq ($(ARCH),cris)
GCC_CONFOPTS+= --disable-tls
else
@@ -55,6 +67,17 @@ ifeq (${ADK_MAKE_PARALLEL},y)
GCC_MAKEOPTS+= -j${ADK_MAKE_JOBS}
endif
+LANGUAGES:=c
+ifeq ($(ADK_TOOLCHAIN_GCC_CXX),y)
+LANGUAGES:=${LANGUAGES},c++
+endif
+ifeq ($(ADK_TOOLCHAIN_GCC_JAVA),y)
+LANGUAGES:=${LANGUAGES},java
+endif
+ifeq ($(ADK_TOOLCHAIN_GCC_ADA),y)
+LANGUAGES:=${LANGUAGES},ada
+endif
+
include ${TOPDIR}/mk/buildhlp.mk
GCC_BUILD_DIR_MINIMAL:= $(WRKBUILD)-minimal
@@ -63,7 +86,12 @@ GCC_BUILD_DIR_FINAL:= $(WRKBUILD)-final
$(GCC_BUILD_DIR_MINIMAL)/.configured:
mkdir -p $(GCC_BUILD_DIR_MINIMAL)
- (cd $(GCC_BUILD_DIR_MINIMAL); rm -f config.cache; \
+ # these symlinks are very important, do not remove
+ rm -rf $(STAGING_HOST_DIR)/$(REAL_GNU_TARGET_NAME)/sys-include
+ ln -sf ${STAGING_TARGET_DIR}/include $(STAGING_HOST_DIR)/$(REAL_GNU_TARGET_NAME)/sys-include
+ rm -rf ${STAGING_HOST_DIR}/$(REAL_GNU_TARGET_NAME)/lib
+ ln -sf ${STAGING_TARGET_DIR}/lib $(STAGING_HOST_DIR)/$(REAL_GNU_TARGET_NAME)/lib
+ (cd $(GCC_BUILD_DIR_MINIMAL); \
PATH='$(TARGET_PATH)' \
$(WRKBUILD)/configure \
${GCC_CONFOPTS} \
@@ -85,12 +113,8 @@ $(WRKBUILD)/.headers: $(GCC_BUILD_DIR_MINIMAL)/.compiled
touch $@
$(GCC_BUILD_DIR_INITIAL)/.configured:
- rm -rf $(STAGING_HOST_DIR)/$(REAL_GNU_TARGET_NAME)/sys-include
- ln -sf ${STAGING_TARGET_DIR}/include $(STAGING_HOST_DIR)/$(REAL_GNU_TARGET_NAME)/sys-include
- rm -rf ${STAGING_HOST_DIR}/$(REAL_GNU_TARGET_NAME)/lib
- ln -sf ${STAGING_TARGET_DIR}/lib $(STAGING_HOST_DIR)/$(REAL_GNU_TARGET_NAME)/lib
mkdir -p $(GCC_BUILD_DIR_INITIAL)
- (cd $(GCC_BUILD_DIR_INITIAL); rm -f config.cache; \
+ (cd $(GCC_BUILD_DIR_INITIAL); \
PATH='$(TARGET_PATH)' \
$(WRKBUILD)/configure \
${GCC_CONFOPTS} \
@@ -98,7 +122,7 @@ $(GCC_BUILD_DIR_INITIAL)/.configured:
--disable-shared \
--disable-threads \
--with-newlib \
- --with-sysroot=$(TOOLCHAIN_SYSROOT) \
+ --with-sysroot=$(STAGING_TARGET_DIR) \
);
touch $@
@@ -115,12 +139,12 @@ $(WRKBUILD)/.configured: $(GCC_BUILD_DIR_INITIAL)/.compiled
$(GCC_BUILD_DIR_FINAL)/.configured:
mkdir -p $(GCC_BUILD_DIR_FINAL)
- (cd $(GCC_BUILD_DIR_FINAL); rm -f config.cache; \
+ (cd $(GCC_BUILD_DIR_FINAL); \
PATH='$(TARGET_PATH)' \
$(WRKBUILD)/configure \
${GCC_CONFOPTS} \
- --enable-languages=c,c++ \
- --with-sysroot=$(STAGING_TARGET_DIR) \
+ --enable-languages=$(LANGUAGES) \
+ --with-sysroot='$${prefix}/${STAGING_HOST2TARGET}' \
--with-slibdir=$(STAGING_TARGET_DIR)/lib \
--enable-shared \
);
@@ -133,9 +157,6 @@ $(WRKBUILD)/.compiled: $(GCC_BUILD_DIR_FINAL)/.configured
$(WRKBUILD)/.installed: $(WRKBUILD)/.compiled
PATH='$(TARGET_PATH)' $(MAKE) -C $(GCC_BUILD_DIR_FINAL) install
- # workaround if you cross-compile binutils
- @-rm $(STAGING_TARGET_DIR)/lib/libiberty.a
- @-rm $(STAGING_TARGET_DIR)/usr/lib/libiberty.a
# Set up the symlinks to enable lying about target name.
set -e; \
(cd $(STAGING_HOST_DIR); \
diff --git a/toolchain/gcc/patches/cflags.patch b/toolchain/gcc/patches/cflags.patch
new file mode 100644
index 000000000..0d5815a54
--- /dev/null
+++ b/toolchain/gcc/patches/cflags.patch
@@ -0,0 +1,253 @@
+
+ This patch brings over a few features from MirBSD:
+ * -fhonour-copts
+ If this option is not given, it's warned (depending
+ on environment variables). This is to catch errors
+ of misbuilt packages which override CFLAGS themselves.
+ * -Werror-maybe-reset
+ Has the effect of -Wno-error if GCC_NO_WERROR is
+ set and not '0', a no-operation otherwise. This is
+ to be able to use -Werror in "make" but prevent
+ GNU autoconf generated configure scripts from
+ freaking out.
+ * Make -fno-strict-aliasing and -fno-delete-null-pointer-checks
+ the default for -O2/-Os, because they trigger gcc bugs
+ and can delete code with security implications.
+
+ This patch was authored by Thorsten Glaser <tg at mirbsd.de>
+ with copyright assignment to the FSF in effect.
+
+--- a/gcc/c-opts.c
++++ b/gcc/c-opts.c
+@@ -105,6 +105,9 @@
+ /* Number of deferred options scanned for -include. */
+ static size_t include_cursor;
+
++/* Check if a port honours COPTS. */
++static int honour_copts = 0;
++
+ static void set_Wimplicit (int);
+ static void handle_OPT_d (const char *);
+ static void set_std_cxx98 (int);
+@@ -454,6 +457,9 @@
+ enable_warning_as_error ("implicit-function-declaration", value, CL_C | CL_ObjC);
+ break;
+
++ case OPT_Werror_maybe_reset:
++ break;
++
+ case OPT_Wformat:
+ set_Wformat (value);
+ break;
+@@ -690,6 +701,12 @@
+ flag_exceptions = value;
+ break;
+
++ case OPT_fhonour_copts:
++ if (c_language == clk_c) {
++ honour_copts++;
++ }
++ break;
++
+ case OPT_fimplement_inlines:
+ flag_implement_inlines = value;
+ break;
+@@ -1209,6 +1226,47 @@
+ return false;
+ }
+
++ if (c_language == clk_c) {
++ char *ev = getenv ("GCC_HONOUR_COPTS");
++ int evv;
++ if (ev == NULL)
++ evv = -1;
++ else if ((*ev == '0') || (*ev == '\0'))
++ evv = 0;
++ else if (*ev == '1')
++ evv = 1;
++ else if (*ev == '2')
++ evv = 2;
++ else if (*ev == 's')
++ evv = -1;
++ else {
++ warning (0, "unknown GCC_HONOUR_COPTS value, assuming 1");
++ evv = 1; /* maybe depend this on something like MIRBSD_NATIVE? */
++ }
++ if (evv == 1) {
++ if (honour_copts == 0) {
++ error ("someone does not honour COPTS at all in lenient mode");
++ return false;
++ } else if (honour_copts != 1) {
++ warning (0, "someone does not honour COPTS correctly, passed %d times",
++ honour_copts);
++ }
++ } else if (evv == 2) {
++ if (honour_copts == 0) {
++ error ("someone does not honour COPTS at all in strict mode");
++ return false;
++ } else if (honour_copts != 1) {
++ error ("someone does not honour COPTS correctly, passed %d times",
++ honour_copts);
++ return false;
++ }
++ } else if (evv == 0) {
++ if (honour_copts != 1)
++ inform (0, "someone does not honour COPTS correctly, passed %d times",
++ honour_copts);
++ }
++ }
++
+ return true;
+ }
+
+--- a/gcc/c.opt
++++ b/gcc/c.opt
+@@ -215,6 +215,10 @@
+ C ObjC RejectNegative Warning
+ This switch is deprecated; use -Werror=implicit-function-declaration instead
+
++Werror-maybe-reset
++C ObjC C++ ObjC++
++; Documented in common.opt
++
+ Wfloat-equal
+ C ObjC C++ ObjC++ Var(warn_float_equal) Warning
+ Warn if testing floating point numbers for equality
+@@ -609,6 +613,9 @@
+ fhonor-std
+ C++ ObjC++
+
++fhonour-copts
++C ObjC C++ ObjC++ RejectNegative
++
+ fhosted
+ C ObjC
+ Assume normal C execution environment
+--- a/gcc/common.opt
++++ b/gcc/common.opt
+@@ -102,6 +102,10 @@
+ Common Joined
+ Treat specified warning as error
+
++Werror-maybe-reset
++Common
++If environment variable GCC_NO_WERROR is set, act as -Wno-error
++
+ Wextra
+ Common Warning
+ Print extra (possibly unwanted) warnings
+@@ -573,6 +577,9 @@
+ Common Report Var(flag_guess_branch_prob) Optimization
+ Enable guessing of branch probabilities
+
++fhonour-copts
++Common RejectNegative
++
+ ; Nonzero means ignore `#ident' directives. 0 means handle them.
+ ; Generate position-independent code for executables if possible
+ ; On SVR4 targets, it also controls whether or not to emit a
+--- a/gcc/opts.c
++++ b/gcc/opts.c
+@@ -896,8 +896,6 @@
+ flag_schedule_insns_after_reload = opt2;
+ #endif
+ flag_regmove = opt2;
+- flag_strict_aliasing = opt2;
+- flag_strict_overflow = opt2;
+ flag_reorder_blocks = opt2;
+ flag_reorder_functions = opt2;
+ flag_tree_vrp = opt2;
+@@ -922,6 +919,8 @@
+
+ /* -O3 optimizations. */
+ opt3 = (optimize >= 3);
++ flag_strict_aliasing = opt3;
++ flag_strict_overflow = opt3;
+ flag_predictive_commoning = opt3;
+ flag_inline_functions = opt3;
+ flag_unswitch_loops = opt3;
+@@ -1601,6 +1601,17 @@
+ enable_warning_as_error (arg, value, lang_mask);
+ break;
+
++ case OPT_Werror_maybe_reset:
++ {
++ char *ev = getenv ("GCC_NO_WERROR");
++ if ((ev != NULL) && (*ev != '0'))
++ warnings_are_errors = 0;
++ }
++ break;
++
++ case OPT_fhonour_copts:
++ break;
++
+ case OPT_Wlarger_than_:
+ /* This form corresponds to -Wlarger-than-.
+ Kept for backward compatibility.
+--- a/gcc/doc/cppopts.texi
++++ b/gcc/doc/cppopts.texi
+@@ -164,6 +164,11 @@
+ Make all warnings into hard errors. Source code which triggers warnings
+ will be rejected.
+
++ at item -Werror-maybe-reset
++ at opindex Werror-maybe-reset
++Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment
++variable is set to anything other than 0 or empty.
++
+ @item -Wsystem-headers
+ @opindex Wsystem-headers
+ Issue warnings for code in system headers. These are normally unhelpful
+--- a/gcc/doc/invoke.texi
++++ b/gcc/doc/invoke.texi
+@@ -234,7 +234,7 @@
+ -Wconversion -Wcoverage-mismatch -Wno-deprecated @gol
+ -Wno-deprecated-declarations -Wdisabled-optimization @gol
+ -Wno-div-by-zero -Wempty-body -Wenum-compare -Wno-endif-labels @gol
+--Werror -Werror=* @gol
++-Werror -Werror=* -Werror-maybe-reset @gol
+ -Wfatal-errors -Wfloat-equal -Wformat -Wformat=2 @gol
+ -Wno-format-contains-nul -Wno-format-extra-args -Wformat-nonliteral @gol
+ -Wformat-security -Wformat-y2k @gol
+@@ -4161,6 +4161,22 @@
+ @option{-Wall} and by @option{-pedantic}, which can be disabled with
+ @option{-Wno-pointer-sign}.
+
++ at item -Werror-maybe-reset
++ at opindex Werror-maybe-reset
++Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment
++variable is set to anything other than 0 or empty.
++
++ at item -fhonour-copts
++ at opindex fhonour-copts
++If @env{GCC_HONOUR_COPTS} is set to 1, abort if this option is not
++given at least once, and warn if it is given more than once.
++If @env{GCC_HONOUR_COPTS} is set to 2, abort if this option is not
++given exactly once.
++If @env{GCC_HONOUR_COPTS} is set to 0 or unset, warn if this option
++is not given exactly once.
++The warning is quelled if @env{GCC_HONOUR_COPTS} is set to @samp{s}.
++This flag and environment variable only affect the C language.
++
+ @item -Wstack-protector
+ @opindex Wstack-protector
+ @opindex Wno-stack-protector
+@@ -5699,7 +5715,7 @@
+ second branch or a point immediately following it, depending on whether
+ the condition is known to be true or false.
+
+-Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
++Enabled at levels @option{-O3}.
+
+ @item -fsplit-wide-types
+ @opindex fsplit-wide-types
+--- a/gcc/java/jvspec.c
++++ b/gcc/java/jvspec.c
+@@ -670,6 +670,7 @@
+ class name. Append dummy `.c' that can be stripped by set_input so %b
+ is correct. */
+ set_input (concat (main_class_name, "main.c", NULL));
++ putenv ("GCC_HONOUR_COPTS=s"); /* XXX hack! */
+ err = do_spec (jvgenmain_spec);
+ if (err == 0)
+ {
diff --git a/toolchain/gdb/Makefile b/toolchain/gdb/Makefile
index bf7c7d457..2025746cf 100644
--- a/toolchain/gdb/Makefile
+++ b/toolchain/gdb/Makefile
@@ -4,7 +4,6 @@
include $(TOPDIR)/rules.mk
include ../rules.mk
include Makefile.inc
-
include ${TOPDIR}/mk/buildhlp.mk
ifeq (${ADK_MAKE_PARALLEL},y)
diff --git a/toolchain/glibc/Makefile b/toolchain/glibc/Makefile
index 4d39e2b27..d492b9837 100644
--- a/toolchain/glibc/Makefile
+++ b/toolchain/glibc/Makefile
@@ -17,6 +17,7 @@ ifeq ($(ADK_TARGET_NO_FPU),y)
GLIBC_CONFOPTS+= --without-fp
endif
+GLIBC_MAKEOPTS+= cross-compiling=yes
ifeq (${ADK_MAKE_PARALLEL},y)
GLIBC_MAKEOPTS+= PARALLELMFLAGS="-j${ADK_MAKE_JOBS}"
endif
@@ -31,21 +32,19 @@ $(WRKBUILD)/.headers_configure:
(cd $(GLIBC_BUILD_DIR_INITIAL); \
${GLIBC_ENV} \
$(WRKBUILD)/configure \
- --prefix=$(TOOLCHAIN_SYSROOT)/usr \
- --with-sysroot=$(TOOLCHAIN_SYSROOT) \
+ --prefix=$(STAGING_TARGET_DIR)/usr \
+ --with-sysroot=$(STAGING_TARGET_DIR) \
${GLIBC_CONFOPTS} \
);
touch $@
$(WRKBUILD)/.headers: $(WRKBUILD)/.headers_configure
- mkdir -p $(TOOLCHAIN_SYSROOT)/usr/lib
(cd $(GLIBC_BUILD_DIR_INITIAL); \
${GLIBC_ENV} \
$(MAKE) ${GLIBC_MAKEOPTS} \
- cross-compiling=yes \
install-headers \
);
- touch $(TOOLCHAIN_SYSROOT)/usr/include/gnu/stubs.h
+ touch $(STAGING_TARGET_DIR)/usr/include/gnu/stubs.h
touch $@
$(WRKBUILD)/.configured:
@@ -67,6 +66,10 @@ $(WRKBUILD)/.compiled:
$(WRKBUILD)/.installed:
${GLIBC_ENV} $(MAKE) -C $(GLIBC_BUILD_DIR_FINAL) \
install_root=$(STAGING_TARGET_DIR) install
+ mkdir -p ${STAGING_TARGET_DIR}/etc
+ ${INSTALL_DATA} ${WRKBUILD}/posix/gai.conf ${STAGING_TARGET_DIR}/etc/
+ ${INSTALL_DATA} ${WRKBUILD}/nscd/nscd.conf ${STAGING_TARGET_DIR}/etc/
+ ${INSTALL_DATA} ${WRKBUILD}/nss/nsswitch.conf ${STAGING_TARGET_DIR}/etc/
touch $(STAGING_TARGET_DIR)/usr/include/gnu/stubs.h
touch $(WRKBUILD)/.installed
diff --git a/toolchain/glibc/Makefile.inc b/toolchain/glibc/Makefile.inc
index ff4753465..79ba89cc2 100644
--- a/toolchain/glibc/Makefile.inc
+++ b/toolchain/glibc/Makefile.inc
@@ -9,7 +9,7 @@ PKG_SITES:= ${MASTER_SITE_GNU:=glibc/}
GLIBC_PORTS_VERSION:= 2.12
GLIBC_CONFOPTS:= --build=$(GNU_HOST_NAME) \
--host=$(REAL_GNU_TARGET_NAME) \
- --with-headers=$(TOOLCHAIN_SYSROOT)/usr/include \
+ --with-headers=$(STAGING_TARGET_DIR)/usr/include \
--disable-nls \
--disable-sanity-checks \
--disable-nls \
@@ -32,3 +32,4 @@ GLIBC_ENV:= PATH='${TARGET_PATH}' \
libc_cv_c_cleanup=yes \
libc_cv_gnu99_inline=yes \
libc_cv_sparc64_tls=yes \
+ libc_cv_slibdir="/lib" \
diff --git a/toolchain/glibc/patches/i686_define_bug.patch b/toolchain/glibc/patches/i686_define_bug.patch
new file mode 100644
index 000000000..0414fecc9
--- /dev/null
+++ b/toolchain/glibc/patches/i686_define_bug.patch
@@ -0,0 +1,38 @@
+ Fix for compiling glibc with -march=i686 specified.
+ The patch below found at: http://permalink.gmane.org/gmane.linux.lfs.devel/9758,
+ a nice discussion (with a comment of the glibc maintainer) can be found here:
+ http://old.nabble.com/-RFC-PATCH--glibc-doesn%27t-build-with-%22gcc--march%3Di686%22-td17442608.html
+
+ To me, this simply shows once more how fucked up things can be. E.g. the (related) bug report here:
+ http://bugs.gentoo.org/show_bug.cgi?id=201815. There are lots of duplicates to it, many people are
+ affected, one can find really elaborate reports. And the responsible gentoo developers are too
+ elite to even point to the actual patch fixing the issue.
+diff -Naur glibc-2.11.1-orig/nptl/sysdeps/pthread/pt-initfini.c glibc-2.11.1/nptl/sysdeps/pthread/pt-initfini.c
+--- glibc-2.11.1-orig/nptl/sysdeps/pthread/pt-initfini.c 2009-12-08 20:10:20.000000000 +0000
++++ glibc-2.11.1/nptl/sysdeps/pthread/pt-initfini.c 2010-04-17 02:24:02.000000000 +0100
+@@ -45,6 +45,11 @@
+ /* Embed an #include to pull in the alignment and .end directives. */
+ asm ("\n#include \"defs.h\"");
+
++asm ("\n#if defined __i686 && defined __ASSEMBLER__");
++asm ("\n#undef __i686");
++asm ("\n#define __i686 __i686");
++asm ("\n#endif");
++
+ /* The initial common code ends here. */
+ asm ("\n/*@HEADER_ENDS*/");
+
+diff -Naur glibc-2.11.1-orig/sysdeps/unix/sysv/linux/i386/sysdep.h glibc-2.11.1/sysdeps/unix/sysv/linux/i386/sysdep.h
+--- glibc-2.11.1-orig/sysdeps/unix/sysv/linux/i386/sysdep.h 2009-12-08 20:10:20.000000000 +0000
++++ glibc-2.11.1/sysdeps/unix/sysv/linux/i386/sysdep.h 2010-04-17 02:24:02.000000000 +0100
+@@ -29,6 +29,10 @@
+ #include <dl-sysdep.h>
+ #include <tls.h>
+
++#if defined __i686 && defined __ASSEMBLER__
++#undef __i686
++#define __i686 __i686
++#endif
+
+ /* For Linux we can use the system call table in the header file
+ /usr/include/asm/unistd.h
diff --git a/toolchain/glibc/patches/tz.patch b/toolchain/glibc/patches/tz.patch
new file mode 100644
index 000000000..990458aa4
--- /dev/null
+++ b/toolchain/glibc/patches/tz.patch
@@ -0,0 +1,135 @@
+--- glibc-2.12.1/timezone/Makefile 2010-07-27 13:34:39.000000000 +0200
++++ glibc-2.12.1.orig/timezone/Makefile 2011-01-10 15:20:02.576150764 +0100
+@@ -69,13 +69,10 @@
+ $(addprefix $(inst_zonedir)/, \
+ $(posixrules-file)))
+
+-ifeq ($(cross-compiling),no)
+-# Don't try to install the zoneinfo files since we can't run zic.
+ install-others = $(addprefix $(inst_zonedir)/,$(zonenames) \
+ $(zonenames:%=posix/%) \
+ $(zonenames:%=right/%)) \
+ $(installed-localtime-file) $(installed-posixrules-file)
+-endif
+
+ ifeq ($(have-ksh),yes)
+ install-others += $(inst_zonedir)/iso3166.tab $(inst_zonedir)/zone.tab
+@@ -106,18 +103,35 @@
+ echo '$$(addprefix $$(inst_zonedir)/,$$($*-zones)): \' ;\
+ echo '$$(foreach t,$$(tzbases),$$(addprefix $$(inst_zonedir)/,$$($$t-zones)))' ;\
+ fi ;\
+- echo '$$(addprefix $$(dir $$(inst_zonedir))zone%/right/,$$($*-zones)): \' ;\
+- echo '$< $$(objpfx)zic leapseconds yearistype' ;\
+- echo ' $$(tzcompile)' ;\
+- echo '$$(addprefix $$(dir $$(inst_zonedir))zone%/posix/,$$($*-zones)): \' ;\
+- echo '$< $$(objpfx)zic /dev/null yearistype' ;\
+- echo ' $$(tzcompile)' ;\
+- echo '$$(addprefix $$(dir $$(inst_zonedir))zone%/,$$($*-zones)): \' ;\
+- echo '$< $$(objpfx)zic $$(leapseconds) yearistype' ;\
+- echo ' $$(tzcompile)' ;\
++ echo '$$(addprefix $$(dir $$(inst_zonedir))zone%/right/,$$($*-zones)): \' ;) > $@.new
++
++ifeq (no,$(cross-compiling))
++ (echo '$< $$(objpfx)zic leapseconds yearistype' ;) >> $@.new
++else
++ (echo '$< $$(objpfx)cross-zic leapseconds yearistype' ;) >> $@.new
++endif
++
++ (echo ' $$(tzcompile)' ;\
++ echo '$$(addprefix $$(dir $$(inst_zonedir))zone%/posix/,$$($*-zones)): \' ;) >> $@.new
++
++ifeq (no,$(cross-compiling))
++ (echo '$< $$(objpfx)zic /dev/null yearistype' ;) >> $@.new
++else
++ (echo '$< $$(objpfx)cross-zic /dev/null yearistype' ;) >> $@.new
++endif
++
++ (echo ' $$(tzcompile)' ;\
++ echo '$$(addprefix $$(dir $$(inst_zonedir))zone%/,$$($*-zones)): \' ;) >> $@.new
++
++ifeq (no,$(cross-compiling))
++ (echo '$< $$(objpfx)zic $$(leapseconds) yearistype' ;) >> $@.new
++else
++ (echo '$< $$(objpfx)cross-zic $$(leapseconds) yearistype' ;) >> $@.new
++endif
++
++ (echo ' $$(tzcompile)' ;\
+ echo 'endif' ;\
+- echo 'zonenames := $$(zonenames) $$($*-zones)' ;\
+- ) > $@.new
++ echo 'zonenames := $$(zonenames) $$($*-zones)' ;) >> $@.new
+ mv $@.new $@
+
+ .PHONY: echo-zonenames
+@@ -128,7 +142,11 @@
+ # We have to use `-d $(inst_zonedir)' to explictly tell zic where to
+ # place the output files although $(zonedir) is compiled in. But the
+ # user might have set $(install_root) on the command line of `make install'.
++ifeq (no,$(cross-compiling))
+ zic-cmd = $(built-program-cmd) -d $(inst_zonedir)
++else
++zic-cmd = $(objpfx)cross-zic -d $(inst_zonedir)
++endif
+ tzcompile = $(zic-cmd)$(target-zone-flavor) -L $(word 3,$^) \
+ -y $(dir $(word 4,$^))$(notdir $(word 4,$^)) $<
+
+@@ -158,8 +176,17 @@
+ $(zic-cmd) -p $(posixrules)
+ endif
+
++zic-objs = zic.o ialloc.o scheck.o
++
++$(objpfx)zic: $(addprefix $(objpfx), $(zic-objs))
++
++$(addprefix $(objpfx)cross-,$(zic-objs)): $(objpfx)cross-%.o: %.c
++ gcc $< -c $(OUTPUT_OPTION) \
++ $(filter-out -DHAVE_GETTEXT,$(CFLAGS-$*.c)) \
++ $(CPPFLAGS-$*) -DCROSS_ZIC $(compile-mkdep-flags)
+
+-$(objpfx)zic: $(objpfx)scheck.o $(objpfx)ialloc.o
++$(objpfx)cross-zic: $(addprefix $(objpfx)cross-,$(zic-objs))
++ gcc $(addprefix $(objpfx)cross-,$(zic-objs)) -o $@
+
+ tz-cflags = -DTZDIR='"$(zonedir)"' \
+ -DTZDEFAULT='"$(localtime-file)"' \
+@@ -176,10 +203,17 @@
+ # Don't add leapseconds here since test-tz made checks that work only without
+ # leapseconds.
+ testdata = $(objpfx)testdata
++ifeq (no,$(cross-compiling))
+ define build-testdata
+ GCONV_PATH=${common-objpfx}iconvdata LANGUAGE=C LC_ALL=C \
+ $(built-program-cmd) -d $(testdata) -y ./yearistype $<
+ endef
++else
++define build-testdata
++LANGUAGE=C LC_ALL=C \
++ $(objpfx)cross-zic -d $(testdata) -y ./yearistype $<
++endef
++endif
+
+ $(objpfx)test-tz.out: $(addprefix $(testdata)/, America/New_York Etc/UTC UTC)
+ $(objpfx)tst-timezone.out: $(addprefix $(testdata)/, \
+@@ -192,7 +226,11 @@
+ tst-timezone-ENV = TZDIR=$(testdata)
+
+ # Note this must come second in the deps list for $(built-program-cmd) to work.
++ifeq (no,$(cross-compiling))
+ zic-deps = $(objpfx)zic $(leapseconds) yearistype
++else
++zic-deps = $(objpfx)cross-zic $(objpfx)zic $(leapseconds) yearistype
++endif
+
+ $(testdata)/America/New_York: northamerica $(zic-deps)
+ $(build-testdata)
+@@ -214,7 +252,9 @@
+
+ $(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make
+ sed -e 's%@KSH@%$(KSH)%g' \
+- -e 's%@TZDIR@%$(zonedir)%g' < $< > $@.new
++ -e 's%@TZDIR@%$(zonedir)%g' \
++ -e 's%@PKGVERSION@%$(PKGVERSION)%g' \
++ -e 's%@REPORT_BUGS_TO@%$(REPORT_BUGS_TO)%g' < $< > $@.new
+ chmod 555 $@.new
+ mv -f $@.new $@
+
diff --git a/toolchain/kernel-headers/Makefile b/toolchain/kernel-headers/Makefile
index 45160fab1..81c2b6593 100644
--- a/toolchain/kernel-headers/Makefile
+++ b/toolchain/kernel-headers/Makefile
@@ -11,9 +11,6 @@ $(WRKBUILD)/.headers:
INSTALL_HDR_PATH=$(STAGING_TARGET_DIR)/usr \
headers_install
$(MAKE) -C $(WRKBUILD) HOSTCC=$(HOSTCC) ARCH=$(ARCH) V=1 \
- INSTALL_HDR_PATH=$(TOOLCHAIN_SYSROOT)/usr \
- headers_install
- $(MAKE) -C $(WRKBUILD) HOSTCC=$(HOSTCC) ARCH=$(ARCH) V=1 \
INSTALL_HDR_PATH=$(LINUX_HEADER_DIR) \
headers_install
# cryptodev.h from ocf-linux-20080917
@@ -22,10 +19,8 @@ $(WRKBUILD)/.headers:
ifeq ($(ARCH),cris)
ifeq ($(CPU_ARCH),crisv32)
cd $(STAGING_TARGET_DIR)/usr/include && ln -sf arch-v32/arch arch
- cd $(TOOLCHAIN_SYSROOT)/usr/include && ln -sf arch-v32/arch arch
else
cd $(STAGING_TARGET_DIR)/usr/include && ln -sf arch-v10/arch arch
- cd $(TOOLCHAIN_SYSROOT)/usr/include && ln -sf arch-v10/arch arch
endif
endif
touch $@
diff --git a/toolchain/kernel-headers/patches/2.6.36/aufs2.patch b/toolchain/kernel-headers/patches/2.6.36/aufs2.patch
new file mode 100644
index 000000000..eafbe6814
--- /dev/null
+++ b/toolchain/kernel-headers/patches/2.6.36/aufs2.patch
@@ -0,0 +1,240 @@
+diff -Nur linux-2.6.36.orig/include/linux/Kbuild linux-2.6.36/include/linux/Kbuild
+--- linux-2.6.36.orig/include/linux/Kbuild 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/include/linux/Kbuild 2011-01-10 19:52:38.000000000 +0100
+@@ -60,6 +60,7 @@
+ header-y += atmsap.h
+ header-y += atmsvc.h
+ header-y += audit.h
++header-y += aufs_type.h
+ header-y += auto_fs.h
+ header-y += auto_fs4.h
+ header-y += auxvec.h
+diff -Nur linux-2.6.36.orig/include/linux/aufs_type.h linux-2.6.36/include/linux/aufs_type.h
+--- linux-2.6.36.orig/include/linux/aufs_type.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/include/linux/aufs_type.h 2011-01-10 19:54:22.000000000 +0100
+@@ -0,0 +1,197 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++#ifndef __AUFS_TYPE_H__
++#define __AUFS_TYPE_H__
++
++#include <linux/ioctl.h>
++#include <linux/kernel.h>
++#include <linux/limits.h>
++#include <linux/types.h>
++
++#define AUFS_VERSION "2.1-standalone.tree-36-20110110"
++
++/* todo? move this to linux-2.6.19/include/magic.h */
++#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_BRANCH_MAX_127
++typedef __s8 aufs_bindex_t;
++#define AUFS_BRANCH_MAX 127
++#else
++typedef __s16 aufs_bindex_t;
++#ifdef CONFIG_AUFS_BRANCH_MAX_511
++#define AUFS_BRANCH_MAX 511
++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023)
++#define AUFS_BRANCH_MAX 1023
++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767)
++#define AUFS_BRANCH_MAX 32767
++#endif
++#endif
++
++#ifdef __KERNEL__
++#ifndef AUFS_BRANCH_MAX
++#error unknown CONFIG_AUFS_BRANCH_MAX value
++#endif
++#endif /* __KERNEL__ */
++
++/* ---------------------------------------------------------------------- */
++
++#define AUFS_NAME "aufs"
++#define AUFS_FSTYPE AUFS_NAME
++
++#define AUFS_ROOT_INO 2
++#define AUFS_FIRST_INO 11
++
++#define AUFS_WH_PFX ".wh."
++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1)
++#define AUFS_WH_TMP_LEN 4
++/* a limit for rmdir/rename a dir */
++#define AUFS_MAX_NAMELEN (NAME_MAX \
++ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\
++ - 1 /* dot */\
++ - AUFS_WH_TMP_LEN) /* hex */
++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino"
++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME
++#define AUFS_XINO_TRUNC_INIT 64 /* blocks */
++#define AUFS_XINO_TRUNC_STEP 4 /* blocks */
++#define AUFS_DIRWH_DEF 3
++#define AUFS_RDCACHE_DEF 10 /* seconds */
++#define AUFS_RDCACHE_MAX 3600 /* seconds */
++#define AUFS_RDBLK_DEF 512 /* bytes */
++#define AUFS_RDHASH_DEF 32
++#define AUFS_WKQ_NAME AUFS_NAME "d"
++#define AUFS_WKQ_PRE_NAME AUFS_WKQ_NAME "_pre"
++#define AUFS_MFS_DEF_SEC 30 /* seconds */
++#define AUFS_MFS_MAX_SEC 3600 /* seconds */
++#define AUFS_PLINK_WARN 100 /* number of plinks */
++
++/* pseudo-link maintenace under /proc */
++#define AUFS_PLINK_MAINT_NAME "plink_maint"
++#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME
++#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME
++
++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */
++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME
++
++#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME
++#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk"
++#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph"
++
++/* doubly whiteouted */
++#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME
++#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME
++#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME
++
++/* branch permission */
++#define AUFS_BRPERM_RW "rw"
++#define AUFS_BRPERM_RO "ro"
++#define AUFS_BRPERM_RR "rr"
++#define AUFS_BRPERM_WH "wh"
++#define AUFS_BRPERM_NLWH "nolwh"
++#define AUFS_BRPERM_ROWH AUFS_BRPERM_RO "+" AUFS_BRPERM_WH
++#define AUFS_BRPERM_RRWH AUFS_BRPERM_RR "+" AUFS_BRPERM_WH
++#define AUFS_BRPERM_RWNLWH AUFS_BRPERM_RW "+" AUFS_BRPERM_NLWH
++
++/* ---------------------------------------------------------------------- */
++
++/* ioctl */
++enum {
++ /* readdir in userspace */
++ AuCtl_RDU,
++ AuCtl_RDU_INO,
++
++ /* pathconf wrapper */
++ AuCtl_WBR_FD
++};
++
++/* borrowed from linux/include/linux/kernel.h */
++#ifndef ALIGN
++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
++#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
++#endif
++
++/* borrowed from linux/include/linux/compiler-gcc3.h */
++#ifndef __aligned
++#define __aligned(x) __attribute__((aligned(x)))
++#define __packed __attribute__((packed))
++#endif
++
++struct au_rdu_cookie {
++ __u64 h_pos;
++ __s16 bindex;
++ __u8 flags;
++ __u8 pad;
++ __u32 generation;
++} __aligned(8);
++
++struct au_rdu_ent {
++ __u64 ino;
++ __s16 bindex;
++ __u8 type;
++ __u8 nlen;
++ __u8 wh;
++ char name[0];
++} __aligned(8);
++
++static inline int au_rdu_len(int nlen)
++{
++ /* include the terminating NULL */
++ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1,
++ sizeof(__u64));
++}
++
++union au_rdu_ent_ul {
++ struct au_rdu_ent __user *e;
++ __u64 ul;
++};
++
++enum {
++ AufsCtlRduV_SZ,
++ AufsCtlRduV_End
++};
++
++struct aufs_rdu {
++ /* input */
++ union {
++ __u64 sz; /* AuCtl_RDU */
++ __u64 nent; /* AuCtl_RDU_INO */
++ };
++ union au_rdu_ent_ul ent;
++ __u16 verify[AufsCtlRduV_End];
++
++ /* input/output */
++ __u32 blk;
++
++ /* output */
++ union au_rdu_ent_ul tail;
++ /* number of entries which were added in a single call */
++ __u64 rent;
++ __u8 full;
++ __u8 shwh;
++
++ struct au_rdu_cookie cookie;
++} __aligned(8);
++
++#define AuCtlType 'A'
++#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu)
++#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu)
++#define AUFS_CTL_WBR_FD _IO(AuCtlType, AuCtl_WBR_FD)
++
++#endif /* __AUFS_TYPE_H__ */
+diff -Nur linux-2.6.36.orig/include/linux/namei.h linux-2.6.36/include/linux/namei.h
+--- linux-2.6.36.orig/include/linux/namei.h 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/include/linux/namei.h 2011-01-10 19:52:38.000000000 +0100
+@@ -73,6 +73,9 @@
+ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
+ int (*open)(struct inode *, struct file *));
+
++extern struct dentry *lookup_hash(struct nameidata *nd);
++extern int __lookup_one_len(const char *name, struct qstr *this,
++ struct dentry *base, int len);
+ extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
+
+ extern int follow_down(struct path *);
+diff -Nur linux-2.6.36.orig/include/linux/splice.h linux-2.6.36/include/linux/splice.h
+--- linux-2.6.36.orig/include/linux/splice.h 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/include/linux/splice.h 2011-01-10 19:52:38.000000000 +0100
+@@ -89,4 +89,10 @@
+ extern void splice_shrink_spd(struct pipe_inode_info *,
+ struct splice_pipe_desc *);
+
++extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags);
++extern long do_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags);
++
+ #endif
+
diff --git a/toolchain/kernel-headers/patches/2.6.37/aufs2.patch b/toolchain/kernel-headers/patches/2.6.37/aufs2.patch
new file mode 100644
index 000000000..eafbe6814
--- /dev/null
+++ b/toolchain/kernel-headers/patches/2.6.37/aufs2.patch
@@ -0,0 +1,240 @@
+diff -Nur linux-2.6.36.orig/include/linux/Kbuild linux-2.6.36/include/linux/Kbuild
+--- linux-2.6.36.orig/include/linux/Kbuild 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/include/linux/Kbuild 2011-01-10 19:52:38.000000000 +0100
+@@ -60,6 +60,7 @@
+ header-y += atmsap.h
+ header-y += atmsvc.h
+ header-y += audit.h
++header-y += aufs_type.h
+ header-y += auto_fs.h
+ header-y += auto_fs4.h
+ header-y += auxvec.h
+diff -Nur linux-2.6.36.orig/include/linux/aufs_type.h linux-2.6.36/include/linux/aufs_type.h
+--- linux-2.6.36.orig/include/linux/aufs_type.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/include/linux/aufs_type.h 2011-01-10 19:54:22.000000000 +0100
+@@ -0,0 +1,197 @@
++/*
++ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ *
++ * This program, aufs 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
++ */
++
++#ifndef __AUFS_TYPE_H__
++#define __AUFS_TYPE_H__
++
++#include <linux/ioctl.h>
++#include <linux/kernel.h>
++#include <linux/limits.h>
++#include <linux/types.h>
++
++#define AUFS_VERSION "2.1-standalone.tree-36-20110110"
++
++/* todo? move this to linux-2.6.19/include/magic.h */
++#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_BRANCH_MAX_127
++typedef __s8 aufs_bindex_t;
++#define AUFS_BRANCH_MAX 127
++#else
++typedef __s16 aufs_bindex_t;
++#ifdef CONFIG_AUFS_BRANCH_MAX_511
++#define AUFS_BRANCH_MAX 511
++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023)
++#define AUFS_BRANCH_MAX 1023
++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767)
++#define AUFS_BRANCH_MAX 32767
++#endif
++#endif
++
++#ifdef __KERNEL__
++#ifndef AUFS_BRANCH_MAX
++#error unknown CONFIG_AUFS_BRANCH_MAX value
++#endif
++#endif /* __KERNEL__ */
++
++/* ---------------------------------------------------------------------- */
++
++#define AUFS_NAME "aufs"
++#define AUFS_FSTYPE AUFS_NAME
++
++#define AUFS_ROOT_INO 2
++#define AUFS_FIRST_INO 11
++
++#define AUFS_WH_PFX ".wh."
++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1)
++#define AUFS_WH_TMP_LEN 4
++/* a limit for rmdir/rename a dir */
++#define AUFS_MAX_NAMELEN (NAME_MAX \
++ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\
++ - 1 /* dot */\
++ - AUFS_WH_TMP_LEN) /* hex */
++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino"
++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME
++#define AUFS_XINO_TRUNC_INIT 64 /* blocks */
++#define AUFS_XINO_TRUNC_STEP 4 /* blocks */
++#define AUFS_DIRWH_DEF 3
++#define AUFS_RDCACHE_DEF 10 /* seconds */
++#define AUFS_RDCACHE_MAX 3600 /* seconds */
++#define AUFS_RDBLK_DEF 512 /* bytes */
++#define AUFS_RDHASH_DEF 32
++#define AUFS_WKQ_NAME AUFS_NAME "d"
++#define AUFS_WKQ_PRE_NAME AUFS_WKQ_NAME "_pre"
++#define AUFS_MFS_DEF_SEC 30 /* seconds */
++#define AUFS_MFS_MAX_SEC 3600 /* seconds */
++#define AUFS_PLINK_WARN 100 /* number of plinks */
++
++/* pseudo-link maintenace under /proc */
++#define AUFS_PLINK_MAINT_NAME "plink_maint"
++#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME
++#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME
++
++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */
++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME
++
++#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME
++#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk"
++#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph"
++
++/* doubly whiteouted */
++#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME
++#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME
++#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME
++
++/* branch permission */
++#define AUFS_BRPERM_RW "rw"
++#define AUFS_BRPERM_RO "ro"
++#define AUFS_BRPERM_RR "rr"
++#define AUFS_BRPERM_WH "wh"
++#define AUFS_BRPERM_NLWH "nolwh"
++#define AUFS_BRPERM_ROWH AUFS_BRPERM_RO "+" AUFS_BRPERM_WH
++#define AUFS_BRPERM_RRWH AUFS_BRPERM_RR "+" AUFS_BRPERM_WH
++#define AUFS_BRPERM_RWNLWH AUFS_BRPERM_RW "+" AUFS_BRPERM_NLWH
++
++/* ---------------------------------------------------------------------- */
++
++/* ioctl */
++enum {
++ /* readdir in userspace */
++ AuCtl_RDU,
++ AuCtl_RDU_INO,
++
++ /* pathconf wrapper */
++ AuCtl_WBR_FD
++};
++
++/* borrowed from linux/include/linux/kernel.h */
++#ifndef ALIGN
++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
++#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
++#endif
++
++/* borrowed from linux/include/linux/compiler-gcc3.h */
++#ifndef __aligned
++#define __aligned(x) __attribute__((aligned(x)))
++#define __packed __attribute__((packed))
++#endif
++
++struct au_rdu_cookie {
++ __u64 h_pos;
++ __s16 bindex;
++ __u8 flags;
++ __u8 pad;
++ __u32 generation;
++} __aligned(8);
++
++struct au_rdu_ent {
++ __u64 ino;
++ __s16 bindex;
++ __u8 type;
++ __u8 nlen;
++ __u8 wh;
++ char name[0];
++} __aligned(8);
++
++static inline int au_rdu_len(int nlen)
++{
++ /* include the terminating NULL */
++ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1,
++ sizeof(__u64));
++}
++
++union au_rdu_ent_ul {
++ struct au_rdu_ent __user *e;
++ __u64 ul;
++};
++
++enum {
++ AufsCtlRduV_SZ,
++ AufsCtlRduV_End
++};
++
++struct aufs_rdu {
++ /* input */
++ union {
++ __u64 sz; /* AuCtl_RDU */
++ __u64 nent; /* AuCtl_RDU_INO */
++ };
++ union au_rdu_ent_ul ent;
++ __u16 verify[AufsCtlRduV_End];
++
++ /* input/output */
++ __u32 blk;
++
++ /* output */
++ union au_rdu_ent_ul tail;
++ /* number of entries which were added in a single call */
++ __u64 rent;
++ __u8 full;
++ __u8 shwh;
++
++ struct au_rdu_cookie cookie;
++} __aligned(8);
++
++#define AuCtlType 'A'
++#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu)
++#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu)
++#define AUFS_CTL_WBR_FD _IO(AuCtlType, AuCtl_WBR_FD)
++
++#endif /* __AUFS_TYPE_H__ */
+diff -Nur linux-2.6.36.orig/include/linux/namei.h linux-2.6.36/include/linux/namei.h
+--- linux-2.6.36.orig/include/linux/namei.h 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/include/linux/namei.h 2011-01-10 19:52:38.000000000 +0100
+@@ -73,6 +73,9 @@
+ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
+ int (*open)(struct inode *, struct file *));
+
++extern struct dentry *lookup_hash(struct nameidata *nd);
++extern int __lookup_one_len(const char *name, struct qstr *this,
++ struct dentry *base, int len);
+ extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
+
+ extern int follow_down(struct path *);
+diff -Nur linux-2.6.36.orig/include/linux/splice.h linux-2.6.36/include/linux/splice.h
+--- linux-2.6.36.orig/include/linux/splice.h 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/include/linux/splice.h 2011-01-10 19:52:38.000000000 +0100
+@@ -89,4 +89,10 @@
+ extern void splice_shrink_spd(struct pipe_inode_info *,
+ struct splice_pipe_desc *);
+
++extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags);
++extern long do_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags);
++
+ #endif
+
diff --git a/toolchain/kernel-headers/patches/2.6.37/cleankernel.patch b/toolchain/kernel-headers/patches/2.6.37/cleankernel.patch
new file mode 100644
index 000000000..f8d5448ee
--- /dev/null
+++ b/toolchain/kernel-headers/patches/2.6.37/cleankernel.patch
@@ -0,0 +1,11 @@
+diff -Nur linux-2.6.29.1.orig/scripts/Makefile.headersinst linux-2.6.29.1/scripts/Makefile.headersinst
+--- linux-2.6.29.1.orig/scripts/Makefile.headersinst 2009-04-02 22:55:27.000000000 +0200
++++ linux-2.6.29.1/scripts/Makefile.headersinst 2009-04-17 20:56:09.143476927 +0200
+@@ -65,7 +65,6 @@
+
+ targets += $(install-file)
+ $(install-file): scripts/headers_install.pl $(input-files) FORCE
+- $(if $(unwanted),$(call cmd,remove),)
+ $(if $(wildcard $(dir $@)),,$(shell mkdir -p $(dir $@)))
+ $(call if_changed,install)
+
diff --git a/toolchain/kernel-headers/patches/2.6.37/etrax-header.patch b/toolchain/kernel-headers/patches/2.6.37/etrax-header.patch
new file mode 100644
index 000000000..0c644ce25
--- /dev/null
+++ b/toolchain/kernel-headers/patches/2.6.37/etrax-header.patch
@@ -0,0 +1,75 @@
+diff -Nur linux-2.6.36.orig/arch/cris/include/arch-v10/arch/Kbuild linux-2.6.36/arch/cris/include/arch-v10/arch/Kbuild
+--- linux-2.6.36.orig/arch/cris/include/arch-v10/arch/Kbuild 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/include/arch-v10/arch/Kbuild 2010-11-15 17:35:24.000000000 +0100
+@@ -1,4 +1,9 @@
++header-y += dma.h
++header-y += io_interface_mux.h
+ header-y += user.h
+ header-y += svinto.h
+ header-y += sv_addr_ag.h
+ header-y += sv_addr.agh
++header-y += elf.h
++header-y += page.h
++header-y += ptrace.h
+diff -Nur linux-2.6.36.orig/arch/cris/include/arch-v32/arch/Kbuild linux-2.6.36/arch/cris/include/arch-v32/arch/Kbuild
+--- linux-2.6.36.orig/arch/cris/include/arch-v32/arch/Kbuild 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/include/arch-v32/arch/Kbuild 2010-11-15 17:35:24.000000000 +0100
+@@ -1,2 +1,6 @@
+ header-y += user.h
+ header-y += cryptocop.h
++header-y += elf.h
++header-y += page.h
++header-y += ptrace.h
++
+diff -Nur linux-2.6.36.orig/arch/cris/include/asm/Kbuild linux-2.6.36/arch/cris/include/asm/Kbuild
+--- linux-2.6.36.orig/arch/cris/include/asm/Kbuild 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/include/asm/Kbuild 2010-11-15 17:37:57.000000000 +0100
+@@ -1,10 +1,13 @@
+ include include/asm-generic/Kbuild.asm
+
+-header-y += arch-v10/
+-header-y += arch-v32/
+-
++header-y += ../arch-v10/arch/
++header-y += ../arch-v32/arch/
++
++header-y += elf.h
+ header-y += ethernet.h
+ header-y += etraxgpio.h
+ header-y += rs485.h
+ header-y += rtc.h
+ header-y += sync_serial.h
++header-y += page.h
++header-y += user.h
+diff -Nur linux-2.6.36.orig/include/asm-generic/Kbuild linux-2.6.36/include/asm-generic/Kbuild
+--- linux-2.6.36.orig/include/asm-generic/Kbuild 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/include/asm-generic/Kbuild 2010-11-15 17:37:02.000000000 +0100
+@@ -3,14 +3,17 @@
+ header-y += errno-base.h
+ header-y += errno.h
+ header-y += fcntl.h
++header-y += getorder.h
+ header-y += int-l64.h
+ header-y += int-ll64.h
+ header-y += ioctl.h
+ header-y += ioctls.h
+ header-y += ipcbuf.h
++header-y += memory_model.h
+ header-y += mman-common.h
+ header-y += mman.h
+ header-y += msgbuf.h
++header-y += page.h
+ header-y += param.h
+ header-y += poll.h
+ header-y += posix_types.h
+diff -Nur linux-2.6.36.orig/include/linux/Kbuild linux-2.6.36/include/linux/Kbuild
+--- linux-2.6.36.orig/include/linux/Kbuild 2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/include/linux/Kbuild 2010-11-15 17:36:11.000000000 +0100
+@@ -365,6 +365,7 @@
+ header-y += un.h
+ header-y += unistd.h
+ header-y += usbdevice_fs.h
++header-y += user.h
+ header-y += utime.h
+ header-y += utsname.h
+ header-y += veth.h
diff --git a/toolchain/kernel-headers/patches/2.6.37/linux-gcc-check.patch b/toolchain/kernel-headers/patches/2.6.37/linux-gcc-check.patch
new file mode 100644
index 000000000..7cc381845
--- /dev/null
+++ b/toolchain/kernel-headers/patches/2.6.37/linux-gcc-check.patch
@@ -0,0 +1,18 @@
+diff -Nur linux-2.6.32.orig/arch/mips/include/asm/sgidefs.h linux-2.6.32/arch/mips/include/asm/sgidefs.h
+--- linux-2.6.32.orig/arch/mips/include/asm/sgidefs.h 2009-12-03 04:51:21.000000000 +0100
++++ linux-2.6.32/arch/mips/include/asm/sgidefs.h 2010-02-14 11:49:21.000000000 +0100
+@@ -11,14 +11,6 @@
+ #define __ASM_SGIDEFS_H
+
+ /*
+- * Using a Linux compiler for building Linux seems logic but not to
+- * everybody.
+- */
+-#ifndef __linux__
+-#error Use a Linux compiler or give up.
+-#endif
+-
+-/*
+ * Definitions for the ISA levels
+ *
+ * With the introduction of MIPS32 / MIPS64 instruction sets definitions
diff --git a/toolchain/kernel-headers/patches/2.6.37/microperl.patch b/toolchain/kernel-headers/patches/2.6.37/microperl.patch
new file mode 100644
index 000000000..2955b7421
--- /dev/null
+++ b/toolchain/kernel-headers/patches/2.6.37/microperl.patch
@@ -0,0 +1,24 @@
+diff -Nur linux-2.6.30.5.orig/scripts/headers_check.pl linux-2.6.30.5/scripts/headers_check.pl
+--- linux-2.6.30.5.orig/scripts/headers_check.pl 2009-08-16 23:19:38.000000000 +0200
++++ linux-2.6.30.5/scripts/headers_check.pl 2009-09-14 21:16:21.000000000 +0200
+@@ -18,7 +18,7 @@
+ #
+ # 3) Check for leaked CONFIG_ symbols
+
+-use strict;
++#use strict;
+
+ my ($dir, $arch, @files) = @ARGV;
+
+diff -Nur linux-2.6.30.5.orig/scripts/headers_install.pl linux-2.6.30.5/scripts/headers_install.pl
+--- linux-2.6.30.5.orig/scripts/headers_install.pl 2009-08-16 23:19:38.000000000 +0200
++++ linux-2.6.30.5/scripts/headers_install.pl 2009-09-14 21:16:11.000000000 +0200
+@@ -16,7 +16,7 @@
+ # 2) Drop include of compiler.h
+ # 3) Drop all sections defined out by __KERNEL__ (using unifdef)
+
+-use strict;
++#use strict;
+
+ my ($readdir, $installdir, $arch, @files) = @ARGV;
+
diff --git a/toolchain/libelf/Makefile b/toolchain/libelf/Makefile
new file mode 100644
index 000000000..485978cf0
--- /dev/null
+++ b/toolchain/libelf/Makefile
@@ -0,0 +1,31 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include $(TOPDIR)/rules.mk
+include Makefile.inc
+include ../rules.mk
+include ${TOPDIR}/mk/buildhlp.mk
+
+ifeq (${ADK_MAKE_PARALLEL},y)
+LIBELF_MAKEOPTS+= -j${ADK_MAKE_JOBS}
+endif
+
+$(WRKBUILD)/.headers:
+$(WRKBUILD)/.configured:
+ (cd $(WRKBUILD); \
+ $(WRKBUILD)/configure \
+ --prefix=$(STAGING_HOST_DIR) \
+ --disable-shared \
+ --enable-static \
+ );
+ touch $@
+
+$(WRKBUILD)/.compiled: $(WRKBUILD)/.configured
+ $(MAKE) ${LIBELF_MAKEOPTS} -C $(WRKBUILD) all
+ touch $@
+
+$(WRKBUILD)/.installed: $(WRKBUILD)/.compiled
+ $(MAKE) -C $(WRKBUILD) install
+ touch $@
+
+include ${TOPDIR}/mk/toolchain.mk
diff --git a/toolchain/libelf/Makefile.inc b/toolchain/libelf/Makefile.inc
new file mode 100644
index 000000000..66ca9fd2c
--- /dev/null
+++ b/toolchain/libelf/Makefile.inc
@@ -0,0 +1,8 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+PKG_NAME:= libelf
+PKG_VERSION:= 0.8.13
+PKG_RELEASE:= 1
+PKG_MD5SUM:= 4136d7b4c04df68b686570afa26988ac
+PKG_SITES:= http://www.mr511.de/software/
diff --git a/toolchain/uClibc/Makefile b/toolchain/uClibc/Makefile
index 194bce39a..6dd77146f 100644
--- a/toolchain/uClibc/Makefile
+++ b/toolchain/uClibc/Makefile
@@ -14,15 +14,28 @@ endif
$(WRKBUILD)/.headers:
$(SED) 's,^CROSS=.*,CROSS=$(TARGET_CROSS),g' $(WRKBUILD)/Rules.mak
- sed -e 's^KERNEL_HEADERS.*$$KERNEL_HEADERS=\"${TOOLCHAIN_SYSROOT}/usr/include\"' \
+ sed -e 's^KERNEL_HEADERS.*$$KERNEL_HEADERS=\"${STAGING_TARGET_DIR}/usr/include\"' \
$(TOPDIR)/target/$(ADK_TARGET_ARCH)/uclibc.config >${WRKBUILD}/.config
ifneq ($(ADK_DEBUG),)
$(SED) 's,DOSTRIP,DODEBUG,' ${WRKBUILD}/.config
endif
+ifeq ($(ADK_TOOLCHAIN_GCC_USE_SSP),y)
+ $(SED) 's,.*UCLIBC_HAS_SSP,UCLIBC_HAS_SSP=y,' ${WRKBUILD}/.config
+ echo "UCLIBC_HAS_SSP_COMPAT=n" >> ${WRKBUILD}/.config
+ echo "SSP_QUICK_CANARY=n" >> ${WRKBUILD}/.config
+ echo "UCLIBC_BUILD_SSP=y" >> ${WRKBUILD}/.config
+endif
+ echo N|$(MAKE) ${UCLIBC_MAKEOPTS} -C $(WRKBUILD) \
+ PREFIX=$(STAGING_TARGET_DIR) \
+ DEVEL_PREFIX=/usr/ \
+ RUNTIME_PREFIX=$(STAGING_TARGET_DIR) \
+ HOSTCC="$(HOSTCC)" \
+ CPU_CFLAGS="$(TARGET_CFLAGS)" \
+ oldconfig
$(MAKE) ${UCLIBC_MAKEOPTS} -C $(WRKBUILD) \
- PREFIX=$(TOOLCHAIN_SYSROOT) \
+ PREFIX=$(STAGING_TARGET_DIR) \
DEVEL_PREFIX=/usr/ \
- RUNTIME_PREFIX=$(TOOLCHAIN_SYSROOT) \
+ RUNTIME_PREFIX=$(STAGING_TARGET_DIR) \
HOSTCC="$(HOSTCC)" \
CPU_CFLAGS="$(TARGET_CFLAGS)" \
install_headers
diff --git a/tools/adk/Makefile b/tools/adk/Makefile
index 02171c99b..638935e5e 100644
--- a/tools/adk/Makefile
+++ b/tools/adk/Makefile
@@ -3,19 +3,17 @@
include $(TOPDIR)/rules.mk
-$(TOPDIR)/bin/tools:
- @mkdir -p $(TOPDIR)/bin/tools
+CCANDLD.c= ${HOSTCC} ${HOSTCFLAGS} ${HOSTCPPFLAGS} ${HOSTLDFLAGS}
-${TOPDIR}/bin/tools/depmaker: $(TOPDIR)/bin/tools
- $(HOSTCC) -o $(TOPDIR)/bin/tools/depmaker depmaker.c
+${TOOLS_DIR}/depmaker:
+ ${CCANDLD.c} -Wall -o $@ depmaker.c
-${TOPDIR}/bin/tools/pkgrebuild: $(TOPDIR)/bin/tools
- $(HOSTCC) -o $(TOPDIR)/bin/tools/pkgrebuild pkgrebuild.c strmap.c
+${TOOLS_DIR}/pkgrebuild:
+ ${CCANDLD.c} -Wall -o $@ pkgrebuild.c strmap.c
-${TOPDIR}/bin/tools/dkgetsz: ${TOPDIR}/bin/tools
- ${HOSTCC} -O2 -Wall -o $@ dkgetsz.c
+${TOOLS_DIR}/dkgetsz:
+ ${CCANDLD.c} -Wall -o $@ dkgetsz.c
-install: ${TOPDIR}/bin/tools/depmaker ${TOPDIR}/bin/tools/pkgrebuild \
- ${TOPDIR}/bin/tools/dkgetsz
+install: ${TOOLS_DIR}/depmaker ${TOOLS_DIR}/pkgrebuild ${TOOLS_DIR}/dkgetsz
include $(TOPDIR)/mk/tools.mk
diff --git a/tools/adk/pkgmaker.c b/tools/adk/pkgmaker.c
index cee3f1420..18465ce18 100644
--- a/tools/adk/pkgmaker.c
+++ b/tools/adk/pkgmaker.c
@@ -1,7 +1,7 @@
/*
* pkgmaker - create package meta-data for OpenADK buildsystem
*
- * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
+ * Copyright (C) 2010,2011 Waldemar Brodkorb <wbx@openadk.org>
*
* 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
@@ -37,10 +37,11 @@
static int nobinpkgs;
-static void fatal_error(const char *message) {
-
- fprintf(stderr, "Fatal error. %s\n", message);
- exit(1);
+#define fatal_error(...) { \
+ fprintf(stderr, "Fatal error. "); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ exit(1); \
}
static int parse_var_hash(char *buf, const char *varname, StrMap *strmap) {
@@ -110,6 +111,53 @@ static int parse_var(char *buf, const char *varname, char *pvalue, char **result
return(1);
}
+static int parse_var_with_pkg(char *buf, const char *varname, char *pvalue, char **result, char **pkgname, int varlen) {
+
+ char *pkg_var, *check;
+ char *key, *value, *string;
+
+ if ((pkg_var = malloc(MAXLINE)) != NULL)
+ memset(pkg_var, 0, MAXLINE);
+ else {
+ perror("Can not allocate memory");
+ exit(EXIT_FAILURE);
+ }
+
+ check = strstr(buf, ":=");
+ if (check != NULL) {
+ string = strstr(buf, varname);
+ if (string != NULL) {
+ string[strlen(string)-1] = '\0';
+ key = strtok(string, ":=");
+ *pkgname = strdup(key+varlen);
+ value = strtok(NULL, "=\t");
+ if (value != NULL) {
+ strncat(pkg_var, value, strlen(value));
+ *result = strdup(pkg_var);
+ }
+ free(pkg_var);
+ return(0);
+ }
+ } else {
+ string = strstr(buf, varname);
+ if (string != NULL) {
+ string[strlen(string)-1] = '\0';
+ key = strtok(string, "+=");
+ value = strtok(NULL, "=\t");
+ if (pvalue != NULL)
+ strncat(pkg_var, pvalue, strlen(pvalue));
+ strncat(pkg_var, " ", 1);
+ if (value != NULL)
+ strncat(pkg_var, value, strlen(value));
+ *result = strdup(pkg_var);
+ free(pkg_var);
+ return(0);
+ }
+ }
+ free(pkg_var);
+ return(1);
+}
+
/*
static void iter_debug(const char *key, const char *value, const void *obj) {
fprintf(stderr, "HASHMAP key: %s value: %s\n", key, value);
@@ -222,6 +270,7 @@ int main() {
char *key, *value, *token, *cftoken, *sp, *hkey, *val, *pkg_fd;
char *pkg_name, *pkg_depends, *pkg_section, *pkg_descr, *pkg_url;
char *pkg_cxx, *pkg_subpkgs, *pkg_cfline, *pkg_dflt, *pkg_multi;
+ char *pkg_need_cxx, *pkg_need_java, *pkgname;
char *pkg_host_depends, *pkg_arch_depends, *pkg_flavours, *pkg_choices, *pseudo_name;
char *packages, *pkg_name_u, *pkgs;
char *saveptr, *p_ptr, *s_ptr;
@@ -242,6 +291,9 @@ int main() {
pkg_dflt = NULL;
pkg_cfline = NULL;
pkg_multi = NULL;
+ pkg_need_cxx = NULL;
+ pkg_need_java = NULL;
+ pkgname = NULL;
p_ptr = NULL;
s_ptr = NULL;
@@ -301,7 +353,8 @@ int main() {
fclose(section);
}
} else
- fatal_error("Can not find section description for package.");
+ fatal_error("Can not find section description for package %s.",
+ pkgdirp->d_name);
fclose(pkg);
continue;
@@ -351,17 +404,21 @@ int main() {
continue;
if ((parse_var(buf, "PKG_CXX", NULL, &pkg_cxx)) == 0)
continue;
+ if ((parse_var(buf, "PKG_NEED_CXX", NULL, &pkg_need_cxx)) == 0)
+ continue;
+ if ((parse_var(buf, "PKG_NEED_JAVA", NULL, &pkg_need_java)) == 0)
+ continue;
if ((parse_var(buf, "PKG_MULTI", NULL, &pkg_multi)) == 0)
continue;
if ((parse_var(buf, "PKG_DEPENDS", pkg_depends, &pkg_depends)) == 0)
continue;
- if ((parse_var(buf, "PKG_FLAVOURS", pkg_flavours, &pkg_flavours)) == 0)
+ if ((parse_var_with_pkg(buf, "PKG_FLAVOURS_", pkg_flavours, &pkg_flavours, &pkgname, 13)) == 0)
continue;
if ((parse_var_hash(buf, "PKGFD_", pkgmap)) == 0)
continue;
if ((parse_var_hash(buf, "PKGFS_", pkgmap)) == 0)
continue;
- if ((parse_var(buf, "PKG_CHOICES", pkg_choices, &pkg_choices)) == 0)
+ if ((parse_var_with_pkg(buf, "PKG_CHOICES_", pkg_choices, &pkg_choices, &pkgname, 12)) == 0)
continue;
if ((parse_var_hash(buf, "PKGCD_", pkgmap)) == 0)
continue;
@@ -393,10 +450,10 @@ int main() {
fprintf(stderr, "Package dependencies are %s\n", pkg_depends);
if (pkg_subpkgs != NULL)
fprintf(stderr, "Package subpackages are %s\n", pkg_subpkgs);
- if (pkg_flavours != NULL)
- fprintf(stderr, "Package flavours are %s\n", pkg_flavours);
- if (pkg_choices != NULL)
- fprintf(stderr, "Package choices are %s\n", pkg_choices);
+ if (pkg_flavours != NULL && pkgname != NULL)
+ fprintf(stderr, "Package flavours for %s are %s\n", pkgname, pkg_flavours);
+ if (pkg_choices != NULL && pkgname != NULL)
+ fprintf(stderr, "Package choices for %s are %s\n", pkgname, pkg_choices);
if (pkg_url != NULL)
fprintf(stderr, "Package homepage is %s\n", pkg_url);
if (pkg_cfline != NULL)
@@ -494,15 +551,19 @@ int main() {
fclose(section);
}
} else
- fatal_error("Can not find section description for package");
+ fatal_error("Can not find section description for package %s.", pkgdirp->d_name);
unlink(path);
cfg = fopen(path, "w");
if (cfg == NULL)
perror("Can not open Config.in file");
+ if (pkg_need_cxx != NULL) {
+ fprintf(cfg, "comment \"%s... %s (disabled, c++ missing)\"\n", token, pkg_descr);
+ fprintf(cfg, "depends on !ADK_TOOLCHAIN_GCC_CXX\n\n");
+ }
fprintf(cfg, "config ADK_PACKAGE_%s\n", toupperstr(token));
- fprintf(cfg, "\tprompt \"%s... %s\"\n", pseudo_name, pkg_descr);
+ fprintf(cfg, "\tprompt \"%s. %s\"\n", pseudo_name, pkg_descr);
fprintf(cfg, "\ttristate\n");
if (pkg_multi != NULL)
if (strncmp(pkg_multi, "1", 1) == 0)
@@ -584,6 +645,14 @@ int main() {
pkg_depends = NULL;
}
+ if (pkg_need_cxx != NULL) {
+ fprintf(cfg, "\tdepends on ADK_TOOLCHAIN_GCC_CXX\n");
+ }
+ if (pkg_need_java != NULL) {
+ fprintf(cfg, "\tdepends on ADK_TOOLCHAIN_GCC_JAVA\n");
+ pkg_need_java = NULL;
+ }
+
fprintf(cfg, "\tselect ADK_COMPILE_%s\n", toupperstr(pkgdirp->d_name));
if (pkg_dflt != NULL) {
@@ -620,9 +689,8 @@ int main() {
if (pkg_flavours != NULL) {
token = strtok(pkg_flavours, " ");
while (token != NULL) {
- fprintf(cfg, "\nconfig ADK_PACKAGE_%s_%s\n", toupperstr(pkgdirp->d_name),
- toupperstr(token));
- fprintf(cfg, "\tbool ");
+ fprintf(cfg, "\nconfig ADK_PACKAGE_%s_%s\n", pkgname, toupperstr(token));
+ fprintf(cfg, "\tboolean ");
strncat(hkey, "PKGFD_", 6);
strncat(hkey, token, strlen(token));
memset(hvalue, 0 , MAXVALUE);
@@ -632,7 +700,7 @@ int main() {
fprintf(cfg, "\"%s\"\n", pkg_fd);
fprintf(cfg, "\tdefault n\n");
- fprintf(cfg, "\tdepends on ADK_PACKAGE_%s\n", toupperstr(pkgdirp->d_name));
+ fprintf(cfg, "\tdepends on ADK_PACKAGE_%s\n", pkgname);
strncat(hkey, "PKGFS_", 6);
strncat(hkey, token, strlen(token));
@@ -657,11 +725,10 @@ int main() {
if (pkg_choices != NULL) {
fprintf(cfg, "\nchoice\n");
fprintf(cfg, "prompt \"Package flavour choice\"\n");
- fprintf(cfg, "depends on ADK_COMPILE_%s\n\n", toupperstr(pkgdirp->d_name));
+ fprintf(cfg, "depends on ADK_PACKAGE_%s\n\n", pkgname);
token = strtok(pkg_choices, " ");
while (token != NULL) {
- fprintf(cfg, "config ADK_PACKAGE_%s_%s\n", toupperstr(pkgdirp->d_name),
- toupperstr(token));
+ fprintf(cfg, "config ADK_PACKAGE_%s_%s\n", pkgname, toupperstr(token));
fprintf(cfg, "\tbool ");
strncat(hkey, "PKGCD_", 6);
@@ -698,6 +765,8 @@ int main() {
free(packages);
packages = NULL;
+ pkg_need_cxx = NULL;
+ pkg_need_java = NULL;
/* reset flags, free memory */
free(pkg_name);
free(pkg_descr);
diff --git a/tools/cpio/Makefile b/tools/cpio/Makefile
index 142f65b70..a012c43a5 100644
--- a/tools/cpio/Makefile
+++ b/tools/cpio/Makefile
@@ -27,9 +27,9 @@ SRCS+= \
src/nonpax.c \
src/cpio.c
-${TOPDIR}/bin/tools/cpio: ${SRCS}
- @${HOSTCC} ${HOSTCFLAGS} -D_GNU_SOURCE -Isrc -o $@ $^
+${TOOLS_DIR}/cpio: ${SRCS}
+ ${HOSTCC} ${HOSTCFLAGS} -D_GNU_SOURCE -Isrc -o $@ $^
-install: ${TOPDIR}/bin/tools/cpio
+install: ${TOOLS_DIR}/cpio
include $(TOPDIR)/mk/tools.mk
diff --git a/tools/mkcrypt/Makefile b/tools/mkcrypt/Makefile
index 4baf56c44..1708f9f13 100644
--- a/tools/mkcrypt/Makefile
+++ b/tools/mkcrypt/Makefile
@@ -3,9 +3,9 @@
include $(TOPDIR)/rules.mk
-${TOPDIR}/bin/tools/mkcrypt:
- $(HOSTCC) -o $(TOPDIR)/bin/tools/mkcrypt mkcrypt.c
+${TOOLS_DIR}/mkcrypt:
+ $(HOSTCC) ${HOSTCFLAGS} -o $@ mkcrypt.c
-install: ${TOPDIR}/bin/tools/mkcrypt
+install: ${TOOLS_DIR}/mkcrypt
include $(TOPDIR)/mk/tools.mk