summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2020-04-10 16:27:26 +0100
committerRussell King <rmk+kernel@armlinux.org.uk>2020-04-10 16:53:11 +0100
commitaafe03561694271e9d07bc0696b40d9a01dbcdbf (patch)
tree50b37c9a3f942b5759b1b91cde4b53353a9afad9
parentb02d1e52db310aaa41fd0bff0d6244a8cfb9c8a5 (diff)
libmii: add a bunch of additional PHY support
(this commit will be broken up) Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--libmii.c2015
-rw-r--r--mii-diag.c36
2 files changed, 1877 insertions, 174 deletions
diff --git a/libmii.c b/libmii.c
index 96f0060..49e7934 100644
--- a/libmii.c
+++ b/libmii.c
@@ -31,20 +31,24 @@ int monitor_mii(long ioaddr, int phy_id);
/* This library expects to be able to call the following functions: */
extern int mdio_read(long ioaddr, int phy_id, int mii_reg_num);
+extern void mdio_write(long ioaddr, int phy_id, int mii_reg_num, int value);
#include <unistd.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
+
typedef u_int32_t u32;
typedef u_int16_t u16;
typedef u_int8_t u8;
static const char *media_names[] = {
"10baseT", "10baseT-FD", "100baseTx", "100baseTx-FD", "100baseT4",
- "Flow-control", 0,
+ "Pause", "AsymPause", 0,
};
static void ns83843(long ioaddr, int phy_id);
@@ -63,177 +67,1636 @@ static void via_tahoe(long ioaddr, int phy_id);
static void via_vt6103(long ioaddr, int phy_id);
static void via_vt6105(long ioaddr, int phy_id);
static void intel(long ioaddr, int phy_id);
+static void mv88x3310_xs(long ioaddr, int phy_id);
+static void mv88x3310(long ioaddr, int phy_id);
+static void mv88e1111(long ioaddr, int phy_id);
+static void mv88e151x(long ioaddr, int phy_id);
+
+enum {
+ MDIO_MMD_PMAPMD = 1,
+ MDIO_MMD_WIS = 2,
+ MDIO_MMD_PCS = 3,
+ MDIO_MMD_PHY_XS = 4,
+ MDIO_MMD_DTE_XS = 5,
+ MDIO_MMD_TC = 6,
+ MDIO_MMD_AN = 7,
+ MDIO_MMD_VENDOR1 = 30,
+ MDIO_MMD_VENDOR2 = 31,
+
+ MMD_CTRL1 = 0,
+ MMD_STAT1 = 1,
+ MMD_DEVID1 = 2,
+ MMD_DEVID2 = 3,
+ MMD_SPEED = 4,
+ MMD_DEVPKG1 = 5,
+ MMD_DEVPKG2 = 6,
+ MMD_CTRL2 = 7,
+ MMD_STAT2 = 8,
+ MMD_PKGID1 = 14,
+ MMD_PKGID2 = 15,
+
+ MMD_PMA_EXT_ABL = 11,
+ MMD_PMA_40G100G_EXT_ABL = 13,
+ MMD_PMA_EEE_CAPABILITY = 16,
+ MMD_PMA_25G_EXT_ABL = 19,
+ MMD_PMA_NBASE_EXT_ABL = 21,
+ MMD_PMA_10GBT_STATUS = 129,
+ MMD_PMA_10GBT_SWAPPOL = 130,
+
+ MMD_PCS_EEE_CTRL_CAPAB = 20,
+ MMD_PCS_EEE_WAKE_ERR = 22,
+ MMD_PCS_BASERT_STAT1 = 32,
+ MMD_PCS_BASERT_STAT2 = 33,
+
+ MMD_PHY_XS_EEE_CAPAB = 20,
+ MMD_PHY_XS_EEE_WAKE_ERR = 22,
+ MMD_PHY_XS_LANE_STATUS = 24,
+
+ MMD_DTE_XS_EEE_CAPAB = 20,
+ MMD_DTE_XS_EEE_WAKE_ERR = 22,
+
+ MMD_AN_BASE_ADV0 = 16,
+ MMD_AN_BASE_ADV1 = 17,
+ MMD_AN_BASE_ADV2 = 18,
+ MMD_AN_BASE_LPA0 = 19,
+ MMD_AN_BASE_LPA1 = 20,
+ MMD_AN_BASE_LPA2 = 21,
+ MMD_AN_XNP_ADV0 = 22,
+ MMD_AN_XNP_ADV1 = 23,
+ MMD_AN_XNP_ADV2 = 24,
+ MMD_AN_XNP_LPA0 = 25,
+ MMD_AN_XNP_LPA1 = 26,
+ MMD_AN_XNP_LPA2 = 27,
+ MMD_AN_MULTI_GBT_CTRL = 32,
+ MMD_AN_MULTI_GBT_STAT = 33,
+ MMD_AN_BASER_STAT = 48,
+ MMD_AN_EEE_ADV = 60,
+ MMD_AN_EEE_LPA = 61,
+};
+
+#define BIT(x) (1 << (x))
+
+static const char *mmd_name[32] = {
+ [MDIO_MMD_PMAPMD] = "PMA/PMD",
+ [MDIO_MMD_WIS] = "WIS",
+ [MDIO_MMD_PCS] = "PCS",
+ [MDIO_MMD_PHY_XS] = "PHY XS",
+ [MDIO_MMD_DTE_XS] = "DTE XS",
+ [MDIO_MMD_TC] = "TC",
+ [MDIO_MMD_AN] = "AN",
+ [MDIO_MMD_VENDOR1] = "Vendor Specific 1",
+ [MDIO_MMD_VENDOR2] = "Vendor Specific 2",
+};
+
+struct phy {
+ long ioaddr;
+ int phy_id;
+ int devad;
+ unsigned int page;
+ unsigned int offset;
+ int (*mdio_read)(const struct phy *phy, unsigned int reg);
+};
+
+#define DEFINE_C22_PHY(name, addr, id) \
+ struct phy name = { \
+ .ioaddr = addr, \
+ .phy_id = id, \
+ .mdio_read = __mdio_read_phy, \
+ }
+#define DEFINE_C45_PHY(name, addr, id, __devad) \
+ struct phy name = { \
+ .ioaddr = addr, \
+ .phy_id = id, \
+ .devad = __devad, \
+ .mdio_read = __mdio_read_phy, \
+ }
+
+struct c22_decoder {
+ void (*show_advert)(struct phy *phy, u16 *regs);
+ void (*show_lpar)(struct phy *phy, u16 *regs);
+};
struct mii_partnum {
- const char *vendor; /* Vendor name. */
- u16 phy_id0; /* Vendor ID (alternate ver. of ieee_oui[]) */
- u16 phy_id1; /* Vendor ID (alternate ver. of ieee_oui[]) */
- unsigned char ieee_oui[3]; /* IEEE-assigned organizationally unique ID */
- char flags;
+ u32 phy_id; /* Vendor ID */
+ u32 msk_id; /* Vendor ID mask */
+ const char *vendor; /* Vendor name. */
void (*(func))(long xcvr_if, int phy_id);/* Function to emit more info. */
} static oui_map[] = {
- {"Unknown transceiver type", 0x0000, 0x0000, {0,}, 0, NULL,},
- {"National Semiconductor 83840A", 0x2000, 0x5c01, {0,}, 0, NULL,},
- {"National Semiconductor 83843", 0x2000, 0x5c10, {0,}, 0, ns83843, },
- {"Level One LXT970", 0x7810, 0x0000, {0,}, 0, NULL, },
- {"Level One LXT971", 0x7810, 0x0001, {0,}, 0, NULL, },
- {"Level One LXT971A",0x7810, 0x0003, {0,}, 0, NULL, },
- {"Level One (unknown type)", 0, 0, {0x1e,0x04,0x00}, 0, NULL, },
- {"Davicom DM9101", 0x0181, 0xB800, {0,}, 0, davicom_dm9101, },
- {"Davicom (unknown type)", 0, 0, {0x00, 0x60, 0x6e}, 0, davicom_dm9101, },
- {"Quality Semiconductor QS6612", 0x0181, 0x4410, {0,}, 0, qs6612},
- {"Quality Semiconductor (unknown type)", 0,0, {0x00, 0x60, 0x51}, 0, NULL},
- {"SMSC 83c180", 0x0282, 0x1C51, {0}, 0, smsc83c180, },
- {"TDK Semi 78Q2120 rev. 2", 0x0300, 0xE542, {0,}, 0, tdk78q2120, },
- {"TDK Semi 78Q2120 rev. 3", 0x0300, 0xE543, {0,}, 0, tdk78q2120, },
- {"TDK Semi 78Q2120 rev. 11", 0x0300, 0xE54B, {0,}, 0, tdk78q2120, },
- {"TDK transceiver (unknown type)", 0,0, {0x00, 0xc0, 0x39}, 0, tdk78q2120},
- {"Intel (unknown type)", 0,0, {0x00, 0xf8, 0x00}, 0, intel_i553},
- {"Enable Semiconductor EL40-331", 0x0043, 0x7411, {0,}, 0, enablesemi},
- {"AMD 79c901A.1 HomePNA", 0x0000, 0x6B91, {0,}, 0, amd_pna},
- {"AMD 79c901A.2 HomePNA", 0x0000, 0x6B92, {0,}, 0, amd_pna},
- {"AMD 79c901A.3 HomePNA", 0x0000, 0x6B93, {0,}, 0, amd_pna},
- {"AMD 79c901A.3 10baseT", 0x0000, 0x6B71, {0,}, 0, amd_tx},
- {"AdHoc Technology AH101LF", 0x0022, 0x561B, {0,}, 0, tdk78q2120},
- {"Altimata Communications AC101LF", 0x0022, 0x5523, {0,}, 0, tdk78q2120},
- {"Altimata Comm (unknown type)", 0, 0, {0x00,0x10,0xA9}, 0, tdk78q2120},
- {"ASIX (unknown type)", 0, 0, {0x00,0xC0,0xB4}, 0, tdk78q2120},
- {"ADMtek AN983 Comet", 0x0022, 0x5410, {0,}, 0, admtek},
- {"ADMtek AN985 Comet", 0x0022, 0x5513, {0,}, 0, admtek},
- {"ADMtek (unknown type)", 0, 0, {0x00,0xe0,0x92}, 0, admtek},
- {"Lucent LU6612", 0x0180, 0x7641, {0,}, 0, qs6612},
- {"Lucent LU3X31", 0x0043, 0x7411, {0,}, 0, lu3x31},
- {"LSI Logic (Seeq) 80225", 0, 0, {0x00,0xA0,0x7D}, 0, NULL},
- {"Myson MTD981", 0x0302, 0xD000, {0,}, 0, myson981},
- {"Myson (unknown type)", 0, 0, {0x00,0xC0,0xB4,}, 0, myson981},
- {"Alta/Kendin Sundance", 0x0022, 0x1720, {0,}, 0, NULL},
- {"Alta/Kendin Sundance", 0, 0, {0x00,0x08,0x85}, 0, NULL},
- {"VIA Tahoe VT6103", 0x0101, 0x8f20, {0,}, 0, via_vt6103},
- {"VIA Tahoe VT6104", 0x0101, 0x8f30, {0,}, 0, via_tahoe},
- {"VIA Rhine VT6105", 0x0101, 0x8f22, {0,}, 0, via_vt6105},
- {"Intel 82557 series", 0x02a8, 0x0150, {0,}, 0, intel},
- {"Intel 82555 rev 1", 0x02a8, 0x0151, {0,}, 0, intel},
- {"Intel 82559 transceiver", 0x02a8, 0x0154, {0,}, 0, intel},
- {"Intel 82555 series transceiver", 0,0, {0x00,0xaa,0x00}, 0, intel},
+#define OUI(a,b,c) ((a) << 26 | (b) << 18 | (c) << 10), 0xfffffc00
+ /* Table sorted in numerical order, but with regard to the mask */
+ {0x00000000, 0xffffffff, "Unknown transceiver type"},
+ {0x00006b91, 0xffffffff, "AMD 79c901A.1 HomePNA", amd_pna },
+ {0x00006b92, 0xffffffff, "AMD 79c901A.2 HomePNA", amd_pna },
+ {0x00006b93, 0xffffffff, "AMD 79c901A.3 HomePNA", amd_pna },
+ {0x00007b71, 0xffffffff, "AMD 79c901A.3 10baseT", amd_tx },
+ {0x00221720, 0xffffffff, "Alta/Kendin Sundance"},
+ {OUI(0x00, 0x08, 0x85), "Alta/Kendin Sundance"},
+ {0x002b09a0, 0xfffffff0, "Marvell Semiconductor 88X3310", mv88x3310 },
+ {0x002bdc00, 0xfffffc00, "Broadcom BCM63XX"},
+ {0x00406000, 0xfffffc00, "Broadcom BCM63XX"},
+ {0x00437411, 0xffffffff, "Enable Semiconductor EL40-331", enablesemi },
+ {0x004dd076, 0xffffffef, "Atheros AT8030"},
+ {0x004dd074, 0xffffffef, "Atheros AT8031"},
+ {0x004dd072, 0xffffffef, "Atheros AT8035"},
+ {0x01018f20, 0xffffffff, "VIA Tahoe VT6103", via_vt6103 },
+ {0x01018f30, 0xffffffff, "VIA Tahoe VT6104", via_tahoe },
+ {0x01018f22, 0xffffffff, "VIA Rhine VT6105", via_vt6105 },
+ {0x01410c60, 0xfffffff0, "Marvell Semiconductor 88E1101"},
+ {0x01410c90, 0xfffffff0, "Marvell Semiconductor 88E1112"},
+ {0x01410cb0, 0xfffffff0, "Marvell Semiconductor 88E1121R"},
+ {0x01410cc0, 0xfffffff0, "Marvell Semiconductor 88E1111", mv88e1111 },
+ {0x01410cd0, 0xfffffff0, "Marvell Semiconductor 88E1145"},
+ {0x01410da0, 0xfffffff0, "Marvell Semiconductor 88X3310", mv88x3310_xs},
+ {0x01410dd0, 0xfffffff0, "Marvell Semiconductor 88E151x", mv88e151x },
+ {0x01410e10, 0xfffffff0, "Marvell Semiconductor 88E1118"},
+ {0x01410e30, 0xfffffff0, "Marvell Semiconductor 88E1240"},
+ {0x01410e40, 0xfffffff0, "Marvell Semiconductor 88E1116R"},
+ {0x01410e50, 0xfffffff0, "Marvell Semiconductor 88E1149R"},
+ {0x01410e60, 0xfffffff0, "Marvell Semiconductor 88E3016"},
+ {0x01410e90, 0xfffffff0, "Marvell Semiconductor 88E1318S"},
+ {0x01410ea0, 0xfffffff0, "Marvell Semiconductor 88E1545"},
+ {0x01410eb0, 0xfffffff0, "Marvell Semiconductor 88E1540"},
+ {OUI(0x00, 0x50, 0x43), "Marvell Semiconductor (unknown type)"},
+ {0x0143bc30, 0xfffffff0, "Broadcom BCM5241"},
+ {0x0143bc70, 0xfffffff0, "Broadcom BCMAC131"},
+ {0x0143bca0, 0xfffffff0, "Broadcom BCM5481"},
+ {0x0143bcf0, 0xfffffff0, "Broadcom BCM5395"},
+ {0x0143bd60, 0xfffffff0, "Broadcom BCM50610"},
+ {0x0143bd70, 0xfffffff0, "Broadcom BCM50610M"},
+ {0x01814410, 0xffffffff, "Quality Semiconductor QS6612", qs6612 },
+ {OUI(0x00, 0x60, 0x51), "Quality Semiconductor (unknown type)" },
+ {0x0181b800, 0xffffffff, "Davicom DM9101", davicom_dm9101 },
+ {OUI(0x00, 0x60, 0x6e), "Davicom (unknown type)", davicom_dm9101 },
+ {0x02821c51, 0xffffffff, "SMSC 83c180", smsc83c180 },
+ {0x02a80150, 0xffffffff, "Intel 82557 series", intel },
+ {0x02a80151, 0xffffffff, "Intel 82555 rev 1", intel },
+ {0x02a80154, 0xffffffff, "Intel 82559 transceiver", intel },
+ {OUI(0x00, 0xaa, 0x00), "Intel 82555 series transceiver", intel },
+ {0x0300e542, 0xffffffff, "TDK Semi 78Q2120 rev. 2", tdk78q2120 },
+ {0x0300e543, 0xffffffff, "TDK Semi 78Q2120 rev. 3", tdk78q2120 },
+ {0x0300e54b, 0xffffffff, "TDK Semi 78Q2120 rev. 11", tdk78q2120 },
+ {OUI(0x00, 0xc0, 0x39), "TDK transceiver (unknown type)", tdk78q2120 },
+ {0x0302d000, 0xffffffff, "Myson MTD981", myson981 },
+ {OUI(0x00, 0xc0, 0xb4), "Myson (unknown type)", myson981 },
+ {OUI(0x00, 0xf8, 0x00), "Intel (unknown type)", intel_i553 },
+ {0x20005c01, 0xffffffff, "National Semiconductor 83840A"},
+ {0x20005c10, 0xffffffff, "National Semiconductor 83843", ns83843 },
+ {0x600d8480, 0xfffffff0, "Broadcom BCM7439"},
+ {0x600d8490, 0xfffffff0, "Broadcom BCM7366"},
+ {0x600d84b0, 0xfffffff0, "Broadcom BCM7362"},
+ {0x600d8510, 0xfffffff0, "Broadcom BCM7445"},
+ {0x600d8650, 0xfffffff0, "Broadcom BCM7346"},
+ {0x600d86b0, 0xfffffff0, "Broadcom BCM7425"},
+ {0x600d8730, 0xfffffff0, "Broadcom BCM7429"},
+ {0x600d8750, 0xfffffff0, "Broadcom BCM7435"},
+ {0x78100000, 0xffffffff, "Level One LXT970"},
+ {0x78100001, 0xffffffff, "Level One LXT971"},
+ {0x78100003, 0xffffffff, "Level One LXT971A"},
+ {OUI(0x1e, 0x04, 0x00), "Level One (unknown type)"},
+ {0xae025080, 0xfffffff0, "Broadcom BCM7439"},
+ {0xae025090, 0xfffffff0, "Broadcom BCM7268"},
+ {0xae025190, 0xfffffff0, "Broadcom BCM7260"},
+ {0xae0251a0, 0xfffffff0, "Broadcom BCM7278"},
+ {0xae025260, 0xfffffff0, "Broadcom BCM7364"},
+ {0xae025280, 0xfffffff0, "Broadcom BCM7250"},
+ {0xae0252e0, 0xfffffff0, "Broadcom BCM74371"},
+ {0xae0253b0, 0xfffffff0, "Broadcom BCM7271"},
+
+ /* Unsorted entries */
+ {0x0022561b, 0xffffffff, "AdHoc Technology AH101LF", tdk78q2120 },
+ {0x00225523, 0xffffffff, "Altimata Communications AC101LF", tdk78q2120 },
+ {OUI(0x00, 0x10, 0xa9), "Altimata Comm (unknown type)", tdk78q2120 },
+ {OUI(0x00, 0xc0, 0xb4), "ASIX (unknown type)", tdk78q2120 },
+ {0x00225410, 0xffffffff, "ADMtek AN983 Comet", admtek },
+ {0x00225513, 0xffffffff, "ADMtek AN985 Comet", admtek },
+ {OUI(0x00, 0xe0, 0x92), "ADMtek (unknown type)", admtek },
+ {0x01807641, 0xffffffff, "Lucent LU6612", qs6612 },
+ {0x00437411, 0xffffffff, "Lucent LU3X31", lu3x31 },
+ {OUI(0x00, 0xa0, 0x7d), "LSI Logic (Seeq) 80225"},
{0, },
};
-static u16 mii_val[32];
+static int __mdio_read_phy(const struct phy *phy, unsigned int reg)
+{
+ return mdio_read(phy->ioaddr, phy->phy_id | phy->devad,
+ phy->offset + reg);
+}
-void show_mii_details(long ioaddr, int phy_id)
+static int mdio_read_phy(const struct phy *phy, unsigned int reg)
{
- int mii_reg, i, vendor = 0;
- u16 bmcr, bmsr, new_bmsr;
+ return phy->mdio_read(phy, reg);
+}
- /* This may not be omitted from the output. */
- printf("%s", version_msg);
- printf(" MII PHY #%d transceiver registers:", phy_id);
- for (mii_reg = 0; mii_reg < 32; mii_reg++) {
- mii_val[mii_reg] = mdio_read(ioaddr, phy_id, mii_reg);
+static int lookup_vendor(int reg2, int reg3)
+{
+ u32 id = reg2 << 16 | reg3;
+ unsigned char oui_0 = id >> 26;
+ unsigned char oui_1 = id >> 18;
+ unsigned char oui_2 = id >> 10;
+ unsigned char model = (id >> 4) & 0x3f;
+ unsigned char rev = id & 0x0f;
+ int i, vendor = 0;
+
+ printf(" Vendor ID is %2.2x:%2.2x:%2.2x:--:--:--, model %d rev. %d.\n",
+ oui_0, oui_1, oui_2, model, rev);
+
+ for (i = 0; oui_map[i].vendor; i++)
+ if (((oui_map[i].phy_id ^ id) & oui_map[i].msk_id) == 0) {
+ printf(" Vendor/Part: %s.\n", oui_map[i].vendor);
+ vendor = i;
+ break;
+ }
+ if (oui_map[i].vendor == NULL)
+ printf(" No specific information is known about this transceiver"
+ " type.\n");
+
+ return vendor;
+}
+
+struct msg_tbl { int bitmask; char *msg; };
+
+static void msg_if_set(const int val, const struct msg_tbl msg_tbl[])
+{
+ int i;
+ for (i = 0; msg_tbl[i].bitmask; i++)
+ if (msg_tbl[i].bitmask & val)
+ printf(" %s\n", msg_tbl[i].msg);
+}
+
+static void msg_if_set_fmt(const int val, const struct msg_tbl msg_tbl[],
+ const char *fmt)
+{
+ int i;
+ for (i = 0; msg_tbl[i].bitmask; i++)
+ if (msg_tbl[i].bitmask & val)
+ printf(fmt, msg_tbl[i].msg);
+}
+
+static u16 mii_val[64], c45_an_ctrl;
+
+void read_mii_regs(long ioaddr, int phy_id, unsigned int first, unsigned int num_regs)
+{
+ int mii_reg;
+
+ for (mii_reg = 0; mii_reg < num_regs; mii_reg++) {
+ int val = mdio_read(ioaddr, phy_id, first + mii_reg);
+ mii_val[mii_reg] = val < 0 ? 0 : val;
+ }
+}
+
+static void show_mii_regs(int num_regs)
+{
+ int mii_reg;
+
+ for (mii_reg = 0; mii_reg < num_regs; mii_reg++)
printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "",
mii_val[mii_reg]);
+}
+
+struct bit_decoder {
+ u16 mask;
+ u16 val;
+ const char *str;
+};
+
+static const char **bit_decoder(const char **str, u16 val,
+ const struct bit_decoder *decoder)
+{
+ int i;
+
+ for (i = 0; decoder[i].str; i++)
+ if ((val & decoder[i].mask) == decoder[i].val)
+ *str++ = decoder[i].str;
+ *str = NULL;
+
+ return str;
+}
+
+struct multi_bit_decoder {
+ unsigned int offset;
+ const struct bit_decoder *bits;
+};
+
+static const char **multi_bit_decoder(const char **str, const u16 *vals,
+ const struct multi_bit_decoder *mdec)
+{
+ const char **p = str;
+ int i;
+
+ for (i = 0; mdec[i].bits; i++)
+ p = bit_decoder(p, vals[mdec[i].offset], mdec[i].bits);
+
+ return p;
+}
+
+#if 0
+static char *strconcat(const char *separator, const char **strings)
+{
+ size_t length, sep_length = strlen(separator);
+ char *string, *p;
+ int i;
+
+ if (!strings[0])
+ return NULL;
+
+ for (i = 0, length = 0; strings[i]; i++)
+ length += strlen(strings[i]);
+ length += (i - 1) * sep_length;
+
+ string = malloc(length);
+ if (!string)
+ return NULL;
+
+ for (i = 0, p = string; strings[i]; i++) {
+ if (i) {
+ strcpy(p, separator);
+ p += sep_length;
+ }
+ strcpy(p, strings[i]);
+ p += strlen(p);
+ }
+
+ return string;
+}
+#endif
+
+static void print_strings(const char **strs, const char *prefix,
+ const char *separator)
+{
+ int need_separator = 0;
+ int need_prefix = 1;
+ int i;
+
+ for (i = 0; strs[i]; i++) {
+ const char *pfx = "";
+ const char *str = strs[i];
+
+ if (need_prefix) {
+ pfx = prefix;
+ need_prefix = 0;
+ } else if (need_separator) {
+ pfx = separator;
+ }
+
+ printf("%s%s", pfx, str);
+ if (str[strlen(str) - 1] == '\n')
+ need_prefix = 1;
+ need_separator = 1;
}
+ if (!need_separator || !need_prefix)
+ printf(".\n");
+}
+
+static void show_mii_bits(u16 val, const struct bit_decoder *decoder,
+ const char *prefix, const char *separator)
+{
+ const char *strings[64];
+
+ bit_decoder(strings, val, decoder);
+ print_strings(strings, prefix, separator);
+}
+
+static void show_mii_reg(const char *name, u16 val,
+ const struct bit_decoder *decoder,
+ const char *prefix, const char *separator)
+{
+ printf(" %s %4.4x", name, val);
+ show_mii_bits(val, decoder, prefix, separator);
+}
+
+static void show_mii_multibits(u16 *vals,
+ const struct multi_bit_decoder *decoder,
+ const char *prefix, const char *separator)
+{
+ const char *strings[64];
+
+ multi_bit_decoder(strings, vals, decoder);
+ print_strings(strings, prefix, separator);
+}
+
+static const char *protocol(unsigned int proto)
+{
+ if (proto == 1)
+ return "IEEE 802.3 CSMA/CD protocol";
+ else
+ return "Using an unknown (non 802.3) encapsulation";
+}
+
+static void show_protocol(unsigned int proto)
+{
+ printf(" %s.\n", protocol(proto));
+}
+
+
+/* AN advertisements etc */
+// Clause 22 base page advert
+static const struct bit_decoder c22_base_advert[] = {
+ { BIT(11), BIT(11), "AsymPause" },
+ { BIT(10), BIT(10), "Pause" },
+ { BIT(9), BIT(9), "100baseT4" },
+ { BIT(8), BIT(8), "100baseTx-FD" },
+ { BIT(7), BIT(7), "100baseTx" },
+ { BIT(6), BIT(6), "10baseT-FD" },
+ { BIT(5), BIT(5), "10baseT" },
+ { },
+};
+
+static void show_advert(u16 advert)
+{
+ show_mii_reg("I'm advertising", advert, c22_base_advert,
+ ".\n Advertising ", " ");
+ printf(" Advertising %sadditional info pages.\n",
+ advert & BIT(15) ? "" : "no ");
+ show_protocol(advert & 31);
+}
+
+static void show_lpar(u16 lpar)
+{
+ show_mii_reg("Link partner advertisment is", lpar, c22_base_advert,
+ ".\n Advertising ", " ");
+ if (lpar & BIT(13))
+ printf(" Remote fault.\n");
+ printf(" Negotiation %s.\n",
+ lpar & BIT(14) ? "completed" : "did not complete");
+}
+
+static void show_xnp(const char *prefix, u16 adv)
+{
+ printf(" %s is %4.4x: ", prefix, adv);
+ if (adv & BIT(13))
+ printf("message page %u\n", adv & 0x07ff);
+ else
+ printf("unformatted code %3.3x\n", adv & 0x07ff);
+}
+
+static void show_xnp_advert(u16 adv)
+{
+ show_xnp("XNP advert", adv);
+}
+
+static void show_xnp_lpar(u16 lpa)
+{
+ show_xnp("XNP link partner", lpa);
+}
+
+// Clause 28 base page and 1000Base-T control/status
+static void show_c28_advert(struct phy *phy, u16 *regs)
+{
+ show_advert(regs[4]);
+ if (regs[1] & BIT(8)) {
+ printf(" 1000baseT control %4.4x:", regs[9]);
+ if (regs[9] & BIT(8))
+ printf(" 1000baseT-HD");
+ if (regs[9] & BIT(9))
+ printf(" 1000baseT-FD");
+ printf("\n");
+ }
+}
+
+static void show_c28_lpar(struct phy *phy, u16 *regs)
+{
+ show_lpar(regs[5]);
+ if (regs[1] & BIT(8)) {
+ printf(" 1000baseT status %4.4x:", regs[10]);
+ if (regs[10] & BIT(10))
+ printf(" 1000baseT-HD");
+ if (regs[10] & BIT(11))
+ printf(" 1000baseT-FD");
+ if (regs[10] & BIT(12))
+ printf(" RemoteRxOK");
+ if (regs[10] & BIT(13))
+ printf(" LocalRxOK");
+ printf("\n");
+ }
+}
+
+static const struct c22_decoder c28_linkword = {
+ .show_advert = show_c28_advert,
+ .show_lpar = show_c28_lpar,
+};
+
+// Clause 37 1000baseX advert
+static void show_c37_advert(struct phy *phy, u16 *regs)
+{
+ u16 base = regs[4];
+
+ printf(" I'm advertising %4.4x:", base);
+ if (base & BIT(6))
+ printf(" 1000baseX");
+ if (base & BIT(5))
+ printf(" 1000baseX-FD");
+ if (base & BIT(7))
+ printf(" Pause");
+ if (base & BIT(8))
+ printf(" AsymPause");
printf(".\n");
+}
+
+static void show_c37_lpar(struct phy *phy, u16 *regs)
+{
+ u16 base = regs[5];
+ if (base) {
+ printf(" Link partner advertisment is %4.4x.\n Advertising", base);
+ if (base & BIT(6))
+ printf(" 1000baseX");
+ if (base & BIT(5))
+ printf(" 1000baseX-FD");
+ if (base & BIT(7))
+ printf(" Pause");
+ if (base & BIT(8))
+ printf(" AsymPause");
+ printf(".\n");
+ }
+}
+
+static const struct c22_decoder c37_linkword = {
+ .show_advert = show_c37_advert,
+ .show_lpar = show_c37_lpar,
+};
+
+// Cisco SGMII advert
+static const struct bit_decoder cisco_sgmii_adv_decoder[] = {
+ { 0x8000, 0x0000, "Link Down" },
+ { 0x8000, 0x8000, "Link Up, " },
+ { 0x8c00, 0x8000, "10M" },
+ { 0x8c00, 0x8400, "100M" },
+ { 0x8c00, 0x8800, "1000M" },
+ { 0x8c00, 0x8c00, "?" },
+ { 0x9000, 0x8000, "/Half" },
+ { 0x9000, 0x9000, "/Full" },
+ { 0, 0, NULL },
+};
+
+static void cisco_sgmii_advert(struct phy *phy, u16 *regs)
+{
+ const char *strings[17], **p = strings;
+ u16 base = regs[4];
+
+ printf(" SGMII advertisement %4.4x", base);
+ if (base & 1)
+ p = bit_decoder(p, base, cisco_sgmii_adv_decoder);
+ else
+ *p++ = " Link down";
+ if (base & 0x63fe)
+ *p++ = ", reserved bits are set";
+ *p = NULL;
+ print_strings(strings, ": ", "");
+}
+
+static void cisco_sgmii_lpar(struct phy *phy, u16 *regs)
+{
+ u16 base = regs[5];
+
+ printf(" SGMII acknowledgement %4.4x: ", base);
+ if (base & 1)
+ printf("%s.", base == 0x4001 ? "MAC acknowledged" : "unknown");
+ else if (base == 0)
+ printf("Unacknowledged.");
+
+ printf("\n");
+}
+
+static const struct c22_decoder cisco_sgmii_linkword = {
+ .show_advert = cisco_sgmii_advert,
+ .show_lpar = cisco_sgmii_lpar,
+};
+
+// Clause 73.6 (baseR) advert
+static const struct bit_decoder c73_linkword_high16[] = {
+ { BIT(15), BIT(15), "FEC requested" }, /* F1 */
+ { BIT(14), BIT(14), "FEC ability" }, /* F0 */
+ { },
+};
+
+static const struct bit_decoder c73_linkword_mid16[] = {
+ { BIT(13), BIT(13), "100GbaseCR4" }, /* A8 */
+ { BIT(12), BIT(12), "100GbaseKR4" }, /* A7 */
+ { BIT(11), BIT(11), "100GbaseKP4" }, /* A6 */
+ { BIT(10), BIT(10), "100GbaseCR10" }, /* A5 */
+ { BIT(9), BIT(9), "40GbaseCR4" }, /* A4 */
+ { BIT(8), BIT(8), "40GbaseKR4" }, /* A3 */
+ { BIT(7), BIT(7), "10GbaseKR" }, /* A2 */
+ { BIT(6), BIT(6), "10GbaseKX4" }, /* A1 */
+ { BIT(5), BIT(5), "1000baseKX" }, /* A0 */
+ { },
+};
+
+static const struct bit_decoder c73_linkword_low16[] = {
+ { BIT(11), BIT(11), "AsmPause" }, /* C1 */
+ { BIT(10), BIT(10), "Pause" }, /* C0 */
+ { },
+};
+
+static const struct multi_bit_decoder c73_linkword[] = {
+ { 2, c73_linkword_high16 }, /* D32:D47 */
+ { 1, c73_linkword_mid16 }, /* D16:D31 */
+ { 0, c73_linkword_low16 }, /* D0:D15 */
+ { },
+};
+
+static void show_c73_linkword(const char *desc, u16 *lwp)
+{
+ printf(" %s %4.4x%4.4x%4.4x.\n", desc, lwp[2], lwp[1], lwp[0]);
+ show_mii_multibits(lwp, c73_linkword, " Advertising ", " ");
+ if (lwp[0] & BIT(13))
+ printf(" Remote fault.\n");
+ show_protocol(lwp[0] & 31);
+}
+
+
+/* PMA/PMD tables */
+// 1.0.5:2: Control register 1: Speed selection
+static const char *pma_speed[16] = {
+ [0x0] = "10Gb/s",
+ [0x1] = "10PASS-TS/2base-TL",
+ [0x2] = "40Gb/s",
+ [0x3] = "100Gb/s",
+ [0x4] = "25Gb/s",
+ [0x6] = "2.5Gb/s", // 802.3bz
+ [0x7] = "5Gb/s", // 802.3bz
+};
+
+// 1.4: PMA/PMD speed ability
+static const struct bit_decoder mii_c45_spd_cap_pma[] = {
+ { BIT(8), BIT(8), "100G" },
+ { BIT(7), BIT(7), "40G" },
+ { BIT(0), BIT(0), "10G" },
+ { BIT(6), BIT(6), "10G/1G" },
+ { BIT(14), BIT(14), "5G" }, // 802.3bz
+ { BIT(13), BIT(13), "2.5G" }, // 802.3bz
+ { BIT(3), BIT(3), "1G" },
+ { BIT(4), BIT(4), "100M" },
+ { BIT(5), BIT(5), "10M" },
+ { BIT(2), BIT(2), "10PASS-TS" },
+ { BIT(1), BIT(1), "2base-TL" },
+ { },
+};
+
+// 1.7: PMA/PMD control 2 register
+static const char *mii_c45_type_pma[128] = {
+ [0x00] = "10GbaseCX4", [0x01] = "10GbaseEW",
+ [0x02] = "10GbaseLW", [0x03] = "10GbaseSW",
+ [0x04] = "10GbaseLX4", [0x05] = "10GbaseER",
+ [0x06] = "10GbaseLR", [0x07] = "10GbaseSR",
+ [0x08] = "10GbaseLRM", [0x09] = "10GbaseT",
+ [0x0a] = "10GbaseKX4", [0x0b] = "10GbaseKR",
+ [0x0c] = "1000baseT", [0x0d] = "1000baseKX",
+ [0x0e] = "100baseTX", [0x0f] = "10baseT",
+ [0x10] = "10/1GbasePRX-D1", [0x11] = "10/1GbasePRX-D2",
+ [0x12] = "10/1GbasePRX-D3", [0x13] = "10GbasePR-D1",
+ [0x14] = "10GbasePR-D2", [0x15] = "10GbasePR-D3",
+ [0x16] = "10/1GbasePRX-U1", [0x17] = "10/1GbasePRX-U2",
+ [0x18] = "10/1GbasePRX-U3", [0x19] = "10GbasePR-U1",
+ [0x1a] = "10GbasePR-U3",
+ [0x26] = "40GbaseT", // 802.3bq
+ [0x30] = "2.5GbaseT", [0x31] = "5GbaseT", // 802.3bz
+ [0x37] = "25GbaseT", // 802.3bq
+ [0x40] = "40GbaseKR4", [0x41] = "40GbaseCR4",
+ [0x42] = "40GbaseSR4", [0x43] = "40GbaseLR4",
+ [0x44] = "40GbaseFR",
+ [0x50] = "100GbaseCR10", [0x51] = "100GbaseSR10",
+ [0x52] = "100GbaseLR4", [0x53] = "100GbaseER4",
+};
+
+// 1.8: PMA/PMD status 2 register
+static const struct bit_decoder mii_c45_stat_2_pma[] = {
+ { BIT(0), BIT(0), "Local loopback" },
+ { BIT(1), BIT(1), "10GbaseEW" },
+ { BIT(2), BIT(2), "10GbaseLW" },
+ { BIT(3), BIT(3), "10GbaseSW" },
+ { BIT(4), BIT(4), "10GbaseLX4" },
+ { BIT(5), BIT(5), "10GbaseER" },
+ { BIT(6), BIT(6), "10GbaseLR" },
+ { BIT(7), BIT(7), "10GbaseSR" },
+ { BIT(8), BIT(8), "Transmit disable" },
+ { BIT(12), BIT(12), "Receive fault" },
+ { BIT(13), BIT(13), "Transmit fault" },
+ { },
+};
+
+// 1.11: PMA/PMD extended ability register
+static const struct bit_decoder mii_c45_ext_ability_pma[] = {
+ { BIT(10), BIT(10), "40G/100G (below)" },
+ { BIT(0), BIT(0), "10GbaseCX4" },
+ { BIT(1), BIT(1), "10GbaseLRM" },
+ { BIT(2), BIT(2), "10GbaseT" },
+ { BIT(3), BIT(3), "10GbaseKX4" },
+ { BIT(4), BIT(4), "10GbaseKR" },
+ { BIT(14), BIT(14), "2.5G/5G (below)" }, // 802.3bz
+ { BIT(5), BIT(5), "1000baseT" },
+ { BIT(6), BIT(6), "1000baseKX" },
+ { BIT(7), BIT(7), "100baseTX" },
+ { BIT(8), BIT(8), "10baseT" },
+ { BIT(9), BIT(9), "P2MP" },
+ { },
+};
+
+// 1.13: 40G/100G PMA/PMD extended ability register
+static const struct bit_decoder mii_c45_40g_ext_abl_pma[] = {
+ { BIT(7), BIT(7), "100GbaseSR4" },
+ { BIT(8), BIT(8), "100GbaseCR10" },
+ { BIT(9), BIT(9), "100GbaseSR10" },
+ { BIT(10), BIT(10), "100GbaseLR4" },
+ { BIT(11), BIT(11), "100GbaseER4" },
+ { BIT(12), BIT(12), "100GbaseKP4" },
+ { BIT(13), BIT(13), "100GbaseKR4" },
+ { BIT(14), BIT(14), "100GbaseCR4" },
+ { BIT(0), BIT(0), "40GbaseKR4" },
+ { BIT(1), BIT(1), "40GbaseCR4" },
+ { BIT(2), BIT(2), "40GbaseSR4" },
+ { BIT(3), BIT(3), "40GbaseLR4" },
+ { BIT(4), BIT(4), "40GbaseFR" },
+ { BIT(5), BIT(5), "40GbaseER4" },
+ { BIT(6), BIT(6), "40GbaseT" }, // 802.3bq
+ { BIT(15), BIT(15), "PMA remote loopback" },
+ { },
+};
+
+// 1.16: EEE capability
+static const struct bit_decoder mii_c45_eee_capability_pma[] = {
+ { BIT(11), BIT(11), "100GBASE-CR4" },
+ { BIT(10), BIT(10), "100GBASE-KR4" },
+ { BIT(9), BIT(9), "100GBASE-KP4" },
+ { BIT(8), BIT(8), "100GBASE-CR10" },
+ { BIT(1), BIT(1), "40GBASE-CR4" },
+ { BIT(0), BIT(0), "40GBASE-KR4" },
+ { },
+};
+
+// 1.19: 25G PMA/PMD extended ability register
+static const struct bit_decoder mii_c45_25g_ext_abl_pma[] = {
+ { BIT(5), BIT(5), "25GbaseT" }, // 802.3bq
+ { },
+};
+
+// 1.21: 2.5G/5G PMA/PMD extended ability register
+static const struct bit_decoder mii_c45_nbase_ext_abl_pma[] = {
+ { BIT(1), BIT(1), "5GbaseT" }, // 802.3bz
+ { BIT(0), BIT(0), "2.5GbaseT" }, // 802.3bz
+ { },
+};
+
+
+/* PCS */
+// 3.0.5:2: Control register 1: Speed selection
+static const char *pcs_speed[16] = {
+ [0x0] = "10Gb/s",
+ [0x1] = "10PASS-TS/2base-TL",
+ [0x2] = "10/1Gb/s",
+ [0x3] = "40Gb/s",
+ [0x4] = "100Gb/s",
+ [0x7] = "2.5Gb/s", // 802.3bz
+ [0x8] = "5Gb/s", // 802.3bz
+};
+
+// 3.1: PCS status 1 register
+static const struct bit_decoder mii_c45_pcs_stat[] = {
+ { BIT(11), BIT(11), "Tx LPI received" },
+ { BIT(10), BIT(10), "Rx LPI received" },
+ { BIT(9), BIT(9), "Tx LPI indication" },
+ { BIT(8), BIT(8), "Rx LPI indication" },
+ { BIT(6), BIT(6), "Clock stop capable" },
+ { BIT(1), BIT(1), "Supports low-power mode" },
+ { },
+};
+
+// 3.4: PCS speed ability register
+static const struct bit_decoder mii_c45_spd_cap_pcs[] = {
+ { BIT(3), BIT(3), "100G" },
+ { BIT(2), BIT(2), "40G" },
+ { BIT(0), BIT(0), "10G" },
+ { BIT(7), BIT(7), "5G" }, // 802.3bz
+ { BIT(6), BIT(6), "2.5G" }, // 802.3bz
+ { BIT(1), BIT(1), "10PASS-TS/2base-TL" },
+ { },
+};
+
+// 3.7.3:0 PCS type selection
+static const char *mii_c45_type_pcs[16] = {
+ [0x0] = "10GbaseR",
+ [0x1] = "10GbaseX",
+ [0x2] = "10GbaseW",
+ [0x3] = "10GbaseT",
+ [0x4] = "40GbaseR",
+ [0x5] = "100GbaseR",
+ [0x6] = "40GbaseT", // 802.3bq
+ [0x7] = "25GbaseR", // 802.3bq
+ [0x9] = "25GbaseT", // 802.3bq
+ [0xa] = "2.5GbaseT", // 802.3bz
+ [0xb] = "5GbaseT", // 802.3bz
+};
+
+// 3.8: PCS status 2 register
+static const struct bit_decoder mii_c45_stat_2_pcs[] = {
+ { BIT(5), BIT(5), "100GbaseR" },
+ { BIT(4), BIT(4), "40GbaseR" },
+ { BIT(6), BIT(6), "40GbaseT" }, // 802.3bq
+ { BIT(9), BIT(9), "25GbaseT" }, // 802.3bq
+ { BIT(0), BIT(0), "10GbaseR" },
+ { BIT(1), BIT(1), "10GbaseX" },
+ { BIT(2), BIT(2), "10GbaseW" },
+ { BIT(3), BIT(3), "10GbaseT" },
+ { BIT(12), BIT(12), "5GbaseT" }, // 802.3bz
+ { BIT(13), BIT(13), "2.5GbaseT" }, // 802.3bz
+ { },
+};
+
+// 3.20: EEE control and capability
+static const struct bit_decoder mii_c45_eee_ctrl_capab_pcs[] = {
+ { BIT(13), BIT(13), "100GBASE-R deep sleep" },
+ { BIT(12), BIT(12), "100GBASE-R fast wake" },
+ { BIT(9), BIT(9), "40GBASE-R deep sleep" },
+ { BIT(8), BIT(8), "40GBASE-R fast wake" },
+ { BIT(6), BIT(6), "10GBASE-KR" },
+ { BIT(5), BIT(5), "10GBASE-KX4" },
+ { BIT(4), BIT(4), "1000BASE-KX" },
+ { BIT(3), BIT(3), "10GBASE-T" },
+ { BIT(2), BIT(2), "1000BASE-T" },
+ { BIT(1), BIT(1), "100BASE-TX" },
+ { BIT(0), BIT(0), "FastWake" },
+ { },
+};
+
+// 3.32: baseR and MultiGbaseT PCS status 1 register
+static const struct bit_decoder mii_pcs_basert_stat1[] = {
+ { BIT(12), BIT(12), "PCS receive link up" },
+ { BIT(3), BIT(3), "PRBS9 pattern testing" },
+ { BIT(2), BIT(2), "PRBS31 pattern testing" },
+ { BIT(1), BIT(1), "High BER" },
+ { BIT(0), BIT(0), "Block lock" },
+ { },
+};
+
+// 3.33: baseR and MultiGbaseT PCS status 2 register
+static const struct bit_decoder mii_pcs_basert_stat2[] = {
+ { BIT(15), BIT(15), "Block lock (latched)" },
+ { BIT(14), BIT(14), "High BER (latched)" },
+ { },
+};
+
+static const struct multi_bit_decoder mii_pcs_basert_stat[] = {
+ { MMD_PCS_BASERT_STAT1, mii_pcs_basert_stat1 },
+ { MMD_PCS_BASERT_STAT2, mii_pcs_basert_stat2 },
+ { },
+};
+
+
+/* PHY XGXS / DTE XGXS */
+// 4.0.5:2: PHY XGXS Control register 1: Speed selection
+// 5.0.5:2: DTE XGXS Control register 1: Speed selection
+static const char *xs_speed[16] = {
+ [0x0] = "10Gb/s",
+};
+
+// 4.1: PHYXS status 1 register
+static const struct bit_decoder mii_c45_phyxs_stat[] = {
+ { BIT(11), BIT(11), "Tx LPI received" },
+ { BIT(10), BIT(10), "Rx LPI received" },
+ { BIT(9), BIT(9), "Tx LPI indication" },
+ { BIT(8), BIT(8), "Rx LPI indication" },
+ { BIT(6), BIT(6), "Clock stop capable" },
+ { BIT(1), BIT(1), "Supports low-power mode" },
+ { },
+};
+
+// 4.4: PHY XGXS speed ability register
+// 5.4: DTE XGXS speed ability register
+static const struct bit_decoder mii_c45_spd_cap_xs[] = {
+ { BIT(0), BIT(0), "10G" },
+ { },
+};
+
+// 4.20: EEE capability
+// 5.20: EEE capability
+static const struct bit_decoder mii_c45_eee_ctrl_capab_xs[] = {
+ { BIT(4), BIT(4), "EEE" },
+ { BIT(0), BIT(0), "XAUI stop capable" },
+ { },
+};
+
+// 4.24: PHY XGXS lane status register
+static const struct bit_decoder mii_phyxs_lane_status[] = {
+ { BIT(12), BIT(12), "lanes synchronized and aligned" },
+ { BIT(11), BIT(11), "pattern testing supported" },
+ { BIT(10), BIT(10), "loopback support" },
+ { BIT(3), BIT(3), "lane 3 synchronized" },
+ { BIT(2), BIT(2), "lane 2 synchronized" },
+ { BIT(1), BIT(1), "lane 2 synchronized" },
+ { BIT(0), BIT(0), "lane 2 synchronized" },
+ { },
+};
+
+/* AN */
+// 7.1: AN status
+static const struct bit_decoder mii_c45_an_stat[] = {
+ { BIT(3), 0, "Unable to perform Auto-negotiation.\n" },
+ { BIT(3) | BIT(5), BIT(3), "Able to perform Auto-negotiation, negotiation not complete.\n" },
+ { BIT(3) | BIT(5), BIT(3) | BIT(5), "Able to perform Auto-negotiation, negotiation complete.\n" },
+ { BIT(0), BIT(0), "LP Auto-negotiation" },
+ { BIT(4), BIT(4), "Remote fault" },
+ { BIT(6), BIT(6), "Page Rcvd" },
+ { BIT(7), BIT(7), "Ext Next Pg" },
+ { BIT(9), BIT(9), "Parallel detection fault" },
+ { },
+};
+
+// 7.32: 10GbaseT AN control register (tech bits)
+static const struct bit_decoder mii_c45_an_multi_gbt_tech[] = {
+ /* 0..2 below */
+ { BIT(3), BIT(3), "40GbaseT/fast" }, // 802.3bq
+ { BIT(11), BIT(11), "40GbaseT" }, // 802.3bq
+ { BIT(9), BIT(9), "25GbaseT/fast" }, // 802.3bq
+ { BIT(10), BIT(10), "25GbaseT" }, // 802.3bq
+ { BIT(12), BIT(12), "10GbaseT" },
+ { BIT(6), BIT(6), "5GbaseT/fast" }, // 802.3bz
+ { BIT(8), BIT(8), "5GbaseT" }, // 802.3bz
+ { BIT(5), BIT(5), "2.5GbaseT/fast" }, // 802.3bz
+ { BIT(7), BIT(7), "2.5GbaseT" }, // 802.3bz
+ /* 13..15 below */
+ { },
+};
+
+// 7.32: 10GbaseT AN control register (other bits)
+static const struct bit_decoder mii_c45_an_multi_gbt_other[] = {
+ { 0, 0, "\n" },
+ { BIT(15) | BIT(14), BIT(15), "I'm configured to be the slave phy.\n" },
+ { BIT(15) | BIT(14), BIT(15) | BIT(14), "I'm configured to be the master phy.\n" },
+ { BIT(13), BIT(13), "I'm part of a multi-port device.\n" },
+ { BIT(13), 0, "I'm part of a single-port device.\n" },
+ { BIT(2), BIT(2), "10GbaseT LD frame reset" },
+ { BIT(1), BIT(1), "10GbaseT Fast retrain" },
+ { BIT(0), BIT(0), "10GbaseT LD loop timing" },
+ { },
+};
+
+static const struct multi_bit_decoder mii_c45_an_advert[] = {
+ { MMD_AN_MULTI_GBT_CTRL, mii_c45_an_multi_gbt_tech },
+ { MMD_AN_BASE_ADV0, c22_base_advert },
+ { MMD_AN_MULTI_GBT_CTRL, mii_c45_an_multi_gbt_other },
+ { },
+};
+
+// 7.33: 10GbaseT AN status register
+static const struct bit_decoder mii_an_multi_gbt_stat[] = {
+ { BIT(15), BIT(15), "Master/slave config fault" },
+ { BIT(14), BIT(14), "Local PHY master" },
+ { BIT(14), 0 << 14, "Local PHY slave" },
+ { BIT(13), 0 << 13, "Local RX not ok" },
+ { BIT(12), 0 << 13, "Remote RX not ok" },
+ { BIT(10), BIT(10), "LP loop timing" },
+ { BIT(8), BIT(8), "LP 40GbaseT" }, // 802.3bq
+ { BIT(2), BIT(2), "LP 25GbaseT/fast" }, // 802.3bq
+ { BIT(7), BIT(7), "LP 25GbaseT" }, // 802.3bq
+ { BIT(9), BIT(9), "LP 10GbaseT PMA retrain req" }, // 802.3bq
+ { BIT(11), BIT(11), "LP 10GbaseT" },
+ { BIT(4), BIT(4), "LP 5GbaseT/fast" }, // 802.3bz
+ { BIT(6), BIT(6), "LP 5GbaseT" }, // 802.3bz
+ { BIT(3), BIT(3), "LP 2.5GbaseT/fast" }, // 802.3bz
+ { BIT(5), BIT(5), "LP 2.5GbaseT" }, // 802.3bz
+ { BIT(1), BIT(1), "LP Fast retrain" },
+ { }
+};
+
+// 7.48: Backplane Ethernet, baseR copper status
+#define BASE_R_PORT_TYPE_MASK 0x0f6e
+static const struct bit_decoder mii_an_baser_status[] = {
+ { BASE_R_PORT_TYPE_MASK, BIT(1), "1000baseKX" },
+ { BASE_R_PORT_TYPE_MASK, BIT(2), "10GbaseKX4 or CX4" },
+ { BASE_R_PORT_TYPE_MASK, BIT(3), "10GbaseKR" },
+ { BASE_R_PORT_TYPE_MASK, BIT(5), "40GbaseKR4" },
+ { BASE_R_PORT_TYPE_MASK, BIT(6), "40GbaseCR4" },
+ { BASE_R_PORT_TYPE_MASK, BIT(8), "100GbaseCR10" },
+ { BASE_R_PORT_TYPE_MASK, BIT(9), "100GbaseKP4" },
+ { BASE_R_PORT_TYPE_MASK, BIT(10), "100GbaseKR4" },
+ { BASE_R_PORT_TYPE_MASK, BIT(11), "100GbaseCR4" },
+ { BIT(4), BIT(4), "FEC" },
+ { }
+};
+
+// 7.60: EEE advertisement
+// 7.61: EEE link partner ability
+static const struct bit_decoder mii_an_eee_advertisement[] = {
+ { BIT(13), BIT(13), "100GBASE-CR4" },
+ { BIT(12), BIT(12), "100GBASE-KR4" },
+ { BIT(11), BIT(11), "100GBASE-KP4" },
+ { BIT(10), BIT(10), "100GBASE-CR10" },
+ { BIT(8), BIT(8), "40GBASE-CR4" },
+ { BIT(7), BIT(7), "40GBASE-KR4" },
+ { BIT(6), BIT(6), "10GBASE-KR" },
+ { BIT(5), BIT(5), "10GBASE-KX4" },
+ { BIT(4), BIT(4), "1000BASE-KX" },
+ { BIT(3), BIT(3), "10GBASE-T" },
+ { BIT(2), BIT(2), "1000BASE-T" },
+ { BIT(1), BIT(1), "100BASE-TX" },
+ { }
+};
+
+
+static const char *mii_c45_speed(int devad)
+{
+ const char **speed_table = NULL;
+ unsigned int speed;
+
+ switch (devad) {
+ case MDIO_MMD_PMAPMD:
+ speed_table = pma_speed;
+ break;
+ case MDIO_MMD_PCS:
+ speed_table = pcs_speed;
+ break;
+ case MDIO_MMD_PHY_XS:
+ case MDIO_MMD_DTE_XS:
+ speed_table = xs_speed;
+ break;
+ }
+ switch (mii_val[MMD_CTRL1] & 0x2040) {
+ case 0x0000:
+ return "10Mb/s";
+ case 0x0040:
+ return "100Mb/s";
+ case 0x2000:
+ return "1Gb/s";
+ case 0x2040:
+ speed = (mii_val[MMD_CTRL1] & 0x003c) >> 2;
+ if (speed_table && speed_table[speed])
+ return speed_table[speed];
+ default:
+ return "Reserved";
+ }
+}
+
+static void show_mii_c45_status2(const struct phy *phy,
+ u16 stat2, const struct bit_decoder *decoder)
+{
+ u16 new_stat2 = mdio_read_phy(phy, MMD_STAT2);
+
+ printf(" Status 2 register %4.4x ... %4.4x\n", stat2, new_stat2);
+
+ if (decoder)
+ show_mii_bits(stat2, decoder, " Abilities: ", ", ");
+
+ if (new_stat2 & BIT(11))
+ printf(" *Transmit fault reported*.\n");
+ else if (stat2 & BIT(11))
+ printf(" Transmit fault previously reported, but now cleared.\n");
+ if (new_stat2 & BIT(10))
+ printf(" *Receive fault reported*.\n");
+ else if (stat2 & BIT(10))
+ printf(" Receive fault previously reported, but now cleared.\n");
+}
+
+static void show_mii_c45_pmapmd_10gbt_status(const struct phy *phy)
+{
+ static const char *mdi[4] = { "AB and CD crossed", "Reserved", "Reserved", "no crossover" };
+ u16 rval[18];
+ int val, i;
+
+ for (i = 0; i < sizeof(rval) / 2; i++) {
+ val = mdio_read_phy(phy, MMD_PMA_10GBT_SWAPPOL + i);
+ rval[i] = val < 0 ? 0 : val;
+ }
+
+ printf(" Pair swap %4.4x: MDI %s, A %s, B %s, C %s, D %s.\n",
+ rval[0],
+ mdi[rval[0] & 3],
+ rval[0] & BIT(8) ? "reversed" : "normal",
+ rval[0] & BIT(9) ? "reversed" : "normal",
+ rval[0] & BIT(10) ? "reversed" : "normal",
+ rval[0] & BIT(11) ? "reversed" : "normal");
+ if (rval[1])
+ printf(" TX backoff %4.4x: LP TX backoff %udB TX backoff %udB%s.\n",
+ rval[1],
+ 2 * ((rval[1] & 0xe000) >> 13),
+ 2 * ((rval[1] & 0x1c00) >> 10),
+ rval[1] & 1 ? " short reach" : "");
+
+#define SNR(x) (((x) - 0x8000) / 10.f)
+ printf(" Operating SNR: A: %5.1fdB B: %5.1fdB C: %5.1fdB D: %5.1fdB.\n",
+ SNR(rval[3]), SNR(rval[4]), SNR(rval[5]), SNR(rval[6]));
+ printf(" Minimum SNR : A: %5.1fdB B: %5.1fdB C: %5.1fdB D: %5.1fdB.\n",
+ SNR(rval[7]), SNR(rval[8]), SNR(rval[9]), SNR(rval[10]));
+ if (rval[11] || rval[12] || rval[13] || rval[14])
+ printf(" RX power : A: %5.1fdBm B: %5.1fdBm C: %5.1fdBm D: %5.1fdBm.\n",
+ SNR(rval[11]), SNR(rval[12]), SNR(rval[13]), SNR(rval[14]));
+#define SKEW(x) (((int)((x) & 0x7f) - 64) * 1.25f)
+ printf(" Skew A>B %6.2fns A>C %6.2fns A>D %6.2fns\n",
+ SKEW(rval[15] >> 8), SKEW(rval[16]), SKEW(rval[16] >> 8));
+ if (rval[17])
+ printf(" Fast retrain %4.4x.\n",
+ rval[17]);
+}
+
+static const char *c45_mmd_name(unsigned int devad)
+{
+ const char *name = mmd_name[devad];
+
+ return name ? name : "";
+}
+
+static void show_mii_c45_details(const struct phy *phy)
+{
+ const struct bit_decoder *decoder;
+ const char *type;
+ const char *col_end = "\033[m";
+ const char *col_red = "\033[31m";
+ const char *col_grn = "\033[32m";
+ int new_stat, val;
+
+ if (mii_val[MMD_CTRL1] == 0xffff) {
+ printf(" No MII transceiver present!.\n");
+ return;
+ }
+
+ if (phy->devad == MDIO_MMD_VENDOR1 ||
+ phy->devad == MDIO_MMD_VENDOR2)
+ return;
+
+ if ((mii_val[MMD_STAT2] & 0xc000) != 0x8000 &&
+ (phy->phy_id & 0xc000) != 0xc000 &&
+ phy->devad != MDIO_MMD_AN) {
+ printf(" No device responding at this address!\n");
+ return;
+ }
+
+ printf(" Control 1 register %4.4x: ", mii_val[MMD_CTRL1]);
+ switch (phy->devad) {
+ case MDIO_MMD_PMAPMD:
+ if (c45_an_ctrl & BIT(12)) {
+ printf("Speed determined by auto-negotiation.\n");
+ break;
+ }
+ /*FALLTHROUGH*/
+ default:
+ printf("Speed %s.\n", mii_c45_speed(phy->devad));
+ break;
+ case MDIO_MMD_AN:
+ printf("Auto-negotiation %sabled.\n",
+ mii_val[MMD_CTRL1] & BIT(12) ? "en" : "dis");
+ break;
+ }
+
+ new_stat = mdio_read_phy(phy, MMD_STAT1);
+ printf(" Status register %4.4x ... %4.4x.\n",
+ mii_val[MMD_STAT1], new_stat);
+ switch (phy->devad) {
+ case MDIO_MMD_PMAPMD: /* has fault */
+ case MDIO_MMD_PCS: /* has fault */
+ case MDIO_MMD_DTE_XS: /* has fault */
+ type = "Receive link";
+ break;
+ case MDIO_MMD_PHY_XS: /* has fault */
+ type = "Transmit link";
+ break;
+ case MDIO_MMD_WIS: /* no fault */
+ case MDIO_MMD_AN: /* no fault */
+ default:
+ type = NULL;
+ break;
+ }
+ if (!type) {
+ printf(" Link status: %s%sestablished%s.\n",
+ /* transmit on #4 */
+ new_stat & BIT(2) ? col_grn : col_red,
+ mii_val[MMD_STAT1] & BIT(2) ? "" :
+ new_stat & BIT(2) ? "previously broken, but now re" :
+ "not ", col_end);
+ } else {
+ printf(" %s status: %s%sestablished%s.%s\n", type,
+ /* transmit on #4 */
+ new_stat & BIT(2) ? col_grn : col_red,
+ mii_val[MMD_STAT1] & BIT(2) ? "" :
+ new_stat & BIT(2) ? "previously broken, but now re" :
+ "not ", col_end,
+ new_stat & BIT(7) ? "\n *Fault condition detected*" :
+ mii_val[MMD_STAT1] & BIT(7) ? "\n Fault condition previously reported, but now cleared" : "");
+ }
+ switch (phy->devad) {
+ case MDIO_MMD_PCS:
+ decoder = mii_c45_pcs_stat;
+ break;
+ case MDIO_MMD_PHY_XS:
+ decoder = mii_c45_phyxs_stat;
+ break;
+ case MDIO_MMD_AN:
+ decoder = mii_c45_an_stat;
+ break;
+ default:
+ decoder = NULL;
+ break;
+ }
+ if (decoder)
+ show_mii_bits(new_stat, decoder, " ", ", ");
+
+ switch (phy->devad) {
+ case MDIO_MMD_PMAPMD:
+ decoder = mii_c45_spd_cap_pma;
+ type = mii_c45_type_pma[mii_val[MMD_CTRL2] & 0x007f];
+ if (c45_an_ctrl & BIT(12))
+ type = "determined by auto-negotiation";
+ break;
+ case MDIO_MMD_PCS:
+ decoder = mii_c45_spd_cap_pcs;
+ type = mii_c45_type_pcs[mii_val[MMD_CTRL2] & 0x000f];
+ break;
+ case MDIO_MMD_PHY_XS:
+ case MDIO_MMD_DTE_XS:
+ decoder = mii_c45_spd_cap_xs;
+ type = NULL;
+ break;
+ default:
+ decoder = NULL;
+ type = NULL;
+ break;
+ }
+ if (decoder)
+ show_mii_reg("Speed capability", mii_val[MMD_SPEED],
+ decoder, ": ", ", ");
+
+ if (phy->devad == MDIO_MMD_PMAPMD || phy->devad == MDIO_MMD_PCS) {
+ if (!type)
+ type = "unknown";
+ printf(" Control 2 register %4.4x: Type %s.\n",
+ mii_val[MMD_CTRL2], type);
+ }
+
+ switch (phy->devad) {
+ case MDIO_MMD_PMAPMD:
+ show_mii_c45_status2(phy, mii_val[MMD_STAT2],
+ mii_c45_stat_2_pma);
+
+ if (mii_val[MMD_PMA_EXT_ABL])
+ show_mii_reg("Extended Ability register",
+ mii_val[MMD_PMA_EXT_ABL],
+ mii_c45_ext_ability_pma,
+ "\n Abilities: ", ", ");
+
+ // Don't have the information for this yet...
+ if (mii_val[MMD_PMA_25G_EXT_ABL])
+ show_mii_reg("25G Extended Ability register",
+ mii_val[MMD_PMA_25G_EXT_ABL],
+ mii_c45_25g_ext_abl_pma,
+ "\n Abilities: ", ", ");
+
+ if (mii_val[MMD_PMA_EXT_ABL] & BIT(10))
+ show_mii_reg("40G/100G Extended Ability register",
+ mii_val[MMD_PMA_40G100G_EXT_ABL],
+ mii_c45_40g_ext_abl_pma,
+ "\n Abilities: ", ", ");
+
+ // This should be predicated on a bit in MMD_PMA_EXT_ABL
+ // but 88x3310 doesn't do this!
+ if (mii_val[MMD_PMA_NBASE_EXT_ABL])
+ show_mii_reg("2.5G/5G Extended Ability register",
+ mii_val[MMD_PMA_NBASE_EXT_ABL],
+ mii_c45_nbase_ext_abl_pma,
+ "\n Abilities: ", ", ");
+
+ val = mdio_read_phy(phy, MMD_PMA_10GBT_STATUS);
+ if (val & 1)
+ show_mii_c45_pmapmd_10gbt_status(phy);
+
+ if (mii_val[MMD_PMA_EEE_CAPABILITY])
+ show_mii_reg("EEE capabilities",
+ mii_val[MMD_PMA_EEE_CAPABILITY],
+ mii_c45_eee_capability_pma,
+ "\n ", ", ");
+ break;
+
+ case MDIO_MMD_PCS:
+ show_mii_c45_status2(phy, mii_val[MMD_STAT2],
+ mii_c45_stat_2_pcs);
+ printf(" baseR or 10GbaseT status %4.4x %4.4x",
+ mii_val[MMD_PCS_BASERT_STAT1],
+ mii_val[MMD_PCS_BASERT_STAT2]);
+ show_mii_multibits(mii_val, mii_pcs_basert_stat,
+ "\n ", "\n ");
+ if (mii_val[MMD_PCS_EEE_CTRL_CAPAB]) {
+ show_mii_reg("EEE control and capabilities",
+ mii_val[MMD_PCS_EEE_CTRL_CAPAB],
+ mii_c45_eee_ctrl_capab_pcs,
+ "\n ", ", ");
+ printf(" EEE wake error counter: %4.4x\n",
+ mii_val[MMD_PCS_EEE_WAKE_ERR]);
+ }
+ break;
+
+ case MDIO_MMD_PHY_XS:
+ if (mii_val[MMD_PHY_XS_EEE_CAPAB]) {
+ show_mii_reg("EEE capabilities",
+ mii_val[MMD_PHY_XS_EEE_CAPAB],
+ mii_c45_eee_ctrl_capab_xs,
+ "\n ", ", ");
+ printf(" EEE wake error counter: %4.4x\n",
+ mii_val[MMD_PHY_XS_EEE_WAKE_ERR]);
+ }
+ val = mii_val[MMD_PHY_XS_LANE_STATUS];
+ show_mii_reg("Lane Status", val, mii_phyxs_lane_status,
+ ":\n ", "\n ");
+ break;
+
+ case MDIO_MMD_DTE_XS:
+ if (mii_val[MMD_DTE_XS_EEE_CAPAB]) {
+ show_mii_reg("EEE capabilities",
+ mii_val[MMD_DTE_XS_EEE_CAPAB],
+ mii_c45_eee_ctrl_capab_xs,
+ "\n ", ", ");
+ printf(" EEE wake error counter: %4.4x\n",
+ mii_val[MMD_DTE_XS_EEE_WAKE_ERR]);
+ }
+ break;
+
+ case MDIO_MMD_AN:
+ val = mdio_read_phy(phy, MMD_AN_BASER_STAT);
+ if (val < 0)
+ val = 0;
+
+ if (val & 1) {
+ /* bits defined as per 73.6. */
+ show_c73_linkword("I'm advertising",
+ mii_val + MMD_AN_BASE_ADV0);
+ if (mii_val[MMD_AN_BASE_LPA2] |
+ mii_val[MMD_AN_BASE_LPA1] |
+ mii_val[MMD_AN_BASE_LPA0])
+ show_c73_linkword("Link partner advertisment is",
+ mii_val + MMD_AN_BASE_LPA0);
+
+ show_mii_reg("baseR Status", val, mii_an_baser_status,
+ ": ", " ");
+ } else {
+ /* bits defined as per 28.2.1.2. */
+ printf(" I'm advertising %4.4x %4.4x.\n",
+ mii_val[MMD_AN_BASE_ADV0],
+ mii_val[MMD_AN_MULTI_GBT_CTRL]);
+ show_mii_multibits(mii_val, mii_c45_an_advert,
+ " ", " ");
+ printf(" Advertising %sadditional info pages.\n",
+ mii_val[MMD_AN_BASE_ADV0] & BIT(15) ? "" : "no ");
+ show_protocol(mii_val[MMD_AN_BASE_ADV0] & 31);
+ show_lpar(mii_val[MMD_AN_BASE_LPA0]);
+ }
+
+ if (mii_val[MMD_AN_MULTI_GBT_CTRL])
+ show_mii_reg("10GbaseT status",
+ mii_val[MMD_AN_MULTI_GBT_STAT],
+ mii_an_multi_gbt_stat, "\n ", ", ");
+
+ if (mii_val[MMD_CTRL1] & BIT(13)) {
+ show_xnp_advert(mii_val[MMD_AN_XNP_ADV0]);
+ show_xnp_lpar(mii_val[MMD_AN_XNP_LPA0]);
+ }
+
+ if (mii_val[MMD_AN_EEE_ADV]) {
+ show_mii_reg("EEE advertisement",
+ mii_val[MMD_AN_EEE_ADV],
+ mii_an_eee_advertisement, "\n ", ", ");
+ }
+ if (mii_val[MMD_AN_EEE_LPA]) {
+ show_mii_reg("EEE link partner advertisement",
+ mii_val[MMD_AN_EEE_LPA],
+ mii_an_eee_advertisement, "\n ", ", ");
+ }
+ break;
+ }
+}
+
+
+static void show_mii_c22_details(struct phy *phy, const struct c22_decoder *dec)
+{
+ const char *col_end = "\033[m";
+ const char *col_red = "\033[31m";
+ const char *col_grn = "\033[32m";
+ int i;
+ u16 bmcr, bmsr, new_bmsr;
+
if (mii_val[0] == 0xffff) {
printf(" No MII transceiver present!.\n");
return;
}
bmcr = mii_val[0];
bmsr = mii_val[1];
- printf(" Basic mode control register 0x%4.4x:", bmcr);
- if (bmcr & 0x1000)
+ printf(" Basic mode control register %4.4x:", bmcr);
+ if (bmcr & BIT(12))
printf(" Auto-negotiation enabled.\n");
else
printf(" Auto-negotiation disabled!\n"
" Speed fixed at 10%s mbps, %s-duplex.\n",
- bmcr & 0x2000 ? "0" : "",
- bmcr & 0x0100 ? "full":"half");
- if (bmcr & 0x8000)
+ bmcr & BIT(6) ? "00" : bmcr & BIT(13) ? "0" : "",
+ bmcr & BIT(8) ? "full":"half");
+ if (bmcr & BIT(15))
printf(" Transceiver currently being reset!\n");
- if (bmcr & 0x4000)
+ if (bmcr & BIT(14))
printf(" Transceiver in loopback mode!\n");
- if (bmcr & 0x0800)
+ if (bmcr & BIT(11))
printf(" Transceiver powered down!\n");
- if (bmcr & 0x0400)
+ if (bmcr & BIT(10))
printf(" Transceiver isolated from the MII!\n");
- if (bmcr & 0x0200)
+ if (bmcr & BIT(9))
printf(" Restarted auto-negotiation in progress!\n");
- if (bmcr & 0x0080)
+ if (bmcr & BIT(7))
printf(" Internal Collision-Test enabled!\n");
- new_bmsr = mdio_read(ioaddr, phy_id, 1);
- printf(" Basic mode status register 0x%4.4x ... %4.4x.\n"
- " Link status: %sestablished.\n"
- " Capable of ",
- bmsr, new_bmsr,
- bmsr & 0x0004 ? "" :
- (new_bmsr & 0x0004) ? "previously broken, but now re" : "not ");
- if (bmsr & 0xF800) {
+ new_bmsr = mdio_read_phy(phy, 1);
+ printf(" Basic mode status register %4.4x ... %4.4x.\n",
+ bmsr, new_bmsr);
+ if (bmsr & BIT(8))
+ printf(" With extended status register %4.4x.\n",
+ mii_val[15]);
+ printf(" Link status: %s%sestablished%s.\n"
+ " Capable of",
+ new_bmsr & BIT(2) ? col_grn : col_red,
+ bmsr & BIT(2) ? "" :
+ (new_bmsr & BIT(2)) ? "previously broken, but now re" : "not ",
+ col_end);
+ if (bmsr & 0xF800 || (bmsr & BIT(8) && mii_val[15] & 0xf000)) {
for (i = 15; i >= 11; i--)
if (bmsr & (1<<i))
printf(" %s", media_names[i-11]);
+ if (bmsr & BIT(8)) {
+ if (mii_val[15] & BIT(12))
+ printf(" 1000baseT");
+ if (mii_val[15] & BIT(13))
+ printf(" 1000baseT-FD");
+ if (mii_val[15] & BIT(14))
+ printf(" 1000baseX");
+ if (mii_val[15] & BIT(15))
+ printf(" 1000baseX-FD");
+ }
} else
- printf("<Warning! No media capabilities>");
+ printf(" <Warning! No media capabilities>");
printf(".\n"
" %s to perform Auto-negotiation, negotiation %scomplete.\n",
- bmsr & 0x0008 ? "Able" : "Unable",
- bmsr & 0x0020 ? "" : "not ");
+ bmsr & BIT(3) ? "Able" : "Unable",
+ bmsr & BIT(5) ? "" : "not ");
- if (bmsr & 0x0010)
+ if (bmsr & BIT(4))
printf(" Remote fault detected!\n");
- if (bmsr & 0x0002)
+ if (bmsr & BIT(1))
printf(" *** Link Jabber! ***\n");
- if (mii_val[2] ^ mii_val[3]) { /* Eliminate 0x0000 and 0xffff IDs. */
- unsigned char oui_0 = mii_val[2] >> 10;
- unsigned char oui_1 = mii_val[2] >> 2;
- unsigned char oui_2 = (mii_val[2] << 6) | (mii_val[3] >> 10);
-
- printf(" Vendor ID is %2.2x:%2.2x:%2.2x:--:--:--, model %d rev. %d.\n",
- oui_0, oui_1, oui_2,
- ((mii_val[3] >> 4) & 0x3f), mii_val[3] & 0x0f);
- for ( i = 0; oui_map[i].vendor; i++)
- /* We match either the Phy ID or the IEEE OUI. */
- if ((oui_map[i].phy_id0 == mii_val[2] &&
- oui_map[i].phy_id1 == mii_val[3]) ||
- (oui_map[i].ieee_oui[0] == oui_0 &&
- oui_map[i].ieee_oui[1] == oui_1 &&
- oui_map[i].ieee_oui[2] == oui_2)) {
- printf(" Vendor/Part: %s.\n", oui_map[i].vendor);
- vendor = i;
- break;
- }
- if (oui_map[i].vendor == NULL)
- printf(" No specific information is known about this transceiver"
- " type.\n");
- } else
+ dec->show_advert(phy, mii_val);
+ dec->show_lpar(phy, mii_val);
+}
+
+static int show_c22_subdev(struct phy *phy, int subdev, unsigned int off,
+ const struct c22_decoder *dec)
+{
+ int vendor = 0;
+
+ phy->offset = off;
+
+ if (phy->phy_id & 0x8000)
+ printf("\n MII PHY #%d:%d %s",
+ (phy->phy_id >> 5) & 31, phy->devad,
+ c45_mmd_name(phy->devad));
+ else
+ printf("\n MII PHY #%d", phy->phy_id);
+
+ if (subdev)
+ printf(" Subdevice #%d", subdev);
+
+ printf(" transceiver registers:");
+ read_mii_regs(phy->ioaddr, phy->phy_id | phy->devad, off, 32);
+ show_mii_regs(32);
+ printf(".\n");
+ if (mii_val[2] ^ mii_val[3]) { /* Eliminate 0x0000 and 0xffff IDs. */
+ vendor = lookup_vendor(mii_val[2], mii_val[3]);
+ } else {
printf(" This transceiver has no vendor identification.\n");
+ }
+ show_mii_c22_details(phy, dec);
+
+ return vendor;
+}
+
+static int show_c45_subdev(struct phy *phy, int subdev, unsigned int off)
+{
+ const char *name = c45_mmd_name(phy->devad);
+ int vendor = 0;
- {
- int nway_advert = mii_val[4];
- int lkpar = mii_val[5];
- printf(" I'm advertising %4.4x:", nway_advert);
- for (i = 10; i >= 5; i--)
- if (nway_advert & (1<<i))
- printf(" %s", media_names[i-5]);
- printf("\n Advertising %sadditional info pages.\n",
- nway_advert & 0x8000 ? "" : "no ");
- if ((nway_advert & 31) == 1)
- printf(" IEEE 802.3 CSMA/CD protocol.\n");
- else
- printf(" Using an unknown (non 802.3) encapsulation.\n");
- printf(" Link partner capability is %4.4x:",
- lkpar);
- for (i = 10; i >= 5; i--)
- if (lkpar & (1<<i))
- printf(" %s", media_names[i-5]);
- printf(".\n Negotiation %s.\n",
- lkpar & 0x4000 ? " completed" : "did not complete");
- }
- if (oui_map[vendor].func)
- oui_map[vendor].func(ioaddr, phy_id);
+ phy->offset = off;
+ if (subdev)
+ printf("\n MII PHY #%d:%d %s Subdevice #%d transceiver registers:",
+ (phy->phy_id >> 5) & 31, phy->devad, name, subdev);
+ else
+ printf("\n MII PHY #%d:%d %s transceiver registers:",
+ (phy->phy_id >> 5) & 31, phy->devad, name);
+ read_mii_regs(phy->ioaddr, phy->phy_id | phy->devad, off, 64);
+ show_mii_regs(64);
+ printf(".\n");
+
+ if (phy->devad != MDIO_MMD_VENDOR1 && phy->devad != MDIO_MMD_VENDOR2) {
+ if (mii_val[MMD_DEVID1] ^ mii_val[MMD_DEVID2]) {
+ vendor = lookup_vendor(mii_val[MMD_DEVID1],
+ mii_val[MMD_DEVID2]);
+ } else {
+ printf(" This transceiver has no vendor identification.\n");
+ }
+ }
+
+ show_mii_c45_details(phy);
+
+ return vendor;
+}
+
+
+void show_mii_details(long ioaddr, int phy_id)
+{
+ DEFINE_C22_PHY(phy, ioaddr, phy_id);
+ int vendor, i;
+
+ /* This may not be omitted from the output. */
+ printf("%s", version_msg);
+ if ((phy_id & 0x801f) == 0x8000) {
+ int val;
+ u32 v, mmds = 0;
+ for (i = 1; i < 32; i++) {
+ val = mdio_read(ioaddr, phy_id | i, MMD_DEVPKG1);
+ if (val < 0)
+ continue;
+ v = val;
+ val = mdio_read(ioaddr, phy_id | i, MMD_DEVPKG2);
+ if (val < 0)
+ continue;
+ v |= val << 16;
+ if (v == 0xffffffff)
+ continue;
+ mmds = v;
+ break;
+ }
+
+ if (mmds & BIT(7)) {
+ val = mdio_read(ioaddr, phy_id | MDIO_MMD_AN, MMD_CTRL1);
+ if (val >= 0)
+ c45_an_ctrl = val;
+ }
+
+ for (i = 1; i < 32; i++) {
+ if (mmds & (1 << i)) {
+ phy.devad = i;
+ vendor = show_c45_subdev(&phy, 0, 0);
+ if (oui_map[vendor].func)
+ oui_map[vendor].func(ioaddr, phy_id | i);
+ }
+ }
+ } else if (phy_id & 0x8000) {
+ phy.devad = phy.phy_id & 31;
+ phy.phy_id &= ~31;
+
+ vendor = show_c45_subdev(&phy, 0, 0);
+ if (oui_map[vendor].func)
+ oui_map[vendor].func(ioaddr, phy_id);
+ } else {
+ vendor = show_c22_subdev(&phy, 0, 0, &c28_linkword);
+ if (oui_map[vendor].func)
+ oui_map[vendor].func(ioaddr, phy_id);
+ }
+}
+
+static void dump_mii_range(long ioaddr, int phy_id, unsigned int start,
+ unsigned int len)
+{
+ unsigned int i, j;
+ int gap = 0;
+
+ for (i = start; i < start + len; i += 8) {
+ u16 vals[8], v;
+
+ for (j = 0, v = 0; j < 8; j++) {
+ int val = mdio_read(ioaddr, phy_id, i + j);
+ if (val < 0)
+ val = 0;
+ vals[j] = val;
+ v |= val;
+ }
+
+ if (v) {
+ if (gap) {
+ printf("\n ...");
+ gap = 0;
+ }
+ printf("\n %4.4x:", i);
+ for (j = 0; j < 8; j++)
+ printf(" %4.4x", vals[j]);
+ } else {
+ gap = 1;
+ }
+ }
+ printf("\n");
+}
+
+void dump_mii(long ioaddr, int phy_id)
+{
+ unsigned int max;
+
+ if (phy_id & 0x8000)
+ max = 65536;
+ else
+ max = 32;
+
+ printf(" MII PHY #%d transceiver registers:", phy_id);
+ dump_mii_range(ioaddr, phy_id, 0, max);
}
int monitor_mii(long ioaddr, int phy_id)
@@ -312,25 +1775,6 @@ int monitor_mii(long ioaddr, int phy_id)
/* Emit transceiver-specific info. */
-struct msg_tbl { int bitmask; char *msg; };
-
-static void msg_if_set(const int val, const struct msg_tbl msg_tbl[])
-{
- int i;
- for (i = 0; msg_tbl[i].bitmask; i++)
- if (msg_tbl[i].bitmask & val)
- printf(" %s\n", msg_tbl[i].msg);
-}
-
-static void msg_if_set_fmt(const int val, const struct msg_tbl msg_tbl[],
- const char *fmt)
-{
- int i;
- for (i = 0; msg_tbl[i].bitmask; i++)
- if (msg_tbl[i].bitmask & val)
- printf(fmt, msg_tbl[i].msg);
-}
-
static void qs6612(long ioaddr, int phy_id)
{
printf(" QS6612 extra registers: Mode %4.4x.\n"
@@ -352,13 +1796,13 @@ static void ns83843(long ioaddr, int phy_id)
" Receive errors %d\n"
" Link beat is currently %sstable\n",
mii_val[0x10],
- mii_val[10] & 0x0001 ? "Valid" : "Invalid",
- mii_val[10] & 0x0002 ? 10 : 100,
- mii_val[10] & 0x0004 ? "full" : "half",
- mii_val[0x11] & 0x0002 ? "en":"dis",
- mii_val[0x10] & 0x0100 ? "interrupt": "none",
+ mii_val[10] & BIT(0) ? "Valid" : "Invalid",
+ mii_val[10] & BIT(1) ? 10 : 100,
+ mii_val[10] & BIT(2) ? "full" : "half",
+ mii_val[0x11] & BIT(1) ? "en":"dis",
+ mii_val[0x10] & BIT(8) ? "interrupt": "none",
mii_val[0x13], mii_val[0x14], mii_val[0x15],
- mii_val[0x16] & 0x0010 ? "UN" : "");
+ mii_val[0x16] & BIT(4) ? "UN" : "");
return;
}
static void smsc83c180(long ioaddr, int phy_id)
@@ -371,11 +1815,11 @@ static void smsc83c180(long ioaddr, int phy_id)
" Auto-negotiation %scomplete, 1%s0Mbps %s duplex.\n"
" Rx symbol errors since last read %d.\n",
mii_reg25,
- mii_reg25 & 0x2000 ? "normal" : "reversed",
+ mii_reg25 & BIT(13) ? "normal" : "reversed",
(mii_reg25>>8) & 0x1F,
- mii_reg25 & 0x0080 ? "did not " : "",
- mii_reg25 & 0x0020 ? "0" : "",
- mii_reg25 & 0x0040 ? "full" : "half",
+ mii_reg25 & BIT(7) ? "did not " : "",
+ mii_reg25 & BIT(5) ? "0" : "",
+ mii_reg25 & BIT(6) ? "full" : "half",
mdio_read(ioaddr, phy_id, 26));
return;
}
@@ -407,16 +1851,16 @@ static void tdk78q2120(long ioaddr, int phy_id)
"%s%s"
" Auto-negotiation %s, 1%s0Mbps %s duplex.\n"
" Rx link in %s state, PLL %s.\n",
- mii_reg16 & 0x0020 ? "OVERRIDDEN to" : "detected as",
- mii_reg16 & 0x0010 ? "reversed" : "normal",
- mii_reg16 & 0x0002 ?
+ mii_reg16 & BIT(5) ? "OVERRIDDEN to" : "detected as",
+ mii_reg16 & BIT(4) ? "reversed" : "normal",
+ mii_reg16 & BIT(1) ?
" 100baseTx Coding and scrambling is disabled!\n":"",
- mii_reg16 & 0x0001 ? " Rx_CLK power-save mode is enabled!\n":"",
- mii_reg18 & 0x1000 ? "had no common media" : "complete",
- mii_reg18 & 0x0400 ? "0" : "",
- mii_reg18 & 0x0800 ? "full" : "half",
- mii_reg18 & 0x0200 ? "pass" : "fail",
- mii_reg18 & 0x0100 ? "slipped since last read" : "locked");
+ mii_reg16 & BIT(0) ? " Rx_CLK power-save mode is enabled!\n":"",
+ mii_reg18 & BIT(12) ? "had no common media" : "complete",
+ mii_reg18 & BIT(10) ? "0" : "",
+ mii_reg18 & BIT(11) ? "full" : "half",
+ mii_reg18 & BIT(9) ? "pass" : "fail",
+ mii_reg18 & BIT(8) ? "slipped since last read" : "locked");
msg_if_set(mii_reg16, tdk_reg16);
if (mii_reg17 & 0x00ff) {
@@ -453,8 +1897,8 @@ static void enablesemi(long ioaddr, int phy_id)
printf(" Isolated %d times, %d false carrier events, %d Rx errors.\n",
mii_val[18], mii_val[19], mii_val[21]);
printf(" Cable polarity is %s, 100Mb PLL is %slocked.\n",
- mii_val[28]&0x8000 ? "reversed" : "normal",
- mii_val[27]&0x2000 ? "" : "un");
+ mii_val[28]&BIT(15) ? "reversed" : "normal",
+ mii_val[27]&BIT(13) ? "" : "un");
}
/* The amd79c901 contains both PNA and 10/100 management registers.
http://www.amd.com/products/npd/techdocs/22304.pdf
@@ -570,9 +2014,9 @@ static void via_tahoe(long ioaddr, int phy_id)
mii_reg16, mii_reg17, mii_reg18);
msg_if_set_fmt(mii_reg17, via_reg17, " %s\n");
printf(" Link %s 10%s Mbps %s duplex\n",
- mii_reg18 & 0x2000 ? "up" : "down",
- mii_reg18 & 0x0400 ? "0" : "",
- mii_reg18 & 0x0800 ? "full" : "half");
+ mii_reg18 & BIT(13) ? "up" : "down",
+ mii_reg18 & BIT(10) ? "0" : "",
+ mii_reg18 & BIT(11) ? "full" : "half");
}
/* Information from
@@ -596,8 +2040,8 @@ static void via_vt6105(long ioaddr, int phy_id)
{
printf(" VIA vt6105 PHY status:\n"
" Duplex %s speed %s\n",
- mii_val[20] & 0x0001 ? "full" : "half",
- mii_val[20] & 0x0002 ? "100" : "10");
+ mii_val[20] & BIT(0) ? "full" : "half",
+ mii_val[20] & BIT(1) ? "100" : "10");
}
/* Information from
@@ -619,6 +2063,233 @@ static void intel(long ioaddr, int phy_id)
mii_val[24], mii_val[25]);
}
+static void mv88x3310_xs(long ioaddr, int phy_id)
+{
+ DEFINE_C45_PHY(phy, ioaddr, phy_id & ~31, phy_id & 31);
+
+ if (phy.devad != 4)
+ return;
+
+ show_c45_subdev(&phy, 2, 0x1000);
+ show_c22_subdev(&phy, 3, 0x2000, &cisco_sgmii_linkword);
+}
+
+static void mv88x3310(long ioaddr, int phy_id)
+{
+ DEFINE_C45_PHY(phy, ioaddr, phy_id & ~31, phy_id & 31);
+
+ switch (phy.devad) {
+ case MDIO_MMD_PCS:
+ show_c45_subdev(&phy, 2, 0x1000);
+ show_c22_subdev(&phy, 3, 0x2000, &c37_linkword);
+ break;
+
+ case MDIO_MMD_AN:
+ show_c45_subdev(&phy, 2, 0x1000);
+ show_c45_subdev(&phy, 3, 0x1800);
+ show_c45_subdev(&phy, 4, 0x2000);
+
+ printf("\n Other registers");
+ dump_mii_range(ioaddr, phy_id, 0x8000, 32);
+ dump_mii_range(ioaddr, phy_id, 0x9000, 16);
+ dump_mii_range(ioaddr, phy_id, 0x9800, 16);
+ dump_mii_range(ioaddr, phy_id, 0xa000, 64);
+ break;
+ }
+}
+
+
+
+static int marvell_read_paged(const struct phy *phy, unsigned int addr)
+{
+ u16 val, old_page;
+ long ioaddr = phy->ioaddr;
+ int phy_id = phy->phy_id;
+
+ old_page = mdio_read(ioaddr, phy_id, 22);
+ mdio_write(ioaddr, phy_id, 22, phy->page);
+ val = mdio_read(ioaddr, phy_id, addr);
+ mdio_write(ioaddr, phy_id, 22, old_page);
+
+ return val;
+}
+
+static const struct bit_decoder mv88e1111_pss_decoder[] = {
+ { 0xc800, 0x8800, "1000Mbps" },
+ { 0xc800, 0x4800, "100Mbps" },
+ { 0xc800, 0x0800, "10Mbps" },
+ { 0x2800, 0x2800, "Full" },
+ { 0x2800, 0x0800, "Half" },
+ { 0x0400, 0x0400, "Link Up" },
+ { 0x0440, 0x0440, "MDIX" },
+ { 0x0440, 0x0400, "MDI" },
+ { 0x0420, 0x0420, "Downshift" },
+ { 0x0808, 0x0808, "TX Pause" },
+ { 0x0804, 0x0804, "RX Pause" },
+ { },
+};
+
+static const struct bit_decoder mv88e1111_epss_decoder[] = {
+ { 0x8000, 0x8000, "Fiber/copper auto-selection disabled" },
+ { 0x8000, 0x0000, "Fiber/copper auto-selection enabled" },
+ { 0x2000, 0x2000, "Fiber link selected" },
+ { 0x2000, 0x0000, "Copper link selected" },
+ { 0x1000, 0x1000, "AN bypass enabled" },
+ { 0x1000, 0x0000, "AN bypass disabled" },
+ { 0x0800, 0x0800, "AN is bypassed" },
+ { 0x0200, 0x0200, "Auto-medium register selection enabled" },
+ { 0x000f, 0x0000, "SGMII w/ clock w/ SGMII AN to copper" },
+ { 0x000f, 0x0003, "RGMII to fiber" },
+ { 0x000f, 0x0004, "SGMII w/o clock w/ SGMII AN to copper" },
+ { 0x000f, 0x0006, "RGMII to SGMII" },
+ { 0x000f, 0x0007, "GMII to fiber" },
+ { 0x000f, 0x0008, "1000baseX w/o clock w/ 1000baseX AN to copper" },
+ { 0x000f, 0x0009, "RTBI to copper" },
+ { 0x000f, 0x000b, "RGMII/Modified MII to copper" },
+ { 0x000f, 0x000c, "1000baseX w/o clock w/o 1000baseX AN to copper" },
+ { 0x000f, 0x000d, "TBI to copper" },
+ { 0x000f, 0x000e, "GMII to SGMII" },
+ { 0x000f, 0x000f, "GMII to copper" },
+ { },
+};
+
+static void mv88e1111(long ioaddr, int phy_id)
+{
+ DEFINE_C22_PHY(phy, ioaddr, phy_id);
+ int i;
+
+ show_mii_reg("PHY Specific Status", mii_val[17],
+ mv88e1111_pss_decoder, "\n ", ", ");
+
+ show_mii_reg("Extended PHY Specific Status", mii_val[27],
+ mv88e1111_epss_decoder, " ", ".\n ");
+
+ phy.page = 1;
+ phy.mdio_read = marvell_read_paged;
+ for (i = 0; i < 32; i++)
+ mii_val[i] = mdio_read_phy(&phy, i);
+ printf("\n MII PHY #%d fiber registers:", phy_id);
+ show_mii_regs(32);
+ printf(".\n");
+
+ switch (mii_val[27] & 15) {
+ case 0:
+ case 4: /* SGMII to copper */
+ show_mii_c22_details(&phy, &cisco_sgmii_linkword);
+ break;
+ case 8:
+ case 12:
+ /* GMII mode */
+ show_mii_c22_details(&phy, &c37_linkword);
+ break;
+ default:
+ break;
+ }
+}
+
+static const struct bit_decoder mv88e151x_gcr[] = {
+ { 0x0040, 0x0040, "Auto-media:" },
+ { 0x0070, 0x0040, "Link on first media" },
+ { 0x0070, 0x0050, "Copper preferred" },
+ { 0x0070, 0x0060, "Fiber preferred" },
+ { 0x0070, 0x0070, "Reserved" },
+ { 0x0007, 0x0000, "RGMII(sys) to Copper" },
+ { 0x0007, 0x0001, "SGMII(sys) to Copper" },
+ { 0x0007, 0x0002, "RGMII(sys) to 1000baseX" },
+ { 0x0007, 0x0003, "SGMII(sys) to 100baseFX" },
+ { 0x0007, 0x0004, "SGMII(sys) to SGMII(media)" },
+ { 0x0007, 0x0005, "Reserved" },
+ { 0x0007, 0x0006, "RGMII(sys) to Auto" },
+ { 0x0007, 0x0007, "RGMII(sys) to Auto" },
+ { },
+};
+
+static const struct bit_decoder marvell_sgmii_adv_decoder[] = {
+ { 0x8000, 0x0000, "Link Down" },
+ { 0x8000, 0x8000, "Link Up, " },
+ { 0x8c00, 0x8000, "10M/" },
+ { 0x8c00, 0x8400, "100M/" },
+ { 0x8c00, 0x8800, "1000M/" },
+ { 0x8c00, 0x8c00, "?/" },
+ { 0x9000, 0x8000, "Half, " },
+ { 0x9000, 0x9000, "Full, " },
+ /* These are the Marvell additions */
+ { 0x8200, 0x8200, "TxPause, " },
+ { 0x8100, 0x8100, "RxPause, " },
+ { 0x8080, 0x8000, "Copper" },
+ { 0x8080, 0x8080, "Fiber" },
+ { },
+};
+
+static void marvell_sgmii_advert(struct phy *phy, u16 *regs)
+{
+ const char *strings[17], **p = strings;
+ u16 base = regs[4];
+
+ printf(" SGMII advertisement %4.4x", base);
+ if (base & 1) {
+ p = bit_decoder(p, base, marvell_sgmii_adv_decoder);
+ } else {
+ *p++ = " Link down";
+ *p = NULL;
+ }
+ if (base & 0x607e) {
+ *p++ = ", reserved bits are set";
+ *p = NULL;
+ }
+ print_strings(strings, ": ", "");
+}
+
+static const struct c22_decoder marvell_system_sgmii_linkword = {
+ .show_advert = marvell_sgmii_advert,
+ .show_lpar = cisco_sgmii_lpar,
+};
+
+static const struct bit_decoder marvell_fscr2_decoder[] = {
+ { 0x4000, 0x4000, "1000baseX noise filter" },
+ { 0x0200, 0x0200, "100baseFX FEFI enabled" },
+ { 0x0040, 0x0040, "AN bypass enabled" },
+ { 0x0040, 0x0000, "AN bypass disabled" },
+ { 0x0020, 0x0020, "AN was bypassed" },
+ { 0x0008, 0x0008, "Fiber TX disabled" },
+ { },
+};
+
+static void mv88e151x(long ioaddr, int phy_id)
+{
+ DEFINE_C22_PHY(phy, ioaddr, phy_id);
+ u16 gcr;
+ int i;
+
+ phy.page = 18;
+ gcr = mdio_read_phy(&phy, 20);
+ show_mii_reg("General Control Register 1", gcr, mv88e151x_gcr, ": ", ", ");
+
+ phy.page = 1;
+ phy.mdio_read = marvell_read_paged;
+ for (i = 0; i < 32; i++)
+ mii_val[i] = mdio_read_phy(&phy, i);
+ printf("\n MII PHY #%d fiber registers:", phy_id);
+ show_mii_regs(32);
+ printf(".\n");
+
+ switch (mii_val[16] & 3) {
+ case 0: /* 100baseFX */
+ break;
+ case 1: /* 1000baseX */
+ show_mii_c22_details(&phy, &c37_linkword);
+ break;
+ case 2: /* SGMII System mode */
+ show_mii_c22_details(&phy, &marvell_system_sgmii_linkword);
+ break;
+ case 3: /* SGMII Media mode */
+ show_mii_c22_details(&phy, &cisco_sgmii_linkword);
+ break;
+ }
+ show_mii_reg("Fiber Specific Control Register 2", mii_val[26],
+ marvell_fscr2_decoder, ": ", ", ");
+}
+
/*
* Local variables:
diff --git a/mii-diag.c b/mii-diag.c
index f3f3f2f..5426603 100644
--- a/mii-diag.c
+++ b/mii-diag.c
@@ -403,7 +403,7 @@ int do_one_xcvr(int skfd)
return 0;
}
-int mdio_read(int skfd, int phy_id, int location)
+static int __mdio_read(int skfd, int phy_id, int location)
{
u16 *data = (u16 *)(&ifr.ifr_data);
@@ -418,7 +418,7 @@ int mdio_read(int skfd, int phy_id, int location)
return data[3];
}
-void mdio_write(int skfd, int phy_id, int location, int value)
+static void __mdio_write(int skfd, int phy_id, int location, int value)
{
u16 *data = (u16 *)(&ifr.ifr_data);
@@ -432,6 +432,38 @@ void mdio_write(int skfd, int phy_id, int location, int value)
}
}
+#define MII_MMD_CTRL 0x0d
+#define MII_MMD_DATA 0x0e
+#define MII_MMD_CTRL_NOINCR 0x4000
+
+int mdio_read(int skfd, int phy_id, int location)
+{
+ if ((phy_id & 0xc000) == 0xc000) {
+ unsigned int devad = phy_id & 31;
+ int pkgad = (phy_id >> 5) & 31;
+ __mdio_write(skfd, pkgad, MII_MMD_CTRL, devad);
+ __mdio_write(skfd, pkgad, MII_MMD_DATA, location);
+ __mdio_write(skfd, pkgad, MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
+ return __mdio_read(skfd, pkgad, MII_MMD_DATA);
+ } else {
+ return __mdio_read(skfd, phy_id, location);
+ }
+}
+
+void mdio_write(int skfd, int phy_id, int location, int value)
+{
+ if ((phy_id & 0xc000) == 0xc000) {
+ unsigned int devad = phy_id & 31;
+ int pkgad = (phy_id >> 5) & 31;
+ __mdio_write(skfd, pkgad, MII_MMD_CTRL, devad);
+ __mdio_write(skfd, pkgad, MII_MMD_DATA, location);
+ __mdio_write(skfd, pkgad, MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
+ __mdio_write(skfd, pkgad, MII_MMD_DATA, value);
+ } else {
+ __mdio_write(skfd, phy_id, location, value);
+ }
+}
+
/* Parse the command line argument for advertised capabilities. */
static int parse_advertise(const char *capabilities)
{