From 3d2b95309cab2374c3d5fa05c1f1814f782a0ab2 Mon Sep 17 00:00:00 2001 From: Sascha Wildner Date: Sat, 15 Nov 2014 17:50:05 +0100 Subject: [PATCH 1/1] kernel/usb4bsd: Bring in the axge(4) ethernet driver. It supports USB Gigabit Ethernet adapters based on the ASIX Electronics AX88179 USB 3.0 and AX88178A USB 2.0 chipsets. Taken-from: FreeBSD --- etc/devd/usb.conf | 46 +- share/man/man4/Makefile | 2 + share/man/man4/axge.4 | 152 +++++ share/man/man4/miibus.4 | 3 + share/man/man4/usb.4 | 6 +- sys/bus/u4b/net/Makefile | 4 +- sys/bus/u4b/net/axge/Makefile | 10 + sys/bus/u4b/net/if_axge.c | 1036 +++++++++++++++++++++++++++++++++ sys/bus/u4b/net/if_axgereg.h | 173 ++++++ sys/bus/u4b/usbdevs | 2 + sys/conf/files | 1 + sys/config/LINT | 3 + sys/config/LINT64 | 3 + 13 files changed, 1434 insertions(+), 7 deletions(-) create mode 100644 share/man/man4/axge.4 create mode 100644 sys/bus/u4b/net/axge/Makefile create mode 100644 sys/bus/u4b/net/if_axge.c create mode 100644 sys/bus/u4b/net/if_axgereg.h diff --git a/etc/devd/usb.conf b/etc/devd/usb.conf index bad52da8c1..0f69cd1fa1 100644 --- a/etc/devd/usb.conf +++ b/etc/devd/usb.conf @@ -1599,7 +1599,23 @@ nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; match "vendor" "0x0b95"; - match "product" "(0x1720|0x1780|0x7720|0x772a|0x772b|0x7e2b)"; + match "product" "(0x1720|0x1780)"; + action "kldload -n if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b95"; + match "product" "(0x178a|0x1790)"; + action "kldload -n if_axge"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b95"; + match "product" "(0x7720|0x772a|0x772b|0x7e2b)"; action "kldload -n if_axe"; }; @@ -1763,6 +1779,14 @@ nomatch 32 { action "kldload -n if_urtwn"; }; +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0df6"; + match "product" "0x0072"; + action "kldload -n if_axge"; +}; + nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; @@ -2895,7 +2919,23 @@ nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; match "vendor" "0x2001"; - match "product" "(0x4001|0x4002|0x4003|0x400b|0x4102|0xabc1)"; + match "product" "(0x4001|0x4002|0x4003|0x400b|0x4102)"; + action "kldload -n if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2001"; + match "product" "0x4a00"; + action "kldload -n if_axge"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2001"; + match "product" "0xabc1"; action "kldload -n if_aue"; }; @@ -3383,5 +3423,5 @@ nomatch 32 { action "kldload -n umass"; }; -# 1531 USB entries processed +# 1535 USB entries processed diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index a3a56f47e3..49325a5622 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -46,6 +46,7 @@ MAN= aac.4 \ atkbdc.4 \ aue.4 \ axe.4 \ + axge.4 \ bce.4 \ bfe.4 \ bge.4 \ @@ -419,6 +420,7 @@ MLINKS+=an.4 if_an.4 MLINKS+=ath.4 if_ath.4 MLINKS+=aue.4 if_aue.4 MLINKS+=axe.4 if_axe.4 +MLINKS+=axge.4 if_axge.4 MLINKS+=bce.4 if_bce.4 MLINKS+=bfe.4 if_bfe.4 MLINKS+=bge.4 if_bge.4 diff --git a/share/man/man4/axge.4 b/share/man/man4/axge.4 new file mode 100644 index 0000000000..78b370f6a7 --- /dev/null +++ b/share/man/man4/axge.4 @@ -0,0 +1,152 @@ +.\" Copyright (c) 1997, 1998, 1999, 2000-2003 +.\" 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: head/share/man/man4/axge.4 267938 2014-06-26 21:46:14Z bapt $ +.\" +.Dd November 15, 2014 +.Dt AXGE 4 +.Os +.Sh NAME +.Nm axge +.Nd "ASIX Electronics AX88178A/AX88179 USB Gigabit Ethernet driver" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device xhci" +.Cd "device ehci" +.Cd "device uhci" +.Cd "device ohci" +.Cd "device usb" +.Cd "device miibus" +.Cd "device axge" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +if_axge_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for USB Gigabit Ethernet adapters based on the ASIX +Electronics AX88179 USB 3.0 and AX88178A USB 2.0 chipsets. +.Pp +The AX88179 and AX88178A contain a 10/100/1000 Ethernet MAC with a GMII +interface for interfacing with the Gigabit Ethernet PHY. +.Pp +These devices will operate with both USB 1.x and USB 2.0 controllers, and the +AX88179 will operate with USB 3.0 controllers. +Packets are received and transmitted over separate USB bulk transfer endpoints. +.Pp +The +.Nm +driver supports the following media types: +.Bl -tag -width ".Cm 10baseT/UTP" +.It Cm autoselect +Enable autoselection of the media type and options. +The user can manually override +the autoselected mode by adding media options to +.Xr rc.conf 5 . +.It Cm 10baseT/UTP +Set 10Mbps operation. +The +.Xr ifconfig 8 +.Cm mediaopt +option can also be used to select either +.Cm full-duplex +or +.Cm half-duplex +modes. +.It Cm 100baseTX +Set 100Mbps (Fast Ethernet) operation. +The +.Xr ifconfig 8 +.Cm mediaopt +option can also be used to select either +.Cm full-duplex +or +.Cm half-duplex +modes. +.It Cm 1000baseT +Set 1000Mbps (Gigabit Ethernet) operation (AX88178 only). +The +.Xr ifconfig 8 +.Cm mediaopt +option can also be used to select either +.Cm full-duplex +or +.Cm half-duplex +modes. +.El +.Pp +The +.Nm +driver supports the following media options: +.Bl -tag -width ".Cm full-duplex" +.It Cm full-duplex +Force full duplex operation. +.It Cm half-duplex +Force half duplex operation. +.El +.Pp +For more information on configuring this device, see +.Xr ifconfig 8 . +.Sh SEE ALSO +.Xr altq 4 , +.Xr arp 4 , +.Xr ifmedia 4 , +.Xr miibus 4 , +.Xr netintro 4 , +.Xr ng_ether 4 , +.Xr rgephy 4 , +.Xr vlan 4 , +.Xr ifconfig 8 +.Sh HISTORY +The +.Nm +device driver first appeared in +.Fx 10.1 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Kevin Lo Aq Mt kevlo@FreeBSD.org +and +.An Li-Wen Hsu Aq Mt lwhsu@FreeBSD.org . +This manual page was adapted by +.An Mark Johnston Aq Mt markj@FreeBSD.org +from the +.Xr axe 4 +manual page. diff --git a/share/man/man4/miibus.4 b/share/man/man4/miibus.4 index 085454fe82..c7755902f3 100644 --- a/share/man/man4/miibus.4 +++ b/share/man/man4/miibus.4 @@ -59,6 +59,8 @@ Atheros AR8121/AR8113/AR8114 Gigabit/Fast Ethernet ADMtek USB Ethernet .It Xr axe 4 ASIX Electronics AX88172 USB Ethernet +.It Xr axge 4 +ASIX Electronics AX88178A/AX88179 USB Gigabit Ethernet .It Xr bce 4 Broadcom BCM5706/BCM5708 Gigabit Ethernet .It Xr bfe 4 @@ -135,6 +137,7 @@ but as a result are not well behaved newbus device drivers. .Xr arp 4 , .Xr aue 4 , .Xr axe 4 , +.Xr axge 4 , .Xr bce 4 , .Xr bfe 4 , .Xr bge 4 , diff --git a/share/man/man4/usb.4 b/share/man/man4/usb.4 index 1667bb017e..ec1ab2164a 100644 --- a/share/man/man4/usb.4 +++ b/share/man/man4/usb.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD: head/share/man/man4/usb.4 258618 2013-11-26 07:52:40Z lwhsu $ .\" -.Dd November 10, 2014 +.Dd November 15, 2014 .Dt USB 4 .Os .Sh NAME @@ -98,6 +98,8 @@ Mass storage driver for device-side mode ADMtek AN986 Pegasus Ethernet driver .It Xr axe 4 ASIX Electronics AX88x7x/760 USB Ethernet driver +.It Xr axge 4 +ASIX Electronics AX88178A/AX88179 USB Gigabit Ethernet driver .It Xr cue 4 CATC USB-EL1210A Ethernet driver .It Xr ipheth 4 @@ -271,7 +273,7 @@ specifications can be found at: .Xr libusb 3 , .Xr aue 4 , .Xr axe 4 , -.\".Xr axge 4 , +.Xr axge 4 , .Xr cue 4 , .Xr ehci 4 , .Xr ipheth 4 , diff --git a/sys/bus/u4b/net/Makefile b/sys/bus/u4b/net/Makefile index d9dc7626bf..a13690d28a 100644 --- a/sys/bus/u4b/net/Makefile +++ b/sys/bus/u4b/net/Makefile @@ -1,6 +1,6 @@ # -# XXX MISSING: axge cdce rue smsc uhso usie +# XXX MISSING: cdce rue smsc uhso usie -SUBDIR= aue axe cue ipheth kue mos udav uether urndis +SUBDIR= aue axe axge cue ipheth kue mos udav uether urndis .include diff --git a/sys/bus/u4b/net/axge/Makefile b/sys/bus/u4b/net/axge/Makefile new file mode 100644 index 0000000000..83c46ddf8b --- /dev/null +++ b/sys/bus/u4b/net/axge/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD: head/sys/modules/usb/axge/Makefile 258331 2013-11-19 00:37:53Z markj $ + +.PATH: ${.CURDIR}/.. + +KMOD= if_axge +SRCS+= if_axge.c usbdevs.h +SRCS+= bus_if.h device_if.h miibus_if.h usb_if.h \ + opt_bus.h opt_inet.h opt_usb.h + +.include diff --git a/sys/bus/u4b/net/if_axge.c b/sys/bus/u4b/net/if_axge.c new file mode 100644 index 0000000000..90f244fea3 --- /dev/null +++ b/sys/bus/u4b/net/if_axge.c @@ -0,0 +1,1036 @@ +/*- + * Copyright (c) 2013-2014 Kevin Lo + * 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 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 AUTHOR 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: head/sys/dev/usb/net/if_axge.c 271832 2014-09-18 21:09:22Z glebius $ + */ + +/* + * ASIX Electronics AX88178A/AX88179 USB 2.0/3.0 gigabit ethernet driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include "usbdevs.h" + +#define USB_DEBUG_VAR axge_debug +#include +#include + +#include +#include + +/* + * Various supported device vendors/products. + */ + +static const STRUCT_USB_HOST_ID axge_devs[] = { +#define AXGE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } + AXGE_DEV(ASIX, AX88178A), + AXGE_DEV(ASIX, AX88179), + AXGE_DEV(DLINK, DUB1312), + AXGE_DEV(SITECOMEU, LN032), +#undef AXGE_DEV +}; + +static const struct { + uint8_t ctrl; + uint8_t timer_l; + uint8_t timer_h; + uint8_t size; + uint8_t ifg; +} __packed axge_bulk_size[] = { + { 7, 0x4f, 0x00, 0x12, 0xff }, + { 7, 0x20, 0x03, 0x16, 0xff }, + { 7, 0xae, 0x07, 0x18, 0xff }, + { 7, 0xcc, 0x4c, 0x18, 0x08 } +}; + +/* prototypes */ + +static device_probe_t axge_probe; +static device_attach_t axge_attach; +static device_detach_t axge_detach; + +static usb_callback_t axge_bulk_read_callback; +static usb_callback_t axge_bulk_write_callback; + +static miibus_readreg_t axge_miibus_readreg; +static miibus_writereg_t axge_miibus_writereg; +static miibus_statchg_t axge_miibus_statchg; + +static uether_fn_t axge_attach_post; +static uether_fn_t axge_init; +static uether_fn_t axge_stop; +static uether_fn_t axge_start; +static uether_fn_t axge_tick; +static uether_fn_t axge_setmulti; +static uether_fn_t axge_setpromisc; + +static int axge_read_mem(struct axge_softc *, uint8_t, uint16_t, + uint16_t, void *, int); +static void axge_write_mem(struct axge_softc *, uint8_t, uint16_t, + uint16_t, void *, int); +static uint8_t axge_read_cmd_1(struct axge_softc *, uint8_t, uint16_t); +static uint16_t axge_read_cmd_2(struct axge_softc *, uint8_t, uint16_t, + uint16_t); +static void axge_write_cmd_1(struct axge_softc *, uint8_t, uint16_t, + uint8_t); +static void axge_write_cmd_2(struct axge_softc *, uint8_t, uint16_t, + uint16_t, uint16_t); +static void axge_chip_init(struct axge_softc *); +static void axge_reset(struct axge_softc *); + +static int axge_attach_post_sub(struct usb_ether *); +static int axge_ifmedia_upd(struct ifnet *); +static void axge_ifmedia_sts(struct ifnet *, struct ifmediareq *); +static int axge_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); +static void axge_rx_frame(struct usb_ether *, struct usb_page_cache *, int); +static void axge_rxeof(struct usb_ether *, struct usb_page_cache *, + unsigned int, unsigned int, uint32_t); +static void axge_csum_cfg(struct usb_ether *); + +#define AXGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) + +#ifdef USB_DEBUG +static int axge_debug = 0; + +static SYSCTL_NODE(_hw_usb, OID_AUTO, axge, CTLFLAG_RW, 0, "USB axge"); +SYSCTL_INT(_hw_usb_axge, OID_AUTO, debug, CTLFLAG_RW, &axge_debug, 0, + "Debug level"); +#endif + +static const struct usb_config axge_config[AXGE_N_TRANSFER] = { + [AXGE_BULK_DT_WR] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .frames = 16, + .bufsize = 16 * MCLBYTES, + .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, + .callback = axge_bulk_write_callback, + .timeout = 10000, /* 10 seconds */ + }, + [AXGE_BULK_DT_RD] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .bufsize = 65536, + .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, + .callback = axge_bulk_read_callback, + .timeout = 0, /* no timeout */ + }, +}; + +static device_method_t axge_methods[] = { + /* Device interface. */ + DEVMETHOD(device_probe, axge_probe), + DEVMETHOD(device_attach, axge_attach), + DEVMETHOD(device_detach, axge_detach), + + /* MII interface. */ + DEVMETHOD(miibus_readreg, axge_miibus_readreg), + DEVMETHOD(miibus_writereg, axge_miibus_writereg), + DEVMETHOD(miibus_statchg, axge_miibus_statchg), + + DEVMETHOD_END +}; + +static driver_t axge_driver = { + .name = "axge", + .methods = axge_methods, + .size = sizeof(struct axge_softc), +}; + +static devclass_t axge_devclass; + +DRIVER_MODULE(axge, uhub, axge_driver, axge_devclass, NULL, NULL); +DRIVER_MODULE(miibus, axge, miibus_driver, miibus_devclass, NULL, NULL); +MODULE_DEPEND(axge, uether, 1, 1, 1); +MODULE_DEPEND(axge, usb, 1, 1, 1); +MODULE_DEPEND(axge, ether, 1, 1, 1); +MODULE_DEPEND(axge, miibus, 1, 1, 1); +MODULE_VERSION(axge, 1); + +static const struct usb_ether_methods axge_ue_methods = { + .ue_attach_post = axge_attach_post, + .ue_attach_post_sub = axge_attach_post_sub, + .ue_start = axge_start, + .ue_init = axge_init, + .ue_stop = axge_stop, + .ue_tick = axge_tick, + .ue_setmulti = axge_setmulti, + .ue_setpromisc = axge_setpromisc, + .ue_mii_upd = axge_ifmedia_upd, + .ue_mii_sts = axge_ifmedia_sts, +}; + +static int +axge_read_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index, + uint16_t val, void *buf, int len) +{ + struct usb_device_request req; + + AXGE_LOCK_ASSERT(sc); + + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = cmd; + USETW(req.wValue, val); + USETW(req.wIndex, index); + USETW(req.wLength, len); + + return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); +} + +static void +axge_write_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index, + uint16_t val, void *buf, int len) +{ + struct usb_device_request req; + + AXGE_LOCK_ASSERT(sc); + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = cmd; + USETW(req.wValue, val); + USETW(req.wIndex, index); + USETW(req.wLength, len); + + if (uether_do_request(&sc->sc_ue, &req, buf, 1000)) { + /* Error ignored. */ + } +} + +static uint8_t +axge_read_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg) +{ + uint8_t val; + + axge_read_mem(sc, cmd, 1, reg, &val, 1); + return (val); +} + +static uint16_t +axge_read_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index, + uint16_t reg) +{ + uint8_t val[2]; + + axge_read_mem(sc, cmd, index, reg, &val, 2); + return (UGETW(val)); +} + +static void +axge_write_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg, uint8_t val) +{ + axge_write_mem(sc, cmd, 1, reg, &val, 1); +} + +static void +axge_write_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index, + uint16_t reg, uint16_t val) +{ + uint8_t temp[2]; + + USETW(temp, val); + axge_write_mem(sc, cmd, index, reg, &temp, 2); +} + +static int +axge_miibus_readreg(device_t dev, int phy, int reg) +{ + struct axge_softc *sc; + uint16_t val; + int locked; + + sc = device_get_softc(dev); + locked = lockowned(&sc->sc_lock); + if (!locked) + AXGE_LOCK(sc); + + val = axge_read_cmd_2(sc, AXGE_ACCESS_PHY, reg, phy); + + if (!locked) + AXGE_UNLOCK(sc); + + return (val); +} + +static int +axge_miibus_writereg(device_t dev, int phy, int reg, int val) +{ + struct axge_softc *sc; + int locked; + + sc = device_get_softc(dev); + if (sc->sc_phyno != phy) + return (0); + locked = lockowned(&sc->sc_lock); + if (!locked) + AXGE_LOCK(sc); + + axge_write_cmd_2(sc, AXGE_ACCESS_PHY, reg, phy, val); + + if (!locked) + AXGE_UNLOCK(sc); + + return (0); +} + +static void +axge_miibus_statchg(device_t dev) +{ + struct axge_softc *sc; + struct mii_data *mii; + struct ifnet *ifp; + uint8_t link_status, tmp[5]; + uint16_t val; + int locked; + + sc = device_get_softc(dev); + mii = GET_MII(sc); + locked = lockowned(&sc->sc_lock); + if (!locked) + AXGE_LOCK(sc); + + ifp = uether_getifp(&sc->sc_ue); + if (mii == NULL || ifp == NULL || + (ifp->if_flags & IFF_RUNNING) == 0) + goto done; + + sc->sc_flags &= ~AXGE_FLAG_LINK; + if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: + case IFM_100_TX: + case IFM_1000_T: + sc->sc_flags |= AXGE_FLAG_LINK; + break; + default: + break; + } + } + + /* Lost link, do nothing. */ + if ((sc->sc_flags & AXGE_FLAG_LINK) == 0) + goto done; + + link_status = axge_read_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PLSR); + + val = 0; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { + val |= MSR_FD; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) + val |= MSR_TFC; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) + val |= MSR_RFC; + } + val |= MSR_RE; + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_1000_T: + val |= MSR_GM | MSR_EN_125MHZ; + if (link_status & PLSR_USB_SS) + memcpy(tmp, &axge_bulk_size[0], 5); + else if (link_status & PLSR_USB_HS) + memcpy(tmp, &axge_bulk_size[1], 5); + else + memcpy(tmp, &axge_bulk_size[3], 5); + break; + case IFM_100_TX: + val |= MSR_PS; + if (link_status & (PLSR_USB_SS | PLSR_USB_HS)) + memcpy(tmp, &axge_bulk_size[2], 5); + else + memcpy(tmp, &axge_bulk_size[3], 5); + break; + case IFM_10_T: + memcpy(tmp, &axge_bulk_size[3], 5); + break; + } + /* Rx bulk configuration. */ + axge_write_mem(sc, AXGE_ACCESS_MAC, 5, AXGE_RX_BULKIN_QCTRL, tmp, 5); + axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_MSR, val); +done: + if (!locked) + AXGE_UNLOCK(sc); +} + +static void +axge_chip_init(struct axge_softc *sc) +{ + /* Power up ethernet PHY. */ + axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, 0); + axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, EPPRCR_IPRL); + uether_pause(&sc->sc_ue, hz / 4); + axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CLK_SELECT, + AXGE_CLK_SELECT_ACS | AXGE_CLK_SELECT_BCS); + uether_pause(&sc->sc_ue, hz / 10); +} + +static void +axge_reset(struct axge_softc *sc) +{ + struct usb_config_descriptor *cd; + usb_error_t err; + + cd = usbd_get_config_descriptor(sc->sc_ue.ue_udev); + + err = usbd_req_set_config(sc->sc_ue.ue_udev, &sc->sc_lock, + cd->bConfigurationValue); + if (err) + DPRINTF("reset failed (ignored)\n"); + + /* Wait a little while for the chip to get its brains in order. */ + uether_pause(&sc->sc_ue, hz / 100); + + /* Reinitialize controller to achieve full reset. */ + axge_chip_init(sc); +} + +static void +axge_attach_post(struct usb_ether *ue) +{ + struct axge_softc *sc; + + sc = uether_getsc(ue); + sc->sc_phyno = 3; + + /* Initialize controller and get station address. */ + axge_chip_init(sc); + axge_read_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NIDR, + ue->ue_eaddr, ETHER_ADDR_LEN); +} + +static int +axge_attach_post_sub(struct usb_ether *ue) +{ + struct axge_softc *sc; + struct ifnet *ifp; + int error; + + sc = uether_getsc(ue); + ifp = uether_getifp(ue); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_start = uether_start; + ifp->if_ioctl = axge_ioctl; + ifp->if_init = uether_init; + ifq_set_maxlen(&ifp->if_snd, ifqmaxlen); + ifq_set_ready(&ifp->if_snd); + + ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_TXCSUM | IFCAP_RXCSUM; + ifp->if_hwassist = AXGE_CSUM_FEATURES; + ifp->if_capenable = ifp->if_capabilities; + + /* + * NB: miibus assumes that the first member of the softc + * of it's parent is an arpcom structure + */ + error = mii_phy_probe(ue->ue_dev, &ue->ue_miibus, + uether_ifmedia_upd, ue->ue_methods->ue_mii_sts); + + return (error); +} + +/* + * Set media options. + */ +static int +axge_ifmedia_upd(struct ifnet *ifp) +{ + struct axge_softc *sc; + struct mii_data *mii; + struct mii_softc *miisc; + int error; + + sc = ifp->if_softc; + mii = GET_MII(sc); + AXGE_LOCK_ASSERT(sc); + + LIST_FOREACH(miisc, &mii->mii_phys, mii_list) + mii_phy_reset(miisc); + error = mii_mediachg(mii); + + return (error); +} + +/* + * Report current media status. + */ +static void +axge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct axge_softc *sc; + struct mii_data *mii; + + sc = ifp->if_softc; + mii = GET_MII(sc); + AXGE_LOCK(sc); + mii_pollstat(mii); + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; + AXGE_UNLOCK(sc); +} + +/* + * Probe for a AX88179 chip. + */ +static int +axge_probe(device_t dev) +{ + struct usb_attach_arg *uaa; + + uaa = device_get_ivars(dev); + if (uaa->usb_mode != USB_MODE_HOST) + return (ENXIO); + if (uaa->info.bConfigIndex != AXGE_CONFIG_IDX) + return (ENXIO); + if (uaa->info.bIfaceIndex != AXGE_IFACE_IDX) + return (ENXIO); + + return (usbd_lookup_id_by_uaa(axge_devs, sizeof(axge_devs), uaa)); +} + +/* + * Attach the interface. Allocate softc structures, do ifmedia + * setup and ethernet/BPF attach. + */ +static int +axge_attach(device_t dev) +{ + struct usb_attach_arg *uaa; + struct axge_softc *sc; + struct usb_ether *ue; + uint8_t iface_index; + int error; + + uaa = device_get_ivars(dev); + sc = device_get_softc(dev); + ue = &sc->sc_ue; + + device_set_usb_desc(dev); + lockinit(&sc->sc_lock, device_get_nameunit(dev), 0, LK_CANRECURSE); + + iface_index = AXGE_IFACE_IDX; + error = usbd_transfer_setup(uaa->device, &iface_index, + sc->sc_xfer, axge_config, AXGE_N_TRANSFER, sc, &sc->sc_lock); + if (error) { + device_printf(dev, "allocating USB transfers failed\n"); + goto detach; + } + + ue->ue_sc = sc; + ue->ue_dev = dev; + ue->ue_udev = uaa->device; + ue->ue_lock = &sc->sc_lock; + ue->ue_methods = &axge_ue_methods; + + error = uether_ifattach(ue); + if (error) { + device_printf(dev, "could not attach interface\n"); + goto detach; + } + return (0); /* success */ + +detach: + axge_detach(dev); + return (ENXIO); /* failure */ +} + +static int +axge_detach(device_t dev) +{ + struct axge_softc *sc; + struct usb_ether *ue; + + sc = device_get_softc(dev); + ue = &sc->sc_ue; + usbd_transfer_unsetup(sc->sc_xfer, AXGE_N_TRANSFER); + uether_ifdetach(ue); + lockuninit(&sc->sc_lock); + + return (0); +} + +static void +axge_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct axge_softc *sc; + struct usb_ether *ue; + struct usb_page_cache *pc; + int actlen; + + sc = usbd_xfer_softc(xfer); + ue = &sc->sc_ue; + usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + pc = usbd_xfer_get_frame(xfer, 0); + axge_rx_frame(ue, pc, actlen); + + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); + usbd_transfer_submit(xfer); + uether_rxflush(ue); + break; + + default: + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } +} + +static void +axge_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct axge_softc *sc; + struct ifnet *ifp; + struct usb_page_cache *pc; + struct mbuf *m; + uint32_t txhdr; + int nframes, pos; + + sc = usbd_xfer_softc(xfer); + ifp = uether_getifp(&sc->sc_ue); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + ifq_clr_oactive(&ifp->if_snd); + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + if ((sc->sc_flags & AXGE_FLAG_LINK) == 0 || + ifq_is_oactive(&ifp->if_snd)) { + /* + * Don't send anything if there is no link or + * controller is busy. + */ + return; + } + + for (nframes = 0; nframes < 16 && + !ifq_is_empty(&ifp->if_snd); nframes++) { + m = ifq_dequeue(&ifp->if_snd); + if (m == NULL) + break; + usbd_xfer_set_frame_offset(xfer, nframes * MCLBYTES, + nframes); + pos = 0; + pc = usbd_xfer_get_frame(xfer, nframes); + txhdr = htole32(m->m_pkthdr.len); + usbd_copy_in(pc, 0, &txhdr, sizeof(txhdr)); + txhdr = 0; + txhdr = htole32(txhdr); + usbd_copy_in(pc, 4, &txhdr, sizeof(txhdr)); + pos += 8; + usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len); + pos += m->m_pkthdr.len; + if ((pos % usbd_xfer_max_framelen(xfer)) == 0) + txhdr |= 0x80008000; + + /* + * XXX + * Update TX packet counter here. This is not + * correct way but it seems that there is no way + * to know how many packets are sent at the end + * of transfer because controller combines + * multiple writes into single one if there is + * room in TX buffer of controller. + */ + IFNET_STAT_INC(ifp, opackets, 1); + + /* + * if there's a BPF listener, bounce a copy + * of this frame to him: + */ + BPF_MTAP(ifp, m); + + m_freem(m); + + /* Set frame length. */ + usbd_xfer_set_frame_len(xfer, nframes, pos); + } + if (nframes != 0) { + usbd_xfer_set_frames(xfer, nframes); + usbd_transfer_submit(xfer); + ifq_set_oactive(&ifp->if_snd); + } + return; + /* NOTREACHED */ + default: + IFNET_STAT_INC(ifp, oerrors, 1); + ifq_clr_oactive(&ifp->if_snd); + + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + return; + + } +} + +static void +axge_tick(struct usb_ether *ue) +{ + struct axge_softc *sc; + struct mii_data *mii; + + sc = uether_getsc(ue); + mii = GET_MII(sc); + AXGE_LOCK_ASSERT(sc); + + mii_tick(mii); + if ((sc->sc_flags & AXGE_FLAG_LINK) == 0) { + axge_miibus_statchg(ue->ue_dev); + if ((sc->sc_flags & AXGE_FLAG_LINK) != 0) + axge_start(ue); + } +} + +static void +axge_setmulti(struct usb_ether *ue) +{ + struct axge_softc *sc; + struct ifnet *ifp; + struct ifmultiaddr *ifma; + uint32_t h; + uint16_t rxmode; + uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + sc = uether_getsc(ue); + ifp = uether_getifp(ue); + h = 0; + AXGE_LOCK_ASSERT(sc); + + rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR); + if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { + rxmode |= RCR_AMALL; + axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); + return; + } + rxmode &= ~RCR_AMALL; + + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + h = ether_crc32_be(LLADDR((struct sockaddr_dl *) + ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; + hashtbl[h / 8] |= 1 << (h % 8); + } + + axge_write_mem(sc, AXGE_ACCESS_MAC, 8, AXGE_MFA, (void *)&hashtbl, 8); + axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); +} + +static void +axge_setpromisc(struct usb_ether *ue) +{ + struct axge_softc *sc; + struct ifnet *ifp; + uint16_t rxmode; + + sc = uether_getsc(ue); + ifp = uether_getifp(ue); + rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR); + + if (ifp->if_flags & IFF_PROMISC) + rxmode |= RCR_PRO; + else + rxmode &= ~RCR_PRO; + + axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); + axge_setmulti(ue); +} + +static void +axge_start(struct usb_ether *ue) +{ + struct axge_softc *sc; + + sc = uether_getsc(ue); + /* + * Start the USB transfers, if not already started. + */ + usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_RD]); + usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_WR]); +} + +static void +axge_init(struct usb_ether *ue) +{ + struct axge_softc *sc; + struct ifnet *ifp; + uint16_t rxmode; + + sc = uether_getsc(ue); + ifp = uether_getifp(ue); + AXGE_LOCK_ASSERT(sc); + + if ((ifp->if_flags & IFF_RUNNING) != 0) + return; + + /* + * Cancel pending I/O and free all RX/TX buffers. + */ + axge_stop(ue); + + axge_reset(sc); + + /* Set MAC address. */ + axge_write_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NIDR, + IF_LLADDR(ifp), ETHER_ADDR_LEN); + + axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLLR, 0x34); + axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLHR, 0x52); + + /* Configure TX/RX checksum offloading. */ + axge_csum_cfg(ue); + + /* Configure RX settings. */ + rxmode = (RCR_AM | RCR_SO | RCR_DROP_CRCE); + if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) + rxmode |= RCR_IPE; + + /* If we want promiscuous mode, set the allframes bit. */ + if (ifp->if_flags & IFF_PROMISC) + rxmode |= RCR_PRO; + + if (ifp->if_flags & IFF_BROADCAST) + rxmode |= RCR_AB; + + axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); + + axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_MMSR, + MMSR_PME_TYPE | MMSR_PME_POL | MMSR_RWMP); + + /* Load the multicast filter. */ + axge_setmulti(ue); + + usbd_xfer_set_stall(sc->sc_xfer[AXGE_BULK_DT_WR]); + + ifp->if_flags |= IFF_RUNNING; + /* Switch to selected media. */ + axge_ifmedia_upd(ifp); +} + +static void +axge_stop(struct usb_ether *ue) +{ + struct axge_softc *sc; + struct ifnet *ifp; + + sc = uether_getsc(ue); + ifp = uether_getifp(ue); + + AXGE_LOCK_ASSERT(sc); + + ifp->if_flags &= ~IFF_RUNNING; + ifq_clr_oactive(&ifp->if_snd); + sc->sc_flags &= ~AXGE_FLAG_LINK; + + /* + * Stop all the transfers, if not already stopped: + */ + usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_WR]); + usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_RD]); +} + +static int +axge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *uc) +{ + struct usb_ether *ue; + struct axge_softc *sc; + struct ifreq *ifr; + int error, mask, reinit; + + ue = ifp->if_softc; + sc = uether_getsc(ue); + ifr = (struct ifreq *)data; + error = 0; + reinit = 0; + if (cmd == SIOCSIFCAP) { + AXGE_LOCK(sc); + mask = ifr->ifr_reqcap ^ ifp->if_capenable; + if ((mask & IFCAP_TXCSUM) != 0 && + (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { + ifp->if_capenable ^= IFCAP_TXCSUM; + if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) + ifp->if_hwassist |= AXGE_CSUM_FEATURES; + else + ifp->if_hwassist &= ~AXGE_CSUM_FEATURES; + reinit++; + } + if ((mask & IFCAP_RXCSUM) != 0 && + (ifp->if_capabilities & IFCAP_RXCSUM) != 0) { + ifp->if_capenable ^= IFCAP_RXCSUM; + reinit++; + } + if (reinit > 0 && ifp->if_flags & IFF_RUNNING) + ifp->if_flags &= ~IFF_RUNNING; + else + reinit = 0; + AXGE_UNLOCK(sc); + if (reinit > 0) + uether_init(ue); + } else + error = uether_ioctl(ifp, cmd, data, uc); + + return (error); +} + +static void +axge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen) +{ + uint32_t pos; + uint32_t pkt_cnt; + uint32_t rxhdr; + uint32_t pkt_hdr; + uint32_t hdr_off; + uint32_t pktlen; + + /* verify we have enough data */ + if (actlen < (int)sizeof(rxhdr)) + return; + + pos = 0; + + usbd_copy_out(pc, actlen - sizeof(rxhdr), &rxhdr, sizeof(rxhdr)); + rxhdr = le32toh(rxhdr); + + pkt_cnt = (uint16_t)rxhdr; + hdr_off = (uint16_t)(rxhdr >> 16); + + while (pkt_cnt--) { + /* verify the header offset */ + if ((int)(hdr_off + sizeof(pkt_hdr)) > actlen) { + DPRINTF("End of packet headers\n"); + break; + } + if ((int)pos >= actlen) { + DPRINTF("Data position reached end\n"); + break; + } + usbd_copy_out(pc, hdr_off, &pkt_hdr, sizeof(pkt_hdr)); + + pkt_hdr = le32toh(pkt_hdr); + pktlen = (pkt_hdr >> 16) & 0x1fff; + if (pkt_hdr & (AXGE_RXHDR_CRC_ERR | AXGE_RXHDR_DROP_ERR)) { + DPRINTF("Dropped a packet\n"); + IFNET_STAT_INC(uether_getifp(ue), ierrors, 1); + } + if (pktlen >= 6 && (int)(pos + pktlen) <= actlen) { + axge_rxeof(ue, pc, pos + 2, pktlen - 6, pkt_hdr); + } else { + DPRINTF("Invalid packet pos=%d len=%d\n", + (int)pos, (int)pktlen); + } + pos += (pktlen + 7) & ~7; + hdr_off += sizeof(pkt_hdr); + } +} + +static void +axge_rxeof(struct usb_ether *ue, struct usb_page_cache *pc, + unsigned int offset, unsigned int len, uint32_t pkt_hdr) +{ + struct ifnet *ifp; + struct mbuf *m; + + ifp = uether_getifp(ue); + if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN) { + IFNET_STAT_INC(ifp, ierrors, 1); + return; + } + + m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) { + IFNET_STAT_INC(ifp, iqdrops, 1); + return; + } + m->m_pkthdr.rcvif = ifp; + m->m_len = m->m_pkthdr.len = len + ETHER_ALIGN; + m_adj(m, ETHER_ALIGN); + + usbd_copy_out(pc, offset, mtod(m, uint8_t *), len); + + IFNET_STAT_INC(ifp, ipackets, 1); + + if ((pkt_hdr & (AXGE_RXHDR_L4CSUM_ERR | AXGE_RXHDR_L3CSUM_ERR)) == 0) { + if ((pkt_hdr & AXGE_RXHDR_L4_TYPE_MASK) == + AXGE_RXHDR_L4_TYPE_TCP || + (pkt_hdr & AXGE_RXHDR_L4_TYPE_MASK) == + AXGE_RXHDR_L4_TYPE_UDP) { + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | + CSUM_PSEUDO_HDR | CSUM_IP_CHECKED | CSUM_IP_VALID; + m->m_pkthdr.csum_data = 0xffff; + } + } + + IF_ENQUEUE(&ue->ue_rxq, m); +} + +static void +axge_csum_cfg(struct usb_ether *ue) +{ + struct axge_softc *sc; + struct ifnet *ifp; + uint8_t csum; + + sc = uether_getsc(ue); + AXGE_LOCK_ASSERT(sc); + ifp = uether_getifp(ue); + + csum = 0; + if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) + csum |= CTCR_IP | CTCR_TCP | CTCR_UDP; + axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CTCR, csum); + + csum = 0; + if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) + csum |= CRCR_IP | CRCR_TCP | CRCR_UDP; + axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CRCR, csum); +} diff --git a/sys/bus/u4b/net/if_axgereg.h b/sys/bus/u4b/net/if_axgereg.h new file mode 100644 index 0000000000..ce7f20314a --- /dev/null +++ b/sys/bus/u4b/net/if_axgereg.h @@ -0,0 +1,173 @@ +/*- + * Copyright (c) 2013-2014 Kevin Lo + * 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 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 AUTHOR 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: head/sys/dev/usb/net/if_axgereg.h 269322 2014-07-31 05:12:21Z kevlo $ + */ + +#define AXGE_ACCESS_MAC 0x01 +#define AXGE_ACCESS_PHY 0x02 +#define AXGE_ACCESS_WAKEUP 0x03 +#define AXGE_ACCESS_EEPROM 0x04 +#define AXGE_ACCESS_EFUSE 0x05 +#define AXGE_RELOAD_EEPROM_EFUSE 0x06 +#define AXGE_WRITE_EFUSE_EN 0x09 +#define AXGE_WRITE_EFUSE_DIS 0x0A +#define AXGE_ACCESS_MFAB 0x10 + +/* Physical link status register */ +#define AXGE_PLSR 0x02 +#define PLSR_USB_FS 0x01 +#define PLSR_USB_HS 0x02 +#define PLSR_USB_SS 0x04 + +/* EEPROM address register */ +#define AXGE_EAR 0x07 + +/* EEPROM data low register */ +#define AXGE_EDLR 0x08 + +/* EEPROM data high register */ +#define AXGE_EDHR 0x09 + +/* EEPROM command register */ +#define AXGE_ECR 0x0a + +/* Rx control register */ +#define AXGE_RCR 0x0b +#define RCR_STOP 0x0000 +#define RCR_PRO 0x0001 +#define RCR_AMALL 0x0002 +#define RCR_AB 0x0008 +#define RCR_AM 0x0010 +#define RCR_AP 0x0020 +#define RCR_SO 0x0080 +#define RCR_DROP_CRCE 0x0100 +#define RCR_IPE 0x0200 +#define RCR_TX_CRC_PAD 0x0400 + +/* Node id register */ +#define AXGE_NIDR 0x10 + +/* Multicast filter array */ +#define AXGE_MFA 0x16 + +/* Medium status register */ +#define AXGE_MSR 0x22 +#define MSR_GM 0x0001 +#define MSR_FD 0x0002 +#define MSR_EN_125MHZ 0x0008 +#define MSR_RFC 0x0010 +#define MSR_TFC 0x0020 +#define MSR_RE 0x0100 +#define MSR_PS 0x0200 + +/* Monitor mode status register */ +#define AXGE_MMSR 0x24 +#define MMSR_RWLC 0x02 +#define MMSR_RWMP 0x04 +#define MMSR_RWWF 0x08 +#define MMSR_RW_FLAG 0x10 +#define MMSR_PME_POL 0x20 +#define MMSR_PME_TYPE 0x40 +#define MMSR_PME_IND 0x80 + +/* GPIO control/status register */ +#define AXGE_GPIOCR 0x25 + +/* Ethernet PHY power & reset control register */ +#define AXGE_EPPRCR 0x26 +#define EPPRCR_BZ 0x0010 +#define EPPRCR_IPRL 0x0020 +#define EPPRCR_AUTODETACH 0x1000 + +#define AXGE_RX_BULKIN_QCTRL 0x2e + +#define AXGE_CLK_SELECT 0x33 +#define AXGE_CLK_SELECT_BCS 0x01 +#define AXGE_CLK_SELECT_ACS 0x02 +#define AXGE_CLK_SELECT_ACSREQ 0x10 +#define AXGE_CLK_SELECT_ULR 0x08 + +/* COE Rx control register */ +#define AXGE_CRCR 0x34 +#define CRCR_IP 0x01 +#define CRCR_TCP 0x02 +#define CRCR_UDP 0x04 +#define CRCR_ICMP 0x08 +#define CRCR_IGMP 0x10 +#define CRCR_TCPV6 0x20 +#define CRCR_UDPV6 0x40 +#define CRCR_ICMPV6 0x80 + +/* COE Tx control register */ +#define AXGE_CTCR 0x35 +#define CTCR_IP 0x01 +#define CTCR_TCP 0x02 +#define CTCR_UDP 0x04 +#define CTCR_ICMP 0x08 +#define CTCR_IGMP 0x10 +#define CTCR_TCPV6 0x20 +#define CTCR_UDPV6 0x40 +#define CTCR_ICMPV6 0x80 + +/* Pause water level high register */ +#define AXGE_PWLHR 0x54 + +/* Pause water level low register */ +#define AXGE_PWLLR 0x55 + +#define AXGE_CONFIG_IDX 0 /* config number 1 */ +#define AXGE_IFACE_IDX 0 + +#define AXGE_RXHDR_L4_TYPE_MASK 0x1c +#define AXGE_RXHDR_L4CSUM_ERR 1 +#define AXGE_RXHDR_L3CSUM_ERR 2 +#define AXGE_RXHDR_L4_TYPE_UDP 4 +#define AXGE_RXHDR_L4_TYPE_TCP 16 +#define AXGE_RXHDR_CRC_ERR 0x20000000 +#define AXGE_RXHDR_DROP_ERR 0x80000000 + +#define GET_MII(sc) uether_getmii(&(sc)->sc_ue) + +/* The interrupt endpoint is currently unused by the ASIX part. */ +enum { + AXGE_BULK_DT_WR, + AXGE_BULK_DT_RD, + AXGE_N_TRANSFER, +}; + +struct axge_softc { + struct usb_ether sc_ue; + struct lock sc_lock; + struct usb_xfer *sc_xfer[AXGE_N_TRANSFER]; + int sc_phyno; + + int sc_flags; +#define AXGE_FLAG_LINK 0x0001 /* got a link */ +}; + +#define AXGE_LOCK(_sc) lockmgr(&(_sc)->sc_lock, LK_EXCLUSIVE) +#define AXGE_UNLOCK(_sc) lockmgr(&(_sc)->sc_lock, LK_RELEASE) +#define AXGE_LOCK_ASSERT(_sc) KKASSERT(lockowned(&(_sc)->sc_lock)) diff --git a/sys/bus/u4b/usbdevs b/sys/bus/u4b/usbdevs index e2acf94d5e..86698ad63d 100644 --- a/sys/bus/u4b/usbdevs +++ b/sys/bus/u4b/usbdevs @@ -1562,6 +1562,7 @@ product DLINK DSB650TX 0x4002 10/100 Ethernet product DLINK DSB650TX_PNA 0x4003 1/10/100 Ethernet product DLINK DSB650TX3 0x400b 10/100 Ethernet product DLINK DSB650TX2 0x4102 10/100 Ethernet +product DLINK DUB1312 0x4a00 10/100/1000 Ethernet product DLINK DSB650 0xabc1 10/100 Ethernet product DLINK DUBH7 0xf103 DUB-H7 USB 2.0 7-Port Hub product DLINK DWR510_CD 0xa805 DWR-510 CD-ROM Mode @@ -4039,6 +4040,7 @@ product SITECOMEU RT3072_6 0x004d RT3072 product SITECOMEU RTL8188CU_1 0x0052 RTL8188CU product SITECOMEU RTL8188CU_2 0x005c RTL8188CU product SITECOMEU RTL8192CU 0x0061 RTL8192CU +product SITECOMEU LN032 0x0072 LN-032 product SITECOMEU LN028 0x061c LN-028 product SITECOMEU WL113 0x9071 WL-113 product SITECOMEU ZD1211B 0x9075 ZD1211B diff --git a/sys/conf/files b/sys/conf/files index 8ef4f43883..f87e76d295 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2265,6 +2265,7 @@ bus/u4b/storage/ustorage_fs.c optional usfs usb bus/u4b/net/usb_ethernet.c optional uether usb bus/u4b/net/if_aue.c optional aue uether usb bus/u4b/net/if_axe.c optional axe uether usb +bus/u4b/net/if_axge.c optional axge uether usb bus/u4b/net/if_cue.c optional cue uether usb bus/u4b/net/if_ipheth.c optional ipheth uether usb bus/u4b/net/if_kue.c optional kue uether usb diff --git a/sys/config/LINT b/sys/config/LINT index 4460ddd929..676de74f05 100644 --- a/sys/config/LINT +++ b/sys/config/LINT @@ -2151,6 +2151,9 @@ device aue # LinkSys USB200M and various other adapters. device axe # +# ASIX Electronics AX88178A/AX88179 USB 2.0/3.0 gigabit ethernet driver. +device axge +# # CATC USB-EL1201A USB ethernet. Supports the CATC Netmate # and Netmate II, and the Belkin F5U111. device cue diff --git a/sys/config/LINT64 b/sys/config/LINT64 index 1bd7ec2e88..7c466a3903 100644 --- a/sys/config/LINT64 +++ b/sys/config/LINT64 @@ -1982,6 +1982,9 @@ device aue # LinkSys USB200M and various other adapters. device axe # +# ASIX Electronics AX88178A/AX88179 USB 2.0/3.0 gigabit ethernet driver. +device axge +# # CATC USB-EL1201A USB ethernet. Supports the CATC Netmate # and Netmate II, and the Belkin F5U111. device cue -- 2.41.0