From 47fe7767ca51f930aa6c5acead0403ff18fce02c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Thu, 10 Oct 2013 18:42:04 +0200 Subject: [PATCH] pcnet: add pcn driver * le still working ok with QEmu * pcn brings support for the following devices in 32-bit mode (instead of 16-bit Lance compatibility mode), all untested, feedback is welcome. AMD Am79C971 PCnet-FAST, AMD Am79C972 PCnet-FAST+, AMD Am79C973/Am79C975 PCnet-FAST III, AMD Am79C976 PCnet-PRO, AMD Am79C978 PCnet-Home, Allied-Telesis LA-PCI * added PHY nsphy, nsphyter and ukphy, which seem the ones needed for pcn. * synched miidevs with FreeBSD 9.2 --- .../kernel/drivers/network/pcnet/dev/Jamfile | 2 + .../drivers/network/pcnet/dev/le/Jamfile | 3 +- .../drivers/network/pcnet/dev/le/glue.c | 88 +- .../drivers/network/pcnet/dev/mii/Jamfile | 23 + .../drivers/network/pcnet/dev/mii/nsphy.c | 332 ++++ .../drivers/network/pcnet/dev/mii/nsphyreg.h | 108 ++ .../drivers/network/pcnet/dev/mii/nsphyter.c | 268 +++ .../network/pcnet/dev/mii/nsphyterreg.h | 179 ++ .../drivers/network/pcnet/dev/mii/ukphy.c | 164 ++ .../network/pcnet/dev/mii/ukphy_subr.c | 129 ++ .../drivers/network/pcnet/dev/pcn/Jamfile | 15 + .../drivers/network/pcnet/dev/pcn/glue.c | 77 + .../drivers/network/pcnet/dev/pcn/if_pcn.c | 1518 +++++++++++++++++ .../drivers/network/pcnet/dev/pcn/if_pcnreg.h | 531 ++++++ .../freebsd_network/compat/dev/mii/miidevs | 2 +- 15 files changed, 3431 insertions(+), 8 deletions(-) create mode 100644 src/add-ons/kernel/drivers/network/pcnet/dev/mii/Jamfile create mode 100644 src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphy.c create mode 100644 src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyreg.h create mode 100644 src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyter.c create mode 100644 src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyterreg.h create mode 100644 src/add-ons/kernel/drivers/network/pcnet/dev/mii/ukphy.c create mode 100644 src/add-ons/kernel/drivers/network/pcnet/dev/mii/ukphy_subr.c create mode 100644 src/add-ons/kernel/drivers/network/pcnet/dev/pcn/Jamfile create mode 100644 src/add-ons/kernel/drivers/network/pcnet/dev/pcn/glue.c create mode 100644 src/add-ons/kernel/drivers/network/pcnet/dev/pcn/if_pcn.c create mode 100644 src/add-ons/kernel/drivers/network/pcnet/dev/pcn/if_pcnreg.h diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/Jamfile b/src/add-ons/kernel/drivers/network/pcnet/dev/Jamfile index 8aafd67acc3..7dc10711ba7 100644 --- a/src/add-ons/kernel/drivers/network/pcnet/dev/Jamfile +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/Jamfile @@ -1,3 +1,5 @@ SubDir HAIKU_TOP src add-ons kernel drivers network pcnet dev ; SubInclude HAIKU_TOP src add-ons kernel drivers network pcnet dev le ; +SubInclude HAIKU_TOP src add-ons kernel drivers network pcnet dev mii ; +SubInclude HAIKU_TOP src add-ons kernel drivers network pcnet dev pcn ; diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/le/Jamfile b/src/add-ons/kernel/drivers/network/pcnet/dev/le/Jamfile index 172b8e5a64c..e9b3c364b17 100644 --- a/src/add-ons/kernel/drivers/network/pcnet/dev/le/Jamfile +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/le/Jamfile @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers network pcnet dev le ; UseHeaders [ FDirName $(SUBDIR) .. .. ] : true ; +UseHeaders [ FDirName $(HAIKU_TOP) src libs compat freebsd_network ] : true ; UseHeaders [ FDirName $(HAIKU_TOP) src libs compat freebsd_network compat ] : true ; UsePrivateHeaders net system ; @@ -14,5 +15,5 @@ KernelAddon pcnet : if_le_pci.c lance.c glue.c - : libfreebsd_network.a + : libfreebsd_network.a pcnet_pcn.a pcnet_mii.a ; diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/le/glue.c b/src/add-ons/kernel/drivers/network/pcnet/dev/le/glue.c index 50cac121c55..54818a0bb7b 100644 --- a/src/add-ons/kernel/drivers/network/pcnet/dev/le/glue.c +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/le/glue.c @@ -7,16 +7,91 @@ #include #include +#include #include #include #include -HAIKU_FBSD_DRIVER_GLUE(pcnet, le, pci); +HAIKU_FBSD_DRIVERS_GLUE(pcnet); HAIKU_DRIVER_REQUIREMENTS(0); -NO_HAIKU_FBSD_MII_DRIVER(); -NO_HAIKU_REENABLE_INTERRUPTS(); +extern driver_t *DRIVER_MODULE_NAME(nsphy, miibus); +extern driver_t *DRIVER_MODULE_NAME(nsphyter, miibus); +extern driver_t *DRIVER_MODULE_NAME(ukphy, miibus); + + +driver_t * +__haiku_select_miibus_driver(device_t dev) +{ + driver_t *drivers[] = { + DRIVER_MODULE_NAME(nsphy, miibus), + DRIVER_MODULE_NAME(nsphyter, miibus), + DRIVER_MODULE_NAME(ukphy, miibus), + NULL + }; + + return __haiku_probe_miibus(dev, drivers); +} + +int check_disable_interrupts_le(device_t dev); +void reenable_interrupts_le(device_t dev); + +extern int check_disable_interrupts_pcn(device_t dev); +extern void reenable_interrupts_pcn(device_t dev); + + +extern driver_t *DRIVER_MODULE_NAME(le, pci); +extern driver_t *DRIVER_MODULE_NAME(pcn, pci); + + +status_t +__haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[])) +{ + driver_t *drivers[] = { + DRIVER_MODULE_NAME(le, pci), + DRIVER_MODULE_NAME(pcn, pci), + NULL + }; + return (*handler)(drivers); +} + + +int +HAIKU_CHECK_DISABLE_INTERRUPTS(device_t dev) +{ + switch (dev->device_name[0]) { + case 'l': + return check_disable_interrupts_le(dev); + case 'p': + return check_disable_interrupts_pcn(dev); + default: + break; + } + + panic("Unsupported device: %#x (%s)!", dev->device_name[0], + dev->device_name); + return 0; +} + + +void +HAIKU_REENABLE_INTERRUPTS(device_t dev) +{ + switch (dev->device_name[0]) { + case 'l': + break; + case 'p': + reenable_interrupts_pcn(dev); + break; + default: + panic("Unsupported device: %#x (%s)!", dev->device_name[0], + dev->device_name); + break; + } +} + + /* from if_le_pci.c */ #define PCNET_PCI_RDP 0x10 @@ -35,7 +110,8 @@ struct le_pci_softc { bus_dmamap_t sc_dmam; }; -int HAIKU_CHECK_DISABLE_INTERRUPTS(device_t dev) { +int +check_disable_interrupts_le(device_t dev) { struct le_pci_softc *lesc = (struct le_pci_softc *)device_get_softc(dev); HAIKU_INTR_REGISTER_STATE; uint16_t isr; @@ -57,9 +133,9 @@ int HAIKU_CHECK_DISABLE_INTERRUPTS(device_t dev) { bus_write_2(lesc->sc_rres, PCNET_PCI_RAP, LE_CSR0); bus_barrier(lesc->sc_rres, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE); bus_write_2(lesc->sc_rres, PCNET_PCI_RDP, isr & ~(LE_C0_INEA)); - + lesc->sc_am79900.lsc.sc_lastisr |= isr; - + HAIKU_INTR_REGISTER_LEAVE(); return 1; diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/mii/Jamfile b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/Jamfile new file mode 100644 index 00000000000..00cd28b6bb9 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/Jamfile @@ -0,0 +1,23 @@ +SubDir HAIKU_TOP src add-ons kernel drivers network pcnet dev mii ; + +UseHeaders [ FDirName $(SUBDIR) .. .. ] : true ; +UseHeaders [ FDirName $(HAIKU_TOP) src libs compat freebsd_network compat ] : true ; + +UsePrivateHeaders net system ; +UsePrivateKernelHeaders ; + +SubDirCcFlags [ FDefines _KERNEL=1 FBSD_DRIVER=1 ] ; + +KernelStaticLibrary pcnet_mii.a + : + nsphy.c + nsphyter.c + ukphy.c + ukphy_subr.c + ; + +ObjectHdrs [ FGristFiles nsphy$(SUFOBJ) nsphyter$(SUFOBJ) ] + : [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR_$(TARGET_PACKAGING_ARCH)) libs + compat freebsd_network ] ; +Includes [ FGristFiles nsphy.c nsphyter.c ] + : miidevs.h ; diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphy.c b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphy.c new file mode 100644 index 00000000000..01cd31d77b0 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphy.c @@ -0,0 +1,332 @@ +/* $NetBSD: nsphy.c,v 1.18 1999/07/14 23:57:36 thorpej Exp $ */ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * driver for National Semiconductor's DP83840A ethernet 10/100 PHY + * Data Sheet available from www.national.com + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "miidevs.h" + +#include + +#include "miibus_if.h" + +static int nsphy_probe(device_t); +static int nsphy_attach(device_t); + +static device_method_t nsphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, nsphy_probe), + DEVMETHOD(device_attach, nsphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD_END +}; + +static devclass_t nsphy_devclass; + +static driver_t nsphy_driver = { + "nsphy", + nsphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(nsphy, miibus, nsphy_driver, nsphy_devclass, 0, 0); + +static int nsphy_service(struct mii_softc *, struct mii_data *, int); +static void nsphy_status(struct mii_softc *); +static void nsphy_reset(struct mii_softc *); + +static const struct mii_phydesc nsphys[] = { + MII_PHY_DESC(xxNATSEMI, DP83840), + MII_PHY_END +}; + +static const struct mii_phy_funcs nsphy_funcs = { + nsphy_service, + nsphy_status, + nsphy_reset +}; + +static int +nsphy_probe(device_t dev) +{ + + return (mii_phy_dev_probe(dev, nsphys, BUS_PROBE_DEFAULT)); +} + +static int +nsphy_attach(device_t dev) +{ + const char *nic; + u_int flags; + + nic = device_get_name(device_get_parent(device_get_parent(dev))); + flags = MIIF_NOMANPAUSE; + /* + * Am79C971 wedge when isolating all of their external PHYs. + */ + if (strcmp(nic, "pcn") == 0) + flags |= MIIF_NOISOLATE; + mii_phy_dev_attach(dev, flags, &nsphy_funcs, 1); + return (0); +} + +static int +nsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + int reg; + + switch (cmd) { + case MII_POLLSTAT: + break; + + case MII_MEDIACHG: + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + reg = PHY_READ(sc, MII_NSPHY_PCR); + + /* + * Set up the PCR to use LED4 to indicate full-duplex + * in both 10baseT and 100baseTX modes. + */ + reg |= PCR_LED4MODE; + + /* + * Make sure Carrier Integrity Monitor function is + * disabled (normal for Node operation, but sometimes + * it's not set?!) + */ + reg |= PCR_CIMDIS; + + /* + * Make sure "force link good" is set to normal mode. + * It's only intended for debugging. + */ + reg |= PCR_FLINK100; + + /* + * Mystery bits which are supposedly `reserved', + * but we seem to need to set them when the PHY + * is connected to some interfaces: + * + * 0x0400 is needed for fxp + * (Intel EtherExpress Pro 10+/100B, 82557 chip) + * (nsphy with a DP83840 chip) + * 0x0100 may be needed for some other card + */ + reg |= 0x0100 | 0x0400; + + if (strcmp(mii->mii_ifp->if_dname, "fxp") == 0) + PHY_WRITE(sc, MII_NSPHY_PCR, reg); + + mii_phy_setmedia(sc); + break; + + case MII_TICK: + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + PHY_STATUS(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +nsphy_status(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmsr, bmcr, par, anlpar; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, MII_BMSR) | + PHY_READ(sc, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + /* + * The PAR status bits are only valid if autonegotiation + * has completed (or it's disabled). + */ + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + /* + * Argh. The PAR doesn't seem to indicate duplex mode + * properly! Determine media based on link partner's + * advertised capabilities. + */ + if (PHY_READ(sc, MII_ANER) & ANER_LPAN) { + anlpar = PHY_READ(sc, MII_ANAR) & + PHY_READ(sc, MII_ANLPAR); + if (anlpar & ANLPAR_TX_FD) + mii->mii_media_active |= IFM_100_TX|IFM_FDX; + else if (anlpar & ANLPAR_T4) + mii->mii_media_active |= IFM_100_T4|IFM_HDX; + else if (anlpar & ANLPAR_TX) + mii->mii_media_active |= IFM_100_TX|IFM_HDX; + else if (anlpar & ANLPAR_10_FD) + mii->mii_media_active |= IFM_10_T|IFM_FDX; + else if (anlpar & ANLPAR_10) + mii->mii_media_active |= IFM_10_T|IFM_HDX; + else + mii->mii_media_active |= IFM_NONE; + if ((mii->mii_media_active & IFM_FDX) != 0) + mii->mii_media_active |= + mii_phy_flowstatus(sc); + return; + } + + /* + * Link partner is not capable of autonegotiation. + * We will never be in full-duplex mode if this is + * the case, so reading the PAR is OK. + */ + par = PHY_READ(sc, MII_NSPHY_PAR); + if (par & PAR_10) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_100_TX; + mii->mii_media_active |= IFM_HDX; + } else + mii->mii_media_active = ife->ifm_media; +} + +static void +nsphy_reset(struct mii_softc *sc) +{ + struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; + int reg, i; + + if (sc->mii_flags & MIIF_NOISOLATE) + reg = BMCR_RESET; + else + reg = BMCR_RESET | BMCR_ISO; + PHY_WRITE(sc, MII_BMCR, reg); + + /* + * It is best to allow a little time for the reset to settle + * in before we start polling the BMCR again. Notably, the + * DP83840A manuals state that there should be a 500us delay + * between asserting software reset and attempting MII serial + * operations. Be conservative. + */ + DELAY(1000); + + /* + * Wait another 2s for it to complete. + * This is only a little overkill as under normal circumstances + * the PHY can take up to 1s to complete reset. + * This is also a bit odd because after a reset, the BMCR will + * clear the reset bit and simply reports 0 even though the reset + * is not yet complete. + */ + for (i = 0; i < 1000; i++) { + reg = PHY_READ(sc, MII_BMCR); + if (reg != 0 && (reg & BMCR_RESET) == 0) + break; + DELAY(2000); + } + + if ((sc->mii_flags & MIIF_NOISOLATE) == 0) { + if ((ife == NULL && sc->mii_inst != 0) || + (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst)) + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + } +} diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyreg.h b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyreg.h new file mode 100644 index 00000000000..71fcfb687c0 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyreg.h @@ -0,0 +1,108 @@ +/* $NetBSD: nsphyreg.h,v 1.1 1998/08/10 23:58:39 thorpej Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_NSPHYREG_H_ +#define _DEV_MII_NSPHYREG_H_ + +/* + * DP83840 registers. + */ + +#define MII_NSPHY_DCR 0x12 /* Disconnect counter */ + +#define MII_NSPHY_FCSCR 0x13 /* False carrier sense counter */ + +#define MII_NSPHY_RECR 0x15 /* Receive error counter */ + +#define MII_NSPHY_SRR 0x16 /* Silicon revision */ + +#define MII_NSPHY_PCR 0x17 /* PCS sub-layer configuration */ +#define PCR_NRZI 0x8000 /* NRZI encoding enabled for 100TX */ +#define PCR_DESCRTOSEL 0x4000 /* descrambler t/o select (2ms) */ +#define PCR_DESCRTODIS 0x2000 /* descrambler t/o disable */ +#define PCR_REPEATER 0x1000 /* repeater mode */ +#define PCR_ENCSEL 0x0800 /* encoder mode select */ +#define PCR_CLK25MDIS 0x0080 /* CLK25M disable */ +#define PCR_FLINK100 0x0040 /* force good link in 100mbps */ +#define PCR_CIMDIS 0x0020 /* carrier integrity monitor disable */ +#define PCR_TXOFF 0x0010 /* force transmit off */ +#define PCR_LED1MODE 0x0004 /* LED1 mode: see below */ +#define PCR_LED4MODE 0x0002 /* LED4 mode: see below */ + +/* + * LED1 Mode: + * + * 1 LED1 output configured to PAR's CON_STATUS, useful for + * network management in 100baseTX mode. + * + * 0 Normal LED1 operation - 10baseTX and 100baseTX transmission + * activity. + * + * LED4 Mode: + * + * 1 LED4 output configured to indicate full-duplex in both + * 10baseT and 100baseTX modes. + * + * 0 LED4 output configured to indicate polarity in 10baseT + * mode and full-duplex in 100baseTX mode. + */ + +#define MII_NSPHY_LBREMR 0x18 /* Loopback, bypass, error mask */ +#define LBREMR_BADSSDEN 0x8000 /* enable bad SSD detection */ +#define LBREMR_BP4B5B 0x4000 /* bypass 4b/5b encoding */ +#define LBREMR_BPSCR 0x2000 /* bypass scrambler */ +#define LBREMR_BPALIGN 0x1000 /* bypass alignment function */ +#define LBREMR_10LOOP 0x0800 /* 10baseT loopback */ +#define LBREMR_LB1 0x0200 /* loopback ctl 1 */ +#define LBREMR_LB0 0x0100 /* loopback ctl 0 */ +#define LBREMR_ALTCRS 0x0040 /* alt crs operation */ +#define LBREMR_LOOPXMTDIS 0x0020 /* disable transmit in 100TX loopbk */ +#define LBREMR_CODEERR 0x0010 /* code errors */ +#define LBREMR_PEERR 0x0008 /* premature end errors */ +#define LBREMR_LINKERR 0x0004 /* link errors */ +#define LBREMR_PKTERR 0x0002 /* packet errors */ + +#define MII_NSPHY_PAR 0x19 /* Physical address and status */ +#define PAR_DISCRSJAB 0x0800 /* disable car sense during jab */ +#define PAR_ANENSTAT 0x0400 /* autoneg mode status */ +#define PAR_FEFIEN 0x0100 /* far end fault enable */ +#define PAR_FDX 0x0080 /* full duplex status */ +#define PAR_10 0x0040 /* 10mbps mode */ +#define PAR_CON 0x0020 /* connect status */ +#define PAR_AMASK 0x001f /* PHY address bits */ + +#define MII_NSPHY_10BTSR 0x1b /* 10baseT status */ +#define MII_NSPHY_10BTCR 0x1c /* 10baseT configuration */ + +#endif /* _DEV_MII_NSPHYREG_H_ */ diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyter.c b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyter.c new file mode 100644 index 00000000000..dabb156a536 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyter.c @@ -0,0 +1,268 @@ +/* $NetBSD: nsphyter.c,v 1.28 2008/01/20 07:58:19 msaitoh Exp $ */ + +/*- + * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Driver for the National Semiconductor's DP83843, DP83847 and DP83849 + * `PHYTER' Ethernet 10/100 PHYs + * Data Sheets are available from http://www.national.com + * + * We also support the DP83815 `MacPHYTER' internal PHY since, for our + * purposes, they are compatible. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "miidevs.h" + +#include + +#include "miibus_if.h" + +static device_probe_t nsphyter_probe; +static device_attach_t nsphyter_attach; + +static device_method_t nsphyter_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, nsphyter_probe), + DEVMETHOD(device_attach, nsphyter_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD_END +}; + +static devclass_t nsphyter_devclass; + +static driver_t nsphyter_driver = { + "nsphyter", + nsphyter_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(nsphyter, miibus, nsphyter_driver, nsphyter_devclass, 0, 0); + +static int nsphyter_service(struct mii_softc *, struct mii_data *, int); +static void nsphyter_status(struct mii_softc *); +static void nsphyter_reset(struct mii_softc *); + +static const struct mii_phydesc nsphyters[] = { + MII_PHY_DESC(xxNATSEMI, DP83815), + MII_PHY_DESC(xxNATSEMI, DP83843), + MII_PHY_DESC(xxNATSEMI, DP83847), + MII_PHY_DESC(xxNATSEMI, DP83849), + MII_PHY_END +}; + +static const struct mii_phy_funcs nsphyter_funcs = { + nsphyter_service, + nsphyter_status, + nsphyter_reset +}; + +static int +nsphyter_probe(device_t dev) +{ + + return (mii_phy_dev_probe(dev, nsphyters, BUS_PROBE_DEFAULT)); +} + +static int +nsphyter_attach(device_t dev) +{ + + mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &nsphyter_funcs, 1); + return (0); +} + +static int +nsphyter_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + + switch (cmd) { + case MII_POLLSTAT: + break; + + case MII_MEDIACHG: + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + mii_phy_setmedia(sc); + break; + + case MII_TICK: + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + PHY_STATUS(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +nsphyter_status(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmsr, bmcr, physts; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); + physts = PHY_READ(sc, MII_NSPHYTER_PHYSTS); + + if ((physts & PHYSTS_LINK) != 0) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, MII_BMCR); + if ((bmcr & BMCR_ISO) != 0) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if ((bmcr & BMCR_LOOP) != 0) + mii->mii_media_active |= IFM_LOOP; + + if ((bmcr & BMCR_AUTOEN) != 0) { + /* + * The media status bits are only valid if autonegotiation + * has completed (or it's disabled). + */ + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + if ((physts & PHYSTS_SPEED10) != 0) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_100_TX; + if ((physts & PHYSTS_DUPLEX) != 0) + mii->mii_media_active |= + IFM_FDX | mii_phy_flowstatus(sc); + else + mii->mii_media_active |= IFM_HDX; + } else + mii->mii_media_active = ife->ifm_media; +} + +static void +nsphyter_reset(struct mii_softc *sc) +{ + struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; + int reg, i; + + if ((sc->mii_flags & MIIF_NOISOLATE) != 0) + reg = BMCR_RESET; + else + reg = BMCR_RESET | BMCR_ISO; + PHY_WRITE(sc, MII_BMCR, reg); + + /* + * It is best to allow a little time for the reset to settle + * in before we start polling the BMCR again. Notably, the + * DP8384{3,7} manuals state that there should be a 500us delay + * between asserting software reset and attempting MII serial + * operations. Be conservative. Also, a DP83815 can get into + * a bad state on cable removal and reinsertion if we do not + * delay here. + */ + DELAY(1000); + + /* + * Wait another 2s for it to complete. + * This is only a little overkill as under normal circumstances + * the PHY can take up to 1s to complete reset. + * This is also a bit odd because after a reset, the BMCR will + * clear the reset bit and simply reports 0 even though the reset + * is not yet complete. + */ + for (i = 0; i < 1000; i++) { + reg = PHY_READ(sc, MII_BMCR); + if (reg != 0 && (reg & BMCR_RESET) == 0) + break; + DELAY(2000); + } + + if ((sc->mii_flags & MIIF_NOISOLATE) == 0) { + if ((ife == NULL && sc->mii_inst != 0) || + (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst)) + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + } +} diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyterreg.h b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyterreg.h new file mode 100644 index 00000000000..3bf5208ab95 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/nsphyterreg.h @@ -0,0 +1,179 @@ +/* $NetBSD: nsphyterreg.h,v 1.4 2005/12/11 12:22:42 christos Exp $ */ + +/*- + * Copyright (c) 1999, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_MII_NSPHYTERREG_H_ +#define _DEV_MII_NSPHYTERREG_H_ + +/* + * DP83843 registers; We also have the MacPHYTER (DP83815) internal + * PHY register definitions here, since the two are, for our purposes, + * compatible. + */ + +#define MII_NSPHYTER_PHYSTS 0x10 /* PHY status */ +#define PHYSTS_REL 0x8000 /* receive error latch */ +#define PHYSTS_CIML 0x4000 /* CIM latch */ +#define PHYSTS_FCSL 0x2000 /* false carrier sense latch */ +#define PHYSTS_DEVRDY 0x0800 /* device ready */ +#define PHYSTS_PGRX 0x0400 /* page received */ +#define PHYSTS_ANEGEN 0x0200 /* autoneg. enabled */ +#define PHYSTS_MIIINTR 0x0100 /* MII interrupt */ +#define PHYSTS_REMFAULT 0x0080 /* remote fault */ +#define PHYSTS_JABBER 0x0040 /* jabber detect */ +#define PHYSTS_NWAYCOMP 0x0020 /* NWAY complete */ +#define PHYSTS_RESETSTAT 0x0010 /* reset status */ +#define PHYSTS_LOOPBACK 0x0008 /* loopback status */ +#define PHYSTS_DUPLEX 0x0004 /* full duplex */ +#define PHYSTS_SPEED10 0x0002 /* speed == 10Mb/s */ +#define PHYSTS_LINK 0x0001 /* link up */ + /* Below are the MacPHYTER bits that are different. */ +#define PHYSTS_MP_REL 0x2000 /* receive error latch */ +#define PHYSTS_MP_POLARITY 0x1000 /* polarity inverted */ +#define PHYSTS_MP_FCSL 0x0800 /* false carrier sense latch */ +#define PHYSTS_MP_SIGNAL 0x0400 /* signal detect */ +#define PHYSTS_MP_DESCRLK 0x0200 /* de-scrambler lock */ +#define PHYSTS_MP_PGRX 0x0100 /* page received */ +#define PHYSTS_MP_MIIINTR 0x0080 /* MII interrupt */ +#define PHYSTS_MP_REMFAULT 0x0040 /* remote fault */ +#define PHYSTS_MP_JABBER 0x0020 /* jabber detect */ +#define PHYSTS_MP_NWAYCOMP 0x0010 /* NWAY complete */ + + +#define MII_NSPHYTER_MIPSCR 0x11 /* MII interrupt PHY specific + control */ + +#define MIPSCR_INTEN 0x0002 /* interrupt enable */ +#define MIPSCR_TINT 0x0001 /* test interrupt */ + + +#define MII_NSPHYTER_MIPGSR 0x12 /* MII interrupt PHY generic + status */ +#define MIPGSR_MINT 0x8000 /* MII interrupt pending */ + /* The bits below are MacPHYTER only. */ +#define MIPGSR_MSK_LINK 0x4000 /* mask link status event */ +#define MIPGSR_MSK_JAB 0x2000 /* mask jabber event */ +#define MIPGSR_MSK_RF 0x1000 /* mask remote fault event */ +#define MIPGSR_MSK_ANC 0x0800 /* mask auto-neg complete event */ +#define MIPGSR_MSK_FHF 0x0400 /* mask false carrier half full event */ +#define MIPGSR_MSK_RHF 0x0200 /* mask RX error half full event */ + +#define MII_NSPHYTER_DCR 0x13 /* Disconnect counter */ + +#define MII_NSPHYTER_FCSCR 0x14 /* False carrier sense counter */ + +#define MII_NSPHYTER_RECR 0x15 /* Receive error counter */ + + +#define MII_NSPHYTER_PCSR 0x16 /* PCS configuration and status */ +#define PCSR_SINGLE_SD 0x8000 /* single-ended SD mode */ +#define PCSR_FEFI_EN 0x4000 /* far end fault indication mode */ +#define PCSR_DESCR_TO_RST 0x2000 /* reset descrambler timeout counter */ +#define PCSR_DESCR_TO_SEL 0x1000 /* descrambler timer mode */ +#define PCSR_DESCR_TO_DIS 0x0800 /* descrambler timer disable */ +#define PCSR_LD_SCR_SD 0x0400 /* load scrambler seed */ +#define PCSR_TX_QUIET 0x0200 /* 100Mb/s transmit true quiet mode */ +#define PCSR_TX_PATTERN 0x0180 /* 100Mb/s transmit test pattern */ +#define PCSR_F_LINK_100 0x0040 /* force good link in 100Mb/s */ +#define PCSR_CIM_DIS 0x0020 /* carrier integrity monitor disable */ +#define PCSR_CIM_STATUS 0x0010 /* carrier integrity monitor status */ +#define PCSR_CODE_ERR 0x0008 /* code errors */ +#define PCSR_PME_ERR 0x0004 /* premature end errors */ +#define PCSR_LINK_ERR 0x0002 /* link errors */ +#define PCSR_PKT_ERR 0x0001 /* packet errors */ + /* Below are the MacPHYTER bits that are different. */ +#define PCSR_MP_BYP_4B5B 0x1000 /* bypass encoder */ +#define PCSR_MP_FREE_CLK 0x0800 /* free funning RX clock */ +#define PCSR_MP_TQ_EN 0x0400 /* enable True Quiet mode */ +#define PCSR_MP_SD_FORCE_B 0x0200 /* force signal detection */ +#define PCSR_MP_SD_OPTION 0x0100 /* enhanced signal detection alg. */ +#define PCSR_MP_NRZI_BYPASS 0x0004 /* NRZI bypass enabled */ + + + /* The bits below are not on MacPHYTER. */ +#define MII_NSPHYTER_LBR 0x17 /* loopback and bypass */ +#define LBR_BP_STRETCH 0x4000 /* bypass LED stretching */ +#define LBR_BP_4B5B 0x2000 /* bypass encoding/decoding */ +#define LBR_BP_SCR 0x1000 /* bypass scrambler/descrambler */ +#define LBR_BP_RX 0x0800 /* bypass receive function */ +#define LBR_BP_TX 0x0400 /* bypass transmit function */ +#define LBR_100_DP_CTL 0x0380 /* 100Mb/s data patch control */ +#define LBR_TW_LBEN 0x0020 /* TWISTER loopback enable */ +#define LBR_10_ENDEC_LB 0x0010 /* 10Mb/s ENDEC loopback */ + + + /* The bits below are not on MacPHYTER. */ +#define MII_NSPHYTER_10BTSCR 0x18 /* 10baseT status and control */ +#define BTSCR_AUI_TPI 0x2000 /* TREX operating mode */ +#define BTSCR_RX_SERIAL 0x1000 /* 10baseT RX serial mode */ +#define BTSCR_TX_SERIAL 0x0800 /* 10baseT TX serial mode */ +#define BTSCR_POL_DS 0x0400 /* polarity detection and correction + disable */ +#define BTSCR_AUTOSW_EN 0x0200 /* AUI/TPI autoswitch */ +#define BTSCR_LP_DS 0x0100 /* link pulse disable */ +#define BTSCR_HB_DS 0x0080 /* heartbeat disabled */ +#define BTSCR_LS_SEL 0x0040 /* low squelch select */ +#define BTSCR_AUI_SEL 0x0020 /* AUI select */ +#define BTSCR_JAB_DS 0x0010 /* jabber disable */ +#define BTSCR_THIN_SEL 0x0008 /* thin ethernet select */ +#define BTSCR_TX_FILT_DS 0x0004 /* TPI receive filter disable */ + + +#define MII_NSPHYTER_PHYCTRL 0x19 /* PHY control */ +#define PHYCTRL_TW_EQSEL 0x3000 /* TWISTER e.q. select */ +#define PHYCTRL_BLW_DS 0x0800 /* TWISTER base line wander disable */ +#define PHYCTRL_REPEATER 0x0200 /* repeater mode */ +#define PHYCTRL_LED_TXRX_MODE 0x0180 /* LED TX/RX mode */ +#define PHYCTRL_LED_DUP_MODE 0x0040 /* LED DUP mode */ +#define PHYCTRL_FX_EN 0x0020 /* Fiber mode enable */ +#define PHYCTRL_PHYADDR 0x001f /* PHY address */ + /* Below are the MacPHYTER bits that are different. */ +#define PHYCRTL_MP_PSR_15 0x0800 /* BIST sequence select */ +#define PHYCTRL_MP_BIST_STAT 0x0400 /* BIST passed */ +#define PHYCTRL_MP_BIST_START 0x0200 /* start BIST */ +#define PHYCTRL_MP_BP_STRETCH 0x0100 /* bypass LED stretching */ +#define PHYCTRL_MP_PAUSE_STS 0x0080 /* pause status */ + + + /* The bits below are MacPHYTER only. */ +#define MII_MACPHYTER_TBTCTL 0x1a /* 10baseT Control */ +#define TBTCTL_LOOPBACK_10_DIS 0x0100 /* loopback 10Mb/s disable */ +#define TBTCTL_LP_DIS 0x0080 /* link pulse disable */ +#define TBTCTL_FORCE_LINK_10 0x0040 /* force 10Mb/s link good */ +#define TBTCTL_FORCE_POL_COR 0x0020 /* force polarity correction */ +#define TBTCTL_INV_POLARITY 0x0010 /* inverted polarity */ +#define TBTCTL_AUTOPOL_DIS 0x0008 /* auto-polarity disable */ +#define TBTCTL_HEARTBEAT_DIS 0x0002 /* heartbeat disable */ +#define TBTCTL_JABBER_DIS 0x0001 /* jabber disable */ + +#endif /* _DEV_MII_NSPHYTERREG_H_ */ diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/mii/ukphy.c b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/ukphy.c new file mode 100644 index 00000000000..9d52eb580ca --- /dev/null +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/ukphy.c @@ -0,0 +1,164 @@ +/* $NetBSD: ukphy.c,v 1.2 1999/04/23 04:24:32 thorpej Exp $ */ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center, and by Frank van der Linden. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1997 Manuel Bouyer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * driver for generic unknown PHYs + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "miibus_if.h" + +static int ukphy_probe(device_t); +static int ukphy_attach(device_t); + +static device_method_t ukphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ukphy_probe), + DEVMETHOD(device_attach, ukphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD_END +}; + +static devclass_t ukphy_devclass; + +static driver_t ukphy_driver = { + "ukphy", + ukphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(ukphy, miibus, ukphy_driver, ukphy_devclass, 0, 0); + +static int ukphy_service(struct mii_softc *, struct mii_data *, int); + +static const struct mii_phy_funcs ukphy_funcs = { + ukphy_service, + ukphy_status, + mii_phy_reset +}; + +static int +ukphy_probe(device_t dev) +{ + + /* + * We know something is here, so always match at a low priority. + */ + device_set_desc(dev, "Generic IEEE 802.3u media interface"); + return (BUS_PROBE_GENERIC); +} + +static int +ukphy_attach(device_t dev) +{ + struct mii_softc *sc; + + sc = device_get_softc(dev); + + mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &ukphy_funcs, 1); + mii_phy_setmedia(sc); + + return (0); +} + +static int +ukphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + + switch (cmd) { + case MII_POLLSTAT: + break; + + case MII_MEDIACHG: + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + mii_phy_setmedia(sc); + break; + + case MII_TICK: + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + PHY_STATUS(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/mii/ukphy_subr.c b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/ukphy_subr.c new file mode 100644 index 00000000000..5f2f6341ba6 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/mii/ukphy_subr.c @@ -0,0 +1,129 @@ +/* $NetBSD: ukphy_subr.c,v 1.2 1998/11/05 04:08:02 thorpej Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center, and by Frank van der Linden. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Subroutines shared by the ukphy driver and other PHY drivers. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "miibus_if.h" + +/* + * Media status subroutine. If a PHY driver does media detection simply + * by decoding the NWay autonegotiation, use this routine. + */ +void +ukphy_status(struct mii_softc *phy) +{ + struct mii_data *mii = phy->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmsr, bmcr, anlpar, gtcr, gtsr; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(phy, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + /* + * NWay autonegotiation takes the highest-order common + * bit of the ANAR and ANLPAR (i.e. best media advertised + * both by us and our link partner). + */ + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + anlpar = PHY_READ(phy, MII_ANAR) & PHY_READ(phy, MII_ANLPAR); + if ((phy->mii_flags & MIIF_HAVE_GTCR) != 0 && + (phy->mii_extcapabilities & + (EXTSR_1000THDX | EXTSR_1000TFDX)) != 0) { + gtcr = PHY_READ(phy, MII_100T2CR); + gtsr = PHY_READ(phy, MII_100T2SR); + } else + gtcr = gtsr = 0; + + if ((gtcr & GTCR_ADV_1000TFDX) && (gtsr & GTSR_LP_1000TFDX)) + mii->mii_media_active |= IFM_1000_T|IFM_FDX; + else if ((gtcr & GTCR_ADV_1000THDX) && + (gtsr & GTSR_LP_1000THDX)) + mii->mii_media_active |= IFM_1000_T|IFM_HDX; + else if (anlpar & ANLPAR_TX_FD) + mii->mii_media_active |= IFM_100_TX|IFM_FDX; + else if (anlpar & ANLPAR_T4) + mii->mii_media_active |= IFM_100_T4|IFM_HDX; + else if (anlpar & ANLPAR_TX) + mii->mii_media_active |= IFM_100_TX|IFM_HDX; + else if (anlpar & ANLPAR_10_FD) + mii->mii_media_active |= IFM_10_T|IFM_FDX; + else if (anlpar & ANLPAR_10) + mii->mii_media_active |= IFM_10_T|IFM_HDX; + else + mii->mii_media_active |= IFM_NONE; + + if ((mii->mii_media_active & IFM_1000_T) != 0 && + (gtsr & GTSR_MS_RES) != 0) + mii->mii_media_active |= IFM_ETH_MASTER; + + if ((mii->mii_media_active & IFM_FDX) != 0) + mii->mii_media_active |= mii_phy_flowstatus(phy); + } else + mii->mii_media_active = ife->ifm_media; +} diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/Jamfile b/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/Jamfile new file mode 100644 index 00000000000..5e73bd0a3ab --- /dev/null +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/Jamfile @@ -0,0 +1,15 @@ +SubDir HAIKU_TOP src add-ons kernel drivers network pcnet dev pcn ; + +UseHeaders [ FDirName $(SUBDIR) .. .. ] : true ; +UseHeaders [ FDirName $(HAIKU_TOP) src libs compat freebsd_network compat ] : true ; + +UsePrivateHeaders net system ; +UsePrivateKernelHeaders ; + +SubDirCcFlags [ FDefines _KERNEL=1 FBSD_DRIVER=1 ] ; + +KernelStaticLibrary pcnet_pcn.a + : + if_pcn.c + glue.c + ; diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/glue.c b/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/glue.c new file mode 100644 index 00000000000..41b5f20d33f --- /dev/null +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/glue.c @@ -0,0 +1,77 @@ +#include + +#include +#include +#include + +#include + +#include + +#define PCN_CSR_SETBIT(sc, reg, x) \ + pcn_csr_write(sc, reg, pcn_csr_read(sc, reg) | (x)) + +#define PCN_CSR_CLRBIT(sc, reg, x) \ + pcn_csr_write(sc, reg, pcn_csr_read(sc, reg) & ~(x)) + + +int check_disable_interrupts_pcn(device_t dev); +void reenable_interrupts_pcn(device_t dev); + + +static u_int32_t +pcn_csr_read(sc, reg) + struct pcn_softc *sc; + int reg; +{ + CSR_WRITE_4(sc, PCN_IO32_RAP, reg); + return(CSR_READ_4(sc, PCN_IO32_RDP)); +} + + +static void +pcn_csr_write(sc, reg, val) + struct pcn_softc *sc; + int reg; + int val; +{ + CSR_WRITE_4(sc, PCN_IO32_RAP, reg); + CSR_WRITE_4(sc, PCN_IO32_RDP, val); + return; +} + + +int +check_disable_interrupts_pcn(device_t dev) +{ + struct pcn_softc *sc = device_get_softc(dev); + HAIKU_INTR_REGISTER_STATE; + uint32_t status; + + HAIKU_INTR_REGISTER_ENTER(); + + /* get current flags */ + CSR_WRITE_4(sc, PCN_IO32_RAP, PCN_CSR_CSR); + status = CSR_READ_4(sc, PCN_IO32_RDP); + + /* is there a pending interrupt? */ + if ((status & PCN_CSR_INTR) == 0) { + HAIKU_INTR_REGISTER_LEAVE(); + return 0; + } + + /* set the new flags, disable interrupts */ + PCN_CSR_CLRBIT(sc, PCN_CSR_CSR, PCN_CSR_INTEN); + + HAIKU_INTR_REGISTER_LEAVE(); + + return 1; +} + + +void +reenable_interrupts_pcn(device_t dev) +{ + struct pcn_softc *sc = device_get_softc(dev); + PCN_CSR_SETBIT(sc, PCN_CSR_CSR, PCN_CSR_INTEN); +} diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/if_pcn.c b/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/if_pcn.c new file mode 100644 index 00000000000..d7e3d2e05f7 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/if_pcn.c @@ -0,0 +1,1518 @@ +/*- + * Copyright (c) 2000 Berkeley Software Design, Inc. + * Copyright (c) 1997, 1998, 1999, 2000 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * AMD Am79c972 fast ethernet PCI NIC driver. Datasheets are available + * from http://www.amd.com. + * + * The AMD PCnet/PCI controllers are more advanced and functional + * versions of the venerable 7990 LANCE. The PCnet/PCI chips retain + * backwards compatibility with the LANCE and thus can be made + * to work with older LANCE drivers. This is in fact how the + * PCnet/PCI chips were supported in FreeBSD originally. The trouble + * is that the PCnet/PCI devices offer several performance enhancements + * which can't be exploited in LANCE compatibility mode. Chief among + * these enhancements is the ability to perform PCI DMA operations + * using 32-bit addressing (which eliminates the need for ISA + * bounce-buffering), and special receive buffer alignment (which + * allows the receive handler to pass packets to the upper protocol + * layers without copying on both the x86 and alpha platforms). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include /* for vtophys */ +#include /* for vtophys */ +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define PCN_USEIOSPACE + +#include + +MODULE_DEPEND(pcn, pci, 1, 1, 1); +MODULE_DEPEND(pcn, ether, 1, 1, 1); +MODULE_DEPEND(pcn, miibus, 1, 1, 1); + +/* "device miibus" required. See GENERIC if you get errors here. */ +#include "miibus_if.h" + +/* + * Various supported device vendors/types and their names. + */ +static const struct pcn_type pcn_devs[] = { + { PCN_VENDORID, PCN_DEVICEID_PCNET, "AMD PCnet/PCI 10/100BaseTX" }, + { PCN_VENDORID, PCN_DEVICEID_HOME, "AMD PCnet/Home HomePNA" }, + { 0, 0, NULL } +}; + +static const struct pcn_chipid { + u_int32_t id; + const char *name; +} pcn_chipid[] = { + { Am79C971, "Am79C971" }, + { Am79C972, "Am79C972" }, + { Am79C973, "Am79C973" }, + { Am79C978, "Am79C978" }, + { Am79C975, "Am79C975" }, + { Am79C976, "Am79C976" }, + { 0, NULL }, +}; + +static const char *pcn_chipid_name(u_int32_t); +static u_int32_t pcn_chip_id(device_t); +static const struct pcn_type *pcn_match(u_int16_t, u_int16_t); + +static u_int32_t pcn_csr_read(struct pcn_softc *, int); +static u_int16_t pcn_csr_read16(struct pcn_softc *, int); +static u_int16_t pcn_bcr_read16(struct pcn_softc *, int); +static void pcn_csr_write(struct pcn_softc *, int, int); +static u_int32_t pcn_bcr_read(struct pcn_softc *, int); +static void pcn_bcr_write(struct pcn_softc *, int, int); + +static int pcn_probe(device_t); +static int pcn_attach(device_t); +static int pcn_detach(device_t); + +static int pcn_newbuf(struct pcn_softc *, int, struct mbuf *); +static int pcn_encap(struct pcn_softc *, struct mbuf *, u_int32_t *); +static void pcn_rxeof(struct pcn_softc *); +static void pcn_txeof(struct pcn_softc *); +static void pcn_intr(void *); +static void pcn_tick(void *); +static void pcn_start(struct ifnet *); +static void pcn_start_locked(struct ifnet *); +static int pcn_ioctl(struct ifnet *, u_long, caddr_t); +static void pcn_init(void *); +static void pcn_init_locked(struct pcn_softc *); +static void pcn_stop(struct pcn_softc *); +static void pcn_watchdog(struct pcn_softc *); +static int pcn_shutdown(device_t); +static int pcn_ifmedia_upd(struct ifnet *); +static void pcn_ifmedia_sts(struct ifnet *, struct ifmediareq *); + +static int pcn_miibus_readreg(device_t, int, int); +static int pcn_miibus_writereg(device_t, int, int, int); +static void pcn_miibus_statchg(device_t); + +static void pcn_setfilt(struct ifnet *); +static void pcn_setmulti(struct pcn_softc *); +static void pcn_reset(struct pcn_softc *); +static int pcn_list_rx_init(struct pcn_softc *); +static int pcn_list_tx_init(struct pcn_softc *); + +#ifdef PCN_USEIOSPACE +#define PCN_RES SYS_RES_IOPORT +#define PCN_RID PCN_PCI_LOIO +#else +#define PCN_RES SYS_RES_MEMORY +#define PCN_RID PCN_PCI_LOMEM +#endif + +static device_method_t pcn_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, pcn_probe), + DEVMETHOD(device_attach, pcn_attach), + DEVMETHOD(device_detach, pcn_detach), + DEVMETHOD(device_shutdown, pcn_shutdown), + + /* MII interface */ + DEVMETHOD(miibus_readreg, pcn_miibus_readreg), + DEVMETHOD(miibus_writereg, pcn_miibus_writereg), + DEVMETHOD(miibus_statchg, pcn_miibus_statchg), + + DEVMETHOD_END +}; + +static driver_t pcn_driver = { + "pcn", + pcn_methods, + sizeof(struct pcn_softc) +}; + +static devclass_t pcn_devclass; + +DRIVER_MODULE(pcn, pci, pcn_driver, pcn_devclass, 0, 0); +DRIVER_MODULE(miibus, pcn, miibus_driver, miibus_devclass, 0, 0); + +#define PCN_CSR_SETBIT(sc, reg, x) \ + pcn_csr_write(sc, reg, pcn_csr_read(sc, reg) | (x)) + +#define PCN_CSR_CLRBIT(sc, reg, x) \ + pcn_csr_write(sc, reg, pcn_csr_read(sc, reg) & ~(x)) + +#define PCN_BCR_SETBIT(sc, reg, x) \ + pcn_bcr_write(sc, reg, pcn_bcr_read(sc, reg) | (x)) + +#define PCN_BCR_CLRBIT(sc, reg, x) \ + pcn_bcr_write(sc, reg, pcn_bcr_read(sc, reg) & ~(x)) + +static u_int32_t +pcn_csr_read(sc, reg) + struct pcn_softc *sc; + int reg; +{ + CSR_WRITE_4(sc, PCN_IO32_RAP, reg); + return(CSR_READ_4(sc, PCN_IO32_RDP)); +} + +static u_int16_t +pcn_csr_read16(sc, reg) + struct pcn_softc *sc; + int reg; +{ + CSR_WRITE_2(sc, PCN_IO16_RAP, reg); + return(CSR_READ_2(sc, PCN_IO16_RDP)); +} + +static void +pcn_csr_write(sc, reg, val) + struct pcn_softc *sc; + int reg; + int val; +{ + CSR_WRITE_4(sc, PCN_IO32_RAP, reg); + CSR_WRITE_4(sc, PCN_IO32_RDP, val); + return; +} + +static u_int32_t +pcn_bcr_read(sc, reg) + struct pcn_softc *sc; + int reg; +{ + CSR_WRITE_4(sc, PCN_IO32_RAP, reg); + return(CSR_READ_4(sc, PCN_IO32_BDP)); +} + +static u_int16_t +pcn_bcr_read16(sc, reg) + struct pcn_softc *sc; + int reg; +{ + CSR_WRITE_2(sc, PCN_IO16_RAP, reg); + return(CSR_READ_2(sc, PCN_IO16_BDP)); +} + +static void +pcn_bcr_write(sc, reg, val) + struct pcn_softc *sc; + int reg; + int val; +{ + CSR_WRITE_4(sc, PCN_IO32_RAP, reg); + CSR_WRITE_4(sc, PCN_IO32_BDP, val); + return; +} + +static int +pcn_miibus_readreg(dev, phy, reg) + device_t dev; + int phy, reg; +{ + struct pcn_softc *sc; + int val; + + sc = device_get_softc(dev); + + /* + * At least Am79C971 with DP83840A wedge when isolating the + * external PHY so we can't allow multiple external PHYs. + * There are cards that use Am79C971 with both the internal + * and an external PHY though. + * For internal PHYs it doesn't really matter whether we can + * isolate the remaining internal and the external ones in + * the PHY drivers as the internal PHYs have to be enabled + * individually in PCN_BCR_PHYSEL, PCN_CSR_MODE, etc. + * With Am79C97{3,5,8} we don't support switching beetween + * the internal and external PHYs, yet, so we can't allow + * multiple PHYs with these either. + * Am79C97{2,6} actually only support external PHYs (not + * connectable internal ones respond at the usual addresses, + * which don't hurt if we let them show up on the bus) and + * isolating them works. + */ + if (((sc->pcn_type == Am79C971 && phy != PCN_PHYAD_10BT) || + sc->pcn_type == Am79C973 || sc->pcn_type == Am79C975 || + sc->pcn_type == Am79C978) && sc->pcn_extphyaddr != -1 && + phy != sc->pcn_extphyaddr) + return(0); + + pcn_bcr_write(sc, PCN_BCR_MIIADDR, reg | (phy << 5)); + val = pcn_bcr_read(sc, PCN_BCR_MIIDATA) & 0xFFFF; + if (val == 0xFFFF) + return(0); + + if (((sc->pcn_type == Am79C971 && phy != PCN_PHYAD_10BT) || + sc->pcn_type == Am79C973 || sc->pcn_type == Am79C975 || + sc->pcn_type == Am79C978) && sc->pcn_extphyaddr == -1) + sc->pcn_extphyaddr = phy; + + return(val); +} + +static int +pcn_miibus_writereg(dev, phy, reg, data) + device_t dev; + int phy, reg, data; +{ + struct pcn_softc *sc; + + sc = device_get_softc(dev); + + pcn_bcr_write(sc, PCN_BCR_MIIADDR, reg | (phy << 5)); + pcn_bcr_write(sc, PCN_BCR_MIIDATA, data); + + return(0); +} + +static void +pcn_miibus_statchg(dev) + device_t dev; +{ + struct pcn_softc *sc; + struct mii_data *mii; + + sc = device_get_softc(dev); + mii = device_get_softc(sc->pcn_miibus); + + if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { + PCN_BCR_SETBIT(sc, PCN_BCR_DUPLEX, PCN_DUPLEX_FDEN); + } else { + PCN_BCR_CLRBIT(sc, PCN_BCR_DUPLEX, PCN_DUPLEX_FDEN); + } + + return; +} + +static void +pcn_setmulti(sc) + struct pcn_softc *sc; +{ + struct ifnet *ifp; + struct ifmultiaddr *ifma; + u_int32_t h, i; + u_int16_t hashes[4] = { 0, 0, 0, 0 }; + + ifp = sc->pcn_ifp; + + PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND); + + if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { + for (i = 0; i < 4; i++) + pcn_csr_write(sc, PCN_CSR_MAR0 + i, 0xFFFF); + PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND); + return; + } + + /* first, zot all the existing hash bits */ + for (i = 0; i < 4; i++) + pcn_csr_write(sc, PCN_CSR_MAR0 + i, 0); + + /* now program new ones */ + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + h = ether_crc32_le(LLADDR((struct sockaddr_dl *) + ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; + hashes[h >> 4] |= 1 << (h & 0xF); + } + if_maddr_runlock(ifp); + + for (i = 0; i < 4; i++) + pcn_csr_write(sc, PCN_CSR_MAR0 + i, hashes[i]); + + PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND); + + return; +} + +static void +pcn_reset(sc) + struct pcn_softc *sc; +{ + /* + * Issue a reset by reading from the RESET register. + * Note that we don't know if the chip is operating in + * 16-bit or 32-bit mode at this point, so we attempt + * to reset the chip both ways. If one fails, the other + * will succeed. + */ + CSR_READ_2(sc, PCN_IO16_RESET); + CSR_READ_4(sc, PCN_IO32_RESET); + + /* Wait a little while for the chip to get its brains in order. */ + DELAY(1000); + + /* Select 32-bit (DWIO) mode */ + CSR_WRITE_4(sc, PCN_IO32_RDP, 0); + + /* Select software style 3. */ + pcn_bcr_write(sc, PCN_BCR_SSTYLE, PCN_SWSTYLE_PCNETPCI_BURST); + + return; +} + +static const char * +pcn_chipid_name(u_int32_t id) +{ + const struct pcn_chipid *p; + + p = pcn_chipid; + while (p->name) { + if (id == p->id) + return (p->name); + p++; + } + return ("Unknown"); +} + +static u_int32_t +pcn_chip_id(device_t dev) +{ + struct pcn_softc *sc; + u_int32_t chip_id; + + sc = device_get_softc(dev); + /* + * Note: we can *NOT* put the chip into + * 32-bit mode yet. The le(4) driver will only + * work in 16-bit mode, and once the chip + * goes into 32-bit mode, the only way to + * get it out again is with a hardware reset. + * So if pcn_probe() is called before the + * le(4) driver's probe routine, the chip will + * be locked into 32-bit operation and the + * le(4) driver will be unable to attach to it. + * Note II: if the chip happens to already + * be in 32-bit mode, we still need to check + * the chip ID, but first we have to detect + * 32-bit mode using only 16-bit operations. + * The safest way to do this is to read the + * PCI subsystem ID from BCR23/24 and compare + * that with the value read from PCI config + * space. + */ + chip_id = pcn_bcr_read16(sc, PCN_BCR_PCISUBSYSID); + chip_id <<= 16; + chip_id |= pcn_bcr_read16(sc, PCN_BCR_PCISUBVENID); + /* + * Note III: the test for 0x10001000 is a hack to + * pacify VMware, who's pseudo-PCnet interface is + * broken. Reading the subsystem register from PCI + * config space yields 0x00000000 while reading the + * same value from I/O space yields 0x10001000. It's + * not supposed to be that way. + */ + if (chip_id == pci_read_config(dev, + PCIR_SUBVEND_0, 4) || chip_id == 0x10001000) { + /* We're in 16-bit mode. */ + chip_id = pcn_csr_read16(sc, PCN_CSR_CHIPID1); + chip_id <<= 16; + chip_id |= pcn_csr_read16(sc, PCN_CSR_CHIPID0); + } else { + /* We're in 32-bit mode. */ + chip_id = pcn_csr_read(sc, PCN_CSR_CHIPID1); + chip_id <<= 16; + chip_id |= pcn_csr_read(sc, PCN_CSR_CHIPID0); + } + + return (chip_id); +} + +static const struct pcn_type * +pcn_match(u_int16_t vid, u_int16_t did) +{ + const struct pcn_type *t; + + t = pcn_devs; + while (t->pcn_name != NULL) { + if ((vid == t->pcn_vid) && (did == t->pcn_did)) + return (t); + t++; + } + return (NULL); +} + +/* + * Probe for an AMD chip. Check the PCI vendor and device + * IDs against our list and return a device name if we find a match. + */ +static int +pcn_probe(dev) + device_t dev; +{ + const struct pcn_type *t; + struct pcn_softc *sc; + int rid; + u_int32_t chip_id; + + t = pcn_match(pci_get_vendor(dev), pci_get_device(dev)); + if (t == NULL) + return (ENXIO); + sc = device_get_softc(dev); + + /* + * Temporarily map the I/O space so we can read the chip ID register. + */ + rid = PCN_RID; + sc->pcn_res = bus_alloc_resource_any(dev, PCN_RES, &rid, RF_ACTIVE); + if (sc->pcn_res == NULL) { + device_printf(dev, "couldn't map ports/memory\n"); + return(ENXIO); + } + sc->pcn_btag = rman_get_bustag(sc->pcn_res); + sc->pcn_bhandle = rman_get_bushandle(sc->pcn_res); + + chip_id = pcn_chip_id(dev); + + bus_release_resource(dev, PCN_RES, PCN_RID, sc->pcn_res); + + switch((chip_id >> 12) & PART_MASK) { + case Am79C971: + case Am79C972: + case Am79C973: + case Am79C975: + case Am79C976: + case Am79C978: + break; + default: + return(ENXIO); + } + device_set_desc(dev, t->pcn_name); + return(BUS_PROBE_DEFAULT); +} + +/* + * Attach the interface. Allocate softc structures, do ifmedia + * setup and ethernet/BPF attach. + */ +static int +pcn_attach(dev) + device_t dev; +{ + u_int32_t eaddr[2]; + struct pcn_softc *sc; + struct mii_data *mii; + struct mii_softc *miisc; + struct ifnet *ifp; + int error = 0, rid; + + sc = device_get_softc(dev); + + /* Initialize our mutex. */ + mtx_init(&sc->pcn_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, + MTX_DEF); + /* + * Map control/status registers. + */ + pci_enable_busmaster(dev); + + /* Retrieve the chip ID */ + sc->pcn_type = (pcn_chip_id(dev) >> 12) & PART_MASK; + device_printf(dev, "Chip ID %04x (%s)\n", + sc->pcn_type, pcn_chipid_name(sc->pcn_type)); + + rid = PCN_RID; + sc->pcn_res = bus_alloc_resource_any(dev, PCN_RES, &rid, RF_ACTIVE); + + if (sc->pcn_res == NULL) { + device_printf(dev, "couldn't map ports/memory\n"); + error = ENXIO; + goto fail; + } + + sc->pcn_btag = rman_get_bustag(sc->pcn_res); + sc->pcn_bhandle = rman_get_bushandle(sc->pcn_res); + + /* Allocate interrupt */ + rid = 0; + sc->pcn_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + + if (sc->pcn_irq == NULL) { + device_printf(dev, "couldn't map interrupt\n"); + error = ENXIO; + goto fail; + } + + /* Reset the adapter. */ + pcn_reset(sc); + + /* + * Get station address from the EEPROM. + */ + eaddr[0] = CSR_READ_4(sc, PCN_IO32_APROM00); + eaddr[1] = CSR_READ_4(sc, PCN_IO32_APROM01); + + callout_init_mtx(&sc->pcn_stat_callout, &sc->pcn_mtx, 0); + + sc->pcn_ldata = contigmalloc(sizeof(struct pcn_list_data), M_DEVBUF, + M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); + + if (sc->pcn_ldata == NULL) { + device_printf(dev, "no memory for list buffers!\n"); + error = ENXIO; + goto fail; + } + bzero(sc->pcn_ldata, sizeof(struct pcn_list_data)); + + ifp = sc->pcn_ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) { + device_printf(dev, "can not if_alloc()\n"); + error = ENOSPC; + goto fail; + } + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = pcn_ioctl; + ifp->if_start = pcn_start; + ifp->if_init = pcn_init; + ifp->if_snd.ifq_maxlen = PCN_TX_LIST_CNT - 1; + + /* + * Do MII setup. + * See the comment in pcn_miibus_readreg() for why we can't + * universally pass MIIF_NOISOLATE here. + */ + sc->pcn_extphyaddr = -1; + error = mii_attach(dev, &sc->pcn_miibus, ifp, pcn_ifmedia_upd, + pcn_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); + goto fail; + } + /* + * Record the media instances of internal PHYs, which map the + * built-in interfaces to the MII, so we can set the active + * PHY/port based on the currently selected media. + */ + sc->pcn_inst_10bt = -1; + mii = device_get_softc(sc->pcn_miibus); + LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { + switch (miisc->mii_phy) { + case PCN_PHYAD_10BT: + sc->pcn_inst_10bt = miisc->mii_inst; + break; + /* + * XXX deal with the Am79C97{3,5} internal 100baseT + * and the Am79C978 internal HomePNA PHYs. + */ + } + } + + /* + * Call MI attach routine. + */ + ether_ifattach(ifp, (u_int8_t *) eaddr); + + /* Hook interrupt last to avoid having to lock softc */ + error = bus_setup_intr(dev, sc->pcn_irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL, pcn_intr, sc, &sc->pcn_intrhand); + + if (error) { + device_printf(dev, "couldn't set up irq\n"); + ether_ifdetach(ifp); + goto fail; + } + +fail: + if (error) + pcn_detach(dev); + + return(error); +} + +/* + * Shutdown hardware and free up resources. This can be called any + * time after the mutex has been initialized. It is called in both + * the error case in attach and the normal detach case so it needs + * to be careful about only freeing resources that have actually been + * allocated. + */ +static int +pcn_detach(dev) + device_t dev; +{ + struct pcn_softc *sc; + struct ifnet *ifp; + + sc = device_get_softc(dev); + ifp = sc->pcn_ifp; + + KASSERT(mtx_initialized(&sc->pcn_mtx), ("pcn mutex not initialized")); + + /* These should only be active if attach succeeded */ + if (device_is_attached(dev)) { + PCN_LOCK(sc); + pcn_reset(sc); + pcn_stop(sc); + PCN_UNLOCK(sc); + callout_drain(&sc->pcn_stat_callout); + ether_ifdetach(ifp); + } + if (sc->pcn_miibus) + device_delete_child(dev, sc->pcn_miibus); + bus_generic_detach(dev); + + if (sc->pcn_intrhand) + bus_teardown_intr(dev, sc->pcn_irq, sc->pcn_intrhand); + if (sc->pcn_irq) + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->pcn_irq); + if (sc->pcn_res) + bus_release_resource(dev, PCN_RES, PCN_RID, sc->pcn_res); + + if (ifp) + if_free(ifp); + + if (sc->pcn_ldata) { + contigfree(sc->pcn_ldata, sizeof(struct pcn_list_data), + M_DEVBUF); + } + + mtx_destroy(&sc->pcn_mtx); + + return(0); +} + +/* + * Initialize the transmit descriptors. + */ +static int +pcn_list_tx_init(sc) + struct pcn_softc *sc; +{ + struct pcn_list_data *ld; + struct pcn_ring_data *cd; + int i; + + cd = &sc->pcn_cdata; + ld = sc->pcn_ldata; + + for (i = 0; i < PCN_TX_LIST_CNT; i++) { + cd->pcn_tx_chain[i] = NULL; + ld->pcn_tx_list[i].pcn_tbaddr = 0; + ld->pcn_tx_list[i].pcn_txctl = 0; + ld->pcn_tx_list[i].pcn_txstat = 0; + } + + cd->pcn_tx_prod = cd->pcn_tx_cons = cd->pcn_tx_cnt = 0; + + return(0); +} + + +/* + * Initialize the RX descriptors and allocate mbufs for them. + */ +static int +pcn_list_rx_init(sc) + struct pcn_softc *sc; +{ + struct pcn_ring_data *cd; + int i; + + cd = &sc->pcn_cdata; + + for (i = 0; i < PCN_RX_LIST_CNT; i++) { + if (pcn_newbuf(sc, i, NULL) == ENOBUFS) + return(ENOBUFS); + } + + cd->pcn_rx_prod = 0; + + return(0); +} + +/* + * Initialize an RX descriptor and attach an MBUF cluster. + */ +static int +pcn_newbuf(sc, idx, m) + struct pcn_softc *sc; + int idx; + struct mbuf *m; +{ + struct mbuf *m_new = NULL; + struct pcn_rx_desc *c; + + c = &sc->pcn_ldata->pcn_rx_list[idx]; + + if (m == NULL) { + MGETHDR(m_new, M_NOWAIT, MT_DATA); + if (m_new == NULL) + return(ENOBUFS); + + MCLGET(m_new, M_NOWAIT); + if (!(m_new->m_flags & M_EXT)) { + m_freem(m_new); + return(ENOBUFS); + } + m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; + } else { + m_new = m; + m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; + m_new->m_data = m_new->m_ext.ext_buf; + } + + m_adj(m_new, ETHER_ALIGN); + + sc->pcn_cdata.pcn_rx_chain[idx] = m_new; + c->pcn_rbaddr = vtophys(mtod(m_new, caddr_t)); + c->pcn_bufsz = (~(PCN_RXLEN) + 1) & PCN_RXLEN_BUFSZ; + c->pcn_bufsz |= PCN_RXLEN_MBO; + c->pcn_rxstat = PCN_RXSTAT_STP|PCN_RXSTAT_ENP|PCN_RXSTAT_OWN; + + return(0); +} + +/* + * A frame has been uploaded: pass the resulting mbuf chain up to + * the higher level protocols. + */ +static void +pcn_rxeof(sc) + struct pcn_softc *sc; +{ + struct mbuf *m; + struct ifnet *ifp; + struct pcn_rx_desc *cur_rx; + int i; + + PCN_LOCK_ASSERT(sc); + + ifp = sc->pcn_ifp; + i = sc->pcn_cdata.pcn_rx_prod; + + while(PCN_OWN_RXDESC(&sc->pcn_ldata->pcn_rx_list[i])) { + cur_rx = &sc->pcn_ldata->pcn_rx_list[i]; + m = sc->pcn_cdata.pcn_rx_chain[i]; + sc->pcn_cdata.pcn_rx_chain[i] = NULL; + + /* + * If an error occurs, update stats, clear the + * status word and leave the mbuf cluster in place: + * it should simply get re-used next time this descriptor + * comes up in the ring. + */ + if (cur_rx->pcn_rxstat & PCN_RXSTAT_ERR) { + ifp->if_ierrors++; + pcn_newbuf(sc, i, m); + PCN_INC(i, PCN_RX_LIST_CNT); + continue; + } + + if (pcn_newbuf(sc, i, NULL)) { + /* Ran out of mbufs; recycle this one. */ + pcn_newbuf(sc, i, m); + ifp->if_ierrors++; + PCN_INC(i, PCN_RX_LIST_CNT); + continue; + } + + PCN_INC(i, PCN_RX_LIST_CNT); + + /* No errors; receive the packet. */ + ifp->if_ipackets++; + m->m_len = m->m_pkthdr.len = + cur_rx->pcn_rxlen - ETHER_CRC_LEN; + m->m_pkthdr.rcvif = ifp; + + PCN_UNLOCK(sc); + (*ifp->if_input)(ifp, m); + PCN_LOCK(sc); + } + + sc->pcn_cdata.pcn_rx_prod = i; + + return; +} + +/* + * A frame was downloaded to the chip. It's safe for us to clean up + * the list buffers. + */ + +static void +pcn_txeof(sc) + struct pcn_softc *sc; +{ + struct pcn_tx_desc *cur_tx = NULL; + struct ifnet *ifp; + u_int32_t idx; + + ifp = sc->pcn_ifp; + + /* + * Go through our tx list and free mbufs for those + * frames that have been transmitted. + */ + idx = sc->pcn_cdata.pcn_tx_cons; + while (idx != sc->pcn_cdata.pcn_tx_prod) { + cur_tx = &sc->pcn_ldata->pcn_tx_list[idx]; + + if (!PCN_OWN_TXDESC(cur_tx)) + break; + + if (!(cur_tx->pcn_txctl & PCN_TXCTL_ENP)) { + sc->pcn_cdata.pcn_tx_cnt--; + PCN_INC(idx, PCN_TX_LIST_CNT); + continue; + } + + if (cur_tx->pcn_txctl & PCN_TXCTL_ERR) { + ifp->if_oerrors++; + if (cur_tx->pcn_txstat & PCN_TXSTAT_EXDEF) + ifp->if_collisions++; + if (cur_tx->pcn_txstat & PCN_TXSTAT_RTRY) + ifp->if_collisions++; + } + + ifp->if_collisions += + cur_tx->pcn_txstat & PCN_TXSTAT_TRC; + + ifp->if_opackets++; + if (sc->pcn_cdata.pcn_tx_chain[idx] != NULL) { + m_freem(sc->pcn_cdata.pcn_tx_chain[idx]); + sc->pcn_cdata.pcn_tx_chain[idx] = NULL; + } + + sc->pcn_cdata.pcn_tx_cnt--; + PCN_INC(idx, PCN_TX_LIST_CNT); + } + + if (idx != sc->pcn_cdata.pcn_tx_cons) { + /* Some buffers have been freed. */ + sc->pcn_cdata.pcn_tx_cons = idx; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + } + sc->pcn_timer = (sc->pcn_cdata.pcn_tx_cnt == 0) ? 0 : 5; + + return; +} + +static void +pcn_tick(xsc) + void *xsc; +{ + struct pcn_softc *sc; + struct mii_data *mii; + struct ifnet *ifp; + + sc = xsc; + ifp = sc->pcn_ifp; + PCN_LOCK_ASSERT(sc); + + mii = device_get_softc(sc->pcn_miibus); + mii_tick(mii); + + /* link just died */ + if (sc->pcn_link & !(mii->mii_media_status & IFM_ACTIVE)) + sc->pcn_link = 0; + + /* link just came up, restart */ + if (!sc->pcn_link && mii->mii_media_status & IFM_ACTIVE && + IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { + sc->pcn_link++; + if (ifp->if_snd.ifq_head != NULL) + pcn_start_locked(ifp); + } + + if (sc->pcn_timer > 0 && --sc->pcn_timer == 0) + pcn_watchdog(sc); + callout_reset(&sc->pcn_stat_callout, hz, pcn_tick, sc); + + return; +} + +static void +pcn_intr(arg) + void *arg; +{ + struct pcn_softc *sc; + struct ifnet *ifp; + u_int32_t status; + + sc = arg; + ifp = sc->pcn_ifp; + + PCN_LOCK(sc); + + /* Suppress unwanted interrupts */ + if (!(ifp->if_flags & IFF_UP)) { + pcn_stop(sc); + PCN_UNLOCK(sc); + return; + } + + CSR_WRITE_4(sc, PCN_IO32_RAP, PCN_CSR_CSR); + + while ((status = CSR_READ_4(sc, PCN_IO32_RDP)) & PCN_CSR_INTR) { + CSR_WRITE_4(sc, PCN_IO32_RDP, status); + + if (status & PCN_CSR_RINT) + pcn_rxeof(sc); + + if (status & PCN_CSR_TINT) + pcn_txeof(sc); + + if (status & PCN_CSR_ERR) { + pcn_init_locked(sc); + break; + } + } + + if (ifp->if_snd.ifq_head != NULL) + pcn_start_locked(ifp); + + PCN_UNLOCK(sc); + return; +} + +/* + * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data + * pointers to the fragment pointers. + */ +static int +pcn_encap(sc, m_head, txidx) + struct pcn_softc *sc; + struct mbuf *m_head; + u_int32_t *txidx; +{ + struct pcn_tx_desc *f = NULL; + struct mbuf *m; + int frag, cur, cnt = 0; + + /* + * Start packing the mbufs in this chain into + * the fragment pointers. Stop when we run out + * of fragments or hit the end of the mbuf chain. + */ + m = m_head; + cur = frag = *txidx; + + for (m = m_head; m != NULL; m = m->m_next) { + if (m->m_len == 0) + continue; + + if ((PCN_TX_LIST_CNT - (sc->pcn_cdata.pcn_tx_cnt + cnt)) < 2) + return(ENOBUFS); + f = &sc->pcn_ldata->pcn_tx_list[frag]; + f->pcn_txctl = (~(m->m_len) + 1) & PCN_TXCTL_BUFSZ; + f->pcn_txctl |= PCN_TXCTL_MBO; + f->pcn_tbaddr = vtophys(mtod(m, vm_offset_t)); + if (cnt == 0) + f->pcn_txctl |= PCN_TXCTL_STP; + else + f->pcn_txctl |= PCN_TXCTL_OWN; + cur = frag; + PCN_INC(frag, PCN_TX_LIST_CNT); + cnt++; + } + + if (m != NULL) + return(ENOBUFS); + + sc->pcn_cdata.pcn_tx_chain[cur] = m_head; + sc->pcn_ldata->pcn_tx_list[cur].pcn_txctl |= + PCN_TXCTL_ENP|PCN_TXCTL_ADD_FCS|PCN_TXCTL_MORE_LTINT; + sc->pcn_ldata->pcn_tx_list[*txidx].pcn_txctl |= PCN_TXCTL_OWN; + sc->pcn_cdata.pcn_tx_cnt += cnt; + *txidx = frag; + + return(0); +} + +/* + * Main transmit routine. To avoid having to do mbuf copies, we put pointers + * to the mbuf data regions directly in the transmit lists. We also save a + * copy of the pointers since the transmit list fragment pointers are + * physical addresses. + */ +static void +pcn_start(ifp) + struct ifnet *ifp; +{ + struct pcn_softc *sc; + + sc = ifp->if_softc; + PCN_LOCK(sc); + pcn_start_locked(ifp); + PCN_UNLOCK(sc); +} + +static void +pcn_start_locked(ifp) + struct ifnet *ifp; +{ + struct pcn_softc *sc; + struct mbuf *m_head = NULL; + u_int32_t idx; + + sc = ifp->if_softc; + + PCN_LOCK_ASSERT(sc); + + if (!sc->pcn_link) + return; + + idx = sc->pcn_cdata.pcn_tx_prod; + + if (ifp->if_drv_flags & IFF_DRV_OACTIVE) + return; + + while(sc->pcn_cdata.pcn_tx_chain[idx] == NULL) { + IF_DEQUEUE(&ifp->if_snd, m_head); + if (m_head == NULL) + break; + + if (pcn_encap(sc, m_head, &idx)) { + IF_PREPEND(&ifp->if_snd, m_head); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + + /* + * If there's a BPF listener, bounce a copy of this frame + * to him. + */ + BPF_MTAP(ifp, m_head); + + } + + /* Transmit */ + sc->pcn_cdata.pcn_tx_prod = idx; + pcn_csr_write(sc, PCN_CSR_CSR, PCN_CSR_TX|PCN_CSR_INTEN); + + /* + * Set a timeout in case the chip goes out to lunch. + */ + sc->pcn_timer = 5; + + return; +} + +static void +pcn_setfilt(ifp) + struct ifnet *ifp; +{ + struct pcn_softc *sc; + + sc = ifp->if_softc; + + /* If we want promiscuous mode, set the allframes bit. */ + if (ifp->if_flags & IFF_PROMISC) { + PCN_CSR_SETBIT(sc, PCN_CSR_MODE, PCN_MODE_PROMISC); + } else { + PCN_CSR_CLRBIT(sc, PCN_CSR_MODE, PCN_MODE_PROMISC); + } + + /* Set the capture broadcast bit to capture broadcast frames. */ + if (ifp->if_flags & IFF_BROADCAST) { + PCN_CSR_CLRBIT(sc, PCN_CSR_MODE, PCN_MODE_RXNOBROAD); + } else { + PCN_CSR_SETBIT(sc, PCN_CSR_MODE, PCN_MODE_RXNOBROAD); + } + + return; +} + +static void +pcn_init(xsc) + void *xsc; +{ + struct pcn_softc *sc = xsc; + + PCN_LOCK(sc); + pcn_init_locked(sc); + PCN_UNLOCK(sc); +} + +static void +pcn_init_locked(sc) + struct pcn_softc *sc; +{ + struct ifnet *ifp = sc->pcn_ifp; + struct mii_data *mii = NULL; + struct ifmedia_entry *ife; + + PCN_LOCK_ASSERT(sc); + + /* + * Cancel pending I/O and free all RX/TX buffers. + */ + pcn_stop(sc); + pcn_reset(sc); + + mii = device_get_softc(sc->pcn_miibus); + ife = mii->mii_media.ifm_cur; + + /* Set MAC address */ + pcn_csr_write(sc, PCN_CSR_PAR0, + ((u_int16_t *)IF_LLADDR(sc->pcn_ifp))[0]); + pcn_csr_write(sc, PCN_CSR_PAR1, + ((u_int16_t *)IF_LLADDR(sc->pcn_ifp))[1]); + pcn_csr_write(sc, PCN_CSR_PAR2, + ((u_int16_t *)IF_LLADDR(sc->pcn_ifp))[2]); + + /* Init circular RX list. */ + if (pcn_list_rx_init(sc) == ENOBUFS) { + if_printf(ifp, "initialization failed: no " + "memory for rx buffers\n"); + pcn_stop(sc); + return; + } + + /* + * Init tx descriptors. + */ + pcn_list_tx_init(sc); + + /* Clear PCN_MISC_ASEL so we can set the port via PCN_CSR_MODE. */ + PCN_BCR_CLRBIT(sc, PCN_BCR_MISCCFG, PCN_MISC_ASEL); + + /* + * Set up the port based on the currently selected media. + * For Am79C978 we've to unconditionally set PCN_PORT_MII and + * set the PHY in PCN_BCR_PHYSEL instead. + */ + if (sc->pcn_type != Am79C978 && + IFM_INST(ife->ifm_media) == sc->pcn_inst_10bt) + pcn_csr_write(sc, PCN_CSR_MODE, PCN_PORT_10BASET); + else + pcn_csr_write(sc, PCN_CSR_MODE, PCN_PORT_MII); + + /* Set up RX filter. */ + pcn_setfilt(ifp); + + /* + * Load the multicast filter. + */ + pcn_setmulti(sc); + + /* + * Load the addresses of the RX and TX lists. + */ + pcn_csr_write(sc, PCN_CSR_RXADDR0, + vtophys(&sc->pcn_ldata->pcn_rx_list[0]) & 0xFFFF); + pcn_csr_write(sc, PCN_CSR_RXADDR1, + (vtophys(&sc->pcn_ldata->pcn_rx_list[0]) >> 16) & 0xFFFF); + pcn_csr_write(sc, PCN_CSR_TXADDR0, + vtophys(&sc->pcn_ldata->pcn_tx_list[0]) & 0xFFFF); + pcn_csr_write(sc, PCN_CSR_TXADDR1, + (vtophys(&sc->pcn_ldata->pcn_tx_list[0]) >> 16) & 0xFFFF); + + /* Set the RX and TX ring sizes. */ + pcn_csr_write(sc, PCN_CSR_RXRINGLEN, (~PCN_RX_LIST_CNT) + 1); + pcn_csr_write(sc, PCN_CSR_TXRINGLEN, (~PCN_TX_LIST_CNT) + 1); + + /* We're not using the initialization block. */ + pcn_csr_write(sc, PCN_CSR_IAB1, 0); + + /* Enable fast suspend mode. */ + PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL2, PCN_EXTCTL2_FASTSPNDE); + + /* + * Enable burst read and write. Also set the no underflow + * bit. This will avoid transmit underruns in certain + * conditions while still providing decent performance. + */ + PCN_BCR_SETBIT(sc, PCN_BCR_BUSCTL, PCN_BUSCTL_NOUFLOW| + PCN_BUSCTL_BREAD|PCN_BUSCTL_BWRITE); + + /* Enable graceful recovery from underflow. */ + PCN_CSR_SETBIT(sc, PCN_CSR_IMR, PCN_IMR_DXSUFLO); + + /* Enable auto-padding of short TX frames. */ + PCN_CSR_SETBIT(sc, PCN_CSR_TFEAT, PCN_TFEAT_PAD_TX); + + /* Disable MII autoneg (we handle this ourselves). */ + PCN_BCR_SETBIT(sc, PCN_BCR_MIICTL, PCN_MIICTL_DANAS); + + if (sc->pcn_type == Am79C978) + /* XXX support other PHYs? */ + pcn_bcr_write(sc, PCN_BCR_PHYSEL, + PCN_PHYSEL_PCNET|PCN_PHY_HOMEPNA); + + /* Enable interrupts and start the controller running. */ + pcn_csr_write(sc, PCN_CSR_CSR, PCN_CSR_INTEN|PCN_CSR_START); + + mii_mediachg(mii); + + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + callout_reset(&sc->pcn_stat_callout, hz, pcn_tick, sc); + + return; +} + +/* + * Set media options. + */ +static int +pcn_ifmedia_upd(ifp) + struct ifnet *ifp; +{ + struct pcn_softc *sc; + + sc = ifp->if_softc; + + PCN_LOCK(sc); + + /* + * At least Am79C971 with DP83840A can wedge when switching + * from the internal 10baseT PHY to the external PHY without + * issuing pcn_reset(). For setting the port in PCN_CSR_MODE + * the PCnet chip has to be powered down or stopped anyway + * and although documented otherwise it doesn't take effect + * until the next initialization. + */ + sc->pcn_link = 0; + pcn_stop(sc); + pcn_reset(sc); + pcn_init_locked(sc); + if (ifp->if_snd.ifq_head != NULL) + pcn_start_locked(ifp); + + PCN_UNLOCK(sc); + + return(0); +} + +/* + * Report current media status. + */ +static void +pcn_ifmedia_sts(ifp, ifmr) + struct ifnet *ifp; + struct ifmediareq *ifmr; +{ + struct pcn_softc *sc; + struct mii_data *mii; + + sc = ifp->if_softc; + + mii = device_get_softc(sc->pcn_miibus); + PCN_LOCK(sc); + mii_pollstat(mii); + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; + PCN_UNLOCK(sc); + + return; +} + +static int +pcn_ioctl(ifp, command, data) + struct ifnet *ifp; + u_long command; + caddr_t data; +{ + struct pcn_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; + struct mii_data *mii = NULL; + int error = 0; + + switch(command) { + case SIOCSIFFLAGS: + PCN_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING && + ifp->if_flags & IFF_PROMISC && + !(sc->pcn_if_flags & IFF_PROMISC)) { + PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL1, + PCN_EXTCTL1_SPND); + pcn_setfilt(ifp); + PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1, + PCN_EXTCTL1_SPND); + pcn_csr_write(sc, PCN_CSR_CSR, + PCN_CSR_INTEN|PCN_CSR_START); + } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && + !(ifp->if_flags & IFF_PROMISC) && + sc->pcn_if_flags & IFF_PROMISC) { + PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL1, + PCN_EXTCTL1_SPND); + pcn_setfilt(ifp); + PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1, + PCN_EXTCTL1_SPND); + pcn_csr_write(sc, PCN_CSR_CSR, + PCN_CSR_INTEN|PCN_CSR_START); + } else if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) + pcn_init_locked(sc); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + pcn_stop(sc); + } + sc->pcn_if_flags = ifp->if_flags; + PCN_UNLOCK(sc); + error = 0; + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + PCN_LOCK(sc); + pcn_setmulti(sc); + PCN_UNLOCK(sc); + error = 0; + break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + mii = device_get_softc(sc->pcn_miibus); + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); + break; + default: + error = ether_ioctl(ifp, command, data); + break; + } + + return(error); +} + +static void +pcn_watchdog(struct pcn_softc *sc) +{ + struct ifnet *ifp; + + PCN_LOCK_ASSERT(sc); + ifp = sc->pcn_ifp; + + ifp->if_oerrors++; + if_printf(ifp, "watchdog timeout\n"); + + pcn_stop(sc); + pcn_reset(sc); + pcn_init_locked(sc); + + if (ifp->if_snd.ifq_head != NULL) + pcn_start_locked(ifp); +} + +/* + * Stop the adapter and free any mbufs allocated to the + * RX and TX lists. + */ +static void +pcn_stop(struct pcn_softc *sc) +{ + register int i; + struct ifnet *ifp; + + PCN_LOCK_ASSERT(sc); + ifp = sc->pcn_ifp; + sc->pcn_timer = 0; + + callout_stop(&sc->pcn_stat_callout); + + /* Turn off interrupts */ + PCN_CSR_CLRBIT(sc, PCN_CSR_CSR, PCN_CSR_INTEN); + /* Stop adapter */ + PCN_CSR_SETBIT(sc, PCN_CSR_CSR, PCN_CSR_STOP); + sc->pcn_link = 0; + + /* + * Free data in the RX lists. + */ + for (i = 0; i < PCN_RX_LIST_CNT; i++) { + if (sc->pcn_cdata.pcn_rx_chain[i] != NULL) { + m_freem(sc->pcn_cdata.pcn_rx_chain[i]); + sc->pcn_cdata.pcn_rx_chain[i] = NULL; + } + } + bzero((char *)&sc->pcn_ldata->pcn_rx_list, + sizeof(sc->pcn_ldata->pcn_rx_list)); + + /* + * Free the TX list buffers. + */ + for (i = 0; i < PCN_TX_LIST_CNT; i++) { + if (sc->pcn_cdata.pcn_tx_chain[i] != NULL) { + m_freem(sc->pcn_cdata.pcn_tx_chain[i]); + sc->pcn_cdata.pcn_tx_chain[i] = NULL; + } + } + + bzero((char *)&sc->pcn_ldata->pcn_tx_list, + sizeof(sc->pcn_ldata->pcn_tx_list)); + + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + + return; +} + +/* + * Stop all chip I/O so that the kernel's probe routines don't + * get confused by errant DMAs when rebooting. + */ +static int +pcn_shutdown(device_t dev) +{ + struct pcn_softc *sc; + + sc = device_get_softc(dev); + + PCN_LOCK(sc); + pcn_reset(sc); + pcn_stop(sc); + PCN_UNLOCK(sc); + + return 0; +} diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/if_pcnreg.h b/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/if_pcnreg.h new file mode 100644 index 00000000000..a10edfd76aa --- /dev/null +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/pcn/if_pcnreg.h @@ -0,0 +1,531 @@ +/*- + * Copyright (c) 2000 Berkeley Software Design, Inc. + * Copyright (c) 1997, 1998, 1999, 2000 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * I/O map in 16-bit mode. To switch to 32-bit mode, + * you need to perform a 32-bit write to the RDP register + * (writing a 0 is recommended). + */ +#define PCN_IO16_APROM00 0x00 +#define PCN_IO16_APROM01 0x02 +#define PCN_IO16_APROM02 0x04 +#define PCN_IO16_APROM03 0x06 +#define PCN_IO16_APROM04 0x08 +#define PCN_IO16_APROM05 0x0A +#define PCN_IO16_APROM06 0x0C +#define PCN_IO16_APROM07 0x0E +#define PCN_IO16_RDP 0x10 +#define PCN_IO16_RAP 0x12 +#define PCN_IO16_RESET 0x14 +#define PCN_IO16_BDP 0x16 + +/* + * I/O map in 32-bit mode. + */ +#define PCN_IO32_APROM00 0x00 +#define PCN_IO32_APROM01 0x04 +#define PCN_IO32_APROM02 0x08 +#define PCN_IO32_APROM03 0x0C +#define PCN_IO32_RDP 0x10 +#define PCN_IO32_RAP 0x14 +#define PCN_IO32_RESET 0x18 +#define PCN_IO32_BDP 0x1C + +/* + * CSR registers + */ +#define PCN_CSR_CSR 0x00 +#define PCN_CSR_IAB0 0x01 +#define PCN_CSR_IAB1 0x02 +#define PCN_CSR_IMR 0x03 +#define PCN_CSR_TFEAT 0x04 +#define PCN_CSR_EXTCTL1 0x05 +#define PCN_CSR_DTBLLEN 0x06 +#define PCN_CSR_EXTCTL2 0x07 +#define PCN_CSR_MAR0 0x08 +#define PCN_CSR_MAR1 0x09 +#define PCN_CSR_MAR2 0x0A +#define PCN_CSR_MAR3 0x0B +#define PCN_CSR_PAR0 0x0C +#define PCN_CSR_PAR1 0x0D +#define PCN_CSR_PAR2 0x0E +#define PCN_CSR_MODE 0x0F +#define PCN_CSR_RXADDR0 0x18 +#define PCN_CSR_RXADDR1 0x19 +#define PCN_CSR_TXADDR0 0x1E +#define PCN_CSR_TXADDR1 0x1F +#define PCN_CSR_TXPOLL 0x2F +#define PCN_CSR_RXPOLL 0x31 +#define PCN_CSR_RXRINGLEN 0x4C +#define PCN_CSR_TXRINGLEN 0x4E +#define PCN_CSR_DMACTL 0x50 +#define PCN_CSR_BUSTIMER 0x52 +#define PCN_CSR_MEMERRTIMEO 0x64 +#define PCN_CSR_ONNOWMISC 0x74 +#define PCN_CSR_ADVFEAT 0x7A +#define PCN_CSR_MACCFG 0x7D +#define PCN_CSR_CHIPID0 0x58 +#define PCN_CSR_CHIPID1 0x59 + +/* + * Control and status register (CSR0) + */ +#define PCN_CSR_INIT 0x0001 +#define PCN_CSR_START 0x0002 +#define PCN_CSR_STOP 0x0004 +#define PCN_CSR_TX 0x0008 +#define PCN_CSR_TXON 0x0010 +#define PCN_CSR_RXON 0x0020 +#define PCN_CSR_INTEN 0x0040 +#define PCN_CSR_INTR 0x0080 +#define PCN_CSR_IDONE 0x0100 +#define PCN_CSR_TINT 0x0200 +#define PCN_CSR_RINT 0x0400 +#define PCN_CSR_MERR 0x0800 +#define PCN_CSR_MISS 0x1000 +#define PCN_CSR_CERR 0x2000 +#define PCN_CSR_ERR 0x8000 + +/* + * Interrupt masks and deferral control (CSR3) + */ +#define PCN_IMR_BSWAP 0x0004 +#define PCN_IMR_ENMBA 0x0008 /* enable modified backoff alg */ +#define PCN_IMR_DXMT2PD 0x0010 +#define PCN_IMR_LAPPEN 0x0020 /* lookahead packet processing enb */ +#define PCN_IMR_DXSUFLO 0x0040 /* disable TX stop on underflow */ +#define PCN_IMR_IDONE 0x0100 +#define PCN_IMR_TINT 0x0200 +#define PCN_IMR_RINT 0x0400 +#define PCN_IMR_MERR 0x0800 +#define PCN_IMR_MISS 0x1000 + +/* + * Test and features control (CSR4) + */ +#define PCN_TFEAT_TXSTRTMASK 0x0004 +#define PCN_TFEAT_TXSTRT 0x0008 +#define PCN_TFEAT_RXCCOFLOWM 0x0010 /* Rx collision counter oflow */ +#define PCN_TFEAT_RXCCOFLOW 0x0020 +#define PCN_TFEAT_UINT 0x0040 +#define PCN_TFEAT_UINTREQ 0x0080 +#define PCN_TFEAT_MISSOFLOWM 0x0100 +#define PCN_TFEAT_MISSOFLOW 0x0200 +#define PCN_TFEAT_STRIP_FCS 0x0400 +#define PCN_TFEAT_PAD_TX 0x0800 +#define PCN_TFEAT_TXDPOLL 0x1000 +#define PCN_TFEAT_DMAPLUS 0x4000 + +/* + * Extended control and interrupt 1 (CSR5) + */ +#define PCN_EXTCTL1_SPND 0x0001 /* suspend */ +#define PCN_EXTCTL1_MPMODE 0x0002 /* magic packet mode */ +#define PCN_EXTCTL1_MPENB 0x0004 /* magic packet enable */ +#define PCN_EXTCTL1_MPINTEN 0x0008 /* magic packet interrupt enable */ +#define PCN_EXTCTL1_MPINT 0x0010 /* magic packet interrupt */ +#define PCN_EXTCTL1_MPPLBA 0x0020 /* magic packet phys. logical bcast */ +#define PCN_EXTCTL1_EXDEFEN 0x0040 /* excessive deferral interrupt enb. */ +#define PCN_EXTCTL1_EXDEF 0x0080 /* excessive deferral interrupt */ +#define PCN_EXTCTL1_SINTEN 0x0400 /* system interrupt enable */ +#define PCN_EXTCTL1_SINT 0x0800 /* system interrupt */ +#define PCN_EXTCTL1_LTINTEN 0x4000 /* last TX interrupt enb */ +#define PCN_EXTCTL1_TXOKINTD 0x8000 /* TX OK interrupt disable */ + +/* + * RX/TX descriptor len (CSR6) + */ +#define PCN_DTBLLEN_RLEN 0x0F00 +#define PCN_DTBLLEN_TLEN 0xF000 + +/* + * Extended control and interrupt 2 (CSR7) + */ +#define PCN_EXTCTL2_MIIPDTINTE 0x0001 +#define PCN_EXTCTL2_MIIPDTINT 0x0002 +#define PCN_EXTCTL2_MCCIINTE 0x0004 +#define PCN_EXTCTL2_MCCIINT 0x0008 +#define PCN_EXTCTL2_MCCINTE 0x0010 +#define PCN_EXTCTL2_MCCINT 0x0020 +#define PCN_EXTCTL2_MAPINTE 0x0040 +#define PCN_EXTCTL2_MAPINT 0x0080 +#define PCN_EXTCTL2_MREINTE 0x0100 +#define PCN_EXTCTL2_MREINT 0x0200 +#define PCN_EXTCTL2_STINTE 0x0400 +#define PCN_EXTCTL2_STINT 0x0800 +#define PCN_EXTCTL2_RXDPOLL 0x1000 +#define PCN_EXTCTL2_RDMD 0x2000 +#define PCN_EXTCTL2_RXFRTG 0x4000 +#define PCN_EXTCTL2_FASTSPNDE 0x8000 + + +/* + * Mode (CSR15) + */ +#define PCN_MODE_RXD 0x0001 /* RX disable */ +#define PCN_MODE_TXD 0x0002 /* TX disable */ +#define PCN_MODE_LOOP 0x0004 /* loopback enable */ +#define PCN_MODE_TXCRCD 0x0008 +#define PCN_MODE_FORCECOLL 0x0010 +#define PCN_MODE_RETRYD 0x0020 +#define PCN_MODE_INTLOOP 0x0040 +#define PCN_MODE_PORTSEL 0x0180 +#define PCN_MODE_RXVPAD 0x2000 +#define PCN_MODE_RXNOBROAD 0x4000 +#define PCN_MODE_PROMISC 0x8000 + +/* Settings for PCN_MODE_PORTSEL when ASEL (BCR2[1]) is 0 */ +#define PCN_PORT_AUI 0x0000 +#define PCN_PORT_10BASET 0x0080 +#define PCN_PORT_GPSI 0x0100 +#define PCN_PORT_MII 0x0180 + +/* + * Chip ID values. + */ +/* CSR88-89: Chip ID masks */ +#define AMD_MASK 0x003 +#define PART_MASK 0xffff +#define Am79C971 0x2623 +#define Am79C972 0x2624 +#define Am79C973 0x2625 +#define Am79C978 0x2626 +#define Am79C975 0x2627 +#define Am79C976 0x2628 + +/* + * Advanced feature control (CSR122) + */ +#define PCN_AFC_RXALIGN 0x0001 + +/* + * BCR (bus control) registers + */ +#define PCN_BCR_MMRA 0x00 /* Master Mode Read Active */ +#define PCN_BCR_MMW 0x01 /* Master Mode Write Active */ +#define PCN_BCR_MISCCFG 0x02 +#define PCN_BCR_LED0 0x04 +#define PCN_BCR_LED1 0x05 +#define PCN_BCR_LED2 0x06 +#define PCN_BCR_LED3 0x07 +#define PCN_BCR_DUPLEX 0x09 +#define PCN_BCR_BUSCTL 0x12 +#define PCN_BCR_EECTL 0x13 +#define PCN_BCR_SSTYLE 0x14 +#define PCN_BCR_PCILAT 0x16 +#define PCN_BCR_PCISUBVENID 0x17 +#define PCN_BCR_PCISUBSYSID 0x18 +#define PCN_BCR_SRAMSIZE 0x19 +#define PCN_BCR_SRAMBOUND 0x1A +#define PCN_BCR_SRAMCTL 0x1B +#define PCN_BCR_MIICTL 0x20 +#define PCN_BCR_MIIADDR 0x21 +#define PCN_BCR_MIIDATA 0x22 +#define PCN_BCR_PCIVENID 0x23 +#define PCN_BCR_PCIPCAP 0x24 +#define PCN_BCR_DATA0 0x25 +#define PCN_BCR_DATA1 0x26 +#define PCN_BCR_DATA2 0x27 +#define PCN_BCR_DATA3 0x28 +#define PCN_BCR_DATA4 0x29 +#define PCN_BCR_DATA5 0x2A +#define PCN_BCR_DATA6 0x2B +#define PCN_BCR_DATA7 0x2C +#define PCN_BCR_ONNOWPAT0 0x2D +#define PCN_BCR_ONNOWPAT1 0x2E +#define PCN_BCR_ONNOWPAT2 0x2F +#define PCN_BCR_PHYSEL 0x31 + +/* + * Miscellaneous Configuration (BCR2) + */ +#define PCN_MISC_TMAULOOP 1<<14 /* T-MAU Loopback packet enable. */ +#define PCN_MISC_LEDPE 1<<12 /* LED Program Enable */ +#define PCN_MISC_APROMWE 1<<8 /* Address PROM Write Enable */ +#define PCN_MISC_INTLEVEL 1<<7 /* Interrupt level */ +#define PCN_MISC_EADISEL 1<<3 /* EADI Select */ +#define PCN_MISC_AWAKE 1<<2 /* Power saving mode select */ +#define PCN_MISC_ASEL 1<<1 /* Auto Select */ +#define PCN_MISC_XMAUSEL 1<<0 /* Reserved. */ + +/* + * Full duplex control (BCR9) + */ +#define PCN_DUPLEX_FDEN 0x0001 /* Full-duplex enable */ +#define PCN_DUPLEX_AUI 0x0002 /* AUI full-duplex */ +#define PCN_DUPLEX_FDRPAD 0x0004 /* Full-duplex runt pkt accept dis. */ + +/* + * Burst and bus control register (BCR18) + */ +#define PCN_BUSCTL_BWRITE 0x0020 +#define PCN_BUSCTL_BREAD 0x0040 +#define PCN_BUSCTL_DWIO 0x0080 +#define PCN_BUSCTL_EXTREQ 0x0100 +#define PCN_BUSCTL_MEMCMD 0x0200 +#define PCN_BUSCTL_NOUFLOW 0x0800 +#define PCN_BUSCTL_ROMTMG 0xF000 + +/* + * EEPROM control (BCR19) + */ +#define PCN_EECTL_EDATA 0x0001 +#define PCN_EECTL_ECLK 0x0002 +#define PCN_EECTL_EECS 0x0004 +#define PCN_EECTL_EEN 0x0100 +#define PCN_EECTL_EEDET 0x2000 +#define PCN_EECTL_PREAD 0x4000 +#define PCN_EECTL_PVALID 0x8000 + +/* + * Software style (BCR20) + */ +#define PCN_SSTYLE_APERREN 0x0400 /* advanced parity error checking */ +#define PCN_SSTYLE_SSIZE32 0x0100 +#define PCN_SSTYLE_SWSTYLE 0x00FF + +#define PCN_SWSTYLE_LANCE 0x0000 +#define PCN_SWSTYLE_PCNETPCI 0x0102 +#define PCN_SWSTYLE_PCNETPCI_BURST 0x0103 + +/* + * MII control and status (BCR32) + */ +#define PCN_MIICTL_MIILP 0x0002 /* MII internal loopback */ +#define PCN_MIICTL_XPHYSP 0x0008 /* external PHY speed */ +#define PCN_MIICTL_XPHYFD 0x0010 /* external PHY full duplex */ +#define PCN_MIICTL_XPHYANE 0x0020 /* external phy auto-neg enable */ +#define PCN_MIICTL_XPHYRST 0x0040 /* external PHY reset */ +#define PCN_MIICTL_DANAS 0x0080 /* disable auto-neg auto-setup */ +#define PCN_MIICTL_APDW 0x0700 /* auto-poll dwell time */ +#define PCN_MIICTL_APEP 0x0100 /* auto-poll external PHY */ +#define PCN_MIICTL_FMDC 0x3000 /* data clock speed */ +#define PCN_MIICTL_MIIPD 0x4000 /* PHY detect */ +#define PCN_MIICTL_ANTST 0x8000 /* Manufacturing test */ + +/* + * MII address register (BCR33) + */ +#define PCN_MIIADDR_REGAD 0x001F +#define PCN_MIIADDR_PHYAD 0x03E0 + +/* addresses of internal PHYs */ +#define PCN_PHYAD_100BTX 30 +#define PCN_PHYAD_10BT 31 + +/* + * MII data register (BCR34) + */ +#define PCN_MIIDATA_MIIMD 0xFFFF + +/* + * PHY selection (BCR49) (HomePNA NIC only) + */ +#define PCN_PHYSEL_PHYSEL 0x0003 +#define PCN_PHYSEL_DEFAULT 0x0300 +#define PCN_PHYSEL_PCNET 0x8000 + +#define PCN_PHY_10BT 0x0000 +#define PCN_PHY_HOMEPNA 0x0001 +#define PCN_PHY_EXTERNAL 0x0002 + +struct pcn_rx_desc { + u_int16_t pcn_rxlen; + u_int16_t pcn_rsvd0; + u_int16_t pcn_bufsz; + u_int16_t pcn_rxstat; + u_int32_t pcn_rbaddr; + u_int32_t pcn_uspace; +}; + +#define PCN_RXSTAT_BPE 0x0080 /* bus parity error */ +#define PCN_RXSTAT_ENP 0x0100 /* end of packet */ +#define PCN_RXSTAT_STP 0x0200 /* start of packet */ +#define PCN_RXSTAT_BUFF 0x0400 /* buffer error */ +#define PCN_RXSTAT_CRC 0x0800 /* CRC error */ +#define PCN_RXSTAT_OFLOW 0x1000 /* rx overrun */ +#define PCN_RXSTAT_FRAM 0x2000 /* framing error */ +#define PCN_RXSTAT_ERR 0x4000 /* error summary */ +#define PCN_RXSTAT_OWN 0x8000 + +#define PCN_RXLEN_MBO 0xF000 +#define PCN_RXLEN_BUFSZ 0x0FFF + +#define PCN_OWN_RXDESC(x) (((x)->pcn_rxstat & PCN_RXSTAT_OWN) == 0) + +struct pcn_tx_desc { + u_int32_t pcn_txstat; + u_int32_t pcn_txctl; + u_int32_t pcn_tbaddr; + u_int32_t pcn_uspace; +}; + +#define PCN_TXSTAT_TRC 0x0000000F /* transmit retries */ +#define PCN_TXSTAT_RTRY 0x04000000 /* retry */ +#define PCN_TXSTAT_LCAR 0x08000000 /* lost carrier */ +#define PCN_TXSTAT_LCOL 0x10000000 /* late collision */ +#define PCN_TXSTAT_EXDEF 0x20000000 /* excessive deferrals */ +#define PCN_TXSTAT_UFLOW 0x40000000 /* transmit underrun */ +#define PCN_TXSTAT_BUFF 0x80000000 /* buffer error */ + +#define PCN_TXCTL_OWN 0x80000000 +#define PCN_TXCTL_ERR 0x40000000 /* error summary */ +#define PCN_TXCTL_ADD_FCS 0x20000000 /* add FCS to pkt */ +#define PCN_TXCTL_MORE_LTINT 0x10000000 +#define PCN_TXCTL_ONE 0x08000000 +#define PCN_TXCTL_DEF 0x04000000 +#define PCN_TXCTL_STP 0x02000000 +#define PCN_TXCTL_ENP 0x01000000 +#define PCN_TXCTL_BPE 0x00800000 +#define PCN_TXCTL_MBO 0x0000F000 +#define PCN_TXCTL_BUFSZ 0x00000FFF + +#define PCN_OWN_TXDESC(x) (((x)->pcn_txctl & PCN_TXCTL_OWN) == 0) + +#define PCN_RX_LIST_CNT 64 +#define PCN_TX_LIST_CNT 256 + +struct pcn_list_data { + struct pcn_rx_desc pcn_rx_list[PCN_RX_LIST_CNT]; + struct pcn_tx_desc pcn_tx_list[PCN_TX_LIST_CNT]; +}; + +struct pcn_ring_data { + struct mbuf *pcn_rx_chain[PCN_RX_LIST_CNT]; + struct mbuf *pcn_tx_chain[PCN_TX_LIST_CNT]; + int pcn_rx_prod; + int pcn_tx_prod; + int pcn_tx_cons; + int pcn_tx_cnt; +}; + +/* + * AMD PCI vendor ID. + */ +#define PCN_VENDORID 0x1022 + +/* + * AMD PCnet/PCI device IDs + */ +#define PCN_DEVICEID_PCNET 0x2000 +#define PCN_DEVICEID_HOME 0x2001 + +struct pcn_type { + u_int16_t pcn_vid; + u_int16_t pcn_did; + const char *pcn_name; +}; + +struct pcn_softc { + struct ifnet *pcn_ifp; + bus_space_handle_t pcn_bhandle; + bus_space_tag_t pcn_btag; + struct resource *pcn_res; + struct resource *pcn_irq; + void *pcn_intrhand; + device_t pcn_miibus; + u_int8_t pcn_link; + int8_t pcn_extphyaddr; + int8_t pcn_inst_10bt; + int pcn_if_flags; + int pcn_type; + struct pcn_list_data *pcn_ldata; + struct pcn_ring_data pcn_cdata; + struct callout pcn_stat_callout; + struct mtx pcn_mtx; + int pcn_timer; +}; + +#define PCN_LOCK(_sc) mtx_lock(&(_sc)->pcn_mtx) +#define PCN_UNLOCK(_sc) mtx_unlock(&(_sc)->pcn_mtx) +#define PCN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->pcn_mtx, MA_OWNED) + +/* + * register space access macros + */ +#define CSR_WRITE_4(sc, reg, val) \ + bus_space_write_4(sc->pcn_btag, sc->pcn_bhandle, reg, val) + +#define CSR_READ_4(sc, reg) \ + bus_space_read_4(sc->pcn_btag, sc->pcn_bhandle, reg) + +#define CSR_WRITE_2(sc, reg, val) \ + bus_space_write_2(sc->pcn_btag, sc->pcn_bhandle, reg, val) + +#define CSR_READ_2(sc, reg) \ + bus_space_read_2(sc->pcn_btag, sc->pcn_bhandle, reg) + +#define PCN_TIMEOUT 1000 +#define ETHER_ALIGN 2 +#define PCN_RXLEN 1536 +#define PCN_MIN_FRAMELEN 60 +#define PCN_INC(x, y) (x) = (x + 1) % y +/* + * PCI low memory base and low I/O base register, and + * other PCI registers. + */ + +#define PCN_PCI_VENDOR_ID 0x00 +#define PCN_PCI_DEVICE_ID 0x02 +#define PCN_PCI_COMMAND 0x04 +#define PCN_PCI_STATUS 0x06 +#define PCN_PCI_REVID 0x08 +#define PCN_PCI_CLASSCODE 0x09 +#define PCN_PCI_CACHELEN 0x0C +#define PCN_PCI_LATENCY_TIMER 0x0D +#define PCN_PCI_HEADER_TYPE 0x0E +#define PCN_PCI_LOIO 0x10 +#define PCN_PCI_LOMEM 0x14 +#define PCN_PCI_BIOSROM 0x30 +#define PCN_PCI_INTLINE 0x3C +#define PCN_PCI_INTPIN 0x3D +#define PCN_PCI_MINGNT 0x3E +#define PCN_PCI_MINLAT 0x3F +#define PCN_PCI_RESETOPT 0x48 +#define PCN_PCI_EEPROM_DATA 0x4C + +/* power management registers */ +#define PCN_PCI_CAPID 0x50 /* 8 bits */ +#define PCN_PCI_NEXTPTR 0x51 /* 8 bits */ +#define PCN_PCI_PWRMGMTCAP 0x52 /* 16 bits */ +#define PCN_PCI_PWRMGMTCTRL 0x54 /* 16 bits */ + +#define PCN_PSTATE_MASK 0x0003 +#define PCN_PSTATE_D0 0x0000 +#define PCN_PSTATE_D1 0x0001 +#define PCN_PSTATE_D2 0x0002 +#define PCN_PSTATE_D3 0x0003 +#define PCN_PME_EN 0x0010 +#define PCN_PME_STATUS 0x8000 diff --git a/src/libs/compat/freebsd_network/compat/dev/mii/miidevs b/src/libs/compat/freebsd_network/compat/dev/mii/miidevs index 5629290c961..24662f9f5ed 100644 --- a/src/libs/compat/freebsd_network/compat/dev/mii/miidevs +++ b/src/libs/compat/freebsd_network/compat/dev/mii/miidevs @@ -178,7 +178,7 @@ model BROADCOM2 BCM5722 0x002d BCM5722 1000BASE-T media interface model BROADCOM2 BCM5784 0x003a BCM5784 10/100/1000baseT PHY model BROADCOM2 BCM5709C 0x003c BCM5709 10/100/1000baseT PHY model BROADCOM2 BCM5761 0x003d BCM5761 10/100/1000baseT PHY -model BROADCOM2 BCM5709S 0x003f BCM5709S 1000/2500baseSX PHY +model BROADCOM2 BCM5709S 0x003f BCM5709S/5720S 1000/2500baseSX PHY model BROADCOM3 BCM57780 0x0019 BCM57780 1000BASE-T media interface model BROADCOM3 BCM5717C 0x0020 BCM5717C 1000BASE-T media interface model BROADCOM3 BCM5719C 0x0022 BCM5719C 1000BASE-T media interface