From ab9968a9e41f2629ed4a16bccf0471d5d6213689 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sat, 23 Jun 2012 16:04:02 +0100 Subject: [PATCH] Initial import --- .gitignore | 2 + busybox/README | 14 + busybox/autobuild | 10 + busybox/build | 10 + busybox/clean | 4 + busybox/config-dev-3 | 438 ++ busybox/config-dongle-2 | 391 ++ busybox/fullclean | 3 + busybox/prepare | 6 + crosstool/README | 5 + crosstool/autobuild | 5 + crosstool/build | 17 + crosstool/clean | 3 + crosstool/fullclean | 4 + .../glibc-2.2.5-allow-gcc-4.0-configure.patch | 22 + crosstool/prepare | 13 + dongle/README | 4 + dongle/autobuild | 4 + dongle/build | 88 + dongle/devtable | 48 + dongle/fullclean | 4 + dongle/prepare | 6 + dongle/tofs/dev/fb | 1 + dongle/tofs/dev/kcore | 1 + dongle/tofs/dev/mouse | 1 + dongle/tofs/dev/ram | 1 + dongle/tofs/dev/ramdisk | 1 + dongle/tofs/dev/stderr | 1 + dongle/tofs/dev/stdin | 1 + dongle/tofs/dev/stdout | 1 + dongle/tofs/etc/fstab | 1 + dongle/tofs/etc/group | 1 + dongle/tofs/etc/hosts | 1 + dongle/tofs/etc/inittab | 2 + dongle/tofs/etc/issue.net | 3 + dongle/tofs/etc/passwd | 1 + dongle/tofs/etc/profile | 13 + dongle/tofs/etc/rcS | 34 + dongle/tofs/lib/modules/2.4.31/av_core.o | Bin 0 -> 245035 bytes dongle/tofs/lib/modules/2.4.31/gfx.o | Bin 0 -> 79461 bytes dongle/tofs/lib/modules/2.4.31/ircombo.o | Bin 0 -> 21590 bytes dongle/tofs/lib/modules/2.4.31/os_core.o | Bin 0 -> 22513 bytes dongle/tofs/lib/modules/2.4.31/osdfb.o | Bin 0 -> 14896 bytes jpeg/README | 6 + jpeg/autobuild | 4 + jpeg/build | 11 + jpeg/clean | 4 + jpeg/fullclean | 3 + jpeg/prepare | 3 + kernel/README | 15 + kernel/autobuild | 10 + kernel/build | 13 + kernel/clean | 4 + kernel/config-dev-5 | 682 +++ kernel/config-dongle-2 | 684 +++ kernel/fullclean | 3 + kernel/otherpatches/Makefile.patch | 14 + kernel/otherpatches/bash4_correction.patch | 17 + kernel/otherpatches/dongle_version.h | 21 + kernel/otherpatches/fullduplex.patch | 38 + kernel/otherpatches/ppcfix.patch | 31 + kernel/patch | 12 + kernel/patches-2.4.31/architecture.patch | 24 + kernel/patches-2.4.31/clockfix.patch | 13 + kernel/patches-2.4.31/kexec-ppc-2.4.patch | 1685 ++++++ kernel/patches-2.4.31/memsize.patch | 26 + kernel/patches-2.4.31/mvp-version.patch | 43 + kernel/patches-2.4.31/ppc405-wdt.patch | 360 ++ kernel/patches-2.4.31/redwood.c | 499 ++ kernel/patches-2.4.31/sdram-bank1.patch | 266 + kernel/patches-2.4.31/smc91111.patch | 4500 +++++++++++++++++ kernel/prepare | 7 + lbox_border/README | 3 + lbox_border/autobuild | 4 + lbox_border/build | 7 + lbox_border/clean | 3 + lbox_border/lbox_border.c | 55 + makedevenv | 144 + 78 files changed, 10379 insertions(+) create mode 100644 .gitignore create mode 100644 busybox/README create mode 100755 busybox/autobuild create mode 100755 busybox/build create mode 100644 busybox/clean create mode 100644 busybox/config-dev-3 create mode 100644 busybox/config-dongle-2 create mode 100755 busybox/fullclean create mode 100755 busybox/prepare create mode 100644 crosstool/README create mode 100755 crosstool/autobuild create mode 100755 crosstool/build create mode 100755 crosstool/clean create mode 100755 crosstool/fullclean create mode 100644 crosstool/glibc-2.2.5-allow-gcc-4.0-configure.patch create mode 100755 crosstool/prepare create mode 100644 dongle/README create mode 100755 dongle/autobuild create mode 100755 dongle/build create mode 100644 dongle/devtable create mode 100755 dongle/fullclean create mode 100755 dongle/prepare create mode 120000 dongle/tofs/dev/fb create mode 120000 dongle/tofs/dev/kcore create mode 120000 dongle/tofs/dev/mouse create mode 120000 dongle/tofs/dev/ram create mode 120000 dongle/tofs/dev/ramdisk create mode 120000 dongle/tofs/dev/stderr create mode 120000 dongle/tofs/dev/stdin create mode 120000 dongle/tofs/dev/stdout create mode 100644 dongle/tofs/etc/fstab create mode 100644 dongle/tofs/etc/group create mode 100644 dongle/tofs/etc/hosts create mode 100644 dongle/tofs/etc/inittab create mode 100644 dongle/tofs/etc/issue.net create mode 100644 dongle/tofs/etc/passwd create mode 100644 dongle/tofs/etc/profile create mode 100755 dongle/tofs/etc/rcS create mode 100644 dongle/tofs/lib/modules/2.4.31/av_core.o create mode 100644 dongle/tofs/lib/modules/2.4.31/gfx.o create mode 100644 dongle/tofs/lib/modules/2.4.31/ircombo.o create mode 100644 dongle/tofs/lib/modules/2.4.31/os_core.o create mode 100644 dongle/tofs/lib/modules/2.4.31/osdfb.o create mode 100644 jpeg/README create mode 100755 jpeg/autobuild create mode 100755 jpeg/build create mode 100755 jpeg/clean create mode 100755 jpeg/fullclean create mode 100755 jpeg/prepare create mode 100644 kernel/README create mode 100755 kernel/autobuild create mode 100755 kernel/build create mode 100755 kernel/clean create mode 100644 kernel/config-dev-5 create mode 100644 kernel/config-dongle-2 create mode 100755 kernel/fullclean create mode 100644 kernel/otherpatches/Makefile.patch create mode 100644 kernel/otherpatches/bash4_correction.patch create mode 100644 kernel/otherpatches/dongle_version.h create mode 100644 kernel/otherpatches/fullduplex.patch create mode 100644 kernel/otherpatches/ppcfix.patch create mode 100755 kernel/patch create mode 100644 kernel/patches-2.4.31/architecture.patch create mode 100644 kernel/patches-2.4.31/clockfix.patch create mode 100644 kernel/patches-2.4.31/kexec-ppc-2.4.patch create mode 100644 kernel/patches-2.4.31/memsize.patch create mode 100644 kernel/patches-2.4.31/mvp-version.patch create mode 100644 kernel/patches-2.4.31/ppc405-wdt.patch create mode 100644 kernel/patches-2.4.31/redwood.c create mode 100644 kernel/patches-2.4.31/sdram-bank1.patch create mode 100644 kernel/patches-2.4.31/smc91111.patch create mode 100755 kernel/prepare create mode 100644 lbox_border/README create mode 100755 lbox_border/autobuild create mode 100755 lbox_border/build create mode 100755 lbox_border/clean create mode 100644 lbox_border/lbox_border.c create mode 100755 makedevenv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a868cc5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +client +packages diff --git a/busybox/README b/busybox/README new file mode 100644 index 0000000..923dd42 --- /dev/null +++ b/busybox/README @@ -0,0 +1,14 @@ +$1 argument to scripts that have it should be dev or dongle, see autobuild +for examples. + +autobuild - does full clean then full build +prepare $1 - unpacks busybox tree into $1 dir + only to be used after fullclean (or just un-tarred package) +build $1 $2 - work with busybox under $1 dir. copy config file $2 to busybox + and compile it + only to be used on a cleaned busybox tree +clean $1 - runs make distclean on busybox tree in dir $1 + makes it ready for build +fullclean - removes busybox trees in order to start from scratch + + diff --git a/busybox/autobuild b/busybox/autobuild new file mode 100755 index 0000000..7b708f2 --- /dev/null +++ b/busybox/autobuild @@ -0,0 +1,10 @@ +#!/bin/bash + +./fullclean + +./prepare dev +./prepare dongle + +./build dev config-dev-3 +./build dongle config-dongle-2 + diff --git a/busybox/build b/busybox/build new file mode 100755 index 0000000..4f81d59 --- /dev/null +++ b/busybox/build @@ -0,0 +1,10 @@ +#!/bin/bash + +. ../crosstool/cross-var + +cd $1/busybox-1.00 + +cp ../../$2 .config +make CROSS=${CROSS} +make CROSS=${CROSS} install + diff --git a/busybox/clean b/busybox/clean new file mode 100644 index 0000000..4c42a1c --- /dev/null +++ b/busybox/clean @@ -0,0 +1,4 @@ +#!/bin/bash + +cd $1/busybox-1.00 +make distclean diff --git a/busybox/config-dev-3 b/busybox/config-dev-3 new file mode 100644 index 0000000..9badda3 --- /dev/null +++ b/busybox/config-dev-3 @@ -0,0 +1,438 @@ +# +# Automatically generated make config: don't edit +# +HAVE_DOT_CONFIG=y + +# +# General Configuration +# +# CONFIG_FEATURE_BUFFERS_USE_MALLOC is not set +CONFIG_FEATURE_BUFFERS_GO_ON_STACK=y +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +# CONFIG_FEATURE_VERBOSE_USAGE is not set +# CONFIG_FEATURE_INSTALLER is not set +# CONFIG_LOCALE_SUPPORT is not set +# CONFIG_FEATURE_DEVFS is not set +# CONFIG_FEATURE_DEVPTS is not set +# CONFIG_FEATURE_CLEAN_UP is not set +CONFIG_FEATURE_SUID=y +CONFIG_FEATURE_SUID_CONFIG=y +# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set +# CONFIG_SELINUX is not set + +# +# Build Options +# +CONFIG_STATIC=y +# CONFIG_LFS is not set +USING_CROSS_COMPILER=y +CROSS_COMPILER_PREFIX="/opt/crosstool/powerpc-405-linux-gnu/gcc-2.95.3-glibc-2.2.5/bin/powerpc-405-linux-gnu-" +EXTRA_CFLAGS_OPTIONS="" + +# +# Installation Options +# +# CONFIG_INSTALL_NO_USR is not set +PREFIX="../install" + +# +# Archival Utilities +# +# CONFIG_AR is not set +# CONFIG_BUNZIP2 is not set +# CONFIG_CPIO is not set +# CONFIG_DPKG is not set +# CONFIG_DPKG_DEB is not set +CONFIG_GUNZIP=y +# CONFIG_FEATURE_GUNZIP_UNCOMPRESS is not set +CONFIG_GZIP=y +# CONFIG_RPM2CPIO is not set +# CONFIG_RPM is not set +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +# CONFIG_FEATURE_TAR_BZIP2 is not set +# CONFIG_FEATURE_TAR_FROM is not set +CONFIG_FEATURE_TAR_GZIP=y +# CONFIG_FEATURE_TAR_COMPRESS is not set +# CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY is not set +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set +# CONFIG_UNCOMPRESS is not set +# CONFIG_UNZIP is not set + +# +# Common options for cpio and tar +# +# CONFIG_FEATURE_UNARCHIVE_TAPE is not set + +# +# Coreutils +# +CONFIG_BASENAME=y +# CONFIG_CAL is not set +CONFIG_CAT=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +CONFIG_CHROOT=y +# CONFIG_CMP is not set +CONFIG_CP=y +CONFIG_CUT=y +CONFIG_DATE=y + +# +# date (forced enabled for use with watch) +# +CONFIG_FEATURE_DATE_ISOFMT=y +CONFIG_DD=y +CONFIG_DF=y +CONFIG_DIRNAME=y +# CONFIG_DOS2UNIX is not set +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +# CONFIG_EXPR is not set +CONFIG_FALSE=y +# CONFIG_FOLD is not set +CONFIG_HEAD=y +# CONFIG_FEATURE_FANCY_HEAD is not set +# CONFIG_HOSTID is not set +CONFIG_ID=y +# CONFIG_INSTALL is not set +# CONFIG_LENGTH is not set +CONFIG_LN=y +# CONFIG_LOGNAME is not set +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +# CONFIG_FEATURE_LS_RECURSIVE is not set +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +CONFIG_FEATURE_LS_COLOR=y +# CONFIG_MD5SUM is not set +CONFIG_MKDIR=y +# CONFIG_MKFIFO is not set +CONFIG_MKNOD=y +CONFIG_MV=y +# CONFIG_OD is not set +# CONFIG_PRINTF is not set +CONFIG_PWD=y +# CONFIG_REALPATH is not set +CONFIG_RM=y +CONFIG_RMDIR=y +# CONFIG_SEQ is not set +# CONFIG_SHA1SUM is not set +CONFIG_SLEEP=y +# CONFIG_FEATURE_FANCY_SLEEP is not set +CONFIG_SORT=y +# CONFIG_STTY is not set +CONFIG_SYNC=y +CONFIG_TAIL=y +# CONFIG_FEATURE_FANCY_TAIL is not set +# CONFIG_TEE is not set +CONFIG_TEST=y + +# +# test (forced enabled for use with shell) +# +# CONFIG_FEATURE_TEST_64 is not set +CONFIG_TOUCH=y +# CONFIG_TR is not set +CONFIG_TRUE=y +CONFIG_TTY=y +CONFIG_UNAME=y +CONFIG_UNIQ=y +# CONFIG_USLEEP is not set +# CONFIG_UUDECODE is not set +# CONFIG_UUENCODE is not set +CONFIG_WATCH=y +# CONFIG_WC is not set +# CONFIG_WHO is not set +CONFIG_WHOAMI=y +CONFIG_YES=y + +# +# Common options for cp and mv +# +# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set + +# +# Common options for ls and more +# +CONFIG_FEATURE_AUTOWIDTH=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Console Utilities +# +# CONFIG_CHVT is not set +CONFIG_CLEAR=y +# CONFIG_DEALLOCVT is not set +# CONFIG_DUMPKMAP is not set +# CONFIG_LOADFONT is not set +# CONFIG_LOADKMAP is not set +# CONFIG_OPENVT is not set +CONFIG_RESET=y +# CONFIG_SETKEYCODES is not set + +# +# Debian Utilities +# +# CONFIG_MKTEMP is not set +# CONFIG_PIPE_PROGRESS is not set +# CONFIG_READLINK is not set +# CONFIG_RUN_PARTS is not set +# CONFIG_START_STOP_DAEMON is not set +CONFIG_WHICH=y + +# +# Editors +# +# CONFIG_AWK is not set +# CONFIG_PATCH is not set +CONFIG_SED=y +CONFIG_VI=y +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y + +# +# Finding Utilities +# +CONFIG_FIND=y +# CONFIG_FEATURE_FIND_MTIME is not set +# CONFIG_FEATURE_FIND_PERM is not set +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_XDEV=y +CONFIG_FEATURE_FIND_NEWER=y +CONFIG_FEATURE_FIND_INUM=y +CONFIG_GREP=y +# CONFIG_FEATURE_GREP_EGREP_ALIAS is not set +CONFIG_FEATURE_GREP_FGREP_ALIAS=y +# CONFIG_FEATURE_GREP_CONTEXT is not set +# CONFIG_XARGS is not set + +# +# Init Utilities +# +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +# CONFIG_FEATURE_INITRD is not set +# CONFIG_FEATURE_INIT_COREDUMPS is not set +# CONFIG_FEATURE_EXTRA_QUIET is not set +# CONFIG_HALT is not set +# CONFIG_POWEROFF is not set +CONFIG_REBOOT=y +# CONFIG_MESG is not set + +# +# Login/Password Management Utilities +# +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_ADDGROUP is not set +# CONFIG_DELGROUP is not set +# CONFIG_ADDUSER is not set +# CONFIG_DELUSER is not set +# CONFIG_GETTY is not set +# CONFIG_FEATURE_U_W_TMP is not set +CONFIG_LOGIN=y +CONFIG_FEATURE_SECURETTY=y +# CONFIG_PASSWD is not set +# CONFIG_SU is not set +# CONFIG_SULOGIN is not set +# CONFIG_VLOCK is not set + +# +# Common options for adduser, deluser, login, su +# +# CONFIG_FEATURE_SHADOWPASSWDS is not set + +# +# Miscellaneous Utilities +# +# CONFIG_ADJTIMEX is not set +# CONFIG_CROND is not set +# CONFIG_CRONTAB is not set +# CONFIG_DC is not set +# CONFIG_DEVFSD is not set +# CONFIG_LAST is not set +# CONFIG_HDPARM is not set +# CONFIG_MAKEDEVS is not set +# CONFIG_MT is not set +# CONFIG_RX is not set +# CONFIG_STRINGS is not set +# CONFIG_TIME is not set +# CONFIG_WATCHDOG is not set + +# +# Linux Module Utilities +# +CONFIG_INSMOD=y +CONFIG_FEATURE_2_4_MODULES=y +# CONFIG_FEATURE_2_6_MODULES is not set +CONFIG_FEATURE_INSMOD_VERSION_CHECKING=y +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +CONFIG_LSMOD=y +CONFIG_FEATURE_QUERY_MODULE_INTERFACE=y +CONFIG_MODPROBE=y +CONFIG_RMMOD=y +CONFIG_FEATURE_CHECK_TAINTED_MODULE=y + +# +# Networking Utilities +# +# CONFIG_FEATURE_IPV6 is not set +# CONFIG_ARPING is not set +CONFIG_FTPGET=y +CONFIG_FTPPUT=y +CONFIG_HOSTNAME=y +# CONFIG_HTTPD is not set +CONFIG_IFCONFIG=y +CONFIG_FEATURE_IFCONFIG_STATUS=y +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set +CONFIG_FEATURE_IFCONFIG_HW=y +# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set +# CONFIG_IFUPDOWN is not set +# CONFIG_INETD is not set +# CONFIG_IP is not set +# CONFIG_IPCALC is not set +# CONFIG_IPADDR is not set +# CONFIG_IPLINK is not set +# CONFIG_IPROUTE is not set +# CONFIG_IPTUNNEL is not set +# CONFIG_NAMEIF is not set +# CONFIG_NC is not set +CONFIG_NETSTAT=y +CONFIG_NSLOOKUP=y +CONFIG_PING=y +CONFIG_FEATURE_FANCY_PING=y +CONFIG_ROUTE=y +# CONFIG_TELNET is not set +CONFIG_TELNETD=y +# CONFIG_FEATURE_TELNETD_INETD is not set +# CONFIG_TFTP is not set +# CONFIG_TRACEROUTE is not set +# CONFIG_VCONFIG is not set +# CONFIG_WGET is not set + +# +# udhcp Server/Client +# +# CONFIG_UDHCPD is not set +# CONFIG_UDHCPC is not set + +# +# Process Utilities +# +CONFIG_FREE=y +CONFIG_KILL=y +CONFIG_KILLALL=y +# CONFIG_PIDOF is not set +CONFIG_PS=y +# CONFIG_RENICE is not set +CONFIG_TOP=y +FEATURE_CPU_USAGE_PERCENTAGE=y +CONFIG_UPTIME=y +# CONFIG_SYSCTL is not set + +# +# Another Bourne-like Shell +# +CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_FEATURE_SH_IS_HUSH is not set +# CONFIG_FEATURE_SH_IS_LASH is not set +# CONFIG_FEATURE_SH_IS_MSH is not set +# CONFIG_FEATURE_SH_IS_NONE is not set +CONFIG_ASH=y + +# +# Ash Shell Options +# +CONFIG_ASH_JOB_CONTROL=y +CONFIG_ASH_ALIAS=y +CONFIG_ASH_MATH_SUPPORT=y +# CONFIG_ASH_MATH_SUPPORT_64 is not set +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_CMDCMD is not set +# CONFIG_ASH_MAIL is not set +CONFIG_ASH_OPTIMIZE_FOR_SIZE=y +# CONFIG_ASH_RANDOM_SUPPORT is not set +# CONFIG_HUSH is not set +# CONFIG_LASH is not set +# CONFIG_MSH is not set + +# +# Bourne Shell Options +# +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set +# CONFIG_FEATURE_SH_STANDALONE_SHELL is not set +CONFIG_FEATURE_COMMAND_EDITING=y +CONFIG_FEATURE_COMMAND_HISTORY=15 +# CONFIG_FEATURE_COMMAND_SAVEHISTORY is not set +CONFIG_FEATURE_COMMAND_TAB_COMPLETION=y +# CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION is not set +CONFIG_FEATURE_SH_FANCY_PROMPT=y + +# +# System Logging Utilities +# +CONFIG_SYSLOGD=y +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set +# CONFIG_FEATURE_IPC_SYSLOG is not set +CONFIG_KLOGD=y +CONFIG_LOGGER=y + +# +# Linux System Utilities +# +CONFIG_DMESG=y +# CONFIG_FBSET is not set +# CONFIG_FDFLUSH is not set +# CONFIG_FDFORMAT is not set +# CONFIG_FDISK is not set +# CONFIG_FREERAMDISK is not set +# CONFIG_FSCK_MINIX is not set +# CONFIG_MKFS_MINIX is not set +# CONFIG_GETOPT is not set +# CONFIG_HEXDUMP is not set +# CONFIG_HWCLOCK is not set +# CONFIG_LOSETUP is not set +# CONFIG_MKSWAP is not set +CONFIG_MORE=y +CONFIG_FEATURE_USE_TERMIOS=y +# CONFIG_PIVOT_ROOT is not set +# CONFIG_RDATE is not set +# CONFIG_SWAPONOFF is not set +CONFIG_MOUNT=y +CONFIG_NFSMOUNT=y +CONFIG_UMOUNT=y +# CONFIG_FEATURE_MOUNT_FORCE is not set + +# +# Common options for mount/umount +# +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set + +# +# Debugging Options +# +# CONFIG_DEBUG is not set diff --git a/busybox/config-dongle-2 b/busybox/config-dongle-2 new file mode 100644 index 0000000..e1f26b3 --- /dev/null +++ b/busybox/config-dongle-2 @@ -0,0 +1,391 @@ +# +# Automatically generated make config: don't edit +# +HAVE_DOT_CONFIG=y + +# +# General Configuration +# +# CONFIG_FEATURE_BUFFERS_USE_MALLOC is not set +CONFIG_FEATURE_BUFFERS_GO_ON_STACK=y +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +# CONFIG_FEATURE_VERBOSE_USAGE is not set +# CONFIG_FEATURE_INSTALLER is not set +# CONFIG_LOCALE_SUPPORT is not set +# CONFIG_FEATURE_DEVFS is not set +# CONFIG_FEATURE_DEVPTS is not set +# CONFIG_FEATURE_CLEAN_UP is not set +CONFIG_FEATURE_SUID=y +CONFIG_FEATURE_SUID_CONFIG=y +CONFIG_FEATURE_SUID_CONFIG_QUIET=y +# CONFIG_SELINUX is not set + +# +# Build Options +# +CONFIG_STATIC=y +# CONFIG_LFS is not set +USING_CROSS_COMPILER=y +CROSS_COMPILER_PREFIX="/opt/crosstool/powerpc-405-linux-gnu/gcc-2.95.3-glibc-2.2.5/bin/powerpc-405-linux-gnu-" +EXTRA_CFLAGS_OPTIONS="" + +# +# Installation Options +# +# CONFIG_INSTALL_NO_USR is not set +PREFIX="../install" + +# +# Archival Utilities +# +# CONFIG_AR is not set +# CONFIG_BUNZIP2 is not set +# CONFIG_CPIO is not set +# CONFIG_DPKG is not set +# CONFIG_DPKG_DEB is not set +# CONFIG_GUNZIP is not set +# CONFIG_GZIP is not set +# CONFIG_RPM2CPIO is not set +# CONFIG_RPM is not set +# CONFIG_TAR is not set +# CONFIG_UNCOMPRESS is not set +# CONFIG_UNZIP is not set + +# +# Coreutils +# +# CONFIG_BASENAME is not set +# CONFIG_CAL is not set +CONFIG_CAT=y +# CONFIG_CHGRP is not set +# CONFIG_CHMOD is not set +# CONFIG_CHOWN is not set +# CONFIG_CHROOT is not set +# CONFIG_CMP is not set +# CONFIG_CP is not set +# CONFIG_CUT is not set +CONFIG_DATE=y +# CONFIG_FEATURE_DATE_ISOFMT is not set +# CONFIG_DD is not set +CONFIG_DF=y +# CONFIG_DIRNAME is not set +# CONFIG_DOS2UNIX is not set +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +# CONFIG_EXPR is not set +CONFIG_FALSE=y +# CONFIG_FOLD is not set +# CONFIG_HEAD is not set +# CONFIG_HOSTID is not set +CONFIG_ID=y +# CONFIG_INSTALL is not set +# CONFIG_LENGTH is not set +# CONFIG_LN is not set +# CONFIG_LOGNAME is not set +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +# CONFIG_FEATURE_LS_RECURSIVE is not set +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +CONFIG_FEATURE_LS_COLOR=y +# CONFIG_MD5SUM is not set +# CONFIG_MKDIR is not set +# CONFIG_MKFIFO is not set +# CONFIG_MKNOD is not set +# CONFIG_MV is not set +# CONFIG_OD is not set +# CONFIG_PRINTF is not set +CONFIG_PWD=y +# CONFIG_REALPATH is not set +# CONFIG_RM is not set +# CONFIG_RMDIR is not set +# CONFIG_SEQ is not set +# CONFIG_SHA1SUM is not set +# CONFIG_SLEEP is not set +# CONFIG_SORT is not set +# CONFIG_STTY is not set +# CONFIG_SYNC is not set +# CONFIG_TAIL is not set +# CONFIG_TEE is not set +CONFIG_TEST=y + +# +# test (forced enabled for use with shell) +# +# CONFIG_FEATURE_TEST_64 is not set +# CONFIG_TOUCH is not set +# CONFIG_TR is not set +CONFIG_TRUE=y +CONFIG_TTY=y +CONFIG_UNAME=y +# CONFIG_UNIQ is not set +# CONFIG_USLEEP is not set +# CONFIG_UUDECODE is not set +# CONFIG_UUENCODE is not set +# CONFIG_WATCH is not set +# CONFIG_WC is not set +# CONFIG_WHO is not set +CONFIG_WHOAMI=y +# CONFIG_YES is not set + +# +# Common options for ls and more +# +CONFIG_FEATURE_AUTOWIDTH=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Console Utilities +# +# CONFIG_CHVT is not set +CONFIG_CLEAR=y +# CONFIG_DEALLOCVT is not set +# CONFIG_DUMPKMAP is not set +# CONFIG_LOADFONT is not set +# CONFIG_LOADKMAP is not set +# CONFIG_OPENVT is not set +CONFIG_RESET=y +# CONFIG_SETKEYCODES is not set + +# +# Debian Utilities +# +# CONFIG_MKTEMP is not set +# CONFIG_PIPE_PROGRESS is not set +# CONFIG_READLINK is not set +# CONFIG_RUN_PARTS is not set +# CONFIG_START_STOP_DAEMON is not set +# CONFIG_WHICH is not set + +# +# Editors +# +# CONFIG_AWK is not set +# CONFIG_PATCH is not set +# CONFIG_SED is not set +# CONFIG_VI is not set + +# +# Finding Utilities +# +# CONFIG_FIND is not set +# CONFIG_GREP is not set +# CONFIG_XARGS is not set + +# +# Init Utilities +# +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +CONFIG_FEATURE_INITRD=y +# CONFIG_FEATURE_INIT_COREDUMPS is not set +CONFIG_FEATURE_EXTRA_QUIET=y +# CONFIG_HALT is not set +# CONFIG_POWEROFF is not set +CONFIG_REBOOT=y +# CONFIG_MESG is not set + +# +# Login/Password Management Utilities +# +CONFIG_USE_BB_PWD_GRP=y +# CONFIG_ADDGROUP is not set +# CONFIG_DELGROUP is not set +# CONFIG_ADDUSER is not set +# CONFIG_DELUSER is not set +# CONFIG_GETTY is not set +# CONFIG_FEATURE_U_W_TMP is not set +CONFIG_LOGIN=y +CONFIG_FEATURE_SECURETTY=y +# CONFIG_PASSWD is not set +# CONFIG_SU is not set +# CONFIG_SULOGIN is not set +# CONFIG_VLOCK is not set + +# +# Common options for adduser, deluser, login, su +# +# CONFIG_FEATURE_SHADOWPASSWDS is not set + +# +# Miscellaneous Utilities +# +# CONFIG_ADJTIMEX is not set +# CONFIG_CROND is not set +# CONFIG_CRONTAB is not set +# CONFIG_DC is not set +# CONFIG_DEVFSD is not set +# CONFIG_LAST is not set +# CONFIG_HDPARM is not set +# CONFIG_MAKEDEVS is not set +# CONFIG_MT is not set +# CONFIG_RX is not set +# CONFIG_STRINGS is not set +# CONFIG_TIME is not set +# CONFIG_WATCHDOG is not set + +# +# Linux Module Utilities +# +CONFIG_INSMOD=y +CONFIG_FEATURE_2_4_MODULES=y +# CONFIG_FEATURE_2_6_MODULES is not set +CONFIG_FEATURE_INSMOD_VERSION_CHECKING=y +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +CONFIG_LSMOD=y +CONFIG_FEATURE_QUERY_MODULE_INTERFACE=y +CONFIG_MODPROBE=y +CONFIG_RMMOD=y +CONFIG_FEATURE_CHECK_TAINTED_MODULE=y + +# +# Networking Utilities +# +# CONFIG_FEATURE_IPV6 is not set +# CONFIG_ARPING is not set +# CONFIG_FTPGET is not set +# CONFIG_FTPPUT is not set +CONFIG_HOSTNAME=y +# CONFIG_HTTPD is not set +CONFIG_IFCONFIG=y +CONFIG_FEATURE_IFCONFIG_STATUS=y +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set +CONFIG_FEATURE_IFCONFIG_HW=y +# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set +# CONFIG_IFUPDOWN is not set +# CONFIG_INETD is not set +# CONFIG_IP is not set +# CONFIG_IPCALC is not set +# CONFIG_IPADDR is not set +# CONFIG_IPLINK is not set +# CONFIG_IPROUTE is not set +# CONFIG_IPTUNNEL is not set +# CONFIG_NAMEIF is not set +# CONFIG_NC is not set +CONFIG_NETSTAT=y +# CONFIG_NSLOOKUP is not set +CONFIG_PING=y +CONFIG_FEATURE_FANCY_PING=y +CONFIG_ROUTE=y +# CONFIG_TELNET is not set +CONFIG_TELNETD=y +# CONFIG_FEATURE_TELNETD_INETD is not set +# CONFIG_TFTP is not set +# CONFIG_TRACEROUTE is not set +# CONFIG_VCONFIG is not set +# CONFIG_WGET is not set + +# +# udhcp Server/Client +# +# CONFIG_UDHCPD is not set +# CONFIG_UDHCPC is not set + +# +# Process Utilities +# +CONFIG_FREE=y +CONFIG_KILL=y +CONFIG_KILLALL=y +# CONFIG_PIDOF is not set +CONFIG_PS=y +# CONFIG_RENICE is not set +CONFIG_TOP=y +FEATURE_CPU_USAGE_PERCENTAGE=y +CONFIG_UPTIME=y +# CONFIG_SYSCTL is not set + +# +# Another Bourne-like Shell +# +CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_FEATURE_SH_IS_HUSH is not set +# CONFIG_FEATURE_SH_IS_LASH is not set +# CONFIG_FEATURE_SH_IS_MSH is not set +# CONFIG_FEATURE_SH_IS_NONE is not set +CONFIG_ASH=y + +# +# Ash Shell Options +# +CONFIG_ASH_JOB_CONTROL=y +# CONFIG_ASH_ALIAS is not set +# CONFIG_ASH_MATH_SUPPORT is not set +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_CMDCMD is not set +# CONFIG_ASH_MAIL is not set +CONFIG_ASH_OPTIMIZE_FOR_SIZE=y +# CONFIG_ASH_RANDOM_SUPPORT is not set +# CONFIG_HUSH is not set +# CONFIG_LASH is not set +# CONFIG_MSH is not set + +# +# Bourne Shell Options +# +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set +# CONFIG_FEATURE_SH_STANDALONE_SHELL is not set +CONFIG_FEATURE_COMMAND_EDITING=y +CONFIG_FEATURE_COMMAND_HISTORY=15 +# CONFIG_FEATURE_COMMAND_SAVEHISTORY is not set +CONFIG_FEATURE_COMMAND_TAB_COMPLETION=y +# CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION is not set +CONFIG_FEATURE_SH_FANCY_PROMPT=y + +# +# System Logging Utilities +# +CONFIG_SYSLOGD=y +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +CONFIG_FEATURE_REMOTE_LOG=y +# CONFIG_FEATURE_IPC_SYSLOG is not set +CONFIG_KLOGD=y +CONFIG_LOGGER=y + +# +# Linux System Utilities +# +CONFIG_DMESG=y +# CONFIG_FBSET is not set +# CONFIG_FDFLUSH is not set +# CONFIG_FDFORMAT is not set +# CONFIG_FDISK is not set +# CONFIG_FREERAMDISK is not set +# CONFIG_FSCK_MINIX is not set +# CONFIG_MKFS_MINIX is not set +# CONFIG_GETOPT is not set +# CONFIG_HEXDUMP is not set +# CONFIG_HWCLOCK is not set +# CONFIG_LOSETUP is not set +# CONFIG_MKSWAP is not set +# CONFIG_MORE is not set +# CONFIG_PIVOT_ROOT is not set +# CONFIG_RDATE is not set +# CONFIG_SWAPONOFF is not set +CONFIG_MOUNT=y +# CONFIG_NFSMOUNT is not set +CONFIG_UMOUNT=y +# CONFIG_FEATURE_MOUNT_FORCE is not set + +# +# Common options for mount/umount +# +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set + +# +# Debugging Options +# +# CONFIG_DEBUG is not set diff --git a/busybox/fullclean b/busybox/fullclean new file mode 100755 index 0000000..52109d7 --- /dev/null +++ b/busybox/fullclean @@ -0,0 +1,3 @@ +#!/bin/bash + +rm -rf dev dongle diff --git a/busybox/prepare b/busybox/prepare new file mode 100755 index 0000000..91b7f33 --- /dev/null +++ b/busybox/prepare @@ -0,0 +1,6 @@ +#!/bin/bash + +mkdir $1 +cd $1 +tar -jxvf ../../packages/busybox-1.00.tar.bz2 + diff --git a/crosstool/README b/crosstool/README new file mode 100644 index 0000000..b96c06f --- /dev/null +++ b/crosstool/README @@ -0,0 +1,5 @@ +autobuild - does full clean, unpacks crosstool and runs build +prepare - unpacks the crosstool sources +build - uses crosstool to build a compiler +clean - removes everything except files downloaded by crosstool +fullclean - removes everything diff --git a/crosstool/autobuild b/crosstool/autobuild new file mode 100755 index 0000000..0661f16 --- /dev/null +++ b/crosstool/autobuild @@ -0,0 +1,5 @@ +#!/bin/bash + +./fullclean +./prepare +./build diff --git a/crosstool/build b/crosstool/build new file mode 100755 index 0000000..b3a51d1 --- /dev/null +++ b/crosstool/build @@ -0,0 +1,17 @@ +#!/bin/sh +# Adapted from the demo-powerpc-405 script in crosstool + +set -ex +TARBALLS_DIR=`pwd`/downloads +RESULT_TOP=`pwd` +export TARBALLS_DIR RESULT_TOP +GCC_LANGUAGES="c,c++" +export GCC_LANGUAGES + +cd crosstool-0.43 +eval `cat powerpc-405.dat gcc-3.4.5-glibc-2.2.5.dat` sh all.sh --notest +cd .. + +echo export CROSS=`pwd`/gcc-3.4.5-glibc-2.2.5/powerpc-405-linux-gnu/bin/powerpc-405-linux-gnu- > cross-var + +echo Done. diff --git a/crosstool/clean b/crosstool/clean new file mode 100755 index 0000000..aac4ae2 --- /dev/null +++ b/crosstool/clean @@ -0,0 +1,3 @@ +#!/bin/bash + +rm -rf cross-var crosstool-0.43 gcc-3.4.5-glibc-2.2.5 diff --git a/crosstool/fullclean b/crosstool/fullclean new file mode 100755 index 0000000..038828c --- /dev/null +++ b/crosstool/fullclean @@ -0,0 +1,4 @@ +#!/bin/bash + +rm -rf cross-var crosstool-0.43 gcc-3.4.5-glibc-2.2.5 downloads + diff --git a/crosstool/glibc-2.2.5-allow-gcc-4.0-configure.patch b/crosstool/glibc-2.2.5-allow-gcc-4.0-configure.patch new file mode 100644 index 0000000..6549cd1 --- /dev/null +++ b/crosstool/glibc-2.2.5-allow-gcc-4.0-configure.patch @@ -0,0 +1,22 @@ +Fixes +checking version of powerpc-405-linux-gnu-gcc ... 4.0.0, bad +checking for gnumake... no +checking for gmake... no +checking for make... make +checking version of make... 3.80, ok +configure: error: +*** These critical programs are missing or too old:gcc + + +--- glibc-2.2.5/configure.old 2005-03-10 00:23:46.374213600 -0800 ++++ glibc-2.2.5/configure 2005-03-10 00:25:13.313996744 -0800 +@@ -1476,7 +1476,7 @@ + ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'` + case $ac_prog_version in + '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; +- *gcc-2.9[5-9].*|*2.8.[1-9]*|*2.9|*2.9.[0-9]*|2.9[5-9]*|3.[0-9]*|cygnus-2.9[1-9]*|gcc-2.9[5-9]|gcc-2.1[0-9][0-9]|sgicc-*) ++ *gcc-2.9[5-9].*|*2.8.[1-9]*|*2.9|*2.9.[0-9]*|2.9[5-9]*|3.[0-9]*|4.[01234]*|cygnus-2.9[1-9]*|gcc-2.9[5-9]|gcc-2.1[0-9][0-9]|sgicc-*) + ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; + *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; + + diff --git a/crosstool/prepare b/crosstool/prepare new file mode 100755 index 0000000..f7d81d6 --- /dev/null +++ b/crosstool/prepare @@ -0,0 +1,13 @@ +#!/bin/bash + +# Avoid downloading from GNU +mkdir downloads +ln -s ../../packages/binutils-2.15.tar.bz2 downloads +ln -s ../../packages/glibc-2.2.5.tar.gz downloads +ln -s ../../packages/linux-2.6.8.tar.bz2 downloads +ln -s ../../packages/gcc-3.4.5.tar.bz2 downloads +ln -s ../../packages/glibc-linuxthreads-2.2.5.tar.gz downloads + +tar -zxvf ../packages/crosstool-0.43.tar.gz +rm -fv crosstool-0.43/patches/glibc-2.2.5/glibc-2.2.5-allow-gcc-4.0-configure.patch +cp -v glibc-2.2.5-allow-gcc-4.0-configure.patch crosstool-0.43/patches/glibc-2.2.5 diff --git a/dongle/README b/dongle/README new file mode 100644 index 0000000..0ceaa25 --- /dev/null +++ b/dongle/README @@ -0,0 +1,4 @@ +autobuild - does fullclean, prepare, build +prepare - sets up genext2fs +build - builds the dongle +fullclean - removes temporary build files, genext2fs and the dongle diff --git a/dongle/autobuild b/dongle/autobuild new file mode 100755 index 0000000..a716723 --- /dev/null +++ b/dongle/autobuild @@ -0,0 +1,4 @@ +#!/bin/bash +./fullclean +./prepare +./build diff --git a/dongle/build b/dongle/build new file mode 100755 index 0000000..8daa9c0 --- /dev/null +++ b/dongle/build @@ -0,0 +1,88 @@ +#!/bin/bash + +. ../crosstool/cross-var + +LKERN=../kernel/dongle/linux-2.4.31 +LGENFS=genext2fs-1.4/genext2fs +OUTFILE=vomp-dongle + +# Create initial file system + +cp -a ../busybox/dongle/install fs +cp -a tofs/* fs + +# Insert vompclient + +cp -fv ../client/vompclient fs +cp -fv ../client/other/*.jpg fs +cp -fv ../lbox_border/lbox_border.o fs/lib/modules/2.4.31 + +# Get kernel files temp dir ready + +mkdir kernel_temp +BOOT=${LKERN}/arch/ppc/boot +CFILES=${BOOT}/common/{dummy,misc-common,ns16550,relocate,string,util,serial_stub}.o +SFILES=${BOOT}/simple/{embed_config,head,misc-embedded}.o +KFILE=${BOOT}/images/vmlinux.gz +FILES=`sh -c "echo $CFILES $SFILES $KFILE ${BOOT}/lib/zlib.a ${BOOT}/ld.script"` +cp $FILES kernel_temp + +# Check filesystem size + +RAMDISK_SIZE=`du -ks fs | cut -f 1` +let RAMDISK_SIZE=$RAMDISK_SIZE+300 +if [ $RAMDISK_SIZE -gt 4096 ] ; then + echo "ramdisk too big" + exit +fi + +# Create the ramdisk out of the fs directory + +${LGENFS} -d fs -b ${RAMDISK_SIZE} -D devtable ramdisk +/bin/gzip ramdisk + +# Put it all together + +mkdir build_temp + +# make_dongle() - this is straight out of arch/ppc in the linux tree + +OBJCOPY=${CROSS}objcopy +LD=${CROSS}ld + +$OBJCOPY -O elf32-powerpc \ + --add-section=.ramdisk=ramdisk.gz \ + --set-section-flags=.ramdisk=contents,alloc,load,readonly,data \ + --add-section=.image=kernel_temp/vmlinux.gz \ + --set-section-flags=.image=contents,alloc,load,readonly,data \ + kernel_temp/dummy.o build_temp/image.o + +$LD -T kernel_temp/ld.script -Ttext 0x00400000 -Bstatic -o build_temp/zvmlinux.initrd \ + kernel_temp/head.o kernel_temp/relocate.o kernel_temp/misc-embedded.o \ + kernel_temp/misc-common.o kernel_temp/string.o kernel_temp/util.o kernel_temp/serial_stub.o \ + kernel_temp/embed_config.o kernel_temp/ns16550.o build_temp/image.o \ + kernel_temp/zlib.a + +$OBJCOPY -O elf32-powerpc build_temp/zvmlinux.initrd build_temp/zvmlinux.initrd \ + -R .comment -R .stab -R .stabstr -R .sysmap + +${LKERN}/arch/ppc/boot/utils/mktree build_temp/zvmlinux.initrd $OUTFILE + +# Clean up + +rm -f ramdisk.gz +rm -rf build_temp +rm -rf kernel_temp +rm -rf fs + +# Install to tftp location + +if [ -d /diskless/tftp/mvp ] && [ -w /diskless/tftp/mvp ] +then + cp -v $OUTFILE /diskless/tftp/mvp +fi + +if [ -d /diskless/tftp/wmvp ] && [ -w /diskless/tftp/wmvp ] +then + cp -v $OUTFILE /diskless/tftp/wmvp +fi diff --git a/dongle/devtable b/dongle/devtable new file mode 100644 index 0000000..e95f950 --- /dev/null +++ b/dongle/devtable @@ -0,0 +1,48 @@ +# name type mode uid gid major minor start inc count + +/dev/adec_ac3 c 600 0 0 202 1 0 0 +/dev/adec_dev c 600 0 0 202 0 0 0 +/dev/adec_mixer c 600 0 0 202 3 0 0 +/dev/adec_mpg c 600 0 0 202 0 0 0 +/dev/adec_pcm c 600 0 0 202 2 0 0 +/dev/aud_mpeg c 600 0 0 202 0 0 0 +/dev/console c 600 0 0 5 1 0 0 +/dev/fb0 c 600 0 0 29 0 0 0 +/dev/fb1 c 600 0 0 29 1 0 0 +/dev/full c 600 0 0 1 7 0 0 +/dev/irmouse c 600 0 0 10 11 0 0 +/dev/kmem c 600 0 0 1 2 0 0 +/dev/mem c 600 0 0 1 1 0 0 +/dev/mtd0 c 600 0 0 90 0 0 0 +/dev/mtd1 c 600 0 0 90 2 0 0 +/dev/mtd2 c 600 0 0 90 4 0 0 +/dev/mtd3 c 600 0 0 90 6 0 0 +/dev/mtd4 c 600 0 0 90 8 0 0 +/dev/mtdblock0 b 600 0 0 31 0 0 0 +/dev/mtdblock1 b 600 0 0 31 1 0 0 +/dev/null c 600 0 0 1 3 0 0 +/dev/port c 600 0 0 1 4 0 0 +/dev/ptyp0 c 600 0 0 2 0 0 0 +/dev/ptyp1 c 600 0 0 2 1 0 0 +/dev/ptyp2 c 600 0 0 2 2 0 0 +/dev/ptyp3 c 600 0 0 2 3 0 0 +/dev/ptyp4 c 600 0 0 2 4 0 0 +/dev/ram0 b 600 0 0 1 0 0 0 +/dev/ram1 b 600 0 0 1 1 0 0 +/dev/ram2 b 600 0 0 1 2 0 0 +/dev/random c 600 0 0 1 8 0 0 +/dev/rawir c 600 0 0 100 0 0 0 +/dev/stbgfx c 600 0 0 251 0 0 0 +/dev/tty c 600 0 0 5 0 0 0 +/dev/tty0 c 600 0 0 4 0 0 0 +/dev/tty5 c 600 0 0 4 5 0 0 +/dev/ttyS0 c 600 0 0 4 64 0 0 +/dev/ttyp0 c 600 0 0 3 0 0 0 +/dev/ttyp1 c 600 0 0 3 1 0 0 +/dev/ttyp2 c 600 0 0 3 2 0 0 +/dev/ttyp3 c 600 0 0 3 3 0 0 +/dev/urandom c 600 0 0 1 9 0 0 +/dev/vdec_dev c 600 0 0 203 0 0 0 +/dev/vid c 600 0 0 203 0 0 0 +/dev/xram c 600 0 0 63 0 0 0 +/dev/zero c 600 0 0 1 5 0 0 diff --git a/dongle/fullclean b/dongle/fullclean new file mode 100755 index 0000000..0ff07bb --- /dev/null +++ b/dongle/fullclean @@ -0,0 +1,4 @@ +#!/bin/bash + +rm -rf ramdisk.gz build_temp kernel_temp fs vomp-dongle genext2fs-1.4 + diff --git a/dongle/prepare b/dongle/prepare new file mode 100755 index 0000000..5a7e056 --- /dev/null +++ b/dongle/prepare @@ -0,0 +1,6 @@ +#!/bin/bash + +tar -zxvf ../packages/genext2fs-1.4.tar.gz +cd genext2fs-1.4 +./configure +make diff --git a/dongle/tofs/dev/fb b/dongle/tofs/dev/fb new file mode 120000 index 0000000..2d66930 --- /dev/null +++ b/dongle/tofs/dev/fb @@ -0,0 +1 @@ +fb0 \ No newline at end of file diff --git a/dongle/tofs/dev/kcore b/dongle/tofs/dev/kcore new file mode 120000 index 0000000..d920e94 --- /dev/null +++ b/dongle/tofs/dev/kcore @@ -0,0 +1 @@ +../proc/kcore \ No newline at end of file diff --git a/dongle/tofs/dev/mouse b/dongle/tofs/dev/mouse new file mode 120000 index 0000000..3d81984 --- /dev/null +++ b/dongle/tofs/dev/mouse @@ -0,0 +1 @@ +irmouse \ No newline at end of file diff --git a/dongle/tofs/dev/ram b/dongle/tofs/dev/ram new file mode 120000 index 0000000..5f76aa2 --- /dev/null +++ b/dongle/tofs/dev/ram @@ -0,0 +1 @@ +ram1 \ No newline at end of file diff --git a/dongle/tofs/dev/ramdisk b/dongle/tofs/dev/ramdisk new file mode 120000 index 0000000..b5b544a --- /dev/null +++ b/dongle/tofs/dev/ramdisk @@ -0,0 +1 @@ +ram0 \ No newline at end of file diff --git a/dongle/tofs/dev/stderr b/dongle/tofs/dev/stderr new file mode 120000 index 0000000..c67586e --- /dev/null +++ b/dongle/tofs/dev/stderr @@ -0,0 +1 @@ +../proc/self/fd/2 \ No newline at end of file diff --git a/dongle/tofs/dev/stdin b/dongle/tofs/dev/stdin new file mode 120000 index 0000000..2825dc0 --- /dev/null +++ b/dongle/tofs/dev/stdin @@ -0,0 +1 @@ +../proc/self/fd/0 \ No newline at end of file diff --git a/dongle/tofs/dev/stdout b/dongle/tofs/dev/stdout new file mode 120000 index 0000000..35e0f62 --- /dev/null +++ b/dongle/tofs/dev/stdout @@ -0,0 +1 @@ +../proc/self/fd/1 \ No newline at end of file diff --git a/dongle/tofs/etc/fstab b/dongle/tofs/etc/fstab new file mode 100644 index 0000000..e87aabc --- /dev/null +++ b/dongle/tofs/etc/fstab @@ -0,0 +1 @@ +/proc /proc proc defaults 0 0 diff --git a/dongle/tofs/etc/group b/dongle/tofs/etc/group new file mode 100644 index 0000000..39dbbc7 --- /dev/null +++ b/dongle/tofs/etc/group @@ -0,0 +1 @@ +root::0: diff --git a/dongle/tofs/etc/hosts b/dongle/tofs/etc/hosts new file mode 100644 index 0000000..d0bdd91 --- /dev/null +++ b/dongle/tofs/etc/hosts @@ -0,0 +1 @@ +127.0.0.1 localhost localhost diff --git a/dongle/tofs/etc/inittab b/dongle/tofs/etc/inittab new file mode 100644 index 0000000..cad6a5b --- /dev/null +++ b/dongle/tofs/etc/inittab @@ -0,0 +1,2 @@ +::sysinit:/etc/rcS +::restart:/sbin/init diff --git a/dongle/tofs/etc/issue.net b/dongle/tofs/etc/issue.net new file mode 100644 index 0000000..1418336 --- /dev/null +++ b/dongle/tofs/etc/issue.net @@ -0,0 +1,3 @@ +VOMP Client + + diff --git a/dongle/tofs/etc/passwd b/dongle/tofs/etc/passwd new file mode 100644 index 0000000..233d68f --- /dev/null +++ b/dongle/tofs/etc/passwd @@ -0,0 +1 @@ +root::0:0:root:/:/bin/sh diff --git a/dongle/tofs/etc/profile b/dongle/tofs/etc/profile new file mode 100644 index 0000000..9a39bd1 --- /dev/null +++ b/dongle/tofs/etc/profile @@ -0,0 +1,13 @@ + +# default timezone +#TZ=CST+6CDT,M4.1.0/2,M10.5.0/2 +#export TZ + +# if shell.config exist then source it. +# shell.config should be created by dongle.config +# eg: to set timezone to EST +# echo "TZ=EST+5EDT,M4.1.0/2,M10.5.0/2; export TZ" > /etc/shell.config +# +#if [ -r /etc/shell.config ]; then +# . /etc/shell.config +#fi diff --git a/dongle/tofs/etc/rcS b/dongle/tofs/etc/rcS new file mode 100755 index 0000000..e419989 --- /dev/null +++ b/dongle/tofs/etc/rcS @@ -0,0 +1,34 @@ +#!/bin/sh +# +# Mount everything in /etc/fstab +# +/bin/umount -a +/bin/mount -a -o rw + +# +# Configure lo0 +# eth0 will be autoconfigured by the kernel +# +/sbin/ifconfig lo 127.0.0.1 + +# +# Start telnetd +# +/usr/sbin/telnetd + +# +# Load kernel modules +# +insmod -f os_core +insmod -f av_core _fmt=1 +insmod -f ircombo +insmod -f gfx +insmod -f osdfb +#insmod ac3_mod +#insmod xrmod +insmod lbox_border + +#udhcpc +#. /etc/udhcpc.config + +/vompclient diff --git a/dongle/tofs/lib/modules/2.4.31/av_core.o b/dongle/tofs/lib/modules/2.4.31/av_core.o new file mode 100644 index 0000000000000000000000000000000000000000..fecb73ae1dc3a9cae96fced54e5df09aef42ff5a GIT binary patch literal 245035 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 D`e7Nk literal 0 HcmV?d00001 diff --git a/dongle/tofs/lib/modules/2.4.31/gfx.o b/dongle/tofs/lib/modules/2.4.31/gfx.o new file mode 100644 index 0000000000000000000000000000000000000000..20dc54deaca434b5a90bc8b32a5a8cfeea6f2a64 GIT binary patch literal 79461 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%0DeI`8V=r9$ zpov}VTG3Y86Q*77cjxb+PLOfmC zriiOnlM89l<9MB?5E}+75=)Nat0X^s2s(B6P5rK(7t_l%?Qe3f!>{C{O0zj!k7fS0dT06h;T_KfSGn_UGBH3p*s)`GFuvnR zaOIBG!R7sd;M)Flu(E%5u(tn5u%iFDVBPleU}Sqsuv*@Q=-nM$*C29Xy&N+4##9wH zRw$GFxm{-|;~Ccbd_dNGRh#ilaBVMj^in5u;=R<_3omBAG}t9L;(7f{%Vzp_E!SWq zx;v=ftst&I&cRCWJepKTqr98Nc_exySRH*XSXmzk*4CE?E9zTvtr_t2$#pYC^xv<1mMlQZk3LEqx8wS>McgK7O;LA;tKo_j!r8+d7MW)P#I5GCvt? z*_D5QepbJaGTpkg&ZU#e_Sv%GD=53tmaV*kvemXM>#3)%Z$$RR$V=Wi4uPMF)R1aS zji`;OXE+X^&(+*VUg_1r>NGM-BeOIzqkIYX!WzdS58927KX1oluZvFO>PJno#;4`b z_zNPB*sjnv{uVIKIw^5p%TQ4(?}{Ki5mk}3W$ZfF zHg#QAH(vWiUm}w&SF2f~1Hp}8i}OJ4^V~B&NbDXuo}Gzb5PCvK=<#g9)_de#l~|4B zH-skVd0fvI|02FX+YWx9b3?3VLSOj_zpg}P(9?AqKlFCow!PNZ_KJVcwtM#ej@m5v z@VC|HVwUIuJ*u?r1bfNt%x)9k;qYEu-;)p;!eW=LTqhn-sw$h`O%d5l#qGNeR z+uhZ~bveGDdttFr!3=XP{S%lqbNb{Yaxi;V#?;dPcF&C2ypt1p%RBat^p?~A%;Y0P z9)dyPf5&RGPF%NNFzaCt8GD!$9BTQZ9}myD7=)IVwMWm$_swGli+R3&HP7^`S89j9 zWt;rGi>`BZC^8b>CElEbCGoW$&Zg=;+kcyOzA+{kne_Z+o}DbGH-?Rzz?zLeVnc8B z!FwNcr^Fof5oIy=))tRP&sTYRz>ny7g>&&$eVk8=UxVHACGQcPqsTz>4L=)&clu|> z4A|?09ybaGamH~6$oI6l*Vr+{Zq-T-WI3^R3^~P_+mP{DCF8U( z8vXZewg)h%oYR3*G-q=CLoMybB;;eg*@k}fEy*9>6%kA3A4n0=T z;{iSH(tbN-#$lz5!}NKSv0D9V#tc1-6BsLTy@a`ris*BUr2?w5zFdXtTa?DF$VznR z8z=N>EV14{U9MI!HY;OX*Oh!SPv(9jGImSeuaCn~7y4JsH~BgLd{i+y6FM@+ zE=9MAhG9LWb#2tPYAr*3xFiX!1_3oQIK3iO7CJ7J5APc*>3`@X?GH0uFx} zj|F5c6z|dnT37tw-li2tpJ-a~!-6JggrHG`{$#y+!1t`|Lv_fEN0j)+Sv;HKZvof) z8ipCmef?Jnp-OXR*iu_AN53)91>XfzcTd2RYig@B-`r9O9 zjGVHv{$9#ToydM0Wj0clIB7D?6;IyWq}y?YbqYVi%app|QR?*fCqkFHQ!}+E`Q&Rp z9>-5#VY$&OEH`kuHiOLp?MuY2C)STfcdS;8*h~z3wu+wt)8bPqz$ZBg{0ex+pH#bZ zd558acR?fpm8nugdEyw+y@NDJ@HK=+dVB&qW_6=1beWG8F=z|hmtd$Rtc8vLyU ze-+@5JOe(Y1siW6&(Jc(e{3`RxTphyQQ<>kZZH;L&4%Rs!T797{tCtqt@t_^-vh=U z(HJkKj*n2sRl>)LUhegA@5}n$)!ZxN-dv5F3EKhx!BW9L`H4eq8BF1I{HWnIxX$t#&*AkN_?ZVkk*WOT4I6&)mJ2`F)+P@-=?41w+f~K=yVW)D zR*k<~iEUJ9zlh%gSM;=EaC%)O2XDV3eR=#Don34MNBH%;Ab$&DL&P)hpzVI1HCC<9 z_2hOrEPDErXFV(m2Bn=Ezeg0~P5N=$CuDIcm=tV+>r2J`;Axd^-w6AJ>GoY{eJAbv zo$407ZpG(_jzzzsSFi2K!J88AP5Z}nziaKfSmeiAwrc5%Ctt%Ze+#{{PRya->EA(& zfAm!*whRCUg-ByKhJmdQco{+6Q^yo@ol%nx4wQSihpXvKgIB~ zt@Jx>^gGMpH^eVDZk2VbI!6nJWG{je*>6eqSRxkagU9SW{PAhCjz17im9ds

EgX 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 Tf7aSq4UFaOmOENPi17Ts3!TQA literal 0 HcmV?d00001 diff --git a/dongle/tofs/lib/modules/2.4.31/osdfb.o b/dongle/tofs/lib/modules/2.4.31/osdfb.o new file mode 100644 index 0000000000000000000000000000000000000000..b50bdf090c0a7dde4b8e82ce6ddc87750b441d73 GIT binary patch literal 14896 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 eN(Z%O9r5=wtZk;n|HWHj(9jlt8{t2_5dAOo.config-is-not.$$ +- . .config-is-not.$$ +- rm .config-is-not.$$ ++ . `pwd`/.config-is-not.$$ ++ rm `pwd`/.config-is-not.$$ + else + echo "#" + echo "# No defaults found" diff --git a/kernel/otherpatches/dongle_version.h b/kernel/otherpatches/dongle_version.h new file mode 100644 index 0000000..8750698 --- /dev/null +++ b/kernel/otherpatches/dongle_version.h @@ -0,0 +1,21 @@ +/* _______________________________________________________________________ + dongle_version.h - Contains constants for current compatible and build + Versions + + first created: 9/8/2005 + last modified: 9/8/2005 + + tab size = 4 + + copyright © 1999-2005 by Hauppauge Computer Works - all rights reserved. + _______________________________________________________________________*/ + +#ifndef _dongle_version_ +#define _dongle_version_ + +#define HCW_COMPATIBLE_VERSION 0x01010003 +#define HCW_BUILD_VERSION 0x01012C03 + +#endif /* _dongle_version_ */ + +/*______________________________________________________________________*/ diff --git a/kernel/otherpatches/fullduplex.patch b/kernel/otherpatches/fullduplex.patch new file mode 100644 index 0000000..b4594f6 --- /dev/null +++ b/kernel/otherpatches/fullduplex.patch @@ -0,0 +1,38 @@ +diff -Narup kernel/drivers/net/smc91111.c dev/mvpdist/kernel/drivers/net/smc91111.c +--- kernel/drivers/net/smc91111.c 2003-11-13 23:14:34.000000000 +0100 ++++ kernel/drivers/net/smc91111.c 2006-11-27 02:22:29.000000000 +0100 +@@ -1400,7 +1400,7 @@ static int smc_open(struct net_device *d + lp->ctl_ephloop = 0; + lp->ctl_miiop = 0; + lp->ctl_autoneg = 1; //1 +- lp->ctl_rfduplx = 0; //Haup=> negotiate for HALF? ++ lp->ctl_rfduplx = 1; //1 + lp->ctl_rspeed = 100; //100 + lp->ctl_afduplx = 0; //1 + lp->ctl_aspeed = 100; //100 +@@ -3742,5 +3742,25 @@ static void smc_phy_interrupt(struct net + #endif + // Update the last phy 18 variable + lp->lastPhy18 = phy18; ++ ++ // if Fullduplex and 100MBit detected we set swfdup ++ if (lp->lastPhy18 & PHY_INT_DPLXDET && ++ lp->lastPhy18 & PHY_INT_SPDDET) ++ { ++ if (!(lp->tcr_cur_mode & TCR_SWFDUP)) ++ { ++ PRINTK2 ("SMC91111 detect 100MBit Full Duplex.. enable swfdup\n"); ++ lp->tcr_cur_mode |= TCR_SWFDUP; ++ lp->ctl_swfdup = 1; ++ smc_modify_regbit (0, ioaddr, TCR_REG, TCR_SWFDUP, 1); ++ } ++ } ++ else if (lp->tcr_cur_mode & TCR_SWFDUP) ++ { ++ PRINTK2 ("SMC91111 no 100MBit Full Duplex detected.. disable swfdup\n"); ++ lp->tcr_cur_mode &= ~TCR_SWFDUP; ++ lp->ctl_swfdup = 0; ++ smc_modify_regbit (0, ioaddr, TCR_REG, TCR_SWFDUP, 0); ++ } + } + } diff --git a/kernel/otherpatches/ppcfix.patch b/kernel/otherpatches/ppcfix.patch new file mode 100644 index 0000000..c75bc30 --- /dev/null +++ b/kernel/otherpatches/ppcfix.patch @@ -0,0 +1,31 @@ +diff -Narup linux-2.4.31-orig/arch/ppc/boot/utils/mktree.c linux-2.4.31/arch/ppc/boot/utils/mktree.c +--- linux-2.4.31-orig/arch/ppc/boot/utils/mktree.c 2004-08-03 16:31:09.568992888 -0500 ++++ linux-2.4.31/arch/ppc/boot/utils/mktree.c 2004-08-04 11:06:39.799051328 -0500 +@@ -15,19 +15,20 @@ + #include + #include + #include ++#include + + /* This gets tacked on the front of the image. There are also a few + * bytes allocated after the _start label used by the boot rom (see + * head.S for details). + */ + typedef struct boot_block { +- unsigned long bb_magic; /* 0x0052504F */ +- unsigned long bb_dest; /* Target address of the image */ +- unsigned long bb_num_512blocks; /* Size, rounded-up, in 512 byte blks */ +- unsigned long bb_debug_flag; /* Run debugger or image after load */ +- unsigned long bb_entry_point; /* The image address to start */ +- unsigned long bb_checksum; /* 32 bit checksum including header */ +- unsigned long reserved[2]; ++ uint32_t bb_magic; /* 0x0052504F */ ++ uint32_t bb_dest; /* Target address of the image */ ++ uint32_t bb_num_512blocks; /* Size, rounded-up, in 512 byte blks */ ++ uint32_t bb_debug_flag; /* Run debugger or image after load */ ++ uint32_t bb_entry_point; /* The image address to start */ ++ uint32_t bb_checksum; /* 32 bit checksum including header */ ++ uint32_t reserved[2]; + } boot_block_t; + + #define IMGBLK 512 diff --git a/kernel/patch b/kernel/patch new file mode 100755 index 0000000..c9e9719 --- /dev/null +++ b/kernel/patch @@ -0,0 +1,12 @@ +#!/bin/bash + +for j in $( ls patches-2.4.31/*.patch); do + patch -f -N -p1 -d $1/linux-2.4.31 < $j +done + +for j in $( ls otherpatches/*.patch); do + patch -f -N -p1 -d $1/linux-2.4.31 < $j +done + +cp -vf patches-2.4.31/redwood.c $1/linux-2.4.31/drivers/mtd/maps +cp -vf otherpatches/dongle_version.h $1/linux-2.4.31/arch/ppc diff --git a/kernel/patches-2.4.31/architecture.patch b/kernel/patches-2.4.31/architecture.patch new file mode 100644 index 0000000..020f959 --- /dev/null +++ b/kernel/patches-2.4.31/architecture.patch @@ -0,0 +1,24 @@ +diff -Narup linux-2.4.31-orig/Makefile linux-2.4.31/Makefile +--- linux-2.4.31-orig/Makefile 2005-08-09 11:30:57.000000000 -0700 ++++ linux-2.4.31/Makefile 2005-08-09 11:33:15.000000000 -0700 +@@ -5,7 +5,7 @@ EXTRAVERSION = + + KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) + +-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) ++#ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) + KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g") + + CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ +@@ -19,7 +19,10 @@ FINDHPATH = $(HPATH)/asm $(HPATH)/linux + HOSTCC = gcc + HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer + +-CROSS_COMPILE = ++#CROSS_COMPILE = ++ ++ARCH=ppc ++CROSS_COMPILE = powerpc-405-linux-gnu- + + # + # Include the make variables (CC, etc...) diff --git a/kernel/patches-2.4.31/clockfix.patch b/kernel/patches-2.4.31/clockfix.patch new file mode 100644 index 0000000..ae063ca --- /dev/null +++ b/kernel/patches-2.4.31/clockfix.patch @@ -0,0 +1,13 @@ +diff -Narup linux-2.4.31-orig/arch/ppc/boot/simple/embed_config.c linux-2.4.31/arch/ppc/boot/simple/embed_config.c +--- linux-2.4.31-orig/arch/ppc/boot/simple/embed_config.c 2004-04-14 06:05:27.000000000 -0700 ++++ linux-2.4.31/arch/ppc/boot/simple/embed_config.c 2005-10-06 00:05:18.000000000 -0700 +@@ -711,6 +711,9 @@ embed_config(bd_t **bdp) + bd->bi_tbfreq = bd->bi_intfreq; + #endif + } ++#if defined (CONFIG_REDWOOD_5) || defined (CONFIG_REDWOOD_6) ++ bd->bi_tbfreq = 27 * 1000 * 1000; ++#endif + } + #endif + diff --git a/kernel/patches-2.4.31/kexec-ppc-2.4.patch b/kernel/patches-2.4.31/kexec-ppc-2.4.patch new file mode 100644 index 0000000..b4f5ca2 --- /dev/null +++ b/kernel/patches-2.4.31/kexec-ppc-2.4.patch @@ -0,0 +1,1685 @@ +diff -Narup linux-2.4.31-orig/arch/ppc/config.in linux-2.4.31/arch/ppc/config.in +--- linux-2.4.31-orig/arch/ppc/config.in 2004-08-07 16:26:04.000000000 -0700 ++++ linux-2.4.31/arch/ppc/config.in 2005-08-24 22:14:47.000000000 -0700 +@@ -167,6 +167,8 @@ if [ "$CONFIG_SMP" = "y" ]; then + int 'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32 + fi + ++bool 'kexec system call' CONFIG_KEXEC ++ + if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then + bool 'AltiVec Support' CONFIG_ALTIVEC + bool 'Thermal Management Support' CONFIG_TAU +diff -Narup linux-2.4.31-orig/arch/ppc/kernel/Makefile linux-2.4.31/arch/ppc/kernel/Makefile +--- linux-2.4.31-orig/arch/ppc/kernel/Makefile 2004-04-14 06:05:27.000000000 -0700 ++++ linux-2.4.31/arch/ppc/kernel/Makefile 2005-08-24 22:17:32.000000000 -0700 +@@ -49,6 +49,7 @@ obj-$(CONFIG_PCI) += pci-dma.o + obj-$(CONFIG_KGDB) += ppc-stub.o + obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o + obj-$(CONFIG_SMP) += smp.o ++obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o + obj-$(CONFIG_TAU) += temp.o + ifeq ($(CONFIG_SERIAL)$(CONFIG_GEN550),yy) + obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o +diff -Narup linux-2.4.31-orig/arch/ppc/kernel/machine_kexec.c linux-2.4.31/arch/ppc/kernel/machine_kexec.c +--- linux-2.4.31-orig/arch/ppc/kernel/machine_kexec.c 1969-12-31 16:00:00.000000000 -0800 ++++ linux-2.4.31/arch/ppc/kernel/machine_kexec.c 2005-08-24 23:43:17.000000000 -0700 +@@ -0,0 +1,121 @@ ++/* ++ * machine_kexec.c - handle transition of Linux booting another kernel ++ * Copyright (C) 2002-2003 Eric Biederman ++ * ++ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz ++ * ++ * This source code is licensed under the GNU General Public License, ++ * Version 2. See the file COPYING for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++#include ++ ++typedef NORET_TYPE void (*relocate_new_kernel_t)( ++ unsigned long indirection_page, unsigned long reboot_code_buffer, ++ unsigned long start_address) ATTRIB_NORET; ++ ++const extern unsigned char relocate_new_kernel[]; ++const extern unsigned int relocate_new_kernel_size; ++ ++void machine_shutdown(void) ++{ ++ if (ppc_md.machine_shutdown) { ++ ppc_md.machine_shutdown(); ++ } ++} ++ ++void machine_crash_shutdown(void) ++{ ++ if (ppc_md.machine_crash_shutdown) { ++ ppc_md.machine_crash_shutdown(); ++ } ++} ++ ++/* ++ * Do what every setup is needed on image and the ++ * reboot code buffer to allow us to avoid allocations ++ * later. ++ */ ++int machine_kexec_prepare(struct kimage *image) ++{ ++ if (ppc_md.machine_kexec_prepare) { ++ return ppc_md.machine_kexec_prepare(image); ++ } ++ /* ++ * Fail if platform doesn't provide its own machine_kexec_prepare ++ * implementation. ++ */ ++ return -ENOSYS; ++} ++ ++void machine_kexec_cleanup(struct kimage *image) ++{ ++ if (ppc_md.machine_kexec_cleanup) { ++ ppc_md.machine_kexec_cleanup(image); ++ } ++} ++ ++/* ++ * Do not allocate memory (or fail in any way) in machine_kexec(). ++ * We are past the point of no return, committed to rebooting now. ++ */ ++NORET_TYPE void machine_kexec(struct kimage *image) ++{ ++ if (ppc_md.machine_kexec) { ++ ppc_md.machine_kexec(image); ++ } else { ++ /* ++ * Fall back to normal restart if platform doesn't provide ++ * its own kexec function, and user insist to kexec... ++ */ ++ machine_restart(NULL); ++ } ++ for(;;); ++} ++ ++ ++/* ++ * This is a generic machine_kexec function suitable at least for ++ * non-OpenFirmware embedded platforms. ++ * It merely copies the image relocation code to the control page and ++ * jumps to it. ++ * A platform specific function may just call this one. ++ */ ++void machine_kexec_simple(struct kimage *image) ++{ ++ unsigned long page_list; ++ unsigned long reboot_code_buffer, reboot_code_buffer_phys; ++ relocate_new_kernel_t rnk; ++ ++ /* Interrupts aren't acceptable while we reboot */ ++ local_irq_disable(); ++ ++ page_list = image->head; ++ ++ /* we need both effective and real address here */ ++ reboot_code_buffer = ++ (unsigned long)page_address(image->control_code_page); ++ reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer); ++ ++ /* copy our kernel relocation code to the control code page */ ++ memcpy((void *)reboot_code_buffer, ++ relocate_new_kernel, relocate_new_kernel_size); ++ ++ flush_icache_range(reboot_code_buffer, ++ reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); ++ printk(KERN_INFO "Bye!\n"); ++ ++ /* now call it */ ++ rnk = (relocate_new_kernel_t) reboot_code_buffer; ++ (*rnk)(page_list, reboot_code_buffer_phys, image->start); ++} +diff -Narup linux-2.4.31-orig/arch/ppc/kernel/misc.S linux-2.4.31/arch/ppc/kernel/misc.S +--- linux-2.4.31-orig/arch/ppc/kernel/misc.S 2004-04-14 06:05:27.000000000 -0700 ++++ linux-2.4.31/arch/ppc/kernel/misc.S 2005-08-24 22:22:21.000000000 -0700 +@@ -1310,6 +1310,25 @@ _GLOBAL(sys_call_table) + .long sys_ni_syscall /* reserved for sys_clock_getres */ + .long sys_ni_syscall /* reserved for sys_clock_nanosleep */ + .long sys_swapcontext ++ .long sys_ni_syscall /* 250 */ ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_ni_syscall /* 255 */ ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_ni_syscall /* 260 */ ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_ni_syscall /* 265 */ ++ .long sys_ni_syscall ++ .long sys_ni_syscall ++ .long sys_kexec_load /* and finally, 268 sys_kexec_load... */ + + .rept NR_syscalls-(.-sys_call_table)/4 + .long sys_ni_syscall +diff -Narup linux-2.4.31-orig/arch/ppc/kernel/relocate_kernel.S linux-2.4.31/arch/ppc/kernel/relocate_kernel.S +--- linux-2.4.31-orig/arch/ppc/kernel/relocate_kernel.S 1969-12-31 16:00:00.000000000 -0800 ++++ linux-2.4.31/arch/ppc/kernel/relocate_kernel.S 2005-08-24 11:37:15.000000000 -0700 +@@ -0,0 +1,122 @@ ++/* ++ * relocate_kernel.S - put the kernel image in place to boot ++ * Copyright (C) 2002-2003 Eric Biederman ++ * ++ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz ++ * ++ * This source code is licensed under the GNU General Public License, ++ * Version 2. See the file COPYING for more details. ++ */ ++ ++#include ++#include ++ ++#include ++ ++#define PAGE_SIZE 4096 /* must be same value as in */ ++ ++ /* ++ * Must be relocatable PIC code callable as a C function. ++ */ ++ .globl relocate_new_kernel ++relocate_new_kernel: ++ /* r3 = page_list */ ++ /* r4 = reboot_code_buffer */ ++ /* r5 = start_address */ ++ ++ li r0, 0 ++ ++ /* ++ * Set Machine Status Register to a known status, ++ * switch the MMU off and jump to 1: in a single step. ++ */ ++ ++ mr r8, r0 ++ ori r8, r8, MSR_RI|MSR_ME ++ mtspr SPRN_SRR1, r8 ++ addi r8, r4, 1f - relocate_new_kernel ++ mtspr SPRN_SRR0, r8 ++ sync ++ rfi ++ ++1: ++ /* from this point address translation is turned off */ ++ /* and interrupts are disabled */ ++ ++ /* set a new stack at the bottom of our page... */ ++ /* (not really needed now) */ ++ addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */ ++ stw r0, 0(r1) ++ ++ /* Do the copies */ ++ li r6, 0 /* checksum */ ++ mr r0, r3 ++ b 1f ++ ++0: /* top, read another word for the indirection page */ ++ lwzu r0, 4(r3) ++ ++1: ++ /* is it a destination page? (r8) */ ++ rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */ ++ beq 2f ++ ++ rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */ ++ b 0b ++ ++2: /* is it an indirection page? (r3) */ ++ rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */ ++ beq 2f ++ ++ rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */ ++ subi r3, r3, 4 ++ b 0b ++ ++2: /* are we done? */ ++ rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */ ++ beq 2f ++ b 3f ++ ++2: /* is it a source page? (r9) */ ++ rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */ ++ beq 0b ++ ++ rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */ ++ ++ li r7, PAGE_SIZE / 4 ++ mtctr r7 ++ subi r9, r9, 4 ++ subi r8, r8, 4 ++9: ++ lwzu r0, 4(r9) /* do the copy */ ++ xor r6, r6, r0 ++ stwu r0, 4(r8) ++ dcbst 0, r8 ++ sync ++ icbi 0, r8 ++ bdnz 9b ++ ++ addi r9, r9, 4 ++ addi r8, r8, 4 ++ b 0b ++ ++3: ++ ++ /* To be certain of avoiding problems with self-modifying code ++ * execute a serializing instruction here. ++ */ ++ isync ++ sync ++ ++ /* jump to the entry point, usually the setup routine */ ++ mtlr r5 ++ blrl ++ ++1: b 1b ++ ++relocate_new_kernel_end: ++ ++ .globl relocate_new_kernel_size ++relocate_new_kernel_size: ++ .long relocate_new_kernel_end - relocate_new_kernel ++ +diff -Narup linux-2.4.31-orig/arch/ppc/platforms/redwood6.c linux-2.4.31/arch/ppc/platforms/redwood6.c +--- linux-2.4.31-orig/arch/ppc/platforms/redwood6.c 2004-04-14 06:05:27.000000000 -0700 ++++ linux-2.4.31/arch/ppc/platforms/redwood6.c 2005-08-24 22:57:12.000000000 -0700 +@@ -168,7 +168,26 @@ board_setup_irq(void) + { + } + ++#ifdef CONFIG_KEXEC ++int redwood6_kexec_prepare(struct kimage *image) ++{ ++ /* here, we can place additional preparations */ ++ return 0; /* yes, we support kexec */ ++} ++ ++ ++void redwood6_kexec(struct kimage *image) ++{ ++ /* just call the simple kexec version... */ ++ machine_kexec_simple(image); ++} ++#endif /* CONFIG_KEXEC */ ++ + void __init + board_init(void) + { ++#ifdef CONFIG_KEXEC ++ ppc_md.machine_kexec_prepare = redwood6_kexec_prepare; ++ ppc_md.machine_kexec = redwood6_kexec; ++#endif + } +diff -Narup linux-2.4.31-orig/include/asm-ppc/io.h linux-2.4.31/include/asm-ppc/io.h +--- linux-2.4.31-orig/include/asm-ppc/io.h 2003-11-28 10:26:21.000000000 -0800 ++++ linux-2.4.31/include/asm-ppc/io.h 2005-08-24 23:28:30.000000000 -0700 +@@ -275,6 +275,10 @@ extern inline void * phys_to_virt(unsign + #define page_to_phys(page) (((page - mem_map) << PAGE_SHIFT) + PPC_MEMSTART) + #define page_to_bus(page) (page_to_phys(page) + PCI_DRAM_OFFSET) + ++/* added for kexec support */ ++#define pfn_to_page(pfn) (mem_map + ((pfn) - PPC_PGSTART)) ++#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PPC_PGSTART) ++ + /* + * Enforce In-order Execution of I/O: + * Acts as a barrier to ensure all previous I/O accesses have +diff -Narup linux-2.4.31-orig/include/asm-ppc/kexec.h linux-2.4.31/include/asm-ppc/kexec.h +--- linux-2.4.31-orig/include/asm-ppc/kexec.h 1969-12-31 16:00:00.000000000 -0800 ++++ linux-2.4.31/include/asm-ppc/kexec.h 2005-08-24 22:58:28.000000000 -0700 +@@ -0,0 +1,38 @@ ++#ifndef _PPC_KEXEC_H ++#define _PPC_KEXEC_H ++ ++#ifdef CONFIG_KEXEC ++ ++/* ++ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. ++ * I.e. Maximum page that is mapped directly into kernel memory, ++ * and kmap is not required. ++ * ++ * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct ++ * calculation for the amount of memory directly mappable into the ++ * kernel memory space. ++ */ ++ ++/* Maximum physical address we can use pages from */ ++#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) ++/* Maximum address we can reach in physical address mode */ ++#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) ++/* Maximum address we can use for the control code buffer */ ++#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE ++ ++#define KEXEC_CONTROL_CODE_SIZE 4096 ++ ++/* The native architecture */ ++#define KEXEC_ARCH KEXEC_ARCH_PPC ++ ++#ifndef __ASSEMBLY__ ++ ++struct kimage; ++ ++extern void machine_kexec_simple(struct kimage *image); ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* CONFIG_KEXEC */ ++ ++#endif /* _PPC_KEXEC_H */ +diff -Narup linux-2.4.31-orig/include/asm-ppc/machdep.h linux-2.4.31/include/asm-ppc/machdep.h +--- linux-2.4.31-orig/include/asm-ppc/machdep.h 2005-08-24 22:05:10.000000000 -0700 ++++ linux-2.4.31/include/asm-ppc/machdep.h 2005-08-24 23:41:01.000000000 -0700 +@@ -3,6 +3,7 @@ + #define _PPC_MACHDEP_H + + #include ++#include + + #ifdef CONFIG_APUS + #include +@@ -113,6 +114,36 @@ struct machdep_calls { + /* functions for dealing with other cpus */ + struct smp_ops_t *smp_ops; + #endif /* CONFIG_SMP */ ++ ++#ifdef CONFIG_KEXEC ++ /* Called to shutdown machine specific hardware not already controlled ++ * by other drivers. ++ * XXX Should we move this one out of kexec scope? ++ */ ++ void (*machine_shutdown)(void); ++ ++ /* Called to do the minimal shutdown needed to run a kexec'd kernel ++ * to run successfully. ++ * XXX Should we move this one out of kexec scope? ++ */ ++ void (*machine_crash_shutdown)(void); ++ ++ /* Called to do what every setup is needed on image and the ++ * reboot code buffer. Returns 0 on success. ++ * Provide your own (maybe dummy) implementation if your platform ++ * claims to support kexec. ++ */ ++ int (*machine_kexec_prepare)(struct kimage *image); ++ ++ /* Called to handle any machine specific cleanup on image */ ++ void (*machine_kexec_cleanup)(struct kimage *image); ++ ++ /* Called to perform the _real_ kexec. ++ * Do NOT allocate memory or fail here. We are past the point of ++ * no return. ++ */ ++ void (*machine_kexec)(struct kimage *image); ++#endif /* CONFIG_KEXEC */ + }; + + extern struct machdep_calls ppc_md; +diff -Narup linux-2.4.31-orig/include/asm-ppc/page.h linux-2.4.31/include/asm-ppc/page.h +--- linux-2.4.31-orig/include/asm-ppc/page.h 2003-11-28 10:26:21.000000000 -0800 ++++ linux-2.4.31/include/asm-ppc/page.h 2005-08-24 23:27:19.000000000 -0700 +@@ -104,6 +104,7 @@ extern unsigned long ppc_memstart; + extern unsigned long ppc_memoffset; + #ifndef CONFIG_APUS + #define PPC_MEMSTART 0 ++#define PPC_PGSTART 0 + #define PPC_MEMOFFSET PAGE_OFFSET + #else + #define PPC_MEMSTART ppc_memstart +diff -Narup linux-2.4.31-orig/include/asm-ppc/unistd.h linux-2.4.31/include/asm-ppc/unistd.h +--- linux-2.4.31-orig/include/asm-ppc/unistd.h 2004-11-17 03:54:22.000000000 -0800 ++++ linux-2.4.31/include/asm-ppc/unistd.h 2005-08-24 22:49:47.000000000 -0700 +@@ -257,6 +257,8 @@ + #endif + #define __NR_swapcontext 249 + ++#define __NR_kexec_load 268 ++ + #define __NR(n) #n + + /* On powerpc a system call basically clobbers the same registers like a +diff -Narup linux-2.4.31-orig/include/linux/kexec.h linux-2.4.31/include/linux/kexec.h +--- linux-2.4.31-orig/include/linux/kexec.h 1969-12-31 16:00:00.000000000 -0800 ++++ linux-2.4.31/include/linux/kexec.h 2005-08-24 23:40:30.000000000 -0700 +@@ -0,0 +1,115 @@ ++#ifndef LINUX_KEXEC_H ++#define LINUX_KEXEC_H ++ ++#ifdef CONFIG_KEXEC ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Verify architecture specific macros are defined */ ++ ++#ifndef KEXEC_SOURCE_MEMORY_LIMIT ++#error KEXEC_SOURCE_MEMORY_LIMIT not defined ++#endif ++ ++#ifndef KEXEC_DESTINATION_MEMORY_LIMIT ++#error KEXEC_DESTINATION_MEMORY_LIMIT not defined ++#endif ++ ++#ifndef KEXEC_CONTROL_MEMORY_LIMIT ++#error KEXEC_CONTROL_MEMORY_LIMIT not defined ++#endif ++ ++#ifndef KEXEC_CONTROL_CODE_SIZE ++#error KEXEC_CONTROL_CODE_SIZE not defined ++#endif ++ ++#ifndef KEXEC_ARCH ++#error KEXEC_ARCH not defined ++#endif ++ ++/* ++ * This structure is used to hold the arguments that are used when loading ++ * kernel binaries. ++ */ ++ ++typedef unsigned long kimage_entry_t; ++#define IND_DESTINATION 0x1 ++#define IND_INDIRECTION 0x2 ++#define IND_DONE 0x4 ++#define IND_SOURCE 0x8 ++ ++#define KEXEC_SEGMENT_MAX 8 ++struct kexec_segment { ++ void __user *buf; ++ size_t bufsz; ++ unsigned long mem; /* User space sees this as a (void *) ... */ ++ size_t memsz; ++}; ++ ++struct kimage { ++ kimage_entry_t head; ++ kimage_entry_t *entry; ++ kimage_entry_t *last_entry; ++ ++ unsigned long destination; ++ ++ unsigned long start; ++ struct page *control_code_page; ++ ++ unsigned long nr_segments; ++ struct kexec_segment segment[KEXEC_SEGMENT_MAX]; ++ ++ struct list_head control_pages; ++ struct list_head dest_pages; ++ struct list_head unuseable_pages; ++ ++ /* Address of next control page to allocate for crash kernels. */ ++ unsigned long control_page; ++ ++ /* Flags to indicate special processing */ ++ unsigned int type : 1; ++#define KEXEC_TYPE_DEFAULT 0 ++#define KEXEC_TYPE_CRASH 1 ++}; ++ ++ ++ ++/* kexec interface functions */ ++extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET; ++extern int machine_kexec_prepare(struct kimage *image); ++extern void machine_kexec_cleanup(struct kimage *image); ++extern asmlinkage long sys_kexec_load(unsigned long entry, ++ unsigned long nr_segments, struct kexec_segment __user *segments, ++ unsigned long flags); ++extern struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order); ++extern void crash_kexec(void); ++extern struct kimage *kexec_image; ++extern struct kimage *kexec_crash_image; ++ ++#define KEXEC_ON_CRASH 0x00000001 ++#define KEXEC_ARCH_MASK 0xffff0000 ++ ++/* These values match the ELF architecture values. ++ * Unless there is a good reason that should continue to be the case. ++ */ ++#define KEXEC_ARCH_DEFAULT ( 0 << 16) ++#define KEXEC_ARCH_386 ( 3 << 16) ++#define KEXEC_ARCH_X86_64 (62 << 16) ++#define KEXEC_ARCH_PPC (20 << 16) ++#define KEXEC_ARCH_PPC64 (21 << 16) ++#define KEXEC_ARCH_IA_64 (50 << 16) ++ ++#define KEXEC_FLAGS (KEXEC_ON_CRASH) /* List of defined/legal kexec flags */ ++ ++/* Location of a reserved region to hold the crash kernel. ++ */ ++extern struct resource crashk_res; ++ ++#else /* !CONFIG_KEXEC */ ++static inline void crash_kexec(void) { } ++#endif /* CONFIG_KEXEC */ ++#endif /* LINUX_KEXEC_H */ +diff -Narup linux-2.4.31-orig/include/linux/mm.h linux-2.4.31/include/linux/mm.h +--- linux-2.4.31-orig/include/linux/mm.h 2005-01-19 06:10:12.000000000 -0800 ++++ linux-2.4.31/include/linux/mm.h 2005-08-24 23:27:57.000000000 -0700 +@@ -165,6 +165,8 @@ typedef struct page { + struct page **pprev_hash; /* Complement to *next_hash. */ + struct buffer_head * buffers; /* Buffer maps us to a disk block. */ + ++ unsigned long private; /* added for kexec */ ++ + /* + * On machines where all RAM is mapped into kernel address space, + * we can simply calculate the virtual address. On machines with +diff -Narup linux-2.4.31-orig/include/linux/reboot.h linux-2.4.31/include/linux/reboot.h +--- linux-2.4.31-orig/include/linux/reboot.h 2001-02-09 14:46:13.000000000 -0800 ++++ linux-2.4.31/include/linux/reboot.h 2005-08-24 23:00:54.000000000 -0700 +@@ -20,6 +20,7 @@ + * CAD_OFF Ctrl-Alt-Del sequence sends SIGINT to init task. + * POWER_OFF Stop OS and remove all power from system, if possible. + * RESTART2 Restart system using given command string. ++ * KEXEC Restart system using a previously loaded Linux kernel + */ + + #define LINUX_REBOOT_CMD_RESTART 0x01234567 +@@ -28,6 +29,7 @@ + #define LINUX_REBOOT_CMD_CAD_OFF 0x00000000 + #define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC + #define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 ++#define LINUX_REBOOT_CMD_KEXEC 0x45584543 + + + #ifdef __KERNEL__ +@@ -45,6 +47,8 @@ extern int unregister_reboot_notifier(st + extern void machine_restart(char *cmd); + extern void machine_halt(void); + extern void machine_power_off(void); ++extern void machine_shutdown(void); ++extern void machine_crash_shutdown(void); + + #endif + +diff -Narup linux-2.4.31-orig/kernel/Makefile linux-2.4.31/kernel/Makefile +--- linux-2.4.31-orig/kernel/Makefile 2001-09-16 21:22:40.000000000 -0700 ++++ linux-2.4.31/kernel/Makefile 2005-08-24 22:38:41.000000000 -0700 +@@ -19,6 +19,7 @@ obj-y = sched.o dma.o fork.o exec_do + obj-$(CONFIG_UID16) += uid16.o + obj-$(CONFIG_MODULES) += ksyms.o + obj-$(CONFIG_PM) += pm.o ++obj-$(CONFIG_KEXEC) += kexec.o + + ifneq ($(CONFIG_IA64),y) + # According to Alan Modra , the -fno-omit-frame-pointer is +diff -Narup linux-2.4.31-orig/kernel/kexec.c linux-2.4.31/kernel/kexec.c +--- linux-2.4.31-orig/kernel/kexec.c 1969-12-31 16:00:00.000000000 -0800 ++++ linux-2.4.31/kernel/kexec.c 2005-08-24 23:30:47.000000000 -0700 +@@ -0,0 +1,993 @@ ++/* ++ * kexec.c - kexec system call ++ * Copyright (C) 2002-2004 Eric Biederman ++ * ++ * This source code is licensed under the GNU General Public License, ++ * Version 2. See the file COPYING for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Location of the reserved area for the crash kernel */ ++struct resource crashk_res = { ++ .name = "Crash kernel", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_BUSY | IORESOURCE_MEM ++}; ++ ++/* ++ * When kexec transitions to the new kernel there is a one-to-one ++ * mapping between physical and virtual addresses. On processors ++ * where you can disable the MMU this is trivial, and easy. For ++ * others it is still a simple predictable page table to setup. ++ * ++ * In that environment kexec copies the new kernel to its final ++ * resting place. This means I can only support memory whose ++ * physical address can fit in an unsigned long. In particular ++ * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled. ++ * If the assembly stub has more restrictive requirements ++ * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be ++ * defined more restrictively in . ++ * ++ * The code for the transition from the current kernel to the ++ * the new kernel is placed in the control_code_buffer, whose size ++ * is given by KEXEC_CONTROL_CODE_SIZE. In the best case only a single ++ * page of memory is necessary, but some architectures require more. ++ * Because this memory must be identity mapped in the transition from ++ * virtual to physical addresses it must live in the range ++ * 0 - TASK_SIZE, as only the user space mappings are arbitrarily ++ * modifiable. ++ * ++ * The assembly stub in the control code buffer is passed a linked list ++ * of descriptor pages detailing the source pages of the new kernel, ++ * and the destination addresses of those source pages. As this data ++ * structure is not used in the context of the current OS, it must ++ * be self-contained. ++ * ++ * The code has been made to work with highmem pages and will use a ++ * destination page in its final resting place (if it happens ++ * to allocate it). The end product of this is that most of the ++ * physical address space, and most of RAM can be used. ++ * ++ * Future directions include: ++ * - allocating a page table with the control code buffer identity ++ * mapped, to simplify machine_kexec and make kexec_on_panic more ++ * reliable. ++ */ ++ ++/* ++ * KIMAGE_NO_DEST is an impossible destination address..., for ++ * allocating pages whose destination address we do not care about. ++ */ ++#define KIMAGE_NO_DEST (-1UL) ++ ++static int kimage_is_destination_range( ++ struct kimage *image, unsigned long start, unsigned long end); ++static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long dest); ++ ++static int do_kimage_alloc(struct kimage **rimage, unsigned long entry, ++ unsigned long nr_segments, struct kexec_segment __user *segments) ++{ ++ size_t segment_bytes; ++ struct kimage *image; ++ unsigned long i; ++ int result; ++ ++ /* Allocate a controlling structure */ ++ result = -ENOMEM; ++ image = kmalloc(sizeof(*image), GFP_KERNEL); ++ if (!image) { ++ goto out; ++ } ++ memset(image, 0, sizeof(*image)); ++ image->head = 0; ++ image->entry = &image->head; ++ image->last_entry = &image->head; ++ image->control_page = ~0; /* By default this does not apply */ ++ image->start = entry; ++ image->type = KEXEC_TYPE_DEFAULT; ++ ++ /* Initialize the list of control pages */ ++ INIT_LIST_HEAD(&image->control_pages); ++ ++ /* Initialize the list of destination pages */ ++ INIT_LIST_HEAD(&image->dest_pages); ++ ++ /* Initialize the list of unuseable pages */ ++ INIT_LIST_HEAD(&image->unuseable_pages); ++ ++ /* Read in the segments */ ++ image->nr_segments = nr_segments; ++ segment_bytes = nr_segments * sizeof(*segments); ++ result = copy_from_user(image->segment, segments, segment_bytes); ++ if (result) ++ goto out; ++ ++ /* ++ * Verify we have good destination addresses. The caller is ++ * responsible for making certain we don't attempt to load ++ * the new image into invalid or reserved areas of RAM. This ++ * just verifies it is an address we can use. ++ * ++ * Since the kernel does everything in page size chunks ensure ++ * the destination addreses are page aligned. Too many ++ * special cases crop of when we don't do this. The most ++ * insidious is getting overlapping destination addresses ++ * simply because addresses are changed to page size ++ * granularity. ++ */ ++ result = -EADDRNOTAVAIL; ++ for (i = 0; i < nr_segments; i++) { ++ unsigned long mstart, mend; ++ mstart = image->segment[i].mem; ++ mend = mstart + image->segment[i].memsz; ++ if ((mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK)) ++ goto out; ++ if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT) ++ goto out; ++ } ++ ++ /* Verify our destination addresses do not overlap. ++ * If we alloed overlapping destination addresses ++ * through very weird things can happen with no ++ * easy explanation as one segment stops on another. ++ */ ++ result = -EINVAL; ++ for(i = 0; i < nr_segments; i++) { ++ unsigned long mstart, mend; ++ unsigned long j; ++ mstart = image->segment[i].mem; ++ mend = mstart + image->segment[i].memsz; ++ for(j = 0; j < i; j++) { ++ unsigned long pstart, pend; ++ pstart = image->segment[j].mem; ++ pend = pstart + image->segment[j].memsz; ++ /* Do the segments overlap ? */ ++ if ((mend > pstart) && (mstart < pend)) ++ goto out; ++ } ++ } ++ ++ /* Ensure our buffer sizes are strictly less than ++ * our memory sizes. This should always be the case, ++ * and it is easier to check up front than to be surprised ++ * later on. ++ */ ++ result = -EINVAL; ++ for(i = 0; i < nr_segments; i++) { ++ if (image->segment[i].bufsz > image->segment[i].memsz) ++ goto out; ++ } ++ ++ ++ result = 0; ++ out: ++ if (result == 0) { ++ *rimage = image; ++ } else { ++ kfree(image); ++ } ++ return result; ++ ++} ++ ++static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry, ++ unsigned long nr_segments, struct kexec_segment __user *segments) ++{ ++ int result; ++ struct kimage *image; ++ ++ /* Allocate and initialize a controlling structure */ ++ image = NULL; ++ result = do_kimage_alloc(&image, entry, nr_segments, segments); ++ if (result) { ++ goto out; ++ } ++ *rimage = image; ++ ++ /* ++ * Find a location for the control code buffer, and add it ++ * the vector of segments so that it's pages will also be ++ * counted as destination pages. ++ */ ++ result = -ENOMEM; ++ image->control_code_page = kimage_alloc_control_pages(image, ++ get_order(KEXEC_CONTROL_CODE_SIZE)); ++ if (!image->control_code_page) { ++ printk(KERN_ERR "Could not allocate control_code_buffer\n"); ++ goto out; ++ } ++ ++ result = 0; ++ out: ++ if (result == 0) { ++ *rimage = image; ++ } else { ++ kfree(image); ++ } ++ return result; ++} ++ ++static int kimage_crash_alloc(struct kimage **rimage, unsigned long entry, ++ unsigned long nr_segments, struct kexec_segment *segments) ++{ ++ int result; ++ struct kimage *image; ++ unsigned long i; ++ ++ image = NULL; ++ /* Verify we have a valid entry point */ ++ if ((entry < crashk_res.start) || (entry > crashk_res.end)) { ++ result = -EADDRNOTAVAIL; ++ goto out; ++ } ++ ++ /* Allocate and initialize a controlling structure */ ++ result = do_kimage_alloc(&image, entry, nr_segments, segments); ++ if (result) { ++ goto out; ++ } ++ ++ /* Enable the special crash kernel control page ++ * allocation policy. ++ */ ++ image->control_page = crashk_res.start; ++ image->type = KEXEC_TYPE_CRASH; ++ ++ /* ++ * Verify we have good destination addresses. Normally ++ * the caller is responsible for making certain we don't ++ * attempt to load the new image into invalid or reserved ++ * areas of RAM. But crash kernels are preloaded into a ++ * reserved area of ram. We must ensure the addresses ++ * are in the reserved area otherwise preloading the ++ * kernel could corrupt things. ++ */ ++ result = -EADDRNOTAVAIL; ++ for (i = 0; i < nr_segments; i++) { ++ unsigned long mstart, mend; ++ mstart = image->segment[i].mem; ++ mend = mstart + image->segment[i].memsz; ++ /* Ensure we are within the crash kernel limits */ ++ if ((mstart < crashk_res.start) || (mend > crashk_res.end)) ++ goto out; ++ } ++ ++ ++ /* ++ * Find a location for the control code buffer, and add ++ * the vector of segments so that it's pages will also be ++ * counted as destination pages. ++ */ ++ result = -ENOMEM; ++ image->control_code_page = kimage_alloc_control_pages(image, ++ get_order(KEXEC_CONTROL_CODE_SIZE)); ++ if (!image->control_code_page) { ++ printk(KERN_ERR "Could not allocate control_code_buffer\n"); ++ goto out; ++ } ++ ++ result = 0; ++ out: ++ if (result == 0) { ++ *rimage = image; ++ } else { ++ kfree(image); ++ } ++ return result; ++} ++ ++static int kimage_is_destination_range( ++ struct kimage *image, unsigned long start, unsigned long end) ++{ ++ unsigned long i; ++ ++ for (i = 0; i < image->nr_segments; i++) { ++ unsigned long mstart, mend; ++ mstart = image->segment[i].mem; ++ mend = mstart + image->segment[i].memsz; ++ if ((end > mstart) && (start < mend)) { ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static struct page *kimage_alloc_pages(unsigned int gfp_mask, unsigned int order) ++{ ++ struct page *pages; ++ pages = alloc_pages(gfp_mask, order); ++ if (pages) { ++ unsigned int count, i; ++ pages->mapping = NULL; ++ pages->private = order; ++ count = 1 << order; ++ for(i = 0; i < count; i++) { ++ SetPageReserved(pages + i); ++ } ++ } ++ return pages; ++} ++ ++static void kimage_free_pages(struct page *page) ++{ ++ unsigned int order, count, i; ++ order = page->private; ++ count = 1 << order; ++ for(i = 0; i < count; i++) { ++ ClearPageReserved(page + i); ++ } ++ __free_pages(page, order); ++} ++ ++static void kimage_free_page_list(struct list_head *list) ++{ ++ struct list_head *pos, *next; ++ list_for_each_safe(pos, next, list) { ++ struct page *page; ++ ++ page = list_entry(pos, struct page, lru); ++ list_del(&page->lru); ++ ++ kimage_free_pages(page); ++ } ++} ++ ++static struct page *kimage_alloc_normal_control_pages( ++ struct kimage *image, unsigned int order) ++{ ++ /* Control pages are special, they are the intermediaries ++ * that are needed while we copy the rest of the pages ++ * to their final resting place. As such they must ++ * not conflict with either the destination addresses ++ * or memory the kernel is already using. ++ * ++ * The only case where we really need more than one of ++ * these are for architectures where we cannot disable ++ * the MMU and must instead generate an identity mapped ++ * page table for all of the memory. ++ * ++ * At worst this runs in O(N) of the image size. ++ */ ++ struct list_head extra_pages; ++ struct page *pages; ++ unsigned int count; ++ ++ count = 1 << order; ++ INIT_LIST_HEAD(&extra_pages); ++ ++ /* Loop while I can allocate a page and the page allocated ++ * is a destination page. ++ */ ++ do { ++ unsigned long pfn, epfn, addr, eaddr; ++ pages = kimage_alloc_pages(GFP_KERNEL, order); ++ if (!pages) ++ break; ++ pfn = page_to_pfn(pages); ++ epfn = pfn + count; ++ addr = pfn << PAGE_SHIFT; ++ eaddr = epfn << PAGE_SHIFT; ++ if ((epfn >= (KEXEC_CONTROL_MEMORY_LIMIT >> PAGE_SHIFT)) || ++ kimage_is_destination_range(image, addr, eaddr)) ++ { ++ list_add(&pages->lru, &extra_pages); ++ pages = NULL; ++ } ++ } while(!pages); ++ if (pages) { ++ /* Remember the allocated page... */ ++ list_add(&pages->lru, &image->control_pages); ++ ++ /* Because the page is already in it's destination ++ * location we will never allocate another page at ++ * that address. Therefore kimage_alloc_pages ++ * will not return it (again) and we don't need ++ * to give it an entry in image->segment[]. ++ */ ++ } ++ /* Deal with the destination pages I have inadvertently allocated. ++ * ++ * Ideally I would convert multi-page allocations into single ++ * page allocations, and add everyting to image->dest_pages. ++ * ++ * For now it is simpler to just free the pages. ++ */ ++ kimage_free_page_list(&extra_pages); ++ return pages; ++ ++} ++ ++static struct page *kimage_alloc_crash_control_pages( ++ struct kimage *image, unsigned int order) ++{ ++ /* Control pages are special, they are the intermediaries ++ * that are needed while we copy the rest of the pages ++ * to their final resting place. As such they must ++ * not conflict with either the destination addresses ++ * or memory the kernel is already using. ++ * ++ * Control pages are also the only pags we must allocate ++ * when loading a crash kernel. All of the other pages ++ * are specified by the segments and we just memcpy ++ * into them directly. ++ * ++ * The only case where we really need more than one of ++ * these are for architectures where we cannot disable ++ * the MMU and must instead generate an identity mapped ++ * page table for all of the memory. ++ * ++ * Given the low demand this implements a very simple ++ * allocator that finds the first hole of the appropriate ++ * size in the reserved memory region, and allocates all ++ * of the memory up to and including the hole. ++ */ ++ unsigned long hole_start, hole_end, size; ++ struct page *pages; ++ pages = NULL; ++ size = (1 << order) << PAGE_SHIFT; ++ hole_start = (image->control_page + (size - 1)) & ~(size - 1); ++ hole_end = hole_start + size - 1; ++ while(hole_end <= crashk_res.end) { ++ unsigned long i; ++ if (hole_end > KEXEC_CONTROL_MEMORY_LIMIT) { ++ break; ++ } ++ if (hole_end > crashk_res.end) { ++ break; ++ } ++ /* See if I overlap any of the segments */ ++ for(i = 0; i < image->nr_segments; i++) { ++ unsigned long mstart, mend; ++ mstart = image->segment[i].mem; ++ mend = mstart + image->segment[i].memsz - 1; ++ if ((hole_end >= mstart) && (hole_start <= mend)) { ++ /* Advance the hole to the end of the segment */ ++ hole_start = (mend + (size - 1)) & ~(size - 1); ++ hole_end = hole_start + size - 1; ++ break; ++ } ++ } ++ /* If I don't overlap any segments I have found my hole! */ ++ if (i == image->nr_segments) { ++ pages = pfn_to_page(hole_start >> PAGE_SHIFT); ++ break; ++ } ++ } ++ if (pages) { ++ image->control_page = hole_end; ++ } ++ return pages; ++} ++ ++ ++struct page *kimage_alloc_control_pages( ++ struct kimage *image, unsigned int order) ++{ ++ struct page *pages = NULL; ++ switch(image->type) { ++ case KEXEC_TYPE_DEFAULT: ++ pages = kimage_alloc_normal_control_pages(image, order); ++ break; ++ case KEXEC_TYPE_CRASH: ++ pages = kimage_alloc_crash_control_pages(image, order); ++ break; ++ } ++ return pages; ++} ++ ++static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) ++{ ++ if (*image->entry != 0) { ++ image->entry++; ++ } ++ if (image->entry == image->last_entry) { ++ kimage_entry_t *ind_page; ++ struct page *page; ++ page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST); ++ if (!page) { ++ return -ENOMEM; ++ } ++ ind_page = page_address(page); ++ *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION; ++ image->entry = ind_page; ++ image->last_entry = ++ ind_page + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1); ++ } ++ *image->entry = entry; ++ image->entry++; ++ *image->entry = 0; ++ return 0; ++} ++ ++static int kimage_set_destination( ++ struct kimage *image, unsigned long destination) ++{ ++ int result; ++ ++ destination &= PAGE_MASK; ++ result = kimage_add_entry(image, destination | IND_DESTINATION); ++ if (result == 0) { ++ image->destination = destination; ++ } ++ return result; ++} ++ ++ ++static int kimage_add_page(struct kimage *image, unsigned long page) ++{ ++ int result; ++ ++ page &= PAGE_MASK; ++ result = kimage_add_entry(image, page | IND_SOURCE); ++ if (result == 0) { ++ image->destination += PAGE_SIZE; ++ } ++ return result; ++} ++ ++ ++static void kimage_free_extra_pages(struct kimage *image) ++{ ++ /* Walk through and free any extra destination pages I may have */ ++ kimage_free_page_list(&image->dest_pages); ++ ++ /* Walk through and free any unuseable pages I have cached */ ++ kimage_free_page_list(&image->unuseable_pages); ++ ++} ++static int kimage_terminate(struct kimage *image) ++{ ++ if (*image->entry != 0) { ++ image->entry++; ++ } ++ *image->entry = IND_DONE; ++ return 0; ++} ++ ++#define for_each_kimage_entry(image, ptr, entry) \ ++ for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ ++ ptr = (entry & IND_INDIRECTION)? \ ++ phys_to_virt((entry & PAGE_MASK)): ptr +1) ++ ++static void kimage_free_entry(kimage_entry_t entry) ++{ ++ struct page *page; ++ ++ page = pfn_to_page(entry >> PAGE_SHIFT); ++ kimage_free_pages(page); ++} ++ ++static void kimage_free(struct kimage *image) ++{ ++ kimage_entry_t *ptr, entry; ++ kimage_entry_t ind = 0; ++ ++ if (!image) ++ return; ++ kimage_free_extra_pages(image); ++ for_each_kimage_entry(image, ptr, entry) { ++ if (entry & IND_INDIRECTION) { ++ /* Free the previous indirection page */ ++ if (ind & IND_INDIRECTION) { ++ kimage_free_entry(ind); ++ } ++ /* Save this indirection page until we are ++ * done with it. ++ */ ++ ind = entry; ++ } ++ else if (entry & IND_SOURCE) { ++ kimage_free_entry(entry); ++ } ++ } ++ /* Free the final indirection page */ ++ if (ind & IND_INDIRECTION) { ++ kimage_free_entry(ind); ++ } ++ ++ /* Handle any machine specific cleanup */ ++ machine_kexec_cleanup(image); ++ ++ /* Free the kexec control pages... */ ++ kimage_free_page_list(&image->control_pages); ++ kfree(image); ++} ++ ++static kimage_entry_t *kimage_dst_used(struct kimage *image, unsigned long page) ++{ ++ kimage_entry_t *ptr, entry; ++ unsigned long destination = 0; ++ ++ for_each_kimage_entry(image, ptr, entry) { ++ if (entry & IND_DESTINATION) { ++ destination = entry & PAGE_MASK; ++ } ++ else if (entry & IND_SOURCE) { ++ if (page == destination) { ++ return ptr; ++ } ++ destination += PAGE_SIZE; ++ } ++ } ++ return 0; ++} ++ ++static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long destination) ++{ ++ /* ++ * Here we implement safeguards to ensure that a source page ++ * is not copied to its destination page before the data on ++ * the destination page is no longer useful. ++ * ++ * To do this we maintain the invariant that a source page is ++ * either its own destination page, or it is not a ++ * destination page at all. ++ * ++ * That is slightly stronger than required, but the proof ++ * that no problems will not occur is trivial, and the ++ * implementation is simply to verify. ++ * ++ * When allocating all pages normally this algorithm will run ++ * in O(N) time, but in the worst case it will run in O(N^2) ++ * time. If the runtime is a problem the data structures can ++ * be fixed. ++ */ ++ struct page *page; ++ unsigned long addr; ++ ++ /* ++ * Walk through the list of destination pages, and see if I ++ * have a match. ++ */ ++ list_for_each_entry(page, &image->dest_pages, lru) { ++ addr = page_to_pfn(page) << PAGE_SHIFT; ++ if (addr == destination) { ++ list_del(&page->lru); ++ return page; ++ } ++ } ++ page = NULL; ++ while (1) { ++ kimage_entry_t *old; ++ ++ /* Allocate a page, if we run out of memory give up */ ++ page = kimage_alloc_pages(gfp_mask, 0); ++ if (!page) { ++ return 0; ++ } ++ /* If the page cannot be used file it away */ ++ if (page_to_pfn(page) > (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { ++ list_add(&page->lru, &image->unuseable_pages); ++ continue; ++ } ++ addr = page_to_pfn(page) << PAGE_SHIFT; ++ ++ /* If it is the destination page we want use it */ ++ if (addr == destination) ++ break; ++ ++ /* If the page is not a destination page use it */ ++ if (!kimage_is_destination_range(image, addr, addr + PAGE_SIZE)) ++ break; ++ ++ /* ++ * I know that the page is someones destination page. ++ * See if there is already a source page for this ++ * destination page. And if so swap the source pages. ++ */ ++ old = kimage_dst_used(image, addr); ++ if (old) { ++ /* If so move it */ ++ unsigned long old_addr; ++ struct page *old_page; ++ ++ old_addr = *old & PAGE_MASK; ++ old_page = pfn_to_page(old_addr >> PAGE_SHIFT); ++ copy_highpage(page, old_page); ++ *old = addr | (*old & ~PAGE_MASK); ++ ++ /* The old page I have found cannot be a ++ * destination page, so return it. ++ */ ++ addr = old_addr; ++ page = old_page; ++ break; ++ } ++ else { ++ /* Place the page on the destination list I ++ * will use it later. ++ */ ++ list_add(&page->lru, &image->dest_pages); ++ } ++ } ++ return page; ++} ++ ++static int kimage_load_normal_segment(struct kimage *image, ++ struct kexec_segment *segment) ++{ ++ unsigned long maddr; ++ unsigned long ubytes, mbytes; ++ int result; ++ unsigned char *buf; ++ ++ result = 0; ++ buf = segment->buf; ++ ubytes = segment->bufsz; ++ mbytes = segment->memsz; ++ maddr = segment->mem; ++ ++ result = kimage_set_destination(image, maddr); ++ if (result < 0) { ++ goto out; ++ } ++ while(mbytes) { ++ struct page *page; ++ char *ptr; ++ size_t uchunk, mchunk; ++ page = kimage_alloc_page(image, GFP_HIGHUSER, maddr); ++ if (page == 0) { ++ result = -ENOMEM; ++ goto out; ++ } ++ result = kimage_add_page(image, page_to_pfn(page) << PAGE_SHIFT); ++ if (result < 0) { ++ goto out; ++ } ++ ptr = kmap(page); ++ /* Start with a clear page */ ++ memset(ptr, 0, PAGE_SIZE); ++ ptr += maddr & ~PAGE_MASK; ++ mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK); ++ if (mchunk > mbytes) { ++ mchunk = mbytes; ++ } ++ uchunk = mchunk; ++ if (uchunk > ubytes) { ++ uchunk = ubytes; ++ } ++ result = copy_from_user(ptr, buf, uchunk); ++ kunmap(page); ++ if (result) { ++ result = (result < 0) ? result : -EIO; ++ goto out; ++ } ++ ubytes -= uchunk; ++ maddr += mchunk; ++ buf += mchunk; ++ mbytes -= mchunk; ++ } ++ out: ++ return result; ++} ++ ++static int kimage_load_crash_segment(struct kimage *image, ++ struct kexec_segment *segment) ++{ ++ /* For crash dumps kernels we simply copy the data from ++ * user space to it's destination. ++ * We do things a page at a time for the sake of kmap. ++ */ ++ unsigned long maddr; ++ unsigned long ubytes, mbytes; ++ int result; ++ unsigned char *buf; ++ ++ result = 0; ++ buf = segment->buf; ++ ubytes = segment->bufsz; ++ mbytes = segment->memsz; ++ maddr = segment->mem; ++ while(mbytes) { ++ struct page *page; ++ char *ptr; ++ size_t uchunk, mchunk; ++ page = pfn_to_page(maddr >> PAGE_SHIFT); ++ if (page == 0) { ++ result = -ENOMEM; ++ goto out; ++ } ++ ptr = kmap(page); ++ ptr += maddr & ~PAGE_MASK; ++ mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK); ++ if (mchunk > mbytes) { ++ mchunk = mbytes; ++ } ++ uchunk = mchunk; ++ if (uchunk > ubytes) { ++ uchunk = ubytes; ++ /* Zero the trailing part of the page */ ++ memset(ptr + uchunk, 0, mchunk - uchunk); ++ } ++ result = copy_from_user(ptr, buf, uchunk); ++ kunmap(page); ++ if (result) { ++ result = (result < 0) ? result : -EIO; ++ goto out; ++ } ++ ubytes -= uchunk; ++ maddr += mchunk; ++ buf += mchunk; ++ mbytes -= mchunk; ++ } ++ out: ++ return result; ++} ++ ++static int kimage_load_segment(struct kimage *image, ++ struct kexec_segment *segment) ++{ ++ int result = -ENOMEM; ++ switch(image->type) { ++ case KEXEC_TYPE_DEFAULT: ++ result = kimage_load_normal_segment(image, segment); ++ break; ++ case KEXEC_TYPE_CRASH: ++ result = kimage_load_crash_segment(image, segment); ++ break; ++ } ++ return result; ++} ++ ++/* ++ * Exec Kernel system call: for obvious reasons only root may call it. ++ * ++ * This call breaks up into three pieces. ++ * - A generic part which loads the new kernel from the current ++ * address space, and very carefully places the data in the ++ * allocated pages. ++ * ++ * - A generic part that interacts with the kernel and tells all of ++ * the devices to shut down. Preventing on-going dmas, and placing ++ * the devices in a consistent state so a later kernel can ++ * reinitialize them. ++ * ++ * - A machine specific part that includes the syscall number ++ * and the copies the image to it's final destination. And ++ * jumps into the image at entry. ++ * ++ * kexec does not sync, or unmount filesystems so if you need ++ * that to happen you need to do that yourself. ++ */ ++struct kimage *kexec_image = NULL; ++struct kimage *kexec_crash_image = NULL; ++/* ++ * A home grown binary mutex. ++ * Nothing can wait so this mutex is safe to use ++ * in interrupt context :) ++ */ ++static int kexec_lock = 0; ++ ++asmlinkage long sys_kexec_load(unsigned long entry, ++ unsigned long nr_segments, struct kexec_segment __user *segments, ++ unsigned long flags) ++{ ++ struct kimage **dest_image, *image; ++ int locked; ++ int result; ++ ++ /* We only trust the superuser with rebooting the system. */ ++ if (!capable(CAP_SYS_BOOT)) ++ return -EPERM; ++ ++ /* ++ * Verify we have a legal set of flags ++ * This leaves us room for future extensions. ++ */ ++ if ((flags & KEXEC_FLAGS) != (flags & ~KEXEC_ARCH_MASK)) ++ return -EINVAL; ++ ++ /* Verify we are on the appropriate architecture */ ++ if (((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH) && ++ ((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH_DEFAULT)) ++ { ++ return -EINVAL; ++ } ++ ++ /* Put an artificial cap on the number ++ * of segments passed to kexec_load. ++ */ ++ if (nr_segments > KEXEC_SEGMENT_MAX) ++ return -EINVAL; ++ ++ image = NULL; ++ result = 0; ++ ++ /* Because we write directly to the reserved memory ++ * region when loading crash kernels we need a mutex here to ++ * prevent multiple crash kernels from attempting to load ++ * simultaneously, and to prevent a crash kernel from loading ++ * over the top of a in use crash kernel. ++ * ++ * KISS: always take the mutex. ++ */ ++ locked = xchg(&kexec_lock, 1); ++ if (locked) { ++ return -EBUSY; ++ } ++ dest_image = &kexec_image; ++ if (flags & KEXEC_ON_CRASH) { ++ dest_image = &kexec_crash_image; ++ } ++ if (nr_segments > 0) { ++ unsigned long i; ++ /* Loading another kernel to reboot into */ ++ if ((flags & KEXEC_ON_CRASH) == 0) { ++ result = kimage_normal_alloc(&image, entry, nr_segments, segments); ++ } ++ /* Loading another kernel to switch to if this one crashes */ ++ else if (flags & KEXEC_ON_CRASH) { ++ /* Free any current crash dump kernel before ++ * we corrupt it. ++ */ ++ kimage_free(xchg(&kexec_crash_image, NULL)); ++ result = kimage_crash_alloc(&image, entry, nr_segments, segments); ++ } ++ if (result) { ++ goto out; ++ } ++ result = machine_kexec_prepare(image); ++ if (result) { ++ goto out; ++ } ++ for(i = 0; i < nr_segments; i++) { ++ result = kimage_load_segment(image, &image->segment[i]); ++ if (result) { ++ goto out; ++ } ++ } ++ result = kimage_terminate(image); ++ if (result) { ++ goto out; ++ } ++ } ++ /* Install the new kernel, and Uninstall the old */ ++ image = xchg(dest_image, image); ++ ++ out: ++ xchg(&kexec_lock, 0); /* Release the mutex */ ++ kimage_free(image); ++ return result; ++} ++ ++void crash_kexec(void) ++{ ++ struct kimage *image; ++ int locked; ++ ++ ++ /* Take the kexec_lock here to prevent sys_kexec_load ++ * running on one cpu from replacing the crash kernel ++ * we are using after a panic on a different cpu. ++ * ++ * If the crash kernel was not located in a fixed area ++ * of memory the xchg(&kexec_crash_image) would be ++ * sufficient. But since I reuse the memory... ++ */ ++ locked = xchg(&kexec_lock, 1); ++ if (!locked) { ++ image = xchg(&kexec_crash_image, NULL); ++ if (image) { ++ machine_crash_shutdown(); ++ machine_kexec(image); ++ } ++ xchg(&kexec_lock, 0); ++ } ++} +diff -Narup linux-2.4.31-orig/kernel/panic.c linux-2.4.31/kernel/panic.c +--- linux-2.4.31-orig/kernel/panic.c 2004-11-17 03:54:22.000000000 -0800 ++++ linux-2.4.31/kernel/panic.c 2005-08-24 22:40:47.000000000 -0700 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + asmlinkage void sys_sync(void); /* it's really int */ + +@@ -70,6 +71,11 @@ NORET_TYPE void panic(const char * fmt, + sys_sync(); + bust_spinlocks(0); + ++ /* if we crash and have a crash kernel loaded ++ * let it handle everything else ++ */ ++ crash_kexec(); ++ + #ifdef CONFIG_SMP + smp_send_stop(); + #endif +diff -Narup linux-2.4.31-orig/kernel/sys.c linux-2.4.31/kernel/sys.c +--- linux-2.4.31-orig/kernel/sys.c 2003-11-28 10:26:21.000000000 -0800 ++++ linux-2.4.31/kernel/sys.c 2005-08-24 23:01:24.000000000 -0700 +@@ -15,6 +15,9 @@ + #include + #include + ++#include ++#include ++ + #include + #include + +@@ -342,6 +345,21 @@ asmlinkage long sys_reboot(int magic1, i + machine_restart(buffer); + break; + ++ case LINUX_REBOOT_CMD_KEXEC: ++ { ++ struct kimage *image; ++ image = xchg(&kexec_image, 0); ++ if (!image) { ++ unlock_kernel(); ++ return -EINVAL; ++ } ++ notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL); ++ printk(KERN_EMERG "Starting new kernel\n"); ++ machine_shutdown(); ++ machine_kexec(image); ++ break; ++ } ++ + default: + unlock_kernel(); + return -EINVAL; diff --git a/kernel/patches-2.4.31/memsize.patch b/kernel/patches-2.4.31/memsize.patch new file mode 100644 index 0000000..3ba171e --- /dev/null +++ b/kernel/patches-2.4.31/memsize.patch @@ -0,0 +1,26 @@ +diff -Narup linux-2.4.31-orig/arch/ppc/boot/simple/misc-embedded.c linux-2.4.31/arch/ppc/boot/simple/misc-embedded.c +--- linux-2.4.31-orig/arch/ppc/boot/simple/misc-embedded.c 2006-03-16 23:13:06.000000000 +0800 ++++ linux-2.4.31/arch/ppc/boot/simple/misc-embedded.c 2006-03-16 12:43:57.000000000 +0800 +@@ -112,6 +112,9 @@ load_kernel(unsigned long load_addr, int + /* Set end of memory available to us. It is always the highest + * memory address provided by the board information. + */ ++#if defined (CONFIG_REDWOOD_5) || defined (CONFIG_REDWOOD_6) ++ bp->bi_memsize = (16 * 1024 * 1024); // memory limited to 16 MBytes ++#endif + end_avail = (char *)(bp->bi_memsize); + + puts("\nloaded at: "); puthex(load_addr); +diff -Narup linux-2.4.31-orig/arch/ppc/kernel/ppc4xx_setup.c linux-2.4.31/arch/ppc/kernel/ppc4xx_setup.c +--- linux-2.4.31-orig/arch/ppc/kernel/ppc4xx_setup.c 2006-03-16 23:13:28.000000000 +0800 ++++ linux-2.4.31/arch/ppc/kernel/ppc4xx_setup.c 2006-03-16 12:45:35.000000000 +0800 +@@ -161,6 +161,9 @@ ppc4xx_find_end_of_memory(void) + { + bd_t *bip = (bd_t *) __res; + ++#if defined (CONFIG_REDWOOD_5) || defined (CONFIG_REDWOOD_6) ++ bip->bi_memsize = 0x1000000; // memory was limited 16MB. ++#endif + return ((unsigned long) bip->bi_memsize); + } + diff --git a/kernel/patches-2.4.31/mvp-version.patch b/kernel/patches-2.4.31/mvp-version.patch new file mode 100644 index 0000000..181fede --- /dev/null +++ b/kernel/patches-2.4.31/mvp-version.patch @@ -0,0 +1,43 @@ +diff -Narup -x .DS_Store linux-2.4.31/arch/ppc/boot/simple/head.S linux-2.4.31-mod/arch/ppc/boot/simple/head.S +--- linux-2.4.31/arch/ppc/boot/simple/head.S 2003-11-28 10:26:19.000000000 -0800 ++++ linux-2.4.31-mod/arch/ppc/boot/simple/head.S 2005-09-08 11:09:48.000000000 -0700 +@@ -45,6 +45,25 @@ start: + .long bootrom_cmdline # address of *bootrom_cmdline + #endif + ++#ifdef CONFIG_HCW_MVP ++ /* This is a versioning structure for use with the Hauppauge MediaMVP ++ * it is provided with no warranty whatsoever. Use at your own risk. ++ */ ++#include ++mvp_start: ++ .long 0x48435720 # structure magic - "HCW MVP" (null terminated) ++ .long 0x4D565000 ++ .long (mvp_end - mvp_start) # size ++ .long 0x00010000 # struct version (1.0) ++ .long HCW_COMPATIBLE_VERSION # compatible version ++ .long HCW_BUILD_VERSION # build version ++ .long 0 # reserved[4] ++ .long 0 ++ .long 0 ++ .long 0 ++mvp_end: ++#endif ++ + start_: + #ifdef CONFIG_FORCE + /* We have some really bad firmware. We must disable the L1 +diff -Narup -x .DS_Store linux-2.4.31/arch/ppc/config.in linux-2.4.31-mod/arch/ppc/config.in +--- linux-2.4.31/arch/ppc/config.in 2005-09-08 11:04:56.000000000 -0700 ++++ linux-2.4.31-mod/arch/ppc/config.in 2005-09-08 11:09:01.000000000 -0700 +@@ -81,6 +81,10 @@ if [ "$CONFIG_40x" = "y" ]; then + if [ "$CONFIG_EP405" = "y" ]; then + bool 'EP405PC Support' CONFIG_EP405PC + fi ++ ++ if [ "$CONFIG_REDWOOD_6" = "y" ]; then ++ bool 'Hauppauge MediaMVP support' CONFIG_HCW_MVP ++ fi + fi + + if [ "$CONFIG_44x" = "y" ]; then diff --git a/kernel/patches-2.4.31/ppc405-wdt.patch b/kernel/patches-2.4.31/ppc405-wdt.patch new file mode 100644 index 0000000..ac1e23a --- /dev/null +++ b/kernel/patches-2.4.31/ppc405-wdt.patch @@ -0,0 +1,360 @@ +diff -Narup linux-2.4.31-orig/drivers/char/Config.in linux-2.4.31/drivers/char/Config.in +--- linux-2.4.31-orig/drivers/char/Config.in 2004-08-07 16:26:04.000000000 -0700 ++++ linux-2.4.31/drivers/char/Config.in 2005-08-10 15:01:02.000000000 -0700 +@@ -270,6 +270,7 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then + fi + fi + tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT ++ dep_tristate ' PPC405 Watchdog Timer' CONFIG_PPC405_WDT $CONFIG_4xx + if [ "$CONFIG_SGI_IP22" = "y" ]; then + dep_tristate ' Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22 + fi +diff -Narup linux-2.4.31-orig/drivers/char/Makefile linux-2.4.31/drivers/char/Makefile +--- linux-2.4.31-orig/drivers/char/Makefile 2004-08-07 16:26:04.000000000 -0700 ++++ linux-2.4.31/drivers/char/Makefile 2005-08-10 15:00:48.000000000 -0700 +@@ -323,6 +323,7 @@ obj-$(CONFIG_WAFER_WDT) += wafer5823wdt. + obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o + obj-$(CONFIG_INDYDOG) += indydog.o + obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o ++obj-$(CONFIG_PPC405_WDT) += ppc405_wdt.o + + subdir-$(CONFIG_MWAVE) += mwave + ifeq ($(CONFIG_MWAVE),y) +diff -Narup linux-2.4.31-orig/drivers/char/ppc405_wdt.c linux-2.4.31/drivers/char/ppc405_wdt.c +--- linux-2.4.31-orig/drivers/char/ppc405_wdt.c 1969-12-31 16:00:00.000000000 -0800 ++++ linux-2.4.31/drivers/char/ppc405_wdt.c 2005-08-10 14:56:02.000000000 -0700 +@@ -0,0 +1,305 @@ ++/* ++ * IBM PowerPC 405 Watchdog: A Simple Hardware Watchdog Device ++ * Based on PowerPC 8xx driver by Scott Anderson which was ++ * based on MixCom driver by Gergely Madarasz which was ++ * based on Softdog driver by Alan Cox and PC Watchdog driver by Ken Hollis ++ * ++ * FILE NAME ppc405_wdt.c ++ * ++ * Armin Kuster akuster@mvista.com or source@mvista.com ++ * Sept, 2001 ++ * ++ * Orignial driver ++ * Author: MontaVista Software, Inc. ++ * Debbie Chu ++ * Frank Rowand ++ * ++ * Copyright 2000 MontaVista Software 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 the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * THIS SOFTWARE IS PROVIDED ``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. ++ * ++ * 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., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Version 0.1 (00/06/05): ++ * Version 0.2 (00/07/12) by Debbie Chu ++ * Version 0.4 (01/09/19) by Armin kuster ++ * Version 0.5 (01/10/10) Akuster ++ * - removed ppc4xx_restart w/ machine_restart ++ */ ++ ++#define VERSION "0.5" ++ ++#define WDT_DEFAULT_PERIOD 120 /* system default 2 minutes */ ++#define MAXONEHOUR 3600UL /* Max timeout period 60 minutes */ ++#define TENMSBASE 10000UL /* 10 ms */ ++#define MICROSECBASE 1000000 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define WDIOC_GETPERIOD _IOR(WATCHDOG_IOCTL_BASE, 6, int) ++#define WDIOC_SETPERIOD _IOW(WATCHDOG_IOCTL_BASE, 7, int) ++ ++int wdt_enable; ++unsigned long wdt_period; ++unsigned long wdt_heartbeat_count; ++static unsigned long wdt_count; ++int wdt_default = 1; ++ ++static int ppc405wd_opened; ++ ++static inline void ++ppc405wd_update_timer(void) ++{ ++ wdt_heartbeat_count = wdt_count; ++} ++ ++void ++ppc4xx_wdt_heartbeat(void) ++{ ++ if (wdt_default ){ ++ /* default used until wdt inits */ ++ wdt_heartbeat_count = wdt_period * HZ; ++ wdt_default = 0; ++ } ++ if ((wdt_heartbeat_count > 0) || ( !wdt_enable )) { ++ if (wdt_heartbeat_count > 0) ++ wdt_heartbeat_count--; ++ mtspr(SPRN_TSR, (TSR_ENW | TSR_WIS)); ++ } else ++ machine_restart("Watchdog Timer Timed out, system reset!"); ++ ppc_md.heartbeat_count = 0; ++} ++ ++/* ++ * Allow only one person to hold it open ++ */ ++static int ppc405wd_open(struct inode *inode, struct file *file) ++{ ++ unsigned int tcr_value; ++ ++ if(test_and_set_bit(0,&ppc405wd_opened)) ++ return -EBUSY; ++ ++ MOD_INC_USE_COUNT; ++ ++ /* ++ * There are three ways to enable the watchdog timer: ++ * 1. turn on the watchdog in the bootrom. ++ * 2. turn on the watchdog using the boot command line option, ++ * you can specifiy "wdt=" on the boot cmdline ++ * 3. turn on the watchdog in this routine, ++ * the default timer period is set to 2 minutes. ++ */ ++ ++ tcr_value = mfspr(SPRN_TCR); ++ ++ if ((tcr_value & TCR_WRC_MASK) != TCR_WRC(WRC_SYSTEM)) { ++ /* ++ * watchdog reset not enabled yet, enable it ++ * The default timer period is set to 2 minutes. ++ */ ++#ifdef DEBUG_WDT ++ mtspr(SPRN_TCR, ++ (mfspr(SPRN_TCR) & ~TCR_WP_MASK & ~TCR_WRC_MASK) | ++ TCR_WP(WP_2_29) | ++ TCR_WRC(WRC_SYSTEM)); ++#else ++ mtspr(SPRN_TCR, ++ (mfspr(SPRN_TCR) & ~TCR_WP_MASK & ~TCR_WRC_MASK) | ++ TCR_WP(WP_2_25) | ++ TCR_WRC(WRC_SYSTEM)); ++#endif ++ } ++ ++ if (wdt_period == 0) ++ wdt_period = WDT_DEFAULT_PERIOD; ++ ++ wdt_count = wdt_period * HZ; ++ ppc405wd_update_timer(); ++ wdt_enable = 1; ++ mtspr(SPRN_TSR, (TSR_ENW | TSR_WIS)); ++ return 0; ++} ++ ++static int ppc405wd_release(struct inode *inode, struct file *file) ++{ ++ MOD_DEC_USE_COUNT; ++ ++ clear_bit(0,&ppc405wd_opened); ++ return 0; ++} ++ ++static ssize_t ppc405wd_write(struct file *file, const char *data, size_t len, loff_t *ppos) ++{ ++ /* Can't seek (pwrite) on this device */ ++ if (ppos != &file->f_pos) ++ return -ESPIPE; ++ ++ if (len) { ++ ppc405wd_update_timer(); ++ return 1; ++ } ++ return 0; ++} ++ ++static int ppc405wd_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ unsigned long period; ++ int status; ++ int state; ++ static struct watchdog_info ident = { ++ WDIOF_KEEPALIVEPING, ++ 0, ++ "PPC 405 watchdog" ++ }; ++ ++ switch (cmd) { ++ case WDIOC_GETSTATUS: ++ status = ppc405wd_opened; ++ ++ if (copy_to_user((int *)arg, &status, sizeof(int))) ++ return -EFAULT; ++ break; ++ case WDIOC_GETSUPPORT: ++ if (copy_to_user((struct watchdog_info *)arg, &ident, ++ sizeof(ident))) { ++ return -EFAULT; ++ } ++ break; ++ case WDIOC_KEEPALIVE: ++ ppc405wd_update_timer(); ++ break; ++ case WDIOC_SETOPTIONS: ++ if(copy_from_user(&state, (int*) arg, sizeof(int))) ++ return -EFAULT; ++ if (state & WDIOS_DISABLECARD) { ++ wdt_enable = 0; ++ printk(KERN_NOTICE "Soft watchdog timer is disabled\n"); ++ break; ++ } ++ if (state & WDIOS_ENABLECARD) { ++ ppc405wd_update_timer(); ++ wdt_enable = 1; ++ mtspr(SPRN_TSR, (TSR_ENW | TSR_WIS)); ++ printk(KERN_NOTICE "Soft watchdog timer is enabled\n"); ++ break; ++ } ++ case WDIOC_GETPERIOD: ++ /* return watchdog period (units = microseconds) */ ++ period = (wdt_period / HZ) * MICROSECBASE; ++ if (copy_to_user((unsigned long *)arg, &period, ++ sizeof(period))) { ++ return -EFAULT; ++ } ++ break; ++ case WDIOC_SETPERIOD: ++ /* ++ ** set watchdog period (units = microseconds) ++ ** value of zero means maximum ++ ** ++ ** Don't set a watchdog period to a value less than ++ ** the requested value (period will be rounded up to ++ ** next available interval the watchdog supports). ++ ** ++ ** The software watchdog will expire at some point in ++ ** the range of (rounded up period) .. ++ ** (rounded up period + 1 jiffie). If interrupts are ++ ** disabled so that the software watchdog is unable to ++ ** reset the system, then the hardware watchdog will ++ ** eventually reset the system. ++ */ ++ if (copy_from_user(&period, (unsigned long *)arg, ++ sizeof(period))) { ++ return -EFAULT; ++ } ++ ++ /* ++ ** This code assumes HZ is 100. Need to remove that ++ ** assumption. ++ */ ++ ++ /* ++ ** The minimum period of ppc405wd_timer is a jiffie, ++ ** which is 10 msec when HZ is 100. The units of ++ ** wdt_period is jiffies. ++ ** ++ ** The new timer period will be used at the next ++ ** heartbeat. ++ */ ++ if (period == 0) ++ period = MAXONEHOUR * MICROSECBASE; ++ ++ wdt_count = (period / TENMSBASE) + (period % TENMSBASE ? 1 : 0); ++ ppc405wd_update_timer(); ++ ++ break; ++ default: ++ return -ENOIOCTLCMD; ++ ++ } ++ return 0; ++} ++ ++static struct file_operations ppc405wd_fops = ++{ ++ owner: THIS_MODULE, ++ write: ppc405wd_write, ++ ioctl: ppc405wd_ioctl, ++ open: ppc405wd_open, ++ release: ppc405wd_release, ++}; ++ ++static struct miscdevice ppc405wd_miscdev = ++{ ++ WATCHDOG_MINOR, ++ "405_watchdog", ++ &ppc405wd_fops ++}; ++ ++static int __init ppc405wd_init(void) ++{ ++ misc_register(&ppc405wd_miscdev); ++ printk(KERN_NOTICE "PPC 405 watchdog driver v%s\n", VERSION); ++ if (wdt_period == 0) ++ wdt_period = WDT_DEFAULT_PERIOD; ++ wdt_count = wdt_period * HZ; ++ ppc405wd_update_timer(); ++ mtspr(SPRN_TSR, (TSR_ENW | TSR_WIS)); ++ mtspr(SPRN_TCR, TCR_PIE | TCR_ARE); ++ return 0; ++} ++ ++void __exit ppc405wd_exit(void) ++{ ++ misc_deregister(&ppc405wd_miscdev); ++} ++ ++module_init(ppc405wd_init); ++module_exit(ppc405wd_exit); +diff -Narup linux-2.4.31-orig/include/asm-ppc/machdep.h linux-2.4.31/include/asm-ppc/machdep.h +--- linux-2.4.31-orig/include/asm-ppc/machdep.h 2003-08-25 04:44:44.000000000 -0700 ++++ linux-2.4.31/include/asm-ppc/machdep.h 2005-08-10 15:13:37.000000000 -0700 +@@ -41,6 +41,8 @@ struct machdep_calls { + unsigned long (*get_rtc_time)(void); + void (*calibrate_decr)(void); + void (*heartbeat)(void); ++ unsigned long heartbeat_reset; ++ unsigned long heartbeat_count; + + unsigned long (*find_end_of_memory)(void); + void (*setup_io_mappings)(void); +diff -Narup linux-2.4.31-orig/include/asm-ppc/processor.h linux-2.4.31/include/asm-ppc/processor.h +--- linux-2.4.31-orig/include/asm-ppc/processor.h 2005-04-03 18:42:20.000000000 -0700 ++++ linux-2.4.31/include/asm-ppc/processor.h 2005-08-10 15:10:17.000000000 -0700 +@@ -455,11 +455,13 @@ + #define WP_2_21 1 /* 2^21 clocks */ + #define WP_2_25 2 /* 2^25 clocks */ + #define WP_2_29 3 /* 2^29 clocks */ ++#define TCR_WP_MASK TCR_WP(3) + #define TCR_WRC(x) (((x)&0x3)<<28) /* WDT Reset Control */ + #define WRC_NONE 0 /* No reset will occur */ + #define WRC_CORE 1 /* Core reset will occur */ + #define WRC_CHIP 2 /* Chip reset will occur */ + #define WRC_SYSTEM 3 /* System reset will occur */ ++#define TCR_WRC_MASK TCR_WRC(3) + #define TCR_WIE 0x08000000 /* WDT Interrupt Enable */ + #define TCR_PIE 0x04000000 /* PIT Interrupt Enable */ + #define TCR_DIE TCR_PIE /* DEC Interrupt Enable */ diff --git a/kernel/patches-2.4.31/redwood.c b/kernel/patches-2.4.31/redwood.c new file mode 100644 index 0000000..7619e85 --- /dev/null +++ b/kernel/patches-2.4.31/redwood.c @@ -0,0 +1,499 @@ +/* + * redwood.c - mapper for IBM Redwood-4/5/6 board. + * + * + * Copyright 2001 - 2002 MontaVista Softare 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 the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * History: 12/17/2001 - Armin + * migrated to use do_map_probe + * + * : 07/11/02 - Armin + * added redwood 6 support + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#define STBXX_VPD_SZ 0x10000 +#define STBXX_OB_SZ 0x20000 +#define STBXX_4MB 0x4000000 + +#if !defined (CONFIG_REDWOOD_6) + +#define WINDOW_ADDR 0xffc00000 +#define WINDOW_SIZE 0x00400000 + +#define RW_PART0_OF 0 +#define RW_PART0_SZ 0x10000 +#define RW_PART1_OF RW_PART0_SZ +#define RW_PART1_SZ 0x200000 - 0x10000 +#define RW_PART2_OF 0x200000 +#define RW_PART2_SZ 0x10000 +#define RW_PART3_OF 0x210000 +#define RW_PART3_SZ 0x200000 - (0x10000 + 0x20000) +#define RW_PART4_OF 0x3e0000 +#define RW_PART4_SZ 0x20000 +static struct mtd_partition redwood_flash_partitions[] = { + { + name: "Redwood OpenBIOS Vital Product Data", + offset: RW_PART0_OF, + size: RW_PART0_SZ, + mask_flags: MTD_WRITEABLE /* force read-only */ + }, + { + name: "Redwood kernel", + offset: RW_PART1_OF, + size: RW_PART1_SZ + }, + { + name: "Redwood OpenBIOS non-volatile storage", + offset: RW_PART2_OF, + size: RW_PART2_SZ, + mask_flags: MTD_WRITEABLE /* force read-only */ + }, + { + name: "Redwood filesystem", + offset: RW_PART3_OF, + size: RW_PART3_SZ + }, + { + name: "Redwood OpenBIOS", + offset: RW_PART4_OF, + size: RW_PART4_SZ, + mask_flags: MTD_WRITEABLE /* force read-only */ + } +}; + +#else + +/* FIXME: the window is bigger - armin */ + +/* + * Change4VideoDongle - H. Lin + * Warnning: What effects would be if not end on erase block size?? + * Thus combine VPD,NVRAM,into one 64KB partition, named VPD + */ +#if 1 //hcw + +/* Supported Devices on HCW MediaMVP */ +#define AMD2048X16K +#define AMD512X16K + +#ifdef AMD2048X16K + +#define MB4_WINDOW_ADDR 0xffc00000 /* 4MB part */ +#define MB4_WINDOW_SIZE 0x00400000 /* to hook GPIO Pin26 (BI_ADDR10) to A20 */ + +#define MB4_RW_PART0_OF 0x000000 +#define MB4_RW_PART0_SZ 0x2c0000 +/* +#define MB4_RW_PART0_SZ 0x2c0000 + +#define MB4_RW_PART5_OF MB4_RW_PART0_OF + MB4_RW_PART0_SZ +#define MB4_RW_PART5_SZ 0x200000 + +#define MB4_RW_PART4_OF MB4_RW_PART5_OF + MB4_RW_PART5_SZ +*/ +#define MB4_RW_PART4_OF MB4_RW_PART0_OF + MB4_RW_PART0_SZ +#define MB4_RW_PART4_SZ 0x100000 + +#define MB4_RW_PART1_OF MB4_RW_PART4_OF + MB4_RW_PART4_SZ +#define MB4_RW_PART1_SZ 0x010000 /* 64KB VPD = 4KB VPD + 4KB NVRAM */ + +#define MB4_RW_PART2_OF MB4_RW_PART1_OF + MB4_RW_PART1_SZ +#define MB4_RW_PART2_SZ 0x010000 /* 64KB LOGO = 56KB LOGO + 8KB XXX */ + +#define MB4_RW_PART3_OF MB4_RW_PART2_OF + MB4_RW_PART2_SZ /* 128KB Bootloader(Open BIOS) */ +#define MB4_RW_PART3_SZ 0x020000 + +static struct mtd_partition mb4_redwood_flash_partitions[] = { + { + name: "HCW MediaMVP KERN", + offset: MB4_RW_PART0_OF, + size: MB4_RW_PART0_SZ, + }, +/* + { + name: "HCW MediaMVP FS", + offset: MB4_RW_PART5_OF, + size: MB4_RW_PART5_SZ, + }, +*/ + { + name: "HCW MediaMVP DATA", + offset: MB4_RW_PART4_OF, + size: MB4_RW_PART4_SZ, + }, + { + name: "HCW MediaMVP VPD", + offset: MB4_RW_PART1_OF, + size: MB4_RW_PART1_SZ, + }, + { + name: "HCW MediaMVP LOGO", + offset: MB4_RW_PART2_OF, + size: MB4_RW_PART2_SZ, + }, + { + name: "HCW MediaMVP BOOT", + offset: MB4_RW_PART3_OF, + size: MB4_RW_PART3_SZ, + } +}; + +#endif + + +#ifdef AMD512X16K + +#define MB1_WINDOW_ADDR 0xfff00000 +#define MB1_WINDOW_SIZE 0x00100000 + +#define MB1_RW_PART0_OF 0 +#define MB1_RW_PART0_SZ 0x80000 /* 8*64 = 512KB data */ + +#define MB1_RW_PART1_OF MB1_RW_PART0_OF + MB1_RW_PART0_SZ +#define MB1_RW_PART1_SZ 0x10000 /* 64KB VPD = 4KB VPD + 4KB NVRAM */ + +#define MB1_RW_PART2_OF MB1_RW_PART1_OF + MB1_RW_PART1_SZ +#define MB1_RW_PART2_SZ 0x10000 /* 64KB LOGO = 56KB LOGO + 8KB XXX */ + +#define MB1_RW_PART3_OF MB1_RW_PART2_OF + MB1_RW_PART2_SZ +#define MB1_RW_PART3_SZ 0x80000-0x20000-0x20000 /* 320 - 64 = 256KB File System */ + +#define MB1_RW_PART4_OF MB1_RW_PART3_OF + MB1_RW_PART3_SZ /* 128KB Bootloader(Open BIOS) */ +#define MB1_RW_PART4_SZ 0x20000 + +static struct mtd_partition mb1_redwood_flash_partitions[] = { + { + name: "HCW MediaMVP KERN", + offset: MB1_RW_PART0_OF, + size: MB1_RW_PART0_SZ, + }, + { + name: "HCW MediaMVP VPD", + offset: MB1_RW_PART1_OF, + size: MB1_RW_PART1_SZ, + //mask_flags: MTD_WRITEABLE /* force read-only */ + }, + { + name: "HCW MediaMVP LOGO", + offset: MB1_RW_PART2_OF, + size: MB1_RW_PART2_SZ, + //mask_flags: MTD_WRITEABLE /* force read-only */ + }, + { + name: "HCW MediaMVP FS", + offset: MB1_RW_PART3_OF, + size: MB1_RW_PART3_SZ, + }, + { + name: "HCW MediaMVP BOOT", + offset: MB1_RW_PART4_OF, + size: MB1_RW_PART4_SZ, + //mask_flags: MTD_WRITEABLE /* force read-only */ + } +}; +#endif + +#ifdef AMD128X16K + +#define MBQ_WINDOW_ADDR 0xfffC0000 +#define MBQ_WINDOW_SIZE 0x00040000 + +#define MBQ_RW_PART0_OF 0 +#define MBQ_RW_PART0_SZ 0x10000 /* 64KB VPD (4KB VPD + 4KB NVRAM) */ + +#define MBQ_RW_PART1_OF MBQ_RW_PART0_OF + MBQ_RW_PART0_SZ +#define MBQ_RW_PART1_SZ 0x10000 /* 64KB Logo */ + +#define MBQ_RW_PART2_OF MBQ_RW_PART1_OF + MBQ_RW_PART1_SZ +#define MBQ_RW_PART2_SZ 0x20000 /* 128KB Bootloader(Open BIOS) */ + + +static struct mtd_partition mbq_redwood_flash_partitions[] = { + { + name: "HCW MediaMVP VPD", + offset: MBQ_RW_PART0_OF, + size: MBQ_RW_PART0_SZ, + //mask_flags: MTD_WRITEABLE /* force read-only */ + }, + { + name: "HCW MediaMVP LOGO", + offset: MBQ_RW_PART1_OF, + size: MBQ_RW_PART1_SZ, + //mask_flags: MTD_WRITEABLE /* force read-only */ + }, + { + name: "HCW MediaMVP BOOT", + offset: MBQ_RW_PART2_OF, + size: MBQ_RW_PART2_SZ, + //mask_flags: MTD_WRITEABLE /* force read-only */ + } +}; + +#endif + +#else //org + +#define WINDOW_ADDR 0xff800000 +#define WINDOW_SIZE 0x00800000 + +#define RW_PART0_OF 0 +#define RW_PART0_SZ 0x400000 /* 4 MB data */ +#define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ +#define RW_PART1_SZ 0x10000 /* 64K VPD */ +#define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ +#define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000) +#define RW_PART3_OF RW_PART2_OF + RW_PART2_SZ +#define RW_PART3_SZ 0x20000 + +static struct mtd_partition redwood_flash_partitions[] = { + { + name: "Redwood kernel", + offset: RW_PART0_OF, + size: RW_PART0_SZ + }, + { + name: "Redwood OpenBIOS Vital Product Data", + offset: RW_PART1_OF, + size: RW_PART1_SZ, + mask_flags: MTD_WRITEABLE /* force read-only */ + }, + { + name: "Redwood filesystem", + offset: RW_PART2_OF, + size: RW_PART2_SZ + }, + { + name: "Redwood OpenBIOS", + offset: RW_PART3_OF, + size: RW_PART3_SZ, + mask_flags: MTD_WRITEABLE /* force read-only */ + } +}; + +#endif + +#endif + +__u8 redwood_flash_read8(struct map_info *map, unsigned long ofs) +{ + return *(__u8 *)(map->map_priv_1 + ofs); +} + +__u16 redwood_flash_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *)(map->map_priv_1 + ofs); +} + +__u32 redwood_flash_read32(struct map_info *map, unsigned long ofs) +{ + return *(volatile unsigned int *)(map->map_priv_1 + ofs); +} + +void redwood_flash_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + +void redwood_flash_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + *(__u8 *)(map->map_priv_1 + adr) = d; +} + +void redwood_flash_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *)(map->map_priv_1 + adr) = d; +} + +void redwood_flash_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + *(__u32 *)(map->map_priv_1 + adr) = d; +} + +void redwood_flash_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + memcpy((void *)(map->map_priv_1 + to), from, len); +} + + + +struct map_info redwood_flash_map = { + name: "HCW MediaMVP", +// size: WINDOW_SIZE, + buswidth: 2, + read8: redwood_flash_read8, + read16: redwood_flash_read16, + read32: redwood_flash_read32, + copy_from: redwood_flash_copy_from, + write8: redwood_flash_write8, + write16: redwood_flash_write16, + write32: redwood_flash_write32, + copy_to: redwood_flash_copy_to +}; + +#define NUM_REDWOOD_FLASH_PARTITIONS(flash_partitions) \ + (sizeof(flash_partitions)/sizeof((flash_partitions)[0])) + + +static struct mtd_info *redwood_mtd; + +int __init init_redwood_flash(void) +{ + int numparts; + struct mtd_partition *redwood_flash_partitions; + +#ifdef AMD512X16K + /* + * Am29LV800/200BT does NOT seem to do CFI + */ + redwood_flash_map.map_priv_1 = + (unsigned long)ioremap(MB1_WINDOW_ADDR, MB1_WINDOW_SIZE); + + if (!redwood_flash_map.map_priv_1) { + printk("init_redwood_flash: failed to ioremap\n"); + return -EIO; + } + + printk(KERN_NOTICE "HCW MediaMVP: flash mapping: %x at %x to %lx\n", + MB1_WINDOW_SIZE, MB1_WINDOW_ADDR, redwood_flash_map.map_priv_1); + + redwood_flash_map.size = MB1_WINDOW_SIZE; + redwood_mtd = do_map_probe("jedec_probe",&redwood_flash_map); + if(redwood_mtd) { + printk("jedec_probe: found redwood_mtd size = %08x\n", redwood_mtd->size); + if( redwood_mtd->size == 0x00100000 ) { + redwood_flash_partitions = mb1_redwood_flash_partitions; + numparts = NUM_REDWOOD_FLASH_PARTITIONS(mb1_redwood_flash_partitions); + printk(KERN_NOTICE "HCW MediaMVP: jedec_probe: add [%d]parts\n", numparts); + goto add_parts; + } else { + map_destroy( redwood_mtd ); + } + } + printk(KERN_NOTICE "HCW MediaMVP: jedec_probe: no known JEDEC part found\n"); + iounmap((void*)(redwood_flash_map.map_priv_1)); + +try_4mb_flash: +#endif + +#ifdef AMD2048X16K + + redwood_flash_map.map_priv_1 = + (unsigned long)ioremap(MB4_WINDOW_ADDR, MB4_WINDOW_SIZE); + + if (!redwood_flash_map.map_priv_1) { + printk("init_redwood_flash: failed to ioremap\n"); + return -EIO; + } + + printk(KERN_NOTICE "HCW MediaMVP: flash mapping: %x at %x to %lx\n", + MB4_WINDOW_SIZE, MB4_WINDOW_ADDR, redwood_flash_map.map_priv_1); + +#if 1 + /* + * do CFI for 320DT + */ + redwood_flash_map.size = MB4_WINDOW_SIZE; + redwood_mtd = do_map_probe("cfi_probe",&redwood_flash_map); + if(redwood_mtd) { + printk("cfi_probe: found redwood_mtd size = %08x\n", redwood_mtd->size); + redwood_flash_partitions = mb4_redwood_flash_partitions; + numparts = NUM_REDWOOD_FLASH_PARTITIONS(mb4_redwood_flash_partitions); + printk(KERN_NOTICE "HCW MediaMVP: cfi_probe: adding [%d]parts\n", numparts); + goto add_parts; + } + else { + printk(KERN_NOTICE "HCW MediaMVP: cfi_probe: no known CFI part found\n"); + iounmap((void*)(redwood_flash_map.map_priv_1)); + } +#endif + +#if 0 + /* + * try jedec too for ST320DT??? + */ + redwood_flash_map.map_priv_1 = + (unsigned long)ioremap(MB4_WINDOW_ADDR, MB4_WINDOW_SIZE); + + if (!redwood_flash_map.map_priv_1) { + printk("init_redwood_flash: failed to ioremap\n"); + return -EIO; + } + + printk(KERN_NOTICE "HCW MediaMVP: flash mapping: %x at %x to %lx\n", + MB4_WINDOW_SIZE, MB4_WINDOW_ADDR, redwood_flash_map.map_priv_1); + + redwood_flash_map.size = MB4_WINDOW_SIZE; + redwood_mtd = do_map_probe("jedec_probe",&redwood_flash_map); + if(redwood_mtd) { + printk("jedec_probe: found redwood_mtd size = %08x\n", redwood_mtd->size); + redwood_flash_partitions = mb4_redwood_flash_partitions; + numparts = NUM_REDWOOD_FLASH_PARTITIONS(mb4_redwood_flash_partitions); + printk(KERN_NOTICE "HCW MediaMVP: jedec_probe: adding [%d]parts\n", numparts); + goto add_parts; + } + else { + printk(KERN_NOTICE "HCW MediaMVP: jedec_probe: no known CFI part found\n"); + iounmap((void*)(redwood_flash_map.map_priv_1)); + } +#endif +#endif + + +add_parts: + if (redwood_mtd) { + redwood_mtd->module = THIS_MODULE; + return add_mtd_partitions(redwood_mtd, redwood_flash_partitions, numparts); + } + + return -ENXIO; +} + +static void __exit cleanup_redwood_flash(void) +{ + if (redwood_mtd) { + del_mtd_partitions(redwood_mtd); + /* moved iounmap after map_destroy -armin*/ + map_destroy(redwood_mtd); + iounmap((void *)redwood_flash_map.map_priv_1); + } +} + +module_init(init_redwood_flash); +module_exit(cleanup_redwood_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Armin Kuster "); +MODULE_DESCRIPTION("MTD map driver for the IBM Redwood reference boards"); diff --git a/kernel/patches-2.4.31/sdram-bank1.patch b/kernel/patches-2.4.31/sdram-bank1.patch new file mode 100644 index 0000000..203022c --- /dev/null +++ b/kernel/patches-2.4.31/sdram-bank1.patch @@ -0,0 +1,266 @@ +diff -Narup linux-2.4.31-orig/arch/ppc/boot/simple/Makefile linux-2.4.31/arch/ppc/boot/simple/Makefile +--- linux-2.4.31-orig/arch/ppc/boot/simple/Makefile 2005-12-14 15:16:26.000000000 +0800 ++++ linux-2.4.31/arch/ppc/boot/simple/Makefile 2006-01-15 17:28:42.000000000 +0800 +@@ -152,6 +152,7 @@ zImage: $(ZIMAGE) + rm -f zvmlinux + zImage.initrd: $(ZIMAGEINITRD) + rm -f zvmlinux.initrd ++ cp -f ../images/zImage.initrd.$(END) $(INSTALL_PATH)/dongle.bin + + znetboot: zImage + cp ../images/zImage.$(END) $(TFTPIMAGE) +diff -Narup linux-2.4.31-orig/arch/ppc/boot/simple/misc-embedded.c linux-2.4.31/arch/ppc/boot/simple/misc-embedded.c +--- linux-2.4.31-orig/arch/ppc/boot/simple/misc-embedded.c 2005-12-14 16:27:53.000000000 +0800 ++++ linux-2.4.31/arch/ppc/boot/simple/misc-embedded.c 2006-01-15 17:28:42.000000000 +0800 +@@ -221,6 +221,7 @@ load_kernel(unsigned long load_addr, int + gunzip(0, 0x400000, zimage_start, &zimage_size); + flush_instruction_cache(); + puts("done.\n"); ++#ifdef CONFIG_BLK_DEV_INITRD + { + struct bi_record *rec; + unsigned long initrd_loc; +@@ -271,6 +272,31 @@ load_kernel(unsigned long load_addr, int + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } ++#else ++ { ++ /* Moving Squash Rootfs to sdram bank1 */ ++ if(initrd_size){ ++ #define MAGIC_VER_HCW 0x48435720 ++ #define MAGIC_VER_MVP 0x4D565000 ++ unsigned long *magic_hcw; ++ unsigned long *magic_mvp; ++ unsigned long *initrd_sz; ++ ++ magic_hcw = 0xa0fff200; ++ magic_mvp = 0xa0fff204; ++ /* if there is no magic number on new xram_start + 512 bytes, we assume ++ * system boot first time then move boot data into new xram position. */ ++ if( *magic_hcw != MAGIC_VER_HCW && *magic_mvp != MAGIC_VER_MVP ){ ++ puts("\nMoving xram data to 0xa0fff000\n"); ++ memcpy((void*)(0xa0fff000), (void*)(0xa0f00000), 0x1000); ++ } ++ puts("Moving initrd to 0xa0d00000\n"); ++ memcpy((void*)(0xa0d00000), &__ramdisk_begin, initrd_size); ++ /* writing initrd size into bottom of bank1 memory */ ++ memcpy((void*)0xa0fffffc, &initrd_size, 4); ++ } ++ } ++#endif + puts("Now booting the kernel\n"); + serial_close(com_port); + +diff -Narup linux-2.4.31-orig/drivers/mtd/maps/Config.in linux-2.4.31/drivers/mtd/maps/Config.in +--- linux-2.4.31-orig/drivers/mtd/maps/Config.in 2005-12-14 15:16:07.000000000 +0800 ++++ linux-2.4.31/drivers/mtd/maps/Config.in 2006-01-15 17:28:22.000000000 +0800 +@@ -45,6 +45,7 @@ if [ "$CONFIG_PPC" = "y" ]; then + dep_tristate ' CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI + dep_tristate ' CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI + dep_tristate ' CFI Flash device mapped on IBM Redwood-4/5' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI ++ dep_tristate ' SDRAM device mapping on Hauppauge MVP' CONFIG_MTD_MVP_RAM $CONFIG_MTD_CFI + fi + + if [ "$CONFIG_MIPS" = "y" ]; then +diff -Narup linux-2.4.31-orig/drivers/mtd/maps/Makefile linux-2.4.31/drivers/mtd/maps/Makefile +--- linux-2.4.31-orig/drivers/mtd/maps/Makefile 2005-12-14 15:16:07.000000000 +0800 ++++ linux-2.4.31/drivers/mtd/maps/Makefile 2006-01-15 17:28:22.000000000 +0800 +@@ -61,5 +61,6 @@ obj-$(CONFIG_MTD_REDWOOD) += redwood.o + obj-$(CONFIG_MTD_UCLINUX) += uclinux.o + obj-$(CONFIG_MTD_NETtel) += nettel.o + obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o ++obj-$(CONFIG_MTD_MVP_RAM) += ramdisk.o + + include $(TOPDIR)/Rules.make +diff -Narup linux-2.4.31-orig/drivers/mtd/maps/ramdisk.c linux-2.4.31/drivers/mtd/maps/ramdisk.c +--- linux-2.4.31-orig/drivers/mtd/maps/ramdisk.c 1970-01-01 08:00:00.000000000 +0800 ++++ linux-2.4.31/drivers/mtd/maps/ramdisk.c 2006-01-15 17:28:22.000000000 +0800 +@@ -0,0 +1,187 @@ ++/* ++ * HCW sdram mtd Driver ++ */ ++#include ++#include ++ ++#include ++#include ++ ++#if CONFIG_MODVERSIONS == 1 ++#define MODVERSIONS ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#define KDBG(fmt, args...) if(1) printk(": " fmt, ## args) ++ ++ ++#define __PHYSICAL_ROOTFS_BASE 0xA0D00000 ++#define __PHYSICAL_ROOTFS_SIZE_BASE 0xA0FFFFFC ++#define __PHYSICAL_ROOTFS_END_BASE 0xA0FFF000 ++#define __PHYSICAL_TOTAL_SIZE 0x002FF000 ++ ++#define GetRootSize() {return (*rootfs_size)} ++ ++ ++// ++// read/write function. ++// ++static __u8 sdram_read8(struct map_info *map, unsigned long ofs) ++{ ++ return readb(map->map_priv_1 + ofs); ++} ++ ++static __u16 sdram_read16(struct map_info *map, unsigned long ofs) ++{ ++ return readw(map->map_priv_1 + ofs); ++} ++ ++static __u32 sdram_read32(struct map_info *map, unsigned long ofs) ++{ ++ return readl(map->map_priv_1 + ofs); ++} ++ ++static void sdram_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) ++{ ++ memcpy(to, (void *)(map->map_priv_1 + from), len); ++} ++ ++static void sdram_write8(struct map_info *map, __u8 d, unsigned long adr) ++{ ++ writeb(d, map->map_priv_1 + adr); ++} ++ ++static void sdram_write16(struct map_info *map, __u16 d, unsigned long adr) ++{ ++ writew(d, map->map_priv_1 + adr); ++} ++ ++static void sdram_write32(struct map_info *map, __u32 d, unsigned long adr) ++{ ++ writel(d, map->map_priv_1 + adr); ++} ++ ++static void sdram_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) ++{ ++ memcpy((void *)(map->map_priv_1 + to), from, len); ++} ++ ++static struct mtd_partition hcwmvp_sdram_partitions[] = { ++ { ++ name: "HCW MediaMVP ROOT", ++ offset: 0x00000000 , ++ }, ++ { ++ name: "HCW MediaMVP OSD", ++ }, ++}; ++ ++// ++// sdram mtd map structure. ++// ++struct map_info hcwmvp_sdram_map = { ++ name:"SDRAM MTD Device", ++ buswidth: 2, ++ read8: sdram_read8, ++ read16: sdram_read16, ++ read32: sdram_read32, ++ copy_from: sdram_copy_from, ++ write8: sdram_write8, ++ write16: sdram_write16, ++ write32: sdram_write32, ++ copy_to: sdram_copy_to ++}; ++static struct mtd_info *hcwmvp_sdram_mtd=NULL; ++ ++static unsigned long ++sdram_init(void) ++{ ++ /* ++ * I/O Remap ++ */ ++ hcwmvp_sdram_map.map_priv_1 = ++ (unsigned long)ioremap(__PHYSICAL_ROOTFS_BASE, __PHYSICAL_TOTAL_SIZE); ++ if (!hcwmvp_sdram_map.map_priv_1) { ++ KDBG("sdram-1 MTD device map failed\n"); ++ return 0; ++ } ++ hcwmvp_sdram_map.map_priv_2 = (unsigned long)ioremap(__PHYSICAL_ROOTFS_SIZE_BASE, 4); ++ if (!hcwmvp_sdram_map.map_priv_2) { ++ KDBG("sdram-2 MTD device map failed\n"); ++ return 0; ++ } ++ ++ KDBG("SDRAM MTD(%8.8X) mapped to %08x\n", (int)__PHYSICAL_ROOTFS_BASE, (int)hcwmvp_sdram_map.map_priv_1); ++ ++ return 1; ++} ++ ++/* ++ * module interface ++ */ ++static int __init ++sdram_init_module(void) ++{ ++ unsigned int root_size=0; ++ /* ++ * Probe & reset Device ++ */ ++ if(!sdram_init()) { ++ KDBG("sdram Module Init Failed: Wrong Dev\n"); ++ return -1; ++ } ++ ++ /* ++ * register mtd device ++ */ ++ hcwmvp_sdram_map.size = __PHYSICAL_TOTAL_SIZE; ++ hcwmvp_sdram_mtd = do_map_probe("map_ram",&hcwmvp_sdram_map); ++ if (hcwmvp_sdram_mtd) { ++ hcwmvp_sdram_mtd->module = THIS_MODULE; ++ //hcwmvp_sdram_mtd->erasesize = 0xF0000; ++ //add_mtd_device(hcwmvp_sdram_mtd); ++ root_size = in_be32((u32*)hcwmvp_sdram_map.map_priv_2); ++ //root_size |= in_be16((u16*)(hcwmvp_sdram_map.map_priv_2+2)); ++ //KDBG("root_size =%x \n", root_size); ++ hcwmvp_sdram_partitions[0].size = root_size; ++ hcwmvp_sdram_partitions[1].offset = root_size; ++ hcwmvp_sdram_partitions[1].size = __PHYSICAL_TOTAL_SIZE - root_size; ++ add_mtd_partitions(hcwmvp_sdram_mtd, hcwmvp_sdram_partitions, 2); ++ } ++ else{ ++ iounmap((void*)(hcwmvp_sdram_map.map_priv_1)); ++ } ++ ++ return 0; ++} ++ ++static void __exit ++sdram_cleanup_module(void) ++{ ++ /* unregister mtd device. */ ++ //if (hcwmvp_sdram_mtd) del_mtd_device(hcwmvp_sdram_mtd); ++ if (hcwmvp_sdram_mtd){ ++ del_mtd_partitions(hcwmvp_sdram_mtd); ++ map_destroy(hcwmvp_sdram_mtd); ++ } ++ if (hcwmvp_sdram_map.map_priv_1 != -1) iounmap((void *)hcwmvp_sdram_map.map_priv_1); ++} ++module_init(sdram_init_module); ++module_exit(sdram_cleanup_module); ++MODULE_LICENSE("GPL"); diff --git a/kernel/patches-2.4.31/smc91111.patch b/kernel/patches-2.4.31/smc91111.patch new file mode 100644 index 0000000..27b520e --- /dev/null +++ b/kernel/patches-2.4.31/smc91111.patch @@ -0,0 +1,4500 @@ +diff -Narup linux-2.4.31-orig/drivers/net/Config.in linux-2.4.31/drivers/net/Config.in +--- linux-2.4.31-orig/drivers/net/Config.in 2005-01-19 06:09:56.000000000 -0800 ++++ linux-2.4.31/drivers/net/Config.in 2005-08-03 09:52:16.000000000 -0700 +@@ -116,6 +116,19 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; the + dep_tristate ' SMC Ultra support' CONFIG_ULTRA $CONFIG_ISA + dep_tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA + dep_tristate ' SMC 9194 support' CONFIG_SMC9194 $CONFIG_ISA ++ tristate ' SMC 91111 support' CONFIG_SMC91111 ++ if [ "$CONFIG_SMC91111" != "n" ]; then ++ bool ' Advanced configuration options for SMC91111' CONFIG_SMC91111_ADVANCED ++ if [ "$CONFIG_SMC91111_ADVANCED" = "n" ]; then ++ define_bool CONFIG_SMC91111_BYTE_SWAP n ++ define_bool CONFIG_SMC91111_USE_8_BIT y ++ define_bool CONFIG_SMC91111_USE_32_BIT y ++ else ++ bool ' Byte swap device accesses' CONFIG_SMC91111_BYTE_SWAP ++ bool ' Allow 8 bit device accesses' CONFIG_SMC91111_USE_8_BIT ++ bool ' Allow 32 bit device accesses' CONFIG_SMC91111_USE_32_BIT ++ fi ++ fi + fi + bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL + if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then +diff -Narup linux-2.4.31-orig/drivers/net/Makefile linux-2.4.31/drivers/net/Makefile +--- linux-2.4.31-orig/drivers/net/Makefile 2005-01-19 06:09:56.000000000 -0800 ++++ linux-2.4.31/drivers/net/Makefile 2005-08-03 10:17:28.000000000 -0700 +@@ -139,6 +139,7 @@ obj-$(CONFIG_SHAPER) += shaper.o + obj-$(CONFIG_SK_G16) += sk_g16.o + obj-$(CONFIG_HP100) += hp100.o + obj-$(CONFIG_SMC9194) += smc9194.o ++obj-$(CONFIG_SMC91111) += smc91111.o + obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o + obj-$(CONFIG_ARM_ETHERH) += 8390.o + obj-$(CONFIG_WD80x3) += wd.o 8390.o +diff -Narup linux-2.4.31-orig/drivers/net/smc91111.c linux-2.4.31/drivers/net/smc91111.c +--- linux-2.4.31-orig/drivers/net/smc91111.c 1969-12-31 16:00:00.000000000 -0800 ++++ linux-2.4.31/drivers/net/smc91111.c 2005-08-03 09:52:34.000000000 -0700 +@@ -0,0 +1,3746 @@ ++/*------------------------------------------------------------------------ ++ . smc91111.c ++ . This is a driver for SMSC's 91C111 single-chip Ethernet device. ++ . ++ . Copyright (C) 2001 Standard Microsystems Corporation (SMSC) ++ . Developed by Simple Network Magic Corporation (SNMC) ++ . Copyright (C) 1996 by Erik Stahlman (ES) ++ . ++ . 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 ++ . ++ . Information contained in this file was obtained from the LAN91C111 ++ . manual from SMC. To get a copy, if you really want one, you can find ++ . information under www.smsc.com. ++ . ++ . ++ . "Features" of the SMC chip: ++ . Integrated PHY/MAC for 10/100BaseT Operation ++ . Supports internal and external MII ++ . Integrated 8K packet memory ++ . EEPROM interface for configuration ++ . ++ . Arguments: ++ . io = for the base address ++ . irq = for the IRQ ++ . nowait = 0 for normal wait states, 1 eliminates additional wait states ++ . ++ . author: ++ . Erik Stahlman ( erik@vt.edu ) ++ . Daris A Nevil ( dnevil@snmc.com ) ++ . contributors: ++ . Arnaldo Carvalho de Melo ++ . ++ . Hardware multicast code from Peter Cammaert ( pc@denkart.be ) ++ . ++ . Sources: ++ . o SMSC LAN91C111 databook (www.smsc.com) ++ . o smc9194.c by Erik Stahlman ++ . o skeleton.c by Donald Becker ( becker@scyld.com ) ++ . ++ . History: ++ . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet ++ . 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" ++ . 04/25/01 Daris A Nevil Initial public release through SMSC ++ . 03/16/01 Daris A Nevil Modified smc9194.c for use with LAN91C111 ++ . 08/22/01 Scott Anderson Merge changes from smc9194 to smc91111 ++ ----------------------------------------------------------------------------*/ ++ ++// Use power-down feature of the chip ++#define POWER_DOWN 1 ++ ++/* ++ . DEBUGGING LEVELS ++ . ++ . 0 for normal operation ++ . 1 for slightly more details ++ . >2 for various levels of increasingly useless information ++ . 2 for interrupt tracking, status flags ++ . 3 for packet info ++ . 4 for complete packet dumps ++*/ ++#ifndef SMC_DEBUG ++#define SMC_DEBUG 0 ++#endif ++ ++static const char version[] = ++ "smc91111.c:v1.0saa 08/22/01 by Daris A Nevil (dnevil@snmc.com)\n"; ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#ifdef CONFIG_SYSCTL ++#include ++#include ++#endif ++ ++#include "smc91111.h" ++ ++#ifdef CONFIG_ISA ++ ++/* ++ .the LAN91C111 can be at any of the following port addresses. To change, ++ .for a slightly different card, you can add it to the array. Keep in ++ .mind that the array must end in zero. ++*/ ++static unsigned int smc_portlist[] __initdata = { ++ 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, ++ 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0 ++}; ++ ++#endif /* CONFIG_ISA */ ++ ++static struct net_device *global_dev = NULL; ++#ifndef SMC91111_BASE_ADDR ++# define SMC91111_BASE_ADDR -1 ++#endif ++static int io = SMC91111_BASE_ADDR; ++#ifndef SMC91111_IRQ ++# define SMC91111_IRQ -1 ++#endif ++static int irq = SMC91111_IRQ; ++static int nowait = 1; //Haup=> ++ ++MODULE_PARM(io, "i"); ++MODULE_PARM(irq, "i"); ++MODULE_PARM(nowait, "i"); ++MODULE_PARM_DESC(io, "SMC 91111 I/O base address"); ++MODULE_PARM_DESC(irq, "SMC 91111 IRQ number"); ++ ++/* ++ . Wait time for memory to be free. This probably shouldn't be ++ . tuned that much, as waiting for this means nothing else happens ++ . in the system ++*/ ++#define MEMORY_WAIT_TIME 16 ++ ++#if SMC_DEBUG > 2 ++#define PRINTK3(args...) printk(args) ++#else ++#define PRINTK3(args...) ++#endif ++ ++#if SMC_DEBUG > 1 ++#define PRINTK2(args...) printk(args) ++#else ++#define PRINTK2(args...) ++#endif ++ ++#if SMC_DEBUG > 0 ++#define PRINTK(args...) printk(args) ++#else ++#define PRINTK(args...) ++#endif ++ ++ ++/*------------------------------------------------------------------------ ++ . ++ . The internal workings of the driver. If you are changing anything ++ . here with the SMC stuff, you should have the datasheet and know ++ . what you are doing. ++ . ++ -------------------------------------------------------------------------*/ ++#define CARDNAME "LAN91C111" ++ ++// Memory sizing constant ++#define LAN91C111_MEMORY_MULTIPLIER (1024*2) ++ ++/* store this information for the driver.. */ ++struct smc_local { ++ ++ // these are things that the kernel wants me to keep, so users ++ // can find out semi-useless statistics of how well the card is ++ // performing ++ struct net_device_stats stats; ++ ++ // If I have to wait until memory is available to send ++ // a packet, I will store the skbuff here, until I get the ++ // desired memory. Then, I'll send it out and free it. ++ struct sk_buff * saved_skb; ++ ++ // This keeps track of how many packets that I have ++ // sent out. When an TX_EMPTY interrupt comes, I know ++ // that all of these have been sent. ++ int packets_waiting; ++ ++ // Set to true during the auto-negotiation sequence ++ int autoneg_active; ++ ++ // Address of our PHY port ++ word phyaddr; ++ ++ // Type of PHY ++ word phytype; ++ ++ // Last contents of PHY Register 18 ++ word lastPhy18; ++ ++ // Contains the current active transmission mode ++ word tcr_cur_mode; ++ ++ // Contains the current active receive mode ++ word rcr_cur_mode; ++ ++ // Contains the current active receive/phy mode ++ word rpc_cur_mode; ++ ++ ++#ifdef CONFIG_SYSCTL ++ ++ // Root directory /proc/sys/dev ++ // Second entry must be null to terminate the table ++ ctl_table root_table[2]; ++ ++ // Directory for this device /proc/sys/dev/ethX ++ // Again the second entry must be zero to terminate ++ ctl_table eth_table[2]; ++ ++ // This is the parameters (file) table ++ ctl_table param_table[CTL_SMC_LAST_ENTRY]; ++ ++ // Saves the sysctl header returned by register_sysctl_table() ++ // we send this to unregister_sysctl_table() ++ struct ctl_table_header *sysctl_header; ++ ++ // Parameter variables (files) go here ++ char ctl_info[1024]; ++ int ctl_swfdup; ++ int ctl_ephloop; ++ int ctl_miiop; ++ int ctl_autoneg; ++ int ctl_rfduplx; ++ int ctl_rspeed; ++ int ctl_afduplx; ++ int ctl_aspeed; ++ int ctl_lnkfail; ++ int ctl_forcol; ++ int ctl_filtcar; ++ int ctl_freemem; ++ int ctl_totmem; ++ int ctl_leda; ++ int ctl_ledb; ++ int ctl_chiprev; ++#if SMC_DEBUG > 0 ++ int ctl_reg_bsr; ++ int ctl_reg_tcr; ++ int ctl_reg_esr; ++ int ctl_reg_rcr; ++ int ctl_reg_ctrr; ++ int ctl_reg_mir; ++ int ctl_reg_rpcr; ++ int ctl_reg_cfgr; ++ int ctl_reg_bar; ++ int ctl_reg_iar0; ++ int ctl_reg_iar1; ++ int ctl_reg_iar2; ++ int ctl_reg_gpr; ++ int ctl_reg_ctlr; ++ int ctl_reg_mcr; ++ int ctl_reg_pnr; ++ int ctl_reg_fpr; ++ int ctl_reg_ptr; ++ int ctl_reg_dr; ++ int ctl_reg_isr; ++ int ctl_reg_mtr1; ++ int ctl_reg_mtr2; ++ int ctl_reg_mtr3; ++ int ctl_reg_mtr4; ++ int ctl_reg_miir; ++ int ctl_reg_revr; ++ int ctl_reg_ercvr; ++ int ctl_reg_extr; ++ int ctl_phy_ctrl; ++ int ctl_phy_stat; ++ int ctl_phy_id1; ++ int ctl_phy_id2; ++ int ctl_phy_adc; ++ int ctl_phy_remc; ++ int ctl_phy_cfg1; ++ int ctl_phy_cfg2; ++ int ctl_phy_int; ++ int ctl_phy_mask; ++#endif // SMC_DEBUG > 0 ++ ++ ++#endif // CONFIG_SYSCTL ++ ++}; ++ ++ ++/*----------------------------------------------------------------- ++ . ++ . The driver can be entered at any of the following entry points. ++ . ++ .------------------------------------------------------------------ */ ++ ++/* ++ . The kernel calls this function when someone wants to use the device, ++ . typically 'ifconfig ethX up'. ++*/ ++static int smc_open(struct net_device *dev); ++ ++/* ++ . Our watchdog timed out. Called by the networking layer ++*/ ++static void smc_timeout(struct net_device *dev); ++ ++/* ++ . This is called by the kernel in response to 'ifconfig ethX down'. It ++ . is responsible for cleaning up everything that the open routine ++ . does, and maybe putting the card into a powerdown state. ++*/ ++static int smc_close(struct net_device *dev); ++ ++/* ++ . This routine allows the proc file system to query the driver's ++ . statistics. ++*/ ++static struct net_device_stats * smc_query_statistics( struct net_device *dev); ++ ++/* ++ . Finally, a call to set promiscuous mode ( for TCPDUMP and related ++ . programs ) and multicast modes. ++*/ ++static void smc_set_multicast_list(struct net_device *dev); ++ ++/* ++ . CRC compute ++ */ ++static int crc32( char * s, int length ); ++ ++/* ++ . Configures the PHY through the MII Management interface ++*/ ++static void smc_phy_configure(struct net_device* dev); ++ ++/*--------------------------------------------------------------- ++ . ++ . Interrupt level calls.. ++ . ++ ----------------------------------------------------------------*/ ++ ++/* ++ . Handles the actual interrupt ++*/ ++static void smc_interrupt(int irq, void *, struct pt_regs *regs); ++/* ++ . This is a separate procedure to handle the receipt of a packet, to ++ . leave the interrupt code looking slightly cleaner ++*/ ++inline static void smc_rcv( struct net_device *dev ); ++/* ++ . This handles a TX interrupt, which is only called when an error ++ . relating to a packet is sent. ++*/ ++inline static void smc_tx( struct net_device * dev ); ++ ++/* ++ . This handles interrupts generated from PHY register 18 ++*/ ++static void smc_phy_interrupt(struct net_device* dev); ++ ++/* ++ ------------------------------------------------------------ ++ . ++ . Internal routines ++ . ++ ------------------------------------------------------------ ++*/ ++ ++/* ++ . Test if a given location contains a chip, trying to cause as ++ . little damage as possible if it's not a SMC chip. ++*/ ++static int smc_probe(struct net_device *dev, unsigned long ioaddr); ++ ++/* ++ . A rather simple routine to print out a packet for debugging purposes. ++*/ ++#if SMC_DEBUG > 2 ++static void print_packet( byte *, int ); ++#endif ++ ++#define tx_done(dev) 1 ++ ++/* this is called to actually send the packet to the chip */ ++static void smc_hardware_send_packet( struct net_device * dev ); ++ ++/* Since I am not sure if I will have enough room in the chip's ram ++ . to store the packet, I call this routine, which either sends it ++ . now, or generates an interrupt when the card is ready for the ++ . packet */ ++static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev ); ++ ++/* this does a soft reset on the device */ ++static void smc_reset( struct net_device* dev ); ++ ++/* Enable Interrupts, Receive, and Transmit */ ++static void smc_enable( struct net_device *dev ); ++ ++/* this puts the device in an inactive state */ ++static void smc_shutdown( unsigned long ioaddr ); ++ ++/* This routine will find the IRQ of the driver if one is not ++ . specified in the input to the device. */ ++static int smc_findirq( unsigned long ioaddr ); ++ ++/* Routines to Read and Write the PHY Registers across the ++ MII Management Interface ++*/ ++ ++static word smc_read_phy_register(unsigned long ioaddr, ++ byte phyaddr, byte phyreg); ++static void smc_write_phy_register(unsigned long ioaddr, ++ byte phyaddr, byte phyreg, word phydata); ++ ++/* ++ Initilizes our device's sysctl proc filesystem ++*/ ++ ++#ifdef CONFIG_SYSCTL ++static void smc_sysctl_register(struct net_device *dev); ++static void smc_sysctl_unregister(struct net_device *dev); ++#endif /* CONFIG_SYSCTL */ ++ ++/* ++ . Function: smc_reset( struct net_device* dev ) ++ . Purpose: ++ . This sets the SMC91111 chip to its normal state, hopefully from whatever ++ . mess that any other DOS driver has put it in. ++ . ++ . Maybe I should reset more registers to defaults in here? SOFTRST should ++ . do that for me. ++ . ++ . Method: ++ . 1. send a SOFT RESET ++ . 2. wait for it to finish ++ . 3. enable autorelease mode ++ . 4. reset the memory management unit ++ . 5. clear all interrupts ++ . ++*/ ++static void smc_reset( struct net_device* dev ) ++{ ++ //struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ ++ PRINTK2("%s:smc_reset\n", dev->name); ++ ++ /* This resets the registers mostly to defaults, but doesn't ++ affect EEPROM. That seems unnecessary */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_RCR( RCR_SOFTRST ); ++ ++ /* Setup the Configuration Register */ ++ /* This is necessary because the CONFIG_REG is not affected */ ++ /* by a soft reset */ ++ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_CONFIG( CONFIG_DEFAULT ); ++ ++ /* Setup for fast accesses if requested */ ++ /* If the card/system can't handle it then there will */ ++ /* be no recovery except for a hard reset or power cycle */ ++ ++ if (dev->dma) ++ SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_NO_WAIT ); ++ ++#ifdef POWER_DOWN ++ /* Release from possible power-down state */ ++ /* Configuration register is not affected by Soft Reset */ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_EPH_POWER_EN ); ++#endif ++ ++ SMC_SELECT_BANK( 0 ); ++ ++ /* this should pause enough for the chip to be happy */ ++ mdelay(10); ++ ++ /* Disable transmit and receive functionality */ ++ SMC_SET_RCR( RCR_CLEAR ); ++ SMC_SET_TCR( TCR_CLEAR ); ++ ++ /* set the control register to automatically ++ release successfully transmitted packets, to make the best ++ use out of our limited memory */ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_CTL( SMC_GET_CTL() | CTL_AUTO_RELEASE ); ++ ++ /* Reset the MMU */ ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_MMU_CMD( MC_RESET ); ++ ++ /* Note: It doesn't seem that waiting for the MMU busy is needed here, ++ but this is a place where future chipsets _COULD_ break. Be wary ++ of issuing another MMU command right after this */ ++ ++ /* Disable all interrupts */ ++ SMC_SET_INT_MASK( 0 ); ++} ++ ++/* ++ . Function: smc_enable ++ . Purpose: let the chip talk to the outside work ++ . Method: ++ . 1. Enable the transmitter ++ . 2. Enable the receiver ++ . 3. Enable interrupts ++*/ ++static void smc_enable( struct net_device *dev ) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ ++ PRINTK2("%s:smc_enable\n", dev->name); ++ ++ SMC_SELECT_BANK( 0 ); ++ /* see the header file for options in TCR/RCR DEFAULT*/ ++ SMC_SET_TCR( lp->tcr_cur_mode ); ++ SMC_SET_RCR( lp->rcr_cur_mode ); ++ ++ /* now, enable interrupts */ ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_INT_MASK( SMC_INTERRUPT_MASK ); ++} ++ ++/* ++ . Function: smc_shutdown ++ . Purpose: closes down the SMC91xxx chip. ++ . Method: ++ . 1. zero the interrupt mask ++ . 2. clear the enable receive flag ++ . 3. clear the enable xmit flags ++ . ++ . TODO: ++ . (1) maybe utilize power down mode. ++ . Why not yet? Because while the chip will go into power down mode, ++ . the manual says that it will wake up in response to any I/O requests ++ . in the register space. Empirical results do not show this working. ++*/ ++static void smc_shutdown( unsigned long ioaddr ) ++{ ++ PRINTK2(CARDNAME ":smc_shutdown\n"); ++ ++ /* no more interrupts for me */ ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_INT_MASK( 0 ); ++ ++ /* and tell the card to stay away from that nasty outside world */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_RCR( RCR_CLEAR ); ++ SMC_SET_TCR( TCR_CLEAR ); ++ ++#ifdef POWER_DOWN ++ /* finally, shut the chip down */ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_CONFIG( SMC_GET_CONFIG() & ~CONFIG_EPH_POWER_EN ); ++#endif ++} ++ ++ ++/* ++ . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds ) ++ . Purpose: ++ . This sets the internal hardware table to filter out unwanted multicast ++ . packets before they take up memory. ++ . ++ . The SMC chip uses a hash table where the high 6 bits of the CRC of ++ . address are the offset into the table. If that bit is 1, then the ++ . multicast packet is accepted. Otherwise, it's dropped silently. ++ . ++ . To use the 6 bits as an offset into the table, the high 3 bits are the ++ . number of the 8 bit register, while the low 3 bits are the bit within ++ . that register. ++ . ++ . This routine is based very heavily on the one provided by Peter Cammaert. ++*/ ++ ++ ++static void smc_setmulticast( unsigned long ioaddr, int count, ++ struct dev_mc_list * addrs ) { ++ int i; ++ unsigned char multicast_table[ 8 ]; ++ struct dev_mc_list * cur_addr; ++ /* table for flipping the order of 3 bits */ ++ unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; ++ ++ PRINTK2(CARDNAME ":smc_setmulticast\n"); ++ ++ /* start with a table of all zeros: reject all */ ++ memset( multicast_table, 0, sizeof( multicast_table ) ); ++ ++ cur_addr = addrs; ++ for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) { ++ int position; ++ ++ /* do we have a pointer here? */ ++ if ( !cur_addr ) ++ break; ++ /* make sure this is a multicast address - shouldn't this ++ be a given if we have it here ? */ ++ if ( !( *cur_addr->dmi_addr & 1 ) ) ++ continue; ++ ++ /* only use the low order bits */ ++ position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f; ++ ++ /* do some messy swapping to put the bit in the right spot */ ++ multicast_table[invert3[position&7]] |= ++ (1<>3)&7]); ++ ++ } ++ /* now, the table can be loaded into the chipset */ ++ SMC_SELECT_BANK( 3 ); ++ SMC_SET_MCAST( multicast_table ); ++} ++ ++/* ++ Finds the CRC32 of a set of bytes. ++ Again, from Peter Cammaert's code. ++*/ ++static int crc32( char * s, int length ) { ++ /* indices */ ++ int perByte; ++ int perBit; ++ /* crc polynomial for Ethernet */ ++ const unsigned long poly = 0xedb88320; ++ /* crc value - preinitialized to all 1's */ ++ unsigned long crc_value = 0xffffffff; ++ ++ for ( perByte = 0; perByte < length; perByte ++ ) { ++ unsigned char c; ++ ++ c = *(s++); ++ for ( perBit = 0; perBit < 8; perBit++ ) { ++ crc_value = (crc_value>>1)^ ++ (((crc_value^c)&0x01)?poly:0); ++ c >>= 1; ++ } ++ } ++ return crc_value; ++} ++ ++ ++/* ++ . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * ) ++ . Purpose: ++ . Attempt to allocate memory for a packet, if chip-memory is not ++ . available, then tell the card to generate an interrupt when it ++ . is available. ++ . ++ . Algorithm: ++ . ++ . o if the saved_skb is not currently null, then drop this packet ++ . on the floor. This should never happen, because of TBUSY. ++ . o if the saved_skb is null, then replace it with the current packet, ++ . o See if I can sending it now. ++ . o (NO): Enable interrupts and let the interrupt handler deal with it. ++ . o (YES):Send it now. ++*/ ++static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ word length; ++ unsigned short numPages; ++ word time_out; ++ word status; ++ ++ PRINTK3("%s:smc_wait_to_send_packet\n", dev->name); ++ ++ netif_stop_queue(dev); ++ /* Well, I want to send the packet.. but I don't know ++ if I can send it right now... */ ++ ++ if ( lp->saved_skb) { ++ /* THIS SHOULD NEVER HAPPEN. */ ++ lp->stats.tx_aborted_errors++; ++ printk("%s: Bad Craziness - sent packet while busy.\n", ++ dev->name); ++ return 1; ++ } ++ lp->saved_skb = skb; ++ ++ length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; ++ ++ ++ /* ++ ** The MMU wants the number of pages to be the number of 256 bytes ++ ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) ++ ** ++ ** The 91C111 ignores the size bits, but the code is left intact ++ ** for backwards and future compatibility. ++ ** ++ ** Pkt size for allocating is data length +6 (for additional status ++ ** words, length and ctl!) ++ ** ++ ** If odd size then last byte is included in this header. ++ */ ++ numPages = ((length & 0xfffe) + 6); ++ numPages >>= 8; // Divide by 256 ++ ++ if (numPages > 7 ) { ++ printk("%s: Far too big packet error. \n", dev->name); ++ /* freeing the packet is a good thing here... but should ++ . any packets of this size get down here? */ ++ dev_kfree_skb (skb); ++ lp->saved_skb = NULL; ++ /* this IS an error, but, i don't want the skb saved */ ++ netif_wake_queue(dev); ++ return 0; ++ } ++ /* either way, a packet is waiting now */ ++ lp->packets_waiting++; ++ ++ /* now, try to allocate the memory */ ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_MMU_CMD( MC_ALLOC | numPages ); ++ /* ++ . Performance Hack ++ . ++ . wait a short amount of time.. if I can send a packet now, I send ++ . it now. Otherwise, I enable an interrupt and wait for one to be ++ . available. ++ . ++ . I could have handled this a slightly different way, by checking to ++ . see if any memory was available in the FREE MEMORY register. However, ++ . either way, I need to generate an allocation, and the allocation works ++ . no matter what, so I saw no point in checking free memory. ++ */ ++ time_out = MEMORY_WAIT_TIME; ++ do { ++ status = SMC_GET_INT(); ++ if ( status & IM_ALLOC_INT ) { ++ /* acknowledge the interrupt */ ++ SMC_ACK_INT( IM_ALLOC_INT ); ++ break; ++ } ++ } while ( -- time_out ); ++ ++ if ( !time_out ) { ++ /* oh well, wait until the chip finds memory later */ ++ SMC_ENABLE_INT( IM_ALLOC_INT ); ++ ++ /* Check the status bit one more time just in case */ ++ /* it snuk in between the time we last checked it */ ++ /* and when we set the interrupt bit */ ++ status = SMC_GET_INT(); ++ if ( !(status & IM_ALLOC_INT) ) { ++ PRINTK2("%s: memory allocation deferred. \n", ++ dev->name); ++ /* it's deferred, but I'll handle it later */ ++ return 0; ++ } ++ ++ /* Looks like it did sneak in, so disable */ ++ /* the interrupt */ ++ SMC_DISABLE_INT( IM_ALLOC_INT ); ++ } ++ /* or YES! I can send the packet now.. */ ++ smc_hardware_send_packet(dev); ++ netif_wake_queue(dev); ++ return 0; ++} ++ ++/* ++ . Function: smc_hardware_send_packet(struct net_device * ) ++ . Purpose: ++ . This sends the actual packet to the SMC9xxx chip. ++ . ++ . Algorithm: ++ . First, see if a saved_skb is available. ++ . ( this should NOT be called if there is no 'saved_skb' ++ . Now, find the packet number that the chip allocated ++ . Point the data pointers at it in memory ++ . Set the length word in the chip's memory ++ . Dump the packet to chip memory ++ . Check if a last byte is needed ( odd length packet ) ++ . if so, set the control flag right ++ . Tell the card to send it ++ . Enable the transmit interrupt, so I know if it failed ++ . Free the kernel data if I actually sent it. ++*/ ++static void smc_hardware_send_packet( struct net_device * dev ) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ byte packet_no; ++ struct sk_buff * skb = lp->saved_skb; ++ word length; ++ unsigned long ioaddr; ++ byte * buf; ++ ++ PRINTK3("%s:smc_hardware_send_packet\n", dev->name); ++ ++ ioaddr = dev->base_addr; ++ ++ if ( !skb ) { ++ PRINTK("%s: In XMIT with no packet to send \n", dev->name); ++ return; ++ } ++ length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; ++ buf = skb->data; ++ ++ /* If I get here, I _know_ there is a packet slot waiting for me */ ++ packet_no = SMC_GET_AR(); ++ if ( packet_no & AR_FAILED ) { ++ /* or isn't there? BAD CHIP! */ ++ printk(KERN_DEBUG "%s: Memory allocation failed. \n", ++ dev->name); ++ dev_kfree_skb_any(skb); ++ lp->saved_skb = NULL; ++ netif_wake_queue(dev); ++ return; ++ } ++ ++ /* we have a packet address, so tell the card to use it */ ++ SMC_SET_PN( packet_no ); ++ ++ /* point to the beginning of the packet */ ++ SMC_SET_PTR( PTR_AUTOINC ); ++ ++ PRINTK3("%s: Trying to xmit packet of length %x\n", ++ dev->name, length); ++ ++#if SMC_DEBUG > 2 ++ printk("Transmitting Packet\n"); ++ print_packet( buf, length ); ++#endif ++ ++ /* send the packet length ( +6 for status, length and ctl byte ) ++ and the status word ( set to zeros ) */ ++#ifdef CONFIG_SMC91111_USE_32_BIT ++ SMC_outl( (length +6 ) << 16 , ioaddr + DATA_REG ); ++#else ++ SMC_outw( 0, ioaddr + DATA_REG ); ++ /* send the packet length ( +6 for status words, length, and ctl*/ ++ SMC_outw( (length+6), ioaddr + DATA_REG ); ++#endif ++ ++ /* send the actual data ++ . I _think_ it's faster to send the longs first, and then ++ . mop up by sending the last word. It depends heavily ++ . on alignment, at least on the 486. Maybe it would be ++ . a good idea to check which is optimal? But that could take ++ . almost as much time as is saved? ++ */ ++#ifdef CONFIG_SMC91111_USE_32_BIT ++ SMC_outsl(ioaddr + DATA_REG, buf, length >> 2 ); ++ if ( length & 0x2 ) ++ SMC_outw(*((word *)(buf + (length & 0xFFFFFFFC))),ioaddr + ++ DATA_REG); ++#else ++ SMC_outsw(ioaddr + DATA_REG , buf, (length ) >> 1); ++#endif // CONFIG_SMC91111_USE_32_BIT ++ ++ /* Send the last byte, if there is one. */ ++ if ( (length & 1) == 0 ) { ++ SMC_outw( 0, ioaddr + DATA_REG ); ++ } else { ++ SMC_outw( 0x2000 | buf[length -1 ], ioaddr + DATA_REG ); ++ } ++ ++ /* enable the interrupts */ ++ SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) ); ++ ++ /* and let the chipset deal with it */ ++ SMC_SET_MMU_CMD( MC_ENQUEUE ); ++ ++ PRINTK2("%s: Sent packet of length %d \n", dev->name, length); ++ ++ lp->saved_skb = NULL; ++ dev_kfree_skb_any (skb); ++ ++ dev->trans_start = jiffies; ++ ++ /* we can send another packet */ ++ netif_wake_queue(dev); ++ ++ return; ++} ++ ++/*------------------------------------------------------------------------- ++ | ++ | smc_init( void ) ++ | Input parameters: ++ | dev->base_addr == 0, try to find all possible locations ++ | dev->base_addr > 0x1ff, this is the address to check ++ | dev->base_addr == , return failure code ++ | ++ | Output: ++ | 0 --> there is a device ++ | anything else, error ++ | ++ --------------------------------------------------------------------------- ++*/ ++static int __init smc_init( void ) ++{ ++ int rtn; ++ ++ PRINTK2(CARDNAME ":smc_init\n"); ++ ++ /* ++ * Haup=> Set BRCR1 TWT to wait for 7+1=8 SYS_CLK(63MHz) => 126.98ns > 100 ns) ++ * Changes: 02/09/2004=> reduce Bus Hold Time to 1 SYS_CLK ++ */ ++ { ++ #define BRCR_REGMEM_BASE 0x70 ++ #define REG_BRCRH0 (BRCR_REGMEM_BASE + 0) ++ #define REG_BRCRH1 (BRCR_REGMEM_BASE + 1) ++ #define REG_BRCRH2 (BRCR_REGMEM_BASE + 2) ++ #define REG_BRCRH3 (BRCR_REGMEM_BASE + 3) ++ ++ #define REG_BRCR0 (BRCR_REGMEM_BASE + 0x10) ++ #define REG_BRCR1 (BRCR_REGMEM_BASE + 0x11) ++ #define REG_BRCR2 (BRCR_REGMEM_BASE + 0x12) ++ #define REG_BRCR3 (BRCR_REGMEM_BASE + 0x13) ++ #define REG_BIUCR (BRCR_REGMEM_BASE + 0x2A) ++ ++ #define __to_asm_token(s) #s ++ ++ #define MF_DCR(rn) __mfdcr_or_dflt(rn, 0) ++ ++ #define __mfdcr_or_dflt(rn,default_rval) \ ++ ({unsigned int rval; \ ++ if (rn == 0) \ ++ rval = default_rval; \ ++ else \ ++ asm volatile("mfdcr %0," __to_asm_token(rn) : "=r" (rval)); \ ++ rval;}) ++ ++ #define MT_DCR(rn, v) \ ++ {if (rn != 0) \ ++ asm volatile("mtdcr " __to_asm_token(rn) ",%0" : : "r" (v));} ++ ++ ++ unsigned int brcr1; ++ ++ brcr1 = MF_DCR(REG_BRCR1); ++ printk("smsc91111 org brcr1 = 0x%08x\n", brcr1); ++ ++ /* set TWT = 7+1 SYS_CLK */ ++ brcr1 = (brcr1 & ~(0x3f<<8)) | (7<<8); ++ /* set TH = 1 SYS_CLK */ ++ brcr1 = (brcr1 & ~(0x07<<1)) | (0x01<<1); ++ ++ MT_DCR(REG_BRCR1, brcr1); ++ brcr1 = MF_DCR(REG_BRCR1); ++ printk("smsc91111 (brcr1 = 0x%08x) => TWT cycle = %d\n", ++ brcr1, ++ ((brcr1 & (0x3f<<8))>>8)); ++ } //end of haup ++ ++#ifdef MODULE ++ if (io == -1) ++ printk(KERN_WARNING ++ CARDNAME": You shouldn't use auto-probing with insmod!\n" ); ++#endif ++ ++ if (global_dev) { ++ printk(CARDNAME ": already initialized.\n"); ++ return -EBUSY; ++ } ++ ++ global_dev = init_etherdev(0, sizeof(struct smc_local)); ++ if (!global_dev) { ++ printk(CARDNAME ": could not allocate device.\n"); ++ return -ENODEV; ++ } ++ SET_MODULE_OWNER(global_dev); ++ ++ /* copy the parameters from insmod into the device structure */ ++ if (io != -1) ++ global_dev->base_addr = io; ++ if (irq != -1) ++ global_dev->irq = irq; ++ global_dev->dma = nowait; // Use DMA field for nowait ++ ++#ifdef CONFIG_ISA ++ /* try a specific location */ ++ if (global_dev->base_addr > 0x1ff) ++ rtn = smc_probe(global_dev, global_dev->base_addr); ++ else if (global_dev->base_addr != 0) ++ rtn = -ENXIO; ++ else { ++ int i; ++ ++ /* check every ethernet address */ ++ for (i = 0; smc_portlist[i]; i++) { ++ rtn = smc_probe(global_dev, smc_portlist[i]); ++ if (rtn == 0) ++ break; ++ } ++ } ++ ++xxxx ++#else ++ if (global_dev->base_addr == -1) { ++ printk(KERN_WARNING ++ CARDNAME": SMC91111_BASE_ADDR not set!\n" ); ++ rtn = -ENXIO; ++ } ++ else ++ rtn = smc_probe(global_dev, ++ (int)ioremap(global_dev->base_addr, ++ SMC_IO_EXTENT)); ++#endif ++ ++ if (rtn != 0) { ++ printk(CARDNAME ": not found.\n"); ++ /* couldn't find anything */ ++#ifndef CONFIG_ISA ++ iounmap((void *)global_dev->base_addr); ++#endif ++ kfree(global_dev->priv); ++ unregister_netdev(global_dev); ++ kfree(global_dev); ++ } ++ ++ return rtn; ++} ++ ++/*---------------------------------------------------------------------- ++ . smc_findirq ++ . ++ . This routine has a simple purpose -- make the SMC chip generate an ++ . interrupt, so an auto-detect routine can detect it, and find the IRQ, ++ ------------------------------------------------------------------------ ++*/ ++int __init smc_findirq( unsigned long ioaddr ) ++{ ++ int timeout = 20; ++ unsigned long cookie; ++ ++ PRINTK2(CARDNAME ":smc_findirq\n"); ++ ++ /* I have to do a STI() here, because this is called from ++ a routine that does an CLI during this process, making it ++ rather difficult to get interrupts for auto detection */ ++ sti(); ++ ++ cookie = probe_irq_on(); ++ ++ /* ++ * What I try to do here is trigger an ALLOC_INT. This is done ++ * by allocating a small chunk of memory, which will give an interrupt ++ * when done. ++ */ ++ ++ ++ SMC_SELECT_BANK(2); ++ /* enable ALLOCation interrupts ONLY */ ++ SMC_SET_INT_MASK( IM_ALLOC_INT ); ++ ++ /* ++ . Allocate 512 bytes of memory. Note that the chip was just ++ . reset so all the memory is available ++ */ ++ SMC_SET_MMU_CMD( MC_ALLOC | 1 ); ++ ++ /* ++ . Wait until positive that the interrupt has been generated ++ */ ++ while ( timeout ) { ++ byte int_status; ++ ++ int_status = SMC_GET_INT(); ++ ++ if ( int_status & IM_ALLOC_INT ) ++ break; /* got the interrupt */ ++ timeout--; ++ } ++ ++ /* there is really nothing that I can do here if timeout fails, ++ as autoirq_report will return a 0 anyway, which is what I ++ want in this case. Plus, the clean up is needed in both ++ cases. */ ++ ++ /* DELAY HERE! ++ On a fast machine, the status might change before the interrupt ++ is given to the processor. This means that the interrupt was ++ never detected, and autoirq_report fails to report anything. ++ This should fix autoirq_* problems. ++ */ ++ mdelay(10); ++ ++ /* and disable all interrupts again */ ++ SMC_SET_INT_MASK( 0 ); ++ ++ /* clear hardware interrupts again, because that's how it ++ was when I was called... */ ++ cli(); ++ ++ /* and return what I found */ ++ return probe_irq_off(cookie); ++} ++ ++/*---------------------------------------------------------------------- ++ . Function: smc_probe( unsigned long ioaddr ) ++ . ++ . Purpose: ++ . Tests to see if a given ioaddr points to an SMC91111 chip. ++ . Returns a 0 on success ++ . ++ . Algorithm: ++ . (1) see if the high byte of BANK_SELECT is 0x33 ++ . (2) compare the ioaddr with the base register's address ++ . (3) see if I recognize the chip ID in the appropriate register ++ . ++ .--------------------------------------------------------------------- ++ */ ++/*--------------------------------------------------------------- ++ . Here I do typical initialization tasks. ++ . ++ . o Initialize the structure if needed ++ . o print out my vanity message if not done so already ++ . o print out what type of hardware is detected ++ . o print out the ethernet address ++ . o find the IRQ ++ . o set up my private data ++ . o configure the dev structure with my subroutines ++ . o actually GRAB the irq. ++ . o GRAB the region ++ .----------------------------------------------------------------- ++*/ ++static int __init smc_probe(struct net_device *dev, unsigned long ioaddr) ++{ ++ int i, memory, retval; ++ static unsigned version_printed; ++ unsigned int bank; ++ ++ const char *version_string; ++ const char *if_string = 0; ++ ++ /* registers */ ++ word revision_register; ++ word base_address_register; ++ word memory_info_register; ++ ++ PRINTK2(CARDNAME ":smc_probe\n"); ++ ++ /* Grab the region so that no one else tries to probe our ioports. */ ++ if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) ++ return -EBUSY; ++ ++ /* First, see if the high byte is 0x33 */ ++ bank = SMC_CURRENT_BANK(); ++ if ( (bank & 0xFF00) != 0x3300 ) { ++ if ( (bank & 0xFF) == 0x33 ) { ++ printk(CARDNAME ++ ": Detected possible byte-swapped interface" ++ " at IOADDR %lx\n", ioaddr); ++ } ++ retval = -ENODEV; ++ goto err_out; ++ } ++ /* The above MIGHT indicate a device, but I need to write to further ++ test this. */ ++ SMC_SELECT_BANK(0); ++ bank = SMC_CURRENT_BANK(); ++ if ( (bank & 0xFF00 ) != 0x3300 ) { ++ retval = -ENODEV; ++ goto err_out; ++ } ++ /* well, we've already written once, so hopefully another time won't ++ hurt. This time, I need to switch the bank register to bank 1, ++ so I can access the base address register */ ++ SMC_SELECT_BANK(1); ++ base_address_register = SMC_GET_BASE(); ++ base_address_register = ((base_address_register & 0xE000) ++ | ((base_address_register & 0x1F00) >> 3)); ++ if ( (ioaddr & (PAGE_SIZE-1)) != base_address_register ) { ++ printk(CARDNAME ": IOADDR %lx doesn't match configuration (%x)." ++ "Probably not a SMC chip\n", ++ ioaddr, base_address_register ); ++ /* well, the base address register didn't match. Must not have ++ been a SMC chip after all. */ ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ /* check if the revision register is something that I recognize. ++ These might need to be added to later, as future revisions ++ could be added. */ ++ SMC_SELECT_BANK(3); ++ revision_register = SMC_GET_REV(); ++ if ( !chip_ids[ ( revision_register >> 4 ) & 0xF ] ) { ++ /* I don't recognize this chip, so... */ ++ printk(CARDNAME ": IO %lx: Unrecognized revision register:" ++ " %x, Contact author. \n", ++ ioaddr, revision_register ); ++ ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ /* at this point I'll assume that the chip is an SMC9xxx. ++ It might be prudent to check a listing of MAC addresses ++ against the hardware address, or do some other tests. */ ++ ++ if (version_printed++ == 0) ++ printk("%s", version); ++ ++ /* fill in some of the fields */ ++ dev->base_addr = ioaddr; ++ ++ /* ++ . Get the MAC address ( bank 1, regs 4 - 9 ) ++ */ ++ SMC_SELECT_BANK( 1 ); ++ for ( i = 0; i < 6; i += 2 ) { ++ word address; ++ ++ address = SMC_inw( ioaddr + ADDR0_REG + i ); ++ dev->dev_addr[ i + 1] = address >> 8; ++ dev->dev_addr[ i ] = address & 0xFF; ++ } ++ ++ /* get the memory information */ ++ ++ SMC_SELECT_BANK( 0 ); ++ memory_info_register = SMC_GET_MIR(); ++ memory = memory_info_register & (word)0x00ff; ++ memory *= LAN91C111_MEMORY_MULTIPLIER; ++ ++ /* ++ Now, I want to find out more about the chip. This is sort of ++ redundant, but it's cleaner to have it in both, rather than having ++ one VERY long probe procedure. ++ */ ++ SMC_SELECT_BANK(3); ++ revision_register = SMC_GET_REV(); ++ version_string = chip_ids[ ( revision_register >> 4 ) & 0xF ]; ++ if ( !version_string ) { ++ /* I shouldn't get here because this call was done before.... */ ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ ++ /* now, reset the chip, and put it into a known state */ ++ smc_reset( dev ); ++ ++ /* ++ . If dev->irq is 0, then the device has to be banged on to see ++ . what the IRQ is. ++ . ++ . This banging doesn't always detect the IRQ, for unknown reasons. ++ . a workaround is to reset the chip and try again. ++ . ++ . Interestingly, the DOS packet driver *SETS* the IRQ on the card to ++ . be what is requested on the command line. I don't do that, mostly ++ . because the card that I have uses a non-standard method of accessing ++ . the IRQs, and because this _should_ work in most configurations. ++ . ++ . Specifying an IRQ is done with the assumption that the user knows ++ . what (s)he is doing. No checking is done!!!! ++ . ++ */ ++ if ( dev->irq < 2 ) { ++ int trials; ++ ++ trials = 3; ++ while ( trials-- ) { ++ dev->irq = smc_findirq( ioaddr ); ++ if ( dev->irq ) ++ break; ++ /* kick the card and try again */ ++ smc_reset( dev ); ++ } ++ } ++ if (dev->irq == 0 ) { ++ printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n", ++ dev->name); ++ retval = -ENODEV; ++ goto err_out; ++ } ++ if (dev->irq == 2) { ++ /* Fixup for users that don't know that IRQ 2 is really IRQ 9, ++ * or don't know which one to set. ++ */ ++ dev->irq = 9; ++ } ++ ++ /* now, print out the card info, in a short format.. */ ++ ++ printk("%s: %s(r:%d) at %#lx IRQ:%d\n", dev->name, ++ version_string, revision_register & 0xF, ioaddr, dev->irq ); ++ printk(" INTF:%s MEM:%db NOWAIT:%d", if_string, memory, dev->dma ); ++ /* ++ . Print the Ethernet address ++ */ ++ printk(" ADDR "); ++ for (i = 0; i < 5; i++) ++ printk("%2.2x:", dev->dev_addr[i] ); ++ printk("%2.2x \n", dev->dev_addr[5] ); ++ ++ /* set the private data to zero by default */ ++ memset(dev->priv, 0, sizeof(struct smc_local)); ++ ++ /* Fill in the fields of the device structure with ethernet values. */ ++ ether_setup(dev); ++ ++ /* Grab the IRQ */ ++ retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); ++ if (retval) { ++ goto err_out; ++ } ++ ++ dev->open = smc_open; ++ dev->stop = smc_close; ++ dev->hard_start_xmit = smc_wait_to_send_packet; ++ dev->tx_timeout = smc_timeout; ++ dev->watchdog_timeo = HZ/20; ++ dev->get_stats = smc_query_statistics; ++ dev->set_multicast_list = smc_set_multicast_list; ++ ++ return 0; ++ ++err_out: ++ release_region(ioaddr, SMC_IO_EXTENT); ++ return retval; ++} ++ ++#if SMC_DEBUG > 2 ++static void print_packet( byte * buf, int length ) ++{ ++#if 1 ++#if SMC_DEBUG > 3 ++ int i; ++ int remainder; ++ int lines; ++#endif ++ ++ printk("Packet of length %d \n", length ); ++ ++#if SMC_DEBUG > 3 ++ lines = length / 16; ++ remainder = length % 16; ++ ++ for ( i = 0; i < lines ; i ++ ) { ++ int cur; ++ ++ for ( cur = 0; cur < 8; cur ++ ) { ++ byte a, b; ++ ++ a = *(buf ++ ); ++ b = *(buf ++ ); ++ printk("%02x%02x ", a, b ); ++ } ++ printk("\n"); ++ } ++ for ( i = 0; i < remainder/2 ; i++ ) { ++ byte a, b; ++ ++ a = *(buf ++ ); ++ b = *(buf ++ ); ++ printk("%02x%02x ", a, b ); ++ } ++ printk("\n"); ++#endif ++#endif ++} ++#endif ++ ++ ++/* ++ * Open and Initialize the board ++ * ++ * Set up everything, reset the card, etc .. ++ * ++ */ ++static int smc_open(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ int i; /* used to set hw ethernet address */ ++ ++ PRINTK2("%s:smc_open\n", dev->name); ++ ++ /* clear out all the junk that was put here before... */ ++ memset(dev->priv, 0, sizeof(struct smc_local)); ++ ++ // Setup the default Register Modes ++ lp->tcr_cur_mode = TCR_DEFAULT; ++ lp->rcr_cur_mode = RCR_DEFAULT; ++ lp->rpc_cur_mode = RPC_DEFAULT; ++ ++ // Set default parameters (files) ++ lp->ctl_swfdup = 0; ++ lp->ctl_ephloop = 0; ++ lp->ctl_miiop = 0; ++ lp->ctl_autoneg = 1; //1 ++ lp->ctl_rfduplx = 0; //Haup=> negotiate for HALF? ++ lp->ctl_rspeed = 100; //100 ++ lp->ctl_afduplx = 0; //1 ++ lp->ctl_aspeed = 100; //100 ++ lp->ctl_lnkfail = 1; ++ lp->ctl_forcol = 0; ++ lp->ctl_filtcar = 0; ++ ++ /* reset the hardware */ ++ ++ smc_reset( dev ); ++ smc_enable( dev ); ++ ++ /* Configure the PHY */ ++ smc_phy_configure(dev); ++ ++ /* ++ According to Becker, I have to set the hardware address ++ at this point, because the (l)user can set it with an ++ ioctl. Easily done... ++ */ ++ SMC_SELECT_BANK( 1 ); ++ for ( i = 0; i < 6; i += 2 ) { ++ word address; ++ ++ address = dev->dev_addr[ i + 1 ] << 8 ; ++ address |= dev->dev_addr[ i ]; ++ SMC_outw( address, ioaddr + ADDR0_REG + i ); ++ } ++ ++#ifdef CONFIG_SYSCTL ++ smc_sysctl_register(dev); ++#endif /* CONFIG_SYSCTL */ ++ ++ netif_start_queue(dev); ++ return 0; ++} ++ ++/*-------------------------------------------------------- ++ . Called by the kernel to send a packet out into the void ++ . of the net. This routine is largely based on ++ . skeleton.c, from Becker. ++ .-------------------------------------------------------- ++*/ ++static void smc_timeout(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ ++ PRINTK3("%s:smc_timeout\n", dev->name); ++ ++ /* If we get here, some higher level has decided we are broken. ++ There should really be a "kick me" function call instead. */ ++ printk(KERN_WARNING "%s: transmit timed out, %s?\n", ++ dev->name, tx_done(dev) ? "IRQ conflict" : ++ "network cable problem"); ++ /* "kick" the adaptor */ ++ smc_reset( dev ); ++ smc_enable( dev ); ++ ++#if 0 ++ /* Reconfiguring the PHY doesn't seem like a bad idea here, but ++ * it introduced a problem. Now that this is a timeout routine, ++ * we are getting called from within an interrupt context. ++ * smc_phy_configure() calls smc_wait_ms() which calls ++ * schedule_timeout() which calls schedule(). When schedule() ++ * is called from an interrupt context, it prints out ++ * "Scheduling in interrupt" and then calls BUG(). This is ++ * obviously not desirable. This was worked around by removing ++ * the call to smc_phy_configure() here because it didn't seem ++ * absolutely necessary. Ultimately, if smc_wait_ms() is ++ * supposed to be usable from an interrupt context (which it ++ * looks like it thinks it should handle), it should be fixed. ++ */ ++ /* Reconfigure the PHY */ ++ smc_phy_configure(dev); ++#endif ++ dev->trans_start = jiffies; ++ /* clear anything saved */ ++ if (lp->saved_skb != NULL) { ++ dev_kfree_skb (lp->saved_skb); ++ lp->saved_skb = NULL; ++ } ++ ((struct smc_local *)dev->priv)->saved_skb = NULL; ++ netif_wake_queue(dev); ++} ++ ++/*-------------------------------------------------------------------- ++ . ++ . This is the main routine of the driver, to handle the device when ++ . it needs some attention. ++ . ++ . So: ++ . first, save state of the chipset ++ . branch off into routines to handle each case, and acknowledge ++ . each to the interrupt register ++ . and finally restore state. ++ . ++ ---------------------------------------------------------------------*/ ++static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) ++{ ++ struct net_device *dev = dev_id; ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ ++ byte status; ++ word card_stats; ++ byte mask; ++ int timeout; ++ /* state registers */ ++ word saved_bank; ++ word saved_pointer; ++ ++ PRINTK3("%s: SMC interrupt started \n", dev->name); ++ ++ if (dev == NULL) { ++ printk(KERN_WARNING "%s: irq %d for unknown device.\n", ++ dev->name, irq); ++ return; ++ } ++ ++ saved_bank = SMC_CURRENT_BANK(); ++ ++ SMC_SELECT_BANK(2); ++ saved_pointer = SMC_GET_PTR(); ++ ++ /* read the interrupt mask register */ ++ mask = SMC_GET_INT_MASK(); ++ ++ /* disable all interrupts */ ++ SMC_SET_INT_MASK( 0 ); ++ ++ /* set a timeout value, so I don't stay here forever */ ++ timeout = 4; ++ ++ PRINTK2(KERN_WARNING "%s: MASK IS %x \n", dev->name, mask); ++ do { ++ /* read the status flag, and mask it */ ++ status = SMC_GET_INT() & mask; ++ if (!status ) ++ break; ++ ++ PRINTK3(KERN_WARNING "%s: Handling interrupt status %x \n", ++ dev->name, status); ++ ++ if (status & IM_RCV_INT) { ++ /* Got a packet(s). */ ++ PRINTK2(KERN_WARNING ++ "%s: Receive Interrupt\n", dev->name); ++ smc_rcv(dev); ++ } else if (status & IM_TX_INT ) { ++ PRINTK2(KERN_WARNING "%s: TX ERROR handled\n", ++ dev->name); ++ smc_tx(dev); ++ // Acknowledge the interrupt ++ SMC_ACK_INT( IM_TX_INT ); ++ } else if (status & IM_TX_EMPTY_INT ) { ++ /* update stats */ ++ SMC_SELECT_BANK( 0 ); ++ card_stats = SMC_GET_COUNTER(); ++ /* single collisions */ ++ lp->stats.collisions += card_stats & 0xF; ++ card_stats >>= 4; ++ /* multiple collisions */ ++ lp->stats.collisions += card_stats & 0xF; ++ ++ /* these are for when linux supports these statistics */ ++ ++ SMC_SELECT_BANK( 2 ); ++ PRINTK2(KERN_WARNING "%s: TX_BUFFER_EMPTY handled\n", ++ dev->name); ++ // Acknowledge the interrupt ++ SMC_ACK_INT( IM_TX_EMPTY_INT ); ++ mask &= ~IM_TX_EMPTY_INT; ++ lp->stats.tx_packets += lp->packets_waiting; ++ lp->packets_waiting = 0; ++ ++ } else if (status & IM_ALLOC_INT ) { ++ PRINTK2(KERN_DEBUG "%s: Allocation interrupt \n", ++ dev->name); ++ /* clear this interrupt so it doesn't happen again */ ++ mask &= ~IM_ALLOC_INT; ++ ++ smc_hardware_send_packet( dev ); ++ ++ /* enable xmit interrupts based on this */ ++ mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); ++ ++ /* and let the card send more packets to me */ ++ netif_wake_queue(dev); ++ ++ PRINTK2("%s: Handoff done successfully.\n", ++ dev->name); ++ } else if (status & IM_RX_OVRN_INT ) { ++ lp->stats.rx_errors++; ++ lp->stats.rx_fifo_errors++; ++ // Acknowledge the interrupt ++ SMC_ACK_INT( IM_RX_OVRN_INT ); ++ } else if (status & IM_EPH_INT ) { ++ PRINTK("%s: UNSUPPORTED: EPH INTERRUPT \n", ++ dev->name); ++ } else if (status & IM_MDINT ) { ++ smc_phy_interrupt(dev); ++ // Acknowledge the interrupt ++ SMC_ACK_INT( IM_MDINT ); ++ } else if (status & IM_ERCV_INT ) { ++ PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", ++ dev->name); ++ // Acknowledge the interrupt ++ SMC_ACK_INT( IM_ERCV_INT ); ++ } ++ } while ( timeout -- ); ++ ++ ++ /* restore register states */ ++ ++ SMC_SELECT_BANK( 2 ); ++ ++ SMC_SET_INT_MASK( mask ); ++ ++ PRINTK3( KERN_WARNING "%s: MASK is now %x \n", dev->name, mask); ++ SMC_SET_PTR( saved_pointer ); ++ ++ SMC_SELECT_BANK( saved_bank ); ++ ++ PRINTK3("%s: Interrupt done\n", dev->name); ++ return; ++} ++ ++/*------------------------------------------------------------- ++ . ++ . smc_rcv - receive a packet from the card ++ . ++ . There is ( at least ) a packet waiting to be read from ++ . chip-memory. ++ . ++ . o Read the status ++ . o If an error, record it ++ . o otherwise, read in the packet ++ -------------------------------------------------------------- ++*/ ++static void smc_rcv(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ int packet_number; ++ word status; ++ word packet_length; ++ ++ PRINTK3("%s:smc_rcv\n", dev->name); ++ ++ /* assume bank 2 */ ++ ++ packet_number = SMC_GET_RXFIFO(); ++ ++ if ( packet_number & RXFIFO_REMPTY ) { ++ ++ /* we got called , but nothing was on the FIFO */ ++ PRINTK("%s: WARNING: smc_rcv with nothing on FIFO. \n", ++ dev->name); ++ /* don't need to restore anything */ ++ return; ++ } ++ ++ /* start reading from the start of the packet */ ++ SMC_SET_PTR( PTR_READ | PTR_RCV | PTR_AUTOINC ); ++ ++ /* First two words are status and packet_length */ ++ status = SMC_inw( ioaddr + DATA_REG ); ++ packet_length = SMC_inw( ioaddr + DATA_REG ); ++ ++ packet_length &= 0x07ff; /* mask off top bits */ ++ ++ PRINTK2("RCV: STATUS %4x LENGTH %4x\n", status, packet_length ); ++ ++ if ( !(status & RS_ERRORS ) ){ ++ /* do stuff to make a new packet */ ++ struct sk_buff * skb; ++ byte * data; ++ ++ /* set multicast stats */ ++ if ( status & RS_MULTICAST ) ++ lp->stats.multicast++; ++ ++ // Allocate enough memory for entire receive frame, to be safe ++ skb = dev_alloc_skb( packet_length ); ++ ++ /* Adjust for having already read the first two words */ ++ packet_length -= 4; ++ ++ if ( skb == NULL ) { ++ printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", ++ dev->name); ++ lp->stats.rx_dropped++; ++ goto done; ++ } ++ ++ /* ++ ! This should work without alignment, but it could be ++ ! in the worse case ++ */ ++ ++ skb_reserve( skb, 2 ); /* 16 bit alignment */ ++ ++ skb->dev = dev; ++ ++ // set odd length for bug in LAN91C111, ++ // which never sets RS_ODDFRAME ++ data = skb_put( skb, packet_length + 1 ); ++ ++#ifdef CONFIG_SMC91111_USE_32_BIT ++ PRINTK3(" Reading %d dwords (and %d bytes) \n", ++ packet_length >> 2, packet_length & 3 ); ++ /* QUESTION: Like in the TX routine, do I want ++ to send the DWORDs or the bytes first, or some ++ mixture. A mixture might improve already slow PIO ++ performance */ ++ SMC_insl(ioaddr + DATA_REG , data, packet_length >> 2 ); ++ /* read the left over bytes */ ++#ifdef CONFIG_SMC91111_USE_8_BIT ++ SMC_insb( ioaddr + DATA_REG, data + (packet_length & 0xFFFFFC), ++ packet_length & 0x3 ); ++#else ++ if (packet_length & 0x3) ++ { ++ unsigned long remaining_data; ++ insl(ioaddr + DATA_REG , &remaining_data, 1); ++ memcpy(data + (packet_length & 0xFFFFFC), ++ &remaining_data, packet_length & 0x3 ); ++ } ++#endif // CONFIG_SMC91111_USE_8_BIT ++#else ++ PRINTK3(" Reading %d words and %d byte(s) \n", ++ (packet_length >> 1 ), packet_length & 1 ); ++ SMC_insw(ioaddr + DATA_REG , data, packet_length >> 1); ++ ++#endif // CONFIG_SMC91111_USE_32_BIT ++ ++#if SMC_DEBUG > 2 ++ printk("Receiving Packet\n"); ++ print_packet( data, packet_length ); ++#endif ++ ++ skb->protocol = eth_type_trans(skb, dev ); ++ netif_rx(skb); ++ dev->last_rx = jiffies; ++ lp->stats.rx_packets++; ++ lp->stats.rx_bytes += packet_length; ++ } else { ++ /* error ... */ ++ lp->stats.rx_errors++; ++ ++ if ( status & RS_ALGNERR ) lp->stats.rx_frame_errors++; ++ if ( status & (RS_TOOSHORT | RS_TOOLONG ) ) ++ lp->stats.rx_length_errors++; ++ if ( status & RS_BADCRC) lp->stats.rx_crc_errors++; ++ } ++ ++ while ( SMC_GET_MMU_CMD() & MC_BUSY ) ++ udelay(1); // Wait until not busy ++ ++done: ++ /* error or good, tell the card to get rid of this packet */ ++ SMC_SET_MMU_CMD( MC_RELEASE ); ++} ++ ++ ++/************************************************************************* ++ . smc_tx ++ . ++ . Purpose: Handle a transmit error message. This will only be called ++ . when an error, because of the AUTO_RELEASE mode. ++ . ++ . Algorithm: ++ . Save pointer and packet no ++ . Get the packet no from the top of the queue ++ . check if it's valid ( if not, is this an error??? ) ++ . read the status word ++ . record the error ++ . ( resend? Not really, since we don't want old packets around ) ++ . Restore saved values ++ ************************************************************************/ ++static void smc_tx( struct net_device * dev ) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ byte saved_packet; ++ byte packet_no; ++ word tx_status; ++ ++ ++ PRINTK3("%s:smc_tx\n", dev->name); ++ ++ /* assume bank 2 */ ++ ++ saved_packet = SMC_GET_PN(); ++ packet_no = SMC_GET_RXFIFO(); ++ packet_no &= 0x7F; ++ ++ /* If the TX FIFO is empty then nothing to do */ ++ if ( packet_no & TXFIFO_TEMPTY ) ++ return; ++ ++ /* select this as the packet to read from */ ++ SMC_SET_PN( packet_no ); ++ ++ /* read the first word (status word) from this packet */ ++ SMC_SET_PTR( PTR_AUTOINC | PTR_READ ); ++ ++ tx_status = SMC_inw( ioaddr + DATA_REG ); ++ PRINTK3("%s: TX DONE STATUS: %4x \n", dev->name, tx_status); ++ ++ lp->stats.tx_errors++; ++ if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++; ++ if ( tx_status & TS_LATCOL ) { ++ printk(KERN_DEBUG ++ "%s: Late collision occurred on last xmit.\n", ++ dev->name); ++ lp->stats.tx_window_errors++; ++ lp->ctl_forcol = 0; // Reset forced collsion ++ } ++#if 0 ++ if ( tx_status & TS_16COL ) { ... } ++#endif ++ ++ if ( tx_status & TS_SUCCESS ) { ++ printk("%s: Successful packet caused interrupt \n", dev->name); ++ } ++ /* re-enable transmit */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_TCR( SMC_GET_TCR() | TCR_ENABLE ); ++ ++ /* kill the packet */ ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_MMU_CMD( MC_FREEPKT ); ++ ++ /* one less packet waiting for me */ ++ lp->packets_waiting--; ++ ++ /* Don't change Packet Number Reg until busy bit is cleared */ ++ /* Per LAN91C111 Spec, Page 50 */ ++ while ( SMC_GET_MMU_CMD() & MC_BUSY ); ++ ++ SMC_SET_PN( saved_packet ); ++ return; ++} ++ ++ ++/*---------------------------------------------------- ++ . smc_close ++ . ++ . this makes the board clean up everything that it can ++ . and not talk to the outside world. Caused by ++ . an 'ifconfig ethX down' ++ . ++ -----------------------------------------------------*/ ++static int smc_close(struct net_device *dev) ++{ ++ PRINTK2("%s:smc_close\n", dev->name); ++ ++ netif_stop_queue(dev); ++ ++#ifdef CONFIG_SYSCTL ++ smc_sysctl_unregister(dev); ++#endif /* CONFIG_SYSCTL */ ++ ++ /* clear everything */ ++ smc_shutdown( dev->base_addr ); ++ ++ /* Update the statistics here. */ ++ return 0; ++} ++ ++/*------------------------------------------------------------ ++ . Get the current statistics. ++ . This may be called with the card open or closed. ++ .-------------------------------------------------------------*/ ++static struct net_device_stats* smc_query_statistics(struct net_device *dev) { ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ ++ PRINTK2("%s:smc_query_statistics\n", dev->name); ++ ++ return &lp->stats; ++} ++ ++/*----------------------------------------------------------- ++ . smc_set_multicast_list ++ . ++ . This routine will, depending on the values passed to it, ++ . either make it accept multicast packets, go into ++ . promiscuous mode ( for TCPDUMP and cousins ) or accept ++ . a select set of multicast packets ++*/ ++static void smc_set_multicast_list(struct net_device *dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ ++ PRINTK2("%s:smc_set_multicast_list\n", dev->name); ++ ++ SMC_SELECT_BANK(0); ++ if ( dev->flags & IFF_PROMISC ) { ++ PRINTK2("%s:smc_set_multicast_list:RCR_PRMS\n", dev->name); ++ SMC_SET_RCR( SMC_GET_RCR() | RCR_PRMS ); ++ } ++ ++/* BUG? I never disable promiscuous mode if multicasting was turned on. ++ Now, I turn off promiscuous mode, but I don't do anything to multicasting ++ when promiscuous mode is turned on. ++*/ ++ ++ /* Here, I am setting this to accept all multicast packets. ++ I don't need to zero the multicast table, because the flag is ++ checked before the table is ++ */ ++ else if (dev->flags & IFF_ALLMULTI) { ++ SMC_SET_RCR( SMC_GET_RCR() | RCR_ALMUL ); ++ PRINTK2("%s:smc_set_multicast_list:RCR_ALMUL\n", dev->name); ++ } ++ ++ /* We just get all multicast packets even if we only want them ++ . from one source. This will be changed at some future ++ . point. */ ++ else if (dev->mc_count ) { ++ /* support hardware multicasting */ ++ ++ /* be sure I get rid of flags I might have set */ ++ SMC_SET_RCR( SMC_GET_RCR() & ~(RCR_PRMS | RCR_ALMUL) ); ++ /* NOTE: this has to set the bank, so make sure it is the ++ last thing called. The bank is set to zero at the top */ ++ smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list ); ++ } else { ++ PRINTK2("%s:smc_set_multicast_list:~(RCR_PRMS|RCR_ALMUL)\n", ++ dev->name); ++ SMC_SET_RCR( SMC_GET_RCR() & ~(RCR_PRMS | RCR_ALMUL) ); ++ ++ /* ++ since I'm disabling all multicast entirely, I need to ++ clear the multicast list ++ */ ++ SMC_SELECT_BANK( 3 ); ++ SMC_CLEAR_MCAST(); ++ } ++} ++ ++/*------------------------------------------------------------ ++ . Cleanup when module is removed with rmmod ++ .-------------------------------------------------------------*/ ++static void __exit smc_cleanup(void) ++{ ++ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ ++ unregister_netdev(global_dev); ++ ++ free_irq(global_dev->irq, global_dev); ++ release_region(global_dev->base_addr, SMC_IO_EXTENT); ++ ++#ifndef CONFIG_ISA ++ iounmap((void *)global_dev->base_addr); ++#endif ++ ++ kfree(global_dev); ++ global_dev = NULL; ++} ++ ++module_init(smc_init); ++module_exit(smc_cleanup); ++ ++ ++#ifdef CONFIG_SYSCTL ++/*------------------------------------------------------------ ++ . Modify a bit in the LAN91C111 register set ++ .-------------------------------------------------------------*/ ++static word smc_modify_regbit(int bank, unsigned long ioaddr, int reg, ++ unsigned int bit, int val) ++{ ++ word regval; ++ ++ SMC_SELECT_BANK( bank ); ++ ++ regval = SMC_inw( ioaddr+reg ); ++ if (val) ++ regval |= bit; ++ else ++ regval &= ~bit; ++ ++ SMC_outw( regval, ioaddr ); ++ return(regval); ++} ++ ++ ++/*------------------------------------------------------------ ++ . Retrieve a bit in the LAN91C111 register set ++ .-------------------------------------------------------------*/ ++static int smc_get_regbit(int bank, unsigned long ioaddr, ++ int reg, unsigned int bit) ++{ ++ SMC_SELECT_BANK( bank ); ++ if ( SMC_inw( ioaddr+reg ) & bit) ++ return(1); ++ else ++ return(0); ++} ++ ++ ++/*------------------------------------------------------------ ++ . Modify a LAN91C111 register (word access only) ++ .-------------------------------------------------------------*/ ++static void smc_modify_reg(int bank, unsigned long ioaddr, ++ int reg, word val) ++{ ++ SMC_SELECT_BANK( bank ); ++ SMC_outw( val, ioaddr+reg ); ++} ++ ++ ++/*------------------------------------------------------------ ++ . Retrieve a LAN91C111 register (word access only) ++ .-------------------------------------------------------------*/ ++static int smc_get_reg(int bank, unsigned long ioaddr, ++ int reg) ++{ ++ SMC_SELECT_BANK( bank ); ++ return(SMC_inw( ioaddr+reg )); ++} ++ ++ ++static const char smc_info_string[] = ++"\n" ++"info Provides this information blurb\n" ++"swver Prints the software version information of this driver\n" ++"autoneg Auto-negotiate Mode = 1\n" ++"rspeed Requested Speed, 100=100Mbps, 10=10Mpbs\n" ++"rfduplx Requested Full Duplex Operation\n" ++"aspeed Actual Speed, 100=100Mbps, 10=10Mpbs\n" ++"afduplx Actual Full Duplex Operation\n" ++"lnkfail PHY Link Failure when 1\n" ++"miiop External MII when 1, Internal PHY when 0\n" ++"swfdup Switched Full Duplex Mode (allowed only in MII operation)\n" ++"ephloop EPH Block Loopback\n" ++"forcol Force a collision\n" ++"filtcar Filter leading edge of carrier sense for 12 bit times\n" ++"freemem Free buffer memory in bytes\n" ++"totmem Total buffer memory in bytes\n" ++"leda Output of LED-A (green)\n" ++"ledb Output of LED-B (yellow)\n" ++"chiprev Revision ID of the LAN91C111 chip\n" ++""; ++ ++/*------------------------------------------------------------ ++ . Sysctl handler for all integer parameters ++ .-------------------------------------------------------------*/ ++static int smc_sysctl_handler(ctl_table *ctl, int write, struct file * filp, ++ void *buffer, size_t *lenp) ++{ ++ struct net_device *dev = (struct net_device*)ctl->extra1; ++ struct smc_local *lp = (struct smc_local *)ctl->extra2; ++ unsigned long ioaddr = dev->base_addr; ++ int *valp = ctl->data; ++ int val; ++ int ret; ++ ++ // Update parameters from the real registers ++ switch (ctl->ctl_name) ++ { ++ case CTL_SMC_FORCOL: ++ *valp = smc_get_regbit(0, ioaddr, TCR_REG, TCR_FORCOL); ++ break; ++ ++ case CTL_SMC_FREEMEM: ++ *valp = ( (word)smc_get_reg(0, ioaddr, MIR_REG) >> 8 ) ++ * LAN91C111_MEMORY_MULTIPLIER; ++ break; ++ ++ ++ case CTL_SMC_TOTMEM: ++ *valp = ( smc_get_reg(0, ioaddr, MIR_REG) & (word)0x00ff ) ++ * LAN91C111_MEMORY_MULTIPLIER; ++ break; ++ ++ case CTL_SMC_CHIPREV: ++ *valp = smc_get_reg(3, ioaddr, REV_REG); ++ break; ++ ++ case CTL_SMC_AFDUPLX: ++ *valp = (lp->lastPhy18 & PHY_INT_DPLXDET) ? 1 : 0; ++ break; ++ ++ case CTL_SMC_ASPEED: ++ *valp = (lp->lastPhy18 & PHY_INT_SPDDET) ? 100 : 10; ++ break; ++ ++ case CTL_SMC_LNKFAIL: ++ *valp = (lp->lastPhy18 & PHY_INT_LNKFAIL) ? 1 : 0; ++ break; ++ ++ case CTL_SMC_LEDA: ++ *valp = (lp->rpc_cur_mode >> RPC_LSXA_SHFT) & (word)0x0007; ++ break; ++ ++ case CTL_SMC_LEDB: ++ *valp = (lp->rpc_cur_mode >> RPC_LSXB_SHFT) & (word)0x0007; ++ break; ++ ++ case CTL_SMC_MIIOP: ++ *valp = smc_get_regbit(1, ioaddr, CONFIG_REG, CONFIG_EXT_PHY); ++ break; ++ ++#if SMC_DEBUG > 1 ++ case CTL_SMC_REG_BSR: // Bank Select ++ *valp = smc_get_reg(0, ioaddr, BSR_REG); ++ break; ++ ++ case CTL_SMC_REG_TCR: // Transmit Control ++ *valp = smc_get_reg(0, ioaddr, TCR_REG); ++ break; ++ ++ case CTL_SMC_REG_ESR: // EPH Status ++ *valp = smc_get_reg(0, ioaddr, EPH_STATUS_REG); ++ break; ++ ++ case CTL_SMC_REG_RCR: // Receive Control ++ *valp = smc_get_reg(0, ioaddr, RCR_REG); ++ break; ++ ++ case CTL_SMC_REG_CTRR: // Counter ++ *valp = smc_get_reg(0, ioaddr, COUNTER_REG); ++ break; ++ ++ case CTL_SMC_REG_MIR: // Memory Information ++ *valp = smc_get_reg(0, ioaddr, MIR_REG); ++ break; ++ ++ case CTL_SMC_REG_RPCR: // Receive/Phy Control ++ *valp = smc_get_reg(0, ioaddr, RPC_REG); ++ break; ++ ++ case CTL_SMC_REG_CFGR: // Configuration ++ *valp = smc_get_reg(1, ioaddr, CONFIG_REG); ++ break; ++ ++ case CTL_SMC_REG_BAR: // Base Address ++ *valp = smc_get_reg(1, ioaddr, BASE_REG); ++ break; ++ ++ case CTL_SMC_REG_IAR0: // Individual Address ++ *valp = smc_get_reg(1, ioaddr, ADDR0_REG); ++ break; ++ ++ case CTL_SMC_REG_IAR1: // Individual Address ++ *valp = smc_get_reg(1, ioaddr, ADDR1_REG); ++ break; ++ ++ case CTL_SMC_REG_IAR2: // Individual Address ++ *valp = smc_get_reg(1, ioaddr, ADDR2_REG); ++ break; ++ ++ case CTL_SMC_REG_GPR: // General Purpose ++ *valp = smc_get_reg(1, ioaddr, GP_REG); ++ break; ++ ++ case CTL_SMC_REG_CTLR: // Control ++ *valp = smc_get_reg(1, ioaddr, CTL_REG); ++ break; ++ ++ case CTL_SMC_REG_MCR: // MMU Command ++ *valp = smc_get_reg(2, ioaddr, MMU_CMD_REG); ++ break; ++ ++ case CTL_SMC_REG_PNR: // Packet Number ++ *valp = smc_get_reg(2, ioaddr, PN_REG); ++ break; ++ ++ case CTL_SMC_REG_FPR: // Allocation Result/FIFO Ports ++ *valp = smc_get_reg(2, ioaddr, RXFIFO_REG); ++ break; ++ ++ case CTL_SMC_REG_PTR: // Pointer ++ *valp = smc_get_reg(2, ioaddr, PTR_REG); ++ break; ++ ++ case CTL_SMC_REG_DR: // Data ++ *valp = smc_get_reg(2, ioaddr, DATA_REG); ++ break; ++ ++ case CTL_SMC_REG_ISR: // Interrupt Status/Mask ++ *valp = smc_get_reg(2, ioaddr, INT_REG); ++ break; ++ ++ case CTL_SMC_REG_MTR1: // Multicast Table Entry 1 ++ *valp = smc_get_reg(3, ioaddr, MCAST_REG1); ++ break; ++ ++ case CTL_SMC_REG_MTR2: // Multicast Table Entry 2 ++ *valp = smc_get_reg(3, ioaddr, MCAST_REG2); ++ break; ++ ++ case CTL_SMC_REG_MTR3: // Multicast Table Entry 3 ++ *valp = smc_get_reg(3, ioaddr, MCAST_REG3); ++ break; ++ ++ case CTL_SMC_REG_MTR4: // Multicast Table Entry 4 ++ *valp = smc_get_reg(3, ioaddr, MCAST_REG4); ++ break; ++ ++ case CTL_SMC_REG_MIIR: // Management Interface ++ *valp = smc_get_reg(3, ioaddr, MII_REG); ++ break; ++ ++ case CTL_SMC_REG_REVR: // Revision ++ *valp = smc_get_reg(3, ioaddr, REV_REG); ++ break; ++ ++ case CTL_SMC_REG_ERCVR: // Early RCV ++ *valp = smc_get_reg(3, ioaddr, ERCV_REG); ++ break; ++ ++ case CTL_SMC_REG_EXTR: // External ++ *valp = smc_get_reg(7, ioaddr, EXT_REG); ++ break; ++ ++ case CTL_SMC_PHY_CTRL: ++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr, ++ PHY_CNTL_REG); ++ break; ++ ++ case CTL_SMC_PHY_STAT: ++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr, ++ PHY_STAT_REG); ++ break; ++ ++ case CTL_SMC_PHY_ID1: ++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr, ++ PHY_ID1_REG); ++ break; ++ ++ case CTL_SMC_PHY_ID2: ++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr, ++ PHY_ID2_REG); ++ break; ++ ++ case CTL_SMC_PHY_ADC: ++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr, ++ PHY_AD_REG); ++ break; ++ ++ case CTL_SMC_PHY_REMC: ++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr, ++ PHY_RMT_REG); ++ break; ++ ++ case CTL_SMC_PHY_CFG1: ++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr, ++ PHY_CFG1_REG); ++ break; ++ ++ case CTL_SMC_PHY_CFG2: ++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr, ++ PHY_CFG2_REG); ++ break; ++ ++ case CTL_SMC_PHY_INT: ++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr, ++ PHY_INT_REG); ++ break; ++ ++ case CTL_SMC_PHY_MASK: ++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr, ++ PHY_MASK_REG); ++ break; ++ ++#endif // SMC_DEBUG > 1 ++ ++ default: ++ // Just ignore unsupported parameters ++ break; ++ } ++ ++ // Save old state ++ val = *valp; ++ ++ // Perform the generic integer operation ++ if ((ret = proc_dointvec(ctl, write, filp, buffer, lenp)) != 0) ++ return(ret); ++ ++ // Write changes out to the registers ++ if (write && *valp != val) { ++ ++ val = *valp; ++ switch (ctl->ctl_name) { ++ ++ case CTL_SMC_SWFDUP: ++ if (val) ++ lp->tcr_cur_mode |= TCR_SWFDUP; ++ else ++ lp->tcr_cur_mode &= ~TCR_SWFDUP; ++ ++ smc_modify_regbit(0, ioaddr, TCR_REG, TCR_SWFDUP, val); ++ break; ++ ++ case CTL_SMC_EPHLOOP: ++ if (val) ++ lp->tcr_cur_mode |= TCR_EPH_LOOP; ++ else ++ lp->tcr_cur_mode &= ~TCR_EPH_LOOP; ++ ++ smc_modify_regbit(0, ioaddr, TCR_REG, TCR_EPH_LOOP, val); ++ break; ++ ++ case CTL_SMC_FORCOL: ++ if (val) ++ lp->tcr_cur_mode |= TCR_FORCOL; ++ else ++ lp->tcr_cur_mode &= ~TCR_FORCOL; ++ ++ // Update the EPH block ++ smc_modify_regbit(0, ioaddr, TCR_REG, TCR_FORCOL, val); ++ break; ++ ++ case CTL_SMC_FILTCAR: ++ if (val) ++ lp->rcr_cur_mode |= RCR_FILT_CAR; ++ else ++ lp->rcr_cur_mode &= ~RCR_FILT_CAR; ++ ++ // Update the EPH block ++ smc_modify_regbit(0, ioaddr, RCR_REG, RCR_FILT_CAR, val); ++ break; ++ ++ case CTL_SMC_RFDUPLX: ++ // Disallow changes if in auto-negotiation mode ++ if (lp->ctl_autoneg) ++ break; ++ ++ if (val) ++ lp->rpc_cur_mode |= RPC_DPLX; ++ else ++ lp->rpc_cur_mode &= ~RPC_DPLX; ++ ++ // Reconfigure the PHY ++ smc_phy_configure(dev); ++ ++ break; ++ ++ case CTL_SMC_RSPEED: ++ // Disallow changes if in auto-negotiation mode ++ if (lp->ctl_autoneg) ++ break; ++ ++ if (val > 10) ++ lp->rpc_cur_mode |= RPC_SPEED; ++ else ++ lp->rpc_cur_mode &= ~RPC_SPEED; ++ ++ // Reconfigure the PHY ++ smc_phy_configure(dev); ++ ++ break; ++ ++ case CTL_SMC_AUTONEG: ++ if (val) ++ lp->rpc_cur_mode |= RPC_ANEG; ++ else ++ lp->rpc_cur_mode &= ~RPC_ANEG; ++ ++ // Reconfigure the PHY ++ smc_phy_configure(dev); ++ ++ break; ++ ++ case CTL_SMC_LEDA: ++ val &= 0x07; // Restrict to 3 ls bits ++ lp->rpc_cur_mode &= ~(word)(0x07<rpc_cur_mode |= (word)(val<rpc_cur_mode); ++ break; ++ ++ case CTL_SMC_LEDB: ++ val &= 0x07; // Restrict to 3 ls bits ++ lp->rpc_cur_mode &= ~(word)(0x07<rpc_cur_mode |= (word)(val<rpc_cur_mode); ++ break; ++ ++ case CTL_SMC_MIIOP: ++ // Update the Internal PHY block ++ smc_modify_regbit(1, ioaddr, CONFIG_REG, ++ CONFIG_EXT_PHY, val); ++ break; ++ ++#if SMC_DEBUG > 1 ++ case CTL_SMC_REG_BSR: // Bank Select ++ smc_modify_reg(0, ioaddr, BSR_REG, val); ++ break; ++ ++ case CTL_SMC_REG_TCR: // Transmit Control ++ smc_modify_reg(0, ioaddr, TCR_REG, val); ++ break; ++ ++ case CTL_SMC_REG_ESR: // EPH Status ++ smc_modify_reg(0, ioaddr, EPH_STATUS_REG, val); ++ break; ++ ++ case CTL_SMC_REG_RCR: // Receive Control ++ smc_modify_reg(0, ioaddr, RCR_REG, val); ++ break; ++ ++ case CTL_SMC_REG_CTRR: // Counter ++ smc_modify_reg(0, ioaddr, COUNTER_REG, val); ++ break; ++ ++ case CTL_SMC_REG_MIR: // Memory Information ++ smc_modify_reg(0, ioaddr, MIR_REG, val); ++ break; ++ ++ case CTL_SMC_REG_RPCR: // Receive/Phy Control ++ smc_modify_reg(0, ioaddr, RPC_REG, val); ++ break; ++ ++ case CTL_SMC_REG_CFGR: // Configuration ++ smc_modify_reg(1, ioaddr, CONFIG_REG, val); ++ break; ++ ++ case CTL_SMC_REG_BAR: // Base Address ++ smc_modify_reg(1, ioaddr, BASE_REG, val); ++ break; ++ ++ case CTL_SMC_REG_IAR0: // Individual Address ++ smc_modify_reg(1, ioaddr, ADDR0_REG, val); ++ break; ++ ++ case CTL_SMC_REG_IAR1: // Individual Address ++ smc_modify_reg(1, ioaddr, ADDR1_REG, val); ++ break; ++ ++ case CTL_SMC_REG_IAR2: // Individual Address ++ smc_modify_reg(1, ioaddr, ADDR2_REG, val); ++ break; ++ ++ case CTL_SMC_REG_GPR: // General Purpose ++ smc_modify_reg(1, ioaddr, GP_REG, val); ++ break; ++ ++ case CTL_SMC_REG_CTLR: // Control ++ smc_modify_reg(1, ioaddr, CTL_REG, val); ++ break; ++ ++ case CTL_SMC_REG_MCR: // MMU Command ++ smc_modify_reg(2, ioaddr, MMU_CMD_REG, val); ++ break; ++ ++ case CTL_SMC_REG_PNR: // Packet Number ++ smc_modify_reg(2, ioaddr, PN_REG, val); ++ break; ++ ++ case CTL_SMC_REG_FPR: // Allocation Result/FIFO Ports ++ smc_modify_reg(2, ioaddr, RXFIFO_REG, val); ++ break; ++ ++ case CTL_SMC_REG_PTR: // Pointer ++ smc_modify_reg(2, ioaddr, PTR_REG, val); ++ break; ++ ++ case CTL_SMC_REG_DR: // Data ++ smc_modify_reg(2, ioaddr, DATA_REG, val); ++ break; ++ ++ case CTL_SMC_REG_ISR: // Interrupt Status/Mask ++ smc_modify_reg(2, ioaddr, INT_REG, val); ++ break; ++ ++ case CTL_SMC_REG_MTR1: // Multicast Table Entry 1 ++ smc_modify_reg(3, ioaddr, MCAST_REG1, val); ++ break; ++ ++ case CTL_SMC_REG_MTR2: // Multicast Table Entry 2 ++ smc_modify_reg(3, ioaddr, MCAST_REG2, val); ++ break; ++ ++ case CTL_SMC_REG_MTR3: // Multicast Table Entry 3 ++ smc_modify_reg(3, ioaddr, MCAST_REG3, val); ++ break; ++ ++ case CTL_SMC_REG_MTR4: // Multicast Table Entry 4 ++ smc_modify_reg(3, ioaddr, MCAST_REG4, val); ++ break; ++ ++ case CTL_SMC_REG_MIIR: // Management Interface ++ smc_modify_reg(3, ioaddr, MII_REG, val); ++ break; ++ ++ case CTL_SMC_REG_REVR: // Revision ++ smc_modify_reg(3, ioaddr, REV_REG, val); ++ break; ++ ++ case CTL_SMC_REG_ERCVR: // Early RCV ++ smc_modify_reg(3, ioaddr, ERCV_REG, val); ++ break; ++ ++ case CTL_SMC_REG_EXTR: // External ++ smc_modify_reg(7, ioaddr, EXT_REG, val); ++ break; ++ ++ case CTL_SMC_PHY_CTRL: ++ smc_write_phy_register(ioaddr, lp->phyaddr, ++ PHY_CNTL_REG, val); ++ break; ++ ++ case CTL_SMC_PHY_STAT: ++ smc_write_phy_register(ioaddr, lp->phyaddr, ++ PHY_STAT_REG, val); ++ break; ++ ++ case CTL_SMC_PHY_ID1: ++ smc_write_phy_register(ioaddr, lp->phyaddr, ++ PHY_ID1_REG, val); ++ break; ++ ++ case CTL_SMC_PHY_ID2: ++ smc_write_phy_register(ioaddr, lp->phyaddr, ++ PHY_ID2_REG, val); ++ break; ++ ++ case CTL_SMC_PHY_ADC: ++ smc_write_phy_register(ioaddr, lp->phyaddr, ++ PHY_AD_REG, val); ++ break; ++ ++ case CTL_SMC_PHY_REMC: ++ smc_write_phy_register(ioaddr, lp->phyaddr, ++ PHY_RMT_REG, val); ++ break; ++ ++ case CTL_SMC_PHY_CFG1: ++ smc_write_phy_register(ioaddr, lp->phyaddr, ++ PHY_CFG1_REG, val); ++ break; ++ ++ case CTL_SMC_PHY_CFG2: ++ smc_write_phy_register(ioaddr, lp->phyaddr, ++ PHY_CFG2_REG, val); ++ break; ++ ++ case CTL_SMC_PHY_INT: ++ smc_write_phy_register(ioaddr, lp->phyaddr, ++ PHY_INT_REG, val); ++ break; ++ ++ case CTL_SMC_PHY_MASK: ++ smc_write_phy_register(ioaddr, lp->phyaddr, ++ PHY_MASK_REG, val); ++ break; ++ ++#endif // SMC_DEBUG > 1 ++ ++ default: ++ // Just ignore unsupported parameters ++ break; ++ } // end switch ++ ++ } // end if ++ ++ return ret; ++} ++ ++ ++#ifdef MODULE ++/* ++ * This is called as the fill_inode function when an inode ++ * is going into (fill = 1) or out of service (fill = 0). ++ * We use it here to manage the module use counts. ++ * ++ * Note: only the top-level directory needs to do this; if ++ * a lower level is referenced, the parent will be as well. ++ */ ++static void smc_procfs_modcount(struct inode *inode, int fill) ++{ ++ if (fill) ++ MOD_INC_USE_COUNT; ++ else ++ MOD_DEC_USE_COUNT; ++} ++#endif // MODULE ++ ++/*------------------------------------------------------------ ++ . Sysctl registration function for all parameters (files) ++ .-------------------------------------------------------------*/ ++static void smc_sysctl_register(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ static int ctl_name = CTL_SMC; ++ ctl_table* ct; ++ int i; ++ ++ // Make sure the ctl_tables start out as all zeros ++ memset(lp->root_table, 0, sizeof lp->root_table); ++ memset(lp->eth_table, 0, sizeof lp->eth_table); ++ memset(lp->param_table, 0, sizeof lp->param_table); ++ ++ // Initialize the root table ++ ct = lp->root_table; ++ ct->ctl_name = CTL_DEV; ++ ct->procname = "dev"; ++ ct->maxlen = 0; ++ ct->mode = 0555; ++ ct->child = lp->eth_table; ++ // remaining fields are zero ++ ++ // Initialize the ethX table (this device's table) ++ ct = lp->eth_table; ++ ct->ctl_name = ctl_name++; // Must be unique ++ ct->procname = dev->name; ++ ct->maxlen = 0; ++ ct->mode = 0555; ++ ct->child = lp->param_table; ++ // remaining fields are zero ++ ++ // Initialize the parameter (files) table ++ // Make sure the last entry remains null ++ ct = lp->param_table; ++ for (i = 0; i < (CTL_SMC_LAST_ENTRY-1); ++i) { ++ // Initialize fields common to all table entries ++ ct[i].proc_handler = smc_sysctl_handler; ++ ct[i].extra1 = (void*)dev; // Save our device pointer ++ ct[i].extra2 = (void*)lp; // Save our smc_local data pointer ++ } ++ ++ // INFO - this is our only string parameter ++ i = 0; ++ ct[i].proc_handler = proc_dostring; // use default handler ++ ct[i].ctl_name = CTL_SMC_INFO; ++ ct[i].procname = "info"; ++ ct[i].data = (void*)smc_info_string; ++ ct[i].maxlen = sizeof smc_info_string; ++ ct[i].mode = 0444; // Read only ++ ++ // SWVER ++ ++i; ++ ct[i].proc_handler = proc_dostring; // use default handler ++ ct[i].ctl_name = CTL_SMC_SWVER; ++ ct[i].procname = "swver"; ++ ct[i].data = (void*)version; ++ ct[i].maxlen = sizeof version; ++ ct[i].mode = 0444; // Read only ++ ++ // SWFDUP ++ ++i; ++ ct[i].ctl_name = CTL_SMC_SWFDUP; ++ ct[i].procname = "swfdup"; ++ ct[i].data = (void*)&(lp->ctl_swfdup); ++ ct[i].maxlen = sizeof lp->ctl_swfdup; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // EPHLOOP ++ ++i; ++ ct[i].ctl_name = CTL_SMC_EPHLOOP; ++ ct[i].procname = "ephloop"; ++ ct[i].data = (void*)&(lp->ctl_ephloop); ++ ct[i].maxlen = sizeof lp->ctl_ephloop; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // MIIOP ++ ++i; ++ ct[i].ctl_name = CTL_SMC_MIIOP; ++ ct[i].procname = "miiop"; ++ ct[i].data = (void*)&(lp->ctl_miiop); ++ ct[i].maxlen = sizeof lp->ctl_miiop; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // AUTONEG ++ ++i; ++ ct[i].ctl_name = CTL_SMC_AUTONEG; ++ ct[i].procname = "autoneg"; ++ ct[i].data = (void*)&(lp->ctl_autoneg); ++ ct[i].maxlen = sizeof lp->ctl_autoneg; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // RFDUPLX ++ ++i; ++ ct[i].ctl_name = CTL_SMC_RFDUPLX; ++ ct[i].procname = "rfduplx"; ++ ct[i].data = (void*)&(lp->ctl_rfduplx); ++ ct[i].maxlen = sizeof lp->ctl_rfduplx; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // RSPEED ++ ++i; ++ ct[i].ctl_name = CTL_SMC_RSPEED; ++ ct[i].procname = "rspeed"; ++ ct[i].data = (void*)&(lp->ctl_rspeed); ++ ct[i].maxlen = sizeof lp->ctl_rspeed; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // AFDUPLX ++ ++i; ++ ct[i].ctl_name = CTL_SMC_AFDUPLX; ++ ct[i].procname = "afduplx"; ++ ct[i].data = (void*)&(lp->ctl_afduplx); ++ ct[i].maxlen = sizeof lp->ctl_afduplx; ++ ct[i].mode = 0444; // Read only ++ ++ // ASPEED ++ ++i; ++ ct[i].ctl_name = CTL_SMC_ASPEED; ++ ct[i].procname = "aspeed"; ++ ct[i].data = (void*)&(lp->ctl_aspeed); ++ ct[i].maxlen = sizeof lp->ctl_aspeed; ++ ct[i].mode = 0444; // Read only ++ ++ // LNKFAIL ++ ++i; ++ ct[i].ctl_name = CTL_SMC_LNKFAIL; ++ ct[i].procname = "lnkfail"; ++ ct[i].data = (void*)&(lp->ctl_lnkfail); ++ ct[i].maxlen = sizeof lp->ctl_lnkfail; ++ ct[i].mode = 0444; // Read only ++ ++ // FORCOL ++ ++i; ++ ct[i].ctl_name = CTL_SMC_FORCOL; ++ ct[i].procname = "forcol"; ++ ct[i].data = (void*)&(lp->ctl_forcol); ++ ct[i].maxlen = sizeof lp->ctl_forcol; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // FILTCAR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_FILTCAR; ++ ct[i].procname = "filtcar"; ++ ct[i].data = (void*)&(lp->ctl_filtcar); ++ ct[i].maxlen = sizeof lp->ctl_filtcar; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // FREEMEM ++ ++i; ++ ct[i].ctl_name = CTL_SMC_FREEMEM; ++ ct[i].procname = "freemem"; ++ ct[i].data = (void*)&(lp->ctl_freemem); ++ ct[i].maxlen = sizeof lp->ctl_freemem; ++ ct[i].mode = 0444; // Read only ++ ++ // TOTMEM ++ ++i; ++ ct[i].ctl_name = CTL_SMC_TOTMEM; ++ ct[i].procname = "totmem"; ++ ct[i].data = (void*)&(lp->ctl_totmem); ++ ct[i].maxlen = sizeof lp->ctl_totmem; ++ ct[i].mode = 0444; // Read only ++ ++ // LEDA ++ ++i; ++ ct[i].ctl_name = CTL_SMC_LEDA; ++ ct[i].procname = "leda"; ++ ct[i].data = (void*)&(lp->ctl_leda); ++ ct[i].maxlen = sizeof lp->ctl_leda; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // LEDB ++ ++i; ++ ct[i].ctl_name = CTL_SMC_LEDB; ++ ct[i].procname = "ledb"; ++ ct[i].data = (void*)&(lp->ctl_ledb); ++ ct[i].maxlen = sizeof lp->ctl_ledb; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // CHIPREV ++ ++i; ++ ct[i].ctl_name = CTL_SMC_CHIPREV; ++ ct[i].procname = "chiprev"; ++ ct[i].data = (void*)&(lp->ctl_chiprev); ++ ct[i].maxlen = sizeof lp->ctl_chiprev; ++ ct[i].mode = 0444; // Read only ++ ++#if SMC_DEBUG > 1 ++ // REG_BSR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_BSR; ++ ct[i].procname = "reg_bsr"; ++ ct[i].data = (void*)&(lp->ctl_reg_bsr); ++ ct[i].maxlen = sizeof lp->ctl_reg_bsr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_TCR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_TCR; ++ ct[i].procname = "reg_tcr"; ++ ct[i].data = (void*)&(lp->ctl_reg_tcr); ++ ct[i].maxlen = sizeof lp->ctl_reg_tcr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_ESR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_ESR; ++ ct[i].procname = "reg_esr"; ++ ct[i].data = (void*)&(lp->ctl_reg_esr); ++ ct[i].maxlen = sizeof lp->ctl_reg_esr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_RCR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_RCR; ++ ct[i].procname = "reg_rcr"; ++ ct[i].data = (void*)&(lp->ctl_reg_rcr); ++ ct[i].maxlen = sizeof lp->ctl_reg_rcr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_CTRR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_CTRR; ++ ct[i].procname = "reg_ctrr"; ++ ct[i].data = (void*)&(lp->ctl_reg_ctrr); ++ ct[i].maxlen = sizeof lp->ctl_reg_ctrr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_MIR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_MIR; ++ ct[i].procname = "reg_mir"; ++ ct[i].data = (void*)&(lp->ctl_reg_mir); ++ ct[i].maxlen = sizeof lp->ctl_reg_mir; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_RPCR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_RPCR; ++ ct[i].procname = "reg_rpcr"; ++ ct[i].data = (void*)&(lp->ctl_reg_rpcr); ++ ct[i].maxlen = sizeof lp->ctl_reg_rpcr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_CFGR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_CFGR; ++ ct[i].procname = "reg_cfgr"; ++ ct[i].data = (void*)&(lp->ctl_reg_cfgr); ++ ct[i].maxlen = sizeof lp->ctl_reg_cfgr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_BAR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_BAR; ++ ct[i].procname = "reg_bar"; ++ ct[i].data = (void*)&(lp->ctl_reg_bar); ++ ct[i].maxlen = sizeof lp->ctl_reg_bar; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_IAR0 ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_IAR0; ++ ct[i].procname = "reg_iar0"; ++ ct[i].data = (void*)&(lp->ctl_reg_iar0); ++ ct[i].maxlen = sizeof lp->ctl_reg_iar0; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_IAR1 ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_IAR1; ++ ct[i].procname = "reg_iar1"; ++ ct[i].data = (void*)&(lp->ctl_reg_iar1); ++ ct[i].maxlen = sizeof lp->ctl_reg_iar1; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_IAR2 ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_IAR2; ++ ct[i].procname = "reg_iar2"; ++ ct[i].data = (void*)&(lp->ctl_reg_iar2); ++ ct[i].maxlen = sizeof lp->ctl_reg_iar2; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_GPR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_GPR; ++ ct[i].procname = "reg_gpr"; ++ ct[i].data = (void*)&(lp->ctl_reg_gpr); ++ ct[i].maxlen = sizeof lp->ctl_reg_gpr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_CTLR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_CTLR; ++ ct[i].procname = "reg_ctlr"; ++ ct[i].data = (void*)&(lp->ctl_reg_ctlr); ++ ct[i].maxlen = sizeof lp->ctl_reg_ctlr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_MCR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_MCR; ++ ct[i].procname = "reg_mcr"; ++ ct[i].data = (void*)&(lp->ctl_reg_mcr); ++ ct[i].maxlen = sizeof lp->ctl_reg_mcr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_PNR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_PNR; ++ ct[i].procname = "reg_pnr"; ++ ct[i].data = (void*)&(lp->ctl_reg_pnr); ++ ct[i].maxlen = sizeof lp->ctl_reg_pnr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_FPR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_FPR; ++ ct[i].procname = "reg_fpr"; ++ ct[i].data = (void*)&(lp->ctl_reg_fpr); ++ ct[i].maxlen = sizeof lp->ctl_reg_fpr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_PTR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_PTR; ++ ct[i].procname = "reg_ptr"; ++ ct[i].data = (void*)&(lp->ctl_reg_ptr); ++ ct[i].maxlen = sizeof lp->ctl_reg_ptr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_DR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_DR; ++ ct[i].procname = "reg_dr"; ++ ct[i].data = (void*)&(lp->ctl_reg_dr); ++ ct[i].maxlen = sizeof lp->ctl_reg_dr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_ISR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_ISR; ++ ct[i].procname = "reg_isr"; ++ ct[i].data = (void*)&(lp->ctl_reg_isr); ++ ct[i].maxlen = sizeof lp->ctl_reg_isr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_MTR1 ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_MTR1; ++ ct[i].procname = "reg_mtr1"; ++ ct[i].data = (void*)&(lp->ctl_reg_mtr1); ++ ct[i].maxlen = sizeof lp->ctl_reg_mtr1; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_MTR2 ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_MTR2; ++ ct[i].procname = "reg_mtr2"; ++ ct[i].data = (void*)&(lp->ctl_reg_mtr2); ++ ct[i].maxlen = sizeof lp->ctl_reg_mtr2; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_MTR3 ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_MTR3; ++ ct[i].procname = "reg_mtr3"; ++ ct[i].data = (void*)&(lp->ctl_reg_mtr3); ++ ct[i].maxlen = sizeof lp->ctl_reg_mtr3; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_MTR4 ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_MTR4; ++ ct[i].procname = "reg_mtr4"; ++ ct[i].data = (void*)&(lp->ctl_reg_mtr4); ++ ct[i].maxlen = sizeof lp->ctl_reg_mtr4; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_MIIR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_MIIR; ++ ct[i].procname = "reg_miir"; ++ ct[i].data = (void*)&(lp->ctl_reg_miir); ++ ct[i].maxlen = sizeof lp->ctl_reg_miir; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_REVR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_REVR; ++ ct[i].procname = "reg_revr"; ++ ct[i].data = (void*)&(lp->ctl_reg_revr); ++ ct[i].maxlen = sizeof lp->ctl_reg_revr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_ERCVR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_ERCVR; ++ ct[i].procname = "reg_ercvr"; ++ ct[i].data = (void*)&(lp->ctl_reg_ercvr); ++ ct[i].maxlen = sizeof lp->ctl_reg_ercvr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // REG_EXTR ++ ++i; ++ ct[i].ctl_name = CTL_SMC_REG_EXTR; ++ ct[i].procname = "reg_extr"; ++ ct[i].data = (void*)&(lp->ctl_reg_extr); ++ ct[i].maxlen = sizeof lp->ctl_reg_extr; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // PHY Control ++ ++i; ++ ct[i].ctl_name = CTL_SMC_PHY_CTRL; ++ ct[i].procname = "phy_ctrl"; ++ ct[i].data = (void*)&(lp->ctl_phy_ctrl); ++ ct[i].maxlen = sizeof lp->ctl_phy_ctrl; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // PHY Status ++ ++i; ++ ct[i].ctl_name = CTL_SMC_PHY_STAT; ++ ct[i].procname = "phy_stat"; ++ ct[i].data = (void*)&(lp->ctl_phy_stat); ++ ct[i].maxlen = sizeof lp->ctl_phy_stat; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // PHY ID1 ++ ++i; ++ ct[i].ctl_name = CTL_SMC_PHY_ID1; ++ ct[i].procname = "phy_id1"; ++ ct[i].data = (void*)&(lp->ctl_phy_id1); ++ ct[i].maxlen = sizeof lp->ctl_phy_id1; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // PHY ID2 ++ ++i; ++ ct[i].ctl_name = CTL_SMC_PHY_ID2; ++ ct[i].procname = "phy_id2"; ++ ct[i].data = (void*)&(lp->ctl_phy_id2); ++ ct[i].maxlen = sizeof lp->ctl_phy_id2; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // PHY Advertise Capabilities ++ ++i; ++ ct[i].ctl_name = CTL_SMC_PHY_ADC; ++ ct[i].procname = "phy_adc"; ++ ct[i].data = (void*)&(lp->ctl_phy_adc); ++ ct[i].maxlen = sizeof lp->ctl_phy_adc; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // PHY Remote Capabilities ++ ++i; ++ ct[i].ctl_name = CTL_SMC_PHY_REMC; ++ ct[i].procname = "phy_remc"; ++ ct[i].data = (void*)&(lp->ctl_phy_remc); ++ ct[i].maxlen = sizeof lp->ctl_phy_remc; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // PHY Configuration 1 ++ ++i; ++ ct[i].ctl_name = CTL_SMC_PHY_CFG1; ++ ct[i].procname = "phy_cfg1"; ++ ct[i].data = (void*)&(lp->ctl_phy_cfg1); ++ ct[i].maxlen = sizeof lp->ctl_phy_cfg1; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // PHY Configuration 2 ++ ++i; ++ ct[i].ctl_name = CTL_SMC_PHY_CFG2; ++ ct[i].procname = "phy_cfg2"; ++ ct[i].data = (void*)&(lp->ctl_phy_cfg2); ++ ct[i].maxlen = sizeof lp->ctl_phy_cfg2; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // PHY Interrupt/Status Output ++ ++i; ++ ct[i].ctl_name = CTL_SMC_PHY_INT; ++ ct[i].procname = "phy_int"; ++ ct[i].data = (void*)&(lp->ctl_phy_int); ++ ct[i].maxlen = sizeof lp->ctl_phy_int; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++ // PHY Interrupt/Status Mask ++ ++i; ++ ct[i].ctl_name = CTL_SMC_PHY_MASK; ++ ct[i].procname = "phy_mask"; ++ ct[i].data = (void*)&(lp->ctl_phy_mask); ++ ct[i].maxlen = sizeof lp->ctl_phy_mask; ++ ct[i].mode = 0644; // Read by all, write by root ++ ++#endif // SMC_DEBUG > 1 ++ ++ // Register /proc/sys/dev/ethX ++ lp->sysctl_header = register_sysctl_table(lp->root_table, 1); ++ ++#ifdef MODULE ++ // Register our modcount function which adjusts the module count ++ lp->root_table->child->de->fill_inode = smc_procfs_modcount; ++#endif // MODULE ++ ++} ++ ++ ++/*------------------------------------------------------------ ++ . Sysctl unregistration when driver is closed ++ .-------------------------------------------------------------*/ ++static void smc_sysctl_unregister(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ ++ unregister_sysctl_table(lp->sysctl_header); ++} ++ ++#endif /* endif CONFIG_SYSCTL */ ++ ++ ++//---PHY CONTROL AND CONFIGURATION----------------------------------------- ++ ++#if (SMC_DEBUG > 2 ) ++ ++/*------------------------------------------------------------ ++ . Debugging function for viewing MII Management serial bitstream ++ .-------------------------------------------------------------*/ ++static void smc_dump_mii_stream(byte* bits, int size) ++{ ++ int i; ++ ++ printk("BIT#:"); ++ for (i = 0; i < size; ++i) ++ printk("%d", i%10); ++ ++ printk("\nMDOE:"); ++ for (i = 0; i < size; ++i) { ++ if (bits[i] & MII_MDOE) ++ printk("1"); ++ else ++ printk("0"); ++ } ++ ++ printk("\nMDO :"); ++ for (i = 0; i < size; ++i) { ++ if (bits[i] & MII_MDO) ++ printk("1"); ++ else ++ printk("0"); ++ } ++ ++ printk("\nMDI :"); ++ for (i = 0; i < size; ++i) { ++ if (bits[i] & MII_MDI) ++ printk("1"); ++ else ++ printk("0"); ++ } ++ ++ printk("\n"); ++} ++#endif ++ ++/*------------------------------------------------------------ ++ . Reads a register from the MII Management serial interface ++ .-------------------------------------------------------------*/ ++static word smc_read_phy_register(unsigned long ioaddr, ++ byte phyaddr, byte phyreg) ++{ ++ int oldBank; ++ int i; ++ byte mask; ++ word mii_reg; ++ byte bits[64]; ++ int clk_idx = 0; ++ int input_idx; ++ word phydata; ++ ++ // 32 consecutive ones on MDO to establish sync ++ for (i = 0; i < 32; ++i) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Start code <01> ++ bits[clk_idx++] = MII_MDOE; ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Read command <10> ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Output the PHY address, msb first ++ mask = (byte)0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyaddr & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Output the phy register number, msb first ++ mask = (byte)0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyreg & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Tristate and turnaround (2 bit times) ++ bits[clk_idx++] = 0; ++ //bits[clk_idx++] = 0; ++ ++ // Input starts at this bit time ++ input_idx = clk_idx; ++ ++ // Will input 16 bits ++ for (i = 0; i < 16; ++i) ++ bits[clk_idx++] = 0; ++ ++ // Final clock bit ++ bits[clk_idx++] = 0; ++ ++ // Save the current bank ++ oldBank = SMC_CURRENT_BANK(); ++ ++ // Select bank 3 ++ SMC_SELECT_BANK( 3 ); ++ ++ // Get the current MII register value ++ mii_reg = SMC_GET_MII(); ++ ++ // Turn off all MII Interface bits ++ mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); ++ ++ // Clock all 64 cycles ++ for (i = 0; i < sizeof bits; ++i) { ++ // Clock Low - output data ++ SMC_SET_MII( mii_reg | bits[i] ); ++ udelay(50); ++ ++ ++ // Clock Hi - input data ++ SMC_SET_MII( mii_reg | bits[i] | MII_MCLK ); ++ udelay(50); ++ bits[i] |= SMC_GET_MII() & MII_MDI; ++ } ++ ++ // Return to idle state ++ // Set clock to low, data to low, and output tristated ++ SMC_SET_MII( mii_reg ); ++ udelay(50); ++ ++ // Restore original bank select ++ SMC_SELECT_BANK( oldBank ); ++ ++ // Recover input data ++ phydata = 0; ++ for (i = 0; i < 16; ++i) { ++ phydata <<= 1; ++ ++ if (bits[input_idx++] & MII_MDI) ++ phydata |= 0x0001; ++ } ++ ++#if (SMC_DEBUG > 2 ) ++ printk("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n", ++ phyaddr, phyreg, phydata); ++ smc_dump_mii_stream(bits, sizeof bits); ++#endif ++ ++ return(phydata); ++} ++ ++ ++/*------------------------------------------------------------ ++ . Writes a register to the MII Management serial interface ++ .-------------------------------------------------------------*/ ++static void smc_write_phy_register(unsigned long ioaddr, ++ byte phyaddr, byte phyreg, word phydata) ++{ ++ int oldBank; ++ int i; ++ word mask; ++ word mii_reg; ++ byte bits[65]; ++ int clk_idx = 0; ++ ++ // 32 consecutive ones on MDO to establish sync ++ for (i = 0; i < 32; ++i) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Start code <01> ++ bits[clk_idx++] = MII_MDOE; ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Write command <01> ++ bits[clk_idx++] = MII_MDOE; ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Output the PHY address, msb first ++ mask = (byte)0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyaddr & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Output the phy register number, msb first ++ mask = (byte)0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyreg & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Tristate and turnaround (2 bit times) ++ bits[clk_idx++] = 0; ++ bits[clk_idx++] = 0; ++ ++ // Write out 16 bits of data, msb first ++ mask = 0x8000; ++ for (i = 0; i < 16; ++i) { ++ if (phydata & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Final clock bit (tristate) ++ bits[clk_idx++] = 0; ++ ++ // Save the current bank ++ oldBank = SMC_CURRENT_BANK(); ++ ++ // Select bank 3 ++ SMC_SELECT_BANK( 3 ); ++ ++ // Get the current MII register value ++ mii_reg = SMC_GET_MII(); ++ ++ // Turn off all MII Interface bits ++ mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); ++ ++ // Clock all cycles ++ for (i = 0; i < sizeof bits; ++i) { ++ // Clock Low - output data ++ SMC_SET_MII( mii_reg | bits[i] ); ++ udelay(50); ++ ++ ++ // Clock Hi - input data ++ SMC_SET_MII( mii_reg | bits[i] | MII_MCLK ); ++ udelay(50); ++ bits[i] |= SMC_GET_MII() & MII_MDI; ++ } ++ ++ // Return to idle state ++ // Set clock to low, data to low, and output tristated ++ SMC_SET_MII( mii_reg ); ++ udelay(50); ++ ++ // Restore original bank select ++ SMC_SELECT_BANK( oldBank ); ++ ++#if (SMC_DEBUG > 2 ) ++ printk("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n", ++ phyaddr, phyreg, phydata); ++ smc_dump_mii_stream(bits, sizeof bits); ++#endif ++} ++ ++ ++/*------------------------------------------------------------ ++ . Finds and reports the PHY address ++ .-------------------------------------------------------------*/ ++static int smc_detect_phy(struct net_device* dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ word phy_id1; ++ word phy_id2; ++ int phyaddr; ++ int found = 0; ++ ++ PRINTK3("%s:smc_detect_phy()\n", dev->name); ++ ++ // Scan all 32 PHY addresses if necessary ++ for (phyaddr = 0; phyaddr < 32; ++phyaddr) { ++ // Read the PHY identifiers ++ phy_id1 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG); ++ phy_id2 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG); ++ ++ PRINTK3("%s: phy_id1=%x, phy_id2=%x\n", ++ dev->name, phy_id1, phy_id2); ++ ++ // Make sure it is a valid identifier ++ if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) && ++ (phy_id1 > 0x0000) && (phy_id1 < 0xffff)) { ++ if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000)) { ++ // Save the PHY's address ++ lp->phyaddr = phyaddr; ++ found = 1; ++ break; ++ } ++ } ++ } ++ ++ if (!found) { ++ PRINTK("%s: No PHY found\n", dev->name); ++ return(0); ++ } ++ ++ // Set the PHY type ++ if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) ) { ++ lp->phytype = PHY_LAN83C183; ++ PRINTK("%s: PHY=LAN83C183 (LAN91C111 Internal)\n", dev->name); ++ } ++ ++ if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) ) { ++ lp->phytype = PHY_LAN83C180; ++ PRINTK("%s: PHY=LAN83C180\n", dev->name); ++ } ++ ++ return(1); ++} ++ ++/*------------------------------------------------------------ ++ . Waits the specified number of milliseconds - kernel friendly ++ .-------------------------------------------------------------*/ ++static void smc_wait_ms(unsigned int ms) ++{ ++ ++ if (!in_interrupt()) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(1 + ms * HZ / 1000); ++ } else { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1 + ms * HZ / 1000); ++ set_current_state(TASK_RUNNING); ++ } ++} ++ ++/*------------------------------------------------------------ ++ . Sets the PHY to a configuration as determined by the user ++ .-------------------------------------------------------------*/ ++static int smc_phy_fixed(struct net_device* dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ byte phyaddr = lp->phyaddr; ++ word my_fixed_caps; ++ word cfg1; ++ ++ PRINTK3("%s:smc_phy_fixed()\n", dev->name); ++ ++ // Enter Link Disable state ++ cfg1 = smc_read_phy_register(ioaddr, phyaddr, PHY_CFG1_REG); ++ cfg1 |= PHY_CFG1_LNKDIS; ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CFG1_REG, cfg1); ++ ++ // Set our fixed capabilities ++ // Disable auto-negotiation ++ my_fixed_caps = 0; ++ ++ if (lp->ctl_rfduplx) ++ my_fixed_caps |= PHY_CNTL_DPLX; ++ ++ if (lp->ctl_rspeed == 100) ++ my_fixed_caps |= PHY_CNTL_SPEED; ++ ++ // Write our capabilities to the phy control register ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, my_fixed_caps); ++ ++ // Re-Configure the Receive/Phy Control register ++ SMC_SET_RPC( lp->rpc_cur_mode ); ++ ++ // Success ++ return(1); ++} ++ ++ ++/*------------------------------------------------------------ ++ . Configures the specified PHY using Autonegotiation. Calls ++ . smc_phy_fixed() if the user has requested a certain config. ++ .-------------------------------------------------------------*/ ++static void smc_phy_configure(struct net_device* dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int timeout; ++ byte phyaddr; ++ word my_phy_caps; // My PHY capabilities ++ word my_ad_caps; // My Advertised capabilities ++ word status; ++ int failed = 0; ++ ++ PRINTK3("%s:smc_program_phy()\n", dev->name); ++ ++ // Set the blocking flag ++ lp->autoneg_active = 1; ++ ++ // Find the address and type of our phy ++ if (!smc_detect_phy(dev)) ++ goto smc_phy_configure_exit; ++ ++ // Get the detected phy address ++ phyaddr = lp->phyaddr; ++ ++ // Reset the PHY, setting all other bits to zero ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST); ++ ++ // Wait for the reset to complete, or time out ++ timeout = 6; // Wait up to 3 seconds ++ while (timeout--) { ++ if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG) ++ & PHY_CNTL_RST)) ++ // reset complete ++ break; ++ smc_wait_ms(500); // wait 500 millisecs ++ if (signal_pending(current)) { // Exit anyway if signaled ++ PRINTK2("%s:PHY reset interrupted by signal\n", ++ dev->name); ++ timeout = 0; ++ break; ++ } ++ } ++ ++ if (timeout < 1) { ++ printk("%s:PHY reset timed out\n", dev->name); ++ goto smc_phy_configure_exit; ++ } ++ ++ // Read PHY Register 18, Status Output ++ lp->lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG); ++ ++ // Enable PHY Interrupts (for register 18) ++ // Interrupts listed here are disabled ++ smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG, ++ PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD | ++ PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB | ++ PHY_INT_SPDDET | PHY_INT_DPLXDET); ++ ++ /* Configure the Receive/Phy Control register */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_RPC( lp->rpc_cur_mode ); ++ ++ // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG ++ my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); ++ my_ad_caps = PHY_AD_CSMA; // I am CSMA capable ++ ++ if (my_phy_caps & PHY_STAT_CAP_T4) ++ my_ad_caps |= PHY_AD_T4; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TXF) ++ my_ad_caps |= PHY_AD_TX_FDX; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TXH) ++ my_ad_caps |= PHY_AD_TX_HDX; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TF) ++ my_ad_caps |= PHY_AD_10_FDX; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TH) ++ my_ad_caps |= PHY_AD_10_HDX; ++ ++ // Disable capabilities not selected by our user ++ if (lp->ctl_rspeed != 100) ++ my_ad_caps &= ~(PHY_AD_T4|PHY_AD_TX_FDX|PHY_AD_TX_HDX); ++ ++ if (!lp->ctl_rfduplx) ++ my_ad_caps &= ~(PHY_AD_TX_FDX|PHY_AD_10_FDX); ++ ++ // Update our Auto-Neg Advertisement Register ++ smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps); ++ ++ // Read the register back. Without this, it appears that when ++ // auto-negotiation is restarted, sometimes it isn't ready and ++ // the link does not come up. ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_AD_REG); ++ ++ PRINTK2("%s:phy caps=%x\n", dev->name, my_phy_caps); ++ PRINTK2("%s:phy advertised caps=%x\n", dev->name, my_ad_caps); ++ ++ // If the user requested no auto neg, then go set his request ++ if (!(lp->ctl_autoneg)) { ++ smc_phy_fixed(dev); ++ goto smc_phy_configure_exit; ++ } ++ ++ // Restart auto-negotiation process in order to advertise my caps ++ smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG, ++ PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST ); ++ ++ // Wait for the auto-negotiation to complete. This may take from ++ // 2 to 3 seconds. ++ // Wait for the reset to complete, or time out ++ timeout = 20; // Wait up to 10 seconds ++ while (timeout--) { ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); ++ if (status & PHY_STAT_ANEG_ACK) ++ // auto-negotiate complete ++ break; ++ ++ smc_wait_ms(500); // wait 500 millisecs ++ if (signal_pending(current)) { // Exit anyway if signaled ++ printk(KERN_DEBUG ++ "%s:PHY auto-negotiate interrupted by signal\n", ++ dev->name); ++ timeout = 0; ++ break; ++ } ++ ++ // Restart auto-negotiation if remote fault ++ if (status & PHY_STAT_REM_FLT) { ++ PRINTK2("%s:PHY remote fault detected\n", dev->name); ++ ++ // Restart auto-negotiation ++ PRINTK2("%s:PHY restarting auto-negotiation\n", ++ dev->name); ++ smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG, ++ PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST | ++ PHY_CNTL_SPEED | PHY_CNTL_DPLX); ++ } ++ } ++ ++ if (timeout < 1) { ++ printk(KERN_DEBUG "%s:PHY auto-negotiate timed out\n", ++ dev->name); ++ PRINTK2("%s:PHY auto-negotiate timed out\n", dev->name); ++ failed = 1; ++ } ++ ++ // Fail if we detected an auto-negotiate remote fault ++ if (status & PHY_STAT_REM_FLT) { ++ printk(KERN_DEBUG "%s:PHY remote fault detected\n", dev->name); ++ PRINTK2("%s:PHY remote fault detected\n", dev->name); ++ failed = 1; ++ } ++ ++ // The smc_phy_interrupt() routine will be called to update lastPhy18 ++ ++ // Set our sysctl parameters to match auto-negotiation results ++ if ( lp->lastPhy18 & PHY_INT_SPDDET ) { ++ PRINTK2("%s:PHY 100BaseT\n", dev->name); ++ lp->rpc_cur_mode |= RPC_SPEED; ++ } else { ++ PRINTK2("%s:PHY 10BaseT\n", dev->name); ++ lp->rpc_cur_mode &= ~RPC_SPEED; ++ } ++ ++ if ( lp->lastPhy18 & PHY_INT_DPLXDET ) { ++ PRINTK2("%s:PHY Full Duplex\n", dev->name); ++ lp->rpc_cur_mode |= RPC_DPLX; ++ } else { ++ PRINTK2("%s:PHY Half Duplex\n", dev->name); ++ lp->rpc_cur_mode &= ~RPC_DPLX; ++ } ++ ++ // Re-Configure the Receive/Phy Control register ++ SMC_SET_RPC( lp->rpc_cur_mode ); ++ ++smc_phy_configure_exit: ++ // Exit auto-negotiation ++ lp->autoneg_active = 0; ++} ++ ++ ++ ++/************************************************************************* ++ . smc_phy_interrupt ++ . ++ . Purpose: Handle interrupts relating to PHY register 18. This is ++ . called from the "hard" interrupt handler. ++ . ++ ************************************************************************/ ++static void smc_phy_interrupt(struct net_device* dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ byte phyaddr = lp->phyaddr; ++ word phy18; ++ ++ PRINTK2("%s: smc_phy_interrupt\n", dev->name); ++ ++ for(;;) { ++ // Read PHY Register 18, Status Output ++ phy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG); ++ ++ // Exit if not more changes ++ if (phy18 == lp->lastPhy18) ++ break; ++ ++#if (SMC_DEBUG > 1 ) ++ PRINTK2("%s: phy18=0x%x\n", dev->name, phy18); ++ PRINTK2("%s: lastPhy18=0x%x\n", dev->name, lp->lastPhy18); ++ ++ // Handle events ++ if ((phy18 & PHY_INT_LNKFAIL) != ++ (lp->lastPhy18 & PHY_INT_LNKFAIL)) ++ PRINTK2("%s: PHY Link Fail=%x\n", dev->name, ++ phy18 & PHY_INT_LNKFAIL); ++ ++ if ((phy18 & PHY_INT_LOSSSYNC) != ++ (lp->lastPhy18 & PHY_INT_LOSSSYNC)) ++ PRINTK2("%s: PHY LOSS SYNC=%x\n", dev->name, ++ phy18 & PHY_INT_LOSSSYNC); ++ ++ if ((phy18 & PHY_INT_CWRD) != (lp->lastPhy18 & PHY_INT_CWRD)) ++ PRINTK2("%s: PHY INVALID 4B5B code=%x\n", dev->name, ++ phy18 & PHY_INT_CWRD); ++ ++ if ((phy18 & PHY_INT_SSD) != (lp->lastPhy18 & PHY_INT_SSD)) ++ PRINTK2("%s: PHY No Start Of Stream=%x\n", dev->name, ++ phy18 & PHY_INT_SSD); ++ ++ if ((phy18 & PHY_INT_ESD) != (lp->lastPhy18 & PHY_INT_ESD)) ++ ++ PRINTK2("%s: PHY No End Of Stream=%x\n", dev->name, ++ phy18 & PHY_INT_ESD); ++ ++ if ((phy18 & PHY_INT_RPOL) != (lp->lastPhy18 & PHY_INT_RPOL)) ++ PRINTK2("%s: PHY Reverse Polarity Detected=%x\n", ++ dev->name, phy18 & PHY_INT_RPOL); ++ ++ if ((phy18 & PHY_INT_JAB) != (lp->lastPhy18 & PHY_INT_JAB)) ++ PRINTK2("%s: PHY Jabber Detected=%x\n", dev->name, ++ phy18 & PHY_INT_JAB); ++ ++ if ((phy18 & PHY_INT_SPDDET) != ++ (lp->lastPhy18 & PHY_INT_SPDDET)) ++ PRINTK2("%s: PHY Speed Detect=%x\n", dev->name, ++ phy18 & PHY_INT_SPDDET); ++ ++ if ((phy18 & PHY_INT_DPLXDET) != ++ (lp->lastPhy18 & PHY_INT_DPLXDET)) ++ PRINTK2("%s: PHY Duplex Detect=%x\n", dev->name, ++ phy18 & PHY_INT_DPLXDET); ++#endif ++ // Update the last phy 18 variable ++ lp->lastPhy18 = phy18; ++ } ++} +diff -Narup linux-2.4.31-orig/drivers/net/smc91111.h linux-2.4.31/drivers/net/smc91111.h +--- linux-2.4.31-orig/drivers/net/smc91111.h 1969-12-31 16:00:00.000000000 -0800 ++++ linux-2.4.31/drivers/net/smc91111.h 2005-08-08 16:03:33.000000000 -0700 +@@ -0,0 +1,712 @@ ++/*------------------------------------------------------------------------ ++ . smc91111.h - macros for the LAN91C111 Ethernet Driver ++ . ++ . Copyright (C) 2001 Standard Microsystems Corporation (SMSC) ++ . Developed by Simple Network Magic Corporation (SNMC) ++ . Copyright (C) 1996 by Erik Stahlman (ES) ++ . ++ . 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 ++ . ++ . This file contains register information and access macros for ++ . the LAN91C111 single chip ethernet controller. It is a modified ++ . version of the smc9194.h file. ++ . ++ . Information contained in this file was obtained from the LAN91C111 ++ . manual from SMC. To get a copy, if you really want one, you can find ++ . information under www.smsc.com. ++ . ++ . Authors ++ . Erik Stahlman ( erik@vt.edu ) ++ . Daris A Nevil ( dnevil@snmc.com ) ++ . ++ . History ++ . 03/16/01 Daris A Nevil Modified for use with LAN91C111 device ++ . ++ ---------------------------------------------------------------------------*/ ++#ifndef _SMC91111_H_ ++#define _SMC91111_H_ ++ ++/* I want some simple types */ ++ ++typedef unsigned char byte; ++typedef unsigned short word; ++typedef unsigned long int dword; ++ ++ ++/* ++ . Do you want to use 8 bit xfers? This should work on all chips, as the ++ . chipset is designed to accommodate them, although some hardware engineers ++ . do not connect byte enables so 8 bit xfers can not be used. ++*/ ++#ifdef CONFIG_SMC91111_USE_8_BIT ++#define SMC_inb(port) inb(port) ++#define SMC_insb(port,buf,ns) insb((port),(buf),(ns)) ++#define SMC_outb(val,port) outb((val),(port)) ++#define SMC_outsb(port,buf,ns) outsb((port),(buf),(ns)) ++#endif /* CONFIG_SMC91111_USE_8_BIT */ ++ ++/* Define 16 bit xfers. */ ++#ifdef CONFIG_SMC91111_BYTE_SWAP ++#define SMC_inw(port) swab16(inw(port)) ++#define SMC_insw(port,buf,ns) \ ++ do { \ ++ unsigned long __port = (port); \ ++ word *__buf = (word *)(buf); \ ++ int __ns = (ns); \ ++ insw(__port,__buf,__ns); \ ++ while (__ns > 0) { \ ++ *__buf = swab16(*__buf); \ ++ __buf++; \ ++ __ns--; \ ++ } \ ++ } while (0) ++#define SMC_outw(val,port) outw(swab16(val),(port)) ++#define SMC_outsw(port,buf,ns) \ ++ do { \ ++ unsigned long __port = (port); \ ++ word *__buf = (word *)(buf); \ ++ int __ns = (ns); \ ++ while (__ns > 0) { \ ++ /* Believe it or not, the swab isn't needed. */ \ ++ outw( /* swab16 */ (*__buf++), __port); \ ++ __ns--; \ ++ } \ ++ } while (0) ++#else /* CONFIG_SMC91111_BYTE_SWAP is not defined */ ++#define SMC_inw(port) inw(port) ++#define SMC_insw(port,buf,ns) insw((port),(buf),(ns)) ++#define SMC_outw(val,port) outw((val),(port)) ++#define SMC_outsw(port,buf,ns) outsw((port),(buf),(ns)) ++#endif /* CONFIG_SMC91111_BYTE_SWAP */ ++ ++/* ++ . Do you want to use 32 bit xfers? This should work on all chips, as the ++ . chipset is designed to accommodate them, although some hardware engineers ++ . do not connect all 32 data bits so 32 bit xfers can not be used. ++*/ ++#ifdef CONFIG_SMC91111_USE_32_BIT ++#ifdef CONFIG_SMC91111_BYTE_SWAP ++#define SMC_inl(port) swab32(inl(port)) ++#define SMC_insl(port,buf,ns) \ ++ do { \ ++ unsigned long __port = (port); \ ++ dword *__buf = (dword *)(buf); \ ++ int __ns = (ns); \ ++ insl(__port,__buf,__ns); \ ++ while (__ns > 0) { \ ++ *__buf = swab32(*__buf); \ ++ __buf++; \ ++ __ns--; \ ++ } \ ++ } while (0) ++#define SMC_outl(val,port) outl(swab32(val),(port)) ++#define SMC_outsl(port,buf,ns) \ ++ do { \ ++ unsigned long __port = (port); \ ++ dword *__buf = (dword *)(buf); \ ++ int __ns = (ns); \ ++ while (__ns > 0) { \ ++ /* Believe it or not, the swab isn't needed. */ \ ++ outl( /* swab32 */ (*__buf++), __port); \ ++ __ns--; \ ++ } \ ++ } while (0) ++#else /* CONFIG_SMC91111_BYTE_SWAP is not defined */ ++#define SMC_inl(port) inl(port) ++#define SMC_insl(port,buf,ns) insl((port),(buf),(ns)) ++#define SMC_outl(val,port) outl((val),(port)) ++#define SMC_outsl(port,buf,ns) outsl((port),(buf),(ns)) ++#endif /* CONFIG_SMC91111_BYTE_SWAP */ ++#endif /* CONFIG_SMC91111_USE_32_BIT */ ++ ++ ++/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */ ++ ++#define SMC_IO_EXTENT 16 ++ ++ ++/*--------------------------------------------------------------- ++ . ++ . A description of the SMSC registers is probably in order here, ++ . although for details, the SMC datasheet is invaluable. ++ . ++ . Basically, the chip has 4 banks of registers ( 0 to 3 ), which ++ . are accessed by writing a number into the BANK_SELECT register ++ . ( I also use a SMC_SELECT_BANK macro for this ). ++ . ++ . The banks are configured so that for most purposes, bank 2 is all ++ . that is needed for simple run time tasks. ++ -----------------------------------------------------------------------*/ ++ ++/* ++ . Bank Select Register: ++ . ++ . yyyy yyyy 0000 00xx ++ . xx = bank number ++ . yyyy yyyy = 0x33, for identification purposes. ++*/ ++#define BANK_SELECT 14 ++ ++// Transmit Control Register ++/* BANK 0 */ ++#define TCR_REG 0x0000 // transmit control register ++#define TCR_ENABLE 0x0001 // When 1 we can transmit ++#define TCR_LOOP 0x0002 // Controls output pin LBK ++#define TCR_FORCOL 0x0004 // When 1 will force a collision ++#define TCR_PAD_EN 0x0080 // When 1 will pad tx frames < 64 bytes w/0 ++#define TCR_NOCRC 0x0100 // When 1 will not append CRC to tx frames ++#define TCR_MON_CSN 0x0400 // When 1 tx monitors carrier ++#define TCR_FDUPLX 0x0800 // When 1 enables full duplex operation ++#define TCR_STP_SQET 0x1000 // When 1 stops tx if Signal Quality Error ++#define TCR_EPH_LOOP 0x2000 // When 1 enables EPH block loopback ++#define TCR_SWFDUP 0x8000 // When 1 enables Switched Full Duplex mode ++ ++#define TCR_CLEAR 0 /* do NOTHING */ ++/* the default settings for the TCR register : */ ++/* QUESTION: do I want to enable padding of short packets ? */ ++#define TCR_DEFAULT TCR_ENABLE ++ ++ ++// EPH Status Register ++/* BANK 0 */ ++#define EPH_STATUS_REG 0x0002 ++#define ES_TX_SUC 0x0001 // Last TX was successful ++#define ES_SNGL_COL 0x0002 // Single collision detected for last tx ++#define ES_MUL_COL 0x0004 // Multiple collisions detected for last tx ++#define ES_LTX_MULT 0x0008 // Last tx was a multicast ++#define ES_16COL 0x0010 // 16 Collisions Reached ++#define ES_SQET 0x0020 // Signal Quality Error Test ++#define ES_LTXBRD 0x0040 // Last tx was a broadcast ++#define ES_TXDEFR 0x0080 // Transmit Deferred ++#define ES_LATCOL 0x0200 // Late collision detected on last tx ++#define ES_LOSTCARR 0x0400 // Lost Carrier Sense ++#define ES_EXC_DEF 0x0800 // Excessive Deferral ++#define ES_CTR_ROL 0x1000 // Counter Roll Over indication ++#define ES_LINK_OK 0x4000 // Driven by inverted value of nLNK pin ++#define ES_TXUNRN 0x8000 // Tx Underrun ++ ++ ++// Receive Control Register ++/* BANK 0 */ ++#define RCR_REG 0x0004 ++#define RCR_RX_ABORT 0x0001 // Set if a rx frame was aborted ++#define RCR_PRMS 0x0002 // Enable promiscuous mode ++#define RCR_ALMUL 0x0004 // When set accepts all multicast frames ++#define RCR_RXEN 0x0100 // IFF this is set, we can receive packets ++#define RCR_STRIP_CRC 0x0200 // When set strips CRC from rx packets ++#define RCR_ABORT_ENB 0x0200 // When set will abort rx on collision ++#define RCR_FILT_CAR 0x0400 // When set filters leading 12 bit s of carrier ++#define RCR_SOFTRST 0x8000 // resets the chip ++ ++/* the normal settings for the RCR register : */ ++#define RCR_DEFAULT (RCR_STRIP_CRC | RCR_RXEN) ++#define RCR_CLEAR 0x0 // set it to a base state ++ ++// Counter Register ++/* BANK 0 */ ++#define COUNTER_REG 0x0006 ++ ++// Memory Information Register ++/* BANK 0 */ ++#define MIR_REG 0x0008 ++ ++// Receive/Phy Control Register ++/* BANK 0 */ ++#define RPC_REG 0x000A ++#define RPC_SPEED 0x2000 // When 1 PHY is in 100Mbps mode. ++#define RPC_DPLX 0x1000 // When 1 PHY is in Full-Duplex Mode ++#define RPC_ANEG 0x0800 // When 1 PHY is in Auto-Negotiate Mode ++#define RPC_LSXA_SHFT 5 // Bits to shift LS2A,LS1A,LS0A to lsb ++#define RPC_LSXB_SHFT 2 // Bits to get LS2B,LS1B,LS0B to lsb ++#define RPC_LED_100_10 (0x00) // LED = 100Mbps OR's with 10Mbps link detect ++#define RPC_LED_RES (0x01) // LED = Reserved ++#define RPC_LED_10 (0x02) // LED = 10Mbps link detect ++#define RPC_LED_FD (0x03) // LED = Full Duplex Mode ++#define RPC_LED_TX_RX (0x04) // LED = TX or RX packet occurred ++#define RPC_LED_100 (0x05) // LED = 100Mbps link dectect ++#define RPC_LED_TX (0x06) // LED = TX packet occurred ++#define RPC_LED_RX (0x07) // LED = RX packet occurred ++#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX) ++ ++/* Bank 0 0x000C is reserved */ ++ ++// Bank Select Register ++/* All Banks */ ++#define BSR_REG 0x000E ++ ++ ++// Configuration Reg ++/* BANK 1 */ ++#define CONFIG_REG 0x0000 ++#define CONFIG_EXT_PHY 0x0200 // 1=external MII, 0=internal Phy ++#define CONFIG_GPCNTRL 0x0400 // Inverse value drives pin nCNTRL ++#define CONFIG_NO_WAIT 0x1000 // When 1 no extra wait states on ISA bus ++#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode. ++ ++// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low ++#define CONFIG_DEFAULT (CONFIG_EPH_POWER_EN) ++ ++ ++// Base Address Register ++/* BANK 1 */ ++#define BASE_REG 0x0002 ++ ++ ++// Individual Address Registers ++/* BANK 1 */ ++#define ADDR0_REG 0x0004 ++#define ADDR1_REG 0x0006 ++#define ADDR2_REG 0x0008 ++ ++ ++// General Purpose Register ++/* BANK 1 */ ++#define GP_REG 0x000A ++ ++ ++// Control Register ++/* BANK 1 */ ++#define CTL_REG 0x000C ++#define CTL_RCV_BAD 0x4000 // When 1 bad CRC packets are received ++#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically ++#define CTL_LE_ENABLE 0x0080 // When 1 enables Link Error interrupt ++#define CTL_CR_ENABLE 0x0040 // When 1 enables Counter Rollover interrupt ++#define CTL_TE_ENABLE 0x0020 // When 1 enables Transmit Error interrupt ++#define CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store ++#define CTL_RELOAD 0x0002 // When set reads EEPROM into registers ++#define CTL_STORE 0x0001 // When set stores registers into EEPROM ++ ++ ++// MMU Command Register ++/* BANK 2 */ ++#define MMU_CMD_REG 0x0000 ++#define MC_BUSY 1 // When 1 the last release has not completed ++#define MC_NOP (0<<5) // No Op ++#define MC_ALLOC (1<<5) // OR with number of 256 byte packets ++#define MC_RESET (2<<5) // Reset MMU to initial state ++#define MC_REMOVE (3<<5) // Remove the current rx packet ++#define MC_RELEASE (4<<5) // Remove and release the current rx packet ++#define MC_FREEPKT (5<<5) // Release packet in PNR register ++#define MC_ENQUEUE (6<<5) // Enqueue the packet for transmit ++#define MC_RSTTXFIFO (7<<5) // Reset the TX FIFOs ++ ++ ++// Packet Number Register ++/* BANK 2 */ ++#define PN_REG 0x0002 ++ ++ ++// Allocation Result Register ++/* BANK 2 */ ++#define AR_REG 0x0003 ++#define AR_FAILED 0x80 // Alocation Failed ++ ++ ++// RX FIFO Ports Register ++/* BANK 2 */ ++#define RXFIFO_REG 0x0004 // Must be read as a word ++#define RXFIFO_REMPTY 0x8000 // RX FIFO Empty ++ ++ ++// TX FIFO Ports Register ++/* BANK 2 */ ++#define TXFIFO_REG RXFIFO_REG // Must be read as a word ++#define TXFIFO_TEMPTY 0x80 // TX FIFO Empty ++ ++ ++// Pointer Register ++/* BANK 2 */ ++#define PTR_REG 0x0006 ++#define PTR_RCV 0x8000 // 1=Receive area, 0=Transmit area ++#define PTR_AUTOINC 0x4000 // Auto increment the pointer on each access ++#define PTR_READ 0x2000 // When 1 the operation is a read ++ ++ ++// Data Register ++/* BANK 2 */ ++#define DATA_REG 0x0008 ++ ++ ++// Interrupt Status/Acknowledge Register ++/* BANK 2 */ ++#define INT_REG 0x000C ++ ++ ++// Interrupt Mask Register ++/* BANK 2 */ ++#define IM_REG 0x000D ++#define IM_MDINT 0x80 // PHY MI Register 18 Interrupt ++#define IM_ERCV_INT 0x40 // Early Receive Interrupt ++#define IM_EPH_INT 0x20 // Set by Etheret Protocol Handler section ++#define IM_RX_OVRN_INT 0x10 // Set by Receiver Overruns ++#define IM_ALLOC_INT 0x08 // Set when allocation request is completed ++#define IM_TX_EMPTY_INT 0x04 // Set if the TX FIFO goes empty ++#define IM_TX_INT 0x02 // Transmit Interrrupt ++#define IM_RCV_INT 0x01 // Receive Interrupt ++ ++ ++// Multicast Table Registers ++/* BANK 3 */ ++#define MCAST_REG1 0x0000 ++#define MCAST_REG2 0x0002 ++#define MCAST_REG3 0x0004 ++#define MCAST_REG4 0x0006 ++ ++ ++// Management Interface Register (MII) ++/* BANK 3 */ ++#define MII_REG 0x0008 ++#define MII_MSK_CRS100 0x4000 // Disables CRS100 detection during tx half dup ++#define MII_MDOE 0x0008 // MII Output Enable ++#define MII_MCLK 0x0004 // MII Clock, pin MDCLK ++#define MII_MDI 0x0002 // MII Input, pin MDI ++#define MII_MDO 0x0001 // MII Output, pin MDO ++ ++ ++// Revision Register ++/* BANK 3 */ ++#define REV_REG 0x000A /* ( hi: chip id low: rev # ) */ ++ ++ ++// Early RCV Register ++/* BANK 3 */ ++/* this is NOT on SMC9192 */ ++#define ERCV_REG 0x000C ++#define ERCV_RCV_DISCRD 0x0080 // When 1 discards a packet being received ++#define ERCV_THRESHOLD 0x001F // ERCV Threshold Mask ++ ++// External Register ++/* BANK 7 */ ++#define EXT_REG 0x0000 ++ ++ ++#define CHIP_9192 3 ++#define CHIP_9194 4 ++#define CHIP_9195 5 ++#define CHIP_9196 6 ++#define CHIP_91100 7 ++#define CHIP_91100FD 8 ++#define CHIP_91111FD 9 ++ ++static const char * chip_ids[ 15 ] = { ++ NULL, NULL, NULL, ++ /* 3 */ "SMC91C90/91C92", ++ /* 4 */ "SMC91C94", ++ /* 5 */ "SMC91C95", ++ /* 6 */ "SMC91C96", ++ /* 7 */ "SMC91C100", ++ /* 8 */ "SMC91C100FD", ++ /* 9 */ "SMC91C11xFD", ++ NULL, NULL, ++ NULL, NULL, NULL}; ++ ++/* ++ . Transmit status bits ++*/ ++#define TS_SUCCESS 0x0001 ++#define TS_LOSTCAR 0x0400 ++#define TS_LATCOL 0x0200 ++#define TS_16COL 0x0010 ++ ++/* ++ . Receive status bits ++*/ ++#define RS_ALGNERR 0x8000 ++#define RS_BRODCAST 0x4000 ++#define RS_BADCRC 0x2000 ++#define RS_ODDFRAME 0x1000 // bug: the LAN91C111 never sets this on receive ++#define RS_TOOLONG 0x0800 ++#define RS_TOOSHORT 0x0400 ++#define RS_MULTICAST 0x0001 ++#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) ++ ++ ++// PHY Types ++enum { ++ PHY_LAN83C183 = 1, // LAN91C111 Internal PHY ++ PHY_LAN83C180 ++}; ++ ++ ++// PHY Register Addresses (LAN91C111 Internal PHY) ++ ++// PHY Control Register ++#define PHY_CNTL_REG 0x00 ++#define PHY_CNTL_RST 0x8000 // 1=PHY Reset ++#define PHY_CNTL_LPBK 0x4000 // 1=PHY Loopback ++#define PHY_CNTL_SPEED 0x2000 // 1=100Mbps, 0=10Mpbs ++#define PHY_CNTL_ANEG_EN 0x1000 // 1=Enable Auto negotiation ++#define PHY_CNTL_PDN 0x0800 // 1=PHY Power Down mode ++#define PHY_CNTL_MII_DIS 0x0400 // 1=MII 4 bit interface disabled ++#define PHY_CNTL_ANEG_RST 0x0200 // 1=Reset Auto negotiate ++#define PHY_CNTL_DPLX 0x0100 // 1=Full Duplex, 0=Half Duplex ++#define PHY_CNTL_COLTST 0x0080 // 1= MII Colision Test ++ ++// PHY Status Register ++#define PHY_STAT_REG 0x01 ++#define PHY_STAT_CAP_T4 0x8000 // 1=100Base-T4 capable ++#define PHY_STAT_CAP_TXF 0x4000 // 1=100Base-X full duplex capable ++#define PHY_STAT_CAP_TXH 0x2000 // 1=100Base-X half duplex capable ++#define PHY_STAT_CAP_TF 0x1000 // 1=10Mbps full duplex capable ++#define PHY_STAT_CAP_TH 0x0800 // 1=10Mbps half duplex capable ++#define PHY_STAT_CAP_SUPR 0x0040 // 1=recv mgmt frames with not preamble ++#define PHY_STAT_ANEG_ACK 0x0020 // 1=ANEG has completed ++#define PHY_STAT_REM_FLT 0x0010 // 1=Remote Fault detected ++#define PHY_STAT_CAP_ANEG 0x0008 // 1=Auto negotiate capable ++#define PHY_STAT_LINK 0x0004 // 1=valid link ++#define PHY_STAT_JAB 0x0002 // 1=10Mbps jabber condition ++#define PHY_STAT_EXREG 0x0001 // 1=extended registers implemented ++ ++// PHY Identifier Registers ++#define PHY_ID1_REG 0x02 // PHY Identifier 1 ++#define PHY_ID2_REG 0x03 // PHY Identifier 2 ++ ++// PHY Auto-Negotiation Advertisement Register ++#define PHY_AD_REG 0x04 ++#define PHY_AD_NP 0x8000 // 1=PHY requests exchange of Next Page ++#define PHY_AD_ACK 0x4000 // 1=got link code word from remote ++#define PHY_AD_RF 0x2000 // 1=advertise remote fault ++#define PHY_AD_T4 0x0200 // 1=PHY is capable of 100Base-T4 ++#define PHY_AD_TX_FDX 0x0100 // 1=PHY is capable of 100Base-TX FDPLX ++#define PHY_AD_TX_HDX 0x0080 // 1=PHY is capable of 100Base-TX HDPLX ++#define PHY_AD_10_FDX 0x0040 // 1=PHY is capable of 10Base-T FDPLX ++#define PHY_AD_10_HDX 0x0020 // 1=PHY is capable of 10Base-T HDPLX ++#define PHY_AD_CSMA 0x0001 // 1=PHY is capable of 802.3 CMSA ++ ++// PHY Auto-negotiation Remote End Capability Register ++#define PHY_RMT_REG 0x05 ++// Uses same bit definitions as PHY_AD_REG ++ ++// PHY Configuration Register 1 ++#define PHY_CFG1_REG 0x10 ++#define PHY_CFG1_LNKDIS 0x8000 // 1=Rx Link Detect Function disabled ++#define PHY_CFG1_XMTDIS 0x4000 // 1=TP Transmitter Disabled ++#define PHY_CFG1_XMTPDN 0x2000 // 1=TP Transmitter Powered Down ++#define PHY_CFG1_BYPSCR 0x0400 // 1=Bypass scrambler/descrambler ++#define PHY_CFG1_UNSCDS 0x0200 // 1=Unscramble Idle Reception Disable ++#define PHY_CFG1_EQLZR 0x0100 // 1=Rx Equalizer Disabled ++#define PHY_CFG1_CABLE 0x0080 // 1=STP(150ohm), 0=UTP(100ohm) ++#define PHY_CFG1_RLVL0 0x0040 // 1=Rx Squelch level reduced by 4.5db ++#define PHY_CFG1_TLVL_SHIFT 2 // Transmit Output Level Adjust ++#define PHY_CFG1_TLVL_MASK 0x003C ++#define PHY_CFG1_TRF_MASK 0x0003 // Transmitter Rise/Fall time ++ ++ ++// PHY Configuration Register 2 ++#define PHY_CFG2_REG 0x11 ++#define PHY_CFG2_APOLDIS 0x0020 // 1=Auto Polarity Correction disabled ++#define PHY_CFG2_JABDIS 0x0010 // 1=Jabber disabled ++#define PHY_CFG2_MREG 0x0008 // 1=Multiple register access (MII mgt) ++#define PHY_CFG2_INTMDIO 0x0004 // 1=Interrupt signaled with MDIO pulseo ++ ++// PHY Status Output (and Interrupt status) Register ++#define PHY_INT_REG 0x12 // Status Output (Interrupt Status) ++#define PHY_INT_INT 0x8000 // 1=bits have changed since last read ++#define PHY_INT_LNKFAIL 0x4000 // 1=Link Not detected ++#define PHY_INT_LOSSSYNC 0x2000 // 1=Descrambler has lost sync ++#define PHY_INT_CWRD 0x1000 // 1=Invalid 4B5B code detected on rx ++#define PHY_INT_SSD 0x0800 // 1=No Start Of Stream detected on rx ++#define PHY_INT_ESD 0x0400 // 1=No End Of Stream detected on rx ++#define PHY_INT_RPOL 0x0200 // 1=Reverse Polarity detected ++#define PHY_INT_JAB 0x0100 // 1=Jabber detected ++#define PHY_INT_SPDDET 0x0080 // 1=100Base-TX mode, 0=10Base-T mode ++#define PHY_INT_DPLXDET 0x0040 // 1=Device in Full Duplex ++ ++// PHY Interrupt/Status Mask Register ++#define PHY_MASK_REG 0x13 // Interrupt Mask ++// Uses the same bit definitions as PHY_INT_REG ++ ++ ++ ++/*------------------------------------------------------------------------- ++ . I define some macros to make it easier to do somewhat common ++ . or slightly complicated, repeated tasks. ++ --------------------------------------------------------------------------*/ ++ ++/* select a register bank, 0 to 3 */ ++ ++#define SMC_SELECT_BANK(x) { SMC_outw( x, ioaddr + BANK_SELECT ); } ++#define SMC_CURRENT_BANK() SMC_inw( ioaddr + BANK_SELECT ) ++ ++/* this enables an interrupt in the interrupt mask register */ ++#define SMC_ENABLE_INT(x) {\ ++ unsigned char mask;\ ++ SMC_SELECT_BANK(2);\ ++ mask = SMC_GET_INT_MASK();\ ++ mask |= (x);\ ++ SMC_SET_INT_MASK(mask); \ ++} ++ ++/* this disables an interrupt from the interrupt mask register */ ++ ++#define SMC_DISABLE_INT(x) {\ ++ unsigned char mask;\ ++ SMC_SELECT_BANK(2);\ ++ mask = SMC_GET_INT_MASK();\ ++ mask &= ~(x);\ ++ SMC_SET_INT_MASK(mask); \ ++} ++ ++/* Note: the following macros do *not* select the bank. */ ++#if USE_8_BIT ++#define SMC_GET_PN() SMC_inb( ioaddr + PN_REG ) ++#define SMC_SET_PN(x) SMC_outb( (x), ioaddr + PN_REG ) ++#define SMC_GET_AR() SMC_inb( ioaddr + AR_REG ) ++#define SMC_GET_INT() SMC_inb( ioaddr + INT_REG ) ++#define SMC_ACK_INT(x) SMC_outb( (x), ioaddr + INT_REG ) ++#define SMC_GET_INT_MASK() SMC_inb( ioaddr + IM_REG ) ++#define SMC_SET_INT_MASK(x) SMC_outb( (x), ioaddr + IM_REG ) ++#else ++#define SMC_GET_PN() (SMC_inw( ioaddr + PN_REG ) & 0xFF) ++#define SMC_SET_PN(x) SMC_outw( (x), ioaddr + PN_REG ) ++#define SMC_GET_AR() (SMC_inw( ioaddr + PN_REG ) >> 8) ++#define SMC_GET_INT() (SMC_inw( ioaddr + INT_REG ) & 0xFF) ++#define SMC_ACK_INT(x) SMC_outw( (SMC_GET_INT_MASK() << 8) | (x), \ ++ ioaddr + INT_REG ) ++#define SMC_GET_INT_MASK() (SMC_inw( ioaddr + INT_REG ) >> 8) ++#define SMC_SET_INT_MASK(x) SMC_outw( (x) << 8, ioaddr + INT_REG ) ++#endif ++ ++#define SMC_GET_BASE() SMC_inw( ioaddr + BASE_REG) ++#define SMC_SET_BASE(x) SMC_outw( (x), ioaddr + BASE_REG) ++#define SMC_GET_CONFIG() SMC_inw( ioaddr + CONFIG_REG) ++#define SMC_SET_CONFIG(x) SMC_outw( (x), ioaddr + CONFIG_REG) ++#define SMC_GET_COUNTER() SMC_inw( ioaddr + COUNTER_REG) ++#define SMC_SET_COUNTER(x) SMC_outw( (x), ioaddr + COUNTER_REG) ++#define SMC_GET_CTL() SMC_inw( ioaddr + CTL_REG) ++#define SMC_SET_CTL(x) SMC_outw( (x), ioaddr + CTL_REG) ++#define SMC_GET_MII() SMC_inw( ioaddr + MII_REG) ++#define SMC_SET_MII(x) SMC_outw( (x), ioaddr + MII_REG) ++#define SMC_GET_MIR() SMC_inw( ioaddr + MIR_REG) ++#define SMC_SET_MIR(x) SMC_outw( (x), ioaddr + MIR_REG) ++#define SMC_GET_MMU_CMD() SMC_inw( ioaddr + MMU_CMD_REG) ++#define SMC_SET_MMU_CMD(x) SMC_outw( (x), ioaddr + MMU_CMD_REG) ++#define SMC_GET_PTR() SMC_inw( ioaddr + PTR_REG) ++#define SMC_SET_PTR(x) SMC_outw( (x), ioaddr + PTR_REG) ++#define SMC_GET_RCR() SMC_inw( ioaddr + RCR_REG) ++#define SMC_SET_RCR(x) SMC_outw( (x), ioaddr + RCR_REG) ++#define SMC_GET_REV() SMC_inw( ioaddr + REV_REG) ++#define SMC_SET_REV(x) SMC_outw( (x), ioaddr + REV_REG) ++#define SMC_GET_RPC() SMC_inw( ioaddr + RPC_REG) ++#define SMC_SET_RPC(x) SMC_outw( (x), ioaddr + RPC_REG) ++#define SMC_GET_RXFIFO() SMC_inw( ioaddr + RXFIFO_REG) ++#define SMC_SET_RXFIFO(x) SMC_outw( (x), ioaddr + RXFIFO_REG) ++#define SMC_GET_TCR() SMC_inw( ioaddr + TCR_REG) ++#define SMC_SET_TCR(x) SMC_outw( (x), ioaddr + TCR_REG) ++ ++#define SMC_CLEAR_MCAST() {\ ++ SMC_outw( 0, ioaddr + MCAST_REG1); \ ++ SMC_outw( 0, ioaddr + MCAST_REG2); \ ++ SMC_outw( 0, ioaddr + MCAST_REG3); \ ++ SMC_outw( 0, ioaddr + MCAST_REG4); \ ++} ++#define SMC_SET_MCAST(x) {\ ++ int i;\ ++ word w;\ ++ unsigned char *mt = (x);\ ++ for ( i = 0; i < 8; i += 2 ) {\ ++ w = mt[i] | (mt[i + 1] << 8);\ ++ SMC_outw( w, ioaddr + MCAST_REG1 + i );\ ++ }\ ++} ++ ++ ++/*---------------------------------------------------------------------- ++ . Define the interrupts that I want to receive from the card ++ . ++ . I want: ++ . IM_EPH_INT, for nasty errors ++ . IM_RCV_INT, for happy received packets ++ . IM_RX_OVRN_INT, because I have to kick the receiver ++ . IM_MDINT, for PHY Register 18 Status Changes ++ --------------------------------------------------------------------------*/ ++#define SMC_INTERRUPT_MASK (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | \ ++ IM_MDINT) ++ ++ ++#ifdef CONFIG_SYSCTL ++/* ++ * Declarations for the sysctl interface, which allows users the ability to ++ * control the finer aspects of the LAN91C111 chip. Since the smc ++ * module currently registers its sysctl table dynamically, the sysctl path ++ * for module FOO is /proc/sys/dev/ethX/FOO ++ */ ++#define CTL_SMC (CTL_BUS+1389) // arbitrary and hopefully unused ++ ++enum { ++ CTL_SMC_INFO = 1, // Sysctl files information ++ CTL_SMC_SWVER, // Driver Software Version Info ++ CTL_SMC_SWFDUP, // Switched Full Duplex Mode ++ CTL_SMC_EPHLOOP, // EPH Block Internal Loopback ++ CTL_SMC_MIIOP, // MII Operation ++ CTL_SMC_AUTONEG, // Auto-negotiate Mode ++ CTL_SMC_RFDUPLX, // Request Full Duplex Mode ++ CTL_SMC_RSPEED, // Request Speed Selection ++ CTL_SMC_AFDUPLX, // Actual Full Duplex Mode ++ CTL_SMC_ASPEED, // Actual Speed Selection ++ CTL_SMC_LNKFAIL, // Link Failed ++ CTL_SMC_FORCOL, // Force a Collision ++ CTL_SMC_FILTCAR, // Filter Carrier ++ CTL_SMC_FREEMEM, // Free Buffer Memory ++ CTL_SMC_TOTMEM, // Total Buffer Memory ++ CTL_SMC_LEDA, // Output of LED-A ++ CTL_SMC_LEDB, // Output of LED-B ++ CTL_SMC_CHIPREV, // LAN91C111 Chip Revision ID ++#if SMC_DEBUG > 1 ++ // Register access for debugging ++ CTL_SMC_REG_BSR, // Bank Select ++ CTL_SMC_REG_TCR, // Transmit Control ++ CTL_SMC_REG_ESR, // EPH Status ++ CTL_SMC_REG_RCR, // Receive Control ++ CTL_SMC_REG_CTRR, // Counter ++ CTL_SMC_REG_MIR, // Memory Information ++ CTL_SMC_REG_RPCR, // Receive/Phy Control ++ CTL_SMC_REG_CFGR, // Configuration ++ CTL_SMC_REG_BAR, // Base Address ++ CTL_SMC_REG_IAR0, // Individual Address 0 ++ CTL_SMC_REG_IAR1, // Individual Address 1 ++ CTL_SMC_REG_IAR2, // Individual Address 2 ++ CTL_SMC_REG_GPR, // General Purpose ++ CTL_SMC_REG_CTLR, // Control ++ CTL_SMC_REG_MCR, // MMU Command ++ CTL_SMC_REG_PNR, // Packet Number ++ CTL_SMC_REG_FPR, // FIFO Ports ++ CTL_SMC_REG_PTR, // Pointer ++ CTL_SMC_REG_DR, // Data ++ CTL_SMC_REG_ISR, // Interrupt Status ++ CTL_SMC_REG_MTR1, // Multicast Table Entry 1 ++ CTL_SMC_REG_MTR2, // Multicast Table Entry 2 ++ CTL_SMC_REG_MTR3, // Multicast Table Entry 3 ++ CTL_SMC_REG_MTR4, // Multicast Table Entry 4 ++ CTL_SMC_REG_MIIR, // Management Interface ++ CTL_SMC_REG_REVR, // Revision ++ CTL_SMC_REG_ERCVR, // Early RCV ++ CTL_SMC_REG_EXTR, // External ++ CTL_SMC_PHY_CTRL, // PHY Control ++ CTL_SMC_PHY_STAT, // PHY Status ++ CTL_SMC_PHY_ID1, // PHY ID1 ++ CTL_SMC_PHY_ID2, // PHY ID2 ++ CTL_SMC_PHY_ADC, // PHY Advertise Capability ++ CTL_SMC_PHY_REMC, // PHY Advertise Capability ++ CTL_SMC_PHY_CFG1, // PHY Configuration 1 ++ CTL_SMC_PHY_CFG2, // PHY Configuration 2 ++ CTL_SMC_PHY_INT, // PHY Interrupt/Status Output ++ CTL_SMC_PHY_MASK, // PHY Interrupt/Status Mask ++#endif ++ // --------------------------------------------------- ++ CTL_SMC_LAST_ENTRY // Add new entries above the line ++}; ++#endif // CONFIG_SYSCTL ++#endif /* _SMC_91111_H_ */ diff --git a/kernel/prepare b/kernel/prepare new file mode 100755 index 0000000..78df2f6 --- /dev/null +++ b/kernel/prepare @@ -0,0 +1,7 @@ +#!/bin/bash + +mkdir $1 + +(cd $1 ; tar -jxvf ../../packages/linux-2.4.31.tar.bz2) + +./patch $1 diff --git a/lbox_border/README b/lbox_border/README new file mode 100644 index 0000000..8d8c5e7 --- /dev/null +++ b/lbox_border/README @@ -0,0 +1,3 @@ +autobuild - does clean, build +build - creates the module +clean - removes the module diff --git a/lbox_border/autobuild b/lbox_border/autobuild new file mode 100755 index 0000000..20a6f3f --- /dev/null +++ b/lbox_border/autobuild @@ -0,0 +1,4 @@ +#!/bin/bash + +./clean +./build diff --git a/lbox_border/build b/lbox_border/build new file mode 100755 index 0000000..cde7c12 --- /dev/null +++ b/lbox_border/build @@ -0,0 +1,7 @@ +#!/bin/bash + +LKERN=../kernel/dev/linux-2.4.31/include + +. ../crosstool/cross-var +${CROSS}gcc -I${LKERN} -DLINUX -DMODULE -D__KERNEL__ -Wa,-m405 -c lbox_border.c + diff --git a/lbox_border/clean b/lbox_border/clean new file mode 100755 index 0000000..96402bc --- /dev/null +++ b/lbox_border/clean @@ -0,0 +1,3 @@ +#!/bin/bash + +rm -f lbox_border.o diff --git a/lbox_border/lbox_border.c b/lbox_border/lbox_border.c new file mode 100644 index 0000000..d128c48 --- /dev/null +++ b/lbox_border/lbox_border.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mark Calderbank"); + +static ssize_t do_write(struct file *file, + const char *buf, + size_t length, + loff_t *offset) +{ + int i; + char c; + int border = -1; + + for (i=0; i<3 && i '9') break; + if (i == 0) border = 0; else border *= 10; + border += c - '0'; + } + + if (border != -1) asm volatile("mtdcr 0x17b,%0" : : "r" (border)); + return length; +} + +static struct file_operations f_ops = +{ + owner: THIS_MODULE, + write: do_write +}; + +int init_module(void) +{ + struct proc_dir_entry *entry; + entry = create_proc_entry("lbox_border", S_IWUSR, NULL); + if (!entry) return -EIO; + entry->proc_fops = &f_ops; + MOD_INC_USE_COUNT; /* Just prevent removal - simple */ + return 0; +} + +void cleanup_module(void) +{ + remove_proc_entry("lbox_border", NULL); +} + +long __get_user_bad(void) +{ + return 0; +} diff --git a/makedevenv b/makedevenv new file mode 100755 index 0000000..d6aec1b --- /dev/null +++ b/makedevenv @@ -0,0 +1,144 @@ +#!/bin/bash + +WGET=wget +TAR=tar +GZIP=gzip +BZIP2=bzip2 +PATCH=patch +AUTOCONF=autoconf +MAKE=make +GIT=git +# The following are required by crosstool +BISON=bison +FLEX=flex + +PACKAGES_DIR=packages +DOWNLOAD_PREFIX=http://www.loggytronic.com/dl/ + +FILE_MVPDEVFS=mvpdevfs-4.tar.gz + +# Files used by the script packages +SOURCEFILES="crosstool-0.43.tar.gz linux-2.4.31.tar.bz2 busybox-1.00.tar.bz2 jpegsrc.v6b.tar.gz genext2fs-1.4.tar.gz" +# And files downloaded by crosstool: +SOURCEFILES+=" binutils-2.15.tar.bz2 glibc-2.2.5.tar.gz linux-2.6.8.tar.bz2 gcc-3.4.5.tar.bz2 glibc-linuxthreads-2.2.5.tar.gz" + +set -e + +# ---------------------------------------------- + +makeDir() +{ + if ! mkdir -p $1 + then + echo "Error: could not create directory: $1" + exit + fi +} + +downloadFile() +{ + if [ ! -r ${PACKAGES_DIR}/$1 -o ! -s ${PACKAGES_DIR}/$1 ] + then + if ! $WGET -O ${PACKAGES_DIR}/$1 ${DOWNLOAD_PREFIX}$1 + then + echo "Error: could not download $1" + exit + fi + fi +} + +checkProg() +{ + if [ -x /bin/$1 ] || [ -x /usr/bin/$1 ] + then + return 0 + else + echo "$1 not found in /bin or /usr/bin." + exit 1 + fi +} + +# The Start + +echo +echo "VOMP Development Environment Setup Script (git version)" +echo + +TOP=`pwd` + +# Test for prerequisites + +if [ -L /bin/sh ] && [ $(readlink /bin/sh) = dash ] +then + echo "Your /bin/sh symlink links to dash which causes the crosstool build to fail." + echo "Please point /bin/sh to another shell (bash works)." + exit 1 +fi + +checkProg $WGET +checkProg $TAR +checkProg $GZIP +checkProg $BZIP2 +checkProg $PATCH +checkProg $AUTOCONF +checkProg $MAKE +checkProg $GIT +checkProg $BISON +checkProg $FLEX + +# Make directories + +makeDir $PACKAGES_DIR + +# Download files + +downloadFile $FILE_MVPDEVFS + +for i in $SOURCEFILES ; do + downloadFile $i +done + +# Build cross compiler + +cd ${TOP}/crosstool +./autobuild + +# Build kernels + +cd ${TOP}/kernel +./autobuild + +# Build busybox + +cd ${TOP}/busybox +./autobuild + +# Build JPEG + +cd ${TOP}/jpeg +./autobuild + +# Build kernel module + +cd ${TOP}/lbox_border +./autobuild + +# Get client and build for dongle + +cd $TOP +$GIT clone http://git.vomp.tv/vompclient.git client +cd client +$MAKE release + +# Build a dongle + +cd ${TOP}/dongle +./autobuild + +# Done + +echo +echo "Done. A dongle should have been created as dongle/vomp-dongle" +echo "Optionally you can set-up an NFS root development environment by following the" +echo "MVP-Filesystem->DHCP->TFTP->NFS guide." +echo -- 2.39.2