Exemple #1
0
/* Attach the PHY to the MII bus */
static int
brgphy_attach(device_t dev)
{
	struct brgphy_softc *bsc;
	struct bge_softc *bge_sc = NULL;
	struct bce_softc *bce_sc = NULL;
	struct mii_softc *sc;
	struct ifnet *ifp;

	bsc = device_get_softc(dev);
	sc = &bsc->mii_sc;

	mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE,
	    &brgphy_funcs, 0);

	bsc->serdes_flags = 0;
	ifp = sc->mii_pdata->mii_ifp;

	/* Find the MAC driver associated with this PHY. */
	if (strcmp(ifp->if_dname, "bge") == 0)
		bge_sc = ifp->if_softc;
	else if (strcmp(ifp->if_dname, "bce") == 0)
		bce_sc = ifp->if_softc;

	/* Handle any special cases based on the PHY ID */
	switch (sc->mii_mpd_oui) {
	case MII_OUI_BROADCOM:
		switch (sc->mii_mpd_model) {
		case MII_MODEL_BROADCOM_BCM5706:
		case MII_MODEL_BROADCOM_BCM5714:
			/*
			 * The 5464 PHY used in the 5706 supports both copper
			 * and fiber interfaces over GMII.  Need to check the
			 * shadow registers to see which mode is actually
			 * in effect, and therefore whether we have 5706C or
			 * 5706S.
			 */
			PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C,
				BRGPHY_SHADOW_1C_MODE_CTRL);
			if (PHY_READ(sc, BRGPHY_MII_SHADOW_1C) &
				BRGPHY_SHADOW_1C_ENA_1000X) {
				bsc->serdes_flags |= BRGPHY_5706S;
				sc->mii_flags |= MIIF_HAVEFIBER;
			}
			break;
		}
		break;
	case MII_OUI_BROADCOM2:
		switch (sc->mii_mpd_model) {
		case MII_MODEL_BROADCOM2_BCM5708S:
			bsc->serdes_flags |= BRGPHY_5708S;
			sc->mii_flags |= MIIF_HAVEFIBER;
			break;
		case MII_MODEL_BROADCOM2_BCM5709S:
			/*
			 * XXX
			 * 5720S and 5709S shares the same PHY id.
			 * Assume 5720S PHY if parent device is bge(4).
			 */
			if (bge_sc != NULL)
				bsc->serdes_flags |= BRGPHY_5708S;
			else
				bsc->serdes_flags |= BRGPHY_5709S;
			sc->mii_flags |= MIIF_HAVEFIBER;
			break;
		}
		break;
	}

	PHY_RESET(sc);

	/* Read the PHY's capabilities. */
	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask;
	if (sc->mii_capabilities & BMSR_EXTSTAT)
		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
	device_printf(dev, " ");

#define	ADD(m, c)	ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL)

	/* Add the supported media types */
	if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
		mii_phy_add_media(sc);
		printf("\n");
	} else {
		sc->mii_anegticks = MII_ANEGTICKS_GIGE;
		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst),
			BRGPHY_S1000 | BRGPHY_BMCR_FDX);
		printf("1000baseSX-FDX, ");
		/* 2.5G support is a software enabled feature on the 5708S and 5709S. */
		if (bce_sc && (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)) {
			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX, sc->mii_inst), 0);
			printf("2500baseSX-FDX, ");
		} else if ((bsc->serdes_flags & BRGPHY_5708S) && bce_sc &&
		    (detect_hs21(bce_sc) != 0)) {
			/*
			 * There appears to be certain silicon revision
			 * in IBM HS21 blades that is having issues with
			 * this driver wating for the auto-negotiation to
			 * complete. This happens with a specific chip id
			 * only and when the 1000baseSX-FDX is the only
			 * mode. Workaround this issue since it's unlikely
			 * to be ever addressed.
			 */
			printf("auto-neg workaround, ");
			bsc->serdes_flags |= BRGPHY_NOANWAIT;
		}
		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
		printf("auto\n");
	}

#undef ADD
	MIIBUS_MEDIAINIT(sc->mii_dev);
	return (0);
}
Exemple #2
0
/* Attach the PHY to the MII bus */
static int
brgphy_attach(device_t dev)
{
	struct brgphy_softc *bsc;
	struct bge_softc *bge_sc = NULL;
	struct bce_softc *bce_sc = NULL;
	struct mii_softc *sc;
	struct mii_attach_args *ma;
	struct mii_data *mii;
	struct ifnet *ifp;
	int fast_ether;

	bsc = device_get_softc(dev);
	sc = &bsc->mii_sc;
	ma = device_get_ivars(dev);
	sc->mii_dev = device_get_parent(dev);
	mii = device_get_softc(sc->mii_dev);
	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);

	/* Initialize mii_softc structure */
	sc->mii_inst = mii->mii_instance;
	sc->mii_phy = ma->mii_phyno;
	sc->mii_service = brgphy_service;
	sc->mii_pdata = mii;
	sc->mii_anegticks = MII_ANEGTICKS_GIGE;
	sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
	mii->mii_instance++;

	/* Initialize brgphy_softc structure */
	bsc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
	bsc->mii_model = MII_MODEL(ma->mii_id2);
	bsc->mii_rev = MII_REV(ma->mii_id2);
	bsc->serdes_flags = 0;

	fast_ether = 0;

	if (bootverbose)
		device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n",
		    bsc->mii_oui, bsc->mii_model, bsc->mii_rev);

	/* Handle any special cases based on the PHY ID */
	switch (bsc->mii_oui) {
	case MII_OUI_BROADCOM:
	case MII_OUI_BROADCOM2:
		break;
	case MII_OUI_xxBROADCOM:
		switch (bsc->mii_model) {
		case MII_MODEL_xxBROADCOM_BCM5706:
		case MII_MODEL_xxBROADCOM_BCM5714:
			/*
			 * The 5464 PHY used in the 5706 supports both copper
			 * and fiber interfaces over GMII.  Need to check the
			 * shadow registers to see which mode is actually
			 * in effect, and therefore whether we have 5706C or
			 * 5706S.
			 */
			PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C,
				BRGPHY_SHADOW_1C_MODE_CTRL);
			if (PHY_READ(sc, BRGPHY_MII_SHADOW_1C) &
				BRGPHY_SHADOW_1C_ENA_1000X) {
				bsc->serdes_flags |= BRGPHY_5706S;
				sc->mii_flags |= MIIF_HAVEFIBER;
			}
			break;
		} break;
	case MII_OUI_xxBROADCOM_ALT1:
		switch (bsc->mii_model) {
		case MII_MODEL_xxBROADCOM_ALT1_BCM5708S:
			bsc->serdes_flags |= BRGPHY_5708S;
			sc->mii_flags |= MIIF_HAVEFIBER;
			break;
        case MII_MODEL_xxBROADCOM_ALT1_BCM5709S:
            bsc->serdes_flags |= BRGPHY_5709S;
            sc->mii_flags |= MIIF_HAVEFIBER;
            break;
		} break;
	default:
		device_printf(dev, "Unrecognized OUI for PHY!\n");
	}

	ifp = sc->mii_pdata->mii_ifp;

	/* Find the MAC driver associated with this PHY. */
	if (strcmp(ifp->if_dname, "bge") == 0)	{
		bge_sc = ifp->if_softc;
	} else if (strcmp(ifp->if_dname, "bce") == 0) {
		bce_sc = ifp->if_softc;
	}

	/* Todo: Need to add additional controllers such as 5906 & 5787F */
	/* The 590x chips are 10/100 only. */
	if (bge_sc &&
	    pci_get_vendor(bge_sc->bge_dev) == BCOM_VENDORID &&
	    (pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901 ||
	    pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901A2 ||
	    pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5906 ||
	    pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5906M)) {
		fast_ether = 1;
		sc->mii_anegticks = MII_ANEGTICKS;
	}

	brgphy_reset(sc);

	/* Read the PHY's capabilities. */
	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
	if (sc->mii_capabilities & BMSR_EXTSTAT)
		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
	device_printf(dev, " ");

#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)

	/* Create an instance of Ethernet media. */
	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), BMCR_ISO);

	/* Add the supported media types */
	if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
			BRGPHY_S10);
		printf("10baseT, ");
		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
			BRGPHY_S10 | BRGPHY_BMCR_FDX);
		printf("10baseT-FDX, ");
		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
			BRGPHY_S100);
		printf("100baseTX, ");
		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
			BRGPHY_S100 | BRGPHY_BMCR_FDX);
		printf("100baseTX-FDX, ");
		if (fast_ether == 0) {
			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst),
				BRGPHY_S1000);
			printf("1000baseT, ");
			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst),
				BRGPHY_S1000 | BRGPHY_BMCR_FDX);
			printf("1000baseT-FDX, ");
		}
	} else {
		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst),
			BRGPHY_S1000 | BRGPHY_BMCR_FDX);
		printf("1000baseSX-FDX, ");
		/* 2.5G support is a software enabled feature on the 5708S and 5709S. */
		if (bce_sc && (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)) {
			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX, sc->mii_inst), 0);
			printf("2500baseSX-FDX, ");
		} else if ((bsc->serdes_flags & BRGPHY_5708S) && bce_sc &&
		    (detect_hs21(bce_sc) != 0)) {
			/*
			 * There appears to be certain silicon revision
			 * in IBM HS21 blades that is having issues with
			 * this driver wating for the auto-negotiation to
			 * complete. This happens with a specific chip id
			 * only and when the 1000baseSX-FDX is the only
			 * mode. Workaround this issue since it's unlikely
			 * to be ever addressed.
			 */
			printf("auto-neg workaround, ");
			bsc->serdes_flags |= BRGPHY_NOANWAIT;
		}
	}

	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
	printf("auto\n");

#undef ADD
	MIIBUS_MEDIAINIT(sc->mii_dev);
	return (0);
}