jpopelka / rpms / net-tools

Forked from rpms/net-tools 3 years ago
Clone

Blame SOURCES/mii-diag.c

45db86
/* Mode: C;
45db86
 * mii-diag.c: Examine and set the MII registers of a network interfaces.
45db86
45db86
	Usage:	mii-diag [-vw] interface.
45db86
45db86
	This program reads and writes the Media Independent Interface (MII)
45db86
	management registers on network transceivers.  The registers control
45db86
	and report network link settings and errors.  Examples are link speed,
45db86
	duplex, capabilities advertised to the link partner, status LED
45db86
	indications and link error counters.
45db86
45db86
	Notes:
45db86
	The compile-command is at the end of this source file.
45db86
	This program works with drivers that implement MII ioctl() calls.
45db86
45db86
	Written/copyright 1997-2003 by Donald Becker <becker@scyld.com>
45db86
45db86
	This program is free software; you can redistribute it
45db86
	and/or modify it under the terms of the GNU General Public
45db86
	License as published by the Free Software Foundation.
45db86
45db86
	The author may be reached as becker@scyld.com, or C/O
45db86
	 Scyld Computing Corporation
45db86
	 914 Bay Ridge Road, Suite 220
45db86
	 Annapolis MD 21403
45db86
45db86
	References
45db86
	http://scyld.com/expert/mii-status.html
45db86
	http://scyld.com/expert/NWay.html
45db86
	http://www.national.com/pf/DP/DP83840.html
45db86
*/
45db86
45db86
static char version[] =
45db86
"mii-diag.c:v2.11 3/21/2005 Donald Becker (becker@scyld.com)\n"
45db86
" http://www.scyld.com/diag/index.html\n";
45db86
45db86
static const char usage_msg[] =
45db86
"Usage: %s [--help] [-aDfrRvVw] [-AF <speed+duplex>] [--watch] <interface>\n";
45db86
static const char long_usage_msg[] =
45db86
"Usage: %s [-aDfrRvVw] [-AF <speed+duplex>] [--watch] <interface>\n\
45db86
\n\
45db86
  This program configures and monitors the transceiver management registers\n\
45db86
  for network interfaces.  It uses the Media Independent Interface (MII)\n\
45db86
  standard with additional Linux-specific controls to communicate with the\n\
45db86
  underlying device driver.  The MII registers control and report network\n\
45db86
  link settings and errors.  Examples are link speed, duplex, capabilities\n\
45db86
  advertised to the link partner, status LED indications and link error\n\
45db86
  counters.\n\
45db86
\n\
45db86
   The common usage is\n\
45db86
      mii-diag eth0\n\
45db86
\n\
45db86
 Frequently used options are\n\
45db86
   -A  --advertise <speed|setting>\n\
45db86
   -F  --fixed-speed <speed>\n\
45db86
	Speed is one of: 100baseT4, 100baseTx, 100baseTx-FD, 100baseTx-HD,\n\
45db86
	                 10baseT, 10baseT-FD, 10baseT-HD\n\
45db86
   -s  --status     Return exit status 2 if there is no link beat.\n\
45db86
\n\
45db86
 Less frequently used options are\n\
45db86
   -a  --all-interfaces  Show the status all interfaces\n\
45db86
              (Not recommended with options that change settings.)\n\
45db86
   -D  --debug\n\
45db86
   -g  --read-parameters 	Get driver-specific parameters.\n\
45db86
   -G  --set-parameters PARMS	Set driver-specific parameters.\n\
45db86
       Parameters are comma separated, missing parameters retain\n\
45db86
       their previous values.\n\
45db86
   -M  --msg-level LEVEL 	Set the driver message bit map.\n\
45db86
   -p  --phy ADDR		Set the PHY (MII address) to report.\n\
45db86
   -r  --restart	Restart the link autonegotiation.\n\
45db86
   -R  --reset		Reset the transceiver.\n\
45db86
   -v  --verbose	Report each action taken.\n\
45db86
   -V  --version	Emit version information.\n\
45db86
   -w  --watch		Continuously monitor the transceiver and report changes.\n\
45db86
\n\
45db86
   This command returns success (zero) if the interface information can be\n\
45db86
   read.  If the --status option is passed, a zero return means that the\n\
45db86
   interface has link beat.\n\
45db86
";
45db86
45db86
#include <unistd.h>
45db86
#include <stdlib.h>
45db86
#include <stdio.h>
45db86
#include <ctype.h>
45db86
#include <string.h>
45db86
#include <errno.h>
45db86
#include <fcntl.h>
45db86
#include <getopt.h>
45db86
#include <sys/types.h>
45db86
#include <sys/socket.h>
45db86
#include <sys/ioctl.h>
45db86
#include <net/if.h>
45db86
#ifdef use_linux_libc5
45db86
#include <linux/if_arp.h>
45db86
#include <linux/if_ether.h>
45db86
#endif
45db86
45db86
typedef u_int32_t u32;
45db86
typedef u_int16_t u16;
45db86
typedef u_int8_t u8;
45db86
45db86
#if defined(SIOCGPARAMS)  && SIOCGPARAMS != SIOCDEVPRIVATE+3
45db86
#error Changed definition for SIOCGPARAMS
45db86
#else
45db86
#define SIOCGPARAMS (SIOCDEVPRIVATE+3) 		/* Read operational parameters. */
45db86
#define SIOCSPARAMS (SIOCDEVPRIVATE+4) 		/* Set operational parameters. */
45db86
#endif
45db86
45db86
const char shortopts[] = "aA:C:DfF:gG:hmM:p:rRsvVw?";
45db86
struct option longopts[] = {
45db86
 /* { name  has_arg  *flag  val } */
45db86
    {"all-interfaces", 0, 0, 'a'},	/* Show all interfaces. */
45db86
	{"advertise",	1, 0, 'A'},		/* Change the capabilities advertised. */
45db86
	{"BMCR",		1, 0, 'C'},		/* Set the control register. */
45db86
    {"debug",       0, 0, 'D'},		/* Increase the debug level. */
45db86
    {"force",       0, 0, 'f'},		/* Force the operation. */
45db86
    {"fixed-speed", 1, 0, 'F'},		/* Fixed speed name. */
45db86
    {"read-parameters", 0, 0, 'g'}, /* Show general settings values. */
45db86
    {"set-parameters",  1, 0, 'G'},	/* Write general settings values. */
45db86
    {"help", 		0, 0, 'h'},		/* Print a long usage message. */
45db86
    {"monitor",		0, 0, 'm'},		/* Monitor status register. */
45db86
    {"msg-level",	1, 0, 'M'},		/* Set the driver message level. */
45db86
    {"phy",			1, 0, 'p'},		/* Set the PHY (MII address) to report. */
45db86
    {"restart",		0, 0, 'r'},		/* Restart the link negotiation */
45db86
    {"reset",		0, 0, 'R'},		/* Reset the transceiver. */
45db86
    {"status",		0, 0, 's'},		/* Non-zero exit status w/ no link beat. */
45db86
    {"verbose", 	0, 0, 'v'},		/* Report each action taken.  */
45db86
    {"version", 	0, 0, 'V'},		/* Emit version information.  */
45db86
    {"watch", 		0, 0, 'w'},		/* Constantly monitor the port.  */
45db86
    {"error", 		0, 0, '?'},		/* Return the error message. */
45db86
    { 0, 0, 0, 0 }
45db86
};
45db86
45db86
/* Usually in libmii.c, but trivial substitions are below. */
45db86
extern int  show_mii_details(long ioaddr, int phy_id);
45db86
extern void monitor_mii(long ioaddr, int phy_id);
45db86
int  show_mii_details(long ioaddr, int phy_id) __attribute__((weak));
45db86
void monitor_mii(long ioaddr, int phy_id) __attribute__((weak));
45db86
45db86
45db86
/* Command-line flags. */
45db86
unsigned int opt_a = 0,					/* Show-all-interfaces flag. */
45db86
	opt_f = 0,					/* Force the operation. */
45db86
	opt_g = 0,
45db86
	opt_G = 0,
45db86
	verbose = 0,				/* Verbose flag. */
45db86
	debug = 0,
45db86
	opt_version = 0,
45db86
	opt_restart = 0,
45db86
	opt_reset = 0,
45db86
	opt_status = 0,
45db86
	opt_watch = 0;
45db86
static int msg_level = -1;
45db86
static int set_BMCR = -1;
45db86
static int nway_advertise = 0;
45db86
static int fixed_speed = -1;
45db86
static int override_phy = -1;
45db86
char *opt_G_string = NULL;
45db86
45db86
/* Internal values. */
45db86
int new_ioctl_nums;
45db86
int skfd = -1;					/* AF_INET socket for ioctl() calls.	*/
45db86
struct ifreq ifr;
45db86
45db86
int do_one_xcvr(int skfd);
45db86
int show_basic_mii(long ioaddr, int phy_id);
45db86
int mdio_read(int skfd, int phy_id, int location);
45db86
void mdio_write(int skfd, int phy_id, int location, int value);
45db86
static int parse_advertise(const char *capabilities);
45db86
static void monitor_status(long ioaddr, int phy_id);
45db86
45db86
45db86
int
45db86
main(int argc, char **argv)
45db86
{
45db86
	int c, errflag = 0;
45db86
	char **spp, *ifname;
45db86
    char *progname = rindex(argv[0], '/') ? rindex(argv[0], '/')+1 : argv[0];
45db86
45db86
	while ((c = getopt_long(argc, argv, shortopts, longopts, 0)) != EOF)
45db86
		switch (c) {
45db86
		case 'a': opt_a++; break;
45db86
		case 'A': nway_advertise |= parse_advertise(optarg);
45db86
			if (nway_advertise == -1) errflag++;
45db86
			break;
45db86
		case 'C': set_BMCR = strtoul(optarg, NULL, 16); break;
45db86
		case 'D': debug++;			break;
45db86
		case 'f': opt_f++; break;
45db86
		case 'F': fixed_speed = parse_advertise(optarg);
45db86
			if (fixed_speed == -1) errflag++;
45db86
			break;
45db86
		case 'g': opt_g++; break;
45db86
		case 'G': opt_G++; opt_G_string = strdup(optarg); break;
45db86
		case 'm': opt_watch++; opt_status++; break;
45db86
		case 'M': msg_level = strtoul(optarg, NULL, 0); break;
45db86
		case 'h': fprintf(stderr, long_usage_msg, progname); return 0;
45db86
		case 'p': override_phy = atoi(optarg); break;
45db86
		case 'r': opt_restart++;	break;
45db86
		case 'R': opt_reset++;		break;
45db86
		case 's': opt_status++;		break;
45db86
		case 'v': verbose++;		break;
45db86
		case 'V': opt_version++;	break;
45db86
		case 'w': opt_watch++;		break;
45db86
		case '?': errflag++;		break;
45db86
		}
45db86
	if (errflag) {
45db86
		fprintf(stderr, usage_msg, progname);
45db86
		return 2;
45db86
	}
45db86
45db86
	if (verbose || opt_version)
45db86
		printf("%s", version);
45db86
45db86
	/* Open a basic socket. */
45db86
	if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) {
45db86
		perror("socket");
45db86
		return 1;
45db86
	}
45db86
45db86
	if (debug)
45db86
		fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n",
45db86
				argc, optind, argv[optind]);
45db86
45db86
	/* No remaining args means interface wasn't specified. */
45db86
	if (optind == argc) {
45db86
		fprintf(stderr, "No interface specified.\n");
45db86
		fprintf(stderr, usage_msg, progname);
45db86
		(void) close(skfd);
45db86
		return 2;
45db86
	} else {
45db86
		/* Copy the interface name. */
45db86
		spp = argv + optind;
45db86
		ifname = *spp++;
45db86
	}
45db86
45db86
	if (ifname == NULL) {
45db86
		fprintf(stderr, "No ifname.\n");
45db86
		(void) close(skfd);
45db86
		return -1;
45db86
	}
45db86
45db86
	/* Verify that the interface supports the ioctl(), and if
45db86
	   it is using the new or old SIOCGMIIPHY value (grrr...).
45db86
	 */
45db86
	{
45db86
		u16 *data = (u16 *)(&ifr.ifr_data);
45db86
45db86
		strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
45db86
		ifr.ifr_name[IFNAMSIZ-1] = '\0';
45db86
		data[0] = 0;
45db86
45db86
		if (ioctl(skfd, 0x8947, &ifr) >= 0) {
45db86
			new_ioctl_nums = 1;
45db86
		} else if (ioctl(skfd, SIOCDEVPRIVATE, &ifr) >= 0) {
45db86
			new_ioctl_nums = 0;
45db86
		} else {
45db86
			fprintf(stderr, "SIOCGMIIPHY on %s failed: %s\n", ifname,
45db86
					strerror(errno));
45db86
			(void) close(skfd);
45db86
			return 1;
45db86
		}
45db86
		if (verbose)
45db86
			printf("  Using the %s SIOCGMIIPHY value on PHY %d "
45db86
				   "(BMCR 0x%4.4x).\n",
45db86
				   new_ioctl_nums ? "new" : "old", data[0], data[3]);
45db86
	}
45db86
45db86
	do_one_xcvr(skfd);
45db86
45db86
	(void) close(skfd);
45db86
	return 0;
45db86
}
45db86
45db86
int do_one_xcvr(int skfd)
45db86
{
45db86
	u16 *data = (u16 *)(&ifr.ifr_data);
45db86
	u32 *data32 = (u32 *)(&ifr.ifr_data);
45db86
	unsigned phy_id = data[0];
45db86
45db86
	if (override_phy >= 0) {
45db86
		printf("Using the specified MII PHY index %d.\n", override_phy);
45db86
		phy_id = override_phy;
45db86
	}
45db86
45db86
	if (opt_g || opt_G || msg_level >= 0) {
45db86
		if (ioctl(skfd, SIOCGPARAMS, &ifr) < 0) {
45db86
			fprintf(stderr, "SIOCGPARAMS on %s failed: %s\n", ifr.ifr_name,
45db86
					strerror(errno));
45db86
			return -1;
45db86
		}
45db86
	}
45db86
	if (opt_g) {
45db86
		int i;
45db86
		printf("Driver general parameter settings:");
45db86
		for (i = 0; i*sizeof(u32) < sizeof(ifr.ifr_ifru); i++) {
45db86
			printf(" %d", data32[i]);
45db86
		}
45db86
		printf(".\n");
45db86
	}
45db86
	if (opt_G) {
45db86
		/* Set up to four arbitrary driver parameters from the -G parameter.
45db86
		   The format is comma separated integers, with a missing element
45db86
		   retaining the previous value.
45db86
		*/
45db86
		char *str = opt_G_string;
45db86
		int i;
45db86
		for (i = 0; str && i < 4; i++) {
45db86
			char *endstr;
45db86
			u32 newval = strtol(str, &endstr, 0);
45db86
			if (debug)
45db86
				printf(" parse string '%s'  value %d end '%s'.\n",
45db86
					   str, newval, endstr);
45db86
			if (str == endstr) {
45db86
				if (endstr[0] == ',') /* No parameter */
45db86
					str = endstr+1;
45db86
				else {
45db86
					fprintf(stderr, "Invalid driver parameter '%s'.\n", str);
45db86
					str = index(str, ',');
45db86
				}
45db86
			} else if (endstr[0] == ',') {
45db86
				data32[i] = newval;
45db86
				str = endstr + 1;
45db86
			} else if (endstr[0] == 0) {
45db86
				data32[i] = newval;
45db86
				break;
45db86
			}
45db86
		}
45db86
		printf("Setting new driver general parameters:");
45db86
		for (i = 0; i*sizeof(u32) < sizeof(ifr.ifr_ifru); i++) {
45db86
			printf(" %d", data32[i]);
45db86
		}
45db86
		printf(".\n");
45db86
		if (ioctl(skfd, SIOCSPARAMS, &ifr) < 0) {
45db86
			fprintf(stderr, "SIOCSPARAMS on %s failed: %s\n", ifr.ifr_name,
45db86
					strerror(errno));
45db86
			return -1;
45db86
		}
45db86
	}
45db86
	if (msg_level >= 0) {
45db86
		data32[0] = msg_level;
45db86
		if (ioctl(skfd, SIOCSPARAMS, &ifr) < 0) {
45db86
			fprintf(stderr, "SIOCSPARAMS on %s failed: %s\n", ifr.ifr_name,
45db86
					strerror(errno));
45db86
			return -1;
45db86
		}
45db86
	}
45db86
45db86
	if (opt_reset) {
45db86
		printf("Resetting the transceiver...\n");
45db86
		mdio_write(skfd, phy_id, 0, 0x8000);
45db86
	}
45db86
	/* Note: PHY addresses > 32 are pseudo-MII devices, usually built-in. */
45db86
	if (phy_id < 64  &&  nway_advertise > 0) {
45db86
		printf(" Setting the media capability advertisement register of "
45db86
			   "PHY #%d to 0x%4.4x.\n", phy_id, nway_advertise | 1);
45db86
		mdio_write(skfd, phy_id, 4, nway_advertise | 1);
45db86
		mdio_write(skfd, phy_id, 0, 0x1000);
45db86
	}
45db86
45db86
	if (opt_restart) {
45db86
		printf("Restarting negotiation...\n");
45db86
		mdio_write(skfd, phy_id, 0, 0x0000);
45db86
		mdio_write(skfd, phy_id, 0, 0x1200);
45db86
	}
45db86
	/* To force 100baseTx-HD do  mdio_write(skfd, phy_id, 0, 0x2000); */
45db86
	if (fixed_speed >= 0) {
45db86
		int reg0_val = 0;
45db86
		if (fixed_speed & 0x0180) 		/* 100mpbs */
45db86
			reg0_val |=  0x2000;
45db86
		if ((fixed_speed & 0x0140) &&		/* A full duplex type and */
45db86
			! (fixed_speed & 0x0820)) 		/* no half duplex types. */
45db86
			reg0_val |= 0x0100;
45db86
		printf("Setting the speed to \"fixed\", Control register %4.4x.\n",
45db86
			   reg0_val);
45db86
		mdio_write(skfd, phy_id, 0, reg0_val);
45db86
	}
45db86
	if (set_BMCR >= 0) {
45db86
		printf("Setting the Basic Mode Control Register to 0x%4.4x.\n",
45db86
			   set_BMCR);
45db86
		mdio_write(skfd, phy_id, 0, set_BMCR);
45db86
	}
45db86
45db86
	if (opt_watch && opt_status)
45db86
		monitor_status(skfd, phy_id);
45db86
45db86
	show_basic_mii(skfd, phy_id);
45db86
#ifdef LIBMII
45db86
	if (verbose)
45db86
		show_mii_details(skfd, phy_id);
45db86
#else
45db86
	if (verbose || debug) {
45db86
		int mii_reg, mii_val;
45db86
		printf(" MII PHY #%d transceiver registers:", phy_id);
45db86
		for (mii_reg = 0; mii_reg < 32; mii_reg++) {
45db86
			mii_val = mdio_read(skfd, phy_id, mii_reg);
45db86
			printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n  " : "",
45db86
				   mii_val);
45db86
		}
45db86
		printf("\n");
45db86
	}
45db86
#endif
45db86
45db86
	if (opt_watch)
45db86
		monitor_mii(skfd, phy_id);
45db86
	if (opt_status &&
45db86
		(mdio_read(skfd, phy_id, 1) & 0x0004) == 0)
45db86
		exit(2);
45db86
	return 0;
45db86
}
45db86
45db86
int mdio_read(int skfd, int phy_id, int location)
45db86
{
45db86
	u16 *data = (u16 *)(&ifr.ifr_data);
45db86
45db86
	data[0] = phy_id;
45db86
	data[1] = location;
45db86
45db86
	if (ioctl(skfd, new_ioctl_nums ? 0x8948 : SIOCDEVPRIVATE+1, &ifr) < 0) {
45db86
		fprintf(stderr, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
45db86
				strerror(errno));
45db86
		return -1;
45db86
	}
45db86
	return data[3];
45db86
}
45db86
45db86
void mdio_write(int skfd, int phy_id, int location, int value)
45db86
{
45db86
	u16 *data = (u16 *)(&ifr.ifr_data);
45db86
45db86
	data[0] = phy_id;
45db86
	data[1] = location;
45db86
	data[2] = value;
45db86
45db86
	if (ioctl(skfd, new_ioctl_nums ? 0x8949 : SIOCDEVPRIVATE+2, &ifr) < 0) {
45db86
		fprintf(stderr, "SIOCSMIIREG on %s failed: %s\n", ifr.ifr_name,
45db86
				strerror(errno));
45db86
	}
45db86
}
45db86
45db86
/* Parse the command line argument for advertised capabilities. */
45db86
static int parse_advertise(const char *capabilities)
45db86
{
45db86
	const char *mtypes[] = {
45db86
		"100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD",
45db86
		"10baseT", "10baseT-FD", "10baseT-HD", 0,
45db86
	};
45db86
	char *endptr;
45db86
	int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,};
45db86
	int i;
45db86
	if ( ! capabilities) {
45db86
		fprintf(stderr, "You passed -A 'NULL'.  You must provide a media"
45db86
				" list to advertise!\n");
45db86
		return -1;
45db86
	}
45db86
	if (debug)
45db86
		fprintf(stderr, "Advertise string is '%s'.\n", capabilities);
45db86
	for (i = 0; mtypes[i]; i++)
45db86
		if (strcasecmp(mtypes[i], capabilities) == 0)
45db86
			return cap_map[i];
45db86
	if ((i = strtol(capabilities, &endptr, 16)) <= 0xffff  &&  endptr[0] == 0)
45db86
		return i;
45db86
	fprintf(stderr, "Invalid media advertisement value '%s'.\n"
45db86
			"  Either pass a numeric value or one of the following names:\n",
45db86
			capabilities);
45db86
	for (i = 0; mtypes[i]; i++)
45db86
		fprintf(stderr, "   %-14s %3.3x\n", mtypes[i], cap_map[i]);
45db86
	return -1;
45db86
}
45db86
45db86
/* Trivial versions if we don't link against libmii.c */
45db86
static const char *media_names[] = {
45db86
	"10baseT", "10baseT-FD", "100baseTx", "100baseTx-FD", "100baseT4",
45db86
	"Flow-control", 0,
45db86
};
45db86
/* Various non-good bits in the command register. */
45db86
static const char *bmcr_bits[] = {
45db86
	"  Internal Collision-Test enabled!\n", "",		/* 0x0080,0x0100 */
45db86
	"  Restarted auto-negotiation in progress!\n",
45db86
	"  Transceiver isolated from the MII!\n",
45db86
	"  Transceiver powered down!\n", "", "",
45db86
	"  Transceiver in loopback mode!\n",
45db86
	"  Transceiver currently being reset!\n",
45db86
};
45db86
45db86
int show_basic_mii(long ioaddr, int phy_id)
45db86
{
45db86
	int mii_reg, i;
45db86
	u16 mii_val[32];
45db86
	u16 bmcr, bmsr, new_bmsr, nway_advert, lkpar;
45db86
45db86
	for (mii_reg = 0; mii_reg < 8; mii_reg++)
45db86
		mii_val[mii_reg] = mdio_read(ioaddr, phy_id, mii_reg);
45db86
	if ( ! verbose) {
45db86
		printf("Basic registers of MII PHY #%d: ", phy_id);
45db86
		for (mii_reg = 0; mii_reg < 8; mii_reg++)
45db86
			printf(" %4.4x", mii_val[mii_reg]);
45db86
		printf(".\n");
45db86
	}
45db86
45db86
	if (mii_val[0] == 0xffff  ||  mii_val[1] == 0x0000) {
45db86
		printf("  No MII transceiver present!.\n");
45db86
		if (! opt_f) {
45db86
			printf("  Use '--force' to view the information anyway.\n");
45db86
			return -1;
45db86
		}
45db86
	}
45db86
	/* Descriptive rename. */
45db86
	bmcr = mii_val[0];
45db86
	bmsr = mii_val[1];
45db86
	nway_advert = mii_val[4];
45db86
	lkpar = mii_val[5];
45db86
45db86
	if (lkpar & 0x4000) {
45db86
		int negotiated = nway_advert & lkpar & 0x3e0;
45db86
		int max_capability = 0;
45db86
		/* Scan for the highest negotiated capability, highest priority
45db86
		   (100baseTx-FDX) to lowest (10baseT-HDX). */
45db86
		int media_priority[] = {8, 9, 7, 6, 5}; 	/* media_names[i-5] */
45db86
		printf(" The autonegotiated capability is %4.4x.\n", negotiated);
45db86
		for (i = 0; media_priority[i]; i++)
45db86
			if (negotiated & (1 << media_priority[i])) {
45db86
				max_capability = media_priority[i];
45db86
				break;
45db86
			}
45db86
		if (max_capability)
45db86
			printf("The autonegotiated media type is %s.\n",
45db86
				   media_names[max_capability - 5]);
45db86
		else
45db86
			printf("No common media type was autonegotiated!\n"
45db86
				   "This is extremely unusual and typically indicates a "
45db86
				   "configuration error.\n" "Perhaps the advertised "
45db86
				   "capability set was intentionally limited.\n");
45db86
	}
45db86
	printf(" Basic mode control register 0x%4.4x:", bmcr);
45db86
	if (bmcr & 0x1000)
45db86
		printf(" Auto-negotiation enabled.\n");
45db86
	else
45db86
		printf(" Auto-negotiation disabled, with\n"
45db86
			   " Speed fixed at 10%s mbps, %s-duplex.\n",
45db86
			   bmcr & 0x2000 ? "0" : "",
45db86
			   bmcr & 0x0100 ? "full":"half");
45db86
	for (i = 0; i < 9; i++)
45db86
		if (bmcr & (0x0080<
45db86
			printf("%s", bmcr_bits[i]);
45db86
45db86
	new_bmsr = mdio_read(ioaddr, phy_id, 1);
45db86
	if ((bmsr & 0x0016) == 0x0004)
45db86
		printf( " You have link beat, and everything is working OK.\n");
45db86
	else
45db86
		printf(" Basic mode status register 0x%4.4x ... %4.4x.\n"
45db86
			   "   Link status: %sestablished.\n",
45db86
			   bmsr, new_bmsr,
45db86
			   bmsr & 0x0004 ? "" :
45db86
			   (new_bmsr & 0x0004) ? "previously broken, but now re" : "not ");
45db86
	if (verbose) {
45db86
		printf("   This transceiver is capable of ");
45db86
		if (bmsr & 0xF800) {
45db86
			for (i = 15; i >= 11; i--)
45db86
				if (bmsr & (1<
45db86
					printf(" %s", media_names[i-11]);
45db86
		} else
45db86
			printf("<Warning! No media capabilities>");
45db86
		printf(".\n");
45db86
		printf("   %s to perform Auto-negotiation, negotiation %scomplete.\n",
45db86
			   bmsr & 0x0008 ? "Able" : "Unable",
45db86
			   bmsr & 0x0020 ? "" : "not ");
45db86
	}
45db86
45db86
	if (bmsr & 0x0010)
45db86
		printf(" Remote fault detected!\n");
45db86
	if (bmsr & 0x0002)
45db86
		printf("   *** Link Jabber! ***\n");
45db86
45db86
	if (lkpar & 0x4000) {
45db86
		printf(" Your link partner advertised %4.4x:",
45db86
			   lkpar);
45db86
		for (i = 5; i >= 0; i--)
45db86
			if (lkpar & (0x20<
45db86
				printf(" %s", media_names[i]);
45db86
		printf("%s.\n", lkpar & 0x0400 ? ", w/ 802.3X flow control" : "");
45db86
	} else if (lkpar & 0x00A0)
45db86
		printf(" Your link partner is generating %s link beat  (no"
45db86
			   " autonegotiation).\n",
45db86
			   lkpar & 0x0080 ? "100baseTx" : "10baseT");
45db86
	else if ( ! (bmcr & 0x1000))
45db86
		printf(" Link partner information is not exchanged when in"
45db86
			   " fixed speed mode.\n");
45db86
	else if ( ! (new_bmsr & 0x004))
45db86
							;	/* If no partner, do not report status. */
45db86
	else if (lkpar == 0x0001  ||  lkpar == 0x0000) {
45db86
		printf(" Your link partner does not do autonegotiation, and this "
45db86
			   "transceiver type\n  does not report the sensed link "
45db86
			   "speed.\n");
45db86
	} else
45db86
		printf(" Your link partner is strange, status %4.4x.\n", lkpar);
45db86
45db86
	printf("   End of basic transceiver information.\n\n");
45db86
	return 0;
45db86
}
45db86
45db86
static void monitor_status(long ioaddr, int phy_id)
45db86
{
45db86
	unsigned int baseline_1 = 0x55555555; 	/* Always show initial status. */
45db86
45db86
	while (1) {
45db86
		unsigned int new_1 = mdio_read(ioaddr, phy_id, 1);
45db86
		if (new_1 != baseline_1) {
45db86
			printf("%-12s 0x%4.4x 0x%4.4x\n",
45db86
				   new_1 & 0x04 ? (new_1==0xffff ? "unknown" : "up") :
45db86
				   new_1 & 0x20 ? "negotiating" : "down",
45db86
				   new_1, mdio_read(ioaddr, phy_id, 5));
45db86
			fflush(stdout);
45db86
			baseline_1 = new_1;
45db86
		}
45db86
		sleep(1);
45db86
	}
45db86
}
45db86
45db86
int  show_mii_details(long ioaddr, int phy_id)
45db86
{
45db86
	int mii_reg, mii_val;
45db86
	printf(" MII PHY #%d transceiver registers:", phy_id);
45db86
	for (mii_reg = 0; mii_reg < 32; mii_reg++) {
45db86
		mii_val = mdio_read(skfd, phy_id, mii_reg);
45db86
		printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n  " : "",
45db86
			   mii_val);
45db86
	}
45db86
	printf("\nThis version of 'mii-diag' has not been linked with "
45db86
			"the libmii.c library.\n"
45db86
			"  That library provides extended transceiver status reports.\n");
45db86
	return 0;
45db86
}
45db86
45db86
void monitor_mii(long ioaddr, int phy_id)
45db86
{
45db86
	fprintf(stderr, "\nThis version of 'mii-diag' has not been linked with "
45db86
			"the libmii.c library \n"
45db86
			"  required for the media monitor option.\n");
45db86
}
45db86
45db86
45db86

45db86
/*
45db86
 * Local variables:
45db86
 *  version-control: t
45db86
 *  kept-new-versions: 5
45db86
 *  c-indent-level: 4
45db86
 *  c-basic-offset: 4
45db86
 *  tab-width: 4
45db86
 *  compile-command: "gcc -Wall -Wstrict-prototypes -O mii-diag.c -DLIBMII libmii.c -o mii-diag"
45db86
 *  simple-compile-command: "gcc mii-diag.c -o mii-diag"
45db86
 * End:
45db86
 */