jpopelka / rpms / net-tools

Forked from rpms/net-tools 4 years ago
Clone

Blame SOURCES/mii-diag.c

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