cxgb_aq100x.c revision 199239
158551Skris/**************************************************************************
258551Skris
358551SkrisCopyright (c) 2009 Chelsio Inc.
458551SkrisAll rights reserved.
558551Skris
658551SkrisRedistribution and use in source and binary forms, with or without
758551Skrismodification, are permitted provided that the following conditions are met:
858551Skris
958551Skris 1. Redistributions of source code must retain the above copyright notice,
1058551Skris    this list of conditions and the following disclaimer.
1158551Skris
1258551Skris 2. Neither the name of the Chelsio Corporation nor the names of its
1358551Skris    contributors may be used to endorse or promote products derived from
1458551Skris    this software without specific prior written permission.
1558551Skris
1658551SkrisTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1758551SkrisAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1858551SkrisIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1958551SkrisARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2058551SkrisLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2158551SkrisCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2258551SkrisSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2358551SkrisINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2458551SkrisCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2558551SkrisARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2658551SkrisPOSSIBILITY OF SUCH DAMAGE.
2758551Skris
2858551Skris***************************************************************************/
2958551Skris
3058551Skris#include <sys/cdefs.h>
3158551Skris__FBSDID("$FreeBSD: head/sys/dev/cxgb/common/cxgb_aq100x.c 199239 2009-11-13 00:34:28Z np $");
3258551Skris
3358551Skris#include <cxgb_include.h>
3458551Skris
3558551Skris#undef msleep
3658551Skris#define msleep t3_os_sleep
3758551Skris
3858551Skrisenum {
3958551Skris	/* MDIO_DEV_PMA_PMD registers */
4058551Skris	AQ_LINK_STAT	= 0xe800,
4158551Skris
4258551Skris	/* MDIO_DEV_XGXS registers */
4358551Skris	AQ_XAUI_RX_CFG	= 0xc400,
4458551Skris	AQ_XAUI_KX_CFG	= 0xc440,
4558551Skris	AQ_XAUI_TX_CFG	= 0xe400,
4658551Skris
4758551Skris	/* MDIO_DEV_ANEG registers */
4858551Skris	AQ_100M_CTRL	= 0x0010,
4958551Skris	AQ_10G_CTRL	= 0x0020,
5058551Skris	AQ_1G_CTRL	= 0xc400,
5158551Skris	AQ_ANEG_STAT	= 0xc800,
5258551Skris
5358551Skris	/* MDIO_DEV_VEND1 registers */
5458551Skris	AQ_FW_VERSION	= 0x0020,
5558551Skris	AQ_THERMAL_THR	= 0xc421,
5658551Skris	AQ_THERMAL1	= 0xc820,
5758551Skris	AQ_THERMAL2	= 0xc821,
5858551Skris	AQ_IFLAG_GLOBAL	= 0xfc00,
5958551Skris	AQ_IMASK_GLOBAL	= 0xff00,
6058551Skris};
6158551Skris
6258551Skris#define AQBIT(x)	(1 << (0x##x))
6358551Skris#define ADV_1G_FULL	AQBIT(f)
6458551Skris#define ADV_1G_HALF	AQBIT(e)
6558551Skris#define ADV_10G_FULL	AQBIT(c)
6658551Skris
6758551Skris#define AQ_WRITE_REGS(phy, regs) do { \
6858551Skris	int i; \
6958551Skris	for (i = 0; i < ARRAY_SIZE(regs); i++) { \
7058551Skris		(void) mdio_write(phy, regs[i].mmd, regs[i].reg, regs[i].val); \
7158551Skris	} \
7258551Skris} while (0)
7358551Skris#define AQ_READ_REGS(phy, regs) do { \
7458551Skris	unsigned i, v; \
7558551Skris	for (i = 0; i < ARRAY_SIZE(regs); i++) { \
7658551Skris		(void) mdio_read(phy, regs[i].mmd, regs[i].reg, &v); \
7758551Skris	} \
7858551Skris} while (0)
7958551Skris
8058551Skris/*
8158551Skris * Return value is temperature in celcius, 0xffff for error or don't know.
8258551Skris */
8358551Skrisstatic int
8458551Skrisaq100x_temperature(struct cphy *phy)
8558551Skris{
8658551Skris	unsigned int v;
8758551Skris
8858551Skris	if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL2, &v) ||
8958551Skris	    v == 0xffff || (v & 1) != 1)
9058551Skris		return (0xffff);
9158551Skris
9258551Skris	if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL1, &v))
9358551Skris		return (0xffff);
9458551Skris
9558551Skris	return ((int)((signed char)(v >> 8)));
9658551Skris}
9758551Skris
9858551Skrisstatic int
9958551Skrisaq100x_set_defaults(struct cphy *phy)
10058551Skris{
10158551Skris	return mdio_write(phy, MDIO_DEV_VEND1, AQ_THERMAL_THR, 0x6c00);
10258551Skris}
10358551Skris
10458551Skrisstatic int
10558551Skrisaq100x_reset(struct cphy *phy, int wait)
10658551Skris{
10758551Skris	int err;
10858551Skris	err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
10958551Skris	if (!err)
11058551Skris		err = aq100x_set_defaults(phy);
11158551Skris	return (err);
11258551Skris}
11358551Skris
11458551Skrisstatic int
11558551Skrisaq100x_intr_enable(struct cphy *phy)
11658551Skris{
11758551Skris	struct {
11858551Skris		int mmd;
11958551Skris		int reg;
12058551Skris		int val;
12158551Skris	} imasks[] = {
12258551Skris		{MDIO_DEV_VEND1, 0xd400, AQBIT(e)},
12358551Skris		{MDIO_DEV_VEND1, 0xff01, AQBIT(2)},
12458551Skris		{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, AQBIT(0)}
12558551Skris	};
12658551Skris
12758551Skris	AQ_WRITE_REGS(phy, imasks);
12858551Skris
12958551Skris	return (0);
13058551Skris}
13158551Skris
13258551Skrisstatic int
13358551Skrisaq100x_intr_disable(struct cphy *phy)
13458551Skris{
13558551Skris	struct {
13658551Skris		int mmd;
13758551Skris		int reg;
13858551Skris		int val;
13958551Skris	} imasks[] = {
14058551Skris		{MDIO_DEV_VEND1, 0xd400, 0},
14158551Skris		{MDIO_DEV_VEND1, 0xff01, 0},
14258551Skris		{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, 0}
14358551Skris	};
14458551Skris
14558551Skris	AQ_WRITE_REGS(phy, imasks);
14658551Skris
14758551Skris	return (0);
14858551Skris}
14958551Skris
15058551Skrisstatic int
15158551Skrisaq100x_intr_clear(struct cphy *phy)
15258551Skris{
15358551Skris	struct {
15458551Skris		int mmd;
15558551Skris		int reg;
15658551Skris	} iclr[] = {
15758551Skris		{MDIO_DEV_VEND1, 0xcc00},
15858551Skris		{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL} /* needed? */
15958551Skris	};
16058551Skris
16158551Skris	AQ_READ_REGS(phy, iclr);
16258551Skris
16358551Skris	return (0);
16458551Skris}
16558551Skris
16658551Skrisstatic int
16758551Skrisaq100x_vendor_intr(struct cphy *phy, int *rc)
16858551Skris{
16958551Skris	int err;
17058551Skris	unsigned int cause, v;
17158551Skris
17258551Skris	err = mdio_read(phy, MDIO_DEV_VEND1, 0xfc01, &cause);
17358551Skris	if (err)
17458551Skris		return (err);
17558551Skris
17658551Skris	if (cause & AQBIT(2)) {
17758551Skris		err = mdio_read(phy, MDIO_DEV_VEND1, 0xcc00, &v);
17858551Skris		if (err)
17958551Skris			return (err);
18058551Skris
18158551Skris		if (v & AQBIT(e)) {
18258551Skris			CH_WARN(phy->adapter, "PHY%d: temperature is now %dC\n",
18358551Skris			    phy->addr, aq100x_temperature(phy));
18458551Skris
18558551Skris			t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN,
18658551Skris			    phy->addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL, 0);
18758551Skris
18858551Skris			*rc |= cphy_cause_alarm;
18958551Skris		}
19058551Skris
19158551Skris		cause &= ~4;
19258551Skris	}
19358551Skris
19458551Skris	if (cause)
19558551Skris		CH_WARN(phy->adapter, "PHY%d: unhandled vendor interrupt"
19658551Skris		    " (0x%x)\n", phy->addr, cause);
19758551Skris
19858551Skris	return (0);
19958551Skris
20058551Skris}
20158551Skris
20258551Skrisstatic int
20358551Skrisaq100x_intr_handler(struct cphy *phy)
20458551Skris{
20558551Skris	int err, rc = 0;
20658551Skris	unsigned int cause;
20758551Skris
20858551Skris	err = mdio_read(phy, MDIO_DEV_VEND1, AQ_IFLAG_GLOBAL, &cause);
20958551Skris	if (err)
21058551Skris		return (err);
21158551Skris
21258551Skris	if (cause & AQBIT(0)) {
21358551Skris		err = aq100x_vendor_intr(phy, &rc);
21458551Skris		if (err)
21558551Skris			return (err);
21658551Skris		cause &= ~AQBIT(0);
21758551Skris	}
21858551Skris
21958551Skris	if (cause)
22058551Skris		CH_WARN(phy->adapter, "PHY%d: unhandled interrupt (0x%x)\n",
22158551Skris		    phy->addr, cause);
22258551Skris
22358551Skris	return (rc);
22458551Skris}
22558551Skris
22658551Skrisstatic int
22758551Skrisaq100x_power_down(struct cphy *phy, int off)
22858551Skris{
22958551Skris	int err, wait = 500;
23058551Skris	unsigned int v;
23158551Skris
23258551Skris	err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, BMCR_PDOWN,
23358551Skris	    off ? BMCR_PDOWN : 0);
23458551Skris	if (err || off)
23558551Skris		return (v);
23658551Skris
23758551Skris	msleep(300);
23858551Skris	do {
23958551Skris		err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
24058551Skris		if (err)
24158551Skris			return (err);
24258551Skris		v &= BMCR_RESET;
24358551Skris		if (v)
24458551Skris			msleep(10);
24558551Skris	} while (v && --wait);
24658551Skris	if (v) {
24758551Skris		CH_WARN(phy->adapter, "PHY%d: power-up timed out (0x%x).\n",
24858551Skris		    phy->addr, v);
24958551Skris		return (ETIMEDOUT);
25058551Skris	}
25158551Skris
25258551Skris	return (0);
25358551Skris}
25458551Skris
25558551Skrisstatic int
25658551Skrisaq100x_autoneg_enable(struct cphy *phy)
25758551Skris{
25858551Skris	int err;
25958551Skris
26058551Skris	err = aq100x_power_down(phy, 0);
26158551Skris	if (!err)
26258551Skris		err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
26358551Skris		    BMCR_RESET, BMCR_ANENABLE | BMCR_ANRESTART);
26458551Skris
26558551Skris	return (err);
26658551Skris}
26758551Skris
26858551Skrisstatic int
26958551Skrisaq100x_autoneg_restart(struct cphy *phy)
27058551Skris{
27158551Skris	return aq100x_autoneg_enable(phy);
27258551Skris}
27358551Skris
27458551Skrisstatic int
27558551Skrisaq100x_advertise(struct cphy *phy, unsigned int advertise_map)
27658551Skris{
27758551Skris	unsigned int adv;
27858551Skris	int err;
27958551Skris
28058551Skris	/* 10G advertisement */
28158551Skris	adv = 0;
28258551Skris	if (advertise_map & ADVERTISED_10000baseT_Full)
28358551Skris		adv |= ADV_10G_FULL;
28458551Skris	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_10G_CTRL,
28558551Skris				  ADV_10G_FULL, adv);
28658551Skris	if (err)
28758551Skris		return (err);
28858551Skris
28958551Skris	/* 1G advertisement */
29058551Skris	adv = 0;
29158551Skris	if (advertise_map & ADVERTISED_1000baseT_Full)
29258551Skris		adv |= ADV_1G_FULL;
29358551Skris	if (advertise_map & ADVERTISED_1000baseT_Half)
29458551Skris		adv |= ADV_1G_HALF;
29558551Skris	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_1G_CTRL,
29658551Skris				  ADV_1G_FULL | ADV_1G_HALF, adv);
29758551Skris	if (err)
29858551Skris		return (err);
29958551Skris
30058551Skris	/* 100M, pause advertisement */
30158551Skris	adv = 0;
30258551Skris	if (advertise_map & ADVERTISED_100baseT_Half)
30358551Skris		adv |= ADVERTISE_100HALF;
30458551Skris	if (advertise_map & ADVERTISED_100baseT_Full)
30558551Skris		adv |= ADVERTISE_100FULL;
30658551Skris	if (advertise_map & ADVERTISED_Pause)
30758551Skris		adv |= ADVERTISE_PAUSE_CAP;
30858551Skris	if (advertise_map & ADVERTISED_Asym_Pause)
30958551Skris		adv |= ADVERTISE_PAUSE_ASYM;
31058551Skris	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_100M_CTRL, 0xfe0, adv);
31158551Skris
31258551Skris	return (err);
31358551Skris}
31458551Skris
31558551Skrisstatic int
31658551Skrisaq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable)
31758551Skris{
31858551Skris	return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
31958551Skris				   BMCR_LOOPBACK, enable ? BMCR_LOOPBACK : 0);
32058551Skris}
32158551Skris
32258551Skrisstatic int
32358551Skrisaq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex)
32458551Skris{
32558551Skris	int err, set;
32658551Skris
32758551Skris	if (speed == SPEED_100)
32858551Skris		set = BMCR_SPEED100;
32958551Skris	else if (speed == SPEED_1000)
33058551Skris		set = BMCR_SPEED1000;
33158551Skris	else if (speed == SPEED_10000)
33258551Skris		set = BMCR_SPEED1000 | BMCR_SPEED100;
33358551Skris	else
33458551Skris		return (EINVAL);
33558551Skris
33658551Skris	if (duplex != DUPLEX_FULL)
33758551Skris		return (EINVAL);
33858551Skris
33958551Skris	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
34058551Skris	    BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART, 0);
34158551Skris	if (err)
34258551Skris		return (err);
34358551Skris
34458551Skris	err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
34558551Skris	    BMCR_SPEED1000 | BMCR_SPEED100, set);
34658551Skris	if (err)
34758551Skris		return (err);
34858551Skris
34958551Skris	return (0);
35058551Skris}
35158551Skris
35258551Skrisstatic int
35358551Skrisaq100x_get_link_status(struct cphy *phy, int *link_ok, int *speed, int *duplex,
35458551Skris		       int *fc)
35558551Skris{
35658551Skris	int err;
35758551Skris	unsigned int v, link = 0;
35858551Skris
35958551Skris	err = mdio_read(phy, MDIO_DEV_PMA_PMD, AQ_LINK_STAT, &v);
36058551Skris	if (err)
36158551Skris		return (err);
36258551Skris	if (v == 0xffff || !(v & 1))
36358551Skris		goto done;
36458551Skris
36558551Skris	err = mdio_read(phy, MDIO_DEV_ANEG, MII_BMCR, &v);
36658551Skris	if (err)
36758551Skris		return (err);
36858551Skris	if (v & 0x8000)
36958551Skris		goto done;
37058551Skris	if (v & BMCR_ANENABLE) {
37158551Skris
37258551Skris		err = mdio_read(phy, MDIO_DEV_ANEG, 1, &v);
37358551Skris		if (err)
37458551Skris			return (err);
37558551Skris		if ((v & 0x20) == 0)
37658551Skris			goto done;
37758551Skris
37858551Skris		err = mdio_read(phy, MDIO_DEV_ANEG, AQ_ANEG_STAT, &v);
37958551Skris		if (err)
38058551Skris			return (err);
38158551Skris
38258551Skris		if (speed) {
38358551Skris			switch (v & 0x6) {
38458551Skris			case 0x6: *speed = SPEED_10000;
38558551Skris				break;
38658551Skris			case 0x4: *speed = SPEED_1000;
38758551Skris				break;
38858551Skris			case 0x2: *speed = SPEED_100;
38958551Skris				break;
39058551Skris			case 0x0: *speed = SPEED_10;
39158551Skris				break;
39258551Skris			}
39358551Skris		}
39458551Skris
39558551Skris		if (duplex)
39658551Skris			*duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF;
39758551Skris
39858551Skris		if (fc) {
39958551Skris			unsigned int lpa, adv;
40058551Skris			err = mdio_read(phy, MDIO_DEV_ANEG, 0x13, &lpa);
40158551Skris			if (!err)
40258551Skris				err = mdio_read(phy, MDIO_DEV_ANEG,
40358551Skris				    AQ_100M_CTRL, &adv);
40458551Skris			if (err)
40558551Skris				return err;
40658551Skris
40758551Skris			if (lpa & adv & ADVERTISE_PAUSE_CAP)
40858551Skris				*fc = PAUSE_RX | PAUSE_TX;
40958551Skris			else if (lpa & ADVERTISE_PAUSE_CAP &&
41058551Skris			    lpa & ADVERTISE_PAUSE_ASYM &&
41158551Skris			    adv & ADVERTISE_PAUSE_ASYM)
41258551Skris				*fc = PAUSE_TX;
41358551Skris			else if (lpa & ADVERTISE_PAUSE_ASYM &&
41458551Skris			    adv & ADVERTISE_PAUSE_CAP)
41558551Skris				*fc = PAUSE_RX;
41658551Skris			else
41758551Skris				*fc = 0;
41858551Skris		}
41958551Skris
42058551Skris	} else {
42158551Skris		err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
42258551Skris		if (err)
42358551Skris			return (err);
42458551Skris
42558551Skris		v &= BMCR_SPEED1000 | BMCR_SPEED100;
42658551Skris		if (speed) {
42758551Skris			if (v == (BMCR_SPEED1000 | BMCR_SPEED100))
42858551Skris				*speed = SPEED_10000;
42958551Skris			else if (v == BMCR_SPEED1000)
43058551Skris				*speed = SPEED_1000;
43158551Skris			else if (v == BMCR_SPEED100)
43258551Skris				*speed = SPEED_100;
43358551Skris			else
43458551Skris				*speed = SPEED_10;
43558551Skris		}
43658551Skris
43758551Skris		if (duplex)
43858551Skris			*duplex = DUPLEX_FULL;
43958551Skris	}
44058551Skris
44158551Skris	link = 1;
44258551Skrisdone:
44358551Skris	if (link_ok)
44458551Skris		*link_ok = link;
44558551Skris	return (0);
44658551Skris}
44758551Skris
44858551Skrisstatic struct cphy_ops aq100x_ops = {
44958551Skris	.reset             = aq100x_reset,
45058551Skris	.intr_enable       = aq100x_intr_enable,
45158551Skris	.intr_disable      = aq100x_intr_disable,
45258551Skris	.intr_clear        = aq100x_intr_clear,
45358551Skris	.intr_handler      = aq100x_intr_handler,
45458551Skris	.autoneg_enable    = aq100x_autoneg_enable,
45558551Skris	.autoneg_restart   = aq100x_autoneg_restart,
45658551Skris	.advertise         = aq100x_advertise,
45758551Skris	.set_loopback      = aq100x_set_loopback,
45858551Skris	.set_speed_duplex  = aq100x_set_speed_duplex,
45958551Skris	.get_link_status   = aq100x_get_link_status,
46058551Skris	.power_down        = aq100x_power_down,
46158551Skris};
46258551Skris
46358551Skrisint
46458551Skrist3_aq100x_phy_prep(pinfo_t *pinfo, int phy_addr,
46558551Skris		       const struct mdio_ops *mdio_ops)
46658551Skris{
46758551Skris	struct cphy *phy = &pinfo->phy;
46858551Skris	unsigned int v, v2, gpio, wait;
46958551Skris	int err;
47058551Skris	adapter_t *adapter = pinfo->adapter;
47158551Skris
47258551Skris	cphy_init(&pinfo->phy, adapter, pinfo, phy_addr, &aq100x_ops, mdio_ops,
47358551Skris		  SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
47458551Skris		  SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI |
47558551Skris		  SUPPORTED_MISC_IRQ, "1000/10GBASE-T");
47658551Skris
47758551Skris	/*
47858551Skris	 * Hard reset the PHY.
47958551Skris	 */
48058551Skris	gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL;
48158551Skris	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0);
48258551Skris	msleep(1);
48358551Skris	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio);
48458551Skris
48558551Skris	/*
48658551Skris	 * Give it enough time to load the firmware and get ready for mdio.
48758551Skris	 */
48858551Skris	msleep(1000);
48958551Skris	wait = 500; /* in 10ms increments */
49058551Skris	do {
49158551Skris		err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
49258551Skris		if (err || v == 0xffff) {
49358551Skris
49458551Skris			/* Allow prep_adapter to succeed when ffff is read */
49558551Skris
49658551Skris			CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n",
49758551Skris				phy_addr, err, v);
49858551Skris			goto done;
49958551Skris		}
50058551Skris
50158551Skris		v &= BMCR_RESET;
50258551Skris		if (v)
50358551Skris			msleep(10);
50458551Skris	} while (v && --wait);
50558551Skris	if (v) {
50658551Skris		CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n",
50758551Skris			phy_addr, v);
50858551Skris
50958551Skris		goto done; /* let prep_adapter succeed */
51058551Skris	}
51158551Skris
51258551Skris	/* Firmware version check. */
51358551Skris	(void) mdio_read(phy, MDIO_DEV_VEND1, AQ_FW_VERSION, &v);
51458551Skris	if (v < 0x115)
51558551Skris		CH_WARN(adapter, "PHY%d: unknown firmware %d.%d\n", phy_addr,
51658551Skris		    v >> 8, v & 0xff);
51758551Skris
51858551Skris	/* The PHY should start in really-low-power mode. */
51958551Skris	(void) mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
52058551Skris	if ((v & BMCR_PDOWN) == 0)
52158551Skris		CH_WARN(adapter, "PHY%d does not start in low power mode.\n",
52258551Skris			phy_addr);
52358551Skris
52458551Skris	/*
52558551Skris	 * Verify XAUI and 1000-X settings, but let prep succeed no matter what.
52658551Skris	 */
52758551Skris	v = v2 = 0;
52858551Skris	(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_RX_CFG, &v);
52958551Skris	(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_TX_CFG, &v2);
53058551Skris	if (v != 0x1b || v2 != 0x1b)
53158551Skris		CH_WARN(adapter, "PHY%d: incorrect XAUI settings "
53258551Skris		    "(0x%x, 0x%x).\n", phy_addr, v, v2);
53358551Skris	v = 0;
53458551Skris	(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_KX_CFG, &v);
53558551Skris	if ((v & 0xf) != 0xf)
53658551Skris		CH_WARN(adapter, "PHY%d: incorrect 1000-X settings "
53758551Skris		    "(0x%x).\n", phy_addr, v);
53858551Skris
53958551Skris	(void) aq100x_set_defaults(phy);
54058551Skrisdone:
54158551Skris	return (err);
54258551Skris}
54358551Skris