154134Swpaul/* 254134Swpaul * Copyright (c) 1997, 1998, 1999 354134Swpaul * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. 454134Swpaul * 554134Swpaul * Redistribution and use in source and binary forms, with or without 654134Swpaul * modification, are permitted provided that the following conditions 754134Swpaul * are met: 854134Swpaul * 1. Redistributions of source code must retain the above copyright 954134Swpaul * notice, this list of conditions and the following disclaimer. 1054134Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1154134Swpaul * notice, this list of conditions and the following disclaimer in the 1254134Swpaul * documentation and/or other materials provided with the distribution. 1354134Swpaul * 3. All advertising materials mentioning features or use of this software 1454134Swpaul * must display the following acknowledgement: 1554134Swpaul * This product includes software developed by Bill Paul. 1654134Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1754134Swpaul * may be used to endorse or promote products derived from this software 1854134Swpaul * without specific prior written permission. 1954134Swpaul * 2054134Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2154134Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2254134Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2354134Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2454134Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2554134Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2654134Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2754134Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2854134Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2954134Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3054134Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3154134Swpaul */ 3254134Swpaul 33119418Sobrien#include <sys/cdefs.h> 34119418Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/dev/dc/pnphy.c 227908 2011-11-23 20:27:26Z marius $"); 35119418Sobrien 3654134Swpaul/* 3754134Swpaul * Pseudo-driver for media selection on the Lite-On PNIC 82c168 38183505Smarius * chip. The NWAY support on this chip is horribly broken, so we 39183505Smarius * only support manual mode selection. This is lame, but getting 4054134Swpaul * NWAY to work right is amazingly difficult. 4154134Swpaul */ 4254134Swpaul 4354134Swpaul#include <sys/param.h> 4454134Swpaul#include <sys/systm.h> 4554134Swpaul#include <sys/kernel.h> 4654134Swpaul#include <sys/socket.h> 4754134Swpaul#include <sys/errno.h> 4874914Sjhb#include <sys/lock.h> 4954134Swpaul#include <sys/module.h> 5067365Sjhb#include <sys/mutex.h> 5154134Swpaul#include <sys/bus.h> 5254134Swpaul 5354134Swpaul#include <net/if.h> 5454134Swpaul#include <net/if_arp.h> 5554134Swpaul#include <net/if_media.h> 5654134Swpaul 5754134Swpaul#include <dev/mii/mii.h> 5854134Swpaul#include <dev/mii/miivar.h> 59109514Sobrien#include "miidevs.h" 6054134Swpaul 6154134Swpaul#include <machine/bus.h> 6254134Swpaul#include <machine/resource.h> 6354134Swpaul 64151435Simp#include <dev/dc/if_dcreg.h> 6554134Swpaul 6654134Swpaul#include "miibus_if.h" 6754134Swpaul 68105135Salfredstatic int pnphy_probe(device_t); 69105135Salfredstatic int pnphy_attach(device_t); 7054134Swpaul 7154134Swpaulstatic device_method_t pnphy_methods[] = { 7254134Swpaul /* device interface */ 7354134Swpaul DEVMETHOD(device_probe, pnphy_probe), 7454134Swpaul DEVMETHOD(device_attach, pnphy_attach), 7595722Sphk DEVMETHOD(device_detach, mii_phy_detach), 7654134Swpaul DEVMETHOD(device_shutdown, bus_generic_shutdown), 77227908Smarius DEVMETHOD_END 7854134Swpaul}; 7954134Swpaul 8054134Swpaulstatic devclass_t pnphy_devclass; 8154134Swpaul 8254134Swpaulstatic driver_t pnphy_driver = { 8354134Swpaul "pnphy", 8454134Swpaul pnphy_methods, 8554134Swpaul sizeof(struct mii_softc) 8654134Swpaul}; 8754134Swpaul 8854134SwpaulDRIVER_MODULE(pnphy, miibus, pnphy_driver, pnphy_devclass, 0, 0); 8954134Swpaul 9092739Salfredstatic int pnphy_service(struct mii_softc *, struct mii_data *, int); 9192739Salfredstatic void pnphy_status(struct mii_softc *); 92221407Smariusstatic void pnphy_reset(struct mii_softc *); 9354134Swpaul 94221407Smariusstatic const struct mii_phy_funcs pnphy_funcs = { 95221407Smarius pnphy_service, 96221407Smarius pnphy_status, 97221407Smarius pnphy_reset 98221407Smarius}; 99221407Smarius 100105135Salfredstatic int 101150763Simppnphy_probe(device_t dev) 10254134Swpaul{ 10354134Swpaul struct mii_attach_args *ma; 10454134Swpaul 10554134Swpaul ma = device_get_ivars(dev); 10654134Swpaul 10754134Swpaul /* 10854134Swpaul * The dc driver will report the 82c168 vendor and device 10954134Swpaul * ID to let us know that it wants us to attach. 11054134Swpaul */ 11154134Swpaul if (ma->mii_id1 != DC_VENDORID_LO || 11254134Swpaul ma->mii_id2 != DC_DEVICEID_82C168) 113183505Smarius return (ENXIO); 11454134Swpaul 11554134Swpaul device_set_desc(dev, "PNIC 82c168 media interface"); 11654134Swpaul 117160907Syongari return (BUS_PROBE_DEFAULT); 11854134Swpaul} 11954134Swpaul 120105135Salfredstatic int 121150763Simppnphy_attach(device_t dev) 12254134Swpaul{ 12354134Swpaul struct mii_softc *sc; 12454134Swpaul 12554134Swpaul sc = device_get_softc(dev); 12654134Swpaul 127221407Smarius mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 128221407Smarius &pnphy_funcs, 0); 12954134Swpaul 13054134Swpaul sc->mii_capabilities = 131183505Smarius BMSR_100TXFDX | BMSR_100TXHDX | BMSR_10TFDX | BMSR_10THDX; 132221407Smarius sc->mii_capabilities &= sc->mii_capmask; 13354134Swpaul device_printf(dev, " "); 134190117Smarius mii_phy_add_media(sc); 13554134Swpaul printf("\n"); 13654134Swpaul 13754134Swpaul MIIBUS_MEDIAINIT(sc->mii_dev); 138183505Smarius return (0); 13954134Swpaul} 14054134Swpaul 14184145Sjlemonstatic int 142150763Simppnphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 14354134Swpaul{ 14454134Swpaul struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 14554134Swpaul 14654134Swpaul switch (cmd) { 14754134Swpaul case MII_POLLSTAT: 14854134Swpaul break; 14954134Swpaul 15054134Swpaul case MII_MEDIACHG: 15154134Swpaul /* 15254134Swpaul * If the interface is not up, don't do anything. 15354134Swpaul */ 15454134Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 15554134Swpaul break; 15654134Swpaul 157217417Smarius /* 158217417Smarius * Note that auto-negotiation is broken on this chip. 159217417Smarius */ 16054134Swpaul switch (IFM_SUBTYPE(ife->ifm_media)) { 16154134Swpaul case IFM_100_TX: 162183505Smarius mii->mii_media_active = IFM_ETHER | IFM_100_TX; 163217417Smarius if ((ife->ifm_media & IFM_FDX) != 0) 16454134Swpaul mii->mii_media_active |= IFM_FDX; 16554134Swpaul MIIBUS_STATCHG(sc->mii_dev); 166183505Smarius return (0); 16754134Swpaul case IFM_10_T: 168183505Smarius mii->mii_media_active = IFM_ETHER | IFM_10_T; 169217417Smarius if ((ife->ifm_media & IFM_FDX) != 0) 17054134Swpaul mii->mii_media_active |= IFM_FDX; 17154134Swpaul MIIBUS_STATCHG(sc->mii_dev); 172183505Smarius return (0); 17354134Swpaul default: 174183505Smarius return (EINVAL); 17554134Swpaul } 17654134Swpaul break; 17754134Swpaul 17854134Swpaul case MII_TICK: 17954134Swpaul /* 18054134Swpaul * Is the interface even up? 18154134Swpaul */ 18254134Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 18354134Swpaul return (0); 18454134Swpaul 18584145Sjlemon break; 18654134Swpaul } 18754134Swpaul 18854134Swpaul /* Update the media status. */ 189221407Smarius PHY_STATUS(sc); 19054134Swpaul 19154134Swpaul /* Callback if something changed. */ 19284145Sjlemon mii_phy_update(sc, cmd); 19354134Swpaul return (0); 19454134Swpaul} 19554134Swpaul 19684145Sjlemonstatic void 197150763Simppnphy_status(struct mii_softc *sc) 19854134Swpaul{ 19954134Swpaul struct mii_data *mii = sc->mii_pdata; 20054134Swpaul int reg; 20154134Swpaul struct dc_softc *dc_sc; 20254134Swpaul 20354134Swpaul dc_sc = mii->mii_ifp->if_softc; 20454134Swpaul 20554134Swpaul mii->mii_media_status = IFM_AVALID; 20654134Swpaul mii->mii_media_active = IFM_ETHER; 20754134Swpaul 20854134Swpaul reg = CSR_READ_4(dc_sc, DC_ISR); 20954134Swpaul if (!(reg & DC_ISR_LINKFAIL)) 21054134Swpaul mii->mii_media_status |= IFM_ACTIVE; 211217417Smarius reg = CSR_READ_4(dc_sc, DC_NETCFG); 212217417Smarius if (reg & DC_NETCFG_SPEEDSEL) 21354134Swpaul mii->mii_media_active |= IFM_10_T; 21454134Swpaul else 21554134Swpaul mii->mii_media_active |= IFM_100_TX; 216217417Smarius if (reg & DC_NETCFG_FULLDUPLEX) 21754134Swpaul mii->mii_media_active |= IFM_FDX; 218213384Smarius else 219213384Smarius mii->mii_media_active |= IFM_HDX; 22054134Swpaul} 221221407Smarius 222221407Smariusstatic void 223221407Smariuspnphy_reset(struct mii_softc *sc __unused) 224221407Smarius{ 225221407Smarius 226221407Smarius} 227