150120Swpaul/*	$NetBSD: ukphy_subr.c,v 1.2 1998/11/05 04:08:02 thorpej Exp $	*/
250120Swpaul
350120Swpaul/*-
450120Swpaul * Copyright (c) 1998 The NetBSD Foundation, Inc.
550120Swpaul * All rights reserved.
650120Swpaul *
750120Swpaul * This code is derived from software contributed to The NetBSD Foundation
850120Swpaul * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
950120Swpaul * NASA Ames Research Center, and by Frank van der Linden.
1050120Swpaul *
1150120Swpaul * Redistribution and use in source and binary forms, with or without
1250120Swpaul * modification, are permitted provided that the following conditions
1350120Swpaul * are met:
1450120Swpaul * 1. Redistributions of source code must retain the above copyright
1550120Swpaul *    notice, this list of conditions and the following disclaimer.
1650120Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1750120Swpaul *    notice, this list of conditions and the following disclaimer in the
1850120Swpaul *    documentation and/or other materials provided with the distribution.
1950120Swpaul *
2050120Swpaul * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2150120Swpaul * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2250120Swpaul * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2350120Swpaul * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2450120Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2550120Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2650120Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2750120Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2850120Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2950120Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3050120Swpaul * POSSIBILITY OF SUCH DAMAGE.
3150120Swpaul */
3250120Swpaul
33119418Sobrien#include <sys/cdefs.h>
34119418Sobrien__FBSDID("$FreeBSD$");
35119418Sobrien
3650120Swpaul/*
3750120Swpaul * Subroutines shared by the ukphy driver and other PHY drivers.
3850120Swpaul */
3950120Swpaul
4050120Swpaul#include <sys/param.h>
4150120Swpaul#include <sys/systm.h>
4250120Swpaul#include <sys/socket.h>
4350120Swpaul#include <sys/module.h>
4450120Swpaul#include <sys/bus.h>
4550120Swpaul
4650120Swpaul#include <net/if.h>
4750120Swpaul#include <net/if_media.h>
4850120Swpaul
4950120Swpaul#include <dev/mii/mii.h>
5050120Swpaul#include <dev/mii/miivar.h>
5150120Swpaul
5250120Swpaul#include "miibus_if.h"
5350120Swpaul
5450120Swpaul/*
5550120Swpaul * Media status subroutine.  If a PHY driver does media detection simply
5650120Swpaul * by decoding the NWay autonegotiation, use this routine.
5750120Swpaul */
5850120Swpaulvoid
5995723Sphkukphy_status(struct mii_softc *phy)
6050120Swpaul{
6150120Swpaul	struct mii_data *mii = phy->mii_pdata;
6295723Sphk	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
63158744Syongari	int bmsr, bmcr, anlpar, gtcr, gtsr;
6450120Swpaul
6550120Swpaul	mii->mii_media_status = IFM_AVALID;
6650120Swpaul	mii->mii_media_active = IFM_ETHER;
6750120Swpaul
6850120Swpaul	bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR);
6950120Swpaul	if (bmsr & BMSR_LINK)
7050120Swpaul		mii->mii_media_status |= IFM_ACTIVE;
7150120Swpaul
7250120Swpaul	bmcr = PHY_READ(phy, MII_BMCR);
7350120Swpaul	if (bmcr & BMCR_ISO) {
7450120Swpaul		mii->mii_media_active |= IFM_NONE;
7550120Swpaul		mii->mii_media_status = 0;
7650120Swpaul		return;
7750120Swpaul	}
7850120Swpaul
7950120Swpaul	if (bmcr & BMCR_LOOP)
8050120Swpaul		mii->mii_media_active |= IFM_LOOP;
8150120Swpaul
8250120Swpaul	if (bmcr & BMCR_AUTOEN) {
8350120Swpaul		/*
8450120Swpaul		 * NWay autonegotiation takes the highest-order common
8550120Swpaul		 * bit of the ANAR and ANLPAR (i.e. best media advertised
8650120Swpaul		 * both by us and our link partner).
8750120Swpaul		 */
8850120Swpaul		if ((bmsr & BMSR_ACOMP) == 0) {
8950120Swpaul			/* Erg, still trying, I guess... */
9050120Swpaul			mii->mii_media_active |= IFM_NONE;
9150120Swpaul			return;
9250120Swpaul		}
9350120Swpaul
9450120Swpaul		anlpar = PHY_READ(phy, MII_ANAR) & PHY_READ(phy, MII_ANLPAR);
95158744Syongari		if ((phy->mii_flags & MIIF_HAVE_GTCR) != 0 &&
96158744Syongari		    (phy->mii_extcapabilities &
97158744Syongari		    (EXTSR_1000THDX | EXTSR_1000TFDX)) != 0) {
98158744Syongari			gtcr = PHY_READ(phy, MII_100T2CR);
99158744Syongari			gtsr = PHY_READ(phy, MII_100T2SR);
100158744Syongari		} else
101158744Syongari			gtcr = gtsr = 0;
102158744Syongari
103158744Syongari		if ((gtcr & GTCR_ADV_1000TFDX) && (gtsr & GTSR_LP_1000TFDX))
104158744Syongari			mii->mii_media_active |= IFM_1000_T|IFM_FDX;
105158744Syongari		else if ((gtcr & GTCR_ADV_1000THDX) &&
106158744Syongari		    (gtsr & GTSR_LP_1000THDX))
107213384Smarius			mii->mii_media_active |= IFM_1000_T|IFM_HDX;
108173665Syongari		else if (anlpar & ANLPAR_TX_FD)
109173665Syongari			mii->mii_media_active |= IFM_100_TX|IFM_FDX;
110158744Syongari		else if (anlpar & ANLPAR_T4)
111213384Smarius			mii->mii_media_active |= IFM_100_T4|IFM_HDX;
11250120Swpaul		else if (anlpar & ANLPAR_TX)
113213384Smarius			mii->mii_media_active |= IFM_100_TX|IFM_HDX;
11450120Swpaul		else if (anlpar & ANLPAR_10_FD)
11550120Swpaul			mii->mii_media_active |= IFM_10_T|IFM_FDX;
11650120Swpaul		else if (anlpar & ANLPAR_10)
117213384Smarius			mii->mii_media_active |= IFM_10_T|IFM_HDX;
11850120Swpaul		else
11950120Swpaul			mii->mii_media_active |= IFM_NONE;
120215297Smarius
121215297Smarius		if ((mii->mii_media_active & IFM_1000_T) != 0 &&
122215297Smarius		    (gtsr & GTSR_MS_RES) != 0)
123215297Smarius			mii->mii_media_active |= IFM_ETH_MASTER;
124215297Smarius
125215297Smarius		if ((mii->mii_media_active & IFM_FDX) != 0)
126215297Smarius			mii->mii_media_active |= mii_phy_flowstatus(phy);
12750120Swpaul	} else
12895723Sphk		mii->mii_media_active = ife->ifm_media;
12950120Swpaul}
130