diff --git a/BUGS b/BUGS index 4ceb2dfa0..a2d72ad79 100644 --- a/BUGS +++ b/BUGS @@ -1,5 +1,10 @@ Known problems/bugs: + - In the netboot code, tlan and fa311 are not used, even though they + are distributed. That's because the entry for tlan is commented out + in the file "NIC" of Etherboot, and fa311 isn't used actually in + Etherboot. Probably they will be fixed in next version of Etherboot. + - The command "geometry" doesn't work with a floppy very well. This bug was incorporated after the rewrite of the partition scanning code by okuji. diff --git a/ChangeLog b/ChangeLog index fe7ef6864..436b0de2c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,91 @@ +2002-01-03 Yoshinori K. Okuji + + Update the netboot stuff to Etherboot-5.0.5. + + * configure.in (--enable-3c590): Removed. This was a mistake. + (--enable-davicom): New option. + (--enable-eepro): Likewise. + (--enable-natsemi): Likewise. + (--enable-ni5010): Likewise. + (--enable-sis900): Likewise. + (--enable-w89c840): Likewise. + (--enable-3c509-hack): Removed. + (--enable-ns8390-force-16bit): Likewise. + + * netboot/Makefile.am (libdrivers_a_SOURCES): Added timer.c and + timer.h. + (EXTRA_libdrivers_a_SOURCES): Added davicom.c, eepro.c, fa311.c, + natsemi.c, ni5010.c, sis900.c, sis900.h, tlan.c and w89c840.c. + (EXTRA_DIST): Added sis900.txt. + (3c595_drivers): Remove 3c590.o from this. + (davicom_drivers): New variable. + (eepro_drivers): Likewise. + (natsemi_drivers): Likewise. + (ni5010_drivers): Likewise. + (sis900_drivers): Likewise. + (w89c840_drivers): Likewise. + (3c590_o_CFLAGS): Removed. + (davicom_o_CFLAGS): New variable. + (eepro_o_CFLAGS): Likewise. + (natsemi_o_CFLAGS): Likewise. + (ni5010_o_CFLAGS): Likewise. + (sis900_o_CFLAGS): Likewise. + (w89c840_o_CFLAGS): Likewise. + + * netboot/davicom.c: New file, from Etherboot-5.0.5. + * netboot/eepro.c: Likewise. + * netboot/natsemi.c: Likewise. + * netboot/ni5010.c: Likewise. + * netboot/sis900.c: Likewise. + * netboot/sis900.h: Likewise. + * netboot/sis900.txt: Likewise. + * netboot/timer.c: Likewise. + * netboot/timer.h: Likewise. + * netboot/w89c840.c: Likewise. + * netboot/fa311.c: Likewise. + * netboot/tlan.c: Likewise. + + * netboot/3c509.c: Copied from Etherboot-5.0.5. + * netboot/3c509.h: Likewise. + * netboot/3c595.c: Likewise. + * netboot/3c90x.c: Likewise. + * netboot/3c90x.txt: Likewise. + * netboot/cards.h: Likewise. + * netboot/cs89x0.c: Likewise. + * netboot/depca.c: Likewise. + * netboot/eepro100.c: Likewise. + * netboot/epic100.c: Likewise. + * netboot/i82586.c: Likewise. + * netboot/lance.c: Likewise. + * netboot/linux-asm-string.h: Likewise. + * netboot/nic.h: Likewise. + * netboot/ns8390.c: Likewise. + * netboot/ns8390.h: Likewise. + * netboot/otulip.c: Likewise. + * netboot/pci.h: Likewise. + * netboot/rtl8139.c: Likewise. + * netboot/sk_g16.c: Likewise. + * netboot/smc9000.c: Likewise. + * netboot/tiara.c: Likewise. + * netboot/tulip.c: Likewise. + * netboot/via-rhine.c: Likewise. + + * netboot/config.c: Applied a diff between Etherboot-4.6.18 and + Etherboot-5.0.5 manually. + * netboot/main.c: Likewise. + * netboot/pci.c: Likewise. + * netboot/etherboot.h: Rewritten mostly from scratch, based on + the same file in Etherboot-5.0.5. + * netboot/misc.c: Likewise. + * netboot/osdep.h: Likewise. + * netboot/fsys_tftp.c (GRUB): Defined. + (buf_fill): Use rfc2131_sleep_interval instead of rfc951_sleep. + + * stage2/builtins.c [SUPPORT_NETBOOT] (GRUB): Defined. + (boot_func) [SUPPORT_NETBOOT]: Call cleanup_net. + * stage2/cmdline.c [SUPPORT_DISKLESS] (GRUB): Defined. + * stage2/common.c [SUPPORT_DISKLESS] (GRUB): Likewise. + 2002-01-02 Jeremy Katz * util/grub-install.in: Support using mktemp as well as tempfile diff --git a/configure b/configure index d10c43ca8..1776d03d6 100644 --- a/configure +++ b/configure @@ -655,11 +655,12 @@ Optional Features: --enable-pci-direct access PCI directly instead of using BIOS --enable-3c509 enable 3Com509 driver --enable-3c529 enable 3Com529 driver - --enable-3c590 enable 3Com590 driver --enable-3c595 enable 3Com595 driver --enable-3c90x enable 3Com90x driver --enable-cs89x0 enable CS89x0 driver + --enable-davicom enable Davicom driver --enable-depca enable DEPCA and EtherWORKS driver + --enable-eepro enable Etherexpress Pro/10 driver --enable-eepro100 enable Etherexpress Pro/100 driver --enable-epic100 enable SMC 83c170 EPIC/100 driver --enable-3c507 enable 3Com507 driver @@ -668,24 +669,25 @@ Optional Features: --enable-lance enable Lance PCI PCNet/32 driver --enable-ne2100 enable Novell NE2100 driver --enable-ni6510 enable Racal-Interlan NI6510 driver + --enable-natsemi enable NatSemi DP8381x driver + --enable-ni5010 enable Racal-Interlan NI5010 driver --enable-3c503 enable 3Com503 driver --enable-ne enable NE1000/2000 ISA driver --enable-ns8390 enable NE2000 PCI driver --enable-wd enable WD8003/8013, SMC8216/8416 driver --enable-otulip enable old Tulip driver --enable-rtl8139 enable Realtek 8139 driver + --enable-sis900 enable SIS 900 and SIS 7016 driver --enable-sk-g16 enable Schneider and Koch G16 driver --enable-smc9000 enable SMC9000 driver --enable-tiara enable Tiara driver --enable-tulip enable Tulip driver --enable-via-rhine enable Rhine-I/II driver + --enable-w89c840 enable Winbond W89c840, Compex RL100-ATX driver --enable-3c503-shmem use 3c503 shared memory mode --enable-3c503-aui use AUI by default on 3c503 cards - --enable-3c509-hack make a 3c509 do bootp quicker --enable-compex-rl2000-fix specify this if you have a Compex RL2000 PCI - --enable-ns8390-force-16bit - specify this if falsely 8 bit is detected --enable-smc9000-scan=LIST probe for SMC9000 I/O addresses using LIST --enable-ne-scan=LIST probe for NE base address using LIST @@ -902,7 +904,7 @@ if test -z "$CONFIG_SITE"; then fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then - { echo "$as_me:905: loading site script $ac_site_file" >&5 + { echo "$as_me:907: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} cat "$ac_site_file" >&5 . "$ac_site_file" @@ -913,7 +915,7 @@ if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then - { echo "$as_me:916: loading cache $cache_file" >&5 + { echo "$as_me:918: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; @@ -921,7 +923,7 @@ echo "$as_me: loading cache $cache_file" >&6;} esac fi else - { echo "$as_me:924: creating cache $cache_file" >&5 + { echo "$as_me:926: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi @@ -937,21 +939,21 @@ for ac_var in `(set) 2>&1 | eval ac_new_val="\$ac_env_${ac_var}_value" case $ac_old_set,$ac_new_set in set,) - { echo "$as_me:940: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 + { echo "$as_me:942: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { echo "$as_me:944: error: \`$ac_var' was not set in the previous run" >&5 + { echo "$as_me:946: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then - { echo "$as_me:950: error: \`$ac_var' has changed since the previous run:" >&5 + { echo "$as_me:952: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - { echo "$as_me:952: former value: $ac_old_val" >&5 + { echo "$as_me:954: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} - { echo "$as_me:954: current value: $ac_new_val" >&5 + { echo "$as_me:956: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; @@ -970,9 +972,9 @@ echo "$as_me: current value: $ac_new_val" >&2;} fi done if $ac_cache_corrupted; then - { echo "$as_me:973: error: changes in the environment can compromise the build" >&5 + { echo "$as_me:975: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} - { { echo "$as_me:975: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 + { { echo "$as_me:977: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi @@ -992,10 +994,10 @@ esac echo "#! $SHELL" >conftest.sh echo "exit 0" >>conftest.sh chmod +x conftest.sh -if { (echo "$as_me:995: PATH=\".;.\"; conftest.sh") >&5 +if { (echo "$as_me:997: PATH=\".;.\"; conftest.sh") >&5 (PATH=".;."; conftest.sh) 2>&5 ac_status=$? - echo "$as_me:998: \$? = $ac_status" >&5 + echo "$as_me:1000: \$? = $ac_status" >&5 (exit $ac_status); }; then ac_path_separator=';' else @@ -1021,7 +1023,7 @@ for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do fi done if test -z "$ac_aux_dir"; then - { { echo "$as_me:1024: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 + { { echo "$as_me:1026: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} { (exit 1); exit 1; }; } fi @@ -1041,7 +1043,7 @@ ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. -echo "$as_me:1044: checking for a BSD compatible install" >&5 +echo "$as_me:1046: checking for a BSD compatible install" >&5 echo $ECHO_N "checking for a BSD compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then @@ -1090,7 +1092,7 @@ fi INSTALL=$ac_install_sh fi fi -echo "$as_me:1093: result: $INSTALL" >&5 +echo "$as_me:1095: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. @@ -1101,7 +1103,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' -echo "$as_me:1104: checking whether build environment is sane" >&5 +echo "$as_me:1106: checking whether build environment is sane" >&5 echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 # Just in case sleep 1 @@ -1125,7 +1127,7 @@ if ( # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". - { { echo "$as_me:1128: error: ls -t appears to fail. Make sure there is not a broken + { { echo "$as_me:1130: error: ls -t appears to fail. Make sure there is not a broken alias in your environment" >&5 echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken alias in your environment" >&2;} @@ -1138,13 +1140,13 @@ then # Ok. : else - { { echo "$as_me:1141: error: newly created file is older than distributed files! + { { echo "$as_me:1143: error: newly created file is older than distributed files! Check your system clock" >&5 echo "$as_me: error: newly created file is older than distributed files! Check your system clock" >&2;} { (exit 1); exit 1; }; } fi -echo "$as_me:1147: result: yes" >&5 +echo "$as_me:1149: result: yes" >&5 echo "${ECHO_T}yes" >&6 test "$program_prefix" != NONE && program_transform_name="s,^,$program_prefix,;$program_transform_name" @@ -1169,7 +1171,7 @@ if eval "$MISSING --run true"; then else am_missing_run= am_backtick='`' - { echo "$as_me:1172: WARNING: ${am_backtick}missing' script is too old or missing" >&5 + { echo "$as_me:1174: WARNING: ${am_backtick}missing' script is too old or missing" >&5 echo "$as_me: WARNING: ${am_backtick}missing' script is too old or missing" >&2;} fi @@ -1177,7 +1179,7 @@ for ac_prog in mawk gawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -echo "$as_me:1180: checking for $ac_word" >&5 +echo "$as_me:1182: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_AWK+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1192,7 +1194,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_AWK="$ac_prog" -echo "$as_me:1195: found $ac_dir/$ac_word" >&5 +echo "$as_me:1197: found $ac_dir/$ac_word" >&5 break done @@ -1200,17 +1202,17 @@ fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then - echo "$as_me:1203: result: $AWK" >&5 + echo "$as_me:1205: result: $AWK" >&5 echo "${ECHO_T}$AWK" >&6 else - echo "$as_me:1206: result: no" >&5 + echo "$as_me:1208: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$AWK" && break done -echo "$as_me:1213: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo "$as_me:1215: checking whether ${MAKE-make} sets \${MAKE}" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then @@ -1230,11 +1232,11 @@ fi rm -f conftest.make fi if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then - echo "$as_me:1233: result: yes" >&5 + echo "$as_me:1235: result: yes" >&5 echo "${ECHO_T}yes" >&6 SET_MAKE= else - echo "$as_me:1237: result: no" >&5 + echo "$as_me:1239: result: no" >&5 echo "${ECHO_T}no" >&6 SET_MAKE="MAKE=${MAKE-make}" fi @@ -1270,7 +1272,7 @@ rmdir .deps 2>/dev/null # test to see if srcdir already configured if test "`CDPATH=:; cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then - { { echo "$as_me:1273: error: source directory already configured; run \"make distclean\" there first" >&5 + { { echo "$as_me:1275: error: source directory already configured; run \"make distclean\" there first" >&5 echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} { (exit 1); exit 1; }; } fi @@ -1323,11 +1325,11 @@ INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" # Make sure we can run config.sub. $ac_config_sub sun4 >/dev/null 2>&1 || - { { echo "$as_me:1326: error: cannot run $ac_config_sub" >&5 + { { echo "$as_me:1328: error: cannot run $ac_config_sub" >&5 echo "$as_me: error: cannot run $ac_config_sub" >&2;} { (exit 1); exit 1; }; } -echo "$as_me:1330: checking build system type" >&5 +echo "$as_me:1332: checking build system type" >&5 echo $ECHO_N "checking build system type... $ECHO_C" >&6 if test "${ac_cv_build+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1336,23 +1338,23 @@ else test -z "$ac_cv_build_alias" && ac_cv_build_alias=`$ac_config_guess` test -z "$ac_cv_build_alias" && - { { echo "$as_me:1339: error: cannot guess build type; you must specify one" >&5 + { { echo "$as_me:1341: error: cannot guess build type; you must specify one" >&5 echo "$as_me: error: cannot guess build type; you must specify one" >&2;} { (exit 1); exit 1; }; } ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || - { { echo "$as_me:1343: error: $ac_config_sub $ac_cv_build_alias failed." >&5 + { { echo "$as_me:1345: error: $ac_config_sub $ac_cv_build_alias failed." >&5 echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed." >&2;} { (exit 1); exit 1; }; } fi -echo "$as_me:1348: result: $ac_cv_build" >&5 +echo "$as_me:1350: result: $ac_cv_build" >&5 echo "${ECHO_T}$ac_cv_build" >&6 build=$ac_cv_build build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` -echo "$as_me:1355: checking host system type" >&5 +echo "$as_me:1357: checking host system type" >&5 echo $ECHO_N "checking host system type... $ECHO_C" >&6 if test "${ac_cv_host+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1361,12 +1363,12 @@ else test -z "$ac_cv_host_alias" && ac_cv_host_alias=$ac_cv_build_alias ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || - { { echo "$as_me:1364: error: $ac_config_sub $ac_cv_host_alias failed" >&5 + { { echo "$as_me:1366: error: $ac_config_sub $ac_cv_host_alias failed" >&5 echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} { (exit 1); exit 1; }; } fi -echo "$as_me:1369: result: $ac_cv_host" >&5 +echo "$as_me:1371: result: $ac_cv_host" >&5 echo "${ECHO_T}$ac_cv_host" >&6 host=$ac_cv_host host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` @@ -1375,7 +1377,7 @@ host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` case "$host_cpu" in i[3456]86) host_cpu=i386 ;; -*) { { echo "$as_me:1378: error: unsupported CPU type" >&5 +*) { { echo "$as_me:1380: error: unsupported CPU type" >&5 echo "$as_me: error: unsupported CPU type" >&2;} { (exit 1); exit 1; }; } ;; esac @@ -1384,7 +1386,7 @@ esac # Options # -echo "$as_me:1387: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo "$as_me:1389: checking whether to enable maintainer-specific portions of Makefiles" >&5 echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6 # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then @@ -1393,7 +1395,7 @@ if test "${enable_maintainer_mode+set}" = set; then else USE_MAINTAINER_MODE=no fi; - echo "$as_me:1396: result: $USE_MAINTAINER_MODE" >&5 + echo "$as_me:1398: result: $USE_MAINTAINER_MODE" >&5 echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6 if test $USE_MAINTAINER_MODE = yes; then @@ -1408,7 +1410,7 @@ fi if test "x$enable_maintainer_mode" = xyes; then # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 -echo "$as_me:1411: checking for $ac_word" >&5 +echo "$as_me:1413: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_PERL+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1425,7 +1427,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if $as_executable_p "$ac_dir/$ac_word"; then ac_cv_path_PERL="$ac_dir/$ac_word" - echo "$as_me:1428: found $ac_dir/$ac_word" >&5 + echo "$as_me:1430: found $ac_dir/$ac_word" >&5 break fi done @@ -1436,15 +1438,15 @@ fi PERL=$ac_cv_path_PERL if test -n "$PERL"; then - echo "$as_me:1439: result: $PERL" >&5 + echo "$as_me:1441: result: $PERL" >&5 echo "${ECHO_T}$PERL" >&6 else - echo "$as_me:1442: result: no" >&5 + echo "$as_me:1444: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test -z "$PERL"; then - { { echo "$as_me:1447: error: perl not found" >&5 + { { echo "$as_me:1449: error: perl not found" >&5 echo "$as_me: error: perl not found" >&2;} { (exit 1); exit 1; }; } fi @@ -1462,7 +1464,7 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -echo "$as_me:1465: checking for $ac_word" >&5 +echo "$as_me:1467: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1477,7 +1479,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_CC="${ac_tool_prefix}gcc" -echo "$as_me:1480: found $ac_dir/$ac_word" >&5 +echo "$as_me:1482: found $ac_dir/$ac_word" >&5 break done @@ -1485,10 +1487,10 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - echo "$as_me:1488: result: $CC" >&5 + echo "$as_me:1490: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else - echo "$as_me:1491: result: no" >&5 + echo "$as_me:1493: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -1497,7 +1499,7 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -echo "$as_me:1500: checking for $ac_word" >&5 +echo "$as_me:1502: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1512,7 +1514,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_ac_ct_CC="gcc" -echo "$as_me:1515: found $ac_dir/$ac_word" >&5 +echo "$as_me:1517: found $ac_dir/$ac_word" >&5 break done @@ -1520,10 +1522,10 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - echo "$as_me:1523: result: $ac_ct_CC" >&5 + echo "$as_me:1525: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else - echo "$as_me:1526: result: no" >&5 + echo "$as_me:1528: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -1540,7 +1542,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -echo "$as_me:1543: checking for $ac_word" >&5 +echo "$as_me:1545: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1555,7 +1557,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_CC="${ac_tool_prefix}gcc" -echo "$as_me:1558: found $ac_dir/$ac_word" >&5 +echo "$as_me:1560: found $ac_dir/$ac_word" >&5 break done @@ -1563,10 +1565,10 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - echo "$as_me:1566: result: $CC" >&5 + echo "$as_me:1568: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else - echo "$as_me:1569: result: no" >&5 + echo "$as_me:1571: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -1575,7 +1577,7 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -echo "$as_me:1578: checking for $ac_word" >&5 +echo "$as_me:1580: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1590,7 +1592,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_ac_ct_CC="gcc" -echo "$as_me:1593: found $ac_dir/$ac_word" >&5 +echo "$as_me:1595: found $ac_dir/$ac_word" >&5 break done @@ -1598,10 +1600,10 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - echo "$as_me:1601: result: $ac_ct_CC" >&5 + echo "$as_me:1603: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else - echo "$as_me:1604: result: no" >&5 + echo "$as_me:1606: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -1614,7 +1616,7 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -echo "$as_me:1617: checking for $ac_word" >&5 +echo "$as_me:1619: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1629,7 +1631,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_CC="${ac_tool_prefix}cc" -echo "$as_me:1632: found $ac_dir/$ac_word" >&5 +echo "$as_me:1634: found $ac_dir/$ac_word" >&5 break done @@ -1637,10 +1639,10 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - echo "$as_me:1640: result: $CC" >&5 + echo "$as_me:1642: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else - echo "$as_me:1643: result: no" >&5 + echo "$as_me:1645: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -1649,7 +1651,7 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -echo "$as_me:1652: checking for $ac_word" >&5 +echo "$as_me:1654: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1664,7 +1666,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_ac_ct_CC="cc" -echo "$as_me:1667: found $ac_dir/$ac_word" >&5 +echo "$as_me:1669: found $ac_dir/$ac_word" >&5 break done @@ -1672,10 +1674,10 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - echo "$as_me:1675: result: $ac_ct_CC" >&5 + echo "$as_me:1677: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else - echo "$as_me:1678: result: no" >&5 + echo "$as_me:1680: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -1688,7 +1690,7 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -echo "$as_me:1691: checking for $ac_word" >&5 +echo "$as_me:1693: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1708,7 +1710,7 @@ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then continue fi ac_cv_prog_CC="cc" -echo "$as_me:1711: found $ac_dir/$ac_word" >&5 +echo "$as_me:1713: found $ac_dir/$ac_word" >&5 break done @@ -1730,10 +1732,10 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - echo "$as_me:1733: result: $CC" >&5 + echo "$as_me:1735: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else - echo "$as_me:1736: result: no" >&5 + echo "$as_me:1738: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -1744,7 +1746,7 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -echo "$as_me:1747: checking for $ac_word" >&5 +echo "$as_me:1749: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1759,7 +1761,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_CC="$ac_tool_prefix$ac_prog" -echo "$as_me:1762: found $ac_dir/$ac_word" >&5 +echo "$as_me:1764: found $ac_dir/$ac_word" >&5 break done @@ -1767,10 +1769,10 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - echo "$as_me:1770: result: $CC" >&5 + echo "$as_me:1772: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else - echo "$as_me:1773: result: no" >&5 + echo "$as_me:1775: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -1783,7 +1785,7 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -echo "$as_me:1786: checking for $ac_word" >&5 +echo "$as_me:1788: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -1798,7 +1800,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_ac_ct_CC="$ac_prog" -echo "$as_me:1801: found $ac_dir/$ac_word" >&5 +echo "$as_me:1803: found $ac_dir/$ac_word" >&5 break done @@ -1806,10 +1808,10 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - echo "$as_me:1809: result: $ac_ct_CC" >&5 + echo "$as_me:1811: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else - echo "$as_me:1812: result: no" >&5 + echo "$as_me:1814: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -1821,32 +1823,32 @@ fi fi -test -z "$CC" && { { echo "$as_me:1824: error: no acceptable cc found in \$PATH" >&5 +test -z "$CC" && { { echo "$as_me:1826: error: no acceptable cc found in \$PATH" >&5 echo "$as_me: error: no acceptable cc found in \$PATH" >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. -echo "$as_me:1829:" \ +echo "$as_me:1831:" \ "checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` -{ (eval echo "$as_me:1832: \"$ac_compiler --version &5\"") >&5 +{ (eval echo "$as_me:1834: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? - echo "$as_me:1835: \$? = $ac_status" >&5 + echo "$as_me:1837: \$? = $ac_status" >&5 (exit $ac_status); } -{ (eval echo "$as_me:1837: \"$ac_compiler -v &5\"") >&5 +{ (eval echo "$as_me:1839: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? - echo "$as_me:1840: \$? = $ac_status" >&5 + echo "$as_me:1842: \$? = $ac_status" >&5 (exit $ac_status); } -{ (eval echo "$as_me:1842: \"$ac_compiler -V &5\"") >&5 +{ (eval echo "$as_me:1844: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? - echo "$as_me:1845: \$? = $ac_status" >&5 + echo "$as_me:1847: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF -#line 1849 "configure" +#line 1851 "configure" #include "confdefs.h" int @@ -1862,13 +1864,13 @@ ac_clean_files="$ac_clean_files a.out a.exe" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -echo "$as_me:1865: checking for C compiler default output" >&5 +echo "$as_me:1867: checking for C compiler default output" >&5 echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` -if { (eval echo "$as_me:1868: \"$ac_link_default\"") >&5 +if { (eval echo "$as_me:1870: \"$ac_link_default\"") >&5 (eval $ac_link_default) 2>&5 ac_status=$? - echo "$as_me:1871: \$? = $ac_status" >&5 + echo "$as_me:1873: \$? = $ac_status" >&5 (exit $ac_status); }; then # Find the output, starting from the most likely. This scheme is # not robust to junk in `.', hence go to wildcards (a.*) only as a last @@ -1891,34 +1893,34 @@ done else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 -{ { echo "$as_me:1894: error: C compiler cannot create executables" >&5 +{ { echo "$as_me:1896: error: C compiler cannot create executables" >&5 echo "$as_me: error: C compiler cannot create executables" >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext -echo "$as_me:1900: result: $ac_file" >&5 +echo "$as_me:1902: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6 # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -echo "$as_me:1905: checking whether the C compiler works" >&5 +echo "$as_me:1907: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' - { (eval echo "$as_me:1911: \"$ac_try\"") >&5 + { (eval echo "$as_me:1913: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:1914: \$? = $ac_status" >&5 + echo "$as_me:1916: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { echo "$as_me:1921: error: cannot run C compiled programs. + { { echo "$as_me:1923: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'." >&2;} @@ -1926,24 +1928,24 @@ If you meant to cross compile, use \`--host'." >&2;} fi fi fi -echo "$as_me:1929: result: yes" >&5 +echo "$as_me:1931: result: yes" >&5 echo "${ECHO_T}yes" >&6 rm -f a.out a.exe conftest$ac_cv_exeext ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -echo "$as_me:1936: checking whether we are cross compiling" >&5 +echo "$as_me:1938: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 -echo "$as_me:1938: result: $cross_compiling" >&5 +echo "$as_me:1940: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6 -echo "$as_me:1941: checking for executable suffix" >&5 +echo "$as_me:1943: checking for executable suffix" >&5 echo $ECHO_N "checking for executable suffix... $ECHO_C" >&6 -if { (eval echo "$as_me:1943: \"$ac_link\"") >&5 +if { (eval echo "$as_me:1945: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:1946: \$? = $ac_status" >&5 + echo "$as_me:1948: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will @@ -1959,25 +1961,25 @@ for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do esac done else - { { echo "$as_me:1962: error: cannot compute EXEEXT: cannot compile and link" >&5 + { { echo "$as_me:1964: error: cannot compute EXEEXT: cannot compile and link" >&5 echo "$as_me: error: cannot compute EXEEXT: cannot compile and link" >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext -echo "$as_me:1968: result: $ac_cv_exeext" >&5 +echo "$as_me:1970: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6 rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT -echo "$as_me:1974: checking for object suffix" >&5 +echo "$as_me:1976: checking for object suffix" >&5 echo $ECHO_N "checking for object suffix... $ECHO_C" >&6 if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 1980 "configure" +#line 1982 "configure" #include "confdefs.h" int @@ -1989,10 +1991,10 @@ main () } _ACEOF rm -f conftest.o conftest.obj -if { (eval echo "$as_me:1992: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:1994: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:1995: \$? = $ac_status" >&5 + echo "$as_me:1997: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in @@ -2004,24 +2006,24 @@ done else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 -{ { echo "$as_me:2007: error: cannot compute OBJEXT: cannot compile" >&5 +{ { echo "$as_me:2009: error: cannot compute OBJEXT: cannot compile" >&5 echo "$as_me: error: cannot compute OBJEXT: cannot compile" >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -echo "$as_me:2014: result: $ac_cv_objext" >&5 +echo "$as_me:2016: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6 OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -echo "$as_me:2018: checking whether we are using the GNU C compiler" >&5 +echo "$as_me:2020: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 2024 "configure" +#line 2026 "configure" #include "confdefs.h" int @@ -2036,16 +2038,16 @@ main () } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:2039: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:2041: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:2042: \$? = $ac_status" >&5 + echo "$as_me:2044: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:2045: \"$ac_try\"") >&5 + { (eval echo "$as_me:2047: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2048: \$? = $ac_status" >&5 + echo "$as_me:2050: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else @@ -2057,19 +2059,19 @@ rm -f conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -echo "$as_me:2060: result: $ac_cv_c_compiler_gnu" >&5 +echo "$as_me:2062: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS CFLAGS="-g" -echo "$as_me:2066: checking whether $CC accepts -g" >&5 +echo "$as_me:2068: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 2072 "configure" +#line 2074 "configure" #include "confdefs.h" int @@ -2081,16 +2083,16 @@ main () } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:2084: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:2086: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:2087: \$? = $ac_status" >&5 + echo "$as_me:2089: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:2090: \"$ac_try\"") >&5 + { (eval echo "$as_me:2092: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2093: \$? = $ac_status" >&5 + echo "$as_me:2095: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_g=yes else @@ -2100,7 +2102,7 @@ ac_cv_prog_cc_g=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:2103: result: $ac_cv_prog_cc_g" >&5 +echo "$as_me:2105: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS @@ -2127,16 +2129,16 @@ cat >conftest.$ac_ext <<_ACEOF #endif _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:2130: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:2132: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:2133: \$? = $ac_status" >&5 + echo "$as_me:2135: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:2136: \"$ac_try\"") >&5 + { (eval echo "$as_me:2138: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2139: \$? = $ac_status" >&5 + echo "$as_me:2141: \$? = $ac_status" >&5 (exit $ac_status); }; }; then for ac_declaration in \ ''\ @@ -2148,7 +2150,7 @@ if { (eval echo "$as_me:2130: \"$ac_compile\"") >&5 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF -#line 2151 "configure" +#line 2153 "configure" #include "confdefs.h" #include $ac_declaration @@ -2161,16 +2163,16 @@ exit (42); } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:2164: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:2166: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:2167: \$? = $ac_status" >&5 + echo "$as_me:2169: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:2170: \"$ac_try\"") >&5 + { (eval echo "$as_me:2172: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2173: \$? = $ac_status" >&5 + echo "$as_me:2175: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else @@ -2180,7 +2182,7 @@ continue fi rm -f conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF -#line 2183 "configure" +#line 2185 "configure" #include "confdefs.h" $ac_declaration int @@ -2192,16 +2194,16 @@ exit (42); } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:2195: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:2197: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:2198: \$? = $ac_status" >&5 + echo "$as_me:2200: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:2201: \"$ac_try\"") >&5 + { (eval echo "$as_me:2203: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2204: \$? = $ac_status" >&5 + echo "$as_me:2206: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else @@ -2236,7 +2238,7 @@ doit: @echo done END # If we don't find an include directive, just comment out the code. -echo "$as_me:2239: checking for style of include used by $am_make" >&5 +echo "$as_me:2241: checking for style of include used by $am_make" >&5 echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 am__include='#' am__quote= @@ -2263,13 +2265,13 @@ if test "$am__include" = "#"; then fi fi -echo "$as_me:2266: result: $_am_result" >&5 +echo "$as_me:2268: result: $_am_result" >&5 echo "${ECHO_T}$_am_result" >&6 rm -f confinc confmf depcc="$CC" am_compiler_list= -echo "$as_me:2272: checking dependency style of $depcc" >&5 +echo "$as_me:2274: checking dependency style of $depcc" >&5 echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2331,7 +2333,7 @@ else fi fi -echo "$as_me:2334: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "$as_me:2336: result: $am_cv_CC_dependencies_compiler_type" >&5 echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 CCDEPMODE="depmode=$am_cv_CC_dependencies_compiler_type" @@ -2339,7 +2341,7 @@ CCDEPMODE="depmode=$am_cv_CC_dependencies_compiler_type" depcc="$CC" am_compiler_list= -echo "$as_me:2342: checking dependency style of $depcc" >&5 +echo "$as_me:2344: checking dependency style of $depcc" >&5 echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2401,7 +2403,7 @@ else fi fi -echo "$as_me:2404: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "$as_me:2406: result: $am_cv_CC_dependencies_compiler_type" >&5 echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 CCDEPMODE="depmode=$am_cv_CC_dependencies_compiler_type" @@ -2416,7 +2418,7 @@ fi; if test "x$with_binutils" != x; then # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 -echo "$as_me:2419: checking for $ac_word" >&5 +echo "$as_me:2421: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2433,7 +2435,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if $as_executable_p "$ac_dir/$ac_word"; then ac_cv_path_RANLIB="$ac_dir/$ac_word" - echo "$as_me:2436: found $ac_dir/$ac_word" >&5 + echo "$as_me:2438: found $ac_dir/$ac_word" >&5 break fi done @@ -2445,10 +2447,10 @@ fi RANLIB=$ac_cv_path_RANLIB if test -n "$RANLIB"; then - echo "$as_me:2448: result: $RANLIB" >&5 + echo "$as_me:2450: result: $RANLIB" >&5 echo "${ECHO_T}$RANLIB" >&6 else - echo "$as_me:2451: result: no" >&5 + echo "$as_me:2453: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -2456,7 +2458,7 @@ else if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -echo "$as_me:2459: checking for $ac_word" >&5 +echo "$as_me:2461: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2471,7 +2473,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" -echo "$as_me:2474: found $ac_dir/$ac_word" >&5 +echo "$as_me:2476: found $ac_dir/$ac_word" >&5 break done @@ -2479,10 +2481,10 @@ fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then - echo "$as_me:2482: result: $RANLIB" >&5 + echo "$as_me:2484: result: $RANLIB" >&5 echo "${ECHO_T}$RANLIB" >&6 else - echo "$as_me:2485: result: no" >&5 + echo "$as_me:2487: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -2491,7 +2493,7 @@ if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 -echo "$as_me:2494: checking for $ac_word" >&5 +echo "$as_me:2496: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2506,7 +2508,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_ac_ct_RANLIB="ranlib" -echo "$as_me:2509: found $ac_dir/$ac_word" >&5 +echo "$as_me:2511: found $ac_dir/$ac_word" >&5 break done @@ -2515,10 +2517,10 @@ fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then - echo "$as_me:2518: result: $ac_ct_RANLIB" >&5 + echo "$as_me:2520: result: $ac_ct_RANLIB" >&5 echo "${ECHO_T}$ac_ct_RANLIB" >&6 else - echo "$as_me:2521: result: no" >&5 + echo "$as_me:2523: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -2539,7 +2541,7 @@ if test "x$ac_cv_c_compiler_gnu" = xyes; then fi STAGE1_CFLAGS="-O2" GRUB_CFLAGS="-O2" - echo "$as_me:2542: checking whether optimization for size works" >&5 + echo "$as_me:2544: checking whether optimization for size works" >&5 echo $ECHO_N "checking whether optimization for size works... $ECHO_C" >&6 if test "${size_flag+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2549,7 +2551,7 @@ else CFLAGS="-Os -g" cat >conftest.$ac_ext <<_ACEOF -#line 2552 "configure" +#line 2554 "configure" #include "confdefs.h" int @@ -2561,16 +2563,16 @@ main () } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:2564: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:2566: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:2567: \$? = $ac_status" >&5 + echo "$as_me:2569: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:2570: \"$ac_try\"") >&5 + { (eval echo "$as_me:2572: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2573: \$? = $ac_status" >&5 + echo "$as_me:2575: \$? = $ac_status" >&5 (exit $ac_status); }; }; then size_flag=yes else @@ -2582,7 +2584,7 @@ rm -f conftest.$ac_objext conftest.$ac_ext CFLAGS=$saved_CFLAGS fi -echo "$as_me:2585: result: $size_flag" >&5 +echo "$as_me:2587: result: $size_flag" >&5 echo "${ECHO_T}$size_flag" >&6 if test "x$size_flag" = xyes; then STAGE2_CFLAGS="-Os" @@ -2596,7 +2598,7 @@ fi CPPFLAGS="$CPPFLAGS -Wall -Wmissing-prototypes -Wunused -Wshadow" CPPFLAGS="$CPPFLAGS -Wpointer-arith" -echo "$as_me:2599: checking whether -Wundef works" >&5 +echo "$as_me:2601: checking whether -Wundef works" >&5 echo $ECHO_N "checking whether -Wundef works... $ECHO_C" >&6 if test "${undef_flag+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2605,7 +2607,7 @@ else saved_CPPFLAGS=$CPPFLAGS CPPFLAGS="-Wundef" cat >conftest.$ac_ext <<_ACEOF -#line 2608 "configure" +#line 2610 "configure" #include "confdefs.h" int @@ -2617,16 +2619,16 @@ main () } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:2620: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:2622: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:2623: \$? = $ac_status" >&5 + echo "$as_me:2625: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:2626: \"$ac_try\"") >&5 + { (eval echo "$as_me:2628: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2629: \$? = $ac_status" >&5 + echo "$as_me:2631: \$? = $ac_status" >&5 (exit $ac_status); }; }; then undef_flag=yes else @@ -2638,7 +2640,7 @@ rm -f conftest.$ac_objext conftest.$ac_ext CPPFLAGS=$saved_CPPFLAGS fi -echo "$as_me:2641: result: $undef_flag" >&5 +echo "$as_me:2643: result: $undef_flag" >&5 echo "${ECHO_T}$undef_flag" >&6 # Force no alignment to save space. @@ -2651,7 +2653,7 @@ fi if test "x$with_binutils" != x; then # Extract the first word of "objcopy", so it can be a program name with args. set dummy objcopy; ac_word=$2 -echo "$as_me:2654: checking for $ac_word" >&5 +echo "$as_me:2656: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_OBJCOPY+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2668,7 +2670,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if $as_executable_p "$ac_dir/$ac_word"; then ac_cv_path_OBJCOPY="$ac_dir/$ac_word" - echo "$as_me:2671: found $ac_dir/$ac_word" >&5 + echo "$as_me:2673: found $ac_dir/$ac_word" >&5 break fi done @@ -2679,10 +2681,10 @@ fi OBJCOPY=$ac_cv_path_OBJCOPY if test -n "$OBJCOPY"; then - echo "$as_me:2682: result: $OBJCOPY" >&5 + echo "$as_me:2684: result: $OBJCOPY" >&5 echo "${ECHO_T}$OBJCOPY" >&6 else - echo "$as_me:2685: result: no" >&5 + echo "$as_me:2687: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -2690,7 +2692,7 @@ else if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objcopy", so it can be a program name with args. set dummy ${ac_tool_prefix}objcopy; ac_word=$2 -echo "$as_me:2693: checking for $ac_word" >&5 +echo "$as_me:2695: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_OBJCOPY+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2705,7 +2707,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_OBJCOPY="${ac_tool_prefix}objcopy" -echo "$as_me:2708: found $ac_dir/$ac_word" >&5 +echo "$as_me:2710: found $ac_dir/$ac_word" >&5 break done @@ -2713,10 +2715,10 @@ fi fi OBJCOPY=$ac_cv_prog_OBJCOPY if test -n "$OBJCOPY"; then - echo "$as_me:2716: result: $OBJCOPY" >&5 + echo "$as_me:2718: result: $OBJCOPY" >&5 echo "${ECHO_T}$OBJCOPY" >&6 else - echo "$as_me:2719: result: no" >&5 + echo "$as_me:2721: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -2725,7 +2727,7 @@ if test -z "$ac_cv_prog_OBJCOPY"; then ac_ct_OBJCOPY=$OBJCOPY # Extract the first word of "objcopy", so it can be a program name with args. set dummy objcopy; ac_word=$2 -echo "$as_me:2728: checking for $ac_word" >&5 +echo "$as_me:2730: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_OBJCOPY+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2740,7 +2742,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_ac_ct_OBJCOPY="objcopy" -echo "$as_me:2743: found $ac_dir/$ac_word" >&5 +echo "$as_me:2745: found $ac_dir/$ac_word" >&5 break done @@ -2748,10 +2750,10 @@ fi fi ac_ct_OBJCOPY=$ac_cv_prog_ac_ct_OBJCOPY if test -n "$ac_ct_OBJCOPY"; then - echo "$as_me:2751: result: $ac_ct_OBJCOPY" >&5 + echo "$as_me:2753: result: $ac_ct_OBJCOPY" >&5 echo "${ECHO_T}$ac_ct_OBJCOPY" >&6 else - echo "$as_me:2754: result: no" >&5 + echo "$as_me:2756: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -2764,7 +2766,7 @@ fi # Defined in acinclude.m4. -echo "$as_me:2767: checking if C symbols get an underscore after compilation" >&5 +echo "$as_me:2769: checking if C symbols get an underscore after compilation" >&5 echo $ECHO_N "checking if C symbols get an underscore after compilation... $ECHO_C" >&6 if test "${grub_cv_asm_uscore+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2779,14 +2781,14 @@ func (int *list) EOF if { ac_try='${CC-cc} ${CFLAGS} -S conftest.c' - { (eval echo "$as_me:2782: \"$ac_try\"") >&5 + { (eval echo "$as_me:2784: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2785: \$? = $ac_status" >&5 + echo "$as_me:2787: \$? = $ac_status" >&5 (exit $ac_status); }; } && test -s conftest.s; then true else - { { echo "$as_me:2789: error: ${CC-cc} failed to produce assembly code" >&5 + { { echo "$as_me:2791: error: ${CC-cc} failed to produce assembly code" >&5 echo "$as_me: error: ${CC-cc} failed to produce assembly code" >&2;} { (exit 1); exit 1; }; } fi @@ -2808,10 +2810,10 @@ EOF fi -echo "$as_me:2811: result: $grub_cv_asm_uscore" >&5 +echo "$as_me:2813: result: $grub_cv_asm_uscore" >&5 echo "${ECHO_T}$grub_cv_asm_uscore" >&6 -echo "$as_me:2814: checking whether ${OBJCOPY} works for absolute addresses" >&5 +echo "$as_me:2816: checking whether ${OBJCOPY} works for absolute addresses" >&5 echo $ECHO_N "checking whether ${OBJCOPY} works for absolute addresses... $ECHO_C" >&6 if test "${grub_cv_prog_objcopy_absolute+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2824,45 +2826,45 @@ cmain (void) } EOF -if { (eval echo "$as_me:2827: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:2829: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:2830: \$? = $ac_status" >&5 + echo "$as_me:2832: \$? = $ac_status" >&5 (exit $ac_status); } && test -s conftest.o; then : else - { { echo "$as_me:2833: error: ${CC-cc} cannot compile C source code" >&5 + { { echo "$as_me:2835: error: ${CC-cc} cannot compile C source code" >&5 echo "$as_me: error: ${CC-cc} cannot compile C source code" >&2;} { (exit 1); exit 1; }; } fi grub_cv_prog_objcopy_absolute=yes for link_addr in 2000 8000 7C00; do if { ac_try='${CC-cc} ${CFLAGS} -nostdlib -Wl,-N -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec' - { (eval echo "$as_me:2840: \"$ac_try\"") >&5 + { (eval echo "$as_me:2842: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2843: \$? = $ac_status" >&5 + echo "$as_me:2845: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else - { { echo "$as_me:2846: error: ${CC-cc} cannot link at address $link_addr" >&5 + { { echo "$as_me:2848: error: ${CC-cc} cannot link at address $link_addr" >&5 echo "$as_me: error: ${CC-cc} cannot link at address $link_addr" >&2;} { (exit 1); exit 1; }; } fi if { ac_try='${OBJCOPY-objcopy} -O binary conftest.exec conftest' - { (eval echo "$as_me:2851: \"$ac_try\"") >&5 + { (eval echo "$as_me:2853: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2854: \$? = $ac_status" >&5 + echo "$as_me:2856: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else - { { echo "$as_me:2857: error: ${OBJCOPY-objcopy} cannot create binary files" >&5 + { { echo "$as_me:2859: error: ${OBJCOPY-objcopy} cannot create binary files" >&5 echo "$as_me: error: ${OBJCOPY-objcopy} cannot create binary files" >&2;} { (exit 1); exit 1; }; } fi if test ! -f conftest.old || { ac_try='cmp -s conftest.old conftest' - { (eval echo "$as_me:2862: \"$ac_try\"") >&5 + { (eval echo "$as_me:2864: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2865: \$? = $ac_status" >&5 + echo "$as_me:2867: \$? = $ac_status" >&5 (exit $ac_status); }; }; then mv -f conftest conftest.old else @@ -2873,15 +2875,15 @@ done rm -f conftest* fi -echo "$as_me:2876: result: $grub_cv_prog_objcopy_absolute" >&5 +echo "$as_me:2878: result: $grub_cv_prog_objcopy_absolute" >&5 echo "${ECHO_T}$grub_cv_prog_objcopy_absolute" >&6 if test "x$grub_cv_prog_objcopy_absolute" != xyes; then - { { echo "$as_me:2879: error: GRUB requires a working absolute objcopy; upgrade your binutils" >&5 + { { echo "$as_me:2881: error: GRUB requires a working absolute objcopy; upgrade your binutils" >&5 echo "$as_me: error: GRUB requires a working absolute objcopy; upgrade your binutils" >&2;} { (exit 1); exit 1; }; } fi -echo "$as_me:2884: checking whether addr32 must be in the same line as the instruction" >&5 +echo "$as_me:2886: checking whether addr32 must be in the same line as the instruction" >&5 echo $ECHO_N "checking whether addr32 must be in the same line as the instruction... $ECHO_C" >&6 if test "${grub_cv_asm_prefix_requirement+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2892,10 +2894,10 @@ l1: addr32 movb %al, l1 EOF if { ac_try='${CC-cc} ${CFLAGS} -c conftest.s' - { (eval echo "$as_me:2895: \"$ac_try\"") >&5 + { (eval echo "$as_me:2897: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2898: \$? = $ac_status" >&5 + echo "$as_me:2900: \$? = $ac_status" >&5 (exit $ac_status); }; } && test -s conftest.o; then grub_cv_asm_prefix_requirement=yes else @@ -2921,10 +2923,10 @@ cat >>confdefs.h <&5 +echo "$as_me:2926: result: $grub_cv_asm_prefix_requirement" >&5 echo "${ECHO_T}$grub_cv_asm_prefix_requirement" >&6 -echo "$as_me:2927: checking for .code16 addr32 assembler support" >&5 +echo "$as_me:2929: checking for .code16 addr32 assembler support" >&5 echo $ECHO_N "checking for .code16 addr32 assembler support... $ECHO_C" >&6 if test "${grub_cv_asm_addr32+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2941,10 +2943,10 @@ else fi if { ac_try='${CC-cc} ${CFLAGS} -c conftest.s' - { (eval echo "$as_me:2944: \"$ac_try\"") >&5 + { (eval echo "$as_me:2946: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2947: \$? = $ac_status" >&5 + echo "$as_me:2949: \$? = $ac_status" >&5 (exit $ac_status); }; } && test -s conftest.o; then grub_cv_asm_addr32=yes else @@ -2954,15 +2956,15 @@ fi rm -f conftest* fi -echo "$as_me:2957: result: $grub_cv_asm_addr32" >&5 +echo "$as_me:2959: result: $grub_cv_asm_addr32" >&5 echo "${ECHO_T}$grub_cv_asm_addr32" >&6 if test "x$grub_cv_asm_addr32" != xyes; then - { { echo "$as_me:2960: error: GRUB requires GAS .code16 addr32 support; upgrade your binutils" >&5 + { { echo "$as_me:2962: error: GRUB requires GAS .code16 addr32 support; upgrade your binutils" >&5 echo "$as_me: error: GRUB requires GAS .code16 addr32 support; upgrade your binutils" >&2;} { (exit 1); exit 1; }; } fi -echo "$as_me:2965: checking whether an absolute indirect call/jump must not be prefixed with an asterisk" >&5 +echo "$as_me:2967: checking whether an absolute indirect call/jump must not be prefixed with an asterisk" >&5 echo $ECHO_N "checking whether an absolute indirect call/jump must not be prefixed with an asterisk... $ECHO_C" >&6 if test "${grub_cv_asm_absolute_without_asterisk+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -2975,10 +2977,10 @@ offset: EOF if { ac_try='${CC-cc} ${CFLAGS} -c conftest.s' - { (eval echo "$as_me:2978: \"$ac_try\"") >&5 + { (eval echo "$as_me:2980: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:2981: \$? = $ac_status" >&5 + echo "$as_me:2983: \$? = $ac_status" >&5 (exit $ac_status); }; } && test -s conftest.o; then grub_cv_asm_absolute_without_asterisk=no else @@ -2995,16 +2997,16 @@ EOF fi -echo "$as_me:2998: result: $grub_cv_asm_absolute_without_asterisk" >&5 +echo "$as_me:3000: result: $grub_cv_asm_absolute_without_asterisk" >&5 echo "${ECHO_T}$grub_cv_asm_absolute_without_asterisk" >&6 -echo "$as_me:3001: checking if start is defined by the compiler" >&5 +echo "$as_me:3003: checking if start is defined by the compiler" >&5 echo $ECHO_N "checking if start is defined by the compiler... $ECHO_C" >&6 if test "${grub_cv_check_start_symbol+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3007 "configure" +#line 3009 "configure" #include "confdefs.h" int @@ -3016,16 +3018,16 @@ asm ("incl start") } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:3019: \"$ac_link\"") >&5 +if { (eval echo "$as_me:3021: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:3022: \$? = $ac_status" >&5 + echo "$as_me:3024: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:3025: \"$ac_try\"") >&5 + { (eval echo "$as_me:3027: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3028: \$? = $ac_status" >&5 + echo "$as_me:3030: \$? = $ac_status" >&5 (exit $ac_status); }; }; then grub_cv_check_start_symbol=yes else @@ -3043,16 +3045,16 @@ EOF fi -echo "$as_me:3046: result: $grub_cv_check_start_symbol" >&5 +echo "$as_me:3048: result: $grub_cv_check_start_symbol" >&5 echo "${ECHO_T}$grub_cv_check_start_symbol" >&6 -echo "$as_me:3049: checking if _start is defined by the compiler" >&5 +echo "$as_me:3051: checking if _start is defined by the compiler" >&5 echo $ECHO_N "checking if _start is defined by the compiler... $ECHO_C" >&6 if test "${grub_cv_check_uscore_start_symbol+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3055 "configure" +#line 3057 "configure" #include "confdefs.h" int @@ -3064,16 +3066,16 @@ asm ("incl _start") } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:3067: \"$ac_link\"") >&5 +if { (eval echo "$as_me:3069: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:3070: \$? = $ac_status" >&5 + echo "$as_me:3072: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:3073: \"$ac_try\"") >&5 + { (eval echo "$as_me:3075: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3076: \$? = $ac_status" >&5 + echo "$as_me:3078: \$? = $ac_status" >&5 (exit $ac_status); }; }; then grub_cv_check_uscore_start_symbol=yes else @@ -3091,23 +3093,23 @@ EOF fi -echo "$as_me:3094: result: $grub_cv_check_uscore_start_symbol" >&5 +echo "$as_me:3096: result: $grub_cv_check_uscore_start_symbol" >&5 echo "${ECHO_T}$grub_cv_check_uscore_start_symbol" >&6 if test "x$grub_cv_check_start_symbol" != "xyes" \ -a "x$grub_cv_check_uscore_start_symbol" != "xyes"; then - { { echo "$as_me:3099: error: Neither start nor _start is defined" >&5 + { { echo "$as_me:3101: error: Neither start nor _start is defined" >&5 echo "$as_me: error: Neither start nor _start is defined" >&2;} { (exit 1); exit 1; }; } fi -echo "$as_me:3104: checking if __bss_start is defined by the compiler" >&5 +echo "$as_me:3106: checking if __bss_start is defined by the compiler" >&5 echo $ECHO_N "checking if __bss_start is defined by the compiler... $ECHO_C" >&6 if test "${grub_cv_check_uscore_uscore_bss_start_symbol+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3110 "configure" +#line 3112 "configure" #include "confdefs.h" int @@ -3119,16 +3121,16 @@ asm ("incl __bss_start") } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:3122: \"$ac_link\"") >&5 +if { (eval echo "$as_me:3124: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:3125: \$? = $ac_status" >&5 + echo "$as_me:3127: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:3128: \"$ac_try\"") >&5 + { (eval echo "$as_me:3130: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3131: \$? = $ac_status" >&5 + echo "$as_me:3133: \$? = $ac_status" >&5 (exit $ac_status); }; }; then grub_cv_check_uscore_uscore_bss_start_symbol=yes else @@ -3146,16 +3148,16 @@ EOF fi -echo "$as_me:3149: result: $grub_cv_check_uscore_uscore_bss_start_symbol" >&5 +echo "$as_me:3151: result: $grub_cv_check_uscore_uscore_bss_start_symbol" >&5 echo "${ECHO_T}$grub_cv_check_uscore_uscore_bss_start_symbol" >&6 -echo "$as_me:3152: checking if _edata is defined by the compiler" >&5 +echo "$as_me:3154: checking if _edata is defined by the compiler" >&5 echo $ECHO_N "checking if _edata is defined by the compiler... $ECHO_C" >&6 if test "${grub_cv_check_uscore_edata_symbol+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3158 "configure" +#line 3160 "configure" #include "confdefs.h" int @@ -3167,16 +3169,16 @@ asm ("incl _edata") } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:3170: \"$ac_link\"") >&5 +if { (eval echo "$as_me:3172: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:3173: \$? = $ac_status" >&5 + echo "$as_me:3175: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:3176: \"$ac_try\"") >&5 + { (eval echo "$as_me:3178: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3179: \$? = $ac_status" >&5 + echo "$as_me:3181: \$? = $ac_status" >&5 (exit $ac_status); }; }; then grub_cv_check_uscore_edata_symbol=yes else @@ -3194,16 +3196,16 @@ EOF fi -echo "$as_me:3197: result: $grub_cv_check_uscore_edata_symbol" >&5 +echo "$as_me:3199: result: $grub_cv_check_uscore_edata_symbol" >&5 echo "${ECHO_T}$grub_cv_check_uscore_edata_symbol" >&6 -echo "$as_me:3200: checking if edata is defined by the compiler" >&5 +echo "$as_me:3202: checking if edata is defined by the compiler" >&5 echo $ECHO_N "checking if edata is defined by the compiler... $ECHO_C" >&6 if test "${grub_cv_check_edata_symbol+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3206 "configure" +#line 3208 "configure" #include "confdefs.h" int @@ -3215,16 +3217,16 @@ asm ("incl edata") } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:3218: \"$ac_link\"") >&5 +if { (eval echo "$as_me:3220: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:3221: \$? = $ac_status" >&5 + echo "$as_me:3223: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:3224: \"$ac_try\"") >&5 + { (eval echo "$as_me:3226: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3227: \$? = $ac_status" >&5 + echo "$as_me:3229: \$? = $ac_status" >&5 (exit $ac_status); }; }; then grub_cv_check_edata_symbol=yes else @@ -3242,24 +3244,24 @@ EOF fi -echo "$as_me:3245: result: $grub_cv_check_edata_symbol" >&5 +echo "$as_me:3247: result: $grub_cv_check_edata_symbol" >&5 echo "${ECHO_T}$grub_cv_check_edata_symbol" >&6 if test "x$grub_cv_check_uscore_uscore_bss_start_symbol" != "xyes" \ -a "x$grub_cv_check_uscore_edata_symbol" != "xyes" \ -a "x$grub_cv_check_edata_symbol" != "xyes"; then - { { echo "$as_me:3251: error: None of __bss_start, _edata, edata defined" >&5 + { { echo "$as_me:3253: error: None of __bss_start, _edata, edata defined" >&5 echo "$as_me: error: None of __bss_start, _edata, edata defined" >&2;} { (exit 1); exit 1; }; } fi -echo "$as_me:3256: checking if end is defined by the compiler" >&5 +echo "$as_me:3258: checking if end is defined by the compiler" >&5 echo $ECHO_N "checking if end is defined by the compiler... $ECHO_C" >&6 if test "${grub_cv_check_end_symbol+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3262 "configure" +#line 3264 "configure" #include "confdefs.h" int @@ -3271,16 +3273,16 @@ asm ("incl end") } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:3274: \"$ac_link\"") >&5 +if { (eval echo "$as_me:3276: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:3277: \$? = $ac_status" >&5 + echo "$as_me:3279: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:3280: \"$ac_try\"") >&5 + { (eval echo "$as_me:3282: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3283: \$? = $ac_status" >&5 + echo "$as_me:3285: \$? = $ac_status" >&5 (exit $ac_status); }; }; then grub_cv_check_end_symbol=yes else @@ -3298,16 +3300,16 @@ EOF fi -echo "$as_me:3301: result: $grub_cv_check_end_symbol" >&5 +echo "$as_me:3303: result: $grub_cv_check_end_symbol" >&5 echo "${ECHO_T}$grub_cv_check_end_symbol" >&6 -echo "$as_me:3304: checking if _end is defined by the compiler" >&5 +echo "$as_me:3306: checking if _end is defined by the compiler" >&5 echo $ECHO_N "checking if _end is defined by the compiler... $ECHO_C" >&6 if test "${grub_cv_check_uscore_end_symbol+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3310 "configure" +#line 3312 "configure" #include "confdefs.h" int @@ -3319,16 +3321,16 @@ asm ("incl _end") } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:3322: \"$ac_link\"") >&5 +if { (eval echo "$as_me:3324: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:3325: \$? = $ac_status" >&5 + echo "$as_me:3327: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:3328: \"$ac_try\"") >&5 + { (eval echo "$as_me:3330: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3331: \$? = $ac_status" >&5 + echo "$as_me:3333: \$? = $ac_status" >&5 (exit $ac_status); }; }; then grub_cv_check_uscore_end_symbol=yes else @@ -3346,12 +3348,12 @@ EOF fi -echo "$as_me:3349: result: $grub_cv_check_uscore_end_symbol" >&5 +echo "$as_me:3351: result: $grub_cv_check_uscore_end_symbol" >&5 echo "${ECHO_T}$grub_cv_check_uscore_end_symbol" >&6 if test "x$grub_cv_check_end_symbol" != "xyes" \ -a "x$grub_cv_check_uscore_end_symbol" != "xyes"; then - { { echo "$as_me:3354: error: Neither end nor _end is defined" >&5 + { { echo "$as_me:3356: error: Neither end nor _end is defined" >&5 echo "$as_me: error: Neither end nor _end is defined" >&2;} { (exit 1); exit 1; }; } fi @@ -3366,7 +3368,7 @@ fi; # Get the filename or the whole disk and open it. # Known to work on NetBSD. -echo "$as_me:3369: checking for opendisk in -lutil" >&5 +echo "$as_me:3371: checking for opendisk in -lutil" >&5 echo $ECHO_N "checking for opendisk in -lutil... $ECHO_C" >&6 if test "${ac_cv_lib_util_opendisk+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -3374,7 +3376,7 @@ else ac_check_lib_save_LIBS=$LIBS LIBS="-lutil $LIBS" cat >conftest.$ac_ext <<_ACEOF -#line 3377 "configure" +#line 3379 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ @@ -3393,16 +3395,16 @@ opendisk (); } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:3396: \"$ac_link\"") >&5 +if { (eval echo "$as_me:3398: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:3399: \$? = $ac_status" >&5 + echo "$as_me:3401: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:3402: \"$ac_try\"") >&5 + { (eval echo "$as_me:3404: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3405: \$? = $ac_status" >&5 + echo "$as_me:3407: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_util_opendisk=yes else @@ -3413,7 +3415,7 @@ fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:3416: result: $ac_cv_lib_util_opendisk" >&5 +echo "$as_me:3418: result: $ac_cv_lib_util_opendisk" >&5 echo "${ECHO_T}$ac_cv_lib_util_opendisk" >&6 if test $ac_cv_lib_util_opendisk = yes; then GRUB_LIBS="$GRUB_LIBS -lutil" @@ -3426,7 +3428,7 @@ fi # Unless the user specify --without-curses, check for curses. if test "x$with_curses" != "xno"; then - echo "$as_me:3429: checking for wgetch in -lncurses" >&5 + echo "$as_me:3431: checking for wgetch in -lncurses" >&5 echo $ECHO_N "checking for wgetch in -lncurses... $ECHO_C" >&6 if test "${ac_cv_lib_ncurses_wgetch+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -3434,7 +3436,7 @@ else ac_check_lib_save_LIBS=$LIBS LIBS="-lncurses $LIBS" cat >conftest.$ac_ext <<_ACEOF -#line 3437 "configure" +#line 3439 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ @@ -3453,16 +3455,16 @@ wgetch (); } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:3456: \"$ac_link\"") >&5 +if { (eval echo "$as_me:3458: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:3459: \$? = $ac_status" >&5 + echo "$as_me:3461: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:3462: \"$ac_try\"") >&5 + { (eval echo "$as_me:3464: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3465: \$? = $ac_status" >&5 + echo "$as_me:3467: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_ncurses_wgetch=yes else @@ -3473,7 +3475,7 @@ fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:3476: result: $ac_cv_lib_ncurses_wgetch" >&5 +echo "$as_me:3478: result: $ac_cv_lib_ncurses_wgetch" >&5 echo "${ECHO_T}$ac_cv_lib_ncurses_wgetch" >&6 if test $ac_cv_lib_ncurses_wgetch = yes; then GRUB_LIBS="$GRUB_LIBS -lncurses" @@ -3482,7 +3484,7 @@ if test $ac_cv_lib_ncurses_wgetch = yes; then EOF else - echo "$as_me:3485: checking for wgetch in -lcurses" >&5 + echo "$as_me:3487: checking for wgetch in -lcurses" >&5 echo $ECHO_N "checking for wgetch in -lcurses... $ECHO_C" >&6 if test "${ac_cv_lib_curses_wgetch+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -3490,7 +3492,7 @@ else ac_check_lib_save_LIBS=$LIBS LIBS="-lcurses $LIBS" cat >conftest.$ac_ext <<_ACEOF -#line 3493 "configure" +#line 3495 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ @@ -3509,16 +3511,16 @@ wgetch (); } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:3512: \"$ac_link\"") >&5 +if { (eval echo "$as_me:3514: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:3515: \$? = $ac_status" >&5 + echo "$as_me:3517: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:3518: \"$ac_try\"") >&5 + { (eval echo "$as_me:3520: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3521: \$? = $ac_status" >&5 + echo "$as_me:3523: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_curses_wgetch=yes else @@ -3529,7 +3531,7 @@ fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:3532: result: $ac_cv_lib_curses_wgetch" >&5 +echo "$as_me:3534: result: $ac_cv_lib_curses_wgetch" >&5 echo "${ECHO_T}$ac_cv_lib_curses_wgetch" >&6 if test $ac_cv_lib_curses_wgetch = yes; then GRUB_LIBS="$GRUB_LIBS -lcurses" @@ -3549,7 +3551,7 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -echo "$as_me:3552: checking how to run the C preprocessor" >&5 +echo "$as_me:3554: checking how to run the C preprocessor" >&5 echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then @@ -3570,18 +3572,18 @@ do # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF -#line 3573 "configure" +#line 3575 "configure" #include "confdefs.h" #include Syntax error _ACEOF -if { (eval echo "$as_me:3578: \"$ac_cpp conftest.$ac_ext\"") >&5 +if { (eval echo "$as_me:3580: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? egrep -v '^ *\+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 - echo "$as_me:3584: \$? = $ac_status" >&5 + echo "$as_me:3586: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag @@ -3604,17 +3606,17 @@ rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF -#line 3607 "configure" +#line 3609 "configure" #include "confdefs.h" #include _ACEOF -if { (eval echo "$as_me:3611: \"$ac_cpp conftest.$ac_ext\"") >&5 +if { (eval echo "$as_me:3613: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? egrep -v '^ *\+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 - echo "$as_me:3617: \$? = $ac_status" >&5 + echo "$as_me:3619: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag @@ -3651,7 +3653,7 @@ fi else ac_cv_prog_CPP=$CPP fi -echo "$as_me:3654: result: $CPP" >&5 +echo "$as_me:3656: result: $CPP" >&5 echo "${ECHO_T}$CPP" >&6 ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes @@ -3661,18 +3663,18 @@ do # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF -#line 3664 "configure" +#line 3666 "configure" #include "confdefs.h" #include Syntax error _ACEOF -if { (eval echo "$as_me:3669: \"$ac_cpp conftest.$ac_ext\"") >&5 +if { (eval echo "$as_me:3671: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? egrep -v '^ *\+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 - echo "$as_me:3675: \$? = $ac_status" >&5 + echo "$as_me:3677: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag @@ -3695,17 +3697,17 @@ rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF -#line 3698 "configure" +#line 3700 "configure" #include "confdefs.h" #include _ACEOF -if { (eval echo "$as_me:3702: \"$ac_cpp conftest.$ac_ext\"") >&5 +if { (eval echo "$as_me:3704: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? egrep -v '^ *\+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 - echo "$as_me:3708: \$? = $ac_status" >&5 + echo "$as_me:3710: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag @@ -3733,7 +3735,7 @@ rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else - { { echo "$as_me:3736: error: C preprocessor \"$CPP\" fails sanity check" >&5 + { { echo "$as_me:3738: error: C preprocessor \"$CPP\" fails sanity check" >&5 echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;} { (exit 1); exit 1; }; } fi @@ -3747,23 +3749,23 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu for ac_header in string.h strings.h ncurses/curses.h ncurses.h curses.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -echo "$as_me:3750: checking for $ac_header" >&5 +echo "$as_me:3752: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3756 "configure" +#line 3758 "configure" #include "confdefs.h" #include <$ac_header> _ACEOF -if { (eval echo "$as_me:3760: \"$ac_cpp conftest.$ac_ext\"") >&5 +if { (eval echo "$as_me:3762: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? egrep -v '^ *\+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 - echo "$as_me:3766: \$? = $ac_status" >&5 + echo "$as_me:3768: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag @@ -3782,7 +3784,7 @@ else fi rm -f conftest.err conftest.$ac_ext fi -echo "$as_me:3785: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "$as_me:3787: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <&5 + { { echo "$as_me:4352: error: You must enable at least one network driver" >&5 echo "$as_me: error: You must enable at least one network driver" >&2;} { (exit 1); exit 1; }; } fi @@ -4367,14 +4401,14 @@ main (void) EOF if { ac_try='${CC-cc} ${CFLAGS} conftest.c -o conftest' - { (eval echo "$as_me:4370: \"$ac_try\"") >&5 + { (eval echo "$as_me:4404: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4373: \$? = $ac_status" >&5 + echo "$as_me:4407: \$? = $ac_status" >&5 (exit $ac_status); }; } && test -s conftest; then grub_tmp_value=`./conftest < "$enable_preset_menu"` else - { { echo "$as_me:4377: error: ${CC-cc} failed to produce an executable file" >&5 + { { echo "$as_me:4411: error: ${CC-cc} failed to produce an executable file" >&5 echo "$as_me: error: ${CC-cc} failed to produce an executable file" >&2;} { (exit 1); exit 1; }; } fi @@ -4386,7 +4420,7 @@ EOF rm -f conftest* else - { { echo "$as_me:4389: error: Cannot read the preset menu file $enable_preset_menu" >&5 + { { echo "$as_me:4423: error: Cannot read the preset menu file $enable_preset_menu" >&5 echo "$as_me: error: Cannot read the preset menu file $enable_preset_menu" >&2;} { (exit 1); exit 1; }; } fi @@ -4502,7 +4536,7 @@ DEFS=-DHAVE_CONFIG_H : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ echo "$as_me:4505: creating $CONFIG_STATUS" >&5 +{ echo "$as_me:4539: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL @@ -4678,7 +4712,7 @@ cat >>$CONFIG_STATUS <<\EOF echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header - { { echo "$as_me:4681: error: ambiguous option: $1 + { { echo "$as_me:4715: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} @@ -4697,7 +4731,7 @@ Try \`$0 --help' for more information." >&2;} ac_need_defaults=false;; # This is an error. - -*) { { echo "$as_me:4700: error: unrecognized option: $1 + -*) { { echo "$as_me:4734: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} @@ -4755,7 +4789,7 @@ do "util/grub-md5-crypt" ) CONFIG_FILES="$CONFIG_FILES util/grub-md5-crypt" ;; "default-1" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - *) { { echo "$as_me:4758: error: invalid argument: $ac_config_target" >&5 + *) { { echo "$as_me:4792: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac @@ -5019,7 +5053,7 @@ done; } esac if test x"$ac_file" != x-; then - { echo "$as_me:5022: creating $ac_file" >&5 + { echo "$as_me:5056: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi @@ -5037,7 +5071,7 @@ echo "$as_me: creating $ac_file" >&6;} -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) - test -f "$f" || { { echo "$as_me:5040: error: cannot find input file: $f" >&5 + test -f "$f" || { { echo "$as_me:5074: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo $f;; @@ -5050,7 +5084,7 @@ echo "$as_me: error: cannot find input file: $f" >&2;} echo $srcdir/$f else # /dev/null tree - { { echo "$as_me:5053: error: cannot find input file: $f" >&5 + { { echo "$as_me:5087: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; @@ -5111,7 +5145,7 @@ for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue * ) ac_file_in=$ac_file.in ;; esac - test x"$ac_file" != x- && { echo "$as_me:5114: creating $ac_file" >&5 + test x"$ac_file" != x- && { echo "$as_me:5148: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} # First look for the input files in the build tree, otherwise in the @@ -5122,7 +5156,7 @@ echo "$as_me: creating $ac_file" >&6;} -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) - test -f "$f" || { { echo "$as_me:5125: error: cannot find input file: $f" >&5 + test -f "$f" || { { echo "$as_me:5159: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo $f;; @@ -5135,7 +5169,7 @@ echo "$as_me: error: cannot find input file: $f" >&2;} echo $srcdir/$f else # /dev/null tree - { { echo "$as_me:5138: error: cannot find input file: $f" >&5 + { { echo "$as_me:5172: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; @@ -5252,7 +5286,7 @@ cat >>$CONFIG_STATUS <<\EOF rm -f $tmp/in if test x"$ac_file" != x-; then if cmp -s $ac_file $tmp/config.h 2>/dev/null; then - { echo "$as_me:5255: $ac_file is unchanged" >&5 + { echo "$as_me:5289: $ac_file is unchanged" >&5 echo "$as_me: $ac_file is unchanged" >&6;} else ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ diff --git a/configure.in b/configure.in index 3fa85de9e..d88b6049a 100644 --- a/configure.in +++ b/configure.in @@ -292,13 +292,6 @@ if test "x$enable_3c529" = xyes; then NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c529.o" fi -AC_ARG_ENABLE(3c590, - [ --enable-3c590 enable 3Com590 driver]) -if test "x$enable_3c590" = xyes; then - NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C590=1" - NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c590.o" -fi - AC_ARG_ENABLE(3c595, [ --enable-3c595 enable 3Com595 driver]) if test "x$enable_3c595" = xyes; then @@ -320,6 +313,13 @@ if test "x$enable_cs89x0" = xyes; then NETBOOT_DRIVERS="$NETBOOT_DRIVERS cs89x0.o" fi +AC_ARG_ENABLE(davicom, + [ --enable-davicom enable Davicom driver]) +if test "x$enable_davicom" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_DAVICOM=1" + NETBOOT_DRIVERS="$NETBOOT_DRIVERS davicom.o" +fi + AC_ARG_ENABLE(depca, [ --enable-depca enable DEPCA and EtherWORKS driver]) if test "x$enable_depca" = xyes; then @@ -327,6 +327,13 @@ if test "x$enable_depca" = xyes; then NETBOOT_DRIVERS="$NETBOOT_DRIVERS depca.o" fi +AC_ARG_ENABLE(eepro, + [ --enable-eepro enable Etherexpress Pro/10 driver]) +if test "x$enable_eepro" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EEPRO=1" + NETBOOT_DRIVERS="$NETBOOT_DRIVERS eepro.o" +fi + AC_ARG_ENABLE(eepro100, [ --enable-eepro100 enable Etherexpress Pro/100 driver]) if test "x$enable_eepro100" = xyes; then @@ -383,6 +390,20 @@ if test "x$enable_ni6510" = xyes; then NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni6510.o" fi +AC_ARG_ENABLE(natsemi, + [ --enable-natsemi enable NatSemi DP8381x driver]) +if test "x$enable_natsemi" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NATSEMI=1" + NETBOOT_DRIVERS="$NETBOOT_DRIVERS natsemi.o" +fi + +AC_ARG_ENABLE(ni5010, + [ --enable-ni5010 enable Racal-Interlan NI5010 driver]) +if test "x$enable_ni5010" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI5010=1" + NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni5010.o" +fi + AC_ARG_ENABLE(3c503, [ --enable-3c503 enable 3Com503 driver]) if test "x$enable_3c503" = xyes; then @@ -425,6 +446,13 @@ if test "x$enable_rtl8139" = xyes; then NETBOOT_DRIVERS="$NETBOOT_DRIVERS rtl8139.o" fi +AC_ARG_ENABLE(sis900, + [ --enable-sis900 enable SIS 900 and SIS 7016 driver]) +if test "x$enable_sis900" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SIS900=1" + NETBOOT_DRIVERS="$NETBOOT_DRIVERS sis900.o" +fi + AC_ARG_ENABLE(sk-g16, [ --enable-sk-g16 enable Schneider and Koch G16 driver]) if test "x$enable_sk_g16" = xyes; then @@ -460,6 +488,13 @@ if test "x$enable_via_rhine" = xyes; then NETBOOT_DRIVERS="$NETBOOT_DRIVERS via_rhine.o" fi +AC_ARG_ENABLE(w89c840, + [ --enable-w89c840 enable Winbond W89c840, Compex RL100-ATX driver]) +if test "x$enable_w89c840" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_W89C840=1" + NETBOOT_DRIVERS="$NETBOOT_DRIVERS w89c840.o" +fi + dnl Check if the netboot support is turned on. AM_CONDITIONAL(NETBOOT_SUPPORT, test "x$NET_CFLAGS" != x) if test "x$NET_CFLAGS" != x; then @@ -479,12 +514,6 @@ if test "x$enable_3c503_aui" = xyes; then NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DT503_AUI=1" fi -AC_ARG_ENABLE(3c509-hack, - [ --enable-3c509-hack make a 3c509 do bootp quicker]) -if test "x$enable_3c509_hack" = xyes; then - NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DT509HACK=1" -fi - AC_ARG_ENABLE(compex-rl2000-fix, [ --enable-compex-rl2000-fix specify this if you have a Compex RL2000 PCI]) @@ -492,13 +521,6 @@ if test "x$enable_compex_rl2000_fix" = xyes; then NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCOMPEX_RL2000_FIX=1" fi -AC_ARG_ENABLE(ns8390-force-16bit, - [ --enable-ns8390-force-16bit - specify this if falsely 8 bit is detected]) -if test "x$enable_ns8390_force_16bit" = xyes; then - NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNS8390_FORCE_16BIT=1" -fi - AC_ARG_ENABLE(smc9000-scan, [ --enable-smc9000-scan=LIST probe for SMC9000 I/O addresses using LIST], diff --git a/docs/grub-md5-crypt.8 b/docs/grub-md5-crypt.8 index c5449dc25..34a0b3b06 100644 --- a/docs/grub-md5-crypt.8 +++ b/docs/grub-md5-crypt.8 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23. -.TH GRUB-MD5-CRYPT "8" "December 2001" "grub-md5-crypt (GNU GRUB )" FSF +.TH GRUB-MD5-CRYPT "8" "January 2002" "grub-md5-crypt (GNU GRUB )" FSF .SH NAME grub-md5-crypt \- Encrypt a password in MD5 format .SH SYNOPSIS diff --git a/docs/mbchk.1 b/docs/mbchk.1 index 653d3168f..e290daa94 100644 --- a/docs/mbchk.1 +++ b/docs/mbchk.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23. -.TH MBCHK "1" "December 2001" "mbchk (GNU GRUB 0.90)" FSF +.TH MBCHK "1" "January 2002" "mbchk (GNU GRUB 0.90)" FSF .SH NAME mbchk \- check the format of a Multiboot kernel .SH SYNOPSIS diff --git a/netboot/3c509.c b/netboot/3c509.c index e135f9a41..604a6862b 100644 --- a/netboot/3c509.c +++ b/netboot/3c509.c @@ -27,11 +27,13 @@ $Id$ #include "etherboot.h" #include "nic.h" #include "cards.h" +#include "timer.h" #include "3c509.h" -static unsigned char eth_vendor, eth_flags, eth_laar; -static unsigned short eth_nic_base, eth_asic_base; -static char bnc=0, utp=0; /* for 3C509 */ +#define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000) + +static unsigned short eth_nic_base; +static enum { none, bnc, utp } connector = none; /* for 3C509 */ #ifdef INCLUDE_3C529 /* @@ -55,17 +57,6 @@ static struct el3_mca_adapters_struct el3_mca_adapters[] = { }; #endif -/* a surrogate */ - -static void DELAY(int val) -{ - int c; - - for(c=0; cnode_addr[i], BASE + EP_W2_ADDR_0 + i); outw(RX_RESET, BASE + EP_COMMAND); @@ -133,24 +124,24 @@ static void t509_reset(struct nic *nic) outw(SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST, BASE + EP_COMMAND); /* configure BNC */ - if (bnc) { + if (connector == bnc) { outw(START_TRANSCEIVER, BASE + EP_COMMAND); - DELAY(10000); - } + udelay(1000); + } /* configure UTP */ - if (utp) { + else if (connector == utp) { GO_WINDOW(4); outw(ENABLE_UTP, BASE + EP_W4_MEDIA_TYPE); + sleep(2); /* Give time for media to negotiate */ GO_WINDOW(1); - } + } - /* start tranciever and receiver */ + /* start transceiver and receiver */ outw(RX_ENABLE, BASE + EP_COMMAND); outw(TX_ENABLE, BASE + EP_COMMAND); /* set early threshold for minimal packet length */ - outw(SET_RX_EARLY_THRESH | ETH_MIN_PACKET, BASE + EP_COMMAND); - + outw(SET_RX_EARLY_THRESH | ETH_ZLEN, BASE + EP_COMMAND); outw(SET_TX_START_THRESH | 16, BASE + EP_COMMAND); } @@ -171,17 +162,14 @@ const char *p) /* Packet */ int pad; int status; - if(eth_vendor != VENDOR_3C509) - return; - #ifdef EDEBUG - printf("{l=%d,t=%x}",s+ETHER_HDR_SIZE,t); + printf("{l=%d,t=%hX}",s+ETH_HLEN,t); #endif /* swap bytes of type */ t= htons(t); - len=s+ETHER_HDR_SIZE; /* actual length of packet */ + len=s+ETH_HLEN; /* actual length of packet */ pad = padmap[len & 3]; /* @@ -189,30 +177,28 @@ const char *p) /* Packet */ * but we drop packets that are too large. Perhaps we should truncate * them instead? */ - if (len + pad > ETH_MAX_PACKET) { + if (len + pad > ETH_FRAME_LEN) { return; } /* drop acknowledgements */ - while(( status=inb(BASE + EP_W1_TX_STATUS) )& TXS_COMPLETE ) { - if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) { + while ((status=inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE ) { + if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) { outw(TX_RESET, BASE + EP_COMMAND); outw(TX_ENABLE, BASE + EP_COMMAND); } - outb(0x0, BASE + EP_W1_TX_STATUS); } - while (inw(BASE + EP_W1_FREE_TX) < (unsigned short)len + pad + 4) { - /* no room in FIFO */ - } + while (inw(BASE + EP_W1_FREE_TX) < (unsigned short)len + pad + 4) + ; /* no room in FIFO */ outw(len, BASE + EP_W1_TX_PIO_WR_1); outw(0x0, BASE + EP_W1_TX_PIO_WR_1); /* Second dword meaningless */ /* write packet */ - outsw(BASE + EP_W1_TX_PIO_WR_1, d, ETHER_ADDR_SIZE/2); - outsw(BASE + EP_W1_TX_PIO_WR_1, nic->node_addr, ETHER_ADDR_SIZE/2); + outsw(BASE + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2); + outsw(BASE + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2); outw(t, BASE + EP_W1_TX_PIO_WR_1); outsw(BASE + EP_W1_TX_PIO_WR_1, p, s / 2); if (s & 1) @@ -221,8 +207,9 @@ const char *p) /* Packet */ while (pad--) outb(0, BASE + EP_W1_TX_PIO_WR_1); /* Padding */ - /* timeout after sending */ - DELAY(1000); + /* wait for Tx complete */ + while((inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0) + ; } /************************************************************************** @@ -236,14 +223,11 @@ static int t509_poll(struct nic *nic) short status, cst; register short rx_fifo; - if(eth_vendor!=VENDOR_3C509) - return 0; - cst=inw(BASE + EP_STATUS); #ifdef EDEBUG if(cst & 0x1FFF) - printf("-%x-",cst); + printf("-%hX-",cst); #endif if( (cst & S_RX_COMPLETE)==0 ) { @@ -256,7 +240,7 @@ static int t509_poll(struct nic *nic) status = inw(BASE + EP_W1_RX_STATUS); #ifdef EDEBUG - printf("*%x*",status); + printf("*%hX*",status); #endif if (status & ERR_RX) { @@ -280,10 +264,9 @@ static int t509_poll(struct nic *nic) while(1) { status = inw(BASE + EP_W1_RX_STATUS); #ifdef EDEBUG - printf("*%x*",status); + printf("*%hX*",status); #endif rx_fifo = status & RX_BYTES_MASK; - if(rx_fifo>0) { insw(BASE + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2); if(rx_fifo & 1) @@ -293,32 +276,29 @@ static int t509_poll(struct nic *nic) printf("+%d",rx_fifo); #endif } - if(( status & RX_INCOMPLETE )==0) { #ifdef EDEBUG printf("=%d",nic->packetlen); #endif break; } - - DELAY(1000); + udelay(1000); /* if incomplete wait 1 ms */ } - /* acknowledge reception of packet */ outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND); - while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) + ; #ifdef EDEBUG type = (nic->packet[12]<<8) | nic->packet[13]; if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+ - nic->packet[5] == 0xFF*ETHER_ADDR_SIZE) - printf(",t=0x%x,b]",type); + nic->packet[5] == 0xFF*ETH_ALEN) + printf(",t=%hX,b]",type); else - printf(",t=0x%x]",type); + printf(",t=%hX]",type); #endif - return 1; + return (1); } - /************************************************************************* 3Com 509 - specific routines **************************************************************************/ @@ -384,7 +364,8 @@ get_eeprom_data(int id_port, int offset) { int i, data = 0; outb(0x80 + offset, id_port); - DELAY(10000); + /* Do we really need this wait? Won't be noticeable anyway */ + udelay(10000); for (i = 0; i < 16; i++) data = (data << 1) | (inw(id_port) & 1); return (data); @@ -415,11 +396,10 @@ struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) t509_disable(nic); /* in case board was active */ /* note that nic is not used */ - - for (failcount=0; failcount<4000; failcount++) { - int data, j, io_base, id_port = EP_ID_PORT; + for (failcount = 0; failcount < 4000; failcount++) { + int data, j, io_base, id_port; unsigned short k; - int ep_current_tag = EP_LAST_TAG + 1; + int ep_current_tag; short *p; #ifdef INCLUDE_3C529 int curboard; @@ -427,7 +407,6 @@ struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) id_port = EP_ID_PORT; ep_current_tag = EP_LAST_TAG + 1; - eth_vendor = VENDOR_NONE; /********************************************************* Search for 3Com 509 card @@ -476,8 +455,6 @@ struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) outb_p(0, MCA_ADAPTER_SETUP_REG); if (mcafound) { - eth_vendor = VENDOR_3C509; - eth_nic_base = ((short)((mca_pos4&0xfc)|0x02)) << 8; mca_irq = mca_pos5 & 0x0f; ep_current_tag--; @@ -487,18 +464,18 @@ struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) #endif /* Look for the EISA boards, leave them activated */ /* search for the first card, ignore all others */ - for(j = 1; j < 16 && eth_vendor==VENDOR_NONE ; j++) { + for(j = 1; j < 16; j++) { io_base = (j * EP_EISA_START) | EP_EISA_W0; if (inw(io_base + EP_W0_MFG_ID) != MFG_ID) continue; - /* we must found 0x1f if the board is EISA configurated */ + /* we must have found 0x1f if the board is EISA configurated */ if ((inw(io_base + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f) continue; /* Reset and Enable the card */ outb(W0_P4_CMD_RESET_ADAPTER, io_base + EP_W0_CONFIG_CTRL); - DELAY(10000); /* we must wait at least 10 ms */ + udelay(1000); /* Must wait 800 µs, be conservative */ outb(W0_P4_CMD_ENABLE_ADAPTER, io_base + EP_W0_CONFIG_CTRL); /* @@ -506,15 +483,15 @@ struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) * x000 - x00F, where x is the slot number. */ eth_nic_base = j * EP_EISA_START; - eth_vendor = VENDOR_3C509; + break; } ep_current_tag--; /* Look for the ISA boards. Init and leave them actived */ /* search for the first card, ignore all others */ outb(0xc0, id_port); /* Global reset */ - DELAY(10000); - for (i = 0; i < EP_MAX_BOARDS && eth_vendor==VENDOR_NONE; i++) { + udelay(1000); /* wait 1 ms */ + for (i = 0; i < EP_MAX_BOARDS; i++) { outb(0, id_port); outb(0, id_port); send_ID_sequence(id_port); @@ -531,11 +508,11 @@ struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200; outb(ep_current_tag, id_port); /* tags board */ outb(ACTIVATE_ADAPTER_TO_CONFIG, id_port); - eth_vendor = VENDOR_3C509; ep_current_tag--; + break; } - if(eth_vendor != VENDOR_3C509) + if (i >= EP_MAX_BOARDS) goto no3c509; /* @@ -550,7 +527,7 @@ struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) */ if (mcafound) { if (mcafound->id != k) { - printf("MCA: PROD_ID in EEPROM does not match MCA card ID! (%x != %x)\n", k, mcafound->id); + printf("MCA: PROD_ID in EEPROM does not match MCA card ID! (%hX != %hX)\n", k, mcafound->id); goto no3c509; } } else { /* for ISA/EISA */ @@ -564,15 +541,14 @@ struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) #ifdef INCLUDE_3C529 if (mcafound) { - printf("%s board found on MCA at 0x%x IRQ %d -", + printf("%s board found on MCA at %#hx IRQ %d -", mcafound->name, eth_nic_base, mca_irq); } else { #endif - if(eth_nic_base >= EP_EISA_START) { - printf("3C5x9 board on EISA at 0x%x - ",eth_nic_base); - } else { - printf("3C5x9 board on ISA at 0x%x - ",eth_nic_base); - } + if(eth_nic_base >= EP_EISA_START) + printf("3C5x9 board on EISA at %#hx - ",eth_nic_base); + else + printf("3C5x9 board on ISA at %#hx - ",eth_nic_base); #ifdef INCLUDE_3C529 } #endif @@ -583,61 +559,48 @@ struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) switch(j) { case 0: - if(i & IS_UTP) { + if (i & IS_UTP) { printf("10baseT\n"); - utp=1; + connector = utp; } else { printf("10baseT not present\n"); - eth_vendor=VENDOR_NONE; goto no3c509; } - break; case 1: - if(i & IS_AUI) + if (i & IS_AUI) printf("10base5\n"); else { printf("10base5 not present\n"); - eth_vendor=VENDOR_NONE; goto no3c509; } - break; case 3: - if(i & IS_BNC) { + if (i & IS_BNC) { printf("10base2\n"); - bnc=1; + connector = bnc; } else { printf("10base2 not present\n"); - eth_vendor=VENDOR_NONE; goto no3c509; } - break; default: printf("unknown connector\n"); - eth_vendor=VENDOR_NONE; goto no3c509; } /* * Read the station address from the eeprom */ p = (unsigned short *) nic->node_addr; - for (i = 0; i < 3; i++) { + for (i = 0; i < ETH_ALEN / 2; i++) { GO_WINDOW(0); p[i] = htons(get_e(i)); GO_WINDOW(2); outw(ntohs(p[i]), BASE + EP_W2_ADDR_0 + (i * 2)); } - - printf("Ethernet address: "); - for(i=0; i<5; i++) { - printf("%b:",nic->node_addr[i]); - } - printf("%b\n",nic->node_addr[i]); - + printf("Ethernet address: %!\n", nic->node_addr); t509_reset(nic); nic->reset = t509_reset; nic->poll = t509_poll; @@ -645,7 +608,6 @@ struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) nic->disable = t509_disable; return nic; no3c509: - eth_vendor = VENDOR_NONE; printf("(probe fail)"); } return 0; @@ -656,4 +618,3 @@ no3c509: * c-basic-offset: 8 * End: */ - diff --git a/netboot/3c509.h b/netboot/3c509.h index 46ec7ac60..7214932ae 100644 --- a/netboot/3c509.h +++ b/netboot/3c509.h @@ -395,4 +395,3 @@ * c-basic-offset: 8 * End: */ - diff --git a/netboot/3c595.c b/netboot/3c595.c index 690b63d9d..5a04e2569 100644 --- a/netboot/3c595.c +++ b/netboot/3c595.c @@ -28,8 +28,8 @@ #include "nic.h" #include "pci.h" #include "3c595.h" +#include "timer.h" -static unsigned char eth_vendor, eth_flags, eth_laar; static unsigned short eth_nic_base, eth_asic_base; static unsigned short vx_connector, vx_connectors; @@ -57,34 +57,7 @@ static struct connector_entry { static void vxgetlink(void); static void vxsetlink(void); -static void safetwiddle() -{ - static int count=0; - static int count2=0; - static char tiddles[]="-\\|/"; - putchar(tiddles[(count2++)&0xfff?count&3:(count++)&3]); - putchar('\b'); -} - -/* a surrogate */ - -static void DELAY(int val) -{ - int c; - - for(c=0; cnode_addr[i], BASE + VX_W2_ADDR_0 + i); outw(RX_RESET, BASE + VX_COMMAND); @@ -193,26 +166,26 @@ unsigned int t, /* Type */ unsigned int s, /* size */ const char *p) /* Packet */ { - register unsigned int len; + register int len; int pad; int status; #ifdef EDEBUG - printf("{l=%d,t=%x}",s+ETHER_HDR_SIZE,t); + printf("{l=%d,t=%hX}",s+ETH_HLEN,t); #endif /* swap bytes of type */ t= htons(t); - len=s+ETHER_HDR_SIZE; /* actual length of packet */ + len=s+ETH_HLEN; /* actual length of packet */ pad = padmap[len & 3]; /* - * The 3c509 automatically pads short packets to minimum ethernet length, + * The 3c595 automatically pads short packets to minimum ethernet length, * but we drop packets that are too large. Perhaps we should truncate * them instead? */ - if (len + pad > ETH_MAX_PACKET) { + if (len + pad > ETH_FRAME_LEN) { return; } @@ -234,8 +207,8 @@ const char *p) /* Packet */ outw(0x0, BASE + VX_W1_TX_PIO_WR_1); /* Second dword meaningless */ /* write packet */ - outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETHER_ADDR_SIZE/2); - outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETHER_ADDR_SIZE/2); + outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2); + outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2); outw(t, BASE + VX_W1_TX_PIO_WR_1); outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2); if (s & 1) @@ -244,8 +217,9 @@ const char *p) /* Packet */ while (pad--) outb(0, BASE + VX_W1_TX_PIO_WR_1); /* Padding */ - /* timeout after sending */ - DELAY(1000); + /* wait for Tx complete */ + while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0) + ; } /************************************************************************** @@ -255,7 +229,7 @@ static int t595_poll(struct nic *nic) { /* common variables */ unsigned short type = 0; /* used by EDEBUG */ - /* variables for 3C509 */ + /* variables for 3C595 */ short status, cst; register short rx_fifo; @@ -263,7 +237,7 @@ static int t595_poll(struct nic *nic) #ifdef EDEBUG if(cst & 0x1FFF) - printf("-%x-",cst); + printf("-%hX-",cst); #endif if( (cst & S_RX_COMPLETE)==0 ) { @@ -276,7 +250,7 @@ static int t595_poll(struct nic *nic) status = inw(BASE + VX_W1_RX_STATUS); #ifdef EDEBUG - printf("*%x*",status); + printf("*%hX*",status); #endif if (status & ERR_RX) { @@ -300,7 +274,7 @@ static int t595_poll(struct nic *nic) while(1) { status = inw(BASE + VX_W1_RX_STATUS); #ifdef EDEBUG - printf("*%x*",status); + printf("*%hX*",status); #endif rx_fifo = status & RX_BYTES_MASK; @@ -313,15 +287,13 @@ static int t595_poll(struct nic *nic) printf("+%d",rx_fifo); #endif } - if(( status & RX_INCOMPLETE )==0) { #ifdef EDEBUG printf("=%d",nic->packetlen); #endif break; } - - DELAY(1000); + udelay(1000); } /* acknowledge reception of packet */ @@ -330,17 +302,17 @@ static int t595_poll(struct nic *nic) #ifdef EDEBUG type = (nic->packet[12]<<8) | nic->packet[13]; if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+ - nic->packet[5] == 0xFF*ETHER_ADDR_SIZE) - printf(",t=0x%x,b]",type); + nic->packet[5] == 0xFF*ETH_ALEN) + printf(",t=%hX,b]",type); else - printf(",t=0x%x]",type); + printf(",t=%hX]",type); #endif return 1; } /************************************************************************* - 3Com 509 - specific routines + 3Com 595 - specific routines **************************************************************************/ static int @@ -349,9 +321,9 @@ eeprom_rdy() int i; for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++) - DELAY(1000); + udelay(1000); if (i >= MAX_EEPROMBUSY) { - /* printf("3c509: eeprom failed to come ready.\n"); */ + /* printf("3c595: eeprom failed to come ready.\n"); */ printf("3c595: eeprom is busy.\n"); /* memory in EPROM is tight */ return (0); } @@ -441,7 +413,7 @@ vxsetlink(void) /* First, disable all. */ outw(STOP_TRANSCEIVER, BASE + VX_COMMAND); - DELAY(8000); + udelay(8000); GO_WINDOW(4); outw(0, BASE + VX_W4_MEDIA_TYPE); @@ -453,7 +425,7 @@ vxsetlink(void) break; case CONNECTOR_BNC: outw(START_TRANSCEIVER,BASE + VX_COMMAND); - DELAY(8000); + udelay(8000); break; case CONNECTOR_TX: case CONNECTOR_FX: @@ -469,7 +441,7 @@ vxsetlink(void) static void t595_disable(struct nic *nic) { outw(STOP_TRANSCEIVER, BASE + VX_COMMAND); - DELAY(8000); + udelay(8000); GO_WINDOW(4); outw(0, BASE + VX_W4_MEDIA_TYPE); GO_WINDOW(1); @@ -497,7 +469,7 @@ struct nic *t595_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_d /* printf("\nEEPROM:"); for (i = 0; i < (EEPROMSIZE/2); i++) { - printf("%x:", get_e(i)); + printf("%hX:", get_e(i)); } printf("\n"); */ @@ -512,11 +484,7 @@ struct nic *t595_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_d outw(ntohs(p[i]), BASE + VX_W2_ADDR_0 + (i * 2)); } - printf("Ethernet address: "); - for(i=0; i<5; i++) { - printf("%b:",nic->node_addr[i]); - } - printf("%b\n",nic->node_addr[i]); + printf("Ethernet address: %!\n", nic->node_addr); t595_reset(nic); nic->reset = t595_reset; diff --git a/netboot/3c90x.c b/netboot/3c90x.c index 191603043..93996e00a 100644 --- a/netboot/3c90x.c +++ b/netboot/3c90x.c @@ -38,8 +38,8 @@ #include "nic.h" #include "pci.h" #include "cards.h" +#include "timer.h" -#define TIME_OUT 60000 #define XCVR_MAGIC (0x5A00) /** any single transmission fails after 16 collisions or other errors ** this is the number of times to retry the transmission -- this should @@ -243,7 +243,7 @@ static struct unsigned char isBrev; unsigned char CurrentWindow; unsigned int IOAddr; - unsigned char HWAddr[6]; + unsigned char HWAddr[ETH_ALEN]; TXD TransmitDPD; RXD ReceiveUPD; } @@ -479,13 +479,13 @@ a3c90x_transmit(struct nic *nic, const char *d, unsigned int t, struct eth_hdr { - unsigned char dst_addr[6]; - unsigned char src_addr[6]; + unsigned char dst_addr[ETH_ALEN]; + unsigned char src_addr[ETH_ALEN]; unsigned short type; } hdr; unsigned char status; - unsigned timeout, i, retries; + unsigned i, retries; for (retries=0; retries < XMIT_RETRIES ; retries++) { @@ -504,10 +504,10 @@ a3c90x_transmit(struct nic *nic, const char *d, unsigned int t, hdr.type = htons(t); /** Copy the destination address **/ - memcpy(hdr.dst_addr, d, 6); + memcpy(hdr.dst_addr, d, ETH_ALEN); /** Copy our MAC address **/ - memcpy(hdr.src_addr, INF_3C90X.HWAddr, 6); + memcpy(hdr.src_addr, INF_3C90X.HWAddr, ETH_ALEN); /** Setup the DPD (download descriptor) **/ INF_3C90X.TransmitDPD.DnNextPtr = 0; @@ -528,12 +528,12 @@ a3c90x_transmit(struct nic *nic, const char *d, unsigned int t, ; /** Wait for NIC Transmit to Complete **/ - timeout=TIME_OUT; + load_timer2(10*TICKS_PER_MS); /* Give it 10 ms */ while (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004) && - --timeout) - for(i=0;i>16); + printf("3C90X: Rx Overrun (%hX)\n",errcode>>16); else if (errcode & (1<<17)) - printf("3C90X: Runt Frame (%x)\n",errcode>>16); + printf("3C90X: Runt Frame (%hX)\n",errcode>>16); else if (errcode & (1<<18)) - printf("3C90X: Alignment Error (%x)\n",errcode>>16); + printf("3C90X: Alignment Error (%hX)\n",errcode>>16); else if (errcode & (1<<19)) - printf("3C90X: CRC Error (%x)\n",errcode>>16); + printf("3C90X: CRC Error (%hX)\n",errcode>>16); else if (errcode & (1<<20)) - printf("3C90X: Oversized Frame (%x)\n",errcode>>16); + printf("3C90X: Oversized Frame (%hX)\n",errcode>>16); else - printf("3C90X: Packet error (%x)\n",errcode>>16); + printf("3C90X: Packet error (%hX)\n",errcode>>16); return 0; } @@ -659,10 +659,15 @@ a3c90x_poll(struct nic *nic) /*** a3c90x_disable: exported routine to disable the card. What's this for? *** the eepro100.c driver didn't have one, so I just left this one empty too. *** Ideas anyone? + *** Must turn off receiver at least so stray packets will not corrupt memory + *** [Ken] ***/ static void a3c90x_disable(struct nic *nic) { + /* Disable the receiver and transmitter. */ + outw(cmdRxDisable, INF_3C90X.IOAddr + regCommandIntStatus_w); + outw(cmdTxDisable, INF_3C90X.IOAddr + regCommandIntStatus_w); } @@ -683,6 +688,8 @@ a3c90x_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci if (probeaddrs == 0 || probeaddrs[0] == 0) return 0; + adjust_pci_device(pci); + INF_3C90X.IOAddr = probeaddrs[0] & ~3; INF_3C90X.CurrentWindow = 255; switch (a3c90x_internal_ReadEeprom(INF_3C90X.IOAddr, 0x03)) @@ -759,9 +766,7 @@ a3c90x_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci INF_3C90X.HWAddr[3] = eeprom[1]&0xFF; INF_3C90X.HWAddr[4] = eeprom[2]>>8; INF_3C90X.HWAddr[5] = eeprom[2]&0xFF; - printf("MAC Address = %b:%b:%b:%b:%b:%b\n", - INF_3C90X.HWAddr[0],INF_3C90X.HWAddr[1],INF_3C90X.HWAddr[2], - INF_3C90X.HWAddr[3],INF_3C90X.HWAddr[4],INF_3C90X.HWAddr[5]); + printf("MAC Address = %!\n", INF_3C90X.HWAddr); /** Program the MAC address into the station address registers **/ a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winAddressing2); @@ -773,7 +778,8 @@ a3c90x_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+4); /** Fill in our entry in the etherboot arp table **/ - for(i=0;i<6;i++) nic->node_addr[i] = (eeprom[i/2] >> (8*((i&1)^1))) & 0xff; + for(i=0;inode_addr[i] = (eeprom[i/2] >> (8*((i&1)^1))) & 0xff; /** Read the media options register, print a message and set default ** xcvr. diff --git a/netboot/3c90x.txt b/netboot/3c90x.txt index 7071ceb3e..3d6746c51 100644 --- a/netboot/3c90x.txt +++ b/netboot/3c90x.txt @@ -77,6 +77,10 @@ II FLASH PROMS have heard problem reports of its use under FreeBSD. Anyone willing to make it work under FreeBSD is more than welcome to do so! + You also have the option of using EPROM chips - the 3C905B-TX-NM has been + successfully tested with 27C256 (32kB) and 27C512 (64kB) chips with a + specified access time of 100ns and faster. + III GENERAL USE @@ -87,10 +91,10 @@ III GENERAL USE 2. Build the appropriate 3c90x.fd0 or 3c90x.fd0 floppy image with possibly the value CFG_3C90X_XCVR defined to the transceiver type that you want to use (i.e., 10/100 rj45, AUI, coax, MII). - 3. Run the floppy image on the PC to be network booted, to verify that - it will boot properly. + 3. Run the floppy image on the PC to be network booted, to get + it configured, and to verify that it will boot properly. 4. Build the 3c90x.rom or 3c90x.lzrom PROM image and program - it into the flash memory chip. + it into the flash or EPROM memory chip. 5. Put the PROM in the ethernet card, boot and enable 'boot from network first' in the system BIOS, save and reboot. @@ -100,6 +104,8 @@ III GENERAL USE boot PROM, add the setting CFG_3C90X_BOOTROM_FIX and go through the steps 2-5 above. This works around a bug in some 3c905B cards (see below), but has some side-effects which may not be desirable. + Please note that you have to boot off a floppy (not PROM!) once for + this fix to take effect. 2. The possible need to manually set the CFG_3C90X_XCVR value to configure the transceiver type. Values are listed below. 3. The possible need to define CFG_3C90X_PRESERVE_XCVR for use in @@ -160,7 +166,9 @@ III GENERAL USE by the driver. To enable the 3c905B bugfix, which is necessary for these cards when - booting from the Flash ROM, define -DCFG_3C90X_BOOTROM_FIX when building. + booting from the Flash ROM, define -DCFG_3C90X_BOOTROM_FIX when building, + create a floppy image and boot it once. + Thereafter, the card should accept the larger prom image. The driver should choose an appropriate transceiver on the card. However, if it doesn't on your card or if you need to, for instance, set your @@ -276,3 +284,24 @@ IV FOR DEVELOPERS.... number. Another driver used 't' (for 'three'?); I chose 'a' for no reason at all. +Addendum by Jorge L. deLyra , 22Nov2000 re +working around the 3C905 hardware bug mentioned above: + +Use this floppy to fix any 3COM model 3C905B PCI 10/100 Ethernet cards +that fail to load and run the boot program the first time around. If +they have a "Lucent" rather than a "Broadcom" chipset these cards have +a configuration bug that causes a hang when trying to load the boot +program from the PROM, if you try to use them right out of the box. + +The boot program in this floppy is the file named 3c905b-tpo100.rom +from Etherboot version 4.6.10, compiled with the bugfix parameter + + CFG_3C90X_BOOTROM_FIX + +You have to take the chip off the card and boot the system once using +this floppy. Once loaded from the floppy, the boot program will access +the card and change some setting in it, correcting the problem. After +that you may use either this boot program or the normal one, compiled +without this bugfix parameter, to boot the machine from the PROM chip. + +[Any recent Etherboot version should do, not just 4.6.10 - Ed.] diff --git a/netboot/Makefile.am b/netboot/Makefile.am index a0bc84432..0855bb4ad 100644 --- a/netboot/Makefile.am +++ b/netboot/Makefile.am @@ -12,53 +12,52 @@ noinst_LIBRARIES = $(LIBDRIVERS) libdrivers_a_SOURCES = cards.h config.c etherboot.h \ fsys_tftp.c linux-asm-io.h linux-asm-string.h \ - main.c misc.c nic.h osdep.h pci.c pci.h + main.c misc.c nic.h osdep.h pci.c pci.h timer.c timer.h EXTRA_libdrivers_a_SOURCES = 3c509.c 3c509.h 3c595.c 3c595.h 3c90x.c \ - cs89x0.c cs89x0.h depca.c eepro100.c epic100.c epic100.h \ - i82586.c lance.c ns8390.c ns8390.h otulip.c otulip.h rtl8139.c \ - sk_g16.c sk_g16.h smc9000.c smc9000.h tiara.c tulip.c \ - via-rhine.c + cs89x0.c cs89x0.h davicom.c depca.c eepro.c eepro100.c \ + epic100.c epic100.h fa311.c i82586.c lance.c natsemi.c \ + ni5010.c ns8390.c ns8390.h otulip.c otulip.h rtl8139.c \ + sis900.c sis900.h sk_g16.c sk_g16.h smc9000.c smc9000.h \ + tiara.c tlan.c tulip.c via-rhine.c w89c840.c libdrivers_a_CFLAGS = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ -DFSYS_TFTP=1 $(NET_CFLAGS) $(NET_EXTRAFLAGS) # Filled by configure. libdrivers_a_LIBADD = @NETBOOT_DRIVERS@ libdrivers_a_DEPENDENCIES = $(libdrivers_a_LIBADD) -EXTRA_DIST = README.netboot 3c90x.txt cs89x0.txt tulip.txt +EXTRA_DIST = README.netboot 3c90x.txt cs89x0.txt sis900.txt tulip.txt # These below are several special rules for the device drivers. # We cannot use a simple rule for them... # What objects are derived from a driver? 3c509_drivers = 3c509.o 3c529.o -3c595_drivers = 3c590.o 3c595.o +3c595_drivers = 3c595.o 3c90x_drivers = 3c90x.o cs89x0_drivers = cs89x0.o +davicom_drivers = davicom.o depca_drivers = depca.o +eepro_drivers = eepro.o eepro100_drivers = eepro100.o epic100_drivers = epic100.o +#fa311_drivers = fa311.o i82586_drivers = 3c507.o exos205.o ni5210.o lance_drivers = lance.o ne2100.o ni6510.o +natsemi_drivers = natsemi.o +ni5010_drivers = ni5010.o ns8390_drivers = 3c503.o ne.o ns8390.o wd.o otulip_drivers = otulip.o rtl8139_drivers = rtl8139.o +sis900_drivers = sis900.o sk_g16_drivers = sk_g16.o smc9000_drivers = smc9000.o tiara_drivers = tiara.o +#tlan_drivers = tlan.o tulip_drivers = tulip.o via_rhine_drivers = via_rhine.o +w89c840_drivers = w89c840.o # Is it really necessary to specify dependecies explicitly? -$(ns8390_drivers): ns8390.c ns8390.h -$(ns8390_drivers): %.o: ns8390.c - $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ - $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< - -$(i82586_drivers): i82586.c -$(i82586_drivers): %.o: i82586.c - $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ - $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< - $(3c509_drivers): 3c509.c 3c509.h $(3c509_drivers): %.o: 3c509.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ @@ -79,11 +78,21 @@ $(cs89x0_drivers): %.o: cs89x0.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< +$(davicom_drivers): davicom.c +$(davicom_drivers): %.o: davicom.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + $(depca_drivers): depca.c $(depca_drivers): %.o: depca.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< +$(eepro_drivers): eepro.c +$(eepro_drivers): %.o: eepro.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + $(eepro100_drivers): eepro100.c $(eepro100_drivers): %.o: eepro100.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ @@ -94,13 +103,38 @@ $(epic100_drivers): %.o: epic100.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< +#$(fa311_drivers): fa311.c +#$(fa311_drivers): %.o: fa311.c +# $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ +# $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + +$(i82586_drivers): i82586.c +$(i82586_drivers): %.o: i82586.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + $(lance_drivers): lance.c $(lance_drivers): %.o: lance.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< -$(tulip_drivers): tulip.c -$(tulip_drivers): %.o: tulip.c +$(natsemi_drivers): natsemi.c +$(natsemi_drivers): %.o: natsemi.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + +$(ni5010_drivers): ni5010.c +$(ni5010_drivers): %.o: ni5010.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + +$(ns8390_drivers): ns8390.c ns8390.h +$(ns8390_drivers): %.o: ns8390.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + +$(otulip_drivers): otulip.c otulip.h +$(otulip_drivers): %.o: otulip.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< @@ -109,6 +143,11 @@ $(rtl8139_drivers): %.o: rtl8139.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< +$(sis900_drivers): sis900.c +$(sis900_drivers): %.o: sis900.c sis900.h + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + $(sk_g16_drivers): sk_g16.c sk_g16.h $(sk_g16_drivers): %.o: sk_g16.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ @@ -124,8 +163,13 @@ $(tiara_drivers): %.o: tiara.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< -$(otulip_drivers): otulip.c otulip.h -$(otulip_drivers): %.o: otulip.c +#$(tlan_drivers): tlan.c +#$(tlan_drivers): %.o: tlan.c +# $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ +# $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + +$(tulip_drivers): tulip.c +$(tulip_drivers): %.o: tulip.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< @@ -134,31 +178,42 @@ $(via_rhine_drivers): %.o: via-rhine.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< +$(w89c840_drivers): w89c840.c +$(w89c840_drivers): %.o: w89c840.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< # Per-object flags. 3c509_o_CFLAGS = -DINCLUDE_3C509=1 3c529_o_CFLAGS = -DINCLUDE_3C529=1 -3c590_o_CFLAGS = -DINCLUDE_3C590=1 3c595_o_CFLAGS = -DINCLUDE_3C595=1 3c90x_o_CFLAGS = -DINCLUDE_3C90X=1 cs89x0_o_CFLAGS = -DINCLUDE_CS89X0=1 +davicom_o_CFLAGS = -DINCLUDE_DAVICOM=1 depca_o_CFLAGS = -DINCLUDE_DEPCA=1 +eepro_o_CFLAGS = -DINCLUDE_EEPRO=1 eepro100_o_CFLAGS = -DINCLUDE_EEPRO100=1 epic100_o_CFLAGS = -DINCLUDE_EPIC100=1 +#fa311_o_CFLAGS = -DINCLUDE_FA311=1 3c507_o_CFLAGS = -DINCLUDE_3C507=1 exos205_o_CFLAGS = -DINCLUDE_EXOS205=1 ni5210_o_CFLAGS = -DINCLUDE_NI5210=1 lance_o_CFLAGS = -DINCLUDE_LANCE=1 ne2100_o_CFLAGS = -DINCLUDE_NE2100=1 ni6510_o_CFLAGS = -DINCLUDE_NI6510=1 +natsemi_o_CFLAGS = -DINCLUDE_NATSEMI=1 +ni5010_o_CFLAGS = -DINCLUDE_NI5010=1 3c503_o_CFLAGS = -DINCLUDE_3C503=1 ne_o_CFLAGS = -DINCLUDE_NE=1 ns8390_o_CFLAGS = -DINCLUDE_NS8390=1 wd_o_CFLAGS = -DINCLUDE_WD=1 otulip_o_CFLAGS = -DINCLUDE_OTULIP=1 rtl8139_o_CFLAGS = -DINCLUDE_RTL8139=1 +sis900_o_CFLAGS = -DINCLUDE_SIS900=1 sk_g16_o_CFLAGS = -DINCLUDE_SK_G16=1 smc9000_o_CFLAGS = -DINCLUDE_SMC9000=1 tiara_o_CFLAGS = -DINCLUDE_TIARA=1 +#tlan_o_CFLAGS = -DINCLUDE_TLAN=1 tulip_o_CFLAGS = -DINCLUDE_TULIP=1 via_rhine_o_CFLAGS = -DINCLUDE_VIA_RHINE=1 +w89c840_o_CFLAGS = -DINCLUDE_W89C840=1 diff --git a/netboot/Makefile.in b/netboot/Makefile.in index 5b73e3f98..4262ad3e1 100644 --- a/netboot/Makefile.in +++ b/netboot/Makefile.in @@ -98,13 +98,14 @@ noinst_LIBRARIES = $(LIBDRIVERS) libdrivers_a_SOURCES = cards.h config.c etherboot.h \ fsys_tftp.c linux-asm-io.h linux-asm-string.h \ - main.c misc.c nic.h osdep.h pci.c pci.h + main.c misc.c nic.h osdep.h pci.c pci.h timer.c timer.h EXTRA_libdrivers_a_SOURCES = 3c509.c 3c509.h 3c595.c 3c595.h 3c90x.c \ - cs89x0.c cs89x0.h depca.c eepro100.c epic100.c epic100.h \ - i82586.c lance.c ns8390.c ns8390.h otulip.c otulip.h rtl8139.c \ - sk_g16.c sk_g16.h smc9000.c smc9000.h tiara.c tulip.c \ - via-rhine.c + cs89x0.c cs89x0.h davicom.c depca.c eepro.c eepro100.c \ + epic100.c epic100.h fa311.c i82586.c lance.c natsemi.c \ + ni5010.c ns8390.c ns8390.h otulip.c otulip.h rtl8139.c \ + sis900.c sis900.h sk_g16.c sk_g16.h smc9000.c smc9000.h \ + tiara.c tlan.c tulip.c via-rhine.c w89c840.c libdrivers_a_CFLAGS = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ -DFSYS_TFTP=1 $(NET_CFLAGS) $(NET_EXTRAFLAGS) @@ -113,57 +114,72 @@ libdrivers_a_CFLAGS = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ libdrivers_a_LIBADD = @NETBOOT_DRIVERS@ libdrivers_a_DEPENDENCIES = $(libdrivers_a_LIBADD) -EXTRA_DIST = README.netboot 3c90x.txt cs89x0.txt tulip.txt +EXTRA_DIST = README.netboot 3c90x.txt cs89x0.txt sis900.txt tulip.txt # These below are several special rules for the device drivers. # We cannot use a simple rule for them... # What objects are derived from a driver? 3c509_drivers = 3c509.o 3c529.o -3c595_drivers = 3c590.o 3c595.o +3c595_drivers = 3c595.o 3c90x_drivers = 3c90x.o cs89x0_drivers = cs89x0.o +davicom_drivers = davicom.o depca_drivers = depca.o +eepro_drivers = eepro.o eepro100_drivers = eepro100.o epic100_drivers = epic100.o +#fa311_drivers = fa311.o i82586_drivers = 3c507.o exos205.o ni5210.o lance_drivers = lance.o ne2100.o ni6510.o +natsemi_drivers = natsemi.o +ni5010_drivers = ni5010.o ns8390_drivers = 3c503.o ne.o ns8390.o wd.o otulip_drivers = otulip.o rtl8139_drivers = rtl8139.o +sis900_drivers = sis900.o sk_g16_drivers = sk_g16.o smc9000_drivers = smc9000.o tiara_drivers = tiara.o +#tlan_drivers = tlan.o tulip_drivers = tulip.o via_rhine_drivers = via_rhine.o +w89c840_drivers = w89c840.o # Per-object flags. 3c509_o_CFLAGS = -DINCLUDE_3C509=1 3c529_o_CFLAGS = -DINCLUDE_3C529=1 -3c590_o_CFLAGS = -DINCLUDE_3C590=1 3c595_o_CFLAGS = -DINCLUDE_3C595=1 3c90x_o_CFLAGS = -DINCLUDE_3C90X=1 cs89x0_o_CFLAGS = -DINCLUDE_CS89X0=1 +davicom_o_CFLAGS = -DINCLUDE_DAVICOM=1 depca_o_CFLAGS = -DINCLUDE_DEPCA=1 +eepro_o_CFLAGS = -DINCLUDE_EEPRO=1 eepro100_o_CFLAGS = -DINCLUDE_EEPRO100=1 epic100_o_CFLAGS = -DINCLUDE_EPIC100=1 +#fa311_o_CFLAGS = -DINCLUDE_FA311=1 3c507_o_CFLAGS = -DINCLUDE_3C507=1 exos205_o_CFLAGS = -DINCLUDE_EXOS205=1 ni5210_o_CFLAGS = -DINCLUDE_NI5210=1 lance_o_CFLAGS = -DINCLUDE_LANCE=1 ne2100_o_CFLAGS = -DINCLUDE_NE2100=1 ni6510_o_CFLAGS = -DINCLUDE_NI6510=1 +natsemi_o_CFLAGS = -DINCLUDE_NATSEMI=1 +ni5010_o_CFLAGS = -DINCLUDE_NI5010=1 3c503_o_CFLAGS = -DINCLUDE_3C503=1 ne_o_CFLAGS = -DINCLUDE_NE=1 ns8390_o_CFLAGS = -DINCLUDE_NS8390=1 wd_o_CFLAGS = -DINCLUDE_WD=1 otulip_o_CFLAGS = -DINCLUDE_OTULIP=1 rtl8139_o_CFLAGS = -DINCLUDE_RTL8139=1 +sis900_o_CFLAGS = -DINCLUDE_SIS900=1 sk_g16_o_CFLAGS = -DINCLUDE_SK_G16=1 smc9000_o_CFLAGS = -DINCLUDE_SMC9000=1 tiara_o_CFLAGS = -DINCLUDE_TIARA=1 +#tlan_o_CFLAGS = -DINCLUDE_TLAN=1 tulip_o_CFLAGS = -DINCLUDE_TULIP=1 via_rhine_o_CFLAGS = -DINCLUDE_VIA_RHINE=1 +w89c840_o_CFLAGS = -DINCLUDE_W89C840=1 subdir = netboot mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h @@ -173,7 +189,8 @@ LIBRARIES = $(noinst_LIBRARIES) libdrivers_a_AR = $(AR) cru am_libdrivers_a_OBJECTS = libdrivers_a-config.$(OBJEXT) \ libdrivers_a-fsys_tftp.$(OBJEXT) libdrivers_a-main.$(OBJEXT) \ - libdrivers_a-misc.$(OBJEXT) libdrivers_a-pci.$(OBJEXT) + libdrivers_a-misc.$(OBJEXT) libdrivers_a-pci.$(OBJEXT) \ + libdrivers_a-timer.$(OBJEXT) libdrivers_a_OBJECTS = $(am_libdrivers_a_OBJECTS) DEFS = @DEFS@ @@ -187,23 +204,32 @@ depcomp = $(SHELL) $(top_srcdir)/depcomp @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-3c90x.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-config.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-cs89x0.Po \ +@AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-davicom.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-depca.Po \ +@AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-eepro.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-eepro100.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-epic100.Po \ +@AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-fa311.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-fsys_tftp.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-i82586.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-lance.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-main.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-misc.Po \ +@AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-natsemi.Po \ +@AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-ni5010.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-ns8390.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-otulip.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-pci.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-rtl8139.Po \ +@AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-sis900.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-sk_g16.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-smc9000.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-tiara.Po \ +@AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-timer.Po \ +@AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-tlan.Po \ @AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-tulip.Po \ -@AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-via-rhine.Po +@AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-via-rhine.Po \ +@AMDEP_TRUE@ $(DEPDIR)/libdrivers_a-w89c840.Po COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) @@ -234,23 +260,32 @@ libdrivers_a-fsys_tftp.$(OBJEXT): fsys_tftp.c libdrivers_a-main.$(OBJEXT): main.c libdrivers_a-misc.$(OBJEXT): misc.c libdrivers_a-pci.$(OBJEXT): pci.c +libdrivers_a-timer.$(OBJEXT): timer.c libdrivers_a-3c509.$(OBJEXT): 3c509.c libdrivers_a-3c595.$(OBJEXT): 3c595.c libdrivers_a-3c90x.$(OBJEXT): 3c90x.c libdrivers_a-cs89x0.$(OBJEXT): cs89x0.c +libdrivers_a-davicom.$(OBJEXT): davicom.c libdrivers_a-depca.$(OBJEXT): depca.c +libdrivers_a-eepro.$(OBJEXT): eepro.c libdrivers_a-eepro100.$(OBJEXT): eepro100.c libdrivers_a-epic100.$(OBJEXT): epic100.c +libdrivers_a-fa311.$(OBJEXT): fa311.c libdrivers_a-i82586.$(OBJEXT): i82586.c libdrivers_a-lance.$(OBJEXT): lance.c +libdrivers_a-natsemi.$(OBJEXT): natsemi.c +libdrivers_a-ni5010.$(OBJEXT): ni5010.c libdrivers_a-ns8390.$(OBJEXT): ns8390.c libdrivers_a-otulip.$(OBJEXT): otulip.c libdrivers_a-rtl8139.$(OBJEXT): rtl8139.c +libdrivers_a-sis900.$(OBJEXT): sis900.c libdrivers_a-sk_g16.$(OBJEXT): sk_g16.c libdrivers_a-smc9000.$(OBJEXT): smc9000.c libdrivers_a-tiara.$(OBJEXT): tiara.c +libdrivers_a-tlan.$(OBJEXT): tlan.c libdrivers_a-tulip.$(OBJEXT): tulip.c libdrivers_a-via-rhine.$(OBJEXT): via-rhine.c +libdrivers_a-w89c840.$(OBJEXT): w89c840.c libdrivers.a: $(libdrivers_a_OBJECTS) $(libdrivers_a_DEPENDENCIES) -rm -f libdrivers.a $(libdrivers_a_AR) libdrivers.a $(libdrivers_a_OBJECTS) $(libdrivers_a_LIBADD) @@ -267,23 +302,32 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-3c90x.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-cs89x0.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-davicom.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-depca.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-eepro.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-eepro100.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-epic100.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-fa311.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-fsys_tftp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-i82586.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-lance.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-misc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-natsemi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-ni5010.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-ns8390.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-otulip.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-pci.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-rtl8139.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-sis900.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-sk_g16.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-smc9000.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-tiara.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-timer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-tlan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-tulip.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-via-rhine.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libdrivers_a-w89c840.Po@am__quote@ distclean-depend: -rm -rf $(DEPDIR) @@ -360,6 +404,18 @@ libdrivers_a-pci.obj: pci.c @AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-pci.obj `cygpath -w pci.c` +libdrivers_a-timer.o: timer.c +@AMDEP_TRUE@ source='timer.c' object='libdrivers_a-timer.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-timer.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-timer.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-timer.o `test -f timer.c || echo '$(srcdir)/'`timer.c + +libdrivers_a-timer.obj: timer.c +@AMDEP_TRUE@ source='timer.c' object='libdrivers_a-timer.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-timer.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-timer.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-timer.obj `cygpath -w timer.c` + libdrivers_a-3c509.o: 3c509.c @AMDEP_TRUE@ source='3c509.c' object='libdrivers_a-3c509.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-3c509.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-3c509.TPo' @AMDEPBACKSLASH@ @@ -408,6 +464,18 @@ libdrivers_a-cs89x0.obj: cs89x0.c @AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-cs89x0.obj `cygpath -w cs89x0.c` +libdrivers_a-davicom.o: davicom.c +@AMDEP_TRUE@ source='davicom.c' object='libdrivers_a-davicom.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-davicom.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-davicom.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-davicom.o `test -f davicom.c || echo '$(srcdir)/'`davicom.c + +libdrivers_a-davicom.obj: davicom.c +@AMDEP_TRUE@ source='davicom.c' object='libdrivers_a-davicom.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-davicom.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-davicom.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-davicom.obj `cygpath -w davicom.c` + libdrivers_a-depca.o: depca.c @AMDEP_TRUE@ source='depca.c' object='libdrivers_a-depca.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-depca.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-depca.TPo' @AMDEPBACKSLASH@ @@ -420,6 +488,18 @@ libdrivers_a-depca.obj: depca.c @AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-depca.obj `cygpath -w depca.c` +libdrivers_a-eepro.o: eepro.c +@AMDEP_TRUE@ source='eepro.c' object='libdrivers_a-eepro.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-eepro.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-eepro.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-eepro.o `test -f eepro.c || echo '$(srcdir)/'`eepro.c + +libdrivers_a-eepro.obj: eepro.c +@AMDEP_TRUE@ source='eepro.c' object='libdrivers_a-eepro.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-eepro.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-eepro.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-eepro.obj `cygpath -w eepro.c` + libdrivers_a-eepro100.o: eepro100.c @AMDEP_TRUE@ source='eepro100.c' object='libdrivers_a-eepro100.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-eepro100.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-eepro100.TPo' @AMDEPBACKSLASH@ @@ -444,6 +524,18 @@ libdrivers_a-epic100.obj: epic100.c @AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-epic100.obj `cygpath -w epic100.c` +libdrivers_a-fa311.o: fa311.c +@AMDEP_TRUE@ source='fa311.c' object='libdrivers_a-fa311.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-fa311.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-fa311.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-fa311.o `test -f fa311.c || echo '$(srcdir)/'`fa311.c + +libdrivers_a-fa311.obj: fa311.c +@AMDEP_TRUE@ source='fa311.c' object='libdrivers_a-fa311.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-fa311.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-fa311.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-fa311.obj `cygpath -w fa311.c` + libdrivers_a-i82586.o: i82586.c @AMDEP_TRUE@ source='i82586.c' object='libdrivers_a-i82586.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-i82586.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-i82586.TPo' @AMDEPBACKSLASH@ @@ -468,6 +560,30 @@ libdrivers_a-lance.obj: lance.c @AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-lance.obj `cygpath -w lance.c` +libdrivers_a-natsemi.o: natsemi.c +@AMDEP_TRUE@ source='natsemi.c' object='libdrivers_a-natsemi.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-natsemi.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-natsemi.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-natsemi.o `test -f natsemi.c || echo '$(srcdir)/'`natsemi.c + +libdrivers_a-natsemi.obj: natsemi.c +@AMDEP_TRUE@ source='natsemi.c' object='libdrivers_a-natsemi.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-natsemi.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-natsemi.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-natsemi.obj `cygpath -w natsemi.c` + +libdrivers_a-ni5010.o: ni5010.c +@AMDEP_TRUE@ source='ni5010.c' object='libdrivers_a-ni5010.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-ni5010.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-ni5010.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-ni5010.o `test -f ni5010.c || echo '$(srcdir)/'`ni5010.c + +libdrivers_a-ni5010.obj: ni5010.c +@AMDEP_TRUE@ source='ni5010.c' object='libdrivers_a-ni5010.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-ni5010.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-ni5010.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-ni5010.obj `cygpath -w ni5010.c` + libdrivers_a-ns8390.o: ns8390.c @AMDEP_TRUE@ source='ns8390.c' object='libdrivers_a-ns8390.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-ns8390.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-ns8390.TPo' @AMDEPBACKSLASH@ @@ -504,6 +620,18 @@ libdrivers_a-rtl8139.obj: rtl8139.c @AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-rtl8139.obj `cygpath -w rtl8139.c` +libdrivers_a-sis900.o: sis900.c +@AMDEP_TRUE@ source='sis900.c' object='libdrivers_a-sis900.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-sis900.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-sis900.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-sis900.o `test -f sis900.c || echo '$(srcdir)/'`sis900.c + +libdrivers_a-sis900.obj: sis900.c +@AMDEP_TRUE@ source='sis900.c' object='libdrivers_a-sis900.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-sis900.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-sis900.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-sis900.obj `cygpath -w sis900.c` + libdrivers_a-sk_g16.o: sk_g16.c @AMDEP_TRUE@ source='sk_g16.c' object='libdrivers_a-sk_g16.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-sk_g16.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-sk_g16.TPo' @AMDEPBACKSLASH@ @@ -540,6 +668,18 @@ libdrivers_a-tiara.obj: tiara.c @AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-tiara.obj `cygpath -w tiara.c` +libdrivers_a-tlan.o: tlan.c +@AMDEP_TRUE@ source='tlan.c' object='libdrivers_a-tlan.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-tlan.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-tlan.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-tlan.o `test -f tlan.c || echo '$(srcdir)/'`tlan.c + +libdrivers_a-tlan.obj: tlan.c +@AMDEP_TRUE@ source='tlan.c' object='libdrivers_a-tlan.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-tlan.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-tlan.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-tlan.obj `cygpath -w tlan.c` + libdrivers_a-tulip.o: tulip.c @AMDEP_TRUE@ source='tulip.c' object='libdrivers_a-tulip.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-tulip.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-tulip.TPo' @AMDEPBACKSLASH@ @@ -563,6 +703,18 @@ libdrivers_a-via-rhine.obj: via-rhine.c @AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-via-rhine.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-via-rhine.TPo' @AMDEPBACKSLASH@ @AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-via-rhine.obj `cygpath -w via-rhine.c` + +libdrivers_a-w89c840.o: w89c840.c +@AMDEP_TRUE@ source='w89c840.c' object='libdrivers_a-w89c840.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-w89c840.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-w89c840.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-w89c840.o `test -f w89c840.c || echo '$(srcdir)/'`w89c840.c + +libdrivers_a-w89c840.obj: w89c840.c +@AMDEP_TRUE@ source='w89c840.c' object='libdrivers_a-w89c840.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/libdrivers_a-w89c840.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-w89c840.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-w89c840.obj `cygpath -w w89c840.c` CCDEPMODE = @CCDEPMODE@ uninstall-info-am: @@ -698,16 +850,6 @@ uninstall-am: uninstall-info-am # Is it really necessary to specify dependecies explicitly? -$(ns8390_drivers): ns8390.c ns8390.h -$(ns8390_drivers): %.o: ns8390.c - $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ - $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< - -$(i82586_drivers): i82586.c -$(i82586_drivers): %.o: i82586.c - $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ - $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< - $(3c509_drivers): 3c509.c 3c509.h $(3c509_drivers): %.o: 3c509.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ @@ -728,11 +870,21 @@ $(cs89x0_drivers): %.o: cs89x0.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< +$(davicom_drivers): davicom.c +$(davicom_drivers): %.o: davicom.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + $(depca_drivers): depca.c $(depca_drivers): %.o: depca.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< +$(eepro_drivers): eepro.c +$(eepro_drivers): %.o: eepro.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + $(eepro100_drivers): eepro100.c $(eepro100_drivers): %.o: eepro100.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ @@ -743,13 +895,38 @@ $(epic100_drivers): %.o: epic100.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< +#$(fa311_drivers): fa311.c +#$(fa311_drivers): %.o: fa311.c +# $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ +# $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + +$(i82586_drivers): i82586.c +$(i82586_drivers): %.o: i82586.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + $(lance_drivers): lance.c $(lance_drivers): %.o: lance.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< -$(tulip_drivers): tulip.c -$(tulip_drivers): %.o: tulip.c +$(natsemi_drivers): natsemi.c +$(natsemi_drivers): %.o: natsemi.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + +$(ni5010_drivers): ni5010.c +$(ni5010_drivers): %.o: ni5010.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + +$(ns8390_drivers): ns8390.c ns8390.h +$(ns8390_drivers): %.o: ns8390.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + +$(otulip_drivers): otulip.c otulip.h +$(otulip_drivers): %.o: otulip.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< @@ -758,6 +935,11 @@ $(rtl8139_drivers): %.o: rtl8139.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< +$(sis900_drivers): sis900.c +$(sis900_drivers): %.o: sis900.c sis900.h + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + $(sk_g16_drivers): sk_g16.c sk_g16.h $(sk_g16_drivers): %.o: sk_g16.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ @@ -773,8 +955,13 @@ $(tiara_drivers): %.o: tiara.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< -$(otulip_drivers): otulip.c otulip.h -$(otulip_drivers): %.o: otulip.c +#$(tlan_drivers): tlan.c +#$(tlan_drivers): %.o: tlan.c +# $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ +# $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + +$(tulip_drivers): tulip.c +$(tulip_drivers): %.o: tulip.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< @@ -782,6 +969,11 @@ $(via_rhine_drivers): via-rhine.c $(via_rhine_drivers): %.o: via-rhine.c $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< + +$(w89c840_drivers): w89c840.c +$(w89c840_drivers): %.o: w89c840.c + $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $< # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/netboot/README.netboot b/netboot/README.netboot index 380696b94..7edfaf02e 100644 --- a/netboot/README.netboot +++ b/netboot/README.netboot @@ -31,29 +31,13 @@ Caution: You should enable them as you need. Don't enable any unnecessary driver, because GRUB might crash if you include too many drivers at the same time. -3Com503, aka Etherlink II, also /16 model - --enable-3c503 - --enable-3c503-shmem - Use 3c503 shared memory mode. - --enable-3c503-aui - Use AUI by default on 3c503 cards. - -3Com507 - --enable-3c507 - 3Com509, ISA/EISA --enable-3c509 - --enable-3c509-hack - Send two bootp packets before waiting for a reply to the first. - Makes a 3c509 do bootp quicker. 3Com529 == MCA 3c509 --enable-3c529 -3Com590 - --enable-3c590 - -3Com595 +3Com59x and 3Com900 --enable-3c595 3Com90x @@ -67,29 +51,52 @@ Crystal Semiconductor CS89x0 a more aggressive probing algorithm. This might be neccessary after a soft-reset of the NIC. +Davicom DM9102 and 9009 + --enable-davicom + Digital DE100 and DE200 --enable-depca +Intel Etherexpress Pro/10 (ISA card) + --enable-eepro + Intel Etherexpress Pro/100 --enable-eepro100 SMC 83c170 EPIC/100 --enable-epic100 +3Com507 + --enable-3c507 + EXOS205 --enable-exos205 +Racal-Interlan NI5210 + --enable-ni5210 + Lance PCI PCNet/32 +AMD HomePNA --enable-lance -Linksys LNE100TX and other NICs using this Tulip clone chip -Netgear FA310TX and other NICs using this Tulip clone chip -Tulip clones based on the ADMtek Centaur-P -Tulip clones based on the Macronix 987x5 -Tulip-Fast -Tulip+ -Tulip 21142 - --enable-tulip +Novell NE2100 and NE1500 + --enable-ne2100 + +Racal-Interlan NI6510 + --enable-ni6510 + +National Semiconductor DP8381x (Netgear FA311 and FA312) + --enable-natsemi + +Racal-Interlan NI5010 + --enable-ni5010 + +3Com503, aka Etherlink II, also /16 model + --enable-3c503 + --enable-3c503-shmem + Use 3c503 shared memory mode. + --enable-3c503-aui + Use AUI by default on 3c503 cards. NE1000/2000 and clones (ISA) --enable-ne @@ -97,35 +104,34 @@ NE1000/2000 and clones (ISA) Probe for NE base address using LIST of comma separated hex addresses. -Novell NE2100 (Lance based, also works on NE1500) - --enable-ne2100 - NE2000 PCI clone (RTL8029) Winbond 86C940 Compex RL2000 KTI ET32P2 NetVin 5000SC +Holtek 80232 --enable-ns8390 --enable-compex-rl2000-fix If you have a Compex RL2000 PCI 32-bit (11F6:1401), and the probe hangs in "Probing...[NE*000/PCI]", try enabling this fix... it worked for me :). - --enable-ns8390-force-16bit - It seems that forcing 16 bit bus width for NEPCI causes - Etherboot/GRUB to fail on the RTL8029. Therefore - --enable-ns8390-force-16bit should only be turned on for those NEPCI - NICs that falsely detect 8 bit bus width when it should be 16. -Racal-Interlan NI5210 - --enable-ni5210 +WD8003/8013, SMC8216/8416 + --enable-wd + --enable-wd-default-mem=MEM (0xCC000) + Default memory location for WD/SMC cards. -Racal-Interlan NI6510 - --enable-ni6510 +Old base driver for Tulip clones + --enable-otulip Realtek 8139 SMC 1211 +D-Link DFE530TX+ and DFE538TX --enable-rtl8139 +SIS 900 and SIS 7016 + --enable-sis900 + Schneider and Koch G16 --enable-sk-g16 @@ -137,17 +143,25 @@ SMC9000 Tiara, Fujitsu Lancard --enable-tiara -Old base driver for Tulip clones - --enable-otulip +Linksys LNE100TX and other NICs using this Tulip clone chip +Netgear FA310TX and other NICs using this Tulip clone chip +Tulip clones based on the ADMtek Centaur-P +Tulip clones based on the Macronix 987x5 +Tulip-Fast +Tulip+ +Tulip 21142 +ASIX AX88140 +Intel Tulip +Compex RL100-TX + --enable-tulip Rhine-I, e.g. D-Link DFE-530TX Rhine-II --enable-via-rhine -WD8003/8013, SMC8216/8416 - --enable-wd - --enable-wd-default-mem=MEM (0xCC000) - Default memory location for WD/SMC cards. +Winbond W89c840 +Compex RL100-ATX + --enable-w89c840 The description about how to use the support can be found in the GRUB diff --git a/netboot/cards.h b/netboot/cards.h index ae7116971..cf37050c8 100644 --- a/netboot/cards.h +++ b/netboot/cards.h @@ -65,6 +65,11 @@ extern struct nic *a3c90x_probe(struct nic *, unsigned short * PCI_ARG(struct pci_device *)); #endif +#ifdef INCLUDE_EEPRO +extern struct nic *eepro_probe(struct nic *, unsigned short * + PCI_ARG(struct pci_device *)); +#endif + #ifdef INCLUDE_EEPRO100 extern struct nic *eepro100_probe(struct nic *, unsigned short * PCI_ARG(struct pci_device *)); @@ -85,6 +90,11 @@ extern struct nic *tulip_probe(struct nic *, unsigned short * PCI_ARG(struct pci_device *)); #endif +#ifdef INCLUDE_DAVICOM +extern struct nic *davicom_probe(struct nic *, unsigned short * + PCI_ARG(struct pci_device *)); +#endif + #ifdef INCLUDE_CS89X0 extern struct nic *cs89x0_probe(struct nic *, unsigned short * PCI_ARG(struct pci_device *)); @@ -115,6 +125,11 @@ extern struct nic *t507_probe(struct nic *, unsigned short * PCI_ARG(struct pci_device *)); #endif +#ifdef INCLUDE_NI5010 +extern struct nic *ni5010_probe(struct nic *, unsigned short * + PCI_ARG(struct pci_device *)); +#endif + #ifdef INCLUDE_NI5210 extern struct nic *ni5210_probe(struct nic *, unsigned short * PCI_ARG(struct pci_device *)); @@ -145,4 +160,24 @@ extern struct nic *rtl8139_probe(struct nic *, unsigned short * PCI_ARG(struct pci_device *)); #endif +#ifdef INCLUDE_W89C840 +extern struct nic *w89c840_probe(struct nic *, unsigned short * + PCI_ARG(struct pci_device *)); +#endif + +#ifdef INCLUDE_SIS900 +extern struct nic *sis900_probe(struct nic *, unsigned short * + PCI_ARG(struct pci_device *)); +#endif + +#ifdef INCLUDE_NATSEMI +extern struct nic *natsemi_probe(struct nic *, unsigned short * + PCI_ARG(struct pci_device *)); +#endif + +#ifdef INCLUDE_TLAN +extern struct nic *tlan_probe(struct nic *, unsigned short * + PCI_ARG(struct pci_device *)); +#endif + #endif /* CARDS_H */ diff --git a/netboot/config.c b/netboot/config.c index 14d922254..f07f548a8 100644 --- a/netboot/config.c +++ b/netboot/config.c @@ -17,7 +17,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* Based on "src/config.c" in etherboot-4.6.4. */ +/* Based on "src/config.c" in etherboot-5.0.5. */ /* * This program is free software; you can redistribute it and/or @@ -26,131 +26,206 @@ * your option) any later version. */ -#include "etherboot.h" -#include "nic.h" +#define GRUB 1 +#include +#include #undef INCLUDE_PCI -#if defined(INCLUDE_NS8390) || defined(INCLUDE_EEPRO100) || defined(INCLUDE_LANCE) || defined(INCLUDE_EPIC100) || defined(INCLUDE_TULIP) || defined(INCLUDE_OTULIP) || defined(INCLUDE_3C90X) || defined(INCLUDE_3C595) || defined(INCLUDE_RTL8139) || defined(INCLUDE_VIA_RHINE) +#if defined(INCLUDE_NS8390) || defined(INCLUDE_EEPRO100) || defined(INCLUDE_LANCE) || defined(INCLUDE_EPIC100) || defined(INCLUDE_TULIP) || defined(INCLUDE_OTULIP) || defined(INCLUDE_3C90X) || defined(INCLUDE_3C595) || defined(INCLUDE_RTL8139) || defined(INCLUDE_VIA_RHINE) || defined(INCLUDE_W89C840) || defined(INCLUDE_DAVICOM) || defined(INCLUDE_SIS900) || defined(INCLUDE_NATSEMI) || defined(INCLUDE_TLAN) /* || others later */ -#if defined(ETHERBOOT32) /* only for 32 bit machines */ -#define INCLUDE_PCI -#include "pci.h" -static unsigned short pci_ioaddrs[16]; +# define INCLUDE_PCI +# include +static unsigned short pci_ioaddrs[16]; -static struct pci_device pci_nic_list[] = { +static struct pci_device pci_nic_list[] = +{ #ifdef INCLUDE_NS8390 - { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029, - "Realtek 8029", 0, 0, 0}, - { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940, - "Winbond NE2000-PCI", 0, 0, 0}, - { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000, - "Compex ReadyLink 2000", 0, 0, 0}, - { PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2, - "KTI ET32P2", 0, 0, 0}, - { PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC, - "NetVin NV5000SC", 0, 0, 0}, + { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029, + "Realtek 8029", 0, 0, 0, 0}, + { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940, + "Winbond NE2000-PCI", 0, 0, 0, 0}, + { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000, + "Compex ReadyLink 2000", 0, 0, 0, 0}, + { PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2, + "KTI ET32P2", 0, 0, 0, 0}, + { PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC, + "NetVin NV5000SC", 0, 0, 0, 0}, + { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_HT80232, + "Holtek HT80232", 0, 0, 0, 0}, #endif #ifdef INCLUDE_3C90X - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900TPO, - "3Com900-TPO", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900COMBO, - "3Com900-Combo", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905TX, - "3Com905-TX", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905T4, - "3Com905-T4", 0, 0, 0}, - - { PCI_VENDOR_ID_3COM, 0x9004, - "3Com900B-TPO", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, 0x9005, - "3Com900B-Combo", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, 0x9006, - "3Com900B-2/T", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, 0x900A, - "3Com900B-FL", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905B_TX, - "3Com905B-TX", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, 0x9056, - "3Com905B-T4", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, 0x905A, - "3Com905B-FL", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905C_TXM, - "3Com905C-TXM", 0, 0, 0}, - + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900TPO, + "3Com900-TPO", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900COMBO, + "3Com900-Combo", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905TX, + "3Com905-TX", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905T4, + "3Com905-T4", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x9004, + "3Com900B-TPO", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x9005, + "3Com900B-Combo", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x9006, + "3Com900B-2/T", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x900A, + "3Com900B-FL", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905B_TX, + "3Com905B-TX", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x9056, + "3Com905B-T4", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x905A, + "3Com905B-FL", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905C_TXM, + "3Com905C-TXM", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x9800, + "3Com980-Cyclone", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x9805, + "3Com9805", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x7646, + "3CSOHO100-TX", 0, 0, 0, 0}, #endif #ifdef INCLUDE_3C595 - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C590, - "3Com590", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595, - "3Com595", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595_1, - "3Com595", 0, 0, 0}, - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595_2, - "3Com595", 0, 0, 0}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C590, + "3Com590", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595, + "3Com595", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595_1, + "3Com595", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595_2, + "3Com595", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900TPO, + "3Com900-TPO", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900COMBO, + "3Com900-Combo", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x9004, + "3Com900B-TPO", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x9005, + "3Com900B-Combo", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x9006, + "3Com900B-2/T", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x900A, + "3Com900B-FL", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x9800, + "3Com980-Cyclone", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x9805, + "3Com9805", 0, 0, 0, 0}, + { PCI_VENDOR_ID_3COM, 0x7646, + "3CSOHO100-TX", 0, 0, 0, 0}, #endif #ifdef INCLUDE_EEPRO100 - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557, - "Intel EtherExpressPro100", 0, 0, 0}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557, + "Intel EtherExpressPro100", 0, 0, 0, 0}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER, + "Intel EtherExpressPro100 82559ER", 0, 0, 0, 0}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029, + "Intel EtherExpressPro100 ID1029", 0, 0, 0, 0}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030, + "Intel Corporation 82559 InBusiness 10/100", 0, 0, 0, 0}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82562, + "Intel EtherExpressPro100 82562EM", 0, 0, 0, 0}, #endif #ifdef INCLUDE_EPIC100 - { PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_EPIC100, - "SMC EtherPowerII", 0, 0, 0}, + { PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_EPIC100, + "SMC EtherPowerII", 0, 0, 0, 0}, #endif #ifdef INCLUDE_LANCE - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, - "AMD Lance/PCI", 0, 0, 0}, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, + "AMD Lance/PCI", 0, 0, 0, 0}, + { PCI_VENDOR_ID_AMD_HOMEPNA, PCI_DEVICE_ID_AMD_HOMEPNA, + "AMD Lance/HomePNA", 0, 0, 0, 0}, #endif #ifdef INCLUDE_RTL8139 - { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139, - "Realtek 8139", 0, 0, 0}, - { PCI_VENDOR_ID_SMC_1211, PCI_DEVICE_ID_SMC_1211, - "SMC EZ10/100", 0, 0, 0}, + { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139, + "Realtek 8139", 0, 0, 0, 0}, + { PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DFE530TXP, + "DFE530TX+/DFE538TX", 0, 0, 0, 0}, + { PCI_VENDOR_ID_SMC_1211, PCI_DEVICE_ID_SMC_1211, + "SMC EZ10/100", 0, 0, 0, 0}, #endif #ifdef INCLUDE_OTULIP - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP, - "Digital Tulip", 0, 0, 0}, - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, - "Digital Tulip Fast", 0, 0, 0}, - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, - "Digital Tulip+", 0, 0, 0}, - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, - "Digital Tulip 21142", 0, 0, 0}, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP, + "Digital Tulip", 0, 0, 0, 0}, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, + "Digital Tulip Fast", 0, 0, 0, 0}, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, + "Digital Tulip+", 0, 0, 0, 0}, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, + "Digital Tulip 21142", 0, 0, 0, 0}, #endif #ifdef INCLUDE_TULIP - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP, - "Digital Tulip", 0, 0, 0}, - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, - "Digital Tulip Fast", 0, 0, 0}, - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, - "Digital Tulip+", 0, 0, 0}, - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, - "Digital Tulip 21142", 0, 0, 0}, - { PCI_VENDOR_ID_MACRONIX, PCI_DEVICE_ID_MX987x5, - "Macronix MX987x5", 0, 0, 0}, - { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LC82C115, - "LinkSys LNE100TX", 0, 0, 0}, - { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_DEC_TULIP, - "Netgear FA310TX", 0, 0, 0}, - { PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9102, - "Davicom 9102", 0, 0, 0}, - { PCI_VENDOR_ID_ADMTEK, PCI_DEVICE_ID_ADMTEK_0985, - "ADMtek Centaur-P", 0, 0, 0}, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP, + "Digital Tulip", 0, 0, 0, 0}, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, + "Digital Tulip Fast", 0, 0, 0, 0}, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, + "Digital Tulip+", 0, 0, 0, 0}, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, + "Digital Tulip 21142", 0, 0, 0, 0}, + { PCI_VENDOR_ID_MACRONIX, PCI_DEVICE_ID_MX987x5, + "Macronix MX987x5", 0, 0, 0, 0}, + { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LC82C115, + "LinkSys LNE100TX", 0, 0, 0, 0}, + { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_DEC_TULIP, + "Netgear FA310TX", 0, 0, 0, 0}, + { PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9102, + "Davicom 9102", 0, 0, 0, 0}, + { PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9009, + "Davicom 9009", 0, 0, 0, 0}, + { PCI_VENDOR_ID_ADMTEK, PCI_DEVICE_ID_ADMTEK_0985, + "ADMtek Centaur-P", 0, 0, 0, 0}, + { PCI_VENDOR_ID_ADMTEK, 0x0981, + "ADMtek AN981 Comet", 0, 0, 0, 0}, + { 0x125B, 0x1400, + "ASIX AX88140", 0, 0, 0, 0 }, + { 0x11F6, 0x9881, + "Compex RL100-TX", 0, 0, 0, 0 }, +#endif +#ifdef INCLUDE_DAVICOM + { PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9102, + "Davicom 9102", 0, 0, 0, 0}, + { PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9009, + "Davicom 9009", 0, 0, 0, 0}, #endif #ifdef INCLUDE_VIA_RHINE - { PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_RHINE_I, - "VIA 3043", 0, 0, 0}, - { PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_86C100A, - "VIA 86C100A", 0, 0, 0}, + { PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_VT6102, + "VIA 6102", 0, 0, 0, 0}, + { PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_RHINE_I, + "VIA 3043", 0, 0, 0, 0}, + { PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_86C100A, + "VIA 86C100A", 0, 0, 0, 0}, #endif -/* other PCI NICs go here */ - {0, 0, NULL, 0, 0, 0} +#ifdef INCLUDE_W89C840 + { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C840, + "Winbond W89C840F", 0, 0, 0, 0}, + { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL100ATX, + "Compex RL100ATX", 0, 0, 0, 0}, +#endif +#ifdef INCLUDE_SIS900 + { PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900, + "SIS900", 0, 0, 0, 0}, + { PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016, + "SIS7016", 0, 0, 0, 0}, +#endif + +#ifdef INCLUDE_NATSEMI + { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_DP83815, + "DP83815", 0, 0, 0, 0}, +#endif + +#ifdef INCLUDE_TLAN + { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2326, + "OC2326", 0, 0, 0, 0}, +#endif + + /* other PCI NICs go here */ + {0, 0, NULL, 0, 0, 0, 0} }; -#endif /* ETHERBOOT32 */ #endif /* INCLUDE_*PCI */ -#include "cards.h" +#include -#if defined(GRUB) && defined(INCLUDE_PCI) +#ifdef INCLUDE_PCI struct pci_dispatch_table { unsigned short vendor; @@ -167,6 +242,7 @@ static struct pci_dispatch_table PCI_NIC[] = { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000, nepci_probe }, { PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2, nepci_probe }, { PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC, nepci_probe }, + { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_HT80232, nepci_probe }, # endif /* INCLUDE_NS8390 */ # ifdef INCLUDE_3C90X { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900TPO, a3c90x_probe }, @@ -181,24 +257,42 @@ static struct pci_dispatch_table PCI_NIC[] = { PCI_VENDOR_ID_3COM, 0x9056, a3c90x_probe }, { PCI_VENDOR_ID_3COM, 0x905A, a3c90x_probe }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905C_TXM, a3c90x_probe }, + { PCI_VENDOR_ID_3COM, 0x9800, a3c90x_probe }, + { PCI_VENDOR_ID_3COM, 0x9805, a3c90x_probe }, + { PCI_VENDOR_ID_3COM, 0x7646, a3c90x_probe }, # endif /* INCLUDE_3C90X */ # ifdef INCLUDE_3C595 { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C590, t595_probe }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595, t595_probe }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595_1, t595_probe }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595_2, t595_probe }, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900TPO, t595_probe }, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900COMBO, t595_probe }, + { PCI_VENDOR_ID_3COM, 0x9004, t595_probe }, + { PCI_VENDOR_ID_3COM, 0x9005, t595_probe }, + { PCI_VENDOR_ID_3COM, 0x9006, t595_probe }, + { PCI_VENDOR_ID_3COM, 0x900A, t595_probe }, + { PCI_VENDOR_ID_3COM, 0x9800, t595_probe }, + { PCI_VENDOR_ID_3COM, 0x9805, t595_probe }, + { PCI_VENDOR_ID_3COM, 0x7646, t595_probe }, # endif /* INCLUDE_3C595 */ # ifdef INCLUDE_EEPRO100 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557, eepro100_probe }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER, eepro100_probe }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029, eepro100_probe }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030, eepro100_probe }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82562, eepro100_probe }, # endif /* INCLUDE_EEPRO100 */ # ifdef INCLUDE_EPIC100 { PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_EPIC100, epic100_probe }, # endif /* INCLUDE_EPIC100 */ # ifdef INCLUDE_LANCE { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, lancepci_probe }, + { PCI_VENDOR_ID_AMD_HOMEPNA, PCI_DEVICE_ID_AMD_HOMEPNA, lancepci_probe }, # endif /* INCLUDE_LANCE */ # ifdef INCLUDE_RTL8139 { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139, rtl8139_probe }, + { PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DFE530TXP, rtl8139_probe }, { PCI_VENDOR_ID_SMC_1211, PCI_DEVICE_ID_SMC_1211, rtl8139_probe }, # endif /* INCLUDE_RTL8139 */ # ifdef INCLUDE_OTULIP @@ -216,26 +310,49 @@ static struct pci_dispatch_table PCI_NIC[] = { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LC82C115, tulip_probe }, { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_DEC_TULIP, tulip_probe }, { PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9102, tulip_probe }, + { PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9009, tulip_probe }, { PCI_VENDOR_ID_ADMTEK, PCI_DEVICE_ID_ADMTEK_0985, tulip_probe }, + { PCI_VENDOR_ID_ADMTEK, 0x0981, tulip_probe }, + { 0x125B, 0x1400, tulip_probe }, + { 0x11F6, 0x9881, tulip_probe }, # endif /* INCLUDE_TULIP */ +# ifdef INCLUDE_DAVICOM + { PC_VENDOR_ID_DAVICOM, PC_DEVICE_ID_DM9102, davicom_probe }, + { PC_VENDOR_ID_DAVICOM, PC_DEVICE_ID_DM9009, davicom_probe }, +# endif /* INCLUDE_DAVICOM */ # ifdef INCLUDE_VIA_RHINE + { PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_VT6102, rhine_probe }, { PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_RHINE_I, rhine_probe }, { PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_86C100A, rhine_probe }, # endif /* INCLUDE_VIA_RHINE */ +# ifdef INCLUDE_W89C840 + { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C840, w89c840_probe }, + { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL100ATX, w89c840_probe }, +# endif /* INCLUDE_W89C840 */ +# ifdef INCLUDE_SIS900 + { PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900, sis900_probe }, + { PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016, sis900_probe }, +# endif /* INCLUDE_SIS900 */ +# ifdef INCLUDE_NATSEMI + { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_DP83815, natsemi_probe }, +# endif /* INCLUDE_NATSEMI */ +# ifdef INCLUDE_TLAN + { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2326, tlan_probe }, +# endif /* INCLUDE_TLAN */ { 0, 0, 0 } }; #endif /* GRUB && INCLUDE_PCI */ struct dispatch_table { - const char *nic_name; + const char *nic_name; #ifdef INCLUDE_PCI - struct nic *(*eth_probe)(struct nic *, unsigned short *, - struct pci_device *); + struct nic *(*eth_probe) (struct nic *, unsigned short *, + struct pci_device *); #else - struct nic *(*eth_probe)(struct nic *, unsigned short *); + struct nic *(*eth_probe) (struct nic *, unsigned short *); #endif /* INCLUDE_PCI */ - unsigned short *probe_ioaddrs; /* for probe overrides */ + unsigned short *probe_ioaddrs; /* for probe overrides */ }; /* @@ -246,233 +363,236 @@ struct dispatch_table static struct dispatch_table NIC[] = { #ifdef INCLUDE_RTL8139 - { "RTL8139", rtl8139_probe, pci_ioaddrs }, + { "RTL8139", rtl8139_probe, pci_ioaddrs }, +#endif +#ifdef INCLUDE_SIS900 + { "SIS900", sis900_probe, pci_ioaddrs }, +#endif +#ifdef INCLUDE_NATSEMI + { "NATSEMI", natsemi_probe, pci_ioaddrs }, #endif #ifdef INCLUDE_WD - { "WD", wd_probe, 0 }, + { "WD", wd_probe, 0 }, #endif #ifdef INCLUDE_3C503 - { "3C503", t503_probe, 0 }, + { "3C503", t503_probe, 0 }, #endif #ifdef INCLUDE_NE - { "NE*000", ne_probe, 0 }, + { "NE*000", ne_probe, 0 }, #endif #ifdef INCLUDE_3C509 - { "3C5x9", t509_probe, 0 }, + { "3C5x9", t509_probe, 0 }, #endif #ifdef INCLUDE_3C529 - { "3C5x9", t529_probe, 0 }, + { "3C5x9", t529_probe, 0 }, #endif #ifdef INCLUDE_3C595 - { "3C595", t595_probe, pci_ioaddrs }, + { "3C595", t595_probe, pci_ioaddrs }, #endif #ifdef INCLUDE_3C90X - { "3C90X", a3c90x_probe, pci_ioaddrs }, + { "3C90X", a3c90x_probe, pci_ioaddrs }, +#endif +#ifdef INCLUDE_EEPRO + { "EEPRO", eepro_probe, 0 }, #endif #ifdef INCLUDE_EEPRO100 - { "EEPRO100", eepro100_probe, pci_ioaddrs }, + { "EEPRO100", eepro100_probe, pci_ioaddrs }, #endif #ifdef INCLUDE_EPIC100 - { "EPIC100", epic100_probe, pci_ioaddrs }, + { "EPIC100", epic100_probe, pci_ioaddrs }, #endif #ifdef INCLUDE_OTULIP - { "OTulip", otulip_probe, pci_ioaddrs }, + { "OTulip", otulip_probe, pci_ioaddrs }, #endif #ifdef INCLUDE_TULIP - { "Tulip", tulip_probe, pci_ioaddrs }, + { "Tulip", tulip_probe, pci_ioaddrs }, +#endif +#ifdef INCLUDE_DAVICOM + { "DAVICOM", davicom_probe, pci_ioaddrs }, #endif #ifdef INCLUDE_CS89X0 - { "CS89x0", cs89x0_probe, 0 }, + { "CS89x0", cs89x0_probe, 0 }, #endif #ifdef INCLUDE_NE2100 - { "NE2100", ne2100_probe, 0 }, + { "NE2100", ne2100_probe, 0 }, #endif #ifdef INCLUDE_NI6510 - { "NI6510", ni6510_probe, 0 }, + { "NI6510", ni6510_probe, 0 }, #endif #ifdef INCLUDE_SK_G16 - { "SK_G16", SK_probe, 0 }, + { "SK_G16", SK_probe, 0 }, #endif #ifdef INCLUDE_3C507 - { "3C507", t507_probe, 0 }, + { "3C507", t507_probe, 0 }, +#endif +#ifdef INCLUDE_NI5010 + { "NI5010", ni5010_probe, 0 }, #endif #ifdef INCLUDE_NI5210 - { "NI5210", ni5210_probe, 0 }, + { "NI5210", ni5210_probe, 0 }, #endif #ifdef INCLUDE_EXOS205 - { "EXOS205", exos205_probe, 0 }, + { "EXOS205", exos205_probe, 0 }, #endif #ifdef INCLUDE_SMC9000 - { "SMC9000", smc9000_probe, 0 }, + { "SMC9000", smc9000_probe, 0 }, #endif #ifdef INCLUDE_TIARA - { "TIARA", tiara_probe, 0 }, + { "TIARA", tiara_probe, 0 }, #endif #ifdef INCLUDE_DEPCA - { "DEPCA", depca_probe, 0 }, + { "DEPCA", depca_probe, 0 }, #endif #ifdef INCLUDE_NS8390 - { "NE2000/PCI", nepci_probe, pci_ioaddrs }, + { "NE2000/PCI", nepci_probe, pci_ioaddrs }, #endif #ifdef INCLUDE_LANCE - { "LANCE/PCI", lancepci_probe, pci_ioaddrs }, + { "LANCE/PCI", lancepci_probe, pci_ioaddrs }, #endif #ifdef INCLUDE_VIA_RHINE - { "VIA 86C100", rhine_probe, pci_ioaddrs }, + { "VIA 86C100", rhine_probe, pci_ioaddrs }, #endif - /* this entry must always be last to mark the end of list */ - { 0, 0, 0 } +#ifdef INCLUDE_W89C840 + { "W89C840F", w89c840_probe, pci_ioaddrs }, +#endif +#ifdef INCLUDE_TLAN + { "Olicom 2326", tlan_probe, pci_ioaddrs }, +#endif + /* this entry must always be last to mark the end of list */ + { 0, 0, 0 } }; -#define NIC_TABLE_SIZE (sizeof(NIC)/sizeof(NIC[0])) +#define NIC_TABLE_SIZE (sizeof (NIC) / sizeof (NIC[0])) -static int eth_dummy(struct nic *nic) +static int +eth_dummy (struct nic *dummy) { - return (0); + return 0; } -static char packet[ETH_MAX_PACKET]; +static char packet[ETH_FRAME_LEN]; struct nic nic = { -#ifdef ETHERBOOT32 - (void (*)(struct nic *))eth_dummy, /* reset */ - eth_dummy, /* poll */ - (void (*)(struct nic *, const char *, - unsigned int, unsigned int, - const char *))eth_dummy, /* transmit */ - (void (*)(struct nic *))eth_dummy, /* disable */ -#endif -/* bcc has problems with complicated casts */ -#ifdef ETHERBOOT16 - eth_dummy, - eth_dummy, - eth_dummy, - eth_dummy, -#endif + (void (*) (struct nic *)) eth_dummy, /* reset */ + eth_dummy, /* poll */ + (void (*) (struct nic *, const char *, + unsigned int, unsigned int, + const char *)) eth_dummy, /* transmit */ + (void (*) (struct nic *)) eth_dummy, /* disable */ #ifdef T503_AUI - 1, /* aui */ + 1, /* aui */ #else - 0, /* no aui */ + 0, /* no aui */ #endif - arptable[ARP_CLIENT].node, /* node_addr */ - packet, /* packet */ - 0, /* packetlen */ - 0 /* priv_data */ + &rom, /* rom_info */ + arptable[ARP_CLIENT].node, /* node_addr */ + packet, /* packet */ + 0, /* packetlen */ + 0, /* priv_data */ }; -#ifndef GRUB -void print_config(void) +void +eth_reset (void) { - struct dispatch_table *t; - -#ifdef ETHERBOOT32 - printf("Etherboot/32 version " VERSION " (GPL) for "); -#endif -#ifdef ETHERBOOT16 - /* Must be all on line or bcc can't handle concatenation */ - printf("Etherboot/16 version " VERSION " (GPL) for "); -#endif - for (t = NIC; t->nic_name != 0; ++t) - printf("[%s]", t->nic_name); - putchar('\n'); -} -#endif /* ! GRUB */ - -void eth_reset(void) -{ - (*nic.reset)(&nic); + (*nic.reset) (&nic); } -int eth_probe(void) +int +eth_probe (void) { - struct pci_device *p; - struct dispatch_table *t; -#ifdef GRUB - static int probed = 0; -#endif /* GRUB */ + struct pci_device *p; + const struct dispatch_table *t; + static int probed = 0; -#ifdef GRUB - /* If already probed, don't try to probe it any longer. */ - if (probed) - return 1; - - /* Clear the ready flag. */ - network_ready = 0; - /* Clear the ARP table. */ - grub_memset ((char *) arptable, 0, - MAX_ARP * sizeof (struct arptable_t)); -#endif /* GRUB */ - - p = 0; + /* If already probed, don't try to probe it any longer. */ + if (probed) + return 1; + + /* Clear the ready flag. */ + network_ready = 0; + /* Clear the ARP table. */ + grub_memset ((char *) arptable, 0, + MAX_ARP * sizeof (struct arptable_t)); + + p = 0; + #ifdef INCLUDE_PCI - -# ifdef GRUB - /* In GRUB, the ROM info is initialized here. */ - rom = *((struct rom_info *) ROM_INFO_LOCATION); -# endif /* GRUB */ - - eth_pci_init(pci_nic_list); - pci_ioaddrs[0] = 0; - pci_ioaddrs[1] = 0; - /* at this point we have a list of possible PCI candidates - we just pick the first one with a non-zero ioaddr */ - for (p = pci_nic_list; p->vendor != 0; ++p) { - if (p->ioaddr != 0) { - pci_ioaddrs[0] = p->ioaddr; - break; - } - } -#endif - printf("Probing..."); - -#if defined(GRUB) && defined(INCLUDE_PCI) - if (p->vendor) - { - struct pci_dispatch_table *pt; - - for (pt = PCI_NIC; pt->eth_probe != 0; pt++) - if (p->vendor == pt->vendor && p->dev_id == pt->dev_id) - { - printf ("[%s]", p->name); - if ((pt->eth_probe) (&nic, pci_ioaddrs, p)) - { - probed = 1; - return 1; - } - } - } -#endif /* GRUB && INCLUDE_PCI */ - - for (t = NIC; t->nic_name != 0; ++t) + /* In GRUB, the ROM info is initialized here. */ + rom = *((struct rom_info *) ROM_INFO_LOCATION); + + eth_pci_init(pci_nic_list); + pci_ioaddrs[0] = 0; + pci_ioaddrs[1] = 0; + /* at this point we have a list of possible PCI candidates + we just pick the first one with a non-zero ioaddr */ + for (p = pci_nic_list; p->vendor != 0; ++p) + { + if (p->ioaddr != 0) { - printf("[%s]", t->nic_name); -#ifdef INCLUDE_PCI - if ((*t->eth_probe)(&nic, t->probe_ioaddrs, p)) { -#else - if ((*t->eth_probe)(&nic, t->probe_ioaddrs)) { -#endif /* INCLUDE_PCI */ -#ifdef GRUB - probed = 1; -#endif /* GRUB */ - return (1); - } + pci_ioaddrs[0] = p->ioaddr; + break; } - return (0); + } +#endif + + etherboot_printf("Probing..."); + +#ifdef INCLUDE_PCI + if (p->vendor) + { + struct pci_dispatch_table *pt; + + for (pt = PCI_NIC; pt->eth_probe != 0; pt++) + if (p->vendor == pt->vendor && p->dev_id == pt->dev_id) + { + etherboot_printf ("[%s]", p->name); + if ((pt->eth_probe) (&nic, pci_ioaddrs, p)) + { + probed = 1; + return 1; + } + } + } +#endif /* INCLUDE_PCI */ + + for (t = NIC; t->nic_name != 0; ++t) + { + etherboot_printf("[%s]", t->nic_name); +#ifdef INCLUDE_PCI + if ((*t->eth_probe) (&nic, t->probe_ioaddrs, p)) + { + probed = 1; + return 1; + } +#else + if ((*t->eth_probe) (&nic, t->probe_ioaddrs)) + { + probed = 1; + return 1; + } +#endif /* INCLUDE_PCI */ + } + + return 0; } -int eth_poll(void) +int +eth_poll (void) { - return ((*nic.poll)(&nic)); + return ((*nic.poll) (&nic)); } -void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p) +void +eth_transmit (const char *d, unsigned int t, unsigned int s, const void *p) { - (*nic.transmit)(&nic, d, t, s, p); - twiddle(); + (*nic.transmit) (&nic, d, t, s, p); + if (t == IP) + twiddle (); } -void eth_disable(void) +void +eth_disable (void) { - (*nic.disable)(&nic); + (*nic.disable) (&nic); } diff --git a/netboot/cs89x0.c b/netboot/cs89x0.c index 9a7cb8212..9f964811d 100644 --- a/netboot/cs89x0.c +++ b/netboot/cs89x0.c @@ -75,7 +75,6 @@ static unsigned short eth_cs_type; /* one of: CS8900, CS8920, CS8920M */ static unsigned short eth_auto_neg_cnf; static unsigned short eth_adapter_cnf; static unsigned short eth_linectl; -static unsigned char eth_vendor; /************************************************************************* CS89x0 - specific routines @@ -116,7 +115,7 @@ static int get_eeprom_data(int off, int len, unsigned short *buffer) int i; #ifdef EDEBUG - printf("\ncs: EEPROM data from %x for %x:",off,len); + printf("\ncs: EEPROM data from %hX for %hX:",off,len); #endif for (i = 0; i < len; i++) { if (wait_eeprom_ready() < 0) @@ -130,7 +129,7 @@ static int get_eeprom_data(int off, int len, unsigned short *buffer) #ifdef EDEBUG if (!(i%10)) printf("\ncs: "); - printf("%x ", buffer[i]); + printf("%hX ", buffer[i]); #endif } #ifdef EDEBUG @@ -235,7 +234,7 @@ static int detect_tp(void) /* send a test packet - return true if carrier bits are ok */ static int send_test_pkt(struct nic *nic) { - static char testpacket[] = { 0,0,0,0,0,0, 0,0,0,0,0,0, + static unsigned char testpacket[] = { 0,0,0,0,0,0, 0,0,0,0,0,0, 0, 46, /*A 46 in network order */ 0, 0, /*DSAP=0 & SSAP=0 fields */ 0xf3,0 /*Control (Test Req+P bit set)*/ }; @@ -243,11 +242,11 @@ static int send_test_pkt(struct nic *nic) writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_TX_ON); - memcpy(testpacket, nic->node_addr, ETHER_ADDR_SIZE); - memcpy(testpacket+ETHER_ADDR_SIZE, nic->node_addr, ETHER_ADDR_SIZE); + memcpy(testpacket, nic->node_addr, ETH_ALEN); + memcpy(testpacket+ETH_ALEN, nic->node_addr, ETH_ALEN); outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT); - outw(ETH_MIN_PACKET, eth_nic_base + TX_LEN_PORT); + outw(ETH_ZLEN, eth_nic_base + TX_LEN_PORT); /* Test to see if the chip has allocated memory for the packet */ for (tmo = currticks() + 2; @@ -257,7 +256,7 @@ static int send_test_pkt(struct nic *nic) /* Write the contents of the packet */ outsw(eth_nic_base + TX_FRAME_PORT, testpacket, - (ETH_MIN_PACKET+1)>>1); + (ETH_ZLEN+1)>>1); printf(" sending test packet "); /* wait a couple of timer ticks for packet to be received */ @@ -307,9 +306,6 @@ static void cs89x0_reset(struct nic *nic) int i; unsigned long reset_tmo; - if(eth_vendor!=VENDOR_CS89x0) - return; - writereg(PP_SelfCTL, readreg(PP_SelfCTL) | POWER_ON_RESET); /* wait for two ticks; that is 2*55ms */ @@ -337,7 +333,7 @@ static void cs89x0_reset(struct nic *nic) writereg(PP_BusCTL, 0); /* set the ethernet address */ - for (i=0; i < ETHER_ADDR_SIZE/2; i++) + for (i=0; i < ETH_ALEN/2; i++) writereg(PP_IA+i*2, nic->node_addr[i*2] | (nic->node_addr[i*2+1] << 8)); @@ -374,13 +370,10 @@ static void cs89x0_transmit( unsigned long tmo; int sr; - if(eth_vendor!=VENDOR_CS89x0) - return; - /* does this size have to be rounded??? please, somebody have a look in the specs */ - if ((sr = ((s + ETHER_HDR_SIZE + 1)&~1)) < ETH_MIN_PACKET) - sr = ETH_MIN_PACKET; + if ((sr = ((s + ETH_HLEN + 1)&~1)) < ETH_ZLEN) + sr = ETH_ZLEN; retry: /* initiate a transmit sequence */ @@ -396,12 +389,12 @@ retry: goto retry; } /* Write the contents of the packet */ - outsw(eth_nic_base + TX_FRAME_PORT, d, ETHER_ADDR_SIZE/2); + outsw(eth_nic_base + TX_FRAME_PORT, d, ETH_ALEN/2); outsw(eth_nic_base + TX_FRAME_PORT, nic->node_addr, - ETHER_ADDR_SIZE/2); + ETH_ALEN/2); outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT); outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2); - for (sr = sr/2 - (s+1)/2 - ETHER_ADDR_SIZE - 1; sr-- > 0; + for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr-- > 0; outw(0, eth_nic_base + TX_FRAME_PORT)); /* wait for transfer to succeed */ @@ -409,7 +402,7 @@ retry: (s = readreg(PP_TxEvent)&~0x1F) == 0 && currticks() < tmo;) /* nothing */ ; if ((s & TX_SEND_OK_BITS) != TX_OK) { - printf("\ntransmission error 0x%x\n", s); + printf("\ntransmission error %#hX\n", s); } return; @@ -423,9 +416,6 @@ static int cs89x0_poll(struct nic *nic) { int status; - if(eth_vendor!=VENDOR_CS89x0) - return 0; - status = readreg(PP_RxEvent); if ((status & RX_OK) == 0) @@ -441,6 +431,7 @@ static int cs89x0_poll(struct nic *nic) static void cs89x0_disable(struct nic *nic) { + cs89x0_reset(nic); } /************************************************************************** @@ -466,9 +457,7 @@ struct nic *cs89x0_probe(struct nic *nic, unsigned short *probe_addrs) unsigned short eeprom_buff[CHKSUM_LEN]; - for (eth_vendor = VENDOR_NONE, ioidx = 0; - eth_vendor == VENDOR_NONE && - (ioaddr=netcard_portlist[ioidx++]) != 0;) { + for (ioidx = 0; (ioaddr=netcard_portlist[ioidx++]) != 0; ) { /* if they give us an odd I/O address, then do ONE write to the address port, to get it back to address zero, where we expect to find the EISA signature word. */ @@ -488,7 +477,7 @@ struct nic *cs89x0_probe(struct nic *nic, unsigned short *probe_addrs) eth_cs_type = rev_type &~ REVISON_BITS; cs_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; - printf("\ncs: cs89%c0%s rev %c, base 0x%x", + printf("\ncs: cs89%c0%s rev %c, base %#hX", eth_cs_type==CS8900?'0':'2', eth_cs_type==CS8920M?"M":"", cs_revision, @@ -548,10 +537,10 @@ struct nic *cs89x0_probe(struct nic *nic, unsigned short *probe_addrs) eth_irq = i; } /* Retrieve and print the ethernet address. */ - for (i=0; inode_addr[i] = - ((unsigned char *)eeprom_buff)[i]), - i < ETHER_ADDR_SIZE-1 ? ":" : "\n"); } + for (i=0; inode_addr[i] = ((unsigned char *)eeprom_buff)[i]; + } + printf("%!\n", nic->node_addr); /* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */ @@ -583,9 +572,7 @@ struct nic *cs89x0_probe(struct nic *nic, unsigned short *probe_addrs) } /* Initialize the card for probing of the attached media */ - eth_vendor = VENDOR_CS89x0; cs89x0_reset(nic); - eth_vendor = VENDOR_NONE; /* set the hardware to the configured choice */ switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) { @@ -652,14 +639,16 @@ struct nic *cs89x0_probe(struct nic *nic, unsigned short *probe_addrs) writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); - eth_vendor = VENDOR_CS89x0; + break; } + if (ioaddr == 0) + return (0); nic->reset = cs89x0_reset; nic->poll = cs89x0_poll; nic->transmit = cs89x0_transmit; nic->disable = cs89x0_disable; - return nic; + return (nic); } /* diff --git a/netboot/davicom.c b/netboot/davicom.c new file mode 100644 index 000000000..5a9865691 --- /dev/null +++ b/netboot/davicom.c @@ -0,0 +1,692 @@ +/* + DAVICOM DM9009/DM9102/DM9102A Etherboot Driver V1.00 + + This driver was ported from Marty Conner's Tulip Etherboot driver. + Thanks Marty Connor (mdc@thinguin.org) + You can get Tulip driver source file from this URL: + + "http://etherboot.sourceforge..net/#Distribution" + + This davicom etherboot driver supports DM9009/DM9102/DM9102A/ + DM9102A+DM9801/DM9102A+DM9802 NICs. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + +*/ + +/*********************************************************************/ +/* Revision History */ +/*********************************************************************/ + +/* + 19 OCT 2000 Sten 1.00 + Different half and full duplex mode + Do the different programming for DM9801/DM9802 + + 12 OCT 2000 Sten 0.90 + This driver was ported from tulip driver and it + has the following difference. + Changed symbol tulip/TULIP to davicom/DAVICOM + Deleted some code that did not use in this driver. + Used chain-strcture to replace ring structure + for both TX/RX descriptor. + Allocated two tx descriptor. + According current media mode to set operating + register(CR6) +*/ + + +/*********************************************************************/ +/* Declarations */ +/*********************************************************************/ + +#include "etherboot.h" +#include "nic.h" +#include "pci.h" +#include "cards.h" + +#undef DAVICOM_DEBUG +#undef DAVICOM_DEBUG_WHERE + +#define TX_TIME_OUT 2*TICKS_PER_SEC + +typedef unsigned char u8; +typedef signed char s8; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned int u32; +typedef signed int s32; + +/* Register offsets for davicom device */ +enum davicom_offsets { + CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, + CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, + CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x80, CSR20=0xA0 +}; + +/* EEPROM Address width definitions */ +#define EEPROM_ADDRLEN 6 +#define EEPROM_SIZE 32 /* 1 << EEPROM_ADDRLEN */ +/* Used to be 128, but we only need to read enough to get the MAC + address at bytes 20..25 */ + +/* Data Read from the EEPROM */ +static unsigned char ee_data[EEPROM_SIZE]; + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << addr_len) +#define EE_READ_CMD (6 << addr_len) +#define EE_ERASE_CMD (7 << addr_len) + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ +#define EE_CS 0x01 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ +#define EE_ENB (0x4800 | EE_CS) + +/* Sten 10/11 for phyxcer */ +#define PHY_DATA_0 0x0 +#define PHY_DATA_1 0x20000 +#define MDCLKH 0x10000 + +/* Delay between EEPROM clock transitions. Even at 33Mhz current PCI + implementations don't overrun the EEPROM clock. We add a bus + turn-around to insure that this remains true. */ +#define eeprom_delay() inl(ee_addr) + +/* helpful macro if on a big_endian machine for changing byte order. + not strictly needed on Intel */ +#define le16_to_cpu(val) (val) + +/* transmit and receive descriptor format */ +struct txdesc { + volatile unsigned long status; /* owner, status */ + unsigned long buf1sz:11, /* size of buffer 1 */ + buf2sz:11, /* size of buffer 2 */ + control:10; /* control bits */ + const unsigned char *buf1addr; /* buffer 1 address */ + const unsigned char *buf2addr; /* buffer 2 address */ +}; + +struct rxdesc { + volatile unsigned long status; /* owner, status */ + unsigned long buf1sz:11, /* size of buffer 1 */ + buf2sz:11, /* size of buffer 2 */ + control:10; /* control bits */ + unsigned char *buf1addr; /* buffer 1 address */ + unsigned char *buf2addr; /* buffer 2 address */ +}; + +/* Size of transmit and receive buffers */ +#define BUFLEN 1536 + +/*********************************************************************/ +/* Global Storage */ +/*********************************************************************/ + +/* PCI Bus parameters */ +static unsigned short vendor, dev_id; +static unsigned long ioaddr; + +/* Note: transmit and receive buffers must be longword aligned and + longword divisable */ + +/* transmit descriptor and buffer */ +#define NTXD 2 +static struct txdesc txd[NTXD] __attribute__ ((aligned(4))); +#ifdef USE_LOWMEM_BUFFER +#define txb ((char *)0x10000 - BUFLEN) +#else +static unsigned char txb[BUFLEN] __attribute__ ((aligned(4))); +#endif + +/* receive descriptor(s) and buffer(s) */ +#define NRXD 4 +static struct rxdesc rxd[NRXD] __attribute__ ((aligned(4))); +#ifdef USE_LOWMEM_BUFFER +#define rxb ((char *)0x10000 - NRXD * BUFLEN - BUFLEN) +#else +static unsigned char rxb[NRXD * BUFLEN] __attribute__ ((aligned(4))); +#endif +static int rxd_tail; +static int TxPtr; + + +/*********************************************************************/ +/* Function Prototypes */ +/*********************************************************************/ +static void whereami(const char *str); +static int read_eeprom(unsigned long ioaddr, int location, int addr_len); +struct nic *davicom_probe(struct nic *nic, unsigned short *io_addrs, + struct pci_device *pci); +static void davicom_init_chain(struct nic *nic); /* Sten 10/9 */ +static void davicom_reset(struct nic *nic); +static void davicom_transmit(struct nic *nic, const char *d, unsigned int t, + unsigned int s, const char *p); +static int davicom_poll(struct nic *nic); +static void davicom_disable(struct nic *nic); +static void whereami (const char *str); +#ifdef DAVICOM_DEBUG +static void davicom_more(void); +#endif /* DAVICOM_DEBUG */ +static void davicom_wait(unsigned int nticks); +static int phy_read(int); +static void phy_write(int, u16); +static void phy_write_1bit(u32, u32); +static int phy_read_1bit(u32); +static void davicom_media_chk(struct nic *); + + +/*********************************************************************/ +/* Utility Routines */ +/*********************************************************************/ + +static inline void whereami (const char *str) +{ +#ifdef DAVICOM_DEBUG_WHERE + printf("%s\n", str); + /* sleep(2); */ +#endif +} + +#ifdef DAVICOM_DEBUG +static void davicom_more() +{ + printf("\n\n-- more --"); + while (!iskey()) + /* wait */; + getchar(); + printf("\n\n"); +} +#endif /* DAVICOM_DEBUG */ + +static void davicom_wait(unsigned int nticks) +{ + unsigned int to = currticks() + nticks; + while (currticks() < to) + /* wait */ ; +} + + +/*********************************************************************/ +/* For DAVICOM phyxcer register by MII interface */ +/*********************************************************************/ +/* + Read a word data from phy register +*/ +static int phy_read(int location) +{ + int i, phy_addr=1; + u16 phy_data; + u32 io_dcr9; + + whereami("phy_read\n"); + + io_dcr9 = ioaddr + CSR9; + + /* Send 33 synchronization clock to Phy controller */ + for (i=0; i<34; i++) + phy_write_1bit(io_dcr9, PHY_DATA_1); + + /* Send start command(01) to Phy */ + phy_write_1bit(io_dcr9, PHY_DATA_0); + phy_write_1bit(io_dcr9, PHY_DATA_1); + + /* Send read command(10) to Phy */ + phy_write_1bit(io_dcr9, PHY_DATA_1); + phy_write_1bit(io_dcr9, PHY_DATA_0); + + /* Send Phy addres */ + for (i=0x10; i>0; i=i>>1) + phy_write_1bit(io_dcr9, phy_addr&i ? PHY_DATA_1: PHY_DATA_0); + + /* Send register addres */ + for (i=0x10; i>0; i=i>>1) + phy_write_1bit(io_dcr9, location&i ? PHY_DATA_1: PHY_DATA_0); + + /* Skip transition state */ + phy_read_1bit(io_dcr9); + + /* read 16bit data */ + for (phy_data=0, i=0; i<16; i++) { + phy_data<<=1; + phy_data|=phy_read_1bit(io_dcr9); + } + + return phy_data; +} + +/* + Write a word to Phy register +*/ +static void phy_write(int location, u16 phy_data) +{ + u16 i, phy_addr=1; + u32 io_dcr9; + + whereami("phy_write\n"); + + io_dcr9 = ioaddr + CSR9; + + /* Send 33 synchronization clock to Phy controller */ + for (i=0; i<34; i++) + phy_write_1bit(io_dcr9, PHY_DATA_1); + + /* Send start command(01) to Phy */ + phy_write_1bit(io_dcr9, PHY_DATA_0); + phy_write_1bit(io_dcr9, PHY_DATA_1); + + /* Send write command(01) to Phy */ + phy_write_1bit(io_dcr9, PHY_DATA_0); + phy_write_1bit(io_dcr9, PHY_DATA_1); + + /* Send Phy addres */ + for (i=0x10; i>0; i=i>>1) + phy_write_1bit(io_dcr9, phy_addr&i ? PHY_DATA_1: PHY_DATA_0); + + /* Send register addres */ + for (i=0x10; i>0; i=i>>1) + phy_write_1bit(io_dcr9, location&i ? PHY_DATA_1: PHY_DATA_0); + + /* written trasnition */ + phy_write_1bit(io_dcr9, PHY_DATA_1); + phy_write_1bit(io_dcr9, PHY_DATA_0); + + /* Write a word data to PHY controller */ + for (i=0x8000; i>0; i>>=1) + phy_write_1bit(io_dcr9, phy_data&i ? PHY_DATA_1: PHY_DATA_0); +} + +/* + Write one bit data to Phy Controller +*/ +static void phy_write_1bit(u32 ee_addr, u32 phy_data) +{ + whereami("phy_write_1bit\n"); + outl(phy_data, ee_addr); /* MII Clock Low */ + eeprom_delay(); + outl(phy_data|MDCLKH, ee_addr); /* MII Clock High */ + eeprom_delay(); + outl(phy_data, ee_addr); /* MII Clock Low */ + eeprom_delay(); +} + +/* + Read one bit phy data from PHY controller +*/ +static int phy_read_1bit(u32 ee_addr) +{ + int phy_data; + + whereami("phy_read_1bit\n"); + + outl(0x50000, ee_addr); + eeprom_delay(); + + phy_data=(inl(ee_addr)>>19) & 0x1; + + outl(0x40000, ee_addr); + eeprom_delay(); + + return phy_data; +} + +/* + DM9801/DM9802 present check and program +*/ +static void HPNA_process(void) +{ + + if ( (phy_read(3) & 0xfff0) == 0xb900 ) { + if ( phy_read(31) == 0x4404 ) { + /* DM9801 present */ + if (phy_read(3) == 0xb901) + phy_write(16, 0x5); /* DM9801 E4 */ + else + phy_write(16, 0x1005); /* DM9801 E3 and others */ + phy_write(25, ((phy_read(24) + 3) & 0xff) | 0xf000); + } else { + /* DM9802 present */ + phy_write(16, 0x5); + phy_write(25, (phy_read(25) & 0xff00) + 2); + } + } +} + +/* + Sense media mode and set CR6 +*/ +static void davicom_media_chk(struct nic * nic) +{ + unsigned long to, csr6; + + csr6 = 0x00200000; /* SF */ + outl(csr6, ioaddr + CSR6); + + if (vendor == PCI_VENDOR_ID_DAVICOM && dev_id == PCI_DEVICE_ID_DM9009) { + /* Set to 10BaseT mode for DM9009 */ + phy_write(0, 0); + } else { + /* For DM9102/DM9102A */ + to = currticks() + 2 * TICKS_PER_SEC; + while ( ((phy_read(1) & 0x24)!=0x24) && (currticks() < to)) + /* wait */ ; + + if ( (phy_read(1) & 0x24) == 0x24 ) { + if (phy_read(17) & 0xa000) + csr6 |= 0x00000200; /* Full Duplex mode */ + } else + csr6 |= 0x00040000; /* Select DM9801/DM9802 when Ethernet link failed */ + } + + /* set the chip's operating mode */ + outl(csr6, ioaddr + CSR6); + + /* DM9801/DM9802 present check & program */ + if (csr6 & 0x40000) + HPNA_process(); +} + + +/*********************************************************************/ +/* EEPROM Reading Code */ +/*********************************************************************/ +/* EEPROM routines adapted from the Linux Tulip Code */ +/* Reading a serial EEPROM is a "bit" grungy, but we work our way + through:->. +*/ +static int read_eeprom(unsigned long ioaddr, int location, int addr_len) +{ + int i; + unsigned short retval = 0; + long ee_addr = ioaddr + CSR9; + int read_cmd = location | EE_READ_CMD; + + whereami("read_eeprom\n"); + + outl(EE_ENB & ~EE_CS, ee_addr); + outl(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 4 + addr_len; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outl(EE_ENB | dataval, ee_addr); + eeprom_delay(); + outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + } + outl(EE_ENB, ee_addr); + + for (i = 16; i > 0; i--) { + outl(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + outl(EE_ENB, ee_addr); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + +/*********************************************************************/ +/* davicom_init_chain - setup the tx and rx descriptors */ +/* Sten 10/9 */ +/*********************************************************************/ +static void davicom_init_chain(struct nic *nic) +{ + int i; + + /* setup the transmit descriptor */ + /* Sten: Set 2 TX descriptor but use one TX buffer because + it transmit a packet and wait complete every time. */ + for (i=0; inode_addr[0]; + txb[1] = nic->node_addr[1]; + txb[4] = nic->node_addr[2]; + txb[5] = nic->node_addr[3]; + txb[8] = nic->node_addr[4]; + txb[9] = nic->node_addr[5]; + + /* setup receive descriptor */ + for (i=0; i= to) { + printf ("TX Setup Timeout!\n"); + } + /* Point to next TX descriptor */ + TxPtr = (++TxPtr >= NTXD) ? 0:TxPtr; /* Sten 10/9 */ + +#ifdef DAVICOM_DEBUG + printf("txd.status = %X\n", txd.status); + printf("ticks = %d\n", currticks() - (to - TX_TIME_OUT)); + davicom_more(); +#endif + + /* enable RX */ + outl(inl(ioaddr + CSR6) | 0x00000002, ioaddr + CSR6); + /* immediate poll demand */ + outl(0, ioaddr + CSR2); +} + + +/*********************************************************************/ +/* eth_transmit - Transmit a frame */ +/*********************************************************************/ +static void davicom_transmit(struct nic *nic, const char *d, unsigned int t, + unsigned int s, const char *p) +{ + unsigned long to; + + whereami("davicom_transmit\n"); + + /* Stop Tx */ + /* outl(inl(ioaddr + CSR6) & ~0x00002000, ioaddr + CSR6); */ + + /* setup ethernet header */ + memcpy(&txb[0], d, ETH_ALEN); /* DA 6byte */ + memcpy(&txb[ETH_ALEN], nic->node_addr, ETH_ALEN); /* SA 6byte*/ + txb[ETH_ALEN*2] = (t >> 8) & 0xFF; /* Frame type: 2byte */ + txb[ETH_ALEN*2+1] = t & 0xFF; + memcpy(&txb[ETH_HLEN], p, s); /* Frame data */ + + /* setup the transmit descriptor */ + txd[TxPtr].buf1sz = ETH_HLEN+s; + txd[TxPtr].control = 0x00000184; /* LS+FS+CE */ + txd[TxPtr].status = 0x80000000; /* give ownership to device */ + + /* immediate transmit demand */ + outl(0, ioaddr + CSR1); + + to = currticks() + TX_TIME_OUT; + while ((txd[TxPtr].status & 0x80000000) && (currticks() < to)) + /* wait */ ; + + if (currticks() >= to) { + printf ("TX Timeout!\n"); + } + + /* Point to next TX descriptor */ + TxPtr = (++TxPtr >= NTXD) ? 0:TxPtr; /* Sten 10/9 */ + +} + +/*********************************************************************/ +/* eth_poll - Wait for a frame */ +/*********************************************************************/ +static int davicom_poll(struct nic *nic) +{ + whereami("davicom_poll\n"); + + if (rxd[rxd_tail].status & 0x80000000) + return 0; + + whereami("davicom_poll got one\n"); + + nic->packetlen = (rxd[rxd_tail].status & 0x3FFF0000) >> 16; + + if( rxd[rxd_tail].status & 0x00008000){ + rxd[rxd_tail].status = 0x80000000; + rxd_tail++; + if (rxd_tail == NRXD) rxd_tail = 0; + return 0; + } + + /* copy packet to working buffer */ + /* XXX - this copy could be avoided with a little more work + but for now we are content with it because the optimised + memcpy is quite fast */ + + memcpy(nic->packet, rxb + rxd_tail * BUFLEN, nic->packetlen); + + /* return the descriptor and buffer to receive ring */ + rxd[rxd_tail].status = 0x80000000; + rxd_tail++; + if (rxd_tail == NRXD) rxd_tail = 0; + + return 1; +} + +/*********************************************************************/ +/* eth_disable - Disable the interface */ +/*********************************************************************/ +static void davicom_disable(struct nic *nic) +{ + whereami("davicom_disable\n"); + + /* disable interrupts */ + outl(0x00000000, ioaddr + CSR7); + + /* Stop the chip's Tx and Rx processes. */ + outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); + + /* Clear the missed-packet counter. */ + (volatile unsigned long)inl(ioaddr + CSR8); +} + +/*********************************************************************/ +/* eth_probe - Look for an adapter */ +/*********************************************************************/ +struct nic *davicom_probe(struct nic *nic, unsigned short *io_addrs, + struct pci_device *pci) +{ + unsigned int i; + u32 l1, l2; + + whereami("davicom_probe\n"); + + if (io_addrs == 0 || *io_addrs == 0) + return 0; + + vendor = pci->vendor; + dev_id = pci->dev_id; + ioaddr = *io_addrs; + + /* wakeup chip */ + pcibios_write_config_dword(pci->bus, pci->devfn, 0x40, 0x00000000); + + /* Stop the chip's Tx and Rx processes. */ + outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); + + /* Clear the missed-packet counter. */ + (volatile unsigned long)inl(ioaddr + CSR8); + + /* Get MAC Address */ + /* read EEPROM data */ + for (i = 0; i < sizeof(ee_data)/2; i++) + ((unsigned short *)ee_data)[i] = + le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN)); + + /* extract MAC address from EEPROM buffer */ + for (i=0; inode_addr[i] = ee_data[20+i]; + + printf("Davicom %! at ioaddr %#hX\n", nic->node_addr, ioaddr); + + /* initialize device */ + davicom_reset(nic); + + nic->reset = davicom_reset; + nic->poll = davicom_poll; + nic->transmit = davicom_transmit; + nic->disable = davicom_disable; + + return nic; +} diff --git a/netboot/depca.c b/netboot/depca.c index f2cd181ae..120520bc4 100644 --- a/netboot/depca.c +++ b/netboot/depca.c @@ -351,59 +351,6 @@ #define TMD3_LCAR 0x0800 /* Loss of CARrier */ #define TMD3_RTRY 0x0400 /* ReTRY error */ -/* -** EISA configuration Register (CNFG) bit definitions -*/ - -#define TIMEO 0x0100 /* 0:2.5 mins, 1: 30 secs */ -#define REMOTE 0x0080 /* Remote Boot Enable -> 1 */ -#define IRQ11 0x0040 /* Enable -> 1 */ -#define IRQ10 0x0020 /* Enable -> 1 */ -#define IRQ9 0x0010 /* Enable -> 1 */ -#define IRQ5 0x0008 /* Enable -> 1 */ -#define BUFF 0x0004 /* 0: 64kB or 128kB, 1: 32kB */ -#define PADR16 0x0002 /* RAM on 64kB boundary */ -#define PADR17 0x0001 /* RAM on 128kB boundary */ - -/* -** Miscellaneous -*/ -#define HASH_TABLE_LEN 64 /* Bits */ -#define HASH_BITS 0x003f /* 6 LS bits */ - -#define MASK_INTERRUPTS 1 -#define UNMASK_INTERRUPTS 0 - -#define EISA_EN 0x0001 /* Enable EISA bus buffers */ -#define EISA_ID iobase+0x0080 /* ID long word for EISA card */ -#define EISA_CTRL iobase+0x0084 /* Control word for EISA card */ - -/* -** Recognised commands for the driver -*/ -#define DEPCA_GET_HWADDR 0x01 /* Get the hardware address */ -#define DEPCA_SET_HWADDR 0x02 /* Get the hardware address */ -#define DEPCA_SET_PROM 0x03 /* Set Promiscuous Mode */ -#define DEPCA_CLR_PROM 0x04 /* Clear Promiscuous Mode */ -#define DEPCA_SAY_BOO 0x05 /* Say "Boo!" to the kernel log file */ -#define DEPCA_GET_MCA 0x06 /* Get a multicast address */ -#define DEPCA_SET_MCA 0x07 /* Set a multicast address */ -#define DEPCA_CLR_MCA 0x08 /* Clear a multicast address */ -#define DEPCA_MCA_EN 0x09 /* Enable a multicast address group */ -#define DEPCA_GET_STATS 0x0a /* Get the driver statistics */ -#define DEPCA_CLR_STATS 0x0b /* Zero out the driver statistics */ -#define DEPCA_GET_REG 0x0c /* Get the Register contents */ -#define DEPCA_SET_REG 0x0d /* Set the Register contents */ -#define DEPCA_DUMP 0x0f /* Dump the DEPCA Status */ - -#ifdef DEPCA_DEBUG -static int depca_debug = DEPCA_DEBUG; -#else -static int depca_debug = 1; -#endif - -#define DEPCA_NDA 0xffe0 /* No Device Address */ - /* ** Ethernet PROM defines */ @@ -416,14 +363,11 @@ static int depca_debug = 1; ** ** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ) */ -#define NUM_RX_DESC 8 /* Number of RX descriptors */ -#define NUM_TX_DESC 8 /* Number of TX descriptors */ +#define NUM_RX_DESC 2 /* Number of RX descriptors */ +#define NUM_TX_DESC 2 /* Number of TX descriptors */ #define RX_BUFF_SZ 1536 /* Buffer size for each Rx buffer */ #define TX_BUFF_SZ 1536 /* Buffer size for each Tx buffer */ -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - /* ** ISA Bus defines */ @@ -494,25 +438,31 @@ struct depca_tx_desc { */ struct depca_init { u16 mode; /* Mode register */ - u8 phys_addr[ETHER_ADDR_SIZE]; /* Physical ethernet address */ + u8 phys_addr[ETH_ALEN]; /* Physical ethernet address */ u8 mcast_table[8]; /* Multicast Hash Table. */ u32 rx_ring; /* Rx ring base pointer & ring length */ u32 tx_ring; /* Tx ring base pointer & ring length */ }; -/* -** The transmit ring full condition is described by the tx_old and tx_new -** pointers by: -** tx_old = tx_new Empty ring -** tx_old = tx_new+1 Full ring -** tx_old+txRingMask = tx_new Full ring (wrapped condition) -*/ -#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ - lp->tx_old+lp->txRingMask-lp->tx_new:\ - lp->tx_old -lp->tx_new-1) +struct depca_private { + struct depca_rx_desc *rx_ring; + struct depca_tx_desc *tx_ring; + struct depca_init init_block; /* Shadow init block */ + char *rx_memcpy[NUM_RX_DESC]; + char *tx_memcpy[NUM_TX_DESC]; + u32 bus_offset; /* ISA bus address offset */ + u32 sh_mem; /* address of shared mem */ + u32 dma_buffs; /* Rx & Tx buffer start */ + int rx_cur, tx_cur; /* Next free ring entry */ + int txRingMask, rxRingMask; + s32 rx_rlen, tx_rlen; + /* log2([rt]xRingMask+1) for the descriptors */ +}; static Address mem_start = DEPCA_RAM_BASE; +static Address mem_len, offset; static unsigned short ioaddr = 0; +static struct depca_private lp; /* ** Miscellaneous defines... @@ -521,7 +471,64 @@ static unsigned short ioaddr = 0; outw(CSR0, DEPCA_ADDR);\ outw(STOP, DEPCA_DATA) - +/* Initialize the lance Rx and Tx descriptor rings. */ +static void depca_init_ring(struct nic *nic) +{ + int i; + u32 p; + + lp.rx_cur = lp.tx_cur = 0; + /* Initialize the base addresses and length of each buffer in the ring */ + for (i = 0; i <= lp.rxRingMask; i++) { + writel((p = lp.dma_buffs + i * RX_BUFF_SZ) | R_OWN, &lp.rx_ring[i].base); + writew(-RX_BUFF_SZ, &lp.rx_ring[i].buf_length); + lp.rx_memcpy[i] = (char *) (p + lp.bus_offset); + } + for (i = 0; i <= lp.txRingMask; i++) { + writel((p = lp.dma_buffs + (i + lp.txRingMask + 1) * TX_BUFF_SZ) & 0x00ffffff, &lp.tx_ring[i].base); + lp.tx_memcpy[i] = (char *) (p + lp.bus_offset); + } + + /* Set up the initialization block */ + lp.init_block.rx_ring = ((u32) ((u32) lp.rx_ring) & LA_MASK) | lp.rx_rlen; + lp.init_block.tx_ring = ((u32) ((u32) lp.tx_ring) & LA_MASK) | lp.tx_rlen; + for (i = 0; i < ETH_ALEN; i++) + lp.init_block.phys_addr[i] = nic->node_addr[i]; + lp.init_block.mode = 0x0000; /* Enable the Tx and Rx */ + memset(lp.init_block.mcast_table, 0, sizeof(lp.init_block.mcast_table)); +} + +static void LoadCSRs(void) +{ + outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */ + outw((u16) (lp.sh_mem & LA_MASK), DEPCA_DATA); + outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */ + outw((u16) ((lp.sh_mem & LA_MASK) >> 16), DEPCA_DATA); + outw(CSR3, DEPCA_ADDR); /* ALE control */ + outw(ACON, DEPCA_DATA); + outw(CSR0, DEPCA_ADDR); /* Point back to CSR0 */ +} + +static int InitRestartDepca(void) +{ + int i; + + /* Copy the shadow init_block to shared memory */ + memcpy_toio((char *)lp.sh_mem, &lp.init_block, sizeof(struct depca_init)); + outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */ + outw(INIT, DEPCA_DATA); /* initialise DEPCA */ + + for (i = 0; i < 100 && !(inw(DEPCA_DATA) & IDON); i++) + ; + if (i < 100) { + /* clear IDON by writing a 1, and start LANCE */ + outw(IDON | STRT, DEPCA_DATA); + } else { + printf("DEPCA not initialised\n"); + return (1); + } + return (0); +} /************************************************************************** RESET - Reset adapter @@ -529,15 +536,50 @@ RESET - Reset adapter static void depca_reset(struct nic *nic) { s16 nicsr; - int status = 0; + int i, j; STOP_DEPCA; nicsr = inb(DEPCA_NICSR); + nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM); + outb(nicsr, DEPCA_NICSR); + if (inw(DEPCA_DATA) != STOP) + { + printf("depca: Cannot stop NIC\n"); + return; + } - /* non-DEPCA need this */ - if (adapter != DEPCA) - outb(nicsr | SHE, DEPCA_NICSR); + /* Initialisation block */ + lp.sh_mem = mem_start; + mem_start += sizeof(struct depca_init); + /* Tx & Rx descriptors (aligned to a quadword boundary) */ + mem_start = (mem_start + ALIGN) & ~ALIGN; + lp.rx_ring = (struct depca_rx_desc *) mem_start; + mem_start += (sizeof(struct depca_rx_desc) * NUM_RX_DESC); + lp.tx_ring = (struct depca_tx_desc *) mem_start; + mem_start += (sizeof(struct depca_tx_desc) * NUM_TX_DESC); + lp.bus_offset = mem_start & 0x00ff0000; + /* LANCE re-mapped start address */ + lp.dma_buffs = mem_start & LA_MASK; + + /* Finish initialising the ring information. */ + lp.rxRingMask = NUM_RX_DESC - 1; + lp.txRingMask = NUM_TX_DESC - 1; + + /* Calculate Tx/Rx RLEN size for the descriptors. */ + for (i = 0, j = lp.rxRingMask; j > 0; i++) { + j >>= 1; + } + lp.rx_rlen = (s32) (i << 29); + for (i = 0, j = lp.txRingMask; j > 0; i++) { + j >>= 1; + } + lp.tx_rlen = (s32) (i << 29); + + /* Load the initialisation block */ + depca_init_ring(nic); + LoadCSRs(); + InitRestartDepca(); } /************************************************************************** @@ -545,10 +587,16 @@ POLL - Wait for a frame ***************************************************************************/ static int depca_poll(struct nic *nic) { - /* return true if there's an ethernet packet ready to read */ - /* nic->packet should contain data on return */ - /* nic->packetlen should contain length of data */ - return 0; + int entry; + u32 status; + + entry = lp.rx_cur; + if ((status = readl(&lp.rx_ring[entry].base) & R_OWN)) + return (0); + memcpy(nic->packet, lp.rx_memcpy[entry], nic->packetlen = lp.rx_ring[entry].msg_length); + lp.rx_ring[entry].base |= R_OWN; + lp.rx_cur = (++lp.rx_cur) & lp.rxRingMask; + return (1); } /************************************************************************** @@ -561,7 +609,33 @@ static void depca_transmit( unsigned int s, /* size */ const char *p) /* Packet */ { + int entry, len; + char *mem; + /* send the packet to destination */ + /* + ** Caution: the right order is important here... dont + ** setup the ownership rights until all the other + ** information is in place + */ + mem = lp.tx_memcpy[entry = lp.tx_cur]; + memcpy_toio(mem, d, ETH_ALEN); + memcpy_toio(mem + ETH_ALEN, nic->node_addr, ETH_ALEN); + mem[ETH_ALEN * 2] = t >> 8; + mem[ETH_ALEN * 2 + 1] = t; + memcpy_toio(mem + ETH_HLEN, p, s); + s += ETH_HLEN; + len = (s < ETH_ZLEN ? ETH_ZLEN : s); + /* clean out flags */ + writel(readl(&lp.tx_ring[entry].base) & ~T_FLAGS, &lp.tx_ring[entry].base); + /* clears other error flags */ + writew(0x0000, &lp.tx_ring[entry].misc); + /* packet length in buffer */ + writew(-len, &lp.tx_ring[entry].length); + /* start and end of packet, ownership */ + writel(readl(&lp.tx_ring[entry].base) | (T_STP|T_ENP|T_OWN), &lp.tx_ring[entry].base); + /* update current pointers */ + lp.tx_cur = (++lp.tx_cur) & lp.txRingMask; } /************************************************************************** @@ -569,6 +643,7 @@ DISABLE - Turn off ethernet interface ***************************************************************************/ static void depca_disable(struct nic *nic) { + STOP_DEPCA; } /* @@ -594,7 +669,6 @@ static int depca_probe1(struct nic *nic) u8 sig[] = { 0xFF, 0x00, 0x55, 0xAA, 0xFF, 0x00, 0x55, 0xAA }; int i, j; long sum, chksum; - Address mem_len, offset; data = inb(DEPCA_PROM); /* clear counter on DEPCA */ data = inb(DEPCA_PROM); /* read data */ @@ -641,18 +715,14 @@ static int depca_probe1(struct nic *nic) nicsr &= ~BS; mem_len -= (32 << 10); } - if (adapter != DEPCA) + if (adapter != DEPCA) /* enable shadow RAM */ outb(nicsr |= SHE, DEPCA_NICSR); - printf("%s base 0x%x, memory [0x%X-0x%X], addr ", adapter_name[adapter], - ioaddr, mem_start, mem_start + mem_len); - for (i = 0; i < ETHER_ADDR_SIZE; i++) { - if (i != 0) - putchar(':'); - printf("%b", nic->node_addr[i]); - } + printf("%s base %#hX, memory [%#hX-%#hX], addr %!", + adapter_name[adapter], ioaddr, mem_start, mem_start + mem_len, + nic->node_addr); if (sum != chksum) printf(" (bad checksum)"); - printf("\n"); + putchar('\n'); return (1); } @@ -664,21 +734,19 @@ struct nic *depca_probe(struct nic *nic, unsigned short *probe_addrs) static unsigned short base[] = DEPCA_IO_PORTS; int i; - printf("DEPCA driver not fully functional, only probe working...\n"); if (probe_addrs == 0 || probe_addrs[0] == 0) probe_addrs = base; /* Use defaults */ for (i = 0; (ioaddr = base[i]) != 0; ++i) { if (depca_probe1(nic)) break; } - if (ioaddr != 0) { - depca_reset(nic); - /* point to NIC specific routines */ - nic->reset = depca_reset; - nic->poll = depca_poll; - nic->transmit = depca_transmit; - nic->disable = depca_disable; - return nic; - } - return 0; + if (ioaddr == 0) + return (0); + depca_reset(nic); + /* point to NIC specific routines */ + nic->reset = depca_reset; + nic->poll = depca_poll; + nic->transmit = depca_transmit; + nic->disable = depca_disable; + return (nic); } diff --git a/netboot/eepro.c b/netboot/eepro.c new file mode 100644 index 000000000..4e3f07b27 --- /dev/null +++ b/netboot/eepro.c @@ -0,0 +1,586 @@ +/************************************************************************** +Etherboot - BOOTP/TFTP Bootstrap Program +Intel EEPRO/10 NIC driver for Etherboot +Adapted from Linux eepro.c from kernel 2.2.17 + +This board accepts a 32 pin EEPROM (29C256), however a test with a +27C010 shows that this EPROM also works in the socket, but it's not clear +how repeatably. The two top address pins appear to be held low, thus +the bottom 32kB of the 27C010 is visible in the CPU's address space. +To be sure you could put 4 copies of the code in the 27C010, then +it doesn't matter whether the extra lines are held low or high, just +hopefully not floating as CMOS chips don't like floating inputs. + +Be careful with seating the EPROM as the socket on my board actually +has 34 pins, the top row of 2 are not used. +***************************************************************************/ + +/* + * 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, or (at + * your option) any later version. + */ + +/* to get some global routines like printf */ +#include "etherboot.h" +/* to get the interface to the body of the program */ +#include "nic.h" +/* to get our own prototype */ +#include "cards.h" +/* we use timer2 for microsecond waits */ +#include "timer.h" + +#undef DEBUG /* only after include files */ + +/* Different 82595 chips */ +#define LAN595 0 +#define LAN595TX 1 +#define LAN595FX 2 +#define LAN595FX_10ISA 3 + +#define SLOW_DOWN inb(0x80); + +/* The station (ethernet) address prefix, used for IDing the board. */ +#define SA_ADDR0 0x00 /* Etherexpress Pro/10 */ +#define SA_ADDR1 0xaa +#define SA_ADDR2 0x00 + +#define GetBit(x,y) ((x & (1<>y) + +/* EEPROM Word 0: */ +#define ee_PnP 0 /* Plug 'n Play enable bit */ +#define ee_Word1 1 /* Word 1? */ +#define ee_BusWidth 2 /* 8/16 bit */ +#define ee_FlashAddr 3 /* Flash Address */ +#define ee_FlashMask 0x7 /* Mask */ +#define ee_AutoIO 6 /* */ +#define ee_reserved0 7 /* =0! */ +#define ee_Flash 8 /* Flash there? */ +#define ee_AutoNeg 9 /* Auto Negotiation enabled? */ +#define ee_IO0 10 /* IO Address LSB */ +#define ee_IO0Mask 0x /*...*/ +#define ee_IO1 15 /* IO MSB */ + +/* EEPROM Word 1: */ +#define ee_IntSel 0 /* Interrupt */ +#define ee_IntMask 0x7 +#define ee_LI 3 /* Link Integrity 0= enabled */ +#define ee_PC 4 /* Polarity Correction 0= enabled */ +#define ee_TPE_AUI 5 /* PortSelection 1=TPE */ +#define ee_Jabber 6 /* Jabber prevention 0= enabled */ +#define ee_AutoPort 7 /* Auto Port Selection 1= Disabled */ +#define ee_SMOUT 8 /* SMout Pin Control 0= Input */ +#define ee_PROM 9 /* Flash EPROM / PROM 0=Flash */ +#define ee_reserved1 10 /* .. 12 =0! */ +#define ee_AltReady 13 /* Alternate Ready, 0=normal */ +#define ee_reserved2 14 /* =0! */ +#define ee_Duplex 15 + +/* Word2,3,4: */ +#define ee_IA5 0 /*bit start for individual Addr Byte 5 */ +#define ee_IA4 8 /*bit start for individual Addr Byte 5 */ +#define ee_IA3 0 /*bit start for individual Addr Byte 5 */ +#define ee_IA2 8 /*bit start for individual Addr Byte 5 */ +#define ee_IA1 0 /*bit start for individual Addr Byte 5 */ +#define ee_IA0 8 /*bit start for individual Addr Byte 5 */ + +/* Word 5: */ +#define ee_BNC_TPE 0 /* 0=TPE */ +#define ee_BootType 1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */ +#define ee_BootTypeMask 0x3 +#define ee_NumConn 3 /* Number of Connections 0= One or Two */ +#define ee_FlashSock 4 /* Presence of Flash Socket 0= Present */ +#define ee_PortTPE 5 +#define ee_PortBNC 6 +#define ee_PortAUI 7 +#define ee_PowerMgt 10 /* 0= disabled */ +#define ee_CP 13 /* Concurrent Processing */ +#define ee_CPMask 0x7 + +/* Word 6: */ +#define ee_Stepping 0 /* Stepping info */ +#define ee_StepMask 0x0F +#define ee_BoardID 4 /* Manucaturer Board ID, reserved */ +#define ee_BoardMask 0x0FFF + +/* Word 7: */ +#define ee_INT_TO_IRQ 0 /* int to IRQ Mapping = 0x1EB8 for Pro/10+ */ +#define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */ + +/*..*/ +#define ee_SIZE 0x40 /* total EEprom Size */ +#define ee_Checksum 0xBABA /* initial and final value for adding checksum */ + + +/* Card identification via EEprom: */ +#define ee_addr_vendor 0x10 /* Word offset for EISA Vendor ID */ +#define ee_addr_id 0x11 /* Word offset for Card ID */ +#define ee_addr_SN 0x12 /* Serial Number */ +#define ee_addr_CRC_8 0x14 /* CRC over last thee Bytes */ + + +#define ee_vendor_intel0 0x25 /* Vendor ID Intel */ +#define ee_vendor_intel1 0xD4 +#define ee_id_eepro10p0 0x10 /* ID for eepro/10+ */ +#define ee_id_eepro10p1 0x31 + +/* now this section could be used by both boards: the oldies and the ee10: + * ee10 uses tx buffer before of rx buffer and the oldies the inverse. + * (aris) + */ +#define RAM_SIZE 0x8000 + +#define RCV_HEADER 8 +#define RCV_DEFAULT_RAM 0x6000 +#define RCV_RAM rcv_ram + +static unsigned rcv_ram = RCV_DEFAULT_RAM; + +#define XMT_HEADER 8 +#define XMT_RAM (RAM_SIZE - RCV_RAM) + +#define XMT_START ((rcv_start + RCV_RAM) % RAM_SIZE) + +#define RCV_LOWER_LIMIT (rcv_start >> 8) +#define RCV_UPPER_LIMIT (((rcv_start + RCV_RAM) - 2) >> 8) +#define XMT_LOWER_LIMIT (XMT_START >> 8) +#define XMT_UPPER_LIMIT (((XMT_START + XMT_RAM) - 2) >> 8) + +#define RCV_START_PRO 0x00 +#define RCV_START_10 XMT_RAM + /* by default the old driver */ +static unsigned rcv_start = RCV_START_PRO; + +#define RCV_DONE 0x0008 +#define RX_OK 0x2000 +#define RX_ERROR 0x0d81 + +#define TX_DONE_BIT 0x0080 +#define CHAIN_BIT 0x8000 +#define XMT_STATUS 0x02 +#define XMT_CHAIN 0x04 +#define XMT_COUNT 0x06 + +#define BANK0_SELECT 0x00 +#define BANK1_SELECT 0x40 +#define BANK2_SELECT 0x80 + +/* Bank 0 registers */ +#define COMMAND_REG 0x00 /* Register 0 */ +#define MC_SETUP 0x03 +#define XMT_CMD 0x04 +#define DIAGNOSE_CMD 0x07 +#define RCV_ENABLE_CMD 0x08 +#define RCV_DISABLE_CMD 0x0a +#define STOP_RCV_CMD 0x0b +#define RESET_CMD 0x0e +#define POWER_DOWN_CMD 0x18 +#define RESUME_XMT_CMD 0x1c +#define SEL_RESET_CMD 0x1e +#define STATUS_REG 0x01 /* Register 1 */ +#define RX_INT 0x02 +#define TX_INT 0x04 +#define EXEC_STATUS 0x30 +#define ID_REG 0x02 /* Register 2 */ +#define R_ROBIN_BITS 0xc0 /* round robin counter */ +#define ID_REG_MASK 0x2c +#define ID_REG_SIG 0x24 +#define AUTO_ENABLE 0x10 +#define INT_MASK_REG 0x03 /* Register 3 */ +#define RX_STOP_MASK 0x01 +#define RX_MASK 0x02 +#define TX_MASK 0x04 +#define EXEC_MASK 0x08 +#define ALL_MASK 0x0f +#define IO_32_BIT 0x10 +#define RCV_BAR 0x04 /* The following are word (16-bit) registers */ +#define RCV_STOP 0x06 + +#define XMT_BAR_PRO 0x0a +#define XMT_BAR_10 0x0b +static unsigned xmt_bar = XMT_BAR_PRO; + +#define HOST_ADDRESS_REG 0x0c +#define IO_PORT 0x0e +#define IO_PORT_32_BIT 0x0c + +/* Bank 1 registers */ +#define REG1 0x01 +#define WORD_WIDTH 0x02 +#define INT_ENABLE 0x80 +#define INT_NO_REG 0x02 +#define RCV_LOWER_LIMIT_REG 0x08 +#define RCV_UPPER_LIMIT_REG 0x09 + +#define XMT_LOWER_LIMIT_REG_PRO 0x0a +#define XMT_UPPER_LIMIT_REG_PRO 0x0b +#define XMT_LOWER_LIMIT_REG_10 0x0b +#define XMT_UPPER_LIMIT_REG_10 0x0a +static unsigned xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO; +static unsigned xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO; + +/* Bank 2 registers */ +#define XMT_Chain_Int 0x20 /* Interrupt at the end of the transmit chain */ +#define XMT_Chain_ErrStop 0x40 /* Interrupt at the end of the chain even if there are errors */ +#define RCV_Discard_BadFrame 0x80 /* Throw bad frames away, and continue to receive others */ +#define REG2 0x02 +#define PRMSC_Mode 0x01 +#define Multi_IA 0x20 +#define REG3 0x03 +#define TPE_BIT 0x04 +#define BNC_BIT 0x20 +#define REG13 0x0d +#define FDX 0x00 +#define A_N_ENABLE 0x02 + +#define I_ADD_REG0 0x04 +#define I_ADD_REG1 0x05 +#define I_ADD_REG2 0x06 +#define I_ADD_REG3 0x07 +#define I_ADD_REG4 0x08 +#define I_ADD_REG5 0x09 + +#define EEPROM_REG_PRO 0x0a +#define EEPROM_REG_10 0x0b +static unsigned eeprom_reg = EEPROM_REG_PRO; + +#define EESK 0x01 +#define EECS 0x02 +#define EEDI 0x04 +#define EEDO 0x08 + +/* The horrible routine to read a word from the serial EEPROM. */ +/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */ + +/* The delay between EEPROM clock transitions. */ +#define eeprom_delay() { udelay(40); } +#define EE_READ_CMD (6 << 6) + +/* do a full reset */ +#define eepro_full_reset(ioaddr) outb(RESET_CMD, ioaddr); udelay(40); + +/* do a nice reset */ +#define eepro_sel_reset(ioaddr) { \ + outb(SEL_RESET_CMD, ioaddr); \ + SLOW_DOWN; \ + SLOW_DOWN; \ + } + +/* clear all interrupts */ +#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG) + +/* enable rx */ +#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr) + +/* disable rx */ +#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr) + +/* switch bank */ +#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr) +#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr) +#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr) + +static unsigned int rx_start, tx_start; +static int tx_last; +static unsigned tx_end; +static int eepro = 0; +static unsigned short ioaddr = 0; +static unsigned int mem_start, mem_end = RCV_DEFAULT_RAM / 1024; + +#define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000) + +/************************************************************************** +RESET - Reset adapter +***************************************************************************/ +static void eepro_reset(struct nic *nic) +{ + int temp_reg, i; + + /* put the card in its initial state */ + eepro_sw2bank2(ioaddr); /* be careful, bank2 now */ + temp_reg = inb(ioaddr + eeprom_reg); +#ifdef DEBUG + printf("Stepping %d\n", temp_reg >> 5); +#endif + if (temp_reg & 0x10) /* check the TurnOff Enable bit */ + outb(temp_reg & 0xEF, ioaddr + eeprom_reg); + for (i = 0; i < ETH_ALEN; i++) /* fill the MAC address */ + outb(nic->node_addr[i], ioaddr + I_ADD_REG0 + i); + temp_reg = inb(ioaddr + REG1); + /* setup Transmit Chaining and discard bad RCV frames */ + outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop + | RCV_Discard_BadFrame, ioaddr + REG1); + temp_reg = inb(ioaddr + REG2); /* match broadcast */ + outb(temp_reg | 0x14, ioaddr + REG2); + temp_reg = inb(ioaddr + REG3); + outb(temp_reg & 0x3F, ioaddr + REG3); /* clear test mode */ + /* set the receiving mode */ + eepro_sw2bank1(ioaddr); /* be careful, bank1 now */ + /* initialise the RCV and XMT upper and lower limits */ + outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); + outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); + outb(XMT_LOWER_LIMIT, ioaddr + xmt_lower_limit_reg); + outb(XMT_UPPER_LIMIT, ioaddr + xmt_upper_limit_reg); + eepro_sw2bank0(ioaddr); /* Switch back to bank 0 */ + eepro_clear_int(ioaddr); + /* Initialise RCV */ + outw(rx_start = (RCV_LOWER_LIMIT << 8), ioaddr + RCV_BAR); + outw(((RCV_UPPER_LIMIT << 8) | 0xFE), ioaddr + RCV_STOP); + /* Intialise XMT */ + outw((XMT_LOWER_LIMIT << 8), ioaddr + xmt_bar); + eepro_sel_reset(ioaddr); + tx_start = tx_end = (XMT_LOWER_LIMIT << 8); + tx_last = 0; + eepro_en_rx(ioaddr); +} + +/************************************************************************** +POLL - Wait for a frame +***************************************************************************/ +static int eepro_poll(struct nic *nic) +{ + int i; + unsigned int rcv_car = rx_start; + unsigned int rcv_event, rcv_status, rcv_next_frame, rcv_size; + + /* return true if there's an ethernet packet ready to read */ + /* nic->packet should contain data on return */ + /* nic->packetlen should contain length of data */ +#if 0 + if ((inb(ioaddr + STATUS_REG) & 0x40) == 0) + return (0); + outb(0x40, ioaddr + STATUS_REG); +#endif + outw(rcv_car, ioaddr + HOST_ADDRESS_REG); + rcv_event = inw(ioaddr + IO_PORT); + if (rcv_event != RCV_DONE) + return (0); + rcv_status = inw(ioaddr + IO_PORT); + rcv_next_frame = inw(ioaddr + IO_PORT); + rcv_size = inw(ioaddr + IO_PORT); +#if 0 + printf("%hX %hX %d %hhX\n", rcv_status, rcv_next_frame, rcv_size, + inb(ioaddr + STATUS_REG)); +#endif + if ((rcv_status & (RX_OK|RX_ERROR)) != RX_OK) { + printf("Receive error %hX\n", rcv_status); + return (0); + } + rcv_size &= 0x3FFF; + insw(ioaddr + IO_PORT, nic->packet, ((rcv_size + 3) >> 1)); +#if 0 + for (i = 0; i < 48; i++) { + printf("%hhX", nic->packet[i]); + putchar(i % 16 == 15 ? '\n' : ' '); + } +#endif + nic->packetlen = rcv_size; + rcv_car = rx_start + RCV_HEADER + rcv_size; + rx_start = rcv_next_frame; + if (rcv_car == 0) + rcv_car = ((RCV_UPPER_LIMIT << 8) | 0xff); + outw(rcv_car - 1, ioaddr + RCV_STOP); + return (1); +} + +/************************************************************************** +TRANSMIT - Transmit a frame +***************************************************************************/ +static void eepro_transmit( + struct nic *nic, + const char *d, /* Destination */ + unsigned int t, /* Type */ + unsigned int s, /* size */ + const char *p) /* Packet */ +{ + unsigned int status, tx_available, last, end, length; + unsigned short type; + int boguscount = 20; + + length = s + ETH_HLEN; + if (tx_end > tx_start) + tx_available = XMT_RAM - (tx_end - tx_start); + else if (tx_end < tx_start) + tx_available = tx_start - tx_end; + else + tx_available = XMT_RAM; + last = tx_end; + end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; + if (end >= (XMT_UPPER_LIMIT << 8)) { + last = (XMT_LOWER_LIMIT << 8); + end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; + } + outw(last, ioaddr + HOST_ADDRESS_REG); + outw(XMT_CMD, ioaddr + IO_PORT); + outw(0, ioaddr + IO_PORT); + outw(end, ioaddr + IO_PORT); + outw(length, ioaddr + IO_PORT); + outsw(ioaddr + IO_PORT, d, ETH_ALEN / 2); + outsw(ioaddr + IO_PORT, nic->node_addr, ETH_ALEN / 2); + type = htons(t); + outsw(ioaddr + IO_PORT, &type, sizeof(type) / 2); + outsw(ioaddr + IO_PORT, p, (s + 3) >> 1); + /* A dummy read to flush the DRAM write pipeline */ + status = inw(ioaddr + IO_PORT); + outw(last, ioaddr + xmt_bar); + outb(XMT_CMD, ioaddr); + tx_start = last; + tx_last = last; + tx_end = end; +#if 0 + printf("%d %d\n", tx_start, tx_end); +#endif + while (boguscount > 0) { + if (((status = inw(ioaddr + IO_PORT)) & TX_DONE_BIT) == 0) { + udelay(40); + boguscount--; + continue; + } +#if DEBUG + if ((status & 0x2000) == 0) + printf("Transmit status %hX\n", status); +#endif + } +} + +/************************************************************************** +DISABLE - Turn off ethernet interface +***************************************************************************/ +static void eepro_disable(struct nic *nic) +{ + eepro_sw2bank0(ioaddr); /* Switch to bank 0 */ + /* Flush the Tx and disable Rx */ + outb(STOP_RCV_CMD, ioaddr); + tx_start = tx_end = (XMT_LOWER_LIMIT << 8); + tx_last = 0; + /* Reset the 82595 */ + eepro_full_reset(ioaddr); +} + +static int read_eeprom(int location) +{ + int i; + unsigned short retval = 0; + int ee_addr = ioaddr + eeprom_reg; + int read_cmd = location | EE_READ_CMD; + int ctrl_val = EECS; + + if (eepro == LAN595FX_10ISA) { + eepro_sw2bank1(ioaddr); + outb(0x00, ioaddr + STATUS_REG); + } + eepro_sw2bank2(ioaddr); + outb(ctrl_val, ee_addr); + /* shift the read command bits out */ + for (i = 8; i >= 0; i--) { + short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val; + outb(outval, ee_addr); + outb(outval | EESK, ee_addr); /* EEPROM clock tick */ + eeprom_delay(); + outb(outval, ee_addr); /* finish EEPROM clock tick */ + eeprom_delay(); + } + outb(ctrl_val, ee_addr); + for (i = 16; i > 0; i--) { + outb(ctrl_val | EESK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0); + outb(ctrl_val, ee_addr); + eeprom_delay(); + } + /* terminate the EEPROM access */ + ctrl_val &= ~EECS; + outb(ctrl_val | EESK, ee_addr); + eeprom_delay(); + outb(ctrl_val, ee_addr); + eeprom_delay(); + eepro_sw2bank0(ioaddr); + return (retval); +} + +static int eepro_probe1(struct nic *nic) +{ + int i, id, counter, l_eepro = 0; + union { + unsigned char caddr[ETH_ALEN]; + unsigned short saddr[ETH_ALEN/2]; + } station_addr; + char *name; + + id = inb(ioaddr + ID_REG); + if ((id & ID_REG_MASK) != ID_REG_SIG) + return (0); + counter = id & R_ROBIN_BITS; + if (((id = inb(ioaddr + ID_REG)) & R_ROBIN_BITS) != (counter + 0x40)) + return (0); + /* yes the 82595 has been found */ + station_addr.saddr[2] = read_eeprom(2); + if (station_addr.saddr[2] == 0x0000 || station_addr.saddr[2] == 0xFFFF) { + l_eepro = 3; + eepro = LAN595FX_10ISA; + eeprom_reg= EEPROM_REG_10; + rcv_start = RCV_START_10; + xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10; + xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10; + station_addr.saddr[2] = read_eeprom(2); + } + station_addr.saddr[1] = read_eeprom(3); + station_addr.saddr[0] = read_eeprom(4); + if (l_eepro) + name = "Intel EtherExpress 10 ISA"; + else if (read_eeprom(7) == ee_FX_INT2IRQ) { + name = "Intel EtherExpress Pro/10+ ISA"; + l_eepro = 2; + } else if (station_addr.saddr[0] == SA_ADDR1) { + name = "Intel EtherExpress Pro/10 ISA"; + l_eepro = 1; + } else { + l_eepro = 0; + name = "Intel 82595-based LAN card"; + } + station_addr.saddr[0] = swap16(station_addr.saddr[0]); + station_addr.saddr[1] = swap16(station_addr.saddr[1]); + station_addr.saddr[2] = swap16(station_addr.saddr[2]); + for (i = 0; i < ETH_ALEN; i++) { + nic->node_addr[i] = station_addr.caddr[i]; + } + printf("\n%s ioaddr %#hX, addr %!", name, ioaddr, nic->node_addr); + mem_start = RCV_LOWER_LIMIT << 8; + if ((mem_end & 0x3F) < 3 || (mem_end & 0x3F) > 29) + mem_end = RCV_UPPER_LIMIT << 8; + else { + mem_end = mem_end * 1024 + (RCV_LOWER_LIMIT << 8); + rcv_ram = mem_end - (RCV_LOWER_LIMIT << 8); + } + printf(", Rx mem %dK, if %s\n", (mem_end - mem_start) >> 10, + GetBit(read_eeprom(5), ee_BNC_TPE) ? "BNC" : "TP"); + return (1); +} + +/************************************************************************** +PROBE - Look for an adapter, this routine's visible to the outside +***************************************************************************/ +struct nic *eepro_probe(struct nic *nic, unsigned short *probe_addrs) +{ + unsigned short *p; + /* same probe list as the Linux driver */ + static unsigned short ioaddrs[] = { + 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0}; + + if (probe_addrs == 0 || probe_addrs[0] == 0) + probe_addrs = ioaddrs; + for (p = probe_addrs; (ioaddr = *p) != 0; p++) { + if (eepro_probe1(nic)) + break; + } + if (*p == 0) + return (0); + eepro_reset(nic); + /* point to NIC specific routines */ + nic->reset = eepro_reset; + nic->poll = eepro_poll; + nic->transmit = eepro_transmit; + nic->disable = eepro_disable; + return (nic); +} diff --git a/netboot/eepro100.c b/netboot/eepro100.c index 18ceb7b83..0781a3bbe 100644 --- a/netboot/eepro100.c +++ b/netboot/eepro100.c @@ -46,8 +46,6 @@ * I still don't have the docs. * */ - - /* Philosophy of this driver. * * Probing: @@ -91,7 +89,6 @@ * so that you need even more headroom. */ - /* The etherboot authors seem to dislike the argument ordering in * outb macros that Linux uses. I disklike the confusion that this * has caused even more.... This file uses the Linux argument ordering. */ @@ -101,6 +98,7 @@ #include "nic.h" #include "pci.h" #include "cards.h" +#include "timer.h" #undef virt_to_bus #define virt_to_bus(x) ((unsigned long)x) @@ -114,7 +112,6 @@ typedef signed short s16; typedef unsigned int u32; typedef signed int s32; - enum speedo_offsets { SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */ SCBPointer = 4, /* General purpose pointer. */ @@ -124,11 +121,8 @@ enum speedo_offsets { SCBEarlyRx = 20, /* Early receive byte count. */ }; - -static int read_eeprom(int location); -static void udelay (int val); -void hd (void *where, int n); - +static int do_eeprom_cmd(int cmd, int cmd_len); +void hd(void *where, int n); /***********************************************************************/ /* I82557 related defines */ @@ -140,22 +134,15 @@ void hd (void *where, int n); #define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */ #define EE_CS 0x02 /* EEPROM chip select. */ #define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ -#define EE_WRITE_0 0x01 -#define EE_WRITE_1 0x05 #define EE_DATA_READ 0x08 /* EEPROM chip data out. */ +#define EE_WRITE_0 0x4802 +#define EE_WRITE_1 0x4806 #define EE_ENB (0x4800 | EE_CS) - -/* Delay between EEPROM clock transitions. - This is a "nasty" timing loop, but PC compatible machines are defined - to delay an ISA compatible period for the SLOW_DOWN_IO macro. */ -#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) \ - { __SLOW_DOWN_IO; }} while (0) +#define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000) /* The EEPROM commands include the alway-set leading bit. */ -#define EE_WRITE_CMD (5 << 6) -#define EE_READ_CMD (6 << 6) -#define EE_ERASE_CMD (7 << 6) +#define EE_READ_CMD 6 /* The SCB accepts the following controls for the Tx and Rx units: */ #define CU_START 0x0010 @@ -176,8 +163,6 @@ void hd (void *where, int n); enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240, S80C24, PhyUndefined, DP83840A=10, }; - - /* Commands that can be put in a command list entry. */ enum commands { CmdNOp = 0, @@ -195,7 +180,6 @@ enum commands { CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */ }; - /* How to wait for the command unit to accept a command. Typically this takes 0 ticks. */ static inline void wait_for_cmd_done(int cmd_ioaddr) @@ -205,7 +189,6 @@ static inline void wait_for_cmd_done(int cmd_ioaddr) while(inb(cmd_ioaddr) && --wait >= 0); } - /* Elements of the dump_statistics block. This block must be lword aligned. */ static struct speedo_stats { u32 tx_good_frames; @@ -227,7 +210,6 @@ static struct speedo_stats { u32 done_marker; } lstats; - /* A speedo3 TX buffer descriptor with two buffers... */ static struct TxFD { volatile s16 status; @@ -242,7 +224,6 @@ static struct TxFD { s32 tx_buf_size1; /* Length of Tx data. */ } txfd; - struct RxFD { /* Receive frame descriptor. */ volatile s16 status; s16 command; @@ -253,7 +234,7 @@ struct RxFD { /* Receive frame descriptor. */ char packet[1518]; }; -#ifndef USE_INTERNAL_BUFFER +#ifdef USE_LOWMEM_BUFFER #define rxfd ((struct RxFD *)(0x10000 - sizeof(struct RxFD))) #define ACCESS(x) x-> #else @@ -261,16 +242,12 @@ static struct RxFD rxfd; #define ACCESS(x) x. #endif - - static int congenb = 0; /* Enable congestion control in the DP83840. */ static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */ static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */ static int txdmacount = 0; /* Tx DMA burst length, 0-127, default 0. */ static int rxdmacount = 0; /* Rx DMA length, 0 means no preemption. */ - - /* I don't understand a byte in this structure. It was copied from the * Linux kernel initialization for the eepro100. -- REW */ static struct ConfCmd { @@ -287,25 +264,16 @@ static struct ConfCmd { 0x3f, 0x05, } }; - - -#define TIME_OUT 1000000 - -static unsigned short eeprom [0x40]; - - /***********************************************************************/ /* Locally used functions */ /***********************************************************************/ - /* Support function: mdio_write * * This probably writes to the "physical media interface chip". * -- REW */ - static int mdio_write(int phy_id, int location, int value) { int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */ @@ -317,13 +285,12 @@ static int mdio_write(int phy_id, int location, int value) val = inl(ioaddr + SCBCtrlMDI); if (--boguscnt < 0) { - printf(" mdio_write() timed out with val = %8.8x.\n", val); + printf(" mdio_write() timed out with val = %X.\n", val); } } while (! (val & 0x10000000)); return val & 0xffff; } - /* Support function: mdio_read * * This probably reads a register in the "physical media interface chip". @@ -338,54 +305,41 @@ static int mdio_read(int phy_id, int location) val = inl(ioaddr + SCBCtrlMDI); if (--boguscnt < 0) { - printf( " mdio_read() timed out with val = %8.8x.\n", val); + printf( " mdio_read() timed out with val = %X.\n", val); } } while (! (val & 0x10000000)); return val & 0xffff; } - -/* Support function: read_eeprom - * reads a value from the eeprom at a specified location. - * Arguments: location: address of the location to read from the eeprom. - * returns: value read from eeprom at location. - */ -static int read_eeprom(int location) +/* The fixes for the code were kindly provided by Dragan Stancevic + to strictly follow Intel specifications of EEPROM + access timing. + The publicly available sheet 64486302 (sec. 3.1) specifies 1us access + interval for serial EEPROM. However, it looks like that there is an + additional requirement dictating larger udelay's in the code below. + 2000/05/24 SAW */ +static int do_eeprom_cmd(int cmd, int cmd_len) { - int i; - unsigned short retval = 0; - int ee_addr = ioaddr + SCBeeprom; - int read_cmd = location | EE_READ_CMD; + unsigned retval = 0; + long ee_addr = ioaddr + SCBeeprom; - outw(EE_ENB & ~EE_CS, ee_addr); - outw(EE_ENB, ee_addr); + outw(EE_ENB, ee_addr); udelay(2); + outw(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2); - /* Shift the read command bits out. */ - for (i = 10; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - outw(EE_ENB | dataval, ee_addr); - eeprom_delay(100); - outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(150); - outw(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */ - eeprom_delay(250); - } - outw(EE_ENB, ee_addr); + /* Shift the command bits out. */ + do { + short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; + outw(dataval, ee_addr); udelay(2); + outw(dataval | EE_SHIFT_CLK, ee_addr); udelay(2); + retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); + } while (--cmd_len >= 0); + outw(EE_ENB, ee_addr); udelay(2); - for (i = 15; i >= 0; i--) { - outw(EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay(100); - retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); - outw(EE_ENB, ee_addr); - eeprom_delay(100); - } - - /* Terminate the EEPROM access. */ - outw(EE_ENB & ~EE_CS, ee_addr); - return retval; + /* Terminate the EEPROM access. */ + outw(EE_ENB & ~EE_CS, ee_addr); + return retval; } - static inline void whereami (const char *str) { #if 0 @@ -394,15 +348,8 @@ static inline void whereami (const char *str) #endif } - - -/***********************************************************************/ -/* Externally visible functions */ -/***********************************************************************/ - - -/* function: eepro100_reset / eth_reset - * resets the card. This is used to allow Linux to probe the card again +/* function: eepro100_reset + * resets the card. This is used to allow Etherboot to probe the card again * from a "virginal" state.... * Arguments: none * @@ -414,8 +361,6 @@ static void eepro100_reset(struct nic *nic) outl(0, ioaddr + SCBPort); } - - /* function: eepro100_transmit * This transmits a packet. * @@ -429,8 +374,8 @@ static void eepro100_reset(struct nic *nic) static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p) { struct eth_hdr { - unsigned char dst_addr[6]; - unsigned char src_addr[6]; + unsigned char dst_addr[ETH_ALEN]; + unsigned char src_addr[ETH_ALEN]; unsigned short type; } hdr; unsigned short status; @@ -442,13 +387,12 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un outw(status & 0xfc00, ioaddr + SCBStatus); #ifdef DEBUG - printf ("transmitting type %x packet (%d bytes). status = %x, cmd=%x\n", + printf ("transmitting type %hX packet (%d bytes). status = %hX, cmd=%hX\n", t, s, status, inw (ioaddr + SCBCmd)); #endif - - memcpy (&hdr.dst_addr, d, 6); - memcpy (&hdr.src_addr, nic->node_addr, 6); + memcpy (&hdr.dst_addr, d, ETH_ALEN); + memcpy (&hdr.src_addr, nic->node_addr, ETH_ALEN); hdr.type = htons (t); @@ -474,18 +418,16 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un wait_for_cmd_done(ioaddr + SCBCmd); s1 = inw (ioaddr + SCBStatus); - to = TIME_OUT; - while (!txfd.status && --to) + load_timer2(10*TICKS_PER_MS); /* timeout 10 ms for transmit */ + while (!txfd.status && timer2_running()) /* Wait */; s2 = inw (ioaddr + SCBStatus); #ifdef DEBUG - printf ("Tx: Loop executed %d times.\n", TIME_OUT-to); - printf ("s1 = %x, s2 = %x.\n", s1, s2); + printf ("s1 = %hX, s2 = %hX.\n", s1, s2); #endif } - /* function: eepro100_poll / eth_poll * This recieves a packet from the network. * @@ -500,11 +442,8 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un static int eepro100_poll(struct nic *nic) { - int to; - - to = TIME_OUT; - while (!ACCESS(rxfd)status && --to) - /* Wait */; + if (!ACCESS(rxfd)status) + return 0; /* Ok. We got a packet. Now restart the reciever.... */ ACCESS(rxfd)status = 0; @@ -513,22 +452,22 @@ static int eepro100_poll(struct nic *nic) outw(INT_MASK | RX_START, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); - if (to) { #ifdef DEBUG - printf ("Got a packet: Len = %d.\n", ACCESS(rxfd)count & 0x3fff); + printf ("Got a packet: Len = %d.\n", ACCESS(rxfd)count & 0x3fff); #endif - nic->packetlen = ACCESS(rxfd)count & 0x3fff; - memcpy (nic->packet, ACCESS(rxfd)packet, nic->packetlen); + nic->packetlen = ACCESS(rxfd)count & 0x3fff; + memcpy (nic->packet, ACCESS(rxfd)packet, nic->packetlen); #ifdef DEBUG - hd (nic->packet, 0x30); + hd (nic->packet, 0x30); #endif - return 1; - } else - return 0; + return 1; } static void eepro100_disable(struct nic *nic) { + /* See if this PartialReset solves the problem with interfering with + kernel operation after Etherboot hands over. - Ken 20001102 */ + outl(2, ioaddr + SCBPort); } /* exported function: eepro100_probe / eth_probe @@ -541,63 +480,46 @@ static void eepro100_disable(struct nic *nic) struct nic *eepro100_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *p) { - u16 sum = 0; - int i, j, to; - unsigned short value; - int options; - int promisc; + unsigned short sum = 0; + int i; + int read_cmd, ee_size; + unsigned short value; + int options; + int promisc; - unsigned char pci_bus = 0; - unsigned short pci_command; - unsigned short new_command; - unsigned char pci_latency; + /* we cache only the first few words of the EEPROM data + be careful not to access beyond this array */ + unsigned short eeprom[16]; - if (probeaddrs == 0 || probeaddrs[0] == 0) - return 0; + if (probeaddrs == 0 || probeaddrs[0] == 0) + return 0; + ioaddr = probeaddrs[0] & ~3; /* Mask the bit that says "this is an io addr" */ - ioaddr = probeaddrs[0] & ~3; /* Mask the bit that says "this is an io addr" */ + adjust_pci_device(p); - /* Ok. Got one. Read the eeprom. */ - for (j = 0, i = 0; i < 0x40; i++) { - value = read_eeprom(i); - eeprom[i] = value; - sum += value; - } + if ((do_eeprom_cmd(EE_READ_CMD << 24, 27) & 0xffe0000) + == 0xffe0000) { + ee_size = 0x100; + read_cmd = EE_READ_CMD << 24; + } else { + ee_size = 0x40; + read_cmd = EE_READ_CMD << 22; + } - /* From Matt Hortman */ - if (p->dev_id == PCI_DEVICE_ID_INTEL_82557 ){ - /* - * check to make sure the bios properly set the - * 82557 (or 82558) to be bus master - * - * from eepro100.c in 2.2.9 kernel source - */ + for (i = 0, sum = 0; i < ee_size; i++) { + unsigned short value = do_eeprom_cmd(read_cmd | (i << 16), 27); + if (i < (int)(sizeof(eeprom)/sizeof(eeprom[0]))) + eeprom[i] = value; + sum += value; + } - pcibios_read_config_word(pci_bus, p->devfn, PCI_COMMAND, &pci_command); - new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; - - if (pci_command != new_command) { - printf("\nThe PCI BIOS has not enabled this device!\nUpdating PCI command %x->%x. pci_bus %x pci_device_fn %x\n", - pci_command, new_command, pci_bus, p->devfn); - pcibios_write_config_word(pci_bus, p->devfn, PCI_COMMAND, new_command); - } - - pcibios_read_config_byte(pci_bus, p->devfn, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < 32) { - printf("\nPCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency); - pcibios_write_config_byte(pci_bus, p->devfn, PCI_LATENCY_TIMER, 32); - } - } - - printf ("Ethernet addr: "); - for (i=0;i<6;i++) { + for (i=0;inode_addr[i] = (eeprom[i/2] >> (8*(i&1))) & 0xff; - printf ("%b%c", nic->node_addr[i] , i < 5?':':' '); } - printf ("\n"); + printf ("Ethernet addr: %!\n", nic->node_addr); if (sum != 0xBABA) - printf("eepro100: Invalid EEPROM checksum %#4.4x, " + printf("eepro100: Invalid EEPROM checksum %#hX, " "check settings before activating this device!\n", sum); outl(0, ioaddr + SCBPort); udelay (10); @@ -637,7 +559,6 @@ struct nic *eepro100_probe(struct nic *nic, unsigned short *probeaddrs, struct p outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer); outw(INT_MASK | RX_START, ioaddr + SCBCmd); - /* INIT TX stuff. */ /* Base = 0 */ @@ -654,7 +575,7 @@ struct nic *eepro100_probe(struct nic *nic, unsigned short *probeaddrs, struct p { char *t = (char *)&txfd.tx_desc_addr; - for (i=0;i<6;i++) + for (i=0;inode_addr[i]; } @@ -667,13 +588,12 @@ struct nic *eepro100_probe(struct nic *nic, unsigned short *probeaddrs, struct p promisc = 0; - printf ("eeprom[6] = %x \n", eeprom[6]); if ( ((eeprom[6]>>8) & 0x3f) == DP83840 || ((eeprom[6]>>8) & 0x3f) == DP83840A) { int mdi_reg23 = mdio_read(eeprom[6] & 0x1f, 23) | 0x0422; if (congenb) mdi_reg23 |= 0x0100; - printf(" DP83840 specific setup, setting register 23 to %x.\n", + printf(" DP83840 specific setup, setting register 23 to %hX.\n", mdi_reg23); mdio_write(eeprom[6] & 0x1f, 23, mdi_reg23); } @@ -701,13 +621,10 @@ struct nic *eepro100_probe(struct nic *nic, unsigned short *probeaddrs, struct p whereami ("started TX thingy (config, iasetup)."); - to = TIME_OUT; - while (!txfd.status && --to) + load_timer2(10*TICKS_PER_MS); + while (!txfd.status && timer2_running()) /* Wait */; -#ifdef DEBUG - printf ("\nLoop executed %d times.\n", TIME_OUT-to); -#endif nic->reset = eepro100_reset; nic->poll = eepro100_poll; nic->transmit = eepro100_transmit; @@ -715,17 +632,6 @@ struct nic *eepro100_probe(struct nic *nic, unsigned short *probeaddrs, struct p return nic; } -static int loops_per_usec = 300; /* totally bogus value */ - -static void udelay (int val) -{ - int c; - - for(c=0; c 0) { printf ("%X ", where); for (i=0;i < ( (n>16)?16:n);i++) - printf (" %b", ((char *)where)[i]); + printf (" %hhX", ((char *)where)[i]); printf ("\n"); n -= 16; where += 16; diff --git a/netboot/epic100.c b/netboot/epic100.c index 1eef71051..c5c3fd22e 100644 --- a/netboot/epic100.c +++ b/netboot/epic100.c @@ -5,6 +5,7 @@ #include "etherboot.h" #include "nic.h" #include "cards.h" +#include "timer.h" #include "epic100.h" #undef virt_to_bus @@ -15,8 +16,6 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Tx/Rx buffer.*/ -#define TIME_OUT 1000000 - /* #define DEBUG_RX #define DEBUG_TX @@ -83,7 +82,7 @@ static unsigned short eeprom[64]; static signed char phys[4]; /* MII device addresses. */ static struct epic_rx_desc rx_ring[RX_RING_SIZE]; static struct epic_tx_desc tx_ring[TX_RING_SIZE]; -#ifndef USE_INTERNAL_BUFFER +#ifdef USE_LOWMEM_BUFFER #define rx_packet ((char *)0x10000 - PKT_BUF_SZ * RX_RING_SIZE) #define tx_packet ((char *)0x10000 - PKT_BUF_SZ * RX_RING_SIZE - PKT_BUF_SZ * TX_RING_SIZE) #else @@ -170,7 +169,7 @@ epic100_probe(struct nic *nic, unsigned short *probeaddrs) #if (EPIC_DEBUG > 1) printf("EEPROM contents\n"); for (i = 0; i < 64; i++) { - printf(" %02x%s", eeprom[i], i % 16 == 15 ? "\n" : ""); + printf(" %hhX%s", eeprom[i], i % 16 == 15 ? "\n" : ""); } #endif #endif @@ -180,10 +179,7 @@ epic100_probe(struct nic *nic, unsigned short *probeaddrs) for (i = 0; i < 3; i++) *ap++ = inw(lan0 + i*4); - printf(" I/O %x ", ioaddr); - - for (i = 0; i < 6; i++) - printf ("%b%c", nic->node_addr[i] , i < 5 ?':':' '); + printf(" I/O %#hX %! ", ioaddr, nic->node_addr); /* Find the connected MII xcvrs. */ for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(phys); phy++) { @@ -215,7 +211,7 @@ epic100_probe(struct nic *nic, unsigned short *probeaddrs) } static void -epic100_open() +epic100_open(void) { int mii_reg5; int full_duplex = 0; @@ -253,7 +249,7 @@ epic100_open() /* Initialize the Rx and Tx rings. */ static void -epic100_init_ring() +epic100_init_ring(void) { int i; char* p; @@ -300,16 +296,14 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type, unsigned int len, const char *data) { unsigned short nstype; - unsigned short status; char* txp; - int to; int entry; /* Calculate the next Tx descriptor entry. */ entry = cur_tx % TX_RING_SIZE; if ((tx_ring[entry].status & TRING_OWN) == TRING_OWN) { - printf("eth_transmit: Unable to transmit. status=%x. Resetting...\n", + printf("eth_transmit: Unable to transmit. status=%hX. Resetting...\n", tx_ring[entry].status); epic100_open(); @@ -318,13 +312,13 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type, txp = (char*)tx_ring[entry].bufaddr; - memcpy(txp, destaddr, ETHER_ADDR_SIZE); - memcpy(txp + ETHER_ADDR_SIZE, nic->node_addr, ETHER_ADDR_SIZE); + memcpy(txp, destaddr, ETH_ALEN); + memcpy(txp + ETH_ALEN, nic->node_addr, ETH_ALEN); nstype = htons(type); memcpy(txp + 12, (char*)&nstype, 2); - memcpy(txp + ETHER_HDR_SIZE, data, len); + memcpy(txp + ETH_HLEN, data, len); - len += ETHER_HDR_SIZE; + len += ETH_HLEN; /* * Caution: the write order is important here, @@ -340,25 +334,13 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type, /* Trigger an immediate transmit demand. */ outl(CR_QUEUE_TX, command); - to = TIME_OUT; - status = tx_ring[entry].status; + load_timer2(10*TICKS_PER_MS); /* timeout 10 ms for transmit */ + while ((tx_ring[entry].status & TRING_OWN) && timer2_running()) + /* Wait */; - while ( (status & TRING_OWN) && --to) { - status = tx_ring[entry].status; - } - - if ((status & TRING_OWN) == 0) { -#ifdef DEBUG_TX - printf("tx done after %d loop(s), status %x\n", - TIME_OUT-to, tx_ring[entry].status ); -#endif - return; - } - - if (to == 0) { - printf("OOPS, Something wrong with transmitter. status=%x\n", - tx_ring[entry].status); - } + if ((tx_ring[entry].status & TRING_OWN) != 0) + printf("Oops, transmitter timeout, status=%hX\n", + tx_ring[entry].status); } /* function: epic100_poll / eth_poll @@ -376,35 +358,22 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type, static int epic100_poll(struct nic *nic) { - int to; int entry; int status; int retcode; entry = cur_rx % RX_RING_SIZE; - cur_rx++; - to = TIME_OUT; - status = rx_ring[entry].status; - while ( (status & RRING_OWN) == RRING_OWN && --to) { - status = rx_ring[entry].status; - } - - if (to == 0) { -#ifdef DEBUG_RX - printf("epic_poll: time out! status %x\n", status); -#endif - /* Restart Receiver */ - outl(CR_START_RX | CR_QUEUE_RX, command); - return 0; - } + if ((status = rx_ring[entry].status & RRING_OWN) == RRING_OWN) + return (0); /* We own the next entry, it's a new packet. Send it up. */ #if (EPIC_DEBUG > 4) - printf("epic_poll: entry %d status %8x\n", entry, status); + printf("epic_poll: entry %d status %hX\n", entry, status); #endif + cur_rx++; if (status & 0x2000) { printf("epic_poll: Giant packet\n"); retcode = 0; diff --git a/netboot/etherboot.h b/netboot/etherboot.h index 91903a28f..af27673c3 100644 --- a/netboot/etherboot.h +++ b/netboot/etherboot.h @@ -1,3 +1,27 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* RULE: You must define the macro ``GRUB'' when including this header + file in GRUB code. */ + +/* Based on "src/etherboot.h" in etherboot-5.0.5. */ + /************************************************************************** ETHERBOOT - BOOTP/TFTP Bootstrap Program @@ -6,151 +30,75 @@ Author: Martin Renters **************************************************************************/ -/* Enable GRUB-specific stuff. */ -#define GRUB 1 - -#ifdef GRUB /* Include GRUB-specific macros and prototypes here. */ -# include +#include /* FIXME: For now, enable the DHCP support. Perhaps I should segregate the DHCP support from the BOOTP support, and permit both to co-exist. */ -# undef NO_DHCP_SUPPORT +#undef NO_DHCP_SUPPORT /* In GRUB, the relocated address in Etherboot doesn't have any sense. Just define it as a bogus value. */ -# define RELOC 0 - -/* Force to use the internal buffer. */ -# define INTERNAL_BOOTP_DATA 1 - -/* Likewise. */ -# define USE_INTERNAL_BUFFER 1 +#define RELOC 0 /* FIXME: Should be an option. */ -# define BACKOFF_LIMIT 7 -#endif /* GRUB */ +#define BACKOFF_LIMIT 7 -#include "osdep.h" +#include -/* These could be customised for different languages perhaps */ -#define ASK_PROMPT "Boot from (N)etwork or from (L)ocal? " -#define ANS_NETWORK 'N' -#define ANS_LOCAL 'L' -#ifndef ANS_DEFAULT /* in case left out in Makefile */ -#define ANS_DEFAULT ANS_NETWORK -#endif - -#define TAGGED_IMAGE /* eventually optional */ -#if !defined(TAGGED_IMAGE) && !defined(AOUT_IMAGE) && !defined(ELF_IMAGE) -#define TAGGED_IMAGE /* choose at least one */ -#endif - -#ifdef GRUB -# define CTRL_C 3 -#else /* ! GRUB */ -# define ESC 0x1B -#endif /* ! GRUB */ - -#ifndef DEFAULT_BOOTFILE -#define DEFAULT_BOOTFILE "/tftpboot/kernel" -#endif - -/* Clean up console settings... mainly CONSOLE_CRT and CONSOLE_SERIAL are used - * in the sources (except start.S and serial.S which cannot include - * etherboot.h). At least one of the CONSOLE_xxx has to be set, and - * CONSOLE_DUAL sets both CONSOLE_CRT and CONSOLE_SERIAL. If none is set, - * CONSOLE_CRT is assumed. */ -#ifdef CONSOLE_DUAL -#undef CONSOLE_CRT -#define CONSOLE_CRT -#undef CONSOLE_SERIAL -#define CONSOLE_SERIAL -#endif -#if defined(CONSOLE_CRT) && defined(CONSOLE_SERIAL) -#undef CONSOLE_DUAL -#define CONSOLE_DUAL -#endif -#if !defined(CONSOLE_CRT) && !defined(CONSOLE_SERIAL) -#define CONSOLE_CRT -#endif - -#ifndef DOWNLOAD_PROTO_NFS -#undef DOWNLOAD_PROTO_TFTP -#define DOWNLOAD_PROTO_TFTP /* default booting protocol */ -#endif - -#ifdef DOWNLOAD_PROTO_TFTP -#define download(fname,loader) tftp((fname),(loader)) -#endif -#ifdef DOWNLOAD_PROTO_NFS -#define download(fname,loader) nfs((fname),(loader)) -#endif +#define CTRL_C 3 #ifndef MAX_TFTP_RETRIES -#define MAX_TFTP_RETRIES 20 +# define MAX_TFTP_RETRIES 20 #endif #ifndef MAX_BOOTP_RETRIES -#define MAX_BOOTP_RETRIES 20 +# define MAX_BOOTP_RETRIES 20 #endif -#ifndef MAX_BOOTP_EXTLEN -#if (RELOC < 0x94000) -/* Force internal buffer (if external buffer would overlap with our code...) */ -#undef INTERNAL_BOOTP_DATA -#define INTERNAL_BOOTP_DATA -#endif -/* sizeof(struct bootp_t) == 0x240 */ -#if defined(INTERNAL_BOOTP_DATA) || (RELOC >= 0x94240) -#define MAX_BOOTP_EXTLEN 1024 -#else -#define MAX_BOOTP_EXTLEN (1024-sizeof(struct bootp_t)) -#endif -#endif +#define MAX_BOOTP_EXTLEN (ETH_FRAME_LEN - ETH_HLEN - \ + sizeof (struct bootp_t)) #ifndef MAX_ARP_RETRIES -#define MAX_ARP_RETRIES 20 +# define MAX_ARP_RETRIES 20 #endif #ifndef MAX_RPC_RETRIES -#define MAX_RPC_RETRIES 20 +# define MAX_RPC_RETRIES 20 #endif #define TICKS_PER_SEC 18 /* Inter-packet retry in ticks */ -#define TIMEOUT (10*TICKS_PER_SEC) +#define TIMEOUT (10 * TICKS_PER_SEC) /* These settings have sense only if compiled with -DCONGESTED */ /* total retransmission timeout in ticks */ -#define TFTP_TIMEOUT (30*TICKS_PER_SEC) +#define TFTP_TIMEOUT (30 * TICKS_PER_SEC) /* packet retransmission timeout in ticks */ -#define TFTP_REXMT (3*TICKS_PER_SEC) +#define TFTP_REXMT (3 * TICKS_PER_SEC) #ifndef NULL -#define NULL ((void *)0) +# define NULL ((void *) 0) #endif -#define TRUE 1 -#define FALSE 0 +/* + I'm moving towards the defined names in linux/if_ether.h for clarity. + The confusion between 60/64 and 1514/1518 arose because the NS8390 + counts the 4 byte frame checksum in the incoming packet, but not + in the outgoing packet. 60/1514 are the correct numbers for most + if not all of the other NIC controllers. I will be retiring the + 64/1518 defines in the lead-up to 5.0. +*/ -#define ETHER_ADDR_SIZE 6 /* Size of Ethernet address */ -#define ETHER_HDR_SIZE 14 /* Size of ethernet header */ -#define ETH_MIN_PACKET 64 -#define ETH_MAX_PACKET 1518 - -#define VENDOR_NONE 0 -#define VENDOR_WD 1 -#define VENDOR_NOVELL 2 -#define VENDOR_3COM 3 -#define VENDOR_3C509 4 -#define VENDOR_CS89x0 5 - -#define FLAG_PIO 0x01 -#define FLAG_16BIT 0x02 -#define FLAG_790 0x04 +#define ETH_ALEN 6 /* Size of Ethernet address */ +#define ETH_HLEN 14 /* Size of ethernet header */ +#define ETH_ZLEN 60 /* Minimum packet */ +/*#define ETH_MIN_PACKET 64*/ +#define ETH_FRAME_LEN 1514 /* Maximum packet */ +/*#define ETH_MAX_PACKET 1518*/ +#define ETH_MAX_MTU (ETH_FRAME_LEN - ETH_HLEN) #define ARP_CLIENT 0 #define ARP_SERVER 1 @@ -181,7 +129,7 @@ Author: Martin Renters #define BOOTP_REQUEST 1 #define BOOTP_REPLY 2 -#define TAG_LEN(p) (*((p)+1)) +#define TAG_LEN(p) (*((p) + 1)) #define RFC1533_COOKIE 99, 130, 83, 99 #define RFC1533_PAD 0 #define RFC1533_NETMASK 1 @@ -239,6 +187,7 @@ Author: Martin Renters #define RFC2132_SRV_ID 54 #define RFC2132_PARAM_LIST 55 #define RFC2132_MAX_SIZE 57 +#define RFC2132_VENDOR_CLASS_ID 60 #define DHCPDISCOVER 1 #define DHCPOFFER 2 @@ -251,9 +200,6 @@ Author: Martin Renters #define RFC1533_VENDOR_MAGIC 128 #define RFC1533_VENDOR_ADDPARM 129 -#ifdef IMAGE_FREEBSD -#define RFC1533_VENDOR_HOWTO 132 -#endif #define RFC1533_VENDOR_MNUOPTS 160 #define RFC1533_VENDOR_SELECTION 176 #define RFC1533_VENDOR_MOTD 184 @@ -261,11 +207,10 @@ Author: Martin Renters #define RFC1533_VENDOR_IMG 192 #define RFC1533_VENDOR_NUMOFIMG 16 -#ifdef GRUB -# define RFC1533_VENDOR_CONFIGFILE 150 -#endif /* GRUB */ +#define RFC1533_VENDOR_CONFIGFILE 150 #define RFC1533_END 255 + #define BOOTP_VENDOR_LEN 64 #ifndef NO_DHCP_SUPPORT #define DHCP_OPT_LEN 312 @@ -294,129 +239,196 @@ Author: Martin Renters #define AWAIT_RPC 4 #define AWAIT_QDRAIN 5 /* drain queue, process ARP requests */ -typedef struct { - unsigned long s_addr; -} in_addr; +typedef struct +{ + unsigned long s_addr; +} +in_addr; -struct arptable_t { - in_addr ipaddr; - unsigned char node[6]; +struct arptable_t +{ + in_addr ipaddr; + unsigned char node[6]; }; /* * A pity sipaddr and tipaddr are not longword aligned or we could use * in_addr. No, I don't want to use #pragma packed. */ -struct arprequest { - unsigned short hwtype; - unsigned short protocol; - char hwlen; - char protolen; - unsigned short opcode; - char shwaddr[6]; - char sipaddr[4]; - char thwaddr[6]; - char tipaddr[4]; +struct arprequest +{ + unsigned short hwtype; + unsigned short protocol; + char hwlen; + char protolen; + unsigned short opcode; + char shwaddr[6]; + char sipaddr[4]; + char thwaddr[6]; + char tipaddr[4]; }; -struct iphdr { - char verhdrlen; - char service; - unsigned short len; - unsigned short ident; - unsigned short frags; - char ttl; - char protocol; - unsigned short chksum; - in_addr src; - in_addr dest; +struct iphdr +{ + char verhdrlen; + char service; + unsigned short len; + unsigned short ident; + unsigned short frags; + char ttl; + char protocol; + unsigned short chksum; + in_addr src; + in_addr dest; }; -struct udphdr { - unsigned short src; - unsigned short dest; - unsigned short len; - unsigned short chksum; +struct udphdr +{ + unsigned short src; + unsigned short dest; + unsigned short len; + unsigned short chksum; }; -struct bootp_t { - struct iphdr ip; - struct udphdr udp; - char bp_op; - char bp_htype; - char bp_hlen; - char bp_hops; - unsigned long bp_xid; - unsigned short bp_secs; - unsigned short unused; - in_addr bp_ciaddr; - in_addr bp_yiaddr; - in_addr bp_siaddr; - in_addr bp_giaddr; - char bp_hwaddr[16]; - char bp_sname[64]; - char bp_file[128]; +/* Format of a bootp packet. */ +struct bootp_t +{ + char bp_op; + char bp_htype; + char bp_hlen; + char bp_hops; + unsigned long bp_xid; + unsigned short bp_secs; + unsigned short unused; + in_addr bp_ciaddr; + in_addr bp_yiaddr; + in_addr bp_siaddr; + in_addr bp_giaddr; + char bp_hwaddr[16]; + char bp_sname[64]; + char bp_file[128]; #ifdef NO_DHCP_SUPPORT - char bp_vend[BOOTP_VENDOR_LEN]; + char bp_vend[BOOTP_VENDOR_LEN]; #else - char bp_vend[DHCP_OPT_LEN]; + char bp_vend[DHCP_OPT_LEN]; #endif /* NO_DHCP_SUPPORT */ }; -struct bootpd_t { - struct bootp_t bootp_reply; - unsigned char bootp_extension[MAX_BOOTP_EXTLEN]; +/* Format of a bootp IP packet. */ +struct bootpip_t +{ + struct iphdr ip; + struct udphdr udp; + struct bootp_t bp; }; -struct tftp_t { - struct iphdr ip; - struct udphdr udp; - unsigned short opcode; - union { - char rrq[TFTP_DEFAULTSIZE_PACKET]; - struct { - unsigned short block; - char download[TFTP_MAX_PACKET]; - } data; - struct { - unsigned short block; - } ack; - struct { - unsigned short errcode; - char errmsg[TFTP_DEFAULTSIZE_PACKET]; - } err; - struct { - char data[TFTP_DEFAULTSIZE_PACKET+2]; - } oack; - } u; +/* Format of bootp packet with extensions. */ +struct bootpd_t +{ + struct bootp_t bootp_reply; + unsigned char bootp_extension[MAX_BOOTP_EXTLEN]; +}; + +struct tftp_t +{ + struct iphdr ip; + struct udphdr udp; + unsigned short opcode; + union + { + char rrq[TFTP_DEFAULTSIZE_PACKET]; + + struct + { + unsigned short block; + char download[TFTP_MAX_PACKET]; + } + data; + + struct + { + unsigned short block; + } + ack; + + struct + { + unsigned short errcode; + char errmsg[TFTP_DEFAULTSIZE_PACKET]; + } + err; + + struct + { + char data[TFTP_DEFAULTSIZE_PACKET+2]; + } + oack; + } + u; +}; + +/* Define a smaller tftp packet solely for making requests to conserve stack + 512 bytes should be enough. */ +struct tftpreq_t +{ + struct iphdr ip; + struct udphdr udp; + unsigned short opcode; + union + { + char rrq[512]; + + struct + { + unsigned short block; + } + ack; + + struct + { + unsigned short errcode; + char errmsg[512-2]; + } + err; + } + u; }; #define TFTP_MIN_PACKET (sizeof(struct iphdr) + sizeof(struct udphdr) + 4) -struct rpc_t { - struct iphdr ip; - struct udphdr udp; - union { - char data[300]; /* longest RPC call must fit!!!! */ - struct { - long id; - long type; - long rpcvers; - long prog; - long vers; - long proc; - long data[1]; - } call; - struct { - long id; - long type; - long rstatus; - long verifier; - long v2; - long astatus; - long data[1]; - } reply; - } u; +struct rpc_t +{ + struct iphdr ip; + struct udphdr udp; + union + { + char data[300]; /* longest RPC call must fit!!!! */ + + struct + { + long id; + long type; + long rpcvers; + long prog; + long vers; + long proc; + long data[1]; + } + call; + + struct + { + long id; + long type; + long rstatus; + long verifier; + long v2; + long astatus; + long data[1]; + } + reply; + } + u; }; #define PROG_PORTMAP 100000 @@ -446,179 +458,85 @@ struct rpc_t { #define NFS_READ_SIZE 1024 #define FLOPPY_BOOT_LOCATION 0x7c00 +/* Must match offsets in loader.S */ +#define ROM_SEGMENT 0x1fa +#define ROM_LENGTH 0x1fc -#define ROM_INFO_LOCATION 0x7dfa +#define ROM_INFO_LOCATION (FLOPPY_BOOT_LOCATION + ROM_SEGMENT) /* at end of floppy boot block */ -struct rom_info { - unsigned short rom_segment; - unsigned short rom_length; +struct rom_info +{ + unsigned short rom_segment; + unsigned short rom_length; +}; + +static inline int +rom_address_ok (struct rom_info *rom, int assigned_rom_segment) +{ + return (assigned_rom_segment < 0xC000 + || assigned_rom_segment == rom->rom_segment); +} + +/* Define a type for passing info to a loaded program. */ +struct ebinfo +{ + unsigned char major, minor; /* Version */ + unsigned short flags; /* Bit flags */ }; /*************************************************************************** External prototypes ***************************************************************************/ /* main.c */ -#ifdef GRUB -extern void print_network_configuration P((void)); -extern int ifconfig P((char *ip, char *sm, char *gw, char *svr)); -#endif /* GRUB */ - -#ifndef GRUB -extern void print_bytes P((unsigned char *bytes, int len)); -extern void load P((void)); -extern int load_linux P((int root_mount_port,int swap_mount_port, - int root_nfs_port,char *kernel_handle)); -extern int downloadkernel P((unsigned char *, int, int, int)); -extern int tftp P((const char *name, int (*)(unsigned char *, int, int, int))); -extern void rpc_init(void); -extern int nfs P((const char *name, int (*)(unsigned char *, int, int, int))); -extern void nfs_umountall P((int)); -#endif /* ! GRUB */ -extern int bootp P((void)); -extern int rarp P((void)); -extern int udp_transmit P((unsigned long destip, unsigned int srcsock, - unsigned int destsock, int len, const void *buf)); - -extern int await_reply P((int type, int ival, void *ptr, int timeout)); -extern int decode_rfc1533 P((unsigned char *, int, int, int)); -extern unsigned short ipchksum P((unsigned short *, int len)); -extern void rfc951_sleep P((int)); -extern void cleanup_net P((void)); -extern void cleanup P((void)); +extern void print_network_configuration (void); +extern int ifconfig (char *ip, char *sm, char *gw, char *svr); +extern int udp_transmit (unsigned long destip, unsigned int srcsock, + unsigned int destsock, int len, const void *buf); +extern int await_reply (int type, int ival, void *ptr, int timeout); +extern int decode_rfc1533 (unsigned char *, int, int, int); +extern long rfc2131_sleep_interval (int base, int exp); +extern void cleanup (void); +extern int rarp (void); +extern int bootp (void); +extern void cleanup_net (void); /* config.c */ -extern void print_config(void); -extern void eth_reset(void); -extern int eth_probe(void); -extern int eth_poll(void); -extern void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p); -extern void eth_disable(void); - -#ifndef GRUB -/* bootmenu.c */ -extern int execute P((char *string)); -extern void bootmenu P((int)); -extern void show_motd P((void)); -extern void parse_menuopts P((char *,int)); -extern int getoptvalue P((char **, int *, int *)); -extern void selectImage P((char **)); - -/* osloader.c */ -#if defined(AOUT_IMAGE) || defined(ELF_IMAGE) -extern int howto; -#endif -extern int os_download P((unsigned int, unsigned char *,unsigned int)); -#endif /* ! GRUB */ +extern void print_config (void); +extern void eth_reset (void); +extern int eth_probe (void); +extern int eth_poll (void); +extern void eth_transmit (const char *d, unsigned int t, + unsigned int s, const void *p); +extern void eth_disable (void); /* misc.c */ -extern void twiddle P((void)); -extern void sleep P((int secs)); -#ifndef GRUB -extern int strcasecmp P((char *a, char *b)); -extern char *substr P((char *a, char *b)); -#endif /* ! GRUB */ -extern int getdec P((char **)); -#ifndef GRUB -extern void printf P((const char *, ...)); -extern char *sprintf P((char *, const char *, ...)); -#endif /* ! GRUB */ -extern int inet_aton P((char *p, in_addr *i)); -#ifndef GRUB -extern void gateA20_set P((void)); -extern void gateA20_unset P((void)); -extern void putchar P((int)); -extern int getchar P((void)); -extern int iskey P((void)); - -/* start*.S */ -extern int getc P((void)); -extern void putc P((int)); -extern int ischar P((void)); -extern int getshift P((void)); -extern unsigned int memsize P((void)); -extern unsigned short basememsize P((void)); -extern void disk_init P((void)); -extern unsigned int disk_read P((int drv,int c,int h,int s,char *buf)); -extern void xstart P((unsigned long, unsigned long, char *)); -extern unsigned long currticks P((void)); -extern int setjmp P((void *jmpbuf)); -extern void longjmp P((void *jmpbuf, int where)); -extern void exit P((int status)); -extern void slowdownio P((void)); - -/* serial.S */ -extern int serial_getc P((void)); -extern void serial_putc P((int)); -extern int serial_ischar P((void)); -extern int serial_init P((void)); - -/* ansiesc.c */ -extern void ansi_reset P((void)); -extern void enable_cursor P((int)); -extern void handleansi P((unsigned char)); - -/* md5.c */ -extern void md5_put P((unsigned int ch)); -extern void md5_done P((unsigned char *buf)); - -/* floppy.c */ -extern int bootdisk P((int dev,int part)); -#endif /* ! GRUB */ +extern void twiddle (void); +extern void sleep (int secs); +extern int getdec (char **s); +extern void etherboot_printf (const char *, ...); +extern int etherboot_sprintf (char *, const char *, ...); +extern int inet_aton (char *p, in_addr *i); /*************************************************************************** External variables ***************************************************************************/ /* main.c */ -#ifdef GRUB extern int ip_abort; extern int network_ready; -#endif /* GRUB */ - -#ifndef GRUB -extern const char *kernel; -extern char kernel_buf[128]; -#endif /* ! GRUB */ extern struct rom_info rom; -#ifndef GRUB -extern int hostnamelen; -extern unsigned long netmask; -extern int jmp_bootmenu[10]; -#endif /* ! GRUB */ extern struct arptable_t arptable[MAX_ARP]; -#ifndef GRUB -#ifdef IMAGE_MENU -extern char *motd[RFC1533_VENDOR_NUMOFMOTD]; -extern int menutmo,menudefault; -extern unsigned char *defparams; -extern int defparams_max; -#endif -#endif /* ! GRUB */ -#if defined(ETHERBOOT32) && !defined(INTERNAL_BOOTP_DATA) -#define BOOTP_DATA_ADDR ((struct bootpd_t *)0x93C00) -#else extern struct bootpd_t bootp_data; #define BOOTP_DATA_ADDR (&bootp_data) -#endif extern unsigned char *end_of_rfc1533; -#ifdef IMAGE_FREEBSD -extern int freebsd_howto; -#endif /* config.c */ extern struct nic nic; -/* bootmenu.c */ - -/* osloader.c */ - +/* Local hack - define some macros to use etherboot source files "as is". */ #ifndef GRUB -/* created by linker */ -extern char _start[], _edata[], _end[]; -#endif /* ! GRUB */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ +# undef printf +# define printf etherboot_printf +# undef sprintf +# define sprintf etherboot_sprintf +#endif /* GRUB */ diff --git a/netboot/fa311.c b/netboot/fa311.c new file mode 100644 index 000000000..df92a6837 --- /dev/null +++ b/netboot/fa311.c @@ -0,0 +1,421 @@ +/* + Driver for the National Semiconductor DP83810 Ethernet controller. + + Portions Copyright (C) 2001 Inprimis Technologies, Inc. + http://www.inprimis.com/ + + This driver is based (heavily) on the Linux driver for this chip + which is copyright 1999-2001 by Donald Becker. + + This software has no warranties expressed or implied for any + purpose. + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. License for under other terms may be + available. Contact the original author for details. + + The original author may be reached as becker@scyld.com, or at + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 +*/ + + +typedef unsigned char u8; +typedef signed char s8; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned int u32; +typedef signed int s32; + +#include "etherboot.h" +#include "nic.h" +#include "pci.h" + +#undef virt_to_bus +#define virt_to_bus(x) ((unsigned long)x) +#define cpu_to_le32(val) (val) +#define le32_to_cpu(val) (val) +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + +#define TX_RING_SIZE 1 +#define RX_RING_SIZE 4 +#define TIME_OUT 1000000 +#define PKT_BUF_SZ 1536 + +/* Offsets to the device registers. */ +enum register_offsets { + ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, PCIBusCfg=0x0C, + IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18, + TxRingPtr=0x20, TxConfig=0x24, + RxRingPtr=0x30, RxConfig=0x34, + WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C, + BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60, + RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64, +}; + +/* Bit in ChipCmd. */ +enum ChipCmdBits { + ChipReset=0x100, RxReset=0x20, TxReset=0x10, RxOff=0x08, RxOn=0x04, + TxOff=0x02, TxOn=0x01, +}; + +/* Bits in the interrupt status/mask registers. */ +enum intr_status_bits { + IntrRxDone=0x0001, IntrRxIntr=0x0002, IntrRxErr=0x0004, IntrRxEarly=0x0008, + IntrRxIdle=0x0010, IntrRxOverrun=0x0020, + IntrTxDone=0x0040, IntrTxIntr=0x0080, IntrTxErr=0x0100, + IntrTxIdle=0x0200, IntrTxUnderrun=0x0400, + StatsMax=0x0800, LinkChange=0x4000, WOLPkt=0x2000, + RxResetDone=0x1000000, TxResetDone=0x2000000, + IntrPCIErr=0x00f00000, IntrNormalSummary=0x0251, IntrAbnormalSummary=0xED20, +}; + +/* Bits in the RxMode register. */ +enum rx_mode_bits { + AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0xC0000000, + AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000, + AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000, +}; + +/* Bits in network_desc.status */ +enum desc_status_bits { + DescOwn=0x80000000, DescMore=0x40000000, DescIntr=0x20000000, + DescNoCRC=0x10000000, + DescPktOK=0x08000000, RxTooLong=0x00400000, +}; + +/* The Rx and Tx buffer descriptors. */ +struct netdev_desc { + u32 next_desc; + s32 cmd_status; + u32 addr; +}; + +static struct FA311_DEV { + unsigned int ioaddr; + unsigned short vendor; + unsigned short device; + unsigned int cur_rx; + unsigned int cur_tx; + unsigned int rx_buf_sz; + volatile struct netdev_desc *rx_head_desc; + volatile struct netdev_desc rx_ring[RX_RING_SIZE] __attribute__ ((aligned (4))); + volatile struct netdev_desc tx_ring[TX_RING_SIZE] __attribute__ ((aligned (4))); +} fa311_dev; + +static int eeprom_read(long ioaddr, int location); +static void init_ring(struct FA311_DEV *dev); +static void fa311_reset(struct nic *nic); +static int fa311_poll(struct nic *nic); +static void fa311_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p); +static void fa311_disable(struct nic *nic); + +static char rx_packet[PKT_BUF_SZ * RX_RING_SIZE] __attribute__ ((aligned (4))); +static char tx_packet[PKT_BUF_SZ * TX_RING_SIZE] __attribute__ ((aligned (4))); + +struct nic * fa311_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci) +{ +int prev_eedata; +int i; +int duplex; +int tx_config; +int rx_config; +unsigned char macaddr[6]; +unsigned char mactest; +unsigned char pci_bus = 0; +struct FA311_DEV* dev = &fa311_dev; + + if (io_addrs == 0 || *io_addrs == 0) + return (0); + memset(dev, 0, sizeof(*dev)); + dev->vendor = pci->vendor; + dev->device = pci->dev_id; + dev->ioaddr = pci->membase; + + /* Work around the dropped serial bit. */ + prev_eedata = eeprom_read(dev->ioaddr, 6); + for (i = 0; i < 3; i++) { + int eedata = eeprom_read(dev->ioaddr, i + 7); + macaddr[i*2] = (eedata << 1) + (prev_eedata >> 15); + macaddr[i*2+1] = eedata >> 7; + prev_eedata = eedata; + } + mactest = 0; + for (i = 0; i < 6; i++) + mactest |= macaddr[i]; + if (mactest == 0) + return (0); + for (i = 0; i < 6; i++) + nic->node_addr[i] = macaddr[i]; + printf("%! ", nic->node_addr); + + adjust_pci_device(pci); + + fa311_reset(nic); + + nic->reset = fa311_reset; + nic->disable = fa311_disable; + nic->poll = fa311_poll; + nic->transmit = fa311_transmit; + + init_ring(dev); + + writel(virt_to_bus(dev->rx_ring), dev->ioaddr + RxRingPtr); + writel(virt_to_bus(dev->tx_ring), dev->ioaddr + TxRingPtr); + + for (i = 0; i < 6; i += 2) + { + writel(i, dev->ioaddr + RxFilterAddr); + writew(macaddr[i] + (macaddr[i+1] << 8), + dev->ioaddr + RxFilterData); + } + + /* Initialize other registers. */ + /* Configure for standard, in-spec Ethernet. */ + if (readl(dev->ioaddr + ChipConfig) & 0x20000000) + { /* Full duplex */ + tx_config = 0xD0801002; + rx_config = 0x10000020; + } + else + { + tx_config = 0x10801002; + rx_config = 0x0020; + } + writel(tx_config, dev->ioaddr + TxConfig); + writel(rx_config, dev->ioaddr + RxConfig); + + duplex = readl(dev->ioaddr + ChipConfig) & 0x20000000 ? 1 : 0; + if (duplex) { + rx_config |= 0x10000000; + tx_config |= 0xC0000000; + } else { + rx_config &= ~0x10000000; + tx_config &= ~0xC0000000; + } + writew(tx_config, dev->ioaddr + TxConfig); + writew(rx_config, dev->ioaddr + RxConfig); + + writel(AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys, + dev->ioaddr + RxFilterAddr); + + writel(RxOn | TxOn, dev->ioaddr + ChipCmd); + writel(4, dev->ioaddr + StatsCtrl); /* Clear Stats */ + return nic; + +} + +static void fa311_reset(struct nic *nic) +{ +u32 chip_config; +struct FA311_DEV* dev = &fa311_dev; + + /* Reset the chip to erase previous misconfiguration. */ + outl(ChipReset, dev->ioaddr + ChipCmd); + + if ((readl(dev->ioaddr + ChipConfig) & 0xe000) != 0xe000) + { + chip_config = readl(dev->ioaddr + ChipConfig); + } +} + +static int fa311_poll(struct nic *nic) +{ +s32 desc_status; +int to; +int entry; +int retcode; +struct FA311_DEV* dev = &fa311_dev; + + retcode = 0; + entry = dev->cur_rx; + to = TIME_OUT; + while (to != 0) + { + desc_status = dev->rx_ring[entry].cmd_status; + if ((desc_status & DescOwn) != 0) + break; + else + --to; + } + if (to != 0) + { + readl(dev->ioaddr + IntrStatus); /* clear interrrupt bits */ + /* driver owns the next entry it's a new packet. Send it up. */ + if ((desc_status & (DescMore|DescPktOK|RxTooLong)) == DescPktOK) + { + nic->packetlen = (desc_status & 0x0fff) - 4; /* Omit CRC size. */ + memcpy(nic->packet, (char*)(dev->rx_ring[entry].addr), nic->packetlen); + retcode = 1; + } + /* Give the descriptor back to the chip */ + dev->rx_ring[entry].cmd_status = cpu_to_le32(dev->rx_buf_sz); + dev->cur_rx++; + if (dev->cur_rx >= RX_RING_SIZE) + dev->cur_rx = 0; + dev->rx_head_desc = &dev->rx_ring[dev->cur_rx]; + } + /* Restart Rx engine if stopped. */ + writel(RxOn, dev->ioaddr + ChipCmd); + return retcode; +} + +static void fa311_transmit(struct nic *nic, const char *destaddr, unsigned int type, unsigned int len, const char *data) +{ +unsigned short nstype; +s32 desc_status; +int to; +int entry; +char* txp; +unsigned char* s; +struct FA311_DEV* dev = &fa311_dev; + + /* Calculate the next Tx descriptor entry. */ + entry = dev->cur_tx; + txp = (char*)(dev->tx_ring[entry].addr); + + memcpy(txp, destaddr, ETH_ALEN); + memcpy(txp + ETH_ALEN, nic->node_addr, ETH_ALEN); + nstype = htons(type); + memcpy(txp + 12, (char*)&nstype, 2); + memcpy(txp + ETH_HLEN, data, len); + len += ETH_HLEN; + /* pad frame */ + if (len < ETH_ZLEN) + { + s = (unsigned char*)(txp+len); + while (s < (unsigned char*)(txp+ETH_ZLEN)) + *s++ = 0; + len = ETH_ZLEN; + } + dev->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | len); + dev->cur_tx++; + if (dev->cur_tx >= TX_RING_SIZE) + dev->cur_tx = 0; + + /* Wake the potentially-idle transmit channel. */ + writel(TxOn, dev->ioaddr + ChipCmd); + + /* wait for tranmission to complete */ + to = TIME_OUT; + while (to != 0) + { + desc_status = dev->tx_ring[entry].cmd_status; + if ((desc_status & DescOwn) == 0) + break; + else + --to; + } + + readl(dev->ioaddr + IntrStatus); /* clear interrrupt bits */ + return; +} + +static void fa311_disable(struct nic *nic) +{ +struct FA311_DEV* dev = &fa311_dev; + + /* Stop the chip's Tx and Rx processes. */ + writel(RxOff | TxOff, dev->ioaddr + ChipCmd); +} + + +/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. + The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. */ + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need + a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that + made udelay() unreliable. + The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is + depricated. +*/ +#define eeprom_delay(ee_addr) inl(ee_addr) + +enum EEPROM_Ctrl_Bits { + EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02, +}; +#define EE_Write0 (EE_ChipSelect) +#define EE_Write1 (EE_ChipSelect | EE_DataIn) + +/* The EEPROM commands include the alway-set leading bit. */ +enum EEPROM_Cmds { + EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), +}; + + +static int eeprom_read(long addr, int location) +{ + int i; + int retval = 0; + int ee_addr = addr + EECtrl; + int read_cmd = location | EE_ReadCmd; + writel(EE_Write0, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0; + writel(dataval, ee_addr); + eeprom_delay(ee_addr); + writel(dataval | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + } + writel(EE_ChipSelect, ee_addr); + eeprom_delay(ee_addr); + + for (i = 0; i < 16; i++) { + writel(EE_ChipSelect | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + retval |= (readl(ee_addr) & EE_DataOut) ? 1 << i : 0; + writel(EE_ChipSelect, ee_addr); + eeprom_delay(ee_addr); + } + + /* Terminate the EEPROM access. */ + writel(EE_Write0, ee_addr); + writel(0, ee_addr); + return retval; +} + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void init_ring(struct FA311_DEV *dev) +{ + int i; + + dev->cur_rx = 0; + dev->cur_tx = 0; + + dev->rx_buf_sz = PKT_BUF_SZ; + dev->rx_head_desc = &dev->rx_ring[0]; + + /* Initialize all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) { + dev->rx_ring[i].next_desc = virt_to_le32desc(&dev->rx_ring[i+1]); + dev->rx_ring[i].cmd_status = DescOwn; + } + /* Mark the last entry as wrapping the ring. */ + dev->rx_ring[i-1].next_desc = virt_to_le32desc(&dev->rx_ring[0]); + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + dev->rx_ring[i].addr = (u32)(&rx_packet[PKT_BUF_SZ * i]); + dev->rx_ring[i].cmd_status = cpu_to_le32(dev->rx_buf_sz); + } + + for (i = 0; i < TX_RING_SIZE; i++) { + dev->tx_ring[i].next_desc = virt_to_le32desc(&dev->tx_ring[i+1]); + dev->tx_ring[i].cmd_status = 0; + } + dev->tx_ring[i-1].next_desc = virt_to_le32desc(&dev->tx_ring[0]); + + for (i = 0; i < TX_RING_SIZE; i++) + dev->tx_ring[i].addr = (u32)(&tx_packet[PKT_BUF_SZ * i]); + return; +} + diff --git a/netboot/fsys_tftp.c b/netboot/fsys_tftp.c index 2bc2f25c1..cffb85f78 100644 --- a/netboot/fsys_tftp.c +++ b/netboot/fsys_tftp.c @@ -30,6 +30,7 @@ Author: Martin Renters #include +#define GRUB 1 #include #include @@ -56,13 +57,15 @@ buf_fill (int abort) while (! buf_eof && (buf_read + packetsize <= FSYS_BUFLEN)) { struct tftp_t *tr; - + long timeout; + #ifdef CONGESTED - if (! await_reply (AWAIT_TFTP, iport, NULL, - block ? TFTP_REXMT : TIMEOUT)) + timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry); #else - if (! await_reply (AWAIT_TFTP, iport, NULL, TIMEOUT)) + timeout = rfc2131_sleep_interval (TIMEOUT, retry); #endif + + if (! await_reply (AWAIT_TFTP, iport, NULL, timeout)) { if (ip_abort) return 0; @@ -73,7 +76,6 @@ buf_fill (int abort) #ifdef TFTP_DEBUG grub_printf ("Maybe initial request was lost.\n"); #endif - rfc951_sleep (retry); if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp)) return 0; @@ -98,7 +100,7 @@ buf_fill (int abort) return 0; } - tr = (struct tftp_t *) &nic.packet[ETHER_HDR_SIZE]; + tr = (struct tftp_t *) &nic.packet[ETH_HLEN]; if (tr->opcode == ntohs (TFTP_ERROR)) { grub_printf ("TFTP error %d (%s)\n", @@ -161,7 +163,9 @@ buf_fill (int abort) tp.u.err.errcode = 8; len = (grub_sprintf ((char *) tp.u.err.errmsg, "RFC1782 error") - + TFTP_MIN_PACKET + 1); + + sizeof (tp.ip) + sizeof (tp.udp) + + sizeof (tp.opcode) + sizeof (tp.u.err.errcode) + + 1); udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, ntohs (tr->udp.src), len, &tp); @@ -413,7 +417,7 @@ tftp_dir (char *dirname) grub_printf ("tftp_dir (%s)\n", dirname); #endif - /* In TFTP, there is no way to know what files exis. */ + /* In TFTP, there is no way to know what files exist. */ if (print_possibilities) return 1; @@ -429,7 +433,7 @@ tftp_dir (char *dirname) len = (grub_sprintf ((char *) tp.u.rrq, "%s%coctet%cblksize%c%d%ctsize%c0", dirname, 0, 0, 0, TFTP_MAX_PACKET, 0, 0) - + sizeof (struct iphdr) + sizeof (struct udphdr) + 2 + 1); + + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1); /* Restore the original DIRNAME. */ dirname[grub_strlen (dirname)] = ch; /* Save the TFTP packet so that we can reopen the file later. */ diff --git a/netboot/i82586.c b/netboot/i82586.c index e47abf75c..15540c24d 100644 --- a/netboot/i82586.c +++ b/netboot/i82586.c @@ -14,6 +14,9 @@ Ken Yap, January 1998 #include "etherboot.h" #include "nic.h" #include "cards.h" +#include "timer.h" + +#define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000) /* Sources of information: @@ -273,12 +276,7 @@ static void setup_rx_buffers(struct nic *nic) rx_cmd[2] = cur_rx_buf + RX_BUF_SIZE; rx_cmd[3] = cur_rx_buf + 22; rx_cmd[13] = cur_rx_buf + 0x20 + scb_base; -#ifdef ETHERBOOT32 memcpy((char *)write_ptr, (char *)rx_cmd, sizeof(rx_cmd)); -#endif -#ifdef ETHERBOOT16 - memcpyf(write_ptr, (char *)rx_cmd, sizeof(rx_cmd)); -#endif rx_tail = cur_rx_buf; cur_rx_buf += RX_BUF_SIZE; } while (cur_rx_buf <= RX_BUF_END - RX_BUF_SIZE); @@ -287,27 +285,14 @@ static void setup_rx_buffers(struct nic *nic) write_ptr = mem_start + rx_tail; rx_cmd[1] = 0xC000; rx_cmd[2] = rx_head; -#ifdef ETHERBOOT32 memcpy((char *)write_ptr, (char *)rx_cmd, sizeof(unsigned short) * 3); -#endif -#ifdef ETHERBOOT16 - memcpyf(write_ptr, (char *)rx_cmd, sizeof(unsigned short) * 3); -#endif } static void ack_status(void) { unsigned short cmd, status; -#ifdef ETHERBOOT32 unsigned short *shmem = (short *)mem_start; -#endif -#ifdef ETHERBOOT16 - unsigned short shmem[CONFIG_CMD>>1]; -#endif -#ifdef ETHERBOOT16 - read_mem(mem_start, shmem); -#endif cmd = (status = shmem[iSCB_STATUS>>1]) & 0xf000; if (status & 0x100) /* CU suspended? */ cmd |= CUC_RESUME; @@ -320,11 +305,8 @@ static void ack_status(void) if (cmd == 0) /* Nothing to do */ return; shmem[iSCB_CMD>>1] = cmd; -#ifdef ETHERBOOT16 - memcpyf(mem_start, shmem, sizeof(shmem)); -#endif #if defined(DEBUG) - printf("Status %x Command %x\n", status, cmd); + printf("Status %hX Command %hX\n", status, cmd); #endif outb(0, ioaddr + I82586_ATTN); } @@ -336,12 +318,7 @@ RESET - Reset adapter static void i82586_reset(struct nic *nic) { unsigned long time; -#ifdef ETHERBOOT32 unsigned short *shmem = (short *)mem_start; -#endif -#ifdef ETHERBOOT16 - unsigned short shmem[CONFIG_CMD>>1]; -#endif /* put the card in its initial state */ @@ -358,16 +335,9 @@ static void i82586_reset(struct nic *nic) /* Write the words at 0xfff6. */ /* Write the words at 0x0000. */ /* Fill in the station address. */ -#ifdef ETHERBOOT32 memcpy((char *)(mem_end - 10), (char *)init_words, 10); memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10); - memcpy((char *)mem_start + SA_OFFSET, nic->node_addr, ETHER_ADDR_SIZE); -#endif -#ifdef ETHERBOOT16 - memcpyf(mem_end - 10, (char *)init_words, 10); - memcpyf(mem_start, (char *)&init_words[5], sizeof(init_words) - 10); - memcpyf(mem_start + SA_OFFSET, nic->node_addr, ETHER_ADDR_SIZE); -#endif + memcpy((char *)mem_start + SA_OFFSET, nic->node_addr, ETH_ALEN); setup_rx_buffers(nic); #ifdef INCLUDE_3C507 @@ -380,14 +350,11 @@ static void i82586_reset(struct nic *nic) outb(0, ioaddr + I82586_ATTN); time = currticks() + TICKS_PER_SEC; /* allow 1 second to init */ while ( -#ifdef ETHERBOOT16 - read_mem(mem_start, shmem), -#endif shmem[iSCB_STATUS>>1] == 0) { if (currticks() > time) { - printf("i82586 initialisation timed out with status %x, cmd %x\n", + printf("i82586 initialisation timed out with status %hX, cmd %hX\n", shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]); break; } @@ -400,10 +367,7 @@ static void i82586_reset(struct nic *nic) outb(0x80, ioaddr + MISC_CTRL); #endif #if defined(DEBUG) -#ifdef ETHERBOOT16 - read_mem(mem_start, shmem); -#endif - printf("i82586 status %x, cmd %x\n", + printf("i82586 status %hX, cmd %hX\n", shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]); #endif } @@ -416,18 +380,10 @@ static int i82586_poll(struct nic *nic) int status; unsigned short rfd_cmd, next_rx_frame, data_buffer_addr, frame_status, pkt_len; -#ifdef ETHERBOOT32 unsigned short *shmem = (short *)mem_start + rx_head; -#endif -#ifdef ETHERBOOT16 - unsigned short shmem[16]; -#endif /* return true if there's an ethernet packet ready to read */ if ( -#ifdef ETHERBOOT16 - read_mem(mem_start + rx_head, shmem), -#endif ((frame_status = shmem[0]) & 0x8000) == 0) return (0); /* nope */ rfd_cmd = shmem[1]; @@ -444,14 +400,9 @@ static int i82586_poll(struct nic *nic) { /* We have a frame, copy it to our buffer */ pkt_len &= 0x3FFF; -#ifdef ETHERBOOT32 memcpy(nic->packet, (char *)mem_start + rx_head + 0x20, pkt_len); -#endif -#ifdef ETHERBOOT16 - fmemcpy(nic->packet, mem_start + rx_head + 0x20, pkt_len); -#endif /* Only packets not from ourself */ - if (memcmp(nic->packet + ETHER_ADDR_SIZE, nic->node_addr, ETHER_ADDR_SIZE) != 0) + if (memcmp(nic->packet + ETH_ALEN, nic->node_addr, ETH_ALEN) != 0) { nic->packetlen = pkt_len; status = 1; @@ -460,14 +411,7 @@ static int i82586_poll(struct nic *nic) /* Clear the status word and set EOL on Rx frame */ shmem[0] = 0; shmem[1] = 0xC000; -#ifdef ETHERBOOT16 - memcpyf(mem_start + rx_head, shmem, sizeof(unsigned short) * 2); - /* Clear the EOL on previous RFD */ - memcpyf(mem_start + rx_tail + 2, shmem, sizeof(unsigned short)); -#endif -#ifdef ETHERBOOT32 *(short *)(mem_start + rx_tail + 2) = 0; -#endif rx_tail = rx_head; rx_head = next_rx_frame; ack_status(); @@ -499,66 +443,35 @@ static void i82586_transmit( CmdNOp, /* Nop command */ TX_BUF_START+16 /* Next is myself */ }; -#ifdef ETHERBOOT32 unsigned short *shmem = (short *)mem_start + TX_BUF_START; -#endif -#ifdef ETHERBOOT16 - unsigned short shmem[11]; -#endif /* send the packet to destination */ /* adjust some contents */ type = htons(t); - if (s < ETH_MIN_PACKET) - s = ETH_MIN_PACKET; - tx_cmd[4] = (s + ETHER_HDR_SIZE) | 0x8000; + if (s < ETH_ZLEN) + s = ETH_ZLEN; + tx_cmd[4] = (s + ETH_HLEN) | 0x8000; tx_cmd[6] = TX_BUF_START + 22 + scb_base; bptr = mem_start + TX_BUF_START; -#ifdef ETHERBOOT32 memcpy((char *)bptr, (char *)tx_cmd, sizeof(tx_cmd)); bptr += sizeof(tx_cmd); - memcpy((char *)bptr, d, ETHER_ADDR_SIZE); - bptr += ETHER_ADDR_SIZE; - memcpy((char *)bptr, nic->node_addr, ETHER_ADDR_SIZE); - bptr += ETHER_ADDR_SIZE; + memcpy((char *)bptr, d, ETH_ALEN); + bptr += ETH_ALEN; + memcpy((char *)bptr, nic->node_addr, ETH_ALEN); + bptr += ETH_ALEN; memcpy((char *)bptr, (char *)&type, sizeof(type)); bptr += sizeof(type); memcpy((char *)bptr, p, s); /* Change the offset in the IDLELOOP */ *(unsigned short *)(mem_start + IDLELOOP + 4) = TX_BUF_START; -#endif -#ifdef ETHERBOOT16 - memcpyf(bptr, (char *)tx_cmd, sizeof(tx_cmd)); - bptr += sizeof(tx_cmd); - memcpyf(bptr, d, ETHER_ADDR_SIZE); - bptr += ETHER_ADDR_SIZE; - memcpyf(bptr, nic->node_addr, ETHER_ADDR_SIZE); - bptr += ETHER_ADDR_SIZE; - memcpyf(bptr, (char *)&type, sizeof(type)); - bptr += sizeof(type); - memcpyf(bptr, p, s); - /* Change the offset in the IDLELOOP */ - z = TX_BUF_START; - memcpyf(mem_start + IDLELOOP + 4, (char *)&z, sizeof(z)); -#endif /* Wait for transmit completion */ while ( -#ifdef ETHERBOOT16 - read_mem(mem_start + TX_BUF_START, shmem), -#endif (shmem[0] & 0x2000) == 0) ; /* Change the offset in the IDLELOOP back and change the final loop to point here */ -#ifdef ETHERBOOT32 *(unsigned short *)(mem_start + IDLELOOP + 4) = IDLELOOP; *(unsigned short *)(mem_start + TX_BUF_START + 20) = IDLELOOP; -#endif -#ifdef ETHERBOOT16 - z = IDLELOOP; - memcpyf(mem_start + IDLELOOP + 4, (char *)&z, sizeof(z)); - memcpyf(mem_start + TX_BUF_START + 20, (char *)&z, sizeof(z)); -#endif ack_status(); } @@ -567,22 +480,11 @@ static void i82586_transmit( ***************************************************************************/ static void i82586_disable(struct nic *nic) { -#ifdef ETHERBOOT32 unsigned short *shmem = (short *)mem_start; -#endif -#ifdef ETHERBOOT16 - unsigned short shmem[CONFIG_CMD>>1]; -#endif #if 0 /* Flush the Tx and disable Rx. */ -#ifdef ETHERBOOT16 - read_mem(mem_start, shmem); -#endif shmem[iSCB_CMD>>1] = RX_SUSPEND | CUC_SUSPEND; -#ifdef ETHERBOOT16 - memcpyf(mem_start, shmem, sizeof(shmem)); -#endif outb(0, ioaddr + I82586_ATTN); #ifdef INCLUDE_NI5210 outb(0, ioaddr + NI52_RESET); @@ -618,17 +520,14 @@ static int t507_probe1(struct nic *nic, unsigned short ioaddr) mem_end = mem_start + size; scb_base = 65536L - size; if_port = inb(ioaddr + ROM_CONFIG) & 0x80; - printf("\n3c507 ioaddr 0x%x, IRQ %d, mem [0x%X-0x%X], %sternal xcvr, addr ", - ioaddr, irq, mem_start, mem_end, if_port ? "in" : "ex"); /* Get station address */ outb(0x01, ioaddr + MISC_CTRL); - for (i = 0; i < ETHER_ADDR_SIZE; ++i) + for (i = 0; i < ETH_ALEN; ++i) { - printf("%b", nic->node_addr[i] = inb(ioaddr+i)); - if (i < ETHER_ADDR_SIZE -1) - printf(":"); + nic->node_addr[i] = inb(ioaddr+i); } - putchar('\n'); + printf("\n3c507 ioaddr %#hX, IRQ %d, mem [%#X-%#X], %sternal xcvr, addr %!\n", + ioaddr, irq, mem_start, mem_end, if_port ? "in" : "ex", nic->node_addr); return (1); } @@ -695,46 +594,28 @@ static int ni5210_probe2(void) /* Write the words at 0xfff6. */ /* Write the words at 0x0000. */ -#ifdef ETHERBOOT32 memcpy((char *)(mem_end - 10), (char *)init_words, 10); memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10); if (*(unsigned short *)mem_start != 1) return (0); -#endif -#ifdef ETHERBOOT16 - memcpyf(mem_end - 10, (char *)init_words, 10); - memcpyf(mem_start, (char *)&init_words[5], sizeof(init_words) - 10); - fmemcpy((char *)&i, mem_start, sizeof(unsigned short)); - if (i != 1) - return (0); -#endif outb(0, ioaddr + NI52_RESET); outb(0, ioaddr + I82586_ATTN); + udelay(32); i = 50; while ( -#ifdef ETHERBOOT16 - read_mem(mem_start, shmem), -#endif shmem[iSCB_STATUS>>1] == 0) { if (--i == 0) { - printf("i82586 initialisation timed out with status %x, cmd %x\n", + printf("i82586 initialisation timed out with status %hX, cmd %hX\n", shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]); break; } } /* Issue channel-attn -- the 82586 won't start. */ outb(0, ioaddr + I82586_ATTN); -#ifdef ETHERBOOT32 if (*(unsigned short *)mem_start != 0) return (0); -#endif -#ifdef ETHERBOOT16 - fmemcpy((char *)&i, mem_start, sizeof(unsigned short)); - if (i != 0) - return (0); -#endif return (1); } @@ -756,16 +637,13 @@ static int ni5210_probe1(struct nic *nic) break; if (mem_start == 0) return (0); - printf("\nNI5210 ioaddr 0x%x, mem [0x%X-0x%X], addr ", - ioaddr, mem_start, mem_end); /* Get station address */ - for (i = 0; i < ETHER_ADDR_SIZE; ++i) + for (i = 0; i < ETH_ALEN; ++i) { - printf("%b", nic->node_addr[i] = inb(ioaddr+i)); - if (i < ETHER_ADDR_SIZE -1) - printf(":"); + nic->node_addr[i] = inb(ioaddr+i); } - putchar('\n'); + printf("\nNI5210 ioaddr %#hX, mem [%#X-%#X], addr %!\n", + ioaddr, mem_start, mem_end, nic->node_addr); return (1); } @@ -865,46 +743,27 @@ static int exos205_probe2(void) /* Write the words at 0xfff6. */ /* Write the words at 0x0000. */ -#ifdef ETHERBOOT32 memcpy((char *)(mem_end - 10), (char *)init_words, 10); memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10); if (*(unsigned short *)mem_start != 1) return (0); -#endif -#ifdef ETHERBOOT16 - memcpyf(mem_end - 10, (char *)init_words, 10); - memcpyf(mem_start, (char *)&init_words[5], sizeof(init_words) - 10); - fmemcpy((char *)&i, mem_start, sizeof(unsigned short)); - if (i != 1) - return (0); -#endif outb(0, ioaddr + EXOS205_RESET); outb(0, ioaddr + I82586_ATTN); i = 50; while ( -#ifdef ETHERBOOT16 - read_mem(mem_start, shmem), -#endif shmem[iSCB_STATUS>>1] == 0) { if (--i == 0) { - printf("i82586 initialisation timed out with status %x, cmd %x\n", + printf("i82586 initialisation timed out with status %hX, cmd %hX\n", shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]); break; } } /* Issue channel-attn -- the 82586 won't start. */ outb(0, ioaddr + I82586_ATTN); -#ifdef ETHERBOOT32 if (*(unsigned short *)mem_start != 0) return (0); -#endif -#ifdef ETHERBOOT16 - fmemcpy((char *)&i, mem_start, sizeof(unsigned short)); - if (i != 0) - return (0); -#endif return (1); } @@ -922,16 +781,13 @@ static int exos205_probe1(struct nic *nic) break; if (mem_start == 0) return (0); - printf("\nEXOS205 ioaddr 0x%x, mem [0x%X-0x%X], addr ", - ioaddr, mem_start, mem_end); /* Get station address */ - for (i = 0; i < ETHER_ADDR_SIZE; ++i) + for (i = 0; i < ETH_ALEN; ++i) { - printf("%b", nic->node_addr[i] = inb(ioaddr+i)); - if (i < ETHER_ADDR_SIZE -1) - printf(":"); + nic->node_addr[i] = inb(ioaddr+i); } - putchar('\n'); + printf("\nEXOS205 ioaddr %#hX, mem [%#X-%#X], addr %!\n", + ioaddr, mem_start, mem_end, nic->node_addr); return (1); } diff --git a/netboot/lance.c b/netboot/lance.c index 58300cccd..9db11191d 100644 --- a/netboot/lance.c +++ b/netboot/lance.c @@ -39,10 +39,21 @@ Ken Yap, July 1997 #define LANCE_TOTAL_SIZE 0x10 #endif +/* lance_poll() now can use multiple Rx buffers to prevent packet loss. Set + * Set LANCE_LOG_RX_BUFFERS to 0..7 for 1, 2, 4, 8, 16, 32, 64 or 128 Rx + * buffers. Usually 4 (=16 Rx buffers) is a good value. (Andreas Neuhaus) + * Decreased to 2 (=4 Rx buffers) (Ken Yap, 20010305) */ + +#define LANCE_LOG_RX_BUFFERS 2 /* Use 2^2=4 Rx buffers */ + +#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) +#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) +#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) + struct lance_init_block { unsigned short mode; - unsigned char phys_addr[6]; + unsigned char phys_addr[ETH_ALEN]; unsigned long filter[2]; Address rx_ring; Address tx_ring; @@ -52,7 +63,7 @@ struct lance_rx_head { union { Address base; - char addr[4]; + unsigned char addr[4]; } u; short buf_length; /* 2s complement */ short msg_length; @@ -62,7 +73,7 @@ struct lance_tx_head { union { Address base; - char addr[4]; + unsigned char addr[4]; } u; short buf_length; /* 2s complement */ short misc; @@ -71,20 +82,26 @@ struct lance_tx_head struct lance_interface { struct lance_init_block init_block; - struct lance_rx_head rx_ring; + struct lance_rx_head rx_ring[RX_RING_SIZE]; struct lance_tx_head tx_ring; - unsigned char rbuf[ETH_MAX_PACKET]; - unsigned char tbuf[ETH_MAX_PACKET]; + unsigned char rbuf[RX_RING_SIZE][ETH_FRAME_LEN+4]; + unsigned char tbuf[ETH_FRAME_LEN]; + /* + * Do not alter the order of the struct members above; + * the hardware depends on the correct alignment. + */ + int rx_idx; }; #define LANCE_MUST_PAD 0x00000001 #define LANCE_ENABLE_AUTOSELECT 0x00000002 +#define LANCE_SELECT_PHONELINE 0x00000004 #define LANCE_MUST_UNRESET 0x00000008 /* A mapping from the chip ID number to the part number and features. These are from the datasheets -- in real life the '970 version reportedly has the same ID as the '965. */ -static struct lance_chip_type +static const struct lance_chip_type { int id_number; const char *name; @@ -104,32 +121,33 @@ static struct lance_chip_type LANCE_ENABLE_AUTOSELECT}, {0x2621, "PCnet/PCI-II 79C970A", /* 79C970A PCInetPCI II. */ LANCE_ENABLE_AUTOSELECT}, + {0x2625, "PCnet-FAST III 79C973", /* 79C973 PCInet-FAST III. */ + LANCE_ENABLE_AUTOSELECT}, + {0x2626, "PCnet/HomePNA 79C978", + LANCE_ENABLE_AUTOSELECT|LANCE_SELECT_PHONELINE}, {0x0, "PCnet (unknown)", LANCE_ENABLE_AUTOSELECT}, }; /* Define a macro for converting program addresses to real addresses */ -#ifdef ETHERBOOT32 #undef virt_to_bus #define virt_to_bus(x) ((unsigned long)x) -#endif -#ifdef ETHERBOOT16 -#define virt_to_bus(x) (((Address)x)+RELOC) -#endif /* ETHERBOOT16 */ static int chip_version; +static int lance_version; static unsigned short ioaddr; +#ifndef INCLUDE_LANCE static int dma; +#endif static struct lance_interface *lp; /* additional 8 bytes for 8-byte alignment space */ -#ifndef USE_INTERNAL_BUFFER +#ifdef USE_LOWMEM_BUFFER #define lance ((char *)0x10000 - (sizeof(struct lance_interface)+8)) #else static char lance[sizeof(struct lance_interface)+8]; #endif - #ifndef INCLUDE_LANCE /* DMA defines and helper routines */ @@ -199,9 +217,9 @@ static void lance_reset(struct nic *nic) /* Reset the LANCE */ (void)inw(ioaddr+LANCE_RESET); /* Un-Reset the LANCE, needed only for the NE2100 */ - if (chip_table[chip_version].flags & LANCE_MUST_UNRESET) + if (chip_table[lance_version].flags & LANCE_MUST_UNRESET) outw(0, ioaddr+LANCE_RESET); - if (chip_table[chip_version].flags & LANCE_ENABLE_AUTOSELECT) + if (chip_table[lance_version].flags & LANCE_ENABLE_AUTOSELECT) { /* This is 79C960 specific; Turn on auto-select of media (AUI, BNC). */ @@ -209,16 +227,48 @@ static void lance_reset(struct nic *nic) /* Don't touch 10base2 power bit. */ outw(inw(ioaddr+LANCE_BUS_IF) | 0x2, ioaddr+LANCE_BUS_IF); } + /* HomePNA cards need to explicitly pick the phoneline interface. + * Some of these cards have ethernet interfaces as well, this + * code might require some modification for those. + */ + if (chip_table[lance_version].flags & LANCE_SELECT_PHONELINE) { + short media, check ; + /* this is specific to HomePNA cards... */ + outw(49, ioaddr+0x12) ; + media = inw(ioaddr+0x16) ; +#ifdef DEBUG + printf("media was %d\n", media) ; +#endif + media &= ~3 ; + media |= 1 ; +#ifdef DEBUG + printf("media changed to %d\n", media) ; +#endif + media &= ~3 ; + media |= 1 ; + outw(49, ioaddr+0x12) ; + outw(media, ioaddr+0x16) ; + outw(49, ioaddr+0x12) ; + check = inw(ioaddr+0x16) ; +#ifdef DEBUG + printf("check %s, media was set properly\n", + check == media ? "passed" : "FAILED" ) ; +#endif + } + /* Re-initialise the LANCE, and start it when done. */ /* Set station address */ - for (i = 0; i < ETHER_ADDR_SIZE; ++i) + for (i = 0; i < ETH_ALEN; ++i) lp->init_block.phys_addr[i] = nic->node_addr[i]; - /* Preset the receive ring header */ - lp->rx_ring.buf_length = -ETH_MAX_PACKET; - /* OWN */ - lp->rx_ring.u.base = virt_to_bus(lp->rbuf) & 0xffffff; - /* we set the top byte as the very last thing */ - lp->rx_ring.u.addr[3] = 0x80; + /* Preset the receive ring headers */ + for (i=0; irx_ring[i].buf_length = -ETH_FRAME_LEN-4; + /* OWN */ + lp->rx_ring[i].u.base = virt_to_bus(lp->rbuf[i]) & 0xffffff; + /* we set the top byte as the very last thing */ + lp->rx_ring[i].u.addr[3] = 0x80; + } + lp->rx_idx = 0; lp->init_block.mode = 0x0; /* enable Rx and Tx */ l = (Address)virt_to_bus(&lp->init_block); outw(0x1, ioaddr+LANCE_ADDR); @@ -234,9 +284,13 @@ static void lance_reset(struct nic *nic) (void)inw(ioaddr+LANCE_ADDR); outw(0x4, ioaddr+LANCE_DATA); /* stop */ outw(0x1, ioaddr+LANCE_DATA); /* init */ - for (i = 100; i > 0; --i) + for (i = 10000; i > 0; --i) if (inw(ioaddr+LANCE_DATA) & 0x100) break; +#ifdef DEBUG + if (i <= 0) + printf("Init timed out\n"); +#endif /* Apparently clearing the InitDone bit here triggers a bug in the '974. (Mark Stockton) */ outw(0x2, ioaddr+LANCE_DATA); /* start */ @@ -249,23 +303,29 @@ static int lance_poll(struct nic *nic) { int status; - status = lp->rx_ring.u.base >> 24; + status = lp->rx_ring[lp->rx_idx].u.base >> 24; if (status & 0x80) return (0); #ifdef DEBUG - printf("LANCE packet received rx_ring.u.base %X mcnt %x csr0 %x\n", - lp->rx_ring.u.base, lp->rx_ring.msg_length, + printf("LANCE packet received rx_ring.u.base %X mcnt %hX csr0 %hX\n", + lp->rx_ring[lp->rx_idx].u.base, lp->rx_ring[lp->rx_idx].msg_length, inw(ioaddr+LANCE_DATA)); #endif if (status == 0x3) - memcpy(nic->packet, lp->rbuf, nic->packetlen = lp->rx_ring.msg_length); + memcpy(nic->packet, lp->rbuf[lp->rx_idx], nic->packetlen = lp->rx_ring[lp->rx_idx].msg_length); /* Andrew Boyd of QNX reports that some revs of the 79C765 clear the buffer length */ - lp->rx_ring.buf_length = -ETH_MAX_PACKET; - lp->rx_ring.u.addr[3] |= 0x80; /* prime for next receive */ + lp->rx_ring[lp->rx_idx].buf_length = -ETH_FRAME_LEN-4; + lp->rx_ring[lp->rx_idx].u.addr[3] |= 0x80; /* prime for next receive */ + + /* I'm not sure if the following is still ok with multiple Rx buffers, but it works */ outw(0x0, ioaddr+LANCE_ADDR); (void)inw(ioaddr+LANCE_ADDR); outw(0x500, ioaddr+LANCE_DATA); /* clear receive + InitDone */ + + /* Switch to the next Rx ring buffer */ + lp->rx_idx = (lp->rx_idx + 1) & RX_RING_MOD_MASK; + return (status == 0x3); } @@ -282,14 +342,14 @@ static void lance_transmit( unsigned long time; /* copy the packet to ring buffer */ - memcpy(lp->tbuf, d, ETHER_ADDR_SIZE); /* dst */ - memcpy(&lp->tbuf[ETHER_ADDR_SIZE], nic->node_addr, ETHER_ADDR_SIZE); /* src */ - lp->tbuf[ETHER_ADDR_SIZE+ETHER_ADDR_SIZE] = t >> 8; /* type */ - lp->tbuf[ETHER_ADDR_SIZE+ETHER_ADDR_SIZE+1] = t; /* type */ - memcpy(&lp->tbuf[ETHER_HDR_SIZE], p, s); - s += ETHER_HDR_SIZE; + memcpy(lp->tbuf, d, ETH_ALEN); /* dst */ + memcpy(&lp->tbuf[ETH_ALEN], nic->node_addr, ETH_ALEN); /* src */ + lp->tbuf[ETH_ALEN+ETH_ALEN] = t >> 8; /* type */ + lp->tbuf[ETH_ALEN+ETH_ALEN+1] = t; /* type */ + memcpy(&lp->tbuf[ETH_HLEN], p, s); + s += ETH_HLEN; if (chip_table[chip_version].flags & LANCE_MUST_PAD) - while (s < ETH_MIN_PACKET) /* pad to min length */ + while (s < ETH_ZLEN) /* pad to min length */ lp->tbuf[s++] = 0; lp->tx_ring.buf_length = -s; lp->tx_ring.misc = 0x0; @@ -299,7 +359,12 @@ static void lance_transmit( lp->tx_ring.u.addr[3] = 0x83; /* Trigger an immediate send poll */ outw(0x0, ioaddr+LANCE_ADDR); - outw(0x48, ioaddr+LANCE_DATA); + (void)inw(ioaddr+LANCE_ADDR); /* as in the datasheets... */ + /* Klaus Espenlaub: the value below was 0x48, but that enabled the + * interrupt line, causing a hang if for some reasone the interrupt + * controller had the LANCE interrupt enabled. I have no idea why + * nobody ran into this before... */ + outw(0x08, ioaddr+LANCE_DATA); /* wait for transmit complete */ time = currticks() + TICKS_PER_SEC; /* wait one second */ while (currticks() < time && (lp->tx_ring.u.base & 0x80000000) != 0) @@ -309,7 +374,7 @@ static void lance_transmit( (void)inw(ioaddr+LANCE_ADDR); outw(0x200, ioaddr+LANCE_DATA); /* clear transmit + InitDone */ #ifdef DEBUG - printf("tx_ring.u.base %X tx_ring.buf_length %x tx_ring.misc %x csr0 %x\n", + printf("tx_ring.u.base %X tx_ring.buf_length %hX tx_ring.misc %hX csr0 %hX\n", lp->tx_ring.u.base, lp->tx_ring.buf_length, lp->tx_ring.misc, inw(ioaddr+LANCE_DATA)); #endif @@ -317,6 +382,13 @@ static void lance_transmit( static void lance_disable(struct nic *nic) { + (void)inw(ioaddr+LANCE_RESET); + if (chip_table[lance_version].flags & LANCE_MUST_UNRESET) + outw(0, ioaddr+LANCE_RESET); + + outw(0, ioaddr+LANCE_ADDR); + outw(0x0004, ioaddr+LANCE_DATA); /* stop the LANCE */ + #ifndef INCLUDE_LANCE disable_dma(dma); #endif @@ -328,11 +400,13 @@ static int lance_probe1(struct nic *nic, struct pci_device *pci) static int lance_probe1(struct nic *nic) #endif { - int reset_val, lance_version; + int reset_val ; unsigned int i; Address l; short dma_channels; +#ifndef INCLUDE_LANCE static const char dmas[] = { 5, 6, 7, 3 }; +#endif reset_val = inw(ioaddr+LANCE_RESET); outw(reset_val, ioaddr+LANCE_RESET); @@ -361,8 +435,8 @@ static int lance_probe1(struct nic *nic) lp = (struct lance_interface *)l; lp->init_block.mode = 0x3; /* disable Rx and Tx */ lp->init_block.filter[0] = lp->init_block.filter[1] = 0x0; - /* top bits are zero, we have only one buffer each for Rx and Tx */ - lp->init_block.rx_ring = virt_to_bus(&lp->rx_ring) & 0xffffff; + /* using multiple Rx buffer and a single Tx buffer */ + lp->init_block.rx_ring = (virt_to_bus(&lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS; lp->init_block.tx_ring = virt_to_bus(&lp->tx_ring) & 0xffffff; l = virt_to_bus(&lp->init_block); outw(0x1, ioaddr+LANCE_ADDR); @@ -376,6 +450,10 @@ static int lance_probe1(struct nic *nic) outw(0x915, ioaddr+LANCE_DATA); outw(0x0, ioaddr+LANCE_ADDR); (void)inw(ioaddr+LANCE_ADDR); + /* Get station address */ + for (i = 0; i < ETH_ALEN; ++i) { + nic->node_addr[i] = inb(ioaddr+LANCE_ETH_ADDR+i); + } #ifndef INCLUDE_LANCE /* now probe for DMA channel */ dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0xf) | @@ -404,19 +482,11 @@ static int lance_probe1(struct nic *nic) } if (i >= (sizeof(dmas)/sizeof(dmas[0]))) dma = 0; - printf("\n%s base 0x%x, DMA %d, addr ", - chip_table[lance_version].name, ioaddr, dma); + printf("\n%s base %#X, DMA %d, addr %!\n", + chip_table[lance_version].name, ioaddr, dma, nic->node_addr); #else - printf(" %s base 0x%x, addr ", chip_table[lance_version].name, ioaddr); + printf(" %s base %#hX, addr %!\n", chip_table[lance_version].name, ioaddr, nic->node_addr); #endif - /* Get station address */ - for (i = 0; i < ETHER_ADDR_SIZE; ++i) - { - printf("%b", nic->node_addr[i] = inb(ioaddr+LANCE_ETH_ADDR+i)); - if (i < ETHER_ADDR_SIZE -1) - printf(":"); - } - putchar('\n'); if (chip_table[chip_version].flags & LANCE_ENABLE_AUTOSELECT) { /* Turn on auto-select of media (10baseT or BNC) so that the * user watch the LEDs. */ @@ -442,15 +512,22 @@ struct nic *ni6510_probe(struct nic *nic, unsigned short *probe_addrs) #endif { unsigned short *p; +#ifndef INCLUDE_LANCE static unsigned short io_addrs[] = { 0x300, 0x320, 0x340, 0x360, 0 }; +#endif /* if probe_addrs is 0, then routine can use a hardwired default */ - if (probe_addrs == 0) + if (probe_addrs == 0) { +#ifdef INCLUDE_LANCE + return 0; +#else probe_addrs = io_addrs; +#endif + } for (p = probe_addrs; (ioaddr = *p) != 0; ++p) { char offset15, offset14 = inb(ioaddr + 14); - short pci_cmd; + unsigned short pci_cmd; #ifdef INCLUDE_NE2100 if ((offset14 == 0x52 || offset14 == 0x57) && @@ -465,11 +542,7 @@ struct nic *ni6510_probe(struct nic *nic, unsigned short *probe_addrs) break; #endif #ifdef INCLUDE_LANCE - pcibios_read_config_word(0, pci->devfn, PCI_COMMAND, &pci_cmd); - if (!(pci_cmd & PCI_COMMAND_MASTER)) { - pci_cmd |= PCI_COMMAND_MASTER; - pcibios_write_config_word(0, pci->devfn, PCI_COMMAND, pci_cmd); - } + adjust_pci_device(pci); if (lance_probe1(nic, pci) >= 0) break; #endif @@ -485,8 +558,7 @@ struct nic *ni6510_probe(struct nic *nic, unsigned short *probe_addrs) nic->disable = lance_disable; return nic; } - /* else */ - { - return 0; - } + + /* no board found */ + return 0; } diff --git a/netboot/linux-asm-string.h b/netboot/linux-asm-string.h index 814aeafbf..d5bec088c 100644 --- a/netboot/linux-asm-string.h +++ b/netboot/linux-asm-string.h @@ -251,4 +251,41 @@ __asm__ __volatile__("cld\n\t" \ __constant_c_x_memset((s),(c),(count)) : \ __memset((s),(c),(count))) +#define __HAVE_ARCH_STRNCMP +static inline int strncmp(const char * cs,const char * ct,size_t count) +{ +register int __res; +int d0, d1, d2; +__asm__ __volatile__( + "1:\tdecl %3\n\t" + "js 2f\n\t" + "lodsb\n\t" + "scasb\n\t" + "jne 3f\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n" + "2:\txorl %%eax,%%eax\n\t" + "jmp 4f\n" + "3:\tsbbl %%eax,%%eax\n\t" + "orb $1,%%al\n" + "4:" + :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2) + :"1" (cs),"2" (ct),"3" (count)); +return __res; +} + +#define __HAVE_ARCH_STRLEN +static inline size_t strlen(const char * s) +{ +int d0; +register int __res; +__asm__ __volatile__( + "repne\n\t" + "scasb\n\t" + "notl %0\n\t" + "decl %0" + :"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff)); +return __res; +} + #endif diff --git a/netboot/main.c b/netboot/main.c index d9d9bda97..031749f3a 100644 --- a/netboot/main.c +++ b/netboot/main.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2000 Free Software Foundation, Inc. + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* Based on "src/main.c" in etherboot-4.6.4. */ +/* Based on "src/main.c" in etherboot-5.0.5. */ /************************************************************************** ETHERBOOT - BOOTP/TFTP Bootstrap Program @@ -37,11 +37,12 @@ Literature dealing with the network protocols: **************************************************************************/ -/* #define MDEBUG */ - +#define GRUB 1 #include #include +/* #define DEBUG 1 */ + struct arptable_t arptable[MAX_ARP]; /* Set if the user pushes Control-C. */ @@ -58,123 +59,70 @@ static unsigned long xid; static unsigned char *end_of_rfc1533 = NULL; #ifndef NO_DHCP_SUPPORT -static int dhcp_reply; -static in_addr dhcp_server = {0L}; -static in_addr dhcp_addr = {0L}; #endif /* NO_DHCP_SUPPORT */ /* äEth */ static unsigned char vendorext_magic[] = {0xE4, 0x45, 0x74, 0x68}; +static const unsigned char broadcast[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; #ifdef NO_DHCP_SUPPORT -static char rfc1533_cookie[5] = {RFC1533_COOKIE, RFC1533_END}; +static unsigned char rfc1533_cookie[5] = {RFC1533_COOKIE, RFC1533_END}; #else /* ! NO_DHCP_SUPPORT */ -static char rfc1533_cookie[] = {RFC1533_COOKIE}; -static char rfc1533_end[] = {RFC1533_END}; +static int dhcp_reply; +static in_addr dhcp_server = {0L}; +static in_addr dhcp_addr = {0L}; +static unsigned char rfc1533_cookie[] = {RFC1533_COOKIE}; +static unsigned char rfc1533_end[] = {RFC1533_END}; -static const char dhcpdiscover[] = +static const unsigned char dhcpdiscover[] = { RFC2132_MSG_TYPE, 1, DHCPDISCOVER, RFC2132_MAX_SIZE,2, /* request as much as we can */ - sizeof(struct bootpd_t) / 256, sizeof(struct bootpd_t) % 256, + ETH_MAX_MTU / 256, ETH_MAX_MTU % 256, RFC2132_PARAM_LIST, 4, RFC1533_NETMASK, RFC1533_GATEWAY, RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH }; -static const char dhcprequest[] = +static const unsigned char dhcprequest[] = { RFC2132_MSG_TYPE, 1, DHCPREQUEST, RFC2132_SRV_ID, 4, 0, 0, 0, 0, RFC2132_REQ_ADDR, 4, 0, 0, 0, 0, - RFC2132_MAX_SIZE,2, /* request as much as we can */ - sizeof(struct bootpd_t) / 256, sizeof(struct bootpd_t) % 256, + RFC2132_MAX_SIZE, 2, /* request as much as we can */ + ETH_MAX_MTU / 256, ETH_MAX_MTU % 256, /* request parameters */ RFC2132_PARAM_LIST, -#ifdef GRUB /* 4 standard + 2 vendortags */ 4 + 2, -#else -# ifdef IMAGE_FREEBSD - /* 4 standard + 4 vendortags + 8 motd + 16 menu items */ - 4 + 4 + 8 + 16, -# else - /* 4 standard + 3 vendortags + 8 motd + 16 menu items */ - 4 + 3 + 8 + 16, -# endif -#endif /* Standard parameters */ RFC1533_NETMASK, RFC1533_GATEWAY, RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, /* Etherboot vendortags */ RFC1533_VENDOR_MAGIC, -#ifdef GRUB RFC1533_VENDOR_CONFIGFILE, -#else /* ! GRUB */ -# ifdef IMAGE_FREEBSD - RFC1533_VENDOR_HOWTO, -# endif - RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION, - /* 8 MOTD entries */ - RFC1533_VENDOR_MOTD, - RFC1533_VENDOR_MOTD + 1, - RFC1533_VENDOR_MOTD + 2, - RFC1533_VENDOR_MOTD + 3, - RFC1533_VENDOR_MOTD + 4, - RFC1533_VENDOR_MOTD + 5, - RFC1533_VENDOR_MOTD + 6, - RFC1533_VENDOR_MOTD + 7, - /* 16 image entries */ - RFC1533_VENDOR_IMG, - RFC1533_VENDOR_IMG + 1, - RFC1533_VENDOR_IMG + 2, - RFC1533_VENDOR_IMG + 3, - RFC1533_VENDOR_IMG + 4, - RFC1533_VENDOR_IMG + 5, - RFC1533_VENDOR_IMG + 6, - RFC1533_VENDOR_IMG + 7, - RFC1533_VENDOR_IMG + 8, - RFC1533_VENDOR_IMG + 9, - RFC1533_VENDOR_IMG + 10, - RFC1533_VENDOR_IMG + 11, - RFC1533_VENDOR_IMG + 12, - RFC1533_VENDOR_IMG + 13, - RFC1533_VENDOR_IMG + 14, - RFC1533_VENDOR_IMG + 15, -#endif /* ! GRUB */ }; #endif /* ! NO_DHCP_SUPPORT */ -static const char broadcast[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +static unsigned short ipchksum (unsigned short *ip, int len); +static unsigned short udpchksum (struct iphdr *packet); void print_network_configuration (void) { - static void sprint_ip_addr (char *buf, unsigned long addr) - { - grub_sprintf (buf, "%d.%d.%d.%d", - addr & 0xFF, (addr >> 8) & 0xFF, - (addr >> 16) & 0xFF, addr >> 24); - } - if (! eth_probe ()) grub_printf ("No ethernet card found.\n"); else if (! network_ready) grub_printf ("Not initialized yet.\n"); else { - char me[16], my_mask[16], server[16], gw[16]; - - sprint_ip_addr (me, arptable[ARP_CLIENT].ipaddr.s_addr); - sprint_ip_addr (my_mask, netmask); - sprint_ip_addr (server, arptable[ARP_SERVER].ipaddr.s_addr); - sprint_ip_addr (gw, arptable[ARP_GATEWAY].ipaddr.s_addr); - - grub_printf ("Address: %s Netmask: %s\nServer: %s Gateway: %s\n", - me, my_mask, server, gw); + etherboot_printf ("Address: %@\n", arptable[ARP_CLIENT].ipaddr.s_addr); + etherboot_printf ("Netmask: %@\n", netmask); + etherboot_printf ("Server: %@\n", arptable[ARP_SERVER].ipaddr.s_addr); + etherboot_printf ("Gateway: %@\n", arptable[ARP_GATEWAY].ipaddr.s_addr); } } @@ -267,6 +215,10 @@ udp_transmit (unsigned long destip, unsigned int srcsock, udp->dest = htons (destsock); udp->len = htons (len - sizeof (struct iphdr)); udp->chksum = 0; + udp->chksum = htons (udpchksum (ip)); + + if (udp->chksum == 0) + udp->chksum = 0xffff; if (destip == IP_BROADCAST) { @@ -285,48 +237,44 @@ udp_transmit (unsigned long destip, unsigned int srcsock, if (arpentry == MAX_ARP) { - grub_printf ("%x is not in my arp table!\n", destip); + etherboot_printf ("%@ is not in my arp table!\n", destip); return 0; } - for (i = 0; i < ETHER_ADDR_SIZE; i++) + for (i = 0; i < ETH_ALEN; i++) if (arptable[arpentry].node[i]) break; - if (i == ETHER_ADDR_SIZE) + if (i == ETH_ALEN) { /* Need to do arp request. */ +#ifdef DEBUG + grub_printf ("arp request.\n"); +#endif arpreq.hwtype = htons (1); arpreq.protocol = htons (IP); - arpreq.hwlen = ETHER_ADDR_SIZE; + arpreq.hwlen = ETH_ALEN; arpreq.protolen = 4; arpreq.opcode = htons (ARP_REQUEST); grub_memmove (arpreq.shwaddr, arptable[ARP_CLIENT].node, - ETHER_ADDR_SIZE); + ETH_ALEN); grub_memmove (arpreq.sipaddr, (char *) &arptable[ARP_CLIENT].ipaddr, sizeof (in_addr)); - grub_memset (arpreq.thwaddr, 0, ETHER_ADDR_SIZE); + grub_memset (arpreq.thwaddr, 0, ETH_ALEN); grub_memmove (arpreq.tipaddr, (char *) &destip, sizeof (in_addr)); for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) { + long timeout; + eth_transmit (broadcast, ARP, sizeof (arpreq), &arpreq); - if (await_reply (AWAIT_ARP, arpentry, arpreq.tipaddr, TIMEOUT)) + timeout = rfc2131_sleep_interval (TIMEOUT, retry); + + if (await_reply (AWAIT_ARP, arpentry, arpreq.tipaddr, timeout)) goto xmit; if (ip_abort) return 0; - - rfc951_sleep (retry); - /* We have slept for a while - the packet may - * have arrived by now. If not, we have at - * least some room in the Rx buffer for the - * next reply. */ - if (await_reply (AWAIT_ARP, arpentry, arpreq.tipaddr, 0)) - goto xmit; - - if (ip_abort) - return 0; } return 0; @@ -347,11 +295,11 @@ tftp (const char *name, int (*fnc) (unsigned char *, int, int, int)) { int retry = 0; static unsigned short iport = 2000; - unsigned short oport; + unsigned short oport = 0; unsigned short len, block = 0, prevblock = 0; int bcounter = 0; struct tftp_t *tr; - struct tftp_t tp; + struct tftpreq_t tp; int rc; int packetsize = TFTP_DEFAULTSIZE_PACKET; @@ -364,26 +312,28 @@ tftp (const char *name, int (*fnc) (unsigned char *, int, int, int)) await_reply (AWAIT_QDRAIN, 0, NULL, 0); tp.opcode = htons (TFTP_RRQ); - len = (grub_sprintf ((char *)tp.u.rrq, "%s%coctet%cblksize%c%d", + len = (grub_sprintf ((char *) tp.u.rrq, "%s%coctet%cblksize%c%d", name, 0, 0, 0, TFTP_MAX_PACKET) - + TFTP_MIN_PACKET + 1); + + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1); if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp)) return 0; for (;;) { + long timeout; + #ifdef CONGESTED - if (! await_reply (AWAIT_TFTP, iport, NULL, - (block ? TFTP_REXMT : TIMEOUT))) + timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry); #else - if (! await_reply (AWAIT_TFTP, iport, NULL, TIMEOUT)) + timeout = rfc2131_sleep_interval (TIMEOUT, retry); #endif + + if (! await_reply (AWAIT_TFTP, iport, NULL, timeout)) { if (! block && retry++ < MAX_TFTP_RETRIES) { /* Maybe initial request was lost. */ - rfc951_sleep (retry); if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp)) return 0; @@ -408,7 +358,7 @@ tftp (const char *name, int (*fnc) (unsigned char *, int, int, int)) break; } - tr = (struct tftp_t *) &nic.packet[ETHER_HDR_SIZE]; + tr = (struct tftp_t *) &nic.packet[ETH_HLEN]; if (tr->opcode == ntohs (TFTP_ERROR)) { grub_printf ("TFTP error %d (%s)\n", @@ -452,7 +402,9 @@ tftp (const char *name, int (*fnc) (unsigned char *, int, int, int)) tp.u.err.errcode = 8; len = (grub_sprintf ((char *) tp.u.err.errmsg, "RFC1782 error") - + TFTP_MIN_PACKET + 1); + + sizeof (tp.ip) + sizeof (tp.udp) + + sizeof (tp.opcode) + sizeof (tp.u.err.errcode) + + 1); udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, ntohs (tr->udp.src), len, &tp); @@ -530,25 +482,28 @@ rarp (void) /* Clear the ready flag. */ network_ready = 0; - memset (&rarpreq, 0, sizeof (rarpreq)); + grub_memset (&rarpreq, 0, sizeof (rarpreq)); rarpreq.hwtype = htons (1); rarpreq.protocol = htons (IP); - rarpreq.hwlen = ETHER_ADDR_SIZE; + rarpreq.hwlen = ETH_ALEN; rarpreq.protolen = 4; rarpreq.opcode = htons (RARP_REQUEST); grub_memmove ((char *) &rarpreq.shwaddr, arptable[ARP_CLIENT].node, - ETHER_ADDR_SIZE); + ETH_ALEN); /* sipaddr is already zeroed out */ grub_memmove ((char *) &rarpreq.thwaddr, arptable[ARP_CLIENT].node, - ETHER_ADDR_SIZE); + ETH_ALEN); /* tipaddr is already zeroed out */ - for (retry = 0; retry < MAX_ARP_RETRIES; rfc951_sleep (++retry)) + for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) { + long timeout; + eth_transmit (broadcast, RARP, sizeof (rarpreq), &rarpreq); - if (await_reply (AWAIT_RARP, 0, rarpreq.shwaddr, TIMEOUT)) + timeout = rfc2131_sleep_interval (TIMEOUT, retry); + if (await_reply (AWAIT_RARP, 0, rarpreq.shwaddr, timeout)) break; if (ip_abort) @@ -572,15 +527,10 @@ bootp (void) { int retry; #ifndef NO_DHCP_SUPPORT - int retry1; + int reqretry; #endif /* ! NO_DHCP_SUPPORT */ - struct bootp_t bp; + struct bootpip_t ip; unsigned long starttime; -#ifdef T509HACK - int flag; - - flag = 1; -#endif /* Make sure that an ethernet is probed. */ if (! eth_probe ()) @@ -588,27 +538,51 @@ bootp (void) /* Clear the ready flag. */ network_ready = 0; + +#ifdef DEBUG + grub_printf ("network is ready.\n"); +#endif + + grub_memset (&ip, 0, sizeof (struct bootpip_t)); + ip.bp.bp_op = BOOTP_REQUEST; + ip.bp.bp_htype = 1; + ip.bp.bp_hlen = ETH_ALEN; + starttime = currticks (); + /* Use lower 32 bits of node address, more likely to be + distinct than the time since booting */ + grub_memmove (&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid)); + ip.bp.bp_xid = xid += htonl (starttime); + grub_memmove (ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); +#ifdef DEBUG + etherboot_printf ("bp_op = %d\n", ip.bp.bp_op); + etherboot_printf ("bp_htype = %d\n", ip.bp.bp_htype); + etherboot_printf ("bp_hlen = %d\n", ip.bp.bp_hlen); + etherboot_printf ("bp_xid = %d\n", ip.bp.bp_xid); + etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr); + etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops); + etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr); +#endif - grub_memset (&bp, 0, sizeof (struct bootp_t)); - bp.bp_op = BOOTP_REQUEST; - bp.bp_htype = 1; - bp.bp_hlen = ETHER_ADDR_SIZE; - bp.bp_xid = xid = starttime = currticks (); - grub_memmove (bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE); #ifdef NO_DHCP_SUPPORT /* Request RFC-style options. */ - grub_memmove (bp.bp_vend, rfc1533_cookie, 5); + grub_memmove (ip.bp.bp_vend, rfc1533_cookie, 5); #else /* Request RFC-style options. */ - grub_memmove (bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); - grub_memmove (bp.bp_vend + sizeof rfc1533_cookie, dhcpdiscover, + grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); + grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover); - grub_memmove (bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcpdiscover, + grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end); #endif /* ! NO_DHCP_SUPPORT */ for (retry = 0; retry < MAX_BOOTP_RETRIES;) { + long timeout; + +#ifdef DEBUG + grub_printf ("retry = %d\n", retry); +#endif + /* Clear out the Rx queue first. It contains nothing of * interest, except possibly ARP requests from the DHCP/TFTP * server. We use polling throughout Etherboot, so some time @@ -619,77 +593,139 @@ bootp (void) await_reply (AWAIT_QDRAIN, 0, NULL, 0); udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, - sizeof (struct bootp_t), &bp); -#ifdef T509HACK - if (flag) - { - flag--; - continue; - } -#endif /* T509HACK */ - + sizeof (struct bootpip_t), &ip); + timeout = rfc2131_sleep_interval (TIMEOUT, retry++); #ifdef NO_DHCP_SUPPORT - if (await_reply (AWAIT_BOOTP, 0, NULL, TIMEOUT)) + if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) { network_ready = 1; return 1; } #else /* ! NO_DHCP_SUPPORT */ - if (await_reply (AWAIT_BOOTP, 0, NULL, TIMEOUT)) + if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) { - if (dhcp_reply == DHCPOFFER) - { - dhcp_reply = 0; - grub_memmove (bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); - grub_memmove (bp.bp_vend + sizeof rfc1533_cookie, - dhcprequest, sizeof dhcprequest); - grub_memmove (bp.bp_vend + sizeof rfc1533_cookie - + sizeof dhcprequest, - rfc1533_end, sizeof rfc1533_end); - grub_memmove (bp.bp_vend + 9, (char *) &dhcp_server, - sizeof (in_addr)); - grub_memmove (bp.bp_vend + 15, (char *) &dhcp_addr, - sizeof (in_addr)); - for (retry1 = 0; retry1 < MAX_BOOTP_RETRIES;) - { - udp_transmit (IP_BROADCAST, 0, BOOTP_SERVER, - sizeof (struct bootp_t), &bp); - dhcp_reply = 0; - if (await_reply (AWAIT_BOOTP, 0, NULL, TIMEOUT)) - if (dhcp_reply == DHCPACK) - { - network_ready = 1; - return 1; - } - - if (ip_abort) - return 0; - - rfc951_sleep (++retry1); - } - - /* Timeout. */ - return 0; - } - else + if (dhcp_reply != DHCPOFFER) { network_ready = 1; return 1; } + + dhcp_reply = 0; +#ifdef DEBUG + etherboot_printf ("bp_op = %d\n", (int) ip.bp.bp_op); + etherboot_printf ("bp_htype = %d\n", (int) ip.bp.bp_htype); + etherboot_printf ("bp_hlen = %d\n", (int) ip.bp.bp_hlen); + etherboot_printf ("bp_xid = %d\n", (int) ip.bp.bp_xid); + etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr); + etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops); + etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr); +#endif + grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); + grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie, + dhcprequest, sizeof dhcprequest); + grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie + + sizeof dhcprequest, + rfc1533_end, sizeof rfc1533_end); + grub_memmove (ip.bp.bp_vend + 9, (char *) &dhcp_server, + sizeof (in_addr)); + grub_memmove (ip.bp.bp_vend + 15, (char *) &dhcp_addr, + sizeof (in_addr)); +#ifdef DEBUG + grub_printf ("errnum = %d\n", errnum); +#endif + for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES;) + { + int ret; +#ifdef DEBUG + grub_printf ("reqretry = %d\n", reqretry); +#endif + + ret = udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, + sizeof (struct bootpip_t), &ip); + if (! ret) + grub_printf ("udp_transmit failed.\n"); + + dhcp_reply = 0; + timeout = rfc2131_sleep_interval (TIMEOUT, reqretry++); + if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) + if (dhcp_reply == DHCPACK) + { + network_ready = 1; + return 1; + } + +#ifdef DEBUG + grub_printf ("dhcp_reply = %d\n", dhcp_reply); +#endif + + if (ip_abort) + return 0; + } } #endif /* ! NO_DHCP_SUPPORT */ if (ip_abort) return 0; - - rfc951_sleep (++retry); - bp.bp_secs = htons ((currticks () - starttime) / 20); + + ip.bp.bp_secs = htons ((currticks () - starttime) / TICKS_PER_SEC); } /* Timeout. */ return 0; } +/************************************************************************** +UDPCHKSUM - Checksum UDP Packet (one of the rare cases when assembly is + actually simpler...) + RETURNS: checksum, 0 on checksum error. This + allows for using the same routine for RX and TX summing: + RX if (packet->udp.chksum && udpchksum(packet)) + error("checksum error"); + TX packet->udp.chksum=0; + if (0==(packet->udp.chksum=udpchksum(packet))) + packet->upd.chksum=0xffff; +**************************************************************************/ +static inline void +dosum (unsigned short *start, unsigned int len, unsigned short *sum) +{ + __asm__ __volatile__ + ("clc\n" + "1:\tlodsw\n\t" + "xchg %%al,%%ah\n\t" /* convert to host byte order */ + "adcw %%ax,%0\n\t" /* add carry of previous iteration */ + "loop 1b\n\t" + "adcw $0,%0" /* add carry of last iteration */ + : "=b" (*sum), "=S"(start), "=c"(len) + : "0"(*sum), "1"(start), "2"(len) + : "ax", "cc" + ); +} + +/* UDP sum: + * proto, src_ip, dst_ip, udp_dport, udp_sport, 2*udp_len, payload + */ +static unsigned short +udpchksum (struct iphdr *packet) +{ + int len = ntohs (packet->len); + unsigned short rval; + + /* add udplength + protocol number */ + rval = (len - sizeof (struct iphdr)) + IP_UDP; + + /* pad to an even number of bytes */ + if (len % 2) { + ((char *) packet)[len++] = 0; + } + + /* sum over src/dst ipaddr + udp packet */ + len -= (char *) &packet->src - (char *) packet; + dosum ((unsigned short *) &packet->src, len >> 1, &rval); + + /* take one's complement */ + return ~rval; +} + /************************************************************************** AWAIT_REPLY - Wait until we get a response for our request **************************************************************************/ @@ -702,13 +738,13 @@ await_reply (int type, int ival, void *ptr, int timeout) struct arprequest *arpreply; struct bootp_t *bootpreply; unsigned short ptype; - unsigned int protohdrlen = (ETHER_HDR_SIZE + sizeof (struct iphdr) + unsigned int protohdrlen = (ETH_HLEN + sizeof (struct iphdr) + sizeof (struct udphdr)); /* Clear the abort flag. */ ip_abort = 0; - time = currticks () + TIMEOUT; + time = timeout + currticks (); /* The timeout check is done below. The timeout is only checked if * there is no packet in the Rx queue. This assumes that eth_poll() * needs a negligible amount of time. */ @@ -719,7 +755,7 @@ await_reply (int type, int ival, void *ptr, int timeout) /* We have something! */ /* Check for ARP - No IP hdr. */ - if (nic.packetlen >= ETHER_HDR_SIZE) + if (nic.packetlen >= ETH_HLEN) { ptype = (((unsigned short) nic.packet[12]) << 8 | ((unsigned short) nic.packet[13])); @@ -728,46 +764,46 @@ await_reply (int type, int ival, void *ptr, int timeout) /* What else could we do with it? */ continue; - if (nic.packetlen >= ETHER_HDR_SIZE + sizeof (struct arprequest) + if (nic.packetlen >= ETH_HLEN + sizeof (struct arprequest) && ptype == ARP) { unsigned long tmp; - arpreply = (struct arprequest *) &nic.packet[ETHER_HDR_SIZE]; + arpreply = (struct arprequest *) &nic.packet[ETH_HLEN]; - if (arpreply->opcode == ntohs (ARP_REPLY) + if (arpreply->opcode == htons (ARP_REPLY) && ! grub_memcmp (arpreply->sipaddr, ptr, sizeof (in_addr)) && type == AWAIT_ARP) { grub_memmove ((char *) arptable[ival].node, arpreply->shwaddr, - ETHER_ADDR_SIZE); + ETH_ALEN); return 1; } grub_memmove ((char *) &tmp, arpreply->tipaddr, sizeof (in_addr)); - if (arpreply->opcode == ntohs (ARP_REQUEST) + if (arpreply->opcode == htons (ARP_REQUEST) && tmp == arptable[ARP_CLIENT].ipaddr.s_addr) { arpreply->opcode = htons (ARP_REPLY); grub_memmove (arpreply->tipaddr, arpreply->sipaddr, sizeof (in_addr)); grub_memmove (arpreply->thwaddr, (char *) arpreply->shwaddr, - ETHER_ADDR_SIZE); + ETH_ALEN); grub_memmove (arpreply->sipaddr, (char *) &arptable[ARP_CLIENT].ipaddr, sizeof (in_addr)); grub_memmove (arpreply->shwaddr, arptable[ARP_CLIENT].node, - ETHER_ADDR_SIZE); + ETH_ALEN); eth_transmit (arpreply->thwaddr, ARP, sizeof (struct arprequest), arpreply); #ifdef MDEBUG grub_memmove (&tmp, arpreply->tipaddr, sizeof (in_addr)); - grub_printf ("Sent ARP reply to: %x\n", tmp); + etherboot_printf ("Sent ARP reply to: %@\n", tmp); #endif /* MDEBUG */ } @@ -775,22 +811,20 @@ await_reply (int type, int ival, void *ptr, int timeout) } if (type == AWAIT_QDRAIN) - { - continue; - } + continue; /* Check for RARP - No IP hdr. */ if (type == AWAIT_RARP - && nic.packetlen >= ETHER_HDR_SIZE + sizeof (struct arprequest) + && nic.packetlen >= ETH_HLEN + sizeof (struct arprequest) && ptype == RARP) { - arpreply = (struct arprequest *) &nic.packet[ETHER_HDR_SIZE]; + arpreply = (struct arprequest *) &nic.packet[ETH_HLEN]; - if (arpreply->opcode == ntohs (RARP_REPLY) - && ! grub_memcmp (arpreply->thwaddr, ptr, ETHER_ADDR_SIZE)) + if (arpreply->opcode == htons (RARP_REPLY) + && ! grub_memcmp (arpreply->thwaddr, ptr, ETH_ALEN)) { grub_memmove ((char *) arptable[ARP_SERVER].node, - arpreply->shwaddr, ETHER_ADDR_SIZE); + arpreply->shwaddr, ETH_ALEN); grub_memmove ((char *) &arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof (in_addr)); grub_memmove ((char *) &arptable[ARP_CLIENT].ipaddr, @@ -805,53 +839,75 @@ await_reply (int type, int ival, void *ptr, int timeout) if (nic.packetlen < protohdrlen || ptype != IP) continue; - ip = (struct iphdr *) &nic.packet[ETHER_HDR_SIZE]; + ip = (struct iphdr *) &nic.packet[ETH_HLEN]; if (ip->verhdrlen != 0x45 || ipchksum ((unsigned short *) ip, sizeof (struct iphdr)) || ip->protocol != IP_UDP) continue; - udp = (struct udphdr *) - &nic.packet[ETHER_HDR_SIZE + sizeof (struct iphdr)]; + /* + - Till Straumann + added udp checksum (safer on a wireless link) + added fragmentation check: I had a corrupted image + in memory due to fragmented TFTP packets - took me + 3 days to find the cause for this :-( + */ + + /* If More Fragments bit and Fragment Offset field + are non-zero then packet is fragmented */ + if (ip->frags & htons(0x3FFF)) + { + grub_printf ("ALERT: got a fragmented packet - reconfigure your server\n"); + continue; + } + + udp = (struct udphdr *) &nic.packet[(ETH_HLEN + + sizeof (struct iphdr))]; + if (udp->chksum && udpchksum (ip)) + { + grub_printf ("UDP checksum error\n"); + continue; + } /* BOOTP ? */ - bootpreply = (struct bootp_t *) &nic.packet[ETHER_HDR_SIZE]; + bootpreply = (struct bootp_t *) + &nic.packet[(ETH_HLEN + sizeof (struct iphdr) + + sizeof (struct udphdr))]; if (type == AWAIT_BOOTP #ifdef NO_DHCP_SUPPORT - && (nic.packetlen - >= (ETHER_HDR_SIZE + sizeof (struct bootp_t))) + && (nic.packetlen >= (ETH_HLEN + sizeof (struct bootp_t))) #else && (nic.packetlen - >= (ETHER_HDR_SIZE + sizeof (struct bootp_t)) - DHCP_OPT_LEN) + >= (ETH_HLEN + sizeof (struct bootp_t) - DHCP_OPT_LEN)) #endif /* ! NO_DHCP_SUPPORT */ - && ntohs (udp->dest) == BOOTP_CLIENT + && udp->dest == htons (BOOTP_CLIENT) && bootpreply->bp_op == BOOTP_REPLY - && bootpreply->bp_xid == xid) + && bootpreply->bp_xid == xid + && (! grub_memcmp (broadcast, bootpreply->bp_hwaddr, ETH_ALEN) + || ! grub_memcmp (arptable[ARP_CLIENT].node, + bootpreply->bp_hwaddr, ETH_ALEN))) { +#ifdef DEBUG + grub_printf ("BOOTP packet was received.\n"); +#endif arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr; #ifndef NO_DHCP_SUPPORT dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr; +#ifdef DEBUG + etherboot_printf ("dhcp_addr = %@\n", dhcp_addr.s_addr); +#endif #endif /* ! NO_DHCP_SUPPORT */ netmask = default_netmask (); arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr; /* Kill arp. */ - grub_memset (arptable[ARP_SERVER].node, 0, ETHER_ADDR_SIZE); + grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN); arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr; /* Kill arp. */ - grub_memset (arptable[ARP_GATEWAY].node, 0, ETHER_ADDR_SIZE); + grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN); - /* GRUB doesn't autoload any kernel image. */ -#ifndef GRUB - if (bootpreply->bp_file[0]) - { - grub_memmove (kernel_buf, bootpreply->bp_file, 128); - kernel = kernel_buf; - } -#endif /* ! GRUB */ - grub_memmove ((char *) BOOTP_DATA_ADDR, (char *) bootpreply, sizeof (struct bootpd_t)); #ifdef NO_DHCP_SUPPORT @@ -859,7 +915,7 @@ await_reply (int type, int ival, void *ptr, int timeout) 0, BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 1); #else decode_rfc1533 (BOOTP_DATA_ADDR->bootp_reply.bp_vend, - 0, DHCP_OPT_LEN, 1); + 0, DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, 1); #endif /* ! NO_DHCP_SUPPORT */ return 1; @@ -904,15 +960,6 @@ decode_rfc1533 (unsigned char *p, int block, int len, int eof) if (block == 0) { -#ifdef IMAGE_MENU - memset (imagelist, 0, sizeof (imagelist)); - menudefault = useimagemenu = 0; - menutmo = -1; -#endif -#ifdef MOTD - memset (motd, 0, sizeof (motd)); -#endif - end_of_rfc1533 = NULL; vendorext_isvalid = 0; @@ -952,142 +999,104 @@ decode_rfc1533 (unsigned char *p, int block, int len, int eof) p = extdata; endp = extend; } + + if (! eof) + return -1; - if (eof) + while (p < endp) { - while (p < endp) + unsigned char c = *p; + + if (c == RFC1533_PAD) { - unsigned char c = *p; - - if (c == RFC1533_PAD) - { - p++; - continue; - } - else if (c == RFC1533_END) - { - end_of_rfc1533 = endp = p; - continue; - } - else if (c == RFC1533_NETMASK) - { - grub_memmove ((char *) &netmask, p + 2, sizeof (in_addr)); - } - else if (c == RFC1533_GATEWAY) - { - /* This is a little simplistic, but it will - usually be sufficient. - Take only the first entry. */ - if (TAG_LEN (p) >= sizeof (in_addr)) - grub_memmove ((char *) &arptable[ARP_GATEWAY].ipaddr, p + 2, - sizeof (in_addr)); - } - else if (c == RFC1533_EXTENSIONPATH) - extpath = p; + p++; + continue; + } + else if (c == RFC1533_END) + { + end_of_rfc1533 = endp = p; + continue; + } + else if (c == RFC1533_NETMASK) + { + grub_memmove ((char *) &netmask, p + 2, sizeof (in_addr)); + } + else if (c == RFC1533_GATEWAY) + { + /* This is a little simplistic, but it will + usually be sufficient. + Take only the first entry. */ + if (TAG_LEN (p) >= sizeof (in_addr)) + grub_memmove ((char *) &arptable[ARP_GATEWAY].ipaddr, p + 2, + sizeof (in_addr)); + } + else if (c == RFC1533_EXTENSIONPATH) + extpath = p; #ifndef NO_DHCP_SUPPORT - else if (c == RFC2132_MSG_TYPE) - { - dhcp_reply = *(p + 2); - } - else if (c == RFC2132_SRV_ID) - { - grub_memmove ((char *) &dhcp_server, p + 2, sizeof (in_addr)); - } + else if (c == RFC2132_MSG_TYPE) + { + dhcp_reply = *(p + 2); + } + else if (c == RFC2132_SRV_ID) + { + grub_memmove ((char *) &dhcp_server, p + 2, sizeof (in_addr)); +#ifdef DEBUG + etherboot_printf ("dhcp_server = %@\n", dhcp_server.s_addr); +#endif + } #endif /* ! NO_DHCP_SUPPORT */ + else if (c == RFC1533_VENDOR_MAGIC + && TAG_LEN(p) >= 6 + && ! grub_memcmp (p + 2, vendorext_magic, 4) + && p[6] == RFC1533_VENDOR_MAJOR) + vendorext_isvalid++; + /* GRUB now handles its own tag. Get the name of a configuration + file from the network. Cool... */ + else if (c == RFC1533_VENDOR_CONFIGFILE) + { + int l = TAG_LEN (p); - else if (c == RFC1533_VENDOR_MAGIC -# ifndef IMAGE_FREEBSD /* since FreeBSD uses tag 128 for swap definition */ - && TAG_LEN(p) >= 6 && - !memcmp(p+2,vendorext_magic,4) && - p[6] == RFC1533_VENDOR_MAJOR -# endif - ) - vendorext_isvalid++; + /* Eliminate the trailing NULs according to RFC 2132. */ + while (*(p + 2 + l - 1) == '\000' && l > 0) + l--; - /* GRUB now handles its own tag. Get the name of a configuration - file from the network. Cool... */ -#ifdef GRUB - else if (c == RFC1533_VENDOR_CONFIGFILE) - { - int len = TAG_LEN (p); - - /* Eliminate the trailing NULs according to RFC 2132. */ - while (*(p + 2 + len - 1) == '\000' && len > 0) - len--; - - /* XXX: Should check if LEN is less than the maximum length - of CONFIG_FILE. This kind of robustness will be a goal - in GRUB 1.0. */ - grub_memmove (config_file, p + 2, len); - config_file[len] = 0; - } -#else /* ! GRUB */ - -# ifdef IMAGE_FREEBSD - else if (c == RFC1533_VENDOR_HOWTO) { - freebsd_howto = ((p[2]*256+p[3])*256+p[4])*256+p[5]; - } -# endif -# ifdef IMAGE_MENU - else if (c == RFC1533_VENDOR_MNUOPTS) - { - parse_menuopts (p + 2, TAG_LEN (p)); - } - else if (c >= RFC1533_VENDOR_IMG && - c < RFC1533_VENDOR_IMG + RFC1533_VENDOR_NUMOFIMG) - { - imagelist[c - RFC1533_VENDOR_IMG] = p; - useimagemenu++; - } -# endif -# ifdef MOTD - else if (c >= RFC1533_VENDOR_MOTD && - c < RFC1533_VENDOR_MOTD + - RFC1533_VENDOR_NUMOFMOTD) - motd[c - RFC1533_VENDOR_MOTD] = p; -# endif - else - { -# if 0 - printf("Unknown RFC1533-tag "); - for(q=p;q 0) + fnamelen--; + + if (fnamelen + 1 > sizeof (fname)) { - char fname[64]; - int fnamelen = TAG_LEN (extpath); - - while (*(extpath + 2 + fnamelen - 1) == '\000' && fnamelen > 0) - fnamelen--; - - if (fnamelen + 1 > sizeof (fname)) - { - grub_printf ("Too long file name for Extensions Path\n"); - return 0; - } - else if (! fnamelen) - { - grub_printf ("Empty file name for Extensions Path\n"); - return 0; - } - - grub_memmove (fname, extpath + 2, fnamelen); - fname[fnamelen] = '\000'; - grub_printf ("Loading BOOTP-extension file: %s\n", fname); - tftp (fname, decode_rfc1533); + grub_printf ("Too long file name for Extensions Path\n"); + return 0; } + else if (! fnamelen) + { + grub_printf ("Empty file name for Extensions Path\n"); + return 0; + } + + grub_memmove (fname, extpath + 2, fnamelen); + fname[fnamelen] = '\000'; + grub_printf ("Loading BOOTP-extension file: %s\n", fname); + tftp (fname, decode_rfc1533); } /* Proceed with next block. */ @@ -1097,7 +1106,7 @@ decode_rfc1533 (unsigned char *p, int block, int len, int eof) /************************************************************************** IPCHKSUM - Checksum IP Header **************************************************************************/ -unsigned short +static unsigned short ipchksum (unsigned short *ip, int len) { unsigned long sum = 0; @@ -1111,70 +1120,45 @@ ipchksum (unsigned short *ip, int len) return (~sum) & 0x0000FFFF; } +#define TWO_SECOND_DIVISOR (2147483647l/TICKS_PER_SEC) + /************************************************************************** -RFC951_SLEEP - sleep for expotentially longer times +RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times **************************************************************************/ -void -rfc951_sleep (int exp) +long +rfc2131_sleep_interval (int base, int exp) { static long seed = 0; long q; unsigned long tmo; - + #ifdef BACKOFF_LIMIT if (exp > BACKOFF_LIMIT) exp = BACKOFF_LIMIT; #endif - - if (! seed) - /* Initialize linear congruential generator. */ - seed = (currticks () + *(long *) &arptable[ARP_CLIENT].node + if (!seed) + /* Initialize linear congruential generator */ + seed = (currticks () + *((long *) &arptable[ARP_CLIENT].node) + ((short *) arptable[ARP_CLIENT].node)[2]); - - /* Simplified version of the LCG given in Bruce Scheier's - "Applied Cryptography". */ + /* simplified version of the LCG given in Bruce Schneier's + "Applied Cryptography" */ q = seed / 53668; - if ((seed = 40014 * (seed - 53668 * q) - 12211 * q) < 0) - seed += 2147483563l; - - /* Compute mask. */ - for (tmo = 63; tmo <= 60 * TICKS_PER_SEC && --exp > 0; tmo = 2 * tmo + 1) - ; - - /* Sleep. */ - grub_printf ("\n"); - - for (tmo = (tmo & seed) + currticks (); currticks () < tmo;) - /* If the user interrupts, return immediately. */ - if (checkkey () != -1 && ASCII_CHAR (getkey ()) == CTRL_C) - break; + if ((seed = 40014 * (seed - 53668 * q) - 12211 *q ) < 0) + seed += 2147483563L; + tmo = (base << exp) + (TICKS_PER_SEC - (seed / TWO_SECOND_DIVISOR)); + return tmo; } /************************************************************************** -CLEANUP_NET - shut down networking +CLEANUP - shut down networking **************************************************************************/ void cleanup_net (void) { if (network_ready) { -#ifdef DOWNLOAD_PROTO_NFS - nfs_umountall (ARP_SERVER); -#endif + /* Stop receiving packets. */ eth_disable (); network_ready = 0; } } - -#ifndef GRUB -/************************************************************************** -CLEANUP - shut down etherboot so that the OS may be called right away -**************************************************************************/ -void -cleanup (void) -{ -#if defined(ANSIESC) && defined(CONSOLE_CRT) - ansi_reset (); -#endif -} -#endif /* ! GRUB */ diff --git a/netboot/misc.c b/netboot/misc.c index 4fc42d68d..cb9bbff00 100644 --- a/netboot/misc.c +++ b/netboot/misc.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2000 Free Software Foundation, Inc. + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,324 +17,237 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* Based on "src/misc.c" in etherboot-4.5.8. */ +/* Based on "src/misc.c" in etherboot-5.0.5. */ -/************************************************************************** -MISC Support Routines -**************************************************************************/ +#define GRUB 1 +#include -#include "etherboot.h" - -/************************************************************************** -SLEEP -**************************************************************************/ -void sleep(int secs) +void +sleep (int secs) { - unsigned long tmo; + unsigned long tmo = currticks () + secs; - for (tmo = currticks()+secs*TICKS_PER_SEC; currticks() < tmo; ) - /* Nothing */; + while (currticks () < tmo) + ; } -/************************************************************************** -TWIDDLE -**************************************************************************/ -void twiddle() +void +twiddle (void) { - static unsigned long lastticks = 0; - static int count=0; - static char tiddles[]="-\\|/"; - unsigned long ticks; - if ((ticks = currticks()) == lastticks) - return; - lastticks = ticks; - putchar(tiddles[(count++)&3]); - putchar('\b'); -} - -#ifndef GRUB -/************************************************************************** -STRCASECMP (not entirely correct, but this will do for our purposes) -**************************************************************************/ -int strcasecmp(a,b) - char *a, *b; -{ - while (*a && *b && (*a & ~0x20) == (*b & ~0x20)) {a++; b++; } - return((*a & ~0x20) - (*b & ~0x20)); + grub_putchar('.'); } +/* Because Etherboot uses its own formats for the printf family, + define separate definitions from GRUB. */ /************************************************************************** PRINTF and friends Formats: - %X - 4 byte ASCII (8 hex digits) - %x - 2 byte ASCII (4 hex digits) - %b - 1 byte ASCII (2 hex digits) - %d - decimal (also %i) - %c - ASCII char - %s - ASCII string - %I - Internet address in x.x.x.x notation + %[#]x - 4 bytes long (8 hex digits, lower case) + %[#]X - 4 bytes long (8 hex digits, upper case) + %[#]hx - 2 bytes int (4 hex digits, lower case) + %[#]hX - 2 bytes int (4 hex digits, upper case) + %[#]hhx - 1 byte int (2 hex digits, lower case) + %[#]hhX - 1 byte int (2 hex digits, upper case) + - optional # prefixes 0x or 0X + %d - decimal int + %c - char + %s - string + %@ - Internet address in ddd.ddd.ddd.ddd notation + %! - Ethernet address in xx:xx:xx:xx:xx:xx notation + Note: width specification not supported **************************************************************************/ -static char hex[]="0123456789ABCDEF"; -static char *do_printf(char *buf, const char *fmt, const int *dp) +static int +etherboot_vsprintf (char *buf, const char *fmt, const int *dp) { - register char *p; - char tmp[16]; - while (*fmt) { - if (*fmt == '%') { /* switch() uses more space */ - fmt++; - - if (*fmt == 'X') { - const long *lp = (const long *)dp; - register long h = *lp++; - dp = (const int *)lp; - *(buf++) = hex[(h>>28)& 0x0F]; - *(buf++) = hex[(h>>24)& 0x0F]; - *(buf++) = hex[(h>>20)& 0x0F]; - *(buf++) = hex[(h>>16)& 0x0F]; - *(buf++) = hex[(h>>12)& 0x0F]; - *(buf++) = hex[(h>>8)& 0x0F]; - *(buf++) = hex[(h>>4)& 0x0F]; - *(buf++) = hex[h& 0x0F]; - } - if (*fmt == 'x') { - register int h = *(dp++); - *(buf++) = hex[(h>>12)& 0x0F]; - *(buf++) = hex[(h>>8)& 0x0F]; - *(buf++) = hex[(h>>4)& 0x0F]; - *(buf++) = hex[h& 0x0F]; - } - if (*fmt == 'b') { - register int h = *(dp++); - *(buf++) = hex[(h>>4)& 0x0F]; - *(buf++) = hex[h& 0x0F]; - } - if ((*fmt == 'd') || (*fmt == 'i')) { - register int dec = *(dp++); - p = tmp; - if (dec < 0) { - *(buf++) = '-'; - dec = -dec; - } - do { - *(p++) = '0' + (dec%10); - dec = dec/10; - } while(dec); - while ((--p) >= tmp) *(buf++) = *p; - } - if (*fmt == 'I') { - union { - long l; - unsigned char c[4]; - } u; - const long *lp = (const long *)dp; - u.l = *lp++; - dp = (const int *)lp; - buf = sprintf(buf,"%d.%d.%d.%d", - u.c[0], u.c[1], u.c[2], u.c[3]); - } - if (*fmt == 'c') - *(buf++) = *(dp++); - if (*fmt == 's') { - p = (char *)*dp++; - while (*p) *(buf++) = *p++; - } - } else *(buf++) = *fmt; - fmt++; + char *p, *s; + + s = buf; + for ( ; *fmt != '\0'; ++fmt) + { + if (*fmt != '%') + { + buf ? *s++ = *fmt : grub_putchar (*fmt); + continue; } - *buf = 0; - return(buf); -} - -char *sprintf(char *buf, const char *fmt, ...) -{ - return do_printf(buf, fmt, ((const int *)&fmt)+1); -} - -void printf(const char *fmt, ...) -{ - char buf[120],*p; - - p = buf; - do_printf(buf, fmt, ((const int *)&fmt)+1); - while (*p) putchar(*p++); -} -#endif /* ! GRUB */ - -#if defined(IMAGE_MENU) || defined(GRUB) -/************************************************************************** -INET_ATON - Convert an ascii x.x.x.x to binary form -**************************************************************************/ -int inet_aton(char *p, in_addr *i) -{ - unsigned long ip = 0; - int val; - if (((val = getdec(&p)) < 0) || (val > 255)) return(0); - if (*p != '.') return(0); - p++; - ip = val; - if (((val = getdec(&p)) < 0) || (val > 255)) return(0); - if (*p != '.') return(0); - p++; - ip = (ip << 8) | val; - if (((val = getdec(&p)) < 0) || (val > 255)) return(0); - if (*p != '.') return(0); - p++; - ip = (ip << 8) | val; - if (((val = getdec(&p)) < 0) || (val > 255)) return(0); - i->s_addr = htonl((ip << 8) | val); - return(1); -} -#endif /* IMAGE_MENU || GRUB */ - -int getdec(char **ptr) -{ - char *p = *ptr; - int ret=0; - if ((*p < '0') || (*p > '9')) return(-1); - while ((*p >= '0') && (*p <= '9')) { - ret = ret*10 + (*p - '0'); - p++; + + if (*++fmt == 's') + { + for (p = (char *) *dp++; *p != '\0'; p++) + buf ? *s++ = *p : grub_putchar (*p); } - *ptr = p; - return(ret); + else + { + /* Length of item is bounded */ + char tmp[20], *q = tmp; + int alt = 0; + int shift = 28; + + if (*fmt == '#') + { + alt = 1; + fmt++; + } + + if (*fmt == 'h') + { + shift = 12; + fmt++; + } + + if (*fmt == 'h') + { + shift = 4; + fmt++; + } + + /* + * Before each format q points to tmp buffer + * After each format q points past end of item + */ + if ((*fmt | 0x20) == 'x') + { + /* With x86 gcc, sizeof(long) == sizeof(int) */ + const long *lp = (const long *) dp; + long h = *lp++; + int ncase = (*fmt & 0x20); + + dp = (const int *) lp; + if (alt) + { + *q++ = '0'; + *q++ = 'X' | ncase; + } + for (; shift >= 0; shift -= 4) + *q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase; + } + else if (*fmt == 'd') + { + int i = *dp++; + char *r; + + if (i < 0) + { + *q++ = '-'; + i = -i; + } + + p = q; /* save beginning of digits */ + do + { + *q++ = '0' + (i % 10); + i /= 10; + } + while (i); + + /* reverse digits, stop in middle */ + r = q; /* don't alter q */ + while (--r > p) + { + i = *r; + *r = *p; + *p++ = i; + } + } + else if (*fmt == '@') + { + unsigned char *r; + union + { + long l; + unsigned char c[4]; + } + u; + const long *lp = (const long *) dp; + + u.l = *lp++; + dp = (const int *) lp; + + for (r = &u.c[0]; r < &u.c[4]; ++r) + q += etherboot_sprintf (q, "%d.", *r); + + --q; + } + else if (*fmt == '!') + { + char *r; + p = (char *) *dp++; + + for (r = p + ETH_ALEN; p < r; ++p) + q += etherboot_sprintf (q, "%hhX:", *p); + + --q; + } + else if (*fmt == 'c') + *q++ = *dp++; + else + *q++ = *fmt; + + /* now output the saved string */ + for (p = tmp; p < q; ++p) + buf ? *s++ = *p : grub_putchar (*p); + } + } + + if (buf) + *s = '\0'; + + return (s - buf); } -#ifndef GRUB -#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ -#define K_STATUS 0x64 /* keyboard status */ -#define K_CMD 0x64 /* keybd ctlr command (write-only) */ - -#define K_OBUF_FUL 0x01 /* output buffer full */ -#define K_IBUF_FUL 0x02 /* input buffer full */ - -#define KC_CMD_WIN 0xd0 /* read output port */ -#define KC_CMD_WOUT 0xd1 /* write output port */ -#define KB_SET_A20 0xdf /* enable A20, - enable output buffer full interrupt - enable data line - disable clock line */ -#define KB_UNSET_A20 0xdd /* enable A20, - enable output buffer full interrupt - enable data line - disable clock line */ -#ifndef IBM_L40 -static void empty_8042(void) +int +etherboot_sprintf (char *buf, const char *fmt, ...) { - unsigned long time; - char st; - - slowdownio(); - time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */ - while ((((st = inb(K_CMD)) & K_OBUF_FUL) || - (st & K_IBUF_FUL)) && - currticks() < time) - inb(K_RDWR); -} -#endif IBM_L40 - -/* - * Gate A20 for high memory - */ -void gateA20_set(void) -{ -#ifdef IBM_L40 - outb(0x2, 0x92); -#else /* IBM_L40 */ - empty_8042(); - outb(KC_CMD_WOUT, K_CMD); - empty_8042(); - outb(KB_SET_A20, K_RDWR); - empty_8042(); -#endif /* IBM_L40 */ + return etherboot_vsprintf (buf, fmt, ((const int *) &fmt) + 1); } -#ifdef TAGGED_IMAGE -/* - * Unset Gate A20 for high memory - some operating systems (mainly old 16 bit - * ones) don't expect it to be set by the boot loader. - */ -void gateA20_unset(void) -{ -#ifdef IBM_L40 - outb(0x0, 0x92); -#else /* IBM_L40 */ - empty_8042(); - outb(KC_CMD_WOUT, K_CMD); - empty_8042(); - outb(KB_UNSET_A20, K_RDWR); - empty_8042(); -#endif /* IBM_L40 */ -} -#endif - -#ifdef ETHERBOOT32 -/* Serial console is only implemented in ETHERBOOT32 for now */ void -putchar(int c) +etherboot_printf (const char *fmt, ...) { -#ifndef ANSIESC - if (c == '\n') - putchar('\r'); -#endif - -#ifdef CONSOLE_CRT -#ifdef ANSIESC - handleansi(c); -#else - putc(c); -#endif -#endif -#ifdef CONSOLE_SERIAL -#ifdef ANSIESC - if (c == '\n') - serial_putc('\r'); -#endif - serial_putc(c); -#endif -} - -/************************************************************************** -GETCHAR - Read the next character from the console WITHOUT ECHO -**************************************************************************/ -int -getchar(void) -{ - int c = 256; - - do { -#ifdef CONSOLE_CRT - if (ischar()) - c = getc(); -#endif -#ifdef CONSOLE_SERIAL - if (serial_ischar()) - c = serial_getc(); -#endif - } while (c==256); - if (c == '\r') - c = '\n'; - return c; + (void) etherboot_vsprintf (0, fmt, ((const int *) &fmt) + 1); } int -iskey(void) +inet_aton (char *p, in_addr *addr) { -#ifdef CONSOLE_CRT - if (ischar()) - return 1; -#endif -#ifdef CONSOLE_SERIAL - if (serial_ischar()) - return 1; -#endif + unsigned long ip = 0; + int val; + int i; + + for (i = 0; i < 4; i++) + { + val = getdec (&p); + + if (val < 0 || val > 255) return 0; -} -#endif /* ETHERBOOT32 */ -#endif /* ! GRUB */ + + if (*p++ != '.') + return 0; + + ip = (ip << 8) | val; + } -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ + addr->s_addr = htonl (ip); + + return 1; +} + +int +getdec (char **ptr) +{ + char *p = *ptr; + int ret = 0; + + if (*p < '0' || *p > '9') + return -1; + + while (*p >= '0' && *p <= '9') + { + ret = ret * 10 + (*p - '0'); + p++; + } + + *ptr = p; + + return ret; +} diff --git a/netboot/ni5010.c b/netboot/ni5010.c new file mode 100644 index 000000000..da3827a7b --- /dev/null +++ b/netboot/ni5010.c @@ -0,0 +1,371 @@ +/************************************************************************** +Etherboot - BOOTP/TFTP Bootstrap Program +Driver for NI5010. +Code freely taken from Jan-Pascal van Best and Andreas Mohr's +Linux NI5010 driver. +***************************************************************************/ + +/* + * 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, or (at + * your option) any later version. + */ + +/* to get some global routines like printf */ +#include "etherboot.h" +/* to get the interface to the body of the program */ +#include "nic.h" +/* to get our own prototype */ +#include "cards.h" + +/* ni5010.h file included verbatim */ +/* + * Racal-Interlan ni5010 Ethernet definitions + * + * This is an extension to the Linux operating system, and is covered by the + * same Gnu Public License that covers that work. + * + * copyrights (c) 1996 by Jan-Pascal van Best (jvbest@wi.leidenuniv.nl) + * + * I have done a look in the following sources: + * crynwr-packet-driver by Russ Nelson + */ + +#define NI5010_BUFSIZE 2048 /* number of bytes in a buffer */ + +#define NI5010_MAGICVAL0 0x00 /* magic-values for ni5010 card */ +#define NI5010_MAGICVAL1 0x55 +#define NI5010_MAGICVAL2 0xAA + +#define SA_ADDR0 0x02 +#define SA_ADDR1 0x07 +#define SA_ADDR2 0x01 + +/* The number of low I/O ports used by the ni5010 ethercard. */ +#define NI5010_IO_EXTENT 32 + +#define PRINTK(x) if (NI5010_DEBUG) printk x +#define PRINTK2(x) if (NI5010_DEBUG>=2) printk x +#define PRINTK3(x) if (NI5010_DEBUG>=3) printk x + +/* The various IE command registers */ +#define EDLC_XSTAT (ioaddr + 0x00) /* EDLC transmit csr */ +#define EDLC_XCLR (ioaddr + 0x00) /* EDLC transmit "Clear IRQ" */ +#define EDLC_XMASK (ioaddr + 0x01) /* EDLC transmit "IRQ Masks" */ +#define EDLC_RSTAT (ioaddr + 0x02) /* EDLC receive csr */ +#define EDLC_RCLR (ioaddr + 0x02) /* EDLC receive "Clear IRQ" */ +#define EDLC_RMASK (ioaddr + 0x03) /* EDLC receive "IRQ Masks" */ +#define EDLC_XMODE (ioaddr + 0x04) /* EDLC transmit Mode */ +#define EDLC_RMODE (ioaddr + 0x05) /* EDLC receive Mode */ +#define EDLC_RESET (ioaddr + 0x06) /* EDLC RESET register */ +#define EDLC_TDR1 (ioaddr + 0x07) /* "Time Domain Reflectometry" reg1 */ +#define EDLC_ADDR (ioaddr + 0x08) /* EDLC station address, 6 bytes */ + /* 0x0E doesn't exist for r/w */ +#define EDLC_TDR2 (ioaddr + 0x0f) /* "Time Domain Reflectometry" reg2 */ +#define IE_GP (ioaddr + 0x10) /* GP pointer (word register) */ + /* 0x11 is 2nd byte of GP Pointer */ +#define IE_RCNT (ioaddr + 0x10) /* Count of bytes in rcv'd packet */ + /* 0x11 is 2nd byte of "Byte Count" */ +#define IE_MMODE (ioaddr + 0x12) /* Memory Mode register */ +#define IE_DMA_RST (ioaddr + 0x13) /* IE DMA Reset. write only */ +#define IE_ISTAT (ioaddr + 0x13) /* IE Interrupt Status. read only */ +#define IE_RBUF (ioaddr + 0x14) /* IE Receive Buffer port */ +#define IE_XBUF (ioaddr + 0x15) /* IE Transmit Buffer port */ +#define IE_SAPROM (ioaddr + 0x16) /* window on station addr prom */ +#define IE_RESET (ioaddr + 0x17) /* any write causes Board Reset */ + +/* bits in EDLC_XSTAT, interrupt clear on write, status when read */ +#define XS_TPOK 0x80 /* transmit packet successful */ +#define XS_CS 0x40 /* carrier sense */ +#define XS_RCVD 0x20 /* transmitted packet received */ +#define XS_SHORT 0x10 /* transmission media is shorted */ +#define XS_UFLW 0x08 /* underflow. iff failed board */ +#define XS_COLL 0x04 /* collision occurred */ +#define XS_16COLL 0x02 /* 16th collision occurred */ +#define XS_PERR 0x01 /* parity error */ + +#define XS_CLR_UFLW 0x08 /* clear underflow */ +#define XS_CLR_COLL 0x04 /* clear collision */ +#define XS_CLR_16COLL 0x02 /* clear 16th collision */ +#define XS_CLR_PERR 0x01 /* clear parity error */ + +/* bits in EDLC_XMASK, mask/enable transmit interrupts. register is r/w */ +#define XM_TPOK 0x80 /* =1 to enable Xmt Pkt OK interrupts */ +#define XM_RCVD 0x20 /* =1 to enable Xmt Pkt Rcvd ints */ +#define XM_UFLW 0x08 /* =1 to enable Xmt Underflow ints */ +#define XM_COLL 0x04 /* =1 to enable Xmt Collision ints */ +#define XM_COLL16 0x02 /* =1 to enable Xmt 16th Coll ints */ +#define XM_PERR 0x01 /* =1 to enable Xmt Parity Error ints */ + /* note: always clear this bit */ +#define XM_ALL (XM_TPOK | XM_RCVD | XM_UFLW | XM_COLL | XM_COLL16) + +/* bits in EDLC_RSTAT, interrupt clear on write, status when read */ +#define RS_PKT_OK 0x80 /* received good packet */ +#define RS_RST_PKT 0x10 /* RESET packet received */ +#define RS_RUNT 0x08 /* Runt Pkt rcvd. Len < 64 Bytes */ +#define RS_ALIGN 0x04 /* Alignment error. not 8 bit aligned */ +#define RS_CRC_ERR 0x02 /* Bad CRC on rcvd pkt */ +#define RS_OFLW 0x01 /* overflow for rcv FIFO */ +#define RS_VALID_BITS ( RS_PKT_OK | RS_RST_PKT | RS_RUNT | RS_ALIGN | RS_CRC_ERR | RS_OFLW ) + /* all valid RSTAT bits */ + +#define RS_CLR_PKT_OK 0x80 /* clear rcvd packet interrupt */ +#define RS_CLR_RST_PKT 0x10 /* clear RESET packet received */ +#define RS_CLR_RUNT 0x08 /* clear Runt Pckt received */ +#define RS_CLR_ALIGN 0x04 /* clear Alignment error */ +#define RS_CLR_CRC_ERR 0x02 /* clear CRC error */ +#define RS_CLR_OFLW 0x01 /* clear rcv FIFO Overflow */ + +/* bits in EDLC_RMASK, mask/enable receive interrupts. register is r/w */ +#define RM_PKT_OK 0x80 /* =1 to enable rcvd good packet ints */ +#define RM_RST_PKT 0x10 /* =1 to enable RESET packet ints */ +#define RM_RUNT 0x08 /* =1 to enable Runt Pkt rcvd ints */ +#define RM_ALIGN 0x04 /* =1 to enable Alignment error ints */ +#define RM_CRC_ERR 0x02 /* =1 to enable Bad CRC error ints */ +#define RM_OFLW 0x01 /* =1 to enable overflow error ints */ + +/* bits in EDLC_RMODE, set Receive Packet mode. register is r/w */ +#define RMD_TEST 0x80 /* =1 for Chip testing. normally 0 */ +#define RMD_ADD_SIZ 0x10 /* =1 5-byte addr match. normally 0 */ +#define RMD_EN_RUNT 0x08 /* =1 enable runt rcv. normally 0 */ +#define RMD_EN_RST 0x04 /* =1 to rcv RESET pkt. normally 0 */ + +#define RMD_PROMISC 0x03 /* receive *all* packets. unusual */ +#define RMD_MULTICAST 0x02 /* receive multicasts too. unusual */ +#define RMD_BROADCAST 0x01 /* receive broadcasts & normal. usual */ +#define RMD_NO_PACKETS 0x00 /* don't receive any packets. unusual */ + +/* bits in EDLC_XMODE, set Transmit Packet mode. register is r/w */ +#define XMD_COLL_CNT 0xf0 /* coll's since success. read-only */ +#define XMD_IG_PAR 0x08 /* =1 to ignore parity. ALWAYS set */ +#define XMD_T_MODE 0x04 /* =1 to power xcvr. ALWAYS set this */ +#define XMD_LBC 0x02 /* =1 for loopback. normally set */ +#define XMD_DIS_C 0x01 /* =1 disables contention. normally 0 */ + +/* bits in EDLC_RESET, write only */ +#define RS_RESET 0x80 /* =1 to hold EDLC in reset state */ + +/* bits in IE_MMODE, write only */ +#define MM_EN_DMA 0x80 /* =1 begin DMA xfer, Cplt clrs it */ +#define MM_EN_RCV 0x40 /* =1 allows Pkt rcv. clr'd by rcv */ +#define MM_EN_XMT 0x20 /* =1 begin Xmt pkt. Cplt clrs it */ +#define MM_BUS_PAGE 0x18 /* =00 ALWAYS. Used when MUX=1 */ +#define MM_NET_PAGE 0x06 /* =00 ALWAYS. Used when MUX=0 */ +#define MM_MUX 0x01 /* =1 means Rcv Buff on system bus */ + /* =0 means Xmt Buff on system bus */ + +/* bits in IE_ISTAT, read only */ +#define IS_TDIAG 0x80 /* =1 if Diagnostic problem */ +#define IS_EN_RCV 0x20 /* =1 until frame is rcv'd cplt */ +#define IS_EN_XMT 0x10 /* =1 until frame is xmt'd cplt */ +#define IS_EN_DMA 0x08 /* =1 until DMA is cplt or aborted */ +#define IS_DMA_INT 0x04 /* =0 iff DMA done interrupt. */ +#define IS_R_INT 0x02 /* =0 iff unmasked Rcv interrupt */ +#define IS_X_INT 0x01 /* =0 iff unmasked Xmt interrupt */ + +/* NIC specific static variables go here */ + +static unsigned short ioaddr = 0; +static unsigned int bufsize_rcv = 0; + +#if 0 +static void show_registers(void) +{ + printf("XSTAT %hhX ", inb(EDLC_XSTAT)); + printf("XMASK %hhX ", inb(EDLC_XMASK)); + printf("RSTAT %hhX ", inb(EDLC_RSTAT)); + printf("RMASK %hhX ", inb(EDLC_RMASK)); + printf("RMODE %hhX ", inb(EDLC_RMODE)); + printf("XMODE %hhX ", inb(EDLC_XMODE)); + printf("ISTAT %hhX\n", inb(IE_ISTAT)); +} +#endif + +static void reset_receiver(void) +{ + outw(0, IE_GP); /* Receive packet at start of buffer */ + outb(RS_VALID_BITS, EDLC_RCLR); /* Clear all pending Rcv interrupts */ + outb(MM_EN_RCV, IE_MMODE); /* Enable rcv */ +} + +/************************************************************************** +RESET - Reset adapter +***************************************************************************/ +static void ni5010_reset(struct nic *nic) +{ + int i; + + /* Reset the hardware here. Don't forget to set the station address. */ + outb(RS_RESET, EDLC_RESET); /* Hold up EDLC_RESET while configing board */ + outb(0, IE_RESET); /* Hardware reset of ni5010 board */ + outb(0, EDLC_XMASK); /* Disable all Xmt interrupts */ + outb(0, EDLC_RMASK); /* Disable all Rcv interrupt */ + outb(0xFF, EDLC_XCLR); /* Clear all pending Xmt interrupts */ + outb(0xFF, EDLC_RCLR); /* Clear all pending Rcv interrupts */ + outb(XMD_LBC, EDLC_XMODE); /* Only loopback xmits */ + /* Set the station address */ + for(i = 0; i < ETH_ALEN; i++) + outb(nic->node_addr[i], EDLC_ADDR + i); + outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE); + /* Normal packet xmit mode */ + outb(RMD_BROADCAST, EDLC_RMODE); + /* Receive broadcast and normal packets */ + reset_receiver(); + outb(0x00, EDLC_RESET); /* Un-reset the ni5010 */ +} + +/************************************************************************** +POLL - Wait for a frame +***************************************************************************/ +static int ni5010_poll(struct nic *nic) +{ + int rcv_stat; + + if (((rcv_stat = inb(EDLC_RSTAT)) & RS_VALID_BITS) != RS_PKT_OK) { + outb(rcv_stat, EDLC_RSTAT); /* Clear the status */ + return (0); + } + outb(rcv_stat, EDLC_RCLR); /* Clear the status */ + nic->packetlen = inw(IE_RCNT); + /* Read packet into buffer */ + outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */ + outw(0, IE_GP); /* Seek to beginning of packet */ + insb(IE_RBUF, nic->packet, nic->packetlen); + return (1); +} + +/************************************************************************** +TRANSMIT - Transmit a frame +***************************************************************************/ +static void ni5010_transmit(struct nic *nic, + const char *d, /* Destination */ + unsigned int t, /* Type */ + unsigned int s, /* size */ + const char *p) /* Packet */ +{ + unsigned int len; + int buf_offs, xmt_stat; + unsigned long time; + + len = s + ETH_HLEN; + if (len < ETH_ZLEN) + len = ETH_ZLEN; + buf_offs = NI5010_BUFSIZE - len; + outb(0, EDLC_RMASK); /* Mask all receive interrupts */ + outb(0, IE_MMODE); /* Put Xmit buffer on system bus */ + outb(0xFF, EDLC_RCLR); /* Clear out pending rcv interrupts */ + outw(buf_offs, IE_GP); /* Point GP at start of packet */ + outsb(IE_XBUF, d, ETH_ALEN); /* Put dst in buffer */ + outsb(IE_XBUF, nic->node_addr, ETH_ALEN);/* Put src in buffer */ + outb(t >> 8, IE_XBUF); + outb(t, IE_XBUF); + outsb(IE_XBUF, p, s); /* Put data in buffer */ + while (s++ < ETH_ZLEN - ETH_HLEN) /* Pad to min size */ + outb(0, IE_XBUF); + outw(buf_offs, IE_GP); /* Rewrite where packet starts */ + /* should work without that outb() (Crynwr used it) */ + /*outb(MM_MUX, IE_MMODE);*/ + /* Xmt buffer to EDLC bus */ + outb(MM_EN_XMT | MM_MUX, IE_MMODE); /* Begin transmission */ + /* wait for transmit complete */ + while (((xmt_stat = inb(IE_ISTAT)) & IS_EN_XMT) != 0) + ; + reset_receiver(); /* Immediately switch to receive */ +} + +/************************************************************************** +DISABLE - Turn off ethernet interface +***************************************************************************/ +static void ni5010_disable(struct nic *nic) +{ + outb(0, IE_MMODE); + outb(RS_RESET, EDLC_RESET); +} + +static inline int rd_port(void) +{ + inb(IE_RBUF); + return inb(IE_SAPROM); +} + +static int ni5010_probe1(struct nic *nic) +{ + int i, boguscount = 40, data; + + /* The tests are from the Linux NI5010 driver + I don't understand it all, but if it works for them... */ + if (inb(ioaddr) == 0xFF) + return (0); + while ((rd_port() & rd_port() & rd_port() + & rd_port() & rd_port() & rd_port()) != 0xFF) + { + if (boguscount-- <= 0) + return (0); + } + for (i = 0; i < 32; i++) + if ((data = rd_port()) != 0xFF) + break; + if (data == 0xFF) + return (0); + if (data == SA_ADDR0 && rd_port() == SA_ADDR1 && rd_port() == SA_ADDR2) { + for (i = 0; i < 4; i++) + rd_port(); + if (rd_port() != NI5010_MAGICVAL1 || rd_port() != NI5010_MAGICVAL2) + return (0); + } else + return (0); + for (i = 0; i < ETH_ALEN; i++) { + outw(i, IE_GP); + nic->node_addr[i] = inb(IE_SAPROM); + } + printf("\nNI5010 ioaddr %#hX, addr %!\n", ioaddr, nic->node_addr); +/* get the size of the onboard receive buffer + * higher addresses than bufsize are wrapped into real buffer + * i.e. data for offs. 0x801 is written to 0x1 with a 2K onboard buffer + */ + if (bufsize_rcv == 0) { + outb(1, IE_MMODE); /* Put Rcv buffer on system bus */ + outw(0, IE_GP); /* Point GP at start of packet */ + outb(0, IE_RBUF); /* set buffer byte 0 to 0 */ + for (i = 1; i < 0xFF; i++) { + outw(i << 8, IE_GP); /* Point GP at packet size to be tested */ + outb(i, IE_RBUF); + outw(0x0, IE_GP); /* Point GP at start of packet */ + data = inb(IE_RBUF); + if (data == i) break; + } + bufsize_rcv = i << 8; + outw(0, IE_GP); /* Point GP at start of packet */ + outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */ + } + printf("Bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE); + return (1); +} + +/************************************************************************** +PROBE - Look for an adapter, this routine's visible to the outside +***************************************************************************/ +struct nic *ni5010_probe(struct nic *nic, unsigned short *probe_addrs) +{ + static unsigned short io_addrs[] = { + 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 }; + unsigned short *p; + + /* if probe_addrs is 0, then use list above */ + if (probe_addrs == 0 || *probe_addrs == 0) + probe_addrs = io_addrs; + for (p = probe_addrs; (ioaddr = *p) != 0; p++) { + if (ni5010_probe1(nic)) + break; + } + if (ioaddr == 0) + return (0); + ni5010_reset(nic); + /* point to NIC specific routines */ + nic->reset = ni5010_reset; + nic->poll = ni5010_poll; + nic->transmit = ni5010_transmit; + nic->disable = ni5010_disable; + return (nic); +} diff --git a/netboot/nic.h b/netboot/nic.h index a485a9640..7a235fb3c 100644 --- a/netboot/nic.h +++ b/netboot/nic.h @@ -20,7 +20,8 @@ struct nic void (*transmit)P((struct nic *, const char *d, unsigned int t, unsigned int s, const char *p)); void (*disable)P((struct nic *)); - char aui; + int flags; /* driver specific flags */ + struct rom_info *rom_info; /* -> rom_info from main */ unsigned char *node_addr; char *packet; unsigned int packetlen; diff --git a/netboot/ns8390.c b/netboot/ns8390.c index 41e54764f..07ec459f1 100644 --- a/netboot/ns8390.c +++ b/netboot/ns8390.c @@ -252,9 +252,9 @@ static void ns8390_reset(struct nic *nic) #endif outb(D8390_COMMAND_PS1 | D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); - for (i=0; inode_addr[i], eth_nic_base+D8390_P1_PAR0+i); - for (i=0; iaui) ? 0 : _3COM_CR_XSEL; + t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL; outb(t503_output, eth_asic_base + _3COM_CR); #endif } @@ -344,31 +344,15 @@ static void ns8390_transmit( unsigned int s, /* size */ const char *p) /* Packet */ { - int c; /* used in ETHERBOOT16 */ - #ifdef INCLUDE_3C503 if (!(eth_flags & FLAG_PIO)) { -#ifdef ETHERBOOT32 - memcpy((void *)eth_bmem, d, ETHER_ADDR_SIZE); /* dst */ - memcpy((void *)eth_bmem+ETHER_ADDR_SIZE, nic->node_addr, ETHER_ADDR_SIZE); /* src */ + memcpy((char *)eth_bmem, d, ETH_ALEN); /* dst */ + memcpy((char *)eth_bmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ *((char *)eth_bmem+12) = t>>8; /* type */ *((char *)eth_bmem+13) = t; - memcpy((void *)eth_bmem+ETHER_HDR_SIZE, p, s); - s += ETHER_HDR_SIZE; - while (s < ETH_MIN_PACKET) *((char *)eth_bmem+(s++)) = 0; -#endif -#ifdef ETHERBOOT16 - memcpyf(eth_bmem, d, ETHER_ADDR_SIZE); - memcpyf(eth_bmem+ETHER_ADDR_SIZE, nic->node_addr, ETHER_ADDR_SIZE); - c = t >> 8; - memcpyf(eth_bmem+12, &c, 1); - c = t; - memcpyf(eth_bmem+13, &c, 1); - memcpyf((Address)(eth_bmem+ETHER_HDR_SIZE), p, s); - s += ETHER_HDR_SIZE; - if (s < ETH_MIN_PACKET) - bzerof(eth_bmem+s, ETH_MIN_PACKET-s), s = ETH_MIN_PACKET; -#endif + memcpy((char *)eth_bmem+ETH_HLEN, p, s); + s += ETH_HLEN; + while (s < ETH_ZLEN) *((char *)eth_bmem+(s++)) = 0; } #endif @@ -383,28 +367,13 @@ static void ns8390_transmit( inb(0x84); } inb(0x84); -#ifdef ETHERBOOT32 - memcpy((void *)eth_bmem, d, ETHER_ADDR_SIZE); /* dst */ - memcpy((void *)eth_bmem+ETHER_ADDR_SIZE, nic->node_addr, ETHER_ADDR_SIZE); /* src */ + memcpy((char *)eth_bmem, d, ETH_ALEN); /* dst */ + memcpy((char *)eth_bmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ *((char *)eth_bmem+12) = t>>8; /* type */ *((char *)eth_bmem+13) = t; - memcpy((void *)eth_bmem+ETHER_HDR_SIZE, p, s); - s += ETHER_HDR_SIZE; - while (s < ETH_MIN_PACKET) *((char *)eth_bmem+(s++)) = 0; -#endif -#ifdef ETHERBOOT16 - memcpyf(eth_bmem, d, ETHER_ADDR_SIZE); - memcpyf(eth_bmem+ETHER_ADDR_SIZE, nic->node_addr, ETHER_ADDR_SIZE); - c = t >> 8; - /* bcc generates worse code without (const+const) below */ - memcpyf(eth_bmem+(ETHER_ADDR_SIZE+ETHER_ADDR_SIZE), &c, 1); - c = t; - memcpyf(eth_bmem+(ETHER_ADDR_SIZE+ETHER_ADDR_SIZE+1), &c, 1); - memcpyf((Address)(eth_bmem+ETHER_HDR_SIZE), p, s); - s += ETHER_HDR_SIZE; - if (s < ETH_MIN_PACKET) - bzerof(eth_bmem+s, ETH_MIN_PACKET-s), s = ETH_MIN_PACKET; -#endif + memcpy((char *)eth_bmem+ETH_HLEN, p, s); + s += ETH_HLEN; + while (s < ETH_ZLEN) *((char *)eth_bmem+(s++)) = 0; if (eth_flags & FLAG_790) { outb(0, eth_asic_base + WD_MSR); inb(0x84); @@ -422,13 +391,13 @@ static void ns8390_transmit( /* Programmed I/O */ unsigned short type; type = (t >> 8) | (t << 8); - eth_pio_write(d, eth_tx_start<<8, ETHER_ADDR_SIZE); - eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETHER_ADDR_SIZE, ETHER_ADDR_SIZE); + eth_pio_write(d, eth_tx_start<<8, ETH_ALEN); + eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN); /* bcc generates worse code without (const+const) below */ - eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETHER_ADDR_SIZE+ETHER_ADDR_SIZE), 2); - eth_pio_write(p, (eth_tx_start<<8)+ETHER_HDR_SIZE, s); - s += ETHER_HDR_SIZE; - if (s < ETH_MIN_PACKET) s = ETH_MIN_PACKET; + eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2); + eth_pio_write(p, (eth_tx_start<<8)+ETH_HLEN, s); + s += ETH_HLEN; + if (s < ETH_ZLEN) s = ETH_ZLEN; #endif #if defined(INCLUDE_3C503) } @@ -499,15 +468,12 @@ static int ns8390_poll(struct nic *nic) if (eth_flags & FLAG_PIO) eth_pio_read(pktoff, (char *)&pkthdr, 4); else -#ifdef ETHERBOOT32 - memcpy(&pkthdr, (void *)eth_rmem + pktoff, 4); -#endif -#ifdef ETHERBOOT16 - fmemcpy(&pkthdr, eth_rmem + pktoff, 4); -#endif + memcpy(&pkthdr, (char *)eth_rmem + pktoff, 4); pktoff += sizeof(pkthdr); - len = pkthdr.len - 4; /* sub CRC */ - if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || pkthdr.len < ETH_MIN_PACKET) { + /* incoming length includes FCS so must sub 4 */ + len = pkthdr.len - 4; + if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN + || len > ETH_FRAME_LEN) { printf("Bogus packet, ignoring\n"); return (0); } @@ -520,12 +486,7 @@ static int ns8390_poll(struct nic *nic) if (eth_flags & FLAG_PIO) eth_pio_read(pktoff, p, frag); else -#ifdef ETHERBOOT32 - memcpy(p, (void *)eth_rmem + pktoff, frag); -#endif -#ifdef ETHERBOOT16 - fmemcpy(p, eth_rmem + pktoff, frag); -#endif + memcpy(p, (char *)eth_rmem + pktoff, frag); pktoff = eth_rx_start << 8; p += frag; len -= frag; @@ -534,12 +495,7 @@ static int ns8390_poll(struct nic *nic) if (eth_flags & FLAG_PIO) eth_pio_read(pktoff, p, len); else -#ifdef ETHERBOOT32 - memcpy(p, (void *)eth_rmem + pktoff, len); -#endif -#ifdef ETHERBOOT16 - fmemcpy(p, eth_rmem + pktoff, len); -#endif + memcpy(p, (char *)eth_rmem + pktoff, len); ret = 1; } #ifdef INCLUDE_WD @@ -581,9 +537,6 @@ struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs) struct wd_board *brd; unsigned short chksum; unsigned char c; -#if defined(INCLUDE_WD) && defined(ETHERBOOT16) - unsigned char bmem13, bmem11; -#endif eth_vendor = VENDOR_NONE; eth_drain_receiver = 0; @@ -611,7 +564,7 @@ struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs) for (brd = wd_boards; brd->name; brd++) if (brd->id == c) break; if (!brd->name) { - printf("Unknown WD/SMC NIC type %x\n", c); + printf("Unknown WD/SMC NIC type %hhX\n", c); return (0); /* Unknown type */ } eth_flags = brd->flags; @@ -624,23 +577,10 @@ struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs) eth_memsize = MEM_16384; } if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) { -#ifdef ETHERBOOT32 eth_bmem = (0x80000 | ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13)); -#endif -#ifdef ETHERBOOT16 - eth_bmem = inb(eth_asic_base + WD_MSR) & 0x3F; - eth_bmem <<= 13; - eth_bmem |= 0x80000; -#endif } else eth_bmem = WD_DEFAULT_MEM; -#ifdef ETHERBOOT16 - /* cast is to force evaluation in long precision */ - bmem13 = (Address)eth_bmem >> 13; - bmem11 = (Address)eth_bmem >> 11; -#endif -#ifdef ETHERBOOT32 if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) { *((unsigned int *)(eth_bmem + 8192)) = (unsigned int)0; if (*((unsigned int *)(eth_bmem + 8192))) { @@ -648,48 +588,23 @@ struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs) eth_memsize = brd->memsize; } } -#endif -#ifdef ETHERBOOT16 - if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) { - i = 0; - memcpyf(eth_bmem + 8192, &i, sizeof(i)); - if (!fbsame(eth_bmem + 8192, 0, sizeof(i))) { - brd += 2; - eth_memsize = brd->memsize; - } - } -#endif outb(0x80, eth_asic_base + WD_MSR); /* Reset */ - printf("\n%s base 0x%x, memory 0x%X, addr ", - brd->name, eth_asic_base, eth_bmem); - for (i=0; inode_addr[i] = - inb(i+eth_asic_base+WD_LAR))); - if (i < ETHER_ADDR_SIZE-1) printf (":"); + for (i=0; inode_addr[i] = inb(i+eth_asic_base+WD_LAR); } + printf("\n%s base %#hx, memory %#hx, addr %!\n", + brd->name, eth_asic_base, eth_bmem, nic->node_addr); if (eth_flags & FLAG_790) { outb(WD_MSR_MENB, eth_asic_base+WD_MSR); outb((inb(eth_asic_base+0x04) | 0x80), eth_asic_base+0x04); -#ifdef ETHERBOOT32 outb((((unsigned)eth_bmem >> 13) & 0x0F) | (((unsigned)eth_bmem >> 11) & 0x40) | (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B); -#endif -#ifdef ETHERBOOT16 - outb((bmem13 & 0x0F) | - (bmem11 & 0x40) | - (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B); -#endif outb((inb(eth_asic_base+0x04) & ~0x80), eth_asic_base+0x04); } else { -#ifdef ETHERBOOT32 outb((((unsigned)eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR); -#endif -#ifdef ETHERBOOT16 - outb((bmem13 & 0x3F) | 0x40, eth_asic_base+WD_MSR); -#endif } if (eth_flags & FLAG_16BIT) { if (eth_flags & FLAG_790) { @@ -709,7 +624,6 @@ struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs) } inb(0x84); } - putchar('\n'); #endif #ifdef INCLUDE_3C503 /****************************************************************** @@ -794,17 +708,16 @@ struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs) /* Get our ethernet address */ outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR); - printf("\n3Com 3c503 base 0x%x, ", eth_nic_base); + printf("\n3Com 3c503 base %#hx, ", eth_nic_base); if (eth_flags & FLAG_PIO) printf("PIO mode"); else - printf("memory 0x%X", eth_bmem); - printf(", %s, addr ", nic->aui ? "AUI" : "internal xcvr"); - for (i=0; inode_addr[i] = - inb(eth_nic_base+i))); - if (i < ETHER_ADDR_SIZE-1) printf (":"); + printf("memory %#hx", eth_bmem); + for (i=0; inode_addr[i] = inb(eth_nic_base+i); } + printf(", %s, addr %!\n", nic->flags ? "AUI" : "internal xcvr", + nic->node_addr); outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR); /* * Initialize GA configuration register. Set bank and enable shared @@ -821,30 +734,18 @@ struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs) */ if (!(eth_flags & FLAG_PIO)) { -#ifdef ETHERBOOT32 memset((char *)eth_bmem, 0, 0x2000); for(i = 0; i < 0x2000; ++i) if (*(((char *)eth_bmem)+i)) { printf ("Failed to clear 3c503 shared mem.\n"); return (0); } -#endif -#ifdef ETHERBOOT16 - bzerof(eth_bmem, 0x2000); - if (!fbsame(eth_bmem, 0, 0x2000)) { - printf ("Failed to clear 3c503 shared mem.\n"); - return (0); - } -#endif } /* * Initialize GA page/start/stop registers. */ outb(eth_tx_start, eth_asic_base + _3COM_PSTR); outb(eth_memsize, eth_asic_base + _3COM_PSPR); - - printf ("\n"); - } #endif #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) @@ -906,14 +807,12 @@ struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs) eth_flags |= FLAG_16BIT; eth_vendor = VENDOR_NOVELL; eth_pio_read(0, romdata, sizeof(romdata)); - printf("\nNE%c000 base 0x%x, addr ", - (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base); - for (i=0; inode_addr[i] = romdata[i - + ((eth_flags & FLAG_16BIT) ? i : 0)])); - if (i < ETHER_ADDR_SIZE-1) printf (":"); + for (i=0; inode_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)]; } - putchar('\n'); + printf("\nNE%c000 base %#hx, addr %!\n", + (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, + nic->node_addr); } #endif if (eth_vendor == VENDOR_NONE) diff --git a/netboot/ns8390.h b/netboot/ns8390.h index 4dc267f21..2c4e972d5 100644 --- a/netboot/ns8390.h +++ b/netboot/ns8390.h @@ -6,6 +6,15 @@ Author: Martin Renters **************************************************************************/ +#define VENDOR_NONE 0 +#define VENDOR_WD 1 +#define VENDOR_NOVELL 2 +#define VENDOR_3COM 3 + +#define FLAG_PIO 0x01 +#define FLAG_16BIT 0x02 +#define FLAG_790 0x04 + #define MEM_8192 32 #define MEM_16384 64 #define MEM_32768 128 diff --git a/netboot/osdep.h b/netboot/osdep.h index bd63e597f..57218bfa3 100644 --- a/netboot/osdep.h +++ b/netboot/osdep.h @@ -8,14 +8,51 @@ * your option) any later version. */ -#if defined(__linux__) || defined(__FreeBSD__) || defined(GRUB) -#define ETHERBOOT32 -#define ntohl(x) swap32(x) -#define htonl(x) swap32(x) -#define ntohs(x) swap16(x) -#define htons(x) swap16(x) +#define __LITTLE_ENDIAN /* x86 */ -static inline unsigned long int swap32(unsigned long int x) +/* Taken from /usr/include/linux/hfs_sysdep.h */ +#if defined(__BIG_ENDIAN) +# if !defined(__constant_htonl) +# define __constant_htonl(x) (x) +# endif +# if !defined(__constant_htons) +# define __constant_htons(x) (x) +# endif +#elif defined(__LITTLE_ENDIAN) +# if !defined(__constant_htonl) +# define __constant_htonl(x) \ + ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ + (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ + (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ + (((unsigned long int)(x) & 0xff000000U) >> 24))) +# endif +# if !defined(__constant_htons) +# define __constant_htons(x) \ + ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ + (((unsigned short int)(x) & 0xff00) >> 8))) +# endif +#else +# error "Don't know if bytes are big- or little-endian!" +#endif + +#define ntohl(x) \ +(__builtin_constant_p(x) ? \ + __constant_htonl((x)) : \ + __swap32(x)) +#define htonl(x) \ +(__builtin_constant_p(x) ? \ + __constant_htonl((x)) : \ + __swap32(x)) +#define ntohs(x) \ +(__builtin_constant_p(x) ? \ + __constant_htons((x)) : \ + __swap16(x)) +#define htons(x) \ +(__builtin_constant_p(x) ? \ + __constant_htons((x)) : \ + __swap16(x)) + +static inline unsigned long int __swap32(unsigned long int x) { __asm__("xchgb %b0,%h0\n\t" "rorl $16,%0\n\t" @@ -25,7 +62,7 @@ static inline unsigned long int swap32(unsigned long int x) return x; } -static inline unsigned short int swap16(unsigned short int x) +static inline unsigned short int __swap16(unsigned short int x) { __asm__("xchgb %b0,%h0" : "=q" (x) @@ -33,38 +70,11 @@ static inline unsigned short int swap16(unsigned short int x) return x; } -#ifndef GRUB -# include "linux-asm-string.h" -#endif /* ! GRUB */ +/* Make routines available to all */ +#define swap32(x) __swap32(x) +#define swap16(x) __swap16(x) + #include "linux-asm-io.h" -#ifndef GRUB -#define _edata edata /* ELF does not prepend a _ */ -#define _end end -#endif /* ! GRUB */ -#endif - -#ifdef __BCC__ -#define ETHERBOOT16 -#define inline -#define const -#define volatile -#define setjmp _setjmp /* they are that way in libc.a */ -#define longjmp _longjmp - -/* BCC include files are missing these. */ -typedef unsigned char u_char; -typedef unsigned short u_short; -typedef unsigned int u_int; -typedef unsigned long u_long; -#endif - -#if !defined(ETHERBOOT16) && !defined(ETHERBOOT32) -Error, neither ETHERBOOT16 nor ETHERBOOT32 defined -#endif - -#if defined(ETHERBOOT16) && defined(ETHERBOOT32) -Error, both ETHERBOOT16 and ETHERBOOT32 defined -#endif typedef unsigned long Address; diff --git a/netboot/otulip.c b/netboot/otulip.c index 08b90b9c5..ea2b19bc1 100644 --- a/netboot/otulip.c +++ b/netboot/otulip.c @@ -43,7 +43,7 @@ static struct txdesc txd; #define NRXD 4 static struct rxdesc rxd[NRXD]; static int rxd_tail = 0; -#ifndef USE_INTERNAL_BUFFER +#ifdef USE_LOWMEM_BUFFER #define rxb ((char *)0x10000 - NRXD * BUFLEN) #define txb ((char *)0x10000 - NRXD * BUFLEN - BUFLEN) #else @@ -51,7 +51,7 @@ static unsigned char rxb[NRXD * BUFLEN]; static unsigned char txb[BUFLEN]; #endif -static unsigned char ehdr[ETHER_HDR_SIZE]; /* buffer for ethernet header */ +static unsigned char ehdr[ETH_HLEN]; /* buffer for ethernet header */ enum tulip_offsets { CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, @@ -270,17 +270,17 @@ static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, unsig /* setup ethernet header */ - memcpy(ehdr, d, ETHER_ADDR_SIZE); - memcpy(&ehdr[ETHER_ADDR_SIZE], nic->node_addr, ETHER_ADDR_SIZE); - ehdr[ETHER_ADDR_SIZE*2] = (t >> 8) & 0xff; - ehdr[ETHER_ADDR_SIZE*2+1] = t & 0xff; + memcpy(ehdr, d, ETH_ALEN); + memcpy(&ehdr[ETH_ALEN], nic->node_addr, ETH_ALEN); + ehdr[ETH_ALEN*2] = (t >> 8) & 0xff; + ehdr[ETH_ALEN*2+1] = t & 0xff; /* setup the transmit descriptor */ memset(&txd, 0, sizeof(struct txdesc)); txd.buf1addr = &ehdr[0]; /* ethernet header */ - txd.buf1sz = ETHER_HDR_SIZE; + txd.buf1sz = ETH_HLEN; txd.buf2addr = p; /* packet to transmit */ txd.buf2sz = s; @@ -350,7 +350,7 @@ struct nic *otulip_probe(struct nic *nic, unsigned short *io_addrs, struct pci_d membase = (unsigned int *)pci->membase; /* wakeup chip */ - pcibios_write_config_dword(0,pci->devfn,0x40,0x00000000); + pcibios_write_config_dword(pci->bus,pci->devfn,0x40,0x00000000); /* Stop the chip's Tx and Rx processes. */ /* outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6); */ @@ -359,12 +359,10 @@ struct nic *otulip_probe(struct nic *nic, unsigned short *io_addrs, struct pci_d srom_read(); - for (i=0; i < 6; i++) + for (i=0; i < ETH_ALEN; i++) nic->node_addr[i] = srom[20+i]; - printf("Tulip %b:%b:%b:%b:%b:%b at ioaddr 0x%x\n", - srom[20],srom[21],srom[22],srom[23],srom[24],srom[25], - ioaddr); + printf("Tulip %! at ioaddr %#hX\n", nic->node_addr, ioaddr); tulip_reset(nic); diff --git a/netboot/pci.c b/netboot/pci.c index c575cd17c..471c85632 100644 --- a/netboot/pci.c +++ b/netboot/pci.c @@ -22,7 +22,7 @@ #include "pci.h" /*#define DEBUG 1*/ -static unsigned int pci_ioaddr = 0; +#define DEBUG 0 #ifdef CONFIG_PCI_DIRECT #define PCIBIOS_SUCCESSFUL 0x00 @@ -33,47 +33,47 @@ static unsigned int pci_ioaddr = 0; #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3)) -int pcibios_read_config_byte(unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) +int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn, + unsigned int where, unsigned char *value) { outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inb(0xCFC + (where&3)); return PCIBIOS_SUCCESSFUL; } -int pcibios_read_config_word (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned short *value) +int pcibios_read_config_word (unsigned int bus, + unsigned int device_fn, unsigned int where, unsigned short *value) { outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inw(0xCFC + (where&2)); return PCIBIOS_SUCCESSFUL; } -static int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) +int pcibios_read_config_dword (unsigned int bus, unsigned int device_fn, + unsigned int where, unsigned int *value) { outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inl(0xCFC); return PCIBIOS_SUCCESSFUL; } -int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) +int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn, + unsigned int where, unsigned char value) { outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outb(value, 0xCFC + (where&3)); return PCIBIOS_SUCCESSFUL; } -int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) +int pcibios_write_config_word (unsigned int bus, unsigned int device_fn, + unsigned int where, unsigned short value) { outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outw(value, 0xCFC + (where&2)); return PCIBIOS_SUCCESSFUL; } -int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned int value) +int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value) { outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outl(value, 0xCFC); @@ -84,13 +84,12 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, unsi #else /* CONFIG_PCI_DIRECT not defined */ -static unsigned long bios32_entry = 0; static struct { unsigned long address; unsigned short segment; } bios32_indirect = { 0, KERN_CODE_SEG }; -static long pcibios_entry = 0; +static long pcibios_entry; static struct { unsigned long address; unsigned short segment; @@ -106,10 +105,10 @@ static unsigned long bios32_service(unsigned long service) save_flags(flags); __asm__( -#ifndef ABSOLUTE_WITHOUT_ASTERISK - "lcall *(%%edi)" -#else +#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%edi)" +#else + "lcall *(%%edi)" #endif : "=a" (return_code), "=b" (address), @@ -127,14 +126,14 @@ static unsigned long bios32_service(unsigned long service) printf("bios32_service(%d) : not present\n", service); return 0; default: /* Shouldn't happen */ - printf("bios32_service(%d) : returned 0x%x, mail drew@colorado.edu\n", + printf("bios32_service(%d) : returned %#X, mail drew@colorado.edu\n", service, return_code); return 0; } } -int pcibios_read_config_byte(unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned char *value) +int pcibios_read_config_byte(unsigned int bus, + unsigned int device_fn, unsigned int where, unsigned char *value) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; @@ -142,10 +141,10 @@ int pcibios_read_config_byte(unsigned char bus, save_flags(flags); __asm__( -#ifndef ABSOLUTE_WITHOUT_ASTERISK - "lcall *(%%esi)\n\t" -#else +#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%esi)\n\t" +#else + "lcall *(%%esi)\n\t" #endif "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -160,8 +159,8 @@ int pcibios_read_config_byte(unsigned char bus, return (int) (ret & 0xff00) >> 8; } -int pcibios_read_config_word(unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned short *value) +int pcibios_read_config_word(unsigned int bus, + unsigned int device_fn, unsigned int where, unsigned short *value) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; @@ -169,10 +168,10 @@ int pcibios_read_config_word(unsigned char bus, save_flags(flags); __asm__( -#ifndef ABSOLUTE_WITHOUT_ASTERISK - "lcall *(%%esi)\n\t" -#else +#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%esi)\n\t" +#else + "lcall *(%%esi)\n\t" #endif "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -187,8 +186,8 @@ int pcibios_read_config_word(unsigned char bus, return (int) (ret & 0xff00) >> 8; } -static int pcibios_read_config_dword(unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned int *value) +int pcibios_read_config_dword(unsigned int bus, + unsigned int device_fn, unsigned int where, unsigned int *value) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; @@ -196,10 +195,10 @@ static int pcibios_read_config_dword(unsigned char bus, save_flags(flags); __asm__( -#ifndef ABSOLUTE_WITHOUT_ASTERISK - "lcall *(%%esi)\n\t" -#else +#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%esi)\n\t" +#else + "lcall *(%%esi)\n\t" #endif "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -214,8 +213,8 @@ static int pcibios_read_config_dword(unsigned char bus, return (int) (ret & 0xff00) >> 8; } -int pcibios_write_config_byte (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned char value) +int pcibios_write_config_byte (unsigned int bus, + unsigned int device_fn, unsigned int where, unsigned char value) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; @@ -223,10 +222,10 @@ int pcibios_write_config_byte (unsigned char bus, save_flags(flags); cli(); __asm__( -#ifndef ABSOLUTE_WITHOUT_ASTERISK - "lcall *(%%esi)\n\t" -#else +#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%esi)\n\t" +#else + "lcall *(%%esi)\n\t" #endif "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -241,8 +240,8 @@ int pcibios_write_config_byte (unsigned char bus, return (int) (ret & 0xff00) >> 8; } -int pcibios_write_config_word (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned short value) +int pcibios_write_config_word (unsigned int bus, + unsigned int device_fn, unsigned int where, unsigned short value) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; @@ -250,10 +249,10 @@ int pcibios_write_config_word (unsigned char bus, save_flags(flags); cli(); __asm__( -#ifndef ABSOLUTE_WITHOUT_ASTERISK - "lcall *(%%esi)\n\t" -#else +#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%esi)\n\t" +#else + "lcall *(%%esi)\n\t" #endif "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -268,8 +267,8 @@ int pcibios_write_config_word (unsigned char bus, return (int) (ret & 0xff00) >> 8; } -int pcibios_write_config_dword (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned int value) +int pcibios_write_config_dword (unsigned int bus, + unsigned int device_fn, unsigned int where, unsigned int value) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; @@ -277,10 +276,10 @@ int pcibios_write_config_dword (unsigned char bus, save_flags(flags); cli(); __asm__( -#ifndef ABSOLUTE_WITHOUT_ASTERISK - "lcall *(%%esi)\n\t" -#else +#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%esi)\n\t" +#else + "lcall *(%%esi)\n\t" #endif "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -309,10 +308,10 @@ static void check_pcibios(void) save_flags(flags); __asm__( -#ifndef ABSOLUTE_WITHOUT_ASTERISK - "lcall *(%%edi)\n\t" -#else +#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%edi)\n\t" +#else + "lcall *(%%edi)\n\t" #endif "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -335,8 +334,8 @@ static void check_pcibios(void) } #if DEBUG if (pcibios_entry) { - printf ("pcibios_init : PCI BIOS revision %b.%b" - " entry at 0x%X\n", major_revision, + printf ("pcibios_init : PCI BIOS revision %hhX.%hhX" + " entry at %#X\n", major_revision, minor_revision, pcibios_entry); } #endif @@ -348,6 +347,7 @@ static void pcibios_init(void) union bios32 *check; unsigned char sum; int i, length; + unsigned long bios32_entry = 0; /* * Follow the standard procedure for locating the BIOS32 Service @@ -368,13 +368,13 @@ static void pcibios_init(void) if (sum != 0) continue; if (check->fields.revision != 0) { - printf("pcibios_init : unsupported revision %d at 0x%X, mail drew@colorado.edu\n", + printf("pcibios_init : unsupported revision %d at %#X, mail drew@colorado.edu\n", check->fields.revision, check); continue; } #if DEBUG printf("pcibios_init : BIOS32 Service Directory " - "structure at 0x%X\n", check); + "structure at %#X\n", check); #endif if (!bios32_entry) { if (check->fields.entry >= 0x100000) { @@ -385,7 +385,7 @@ static void pcibios_init(void) bios32_entry = check->fields.entry; #if DEBUG printf("pcibios_init : BIOS32 Service Directory" - " entry at 0x%X\n", bios32_entry); + " entry at %#X\n", bios32_entry); #endif bios32_indirect.address = bios32_entry; } @@ -402,11 +402,16 @@ static void scan_bus(struct pci_device *pcidev) unsigned char hdr_type = 0; unsigned short vendor, device; unsigned int membase, ioaddr, romaddr; - unsigned char class, subclass; int i, reg; + unsigned int pci_ioaddr = 0; - pci_ioaddr = 0; - buses=1; + /* Scan all PCI buses, until we find our card. + * We could be smart only scan the required busses but that + * is error prone, and tricky. + * By scanning all possible pci busses in order we should find + * our card eventually. + */ + buses=256; for (bus = 0; bus < buses; ++bus) { for (devfn = 0; devfn < 0xff; ++devfn) { if (PCI_FUNC (devfn) == 0) @@ -422,20 +427,16 @@ static void scan_bus(struct pci_device *pcidev) vendor = l & 0xffff; device = (l >> 16) & 0xffff; - /* check for pci-pci bridge devices!! - more buses when found */ - pcibios_read_config_byte(bus, devfn, PCI_CLASS_CODE, &class); - pcibios_read_config_byte(bus, devfn, PCI_SUBCLASS_CODE, &subclass); - if (class == 0x06 && subclass == 0x04) - buses++; - #if DEBUG - printf("bus %x, function %x, vendor %x, device %x\n", + printf("bus %hhX, function %hhX, vendor %hX, device %hX\n", bus, devfn, vendor, device); #endif for (i = 0; pcidev[i].vendor != 0; i++) { if (vendor != pcidev[i].vendor || device != pcidev[i].dev_id) continue; + pcidev[i].devfn = devfn; + pcidev[i].bus = bus; for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) { pcibios_read_config_dword(bus, devfn, reg, &ioaddr); @@ -449,14 +450,12 @@ static void scan_bus(struct pci_device *pcidev) /* Get the ROM base address */ pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr); romaddr >>= 10; - printf("Found %s at 0x%x, ROM address 0x%X\n", + printf("Found %s at %#hx, ROM address %#hx\n", pcidev[i].name, ioaddr, romaddr); /* Take the first one or the one that matches in boot ROM address */ if (pci_ioaddr == 0 || romaddr == ((unsigned long) rom.rom_segment << 4)) { pcidev[i].membase = membase; pcidev[i].ioaddr = ioaddr; - pcidev[i].devfn = devfn; - return; } } @@ -477,3 +476,26 @@ void eth_pci_init(struct pci_device *pcidev) scan_bus(pcidev); /* return values are in pcidev structures */ } + +/* + * Set device to be a busmaster in case BIOS neglected to do so. + * Also adjust PCI latency timer to a reasonable value, 32. + */ +void adjust_pci_device(struct pci_device *p) +{ + unsigned short new_command, pci_command; + unsigned char pci_latency; + + pcibios_read_config_word(p->bus, p->devfn, PCI_COMMAND, &pci_command); + new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; + if (pci_command != new_command) { + printf("The PCI BIOS has not enabled this device!\nUpdating PCI command %hX->%hX. pci_bus %hhX pci_device_fn %hhX\n", + pci_command, new_command, p->bus, p->devfn); + pcibios_write_config_word(p->bus, p->devfn, PCI_COMMAND, new_command); + } + pcibios_read_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < 32) { + printf("PCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency); + pcibios_write_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, 32); + } +} diff --git a/netboot/pci.h b/netboot/pci.h index 9f8b52205..a99dc141b 100644 --- a/netboot/pci.h +++ b/netboot/pci.h @@ -22,6 +22,7 @@ */ #define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define PCI_COMMAND_MEM 0x2 /* Enable response in mem space */ #define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ #define PCI_LATENCY_TIMER 0x0d /* 8 bits */ @@ -41,6 +42,7 @@ #define PCI_DEVICE_ID 0x02 /* 16 bits */ #define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_REVISION 0x08 /* 8 bits */ #define PCI_CLASS_CODE 0x0b /* 8 bits */ #define PCI_SUBCLASS_CODE 0x0a /* 8 bits */ #define PCI_HEADER_TYPE 0x0e /* 8 bits */ @@ -101,12 +103,16 @@ __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") #define PCI_DEVICE_ID_REALTEK_8139 0x8139 #define PCI_VENDOR_ID_WINBOND2 0x1050 #define PCI_DEVICE_ID_WINBOND2_89C940 0x0940 +#define PCI_DEVICE_ID_WINBOND2_89C840 0x0840 #define PCI_VENDOR_ID_COMPEX 0x11f6 #define PCI_DEVICE_ID_COMPEX_RL2000 0x1401 +#define PCI_DEVICE_ID_COMPEX_RL100ATX 0x2011 #define PCI_VENDOR_ID_KTI 0x8e2e #define PCI_DEVICE_ID_KTI_ET32P2 0x3000 #define PCI_VENDOR_ID_NETVIN 0x4a14 #define PCI_DEVICE_ID_NETVIN_NV5000SC 0x5000 +#define PCI_VENDOR_ID_HOLTEK 0x12c3 +#define PCI_DEVICE_ID_HOLTEK_HT80232 0x0058 #define PCI_VENDOR_ID_3COM 0x10b7 #define PCI_DEVICE_ID_3COM_3C590 0x5900 #define PCI_DEVICE_ID_3COM_3C595 0x5950 @@ -120,8 +126,14 @@ __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") #define PCI_DEVICE_ID_3COM_3C905C_TXM 0x9200 #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_82557 0x1229 +#define PCI_DEVICE_ID_INTEL_82559ER 0x1209 +#define PCI_DEVICE_ID_INTEL_ID1029 0x1029 +#define PCI_DEVICE_ID_INTEL_ID1030 0x1030 +#define PCI_DEVICE_ID_INTEL_82562 0x2449 #define PCI_VENDOR_ID_AMD 0x1022 #define PCI_DEVICE_ID_AMD_LANCE 0x2000 +#define PCI_VENDOR_ID_AMD_HOMEPNA 0x1022 +#define PCI_DEVICE_ID_AMD_HOMEPNA 0x2001 #define PCI_VENDOR_ID_SMC_1211 0x1113 #define PCI_DEVICE_ID_SMC_1211 0x1211 #define PCI_VENDOR_ID_DEC 0x1011 @@ -139,25 +151,42 @@ __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") #define PCI_DEVICE_ID_LC82C115 0xC115 #define PCI_VENDOR_ID_VIATEC 0x1106 #define PCI_DEVICE_ID_VIA_RHINE_I 0x3043 +#define PCI_DEVICE_ID_VIA_VT6102 0x3065 #define PCI_DEVICE_ID_VIA_86C100A 0x6100 #define PCI_VENDOR_ID_DAVICOM 0x1282 +#define PCI_DEVICE_ID_DM9009 0x9009 #define PCI_DEVICE_ID_DM9102 0x9102 +#define PCI_VENDOR_ID_SIS 0x1039 +#define PCI_DEVICE_ID_SIS900 0x0900 +#define PCI_DEVICE_ID_SIS7016 0x7016 +#define PCI_VENDOR_ID_DLINK 0x1186 +#define PCI_DEVICE_ID_DFE530TXP 0x1300 +#define PCI_VENDOR_ID_NS 0x100B +#define PCI_DEVICE_ID_DP83815 0x0020 +#define PCI_VENDOR_ID_OLICOM 0x108d +#define PCI_DEVICE_ID_OLICOM_OC3136 0x0001 +#define PCI_DEVICE_ID_OLICOM_OC2315 0x0011 +#define PCI_DEVICE_ID_OLICOM_OC2325 0x0012 +#define PCI_DEVICE_ID_OLICOM_OC2183 0x0013 +#define PCI_DEVICE_ID_OLICOM_OC2326 0x0014 +#define PCI_DEVICE_ID_OLICOM_OC6151 0x0021 struct pci_device { unsigned short vendor, dev_id; const char *name; unsigned int membase; unsigned short ioaddr; - unsigned short devfn; + unsigned char devfn; + unsigned char bus; }; extern void eth_pci_init(struct pci_device *); -extern int pcibios_read_config_byte(unsigned char bus, unsigned char device_fn, unsigned char where, unsigned char *value); -extern int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned char value); -extern int pcibios_read_config_word(unsigned char bus, unsigned char device_fn, unsigned char where, unsigned short *value); -extern int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned short value); -extern int pcibios_write_config_dword(unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned int value); - +extern int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char *value); +extern int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char value); +extern int pcibios_read_config_word(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned short *value); +extern int pcibios_write_config_word (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned short value); +extern int pcibios_read_config_dword(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int *value); +extern int pcibios_write_config_dword(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value); +void adjust_pci_device(struct pci_device *p); #endif /* PCI_H */ diff --git a/netboot/rtl8139.c b/netboot/rtl8139.c index 7771473c0..62d6e3a7a 100644 --- a/netboot/rtl8139.c +++ b/netboot/rtl8139.c @@ -18,6 +18,10 @@ /* + 06 Apr 2001 ken_yap@users.sourceforge.net (Ken Yap) + Following email from Hyun-Joon Cha, added a disable routine, otherwise + NIC remains live and can crash the kernel later. + 4 Feb 2000 espenlaub@informatik.uni-ulm.de (Klaus Espenlaub) Shuffled things around, removed the leftovers from the 8129 support that was in the Linux driver and added a bit more 8139 definitions. @@ -60,6 +64,7 @@ #include "nic.h" #include "pci.h" #include "cards.h" +#include "timer.h" #define RTL_TIMEOUT (1*TICKS_PER_SEC) @@ -70,7 +75,7 @@ #define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ #define TX_DMA_BURST 4 /* Calculate as 16<vendor; p++) { - if ( ( (p->vendor == PCI_VENDOR_ID_REALTEK) - && (p->dev_id == PCI_DEVICE_ID_REALTEK_8139) ) - || ( (p->vendor == PCI_VENDOR_ID_SMC_1211) - && (p->dev_id == PCI_DEVICE_ID_SMC_1211) ) ) { - probeaddrs[0] = p->ioaddr; - printf("rtl8139: probing %x (membase %x)\n", - p->ioaddr, p->membase); - } - } - return 0; - } /* Mask the bit that says "this is an io addr" */ ioaddr = probeaddrs[0] & ~3; + adjust_pci_device(pci); + /* Bring the chip out of low-power mode. */ outb(0x00, ioaddr + Config1); @@ -214,19 +205,14 @@ struct nic *rtl8139_probe(struct nic *nic, unsigned short *probeaddrs, *ap++ = read_eeprom(i + 7); } else { unsigned char *ap = (unsigned char*)nic->node_addr; - for (i = 0; i < ETHER_ADDR_SIZE; i++) + for (i = 0; i < ETH_ALEN; i++) *ap++ = inb(ioaddr + MAC0 + i); } - printf("ioaddr 0x%x, addr ", ioaddr); - - for (i = 0; i < ETHER_ADDR_SIZE; i++) { - printf("%b", nic->node_addr[i]); - if (i < ETHER_ADDR_SIZE-1) putchar(':'); - } speed10 = inb(ioaddr + MediaStatus) & MSRSpeed10; fullduplex = inw(ioaddr + MII_BMCR) & BMCRDuplex; - printf(" %sMbps %s-duplex\n", speed10 ? "10" : "100", + printf("ioaddr %#hX, addr %! %sMbps %s-duplex\n", ioaddr, + nic->node_addr, speed10 ? "10" : "100", fullduplex ? "full" : "half"); rtl_reset(nic); @@ -305,12 +291,12 @@ static void rtl_reset(struct nic* nic) cur_rx = 0; cur_tx = 0; - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) - break; + /* Give the chip 10ms to finish the reset. */ + load_timer2(10*TICKS_PER_MS); + while ((inb(ioaddr + ChipCmd) & CmdReset) != 0 && timer2_running()) + /* wait */; - for (i = 0; i < 6; i++) + for (i = 0; i < ETH_ALEN; i++) outb(nic->node_addr[i], ioaddr + MAC0 + i); /* Must enable Tx/Rx before setting transfer thresholds! */ @@ -351,20 +337,20 @@ static void rtl_transmit(struct nic *nic, const char *destaddr, unsigned int status, to, nstype; unsigned long txstatus; - memcpy(tx_buffer, destaddr, ETHER_ADDR_SIZE); - memcpy(tx_buffer + ETHER_ADDR_SIZE, nic->node_addr, ETHER_ADDR_SIZE); + memcpy(tx_buffer, destaddr, ETH_ALEN); + memcpy(tx_buffer + ETH_ALEN, nic->node_addr, ETH_ALEN); nstype = htons(type); - memcpy(tx_buffer + 2 * ETHER_ADDR_SIZE, (char*)&nstype, 2); - memcpy(tx_buffer + ETHER_HDR_SIZE, data, len); + memcpy(tx_buffer + 2 * ETH_ALEN, (char*)&nstype, 2); + memcpy(tx_buffer + ETH_HLEN, data, len); - len += ETHER_HDR_SIZE; + len += ETH_HLEN; #ifdef DEBUG_TX - printf("sending %d bytes ethtype %x\n", len, type); + printf("sending %d bytes ethtype %hX\n", len, type); #endif /* Note: RTL8139 doesn't auto-pad, send minimum payload (another 4 * bytes are sent automatically for the FCS, totalling to 64 bytes). */ - while (len < ETH_MIN_PACKET - 4) { + while (len < ETH_ZLEN) { tx_buffer[len++] = '\0'; } @@ -386,14 +372,14 @@ static void rtl_transmit(struct nic *nic, const char *destaddr, txstatus = inl(ioaddr+ TxStatus0 + cur_tx*4); if (status & TxOK) { - cur_tx = ++cur_tx % NUM_TX_DESC; + cur_tx = (cur_tx + 1) % NUM_TX_DESC; #ifdef DEBUG_TX - printf("tx done (%d ticks), status %x txstatus %X\n", + printf("tx done (%d ticks), status %hX txstatus %X\n", to-currticks(), status, txstatus); #endif } else { #ifdef DEBUG_TX - printf("tx timeout/error (%d ticks), status %x txstatus %X\n", + printf("tx timeout/error (%d ticks), status %hX txstatus %X\n", currticks()-to, status, txstatus); #endif rtl_reset(nic); @@ -415,7 +401,7 @@ static int rtl_poll(struct nic *nic) outw(status & ~(RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus); #ifdef DEBUG_RX - printf("rtl_poll: int %x ", status); + printf("rtl_poll: int %hX ", status); #endif ring_offs = cur_rx % RX_BUF_LEN; @@ -424,8 +410,8 @@ static int rtl_poll(struct nic *nic) rx_status &= 0xffff; if ((rx_status & (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) || - (rx_size < ETH_MIN_PACKET) || (rx_size > ETH_MAX_PACKET)) { - printf("rx error %x\n", rx_status); + (rx_size < ETH_ZLEN) || (rx_size > ETH_FRAME_LEN + 4)) { + printf("rx error %hX\n", rx_status); rtl_reset(nic); /* this clears all interrupts still pending */ return 0; } @@ -447,7 +433,7 @@ static int rtl_poll(struct nic *nic) #endif } #ifdef DEBUG_RX - printf(" at %X type %b%b rxstatus %x\n", + printf(" at %X type %hhX%hhX rxstatus %hX\n", (unsigned long)(rx_ring+ring_offs+4), nic->packet[12], nic->packet[13], rx_status); #endif @@ -462,4 +448,11 @@ static int rtl_poll(struct nic *nic) static void rtl_disable(struct nic *nic) { + /* reset the chip */ + outb(CmdReset, ioaddr + ChipCmd); + + /* 10 ms timeout */ + load_timer2(10*TICKS_PER_MS); + while ((inb(ioaddr + ChipCmd) & CmdReset) != 0 && timer2_running()) + /* wait */; } diff --git a/netboot/sis900.c b/netboot/sis900.c new file mode 100644 index 000000000..6208a26a4 --- /dev/null +++ b/netboot/sis900.c @@ -0,0 +1,1034 @@ +/* -*- Mode:C; c-basic-offset:4; -*- */ + +/* + sis900.c: An SiS 900/7016 PCI Fast Ethernet driver for Etherboot + Copyright (C) 2001 Entity Cyber, Inc. + + Revision: 1.0 March 1, 2001 + + Author: Marty Connor (mdc@thinguin.org) + + Adapted from a Linux driver which was written by Donald Becker + and modified by Ollie Lho and Chin-Shan Li of SiS Corporation. + Rewritten for Etherboot by Marty Connor. + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + + References: + SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support, + preliminary Rev. 1.0 Jan. 14, 1998 + SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support, + preliminary Rev. 1.0 Nov. 10, 1998 + SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution, + preliminary Rev. 1.0 Jan. 18, 1998 + http://www.sis.com.tw/support/databook.htm */ + +/* Revision History */ + +/* + 01 March 2001 mdc 1.0 + Initial Release. Tested with PCI based sis900 card and ThinkNIC + computer. + 20 March 2001 P.Koegel + added support for sis630e and PHY ICS1893 and RTL8201 + Testet with SIS730S chipset + ICS1893 +*/ + + +/* Includes */ + +#include "etherboot.h" +#include "nic.h" +#include "pci.h" +#include "cards.h" + +#include "sis900.h" + +/* Globals */ + +static int sis900_debug = 0; + +static unsigned short vendor, dev_id; +static unsigned long ioaddr; + +static unsigned int cur_phy; + +static unsigned int cur_rx; + +static BufferDesc txd; +static BufferDesc rxd[NUM_RX_DESC]; + +#ifdef USE_LOWMEM_BUFFER +#define txb ((char *)0x10000 - TX_BUF_SIZE) +#define rxb ((char *)0x10000 - NUM_RX_DESC*RX_BUF_SIZE - TX_BUF_SIZE) +#else +static unsigned char txb[TX_BUF_SIZE]; +static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE]; +#endif + +static struct mac_chip_info { + const char *name; + u16 vendor_id, device_id, flags; + int io_size; +} mac_chip_table[] = { + { "SiS 900 PCI Fast Ethernet", PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900, + PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE}, + { "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016, + PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE}, + {0,0,0,0,0} /* 0 terminated list. */ +}; + +static void sis900_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex); +static void amd79c901_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex); +static void ics1893_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex); +static void rtl8201_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex); + +static struct mii_chip_info { + const char * name; + u16 phy_id0; + u16 phy_id1; + void (*read_mode) (struct nic *nic, int phy_addr, int *speed, int *duplex); +} mii_chip_table[] = { + {"SiS 900 Internal MII PHY", 0x001d, 0x8000, sis900_read_mode}, + {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode}, + {"AMD 79C901 10BASE-T PHY", 0x0000, 0x35b9, amd79c901_read_mode}, + {"AMD 79C901 HomePNA PHY", 0x0000, 0x35c8, amd79c901_read_mode}, + {"ICS 1893 Integrated PHYceiver" , 0x0015, 0xf441,ics1893_read_mode}, + {"RTL 8201 10/100Mbps Phyceiver" , 0x0000, 0x8201,rtl8201_read_mode}, + {0,0,0,0} +}; + +static struct mii_phy { + struct mii_phy * next; + struct mii_chip_info * chip_info; + int phy_addr; + u16 status; +} mii; + + +// PCI to ISA bridge for SIS640E access +static struct pci_device pci_isa_bridge_list[] = { + { 0x1039, 0x0008, + "SIS 85C503/5513 PCI to ISA bridge", 0, 0, 0, 0}, + {0, 0, NULL, 0, 0, 0, 0} +}; + +/* Function Prototypes */ + +struct nic *sis900_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci); + +static u16 sis900_read_eeprom(int location); +static void sis900_mdio_reset(long mdio_addr); +static void sis900_mdio_idle(long mdio_addr); +static u16 sis900_mdio_read(int phy_id, int location); +static void sis900_mdio_write(int phy_id, int location, int val); + +static void sis900_init(struct nic *nic); + +static void sis900_reset(struct nic *nic); + +static void sis900_init_rxfilter(struct nic *nic); +static void sis900_init_txd(struct nic *nic); +static void sis900_init_rxd(struct nic *nic); +static void sis900_set_rx_mode(struct nic *nic); +static void sis900_check_mode(struct nic *nic); + +static void sis900_transmit(struct nic *nic, const char *d, + unsigned int t, unsigned int s, const char *p); +static int sis900_poll(struct nic *nic); + +static void sis900_disable(struct nic *nic); + +/** + * sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model + * @pci_dev: the sis900 pci device + * @net_dev: the net device to get address for + * + * Older SiS900 and friends, use EEPROM to store MAC address. + * MAC address is read from read_eeprom() into @net_dev->dev_addr. + */ + +static int sis900_get_mac_addr(struct pci_device * pci_dev , struct nic *nic) +{ + u16 signature; + int i; + + /* check to see if we have sane EEPROM */ + signature = (u16) sis900_read_eeprom( EEPROMSignature); + if (signature == 0xffff || signature == 0x0000) { + printf ("sis900_probe: Error EERPOM read %hX\n", signature); + return 0; + } + + /* get MAC address from EEPROM */ + for (i = 0; i < 3; i++) + ((u16 *)(nic->node_addr))[i] = sis900_read_eeprom(i+EEPROMMACAddr); + return 1; +} + +/** + * sis630e_get_mac_addr: - Get MAC address for SiS630E model + * @pci_dev: the sis900 pci device + * @net_dev: the net device to get address for + * + * SiS630E model, use APC CMOS RAM to store MAC address. + * APC CMOS RAM is accessed through ISA bridge. + * MAC address is read into @net_dev->dev_addr. + */ + +static int sis630e_get_mac_addr(struct pci_device * pci_dev, struct nic *nic) +{ + u8 reg; + int i; + struct pci_device *p; + + // find PCI to ISA bridge + eth_pci_init(pci_isa_bridge_list); + + /* the firts entry in this list should contain bus/devfn */ + p = pci_isa_bridge_list; + + pcibios_read_config_byte(p->bus,p->devfn, 0x48, ®); + pcibios_write_config_byte(p->bus,p->devfn, 0x48, reg | 0x40); + + for (i = 0; i < ETH_ALEN; i++) + { + outb(0x09 + i, 0x70); + ((u8 *)(nic->node_addr))[i] = inb(0x71); + } + pcibios_write_config_byte(p->bus,p->devfn, 0x48, reg & ~0x40); + + return 1; +} + +/* + * Function: sis900_probe + * + * Description: initializes initializes the NIC, retrieves the + * MAC address of the card, and sets up some globals required by + * other routines. + * + * Side effects: + * leaves the ioaddress of the sis900 chip in the variable ioaddr. + * leaves the sis900 initialized, and ready to recieve packets. + * + * Returns: struct nic *: pointer to NIC data structure + */ + +struct nic *sis900_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci) +{ + int i; + int found=0; + int phy_addr; + u16 signature; + u8 revision; + int ret; + + if (io_addrs == 0 || *io_addrs == 0) + return NULL; + + ioaddr = *io_addrs & ~3; + vendor = pci->vendor; + dev_id = pci->dev_id; + + /* wakeup chip */ + pcibios_write_config_dword(pci->bus, pci->devfn, 0x40, 0x00000000); + + adjust_pci_device(pci); + + /* get MAC address */ + ret = 0; + pcibios_read_config_byte(pci->bus,pci->devfn, PCI_REVISION, &revision); + if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV) + ret = sis630e_get_mac_addr(pci, nic); + else if (revision == SIS630S_900_REV) + ret = sis630e_get_mac_addr(pci, nic); + else + ret = sis900_get_mac_addr(pci, nic); + + if (ret == 0) + { + printf ("sis900_probe: Error MAC address not found\n"); + return NULL; + } + + printf("\nsis900_probe: MAC addr %! at ioaddr %#hX\n", + nic->node_addr, ioaddr); + printf("sis900_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id); + + /* probe for mii transceiver */ + /* search for total of 32 possible mii phy addresses */ + + found = 0; + for (phy_addr = 0; phy_addr < 32; phy_addr++) { + u16 mii_status; + u16 phy_id0, phy_id1; + + mii_status = sis900_mdio_read(phy_addr, MII_STATUS); + if (mii_status == 0xffff || mii_status == 0x0000) + /* the mii is not accessable, try next one */ + continue; + + phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0); + phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1); + + /* search our mii table for the current mii */ + for (i = 0; mii_chip_table[i].phy_id1; i++) { + + if (phy_id0 == mii_chip_table[i].phy_id0) { + + printf("sis900_probe: %s transceiver found at address %d.\n", + mii_chip_table[i].name, phy_addr); + + mii.chip_info = &mii_chip_table[i]; + mii.phy_addr = phy_addr; + mii.status = sis900_mdio_read(phy_addr, MII_STATUS); + mii.next = NULL; + + found=1; + break; + } + } + } + + if (found == 0) { + printf("sis900_probe: No MII transceivers found!\n"); + return NULL; + } + + /* Arbitrarily select the last PHY found as current PHY */ + cur_phy = mii.phy_addr; + printf("sis900_probe: Using %s as default\n", mii.chip_info->name); + + /* initialize device */ + sis900_init(nic); + + nic->reset = sis900_init; + nic->poll = sis900_poll; + nic->transmit = sis900_transmit; + nic->disable = sis900_disable; + + return nic; +} + + +/* + * EEPROM Routines: These functions read and write to EEPROM for + * retrieving the MAC address and other configuration information about + * the card. + */ + +/* Delay between EEPROM clock transitions. */ +#define eeprom_delay() inl(ee_addr) + + +/* Function: sis900_read_eeprom + * + * Description: reads and returns a given location from EEPROM + * + * Arguments: int location: requested EEPROM location + * + * Returns: u16: contents of requested EEPROM location + * + */ + +/* Read Serial EEPROM through EEPROM Access Register, Note that location is + in word (16 bits) unit */ +static u16 sis900_read_eeprom(int location) +{ + int i; + u16 retval = 0; + long ee_addr = ioaddr + mear; + u32 read_cmd = location | EEread; + + outl(0, ee_addr); + eeprom_delay(); + outl(EECLK, ee_addr); + eeprom_delay(); + + /* Shift the read command (9) bits out. */ + for (i = 8; i >= 0; i--) { + u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS; + outl(dataval, ee_addr); + eeprom_delay(); + outl(dataval | EECLK, ee_addr); + eeprom_delay(); + } + outb(EECS, ee_addr); + eeprom_delay(); + + /* read the 16-bits data in */ + for (i = 16; i > 0; i--) { + outl(EECS, ee_addr); + eeprom_delay(); + outl(EECS | EECLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(0, ee_addr); + eeprom_delay(); + outl(EECLK, ee_addr); + + return (retval); +} + +#define sis900_mdio_delay() inl(mdio_addr) + + +/* + Read and write the MII management registers using software-generated + serial MDIO protocol. Note that the command bits and data bits are + send out seperately +*/ + +static void sis900_mdio_idle(long mdio_addr) +{ + outl(MDIO | MDDIR, mdio_addr); + sis900_mdio_delay(); + outl(MDIO | MDDIR | MDC, mdio_addr); +} + +/* Syncronize the MII management interface by shifting 32 one bits out. */ +static void sis900_mdio_reset(long mdio_addr) +{ + int i; + + for (i = 31; i >= 0; i--) { + outl(MDDIR | MDIO, mdio_addr); + sis900_mdio_delay(); + outl(MDDIR | MDIO | MDC, mdio_addr); + sis900_mdio_delay(); + } + return; +} + +static u16 sis900_mdio_read(int phy_id, int location) +{ + long mdio_addr = ioaddr + mear; + int mii_cmd = MIIread|(phy_id<= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; + outl(dataval, mdio_addr); + sis900_mdio_delay(); + outl(dataval | MDC, mdio_addr); + sis900_mdio_delay(); + } + + /* Read the 16 data bits. */ + for (i = 16; i > 0; i--) { + outl(0, mdio_addr); + sis900_mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0); + outl(MDC, mdio_addr); + sis900_mdio_delay(); + } + return retval; +} + +static void sis900_mdio_write(int phy_id, int location, int value) +{ + long mdio_addr = ioaddr + mear; + int mii_cmd = MIIwrite|(phy_id<= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; + outb(dataval, mdio_addr); + sis900_mdio_delay(); + outb(dataval | MDC, mdio_addr); + sis900_mdio_delay(); + } + sis900_mdio_delay(); + + /* Shift the value bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR; + outl(dataval, mdio_addr); + sis900_mdio_delay(); + outl(dataval | MDC, mdio_addr); + sis900_mdio_delay(); + } + sis900_mdio_delay(); + + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outb(0, mdio_addr); + sis900_mdio_delay(); + outb(MDC, mdio_addr); + sis900_mdio_delay(); + } + return; +} + + +/* Function: sis900_init + * + * Description: resets the ethernet controller chip and various + * data structures required for sending and receiving packets. + * + * Arguments: struct nic *nic: NIC data structure + * + * returns: void. + */ + +static void +sis900_init(struct nic *nic) +{ + /* Soft reset the chip. */ + sis900_reset(nic); + + sis900_init_rxfilter(nic); + + sis900_init_txd(nic); + sis900_init_rxd(nic); + + sis900_set_rx_mode(nic); + + sis900_check_mode(nic); + + outl(RxENA, ioaddr + cr); +} + + +/* + * Function: sis900_reset + * + * Description: disables interrupts and soft resets the controller chip + * + * Arguments: struct nic *nic: NIC data structure + * + * Returns: void. + */ + +static void +sis900_reset(struct nic *nic) +{ + int i = 0; + u32 status = TxRCMP | RxRCMP; + + outl(0, ioaddr + ier); + outl(0, ioaddr + imr); + outl(0, ioaddr + rfcr); + + outl(RxRESET | TxRESET | RESET, ioaddr + cr); + + /* Check that the chip has finished the reset. */ + while (status && (i++ < 1000)) { + status ^= (inl(isr + ioaddr) & status); + } + outl(PESEL, ioaddr + cfg); +} + + +/* Function: sis_init_rxfilter + * + * Description: sets receive filter address to our MAC address + * + * Arguments: struct nic *nic: NIC data structure + * + * returns: void. + */ + +static void +sis900_init_rxfilter(struct nic *nic) +{ + u32 rfcrSave; + int i; + + rfcrSave = inl(rfcr + ioaddr); + + /* disable packet filtering before setting filter */ + outl(rfcrSave & ~RFEN, rfcr); + + /* load MAC addr to filter data register */ + for (i = 0 ; i < 3 ; i++) { + u32 w; + + w = (u32) *((u16 *)(nic->node_addr)+i); + outl((i << RFADDR_shift), ioaddr + rfcr); + outl(w, ioaddr + rfdr); + + if (sis900_debug > 0) + printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%X\n", + i, inl(ioaddr + rfdr)); + } + + /* enable packet filitering */ + outl(rfcrSave | RFEN, rfcr + ioaddr); +} + + +/* + * Function: sis_init_txd + * + * Description: initializes the Tx descriptor + * + * Arguments: struct nic *nic: NIC data structure + * + * returns: void. + */ + +static void +sis900_init_txd(struct nic *nic) +{ + txd.link = (u32) 0; + txd.cmdsts = (u32) 0; + txd.bufptr = (u32) &txb[0]; + + /* load Transmit Descriptor Register */ + outl((u32) &txd, ioaddr + txdp); + if (sis900_debug > 0) + printf("sis900_init_txd: TX descriptor register loaded with: %X\n", + inl(ioaddr + txdp)); +} + + +/* Function: sis_init_rxd + * + * Description: initializes the Rx descriptor ring + * + * Arguments: struct nic *nic: NIC data structure + * + * Returns: void. + */ + +static void +sis900_init_rxd(struct nic *nic) +{ + int i; + + cur_rx = 0; + + /* init RX descriptor */ + for (i = 0; i < NUM_RX_DESC; i++) { + rxd[i].link = (i+1 < NUM_RX_DESC) ? (u32) &rxd[i+1] : (u32) &rxd[0]; + rxd[i].cmdsts = (u32) RX_BUF_SIZE; + rxd[i].bufptr = (u32) &rxb[i*RX_BUF_SIZE]; + if (sis900_debug > 0) + printf("sis900_init_rxd: rxd[%d]=%X link=%X cmdsts=%X bufptr=%X\n", + i, &rxd[i], rxd[i].link, rxd[i].cmdsts, rxd[i].bufptr); + } + + /* load Receive Descriptor Register */ + outl((u32) &rxd[0], ioaddr + rxdp); + + if (sis900_debug > 0) + printf("sis900_init_rxd: RX descriptor register loaded with: %X\n", + inl(ioaddr + rxdp)); + +} + + +/* Function: sis_init_rxd + * + * Description: + * sets the receive mode to accept all broadcast packets and packets + * with our MAC address, and reject all multicast packets. + * + * Arguments: struct nic *nic: NIC data structure + * + * Returns: void. + */ + +static void sis900_set_rx_mode(struct nic *nic) +{ + int i; + + /* Configure Multicast Hash Table in Receive Filter + to reject all MCAST packets */ + for (i = 0; i < 8; i++) { + /* why plus 0x04? That makes the correct value for hash table. */ + outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr); + outl((u32)(0x0), ioaddr + rfdr); + } + /* Accept Broadcast packets, destination addresses that match + our MAC address */ + outl(RFEN | RFAAB, ioaddr + rfcr); + + return; +} + + +/* Function: sis900_check_mode + * + * Description: checks the state of transmit and receive + * parameters on the NIC, and updates NIC registers to match + * + * Arguments: struct nic *nic: NIC data structure + * + * Returns: void. + */ + +static void +sis900_check_mode (struct nic *nic) +{ + int speed, duplex; + u32 tx_flags = 0, rx_flags = 0; + + mii.chip_info->read_mode(nic, cur_phy, &speed, &duplex); + + tx_flags = TxATP | (TX_DMA_BURST << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); + rx_flags = RX_DMA_BURST << RxMXDMA_shift; + + if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS) { + rx_flags |= (RxDRNT_10 << RxDRNT_shift); + tx_flags |= (TxDRNT_10 << TxDRNT_shift); + } + else { + rx_flags |= (RxDRNT_100 << RxDRNT_shift); + tx_flags |= (TxDRNT_100 << TxDRNT_shift); + } + + if (duplex == FDX_CAPABLE_FULL_SELECTED) { + tx_flags |= (TxCSI | TxHBI); + rx_flags |= RxATX; + } + + outl (tx_flags, ioaddr + txcfg); + outl (rx_flags, ioaddr + rxcfg); +} + + +/* Function: sis900_read_mode + * + * Description: retrieves and displays speed and duplex + * parameters from the NIC + * + * Arguments: struct nic *nic: NIC data structure + * + * Returns: void. + */ + +static void +sis900_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex) +{ + int i = 0; + u32 status; + + /* STSOUT register is Latched on Transition, read operation updates it */ + while (i++ < 2) + status = sis900_mdio_read(phy_addr, MII_STSOUT); + + if (status & MII_STSOUT_SPD) + *speed = HW_SPEED_100_MBPS; + else + *speed = HW_SPEED_10_MBPS; + + if (status & MII_STSOUT_DPLX) + *duplex = FDX_CAPABLE_FULL_SELECTED; + else + *duplex = FDX_CAPABLE_HALF_SELECTED; + + if (status & MII_STSOUT_LINK_FAIL) + printf("sis900_read_mode: Media Link Off\n"); + else + printf("sis900_read_mode: Media Link On %s %s-duplex \n", + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); +} + + +/* Function: amd79c901_read_mode + * + * Description: retrieves and displays speed and duplex + * parameters from the NIC + * + * Arguments: struct nic *nic: NIC data structure + * + * Returns: void. + */ + +static void +amd79c901_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex) +{ + int i; + u16 status; + + for (i = 0; i < 2; i++) + status = sis900_mdio_read(phy_addr, MII_STATUS); + + if (status & MII_STAT_CAN_AUTO) { + /* 10BASE-T PHY */ + for (i = 0; i < 2; i++) + status = sis900_mdio_read(phy_addr, MII_STATUS_SUMMARY); + if (status & MII_STSSUM_SPD) + *speed = HW_SPEED_100_MBPS; + else + *speed = HW_SPEED_10_MBPS; + if (status & MII_STSSUM_DPLX) + *duplex = FDX_CAPABLE_FULL_SELECTED; + else + *duplex = FDX_CAPABLE_HALF_SELECTED; + + if (status & MII_STSSUM_LINK) + printf("amd79c901_read_mode: Media Link On %s %s-duplex \n", + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + else + printf("amd79c901_read_mode: Media Link Off\n"); + } + else { + /* HomePNA */ + *speed = HW_SPEED_HOME; + *duplex = FDX_CAPABLE_HALF_SELECTED; + if (status & MII_STAT_LINK) + printf("amd79c901_read_mode:Media Link On 1mbps half-duplex \n"); + else + printf("amd79c901_read_mode: Media Link Off\n"); + } +} + + +/** + * ics1893_read_mode: - read media mode for ICS1893 PHY + * @net_dev: the net device to read mode for + * @phy_addr: mii phy address + * @speed: the transmit speed to be determined + * @duplex: the duplex mode to be determined + * + * ICS1893 PHY use Quick Poll Detailed Status register + * to determine the speed and duplex mode for sis900 + */ + +static void ics1893_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex) +{ + int i = 0; + u32 status; + + /* MII_QPDSTS is Latched, read twice in succession will reflect the current state */ + for (i = 0; i < 2; i++) + status = sis900_mdio_read(phy_addr, MII_QPDSTS); + + if (status & MII_STSICS_SPD) + *speed = HW_SPEED_100_MBPS; + else + *speed = HW_SPEED_10_MBPS; + + if (status & MII_STSICS_DPLX) + *duplex = FDX_CAPABLE_FULL_SELECTED; + else + *duplex = FDX_CAPABLE_HALF_SELECTED; + + if (status & MII_STSICS_LINKSTS) + printf("ics1893_read_mode: Media Link On %s %s-duplex \n", + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + else + printf("ics1893_read_mode: Media Link Off\n"); +} + +/** + * rtl8201_read_mode: - read media mode for rtl8201 phy + * @nic: the net device to read mode for + * @phy_addr: mii phy address + * @speed: the transmit speed to be determined + * @duplex: the duplex mode to be determined + * + * read MII_STATUS register from rtl8201 phy + * to determine the speed and duplex mode for sis900 + */ + +static void rtl8201_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex) +{ + u32 status; + + status = sis900_mdio_read(phy_addr, MII_STATUS); + + if (status & MII_STAT_CAN_TX_FDX) { + *speed = HW_SPEED_100_MBPS; + *duplex = FDX_CAPABLE_FULL_SELECTED; + } + else if (status & MII_STAT_CAN_TX) { + *speed = HW_SPEED_100_MBPS; + *duplex = FDX_CAPABLE_HALF_SELECTED; + } + else if (status & MII_STAT_CAN_T_FDX) { + *speed = HW_SPEED_10_MBPS; + *duplex = FDX_CAPABLE_FULL_SELECTED; + } + else if (status & MII_STAT_CAN_T) { + *speed = HW_SPEED_10_MBPS; + *duplex = FDX_CAPABLE_HALF_SELECTED; + } + + if (status & MII_STAT_LINK) + printf("rtl8201_read_mode: Media Link On %s %s-duplex \n", + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + else + printf("rtl9201_read_config_mode: Media Link Off\n"); +} + +/* Function: sis900_transmit + * + * Description: transmits a packet and waits for completion or timeout. + * + * Arguments: char d[6]: destination ethernet address. + * unsigned short t: ethernet protocol type. + * unsigned short s: size of the data-part of the packet. + * char *p: the data for the packet. + * + * Returns: void. + */ + +static void +sis900_transmit(struct nic *nic, + const char *d, /* Destination */ + unsigned int t, /* Type */ + unsigned int s, /* size */ + const char *p) /* Packet */ +{ + u32 status, to, nstype; + u32 tx_status; + + /* Stop the transmitter */ + outl(TxDIS, ioaddr + cr); + + /* load Transmit Descriptor Register */ + outl((u32) &txd, ioaddr + txdp); + if (sis900_debug > 1) + printf("sis900_transmit: TX descriptor register loaded with: %X\n", + inl(ioaddr + txdp)); + + memcpy(txb, d, ETH_ALEN); + memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN); + nstype = htons(t); + memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2); + memcpy(txb + ETH_HLEN, p, s); + + s += ETH_HLEN; + s &= DSIZE; + + if (sis900_debug > 1) + printf("sis900_transmit: sending %d bytes ethtype %hX\n", (int) s, t); + + /* pad to minimum packet size */ + while (s < ETH_ZLEN) + txb[s++] = '\0'; + + /* set the transmit buffer descriptor and enable Transmit State Machine */ + txd.bufptr = (u32) &txb[0]; + txd.cmdsts = (u32) OWN | s; + + /* restart the transmitter */ + outl(TxENA, ioaddr + cr); + + if (sis900_debug > 1) + printf("sis900_transmit: Queued Tx packet size %d.\n", (int) s); + + to = currticks() + TX_TIMEOUT; + + while ((((volatile u32) tx_status=txd.cmdsts) & OWN) && (currticks() < to)) + /* wait */ ; + + if (currticks() >= to) { + printf("sis900_transmit: TX Timeout! Tx status %X.\n", tx_status); + } + + if (tx_status & (ABORT | UNDERRUN | OWCOLL)) { + /* packet unsuccessfully transmited */ + printf("sis900_transmit: Transmit error, Tx status %X.\n", tx_status); + } + /* Disable interrupts by clearing the interrupt mask. */ + outl(0, ioaddr + imr); +} + + +/* Function: sis900_poll + * + * Description: checks for a received packet and returns it if found. + * + * Arguments: struct nic *nic: NIC data structure + * + * Returns: 1 if a packet was recieved. + * 0 if no pacet was recieved. + * + * Side effects: + * Returns (copies) the packet to the array nic->packet. + * Returns the length of the packet in nic->packetlen. + */ + +static int +sis900_poll(struct nic *nic) +{ + u32 rx_status = rxd[cur_rx].cmdsts; + int retstat = 0; + + if (sis900_debug > 2) + printf("sis900_poll: cur_rx:%d, status:%X\n", cur_rx, rx_status); + + if (!(rx_status & OWN)) + return retstat; + + if (sis900_debug > 1) + printf("sis900_poll: got a packet: cur_rx:%d, status:%X\n", + cur_rx, rx_status); + + nic->packetlen = (rx_status & DSIZE) - CRC_SIZE; + + if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) { + /* corrupted packet received */ + printf("sis900_poll: Corrupted packet received, buffer status = %X\n", + rx_status); + retstat = 0; + } else { + /* give packet to higher level routine */ + memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen); + retstat = 1; + } + + /* return the descriptor and buffer to receive ring */ + rxd[cur_rx].cmdsts = RX_BUF_SIZE; + rxd[cur_rx].bufptr = (u32) &rxb[cur_rx*RX_BUF_SIZE]; + + if (++cur_rx == NUM_RX_DESC) + cur_rx = 0; + + /* re-enable the potentially idle receive state machine */ + outl(RxENA , ioaddr + cr); + + return retstat; +} + + +/* Function: sis900_disable + * + * Description: Turns off interrupts and stops Tx and Rx engines + * + * Arguments: struct nic *nic: NIC data structure + * + * Returns: void. + */ + +static void +sis900_disable(struct nic *nic) +{ + /* Disable interrupts by clearing the interrupt mask. */ + outl(0, ioaddr + imr); + outl(0, ioaddr + ier); + + /* Stop the chip's Tx and Rx Status Machine */ + outl(RxDIS | TxDIS, ioaddr + cr); +} diff --git a/netboot/sis900.h b/netboot/sis900.h new file mode 100644 index 000000000..44feafbad --- /dev/null +++ b/netboot/sis900.h @@ -0,0 +1,363 @@ +/* -*- Mode:C; c-basic-offset:4; -*- */ + +/* Definitions for SiS ethernet controllers including 7014/7016 and 900 + * References: + * SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support, + * preliminary Rev. 1.0 Jan. 14, 1998 + * SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support, + * preliminary Rev. 1.0 Nov. 10, 1998 + * SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution, + * preliminary Rev. 1.0 Jan. 18, 1998 + * http://www.sis.com.tw/support/databook.htm + */ + +/* MAC operationl registers of SiS 7016 and SiS 900 ethernet controller */ +/* The I/O extent, SiS 900 needs 256 bytes of io address */ +#define SIS900_TOTAL_SIZE 0x100 + +/* Symbolic offsets to registers. */ +enum sis900_registers { + cr=0x0, /* Command Register */ + cfg=0x4, /* Configuration Register */ + mear=0x8, /* EEPROM Access Register */ + ptscr=0xc, /* PCI Test Control Register */ + isr=0x10, /* Interrupt Status Register */ + imr=0x14, /* Interrupt Mask Register */ + ier=0x18, /* Interrupt Enable Register */ + epar=0x18, /* Enhanced PHY Access Register */ + txdp=0x20, /* Transmit Descriptor Pointer Register */ + txcfg=0x24, /* Transmit Configuration Register */ + rxdp=0x30, /* Receive Descriptor Pointer Register */ + rxcfg=0x34, /* Receive Configuration Register */ + flctrl=0x38, /* Flow Control Register */ + rxlen=0x3c, /* Receive Packet Length Register */ + rfcr=0x48, /* Receive Filter Control Register */ + rfdr=0x4C, /* Receive Filter Data Register */ + pmctrl=0xB0, /* Power Management Control Register */ + pmer=0xB4 /* Power Management Wake-up Event Register */ +}; + +/* Symbolic names for bits in various registers */ +enum sis900_command_register_bits { + RESET = 0x00000100, + SWI = 0x00000080, + RxRESET = 0x00000020, + TxRESET = 0x00000010, + RxDIS = 0x00000008, + RxENA = 0x00000004, + TxDIS = 0x00000002, + TxENA = 0x00000001 +}; + +enum sis900_configuration_register_bits { + DESCRFMT = 0x00000100, /* 7016 specific */ + REQALG = 0x00000080, + SB = 0x00000040, + POW = 0x00000020, + EXD = 0x00000010, + PESEL = 0x00000008, + LPM = 0x00000004, + BEM = 0x00000001 +}; + +enum sis900_eeprom_access_reigster_bits { + MDC = 0x00000040, + MDDIR = 0x00000020, + MDIO = 0x00000010, /* 7016 specific */ + EECS = 0x00000008, + EECLK = 0x00000004, + EEDO = 0x00000002, + EEDI = 0x00000001 +}; + +enum sis900_interrupt_register_bits { + WKEVT = 0x10000000, + TxPAUSEEND = 0x08000000, + TxPAUSE = 0x04000000, + TxRCMP = 0x02000000, + RxRCMP = 0x01000000, + DPERR = 0x00800000, + SSERR = 0x00400000, + RMABT = 0x00200000, + RTABT = 0x00100000, + RxSOVR = 0x00010000, + HIBERR = 0x00008000, + SWINT = 0x00001000, + MIBINT = 0x00000800, + TxURN = 0x00000400, + TxIDLE = 0x00000200, + TxERR = 0x00000100, + TxDESC = 0x00000080, + TxOK = 0x00000040, + RxORN = 0x00000020, + RxIDLE = 0x00000010, + RxEARLY = 0x00000008, + RxERR = 0x00000004, + RxDESC = 0x00000002, + RxOK = 0x00000001 +}; + +enum sis900_interrupt_enable_reigster_bits { + IE = 0x00000001 +}; + +/* maximum dma burst fro transmission and receive*/ +#define MAX_DMA_RANGE 7 /* actually 0 means MAXIMUM !! */ +#define TxMXDMA_shift 20 +#define RxMXDMA_shift 20 +#define TX_DMA_BURST 0 +#define RX_DMA_BURST 0 + +/* transmit FIFO threshholds */ +#define TX_FILL_THRESH 16 /* 1/4 FIFO size */ +#define TxFILLT_shift 8 +#define TxDRNT_shift 0 +#define TxDRNT_100 48 /* 3/4 FIFO size */ +#define TxDRNT_10 16 /* 1/2 FIFO size */ + +enum sis900_transmit_config_register_bits { + TxCSI = 0x80000000, + TxHBI = 0x40000000, + TxMLB = 0x20000000, + TxATP = 0x10000000, + TxIFG = 0x0C000000, + TxFILLT = 0x00003F00, + TxDRNT = 0x0000003F +}; + +/* recevie FIFO thresholds */ +#define RxDRNT_shift 1 +#define RxDRNT_100 16 /* 1/2 FIFO size */ +#define RxDRNT_10 24 /* 3/4 FIFO size */ + +enum sis900_reveive_config_register_bits { + RxAEP = 0x80000000, + RxARP = 0x40000000, + RxATX = 0x10000000, + RxAJAB = 0x08000000, + RxDRNT = 0x0000007F +}; + +#define RFAA_shift 28 +#define RFADDR_shift 16 + +enum sis900_receive_filter_control_register_bits { + RFEN = 0x80000000, + RFAAB = 0x40000000, + RFAAM = 0x20000000, + RFAAP = 0x10000000, + RFPromiscuous = (RFAAB|RFAAM|RFAAP) +}; + +enum sis900_reveive_filter_data_mask { + RFDAT = 0x0000FFFF +}; + +/* EEPROM Addresses */ +enum sis900_eeprom_address { + EEPROMSignature = 0x00, + EEPROMVendorID = 0x02, + EEPROMDeviceID = 0x03, + EEPROMMACAddr = 0x08, + EEPROMChecksum = 0x0b +}; + +/* The EEPROM commands include the alway-set leading bit. Refer to NM93Cxx datasheet */ +enum sis900_eeprom_command { + EEread = 0x0180, + EEwrite = 0x0140, + EEerase = 0x01C0, + EEwriteEnable = 0x0130, + EEwriteDisable = 0x0100, + EEeraseAll = 0x0120, + EEwriteAll = 0x0110, + EEaddrMask = 0x013F, +}; + +/* Manamgement Data I/O (mdio) frame */ +#define MIIread 0x6000 +#define MIIwrite 0x5002 +#define MIIpmdShift 7 +#define MIIregShift 2 +#define MIIcmdLen 16 +#define MIIcmdShift 16 + +/* Buffer Descriptor Status*/ +enum sis900_buffer_status { + OWN = 0x80000000, + MORE = 0x40000000, + INTR = 0x20000000, + SUPCRC = 0x10000000, + INCCRC = 0x10000000, + OK = 0x08000000, + DSIZE = 0x00000FFF +}; + +/* Status for TX Buffers */ +enum sis900_tx_buffer_status { + ABORT = 0x04000000, + UNDERRUN = 0x02000000, + NOCARRIER = 0x01000000, + DEFERD = 0x00800000, + EXCDEFER = 0x00400000, + OWCOLL = 0x00200000, + EXCCOLL = 0x00100000, + COLCNT = 0x000F0000 +}; + +enum sis900_rx_bufer_status { + OVERRUN = 0x02000000, + DEST = 0x00800000, + BCAST = 0x01800000, + MCAST = 0x01000000, + UNIMATCH = 0x00800000, + TOOLONG = 0x00400000, + RUNT = 0x00200000, + RXISERR = 0x00100000, + CRCERR = 0x00080000, + FAERR = 0x00040000, + LOOPBK = 0x00020000, + RXCOL = 0x00010000 +}; + +/* MII register offsets */ +enum mii_registers { + MII_CONTROL = 0x0000, + MII_STATUS = 0x0001, + MII_PHY_ID0 = 0x0002, + MII_PHY_ID1 = 0x0003, + MII_ANADV = 0x0004, + MII_ANLPAR = 0x0005, + MII_ANEXT = 0x0006 +}; + +/* mii registers specific to SiS 900 */ +enum sis_mii_registers { + MII_CONFIG1 = 0x0010, + MII_CONFIG2 = 0x0011, + MII_STSOUT = 0x0012, + MII_MASK = 0x0013 +}; + +/* mii registers specific to AMD 79C901 */ +enum amd_mii_registers { + MII_STATUS_SUMMARY = 0x0018 +}; + +/* mii registers specific to ICS 1893 */ +enum ics_mii_registers { + MII_EXTCTRL = 0x0010, MII_QPDSTS = 0x0011, MII_10BTOP = 0x0012, + MII_EXTCTRL2 = 0x0013 +}; + + + +/* MII Control register bit definitions. */ +enum mii_control_register_bits { + MII_CNTL_FDX = 0x0100, + MII_CNTL_RST_AUTO = 0x0200, + MII_CNTL_ISOLATE = 0x0400, + MII_CNTL_PWRDWN = 0x0800, + MII_CNTL_AUTO = 0x1000, + MII_CNTL_SPEED = 0x2000, + MII_CNTL_LPBK = 0x4000, + MII_CNTL_RESET = 0x8000 +}; + +/* MII Status register bit */ +enum mii_status_register_bits { + MII_STAT_EXT = 0x0001, + MII_STAT_JAB = 0x0002, + MII_STAT_LINK = 0x0004, + MII_STAT_CAN_AUTO = 0x0008, + MII_STAT_FAULT = 0x0010, + MII_STAT_AUTO_DONE = 0x0020, + MII_STAT_CAN_T = 0x0800, + MII_STAT_CAN_T_FDX = 0x1000, + MII_STAT_CAN_TX = 0x2000, + MII_STAT_CAN_TX_FDX = 0x4000, + MII_STAT_CAN_T4 = 0x8000 +}; + +#define MII_ID1_OUI_LO 0xFC00 /* low bits of OUI mask */ +#define MII_ID1_MODEL 0x03F0 /* model number */ +#define MII_ID1_REV 0x000F /* model number */ + +/* MII NWAY Register Bits ... + valid for the ANAR (Auto-Negotiation Advertisement) and + ANLPAR (Auto-Negotiation Link Partner) registers */ +enum mii_nway_register_bits { + MII_NWAY_NODE_SEL = 0x001f, + MII_NWAY_CSMA_CD = 0x0001, + MII_NWAY_T = 0x0020, + MII_NWAY_T_FDX = 0x0040, + MII_NWAY_TX = 0x0080, + MII_NWAY_TX_FDX = 0x0100, + MII_NWAY_T4 = 0x0200, + MII_NWAY_PAUSE = 0x0400, + MII_NWAY_RF = 0x2000, + MII_NWAY_ACK = 0x4000, + MII_NWAY_NP = 0x8000 +}; + +enum mii_stsout_register_bits { + MII_STSOUT_LINK_FAIL = 0x4000, + MII_STSOUT_SPD = 0x0080, + MII_STSOUT_DPLX = 0x0040 +}; + +enum mii_stsics_register_bits { + MII_STSICS_SPD = 0x8000, MII_STSICS_DPLX = 0x4000, + MII_STSICS_LINKSTS = 0x0001 +}; + +enum mii_stssum_register_bits { + MII_STSSUM_LINK = 0x0008, + MII_STSSUM_DPLX = 0x0004, + MII_STSSUM_AUTO = 0x0002, + MII_STSSUM_SPD = 0x0001 +}; + +enum sis900_revision_id { + SIS630A_900_REV = 0x80, SIS630E_900_REV = 0x81, + SIS630S_900_REV = 0x82, SIS630EA1_900_REV = 0x83 +}; + +enum sis630_revision_id { + SIS630A0 = 0x00, SIS630A1 = 0x01, + SIS630B0 = 0x10, SIS630B1 = 0x11 +}; + +#define FDX_CAPABLE_DUPLEX_UNKNOWN 0 +#define FDX_CAPABLE_HALF_SELECTED 1 +#define FDX_CAPABLE_FULL_SELECTED 2 + +#define HW_SPEED_UNCONFIG 0 +#define HW_SPEED_HOME 1 +#define HW_SPEED_10_MBPS 10 +#define HW_SPEED_100_MBPS 100 +#define HW_SPEED_DEFAULT (HW_SPEED_100_MBPS) + +#define CRC_SIZE 4 +#define MAC_HEADER_SIZE 14 + +#define TX_BUF_SIZE 1536 +#define RX_BUF_SIZE 1536 + +#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */ + +typedef unsigned char u8; +typedef signed char s8; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned int u32; +typedef signed int s32; + +/* Time in ticks before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*TICKS_PER_SEC) + +typedef struct _BufferDesc { + u32 link; + volatile u32 cmdsts; + u32 bufptr; +} BufferDesc; diff --git a/netboot/sis900.txt b/netboot/sis900.txt new file mode 100644 index 000000000..77419fad6 --- /dev/null +++ b/netboot/sis900.txt @@ -0,0 +1,91 @@ +How I added the SIS900 card to Etherboot + +Author: Marty Connor (mdc@thinguin.org) + +Date: 25 Febrary 2001 + +Description: + +This file is intended to help people who want to write an Etherboot +driver or port another driver to Etherboot. It is a starting point. +Perhaps someday I may write a more detailed description of writing an +Etherboot driver. This text should help get people started, and +studying sis900.[ch] should help show the basic structure and +techniques involved in writing and Etherboot driver. + +*********************************************************************** + +0. Back up all the files I need to modify: + +cd etherboot-4.7.20/src +cp Makefile Makefile.orig +cp config.c config.c.orig +cp pci.h pci.h.orig +cp NIC NIC.orig +cp cards.h cards.h.orig + +1. Edit src/Makefile to add SIS900FLAGS to defines + +SIS900FLAGS= -DINCLUDE_SIS900 + +2. edit src/pci.h to add PCI signatures for card + +#define PCI_VENDOR_ID_SIS 0x1039 +#define PCI_DEVICE_ID_SIS900 0x0900 +#define PCI_DEVICE_ID_SIS7016 0x7016 + +3. Edit src/config.c to add the card to the card probe list + +#if defined(INCLUDE_NS8390) || defined(INCLUDE_EEPRO100) || + defined(INCLUDE_LANCE) || defined(INCLUDE_EPIC100) || + defined(INCLUDE_TULIP) || defined(INCLUDE_OTULIP) || + defined(INCLUDE_3C90X) || defined(INCLUDE_3C595) || + defined(INCLUDE_RTL8139) || defined(INCLUDE_VIA_RHINE) || + defined(INCLUDE_SIS900) || defined(INCLUDE_W89C840) + +... and ... + +#ifdef INCLUDE_SIS900 + { PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900, + "SIS900", 0, 0, 0, 0}, + { PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016, + "SIS7016", 0, 0, 0, 0}, +#endif + +... and ... + +#ifdef INCLUDE_SIS900 + { "SIS900", sis900_probe, pci_ioaddrs }, +#endif + +4. Edit NIC to add sis900 and sis7016 to NIC list + +# SIS 900 and SIS 7016 +sis900 sis900 0x1039,0x0900 +sis7016 sis900 0x1039,0x7016 + +5. Edit cards.h to add sis900 probe routine declaration + +#ifdef INCLUDE_SIS900 +extern struct nic *sis900_probe(struct nic *, unsigned short * + PCI_ARG(struct pci_device *)); +#endif + +*********************************************************************** + +At this point, you can begin creating your driver source file. See +the "Writing and Etherboot Driver" section of the Etherboot +documentation for some hints. See the skel.c file for a starting +point. If there is a Linux driver for the card, you may be able to +use that. Copy and learn from existing Etherboot drivers (this is GPL +/ Open Source software!). + +Join the etherboot-developers and etherboot-users mailing lists +(information is on etherboot.sourceforge.net) for information and +assistance. We invite more developers to help improve Etherboot. + +Visit the http://etherboot.sourceforge.net, http://thinguin.org, +http://rom-o-matic.net, and http://ltsp.org sites for information and +assistance. + +Enjoy. diff --git a/netboot/sk_g16.c b/netboot/sk_g16.c index 15babe997..eda52a0f7 100644 --- a/netboot/sk_g16.c +++ b/netboot/sk_g16.c @@ -514,7 +514,7 @@ static int SK_poll(struct nic *nic) struct priv *p; /* SK_G16 private structure */ struct rmd *rmdp; int csr0, rmdstat, packet_there; - PRINTF2(("## %s: At beginning of SK_poll(). CSR0: 0x%X\n", + PRINTF2(("## %s: At beginning of SK_poll(). CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0))); p = nic->priv_data; @@ -529,7 +529,7 @@ static int SK_poll(struct nic *nic) if (csr0 & CSR0_ERR) /* LANCE Error */ { - printf("%s: error: 0x%x", SK_NAME, csr0); + printf("%s: error: %#hX", SK_NAME, csr0); if (csr0 & CSR0_MISS) /* No place to store packet ? */ { @@ -576,7 +576,7 @@ static int SK_poll(struct nic *nic) } else if (rmdstat & RX_ERR) /* Receive Error ? */ { - printf("%s: RX error: 0x%x\n", SK_NAME, (int) rmdstat); + printf("%s: RX error: %#hX\n", SK_NAME, (int) rmdstat); rmdp->u.s.status = RX_OWN; /* Relinquish ownership to LANCE */ } else /* We have a packet which can be queued for the upper layers */ @@ -628,20 +628,20 @@ const char *pack) /* Packet */ short len; int csr0, i, tmdstat; - PRINTF2(("## %s: At beginning of SK_transmit(). CSR0: 0x%X\n", + PRINTF2(("## %s: At beginning of SK_transmit(). CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0))); p = nic->priv_data; tmdp = p->tmdhead + p->tmdnum; /* Which descriptor for transmitting */ /* Copy data into dual ported ram */ - memcpy(&p->ram->tmdbuf[p->tmdnum][0], d, ETHER_ADDR_SIZE); /* dst */ - memcpy(&p->ram->tmdbuf[p->tmdnum][ETHER_ADDR_SIZE], nic->node_addr, ETHER_ADDR_SIZE); /* src */ - p->ram->tmdbuf[p->tmdnum][ETHER_ADDR_SIZE + ETHER_ADDR_SIZE] = t >> 8; /* type */ - p->ram->tmdbuf[p->tmdnum][ETHER_ADDR_SIZE + ETHER_ADDR_SIZE + 1] = t; /* type */ - memcpy(&p->ram->tmdbuf[p->tmdnum][ETHER_HDR_SIZE], pack, s); - s += ETHER_HDR_SIZE; - while (s < ETH_MIN_PACKET) /* pad to min length */ + memcpy(&p->ram->tmdbuf[p->tmdnum][0], d, ETH_ALEN); /* dst */ + memcpy(&p->ram->tmdbuf[p->tmdnum][ETH_ALEN], nic->node_addr, ETH_ALEN); /* src */ + p->ram->tmdbuf[p->tmdnum][ETH_ALEN + ETH_ALEN] = t >> 8; /* type */ + p->ram->tmdbuf[p->tmdnum][ETH_ALEN + ETH_ALEN + 1] = t; /* type */ + memcpy(&p->ram->tmdbuf[p->tmdnum][ETH_HLEN], pack, s); + s += ETH_HLEN; + while (s < ETH_ZLEN) /* pad to min length */ p->ram->tmdbuf[p->tmdnum][s++] = 0; p->ram->tmde[p->tmdnum].status2 = 0x0; @@ -674,7 +674,7 @@ const char *pack) /* Packet */ if (csr0 & CSR0_ERR) /* LANCE Error */ { - printf("%s: error: 0x%x", SK_NAME, csr0); + printf("%s: error: %#hX", SK_NAME, csr0); if (csr0 & CSR0_MISS) /* No place to store packet ? */ { @@ -696,7 +696,7 @@ const char *pack) /* Packet */ */ if (tmdstat & TX_ERR) /* Error occurred */ { - printf("%s: TX error: 0x%x 0x%x\n", SK_NAME, (int) tmdstat, + printf("%s: TX error: %#hX %#hX\n", SK_NAME, (int) tmdstat, (int) tmdp->status2); if (tmdp->status2 & TX_TDR) /* TDR problems? */ @@ -730,9 +730,9 @@ DISABLE - Turn off ethernet interface ***************************************************************************/ static void SK_disable(struct nic *nic) { - PRINTF(("## %s: At beginning of SK_disable(). CSR0: 0x%X\n", + PRINTF(("## %s: At beginning of SK_disable(). CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0))); - PRINTF(("%s: Shutting %s down CSR0 0x%X\n", SK_NAME, SK_NAME, + PRINTF(("%s: Shutting %s down CSR0 %#hX\n", SK_NAME, SK_NAME, (int) SK_read_reg(CSR0))); SK_write_reg(CSR0, CSR0_STOP); /* STOP the LANCE */ @@ -788,7 +788,7 @@ int SK_probe1(struct nic *nic, short ioaddr1) * Now here we could use a routine which searches for a free * place in the ram and set SK_ADDR if found. TODO. */ - printf("%s: SK_ADDR 0x%X is not valid. Check configuration.\n", + printf("%s: SK_ADDR %#hX is not valid. Check configuration.\n", SK_NAME, SK_ADDR); return -1; } @@ -803,11 +803,11 @@ int SK_probe1(struct nic *nic, short ioaddr1) #endif board = (SK_RAM *) rom_addr; - PRINTF(("adr[0]: %x, adr[1]: %x, adr[2]: %x\n", + PRINTF(("adr[0]: %hX, adr[1]: %hX, adr[2]: %hX\n", board->rom[0], board->rom[2], board->rom[4])); /* Read in station address */ - for (i = 0, j = 0; i < ETHER_ADDR_SIZE; i++, j+=2) + for (i = 0, j = 0; i < ETH_ALEN; i++, j+=2) { *(nic->node_addr+i) = board->rom[j]; } @@ -832,15 +832,8 @@ int SK_probe1(struct nic *nic, short ioaddr1) p->tmdhead = &(p->ram)->tmde[0]; /* Set TMD head */ p->rmdhead = &(p->ram)->rmde[0]; /* Set RMD head */ - printf("Schneider & Koch G16 at 0x%x, mem at 0x%X, HW addr: %b:%b:%b:%b:%b:%b\n", - (unsigned int) ioaddr, - (unsigned int) p->ram, - *(nic->node_addr+0), - *(nic->node_addr+1), - *(nic->node_addr+2), - *(nic->node_addr+3), - *(nic->node_addr+4), - *(nic->node_addr+5)); + printf("Schneider & Koch G16 at %#hX, mem at %#hX, HW addr: %!\n", + (unsigned int) ioaddr, (unsigned int) p->ram, nic->node_addr); /* Initialize buffer pointers */ @@ -865,19 +858,19 @@ int SK_probe1(struct nic *nic, short ioaddr1) * then stop again and reinit with NORMAL_MODE */ - printf("## %s: After lance init. CSR0: 0x%X\n", + printf("## %s: After lance init. CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0)); SK_write_reg(CSR0, CSR0_STOP); - printf("## %s: LANCE stopped. CSR0: 0x%X\n", + printf("## %s: LANCE stopped. CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0)); SK_lance_init(nic, MODE_DTX | MODE_DRX); - printf("## %s: Reinit with DTX + DRX off. CSR0: 0x%X\n", + printf("## %s: Reinit with DTX + DRX off. CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0)); SK_write_reg(CSR0, CSR0_STOP); - printf("## %s: LANCE stopped. CSR0: 0x%X\n", + printf("## %s: LANCE stopped. CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0)); SK_lance_init(nic, MODE_NORMAL); - printf("## %s: LANCE back to normal mode. CSR0: 0x%X\n", + printf("## %s: LANCE back to normal mode. CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0)); SK_print_pos(nic, "POS regs before returning OK"); @@ -887,7 +880,7 @@ int SK_probe1(struct nic *nic, short ioaddr1) else /* LANCE init failed */ { - PRINTF(("## %s: LANCE init failed: CSR0: 0x%X\n", + PRINTF(("## %s: LANCE init failed: CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0))); return -1; } @@ -908,7 +901,7 @@ static int SK_lance_init(struct nic *nic, unsigned short mode) struct tmd *tmdp; struct rmd *rmdp; - PRINTF(("## %s: At beginning of LANCE init. CSR0: 0x%X\n", + PRINTF(("## %s: At beginning of LANCE init. CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0))); /* Reset LANCE */ @@ -957,7 +950,7 @@ static int SK_lance_init(struct nic *nic, unsigned short mode) (p->ram)->ib.mode = mode; /* Set operation mode */ - for (i = 0; i < ETHER_ADDR_SIZE; i++) /* Set physical address */ + for (i = 0; i < ETH_ALEN; i++) /* Set physical address */ { (p->ram)->ib.paddr[i] = *(nic->node_addr+i); } @@ -995,7 +988,7 @@ static int SK_lance_init(struct nic *nic, unsigned short mode) SK_write_reg(CSR2, 0); /* Set high order bits 23:16 */ - PRINTF(("## %s: After setting CSR1-3. CSR0: 0x%X\n", + PRINTF(("## %s: After setting CSR1-3. CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0))); /* Initialize LANCE */ @@ -1016,8 +1009,8 @@ static int SK_lance_init(struct nic *nic, unsigned short mode) if (i >= 100) /* Something is wrong ! */ { - printf("%s: can't init am7990, status: 0x%x " - "init_block: 0x%X\n", + printf("%s: can't init am7990, status: %#hX " + "init_block: %#hX\n", SK_NAME, (int) SK_read_reg(CSR0), (unsigned int) &(p->ram)->ib); @@ -1034,7 +1027,7 @@ static int SK_lance_init(struct nic *nic, unsigned short mode) SK_write_reg(CSR0, CSR0_IDON | CSR0_INEA | CSR0_STRT); - PRINTF(("## %s: LANCE started. CSR0: 0x%X\n", SK_NAME, + PRINTF(("## %s: LANCE started. CSR0: %#hX\n", SK_NAME, SK_read_reg(CSR0))); return 0; /* LANCE is up and running */ @@ -1122,7 +1115,7 @@ static void SK_print_pos(struct nic *nic, char *text) printf("## %s: %s.\n" - "## pos0=0x%x pos1=0x%x pos2=0x%x pos3=0x%X pos4=0x%x\n", + "## pos0=%#hX pos1=%#hX pos2=%#hX pos3=%#hX pos4=%#hX\n", SK_NAME, text, pos0, pos1, pos2, (pos3<<14), pos4); } /* End of SK_print_pos() */ @@ -1134,7 +1127,7 @@ static void SK_print_ram(struct nic *nic) struct priv *p = (struct priv *) nic->priv_data; printf("## %s: RAM Details.\n" - "## RAM at 0x%X tmdhead: 0x%X rmdhead: 0x%X initblock: 0x%X\n", + "## RAM at %#hX tmdhead: %#hX rmdhead: %#hX initblock: %#hX\n", SK_NAME, (unsigned int) p->ram, (unsigned int) p->tmdhead, @@ -1149,7 +1142,7 @@ static void SK_print_ram(struct nic *nic) { printf("\n## "); } - printf("tmdbufs%d: 0x%X ", (i+1), (int) p->tmdbufs[i]); + printf("tmdbufs%d: %#hX ", (i+1), (int) p->tmdbufs[i]); } printf("## "); @@ -1159,7 +1152,7 @@ static void SK_print_ram(struct nic *nic) { printf("\n## "); } - printf("rmdbufs%d: 0x%X ", (i+1), (int) p->rmdbufs[i]); + printf("rmdbufs%d: %#hX ", (i+1), (int) p->rmdbufs[i]); } putchar('\n'); diff --git a/netboot/smc9000.c b/netboot/smc9000.c index b2b42436b..4384a1356 100644 --- a/netboot/smc9000.c +++ b/netboot/smc9000.c @@ -134,7 +134,7 @@ static int smc_probe( int ioaddr ) if (ioaddr != (base_address_register >> 3 & 0x3E0)) { #ifdef SMC9000_VERBOSE - printf("SMC9000: IOADDR %x doesn't match configuration (%x)." + printf("SMC9000: IOADDR %hX doesn't match configuration (%hX)." "Probably not a SMC chip\n", ioaddr, base_address_register >> 3 & 0x3E0); #endif @@ -152,8 +152,8 @@ static int smc_probe( int ioaddr ) if (!chip_ids[(revision_register >> 4) & 0xF]) { /* I don't recognize this chip, so... */ #ifdef SMC9000_VERBOSE - printf("SMC9000: IO %x: Unrecognized revision register:" - " %x, Contact author.\n", ioaddr, revision_register); + printf("SMC9000: IO %hX: Unrecognized revision register:" + " %hX, Contact author.\n", ioaddr, revision_register); #endif return -1; } @@ -192,7 +192,7 @@ static void smc9000_transmit( int i; /* We dont pad here since we can have the hardware doing it for us */ - length = (s + ETHER_HDR_SIZE + 1)&~1; + length = (s + ETH_HLEN + 1)&~1; /* convert to MMU pages */ numPages = length / 256; @@ -245,7 +245,7 @@ static void smc9000_transmit( _outw(PTR_AUTOINC, smc9000_base + POINTER); #if SMC9000_DEBUG > 2 - printf("Trying to xmit packet of length %x\n", length ); + printf("Trying to xmit packet of length %hX\n", length ); #endif /* send the packet length ( +6 for status, length and ctl byte ) @@ -259,8 +259,8 @@ static void smc9000_transmit( /* Write the contents of the packet */ /* The ethernet header first... */ - outsw(smc9000_base + DATA_1, d, ETHER_ADDR_SIZE >> 1); - outsw(smc9000_base + DATA_1, nic->node_addr, ETHER_ADDR_SIZE >> 1); + outsw(smc9000_base + DATA_1, d, ETH_ALEN >> 1); + outsw(smc9000_base + DATA_1, nic->node_addr, ETH_ALEN >> 1); _outw(htons(t), smc9000_base + DATA_1); /* ... the data ... */ @@ -300,7 +300,7 @@ static void smc9000_transmit( if (0 == (tx_status & TS_SUCCESS)) { #ifdef SMC9000_VERBOSE - printf("SMC9000: TX FAIL STATUS: %x \n", tx_status); + printf("SMC9000: TX FAIL STATUS: %hX \n", tx_status); #endif /* re-enable transmit */ SMC_SELECT_BANK(smc9000_base, 0); @@ -476,16 +476,13 @@ struct nic *smc9000_probe(struct nic *nic, unsigned short *probe_addrs) /* now, reset the chip, and put it into a known state */ smc_reset(smc9000_base); - printf("%s rev:%d I/O port:%x Interface:%s RAM:%d bytes \n", + printf("%s rev:%d I/O port:%hX Interface:%s RAM:%d bytes \n", version_string, revision & 0xF, smc9000_base, if_string, memory ); /* * Print the Ethernet address */ - printf("Ethernet MAC address: "); - for (i = 0; i < 5; i++) - printf("%b:", nic->node_addr[i]); - printf("%b\n", nic->node_addr[5]); + printf("Ethernet MAC address: %!\n", nic->node_addr); SMC_SELECT_BANK(smc9000_base, 0); diff --git a/netboot/tiara.c b/netboot/tiara.c index f13b3ca0a..cbf485d01 100644 --- a/netboot/tiara.c +++ b/netboot/tiara.c @@ -125,7 +125,7 @@ static void tiara_reset(struct nic *nic) while ((inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY) == 0) inb(ioaddr + BMPR_MEM_PORT); /* Set node address */ - for (i = 0; i < ETHER_ADDR_SIZE; ++i) + for (i = 0; i < ETH_ALEN; ++i) outb(nic->node_addr[i], ioaddr + DLCR_NODE_ID + i); outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT); outb(CARD_ENABLE, ioaddr + DLCR_ENABLE); @@ -145,11 +145,11 @@ static int tiara_poll(struct nic *nic) len = inw(ioaddr + BMPR_MEM_PORT); /* throw away status */ len = inw(ioaddr + BMPR_MEM_PORT); /* Drop overlength packets */ - if (len > ETH_MAX_PACKET) + if (len > ETH_FRAME_LEN) return (0); /* should we drain the buffer? */ insw(ioaddr + BMPR_MEM_PORT, nic->packet, len / 2); /* If it's our own, drop it */ - if (memcmp(nic->packet + ETHER_ADDR_SIZE, nic->node_addr, ETHER_ADDR_SIZE) == 0) + if (memcmp(nic->packet + ETH_ALEN, nic->node_addr, ETH_ALEN) == 0) return (0); nic->packetlen = len; return (1); @@ -168,17 +168,17 @@ const char *p) /* Packet */ unsigned int len; unsigned long time; - len = s + ETHER_HDR_SIZE; - if (len < ETH_MIN_PACKET) - len = ETH_MIN_PACKET; + len = s + ETH_HLEN; + if (len < ETH_ZLEN) + len = ETH_ZLEN; t = htons(t); - outsw(ioaddr + BMPR_MEM_PORT, d, ETHER_ADDR_SIZE / 2); - outsw(ioaddr + BMPR_MEM_PORT, nic->node_addr, ETHER_ADDR_SIZE / 2); + outsw(ioaddr + BMPR_MEM_PORT, d, ETH_ALEN / 2); + outsw(ioaddr + BMPR_MEM_PORT, nic->node_addr, ETH_ALEN / 2); outw(t, ioaddr + BMPR_MEM_PORT); outsw(ioaddr + BMPR_MEM_PORT, p, s / 2); if (s & 1) /* last byte */ outb(p[s-1], ioaddr + BMPR_MEM_PORT); - while (s++ < ETH_MIN_PACKET - ETHER_HDR_SIZE) /* pad */ + while (s++ < ETH_ZLEN - ETH_HLEN) /* pad */ outb(0, ioaddr + BMPR_MEM_PORT); outw(len | (TMST << 8), ioaddr + BMPR_PKT_LEN); /* wait for transmit complete */ @@ -206,20 +206,13 @@ static int tiara_probe1(struct nic *nic) static char all_ones[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; int i; - for (i = 0; i < ETHER_ADDR_SIZE; ++i) + for (i = 0; i < ETH_ALEN; ++i) nic->node_addr[i] = inb(ioaddr + PROM_ID + i); if (memcmp(nic->node_addr, vendor_prefix, sizeof(vendor_prefix)) != 0) return (0); if (memcmp(nic->node_addr, all_ones, sizeof(all_ones)) == 0) return (0); - printf("\nTiara ioaddr 0x%x, addr ", ioaddr); - for (i = 0; i < ETHER_ADDR_SIZE; ++i) - { - printf("%b", nic->node_addr[i]); - if (i < ETHER_ADDR_SIZE - 1) - printf(":"); - } - putchar('\n'); + printf("\nTiara ioaddr %#hX, addr %!\n", ioaddr, nic->node_addr); return (1); } diff --git a/netboot/timer.c b/netboot/timer.c new file mode 100644 index 000000000..2487d63c9 --- /dev/null +++ b/netboot/timer.c @@ -0,0 +1,127 @@ +/* A couple of routines to implement a low-overhead timer for drivers */ + + /* + * 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, or (at + * your option) any later version. + */ + +#include "etherboot.h" +#include "timer.h" + +void load_timer2(unsigned int ticks) +{ + /* Set up the timer gate, turn off the speaker */ + outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); + outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT); + outb(ticks & 0xFF, TIMER2_PORT); + outb(ticks >> 8, TIMER2_PORT); +} + +#if defined(CONFIG_TSC_CURRTICKS) +#define rdtsc(low,high) \ + __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) + +#define rdtscll(val) \ + __asm__ __volatile__ ("rdtsc" : "=A" (val)) + + +#define HZ TICKS_PER_SEC +#define CLOCK_TICK_RATE 1193180U /* Underlying HZ */ +/* LATCH is used in the interval timer and ftape setup. */ +#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ + + +/* ------ Calibrate the TSC ------- + * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). + * Too much 64-bit arithmetic here to do this cleanly in C, and for + * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2) + * output busy loop as low as possible. We avoid reading the CTC registers + * directly because of the awkward 8-bit access mechanism of the 82C54 + * device. + */ + +#define CALIBRATE_LATCH (5 * LATCH) + +static unsigned long long calibrate_tsc(void) +{ + /* Set the Gate high, disable speaker */ + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + + /* + * Now let's take care of CTC channel 2 + * + * Set the Gate high, program CTC channel 2 for mode 0, + * (interrupt on terminal count mode), binary count, + * load 5 * LATCH count, (LSB and MSB) to begin countdown. + */ + outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ + outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ + outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ + + { + unsigned long startlow, starthigh; + unsigned long endlow, endhigh; + unsigned long count; + + rdtsc(startlow,starthigh); + count = 0; + do { + count++; + } while ((inb(0x61) & 0x20) == 0); + rdtsc(endlow,endhigh); + + /* Error: ECTCNEVERSET */ + if (count <= 1) + goto bad_ctc; + + /* 64-bit subtract - gcc just messes up with long longs */ + __asm__("subl %2,%0\n\t" + "sbbl %3,%1" + :"=a" (endlow), "=d" (endhigh) + :"g" (startlow), "g" (starthigh), + "0" (endlow), "1" (endhigh)); + + /* Error: ECPUTOOFAST */ + if (endhigh) + goto bad_ctc; + + endlow /= 5; + return endlow; + } + + /* + * The CTC wasn't reliable: we got a hit on the very first read, + * or the CPU was so fast/slow that the quotient wouldn't fit in + * 32 bits.. + */ +bad_ctc: + printf("bad_ctc\n"); + return 0; +} + + +unsigned long currticks(void) +{ + static unsigned long clocks_per_tick; + unsigned long clocks_high, clocks_low; + unsigned long currticks; + if (!clocks_per_tick) { + clocks_per_tick = calibrate_tsc(); + printf("clocks_per_tick = %d\n", clocks_per_tick); + } + + /* Read the Time Stamp Counter */ + rdtsc(clocks_low, clocks_high); + + /* currticks = clocks / clocks_per_tick; */ + __asm__("divl %1" + :"=a" (currticks) + :"r" (clocks_per_tick), "0" (clocks_low), "d" (clocks_high)); + + + return currticks; +} + +#endif /* RTC_CURRTICKS */ diff --git a/netboot/timer.h b/netboot/timer.h new file mode 100644 index 000000000..b44962a79 --- /dev/null +++ b/netboot/timer.h @@ -0,0 +1,64 @@ +/* Defines for routines to implement a low-overhead timer for drivers */ + + /* + * 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, or (at + * your option) any later version. + */ + +#ifndef TIMER_H +#define TIMER_H + +/* Ports for the 8254 timer chip */ +#define TIMER2_PORT 0x42 +#define TIMER_MODE_PORT 0x43 + +/* Meaning of the mode bits */ +#define TIMER0_SEL 0x00 +#define TIMER1_SEL 0x40 +#define TIMER2_SEL 0x80 +#define READBACK_SEL 0xC0 + +#define LATCH_COUNT 0x00 +#define LOBYTE_ACCESS 0x10 +#define HIBYTE_ACCESS 0x20 +#define WORD_ACCESS 0x30 + +#define MODE0 0x00 +#define MODE1 0x02 +#define MODE2 0x04 +#define MODE3 0x06 +#define MODE4 0x08 +#define MODE5 0x0A + +#define BINARY_COUNT 0x00 +#define BCD_COUNT 0x01 + +/* Timers tick over at this rate */ +#define TICKS_PER_MS 1193 + +/* Parallel Peripheral Controller Port B */ +#define PPC_PORTB 0x61 + +/* Meaning of the port bits */ +#define PPCB_T2OUT 0x20 /* Bit 5 */ +#define PPCB_SPKR 0x02 /* Bit 1 */ +#define PPCB_T2GATE 0x01 /* Bit 0 */ + +/* Ticks must be between 0 and 65535 (0 == 65536) + because it is a 16 bit counter */ +extern void load_timer2(unsigned int ticks); +extern inline int timer2_running(void) +{ + return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0); +} + +extern inline void waiton_timer2(unsigned int ticks) +{ + load_timer2(ticks); + while ((inb(PPC_PORTB) & PPCB_T2OUT) == 0) + ; +} + +#endif /* TIMER_H */ diff --git a/netboot/tlan.c b/netboot/tlan.c new file mode 100644 index 000000000..03b69f7f7 --- /dev/null +++ b/netboot/tlan.c @@ -0,0 +1,3746 @@ +/************************************************************************** +Etherboot - BOOTP/TFTP Bootstrap Program +TLAN driver for Etherboot +***************************************************************************/ + +/* + * 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, or (at + * your option) any later version. + */ + +/* to get some global routines like printf */ +#include "etherboot.h" +/* to get the interface to the body of the program */ +#include "nic.h" +/* to get the PCI support functions, if this is a PCI NIC */ +#include "pci.h" +/* to get our own prototype */ +#include "cards.h" + + /***************************************************************** + * TLan Definitions + * + ****************************************************************/ + +#define TLAN_MIN_FRAME_SIZE 64 +#define TLAN_MAX_FRAME_SIZE 1600 + +#define TLAN_NUM_RX_LISTS 32 +#define TLAN_NUM_TX_LISTS 64 + +#define TLAN_IGNORE 0 +#define TLAN_RECORD 1 + +#define TLAN_DBG(lvl, format, args...) if (debug&lvl) printf("TLAN: " format, ##args ); +#define TLAN_DEBUG_GNRL 0x0001 +#define TLAN_DEBUG_TX 0x0002 +#define TLAN_DEBUG_RX 0x0004 +#define TLAN_DEBUG_LIST 0x0008 +#define TLAN_DEBUG_PROBE 0x0010 + +#define MAX_TLAN_BOARDS 8 /* Max number of boards installed at a time */ + + /***************************************************************** + * Device Identification Definitions + * + ****************************************************************/ + +#define PCI_DEVICE_ID_NETELLIGENT_10_T2 0xB012 +#define PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100 0xB030 +#ifndef PCI_DEVICE_ID_OLICOM_OC2183 +#define PCI_DEVICE_ID_OLICOM_OC2183 0x0013 +#endif +#ifndef PCI_DEVICE_ID_OLICOM_OC2325 +#define PCI_DEVICE_ID_OLICOM_OC2325 0x0012 +#endif +#ifndef PCI_DEVICE_ID_OLICOM_OC2326 +#define PCI_DEVICE_ID_OLICOM_OC2326 0x0014 +#endif +#define TLAN_ADAPTER_NONE 0x00000000 +#define TLAN_ADAPTER_UNMANAGED_PHY 0x00000001 +#define TLAN_ADAPTER_BIT_RATE_PHY 0x00000002 +#define TLAN_ADAPTER_USE_INTERN_10 0x00000004 +#define TLAN_ADAPTER_ACTIVITY_LED 0x00000008 +#define TLAN_SPEED_DEFAULT 0 +#define TLAN_SPEED_10 10 +#define TLAN_SPEED_100 100 +#define TLAN_DUPLEX_DEFAULT 0 +#define TLAN_DUPLEX_HALF 1 +#define TLAN_DUPLEX_FULL 2 +#define TLAN_BUFFERS_PER_LIST 10 +#define TLAN_LAST_BUFFER 0x80000000 +#define TLAN_CSTAT_UNUSED 0x8000 +#define TLAN_CSTAT_FRM_CMP 0x4000 +#define TLAN_CSTAT_READY 0x3000 +#define TLAN_CSTAT_EOC 0x0800 +#define TLAN_CSTAT_RX_ERROR 0x0400 +#define TLAN_CSTAT_PASS_CRC 0x0200 +#define TLAN_CSTAT_DP_PR 0x0100 + + /***************************************************************** + * PHY definitions + * + ****************************************************************/ + +#define TLAN_PHY_MAX_ADDR 0x1F +#define TLAN_PHY_NONE 0x20 + + /***************************************************************** + * TLan Driver Timer Definitions + * + ****************************************************************/ + +#define TLAN_TIMER_LINK_BEAT 1 +#define TLAN_TIMER_ACTIVITY 2 +#define TLAN_TIMER_PHY_PDOWN 3 +#define TLAN_TIMER_PHY_PUP 4 +#define TLAN_TIMER_PHY_RESET 5 +#define TLAN_TIMER_PHY_START_LINK 6 +#define TLAN_TIMER_PHY_FINISH_AN 7 +#define TLAN_TIMER_FINISH_RESET 8 +#define TLAN_TIMER_ACT_DELAY (HZ/10) + + /***************************************************************** + * TLan Driver Eeprom Definitions + * + ****************************************************************/ + +#define TLAN_EEPROM_ACK 0 +#define TLAN_EEPROM_STOP 1 + + /***************************************************************** + * Host Register Offsets and Contents + * + ****************************************************************/ + +#define TLAN_HOST_CMD 0x00 +#define TLAN_HC_GO 0x80000000 +#define TLAN_HC_STOP 0x40000000 +#define TLAN_HC_ACK 0x20000000 +#define TLAN_HC_CS_MASK 0x1FE00000 +#define TLAN_HC_EOC 0x00100000 +#define TLAN_HC_RT 0x00080000 +#define TLAN_HC_NES 0x00040000 +#define TLAN_HC_AD_RST 0x00008000 +#define TLAN_HC_LD_TMR 0x00004000 +#define TLAN_HC_LD_THR 0x00002000 +#define TLAN_HC_REQ_INT 0x00001000 +#define TLAN_HC_INT_OFF 0x00000800 +#define TLAN_HC_INT_ON 0x00000400 +#define TLAN_HC_AC_MASK 0x000000FF +#define TLAN_CH_PARM 0x04 +#define TLAN_DIO_ADR 0x08 +#define TLAN_DA_ADR_INC 0x8000 +#define TLAN_DA_RAM_ADR 0x4000 +#define TLAN_HOST_INT 0x0A +#define TLAN_HI_IV_MASK 0x1FE0 +#define TLAN_HI_IT_MASK 0x001C +#define TLAN_DIO_DATA 0x0C + +/* ThunderLAN Internal Register DIO Offsets */ + +#define TLAN_NET_CMD 0x00 +#define TLAN_NET_CMD_NRESET 0x80 +#define TLAN_NET_CMD_NWRAP 0x40 +#define TLAN_NET_CMD_CSF 0x20 +#define TLAN_NET_CMD_CAF 0x10 +#define TLAN_NET_CMD_NOBRX 0x08 +#define TLAN_NET_CMD_DUPLEX 0x04 +#define TLAN_NET_CMD_TRFRAM 0x02 +#define TLAN_NET_CMD_TXPACE 0x01 +#define TLAN_NET_SIO 0x01 +#define TLAN_NET_SIO_MINTEN 0x80 +#define TLAN_NET_SIO_ECLOK 0x40 +#define TLAN_NET_SIO_ETXEN 0x20 +#define TLAN_NET_SIO_EDATA 0x10 +#define TLAN_NET_SIO_NMRST 0x08 +#define TLAN_NET_SIO_MCLK 0x04 +#define TLAN_NET_SIO_MTXEN 0x02 +#define TLAN_NET_SIO_MDATA 0x01 +#define TLAN_NET_STS 0x02 +#define TLAN_NET_STS_MIRQ 0x80 +#define TLAN_NET_STS_HBEAT 0x40 +#define TLAN_NET_STS_TXSTOP 0x20 +#define TLAN_NET_STS_RXSTOP 0x10 +#define TLAN_NET_STS_RSRVD 0x0F +#define TLAN_NET_MASK 0x03 +#define TLAN_NET_MASK_MASK7 0x80 +#define TLAN_NET_MASK_MASK6 0x40 +#define TLAN_NET_MASK_MASK5 0x20 +#define TLAN_NET_MASK_MASK4 0x10 +#define TLAN_NET_MASK_RSRVD 0x0F +#define TLAN_NET_CONFIG 0x04 +#define TLAN_NET_CFG_RCLK 0x8000 +#define TLAN_NET_CFG_TCLK 0x4000 +#define TLAN_NET_CFG_BIT 0x2000 +#define TLAN_NET_CFG_RXCRC 0x1000 +#define TLAN_NET_CFG_PEF 0x0800 +#define TLAN_NET_CFG_1FRAG 0x0400 +#define TLAN_NET_CFG_1CHAN 0x0200 +#define TLAN_NET_CFG_MTEST 0x0100 +#define TLAN_NET_CFG_PHY_EN 0x0080 +#define TLAN_NET_CFG_MSMASK 0x007F +#define TLAN_MAN_TEST 0x06 +#define TLAN_DEF_VENDOR_ID 0x08 +#define TLAN_DEF_DEVICE_ID 0x0A +#define TLAN_DEF_REVISION 0x0C +#define TLAN_DEF_SUBCLASS 0x0D +#define TLAN_DEF_MIN_LAT 0x0E +#define TLAN_DEF_MAX_LAT 0x0F +#define TLAN_AREG_0 0x10 +#define TLAN_AREG_1 0x16 +#define TLAN_AREG_2 0x1C +#define TLAN_AREG_3 0x22 +#define TLAN_HASH_1 0x28 +#define TLAN_HASH_2 0x2C +#define TLAN_GOOD_TX_FRMS 0x30 +#define TLAN_TX_UNDERUNS 0x33 +#define TLAN_GOOD_RX_FRMS 0x34 +#define TLAN_RX_OVERRUNS 0x37 +#define TLAN_DEFERRED_TX 0x38 +#define TLAN_CRC_ERRORS 0x3A +#define TLAN_CODE_ERRORS 0x3B +#define TLAN_MULTICOL_FRMS 0x3C +#define TLAN_SINGLECOL_FRMS 0x3E +#define TLAN_EXCESSCOL_FRMS 0x40 +#define TLAN_LATE_COLS 0x41 +#define TLAN_CARRIER_LOSS 0x42 +#define TLAN_ACOMMIT 0x43 +#define TLAN_LED_REG 0x44 +#define TLAN_LED_ACT 0x10 +#define TLAN_LED_LINK 0x01 +#define TLAN_BSIZE_REG 0x45 +#define TLAN_MAX_RX 0x46 +#define TLAN_INT_DIS 0x48 +#define TLAN_ID_TX_EOC 0x04 +#define TLAN_ID_RX_EOF 0x02 +#define TLAN_ID_RX_EOC 0x01 + +/* ThunderLAN Interrupt Codes */ + +#define TLAN_INT_NUMBER_OF_INTS 8 + +#define TLAN_INT_NONE 0x0000 +#define TLAN_INT_TX_EOF 0x0001 +#define TLAN_INT_STAT_OVERFLOW 0x0002 +#define TLAN_INT_RX_EOF 0x0003 +#define TLAN_INT_DUMMY 0x0004 +#define TLAN_INT_TX_EOC 0x0005 +#define TLAN_INT_STATUS_CHECK 0x0006 +#define TLAN_INT_RX_EOC 0x0007 +#define TLAN_TLPHY_ID 0x10 +#define TLAN_TLPHY_CTL 0x11 +#define TLAN_TC_IGLINK 0x8000 +#define TLAN_TC_SWAPOL 0x4000 +#define TLAN_TC_AUISEL 0x2000 +#define TLAN_TC_SQEEN 0x1000 +#define TLAN_TC_MTEST 0x0800 +#define TLAN_TC_RESERVED 0x07F8 +#define TLAN_TC_NFEW 0x0004 +#define TLAN_TC_INTEN 0x0002 +#define TLAN_TC_TINT 0x0001 +#define TLAN_TLPHY_STS 0x12 +#define TLAN_TS_MINT 0x8000 +#define TLAN_TS_PHOK 0x4000 +#define TLAN_TS_POLOK 0x2000 +#define TLAN_TS_TPENERGY 0x1000 +#define TLAN_TS_RESERVED 0x0FFF +#define TLAN_TLPHY_PAR 0x19 +#define TLAN_PHY_CIM_STAT 0x0020 +#define TLAN_PHY_SPEED_100 0x0040 +#define TLAN_PHY_DUPLEX_FULL 0x0080 +#define TLAN_PHY_AN_EN_STAT 0x0400 + + +/* ThunderLAN MII Registers */ + +/* Generic MII/PHY Registers */ + +#define MII_GEN_CTL 0x00 +#define MII_GC_RESET 0x8000 +#define MII_GC_LOOPBK 0x4000 +#define MII_GC_SPEEDSEL 0x2000 +#define MII_GC_AUTOENB 0x1000 +#define MII_GC_PDOWN 0x0800 +#define MII_GC_ISOLATE 0x0400 +#define MII_GC_AUTORSRT 0x0200 +#define MII_GC_DUPLEX 0x0100 +#define MII_GC_COLTEST 0x0080 +#define MII_GC_RESERVED 0x007F +#define MII_GEN_STS 0x01 +#define MII_GS_100BT4 0x8000 +#define MII_GS_100BTXFD 0x4000 +#define MII_GS_100BTXHD 0x2000 +#define MII_GS_10BTFD 0x1000 +#define MII_GS_10BTHD 0x0800 +#define MII_GS_RESERVED 0x07C0 +#define MII_GS_AUTOCMPLT 0x0020 +#define MII_GS_RFLT 0x0010 +#define MII_GS_AUTONEG 0x0008 +#define MII_GS_LINK 0x0004 +#define MII_GS_JABBER 0x0002 +#define MII_GS_EXTCAP 0x0001 +#define MII_GEN_ID_HI 0x02 +#define MII_GEN_ID_LO 0x03 +#define MII_GIL_OUI 0xFC00 +#define MII_GIL_MODEL 0x03F0 +#define MII_GIL_REVISION 0x000F +#define MII_AN_ADV 0x04 +#define MII_AN_LPA 0x05 +#define MII_AN_EXP 0x06 + +/* ThunderLAN Specific MII/PHY Registers */ + +#define TLAN_TC_IGLINK 0x8000 +#define TLAN_TC_SWAPOL 0x4000 +#define TLAN_TC_AUISEL 0x2000 +#define TLAN_TC_SQEEN 0x1000 +#define TLAN_TC_MTEST 0x0800 +#define TLAN_TC_RESERVED 0x07F8 +#define TLAN_TC_NFEW 0x0004 +#define TLAN_TC_INTEN 0x0002 +#define TLAN_TC_TINT 0x0001 +#define TLAN_TS_MINT 0x8000 +#define TLAN_TS_PHOK 0x4000 +#define TLAN_TS_POLOK 0x2000 +#define TLAN_TS_TPENERGY 0x1000 +#define TLAN_TS_RESERVED 0x0FFF +#define TLAN_PHY_CIM_STAT 0x0020 +#define TLAN_PHY_SPEED_100 0x0040 +#define TLAN_PHY_DUPLEX_FULL 0x0080 +#define TLAN_PHY_AN_EN_STAT 0x0400 + +/* National Sem. & Level1 PHY id's */ +#define NAT_SEM_ID1 0x2000 +#define NAT_SEM_ID2 0x5C01 +#define LEVEL1_ID1 0x7810 +#define LEVEL1_ID2 0x0000 + +#define TLan_ClearBit( bit, port ) outb_p(inb_p(port) & ~bit, port) +#define TLan_GetBit( bit, port ) ((int) (inb_p(port) & bit)) +#define TLan_SetBit( bit, port ) outb_p(inb_p(port) | bit, port) + +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; + +/* Routines to access internal registers. */ + +inline u8 TLan_DioRead8(u16 base_addr, u16 internal_addr) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + return (inb((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x3))); + +} /* TLan_DioRead8 */ + +inline u16 TLan_DioRead16(u16 base_addr, u16 internal_addr) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + return (inw((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x2))); + +} /* TLan_DioRead16 */ + +inline u32 TLan_DioRead32(u16 base_addr, u16 internal_addr) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + return (inl(base_addr + TLAN_DIO_DATA)); + +} /* TLan_DioRead32 */ + +inline void TLan_DioWrite8(u16 base_addr, u16 internal_addr, u8 data) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + outb(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x3)); + +} + +inline void TLan_DioWrite16(u16 base_addr, u16 internal_addr, u16 data) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + outw(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2)); + +} + +inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + outl(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2)); + +} + +/* NIC specific static variables go here */ + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver Eeprom routines + + The Compaq Netelligent 10 and 10/100 cards use a Microchip 24C02A + EEPROM. These functions are based on information in Microchip's + data sheet. I don't know how well this functions will work with + other EEPROMs. + +****************************************************************************** +*****************************************************************************/ + + /*************************************************************** + * TLan_EeSendStart + * + * Returns: + * Nothing + * Parms: + * io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. + * + * This function sends a start cycle to an EEPROM attached + * to a TLAN chip. + * + **************************************************************/ + +static void TLan_EeSendStart( u16 io_base ) +{ + u16 sio; + + outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; + + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + +} /* TLan_EeSendStart */ + + /*************************************************************** + * TLan_EeSendByte + * + * Returns: + * If the correct ack was received, 0, otherwise 1 + * Parms: io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. + * data The 8 bits of information to + * send to the EEPROM. + * stop If TLAN_EEPROM_STOP is passed, a + * stop cycle is sent after the + * byte is sent after the ack is + * read. + * + * This function sends a byte on the serial EEPROM line, + * driving the clock to send each bit. The function then + * reverses transmission direction and reads an acknowledge + * bit. + * + **************************************************************/ + +static int TLan_EeSendByte( u16 io_base, u8 data, int stop ) +{ + int err; + u8 place; + u16 sio; + + outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; + + /* Assume clock is low, tx is enabled; */ + for ( place = 0x80; place != 0; place >>= 1 ) { + if ( place & data ) + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + else + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + } + TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + err = TLan_GetBit( TLAN_NET_SIO_EDATA, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); + + if ( ( ! err ) && stop ) { + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */ + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + } + + return ( err ); + +} /* TLan_EeSendByte */ + + /*************************************************************** + * TLan_EeReceiveByte + * + * Returns: + * Nothing + * Parms: + * io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. + * data An address to a char to hold the + * data sent from the EEPROM. + * stop If TLAN_EEPROM_STOP is passed, a + * stop cycle is sent after the + * byte is received, and no ack is + * sent. + * + * This function receives 8 bits of data from the EEPROM + * over the serial link. It then sends and ack bit, or no + * ack and a stop bit. This function is used to retrieve + * data after the address of a byte in the EEPROM has been + * sent. + * + **************************************************************/ + +static void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop ) +{ + u8 place; + u16 sio; + + outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; + *data = 0; + + /* Assume clock is low, tx is enabled; */ + TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); + for ( place = 0x80; place; place >>= 1 ) { + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + if ( TLan_GetBit( TLAN_NET_SIO_EDATA, sio ) ) + *data |= place; + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + } + + TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); + if ( ! stop ) { + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* Ack = 0 */ + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + } else { + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); /* No ack = 1 (?) */ + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */ + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + } + +} /* TLan_EeReceiveByte */ + + /*************************************************************** + * TLan_EeReadByte + * + * Returns: + * No error = 0, else, the stage at which the error + * occurred. + * Parms: + * io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. + * ee_addr The address of the byte in the + * EEPROM whose contents are to be + * retrieved. + * data An address to a char to hold the + * data obtained from the EEPROM. + * + * This function reads a byte of information from an byte + * cell in the EEPROM. + * + **************************************************************/ + +static int TLan_EeReadByte( u16 io_base, u8 ee_addr, u8 *data ) +{ + int err; + unsigned long flags = 0; + int ret=0; + + TLan_EeSendStart( io_base ); + err = TLan_EeSendByte( io_base, 0xA0, TLAN_EEPROM_ACK ); + if (err) + { + ret=1; + goto fail; + } + err = TLan_EeSendByte( io_base, ee_addr, TLAN_EEPROM_ACK ); + if (err) + { + ret=2; + goto fail; + } + TLan_EeSendStart( io_base ); + err = TLan_EeSendByte( io_base, 0xA1, TLAN_EEPROM_ACK ); + if (err) + { + ret=3; + goto fail; + } + TLan_EeReceiveByte( io_base, data, TLAN_EEPROM_STOP ); +fail: + + return ret; + +} /* TLan_EeReadByte */ + +#if 0 +/* Not yet converted from Linux driver */ +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver PHY Layer Routines + +****************************************************************************** +*****************************************************************************/ + + /********************************************************************* + * TLan_PhyPrint + * + * Returns: + * Nothing + * Parms: + * dev A pointer to the device structure of the + * TLAN device having the PHYs to be detailed. + * + * This function prints the registers a PHY (aka tranceiver). + * + ********************************************************************/ + +void TLan_PhyPrint( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + u16 i, data0, data1, data2, data3, phy; + + phy = priv->phy[priv->phyNum]; + + if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) { + printk( "TLAN: Device %s, Unmanaged PHY.\n", dev->name ); + } else if ( phy <= TLAN_PHY_MAX_ADDR ) { + printk( "TLAN: Device %s, PHY 0x%02x.\n", dev->name, phy ); + printk( "TLAN: Off. +0 +1 +2 +3 \n" ); + for ( i = 0; i < 0x20; i+= 4 ) { + printk( "TLAN: 0x%02x", i ); + TLan_MiiReadReg( dev, phy, i, &data0 ); + printk( " 0x%04hx", data0 ); + TLan_MiiReadReg( dev, phy, i + 1, &data1 ); + printk( " 0x%04hx", data1 ); + TLan_MiiReadReg( dev, phy, i + 2, &data2 ); + printk( " 0x%04hx", data2 ); + TLan_MiiReadReg( dev, phy, i + 3, &data3 ); + printk( " 0x%04hx\n", data3 ); + } + } else { + printk( "TLAN: Device %s, Invalid PHY.\n", dev->name ); + } + +} /* TLan_PhyPrint */ + + /********************************************************************* + * TLan_PhyDetect + * + * Returns: + * Nothing + * Parms: + * dev A pointer to the device structure of the adapter + * for which the PHY needs determined. + * + * So far I've found that adapters which have external PHYs + * may also use the internal PHY for part of the functionality. + * (eg, AUI/Thinnet). This function finds out if this TLAN + * chip has an internal PHY, and then finds the first external + * PHY (starting from address 0) if it exists). + * + ********************************************************************/ + +void TLan_PhyDetect( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + u16 control; + u16 hi; + u16 lo; + u32 phy; + + if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) { + priv->phyNum = 0xFFFF; + return; + } + + TLan_MiiReadReg( dev, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi ); + + if ( hi != 0xFFFF ) { + priv->phy[0] = TLAN_PHY_MAX_ADDR; + } else { + priv->phy[0] = TLAN_PHY_NONE; + } + + priv->phy[1] = TLAN_PHY_NONE; + for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) { + TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &control ); + TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &hi ); + TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &lo ); + if ( ( control != 0xFFFF ) || ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) { + TLAN_DBG( TLAN_DEBUG_GNRL, "PHY found at %02x %04x %04x %04x\n", phy, control, hi, lo ); + if ( ( priv->phy[1] == TLAN_PHY_NONE ) && ( phy != TLAN_PHY_MAX_ADDR ) ) { + priv->phy[1] = phy; + } + } + } + + if ( priv->phy[1] != TLAN_PHY_NONE ) { + priv->phyNum = 1; + } else if ( priv->phy[0] != TLAN_PHY_NONE ) { + priv->phyNum = 0; + } else { + printk( "TLAN: Cannot initialize device, no PHY was found!\n" ); + } + +} /* TLan_PhyDetect */ + +void TLan_PhyPowerDown( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + u16 value; + + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering down PHY(s).\n", dev->name ); + value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE; + TLan_MiiSync( dev->base_addr ); + TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value ); + if ( ( priv->phyNum == 0 ) && ( priv->phy[1] != TLAN_PHY_NONE ) && ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) { + TLan_MiiSync( dev->base_addr ); + TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value ); + } + + /* Wait for 50 ms and powerup + * This is abitrary. It is intended to make sure the + * tranceiver settles. + */ + TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_PUP ); + +} /* TLan_PhyPowerDown */ + +void TLan_PhyPowerUp( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + u16 value; + + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering up PHY.\n", dev->name ); + TLan_MiiSync( dev->base_addr ); + value = MII_GC_LOOPBK; + TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value ); + TLan_MiiSync(dev->base_addr); + /* Wait for 500 ms and reset the + * tranceiver. The TLAN docs say both 50 ms and + * 500 ms, so do the longer, just in case. + */ + TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_RESET ); + +} /* TLan_PhyPowerUp */ + +void TLan_PhyReset( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + u16 phy; + u16 value; + + phy = priv->phy[priv->phyNum]; + + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Reseting PHY.\n", dev->name ); + TLan_MiiSync( dev->base_addr ); + value = MII_GC_LOOPBK | MII_GC_RESET; + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, value ); + TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value ); + while ( value & MII_GC_RESET ) { + TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value ); + } + + /* Wait for 500 ms and initialize. + * I don't remember why I wait this long. + * I've changed this to 50ms, as it seems long enough. + */ + TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_START_LINK ); + +} /* TLan_PhyReset */ + +void TLan_PhyStartLink( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + u16 ability; + u16 control; + u16 data; + u16 phy; + u16 status; + u16 tctl; + + phy = priv->phy[priv->phyNum]; + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Trying to activate link.\n", dev->name ); + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &ability ); + + if ( ( status & MII_GS_AUTONEG ) && + ( ! priv->aui ) ) { + ability = status >> 11; + if ( priv->speed == TLAN_SPEED_10 && + priv->duplex == TLAN_DUPLEX_HALF) { + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000); + } else if ( priv->speed == TLAN_SPEED_10 && + priv->duplex == TLAN_DUPLEX_FULL) { + priv->tlanFullDuplex = TRUE; + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100); + } else if ( priv->speed == TLAN_SPEED_100 && + priv->duplex == TLAN_DUPLEX_HALF) { + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000); + } else if ( priv->speed == TLAN_SPEED_100 && + priv->duplex == TLAN_DUPLEX_FULL) { + priv->tlanFullDuplex = TRUE; + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100); + } else { + + /* Set Auto-Neg advertisement */ + TLan_MiiWriteReg( dev, phy, MII_AN_ADV, (ability << 5) | 1); + /* Enablee Auto-Neg */ + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 ); + /* Restart Auto-Neg */ + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 ); + /* Wait for 4 sec for autonegotiation + * to complete. The max spec time is less than this + * but the card need additional time to start AN. + * .5 sec should be plenty extra. + */ + printk( "TLAN: %s: Starting autonegotiation.\n", dev->name ); + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN ); + return; + } + + } + + if ( ( priv->aui ) && ( priv->phyNum != 0 ) ) { + priv->phyNum = 0; + data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; + TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data ); + TLan_SetTimer( dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN ); + return; + } else if ( priv->phyNum == 0 ) { + TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl ); + if ( priv->aui ) { + tctl |= TLAN_TC_AUISEL; + } else { + tctl &= ~TLAN_TC_AUISEL; + control = 0; + if ( priv->duplex == TLAN_DUPLEX_FULL ) { + control |= MII_GC_DUPLEX; + priv->tlanFullDuplex = TRUE; + } + if ( priv->speed == TLAN_SPEED_100 ) { + control |= MII_GC_SPEEDSEL; + } + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, control ); + } + TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tctl ); + } + + /* Wait for 2 sec to give the tranceiver time + * to establish link. + */ + TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_FINISH_RESET ); + +} /* TLan_PhyStartLink */ + +void TLan_PhyFinishAutoNeg( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + u16 an_adv; + u16 an_lpa; + u16 data; + u16 mode; + u16 phy; + u16 status; + + phy = priv->phy[priv->phyNum]; + + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); + udelay( 1000 ); + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); + + if ( ! ( status & MII_GS_AUTOCMPLT ) ) { + /* Wait for 8 sec to give the process + * more time. Perhaps we should fail after a while. + */ + if (!priv->neg_be_verbose++) { + printk(KERN_INFO "TLAN: Giving autonegotiation more time.\n"); + printk(KERN_INFO "TLAN: Please check that your adapter has\n"); + printk(KERN_INFO "TLAN: been properly connected to a HUB or Switch.\n"); + printk(KERN_INFO "TLAN: Trying to establish link in the background...\n"); + } + TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN ); + return; + } + + printk( "TLAN: %s: Autonegotiation complete.\n", dev->name ); + TLan_MiiReadReg( dev, phy, MII_AN_ADV, &an_adv ); + TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa ); + mode = an_adv & an_lpa & 0x03E0; + if ( mode & 0x0100 ) { + priv->tlanFullDuplex = TRUE; + } else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) { + priv->tlanFullDuplex = TRUE; + } + + if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) { + priv->phyNum = 0; + data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; + TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data ); + TLan_SetTimer( dev, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN ); + return; + } + + if ( priv->phyNum == 0 ) { + if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || ( an_adv & an_lpa & 0x0040 ) ) { + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB | MII_GC_DUPLEX ); + printk( "TLAN: Starting internal PHY with FULL-DUPLEX\n" ); + } else { + TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB ); + printk( "TLAN: Starting internal PHY with HALF-DUPLEX\n" ); + } + } + + /* Wait for 100 ms. No reason in partiticular. + */ + TLan_SetTimer( dev, (HZ/10), TLAN_TIMER_FINISH_RESET ); + +} /* TLan_PhyFinishAutoNeg */ + +#ifdef MONITOR + + /********************************************************************* + * + * TLan_phyMonitor + * + * Returns: + * None + * + * Params: + * dev The device structure of this device. + * + * + * This function monitors PHY condition by reading the status + * register via the MII bus. This can be used to give info + * about link changes (up/down), and possible switch to alternate + * media. + * + * ******************************************************************/ + +void TLan_PhyMonitor( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + u16 phy; + u16 phy_status; + + phy = priv->phy[priv->phyNum]; + + /* Get PHY status register */ + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &phy_status ); + + /* Check if link has been lost */ + if (!(phy_status & MII_GS_LINK)) { + if (priv->link) { + priv->link = 0; + printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name); + dev->flags &= ~IFF_RUNNING; + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + return; + } + } + + /* Link restablished? */ + if ((phy_status & MII_GS_LINK) && !priv->link) { + priv->link = 1; + printk(KERN_DEBUG "TLAN: %s has reestablished link\n", dev->name); + dev->flags |= IFF_RUNNING; + } + + /* Setup a new monitor */ + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); +} + +#endif /* MONITOR */ + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver MII Routines + + These routines are based on the information in Chap. 2 of the + "ThunderLAN Programmer's Guide", pp. 15-24. + +****************************************************************************** +*****************************************************************************/ + + /*************************************************************** + * TLan_MiiReadReg + * + * Returns: + * 0 if ack received ok + * 1 otherwise. + * + * Parms: + * dev The device structure containing + * The io address and interrupt count + * for this device. + * phy The address of the PHY to be queried. + * reg The register whose contents are to be + * retreived. + * val A pointer to a variable to store the + * retrieved value. + * + * This function uses the TLAN's MII bus to retreive the contents + * of a given register on a PHY. It sends the appropriate info + * and then reads the 16-bit register value from the MII bus via + * the TLAN SIO register. + * + **************************************************************/ + +int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val ) +{ + u8 nack; + u16 sio, tmp; + u32 i; + int err; + int minten; + TLanPrivateInfo *priv = dev->priv; + unsigned long flags = 0; + + err = FALSE; + outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); + sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; + + if (!in_irq()) + spin_lock_irqsave(&priv->lock, flags); + + TLan_MiiSync(dev->base_addr); + + minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio ); + if ( minten ) + TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio); + + TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Start ( 01b ) */ + TLan_MiiSendData( dev->base_addr, 0x2, 2 ); /* Read ( 10b ) */ + TLan_MiiSendData( dev->base_addr, phy, 5 ); /* Device # */ + TLan_MiiSendData( dev->base_addr, reg, 5 ); /* Register # */ + + TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio); /* Change direction */ + + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Clock Idle bit */ + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Wait 300ns */ + + nack = TLan_GetBit(TLAN_NET_SIO_MDATA, sio); /* Check for ACK */ + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); /* Finish ACK */ + if (nack) { /* No ACK, so fake it */ + for (i = 0; i < 16; i++) { + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + } + tmp = 0xffff; + err = TRUE; + } else { /* ACK, so read data */ + for (tmp = 0, i = 0x8000; i; i >>= 1) { + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); + if (TLan_GetBit(TLAN_NET_SIO_MDATA, sio)) + tmp |= i; + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + } + } + + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Idle cycle */ + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + + if ( minten ) + TLan_SetBit(TLAN_NET_SIO_MINTEN, sio); + + *val = tmp; + + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); + + return err; + +} /* TLan_MiiReadReg */ + + /*************************************************************** + * TLan_MiiSendData + * + * Returns: + * Nothing + * Parms: + * base_port The base IO port of the adapter in + * question. + * dev The address of the PHY to be queried. + * data The value to be placed on the MII bus. + * num_bits The number of bits in data that are to + * be placed on the MII bus. + * + * This function sends on sequence of bits on the MII + * configuration bus. + * + **************************************************************/ + +void TLan_MiiSendData( u16 base_port, u32 data, unsigned num_bits ) +{ + u16 sio; + u32 i; + + if ( num_bits == 0 ) + return; + + outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); + sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; + TLan_SetBit( TLAN_NET_SIO_MTXEN, sio ); + + for ( i = ( 0x1 << ( num_bits - 1 ) ); i; i >>= 1 ) { + TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); + (void) TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); + if ( data & i ) + TLan_SetBit( TLAN_NET_SIO_MDATA, sio ); + else + TLan_ClearBit( TLAN_NET_SIO_MDATA, sio ); + TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + (void) TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); + } + +} /* TLan_MiiSendData */ + + /*************************************************************** + * TLan_MiiSync + * + * Returns: + * Nothing + * Parms: + * base_port The base IO port of the adapter in + * question. + * + * This functions syncs all PHYs in terms of the MII configuration + * bus. + * + **************************************************************/ + +void TLan_MiiSync( u16 base_port ) +{ + int i; + u16 sio; + + outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); + sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; + + TLan_ClearBit( TLAN_NET_SIO_MTXEN, sio ); + for ( i = 0; i < 32; i++ ) { + TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); + TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + } + +} /* TLan_MiiSync */ + + /*************************************************************** + * TLan_MiiWriteReg + * + * Returns: + * Nothing + * Parms: + * dev The device structure for the device + * to write to. + * phy The address of the PHY to be written to. + * reg The register whose contents are to be + * written. + * val The value to be written to the register. + * + * This function uses the TLAN's MII bus to write the contents of a + * given register on a PHY. It sends the appropriate info and then + * writes the 16-bit register value from the MII configuration bus + * via the TLAN SIO register. + * + **************************************************************/ + +void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val ) +{ + u16 sio; + int minten; + unsigned long flags = 0; + TLanPrivateInfo *priv = dev->priv; + + outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); + sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; + + if (!in_irq()) + spin_lock_irqsave(&priv->lock, flags); + + TLan_MiiSync( dev->base_addr ); + + minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio ); + if ( minten ) + TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio ); + + TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Start ( 01b ) */ + TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Write ( 01b ) */ + TLan_MiiSendData( dev->base_addr, phy, 5 ); /* Device # */ + TLan_MiiSendData( dev->base_addr, reg, 5 ); /* Register # */ + + TLan_MiiSendData( dev->base_addr, 0x2, 2 ); /* Send ACK */ + TLan_MiiSendData( dev->base_addr, val, 16 ); /* Send Data */ + + TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); /* Idle cycle */ + TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + + if ( minten ) + TLan_SetBit( TLAN_NET_SIO_MINTEN, sio ); + + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); + +} /* TLan_MiiWriteReg */ +#endif + +/************************************************************************** +RESET - Reset adapter +***************************************************************************/ +static void skel_reset(struct nic *nic) +{ + /* put the card in its initial state */ +} + +/************************************************************************** +POLL - Wait for a frame +***************************************************************************/ +static int skel_poll(struct nic *nic) +{ + /* return true if there's an ethernet packet ready to read */ + /* nic->packet should contain data on return */ + /* nic->packetlen should contain length of data */ + return (0); /* initially as this is called to flush the input */ +} + +/************************************************************************** +TRANSMIT - Transmit a frame +***************************************************************************/ +static void skel_transmit( + struct nic *nic, + const char *d, /* Destination */ + unsigned int t, /* Type */ + unsigned int s, /* size */ + const char *p) /* Packet */ +{ + /* send the packet to destination */ +} + +/************************************************************************** +DISABLE - Turn off ethernet interface +***************************************************************************/ +static void skel_disable(struct nic *nic) +{ +} + +/************************************************************************** +PROBE - Look for an adapter, this routine's visible to the outside +You should omit the last argument struct pci_device * for a non-PCI NIC +***************************************************************************/ +struct nic *tlan_probe(struct nic *nic, unsigned short *probe_addrs, + struct pci_device *p) +{ + /* if probe_addrs is 0, then routine can use a hardwired default */ + /* if board found */ + { + /* point to NIC specific routines */ + nic->reset = skel_reset; + nic->poll = skel_poll; + nic->transmit = skel_transmit; + nic->disable = skel_disable; + return nic; + } + /* else */ + return 0; +} + +#if 0 +#ifndef TLAN_H +#define TLAN_H +/******************************************************************** + * + * Linux ThunderLAN Driver + * + * tlan.h + * by James Banks + * + * (C) 1997-1998 Caldera, Inc. + * (C) 1999-2001 Torben Mathiasen + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + ** This file is best viewed/edited with tabstop=4, colums>=132 + * + * + * Dec 10, 1999 Torben Mathiasen + * New Maintainer + * + ********************************************************************/ + +#include +#include +#include + +#define FALSE 0 +#define TRUE 1 + +#define TX_TIMEOUT (10*HZ) /* We need time for auto-neg */ + +typedef struct tlan_adapter_entry { + u16 vendorId; + u16 deviceId; + char *deviceLabel; + u32 flags; + u16 addrOfs; +} TLanAdapterEntry; + + /***************************************************************** + * EISA Definitions + * + ****************************************************************/ + +#define EISA_ID 0xc80 /* EISA ID Registers */ +#define EISA_ID0 0xc80 /* EISA ID Register 0 */ +#define EISA_ID1 0xc81 /* EISA ID Register 1 */ +#define EISA_ID2 0xc82 /* EISA ID Register 2 */ +#define EISA_ID3 0xc83 /* EISA ID Register 3 */ +#define EISA_CR 0xc84 /* EISA Control Register */ +#define EISA_REG0 0xc88 /* EISA Configuration Register 0 */ +#define EISA_REG1 0xc89 /* EISA Configuration Register 1 */ +#define EISA_REG2 0xc8a /* EISA Configuration Register 2 */ +#define EISA_REG3 0xc8f /* EISA Configuration Register 3 */ +#define EISA_APROM 0xc90 /* Ethernet Address PROM */ + + /***************************************************************** + * Rx/Tx List Definitions + * + ****************************************************************/ + +typedef struct tlan_buffer_ref_tag { + u32 count; + u32 address; +} TLanBufferRef; + +typedef struct tlan_list_tag { + u32 forward; + u16 cStat; + u16 frameSize; + TLanBufferRef buffer[TLAN_BUFFERS_PER_LIST]; +} TLanList; + +typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE]; + + /***************************************************************** + * TLAN Private Information Structure + * + ****************************************************************/ + +typedef struct tlan_private_tag { + struct net_device *nextDevice; + void *dmaStorage; + u8 *padBuffer; + TLanList *rxList; + u8 *rxBuffer; + u32 rxHead; + u32 rxTail; + u32 rxEocCount; + TLanList *txList; + u8 *txBuffer; + u32 txHead; + u32 txInProgress; + u32 txTail; + u32 txBusyCount; + u32 phyOnline; + u32 timerSetAt; + u32 timerType; + struct timer_list timer; + struct net_device_stats stats; + struct board *adapter; + u32 adapterRev; + u32 aui; + u32 debug; + u32 duplex; + u32 phy[2]; + u32 phyNum; + u32 speed; + u8 tlanRev; + u8 tlanFullDuplex; + char devName[8]; + spinlock_t lock; + u8 link; + u8 is_eisa; + struct tq_struct tlan_tqueue; + u8 neg_be_verbose; +} TLanPrivateInfo; + +#define TLAN_HC_GO 0x80000000 +#define TLAN_HC_STOP 0x40000000 +#define TLAN_HC_ACK 0x20000000 +#define TLAN_HC_CS_MASK 0x1FE00000 +#define TLAN_HC_EOC 0x00100000 +#define TLAN_HC_RT 0x00080000 +#define TLAN_HC_NES 0x00040000 +#define TLAN_HC_AD_RST 0x00008000 +#define TLAN_HC_LD_TMR 0x00004000 +#define TLAN_HC_LD_THR 0x00002000 +#define TLAN_HC_REQ_INT 0x00001000 +#define TLAN_HC_INT_OFF 0x00000800 +#define TLAN_HC_INT_ON 0x00000400 +#define TLAN_HC_AC_MASK 0x000000FF +#define TLAN_DA_ADR_INC 0x8000 +#define TLAN_DA_RAM_ADR 0x4000 +#define TLAN_HI_IV_MASK 0x1FE0 +#define TLAN_HI_IT_MASK 0x001C + +#define TLAN_NET_CMD_NRESET 0x80 +#define TLAN_NET_CMD_NWRAP 0x40 +#define TLAN_NET_CMD_CSF 0x20 +#define TLAN_NET_CMD_CAF 0x10 +#define TLAN_NET_CMD_NOBRX 0x08 +#define TLAN_NET_CMD_DUPLEX 0x04 +#define TLAN_NET_CMD_TRFRAM 0x02 +#define TLAN_NET_CMD_TXPACE 0x01 +#define TLAN_NET_SIO_MINTEN 0x80 +#define TLAN_NET_SIO_ECLOK 0x40 +#define TLAN_NET_SIO_ETXEN 0x20 +#define TLAN_NET_SIO_EDATA 0x10 +#define TLAN_NET_SIO_NMRST 0x08 +#define TLAN_NET_SIO_MCLK 0x04 +#define TLAN_NET_SIO_MTXEN 0x02 +#define TLAN_NET_SIO_MDATA 0x01 +#define TLAN_NET_STS_MIRQ 0x80 +#define TLAN_NET_STS_HBEAT 0x40 +#define TLAN_NET_STS_TXSTOP 0x20 +#define TLAN_NET_STS_RXSTOP 0x10 +#define TLAN_NET_STS_RSRVD 0x0F +#define TLAN_NET_MASK_MASK7 0x80 +#define TLAN_NET_MASK_MASK6 0x40 +#define TLAN_NET_MASK_MASK5 0x20 +#define TLAN_NET_MASK_MASK4 0x10 +#define TLAN_NET_MASK_RSRVD 0x0F +#define TLAN_NET_CFG_RCLK 0x8000 +#define TLAN_NET_CFG_TCLK 0x4000 +#define TLAN_NET_CFG_BIT 0x2000 +#define TLAN_NET_CFG_RXCRC 0x1000 +#define TLAN_NET_CFG_PEF 0x0800 +#define TLAN_NET_CFG_1FRAG 0x0400 +#define TLAN_NET_CFG_1CHAN 0x0200 +#define TLAN_NET_CFG_MTEST 0x0100 +#define TLAN_NET_CFG_PHY_EN 0x0080 +#define TLAN_NET_CFG_MSMASK 0x007F +#define TLAN_LED_ACT 0x10 +#define TLAN_LED_LINK 0x01 +#define TLAN_ID_TX_EOC 0x04 +#define TLAN_ID_RX_EOF 0x02 +#define TLAN_ID_RX_EOC 0x01 + +#define CIRC_INC( a, b ) if ( ++a >= b ) a = 0 + +#ifdef I_LIKE_A_FAST_HASH_FUNCTION +/* given 6 bytes, view them as 8 6-bit numbers and return the XOR of those */ +/* the code below is about seven times as fast as the original code */ +inline u32 TLan_HashFunc( u8 *a ) +{ + u8 hash; + + hash = (a[0]^a[3]); /* & 077 */ + hash ^= ((a[0]^a[3])>>6); /* & 003 */ + hash ^= ((a[1]^a[4])<<2); /* & 074 */ + hash ^= ((a[1]^a[4])>>4); /* & 017 */ + hash ^= ((a[2]^a[5])<<4); /* & 060 */ + hash ^= ((a[2]^a[5])>>2); /* & 077 */ + + return (hash & 077); +} + +#else /* original code */ + +inline u32 xor( u32 a, u32 b ) +{ + return ( ( a && ! b ) || ( ! a && b ) ); +} +#define XOR8( a, b, c, d, e, f, g, h ) xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) ) +#define DA( a, bit ) ( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) ) + +inline u32 TLan_HashFunc( u8 *a ) +{ + u32 hash; + + hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,36), DA(a,42) ); + hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,37), DA(a,43) ) << 1; + hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,38), DA(a,44) ) << 2; + hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,39), DA(a,45) ) << 3; + hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,40), DA(a,46) ) << 4; + hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,41), DA(a,47) ) << 5; + + return hash; + +} + +#endif /* I_LIKE_A_FAST_HASH_FUNCTION */ +#endif +/******************************************************************************* + * + * Linux ThunderLAN Driver + * + * tlan.c + * by James Banks + * + * (C) 1997-1998 Caldera, Inc. + * (C) 1998 James Banks + * (C) 1999-2001 Torben Mathiasen + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + ** This file is best viewed/edited with columns>=132. + * + ** Useful (if not required) reading: + * + * Texas Instruments, ThunderLAN Programmer's Guide, + * TI Literature Number SPWU013A + * available in PDF format from www.ti.com + * Level One, LXT901 and LXT970 Data Sheets + * available in PDF format from www.level1.com + * National Semiconductor, DP83840A Data Sheet + * available in PDF format from www.national.com + * Microchip Technology, 24C01A/02A/04A Data Sheet + * available in PDF format from www.microchip.com + * + * Change History + * + * Tigran Aivazian : TLan_PciProbe() now uses + * new PCI BIOS interface. + * Alan Cox : Fixed the out of memory + * handling. + * + * Torben Mathiasen New Maintainer! + * + * v1.1 Dec 20, 1999 - Removed linux version checking + * Patch from Tigran Aivazian. + * - v1.1 includes Alan's SMP updates. + * - We still have problems on SMP though, + * but I'm looking into that. + * + * v1.2 Jan 02, 2000 - Hopefully fixed the SMP deadlock. + * - Removed dependency of HZ being 100. + * - We now allow higher priority timers to + * overwrite timers like TLAN_TIMER_ACTIVITY + * Patch from John Cagle . + * - Fixed a few compiler warnings. + * + * v1.3 Feb 04, 2000 - Fixed the remaining HZ issues. + * - Removed call to pci_present(). + * - Removed SA_INTERRUPT flag from irq handler. + * - Added __init and __initdata to reduce resisdent + * code size. + * - Driver now uses module_init/module_exit. + * - Rewrote init_module and tlan_probe to + * share a lot more code. We now use tlan_probe + * with builtin and module driver. + * - Driver ported to new net API. + * - tlan.txt has been reworked to reflect current + * driver (almost) + * - Other minor stuff + * + * v1.4 Feb 10, 2000 - Updated with more changes required after Dave's + * network cleanup in 2.3.43pre7 (Tigran & myself) + * - Minor stuff. + * + * v1.5 March 22, 2000 - Fixed another timer bug that would hang the driver + * if no cable/link were present. + * - Cosmetic changes. + * - TODO: Port completely to new PCI/DMA API + * Auto-Neg fallback. + * + * v1.6 April 04, 2000 - Fixed driver support for kernel-parameters. Haven't + * tested it though, as the kernel support is currently + * broken (2.3.99p4p3). + * - Updated tlan.txt accordingly. + * - Adjusted minimum/maximum frame length. + * - There is now a TLAN website up at + * http://tlan.kernel.dk + * + * v1.7 April 07, 2000 - Started to implement custom ioctls. Driver now + * reports PHY information when used with Donald + * Beckers userspace MII diagnostics utility. + * + * v1.8 April 23, 2000 - Fixed support for forced speed/duplex settings. + * - Added link information to Auto-Neg and forced + * modes. When NIC operates with auto-neg the driver + * will report Link speed & duplex modes as well as + * link partner abilities. When forced link is used, + * the driver will report status of the established + * link. + * Please read tlan.txt for additional information. + * - Removed call to check_region(), and used + * return value of request_region() instead. + * + * v1.8a May 28, 2000 - Minor updates. + * + * v1.9 July 25, 2000 - Fixed a few remaining Full-Duplex issues. + * - Updated with timer fixes from Andrew Morton. + * - Fixed module race in TLan_Open. + * - Added routine to monitor PHY status. + * - Added activity led support for Proliant devices. + * + * v1.10 Aug 30, 2000 - Added support for EISA based tlan controllers + * like the Compaq NetFlex3/E. + * - Rewrote tlan_probe to better handle multiple + * bus probes. Probing and device setup is now + * done through TLan_Probe and TLan_init_one. Actual + * hardware probe is done with kernel API and + * TLan_EisaProbe. + * - Adjusted debug information for probing. + * - Fixed bug that would cause general debug information + * to be printed after driver removal. + * - Added transmit timeout handling. + * - Fixed OOM return values in tlan_probe. + * - Fixed possible mem leak in tlan_exit + * (now tlan_remove_one). + * - Fixed timer bug in TLan_phyMonitor. + * - This driver version is alpha quality, please + * send me any bug issues you may encounter. + * + * v1.11 Aug 31, 2000 - Do not try to register irq 0 if no irq line was + * set for EISA cards. + * - Added support for NetFlex3/E with nibble-rate + * 10Base-T PHY. This is untestet as I haven't got + * one of these cards. + * - Fixed timer being added twice. + * - Disabled PhyMonitoring by default as this is + * work in progress. Define MONITOR to enable it. + * - Now we don't display link info with PHYs that + * doesn't support it (level1). + * - Incresed tx_timeout beacuse of auto-neg. + * - Adjusted timers for forced speeds. + * + * v1.12 Oct 12, 2000 - Minor fixes (memleak, init, etc.) + * + * v1.13 Nov 28, 2000 - Stop flooding console with auto-neg issues + * when link can't be established. + * - Added the bbuf option as a kernel parameter. + * - Fixed ioaddr probe bug. + * - Fixed stupid deadlock with MII interrupts. + * - Added support for speed/duplex selection with + * multiple nics. + * - Added partly fix for TX Channel lockup with + * TLAN v1.0 silicon. This needs to be investigated + * further. + * + * v1.14 Dec 16, 2000 - Added support for servicing multiple frames per. + * interrupt. Thanks goes to + * Adam Keys + * Denis Beaudoin + * for providing the patch. + * - Fixed auto-neg output when using multiple + * adapters. + * - Converted to use new taskq interface. + * + * v1.14a Jan 6, 2001 - Minor adjustments (spinlocks, etc.) + * + *******************************************************************************/ + + +#include + +#include "tlan.h" + +#include +#include +#include +#include +#include +#include +#include + +typedef u32 (TLanIntVectorFunc)( struct net_device *, u16 ); + +/* For removing EISA devices */ +static struct net_device *TLan_Eisa_Devices; + +static int TLanDevicesInstalled; + +/* Set speed, duplex and aui settings */ +static int aui[MAX_TLAN_BOARDS]; +static int duplex[MAX_TLAN_BOARDS]; +static int speed[MAX_TLAN_BOARDS]; +static int boards_found; + +MODULE_AUTHOR("Maintainer: Torben Mathiasen "); +MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(aui, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i"); +MODULE_PARM(duplex, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i"); +MODULE_PARM(speed, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(bbuf, "i"); +MODULE_PARM_DESC(aui, "ThunderLAN use AUI port(s) (0-1)"); +MODULE_PARM_DESC(duplex, "ThunderLAN duplex setting(s) (0-default, 1-half, 2-full)"); +MODULE_PARM_DESC(speed, "ThunderLAN port speen setting(s) (0,10,100)"); +MODULE_PARM_DESC(debug, "ThunderLAN debug mask"); +MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)"); +EXPORT_NO_SYMBOLS; + +/* Define this to enable Link beat monitoring */ +#undef MONITOR + +/* Turn on debugging. See linux/Documentation/networking/tlan.txt for details */ +static int debug; + +static int bbuf; +static u8 *TLanPadBuffer; +static char TLanSignature[] = "TLAN"; +static const char tlan_banner[] = "ThunderLAN driver v1.14a\n"; +static int tlan_have_pci; +static int tlan_have_eisa; + +const char *media[] = { + "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", + "100baseTx-FD", "100baseT4", 0 +}; + +int media_map[] = { 0x0020, 0x0040, 0x0080, 0x0100, 0x0200,}; + +static struct board { + const char *deviceLabel; + u32 flags; + u16 addrOfs; +} board_info[] __devinitdata = { + { "Compaq Netelligent 10 T PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, + { "Compaq Netelligent 10/100 TX PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, + { "Compaq Integrated NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, + { "Compaq NetFlex-3/P", TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, + { "Compaq NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, + { "Compaq Netelligent Integrated 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, + { "Compaq Netelligent Dual 10/100 TX PCI UTP", TLAN_ADAPTER_NONE, 0x83 }, + { "Compaq Netelligent 10/100 TX Embedded UTP", TLAN_ADAPTER_NONE, 0x83 }, + { "Olicom OC-2183/2185", TLAN_ADAPTER_USE_INTERN_10, 0x83 }, + { "Olicom OC-2325", TLAN_ADAPTER_UNMANAGED_PHY, 0xF8 }, + { "Olicom OC-2326", TLAN_ADAPTER_USE_INTERN_10, 0xF8 }, + { "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, + { "Compaq Netelligent 10 T/2 PCI UTP/Coax", TLAN_ADAPTER_NONE, 0x83 }, + { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */ + TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, + { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */ +}; + +static struct pci_device_id tlan_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL10, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETFLEX3I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_THUNDER, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETFLEX3B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100PI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100D, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, + { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2183, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, + { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2325, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, + { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2326, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_T2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, + { 0,} +}; +MODULE_DEVICE_TABLE(pci, tlan_pci_tbl); + +static void TLan_EisaProbe( void ); +static void TLan_Eisa_Cleanup( void ); +static int TLan_Init( struct net_device * ); +static int TLan_Open( struct net_device *dev ); +static int TLan_StartTx( struct sk_buff *, struct net_device *); +static void TLan_HandleInterrupt( int, void *, struct pt_regs *); +static int TLan_Close( struct net_device *); +static struct net_device_stats *TLan_GetStats( struct net_device *); +static void TLan_SetMulticastList( struct net_device *); +static int TLan_ioctl( struct net_device *dev, struct ifreq *rq, int cmd); +static int TLan_probe1( struct pci_dev *pdev, long ioaddr, int irq, int rev, const struct pci_device_id *ent); +static void TLan_tx_timeout( struct net_device *dev); +static int tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent); + +static u32 TLan_HandleInvalid( struct net_device *, u16 ); +static u32 TLan_HandleTxEOF( struct net_device *, u16 ); +static u32 TLan_HandleStatOverflow( struct net_device *, u16 ); +static u32 TLan_HandleRxEOF( struct net_device *, u16 ); +static u32 TLan_HandleDummy( struct net_device *, u16 ); +static u32 TLan_HandleTxEOC( struct net_device *, u16 ); +static u32 TLan_HandleStatusCheck( struct net_device *, u16 ); +static u32 TLan_HandleRxEOC( struct net_device *, u16 ); + +static void TLan_Timer( unsigned long ); + +static void TLan_ResetLists( struct net_device * ); +static void TLan_FreeLists( struct net_device * ); +static void TLan_PrintDio( u16 ); +static void TLan_PrintList( TLanList *, char *, int ); +static void TLan_ReadAndClearStats( struct net_device *, int ); +static void TLan_ResetAdapter( struct net_device * ); +static void TLan_FinishReset( struct net_device * ); +static void TLan_SetMac( struct net_device *, int areg, char *mac ); + +static void TLan_PhyPrint( struct net_device * ); +static void TLan_PhyDetect( struct net_device * ); +static void TLan_PhyPowerDown( struct net_device * ); +static void TLan_PhyPowerUp( struct net_device * ); +static void TLan_PhyReset( struct net_device * ); +static void TLan_PhyStartLink( struct net_device * ); +static void TLan_PhyFinishAutoNeg( struct net_device * ); +#ifdef MONITOR +static void TLan_PhyMonitor( struct net_device * ); +#endif + +/* +static int TLan_PhyNop( struct net_device * ); +static int TLan_PhyInternalCheck( struct net_device * ); +static int TLan_PhyInternalService( struct net_device * ); +static int TLan_PhyDp83840aCheck( struct net_device * ); +*/ + +static int TLan_MiiReadReg( struct net_device *, u16, u16, u16 * ); +static void TLan_MiiSendData( u16, u32, unsigned ); +static void TLan_MiiSync( u16 ); +static void TLan_MiiWriteReg( struct net_device *, u16, u16, u16 ); + +static void TLan_EeSendStart( u16 ); +static int TLan_EeSendByte( u16, u8, int ); +static void TLan_EeReceiveByte( u16, u8 *, int ); +static int TLan_EeReadByte( struct net_device *, u8, u8 * ); + +static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = { + TLan_HandleInvalid, + TLan_HandleTxEOF, + TLan_HandleStatOverflow, + TLan_HandleRxEOF, + TLan_HandleDummy, + TLan_HandleTxEOC, + TLan_HandleStatusCheck, + TLan_HandleRxEOC +}; + +static inline void +TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type ) +{ + TLanPrivateInfo *priv = dev->priv; + unsigned long flags = 0; + + if (!in_irq()) + spin_lock_irqsave(&priv->lock, flags); + if ( priv->timer.function != NULL && + priv->timerType != TLAN_TIMER_ACTIVITY ) { + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + priv->timer.function = &TLan_Timer; + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); + + priv->timer.data = (unsigned long) dev; + priv->timerSetAt = jiffies; + priv->timerType = type; + mod_timer(&priv->timer, jiffies + ticks); + +} /* TLan_SetTimer */ + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver Primary Functions + + These functions are more or less common to all Linux network drivers. + +****************************************************************************** +*****************************************************************************/ + + /*************************************************************** + * tlan_remove_one + * + * Returns: + * Nothing + * Parms: + * None + * + * Goes through the TLanDevices list and frees the device + * structs and memory associated with each device (lists + * and buffers). It also ureserves the IO port regions + * associated with this device. + * + **************************************************************/ + +static void __devexit tlan_remove_one( struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata( pdev ); + TLanPrivateInfo *priv = dev->priv; + + unregister_netdev( dev ); + + if ( priv->dmaStorage ) { + kfree( priv->dmaStorage ); + } + + release_region( dev->base_addr, 0x10 ); + + kfree( dev ); + + pci_set_drvdata( pdev, NULL ); +} + +static struct pci_driver tlan_driver = { + name: "tlan", + id_table: tlan_pci_tbl, + probe: tlan_init_one, + remove: tlan_remove_one, +}; + +static int __init tlan_probe(void) +{ + static int pad_allocated; + + printk(KERN_INFO "%s", tlan_banner); + + TLanPadBuffer = (u8 *) kmalloc(TLAN_MIN_FRAME_SIZE, + GFP_KERNEL); + + if (TLanPadBuffer == NULL) { + printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n"); + return -ENOMEM; + } + + memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE); + pad_allocated = 1; + + TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n"); + + /* Use new style PCI probing. Now the kernel will + do most of this for us */ + pci_register_driver(&tlan_driver); + + TLAN_DBG(TLAN_DEBUG_PROBE, "Starting EISA Probe....\n"); + TLan_EisaProbe(); + + printk(KERN_INFO "TLAN: %d device%s installed, PCI: %d EISA: %d\n", + TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s", + tlan_have_pci, tlan_have_eisa); + + if (TLanDevicesInstalled == 0) { + pci_unregister_driver(&tlan_driver); + kfree(TLanPadBuffer); + return -ENODEV; + } + return 0; +} + + +static int __devinit tlan_init_one( struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + return TLan_probe1( pdev, -1, -1, 0, ent); +} + +/* + *************************************************************** + * tlan_probe1 + * + * Returns: + * 0 on success, error code on error + * Parms: + * none + * + * The name is lower case to fit in with all the rest of + * the netcard_probe names. This function looks for + * another TLan based adapter, setting it up with the + * allocated device struct if one is found. + * tlan_probe has been ported to the new net API and + * now allocates its own device structure. This function + * is also used by modules. + * + **************************************************************/ + +static int __devinit TLan_probe1(struct pci_dev *pdev, + long ioaddr, int irq, int rev, const struct pci_device_id *ent ) +{ + + struct net_device *dev; + TLanPrivateInfo *priv; + u8 pci_rev; + u16 device_id; + int reg; + + if (pdev && pci_enable_device(pdev)) + return -EIO; + + dev = init_etherdev(NULL, sizeof(TLanPrivateInfo)); + if (dev == NULL) { + printk(KERN_ERR "TLAN: Could not allocate memory for device.\n"); + return -ENOMEM; + } + SET_MODULE_OWNER(dev); + + priv = dev->priv; + + /* Is this a PCI device? */ + if (pdev) { + u32 pci_io_base = 0; + + priv->adapter = &board_info[ent->driver_data]; + + pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev); + + for ( reg= 0; reg <= 5; reg ++ ) { + if (pci_resource_flags(pdev, reg) & IORESOURCE_IO) { + pci_io_base = pci_resource_start(pdev, reg); + TLAN_DBG( TLAN_DEBUG_GNRL, "IO mapping is available at %x.\n", + pci_io_base); + break; + } + } + if (!pci_io_base) { + printk(KERN_ERR "TLAN: No IO mappings available\n"); + unregister_netdev(dev); + kfree(dev); + return -ENODEV; + } + + dev->base_addr = pci_io_base; + dev->irq = pdev->irq; + priv->adapterRev = pci_rev; + pci_set_master(pdev); + pci_set_drvdata(pdev, dev); + + } else { /* EISA card */ + /* This is a hack. We need to know which board structure + * is suited for this adapter */ + device_id = inw(ioaddr + EISA_ID2); + priv->is_eisa = 1; + if (device_id == 0x20F1) { + priv->adapter = &board_info[13]; /* NetFlex-3/E */ + priv->adapterRev = 23; /* TLAN 2.3 */ + } else { + priv->adapter = &board_info[14]; + priv->adapterRev = 10; /* TLAN 1.0 */ + } + dev->base_addr = ioaddr; + dev->irq = irq; + } + + /* Kernel parameters */ + if (dev->mem_start) { + priv->aui = dev->mem_start & 0x01; + priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 : (dev->mem_start & 0x06) >> 1; + priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 : (dev->mem_start & 0x18) >> 3; + + if (priv->speed == 0x1) { + priv->speed = TLAN_SPEED_10; + } else if (priv->speed == 0x2) { + priv->speed = TLAN_SPEED_100; + } + debug = priv->debug = dev->mem_end; + } else { + priv->aui = aui[boards_found]; + priv->speed = speed[boards_found]; + priv->duplex = duplex[boards_found]; + priv->debug = debug; + } + + /* This will be used when we get an adapter error from + * within our irq handler */ + INIT_LIST_HEAD(&priv->tlan_tqueue.list); + priv->tlan_tqueue.sync = 0; + priv->tlan_tqueue.routine = (void *)(void*)TLan_tx_timeout; + priv->tlan_tqueue.data = dev; + + spin_lock_init(&priv->lock); + + if (TLan_Init(dev)) { + printk(KERN_ERR "TLAN: Could not register device.\n"); + unregister_netdev(dev); + kfree(dev); + return -EAGAIN; + } else { + + TLanDevicesInstalled++; + boards_found++; + + /* pdev is NULL if this is an EISA device */ + if (pdev) + tlan_have_pci++; + else { + priv->nextDevice = TLan_Eisa_Devices; + TLan_Eisa_Devices = dev; + tlan_have_eisa++; + } + + printk(KERN_INFO "TLAN: %s irq=%2d, io=%04x, %s, Rev. %d\n", + dev->name, + (int) dev->irq, + (int) dev->base_addr, + priv->adapter->deviceLabel, + priv->adapterRev); + return 0; + } + +} + +static void TLan_Eisa_Cleanup(void) +{ + struct net_device *dev; + TLanPrivateInfo *priv; + + while( tlan_have_eisa ) { + dev = TLan_Eisa_Devices; + priv = dev->priv; + if (priv->dmaStorage) { + kfree(priv->dmaStorage); + } + release_region( dev->base_addr, 0x10); + unregister_netdev( dev ); + TLan_Eisa_Devices = priv->nextDevice; + kfree( dev ); + tlan_have_eisa--; + } +} + + +static void __exit tlan_exit(void) +{ + pci_unregister_driver(&tlan_driver); + + if (tlan_have_eisa) + TLan_Eisa_Cleanup(); + + kfree( TLanPadBuffer ); + +} + +/* Module loading/unloading */ +module_init(tlan_probe); +module_exit(tlan_exit); + + /************************************************************** + * TLan_EisaProbe + * + * Returns: 0 on success, 1 otherwise + * + * Parms: None + * + * + * This functions probes for EISA devices and calls + * TLan_probe1 when one is found. + * + *************************************************************/ + +static void __init TLan_EisaProbe (void) +{ + long ioaddr; + int rc = -ENODEV; + int irq; + u16 device_id; + + if (!EISA_bus) { + TLAN_DBG(TLAN_DEBUG_PROBE, "No EISA bus present\n"); + return; + } + + /* Loop through all slots of the EISA bus */ + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { + + TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID)); + TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2)); + + TLAN_DBG(TLAN_DEBUG_PROBE, "Probing for EISA adapter at IO: 0x%4x : ", + (int) ioaddr); + if (request_region(ioaddr, 0x10, TLanSignature) == NULL) + goto out; + + if (inw(ioaddr + EISA_ID) != 0x110E) { + release_region(ioaddr, 0x10); + goto out; + } + + device_id = inw(ioaddr + EISA_ID2); + if (device_id != 0x20F1 && device_id != 0x40F1) { + release_region (ioaddr, 0x10); + goto out; + } + + if (inb(ioaddr + EISA_CR) != 0x1) { /* Check if adapter is enabled */ + release_region (ioaddr, 0x10); + goto out2; + } + + if (debug == 0x10) + printk("Found one\n"); + + /* Get irq from board */ + switch (inb(ioaddr + 0xCC0)) { + case(0x10): + irq=5; + break; + case(0x20): + irq=9; + break; + case(0x40): + irq=10; + break; + case(0x80): + irq=11; + break; + default: + goto out; + } + + + /* Setup the newly found eisa adapter */ + rc = TLan_probe1( NULL, ioaddr, irq, + 12, NULL); + continue; + + out: + if (debug == 0x10) + printk("None found\n"); + continue; + + out2: if (debug == 0x10) + printk("Card found but it is not enabled, skipping\n"); + continue; + + } + +} /* TLan_EisaProbe */ + + + + /*************************************************************** + * TLan_Init + * + * Returns: + * 0 on success, error code otherwise. + * Parms: + * dev The structure of the device to be + * init'ed. + * + * This function completes the initialization of the + * device structure and driver. It reserves the IO + * addresses, allocates memory for the lists and bounce + * buffers, retrieves the MAC address from the eeprom + * and assignes the device's methods. + * + **************************************************************/ + +static int TLan_Init( struct net_device *dev ) +{ + int dma_size; + int err; + int i; + TLanPrivateInfo *priv; + + priv = dev->priv; + + if (!priv->is_eisa) /* EISA devices have already requested IO */ + if (!request_region( dev->base_addr, 0x10, TLanSignature )) { + printk(KERN_ERR "TLAN: %s: IO port region 0x%lx size 0x%x in use.\n", + dev->name, + dev->base_addr, + 0x10 ); + return -EIO; + } + + if ( bbuf ) { + dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) + * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE ); + } else { + dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) + * ( sizeof(TLanList) ); + } + priv->dmaStorage = kmalloc(dma_size, GFP_KERNEL | GFP_DMA); + if ( priv->dmaStorage == NULL ) { + printk(KERN_ERR "TLAN: Could not allocate lists and buffers for %s.\n", + dev->name ); + release_region( dev->base_addr, 0x10 ); + return -ENOMEM; + } + memset( priv->dmaStorage, 0, dma_size ); + priv->rxList = (TLanList *) + ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 ); + priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; + if ( bbuf ) { + priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); + priv->txBuffer = priv->rxBuffer + + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); + } + + err = 0; + for ( i = 0; i < 6 ; i++ ) + err |= TLan_EeReadByte( dev, + (u8) priv->adapter->addrOfs + i, + (u8 *) &dev->dev_addr[i] ); + if ( err ) { + printk(KERN_ERR "TLAN: %s: Error reading MAC from eeprom: %d\n", + dev->name, + err ); + } + dev->addr_len = 6; + + /* Device methods */ + dev->open = &TLan_Open; + dev->hard_start_xmit = &TLan_StartTx; + dev->stop = &TLan_Close; + dev->get_stats = &TLan_GetStats; + dev->set_multicast_list = &TLan_SetMulticastList; + dev->do_ioctl = &TLan_ioctl; + dev->tx_timeout = &TLan_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + return 0; + +} /* TLan_Init */ + + /*************************************************************** + * TLan_Open + * + * Returns: + * 0 on success, error code otherwise. + * Parms: + * dev Structure of device to be opened. + * + * This routine puts the driver and TLAN adapter in a + * state where it is ready to send and receive packets. + * It allocates the IRQ, resets and brings the adapter + * out of reset, and allows interrupts. It also delays + * the startup for autonegotiation or sends a Rx GO + * command to the adapter, as appropriate. + * + **************************************************************/ + +static int TLan_Open( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + int err; + + priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); + err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev ); + + if ( err ) { + printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); + return err; + } + + init_timer(&priv->timer); + netif_start_queue(dev); + + /* NOTE: It might not be necessary to read the stats before a + reset if you don't care what the values are. + */ + TLan_ResetLists( dev ); + TLan_ReadAndClearStats( dev, TLAN_IGNORE ); + TLan_ResetAdapter( dev ); + + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", dev->name, priv->tlanRev ); + + return 0; + +} /* TLan_Open */ + + /************************************************************** + * TLan_ioctl + * + * Returns: + * 0 on success, error code otherwise + * Params: + * dev structure of device to receive ioctl. + * + * rq ifreq structure to hold userspace data. + * + * cmd ioctl command. + * + * + *************************************************************/ + +static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + TLanPrivateInfo *priv = dev->priv; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; + u32 phy = priv->phy[priv->phyNum]; + + if (!priv->phyOnline) + return -EAGAIN; + + switch(cmd) { + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = phy; + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + TLan_MiiReadReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, &data->val_out); + return 0; + + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + TLan_MiiWriteReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); + return 0; + default: + return -EOPNOTSUPP; + } +} /* tlan_ioctl */ + + /*************************************************************** + * TLan_tx_timeout + * + * Returns: nothing + * + * Params: + * dev structure of device which timed out + * during transmit. + * + **************************************************************/ + +static void TLan_tx_timeout(struct net_device *dev) +{ + + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name); + + /* Ok so we timed out, lets see what we can do about it...*/ + TLan_FreeLists( dev ); + TLan_ResetLists( dev ); + TLan_ReadAndClearStats( dev, TLAN_IGNORE ); + TLan_ResetAdapter( dev ); + dev->trans_start = jiffies; + netif_wake_queue( dev ); + +} + + + /*************************************************************** + * TLan_StartTx + * + * Returns: + * 0 on success, non-zero on failure. + * Parms: + * skb A pointer to the sk_buff containing the + * frame to be sent. + * dev The device to send the data on. + * + * This function adds a frame to the Tx list to be sent + * ASAP. First it verifies that the adapter is ready and + * there is room in the queue. Then it sets up the next + * available list, copies the frame to the corresponding + * buffer. If the adapter Tx channel is idle, it gives + * the adapter a Tx Go command on the list, otherwise it + * sets the forward address of the previous list to point + * to this one. Then it frees the sk_buff. + * + **************************************************************/ + +static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + TLanList *tail_list; + u8 *tail_buffer; + int pad; + unsigned long flags; + + if ( ! priv->phyOnline ) { + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", dev->name ); + dev_kfree_skb_any(skb); + return 0; + } + + tail_list = priv->txList + priv->txTail; + + if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); + netif_stop_queue(dev); + priv->txBusyCount++; + return 1; + } + + tail_list->forward = 0; + + if ( bbuf ) { + tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE ); + memcpy( tail_buffer, skb->data, skb->len ); + } else { + tail_list->buffer[0].address = virt_to_bus( skb->data ); + tail_list->buffer[9].address = (u32) skb; + } + + pad = TLAN_MIN_FRAME_SIZE - skb->len; + + if ( pad > 0 ) { + tail_list->frameSize = (u16) skb->len + pad; + tail_list->buffer[0].count = (u32) skb->len; + tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad; + tail_list->buffer[1].address = virt_to_bus( TLanPadBuffer ); + } else { + tail_list->frameSize = (u16) skb->len; + tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len; + tail_list->buffer[1].count = 0; + tail_list->buffer[1].address = 0; + } + + spin_lock_irqsave(&priv->lock, flags); + tail_list->cStat = TLAN_CSTAT_READY; + if ( ! priv->txInProgress ) { + priv->txInProgress = 1; + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); + outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM ); + outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD ); + } else { + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); + if ( priv->txTail == 0 ) { + ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list ); + } else { + ( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list ); + } + } + spin_unlock_irqrestore(&priv->lock, flags); + + CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS ); + + if ( bbuf ) + dev_kfree_skb_any(skb); + + dev->trans_start = jiffies; + return 0; + +} /* TLan_StartTx */ + + /*************************************************************** + * TLan_HandleInterrupt + * + * Returns: + * Nothing + * Parms: + * irq The line on which the interrupt + * occurred. + * dev_id A pointer to the device assigned to + * this irq line. + * regs ??? + * + * This function handles an interrupt generated by its + * assigned TLAN adapter. The function deactivates + * interrupts on its adapter, records the type of + * interrupt, executes the appropriate subhandler, and + * acknowdges the interrupt to the adapter (thus + * re-enabling adapter interrupts. + * + **************************************************************/ + +static void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 ack; + struct net_device *dev; + u32 host_cmd; + u16 host_int; + int type; + TLanPrivateInfo *priv; + + dev = dev_id; + priv = dev->priv; + + spin_lock(&priv->lock); + + host_int = inw( dev->base_addr + TLAN_HOST_INT ); + outw( host_int, dev->base_addr + TLAN_HOST_INT ); + + type = ( host_int & TLAN_HI_IT_MASK ) >> 2; + + ack = TLanIntVector[type]( dev, host_int ); + + if ( ack ) { + host_cmd = TLAN_HC_ACK | ack | ( type << 18 ); + outl( host_cmd, dev->base_addr + TLAN_HOST_CMD ); + } + + spin_unlock(&priv->lock); + +} /* TLan_HandleInterrupts */ + + /*************************************************************** + * TLan_Close + * + * Returns: + * An error code. + * Parms: + * dev The device structure of the device to + * close. + * + * This function shuts down the adapter. It records any + * stats, puts the adapter into reset state, deactivates + * its time as needed, and frees the irq it is using. + * + **************************************************************/ + +static int TLan_Close(struct net_device *dev) +{ + TLanPrivateInfo *priv = dev->priv; + + netif_stop_queue(dev); + priv->neg_be_verbose = 0; + + TLan_ReadAndClearStats( dev, TLAN_RECORD ); + outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); + if ( priv->timer.function != NULL ) { + del_timer_sync( &priv->timer ); + priv->timer.function = NULL; + } + + free_irq( dev->irq, dev ); + TLan_FreeLists( dev ); + TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name ); + + return 0; + +} /* TLan_Close */ + + /*************************************************************** + * TLan_GetStats + * + * Returns: + * A pointer to the device's statistics structure. + * Parms: + * dev The device structure to return the + * stats for. + * + * This function updates the devices statistics by reading + * the TLAN chip's onboard registers. Then it returns the + * address of the statistics structure. + * + **************************************************************/ + +static struct net_device_stats *TLan_GetStats( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + int i; + + /* Should only read stats if open ? */ + TLan_ReadAndClearStats( dev, TLAN_RECORD ); + + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name, priv->rxEocCount ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount ); + if ( debug & TLAN_DEBUG_GNRL ) { + TLan_PrintDio( dev->base_addr ); + TLan_PhyPrint( dev ); + } + if ( debug & TLAN_DEBUG_LIST ) { + for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) + TLan_PrintList( priv->rxList + i, "RX", i ); + for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) + TLan_PrintList( priv->txList + i, "TX", i ); + } + + return ( &( (TLanPrivateInfo *) dev->priv )->stats ); + +} /* TLan_GetStats */ + + /*************************************************************** + * TLan_SetMulticastList + * + * Returns: + * Nothing + * Parms: + * dev The device structure to set the + * multicast list for. + * + * This function sets the TLAN adaptor to various receive + * modes. If the IFF_PROMISC flag is set, promiscuous + * mode is acitviated. Otherwise, promiscuous mode is + * turned off. If the IFF_ALLMULTI flag is set, then + * the hash table is set to receive all group addresses. + * Otherwise, the first three multicast addresses are + * stored in AREG_1-3, and the rest are selected via the + * hash table, as necessary. + * + **************************************************************/ + +static void TLan_SetMulticastList( struct net_device *dev ) +{ + struct dev_mc_list *dmi = dev->mc_list; + u32 hash1 = 0; + u32 hash2 = 0; + int i; + u32 offset; + u8 tmp; + + if ( dev->flags & IFF_PROMISC ) { + tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); + TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF ); + } else { + tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); + TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF ); + if ( dev->flags & IFF_ALLMULTI ) { + for ( i = 0; i < 3; i++ ) + TLan_SetMac( dev, i + 1, NULL ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF ); + } else { + for ( i = 0; i < dev->mc_count; i++ ) { + if ( i < 3 ) { + TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr ); + } else { + offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr ); + if ( offset < 32 ) + hash1 |= ( 1 << offset ); + else + hash2 |= ( 1 << ( offset - 32 ) ); + } + dmi = dmi->next; + } + for ( ; i < 3; i++ ) + TLan_SetMac( dev, i + 1, NULL ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, hash1 ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, hash2 ); + } + } + +} /* TLan_SetMulticastList */ + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver Interrupt Vectors and Table + + Please see Chap. 4, "Interrupt Handling" of the "ThunderLAN + Programmer's Guide" for more informations on handling interrupts + generated by TLAN based adapters. + +****************************************************************************** +*****************************************************************************/ + + /*************************************************************** + * TLan_HandleInvalid + * + * Returns: + * 0 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles invalid interrupts. This should + * never happen unless some other adapter is trying to use + * the IRQ line assigned to the device. + * + **************************************************************/ + +u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int ) +{ + /* printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); */ + return 0; + +} /* TLan_HandleInvalid */ + + /*************************************************************** + * TLan_HandleTxEOF + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles Tx EOF interrupts which are raised + * by the adapter when it has completed sending the + * contents of a buffer. If detemines which list/buffer + * was completed and resets it. If the buffer was the last + * in the channel (EOC), then the function checks to see if + * another buffer is ready to send, and if so, sends a Tx + * Go command. Finally, the driver activates/continues the + * activity LED. + * + **************************************************************/ + +u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) +{ + TLanPrivateInfo *priv = dev->priv; + int eoc = 0; + TLanList *head_list; + u32 ack = 0; + u16 tmpCStat; + + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); + head_list = priv->txList + priv->txHead; + + while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { + ack++; + if ( ! bbuf ) { + dev_kfree_skb_any( (struct sk_buff *) head_list->buffer[9].address ); + head_list->buffer[9].address = 0; + } + + if ( tmpCStat & TLAN_CSTAT_EOC ) + eoc = 1; + + priv->stats.tx_bytes += head_list->frameSize; + + head_list->cStat = TLAN_CSTAT_UNUSED; + netif_start_queue(dev); + CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS ); + head_list = priv->txList + priv->txHead; + } + + if (!ack) + printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n"); + + if ( eoc ) { + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); + head_list = priv->txList + priv->txHead; + if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { + outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + ack |= TLAN_HC_GO; + } else { + priv->txInProgress = 0; + } + } + + if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { + TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); + if ( priv->timer.function == NULL ) { + priv->timer.function = &TLan_Timer; + priv->timer.data = (unsigned long) dev; + priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; + priv->timerSetAt = jiffies; + priv->timerType = TLAN_TIMER_ACTIVITY; + add_timer(&priv->timer); + } else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) { + priv->timerSetAt = jiffies; + } + } + + return ack; + +} /* TLan_HandleTxEOF */ + + /*************************************************************** + * TLan_HandleStatOverflow + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles the Statistics Overflow interrupt + * which means that one or more of the TLAN statistics + * registers has reached 1/2 capacity and needs to be read. + * + **************************************************************/ + +u32 TLan_HandleStatOverflow( struct net_device *dev, u16 host_int ) +{ + TLan_ReadAndClearStats( dev, TLAN_RECORD ); + + return 1; + +} /* TLan_HandleStatOverflow */ + + /*************************************************************** + * TLan_HandleRxEOF + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles the Rx EOF interrupt which + * indicates a frame has been received by the adapter from + * the net and the frame has been transferred to memory. + * The function determines the bounce buffer the frame has + * been loaded into, creates a new sk_buff big enough to + * hold the frame, and sends it to protocol stack. It + * then resets the used buffer and appends it to the end + * of the list. If the frame was the last in the Rx + * channel (EOC), the function restarts the receive channel + * by sending an Rx Go command to the adapter. Then it + * activates/continues the activity LED. + * + **************************************************************/ + +u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) +{ + TLanPrivateInfo *priv = dev->priv; + u32 ack = 0; + int eoc = 0; + u8 *head_buffer; + TLanList *head_list; + struct sk_buff *skb; + TLanList *tail_list; + void *t; + u32 frameSize; + u16 tmpCStat; + + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); + head_list = priv->rxList + priv->rxHead; + + while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { + frameSize = head_list->frameSize; + ack++; + if (tmpCStat & TLAN_CSTAT_EOC) + eoc = 1; + + if (bbuf) { + skb = dev_alloc_skb(frameSize + 7); + if (skb == NULL) + printk(KERN_INFO "TLAN: Couldn't allocate memory for received data.\n"); + else { + head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE); + skb->dev = dev; + skb_reserve(skb, 2); + t = (void *) skb_put(skb, frameSize); + + priv->stats.rx_bytes += head_list->frameSize; + + memcpy( t, head_buffer, frameSize ); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); + } + } else { + struct sk_buff *new_skb; + + /* + * I changed the algorithm here. What we now do + * is allocate the new frame. If this fails we + * simply recycle the frame. + */ + + new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); + + if ( new_skb != NULL ) { + /* If this ever happened it would be a problem */ + /* not any more - ac */ + skb = (struct sk_buff *) head_list->buffer[9].address; + skb_trim( skb, frameSize ); + + priv->stats.rx_bytes += frameSize; + + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); + + new_skb->dev = dev; + skb_reserve( new_skb, 2 ); + t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); + head_list->buffer[0].address = virt_to_bus( t ); + head_list->buffer[8].address = (u32) t; + head_list->buffer[9].address = (u32) new_skb; + } else + printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); + } + + head_list->forward = 0; + head_list->cStat = 0; + tail_list = priv->rxList + priv->rxTail; + tail_list->forward = virt_to_bus( head_list ); + + CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS ); + CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS ); + head_list = priv->rxList + priv->rxHead; + } + + if (!ack) + printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n"); + + + if ( eoc ) { + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); + head_list = priv->rxList + priv->rxHead; + outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + ack |= TLAN_HC_GO | TLAN_HC_RT; + priv->rxEocCount++; + } + + if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { + TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); + if ( priv->timer.function == NULL ) { + priv->timer.function = &TLan_Timer; + priv->timer.data = (unsigned long) dev; + priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; + priv->timerSetAt = jiffies; + priv->timerType = TLAN_TIMER_ACTIVITY; + add_timer(&priv->timer); + } else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) { + priv->timerSetAt = jiffies; + } + } + + dev->last_rx = jiffies; + + return ack; + +} /* TLan_HandleRxEOF */ + + /*************************************************************** + * TLan_HandleDummy + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles the Dummy interrupt, which is + * raised whenever a test interrupt is generated by setting + * the Req_Int bit of HOST_CMD to 1. + * + **************************************************************/ + +u32 TLan_HandleDummy( struct net_device *dev, u16 host_int ) +{ + printk( "TLAN: Test interrupt on %s.\n", dev->name ); + return 1; + +} /* TLan_HandleDummy */ + + /*************************************************************** + * TLan_HandleTxEOC + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This driver is structured to determine EOC occurances by + * reading the CSTAT member of the list structure. Tx EOC + * interrupts are disabled via the DIO INTDIS register. + * However, TLAN chips before revision 3.0 didn't have this + * functionality, so process EOC events if this is the + * case. + * + **************************************************************/ + +u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int ) +{ + TLanPrivateInfo *priv = dev->priv; + TLanList *head_list; + u32 ack = 1; + + host_int = 0; + if ( priv->tlanRev < 0x30 ) { + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail ); + head_list = priv->txList + priv->txHead; + if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { + netif_stop_queue(dev); + outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + ack |= TLAN_HC_GO; + } else { + priv->txInProgress = 0; + } + } + + return ack; + +} /* TLan_HandleTxEOC */ + + /*************************************************************** + * TLan_HandleStatusCheck + * + * Returns: + * 0 if Adapter check, 1 if Network Status check. + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles Adapter Check/Network Status + * interrupts generated by the adapter. It checks the + * vector in the HOST_INT register to determine if it is + * an Adapter Check interrupt. If so, it resets the + * adapter. Otherwise it clears the status registers + * and services the PHY. + * + **************************************************************/ + +u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ) +{ + TLanPrivateInfo *priv = dev->priv; + u32 ack; + u32 error; + u8 net_sts; + u32 phy; + u16 tlphy_ctl; + u16 tlphy_sts; + + ack = 1; + if ( host_int & TLAN_HI_IV_MASK ) { + netif_stop_queue( dev ); + error = inl( dev->base_addr + TLAN_CH_PARM ); + printk( "TLAN: %s: Adaptor Error = 0x%x\n", dev->name, error ); + TLan_ReadAndClearStats( dev, TLAN_RECORD ); + outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); + + queue_task(&priv->tlan_tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + netif_wake_queue(dev); + ack = 0; + } else { + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Status Check\n", dev->name ); + phy = priv->phy[priv->phyNum]; + + net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS ); + if ( net_sts ) { + TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n", dev->name, (unsigned) net_sts ); + } + if ( ( net_sts & TLAN_NET_STS_MIRQ ) && ( priv->phyNum == 0 ) ) { + TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts ); + TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl ); + if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { + tlphy_ctl |= TLAN_TC_SWAPOL; + TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); + } else if ( ( tlphy_sts & TLAN_TS_POLOK ) && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { + tlphy_ctl &= ~TLAN_TC_SWAPOL; + TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); + } + + if (debug) { + TLan_PhyPrint( dev ); + } + } + } + + return ack; + +} /* TLan_HandleStatusCheck */ + + /*************************************************************** + * TLan_HandleRxEOC + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This driver is structured to determine EOC occurances by + * reading the CSTAT member of the list structure. Rx EOC + * interrupts are disabled via the DIO INTDIS register. + * However, TLAN chips before revision 3.0 didn't have this + * CSTAT member or a INTDIS register, so if this chip is + * pre-3.0, process EOC interrupts normally. + * + **************************************************************/ + +u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int ) +{ + TLanPrivateInfo *priv = dev->priv; + TLanList *head_list; + u32 ack = 1; + + if ( priv->tlanRev < 0x30 ) { + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail ); + head_list = priv->rxList + priv->rxHead; + outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + ack |= TLAN_HC_GO | TLAN_HC_RT; + priv->rxEocCount++; + } + + return ack; + +} /* TLan_HandleRxEOC */ + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver Timer Function + +****************************************************************************** +*****************************************************************************/ + + /*************************************************************** + * TLan_Timer + * + * Returns: + * Nothing + * Parms: + * data A value given to add timer when + * add_timer was called. + * + * This function handles timed functionality for the + * TLAN driver. The two current timer uses are for + * delaying for autonegotionation and driving the ACT LED. + * - Autonegotiation requires being allowed about + * 2 1/2 seconds before attempting to transmit a + * packet. It would be a very bad thing to hang + * the kernel this long, so the driver doesn't + * allow transmission 'til after this time, for + * certain PHYs. It would be much nicer if all + * PHYs were interrupt-capable like the internal + * PHY. + * - The ACT LED, which shows adapter activity, is + * driven by the driver, and so must be left on + * for a short period to power up the LED so it + * can be seen. This delay can be changed by + * changing the TLAN_TIMER_ACT_DELAY in tlan.h, + * if desired. 100 ms produces a slightly + * sluggish response. + * + **************************************************************/ + +void TLan_Timer( unsigned long data ) +{ + struct net_device *dev = (struct net_device *) data; + TLanPrivateInfo *priv = dev->priv; + u32 elapsed; + unsigned long flags = 0; + + priv->timer.function = NULL; + + switch ( priv->timerType ) { +#ifdef MONITOR + case TLAN_TIMER_LINK_BEAT: + TLan_PhyMonitor( dev ); + break; +#endif + case TLAN_TIMER_PHY_PDOWN: + TLan_PhyPowerDown( dev ); + break; + case TLAN_TIMER_PHY_PUP: + TLan_PhyPowerUp( dev ); + break; + case TLAN_TIMER_PHY_RESET: + TLan_PhyReset( dev ); + break; + case TLAN_TIMER_PHY_START_LINK: + TLan_PhyStartLink( dev ); + break; + case TLAN_TIMER_PHY_FINISH_AN: + TLan_PhyFinishAutoNeg( dev ); + break; + case TLAN_TIMER_FINISH_RESET: + TLan_FinishReset( dev ); + break; + case TLAN_TIMER_ACTIVITY: + spin_lock_irqsave(&priv->lock, flags); + if ( priv->timer.function == NULL ) { + elapsed = jiffies - priv->timerSetAt; + if ( elapsed >= TLAN_TIMER_ACT_DELAY ) { + TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); + } else { + priv->timer.function = &TLan_Timer; + priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY; + spin_unlock_irqrestore(&priv->lock, flags); + add_timer( &priv->timer ); + break; + } + } + spin_unlock_irqrestore(&priv->lock, flags); + break; + default: + break; + } + +} /* TLan_Timer */ + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver Adapter Related Routines + +****************************************************************************** +*****************************************************************************/ + + /*************************************************************** + * TLan_ResetLists + * + * Returns: + * Nothing + * Parms: + * dev The device structure with the list + * stuctures to be reset. + * + * This routine sets the variables associated with managing + * the TLAN lists to their initial values. + * + **************************************************************/ + +void TLan_ResetLists( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + int i; + TLanList *list; + struct sk_buff *skb; + void *t = NULL; + + priv->txHead = 0; + priv->txTail = 0; + for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { + list = priv->txList + i; + list->cStat = TLAN_CSTAT_UNUSED; + if ( bbuf ) { + list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); + } else { + list->buffer[0].address = 0; + } + list->buffer[2].count = 0; + list->buffer[2].address = 0; + list->buffer[9].address = 0; + } + + priv->rxHead = 0; + priv->rxTail = TLAN_NUM_RX_LISTS - 1; + for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { + list = priv->rxList + i; + list->cStat = TLAN_CSTAT_READY; + list->frameSize = TLAN_MAX_FRAME_SIZE; + list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; + if ( bbuf ) { + list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); + } else { + skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); + if ( skb == NULL ) { + printk( "TLAN: Couldn't allocate memory for received data.\n" ); + /* If this ever happened it would be a problem */ + } else { + skb->dev = dev; + skb_reserve( skb, 2 ); + t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE ); + } + list->buffer[0].address = virt_to_bus( t ); + list->buffer[8].address = (u32) t; + list->buffer[9].address = (u32) skb; + } + list->buffer[1].count = 0; + list->buffer[1].address = 0; + if ( i < TLAN_NUM_RX_LISTS - 1 ) + list->forward = virt_to_bus( list + 1 ); + else + list->forward = 0; + } + +} /* TLan_ResetLists */ + +void TLan_FreeLists( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + int i; + TLanList *list; + struct sk_buff *skb; + + if ( ! bbuf ) { + for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { + list = priv->txList + i; + skb = (struct sk_buff *) list->buffer[9].address; + if ( skb ) { + dev_kfree_skb_any( skb ); + list->buffer[9].address = 0; + } + } + + for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { + list = priv->rxList + i; + skb = (struct sk_buff *) list->buffer[9].address; + if ( skb ) { + dev_kfree_skb_any( skb ); + list->buffer[9].address = 0; + } + } + } + +} /* TLan_FreeLists */ + + /*************************************************************** + * TLan_PrintDio + * + * Returns: + * Nothing + * Parms: + * io_base Base IO port of the device of + * which to print DIO registers. + * + * This function prints out all the internal (DIO) + * registers of a TLAN chip. + * + **************************************************************/ + +void TLan_PrintDio( u16 io_base ) +{ + u32 data0, data1; + int i; + + printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", io_base ); + printk( "TLAN: Off. +0 +4\n" ); + for ( i = 0; i < 0x4C; i+= 8 ) { + data0 = TLan_DioRead32( io_base, i ); + data1 = TLan_DioRead32( io_base, i + 0x4 ); + printk( "TLAN: 0x%02x 0x%08x 0x%08x\n", i, data0, data1 ); + } + +} /* TLan_PrintDio */ + + /*************************************************************** + * TLan_PrintList + * + * Returns: + * Nothing + * Parms: + * list A pointer to the TLanList structure to + * be printed. + * type A string to designate type of list, + * "Rx" or "Tx". + * num The index of the list. + * + * This function prints out the contents of the list + * pointed to by the list parameter. + * + **************************************************************/ + +void TLan_PrintList( TLanList *list, char *type, int num) +{ + int i; + + printk( "TLAN: %s List %d at 0x%08x\n", type, num, (u32) list ); + printk( "TLAN: Forward = 0x%08x\n", list->forward ); + printk( "TLAN: CSTAT = 0x%04hx\n", list->cStat ); + printk( "TLAN: Frame Size = 0x%04hx\n", list->frameSize ); + /* for ( i = 0; i < 10; i++ ) { */ + for ( i = 0; i < 2; i++ ) { + printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address ); + } + +} /* TLan_PrintList */ + + /*************************************************************** + * TLan_ReadAndClearStats + * + * Returns: + * Nothing + * Parms: + * dev Pointer to device structure of adapter + * to which to read stats. + * record Flag indicating whether to add + * + * This functions reads all the internal status registers + * of the TLAN chip, which clears them as a side effect. + * It then either adds the values to the device's status + * struct, or discards them, depending on whether record + * is TLAN_RECORD (!=0) or TLAN_IGNORE (==0). + * + **************************************************************/ + +void TLan_ReadAndClearStats( struct net_device *dev, int record ) +{ + TLanPrivateInfo *priv = dev->priv; + u32 tx_good, tx_under; + u32 rx_good, rx_over; + u32 def_tx, crc, code; + u32 multi_col, single_col; + u32 excess_col, late_col, loss; + + outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR ); + tx_good = inb( dev->base_addr + TLAN_DIO_DATA ); + tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; + tx_under = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); + + outw( TLAN_GOOD_RX_FRMS, dev->base_addr + TLAN_DIO_ADR ); + rx_good = inb( dev->base_addr + TLAN_DIO_DATA ); + rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; + rx_over = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); + + outw( TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR ); + def_tx = inb( dev->base_addr + TLAN_DIO_DATA ); + def_tx += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + crc = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); + code = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); + + outw( TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); + multi_col = inb( dev->base_addr + TLAN_DIO_DATA ); + multi_col += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + single_col = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); + single_col += inb( dev->base_addr + TLAN_DIO_DATA + 3 ) << 8; + + outw( TLAN_EXCESSCOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); + excess_col = inb( dev->base_addr + TLAN_DIO_DATA ); + late_col = inb( dev->base_addr + TLAN_DIO_DATA + 1 ); + loss = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); + + if ( record ) { + priv->stats.rx_packets += rx_good; + priv->stats.rx_errors += rx_over + crc + code; + priv->stats.tx_packets += tx_good; + priv->stats.tx_errors += tx_under + loss; + priv->stats.collisions += multi_col + single_col + excess_col + late_col; + + priv->stats.rx_over_errors += rx_over; + priv->stats.rx_crc_errors += crc; + priv->stats.rx_frame_errors += code; + + priv->stats.tx_aborted_errors += tx_under; + priv->stats.tx_carrier_errors += loss; + } + +} /* TLan_ReadAndClearStats */ + + /*************************************************************** + * TLan_Reset + * + * Returns: + * 0 + * Parms: + * dev Pointer to device structure of adapter + * to be reset. + * + * This function resets the adapter and it's physical + * device. See Chap. 3, pp. 9-10 of the "ThunderLAN + * Programmer's Guide" for details. The routine tries to + * implement what is detailed there, though adjustments + * have been made. + * + **************************************************************/ + +void +TLan_ResetAdapter( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + int i; + u32 addr; + u32 data; + u8 data8; + + priv->tlanFullDuplex = FALSE; + priv->phyOnline=0; +/* 1. Assert reset bit. */ + + data = inl(dev->base_addr + TLAN_HOST_CMD); + data |= TLAN_HC_AD_RST; + outl(data, dev->base_addr + TLAN_HOST_CMD); + + udelay(1000); + +/* 2. Turn off interrupts. ( Probably isn't necessary ) */ + + data = inl(dev->base_addr + TLAN_HOST_CMD); + data |= TLAN_HC_INT_OFF; + outl(data, dev->base_addr + TLAN_HOST_CMD); + +/* 3. Clear AREGs and HASHs. */ + + for ( i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4 ) { + TLan_DioWrite32( dev->base_addr, (u16) i, 0 ); + } + +/* 4. Setup NetConfig register. */ + + data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; + TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data ); + +/* 5. Load Ld_Tmr and Ld_Thr in HOST_CMD. */ + + outl( TLAN_HC_LD_TMR | 0x3f, dev->base_addr + TLAN_HOST_CMD ); + outl( TLAN_HC_LD_THR | 0x9, dev->base_addr + TLAN_HOST_CMD ); + +/* 6. Unreset the MII by setting NMRST (in NetSio) to 1. */ + + outw( TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR ); + addr = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; + TLan_SetBit( TLAN_NET_SIO_NMRST, addr ); + +/* 7. Setup the remaining registers. */ + + if ( priv->tlanRev >= 0x30 ) { + data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC; + TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, data8 ); + } + TLan_PhyDetect( dev ); + data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN; + + if ( priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY ) { + data |= TLAN_NET_CFG_BIT; + if ( priv->aui == 1 ) { + TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x0a ); + } else if ( priv->duplex == TLAN_DUPLEX_FULL ) { + TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x00 ); + priv->tlanFullDuplex = TRUE; + } else { + TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 ); + } + } + + if ( priv->phyNum == 0 ) { + data |= TLAN_NET_CFG_PHY_EN; + } + TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data ); + + if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) { + TLan_FinishReset( dev ); + } else { + TLan_PhyPowerDown( dev ); + } + +} /* TLan_ResetAdapter */ + +void +TLan_FinishReset( struct net_device *dev ) +{ + TLanPrivateInfo *priv = dev->priv; + u8 data; + u32 phy; + u8 sio; + u16 status; + u16 partner; + u16 tlphy_ctl; + u16 tlphy_par; + u16 tlphy_id1, tlphy_id2; + int i; + + phy = priv->phy[priv->phyNum]; + + data = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP; + if ( priv->tlanFullDuplex ) { + data |= TLAN_NET_CMD_DUPLEX; + } + TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data ); + data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5; + if ( priv->phyNum == 0 ) { + data |= TLAN_NET_MASK_MASK7; + } + TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data ); + TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, ((1536)+7)&~7 ); + TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 ); + TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 ); + + if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) { + status = MII_GS_LINK; + printk( "TLAN: %s: Link forced.\n", dev->name ); + } else { + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); + udelay( 1000 ); + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); + if ( (status & MII_GS_LINK) && /* We only support link info on Nat.Sem. PHY's */ + (tlphy_id1 == NAT_SEM_ID1) && + (tlphy_id2 == NAT_SEM_ID2) ) { + TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner ); + TLan_MiiReadReg( dev, phy, TLAN_TLPHY_PAR, &tlphy_par ); + + printk( "TLAN: %s: Link active with ", dev->name ); + if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) { + printk( "forced 10%sMbps %s-Duplex\n", + tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", + tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); + } else { + printk( "AutoNegotiation enabled, at 10%sMbps %s-Duplex\n", + tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", + tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); + printk("TLAN: Partner capability: "); + for (i = 5; i <= 10; i++) + if (partner & (1<base_addr, TLAN_LED_REG, TLAN_LED_LINK ); +#ifdef MONITOR + /* We have link beat..for now anyway */ + priv->link = 1; + /*Enabling link beat monitoring */ + TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_LINK_BEAT ); +#endif + } else if (status & MII_GS_LINK) { + printk( "TLAN: %s: Link active\n", dev->name ); + TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); + } + } + + if ( priv->phyNum == 0 ) { + TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl ); + tlphy_ctl |= TLAN_TC_INTEN; + TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl ); + sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO ); + sio |= TLAN_NET_SIO_MINTEN; + TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio ); + } + + if ( status & MII_GS_LINK ) { + TLan_SetMac( dev, 0, dev->dev_addr ); + priv->phyOnline = 1; + outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); + if ( debug >= 1 && debug != TLAN_DEBUG_PROBE ) { + outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); + } + outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); + outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); + } else { + printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name ); + TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET ); + return; + } + +} /* TLan_FinishReset */ + + /*************************************************************** + * TLan_SetMac + * + * Returns: + * Nothing + * Parms: + * dev Pointer to device structure of adapter + * on which to change the AREG. + * areg The AREG to set the address in (0 - 3). + * mac A pointer to an array of chars. Each + * element stores one byte of the address. + * IE, it isn't in ascii. + * + * This function transfers a MAC address to one of the + * TLAN AREGs (address registers). The TLAN chip locks + * the register on writing to offset 0 and unlocks the + * register after writing to offset 5. If NULL is passed + * in mac, then the AREG is filled with 0's. + * + **************************************************************/ + +void TLan_SetMac( struct net_device *dev, int areg, char *mac ) +{ + int i; + + areg *= 6; + + if ( mac != NULL ) { + for ( i = 0; i < 6; i++ ) + TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, mac[i] ); + } else { + for ( i = 0; i < 6; i++ ) + TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, 0 ); + } + +} /* TLan_SetMac */ + +#endif diff --git a/netboot/tulip.c b/netboot/tulip.c index e1386c6d3..b784ea7bd 100644 --- a/netboot/tulip.c +++ b/netboot/tulip.c @@ -1,38 +1,46 @@ +/* -*- Mode:C; c-basic-offset:4; -*- */ + /* - Tulip and clone Etherboot Driver - By Marty Connor (mdc@thinguin.org) - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. + Tulip and clone Etherboot Driver - Based on Ken Yap's Tulip Etherboot Driver and Donald Becker's - Linux Tulip Driver. Supports N-Way speed auto-configuration on - MX98715, MX98715A and MX98725. Support inexpensive PCI 10/100 cards - based on the Macronix MX987x5 chip, such as the SOHOware Fast - model SFA110A, and the LinkSYS model LNE100TX. The NetGear - model FA310X, based on the LC82C168 chip is supported. - The TRENDnet TE100-PCIA NIC which uses a genuine Intel 21143-PD - chipset is supported. - Also, Davicom DM9102's. + By Marty Connor (mdc@thinguin.org) + Copyright (C) 2001 Entity Cyber, Inc. - Documentation and source code used: - Source for Etherboot driver at - http://etherboot.sourceforge.net/ - MX98715A Data Sheet and MX98715A Application Note - on http://www.macronix.com/ (PDF format files) - Source for Linux tulip driver at - http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. - Adapted by Ken Yap from - FreeBSD netboot DEC 21143 driver - Author: David Sharp - date: Nov/98 + As of April 2001 this driver should support most tulip cards that + the Linux tulip driver supports because Donald Becker's Linux media + detection code is now included. - Some code fragments were taken from verious places, Ken Yap's - etherboot, FreeBSD's if_de.c, and various Linux related files. - DEC's manuals for the 21143 and SROM format were very helpful. - The Linux de driver development page has a number of links to - useful related information. Have a look at: - ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/tulip-devel.html + Based on Ken Yap's Tulip Etherboot Driver and Donald Becker's + Linux Tulip Driver. Supports N-Way speed auto-configuration on + MX98715, MX98715A and MX98725. Support inexpensive PCI 10/100 cards + based on the Macronix MX987x5 chip, such as the SOHOware Fast + model SFA110A, and the LinkSYS model LNE100TX. The NetGear + model FA310X, based on the LC82C168 chip is supported. + The TRENDnet TE100-PCIA NIC which uses a genuine Intel 21143-PD + chipset is supported. Also, Davicom DM9102's. + + Documentation and source code used: + Source for Etherboot driver at + http://etherboot.sourceforge.net/ + MX98715A Data Sheet and MX98715A Application Note + on http://www.macronix.com/ (PDF format files) + Source for Linux tulip driver at + http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html + + Adapted by Ken Yap from + FreeBSD netboot DEC 21143 driver + Author: David Sharp + date: Nov/98 + + Some code fragments were taken from verious places, Ken Yap's + etherboot, FreeBSD's if_de.c, and various Linux related files. + DEC's manuals for the 21143 and SROM format were very helpful. + The Linux de driver development page has a number of links to + useful related information. Have a look at: + ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/tulip-devel.html */ /*********************************************************************/ @@ -40,15 +48,18 @@ /*********************************************************************/ /* + 11 Apr 2001 mdc [patch to etherboot 4.7.24] + Major rewrite to include Linux tulip driver media detection + code. This driver should support a lot more cards now. 16 Jul 2000 mdc 0.75b11 Added support for ADMtek 0985 Centaur-P, a "Comet" tulip clone which is used on the LinkSYS LNE100TX v4.x cards. We already support LNE100TX v2.0 cards, which use a different controller. - 04 Jul 2000 jam ? + 04 Jul 2000 jam ? Added test of status after receiving a packet from the card. Also uncommented the tulip_disable routine. Stray packets seemed to be causing problems. - 27 Apr 2000 njl ? + 27 Apr 2000 njl ? 29 Feb 2000 mdc 0.75b7 Increased reset delay to 3 seconds because Macronix cards seem to need more reset time before card comes back to a usable state. @@ -97,8 +108,11 @@ #include "pci.h" #include "cards.h" -#undef TULIP_DEBUG -#undef TULIP_DEBUG_WHERE +/* User settable parameters */ + +#undef TULIP_DEBUG +#undef TULIP_DEBUG_WHERE +static int tulip_debug = 2; /* 1 normal messages, 0 quiet .. 7 verbose. */ #define TX_TIME_OUT 2*TICKS_PER_SEC @@ -109,24 +123,212 @@ typedef signed short s16; typedef unsigned int u32; typedef signed int s32; -/* Register offsets for tulip device */ -enum tulip_offsets { - CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, - CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, - CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x80, CSR20=0xA0 +/* helpful macros if on a big_endian machine for changing byte order. + not strictly needed on Intel */ +#define le16_to_cpu(val) (val) +#define cpu_to_le32(val) (val) +#define get_unaligned(ptr) (*(ptr)) +#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) )) +#define get_u16(ptr) (*(u16 *)(ptr)) +#define virt_to_bus(x) ((unsigned long)x) +#define virt_to_le32desc(addr) virt_to_bus(addr) + +#define TULIP_IOTYPE PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0 +#define TULIP_SIZE 0x80 + +/* This is a mysterious value that can be written to CSR11 in the 21040 (only) + to support a pre-NWay full-duplex signaling mechanism using short frames. + No one knows what it should be, but if left at its default value some + 10base2(!) packets trigger a full-duplex-request interrupt. */ +#define FULL_DUPLEX_MAGIC 0x6969 + +static const int csr0 = 0x01A00000 | 0x8000; + +/* The possible media types that can be set in options[] are: */ +#define MEDIA_MASK 31 +static const char * const medianame[32] = { + "10baseT", "10base2", "AUI", "100baseTx", + "10baseT-FDX", "100baseTx-FDX", "100baseT4", "100baseFx", + "100baseFx-FDX", "MII 10baseT", "MII 10baseT-FDX", "MII", + "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FDX", "MII 100baseT4", + "MII 100baseFx-HDX", "MII 100baseFx-FDX", "Home-PNA 1Mbps", "Invalid-19", }; -#define DEC_21142_CSR6_TTM 0x00400000 /* Transmit Threshold Mode */ -#define DEC_21142_CSR6_HBD 0x00080000 /* Heartbeat Disable */ -#define DEC_21142_CSR6_PS 0x00040000 /* Port Select */ +/* This much match tulip_tbl[]! Note 21142 == 21143. */ +enum tulip_chips { + DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3, + LC82C168, MX98713, MX98715, MX98725, AX88141, AX88140, PNIC2, COMET, + COMPEX9881, I21145, XIRCOM +}; + +enum pci_id_flags_bits { + /* Set PCI command register bits before calling probe1(). */ + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + /* Read and map the single following PCI BAR. */ + PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, + PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, + PCI_UNUSED_IRQ=0x800, +}; + +struct pci_id_info { + char *name; + struct match_info { + u32 pci, pci_mask, subsystem, subsystem_mask; + u32 revision, revision_mask; /* Only 8 bits. */ + } id; + enum pci_id_flags_bits pci_flags; + int io_size; /* Needed for I/O region check or ioremap(). */ + int drv_flags; /* Driver use, intended as capability flags. */ +}; + +static struct pci_id_info pci_id_tbl[] = { + { "Digital DC21040 Tulip", { 0x00021011, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 0x80, DC21040 }, + { "Digital DC21041 Tulip", { 0x00141011, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 0x80, DC21041 }, + { "Digital DS21140A Tulip", { 0x00091011, 0xffffffff, 0,0, 0x20,0xf0 }, + TULIP_IOTYPE, 0x80, DC21140 }, + { "Digital DS21140 Tulip", { 0x00091011, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 0x80, DC21140 }, + { "Digital DS21143 Tulip", { 0x00191011, 0xffffffff, 0,0, 65,0xff }, + TULIP_IOTYPE, TULIP_SIZE, DC21142 }, + { "Digital DS21142 Tulip", { 0x00191011, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, TULIP_SIZE, DC21142 }, + { "Kingston KNE110tx (PNIC)", { 0x000211AD, 0xffffffff, 0xf0022646, 0xffffffff, 0, 0 }, + TULIP_IOTYPE, 256, LC82C168 }, + { "Lite-On 82c168 PNIC", { 0x000211AD, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 256, LC82C168 }, + { "Macronix 98713 PMAC", { 0x051210d9, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 256, MX98713 }, + { "Macronix 98715 PMAC", { 0x053110d9, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 256, MX98715 }, + { "Macronix 98725 PMAC", { 0x053110d9, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 256, MX98725 }, + { "ASIX AX88141", { 0x1400125B, 0xffffffff, 0,0, 0x10, 0xf0 }, + TULIP_IOTYPE, 128, AX88141 }, + { "ASIX AX88140", { 0x1400125B, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 128, AX88140 }, + { "Lite-On LC82C115 PNIC-II", { 0xc11511AD, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 256, PNIC2 }, + { "ADMtek AN981 Comet", { 0x09811317, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 256, COMET }, + { "ADMtek Centaur-P", { 0x09851317, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 256, COMET }, + { "ADMtek Centaur-C", { 0x19851317, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 256, COMET }, + { "Compex RL100-TX", { 0x988111F6, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 128, COMPEX9881 }, + { "Intel 21145 Tulip", { 0x00398086, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 128, I21145 }, + { "Xircom Tulip clone", { 0x0003115d, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 128, XIRCOM }, + { "Davicom DM9102", { 0x91021282, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 0x80, DC21140 }, + { "Davicom DM9100", { 0x91001282, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 0x80, DC21140 }, + { "Macronix mxic-98715 (EN1217)", { 0x12171113, 0xffffffff, 0, 0, 0, 0 }, + TULIP_IOTYPE, 256, MX98715 }, + { 0, { 0, 0, 0, 0, 0, 0 }, 0, 0, 0 }, +}; + +enum tbl_flag { + HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8, + HAS_PWRDWN=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */ + HAS_PNICNWAY=0x80, HAS_NWAY=0x40, /* Uses internal NWay xcvr. */ + HAS_INTR_MITIGATION=0x100, IS_ASIX=0x200, HAS_8023X=0x400, +}; + +/* Note: this table must match enum tulip_chips above. */ +static struct tulip_chip_table { + char *chip_name; + int flags; +} tulip_tbl[] = { + { "Digital DC21040 Tulip", 0}, + { "Digital DC21041 Tulip", HAS_MEDIA_TABLE | HAS_NWAY }, + { "Digital DS21140 Tulip", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM }, + { "Digital DS21143 Tulip", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII + | HAS_PWRDWN | HAS_NWAY | HAS_INTR_MITIGATION }, + { "Lite-On 82c168 PNIC", HAS_MII | HAS_PNICNWAY }, + { "Macronix 98713 PMAC", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM }, + { "Macronix 98715 PMAC", HAS_MEDIA_TABLE }, + { "Macronix 98725 PMAC", HAS_MEDIA_TABLE }, + { "ASIX AX88140", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM + | MC_HASH_ONLY | IS_ASIX }, + { "ASIX AX88141", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY + | IS_ASIX }, + { "Lite-On PNIC-II", HAS_MII | HAS_NWAY | HAS_8023X }, + { "ADMtek Comet", MC_HASH_ONLY }, + { "Compex 9881 PMAC", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM }, + { "Intel DS21145 Tulip", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII + | HAS_PWRDWN | HAS_NWAY }, + { "Xircom tulip work-alike", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII + | HAS_PWRDWN | HAS_NWAY }, + { 0, 0 }, +}; + +/* A full-duplex map for media types. */ +enum MediaIs { + MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8, + MediaIs100=16}; + +static const char media_cap[32] = +{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20, 20,31,0,0, }; +static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; + +/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD */ +static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; +static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; +static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + +static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; +static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; +static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + +/* Offsets to the Command and Status Registers, "CSRs". All accesses + must be longword instructions and quadword aligned. */ +enum tulip_offsets { + CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, + CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, + CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x80, CSR20=0xA0 +}; + +/* The bits in the CSR5 status registers, mostly interrupt sources. */ +enum status_bits { + TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10, + NormalIntr=0x10000, AbnormalIntr=0x8000, + RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40, + TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01, +}; + +enum desc_status_bits { + DescOwnded=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300, +}; + +struct medialeaf { + u8 type; + u8 media; + unsigned char *leafdata; +}; + +struct mediatable { + u16 defaultmedia; + u8 leafcount, csr12dir; /* General purpose pin directions. */ + unsigned has_mii:1, has_nonmii:1, has_reset:6; + u32 csr15dir, csr15val; /* 21143 NWay setting. */ + struct medialeaf mleaf[0]; +}; + +struct mediainfo { + struct mediainfo *next; + int info_type; + int index; + unsigned char *info; +}; /* EEPROM Address width definitions */ #define EEPROM_ADDRLEN 6 #define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ -/* Data Read from the EEPROM */ -static unsigned char ee_data[EEPROM_SIZE]; - /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5 << addr_len) #define EE_READ_CMD (6 << addr_len) @@ -146,186 +348,338 @@ static unsigned char ee_data[EEPROM_SIZE]; turn-around to insure that this remains true. */ #define eeprom_delay() inl(ee_addr) -/* helpful macro if on a big_endian machine for changing byte order. - not strictly needed on Intel */ -#define le16_to_cpu(val) (val) - -/* transmit and receive descriptor format */ -struct txdesc { - volatile unsigned long status; /* owner, status */ - unsigned long buf1sz:11, /* size of buffer 1 */ - buf2sz:11, /* size of buffer 2 */ - control:10; /* control bits */ - const unsigned char *buf1addr; /* buffer 1 address */ - const unsigned char *buf2addr; /* buffer 2 address */ -}; - -struct rxdesc { - volatile unsigned long status; /* owner, status */ - unsigned long buf1sz:11, /* size of buffer 1 */ - buf2sz:11, /* size of buffer 2 */ - control:10; /* control bits */ - unsigned char *buf1addr; /* buffer 1 address */ - unsigned char *buf2addr; /* buffer 2 address */ -}; - /* Size of transmit and receive buffers */ #define BUFLEN 1536 +/* Ring-wrap flag in length field, use for last ring entry. + 0x01000000 means chain on buffer2 address, + 0x02000000 means use the ring start address in CSR2/3. + Note: Some work-alike chips do not function correctly in chained mode. + The ASIX chip works only in chained mode. + Thus we indicate ring mode, but always write the 'next' field for + chained mode as well. */ +#define DESC_RING_WRAP 0x02000000 + +/* transmit and receive descriptor format */ +struct tulip_rx_desc { + volatile u32 status; + u32 length; + u32 buffer1, buffer2; +}; + +struct tulip_tx_desc { + volatile u32 status; + u32 length; + u32 buffer1, buffer2; +}; + /*********************************************************************/ /* Global Storage */ /*********************************************************************/ -/* PCI Bus parameters */ -static unsigned short vendor, dev_id; -static unsigned long ioaddr; +static u32 ioaddr; /* Note: transmit and receive buffers must be longword aligned and longword divisable */ -/* transmit descriptor and buffer */ -static struct txdesc txd __attribute__ ((aligned(4))); -#ifndef USE_INTERNAL_BUFFER +#define TX_RING_SIZE 2 +static struct tulip_tx_desc tx_ring[TX_RING_SIZE] __attribute__ ((aligned(4))); + +#ifdef USE_LOWMEM_BUFFER #define txb ((char *)0x10000 - BUFLEN) #else static unsigned char txb[BUFLEN] __attribute__ ((aligned(4))); #endif -/* receive descriptor(s) and buffer(s) */ -#define NRXD 4 -static struct rxdesc rxd[NRXD] __attribute__ ((aligned(4))); -#ifndef USE_INTERNAL_BUFFER -#define rxb ((char *)0x10000 - NRXD * BUFLEN - BUFLEN) -#else -static unsigned char rxb[NRXD * BUFLEN] __attribute__ ((aligned(4))); -#endif -static int rxd_tail; +#define RX_RING_SIZE 4 +static struct tulip_rx_desc rx_ring[RX_RING_SIZE] __attribute__ ((aligned(4))); -/* buffer for ethernet header */ -static unsigned char ehdr[ETHER_HDR_SIZE]; +#ifdef USE_LOWMEM_BUFFER +#define rxb ((char *)0x10000 - RX_RING_SIZE * BUFLEN - BUFLEN) +#else +static unsigned char rxb[RX_RING_SIZE * BUFLEN] __attribute__ ((aligned(4))); +#endif + +static struct tulip_private { + int cur_rx; + int chip_id; /* index into tulip_tbl[] */ + int pci_id_idx; /* index into pci_id_tbl[] */ + int revision; + int flags; + unsigned short vendor_id; /* PCI card vendor code */ + unsigned short dev_id; /* PCI card device code */ + unsigned char ehdr[ETH_HLEN]; /* buffer for ethernet header */ + const char *nic_name; + unsigned int csr0, csr6; /* Current CSR0, CSR6 settings. */ + unsigned int if_port; + unsigned int full_duplex; /* Full-duplex operation requested. */ + unsigned int full_duplex_lock; + unsigned int medialock; /* Do not sense media type. */ + unsigned int mediasense; /* Media sensing in progress. */ + unsigned int nway, nwayset; /* 21143 internal NWay. */ + unsigned int default_port; + unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ + u8 media_table_storage[(sizeof(struct mediatable) + 32*sizeof(struct medialeaf))]; + u16 sym_advertise, mii_advertise; /* NWay to-advertise. */ + struct mediatable *mtable; + u16 lpar; /* 21143 Link partner ability. */ + u16 advertising[4]; /* MII advertise, from SROM table. */ + signed char phys[4], mii_cnt; /* MII device addresses. */ + int cur_index; /* Current media index. */ + int saved_if_port; +} tpx; + +static struct tulip_private *tp; + +/* Known cards that have old-style EEPROMs. + Writing this table is described at + http://cesdis.gsfc.nasa.gov/linux/drivers/tulip-drivers/tulip-media.html */ +static struct fixups { + char *name; + unsigned char addr0, addr1, addr2; + u16 newtable[32]; /* Max length below. */ +} eeprom_fixups[] = { + {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, + 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, + {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f, + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0903, 0x006D, /* 100baseTx */ + 0x0905, 0x006D, /* 100baseTx-FD */ }}, + {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, + 0x0107, 0x8021, /* 100baseFx */ + 0x0108, 0x8021, /* 100baseFx-FD */ + 0x0100, 0x009E, /* 10baseT */ + 0x0104, 0x009E, /* 10baseT-FD */ + 0x0103, 0x006D, /* 100baseTx */ + 0x0105, 0x006D, /* 100baseTx-FD */ }}, + {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, + 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ + 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, + {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, + 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ + 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ + 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ + 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ + 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ + }}, + {0, 0, 0, 0, {}}}; + +static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", + "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"}; /*********************************************************************/ /* Function Prototypes */ /*********************************************************************/ -static void whereami(const char *str); -static int lc82c168_mdio_read(int phy_id, int location); -static void lc82c168_mdio_write(int phy_id, int location, int value); -static void lc82c168_do_mii(); +static int mdio_read(struct nic *nic, int phy_id, int location); +static void mdio_write(struct nic *nic, int phy_id, int location, int value); static int read_eeprom(unsigned long ioaddr, int location, int addr_len); +static void parse_eeprom(struct nic *nic); struct nic *tulip_probe(struct nic *nic, unsigned short *io_addrs, - struct pci_device *pci); + struct pci_device *pci); static void tulip_init_ring(struct nic *nic); static void tulip_reset(struct nic *nic); static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, - unsigned int s, const char *p); + unsigned int s, const char *p); static int tulip_poll(struct nic *nic); static void tulip_disable(struct nic *nic); -static void whereami (const char *str); -#ifdef TULIP_DEBUG -static void tulip_more(void); -#endif /* TULIP_DEBUG */ +static void nway_start(struct nic *nic); +static void pnic_do_nway(struct nic *nic); +static void select_media(struct nic *nic, int startup); +static void init_media(struct nic *nic); +static void start_link(struct nic *nic); +static int tulip_check_duplex(struct nic *nic); + static void tulip_wait(unsigned int nticks); +#ifdef TULIP_DEBUG_WHERE +static void whereami(const char *str); +#endif + +#ifdef TULIP_DEBUG +static void tulip_more(void); +#endif + /*********************************************************************/ /* Utility Routines */ /*********************************************************************/ -static inline void whereami (const char *str) +#ifdef TULIP_DEBUG_WHERE +static void whereami (const char *str) { -#ifdef TULIP_DEBUG_WHERE - printf("%s\n", str); - /* sleep(2); */ -#endif + printf("%s: %s\n", tp->nic_name, str); + /* sleep(2); */ } +#endif -#ifdef TULIP_DEBUG -static void tulip_more() +#ifdef TULIP_DEBUG +static void tulip_more(void) { - printf("\n\n-- more --"); - while (!iskey()) - /* wait */; - getchar(); - printf("\n\n"); + printf("\n\n-- more --"); + while (!iskey()) + /* wait */; + getchar(); + printf("\n\n"); } #endif /* TULIP_DEBUG */ static void tulip_wait(unsigned int nticks) { - unsigned int to = currticks() + nticks; - while (currticks() < to) - /* wait */ ; + unsigned int to = currticks() + nticks; + while (currticks() < to) + /* wait */ ; } /*********************************************************************/ /* Media Descriptor Code */ /*********************************************************************/ -static int lc82c168_mdio_read(int phy_id, int location) + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. */ + +/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues or future 66Mhz PCI. */ +#define mdio_delay() inl(mdio_addr) + +/* Read and write the MII registers using software-generated serial + MDIO protocol. It is just different enough from the EEPROM protocol + to not share code. The maxium data clock rate is 2.5 Mhz. */ +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. */ + +int mdio_read(struct nic *nic, int phy_id, int location) { - int i = 1000; - int retval = 0; + int i; + int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int retval = 0; + long mdio_addr = ioaddr + CSR9; - whereami("mdio_read\n"); - - outl(0x60020000 | (phy_id<<23) | (location<<18), ioaddr + 0xA0); - inl(ioaddr + 0xA0); - inl(ioaddr + 0xA0); - while (--i > 0) - if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) - return retval & 0xFFFF; - if (i == 0) printf("mdio read timeout!\n"); - return 0xFFFF; -} - -static void lc82c168_mdio_write(int phy_id, int location, int value) -{ - int i = 1000; - int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; - - whereami("mdio_write\n"); - - outl(cmd, ioaddr + 0xA0); - do - if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) - break; - while (--i > 0); - if (i == 0) printf("mdio write timeout!\n"); - return; -} - -static void lc82c168_do_mii(void) -{ - int phy, phy_idx; - - whereami("do_mii\n"); - - for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < 4; phy++) { - - int mii_status = lc82c168_mdio_read(phy, 1); - - if ((mii_status & 0x8301) == 0x8001 || - ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { - - int mii_reg0 = lc82c168_mdio_read(phy, 0); - int mii_advert = lc82c168_mdio_read(phy, 4); - int mii_reg4 = ((mii_status >> 6) & 0x01E1) | 1; - - phy_idx++; - printf("%s: MII trcvr #%d " - "config %x status %x advertising %x reg4 %x.\n", - "LC82C168", phy, mii_reg0, mii_status, mii_advert, mii_reg4); - - lc82c168_mdio_write(phy, 0, mii_reg0 | 0x1000); - if (mii_advert != mii_reg4) - lc82c168_mdio_write(phy, 4, mii_reg4); - } - } -#ifdef TULIP_DEBUG - printf("mii_cnt = %d\n", phy_idx); +#ifdef TULIP_DEBUG_WHERE + whereami("mdio_read\n"); #endif + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); + inl(ioaddr + 0xA0); + inl(ioaddr + 0xA0); + while (--i > 0) + if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) + return retval & 0xffff; + return 0xffff; + } + + if (tp->chip_id == COMET) { + if (phy_id == 1) { + if (location < 7) + return inl(ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + return inl(ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + return inl(ioaddr + 0xD4 + ((location-29)<<2)); + } + return 0xffff; + } + + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + return (retval>>1) & 0xffff; +} + +void mdio_write(struct nic *nic, int phy_id, int location, int value) +{ + int i; + int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + long mdio_addr = ioaddr + CSR9; + +#ifdef TULIP_DEBUG_WHERE + whereami("mdio_write\n"); +#endif + + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(cmd, ioaddr + 0xA0); + do + if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) + break; + while (--i > 0); + return; + } + + if (tp->chip_id == COMET) { + if (phy_id != 1) + return; + if (location < 7) + outl(value, ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + outl(value, ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + outl(value, ioaddr + 0xD4 + ((location-29)<<2)); + return; + } + + /* Establish sync by sending 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } } @@ -338,77 +692,248 @@ static void lc82c168_do_mii(void) */ static int read_eeprom(unsigned long ioaddr, int location, int addr_len) { - int i; - unsigned short retval = 0; - long ee_addr = ioaddr + CSR9; - int read_cmd = location | EE_READ_CMD; + int i; + unsigned short retval = 0; + long ee_addr = ioaddr + CSR9; + int read_cmd = location | EE_READ_CMD; - whereami("read_eeprom\n"); +#ifdef TULIP_DEBUG_WHERE + whereami("read_eeprom\n"); +#endif - outl(EE_ENB & ~EE_CS, ee_addr); - outl(EE_ENB, ee_addr); - - /* Shift the read command bits out. */ - for (i = 4 + addr_len; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - outl(EE_ENB | dataval, ee_addr); - eeprom_delay(); - outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - } - outl(EE_ENB, ee_addr); - - for (i = 16; i > 0; i--) { - outl(EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + outl(EE_ENB & ~EE_CS, ee_addr); outl(EE_ENB, ee_addr); - eeprom_delay(); - } - /* Terminate the EEPROM access. */ - outl(EE_ENB & ~EE_CS, ee_addr); - return retval; + /* Shift the read command bits out. */ + for (i = 4 + addr_len; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outl(EE_ENB | dataval, ee_addr); + eeprom_delay(); + outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + } + outl(EE_ENB, ee_addr); + + for (i = 16; i > 0; i--) { + outl(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + outl(EE_ENB, ee_addr); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(EE_ENB & ~EE_CS, ee_addr); + return retval; } + + +/*********************************************************************/ +/* EEPROM Parsing Code */ +/*********************************************************************/ +static void parse_eeprom(struct nic *nic) +{ + unsigned char *p, *ee_data = tp->eeprom; + int new_advertise = 0; + int i; + +#ifdef TULIP_DEBUG_WHERE + whereami("parse_eeprom\n"); +#endif + + tp->mtable = 0; + /* Detect an old-style (SA only) EEPROM layout: + memcmp(ee_data, ee_data+16, 8). */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + break; + if (i >= 8) { + /* Do a fix-up based on the vendor half of the station address. */ + for (i = 0; eeprom_fixups[i].name; i++) { + if (nic->node_addr[0] == eeprom_fixups[i].addr0 + && nic->node_addr[1] == eeprom_fixups[i].addr1 + && nic->node_addr[2] == eeprom_fixups[i].addr2) { + if (nic->node_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) + i++; /* An Accton EN1207, not an outlaw Maxtech. */ + memcpy(ee_data + 26, eeprom_fixups[i].newtable, + sizeof(eeprom_fixups[i].newtable)); +#ifdef TULIP_DEBUG + printf("%s: Old format EEPROM on '%s' board.\n%s: Using substitute media control info.\n", + tp->nic_name, eeprom_fixups[i].name, tp->nic_name); +#endif + break; + } + } + if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ +#ifdef TULIP_DEBUG + printf("%s: Old style EEPROM with no media selection information.\n", + tp->nic_name); +#endif + return; + } + } + + if (ee_data[19] > 1) { +#ifdef TULIP_DEBUG + printf("%s: Multiport cards (%d ports) may not work correctly.\n", + tp->nic_name, ee_data[19]); +#endif + } + + p = (void *)ee_data + ee_data[27]; + + if (ee_data[27] == 0) { /* No valid media table. */ +#ifdef TULIP_DEBUG + if (tulip_debug > 1) { + printf("%s: No Valid Media Table. ee_data[27] = %hhX\n", + tp->nic_name, ee_data[27]); + } +#endif + } else if (tp->chip_id == DC21041) { + int media = get_u16(p); + int count = p[2]; + p += 3; + + printf("%s: 21041 Media table, default media %hX (%s).\n", + tp->nic_name, media, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + unsigned char media_block = *p++; + int media_code = media_block & MEDIA_MASK; + if (media_block & 0x40) + p += 6; + switch(media_code) { + case 0: new_advertise |= 0x0020; break; + case 4: new_advertise |= 0x0040; break; + } + printf("%s: 21041 media #%d, %s.\n", + tp->nic_name, media_code, medianame[media_code]); + } + } else { + unsigned char csr12dir = 0; + int count; + struct mediatable *mtable; + u16 media = get_u16(p); + + p += 2; + if (tp->flags & CSR12_IN_SROM) + csr12dir = *p++; + count = *p++; + + tp->mtable = mtable = (struct mediatable *)&tp->media_table_storage[0]; + + mtable->defaultmedia = media; + mtable->leafcount = count; + mtable->csr12dir = csr12dir; + mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; + mtable->csr15dir = mtable->csr15val = 0; + + printf("%s: EEPROM default media type %s.\n", tp->nic_name, + media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); + + for (i = 0; i < count; i++) { + struct medialeaf *leaf = &mtable->mleaf[i]; + + if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ + leaf->type = 0; + leaf->media = p[0] & 0x3f; + leaf->leafdata = p; + if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ + mtable->has_mii = 1; + p += 4; + } else { + switch(leaf->type = p[1]) { + case 5: + mtable->has_reset = i; + leaf->media = p[2] & 0x0f; + break; + case 1: case 3: + mtable->has_mii = 1; + leaf->media = 11; + break; + case 2: + if ((p[2] & 0x3f) == 0) { + u32 base15 = (p[2] & 0x40) ? get_u16(p + 7) : 0x0008; + u16 *p1 = (u16 *)(p + (p[2] & 0x40 ? 9 : 3)); + mtable->csr15dir = (get_unaligned(p1 + 0)<<16) + base15; + mtable->csr15val = (get_unaligned(p1 + 1)<<16) + base15; + } + /* Fall through. */ + case 0: case 4: + mtable->has_nonmii = 1; + leaf->media = p[2] & MEDIA_MASK; + switch (leaf->media) { + case 0: new_advertise |= 0x0020; break; + case 4: new_advertise |= 0x0040; break; + case 3: new_advertise |= 0x0080; break; + case 5: new_advertise |= 0x0100; break; + case 6: new_advertise |= 0x0200; break; + } + break; + default: + leaf->media = 19; + } + leaf->leafdata = p + 2; + p += (p[0] & 0x3f) + 1; + } +#ifdef TULIP_DEBUG + if (tulip_debug > 1 && leaf->media == 11) { + unsigned char *bp = leaf->leafdata; + printf("%s: MII interface PHY %d, setup/reset sequences %d/%d long, capabilities %hhX %hhX.\n", + tp->nic_name, bp[0], bp[1], bp[2 + bp[1]*2], + bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); + } +#endif + printf("%s: Index #%d - Media %s (#%d) described " + "by a %s (%d) block.\n", + tp->nic_name, i, medianame[leaf->media], leaf->media, + leaf->type < 6 ? block_name[leaf->type] : "UNKNOWN", + leaf->type); + } + if (new_advertise) + tp->sym_advertise = new_advertise; + } +} + /*********************************************************************/ /* tulip_init_ring - setup the tx and rx descriptors */ /*********************************************************************/ static void tulip_init_ring(struct nic *nic) { - int i; + int i; - /* setup the transmit descriptor */ - txd.buf1addr = &txb[0]; - txd.buf2addr = &txb[0]; /* just in case */ - txd.buf1sz = 192; /* setup packet must be 192 bytes */ - txd.buf2sz = 0; - txd.control = 0x028; /* setup packet + TER */ - txd.status = 0x80000000; /* give ownership to device */ +#ifdef TULIP_DEBUG_WHERE + whereami("tulip_init_ring\n"); +#endif - /* construct perfect filter frame with mac address as first match - and broadcast address for all others */ - for (i=0; i<192; i++) txb[i] = 0xFF; - txb[0] = nic->node_addr[0]; - txb[1] = nic->node_addr[1]; - txb[4] = nic->node_addr[2]; - txb[5] = nic->node_addr[3]; - txb[8] = nic->node_addr[4]; - txb[9] = nic->node_addr[5]; + tp->cur_rx = 0; - /* setup receive descriptor */ - for (i=0; inode_addr[0] + (nic->node_addr[1] << 8) - + (nic->node_addr[2] << 16) + (nic->node_addr[3] << 24); - addr_high = nic->node_addr[4] + (nic->node_addr[5] << 8); - outl(addr_low, ioaddr + 0xA4); - outl(addr_high, ioaddr + 0xA8); - outl(0, ioaddr + 0xAC); - outl(0, ioaddr + 0xB0); - } - - /* Point to receive descriptor */ - outl((unsigned long)&rxd[0], ioaddr + CSR3); - outl((unsigned long)&txd , ioaddr + CSR4); - - csr6 = 0x02404000; - - /* Chip specific init code */ - - if (vendor == PCI_VENDOR_ID_MACRONIX && dev_id == PCI_DEVICE_ID_MX987x5) { - csr6 = 0x01880200; - /* Set CSR16 and CSR20 to values that allow device modification */ - outl(0x0B3C0000 | inl(ioaddr + CSR16), ioaddr + CSR16); - outl(0x00011000 | inl(ioaddr + CSR20), ioaddr + CSR20); - - } else if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_LC82C115) { - /* This is MX987x5 init code. It seems to work for the LNE100TX - but should be replaced when we figure out the right way - to do this initialization. - */ - csr6 = 0x01880200; - outl(0x0B3C0000 | inl(ioaddr + CSR16), ioaddr + CSR16); - outl(0x00011000 | inl(ioaddr + CSR20), ioaddr + CSR20); - - } else if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_DEC_TULIP) { - - csr6 = 0x814C0000; - outl(0x00000001, ioaddr + CSR15); - - } else if (vendor == PCI_VENDOR_ID_DEC && dev_id == PCI_DEVICE_ID_DEC_21142) { - /* check SROM for evidence of an MII interface */ - /* get Controller_0 Info Leaf Offset from SROM - assume already in ee_data */ - int offset = ee_data [27] + (ee_data [28] << 8); - - /* check offset range and if we have an extended type 3 Info Block */ - if ((offset >= 30) && (offset < 120) && (ee_data [offset + 3] > 128) && - (ee_data [offset + 4] == 3)) { - /* must have an MII interface - disable heartbeat, select port etc. */ - csr6 |= (DEC_21142_CSR6_HBD | DEC_21142_CSR6_PS); - csr6 &= ~(DEC_21142_CSR6_TTM); - } - } else if (vendor == PCI_VENDOR_ID_DAVICOM && dev_id == PCI_DEVICE_ID_DM9102){ - /* setup CR12 */ - outl(0x180, ioaddr + CSR12); /* Let bit 7 output port */ - outl(0x80, ioaddr + CSR12); /* RESET DM9102 phyxcer */ - outl(0x0, ioaddr + CSR12); /* Clear RESET signal */ - - } else if (vendor == PCI_VENDOR_ID_ADMTEK && dev_id == PCI_DEVICE_ID_ADMTEK_0985) { - /* nothing */ - - } - - /* set the chip's operating mode */ - outl(csr6, ioaddr + CSR6); - - /* Start Tx */ - outl(inl(ioaddr + CSR6) | 0x00002000, ioaddr + CSR6); - /* immediate transmit demand */ - outl(0, ioaddr + CSR1); - - to = currticks() + TX_TIME_OUT; - while ((txd.status & 0x80000000) && (currticks() < to)) - /* wait */ ; - - if (currticks() >= to) { - printf ("TX Setup Timeout!\n"); - } - -#ifdef TULIP_DEBUG - printf("txd.status = %X\n", txd.status); - printf("ticks = %d\n", currticks() - (to - TX_TIME_OUT)); - tulip_more(); +#ifdef TULIP_DEBUG_WHERE + whereami("tulip_reset\n"); #endif - /* enable RX */ - outl(inl(ioaddr + CSR6) | 0x00000002, ioaddr + CSR6); - /* immediate poll demand */ - outl(0, ioaddr + CSR2); + /* Stop Tx and RX */ + outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); + + /* On some chip revs we must set the MII/SYM port before the reset!? */ + if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) { + outl(0x814C0000, ioaddr + CSR6); + } + + /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ + outl(0x00000001, ioaddr + CSR0); + tulip_wait(1); + + /* turn off reset and set cache align=16lword, burst=unlimit */ + outl(tp->csr0, ioaddr + CSR0); + + /* Wait the specified 50 PCI cycles after a reset */ + tulip_wait(1); + + /* set up transmit and receive descriptors */ + tulip_init_ring(nic); + + if (tp->chip_id == PNIC2) { + u32 addr_high = (nic->node_addr[1]<<8) + (nic->node_addr[0]<<0); + /* This address setting does not appear to impact chip operation?? */ + outl((nic->node_addr[5]<<8) + nic->node_addr[4] + + (nic->node_addr[3]<<24) + (nic->node_addr[2]<<16), + ioaddr + 0xB0); + outl(addr_high + (addr_high<<16), ioaddr + 0xB8); + } + + /* MC_HASH_ONLY boards don't support setup packets */ + if (tp->flags & MC_HASH_ONLY) { + u32 addr_low = cpu_to_le32(get_unaligned((u32 *)nic->node_addr)); + u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(nic->node_addr+4))); + + /* clear multicast hash filters and setup MAC address filters */ + if (tp->flags & IS_ASIX) { + outl(0, ioaddr + CSR13); + outl(addr_low, ioaddr + CSR14); + outl(1, ioaddr + CSR13); + outl(addr_high, ioaddr + CSR14); + outl(2, ioaddr + CSR13); + outl(0, ioaddr + CSR14); + outl(3, ioaddr + CSR13); + outl(0, ioaddr + CSR14); + } else if (tp->chip_id == COMET) { + outl(addr_low, ioaddr + 0xA4); + outl(addr_high, ioaddr + 0xA8); + outl(0, ioaddr + 0xAC); + outl(0, ioaddr + 0xB0); + } + } else { + /* for other boards we send a setup packet to initialize + the filters */ + u32 tx_flags = 0x08000000 | 192; + + /* construct perfect filter frame with mac address as first match + and broadcast address for all others */ + for (i=0; i<192; i++) + txb[i] = 0xFF; + txb[0] = nic->node_addr[0]; + txb[1] = nic->node_addr[1]; + txb[4] = nic->node_addr[2]; + txb[5] = nic->node_addr[3]; + txb[8] = nic->node_addr[4]; + txb[9] = nic->node_addr[5]; + + tx_ring[0].length = cpu_to_le32(tx_flags); + tx_ring[0].buffer1 = virt_to_le32desc(&txb[0]); + tx_ring[0].status = cpu_to_le32(0x80000000); + } + + /* Point to rx and tx descriptors */ + outl((unsigned long)&rx_ring[0], ioaddr + CSR3); + outl((unsigned long)&tx_ring[0], ioaddr + CSR4); + + init_media(nic); + + /* set the chip's operating mode (but don't turn on xmit and recv yet) */ + outl((tp->csr6 & ~0x00002002), ioaddr + CSR6); + + /* send setup packet for cards that support it */ + if (!(tp->flags & MC_HASH_ONLY)) { + /* enable transmit wait for completion */ + outl(tp->csr6 | 0x00002000, ioaddr + CSR6); + /* immediate transmit demand */ + outl(0, ioaddr + CSR1); + + to = currticks() + TX_TIME_OUT; + while ((tx_ring[0].status & 0x80000000) && (currticks() < to)) + /* wait */ ; + + if (currticks() >= to) { + printf ("%s: TX Setup Timeout.\n", tp->nic_name); + } + } + + if (tp->chip_id == LC82C168) + tulip_check_duplex(nic); + + /* enable transmit and receive */ + outl(tp->csr6 | 0x00002002, ioaddr + CSR6); } @@ -579,44 +1060,58 @@ static void tulip_reset(struct nic *nic) static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p) { - unsigned long to; + u16 nstype; + u32 to; + u32 csr6 = inl(ioaddr + CSR6); - whereami("tulip_transmit\n"); +#ifdef TULIP_DEBUG_WHERE + whereami("tulip_transmit\n"); +#endif - /* Stop Tx */ - outl(inl(ioaddr + CSR6) & ~0x00002000, ioaddr + CSR6); + /* Disable Tx */ + outl(csr6 & ~0x00002000, ioaddr + CSR6); - /* setup ethernet header */ - memcpy(ehdr, d, ETHER_ADDR_SIZE); - memcpy(&ehdr[ETHER_ADDR_SIZE], nic->node_addr, ETHER_ADDR_SIZE); - ehdr[ETHER_ADDR_SIZE*2] = (t >> 8) & 0xFF; - ehdr[ETHER_ADDR_SIZE*2+1] = t & 0xFF; + memcpy(txb, d, ETH_ALEN); + memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN); + nstype = htons((u16) t); + memcpy(txb + 2 * ETH_ALEN, (u8 *)&nstype, 2); + memcpy(txb + ETH_HLEN, p, s); - /* setup the transmit descriptor */ - txd.buf1addr = &ehdr[0]; /* ethernet header */ - txd.buf1sz = ETHER_HDR_SIZE; - txd.buf2addr = p; /* packet to transmit */ - txd.buf2sz = s; - txd.control = 0x00000188; /* LS+FS+TER */ - txd.status = 0x80000000; /* give ownership to device */ + s += ETH_HLEN; + s &= 0x0FFF; - /* Point to transmit descriptor */ - outl((unsigned long)&txd, ioaddr + CSR4); + /* pad to minimum packet size */ + while (s < ETH_ZLEN) + txb[s++] = '\0'; - /* Start Tx */ - outl(inl(ioaddr + CSR6) | 0x00002000, ioaddr + CSR6); +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: sending %d bytes ethtype %hX\n", tp->nic_name, s, t); +#endif + + /* setup the transmit descriptor */ + /* 0x60000000 = no interrupt on completion */ + tx_ring[0].length = cpu_to_le32(0x60000000 | s); + tx_ring[0].status = cpu_to_le32(0x80000000); - /* immediate transmit demand */ - outl(0, ioaddr + CSR1); + /* Point to transmit descriptor */ + outl((u32)&tx_ring[0], ioaddr + CSR4); - to = currticks() + TX_TIME_OUT; - while ((txd.status & 0x80000000) && (currticks() < to)) - /* wait */ ; + /* Enable Tx */ + outl(csr6 | 0x00002000, ioaddr + CSR6); + /* immediate transmit demand */ + outl(0, ioaddr + CSR1); - if (currticks() >= to) { - printf ("TX Timeout!\n"); - } + to = currticks() + TX_TIME_OUT; + while ((tx_ring[0].status & 0x80000000) && (currticks() < to)) + /* wait */ ; + if (currticks() >= to) { + printf ("TX Timeout!\n"); + } + + /* Disable Tx */ + outl(csr6 & ~0x00002000, ioaddr + CSR6); } /*********************************************************************/ @@ -624,35 +1119,37 @@ static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, /*********************************************************************/ static int tulip_poll(struct nic *nic) { - whereami("tulip_poll\n"); - if (rxd[rxd_tail].status & 0x80000000) - return 0; +#ifdef TULIP_DEBUG_WHERE + whereami("tulip_poll\n"); +#endif - whereami("tulip_poll got one\n"); + /* no packet waiting. packet still owned by NIC */ + if (rx_ring[tp->cur_rx].status & 0x80000000) + return 0; - nic->packetlen = (rxd[rxd_tail].status & 0x3FFF0000) >> 16; +#ifdef TULIP_DEBUG_WHERE + whereami("tulip_poll got one\n"); +#endif - if( rxd[rxd_tail].status & 0x00008000){ - rxd[rxd_tail].status = 0x80000000; - rxd_tail++; - if (rxd_tail == NRXD) rxd_tail = 0; - return 0; - } + nic->packetlen = (rx_ring[tp->cur_rx].status & 0x3FFF0000) >> 16; - /* copy packet to working buffer */ - /* XXX - this copy could be avoided with a little more work - but for now we are content with it because the optimised - memcpy is quite fast */ + /* if we get a corrupted packet. throw it away and move on */ + if (rx_ring[tp->cur_rx].status & 0x00008000) { + /* return the descriptor and buffer to receive ring */ + rx_ring[tp->cur_rx].status = 0x80000000; + tp->cur_rx = (++tp->cur_rx) % RX_RING_SIZE; + return 0; + } - memcpy(nic->packet, rxb + rxd_tail * BUFLEN, nic->packetlen); + /* copy packet to working buffer */ + memcpy(nic->packet, rxb + tp->cur_rx * BUFLEN, nic->packetlen); - /* return the descriptor and buffer to receive ring */ - rxd[rxd_tail].status = 0x80000000; - rxd_tail++; - if (rxd_tail == NRXD) rxd_tail = 0; + /* return the descriptor and buffer to receive ring */ + rx_ring[tp->cur_rx].status = 0x80000000; + tp->cur_rx = (++tp->cur_rx) % RX_RING_SIZE; - return 1; + return 1; } /*********************************************************************/ @@ -660,90 +1157,833 @@ static int tulip_poll(struct nic *nic) /*********************************************************************/ static void tulip_disable(struct nic *nic) { - whereami("tulip_disable\n"); - /* disable interrupts */ - outl(0x00000000, ioaddr + CSR7); +#ifdef TULIP_DEBUG_WHERE + whereami("tulip_disable\n"); +#endif - /* Stop the chip's Tx and Rx processes. */ - outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); + /* disable interrupts */ + outl(0x00000000, ioaddr + CSR7); - /* Clear the missed-packet counter. */ - (volatile unsigned long)inl(ioaddr + CSR8); + /* Stop the chip's Tx and Rx processes. */ + outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); + + /* Clear the missed-packet counter. */ + (volatile unsigned long)inl(ioaddr + CSR8); } /*********************************************************************/ /* eth_probe - Look for an adapter */ /*********************************************************************/ struct nic *tulip_probe(struct nic *nic, unsigned short *io_addrs, - struct pci_device *pci) + struct pci_device *pci) { - unsigned int i; - u32 l1, l2; + u32 i, l1, l2; + u8 chip_rev; + u8 ee_data[EEPROM_SIZE]; + unsigned short sum; + int chip_idx; + static unsigned char last_phys_addr[ETH_ALEN] = {0x00, 'L', 'i', 'n', 'u', 'x'}; - whereami("tulip_probe\n"); + if (io_addrs == 0 || *io_addrs == 0) + return 0; - if (io_addrs == 0 || *io_addrs == 0) - return 0; + ioaddr = *io_addrs; - vendor = pci->vendor; - dev_id = pci->dev_id; - ioaddr = *io_addrs; + /* point to private storage */ + tp = &tpx; - /* wakeup chip */ - pcibios_write_config_dword(0, pci->devfn, 0x40, 0x00000000); + tp->vendor_id = pci->vendor; + tp->dev_id = pci->dev_id; + tp->nic_name = pci->name; - /* Stop the chip's Tx and Rx processes. */ - outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); + tp->if_port = 0; + tp->default_port = 0; - /* Clear the missed-packet counter. */ - (volatile unsigned long)inl(ioaddr + CSR8); + adjust_pci_device(pci); - /* Get MAC Address */ + /* disable interrupts */ + outl(0x00000000, ioaddr + CSR7); - /* Hardware Address retrieval method for LC82C168 */ - if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_DEC_TULIP) { - for (i = 0; i < 3; i++) { - int value, boguscnt = 100000; - outl(0x600 | i, ioaddr + 0x98); - do - value = inl(ioaddr + CSR9); - while (value < 0 && --boguscnt > 0); - nic->node_addr[i*2] = (u8)((value >> 8) & 0xFF); - nic->node_addr[i*2 + 1] = (u8)( value & 0xFF); + /* Stop the chip's Tx and Rx processes. */ + outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); + + /* Clear the missed-packet counter. */ + (volatile unsigned long)inl(ioaddr + CSR8); + + printf("\n"); /* so we start on a fresh line */ +#ifdef TULIP_DEBUG_WHERE + whereami("tulip_probe\n"); +#endif + +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf ("%s: Looking for Tulip Chip: Vendor=%hX Device=%hX\n", tp->nic_name, + tp->vendor_id, tp->dev_id); +#endif + + /* Figure out which chip we're dealing with */ + i = 0; + chip_idx = -1; + + while (pci_id_tbl[i].name) { + if ( (((u32) tp->dev_id << 16) | tp->vendor_id) == + (pci_id_tbl[i].id.pci & pci_id_tbl[i].id.pci_mask) ) { + chip_idx = pci_id_tbl[i].drv_flags; + break; + } + i++; } - } else if (vendor == PCI_VENDOR_ID_ADMTEK && - dev_id == PCI_DEVICE_ID_ADMTEK_0985) { - l1 = inl(ioaddr + 0xA4); - l2 = inl(ioaddr + 0xA8); - nic->node_addr[0] = (l1 ) & 0xFF; - nic->node_addr[1] = (l1 >> 8) & 0xFF; - nic->node_addr[2] = (l1 >> 16) & 0xFF; - nic->node_addr[3] = (l1 >> 24) & 0xFF; - nic->node_addr[4] = (l2 ) & 0xFF; - nic->node_addr[5] = (l2 >> 8) & 0xFF; - } else { - /* read EEPROM data */ - for (i = 0; i < sizeof(ee_data)/2; i++) - ((unsigned short *)ee_data)[i] = - le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN)); - /* extract MAC address from EEPROM buffer */ - for (i=0; i<6; i++) - nic->node_addr[i] = ee_data[20+i]; - } + if (chip_idx == -1) { + printf ("%s: Unknown Tulip Chip: Vendor=%hX Device=%hX\n", tp->nic_name, + tp->vendor_id, tp->dev_id); + return 0; + } - printf("Tulip %b:%b:%b:%b:%b:%b at ioaddr 0x%x\n", - nic->node_addr[0],nic->node_addr[1],nic->node_addr[2],nic->node_addr[3], - nic->node_addr[4],nic->node_addr[5],ioaddr); + tp->pci_id_idx = i; + tp->flags = tulip_tbl[chip_idx].flags; - /* initialize device */ - tulip_reset(nic); +#ifdef TULIP_DEBUG + if (tulip_debug > 1) { + printf ("%s: tp->pci_id_idx == %d, name == %s\n", tp->nic_name, + tp->pci_id_idx, pci_id_tbl[tp->pci_id_idx].name); + printf ("%s: chip_idx == %d, name == %s\n", tp->nic_name, chip_idx, + tulip_tbl[chip_idx].chip_name); + } +#endif + + /* Bring the 21041/21143 out of sleep mode. + Caution: Snooze mode does not work with some boards! */ + if (tp->flags & HAS_PWRDWN) + pcibios_write_config_dword(pci->bus, pci->devfn, 0x40, 0x00000000); - nic->reset = tulip_reset; - nic->poll = tulip_poll; - nic->transmit = tulip_transmit; - nic->disable = tulip_disable; + if (inl(ioaddr + CSR5) == 0xFFFFFFFF) { + printf("%s: The Tulip chip at %X is not functioning.\n", + tp->nic_name, ioaddr); + return 0; + } + + pcibios_read_config_byte(pci->bus, pci->devfn, PCI_REVISION, &chip_rev); - return nic; + printf("%s: [chip: %s] rev %d at %hX\n", tp->nic_name, + tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); + printf("%s: Vendor=%hX Device=%hX", tp->nic_name, tp->vendor_id, tp->dev_id); + + if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { + printf(" 21040 compatible mode."); + chip_idx = DC21040; + } + + printf("\n"); + + /* The SROM/EEPROM interface varies dramatically. */ + sum = 0; + if (chip_idx == DC21040) { + outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ + for (i = 0; i < ETH_ALEN; i++) { + int value, boguscnt = 100000; + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + nic->node_addr[i] = value; + sum += value & 0xff; + } + } else if (chip_idx == LC82C168) { + for (i = 0; i < 3; i++) { + int value, boguscnt = 100000; + outl(0x600 | i, ioaddr + 0x98); + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + put_unaligned(le16_to_cpu(value), ((u16*)nic->node_addr) + i); + sum += value & 0xffff; + } + } else if (chip_idx == COMET) { + /* No need to read the EEPROM. */ + put_unaligned(inl(ioaddr + 0xA4), (u32 *)nic->node_addr); + put_unaligned(inl(ioaddr + 0xA8), (u16 *)(nic->node_addr + 4)); + for (i = 0; i < ETH_ALEN; i ++) + sum += nic->node_addr[i]; + } else { + /* A serial EEPROM interface, we read now and sort it out later. */ + int sa_offset = 0; + int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6; + + for (i = 0; i < sizeof(ee_data)/2; i++) + ((u16 *)ee_data)[i] = + le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size)); + + /* DEC now has a specification (see Notes) but early board makers + just put the address in the first EEPROM locations. */ + /* This does memcmp(eedata, eedata+16, 8) */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + sa_offset = 20; + if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { + sa_offset = 2; /* Grrr, damn Matrox boards. */ + } + for (i = 0; i < ETH_ALEN; i ++) { + nic->node_addr[i] = ee_data[i + sa_offset]; + sum += ee_data[i + sa_offset]; + } + } + /* Lite-On boards have the address byte-swapped. */ + if ((nic->node_addr[0] == 0xA0 || nic->node_addr[0] == 0xC0) + && nic->node_addr[1] == 0x00) + for (i = 0; i < ETH_ALEN; i+=2) { + char tmp = nic->node_addr[i]; + nic->node_addr[i] = nic->node_addr[i+1]; + nic->node_addr[i+1] = tmp; + } + + if (sum == 0 || sum == ETH_ALEN*0xff) { + printf("%s: EEPROM not present!\n", tp->nic_name); + for (i = 0; i < ETH_ALEN-1; i++) + nic->node_addr[i] = last_phys_addr[i]; + nic->node_addr[i] = last_phys_addr[i] + 1; + } + + for (i = 0; i < ETH_ALEN; i++) + last_phys_addr[i] = nic->node_addr[i]; + + printf("%s: %! at ioaddr %hX\n", tp->nic_name, nic->node_addr, ioaddr); + + tp->chip_id = chip_idx; + tp->revision = chip_rev; + tp->csr0 = csr0; + + /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. + And the ASIX must have a burst limit or horrible things happen. */ + if (chip_idx == DC21143 && chip_rev == 65) + tp->csr0 &= ~0x01000000; + else if (tp->flags & IS_ASIX) + tp->csr0 |= 0x2000; + + if (media_cap[tp->default_port] & MediaIsMII) { + u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; + tp->mii_advertise = media2advert[tp->default_port - 9]; + tp->mii_advertise |= (tp->flags & HAS_8023X); /* Matching bits! */ + } + + /* This is logically part of the probe routine, but too complex + to write inline. */ + if (tp->flags & HAS_MEDIA_TABLE) { + memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom)); + parse_eeprom(nic); + } + + start_link(nic); + + /* reset the device and make ready for tx and rx of packets */ + tulip_reset(nic); + + nic->reset = tulip_reset; + nic->poll = tulip_poll; + nic->transmit = tulip_transmit; + nic->disable = tulip_disable; + + /* give the board a chance to reset before returning */ + tulip_wait(4*TICKS_PER_SEC); + + return nic; +} + +static void start_link(struct nic *nic) +{ + int i; + +#ifdef TULIP_DEBUG_WHERE + whereami("start_link\n"); +#endif + + if ((tp->flags & ALWAYS_CHECK_MII) || + (tp->mtable && tp->mtable->has_mii) || + ( ! tp->mtable && (tp->flags & HAS_MII))) { + unsigned int phy, phy_idx; + if (tp->mtable && tp->mtable->has_mii) { + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == 11) { + tp->cur_index = i; + tp->saved_if_port = tp->if_port; + select_media(nic, 2); + tp->if_port = tp->saved_if_port; + break; + } + } + + /* Find the connected MII xcvrs. */ + for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); + phy++) { + int mii_status = mdio_read(nic, phy, 1); + if ((mii_status & 0x8301) == 0x8001 || + ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { + int mii_reg0 = mdio_read(nic, phy, 0); + int mii_advert = mdio_read(nic, phy, 4); + int to_advert; + + if (tp->mii_advertise) + to_advert = tp->mii_advertise; + else if (tp->advertising[phy_idx]) + to_advert = tp->advertising[phy_idx]; + else /* Leave unchanged. */ + tp->mii_advertise = to_advert = mii_advert; + + tp->phys[phy_idx++] = phy; + printf("%s: MII transceiver %d config %hX status %hX advertising %hX.\n", + tp->nic_name, phy, mii_reg0, mii_status, mii_advert); + /* Fixup for DLink with miswired PHY. */ + if (mii_advert != to_advert) { + printf("%s: Advertising %hX on PHY %d previously advertising %hX.\n", + tp->nic_name, to_advert, phy, mii_advert); + mdio_write(nic, phy, 4, to_advert); + } + /* Enable autonegotiation: some boards default to off. */ + mdio_write(nic, phy, 0, mii_reg0 | + (tp->full_duplex ? 0x1100 : 0x1000) | + (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); + } + } + tp->mii_cnt = phy_idx; + if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { + printf("%s: ***WARNING***: No MII transceiver found!\n", + tp->nic_name); + tp->phys[0] = 1; + } + } + + /* Reset the xcvr interface and turn on heartbeat. */ + switch (tp->chip_id) { + case DC21040: + outl(0x00000000, ioaddr + CSR13); + outl(0x00000004, ioaddr + CSR13); + break; + case DC21041: + /* This is nway_start(). */ + if (tp->sym_advertise == 0) + tp->sym_advertise = 0x0061; + outl(0x00000000, ioaddr + CSR13); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ + outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6); + outl(0x0000EF01, ioaddr + CSR13); + break; + case DC21140: default: + if (tp->mtable) + outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); + break; + case DC21142: + case PNIC2: + if (tp->mii_cnt || media_cap[tp->if_port] & MediaIsMII) { + outl(0x82020000, ioaddr + CSR6); + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + outl(0x820E0000, ioaddr + CSR6); + } else + nway_start(nic); + break; + case LC82C168: + if ( ! tp->mii_cnt) { + tp->nway = 1; + tp->nwayset = 0; + outl(0x00420000, ioaddr + CSR6); + outl(0x30, ioaddr + CSR12); + outl(0x0001F078, ioaddr + 0xB8); + outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ + } + break; + case MX98713: case COMPEX9881: + outl(0x00000000, ioaddr + CSR6); + outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ + outl(0x00000001, ioaddr + CSR13); + break; + case MX98715: case MX98725: + outl(0x01a80000, ioaddr + CSR6); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00001000, ioaddr + CSR12); + break; + case COMET: + /* No initialization necessary. */ + break; + } +} + +static void nway_start(struct nic *nic) +{ + int csr14 = ((tp->sym_advertise & 0x0780) << 9) | + ((tp->sym_advertise&0x0020)<<1) | 0xffbf; + +#ifdef TULIP_DEBUG_WHERE + whereami("nway_start\n"); +#endif + + tp->if_port = 0; + tp->nway = tp->mediasense = 1; + tp->nwayset = tp->lpar = 0; + if (tp->chip_id == PNIC2) { + tp->csr6 = 0x01000000 | (tp->sym_advertise & 0x0040 ? 0x0200 : 0); + return; + } +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: Restarting internal NWay autonegotiation, %X.\n", + tp->nic_name, csr14); +#endif + outl(0x0001, ioaddr + CSR13); + outl(csr14, ioaddr + CSR14); + tp->csr6 = 0x82420000 | (tp->sym_advertise & 0x0040 ? 0x0200 : 0); + outl(tp->csr6, ioaddr + CSR6); + if (tp->mtable && tp->mtable->csr15dir) { + outl(tp->mtable->csr15dir, ioaddr + CSR15); + outl(tp->mtable->csr15val, ioaddr + CSR15); + } else if (tp->chip_id != PNIC2) + outw(0x0008, ioaddr + CSR15); + if (tp->chip_id == DC21041) /* Trigger NWAY. */ + outl(0xEF01, ioaddr + CSR12); + else + outl(0x1301, ioaddr + CSR12); +} + +static void init_media(struct nic *nic) +{ + int i; + +#ifdef TULIP_DEBUG_WHERE + whereami("init_media\n"); +#endif + + tp->saved_if_port = tp->if_port; + if (tp->if_port == 0) + tp->if_port = tp->default_port; + + /* Allow selecting a default media. */ + i = 0; + if (tp->mtable == NULL) + goto media_picked; + if (tp->if_port) { + int looking_for = media_cap[tp->if_port] & MediaIsMII ? 11 : + (tp->if_port == 12 ? 0 : tp->if_port); + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printf("%s: Using user-specified media %s.\n", + tp->nic_name, medianame[tp->if_port]); + goto media_picked; + } + } + if ((tp->mtable->defaultmedia & 0x0800) == 0) { + int looking_for = tp->mtable->defaultmedia & 15; + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printf("%s: Using EEPROM-set media %s.\n", + tp->nic_name, medianame[looking_for]); + goto media_picked; + } + } + /* Start sensing first non-full-duplex media. */ + for (i = tp->mtable->leafcount - 1; + (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) + ; + media_picked: + + tp->csr6 = 0; + tp->cur_index = i; + tp->nwayset = 0; + + if (tp->if_port) { + if (tp->chip_id == DC21143 && media_cap[tp->if_port] & MediaIsMII) { + /* We must reset the media CSRs when we force-select MII mode. */ + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + outl(0x0008, ioaddr + CSR15); + } + select_media(nic, 1); + return; + } + switch(tp->chip_id) { + case DC21041: + /* tp->nway = 1;*/ + nway_start(nic); + break; + case DC21142: + if (tp->mii_cnt) { + select_media(nic, 1); +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: Using MII transceiver %d, status %hX.\n", + tp->nic_name, tp->phys[0], mdio_read(nic, tp->phys[0], 1)); +#endif + outl(0x82020000, ioaddr + CSR6); + tp->csr6 = 0x820E0000; + tp->if_port = 11; + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + } else + nway_start(nic); + break; + case PNIC2: + nway_start(nic); + break; + case LC82C168: + if (tp->mii_cnt) { + tp->if_port = 11; + tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0001, ioaddr + CSR15); + } else if (inl(ioaddr + CSR5) & TPLnkPass) + pnic_do_nway(nic); + else { + /* Start with 10mbps to do autonegotiation. */ + outl(0x32, ioaddr + CSR12); + tp->csr6 = 0x00420000; + outl(0x0001B078, ioaddr + 0xB8); + outl(0x0201B078, ioaddr + 0xB8); + } + break; + case MX98713: case COMPEX9881: + tp->if_port = 0; + tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + break; + case MX98715: case MX98725: + /* Provided by BOLO, Macronix - 12/10/1998. */ + tp->if_port = 0; + tp->csr6 = 0x01a80200; + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); + break; + case COMET: + tp->if_port = 0; + tp->csr6 = 0x00040000; + break; + case AX88140: case AX88141: + tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100; + break; + default: + select_media(nic, 1); + } +} + +static void pnic_do_nway(struct nic *nic) +{ + u32 phy_reg = inl(ioaddr + 0xB8); + u32 new_csr6 = tp->csr6 & ~0x40C40200; + +#ifdef TULIP_DEBUG_WHERE + whereami("pnic_do_nway\n"); +#endif + + if (phy_reg & 0x78000000) { /* Ignore baseT4 */ + if (phy_reg & 0x20000000) tp->if_port = 5; + else if (phy_reg & 0x40000000) tp->if_port = 3; + else if (phy_reg & 0x10000000) tp->if_port = 4; + else if (phy_reg & 0x08000000) tp->if_port = 0; + tp->nwayset = 1; + new_csr6 = (tp->if_port & 1) ? 0x01860000 : 0x00420000; + outl(0x32 | (tp->if_port & 1), ioaddr + CSR12); + if (tp->if_port & 1) + outl(0x1F868, ioaddr + 0xB8); + if (phy_reg & 0x30000000) { + tp->full_duplex = 1; + new_csr6 |= 0x00000200; + } +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: PNIC autonegotiated status %X, %s.\n", + tp->nic_name, phy_reg, medianame[tp->if_port]); +#endif + if (tp->csr6 != new_csr6) { + tp->csr6 = new_csr6; + outl(tp->csr6 | 0x0002, ioaddr + CSR6); /* Restart Tx */ + outl(tp->csr6 | 0x2002, ioaddr + CSR6); + } + } +} + +/* Set up the transceiver control registers for the selected media type. */ +static void select_media(struct nic *nic, int startup) +{ + struct mediatable *mtable = tp->mtable; + u32 new_csr6; + int i; + +#ifdef TULIP_DEBUG_WHERE + whereami("select_media\n"); +#endif + + if (mtable) { + struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; + unsigned char *p = mleaf->leafdata; + switch (mleaf->type) { + case 0: /* 21140 non-MII xcvr. */ +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: Using a 21140 non-MII transceiver" + " with control setting %hhX.\n", + tp->nic_name, p[1]); +#endif + tp->if_port = p[0]; + if (startup) + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + outl(p[1], ioaddr + CSR12); + new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); + break; + case 2: case 4: { + u16 setup[5]; + u32 csr13val, csr14val, csr15dir, csr15val; + for (i = 0; i < 5; i++) + setup[i] = get_u16(&p[i*2 + 1]); + + tp->if_port = p[0] & 15; + if (media_cap[tp->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + + if (startup && mtable->has_reset) { + struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; + unsigned char *rst = rleaf->leafdata; +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: Resetting the transceiver.\n", + tp->nic_name); +#endif + for (i = 0; i < rst[0]; i++) + outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); + } +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: 21143 non-MII %s transceiver control " + "%hX/%hX.\n", + tp->nic_name, medianame[tp->if_port], setup[0], setup[1]); +#endif + if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ + csr13val = setup[0]; + csr14val = setup[1]; + csr15dir = (setup[3]<<16) | setup[2]; + csr15val = (setup[4]<<16) | setup[2]; + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + outl(csr13val, ioaddr + CSR13); + } else { + csr13val = 1; + csr14val = 0x0003FF7F; + csr15dir = (setup[0]<<16) | 0x0008; + csr15val = (setup[1]<<16) | 0x0008; + if (tp->if_port <= 4) + csr14val = t21142_csr14[tp->if_port]; + if (startup) { + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + } + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + if (startup) outl(csr13val, ioaddr + CSR13); + } +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: Setting CSR15 to %X/%X.\n", + tp->nic_name, csr15dir, csr15val); +#endif + if (mleaf->type == 4) + new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); + else + new_csr6 = 0x82420000; + break; + } + case 1: case 3: { + int phy_num = p[0]; + int init_length = p[1]; + u16 *misc_info; + + tp->if_port = 11; + new_csr6 = 0x020E0000; + if (mleaf->type == 3) { /* 21142 */ + u16 *init_sequence = (u16*)(p+2); + u16 *reset_sequence = &((u16*)(p+3))[init_length]; + int reset_length = p[2 + init_length*2]; + misc_info = reset_sequence + reset_length; + if (startup) + for (i = 0; i < reset_length; i++) + outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); + for (i = 0; i < init_length; i++) + outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); + } else { + u8 *init_sequence = p + 2; + u8 *reset_sequence = p + 3 + init_length; + int reset_length = p[2 + init_length]; + misc_info = (u16*)(reset_sequence + reset_length); + if (startup) { + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + for (i = 0; i < reset_length; i++) + outl(reset_sequence[i], ioaddr + CSR12); + } + for (i = 0; i < init_length; i++) + outl(init_sequence[i], ioaddr + CSR12); + } + tp->advertising[phy_num] = get_u16(&misc_info[1]) | 1; + if (startup < 2) { + if (tp->mii_advertise == 0) + tp->mii_advertise = tp->advertising[phy_num]; +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: Advertising %hX on MII %d.\n", + tp->nic_name, tp->mii_advertise, tp->phys[phy_num]); +#endif + mdio_write(nic, tp->phys[phy_num], 4, tp->mii_advertise); + } + break; + } + default: + printf("%s: Invalid media table selection %d.\n", + tp->nic_name, mleaf->type); + new_csr6 = 0x020E0000; + } +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: Using media type %s, CSR12 is %hhX.\n", + tp->nic_name, medianame[tp->if_port], + inl(ioaddr + CSR12) & 0xff); +#endif + } else if (tp->chip_id == DC21041) { + int port = tp->if_port <= 4 ? tp->if_port : 0; +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: 21041 using media %s, CSR12 is %hX.\n", + tp->nic_name, medianame[port == 3 ? 12: port], + inl(ioaddr + CSR12)); +#endif + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + outl(t21041_csr14[port], ioaddr + CSR14); + outl(t21041_csr15[port], ioaddr + CSR15); + outl(t21041_csr13[port], ioaddr + CSR13); + new_csr6 = 0x80020000; + } else if (tp->chip_id == LC82C168) { + if (startup && ! tp->medialock) + tp->if_port = tp->mii_cnt ? 11 : 0; +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: PNIC PHY status is %hX, media %s.\n", + tp->nic_name, inl(ioaddr + 0xB8), medianame[tp->if_port]); +#endif + if (tp->mii_cnt) { + new_csr6 = 0x810C0000; + outl(0x0001, ioaddr + CSR15); + outl(0x0201B07A, ioaddr + 0xB8); + } else if (startup) { + /* Start with 10mbps to do autonegotiation. */ + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x0001B078, ioaddr + 0xB8); + outl(0x0201B078, ioaddr + 0xB8); + } else if (tp->if_port == 3 || tp->if_port == 5) { + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + /* Trigger autonegotiation. */ + outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8); + } else { + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + } else if (tp->chip_id == DC21040) { /* 21040 */ + /* Turn on the xcvr interface. */ + int csr12 = inl(ioaddr + CSR12); +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: 21040 media type is %s, CSR12 is %hhX.\n", + tp->nic_name, medianame[tp->if_port], csr12); +#endif + if (media_cap[tp->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + new_csr6 = 0x20000; + /* Set the full duplux match frame. */ + outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + if (t21040_csr13[tp->if_port] & 8) { + outl(0x0705, ioaddr + CSR14); + outl(0x0006, ioaddr + CSR15); + } else { + outl(0xffff, ioaddr + CSR14); + outl(0x0000, ioaddr + CSR15); + } + outl(0x8f01 | t21040_csr13[tp->if_port], ioaddr + CSR13); + } else { /* Unknown chip type with no media table. */ + if (tp->default_port == 0) + tp->if_port = tp->mii_cnt ? 11 : 3; + if (media_cap[tp->if_port] & MediaIsMII) { + new_csr6 = 0x020E0000; + } else if (media_cap[tp->if_port] & MediaIsFx) { + new_csr6 = 0x028600000; + } else + new_csr6 = 0x038600000; +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: No media description table, assuming " + "%s transceiver, CSR12 %hhX.\n", + tp->nic_name, medianame[tp->if_port], + inl(ioaddr + CSR12)); +#endif + } + + tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); + return; +} + +/* + Check the MII negotiated duplex and change the CSR6 setting if + required. + Return 0 if everything is OK. + Return < 0 if the transceiver is missing or has no link beat. +*/ +static int tulip_check_duplex(struct nic *nic) +{ + unsigned int bmsr, lpa, negotiated, new_csr6; + + bmsr = mdio_read(nic, tp->phys[0], 1); + lpa = mdio_read(nic, tp->phys[0], 5); + +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: MII status %#x, Link partner report " + "%#x.\n", tp->nic_name, bmsr, lpa); +#endif + + if (bmsr == 0xffff) + return -2; + if ((bmsr & 4) == 0) { + int new_bmsr = mdio_read(nic, tp->phys[0], 1); + if ((new_bmsr & 4) == 0) { +#ifdef TULIP_DEBUG + if (tulip_debug > 1) + printf("%s: No link beat on the MII interface," + " status %#x.\n", tp->nic_name, + new_bmsr); +#endif + return -1; + } + } + tp->full_duplex = lpa & 0x140; + + new_csr6 = tp->csr6; + negotiated = lpa & tp->advertising[0]; + + if(negotiated & 0x380) new_csr6 &= ~0x400000; + else new_csr6 |= 0x400000; + if (tp->full_duplex) new_csr6 |= 0x200; + else new_csr6 &= ~0x200; + + if (new_csr6 != tp->csr6) { + tp->csr6 = new_csr6; + +#ifdef TULIP_DEBUG + if (tulip_debug > 0) + printf("%s: Setting %s-duplex based on MII" + "#%d link partner capability of %#x.\n", + tp->nic_name, + tp->full_duplex ? "full" : "half", + tp->phys[0], lpa); +#endif + return 1; + } + + return 0; } diff --git a/netboot/via-rhine.c b/netboot/via-rhine.c index 3e2b275b1..070edb840 100644 --- a/netboot/via-rhine.c +++ b/netboot/via-rhine.c @@ -688,12 +688,12 @@ rhine_init_ring (struct nic *nic) tp->rx_ring[i].buf_addr_1 = virt_to_bus (tp->rx_buffs[i]); tp->rx_ring[i].buf_addr_2 = virt_to_bus (&tp->rx_ring[i + 1]); - /* printf("[%d]buf1=%x,buf2=%x",i,tp->rx_ring[i].buf_addr_1,tp->rx_ring[i].buf_addr_2); */ + /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->rx_ring[i].buf_addr_1,tp->rx_ring[i].buf_addr_2); */ } /* Mark the last entry as wrapping the ring. */ /* tp->rx_ring[i-1].rx_ctrl.bits.rx_buf_size =1518; */ tp->rx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->rx_ring[0]); - /*printf("[%d]buf1=%x,buf2=%x",i-1,tp->rx_ring[i-1].buf_addr_1,tp->rx_ring[i-1].buf_addr_2); */ + /*printf("[%d]buf1=%hX,buf2=%hX",i-1,tp->rx_ring[i-1].buf_addr_1,tp->rx_ring[i-1].buf_addr_2); */ /* The Tx buffer descriptor is filled in as needed, but we do need to clear the ownership bit. */ @@ -705,11 +705,11 @@ rhine_init_ring (struct nic *nic) tp->tx_ring[i].tx_ctrl.lw = 0x00e08000; tp->tx_ring[i].buf_addr_1 = virt_to_bus (tp->tx_buffs[i]); tp->tx_ring[i].buf_addr_2 = virt_to_bus (&tp->tx_ring[i + 1]); - /* printf("[%d]buf1=%x,buf2=%x",i,tp->tx_ring[i].buf_addr_1,tp->tx_ring[i].buf_addr_2); */ + /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i].buf_addr_1,tp->tx_ring[i].buf_addr_2); */ } tp->tx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->tx_ring[0]); - /* printf("[%d]buf1=%x,buf2=%x",i,tp->tx_ring[i-1].buf_addr_1,tp->tx_ring[i-1].buf_addr_2); */ + /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i-1].buf_addr_1,tp->tx_ring[i-1].buf_addr_2); */ } int @@ -717,33 +717,24 @@ QueryAuto (int ioaddr) { int byMIIIndex; int MIIReturn; - int FDXFlag; - byMIIIndex = 0x06; - MIIReturn = ReadMII (byMIIIndex, ioaddr); - if ((MIIReturn & 0x01) == 0) - { - FDXFlag = 0; - return FDXFlag; - } - byMIIIndex = 0x05; - MIIReturn = ReadMII (byMIIIndex, ioaddr); - if ((MIIReturn & 0x0140) == 0) - { - FDXFlag = 0; - return FDXFlag; - } + int advertising,mii_reg5; + int negociated; byMIIIndex = 0x04; MIIReturn = ReadMII (byMIIIndex, ioaddr); - if ((MIIReturn & 0x0140) == 0) - { - FDXFlag = 0; - return FDXFlag; - } + advertising=MIIReturn; - FDXFlag = 1; - return FDXFlag; + byMIIIndex = 0x05; + MIIReturn = ReadMII (byMIIIndex, ioaddr); + mii_reg5=MIIReturn; + + negociated=mii_reg5 & advertising; + + if ( (negociated & 0x100) || (negociated & 0x1C0) == 0x40 ) + return 1; + else + return 0; } @@ -867,35 +858,12 @@ struct nic * rhine_probe (struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci) { - unsigned char pci_latency; - unsigned short pci_command; - if (!pci->ioaddr) return NULL; nic = rhine_probe1 (nic, pci->ioaddr, 0, -1); if (nic) - { - /* Get and check the bus-master and latency values. */ - pcibios_read_config_word (0, pci->devfn, PCI_COMMAND, &pci_command); - if (!(pci_command & PCI_COMMAND_MASTER)) - { - printf (" PCI Master Bit has not been set! Setting...\n"); - pci_command |= PCI_COMMAND_MASTER; - pcibios_write_config_word (0, pci->devfn, PCI_COMMAND, - pci_command); - } - pcibios_read_config_byte (0, pci->devfn, PCI_LATENCY_TIMER, - &pci_latency); - if (pci_latency < 10) - { - printf (" PCI latency timer (CFLT) is unreasonably low " - "at %d. Setting to 64 clocks.\n", pci_latency); - pcibios_write_config_byte (0, pci->devfn, PCI_LATENCY_TIMER, 64); - } - else if (rhine_debug > 1) - printf (" PCI latency timer (CFLT) is %#x.\n", pci_latency); - } + adjust_pci_device(pci); nic->poll = rhine_poll; nic->transmit = rhine_transmit; nic->reset = rhine_reset; @@ -917,14 +885,10 @@ rhine_probe1 (struct nic *nic, int ioaddr, int chip_id, int options) if (rhine_debug > 0 && did_version++ == 0) printf (version); - printf ("IO adress %x ", ioaddr); /* Perhaps this should be read from the EEPROM? */ - for (i = 0; i < 6; i++) + for (i = 0; i < ETH_ALEN; i++) nic->node_addr[i] = inb (byPAR0 + i); - printf ("Ethernet Address: "); - for (i = 0; i < 5; i++) - printf ("0x%b:", nic->node_addr[i]); - printf ("0x%b\n", nic->node_addr[i]); + printf ("IO address %hX Ethernet Address: %!\n", ioaddr, nic->node_addr); /* restart MII auto-negotiation */ WriteMII (0, 9, 1, ioaddr); @@ -939,10 +903,27 @@ rhine_probe1 (struct nic *nic, int ioaddr, int chip_id, int options) break; } printf ("OK\n"); + +#if 0 + /* JJM : for Debug */ + printf("MII : Address %hhX ",inb(ioaddr+0x6c)); + { + unsigned char st1,st2,adv1,adv2,l1,l2; + + st1=ReadMII(1,ioaddr)>>8; + st2=ReadMII(1,ioaddr)&0xFF; + adv1=ReadMII(4,ioaddr)>>8; + adv2=ReadMII(4,ioaddr)&0xFF; + l1=ReadMII(5,ioaddr)>>8; + l2=ReadMII(5,ioaddr)&0xFF; + printf(" status 0x%hhX%hhX, advertising 0x%hhX%hhX, link 0x%hhX%hhX\n", st1,st2,adv1,adv2,l1,l2); + } +#endif + /* query MII to know LineSpeed,duplex mode */ byMIIvalue = inb (ioaddr + 0x6d); LineSpeed = byMIIvalue & MIISR_SPEED; - if (LineSpeed == 1) + if (LineSpeed != 0) //JJM { printf ("Linespeed=10Mbs"); } @@ -950,6 +931,7 @@ rhine_probe1 (struct nic *nic, int ioaddr, int chip_id, int options) { printf ("Linespeed=100Mbs"); } + FDXFlag = QueryAuto (ioaddr); if (FDXFlag == 1) { @@ -961,6 +943,7 @@ rhine_probe1 (struct nic *nic, int ioaddr, int chip_id, int options) printf (" Halfduplex\n"); } + /* set MII 10 FULL ON */ WriteMII (17, 1, 1, ioaddr); @@ -994,8 +977,14 @@ rhine_probe1 (struct nic *nic, int ioaddr, int chip_id, int options) static void rhine_disable (struct nic *nic) { + struct rhine_private *tp = (struct rhine_private *) nic->priv_data; + int ioaddr = tp->ioaddr; + printf ("rhine disable\n"); - /* nothing for the moment */ + /* Switch to loopback mode to avoid hardware races. */ + writeb(0x60 | 0x01, byTCR); + /* Stop the chip's Tx and Rx processes. */ + writew(CR_STOP, byCR0); } /************************************************************************** @@ -1013,7 +1002,7 @@ rhine_reset (struct nic *nic) int rx_bufs_tmp, rx_bufs_tmp1; int tx_bufs_tmp, tx_bufs_tmp1; -#ifndef USE_INTERNAL_BUFFER +#ifdef USE_LOWMEM_BUFFER #define buf1 (0x10000 - (RX_RING_SIZE * PKT_BUF_SZ + 32)) #define buf2 (buf1 - (RX_RING_SIZE * PKT_BUF_SZ + 32)) #define desc1 (buf2 - (TX_RING_SIZE * sizeof (struct rhine_tx_desc) + 32)) @@ -1043,33 +1032,37 @@ rhine_reset (struct nic *nic) tx_ring_tmp1 = (int) virt_to_bus ((char *) tx_ring_tmp); j = (tx_ring_tmp1 + 32) & (~0x1f); tp->tx_ring = (struct rhine_tx_desc *) bus_to_virt (j); - /* printf ("rxring[%x]", j); */ + /* printf ("rxring[%X]", j); */ tx_bufs_tmp1 = (int) virt_to_bus ((char *) tx_bufs_tmp); j = (int) (tx_bufs_tmp1 + 32) & (~0x1f); tx_bufs_tmp = (int) bus_to_virt (j); - /* printf ("txb[%x]", j); */ + /* printf ("txb[%X]", j); */ rx_bufs_tmp1 = (int) virt_to_bus ((char *) rx_bufs_tmp); j = (int) (rx_bufs_tmp1 + 32) & (~0x1f); rx_bufs_tmp = (int) bus_to_virt (j); - /* printf ("rxb[%x][%x]", rx_bufs_tmp1, j); */ + /* printf ("rxb[%X][%X]", rx_bufs_tmp1, j); */ for (i = 0; i < RX_RING_SIZE; i++) { tp->rx_buffs[i] = (char *) rx_bufs_tmp; - /* printf("r[%x]",tp->rx_buffs[i]); */ + /* printf("r[%X]",tp->rx_buffs[i]); */ rx_bufs_tmp += 1536; } for (i = 0; i < TX_RING_SIZE; i++) { tp->tx_buffs[i] = (char *) tx_bufs_tmp; - /* printf("t[%x]",tp->tx_buffs[i]); */ + /* printf("t[%X]",tp->tx_buffs[i]); */ tx_bufs_tmp += 1536; } + /* software reset */ + outb (CR1_SFRST, byCR1); + MIIDelay (); + /* printf ("init ring"); */ rhine_init_ring (nic); /*write TD RD Descriptor to MAC */ @@ -1079,9 +1072,6 @@ rhine_reset (struct nic *nic) /* close IMR */ outw (0x0000, byIMR0); - /* software reset */ - outb (CR1_SFRST, byCR1); - MIIDelay (); /* set TCR RCR threshold */ outb (0x06, byBCR0); outb (0x00, byBCR1); @@ -1119,7 +1109,7 @@ rhine_poll (struct nic *nic) } else if (rxstatus & (RSR_ABNORMAL)) { - printf ("rxerr[%x]\n", rxstatus); + printf ("rxerr[%X]\n", rxstatus); } else good = 1; @@ -1153,16 +1143,16 @@ rhine_transmit (struct nic *nic, /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % TX_RING_SIZE; - memcpy ((void *) tp->tx_buffs[entry], d, ETHER_ADDR_SIZE); /* dst */ - memcpy ((void *) tp->tx_buffs[entry] + ETHER_ADDR_SIZE, nic->node_addr, ETHER_ADDR_SIZE); /* src */ + memcpy (tp->tx_buffs[entry], d, ETH_ALEN); /* dst */ + memcpy (tp->tx_buffs[entry] + ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ *((char *) tp->tx_buffs[entry] + 12) = t >> 8; /* type */ *((char *) tp->tx_buffs[entry] + 13) = t; - memcpy ((void *) tp->tx_buffs[entry] + ETHER_HDR_SIZE, p, s); - s += ETHER_HDR_SIZE; - while (s < ETH_MIN_PACKET) - *((char *) tp->tx_buffs[entry] + ETHER_HDR_SIZE + (s++)) = 0; + memcpy (tp->tx_buffs[entry] + ETH_HLEN, p, s); + s += ETH_HLEN; + while (s < ETH_ZLEN) + *((char *) tp->tx_buffs[entry] + ETH_HLEN + (s++)) = 0; - tp->tx_ring[entry].tx_ctrl.bits.tx_buf_size = ETHER_HDR_SIZE + s; + tp->tx_ring[entry].tx_ctrl.bits.tx_buf_size = ETH_HLEN + s; tp->tx_ring[entry].tx_status.bits.own_bit = 1; @@ -1170,14 +1160,14 @@ rhine_transmit (struct nic *nic, CR1bak = inb (byCR1); CR1bak = CR1bak | CR1_TDMD1; - /*printf("tdsw=[%x]",tp->tx_ring[entry].tx_status.lw); */ - /*printf("tdcw=[%x]",tp->tx_ring[entry].tx_ctrl.lw); */ - /*printf("tdbuf1=[%x]",tp->tx_ring[entry].buf_addr_1); */ - /*printf("tdbuf2=[%x]",tp->tx_ring[entry].buf_addr_2); */ - /*printf("td1=[%x]",inl(dwCurrentTDSE0)); */ - /*printf("td2=[%x]",inl(dwCurrentTDSE1)); */ - /*printf("td3=[%x]",inl(dwCurrentTDSE2)); */ - /*printf("td4=[%x]",inl(dwCurrentTDSE3)); */ + /*printf("tdsw=[%X]",tp->tx_ring[entry].tx_status.lw); */ + /*printf("tdcw=[%X]",tp->tx_ring[entry].tx_ctrl.lw); */ + /*printf("tdbuf1=[%X]",tp->tx_ring[entry].buf_addr_1); */ + /*printf("tdbuf2=[%X]",tp->tx_ring[entry].buf_addr_2); */ + /*printf("td1=[%X]",inl(dwCurrentTDSE0)); */ + /*printf("td2=[%X]",inl(dwCurrentTDSE1)); */ + /*printf("td3=[%X]",inl(dwCurrentTDSE2)); */ + /*printf("td4=[%X]",inl(dwCurrentTDSE3)); */ outb (CR1bak, byCR1); tp->cur_tx++; diff --git a/netboot/w89c840.c b/netboot/w89c840.c new file mode 100644 index 000000000..cc268c66f --- /dev/null +++ b/netboot/w89c840.c @@ -0,0 +1,934 @@ +/* + * Etherboot - BOOTP/TFTP Bootstrap Program + * + * w89c840.c -- This file implements the winbond-840 driver for etherboot. + * + */ + +/* + * Adapted by Igor V. Kovalenko + * -- + * OR + * -- + * Initial adaptaion stage, including testing, completed 23 August 2000. + */ + +/* + * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * date version by what + * Written: Aug 20 2000 V0.10 iko Initial revision. + * changes: Aug 22 2000 V0.90 iko Works! + * Aug 23 2000 V0.91 iko Cleanup, posted to etherboot + * maintainer. + * Aug 26 2000 V0.92 iko Fixed Rx ring handling. + * First Linux Kernel (TM) + * successfully loaded using + * this driver. + * Jan 07 2001 V0.93 iko Transmitter timeouts are handled + * using timer2 routines. Proposed + * by Ken Yap to eliminate CPU speed + * dependency. + * + * This is the etherboot driver for cards based on Winbond W89c840F chip. + * + * It was written from skeleton source, with Donald Becker's winbond-840.c + * kernel driver as a guideline. Mostly the w89c840 related definitions + * and the lower level routines have been cut-and-pasted into this source. + * + * Frankly speaking, about 90% of the code was obtained using cut'n'paste + * sequence :) while the remainder appeared while brainstorming + * Linux Kernel 2.4.0-testX source code. Thanks, Donald and Linus! + * + * There was a demand for using this card in a rather large + * remote boot environment at MSKP OVTI Lab of + * Moscow Institute for Physics and Technology (MIPT) -- http://www.mipt.ru/ + * so you may count that for motivation. + * + */ + +/* + * If you want to see debugging output then define W89C840_DEBUG + */ + +/* +#define W89C840_DEBUG +*/ + +/* + * Keep using IO_OPS for Etherboot driver! + */ +#define USE_IO_OPS + +#include "etherboot.h" +#include "nic.h" +#include "pci.h" +#include "cards.h" +#include "timer.h" + +static const char *w89c840_version = "diver Version 0.92 - August 27, 2000"; + +typedef unsigned char u8; +typedef signed char s8; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned int u32; +typedef signed int s32; + +/* Linux support functions */ +#define virt_to_bus(x) ((unsigned long)x) +#define bus_to_virt(x) ((void *)x) + +#define virt_to_le32desc(addr) virt_to_bus(addr) +#define le32desc_to_virt(addr) bus_to_virt(addr) + +/* +#define cpu_to_le32(val) (val) +#define le32_to_cpu(val) (val) +*/ + +/* Operational parameters that are set at compile time. */ + +/* Keep the ring sizes a power of two for compile efficiency. + The compiler will convert '%'<2^N> into a bit mask. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 2 + +#define RX_RING_SIZE 2 + +/* The presumed FIFO size for working around the Tx-FIFO-overflow bug. + To avoid overflowing we don't queue again until we have room for a + full-size packet. + */ +#define TX_FIFO_SIZE (2048) +#define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16) + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (10*TICKS_PER_MS) + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +/* + * Used to be this much CPU loops on Celeron@400 (?), + * now using real timer and TX_TIMEOUT! + * #define TX_LOOP_COUNT 10000000 + */ + +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +enum chip_capability_flags {CanHaveMII=1, HasBrokenTx=2}; + +#ifdef USE_IO_OPS +#define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER) +#else +#define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER) +#endif + +static u32 driver_flags = CanHaveMII | HasBrokenTx; + +/* This driver was written to use PCI memory space, however some x86 systems + work only with I/O space accesses. Pass -DUSE_IO_OPS to use PCI I/O space + accesses instead of memory space. */ + +#ifdef USE_IO_OPS +#undef readb +#undef readw +#undef readl +#undef writeb +#undef writew +#undef writel +#define readb inb +#define readw inw +#define readl inl +#define writeb outb +#define writew outw +#define writel outl +#endif + +/* Offsets to the Command and Status Registers, "CSRs". + While similar to the Tulip, these registers are longword aligned. + Note: It's not useful to define symbolic names for every register bit in + the device. The name can only partially document the semantics and make + the driver longer and more difficult to read. +*/ +enum w840_offsets { + PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08, + RxRingPtr=0x0C, TxRingPtr=0x10, + IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C, + RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C, + CurRxDescAddr=0x30, CurRxBufAddr=0x34, /* Debug use */ + MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40, + CurTxDescAddr=0x4C, CurTxBufAddr=0x50, +}; + +/* Bits in the interrupt status/enable registers. */ +/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */ +enum intr_status_bits { + NormalIntr=0x10000, AbnormalIntr=0x8000, + IntrPCIErr=0x2000, TimerInt=0x800, + IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40, + TxFIFOUnderflow=0x20, RxErrIntr=0x10, + TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01, +}; + +/* Bits in the NetworkConfig register. */ +enum rx_mode_bits { + AcceptErr=0x80, AcceptRunt=0x40, + AcceptBroadcast=0x20, AcceptMulticast=0x10, + AcceptAllPhys=0x08, AcceptMyPhys=0x02, +}; + +enum mii_reg_bits { + MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000, + MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000, +}; + +/* The Tulip Rx and Tx buffer descriptors. */ +struct w840_rx_desc { + s32 status; + s32 length; + u32 buffer1; + u32 next_desc; +}; + +struct w840_tx_desc { + s32 status; + s32 length; + u32 buffer1, buffer2; /* We use only buffer 1. */ +}; + +/* Bits in network_desc.status */ +enum desc_status_bits { + DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000, + DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000, + DescIntr=0x80000000, +}; +#define PRIV_ALIGN 15 /* Required alignment mask */ +#define PRIV_ALIGN_BYTES 32 + +static struct winbond_private +{ + /* Descriptor rings first for alignment. */ + struct w840_rx_desc rx_ring[RX_RING_SIZE]; + struct w840_tx_desc tx_ring[TX_RING_SIZE]; + struct net_device *next_module; /* Link for devices of this type. */ + void *priv_addr; /* Unaligned address for kfree */ + const char *product_name; + /* Frequently used values: keep some adjacent for cache effect. */ + int chip_id, drv_flags; + struct pci_dev *pci_dev; + int csr6; + struct w840_rx_desc *rx_head_desc; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int cur_tx, dirty_tx; + int tx_q_bytes; + unsigned int tx_full:1; /* The Tx queue is full. */ + /* These values are keep track of the transceiver/media in use. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + /* MII transceiver section. */ + int mii_cnt; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ + unsigned char phys[2]; /* MII device addresses. */ +} w840private __attribute__ ((aligned (PRIV_ALIGN_BYTES))); + +/* NIC specific static variables go here */ + +static int ioaddr; +static unsigned short eeprom [0x40]; + +#ifdef USE_LOWMEM_BUFFER +#define rx_packet ((char *)0x10000 - PKT_BUF_SZ * RX_RING_SIZE) +#define tx_packet ((char *)0x10000 - PKT_BUF_SZ * RX_RING_SIZE - PKT_BUF_SZ * TX_RING_SIZE) +#else +static char rx_packet[PKT_BUF_SZ * RX_RING_SIZE]; +static char tx_packet[PKT_BUF_SZ * TX_RING_SIZE]; +#endif + +static int eeprom_read(long ioaddr, int location); +static int mdio_read(int base_address, int phy_id, int location); +static void mdio_write(int base_address, int phy_id, int location, int value); + +static void check_duplex(void); +static void set_rx_mode(void); +static void init_ring(void); + +/* +static void wait_long_time(void) +{ + printf("Paused - please read output above this line\n"); + sleep(3); +} +*/ + +#if defined W89C840_DEBUG +static void decode_interrupt(u32 intr_status) +{ + printf("Interrupt status: "); + +#define TRACE_INTR(_intr_) \ + if (intr_status & (_intr_)) { printf (" " #_intr_); } + + TRACE_INTR(NormalIntr); + TRACE_INTR(AbnormalIntr); + TRACE_INTR(IntrPCIErr); + TRACE_INTR(TimerInt); + TRACE_INTR(IntrRxDied); + TRACE_INTR(RxNoBuf); + TRACE_INTR(IntrRxDone); + TRACE_INTR(TxFIFOUnderflow); + TRACE_INTR(RxErrIntr); + TRACE_INTR(TxIdle); + TRACE_INTR(IntrTxStopped); + TRACE_INTR(IntrTxDone); + + printf("\n"); + /*sleep(1);*/ +} +#endif + +/************************************************************************** +w89c840_reset - Reset adapter +***************************************************************************/ +static void w89c840_reset(struct nic *nic) +{ + int i; + + /* Reset the chip to erase previous misconfiguration. + No hold time required! */ + writel(0x00000001, ioaddr + PCIBusCfg); + + init_ring(); + + writel(virt_to_bus(w840private.rx_ring), ioaddr + RxRingPtr); + writel(virt_to_bus(w840private.tx_ring), ioaddr + TxRingPtr); + + for (i = 0; i < ETH_ALEN; i++) + writeb(nic->node_addr[i], ioaddr + StationAddr + i); + + /* Initialize other registers. */ + /* Configure the PCI bus bursts and FIFO thresholds. + 486: Set 8 longword cache alignment, 8 longword burst. + 586: Set 16 longword cache alignment, no burst limit. + Cache alignment bits 15:14 Burst length 13:8 + 0000 0000 align to cache 0800 8 longwords + 4000 8 longwords 0100 1 longword 1000 16 longwords + 8000 16 longwords 0200 2 longwords 2000 32 longwords + C000 32 longwords 0400 4 longwords + Wait the specified 50 PCI cycles after a reset by initializing + Tx and Rx queues and the address filter list. */ + + writel(0xE010, ioaddr + PCIBusCfg); + + writel(0, ioaddr + RxStartDemand); + w840private.csr6 = 0x20022002; + check_duplex(); + set_rx_mode(); + + /* Clear and Enable interrupts by setting the interrupt mask. */ + writel(0x1A0F5, ioaddr + IntrStatus); + writel(0x1A0F5, ioaddr + IntrEnable); + +#if defined(W89C840_DEBUG) + printf("winbond-840 : Done reset.\n"); +#endif +} + +static void handle_intr(u32 intr_stat) +{ + if ((intr_stat & (NormalIntr|AbnormalIntr)) == 0) { + /* we are polling, do not return now */ + /*return 0;*/ + } else { + /* Acknowledge all of the current interrupt sources ASAP. */ + writel(intr_stat & 0x001ffff, ioaddr + IntrStatus); + } + + if (intr_stat & AbnormalIntr) { + /* There was an abnormal interrupt */ + printf("\n-=- Abnormal interrupt.\n"); + +#if defined (W89C840_DEBUG) + decode_interrupt(intr_stat); +#endif + + if (intr_stat & RxNoBuf) { + /* There was an interrupt */ + printf("-=- <=> No receive buffers available.\n"); + writel(0, ioaddr + RxStartDemand); + } + } +} + +/************************************************************************** +w89c840_poll - Wait for a frame +***************************************************************************/ +static int w89c840_poll(struct nic *nic) +{ + /* return true if there's an ethernet packet ready to read */ + /* nic->packet should contain data on return */ + /* nic->packetlen should contain length of data */ + int packet_received = 0; + + u32 intr_status = readl(ioaddr + IntrStatus); + /* handle_intr(intr_status); */ /* -- handled later */ + + do { + /* Code from netdev_rx(dev) */ + + int entry = w840private.cur_rx % RX_RING_SIZE; + + struct w840_rx_desc *desc = w840private.rx_head_desc; + s32 status = desc->status; + + if (status & DescOwn) { + /* DescOwn bit is still set, we should wait for RX to complete */ + packet_received = 0; + break; + } + + if ((status & 0x38008300) != 0x0300) { + if ((status & 0x38000300) != 0x0300) { + /* Ingore earlier buffers. */ + if ((status & 0xffff) != 0x7fff) { + printf("winbond-840 : Oversized Ethernet frame spanned " + "multiple buffers, entry %d status %X !\n", + w840private.cur_rx, status); + } + } else if (status & 0x8000) { + /* There was a fatal error. */ +#if defined(W89C840_DEBUG) + printf("winbond-840 : Receive error, Rx status %X :", status); + if (status & 0x0890) { + printf(" RXLEN_ERROR"); + } + if (status & 0x004C) { + printf(", FRAME_ERROR"); + } + if (status & 0x0002) { + printf(", CRC_ERROR"); + } + printf("\n"); +#endif + + /* Simpy do a reset now... */ + w89c840_reset(nic); + + packet_received = 0; + break; + } + } else { + /* Omit the four octet CRC from the length. */ + int pkt_len = ((status >> 16) & 0x7ff) - 4; + +#if defined(W89C840_DEBUG) + printf(" netdev_rx() normal Rx pkt ring %d length %d status %X\n", entry, pkt_len, status); +#endif + + nic->packetlen = pkt_len; + + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + + memcpy(nic->packet, le32desc_to_virt(w840private.rx_ring[entry].buffer1), pkt_len); + packet_received = 1; + + /* Release buffer to NIC */ + w840private.rx_ring[entry].status = DescOwn; + +#if defined(W89C840_DEBUG) + /* You will want this info for the initial debug. */ + printf(" Rx data %hhX:%hhX:%hhX:%hhX:%hhX:" + "%hhX %hhX:%hhX:%hhX:%hhX:%hhX:%hhX %hhX%hhX " + "%hhX.%hhX.%hhX.%hhX.\n", + nic->packet[0], nic->packet[1], nic->packet[2], nic->packet[3], + nic->packet[4], nic->packet[5], nic->packet[6], nic->packet[7], + nic->packet[8], nic->packet[9], nic->packet[10], + nic->packet[11], nic->packet[12], nic->packet[13], + nic->packet[14], nic->packet[15], nic->packet[16], + nic->packet[17]); +#endif + + } + + entry = (++w840private.cur_rx) % RX_RING_SIZE; + w840private.rx_head_desc = &w840private.rx_ring[entry]; + } while (0); + + if (intr_status & (AbnormalIntr | TxFIFOUnderflow | IntrPCIErr |TimerInt | IntrTxStopped)) { + handle_intr(intr_status); + } + + return packet_received; +} + +/************************************************************************** +w89c840_transmit - Transmit a frame +***************************************************************************/ + +static void w89c840_transmit( + struct nic *nic, + const char *d, /* Destination */ + unsigned int t, /* Type */ + unsigned int s, /* size */ + const char *p) /* Packet */ +{ + /* send the packet to destination */ + unsigned entry; + int transmit_status; + + /* Caution: the write order is important here, set the field + with the "ownership" bits last. */ + + /* Fill in our transmit buffer */ + entry = w840private.cur_tx % TX_RING_SIZE; + + memcpy (tx_packet, d, ETH_ALEN); /* dst */ + memcpy (tx_packet + ETH_ALEN, nic->node_addr, ETH_ALEN);/* src */ + + *((char *) tx_packet + 12) = t >> 8; /* type */ + *((char *) tx_packet + 13) = t; + + memcpy (tx_packet + ETH_HLEN, p, s); + s += ETH_HLEN; + + while (s < ETH_ZLEN) + *((char *) tx_packet + ETH_HLEN + (s++)) = 0; + + w840private.tx_ring[entry].buffer1 = virt_to_le32desc(tx_packet); + + w840private.tx_ring[entry].length = (DescWholePkt | s); + if (entry >= TX_RING_SIZE-1) /* Wrap ring */ + w840private.tx_ring[entry].length |= (DescIntr | DescEndRing); + w840private.tx_ring[entry].status = (DescOwn); + w840private.cur_tx++; + + w840private.tx_q_bytes += s; + writel(0, ioaddr + TxStartDemand); + + /* Work around horrible bug in the chip by marking the queue as full + when we do not have FIFO room for a maximum sized packet. */ + + if ((w840private.drv_flags & HasBrokenTx) && w840private.tx_q_bytes > TX_BUG_FIFO_LIMIT) { + /* Actually this is left to help finding error tails later in debugging... + * See Linux kernel driver in winbond-840.c for details. + */ + w840private.tx_full = 1; + } + +#if defined(W89C840_DEBUG) + printf("winbond-840 : Transmit frame # %d size %d queued in slot %d.\n", w840private.cur_tx, s, entry); +#endif + + /* Now wait for TX to complete. */ + transmit_status = w840private.tx_ring[entry].status; + + load_timer2(TX_TIMEOUT); + + { + u32 intr_stat = 0; + + while (1) { + + intr_stat = readl(ioaddr + IntrStatus); +#if defined(W89C840_DEBUG) + decode_interrupt(intr_stat); +#endif + + if (intr_stat & (NormalIntr | IntrTxDone)) { + + while ( (transmit_status & DescOwn) && timer2_running()) { + + transmit_status = w840private.tx_ring[entry].status; + } + + writel(intr_stat & 0x0001ffff, ioaddr + IntrStatus); + break; + } + } + } + + if ((transmit_status & DescOwn) == 0) { + +#if defined(W89C840_DEBUG) + printf("winbond-840 : transmission complete after %d wait loop iterations, status %X\n", + TX_LOOP_COUNT - transmit_loop_counter, w840private.tx_ring[entry].status); +#endif + + return; + } + + /* Transmit timed out... */ + + printf("winbond-840 : transmission TIMEOUT : status %X\n", w840private.tx_ring[entry].status); + + return; +} + +/************************************************************************** +w89c840_disable - Turn off ethernet interface +***************************************************************************/ +static void w89c840_disable(struct nic *nic) +{ + /* Don't know what to do to disable the board. Is this needed at all? */ + /* Yes, a live NIC can corrupt the loaded memory later [Ken] */ + /* Stop the chip's Tx and Rx processes. */ + writel(w840private.csr6 &= ~0x20FA, ioaddr + NetworkConfig); +} + +/************************************************************************** +w89c840_probe - Look for an adapter, this routine's visible to the outside +***************************************************************************/ +struct nic *w89c840_probe(struct nic *nic, unsigned short *probe_addrs, struct pci_device *p) +{ + u16 sum = 0; + int i, j, to; + unsigned short value; + int options; + int promisc; + + if (probe_addrs == 0 || probe_addrs[0] == 0) + return 0; + + ioaddr = probe_addrs[0]; /* Mask the bit that says "this is an io addr" */ + +#if defined(W89C840_DEBUG) + printf("winbond-840: PCI bus %hhX device function %hhX: I/O address: %hX\n", p->bus, p->devfn, ioaddr); +#endif + + ioaddr = ioaddr & ~3; /* Mask the bit that says "this is an io addr" */ + + /* if probe_addrs is 0, then routine can use a hardwired default */ + + /* From Matt Hortman */ + if (p->vendor == PCI_VENDOR_ID_WINBOND2 + && p->dev_id == PCI_DEVICE_ID_WINBOND2_89C840) { + + /* detected "Winbond W89c840 Fast Ethernet PCI NIC" */ + + } else if ( p->vendor == PCI_VENDOR_ID_COMPEX + && p->dev_id == PCI_DEVICE_ID_COMPEX_RL100ATX) { + + /* detected "Compex RL100ATX Fast Ethernet PCI NIC" */ + + } else { + /* Gee, guess what? They missed again. */ + printf("device ID : %X - is not a Compex RL100ATX NIC.\n", p->dev_id); + return 0; + } + + printf(" %s\n", w89c840_version); + + adjust_pci_device(p); + + /* Ok. Got one. Read the eeprom. */ + for (j = 0, i = 0; i < 0x40; i++) { + value = eeprom_read(ioaddr, i); + eeprom[i] = value; + sum += value; + } + + for (i=0;inode_addr[i] = (eeprom[i/2] >> (8*(i&1))) & 0xff; + } + printf ("Ethernet addr: %!\n", nic->node_addr); + +#if defined(W89C840_DEBUG) + printf("winbond-840: EEPROM checksum %hX, got eeprom", sum); +#endif + + /* Reset the chip to erase previous misconfiguration. + No hold time required! */ + writel(0x00000001, ioaddr + PCIBusCfg); + + if (driver_flags & CanHaveMII) { + int phy, phy_idx = 0; + for (phy = 1; phy < 32 && phy_idx < 4; phy++) { + int mii_status = mdio_read(ioaddr, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + w840private.phys[phy_idx++] = phy; + w840private.advertising = mdio_read(ioaddr, phy, 4); + +#if defined(W89C840_DEBUG) + printf("winbond-840 : MII PHY found at address %d, status " + "%X advertising %hX.\n", phy, mii_status, w840private.advertising); +#endif + + } + } + + w840private.mii_cnt = phy_idx; + + if (phy_idx == 0) { + printf("winbond-840 : MII PHY not found -- this device may not operate correctly.\n"); + } + } + + /* point to NIC specific routines */ + nic->reset = w89c840_reset; + nic->poll = w89c840_poll; + nic->transmit = w89c840_transmit; + nic->disable = w89c840_disable; + + w89c840_reset(nic); + + return nic; +} + +/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. These are + often serial bit streams generated by the host processor. + The example below is for the common 93c46 EEPROM, 64 16 bit words. */ + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need + a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that + made udelay() unreliable. + The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is + depricated. +*/ +#define eeprom_delay(ee_addr) readl(ee_addr) + +enum EEPROM_Ctrl_Bits { + EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805, + EE_ChipSelect=0x801, EE_DataIn=0x08, +}; + +/* The EEPROM commands include the alway-set leading bit. */ +enum EEPROM_Cmds { + EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), +}; + +static int eeprom_read(long addr, int location) +{ + int i; + int retval = 0; + int ee_addr = addr + EECtrl; + int read_cmd = location | EE_ReadCmd; + writel(EE_ChipSelect, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0; + writel(dataval, ee_addr); + eeprom_delay(ee_addr); + writel(dataval | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + } + writel(EE_ChipSelect, ee_addr); + + for (i = 16; i > 0; i--) { + writel(EE_ChipSelect | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0); + writel(EE_ChipSelect, ee_addr); + eeprom_delay(ee_addr); + } + + /* Terminate the EEPROM access. */ + writel(0, ee_addr); + return retval; +} + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. + + The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back 33Mhz PCI cycles. */ +#define mdio_delay(mdio_addr) readl(mdio_addr) + +/* Set iff a MII transceiver on any interface requires mdio preamble. + This only set with older tranceivers, so the extra + code size of a per-interface flag is not worthwhile. */ +static char mii_preamble_required = 1; + +#define MDIO_WRITE0 (MDIO_EnbOutput) +#define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput) + +/* Generate the preamble required for initial synchronization and + a few older transceivers. */ +static void mdio_sync(long mdio_addr) +{ + int bits = 32; + + /* Establish sync by sending at least 32 logic ones. */ + while (--bits >= 0) { + writel(MDIO_WRITE1, mdio_addr); + mdio_delay(mdio_addr); + writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr); + mdio_delay(mdio_addr); + } +} + +static int mdio_read(int base_address, int phy_id, int location) +{ + long mdio_addr = base_address + MIICtrl; + int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int i, retval = 0; + + if (mii_preamble_required) + mdio_sync(mdio_addr); + + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + + writel(dataval, mdio_addr); + mdio_delay(mdio_addr); + writel(dataval | MDIO_ShiftClk, mdio_addr); + mdio_delay(mdio_addr); + } + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 20; i > 0; i--) { + writel(MDIO_EnbIn, mdio_addr); + mdio_delay(mdio_addr); + retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0); + writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); + mdio_delay(mdio_addr); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(int base_address, int phy_id, int location, int value) +{ + long mdio_addr = base_address + MIICtrl; + int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + int i; + + if (location == 4 && phy_id == w840private.phys[0]) + w840private.advertising = value; + + if (mii_preamble_required) + mdio_sync(mdio_addr); + + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + + writel(dataval, mdio_addr); + mdio_delay(mdio_addr); + writel(dataval | MDIO_ShiftClk, mdio_addr); + mdio_delay(mdio_addr); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + writel(MDIO_EnbIn, mdio_addr); + mdio_delay(mdio_addr); + writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); + mdio_delay(mdio_addr); + } + return; +} + +static void check_duplex(void) +{ + int mii_reg5 = mdio_read(ioaddr, w840private.phys[0], 5); + int negotiated = mii_reg5 & w840private.advertising; + int duplex; + + if (w840private.duplex_lock || mii_reg5 == 0xffff) + return; + + duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (w840private.full_duplex != duplex) { + w840private.full_duplex = duplex; + +#if defined(W89C840_DEBUG) + printf("winbond-840 : Setting %s-duplex based on MII # %d negotiated capability %X\n", + duplex ? "full" : "half", w840private.phys[0], negotiated); +#endif + + w840private.csr6 &= ~0x200; + w840private.csr6 |= duplex ? 0x200 : 0; + } +} + +static void set_rx_mode(void) +{ + u32 mc_filter[2]; /* Multicast hash filter */ + u32 rx_mode; + + /* Accept all multicasts from now on. */ + memset(mc_filter, 0xff, sizeof(mc_filter)); + +/* + * Actually, should work OK with multicast enabled. -- iko + */ +/* + * rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast; + */ + rx_mode = AcceptBroadcast | AcceptMyPhys; + + writel(mc_filter[0], ioaddr + MulticastFilter0); + writel(mc_filter[1], ioaddr + MulticastFilter1); + w840private.csr6 &= ~0x00F8; + w840private.csr6 |= rx_mode; + writel(w840private.csr6, ioaddr + NetworkConfig); + +#if defined(W89C840_DEBUG) + printf("winbond-840 : Done setting RX mode.\n"); +#endif +} + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void init_ring(void) +{ + int i; + char * p; + + w840private.tx_full = 0; + w840private.tx_q_bytes = w840private.cur_rx = w840private.cur_tx = 0; + w840private.dirty_rx = w840private.dirty_tx = 0; + + w840private.rx_buf_sz = PKT_BUF_SZ; + w840private.rx_head_desc = &w840private.rx_ring[0]; + + /* Initial all Rx descriptors. Fill in the Rx buffers. */ + + p = &rx_packet[0]; + + for (i = 0; i < RX_RING_SIZE; i++) { + w840private.rx_ring[i].length = w840private.rx_buf_sz; + w840private.rx_ring[i].status = 0; + w840private.rx_ring[i].next_desc = virt_to_le32desc(&w840private.rx_ring[i+1]); + + w840private.rx_ring[i].buffer1 = virt_to_le32desc(p + (PKT_BUF_SZ * i)); + w840private.rx_ring[i].status = DescOwn | DescIntr; + } + + /* Mark the last entry as wrapping the ring. */ + w840private.rx_ring[i-1].length |= DescEndRing; + w840private.rx_ring[i-1].next_desc = virt_to_le32desc(&w840private.rx_ring[0]); + + w840private.dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + for (i = 0; i < TX_RING_SIZE; i++) { + w840private.tx_ring[i].status = 0; + } + return; +} diff --git a/stage2/builtins.c b/stage2/builtins.c index fbf5f598b..bf3c0d32f 100644 --- a/stage2/builtins.c +++ b/stage2/builtins.c @@ -28,6 +28,7 @@ #include #ifdef SUPPORT_NETBOOT +# define GRUB 1 # include #endif @@ -242,6 +243,11 @@ boot_func (char *arg, int flags) not KERNEL_TYPE_NONE. Is this assumption is bad? */ if (kernel_type != KERNEL_TYPE_NONE) unset_int15_handler (); + +#ifdef SUPPORT_NETBOOT + /* Shut down the networking. */ + cleanup_net (); +#endif switch (kernel_type) { diff --git a/stage2/cmdline.c b/stage2/cmdline.c index 96dd823e3..5d89fc7fe 100644 --- a/stage2/cmdline.c +++ b/stage2/cmdline.c @@ -21,6 +21,7 @@ #include #ifdef SUPPORT_DISKLESS +# define GRUB 1 # include #endif diff --git a/stage2/common.c b/stage2/common.c index c47be49b7..21369861c 100644 --- a/stage2/common.c +++ b/stage2/common.c @@ -21,6 +21,7 @@ #include #ifdef SUPPORT_DISKLESS +# define GRUB 1 # include #endif