1*21bc0131Sjmatthew /* $OpenBSD: if_uaq.c,v 1.3 2022/04/24 00:04:10 jmatthew Exp $ */ 2497492a7Sjmatthew /*- 3497492a7Sjmatthew * Copyright (c) 2021 Jonathan Matthew <jonathan@d14n.org> 4497492a7Sjmatthew * All rights reserved. 5497492a7Sjmatthew * 6497492a7Sjmatthew * Redistribution and use in source and binary forms, with or without 7497492a7Sjmatthew * modification, are permitted provided that the following conditions 8497492a7Sjmatthew * are met: 9497492a7Sjmatthew * 1. Redistributions of source code must retain the above copyright 10497492a7Sjmatthew * notice, this list of conditions and the following disclaimer. 11497492a7Sjmatthew * 2. Redistributions in binary form must reproduce the above copyright 12497492a7Sjmatthew * notice, this list of conditions and the following disclaimer in the 13497492a7Sjmatthew * documentation and/or other materials provided with the distribution. 14497492a7Sjmatthew * 15497492a7Sjmatthew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16497492a7Sjmatthew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17497492a7Sjmatthew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18497492a7Sjmatthew * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19497492a7Sjmatthew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20497492a7Sjmatthew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21497492a7Sjmatthew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22497492a7Sjmatthew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23497492a7Sjmatthew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24497492a7Sjmatthew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25497492a7Sjmatthew * SUCH DAMAGE. 26497492a7Sjmatthew */ 27497492a7Sjmatthew 28497492a7Sjmatthew #include "bpfilter.h" 29497492a7Sjmatthew #include "vlan.h" 30497492a7Sjmatthew 31497492a7Sjmatthew #include <sys/param.h> 32497492a7Sjmatthew #include <sys/systm.h> 33497492a7Sjmatthew #include <sys/sockio.h> 34497492a7Sjmatthew #include <sys/rwlock.h> 35497492a7Sjmatthew #include <sys/mbuf.h> 36497492a7Sjmatthew #include <sys/kernel.h> 37497492a7Sjmatthew #include <sys/socket.h> 38497492a7Sjmatthew #include <sys/device.h> 39497492a7Sjmatthew 40497492a7Sjmatthew #include <machine/bus.h> 41497492a7Sjmatthew 42497492a7Sjmatthew #include <net/if.h> 43497492a7Sjmatthew #include <net/if_media.h> 44497492a7Sjmatthew 45497492a7Sjmatthew #if NBPFILTER > 0 46497492a7Sjmatthew #include <net/bpf.h> 47497492a7Sjmatthew #endif 48497492a7Sjmatthew 49497492a7Sjmatthew #include <netinet/in.h> 50497492a7Sjmatthew #include <netinet/if_ether.h> 51497492a7Sjmatthew 52497492a7Sjmatthew #include <dev/usb/usb.h> 53497492a7Sjmatthew #include <dev/usb/usbdi.h> 54497492a7Sjmatthew #include <dev/usb/usbdi_util.h> 55497492a7Sjmatthew #include <dev/usb/usbdivar.h> 56497492a7Sjmatthew #include <dev/usb/usbdevs.h> 57497492a7Sjmatthew 58497492a7Sjmatthew #ifdef UAQ_DEBUG 59497492a7Sjmatthew #define DPRINTF(x) do { if (uaqdebug) printf x; } while (0) 60497492a7Sjmatthew #define DPRINTFN(n,x) do { if (uaqdebug >= (n)) printf x; } while (0) 61497492a7Sjmatthew int uaqdebug = 0; 62497492a7Sjmatthew #else 63497492a7Sjmatthew #define DPRINTF(x) 64497492a7Sjmatthew #define DPRINTFN(n,x) 65497492a7Sjmatthew #endif 66497492a7Sjmatthew 67497492a7Sjmatthew #define UAQ_ENDPT_RX 0 68497492a7Sjmatthew #define UAQ_ENDPT_TX 1 69497492a7Sjmatthew #define UAQ_ENDPT_INTR 2 70497492a7Sjmatthew #define UAQ_ENDPT_MAX 3 71497492a7Sjmatthew 72497492a7Sjmatthew #define UAQ_TX_LIST_CNT 1 73497492a7Sjmatthew #define UAQ_RX_LIST_CNT 1 74497492a7Sjmatthew #define UAQ_TX_BUF_ALIGN 8 75497492a7Sjmatthew #define UAQ_RX_BUF_ALIGN 8 76497492a7Sjmatthew 77497492a7Sjmatthew #define UAQ_TX_BUFSZ 16384 78*21bc0131Sjmatthew #define UAQ_RX_BUFSZ (62 * 1024) 79497492a7Sjmatthew 80497492a7Sjmatthew #define UAQ_CTL_READ 1 81497492a7Sjmatthew #define UAQ_CTL_WRITE 2 82497492a7Sjmatthew 83497492a7Sjmatthew #define UAQ_MCAST_FILTER_SIZE 8 84497492a7Sjmatthew 85497492a7Sjmatthew /* control commands */ 86497492a7Sjmatthew #define UAQ_CMD_ACCESS_MAC 0x01 87497492a7Sjmatthew #define UAQ_CMD_FLASH_PARAM 0x20 88497492a7Sjmatthew #define UAQ_CMD_PHY_POWER 0x31 89497492a7Sjmatthew #define UAQ_CMD_WOL_CFG 0x60 90497492a7Sjmatthew #define UAQ_CMD_PHY_OPS 0x61 91497492a7Sjmatthew 92497492a7Sjmatthew /* SFR registers */ 93497492a7Sjmatthew #define UAQ_SFR_GENERAL_STATUS 0x03 94497492a7Sjmatthew #define UAQ_SFR_CHIP_STATUS 0x05 95497492a7Sjmatthew #define UAQ_SFR_RX_CTL 0x0B 96497492a7Sjmatthew #define UAQ_SFR_RX_CTL_STOP 0x0000 97497492a7Sjmatthew #define UAQ_SFR_RX_CTL_PRO 0x0001 98497492a7Sjmatthew #define UAQ_SFR_RX_CTL_AMALL 0x0002 99497492a7Sjmatthew #define UAQ_SFR_RX_CTL_AB 0x0008 100497492a7Sjmatthew #define UAQ_SFR_RX_CTL_AM 0x0010 101497492a7Sjmatthew #define UAQ_SFR_RX_CTL_START 0x0080 102497492a7Sjmatthew #define UAQ_SFR_RX_CTL_IPE 0x0200 103497492a7Sjmatthew #define UAQ_SFR_IPG_0 0x0D 104497492a7Sjmatthew #define UAQ_SFR_NODE_ID 0x10 105497492a7Sjmatthew #define UAQ_SFR_MCAST_FILTER 0x16 106497492a7Sjmatthew #define UAQ_SFR_MEDIUM_STATUS_MODE 0x22 107497492a7Sjmatthew #define UAQ_SFR_MEDIUM_XGMIIMODE 0x0001 108497492a7Sjmatthew #define UAQ_SFR_MEDIUM_FULL_DUPLEX 0x0002 109497492a7Sjmatthew #define UAQ_SFR_MEDIUM_RXFLOW_CTRLEN 0x0010 110497492a7Sjmatthew #define UAQ_SFR_MEDIUM_TXFLOW_CTRLEN 0x0020 111497492a7Sjmatthew #define UAQ_SFR_MEDIUM_JUMBO_EN 0x0040 112497492a7Sjmatthew #define UAQ_SFR_MEDIUM_RECEIVE_EN 0x0100 113497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE 0x24 114497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_EPHYRW 0x01 115497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_RWLC 0x02 116497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_RWMP 0x04 117497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_RWWF 0x08 118497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_RW_FLAG 0x10 119497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_PMEPOL 0x20 120497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_PMETYPE 0x40 121497492a7Sjmatthew #define UAQ_SFR_RX_BULKIN_QCTRL 0x2E 122497492a7Sjmatthew #define UAQ_SFR_RXCOE_CTL 0x34 123497492a7Sjmatthew #define UAQ_SFR_RXCOE_IP 0x01 124497492a7Sjmatthew #define UAQ_SFR_RXCOE_TCP 0x02 125497492a7Sjmatthew #define UAQ_SFR_RXCOE_UDP 0x04 126497492a7Sjmatthew #define UAQ_SFR_RXCOE_ICMP 0x08 127497492a7Sjmatthew #define UAQ_SFR_RXCOE_IGMP 0x10 128497492a7Sjmatthew #define UAQ_SFR_RXCOE_TCPV6 0x20 129497492a7Sjmatthew #define UAQ_SFR_RXCOE_UDPV6 0x40 130497492a7Sjmatthew #define UAQ_SFR_RXCOE_ICMV6 0x80 131497492a7Sjmatthew #define UAQ_SFR_TXCOE_CTL 0x35 132497492a7Sjmatthew #define UAQ_SFR_TXCOE_IP 0x01 133497492a7Sjmatthew #define UAQ_SFR_TXCOE_TCP 0x02 134497492a7Sjmatthew #define UAQ_SFR_TXCOE_UDP 0x04 135497492a7Sjmatthew #define UAQ_SFR_TXCOE_ICMP 0x08 136497492a7Sjmatthew #define UAQ_SFR_TXCOE_IGMP 0x10 137497492a7Sjmatthew #define UAQ_SFR_TXCOE_TCPV6 0x20 138497492a7Sjmatthew #define UAQ_SFR_TXCOE_UDPV6 0x40 139497492a7Sjmatthew #define UAQ_SFR_TXCOE_ICMV6 0x80 140497492a7Sjmatthew #define UAQ_SFR_BM_INT_MASK 0x41 141497492a7Sjmatthew #define UAQ_SFR_BMRX_DMA_CTRL 0x43 142497492a7Sjmatthew #define UAQ_SFR_BMRX_DMA_EN 0x80 143497492a7Sjmatthew #define UAQ_SFR_BMTX_DMA_CTRL 0x46 144497492a7Sjmatthew #define UAQ_SFR_PAUSE_WATERLVL_LOW 0x54 145497492a7Sjmatthew #define UAQ_SFR_ARC_CTRL 0x9E 146497492a7Sjmatthew #define UAQ_SFR_SWP_CTRL 0xB1 147497492a7Sjmatthew #define UAQ_SFR_TX_PAUSE_RESEND_T 0xB2 148497492a7Sjmatthew #define UAQ_SFR_ETH_MAC_PATH 0xB7 149497492a7Sjmatthew #define UAQ_SFR_RX_PATH_READY 0x01 150497492a7Sjmatthew #define UAQ_SFR_BULK_OUT_CTRL 0xB9 151497492a7Sjmatthew #define UAQ_SFR_BULK_OUT_FLUSH_EN 0x01 152497492a7Sjmatthew #define UAQ_SFR_BULK_OUT_EFF_EN 0x02 153497492a7Sjmatthew 154497492a7Sjmatthew #define UAQ_FW_VER_MAJOR 0xDA 155497492a7Sjmatthew #define UAQ_FW_VER_MINOR 0xDB 156497492a7Sjmatthew #define UAQ_FW_VER_REV 0xDC 157497492a7Sjmatthew 158497492a7Sjmatthew /* phy ops */ 159497492a7Sjmatthew #define UAQ_PHY_ADV_100M (1 << 0) 160497492a7Sjmatthew #define UAQ_PHY_ADV_1G (1 << 1) 161497492a7Sjmatthew #define UAQ_PHY_ADV_2_5G (1 << 2) 162497492a7Sjmatthew #define UAQ_PHY_ADV_5G (1 << 3) 163497492a7Sjmatthew #define UAQ_PHY_ADV_MASK 0x0F 164497492a7Sjmatthew 165497492a7Sjmatthew #define UAQ_PHY_PAUSE (1 << 16) 166497492a7Sjmatthew #define UAQ_PHY_ASYM_PAUSE (1 << 17) 167497492a7Sjmatthew #define UAQ_PHY_LOW_POWER (1 << 18) 168497492a7Sjmatthew #define UAQ_PHY_POWER_EN (1 << 19) 169497492a7Sjmatthew #define UAQ_PHY_WOL (1 << 20) 170497492a7Sjmatthew #define UAQ_PHY_DOWNSHIFT (1 << 21) 171497492a7Sjmatthew 172497492a7Sjmatthew #define UAQ_PHY_DSH_RETRY_SHIFT 0x18 173497492a7Sjmatthew #define UAQ_PHY_DSH_RETRY_MASK 0xF000000 174497492a7Sjmatthew 175497492a7Sjmatthew /* status */ 176497492a7Sjmatthew #define UAQ_STATUS_LINK 0x8000 177497492a7Sjmatthew #define UAQ_STATUS_SPEED_MASK 0x7F00 178497492a7Sjmatthew #define UAQ_STATUS_SPEED_SHIFT 8 179497492a7Sjmatthew #define UAQ_STATUS_SPEED_5G 0x000F 180497492a7Sjmatthew #define UAQ_STATUS_SPEED_2_5G 0x0010 181497492a7Sjmatthew #define UAQ_STATUS_SPEED_1G 0x0011 182497492a7Sjmatthew #define UAQ_STATUS_SPEED_100M 0x0013 183497492a7Sjmatthew 184497492a7Sjmatthew /* rx descriptor */ 185497492a7Sjmatthew #define UAQ_RX_HDR_COUNT_MASK 0x1FFF 186497492a7Sjmatthew #define UAQ_RX_HDR_OFFSET_MASK 0xFFFFE000 187497492a7Sjmatthew #define UAQ_RX_HDR_OFFSET_SHIFT 13 188497492a7Sjmatthew 189497492a7Sjmatthew /* rx packet descriptor */ 190497492a7Sjmatthew #define UAQ_RX_PKT_L4_ERR 0x01 191497492a7Sjmatthew #define UAQ_RX_PKT_L3_ERR 0x02 192497492a7Sjmatthew #define UAQ_RX_PKT_L4_MASK 0x1C 193497492a7Sjmatthew #define UAQ_RX_PKT_L4_UDP 0x04 194497492a7Sjmatthew #define UAQ_RX_PKT_L4_TCP 0x10 195497492a7Sjmatthew #define UAQ_RX_PKT_L3_MASK 0x60 196497492a7Sjmatthew #define UAQ_RX_PKT_L3_IP 0x20 197497492a7Sjmatthew #define UAQ_RX_PKT_L3_IP6 0x40 198497492a7Sjmatthew #define UAQ_RX_PKT_VLAN 0x400 199497492a7Sjmatthew #define UAQ_RX_PKT_RX_OK 0x800 200497492a7Sjmatthew #define UAQ_RX_PKT_DROP 0x80000000 201497492a7Sjmatthew #define UAQ_RX_PKT_LEN_MASK 0x7FFF0000 202497492a7Sjmatthew #define UAQ_RX_PKT_LEN_SHIFT 16 203497492a7Sjmatthew #define UAQ_RX_PKT_VLAN_SHIFT 32 204497492a7Sjmatthew 205497492a7Sjmatthew /* tx packet descriptor */ 206497492a7Sjmatthew #define UAQ_TX_PKT_LEN_MASK 0x1FFFFF 207497492a7Sjmatthew #define UAQ_TX_PKT_DROP_PADD (1 << 28) 208497492a7Sjmatthew #define UAQ_TX_PKT_VLAN (1 << 29) 209497492a7Sjmatthew #define UAQ_TX_PKT_VLAN_MASK 0xFFFF 210497492a7Sjmatthew #define UAQ_TX_PKT_VLAN_SHIFT 0x30 211497492a7Sjmatthew 212497492a7Sjmatthew 213497492a7Sjmatthew struct uaq_chain { 214497492a7Sjmatthew struct uaq_softc *uc_sc; 215497492a7Sjmatthew struct usbd_xfer *uc_xfer; 216497492a7Sjmatthew char *uc_buf; 217497492a7Sjmatthew uint32_t uc_cnt; 218497492a7Sjmatthew uint32_t uc_buflen; 219497492a7Sjmatthew uint32_t uc_bufmax; 220497492a7Sjmatthew SLIST_ENTRY(uaq_chain) uc_list; 221497492a7Sjmatthew uint8_t uc_idx; 222497492a7Sjmatthew }; 223497492a7Sjmatthew 224497492a7Sjmatthew struct uaq_cdata { 225497492a7Sjmatthew struct uaq_chain uaq_rx_chain[UAQ_RX_LIST_CNT]; 226497492a7Sjmatthew struct uaq_chain uaq_tx_chain[UAQ_TX_LIST_CNT]; 227497492a7Sjmatthew SLIST_HEAD(uaq_list_head, uaq_chain) uaq_tx_free; 228497492a7Sjmatthew }; 229497492a7Sjmatthew 230497492a7Sjmatthew struct uaq_softc { 231497492a7Sjmatthew struct device sc_dev; 232497492a7Sjmatthew struct usbd_device *sc_udev; 233497492a7Sjmatthew 234497492a7Sjmatthew struct usbd_interface *sc_iface; 235497492a7Sjmatthew struct usb_task sc_link_task; 236497492a7Sjmatthew struct timeval sc_rx_notice; 237497492a7Sjmatthew int sc_ed[UAQ_ENDPT_MAX]; 238497492a7Sjmatthew struct usbd_pipe *sc_ep[UAQ_ENDPT_MAX]; 239497492a7Sjmatthew int sc_out_frame_size; 240497492a7Sjmatthew 241497492a7Sjmatthew struct arpcom sc_ac; 242497492a7Sjmatthew struct ifmedia sc_ifmedia; 243497492a7Sjmatthew 244497492a7Sjmatthew struct uaq_cdata sc_cdata; 245497492a7Sjmatthew uint64_t sc_link_status; 246497492a7Sjmatthew int sc_link_speed; 247497492a7Sjmatthew 248497492a7Sjmatthew uint32_t sc_phy_cfg; 249497492a7Sjmatthew uint16_t sc_rxctl; 250497492a7Sjmatthew }; 251497492a7Sjmatthew 252497492a7Sjmatthew const struct usb_devno uaq_devs[] = { 253497492a7Sjmatthew { USB_VENDOR_AQUANTIA, USB_PRODUCT_AQUANTIA_AQC111 }, 254497492a7Sjmatthew { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_ASIX111 }, 255497492a7Sjmatthew { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_ASIX112 }, 256497492a7Sjmatthew { USB_VENDOR_TRENDNET, USB_PRODUCT_TRENDNET_TUCET5G }, 257497492a7Sjmatthew { USB_VENDOR_QNAP, USB_PRODUCT_QNAP_UC5G1T }, 258497492a7Sjmatthew }; 259497492a7Sjmatthew 260497492a7Sjmatthew int uaq_match(struct device *, void *, void *); 261497492a7Sjmatthew void uaq_attach(struct device *, struct device *, void *); 262497492a7Sjmatthew int uaq_detach(struct device *, int); 263497492a7Sjmatthew 264497492a7Sjmatthew int uaq_ctl(struct uaq_softc *, uint8_t, uint8_t, uint16_t, 265497492a7Sjmatthew uint16_t, void *, int); 266497492a7Sjmatthew int uaq_read_mem(struct uaq_softc *, uint8_t, uint16_t, uint16_t, 267497492a7Sjmatthew void *, int); 268497492a7Sjmatthew int uaq_write_mem(struct uaq_softc *, uint8_t, uint16_t, uint16_t, 269497492a7Sjmatthew void *, int); 270497492a7Sjmatthew uint8_t uaq_read_1(struct uaq_softc *, uint8_t, uint16_t, uint16_t); 271497492a7Sjmatthew uint16_t uaq_read_2(struct uaq_softc *, uint8_t, uint16_t, uint16_t); 272497492a7Sjmatthew uint32_t uaq_read_4(struct uaq_softc *, uint8_t, uint16_t, uint16_t); 273497492a7Sjmatthew int uaq_write_1(struct uaq_softc *, uint8_t, uint16_t, uint16_t, 274497492a7Sjmatthew uint32_t); 275497492a7Sjmatthew int uaq_write_2(struct uaq_softc *, uint8_t, uint16_t, uint16_t, 276497492a7Sjmatthew uint32_t); 277497492a7Sjmatthew int uaq_write_4(struct uaq_softc *, uint8_t, uint16_t, uint16_t, 278497492a7Sjmatthew uint32_t); 279497492a7Sjmatthew 280497492a7Sjmatthew int uaq_ifmedia_upd(struct ifnet *); 281497492a7Sjmatthew void uaq_ifmedia_sts(struct ifnet *, struct ifmediareq *); 282497492a7Sjmatthew void uaq_add_media_types(struct uaq_softc *); 283497492a7Sjmatthew void uaq_iff(struct uaq_softc *); 284497492a7Sjmatthew 285497492a7Sjmatthew void uaq_init(void *); 286497492a7Sjmatthew int uaq_ioctl(struct ifnet *, u_long, caddr_t); 287497492a7Sjmatthew int uaq_xfer_list_init(struct uaq_softc *, struct uaq_chain *, 288497492a7Sjmatthew uint32_t, int); 289497492a7Sjmatthew void uaq_xfer_list_free(struct uaq_softc *, struct uaq_chain *, int); 290497492a7Sjmatthew 291497492a7Sjmatthew void uaq_stop(struct uaq_softc *); 292497492a7Sjmatthew void uaq_link(struct uaq_softc *); 293497492a7Sjmatthew void uaq_intr(struct usbd_xfer *, void *, usbd_status); 294497492a7Sjmatthew void uaq_start(struct ifnet *); 295497492a7Sjmatthew void uaq_rxeof(struct usbd_xfer *, void *, usbd_status); 296497492a7Sjmatthew void uaq_txeof(struct usbd_xfer *, void *, usbd_status); 297497492a7Sjmatthew void uaq_watchdog(struct ifnet *); 298497492a7Sjmatthew void uaq_reset(struct uaq_softc *); 299497492a7Sjmatthew 300497492a7Sjmatthew int uaq_encap_txpkt(struct uaq_softc *, struct mbuf *, char *, 301497492a7Sjmatthew uint32_t); 302497492a7Sjmatthew int uaq_encap_xfer(struct uaq_softc *, struct uaq_chain *); 303497492a7Sjmatthew 304497492a7Sjmatthew struct cfdriver uaq_cd = { 305497492a7Sjmatthew NULL, "uaq", DV_IFNET 306497492a7Sjmatthew }; 307497492a7Sjmatthew 308497492a7Sjmatthew const struct cfattach uaq_ca = { 309497492a7Sjmatthew sizeof(struct uaq_softc), uaq_match, uaq_attach, uaq_detach 310497492a7Sjmatthew }; 311497492a7Sjmatthew 312497492a7Sjmatthew int 313497492a7Sjmatthew uaq_ctl(struct uaq_softc *sc, uint8_t rw, uint8_t cmd, uint16_t val, 314497492a7Sjmatthew uint16_t index, void *buf, int len) 315497492a7Sjmatthew { 316497492a7Sjmatthew usb_device_request_t req; 317497492a7Sjmatthew usbd_status err; 318497492a7Sjmatthew 319497492a7Sjmatthew if (usbd_is_dying(sc->sc_udev)) 320497492a7Sjmatthew return 0; 321497492a7Sjmatthew 322497492a7Sjmatthew if (rw == UAQ_CTL_WRITE) 323497492a7Sjmatthew req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 324497492a7Sjmatthew else 325497492a7Sjmatthew req.bmRequestType = UT_READ_VENDOR_DEVICE; 326497492a7Sjmatthew req.bRequest = cmd; 327497492a7Sjmatthew USETW(req.wValue, val); 328497492a7Sjmatthew USETW(req.wIndex, index); 329497492a7Sjmatthew USETW(req.wLength, len); 330497492a7Sjmatthew 331497492a7Sjmatthew DPRINTFN(5, ("uaq_ctl: rw %d, val 0x%04hx, index 0x%04hx, len %d\n", 332497492a7Sjmatthew rw, val, index, len)); 333497492a7Sjmatthew err = usbd_do_request(sc->sc_udev, &req, buf); 334497492a7Sjmatthew if (err) { 335497492a7Sjmatthew DPRINTF(("uaq_ctl: error %d\n", err)); 336497492a7Sjmatthew return -1; 337497492a7Sjmatthew } 338497492a7Sjmatthew 339497492a7Sjmatthew return 0; 340497492a7Sjmatthew } 341497492a7Sjmatthew 342497492a7Sjmatthew int 343497492a7Sjmatthew uaq_read_mem(struct uaq_softc *sc, uint8_t cmd, uint16_t addr, uint16_t index, 344497492a7Sjmatthew void *buf, int len) 345497492a7Sjmatthew { 346497492a7Sjmatthew return (uaq_ctl(sc, UAQ_CTL_READ, cmd, addr, index, buf, len)); 347497492a7Sjmatthew } 348497492a7Sjmatthew 349497492a7Sjmatthew int 350497492a7Sjmatthew uaq_write_mem(struct uaq_softc *sc, uint8_t cmd, uint16_t addr, uint16_t index, 351497492a7Sjmatthew void *buf, int len) 352497492a7Sjmatthew { 353497492a7Sjmatthew return (uaq_ctl(sc, UAQ_CTL_WRITE, cmd, addr, index, buf, len)); 354497492a7Sjmatthew } 355497492a7Sjmatthew 356497492a7Sjmatthew uint8_t 357497492a7Sjmatthew uaq_read_1(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index) 358497492a7Sjmatthew { 359497492a7Sjmatthew uint8_t val; 360497492a7Sjmatthew 361497492a7Sjmatthew uaq_read_mem(sc, cmd, reg, index, &val, 1); 362497492a7Sjmatthew DPRINTFN(4, ("uaq_read_1: cmd %x reg %x index %x = %x\n", cmd, reg, 363497492a7Sjmatthew index, val)); 364497492a7Sjmatthew return (val); 365497492a7Sjmatthew } 366497492a7Sjmatthew 367497492a7Sjmatthew uint16_t 368497492a7Sjmatthew uaq_read_2(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index) 369497492a7Sjmatthew { 370497492a7Sjmatthew uint16_t val; 371497492a7Sjmatthew 372497492a7Sjmatthew uaq_read_mem(sc, cmd, reg, index, &val, 2); 373497492a7Sjmatthew DPRINTFN(4, ("uaq_read_2: cmd %x reg %x index %x = %x\n", cmd, reg, 374497492a7Sjmatthew index, UGETW(&val))); 375497492a7Sjmatthew 376497492a7Sjmatthew return (UGETW(&val)); 377497492a7Sjmatthew } 378497492a7Sjmatthew 379497492a7Sjmatthew uint32_t 380497492a7Sjmatthew uaq_read_4(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index) 381497492a7Sjmatthew { 382497492a7Sjmatthew uint32_t val; 383497492a7Sjmatthew 384497492a7Sjmatthew uaq_read_mem(sc, cmd, reg, index, &val, 4); 385497492a7Sjmatthew DPRINTFN(4, ("uaq_read_4: cmd %x reg %x index %x = %x\n", cmd, reg, 386497492a7Sjmatthew index, UGETDW(&val))); 387497492a7Sjmatthew return (UGETDW(&val)); 388497492a7Sjmatthew } 389497492a7Sjmatthew 390497492a7Sjmatthew int 391497492a7Sjmatthew uaq_write_1(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index, 392497492a7Sjmatthew uint32_t val) 393497492a7Sjmatthew { 394497492a7Sjmatthew uint8_t temp; 395497492a7Sjmatthew 396497492a7Sjmatthew DPRINTFN(4, ("uaq_write_1: cmd %x reg %x index %x: %x\n", cmd, reg, 397497492a7Sjmatthew index, val)); 398497492a7Sjmatthew temp = val & 0xff; 399497492a7Sjmatthew return (uaq_write_mem(sc, cmd, reg, index, &temp, 1)); 400497492a7Sjmatthew } 401497492a7Sjmatthew 402497492a7Sjmatthew int 403497492a7Sjmatthew uaq_write_2(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index, 404497492a7Sjmatthew uint32_t val) 405497492a7Sjmatthew { 406497492a7Sjmatthew uint16_t temp; 407497492a7Sjmatthew 408497492a7Sjmatthew DPRINTFN(4, ("uaq_write_2: cmd %x reg %x index %x: %x\n", cmd, reg, 409497492a7Sjmatthew index, val)); 410497492a7Sjmatthew USETW(&temp, val & 0xffff); 411497492a7Sjmatthew return (uaq_write_mem(sc, cmd, reg, index, &temp, 2)); 412497492a7Sjmatthew } 413497492a7Sjmatthew 414497492a7Sjmatthew int 415497492a7Sjmatthew uaq_write_4(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index, 416497492a7Sjmatthew uint32_t val) 417497492a7Sjmatthew { 418497492a7Sjmatthew uint8_t temp[4]; 419497492a7Sjmatthew 420497492a7Sjmatthew DPRINTFN(4, ("uaq_write_4: cmd %x reg %x index %x: %x\n", cmd, reg, 421497492a7Sjmatthew index, val)); 422497492a7Sjmatthew USETDW(temp, val); 423497492a7Sjmatthew return (uaq_write_mem(sc, cmd, reg, index, &temp, 4)); 424497492a7Sjmatthew } 425497492a7Sjmatthew 426497492a7Sjmatthew int 427497492a7Sjmatthew uaq_match(struct device *parent, void *match, void *aux) 428497492a7Sjmatthew { 429497492a7Sjmatthew struct usb_attach_arg *uaa = aux; 430497492a7Sjmatthew 431497492a7Sjmatthew if (uaa->iface == NULL || uaa->configno != 1) 432497492a7Sjmatthew return (UMATCH_NONE); 433497492a7Sjmatthew 434497492a7Sjmatthew return (usb_lookup(uaq_devs, uaa->vendor, uaa->product) != NULL ? 435497492a7Sjmatthew UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE); 436497492a7Sjmatthew } 437497492a7Sjmatthew 438497492a7Sjmatthew void 439497492a7Sjmatthew uaq_attach(struct device *parent, struct device *self, void *aux) 440497492a7Sjmatthew { 441497492a7Sjmatthew struct uaq_softc *sc = (struct uaq_softc *)self; 442497492a7Sjmatthew struct usb_attach_arg *uaa = aux; 443497492a7Sjmatthew usb_interface_descriptor_t *id; 444497492a7Sjmatthew usb_endpoint_descriptor_t *ed; 445497492a7Sjmatthew struct ifnet *ifp; 446497492a7Sjmatthew int i, s; 447497492a7Sjmatthew 448497492a7Sjmatthew sc->sc_udev = uaa->device; 449497492a7Sjmatthew sc->sc_iface = uaa->iface; 450497492a7Sjmatthew 451497492a7Sjmatthew usb_init_task(&sc->sc_link_task, (void (*)(void *))uaq_link, sc, 452497492a7Sjmatthew USB_TASK_TYPE_GENERIC); 453497492a7Sjmatthew 454497492a7Sjmatthew id = usbd_get_interface_descriptor(sc->sc_iface); 455497492a7Sjmatthew 456497492a7Sjmatthew for (i = 0; i < id->bNumEndpoints; i++) { 457497492a7Sjmatthew ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 458497492a7Sjmatthew if (!ed) { 459497492a7Sjmatthew printf("%s: couldn't get ep %d\n", 460497492a7Sjmatthew sc->sc_dev.dv_xname, i); 461497492a7Sjmatthew return; 462497492a7Sjmatthew } 463497492a7Sjmatthew if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 464497492a7Sjmatthew UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 465497492a7Sjmatthew sc->sc_ed[UAQ_ENDPT_RX] = ed->bEndpointAddress; 466497492a7Sjmatthew } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 467497492a7Sjmatthew UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 468497492a7Sjmatthew sc->sc_ed[UAQ_ENDPT_TX] = ed->bEndpointAddress; 469497492a7Sjmatthew sc->sc_out_frame_size = UGETW(ed->wMaxPacketSize); 470497492a7Sjmatthew } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 471497492a7Sjmatthew UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 472497492a7Sjmatthew sc->sc_ed[UAQ_ENDPT_INTR] = ed->bEndpointAddress; 473497492a7Sjmatthew } 474497492a7Sjmatthew } 475497492a7Sjmatthew 476497492a7Sjmatthew if ((sc->sc_ed[UAQ_ENDPT_RX] == 0) || 477497492a7Sjmatthew (sc->sc_ed[UAQ_ENDPT_TX] == 0) || 478497492a7Sjmatthew (sc->sc_ed[UAQ_ENDPT_INTR] == 0)) { 479497492a7Sjmatthew printf("%s: missing one or more endpoints (%d, %d, %d)\n", 480497492a7Sjmatthew sc->sc_dev.dv_xname, sc->sc_ed[UAQ_ENDPT_RX], 481497492a7Sjmatthew sc->sc_ed[UAQ_ENDPT_TX], sc->sc_ed[UAQ_ENDPT_INTR]); 482497492a7Sjmatthew return; 483497492a7Sjmatthew } 484497492a7Sjmatthew 485497492a7Sjmatthew s = splnet(); 486497492a7Sjmatthew 487497492a7Sjmatthew printf("%s: ver %u.%u.%u", sc->sc_dev.dv_xname, 488497492a7Sjmatthew uaq_read_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_FW_VER_MAJOR, 1) & 0x7f, 489497492a7Sjmatthew uaq_read_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_FW_VER_MINOR, 1), 490497492a7Sjmatthew uaq_read_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_FW_VER_REV, 1)); 491497492a7Sjmatthew 492497492a7Sjmatthew uaq_read_mem(sc, UAQ_CMD_FLASH_PARAM, 0, 0, &sc->sc_ac.ac_enaddr, 493497492a7Sjmatthew ETHER_ADDR_LEN); 494497492a7Sjmatthew printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr)); 495497492a7Sjmatthew 496497492a7Sjmatthew ifp = &sc->sc_ac.ac_if; 497497492a7Sjmatthew ifp->if_softc = sc; 498497492a7Sjmatthew strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 499497492a7Sjmatthew ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 500497492a7Sjmatthew ifp->if_ioctl = uaq_ioctl; 501497492a7Sjmatthew ifp->if_start = uaq_start; 502497492a7Sjmatthew ifp->if_watchdog = uaq_watchdog; 503497492a7Sjmatthew 504497492a7Sjmatthew ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_CSUM_IPv4 | 505497492a7Sjmatthew IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4; 506497492a7Sjmatthew 507497492a7Sjmatthew #if NVLAN > 0 508497492a7Sjmatthew ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 509497492a7Sjmatthew #endif 510497492a7Sjmatthew 511497492a7Sjmatthew ifmedia_init(&sc->sc_ifmedia, IFM_IMASK, uaq_ifmedia_upd, 512497492a7Sjmatthew uaq_ifmedia_sts); 513497492a7Sjmatthew uaq_add_media_types(sc); 514497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); 515497492a7Sjmatthew ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO); 516497492a7Sjmatthew sc->sc_ifmedia.ifm_media = sc->sc_ifmedia.ifm_cur->ifm_media; 517497492a7Sjmatthew 518497492a7Sjmatthew if_attach(ifp); 519497492a7Sjmatthew ether_ifattach(ifp); 520497492a7Sjmatthew 521497492a7Sjmatthew splx(s); 522497492a7Sjmatthew } 523497492a7Sjmatthew 524497492a7Sjmatthew int 525497492a7Sjmatthew uaq_detach(struct device *self, int flags) 526497492a7Sjmatthew { 527497492a7Sjmatthew struct uaq_softc *sc = (struct uaq_softc *)self; 528497492a7Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 529497492a7Sjmatthew int s; 530497492a7Sjmatthew 531497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_TX] != NULL) 532497492a7Sjmatthew usbd_abort_pipe(sc->sc_ep[UAQ_ENDPT_TX]); 533497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_RX] != NULL) 534497492a7Sjmatthew usbd_abort_pipe(sc->sc_ep[UAQ_ENDPT_RX]); 535497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_INTR] != NULL) 536497492a7Sjmatthew usbd_abort_pipe(sc->sc_ep[UAQ_ENDPT_INTR]); 537497492a7Sjmatthew 538497492a7Sjmatthew s = splusb(); 539497492a7Sjmatthew 540497492a7Sjmatthew usb_rem_task(sc->sc_udev, &sc->sc_link_task); 541497492a7Sjmatthew 542497492a7Sjmatthew usb_detach_wait(&sc->sc_dev); 543497492a7Sjmatthew 544497492a7Sjmatthew if (ifp->if_flags & IFF_RUNNING) 545497492a7Sjmatthew uaq_stop(sc); 546497492a7Sjmatthew 547497492a7Sjmatthew if (ifp->if_softc != NULL) { 548497492a7Sjmatthew ether_ifdetach(ifp); 549497492a7Sjmatthew if_detach(ifp); 550497492a7Sjmatthew } 551497492a7Sjmatthew 552497492a7Sjmatthew splx(s); 553497492a7Sjmatthew 554497492a7Sjmatthew return 0; 555497492a7Sjmatthew } 556497492a7Sjmatthew 557497492a7Sjmatthew int 558497492a7Sjmatthew uaq_ifmedia_upd(struct ifnet *ifp) 559497492a7Sjmatthew { 560497492a7Sjmatthew struct uaq_softc *sc = ifp->if_softc; 561497492a7Sjmatthew struct ifmedia *ifm = &sc->sc_ifmedia; 562497492a7Sjmatthew int auto_adv; 563497492a7Sjmatthew 564497492a7Sjmatthew if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 565497492a7Sjmatthew return (EINVAL); 566497492a7Sjmatthew 567497492a7Sjmatthew auto_adv = UAQ_PHY_ADV_100M | UAQ_PHY_ADV_1G; 568497492a7Sjmatthew if (sc->sc_udev->speed == USB_SPEED_SUPER) 569497492a7Sjmatthew auto_adv |= UAQ_PHY_ADV_2_5G | UAQ_PHY_ADV_5G; 570497492a7Sjmatthew 571497492a7Sjmatthew sc->sc_phy_cfg &= ~(UAQ_PHY_ADV_MASK); 572497492a7Sjmatthew sc->sc_phy_cfg |= UAQ_PHY_PAUSE | UAQ_PHY_ASYM_PAUSE | 573497492a7Sjmatthew UAQ_PHY_DOWNSHIFT | (3 << UAQ_PHY_DSH_RETRY_SHIFT); 574497492a7Sjmatthew 575497492a7Sjmatthew switch (IFM_SUBTYPE(ifm->ifm_media)) { 576497492a7Sjmatthew case IFM_AUTO: 577497492a7Sjmatthew sc->sc_phy_cfg |= auto_adv; 578497492a7Sjmatthew break; 579497492a7Sjmatthew case IFM_5000_T: 580497492a7Sjmatthew sc->sc_phy_cfg |= UAQ_PHY_ADV_5G; 581497492a7Sjmatthew break; 582497492a7Sjmatthew case IFM_2500_T: 583497492a7Sjmatthew sc->sc_phy_cfg |= UAQ_PHY_ADV_2_5G; 584497492a7Sjmatthew break; 585497492a7Sjmatthew case IFM_1000_T: 586497492a7Sjmatthew sc->sc_phy_cfg |= UAQ_PHY_ADV_1G; 587497492a7Sjmatthew break; 588497492a7Sjmatthew case IFM_100_TX: 589497492a7Sjmatthew sc->sc_phy_cfg |= UAQ_PHY_ADV_100M; 590497492a7Sjmatthew break; 591497492a7Sjmatthew default: 592497492a7Sjmatthew printf("%s: unsupported media type\n", sc->sc_dev.dv_xname); 593497492a7Sjmatthew return (EINVAL); 594497492a7Sjmatthew } 595497492a7Sjmatthew 596497492a7Sjmatthew DPRINTFN(1, ("%s: phy cfg %x\n", sc->sc_dev.dv_xname, sc->sc_phy_cfg)); 597497492a7Sjmatthew uaq_write_4(sc, UAQ_CMD_PHY_OPS, 0, 0, sc->sc_phy_cfg); 598497492a7Sjmatthew return (0); 599497492a7Sjmatthew } 600497492a7Sjmatthew 601497492a7Sjmatthew void 602497492a7Sjmatthew uaq_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 603497492a7Sjmatthew { 604497492a7Sjmatthew struct uaq_softc *sc = ifp->if_softc; 605497492a7Sjmatthew 606497492a7Sjmatthew ifmr->ifm_status = IFM_AVALID; 607497492a7Sjmatthew if (sc->sc_link_speed > 0) { 608497492a7Sjmatthew ifmr->ifm_status |= IFM_ACTIVE; 609497492a7Sjmatthew ifmr->ifm_active = IFM_ETHER | IFM_FDX; 610497492a7Sjmatthew switch (sc->sc_link_speed) { 611497492a7Sjmatthew case UAQ_STATUS_SPEED_5G: 612497492a7Sjmatthew ifmr->ifm_active |= IFM_5000_T; 613497492a7Sjmatthew break; 614497492a7Sjmatthew case UAQ_STATUS_SPEED_2_5G: 615497492a7Sjmatthew ifmr->ifm_active |= IFM_2500_T; 616497492a7Sjmatthew break; 617497492a7Sjmatthew case UAQ_STATUS_SPEED_1G: 618497492a7Sjmatthew ifmr->ifm_active |= IFM_1000_T; 619497492a7Sjmatthew break; 620497492a7Sjmatthew case UAQ_STATUS_SPEED_100M: 621497492a7Sjmatthew ifmr->ifm_active |= IFM_100_TX; 622497492a7Sjmatthew break; 623497492a7Sjmatthew default: 624497492a7Sjmatthew break; 625497492a7Sjmatthew } 626497492a7Sjmatthew } 627497492a7Sjmatthew } 628497492a7Sjmatthew 629497492a7Sjmatthew void 630497492a7Sjmatthew uaq_add_media_types(struct uaq_softc *sc) 631497492a7Sjmatthew { 632497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL); 633497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, 634497492a7Sjmatthew NULL); 635497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_1000_T, 0, NULL); 636497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, 637497492a7Sjmatthew NULL); 638497492a7Sjmatthew /* only add 2.5G and 5G if at super speed */ 639497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_2500_T, 0, NULL); 640497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_2500_T | IFM_FDX, 0, 641497492a7Sjmatthew NULL); 642497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_5000_T, 0, NULL); 643497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_5000_T | IFM_FDX, 0, 644497492a7Sjmatthew NULL); 645497492a7Sjmatthew } 646497492a7Sjmatthew 647497492a7Sjmatthew void 648497492a7Sjmatthew uaq_iff(struct uaq_softc *sc) 649497492a7Sjmatthew { 650497492a7Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 651497492a7Sjmatthew struct ether_multi *enm; 652497492a7Sjmatthew struct ether_multistep step; 653497492a7Sjmatthew uint8_t filter[UAQ_MCAST_FILTER_SIZE]; 654497492a7Sjmatthew uint32_t hash; 655497492a7Sjmatthew 656497492a7Sjmatthew if (usbd_is_dying(sc->sc_udev)) 657497492a7Sjmatthew return; 658497492a7Sjmatthew 659497492a7Sjmatthew sc->sc_rxctl &= ~(UAQ_SFR_RX_CTL_PRO | UAQ_SFR_RX_CTL_AMALL | 660497492a7Sjmatthew UAQ_SFR_RX_CTL_AM); 661093575ddSjmatthew ifp->if_flags &= ~IFF_ALLMULTI; 662093575ddSjmatthew 663093575ddSjmatthew if (ifp->if_flags & IFF_PROMISC) { 664093575ddSjmatthew ifp->if_flags |= IFF_ALLMULTI; 665497492a7Sjmatthew sc->sc_rxctl |= UAQ_SFR_RX_CTL_PRO; 666093575ddSjmatthew } else if (sc->sc_ac.ac_multirangecnt > 0) { 667093575ddSjmatthew ifp->if_flags |= IFF_ALLMULTI; 668497492a7Sjmatthew sc->sc_rxctl |= UAQ_SFR_RX_CTL_AMALL; 669093575ddSjmatthew } else { 670497492a7Sjmatthew sc->sc_rxctl |= UAQ_SFR_RX_CTL_AM; 671497492a7Sjmatthew 672497492a7Sjmatthew bzero(filter, sizeof(filter)); 673497492a7Sjmatthew ETHER_FIRST_MULTI(step, &sc->sc_ac, enm); 674497492a7Sjmatthew while (enm != NULL) { 675497492a7Sjmatthew hash = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) 676497492a7Sjmatthew >> 26; 677497492a7Sjmatthew filter[hash >> 3] |= (1 << (hash & 7)); 678497492a7Sjmatthew ETHER_NEXT_MULTI(step, enm); 679497492a7Sjmatthew } 680497492a7Sjmatthew 681497492a7Sjmatthew uaq_write_mem(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MCAST_FILTER, 682497492a7Sjmatthew UAQ_MCAST_FILTER_SIZE, filter, UAQ_MCAST_FILTER_SIZE); 683497492a7Sjmatthew } 684497492a7Sjmatthew 685497492a7Sjmatthew DPRINTFN(1, ("%s: rxctl = %x\n", sc->sc_dev.dv_xname, sc->sc_rxctl)); 686497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RX_CTL, 2, sc->sc_rxctl); 687497492a7Sjmatthew } 688497492a7Sjmatthew 689497492a7Sjmatthew void 690497492a7Sjmatthew uaq_reset(struct uaq_softc *sc) 691497492a7Sjmatthew { 692497492a7Sjmatthew uint8_t mode; 693497492a7Sjmatthew 694497492a7Sjmatthew sc->sc_phy_cfg = UAQ_PHY_POWER_EN; 695497492a7Sjmatthew uaq_write_4(sc, UAQ_CMD_PHY_OPS, 0, 0, sc->sc_phy_cfg); 696497492a7Sjmatthew 697497492a7Sjmatthew uaq_write_mem(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_NODE_ID, 0, 698497492a7Sjmatthew sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); 699497492a7Sjmatthew uaq_write_mem(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_NODE_ID, ETHER_ADDR_LEN, 700497492a7Sjmatthew sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); 701497492a7Sjmatthew 702497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BM_INT_MASK, 0, 0xff); 703497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_SWP_CTRL, 0, 0); 704497492a7Sjmatthew 705497492a7Sjmatthew mode = uaq_read_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MONITOR_MODE, 1); 706497492a7Sjmatthew mode &= ~(UAQ_SFR_MONITOR_MODE_EPHYRW | UAQ_SFR_MONITOR_MODE_RWLC | 707497492a7Sjmatthew UAQ_SFR_MONITOR_MODE_RWMP | UAQ_SFR_MONITOR_MODE_RWWF | 708497492a7Sjmatthew UAQ_SFR_MONITOR_MODE_RW_FLAG); 709497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MONITOR_MODE, 1, mode); 710497492a7Sjmatthew 711497492a7Sjmatthew sc->sc_link_status = 0; 712497492a7Sjmatthew sc->sc_link_speed = 0; 713497492a7Sjmatthew } 714497492a7Sjmatthew 715497492a7Sjmatthew void 716497492a7Sjmatthew uaq_init(void *xsc) 717497492a7Sjmatthew { 718497492a7Sjmatthew struct uaq_softc *sc = xsc; 719497492a7Sjmatthew struct uaq_chain *c; 720497492a7Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 721497492a7Sjmatthew usbd_status err; 722497492a7Sjmatthew int s, i; 723497492a7Sjmatthew 724497492a7Sjmatthew s = splnet(); 725497492a7Sjmatthew 726497492a7Sjmatthew uaq_stop(sc); 727497492a7Sjmatthew 728497492a7Sjmatthew uaq_reset(sc); 729497492a7Sjmatthew 730497492a7Sjmatthew if (uaq_xfer_list_init(sc, sc->sc_cdata.uaq_rx_chain, 731497492a7Sjmatthew UAQ_RX_BUFSZ, UAQ_RX_LIST_CNT) == ENOBUFS) { 732497492a7Sjmatthew printf("%s: rx list init failed\n", sc->sc_dev.dv_xname); 733497492a7Sjmatthew splx(s); 734497492a7Sjmatthew return; 735497492a7Sjmatthew } 736497492a7Sjmatthew 737497492a7Sjmatthew if (uaq_xfer_list_init(sc, sc->sc_cdata.uaq_tx_chain, 738497492a7Sjmatthew UAQ_TX_BUFSZ, UAQ_TX_LIST_CNT) == ENOBUFS) { 739497492a7Sjmatthew printf("%s: tx list init failed\n", sc->sc_dev.dv_xname); 740497492a7Sjmatthew splx(s); 741497492a7Sjmatthew return; 742497492a7Sjmatthew } 743497492a7Sjmatthew 744497492a7Sjmatthew SLIST_INIT(&sc->sc_cdata.uaq_tx_free); 745497492a7Sjmatthew for (i = 0; i < UAQ_TX_LIST_CNT; i++) 746497492a7Sjmatthew SLIST_INSERT_HEAD(&sc->sc_cdata.uaq_tx_free, 747497492a7Sjmatthew &sc->sc_cdata.uaq_tx_chain[i], uc_list); 748497492a7Sjmatthew 749497492a7Sjmatthew err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UAQ_ENDPT_RX], 750497492a7Sjmatthew USBD_EXCLUSIVE_USE, &sc->sc_ep[UAQ_ENDPT_RX]); 751497492a7Sjmatthew if (err) { 752497492a7Sjmatthew printf("%s: open rx pipe failed: %s\n", 753497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(err)); 754497492a7Sjmatthew splx(s); 755497492a7Sjmatthew return; 756497492a7Sjmatthew } 757497492a7Sjmatthew 758497492a7Sjmatthew err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UAQ_ENDPT_TX], 759497492a7Sjmatthew USBD_EXCLUSIVE_USE, &sc->sc_ep[UAQ_ENDPT_TX]); 760497492a7Sjmatthew if (err) { 761497492a7Sjmatthew printf("%s: open tx pipe failed: %s\n", 762497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(err)); 763497492a7Sjmatthew splx(s); 764497492a7Sjmatthew return; 765497492a7Sjmatthew } 766497492a7Sjmatthew 767497492a7Sjmatthew for (i = 0; i < UAQ_RX_LIST_CNT; i++) { 768497492a7Sjmatthew c = &sc->sc_cdata.uaq_rx_chain[i]; 769497492a7Sjmatthew usbd_setup_xfer(c->uc_xfer, sc->sc_ep[UAQ_ENDPT_RX], 770497492a7Sjmatthew c, c->uc_buf, c->uc_bufmax, 771497492a7Sjmatthew USBD_SHORT_XFER_OK | USBD_NO_COPY, 772497492a7Sjmatthew USBD_NO_TIMEOUT, uaq_rxeof); 773497492a7Sjmatthew usbd_transfer(c->uc_xfer); 774497492a7Sjmatthew } 775497492a7Sjmatthew 776497492a7Sjmatthew err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ed[UAQ_ENDPT_INTR], 777497492a7Sjmatthew 0, &sc->sc_ep[UAQ_ENDPT_INTR], sc, 778497492a7Sjmatthew &sc->sc_link_status, sizeof(sc->sc_link_status), uaq_intr, 779497492a7Sjmatthew USBD_DEFAULT_INTERVAL); 780497492a7Sjmatthew if (err) { 781497492a7Sjmatthew printf("%s: couldn't open interrupt pipe\n", 782497492a7Sjmatthew sc->sc_dev.dv_xname); 783497492a7Sjmatthew return; 784497492a7Sjmatthew } 785497492a7Sjmatthew 786093575ddSjmatthew uaq_iff(sc); 787093575ddSjmatthew 788497492a7Sjmatthew uaq_ifmedia_upd(ifp); 789497492a7Sjmatthew 790497492a7Sjmatthew ifp->if_flags |= IFF_RUNNING; 791497492a7Sjmatthew ifq_clr_oactive(&ifp->if_snd); 792497492a7Sjmatthew 793497492a7Sjmatthew splx(s); 794497492a7Sjmatthew } 795497492a7Sjmatthew 796497492a7Sjmatthew int 797497492a7Sjmatthew uaq_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 798497492a7Sjmatthew { 799497492a7Sjmatthew struct uaq_softc *sc = ifp->if_softc; 800497492a7Sjmatthew struct ifreq *ifr = (struct ifreq *)data; 801497492a7Sjmatthew int s, error = 0; 802497492a7Sjmatthew 803497492a7Sjmatthew s = splnet(); 804497492a7Sjmatthew 805497492a7Sjmatthew switch (cmd) { 806497492a7Sjmatthew case SIOCSIFADDR: 807497492a7Sjmatthew ifp->if_flags |= IFF_UP; 808497492a7Sjmatthew if (!(ifp->if_flags & IFF_RUNNING)) 809497492a7Sjmatthew uaq_init(sc); 810497492a7Sjmatthew break; 811497492a7Sjmatthew 812497492a7Sjmatthew case SIOCSIFFLAGS: 813497492a7Sjmatthew if (ifp->if_flags & IFF_UP) { 814497492a7Sjmatthew if (ifp->if_flags & IFF_RUNNING) 815497492a7Sjmatthew error = ENETRESET; 816497492a7Sjmatthew else 817497492a7Sjmatthew uaq_init(sc); 818497492a7Sjmatthew } else { 819497492a7Sjmatthew if (ifp->if_flags & IFF_RUNNING) 820497492a7Sjmatthew uaq_stop(sc); 821497492a7Sjmatthew } 822497492a7Sjmatthew break; 823497492a7Sjmatthew 824497492a7Sjmatthew case SIOCGIFMEDIA: 825497492a7Sjmatthew case SIOCSIFMEDIA: 826497492a7Sjmatthew error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd); 827497492a7Sjmatthew break; 828497492a7Sjmatthew 829497492a7Sjmatthew default: 830497492a7Sjmatthew error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 831497492a7Sjmatthew } 832497492a7Sjmatthew 833497492a7Sjmatthew if (error == ENETRESET) { 834497492a7Sjmatthew if (ifp->if_flags & IFF_RUNNING) 835497492a7Sjmatthew uaq_iff(sc); 836497492a7Sjmatthew error = 0; 837497492a7Sjmatthew } 838497492a7Sjmatthew 839497492a7Sjmatthew splx(s); 840497492a7Sjmatthew 841497492a7Sjmatthew return (error); 842497492a7Sjmatthew } 843497492a7Sjmatthew 844497492a7Sjmatthew int 845497492a7Sjmatthew uaq_xfer_list_init(struct uaq_softc *sc, struct uaq_chain *ch, 846497492a7Sjmatthew uint32_t bufsize, int listlen) 847497492a7Sjmatthew { 848497492a7Sjmatthew struct uaq_chain *c; 849497492a7Sjmatthew int i; 850497492a7Sjmatthew 851497492a7Sjmatthew for (i = 0; i < listlen; i++) { 852497492a7Sjmatthew c = &ch[i]; 853497492a7Sjmatthew c->uc_sc = sc; 854497492a7Sjmatthew c->uc_idx = i; 855497492a7Sjmatthew c->uc_buflen = 0; 856497492a7Sjmatthew c->uc_bufmax = bufsize; 857497492a7Sjmatthew c->uc_cnt = 0; 858497492a7Sjmatthew if (c->uc_xfer == NULL) { 859497492a7Sjmatthew c->uc_xfer = usbd_alloc_xfer(sc->sc_udev); 860497492a7Sjmatthew if (c->uc_xfer == NULL) 861497492a7Sjmatthew return (ENOBUFS); 862497492a7Sjmatthew 863497492a7Sjmatthew c->uc_buf = usbd_alloc_buffer(c->uc_xfer, c->uc_bufmax); 864497492a7Sjmatthew if (c->uc_buf == NULL) { 865497492a7Sjmatthew usbd_free_xfer(c->uc_xfer); 866497492a7Sjmatthew c->uc_xfer = NULL; 867497492a7Sjmatthew return (ENOBUFS); 868497492a7Sjmatthew } 869497492a7Sjmatthew } 870497492a7Sjmatthew } 871497492a7Sjmatthew 872497492a7Sjmatthew return (0); 873497492a7Sjmatthew } 874497492a7Sjmatthew 875497492a7Sjmatthew void 876497492a7Sjmatthew uaq_xfer_list_free(struct uaq_softc *sc, struct uaq_chain *ch, int listlen) 877497492a7Sjmatthew { 878497492a7Sjmatthew int i; 879497492a7Sjmatthew 880497492a7Sjmatthew for (i = 0; i < listlen; i++) { 881497492a7Sjmatthew if (ch[i].uc_buf != NULL) { 882497492a7Sjmatthew ch[i].uc_buf = NULL; 883497492a7Sjmatthew } 884497492a7Sjmatthew ch[i].uc_cnt = 0; 885497492a7Sjmatthew if (ch[i].uc_xfer != NULL) { 886497492a7Sjmatthew usbd_free_xfer(ch[i].uc_xfer); 887497492a7Sjmatthew ch[i].uc_xfer = NULL; 888497492a7Sjmatthew } 889497492a7Sjmatthew } 890497492a7Sjmatthew } 891497492a7Sjmatthew 892497492a7Sjmatthew void 893497492a7Sjmatthew uaq_stop(struct uaq_softc *sc) 894497492a7Sjmatthew { 895497492a7Sjmatthew struct uaq_cdata *cd; 896497492a7Sjmatthew struct ifnet *ifp; 897497492a7Sjmatthew usbd_status err; 898497492a7Sjmatthew 899497492a7Sjmatthew ifp = &sc->sc_ac.ac_if; 900497492a7Sjmatthew ifp->if_timer = 0; 901497492a7Sjmatthew ifp->if_flags &= ~IFF_RUNNING; 902497492a7Sjmatthew ifq_clr_oactive(&ifp->if_snd); 903497492a7Sjmatthew 904497492a7Sjmatthew sc->sc_link_status = 0; 905497492a7Sjmatthew sc->sc_link_speed = 0; 906497492a7Sjmatthew 907497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_RX] != NULL) { 908497492a7Sjmatthew err = usbd_close_pipe(sc->sc_ep[UAQ_ENDPT_RX]); 909497492a7Sjmatthew if (err) { 910497492a7Sjmatthew printf("%s: close rx pipe failed: %s\n", 911497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(err)); 912497492a7Sjmatthew } 913497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_RX] = NULL; 914497492a7Sjmatthew } 915497492a7Sjmatthew 916497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_TX] != NULL) { 917497492a7Sjmatthew err = usbd_close_pipe(sc->sc_ep[UAQ_ENDPT_TX]); 918497492a7Sjmatthew if (err) { 919497492a7Sjmatthew printf("%s: close tx pipe failed: %s\n", 920497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(err)); 921497492a7Sjmatthew } 922497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_TX] = NULL; 923497492a7Sjmatthew } 924497492a7Sjmatthew 925497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_INTR] != NULL) { 926497492a7Sjmatthew err = usbd_close_pipe(sc->sc_ep[UAQ_ENDPT_INTR]); 927497492a7Sjmatthew if (err) { 928497492a7Sjmatthew printf("%s: close intr pipe failed: %s\n", 929497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(err)); 930497492a7Sjmatthew } 931497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_INTR] = NULL; 932497492a7Sjmatthew } 933497492a7Sjmatthew 934497492a7Sjmatthew cd = &sc->sc_cdata; 935497492a7Sjmatthew uaq_xfer_list_free(sc, cd->uaq_rx_chain, UAQ_RX_LIST_CNT); 936497492a7Sjmatthew uaq_xfer_list_free(sc, cd->uaq_tx_chain, UAQ_TX_LIST_CNT); 937497492a7Sjmatthew } 938497492a7Sjmatthew 939497492a7Sjmatthew void 940497492a7Sjmatthew uaq_link(struct uaq_softc *sc) 941497492a7Sjmatthew { 942497492a7Sjmatthew if (sc->sc_link_speed > 0) { 943497492a7Sjmatthew uint8_t resend[3] = { 0, 0xf8, 7 }; 944497492a7Sjmatthew uint8_t qctrl[5] = { 7, 0x00, 0x01, 0x1e, 0xff }; 945497492a7Sjmatthew uint8_t ipg = 0; 946497492a7Sjmatthew 947497492a7Sjmatthew switch (sc->sc_link_speed) { 948497492a7Sjmatthew case UAQ_STATUS_SPEED_100M: 949497492a7Sjmatthew resend[1] = 0xfb; 950497492a7Sjmatthew resend[2] = 0x4; 951497492a7Sjmatthew break; 952497492a7Sjmatthew 953497492a7Sjmatthew case UAQ_STATUS_SPEED_5G: 954497492a7Sjmatthew ipg = 5; 955497492a7Sjmatthew break; 956497492a7Sjmatthew } 957497492a7Sjmatthew 958497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_IPG_0, 1, ipg); 959497492a7Sjmatthew 960497492a7Sjmatthew uaq_write_mem(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_TX_PAUSE_RESEND_T, 961497492a7Sjmatthew 3, resend, 3); 962497492a7Sjmatthew uaq_write_mem(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RX_BULKIN_QCTRL, 963497492a7Sjmatthew 5, qctrl, 5); 964497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_PAUSE_WATERLVL_LOW, 965497492a7Sjmatthew 2, 0x0810); 966497492a7Sjmatthew 967497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BMRX_DMA_CTRL, 1, 968497492a7Sjmatthew 0); 969497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BMTX_DMA_CTRL, 1, 970497492a7Sjmatthew 0); 971497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_ARC_CTRL, 1, 0); 972497492a7Sjmatthew 973497492a7Sjmatthew sc->sc_rxctl = UAQ_SFR_RX_CTL_IPE | UAQ_SFR_RX_CTL_AB; 974497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RX_CTL, 2, 975497492a7Sjmatthew sc->sc_rxctl); 976497492a7Sjmatthew 977497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_ETH_MAC_PATH, 1, 978497492a7Sjmatthew UAQ_SFR_RX_PATH_READY); 979497492a7Sjmatthew 980497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BULK_OUT_CTRL, 1, 981497492a7Sjmatthew UAQ_SFR_BULK_OUT_EFF_EN); 982497492a7Sjmatthew 983497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MEDIUM_STATUS_MODE, 984497492a7Sjmatthew 2, 0); 985497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MEDIUM_STATUS_MODE, 986497492a7Sjmatthew 2, UAQ_SFR_MEDIUM_XGMIIMODE | UAQ_SFR_MEDIUM_FULL_DUPLEX | 987497492a7Sjmatthew UAQ_SFR_MEDIUM_RECEIVE_EN | UAQ_SFR_MEDIUM_RXFLOW_CTRLEN | 988497492a7Sjmatthew UAQ_SFR_MEDIUM_TXFLOW_CTRLEN); /* JUMBO_EN */ 989497492a7Sjmatthew 990497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RXCOE_CTL, 1, 991497492a7Sjmatthew UAQ_SFR_RXCOE_IP | UAQ_SFR_RXCOE_TCP | UAQ_SFR_RXCOE_UDP | 992497492a7Sjmatthew UAQ_SFR_RXCOE_TCPV6 | UAQ_SFR_RXCOE_UDPV6); 993497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_TXCOE_CTL, 1, 994497492a7Sjmatthew UAQ_SFR_TXCOE_IP | UAQ_SFR_TXCOE_TCP | UAQ_SFR_TXCOE_UDP | 995497492a7Sjmatthew UAQ_SFR_TXCOE_TCPV6 | UAQ_SFR_TXCOE_UDPV6); 996497492a7Sjmatthew 997497492a7Sjmatthew sc->sc_rxctl |= UAQ_SFR_RX_CTL_START; 998497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RX_CTL, 2, 999497492a7Sjmatthew sc->sc_rxctl); 1000497492a7Sjmatthew } else { 1001497492a7Sjmatthew uint16_t mode; 1002497492a7Sjmatthew 1003497492a7Sjmatthew mode = uaq_read_2(sc, UAQ_CMD_ACCESS_MAC, 1004497492a7Sjmatthew UAQ_SFR_MEDIUM_STATUS_MODE, 2); 1005497492a7Sjmatthew mode &= ~UAQ_SFR_MEDIUM_RECEIVE_EN; 1006497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MEDIUM_STATUS_MODE, 1007497492a7Sjmatthew 2, mode); 1008497492a7Sjmatthew 1009497492a7Sjmatthew sc->sc_rxctl &= ~UAQ_SFR_RX_CTL_START; 1010497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RX_CTL, 2, 1011497492a7Sjmatthew sc->sc_rxctl); 1012497492a7Sjmatthew 1013497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BULK_OUT_CTRL, 1, 1014497492a7Sjmatthew UAQ_SFR_BULK_OUT_FLUSH_EN | UAQ_SFR_BULK_OUT_EFF_EN); 1015497492a7Sjmatthew 1016497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BULK_OUT_CTRL, 1, 1017497492a7Sjmatthew UAQ_SFR_BULK_OUT_EFF_EN); 1018497492a7Sjmatthew } 1019497492a7Sjmatthew } 1020497492a7Sjmatthew 1021497492a7Sjmatthew void 1022497492a7Sjmatthew uaq_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 1023497492a7Sjmatthew { 1024497492a7Sjmatthew struct uaq_softc *sc = priv; 1025497492a7Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 1026497492a7Sjmatthew uint64_t linkstatus; 1027497492a7Sjmatthew uint64_t baudrate; 1028497492a7Sjmatthew int link_state; 1029497492a7Sjmatthew 1030497492a7Sjmatthew if (status == USBD_CANCELLED) 1031497492a7Sjmatthew return; 1032497492a7Sjmatthew 1033497492a7Sjmatthew if (status != USBD_NORMAL_COMPLETION) { 1034497492a7Sjmatthew DPRINTFN(2, ("uaq_intr: status=%d\n", status)); 1035497492a7Sjmatthew if (status == USBD_STALLED) 1036497492a7Sjmatthew usbd_clear_endpoint_stall_async( 1037497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_INTR]); 1038497492a7Sjmatthew return; 1039497492a7Sjmatthew } 1040497492a7Sjmatthew 1041497492a7Sjmatthew linkstatus = letoh64(sc->sc_link_status); 1042497492a7Sjmatthew DPRINTFN(1, ("uaq_intr: link status %llx\n", linkstatus)); 1043497492a7Sjmatthew 1044497492a7Sjmatthew if (linkstatus & UAQ_STATUS_LINK) { 1045497492a7Sjmatthew link_state = LINK_STATE_FULL_DUPLEX; 1046497492a7Sjmatthew sc->sc_link_speed = (linkstatus & UAQ_STATUS_SPEED_MASK) 1047497492a7Sjmatthew >> UAQ_STATUS_SPEED_SHIFT; 1048497492a7Sjmatthew switch (sc->sc_link_speed) { 1049497492a7Sjmatthew case UAQ_STATUS_SPEED_5G: 1050497492a7Sjmatthew baudrate = IF_Gbps(5); 1051497492a7Sjmatthew break; 1052497492a7Sjmatthew case UAQ_STATUS_SPEED_2_5G: 1053497492a7Sjmatthew baudrate = IF_Mbps(2500); 1054497492a7Sjmatthew break; 1055497492a7Sjmatthew case UAQ_STATUS_SPEED_1G: 1056497492a7Sjmatthew baudrate = IF_Gbps(1); 1057497492a7Sjmatthew break; 1058497492a7Sjmatthew case UAQ_STATUS_SPEED_100M: 1059497492a7Sjmatthew baudrate = IF_Mbps(100); 1060497492a7Sjmatthew break; 1061497492a7Sjmatthew default: 1062497492a7Sjmatthew baudrate = 0; 1063497492a7Sjmatthew break; 1064497492a7Sjmatthew } 1065497492a7Sjmatthew 1066497492a7Sjmatthew ifp->if_baudrate = baudrate; 1067497492a7Sjmatthew } else { 1068497492a7Sjmatthew link_state = LINK_STATE_DOWN; 1069497492a7Sjmatthew sc->sc_link_speed = 0; 1070497492a7Sjmatthew } 1071497492a7Sjmatthew 1072497492a7Sjmatthew if (link_state != ifp->if_link_state) { 1073497492a7Sjmatthew ifp->if_link_state = link_state; 1074497492a7Sjmatthew if_link_state_change(ifp); 1075497492a7Sjmatthew usb_add_task(sc->sc_udev, &sc->sc_link_task); 1076497492a7Sjmatthew } 1077497492a7Sjmatthew } 1078497492a7Sjmatthew 1079497492a7Sjmatthew void 1080497492a7Sjmatthew uaq_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 1081497492a7Sjmatthew { 1082497492a7Sjmatthew struct uaq_chain *c = (struct uaq_chain *)priv; 1083497492a7Sjmatthew struct uaq_softc *sc = c->uc_sc; 1084497492a7Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 1085497492a7Sjmatthew uint8_t *buf; 1086497492a7Sjmatthew uint64_t *pdesc; 1087497492a7Sjmatthew uint64_t desc; 1088497492a7Sjmatthew uint32_t total_len; 1089497492a7Sjmatthew struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 1090497492a7Sjmatthew struct mbuf *m; 1091497492a7Sjmatthew int pktlen, s; 1092497492a7Sjmatthew int count, offset; 1093497492a7Sjmatthew 1094497492a7Sjmatthew if (usbd_is_dying(sc->sc_udev)) 1095497492a7Sjmatthew return; 1096497492a7Sjmatthew 1097497492a7Sjmatthew if (!(ifp->if_flags & IFF_RUNNING)) 1098497492a7Sjmatthew return; 1099497492a7Sjmatthew 1100497492a7Sjmatthew if (status != USBD_NORMAL_COMPLETION) { 1101497492a7Sjmatthew if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 1102497492a7Sjmatthew return; 1103497492a7Sjmatthew if (usbd_ratecheck(&sc->sc_rx_notice)) { 1104497492a7Sjmatthew printf("%s: usb errors on rx: %s\n", 1105497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(status)); 1106497492a7Sjmatthew } 1107497492a7Sjmatthew if (status == USBD_STALLED) 1108497492a7Sjmatthew usbd_clear_endpoint_stall_async( 1109497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_RX]); 1110497492a7Sjmatthew goto done; 1111497492a7Sjmatthew } 1112497492a7Sjmatthew 1113497492a7Sjmatthew usbd_get_xfer_status(xfer, NULL, (void **)&buf, &total_len, NULL); 1114497492a7Sjmatthew DPRINTFN(3, ("received %d bytes\n", total_len)); 1115497492a7Sjmatthew if ((total_len & 7) != 0) { 1116497492a7Sjmatthew printf("%s: weird rx transfer length %d\n", 1117497492a7Sjmatthew sc->sc_dev.dv_xname, total_len); 1118497492a7Sjmatthew goto done; 1119497492a7Sjmatthew } 1120497492a7Sjmatthew 1121497492a7Sjmatthew pdesc = (uint64_t *)(buf + (total_len - sizeof(desc))); 1122497492a7Sjmatthew desc = lemtoh64(pdesc); 1123497492a7Sjmatthew 1124497492a7Sjmatthew count = desc & UAQ_RX_HDR_COUNT_MASK; 1125497492a7Sjmatthew if (count == 0) 1126497492a7Sjmatthew goto done; 1127497492a7Sjmatthew 1128497492a7Sjmatthew /* get offset of packet headers */ 1129497492a7Sjmatthew offset = total_len - ((count + 1) * sizeof(desc)); 1130497492a7Sjmatthew if (offset != ((desc & UAQ_RX_HDR_OFFSET_MASK) >> 1131497492a7Sjmatthew UAQ_RX_HDR_OFFSET_SHIFT)) { 1132497492a7Sjmatthew printf("%s: offset mismatch, got %d expected %lld\n", 1133497492a7Sjmatthew sc->sc_dev.dv_xname, offset, 1134497492a7Sjmatthew desc >> UAQ_RX_HDR_OFFSET_SHIFT); 1135497492a7Sjmatthew goto done; 1136497492a7Sjmatthew } 1137497492a7Sjmatthew if (offset < 0 || offset > total_len) { 1138497492a7Sjmatthew printf("%s: offset %d outside buffer (%d)\n", 1139497492a7Sjmatthew sc->sc_dev.dv_xname, offset, total_len); 1140497492a7Sjmatthew goto done; 1141497492a7Sjmatthew } 1142497492a7Sjmatthew 1143497492a7Sjmatthew pdesc = (uint64_t *)(buf + offset); 1144497492a7Sjmatthew total_len = offset; 1145497492a7Sjmatthew 1146497492a7Sjmatthew while (count-- > 0) { 1147497492a7Sjmatthew desc = lemtoh64(pdesc); 1148497492a7Sjmatthew pdesc++; 1149497492a7Sjmatthew 1150497492a7Sjmatthew pktlen = (desc & UAQ_RX_PKT_LEN_MASK) >> UAQ_RX_PKT_LEN_SHIFT; 1151497492a7Sjmatthew if (pktlen > total_len) { 1152497492a7Sjmatthew DPRINTFN(2, ("not enough bytes for this packet\n")); 1153497492a7Sjmatthew ifp->if_ierrors++; 1154497492a7Sjmatthew goto done; 1155497492a7Sjmatthew } 1156497492a7Sjmatthew 1157497492a7Sjmatthew m = m_devget(buf + 2, pktlen - 2, ETHER_ALIGN); 1158497492a7Sjmatthew if (m == NULL) { 1159497492a7Sjmatthew DPRINTFN(2, ("m_devget failed for this packet\n")); 1160497492a7Sjmatthew ifp->if_ierrors++; 1161497492a7Sjmatthew goto done; 1162497492a7Sjmatthew } 1163497492a7Sjmatthew 1164497492a7Sjmatthew if ((desc & UAQ_RX_PKT_L3_ERR) == 0) 1165497492a7Sjmatthew m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK; 1166497492a7Sjmatthew 1167497492a7Sjmatthew if ((desc & UAQ_RX_PKT_L4_ERR) == 0) 1168497492a7Sjmatthew m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK | 1169497492a7Sjmatthew M_UDP_CSUM_IN_OK; 1170497492a7Sjmatthew 1171497492a7Sjmatthew #if NVLAN > 0 1172497492a7Sjmatthew if (desc & UAQ_RX_PKT_VLAN) { 1173497492a7Sjmatthew m->m_pkthdr.ether_vtag = (desc >> UAQ_RX_PKT_VLAN_SHIFT) & 1174497492a7Sjmatthew 0xfff; 1175497492a7Sjmatthew m->m_flags |= M_VLANTAG; 1176497492a7Sjmatthew } 1177497492a7Sjmatthew #endif 1178497492a7Sjmatthew ml_enqueue(&ml, m); 1179497492a7Sjmatthew 1180497492a7Sjmatthew total_len -= roundup(pktlen, UAQ_RX_BUF_ALIGN); 1181497492a7Sjmatthew buf += roundup(pktlen, UAQ_RX_BUF_ALIGN); 1182497492a7Sjmatthew } 1183497492a7Sjmatthew 1184497492a7Sjmatthew done: 1185497492a7Sjmatthew s = splnet(); 1186497492a7Sjmatthew if_input(ifp, &ml); 1187497492a7Sjmatthew splx(s); 1188497492a7Sjmatthew memset(c->uc_buf, 0, UAQ_RX_BUFSZ); 1189497492a7Sjmatthew 1190497492a7Sjmatthew usbd_setup_xfer(xfer, sc->sc_ep[UAQ_ENDPT_RX], c, c->uc_buf, 1191497492a7Sjmatthew UAQ_RX_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, 1192497492a7Sjmatthew USBD_NO_TIMEOUT, uaq_rxeof); 1193497492a7Sjmatthew usbd_transfer(xfer); 1194497492a7Sjmatthew } 1195497492a7Sjmatthew 1196497492a7Sjmatthew 1197497492a7Sjmatthew void 1198497492a7Sjmatthew uaq_watchdog(struct ifnet *ifp) 1199497492a7Sjmatthew { 1200497492a7Sjmatthew struct uaq_softc *sc = ifp->if_softc; 1201497492a7Sjmatthew struct uaq_chain *c; 1202497492a7Sjmatthew usbd_status err; 1203497492a7Sjmatthew int i, s; 1204497492a7Sjmatthew 1205497492a7Sjmatthew ifp->if_timer = 0; 1206497492a7Sjmatthew 1207497492a7Sjmatthew if (usbd_is_dying(sc->sc_udev)) 1208497492a7Sjmatthew return; 1209497492a7Sjmatthew 1210497492a7Sjmatthew if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP)) 1211497492a7Sjmatthew return; 1212497492a7Sjmatthew 1213497492a7Sjmatthew sc = ifp->if_softc; 1214497492a7Sjmatthew s = splnet(); 1215497492a7Sjmatthew 1216497492a7Sjmatthew ifp->if_oerrors++; 1217497492a7Sjmatthew DPRINTF(("%s: watchdog timeout\n", sc->sc_dev.dv_xname)); 1218497492a7Sjmatthew 1219497492a7Sjmatthew for (i = 0; i < UAQ_TX_LIST_CNT; i++) { 1220497492a7Sjmatthew c = &sc->sc_cdata.uaq_tx_chain[i]; 1221497492a7Sjmatthew if (c->uc_cnt > 0) { 1222497492a7Sjmatthew usbd_get_xfer_status(c->uc_xfer, NULL, NULL, NULL, 1223497492a7Sjmatthew &err); 1224497492a7Sjmatthew uaq_txeof(c->uc_xfer, c, err); 1225497492a7Sjmatthew } 1226497492a7Sjmatthew } 1227497492a7Sjmatthew 1228497492a7Sjmatthew if (ifq_is_oactive(&ifp->if_snd)) 1229497492a7Sjmatthew ifq_restart(&ifp->if_snd); 1230497492a7Sjmatthew splx(s); 1231497492a7Sjmatthew } 1232497492a7Sjmatthew 1233497492a7Sjmatthew void 1234497492a7Sjmatthew uaq_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 1235497492a7Sjmatthew { 1236497492a7Sjmatthew struct uaq_softc *sc; 1237497492a7Sjmatthew struct uaq_chain *c; 1238497492a7Sjmatthew struct ifnet *ifp; 1239497492a7Sjmatthew int s; 1240497492a7Sjmatthew 1241497492a7Sjmatthew c = priv; 1242497492a7Sjmatthew sc = c->uc_sc; 1243497492a7Sjmatthew ifp = &sc->sc_ac.ac_if; 1244497492a7Sjmatthew 1245497492a7Sjmatthew if (usbd_is_dying(sc->sc_udev)) 1246497492a7Sjmatthew return; 1247497492a7Sjmatthew 1248497492a7Sjmatthew if (status != USBD_NORMAL_COMPLETION) 1249497492a7Sjmatthew DPRINTF(("%s: %s uc_idx=%u : %s\n", sc->sc_dev.dv_xname, 1250497492a7Sjmatthew __func__, c->uc_idx, usbd_errstr(status))); 1251497492a7Sjmatthew else 1252497492a7Sjmatthew DPRINTF(("%s: txeof\n", sc->sc_dev.dv_xname)); 1253497492a7Sjmatthew 1254497492a7Sjmatthew s = splnet(); 1255497492a7Sjmatthew 1256497492a7Sjmatthew c->uc_cnt = 0; 1257497492a7Sjmatthew c->uc_buflen = 0; 1258497492a7Sjmatthew 1259497492a7Sjmatthew SLIST_INSERT_HEAD(&sc->sc_cdata.uaq_tx_free, c, uc_list); 1260497492a7Sjmatthew 1261497492a7Sjmatthew if (status != USBD_NORMAL_COMPLETION) { 1262497492a7Sjmatthew if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { 1263497492a7Sjmatthew splx(s); 1264497492a7Sjmatthew return; 1265497492a7Sjmatthew } 1266497492a7Sjmatthew 1267497492a7Sjmatthew ifp->if_oerrors++; 1268497492a7Sjmatthew printf("%s: usb error on tx: %s\n", sc->sc_dev.dv_xname, 1269497492a7Sjmatthew usbd_errstr(status)); 1270497492a7Sjmatthew 1271497492a7Sjmatthew if (status == USBD_STALLED) 1272497492a7Sjmatthew usbd_clear_endpoint_stall_async( 1273497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_TX]); 1274497492a7Sjmatthew splx(s); 1275497492a7Sjmatthew return; 1276497492a7Sjmatthew } 1277497492a7Sjmatthew 1278497492a7Sjmatthew ifp->if_timer = 0; 1279497492a7Sjmatthew if (ifq_is_oactive(&ifp->if_snd)) 1280497492a7Sjmatthew ifq_restart(&ifp->if_snd); 1281497492a7Sjmatthew splx(s); 1282497492a7Sjmatthew } 1283497492a7Sjmatthew 1284497492a7Sjmatthew void 1285497492a7Sjmatthew uaq_start(struct ifnet *ifp) 1286497492a7Sjmatthew { 1287497492a7Sjmatthew struct uaq_softc *sc = ifp->if_softc; 1288497492a7Sjmatthew struct uaq_cdata *cd = &sc->sc_cdata; 1289497492a7Sjmatthew struct uaq_chain *c; 1290497492a7Sjmatthew struct mbuf *m = NULL; 1291497492a7Sjmatthew int s, mlen; 1292497492a7Sjmatthew 1293497492a7Sjmatthew if ((sc->sc_link_speed == 0) || 1294497492a7Sjmatthew (ifp->if_flags & (IFF_RUNNING|IFF_UP)) != 1295497492a7Sjmatthew (IFF_RUNNING|IFF_UP)) { 1296497492a7Sjmatthew return; 1297497492a7Sjmatthew } 1298497492a7Sjmatthew 1299497492a7Sjmatthew s = splnet(); 1300497492a7Sjmatthew 1301497492a7Sjmatthew c = SLIST_FIRST(&cd->uaq_tx_free); 1302497492a7Sjmatthew while (c != NULL) { 1303497492a7Sjmatthew m = ifq_deq_begin(&ifp->if_snd); 1304497492a7Sjmatthew if (m == NULL) 1305497492a7Sjmatthew break; 1306497492a7Sjmatthew 1307497492a7Sjmatthew mlen = m->m_pkthdr.len; 1308497492a7Sjmatthew 1309497492a7Sjmatthew /* Discard packet larger than buffer. */ 1310497492a7Sjmatthew if (mlen + sizeof(uint64_t) >= c->uc_bufmax) { 1311497492a7Sjmatthew ifq_deq_commit(&ifp->if_snd, m); 1312497492a7Sjmatthew m_freem(m); 1313497492a7Sjmatthew ifp->if_oerrors++; 1314497492a7Sjmatthew continue; 1315497492a7Sjmatthew } 1316497492a7Sjmatthew 1317497492a7Sjmatthew /* Append packet to current buffer. */ 1318497492a7Sjmatthew mlen = uaq_encap_txpkt(sc, m, c->uc_buf + c->uc_buflen, 1319497492a7Sjmatthew c->uc_bufmax - c->uc_buflen); 1320497492a7Sjmatthew if (mlen <= 0) { 1321497492a7Sjmatthew ifq_deq_rollback(&ifp->if_snd, m); 1322497492a7Sjmatthew break; 1323497492a7Sjmatthew } 1324497492a7Sjmatthew 1325497492a7Sjmatthew ifq_deq_commit(&ifp->if_snd, m); 1326497492a7Sjmatthew c->uc_cnt += 1; 1327497492a7Sjmatthew c->uc_buflen += mlen; 1328497492a7Sjmatthew 1329497492a7Sjmatthew #if NBPFILTER > 0 1330497492a7Sjmatthew if (ifp->if_bpf) 1331497492a7Sjmatthew bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 1332497492a7Sjmatthew #endif 1333497492a7Sjmatthew 1334497492a7Sjmatthew m_freem(m); 1335497492a7Sjmatthew } 1336497492a7Sjmatthew 1337497492a7Sjmatthew if (c != NULL) { 1338497492a7Sjmatthew /* Send current buffer unless empty */ 1339497492a7Sjmatthew if (c->uc_buflen > 0 && c->uc_cnt > 0) { 1340497492a7Sjmatthew SLIST_REMOVE_HEAD(&cd->uaq_tx_free, uc_list); 1341497492a7Sjmatthew if (uaq_encap_xfer(sc, c)) { 1342497492a7Sjmatthew SLIST_INSERT_HEAD(&cd->uaq_tx_free, c, 1343497492a7Sjmatthew uc_list); 1344497492a7Sjmatthew } 1345497492a7Sjmatthew c = SLIST_FIRST(&cd->uaq_tx_free); 1346497492a7Sjmatthew 1347497492a7Sjmatthew ifp->if_timer = 5; 1348497492a7Sjmatthew if (c == NULL) 1349497492a7Sjmatthew ifq_set_oactive(&ifp->if_snd); 1350497492a7Sjmatthew } 1351497492a7Sjmatthew } 1352497492a7Sjmatthew 1353497492a7Sjmatthew splx(s); 1354497492a7Sjmatthew } 1355497492a7Sjmatthew 1356497492a7Sjmatthew int 1357497492a7Sjmatthew uaq_encap_txpkt(struct uaq_softc *sc, struct mbuf *m, char *buf, 1358497492a7Sjmatthew uint32_t maxlen) 1359497492a7Sjmatthew { 1360497492a7Sjmatthew uint64_t desc; 1361497492a7Sjmatthew int padded; 1362497492a7Sjmatthew 1363497492a7Sjmatthew desc = m->m_pkthdr.len; 1364497492a7Sjmatthew padded = roundup(m->m_pkthdr.len, UAQ_TX_BUF_ALIGN); 1365497492a7Sjmatthew if (((padded + sizeof(desc)) % sc->sc_out_frame_size) == 0) { 1366497492a7Sjmatthew desc |= UAQ_TX_PKT_DROP_PADD; 1367497492a7Sjmatthew padded += 8; 1368497492a7Sjmatthew } 1369497492a7Sjmatthew 1370497492a7Sjmatthew if (padded + sizeof(desc) > maxlen) 1371497492a7Sjmatthew return (-1); 1372497492a7Sjmatthew 1373497492a7Sjmatthew #if NVLAN > 0 1374497492a7Sjmatthew if (m->m_flags & M_VLANTAG) 1375497492a7Sjmatthew desc |= (((uint64_t)m->m_pkthdr.ether_vtag) << 1376497492a7Sjmatthew UAQ_TX_PKT_VLAN_SHIFT) | UAQ_TX_PKT_VLAN; 1377497492a7Sjmatthew #endif 1378497492a7Sjmatthew 1379497492a7Sjmatthew htolem64((uint64_t *)buf, desc); 1380497492a7Sjmatthew m_copydata(m, 0, m->m_pkthdr.len, buf + sizeof(desc)); 1381497492a7Sjmatthew return (padded + sizeof(desc)); 1382497492a7Sjmatthew } 1383497492a7Sjmatthew 1384497492a7Sjmatthew int 1385497492a7Sjmatthew uaq_encap_xfer(struct uaq_softc *sc, struct uaq_chain *c) 1386497492a7Sjmatthew { 1387497492a7Sjmatthew usbd_status err; 1388497492a7Sjmatthew 1389497492a7Sjmatthew usbd_setup_xfer(c->uc_xfer, sc->sc_ep[UAQ_ENDPT_TX], c, c->uc_buf, 1390497492a7Sjmatthew c->uc_buflen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 10000, 1391497492a7Sjmatthew uaq_txeof); 1392497492a7Sjmatthew 1393497492a7Sjmatthew err = usbd_transfer(c->uc_xfer); 1394497492a7Sjmatthew if (err != USBD_IN_PROGRESS) { 1395497492a7Sjmatthew c->uc_cnt = 0; 1396497492a7Sjmatthew c->uc_buflen = 0; 1397497492a7Sjmatthew uaq_stop(sc); 1398497492a7Sjmatthew return (EIO); 1399497492a7Sjmatthew } 1400497492a7Sjmatthew 1401497492a7Sjmatthew return (0); 1402497492a7Sjmatthew } 1403