jpopelka / rpms / net-tools

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