1*497492a7Sjmatthew /* $OpenBSD: if_uaq.c,v 1.1 2021/09/04 12:11:45 jmatthew Exp $ */ 2*497492a7Sjmatthew /*- 3*497492a7Sjmatthew * Copyright (c) 2021 Jonathan Matthew <jonathan@d14n.org> 4*497492a7Sjmatthew * All rights reserved. 5*497492a7Sjmatthew * 6*497492a7Sjmatthew * Redistribution and use in source and binary forms, with or without 7*497492a7Sjmatthew * modification, are permitted provided that the following conditions 8*497492a7Sjmatthew * are met: 9*497492a7Sjmatthew * 1. Redistributions of source code must retain the above copyright 10*497492a7Sjmatthew * notice, this list of conditions and the following disclaimer. 11*497492a7Sjmatthew * 2. Redistributions in binary form must reproduce the above copyright 12*497492a7Sjmatthew * notice, this list of conditions and the following disclaimer in the 13*497492a7Sjmatthew * documentation and/or other materials provided with the distribution. 14*497492a7Sjmatthew * 15*497492a7Sjmatthew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*497492a7Sjmatthew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*497492a7Sjmatthew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*497492a7Sjmatthew * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*497492a7Sjmatthew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*497492a7Sjmatthew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*497492a7Sjmatthew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*497492a7Sjmatthew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*497492a7Sjmatthew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*497492a7Sjmatthew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*497492a7Sjmatthew * SUCH DAMAGE. 26*497492a7Sjmatthew */ 27*497492a7Sjmatthew 28*497492a7Sjmatthew #include "bpfilter.h" 29*497492a7Sjmatthew #include "vlan.h" 30*497492a7Sjmatthew 31*497492a7Sjmatthew #include <sys/param.h> 32*497492a7Sjmatthew #include <sys/systm.h> 33*497492a7Sjmatthew #include <sys/sockio.h> 34*497492a7Sjmatthew #include <sys/rwlock.h> 35*497492a7Sjmatthew #include <sys/mbuf.h> 36*497492a7Sjmatthew #include <sys/kernel.h> 37*497492a7Sjmatthew #include <sys/socket.h> 38*497492a7Sjmatthew #include <sys/device.h> 39*497492a7Sjmatthew 40*497492a7Sjmatthew #include <machine/bus.h> 41*497492a7Sjmatthew 42*497492a7Sjmatthew #include <net/if.h> 43*497492a7Sjmatthew #include <net/if_media.h> 44*497492a7Sjmatthew 45*497492a7Sjmatthew #if NBPFILTER > 0 46*497492a7Sjmatthew #include <net/bpf.h> 47*497492a7Sjmatthew #endif 48*497492a7Sjmatthew 49*497492a7Sjmatthew #include <netinet/in.h> 50*497492a7Sjmatthew #include <netinet/if_ether.h> 51*497492a7Sjmatthew 52*497492a7Sjmatthew #include <dev/usb/usb.h> 53*497492a7Sjmatthew #include <dev/usb/usbdi.h> 54*497492a7Sjmatthew #include <dev/usb/usbdi_util.h> 55*497492a7Sjmatthew #include <dev/usb/usbdivar.h> 56*497492a7Sjmatthew #include <dev/usb/usbdevs.h> 57*497492a7Sjmatthew 58*497492a7Sjmatthew #ifdef UAQ_DEBUG 59*497492a7Sjmatthew #define DPRINTF(x) do { if (uaqdebug) printf x; } while (0) 60*497492a7Sjmatthew #define DPRINTFN(n,x) do { if (uaqdebug >= (n)) printf x; } while (0) 61*497492a7Sjmatthew int uaqdebug = 0; 62*497492a7Sjmatthew #else 63*497492a7Sjmatthew #define DPRINTF(x) 64*497492a7Sjmatthew #define DPRINTFN(n,x) 65*497492a7Sjmatthew #endif 66*497492a7Sjmatthew 67*497492a7Sjmatthew #define UAQ_ENDPT_RX 0 68*497492a7Sjmatthew #define UAQ_ENDPT_TX 1 69*497492a7Sjmatthew #define UAQ_ENDPT_INTR 2 70*497492a7Sjmatthew #define UAQ_ENDPT_MAX 3 71*497492a7Sjmatthew 72*497492a7Sjmatthew #define UAQ_TX_LIST_CNT 1 73*497492a7Sjmatthew #define UAQ_RX_LIST_CNT 1 74*497492a7Sjmatthew #define UAQ_TX_BUF_ALIGN 8 75*497492a7Sjmatthew #define UAQ_RX_BUF_ALIGN 8 76*497492a7Sjmatthew 77*497492a7Sjmatthew #define UAQ_TX_BUFSZ 16384 78*497492a7Sjmatthew #define UAQ_RX_BUFSZ 32768 79*497492a7Sjmatthew 80*497492a7Sjmatthew #define UAQ_CTL_READ 1 81*497492a7Sjmatthew #define UAQ_CTL_WRITE 2 82*497492a7Sjmatthew 83*497492a7Sjmatthew #define UAQ_MCAST_FILTER_SIZE 8 84*497492a7Sjmatthew 85*497492a7Sjmatthew /* control commands */ 86*497492a7Sjmatthew #define UAQ_CMD_ACCESS_MAC 0x01 87*497492a7Sjmatthew #define UAQ_CMD_FLASH_PARAM 0x20 88*497492a7Sjmatthew #define UAQ_CMD_PHY_POWER 0x31 89*497492a7Sjmatthew #define UAQ_CMD_WOL_CFG 0x60 90*497492a7Sjmatthew #define UAQ_CMD_PHY_OPS 0x61 91*497492a7Sjmatthew 92*497492a7Sjmatthew /* SFR registers */ 93*497492a7Sjmatthew #define UAQ_SFR_GENERAL_STATUS 0x03 94*497492a7Sjmatthew #define UAQ_SFR_CHIP_STATUS 0x05 95*497492a7Sjmatthew #define UAQ_SFR_RX_CTL 0x0B 96*497492a7Sjmatthew #define UAQ_SFR_RX_CTL_STOP 0x0000 97*497492a7Sjmatthew #define UAQ_SFR_RX_CTL_PRO 0x0001 98*497492a7Sjmatthew #define UAQ_SFR_RX_CTL_AMALL 0x0002 99*497492a7Sjmatthew #define UAQ_SFR_RX_CTL_AB 0x0008 100*497492a7Sjmatthew #define UAQ_SFR_RX_CTL_AM 0x0010 101*497492a7Sjmatthew #define UAQ_SFR_RX_CTL_START 0x0080 102*497492a7Sjmatthew #define UAQ_SFR_RX_CTL_IPE 0x0200 103*497492a7Sjmatthew #define UAQ_SFR_IPG_0 0x0D 104*497492a7Sjmatthew #define UAQ_SFR_NODE_ID 0x10 105*497492a7Sjmatthew #define UAQ_SFR_MCAST_FILTER 0x16 106*497492a7Sjmatthew #define UAQ_SFR_MEDIUM_STATUS_MODE 0x22 107*497492a7Sjmatthew #define UAQ_SFR_MEDIUM_XGMIIMODE 0x0001 108*497492a7Sjmatthew #define UAQ_SFR_MEDIUM_FULL_DUPLEX 0x0002 109*497492a7Sjmatthew #define UAQ_SFR_MEDIUM_RXFLOW_CTRLEN 0x0010 110*497492a7Sjmatthew #define UAQ_SFR_MEDIUM_TXFLOW_CTRLEN 0x0020 111*497492a7Sjmatthew #define UAQ_SFR_MEDIUM_JUMBO_EN 0x0040 112*497492a7Sjmatthew #define UAQ_SFR_MEDIUM_RECEIVE_EN 0x0100 113*497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE 0x24 114*497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_EPHYRW 0x01 115*497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_RWLC 0x02 116*497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_RWMP 0x04 117*497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_RWWF 0x08 118*497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_RW_FLAG 0x10 119*497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_PMEPOL 0x20 120*497492a7Sjmatthew #define UAQ_SFR_MONITOR_MODE_PMETYPE 0x40 121*497492a7Sjmatthew #define UAQ_SFR_RX_BULKIN_QCTRL 0x2E 122*497492a7Sjmatthew #define UAQ_SFR_RXCOE_CTL 0x34 123*497492a7Sjmatthew #define UAQ_SFR_RXCOE_IP 0x01 124*497492a7Sjmatthew #define UAQ_SFR_RXCOE_TCP 0x02 125*497492a7Sjmatthew #define UAQ_SFR_RXCOE_UDP 0x04 126*497492a7Sjmatthew #define UAQ_SFR_RXCOE_ICMP 0x08 127*497492a7Sjmatthew #define UAQ_SFR_RXCOE_IGMP 0x10 128*497492a7Sjmatthew #define UAQ_SFR_RXCOE_TCPV6 0x20 129*497492a7Sjmatthew #define UAQ_SFR_RXCOE_UDPV6 0x40 130*497492a7Sjmatthew #define UAQ_SFR_RXCOE_ICMV6 0x80 131*497492a7Sjmatthew #define UAQ_SFR_TXCOE_CTL 0x35 132*497492a7Sjmatthew #define UAQ_SFR_TXCOE_IP 0x01 133*497492a7Sjmatthew #define UAQ_SFR_TXCOE_TCP 0x02 134*497492a7Sjmatthew #define UAQ_SFR_TXCOE_UDP 0x04 135*497492a7Sjmatthew #define UAQ_SFR_TXCOE_ICMP 0x08 136*497492a7Sjmatthew #define UAQ_SFR_TXCOE_IGMP 0x10 137*497492a7Sjmatthew #define UAQ_SFR_TXCOE_TCPV6 0x20 138*497492a7Sjmatthew #define UAQ_SFR_TXCOE_UDPV6 0x40 139*497492a7Sjmatthew #define UAQ_SFR_TXCOE_ICMV6 0x80 140*497492a7Sjmatthew #define UAQ_SFR_BM_INT_MASK 0x41 141*497492a7Sjmatthew #define UAQ_SFR_BMRX_DMA_CTRL 0x43 142*497492a7Sjmatthew #define UAQ_SFR_BMRX_DMA_EN 0x80 143*497492a7Sjmatthew #define UAQ_SFR_BMTX_DMA_CTRL 0x46 144*497492a7Sjmatthew #define UAQ_SFR_PAUSE_WATERLVL_LOW 0x54 145*497492a7Sjmatthew #define UAQ_SFR_ARC_CTRL 0x9E 146*497492a7Sjmatthew #define UAQ_SFR_SWP_CTRL 0xB1 147*497492a7Sjmatthew #define UAQ_SFR_TX_PAUSE_RESEND_T 0xB2 148*497492a7Sjmatthew #define UAQ_SFR_ETH_MAC_PATH 0xB7 149*497492a7Sjmatthew #define UAQ_SFR_RX_PATH_READY 0x01 150*497492a7Sjmatthew #define UAQ_SFR_BULK_OUT_CTRL 0xB9 151*497492a7Sjmatthew #define UAQ_SFR_BULK_OUT_FLUSH_EN 0x01 152*497492a7Sjmatthew #define UAQ_SFR_BULK_OUT_EFF_EN 0x02 153*497492a7Sjmatthew 154*497492a7Sjmatthew #define UAQ_FW_VER_MAJOR 0xDA 155*497492a7Sjmatthew #define UAQ_FW_VER_MINOR 0xDB 156*497492a7Sjmatthew #define UAQ_FW_VER_REV 0xDC 157*497492a7Sjmatthew 158*497492a7Sjmatthew /* phy ops */ 159*497492a7Sjmatthew #define UAQ_PHY_ADV_100M (1 << 0) 160*497492a7Sjmatthew #define UAQ_PHY_ADV_1G (1 << 1) 161*497492a7Sjmatthew #define UAQ_PHY_ADV_2_5G (1 << 2) 162*497492a7Sjmatthew #define UAQ_PHY_ADV_5G (1 << 3) 163*497492a7Sjmatthew #define UAQ_PHY_ADV_MASK 0x0F 164*497492a7Sjmatthew 165*497492a7Sjmatthew #define UAQ_PHY_PAUSE (1 << 16) 166*497492a7Sjmatthew #define UAQ_PHY_ASYM_PAUSE (1 << 17) 167*497492a7Sjmatthew #define UAQ_PHY_LOW_POWER (1 << 18) 168*497492a7Sjmatthew #define UAQ_PHY_POWER_EN (1 << 19) 169*497492a7Sjmatthew #define UAQ_PHY_WOL (1 << 20) 170*497492a7Sjmatthew #define UAQ_PHY_DOWNSHIFT (1 << 21) 171*497492a7Sjmatthew 172*497492a7Sjmatthew #define UAQ_PHY_DSH_RETRY_SHIFT 0x18 173*497492a7Sjmatthew #define UAQ_PHY_DSH_RETRY_MASK 0xF000000 174*497492a7Sjmatthew 175*497492a7Sjmatthew /* status */ 176*497492a7Sjmatthew #define UAQ_STATUS_LINK 0x8000 177*497492a7Sjmatthew #define UAQ_STATUS_SPEED_MASK 0x7F00 178*497492a7Sjmatthew #define UAQ_STATUS_SPEED_SHIFT 8 179*497492a7Sjmatthew #define UAQ_STATUS_SPEED_5G 0x000F 180*497492a7Sjmatthew #define UAQ_STATUS_SPEED_2_5G 0x0010 181*497492a7Sjmatthew #define UAQ_STATUS_SPEED_1G 0x0011 182*497492a7Sjmatthew #define UAQ_STATUS_SPEED_100M 0x0013 183*497492a7Sjmatthew 184*497492a7Sjmatthew /* rx descriptor */ 185*497492a7Sjmatthew #define UAQ_RX_HDR_COUNT_MASK 0x1FFF 186*497492a7Sjmatthew #define UAQ_RX_HDR_OFFSET_MASK 0xFFFFE000 187*497492a7Sjmatthew #define UAQ_RX_HDR_OFFSET_SHIFT 13 188*497492a7Sjmatthew 189*497492a7Sjmatthew /* rx packet descriptor */ 190*497492a7Sjmatthew #define UAQ_RX_PKT_L4_ERR 0x01 191*497492a7Sjmatthew #define UAQ_RX_PKT_L3_ERR 0x02 192*497492a7Sjmatthew #define UAQ_RX_PKT_L4_MASK 0x1C 193*497492a7Sjmatthew #define UAQ_RX_PKT_L4_UDP 0x04 194*497492a7Sjmatthew #define UAQ_RX_PKT_L4_TCP 0x10 195*497492a7Sjmatthew #define UAQ_RX_PKT_L3_MASK 0x60 196*497492a7Sjmatthew #define UAQ_RX_PKT_L3_IP 0x20 197*497492a7Sjmatthew #define UAQ_RX_PKT_L3_IP6 0x40 198*497492a7Sjmatthew #define UAQ_RX_PKT_VLAN 0x400 199*497492a7Sjmatthew #define UAQ_RX_PKT_RX_OK 0x800 200*497492a7Sjmatthew #define UAQ_RX_PKT_DROP 0x80000000 201*497492a7Sjmatthew #define UAQ_RX_PKT_LEN_MASK 0x7FFF0000 202*497492a7Sjmatthew #define UAQ_RX_PKT_LEN_SHIFT 16 203*497492a7Sjmatthew #define UAQ_RX_PKT_VLAN_SHIFT 32 204*497492a7Sjmatthew 205*497492a7Sjmatthew /* tx packet descriptor */ 206*497492a7Sjmatthew #define UAQ_TX_PKT_LEN_MASK 0x1FFFFF 207*497492a7Sjmatthew #define UAQ_TX_PKT_DROP_PADD (1 << 28) 208*497492a7Sjmatthew #define UAQ_TX_PKT_VLAN (1 << 29) 209*497492a7Sjmatthew #define UAQ_TX_PKT_VLAN_MASK 0xFFFF 210*497492a7Sjmatthew #define UAQ_TX_PKT_VLAN_SHIFT 0x30 211*497492a7Sjmatthew 212*497492a7Sjmatthew 213*497492a7Sjmatthew struct uaq_chain { 214*497492a7Sjmatthew struct uaq_softc *uc_sc; 215*497492a7Sjmatthew struct usbd_xfer *uc_xfer; 216*497492a7Sjmatthew char *uc_buf; 217*497492a7Sjmatthew uint32_t uc_cnt; 218*497492a7Sjmatthew uint32_t uc_buflen; 219*497492a7Sjmatthew uint32_t uc_bufmax; 220*497492a7Sjmatthew SLIST_ENTRY(uaq_chain) uc_list; 221*497492a7Sjmatthew uint8_t uc_idx; 222*497492a7Sjmatthew }; 223*497492a7Sjmatthew 224*497492a7Sjmatthew struct uaq_cdata { 225*497492a7Sjmatthew struct uaq_chain uaq_rx_chain[UAQ_RX_LIST_CNT]; 226*497492a7Sjmatthew struct uaq_chain uaq_tx_chain[UAQ_TX_LIST_CNT]; 227*497492a7Sjmatthew SLIST_HEAD(uaq_list_head, uaq_chain) uaq_tx_free; 228*497492a7Sjmatthew }; 229*497492a7Sjmatthew 230*497492a7Sjmatthew struct uaq_softc { 231*497492a7Sjmatthew struct device sc_dev; 232*497492a7Sjmatthew struct usbd_device *sc_udev; 233*497492a7Sjmatthew 234*497492a7Sjmatthew struct usbd_interface *sc_iface; 235*497492a7Sjmatthew struct usb_task sc_link_task; 236*497492a7Sjmatthew struct timeval sc_rx_notice; 237*497492a7Sjmatthew int sc_ed[UAQ_ENDPT_MAX]; 238*497492a7Sjmatthew struct usbd_pipe *sc_ep[UAQ_ENDPT_MAX]; 239*497492a7Sjmatthew int sc_out_frame_size; 240*497492a7Sjmatthew 241*497492a7Sjmatthew struct arpcom sc_ac; 242*497492a7Sjmatthew struct ifmedia sc_ifmedia; 243*497492a7Sjmatthew 244*497492a7Sjmatthew struct uaq_cdata sc_cdata; 245*497492a7Sjmatthew uint64_t sc_link_status; 246*497492a7Sjmatthew int sc_link_speed; 247*497492a7Sjmatthew 248*497492a7Sjmatthew uint32_t sc_phy_cfg; 249*497492a7Sjmatthew uint16_t sc_rxctl; 250*497492a7Sjmatthew }; 251*497492a7Sjmatthew 252*497492a7Sjmatthew const struct usb_devno uaq_devs[] = { 253*497492a7Sjmatthew { USB_VENDOR_AQUANTIA, USB_PRODUCT_AQUANTIA_AQC111 }, 254*497492a7Sjmatthew { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_ASIX111 }, 255*497492a7Sjmatthew { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_ASIX112 }, 256*497492a7Sjmatthew { USB_VENDOR_TRENDNET, USB_PRODUCT_TRENDNET_TUCET5G }, 257*497492a7Sjmatthew { USB_VENDOR_QNAP, USB_PRODUCT_QNAP_UC5G1T }, 258*497492a7Sjmatthew }; 259*497492a7Sjmatthew 260*497492a7Sjmatthew int uaq_match(struct device *, void *, void *); 261*497492a7Sjmatthew void uaq_attach(struct device *, struct device *, void *); 262*497492a7Sjmatthew int uaq_detach(struct device *, int); 263*497492a7Sjmatthew 264*497492a7Sjmatthew int uaq_ctl(struct uaq_softc *, uint8_t, uint8_t, uint16_t, 265*497492a7Sjmatthew uint16_t, void *, int); 266*497492a7Sjmatthew int uaq_read_mem(struct uaq_softc *, uint8_t, uint16_t, uint16_t, 267*497492a7Sjmatthew void *, int); 268*497492a7Sjmatthew int uaq_write_mem(struct uaq_softc *, uint8_t, uint16_t, uint16_t, 269*497492a7Sjmatthew void *, int); 270*497492a7Sjmatthew uint8_t uaq_read_1(struct uaq_softc *, uint8_t, uint16_t, uint16_t); 271*497492a7Sjmatthew uint16_t uaq_read_2(struct uaq_softc *, uint8_t, uint16_t, uint16_t); 272*497492a7Sjmatthew uint32_t uaq_read_4(struct uaq_softc *, uint8_t, uint16_t, uint16_t); 273*497492a7Sjmatthew int uaq_write_1(struct uaq_softc *, uint8_t, uint16_t, uint16_t, 274*497492a7Sjmatthew uint32_t); 275*497492a7Sjmatthew int uaq_write_2(struct uaq_softc *, uint8_t, uint16_t, uint16_t, 276*497492a7Sjmatthew uint32_t); 277*497492a7Sjmatthew int uaq_write_4(struct uaq_softc *, uint8_t, uint16_t, uint16_t, 278*497492a7Sjmatthew uint32_t); 279*497492a7Sjmatthew 280*497492a7Sjmatthew int uaq_ifmedia_upd(struct ifnet *); 281*497492a7Sjmatthew void uaq_ifmedia_sts(struct ifnet *, struct ifmediareq *); 282*497492a7Sjmatthew void uaq_add_media_types(struct uaq_softc *); 283*497492a7Sjmatthew void uaq_iff(struct uaq_softc *); 284*497492a7Sjmatthew 285*497492a7Sjmatthew void uaq_init(void *); 286*497492a7Sjmatthew int uaq_ioctl(struct ifnet *, u_long, caddr_t); 287*497492a7Sjmatthew int uaq_xfer_list_init(struct uaq_softc *, struct uaq_chain *, 288*497492a7Sjmatthew uint32_t, int); 289*497492a7Sjmatthew void uaq_xfer_list_free(struct uaq_softc *, struct uaq_chain *, int); 290*497492a7Sjmatthew 291*497492a7Sjmatthew void uaq_stop(struct uaq_softc *); 292*497492a7Sjmatthew void uaq_link(struct uaq_softc *); 293*497492a7Sjmatthew void uaq_intr(struct usbd_xfer *, void *, usbd_status); 294*497492a7Sjmatthew void uaq_start(struct ifnet *); 295*497492a7Sjmatthew void uaq_rxeof(struct usbd_xfer *, void *, usbd_status); 296*497492a7Sjmatthew void uaq_txeof(struct usbd_xfer *, void *, usbd_status); 297*497492a7Sjmatthew void uaq_watchdog(struct ifnet *); 298*497492a7Sjmatthew void uaq_reset(struct uaq_softc *); 299*497492a7Sjmatthew 300*497492a7Sjmatthew int uaq_encap_txpkt(struct uaq_softc *, struct mbuf *, char *, 301*497492a7Sjmatthew uint32_t); 302*497492a7Sjmatthew int uaq_encap_xfer(struct uaq_softc *, struct uaq_chain *); 303*497492a7Sjmatthew 304*497492a7Sjmatthew struct cfdriver uaq_cd = { 305*497492a7Sjmatthew NULL, "uaq", DV_IFNET 306*497492a7Sjmatthew }; 307*497492a7Sjmatthew 308*497492a7Sjmatthew const struct cfattach uaq_ca = { 309*497492a7Sjmatthew sizeof(struct uaq_softc), uaq_match, uaq_attach, uaq_detach 310*497492a7Sjmatthew }; 311*497492a7Sjmatthew 312*497492a7Sjmatthew int 313*497492a7Sjmatthew uaq_ctl(struct uaq_softc *sc, uint8_t rw, uint8_t cmd, uint16_t val, 314*497492a7Sjmatthew uint16_t index, void *buf, int len) 315*497492a7Sjmatthew { 316*497492a7Sjmatthew usb_device_request_t req; 317*497492a7Sjmatthew usbd_status err; 318*497492a7Sjmatthew 319*497492a7Sjmatthew if (usbd_is_dying(sc->sc_udev)) 320*497492a7Sjmatthew return 0; 321*497492a7Sjmatthew 322*497492a7Sjmatthew if (rw == UAQ_CTL_WRITE) 323*497492a7Sjmatthew req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 324*497492a7Sjmatthew else 325*497492a7Sjmatthew req.bmRequestType = UT_READ_VENDOR_DEVICE; 326*497492a7Sjmatthew req.bRequest = cmd; 327*497492a7Sjmatthew USETW(req.wValue, val); 328*497492a7Sjmatthew USETW(req.wIndex, index); 329*497492a7Sjmatthew USETW(req.wLength, len); 330*497492a7Sjmatthew 331*497492a7Sjmatthew DPRINTFN(5, ("uaq_ctl: rw %d, val 0x%04hx, index 0x%04hx, len %d\n", 332*497492a7Sjmatthew rw, val, index, len)); 333*497492a7Sjmatthew err = usbd_do_request(sc->sc_udev, &req, buf); 334*497492a7Sjmatthew if (err) { 335*497492a7Sjmatthew DPRINTF(("uaq_ctl: error %d\n", err)); 336*497492a7Sjmatthew return -1; 337*497492a7Sjmatthew } 338*497492a7Sjmatthew 339*497492a7Sjmatthew return 0; 340*497492a7Sjmatthew } 341*497492a7Sjmatthew 342*497492a7Sjmatthew int 343*497492a7Sjmatthew uaq_read_mem(struct uaq_softc *sc, uint8_t cmd, uint16_t addr, uint16_t index, 344*497492a7Sjmatthew void *buf, int len) 345*497492a7Sjmatthew { 346*497492a7Sjmatthew return (uaq_ctl(sc, UAQ_CTL_READ, cmd, addr, index, buf, len)); 347*497492a7Sjmatthew } 348*497492a7Sjmatthew 349*497492a7Sjmatthew int 350*497492a7Sjmatthew uaq_write_mem(struct uaq_softc *sc, uint8_t cmd, uint16_t addr, uint16_t index, 351*497492a7Sjmatthew void *buf, int len) 352*497492a7Sjmatthew { 353*497492a7Sjmatthew return (uaq_ctl(sc, UAQ_CTL_WRITE, cmd, addr, index, buf, len)); 354*497492a7Sjmatthew } 355*497492a7Sjmatthew 356*497492a7Sjmatthew uint8_t 357*497492a7Sjmatthew uaq_read_1(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index) 358*497492a7Sjmatthew { 359*497492a7Sjmatthew uint8_t val; 360*497492a7Sjmatthew 361*497492a7Sjmatthew uaq_read_mem(sc, cmd, reg, index, &val, 1); 362*497492a7Sjmatthew DPRINTFN(4, ("uaq_read_1: cmd %x reg %x index %x = %x\n", cmd, reg, 363*497492a7Sjmatthew index, val)); 364*497492a7Sjmatthew return (val); 365*497492a7Sjmatthew } 366*497492a7Sjmatthew 367*497492a7Sjmatthew uint16_t 368*497492a7Sjmatthew uaq_read_2(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index) 369*497492a7Sjmatthew { 370*497492a7Sjmatthew uint16_t val; 371*497492a7Sjmatthew 372*497492a7Sjmatthew uaq_read_mem(sc, cmd, reg, index, &val, 2); 373*497492a7Sjmatthew DPRINTFN(4, ("uaq_read_2: cmd %x reg %x index %x = %x\n", cmd, reg, 374*497492a7Sjmatthew index, UGETW(&val))); 375*497492a7Sjmatthew 376*497492a7Sjmatthew return (UGETW(&val)); 377*497492a7Sjmatthew } 378*497492a7Sjmatthew 379*497492a7Sjmatthew uint32_t 380*497492a7Sjmatthew uaq_read_4(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index) 381*497492a7Sjmatthew { 382*497492a7Sjmatthew uint32_t val; 383*497492a7Sjmatthew 384*497492a7Sjmatthew uaq_read_mem(sc, cmd, reg, index, &val, 4); 385*497492a7Sjmatthew DPRINTFN(4, ("uaq_read_4: cmd %x reg %x index %x = %x\n", cmd, reg, 386*497492a7Sjmatthew index, UGETDW(&val))); 387*497492a7Sjmatthew return (UGETDW(&val)); 388*497492a7Sjmatthew } 389*497492a7Sjmatthew 390*497492a7Sjmatthew int 391*497492a7Sjmatthew uaq_write_1(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index, 392*497492a7Sjmatthew uint32_t val) 393*497492a7Sjmatthew { 394*497492a7Sjmatthew uint8_t temp; 395*497492a7Sjmatthew 396*497492a7Sjmatthew DPRINTFN(4, ("uaq_write_1: cmd %x reg %x index %x: %x\n", cmd, reg, 397*497492a7Sjmatthew index, val)); 398*497492a7Sjmatthew temp = val & 0xff; 399*497492a7Sjmatthew return (uaq_write_mem(sc, cmd, reg, index, &temp, 1)); 400*497492a7Sjmatthew } 401*497492a7Sjmatthew 402*497492a7Sjmatthew int 403*497492a7Sjmatthew uaq_write_2(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index, 404*497492a7Sjmatthew uint32_t val) 405*497492a7Sjmatthew { 406*497492a7Sjmatthew uint16_t temp; 407*497492a7Sjmatthew 408*497492a7Sjmatthew DPRINTFN(4, ("uaq_write_2: cmd %x reg %x index %x: %x\n", cmd, reg, 409*497492a7Sjmatthew index, val)); 410*497492a7Sjmatthew USETW(&temp, val & 0xffff); 411*497492a7Sjmatthew return (uaq_write_mem(sc, cmd, reg, index, &temp, 2)); 412*497492a7Sjmatthew } 413*497492a7Sjmatthew 414*497492a7Sjmatthew int 415*497492a7Sjmatthew uaq_write_4(struct uaq_softc *sc, uint8_t cmd, uint16_t reg, uint16_t index, 416*497492a7Sjmatthew uint32_t val) 417*497492a7Sjmatthew { 418*497492a7Sjmatthew uint8_t temp[4]; 419*497492a7Sjmatthew 420*497492a7Sjmatthew DPRINTFN(4, ("uaq_write_4: cmd %x reg %x index %x: %x\n", cmd, reg, 421*497492a7Sjmatthew index, val)); 422*497492a7Sjmatthew USETDW(temp, val); 423*497492a7Sjmatthew return (uaq_write_mem(sc, cmd, reg, index, &temp, 4)); 424*497492a7Sjmatthew } 425*497492a7Sjmatthew 426*497492a7Sjmatthew int 427*497492a7Sjmatthew uaq_match(struct device *parent, void *match, void *aux) 428*497492a7Sjmatthew { 429*497492a7Sjmatthew struct usb_attach_arg *uaa = aux; 430*497492a7Sjmatthew 431*497492a7Sjmatthew if (uaa->iface == NULL || uaa->configno != 1) 432*497492a7Sjmatthew return (UMATCH_NONE); 433*497492a7Sjmatthew 434*497492a7Sjmatthew return (usb_lookup(uaq_devs, uaa->vendor, uaa->product) != NULL ? 435*497492a7Sjmatthew UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE); 436*497492a7Sjmatthew } 437*497492a7Sjmatthew 438*497492a7Sjmatthew void 439*497492a7Sjmatthew uaq_attach(struct device *parent, struct device *self, void *aux) 440*497492a7Sjmatthew { 441*497492a7Sjmatthew struct uaq_softc *sc = (struct uaq_softc *)self; 442*497492a7Sjmatthew struct usb_attach_arg *uaa = aux; 443*497492a7Sjmatthew usb_interface_descriptor_t *id; 444*497492a7Sjmatthew usb_endpoint_descriptor_t *ed; 445*497492a7Sjmatthew struct ifnet *ifp; 446*497492a7Sjmatthew int i, s; 447*497492a7Sjmatthew 448*497492a7Sjmatthew sc->sc_udev = uaa->device; 449*497492a7Sjmatthew sc->sc_iface = uaa->iface; 450*497492a7Sjmatthew 451*497492a7Sjmatthew usb_init_task(&sc->sc_link_task, (void (*)(void *))uaq_link, sc, 452*497492a7Sjmatthew USB_TASK_TYPE_GENERIC); 453*497492a7Sjmatthew 454*497492a7Sjmatthew id = usbd_get_interface_descriptor(sc->sc_iface); 455*497492a7Sjmatthew 456*497492a7Sjmatthew for (i = 0; i < id->bNumEndpoints; i++) { 457*497492a7Sjmatthew ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 458*497492a7Sjmatthew if (!ed) { 459*497492a7Sjmatthew printf("%s: couldn't get ep %d\n", 460*497492a7Sjmatthew sc->sc_dev.dv_xname, i); 461*497492a7Sjmatthew return; 462*497492a7Sjmatthew } 463*497492a7Sjmatthew if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 464*497492a7Sjmatthew UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 465*497492a7Sjmatthew sc->sc_ed[UAQ_ENDPT_RX] = ed->bEndpointAddress; 466*497492a7Sjmatthew } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 467*497492a7Sjmatthew UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 468*497492a7Sjmatthew sc->sc_ed[UAQ_ENDPT_TX] = ed->bEndpointAddress; 469*497492a7Sjmatthew sc->sc_out_frame_size = UGETW(ed->wMaxPacketSize); 470*497492a7Sjmatthew } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 471*497492a7Sjmatthew UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 472*497492a7Sjmatthew sc->sc_ed[UAQ_ENDPT_INTR] = ed->bEndpointAddress; 473*497492a7Sjmatthew } 474*497492a7Sjmatthew } 475*497492a7Sjmatthew 476*497492a7Sjmatthew if ((sc->sc_ed[UAQ_ENDPT_RX] == 0) || 477*497492a7Sjmatthew (sc->sc_ed[UAQ_ENDPT_TX] == 0) || 478*497492a7Sjmatthew (sc->sc_ed[UAQ_ENDPT_INTR] == 0)) { 479*497492a7Sjmatthew printf("%s: missing one or more endpoints (%d, %d, %d)\n", 480*497492a7Sjmatthew sc->sc_dev.dv_xname, sc->sc_ed[UAQ_ENDPT_RX], 481*497492a7Sjmatthew sc->sc_ed[UAQ_ENDPT_TX], sc->sc_ed[UAQ_ENDPT_INTR]); 482*497492a7Sjmatthew return; 483*497492a7Sjmatthew } 484*497492a7Sjmatthew 485*497492a7Sjmatthew s = splnet(); 486*497492a7Sjmatthew 487*497492a7Sjmatthew printf("%s: ver %u.%u.%u", sc->sc_dev.dv_xname, 488*497492a7Sjmatthew uaq_read_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_FW_VER_MAJOR, 1) & 0x7f, 489*497492a7Sjmatthew uaq_read_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_FW_VER_MINOR, 1), 490*497492a7Sjmatthew uaq_read_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_FW_VER_REV, 1)); 491*497492a7Sjmatthew 492*497492a7Sjmatthew uaq_read_mem(sc, UAQ_CMD_FLASH_PARAM, 0, 0, &sc->sc_ac.ac_enaddr, 493*497492a7Sjmatthew ETHER_ADDR_LEN); 494*497492a7Sjmatthew printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr)); 495*497492a7Sjmatthew 496*497492a7Sjmatthew ifp = &sc->sc_ac.ac_if; 497*497492a7Sjmatthew ifp->if_softc = sc; 498*497492a7Sjmatthew strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 499*497492a7Sjmatthew ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 500*497492a7Sjmatthew ifp->if_ioctl = uaq_ioctl; 501*497492a7Sjmatthew ifp->if_start = uaq_start; 502*497492a7Sjmatthew ifp->if_watchdog = uaq_watchdog; 503*497492a7Sjmatthew 504*497492a7Sjmatthew ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_CSUM_IPv4 | 505*497492a7Sjmatthew IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4; 506*497492a7Sjmatthew 507*497492a7Sjmatthew #if NVLAN > 0 508*497492a7Sjmatthew ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 509*497492a7Sjmatthew #endif 510*497492a7Sjmatthew 511*497492a7Sjmatthew ifmedia_init(&sc->sc_ifmedia, IFM_IMASK, uaq_ifmedia_upd, 512*497492a7Sjmatthew uaq_ifmedia_sts); 513*497492a7Sjmatthew uaq_add_media_types(sc); 514*497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); 515*497492a7Sjmatthew ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO); 516*497492a7Sjmatthew sc->sc_ifmedia.ifm_media = sc->sc_ifmedia.ifm_cur->ifm_media; 517*497492a7Sjmatthew 518*497492a7Sjmatthew if_attach(ifp); 519*497492a7Sjmatthew ether_ifattach(ifp); 520*497492a7Sjmatthew 521*497492a7Sjmatthew splx(s); 522*497492a7Sjmatthew } 523*497492a7Sjmatthew 524*497492a7Sjmatthew int 525*497492a7Sjmatthew uaq_detach(struct device *self, int flags) 526*497492a7Sjmatthew { 527*497492a7Sjmatthew struct uaq_softc *sc = (struct uaq_softc *)self; 528*497492a7Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 529*497492a7Sjmatthew int s; 530*497492a7Sjmatthew 531*497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_TX] != NULL) 532*497492a7Sjmatthew usbd_abort_pipe(sc->sc_ep[UAQ_ENDPT_TX]); 533*497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_RX] != NULL) 534*497492a7Sjmatthew usbd_abort_pipe(sc->sc_ep[UAQ_ENDPT_RX]); 535*497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_INTR] != NULL) 536*497492a7Sjmatthew usbd_abort_pipe(sc->sc_ep[UAQ_ENDPT_INTR]); 537*497492a7Sjmatthew 538*497492a7Sjmatthew s = splusb(); 539*497492a7Sjmatthew 540*497492a7Sjmatthew usb_rem_task(sc->sc_udev, &sc->sc_link_task); 541*497492a7Sjmatthew 542*497492a7Sjmatthew usb_detach_wait(&sc->sc_dev); 543*497492a7Sjmatthew 544*497492a7Sjmatthew if (ifp->if_flags & IFF_RUNNING) 545*497492a7Sjmatthew uaq_stop(sc); 546*497492a7Sjmatthew 547*497492a7Sjmatthew if (ifp->if_softc != NULL) { 548*497492a7Sjmatthew ether_ifdetach(ifp); 549*497492a7Sjmatthew if_detach(ifp); 550*497492a7Sjmatthew } 551*497492a7Sjmatthew 552*497492a7Sjmatthew splx(s); 553*497492a7Sjmatthew 554*497492a7Sjmatthew return 0; 555*497492a7Sjmatthew } 556*497492a7Sjmatthew 557*497492a7Sjmatthew int 558*497492a7Sjmatthew uaq_ifmedia_upd(struct ifnet *ifp) 559*497492a7Sjmatthew { 560*497492a7Sjmatthew struct uaq_softc *sc = ifp->if_softc; 561*497492a7Sjmatthew struct ifmedia *ifm = &sc->sc_ifmedia; 562*497492a7Sjmatthew int auto_adv; 563*497492a7Sjmatthew 564*497492a7Sjmatthew if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 565*497492a7Sjmatthew return (EINVAL); 566*497492a7Sjmatthew 567*497492a7Sjmatthew auto_adv = UAQ_PHY_ADV_100M | UAQ_PHY_ADV_1G; 568*497492a7Sjmatthew if (sc->sc_udev->speed == USB_SPEED_SUPER) 569*497492a7Sjmatthew auto_adv |= UAQ_PHY_ADV_2_5G | UAQ_PHY_ADV_5G; 570*497492a7Sjmatthew 571*497492a7Sjmatthew sc->sc_phy_cfg &= ~(UAQ_PHY_ADV_MASK); 572*497492a7Sjmatthew sc->sc_phy_cfg |= UAQ_PHY_PAUSE | UAQ_PHY_ASYM_PAUSE | 573*497492a7Sjmatthew UAQ_PHY_DOWNSHIFT | (3 << UAQ_PHY_DSH_RETRY_SHIFT); 574*497492a7Sjmatthew 575*497492a7Sjmatthew switch (IFM_SUBTYPE(ifm->ifm_media)) { 576*497492a7Sjmatthew case IFM_AUTO: 577*497492a7Sjmatthew sc->sc_phy_cfg |= auto_adv; 578*497492a7Sjmatthew break; 579*497492a7Sjmatthew case IFM_5000_T: 580*497492a7Sjmatthew sc->sc_phy_cfg |= UAQ_PHY_ADV_5G; 581*497492a7Sjmatthew break; 582*497492a7Sjmatthew case IFM_2500_T: 583*497492a7Sjmatthew sc->sc_phy_cfg |= UAQ_PHY_ADV_2_5G; 584*497492a7Sjmatthew break; 585*497492a7Sjmatthew case IFM_1000_T: 586*497492a7Sjmatthew sc->sc_phy_cfg |= UAQ_PHY_ADV_1G; 587*497492a7Sjmatthew break; 588*497492a7Sjmatthew case IFM_100_TX: 589*497492a7Sjmatthew sc->sc_phy_cfg |= UAQ_PHY_ADV_100M; 590*497492a7Sjmatthew break; 591*497492a7Sjmatthew default: 592*497492a7Sjmatthew printf("%s: unsupported media type\n", sc->sc_dev.dv_xname); 593*497492a7Sjmatthew return (EINVAL); 594*497492a7Sjmatthew } 595*497492a7Sjmatthew 596*497492a7Sjmatthew DPRINTFN(1, ("%s: phy cfg %x\n", sc->sc_dev.dv_xname, sc->sc_phy_cfg)); 597*497492a7Sjmatthew uaq_write_4(sc, UAQ_CMD_PHY_OPS, 0, 0, sc->sc_phy_cfg); 598*497492a7Sjmatthew return (0); 599*497492a7Sjmatthew } 600*497492a7Sjmatthew 601*497492a7Sjmatthew void 602*497492a7Sjmatthew uaq_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 603*497492a7Sjmatthew { 604*497492a7Sjmatthew struct uaq_softc *sc = ifp->if_softc; 605*497492a7Sjmatthew 606*497492a7Sjmatthew ifmr->ifm_status = IFM_AVALID; 607*497492a7Sjmatthew if (sc->sc_link_speed > 0) { 608*497492a7Sjmatthew ifmr->ifm_status |= IFM_ACTIVE; 609*497492a7Sjmatthew ifmr->ifm_active = IFM_ETHER | IFM_FDX; 610*497492a7Sjmatthew switch (sc->sc_link_speed) { 611*497492a7Sjmatthew case UAQ_STATUS_SPEED_5G: 612*497492a7Sjmatthew ifmr->ifm_active |= IFM_5000_T; 613*497492a7Sjmatthew break; 614*497492a7Sjmatthew case UAQ_STATUS_SPEED_2_5G: 615*497492a7Sjmatthew ifmr->ifm_active |= IFM_2500_T; 616*497492a7Sjmatthew break; 617*497492a7Sjmatthew case UAQ_STATUS_SPEED_1G: 618*497492a7Sjmatthew ifmr->ifm_active |= IFM_1000_T; 619*497492a7Sjmatthew break; 620*497492a7Sjmatthew case UAQ_STATUS_SPEED_100M: 621*497492a7Sjmatthew ifmr->ifm_active |= IFM_100_TX; 622*497492a7Sjmatthew break; 623*497492a7Sjmatthew default: 624*497492a7Sjmatthew break; 625*497492a7Sjmatthew } 626*497492a7Sjmatthew } 627*497492a7Sjmatthew } 628*497492a7Sjmatthew 629*497492a7Sjmatthew void 630*497492a7Sjmatthew uaq_add_media_types(struct uaq_softc *sc) 631*497492a7Sjmatthew { 632*497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL); 633*497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, 634*497492a7Sjmatthew NULL); 635*497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_1000_T, 0, NULL); 636*497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, 637*497492a7Sjmatthew NULL); 638*497492a7Sjmatthew /* only add 2.5G and 5G if at super speed */ 639*497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_2500_T, 0, NULL); 640*497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_2500_T | IFM_FDX, 0, 641*497492a7Sjmatthew NULL); 642*497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_5000_T, 0, NULL); 643*497492a7Sjmatthew ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_5000_T | IFM_FDX, 0, 644*497492a7Sjmatthew NULL); 645*497492a7Sjmatthew } 646*497492a7Sjmatthew 647*497492a7Sjmatthew void 648*497492a7Sjmatthew uaq_iff(struct uaq_softc *sc) 649*497492a7Sjmatthew { 650*497492a7Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 651*497492a7Sjmatthew struct ether_multi *enm; 652*497492a7Sjmatthew struct ether_multistep step; 653*497492a7Sjmatthew uint8_t filter[UAQ_MCAST_FILTER_SIZE]; 654*497492a7Sjmatthew uint32_t hash; 655*497492a7Sjmatthew 656*497492a7Sjmatthew if (usbd_is_dying(sc->sc_udev)) 657*497492a7Sjmatthew return; 658*497492a7Sjmatthew 659*497492a7Sjmatthew sc->sc_rxctl &= ~(UAQ_SFR_RX_CTL_PRO | UAQ_SFR_RX_CTL_AMALL | 660*497492a7Sjmatthew UAQ_SFR_RX_CTL_AM); 661*497492a7Sjmatthew if (ifp->if_flags & IFF_PROMISC || sc->sc_ac.ac_multirangecnt > 0) { 662*497492a7Sjmatthew sc->sc_rxctl |= UAQ_SFR_RX_CTL_PRO; 663*497492a7Sjmatthew } else if (ifp->if_flags & IFF_ALLMULTI || 664*497492a7Sjmatthew sc->sc_ac.ac_multirangecnt > 0) { 665*497492a7Sjmatthew sc->sc_rxctl |= UAQ_SFR_RX_CTL_AMALL; 666*497492a7Sjmatthew } else if (sc->sc_ac.ac_multicnt > 0) { 667*497492a7Sjmatthew sc->sc_rxctl |= UAQ_SFR_RX_CTL_AM; 668*497492a7Sjmatthew 669*497492a7Sjmatthew bzero(filter, sizeof(filter)); 670*497492a7Sjmatthew ETHER_FIRST_MULTI(step, &sc->sc_ac, enm); 671*497492a7Sjmatthew while (enm != NULL) { 672*497492a7Sjmatthew hash = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) 673*497492a7Sjmatthew >> 26; 674*497492a7Sjmatthew filter[hash >> 3] |= (1 << (hash & 7)); 675*497492a7Sjmatthew ETHER_NEXT_MULTI(step, enm); 676*497492a7Sjmatthew } 677*497492a7Sjmatthew 678*497492a7Sjmatthew uaq_write_mem(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MCAST_FILTER, 679*497492a7Sjmatthew UAQ_MCAST_FILTER_SIZE, filter, UAQ_MCAST_FILTER_SIZE); 680*497492a7Sjmatthew } 681*497492a7Sjmatthew 682*497492a7Sjmatthew DPRINTFN(1, ("%s: rxctl = %x\n", sc->sc_dev.dv_xname, sc->sc_rxctl)); 683*497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RX_CTL, 2, sc->sc_rxctl); 684*497492a7Sjmatthew } 685*497492a7Sjmatthew 686*497492a7Sjmatthew void 687*497492a7Sjmatthew uaq_reset(struct uaq_softc *sc) 688*497492a7Sjmatthew { 689*497492a7Sjmatthew uint8_t mode; 690*497492a7Sjmatthew 691*497492a7Sjmatthew sc->sc_phy_cfg = UAQ_PHY_POWER_EN; 692*497492a7Sjmatthew uaq_write_4(sc, UAQ_CMD_PHY_OPS, 0, 0, sc->sc_phy_cfg); 693*497492a7Sjmatthew 694*497492a7Sjmatthew uaq_write_mem(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_NODE_ID, 0, 695*497492a7Sjmatthew sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); 696*497492a7Sjmatthew uaq_write_mem(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_NODE_ID, ETHER_ADDR_LEN, 697*497492a7Sjmatthew sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); 698*497492a7Sjmatthew 699*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BM_INT_MASK, 0, 0xff); 700*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_SWP_CTRL, 0, 0); 701*497492a7Sjmatthew 702*497492a7Sjmatthew mode = uaq_read_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MONITOR_MODE, 1); 703*497492a7Sjmatthew mode &= ~(UAQ_SFR_MONITOR_MODE_EPHYRW | UAQ_SFR_MONITOR_MODE_RWLC | 704*497492a7Sjmatthew UAQ_SFR_MONITOR_MODE_RWMP | UAQ_SFR_MONITOR_MODE_RWWF | 705*497492a7Sjmatthew UAQ_SFR_MONITOR_MODE_RW_FLAG); 706*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MONITOR_MODE, 1, mode); 707*497492a7Sjmatthew 708*497492a7Sjmatthew sc->sc_link_status = 0; 709*497492a7Sjmatthew sc->sc_link_speed = 0; 710*497492a7Sjmatthew } 711*497492a7Sjmatthew 712*497492a7Sjmatthew void 713*497492a7Sjmatthew uaq_init(void *xsc) 714*497492a7Sjmatthew { 715*497492a7Sjmatthew struct uaq_softc *sc = xsc; 716*497492a7Sjmatthew struct uaq_chain *c; 717*497492a7Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 718*497492a7Sjmatthew usbd_status err; 719*497492a7Sjmatthew int s, i; 720*497492a7Sjmatthew 721*497492a7Sjmatthew s = splnet(); 722*497492a7Sjmatthew 723*497492a7Sjmatthew uaq_stop(sc); 724*497492a7Sjmatthew 725*497492a7Sjmatthew uaq_reset(sc); 726*497492a7Sjmatthew 727*497492a7Sjmatthew if (uaq_xfer_list_init(sc, sc->sc_cdata.uaq_rx_chain, 728*497492a7Sjmatthew UAQ_RX_BUFSZ, UAQ_RX_LIST_CNT) == ENOBUFS) { 729*497492a7Sjmatthew printf("%s: rx list init failed\n", sc->sc_dev.dv_xname); 730*497492a7Sjmatthew splx(s); 731*497492a7Sjmatthew return; 732*497492a7Sjmatthew } 733*497492a7Sjmatthew 734*497492a7Sjmatthew if (uaq_xfer_list_init(sc, sc->sc_cdata.uaq_tx_chain, 735*497492a7Sjmatthew UAQ_TX_BUFSZ, UAQ_TX_LIST_CNT) == ENOBUFS) { 736*497492a7Sjmatthew printf("%s: tx list init failed\n", sc->sc_dev.dv_xname); 737*497492a7Sjmatthew splx(s); 738*497492a7Sjmatthew return; 739*497492a7Sjmatthew } 740*497492a7Sjmatthew 741*497492a7Sjmatthew SLIST_INIT(&sc->sc_cdata.uaq_tx_free); 742*497492a7Sjmatthew for (i = 0; i < UAQ_TX_LIST_CNT; i++) 743*497492a7Sjmatthew SLIST_INSERT_HEAD(&sc->sc_cdata.uaq_tx_free, 744*497492a7Sjmatthew &sc->sc_cdata.uaq_tx_chain[i], uc_list); 745*497492a7Sjmatthew 746*497492a7Sjmatthew err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UAQ_ENDPT_RX], 747*497492a7Sjmatthew USBD_EXCLUSIVE_USE, &sc->sc_ep[UAQ_ENDPT_RX]); 748*497492a7Sjmatthew if (err) { 749*497492a7Sjmatthew printf("%s: open rx pipe failed: %s\n", 750*497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(err)); 751*497492a7Sjmatthew splx(s); 752*497492a7Sjmatthew return; 753*497492a7Sjmatthew } 754*497492a7Sjmatthew 755*497492a7Sjmatthew err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UAQ_ENDPT_TX], 756*497492a7Sjmatthew USBD_EXCLUSIVE_USE, &sc->sc_ep[UAQ_ENDPT_TX]); 757*497492a7Sjmatthew if (err) { 758*497492a7Sjmatthew printf("%s: open tx pipe failed: %s\n", 759*497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(err)); 760*497492a7Sjmatthew splx(s); 761*497492a7Sjmatthew return; 762*497492a7Sjmatthew } 763*497492a7Sjmatthew 764*497492a7Sjmatthew for (i = 0; i < UAQ_RX_LIST_CNT; i++) { 765*497492a7Sjmatthew c = &sc->sc_cdata.uaq_rx_chain[i]; 766*497492a7Sjmatthew usbd_setup_xfer(c->uc_xfer, sc->sc_ep[UAQ_ENDPT_RX], 767*497492a7Sjmatthew c, c->uc_buf, c->uc_bufmax, 768*497492a7Sjmatthew USBD_SHORT_XFER_OK | USBD_NO_COPY, 769*497492a7Sjmatthew USBD_NO_TIMEOUT, uaq_rxeof); 770*497492a7Sjmatthew usbd_transfer(c->uc_xfer); 771*497492a7Sjmatthew } 772*497492a7Sjmatthew 773*497492a7Sjmatthew err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ed[UAQ_ENDPT_INTR], 774*497492a7Sjmatthew 0, &sc->sc_ep[UAQ_ENDPT_INTR], sc, 775*497492a7Sjmatthew &sc->sc_link_status, sizeof(sc->sc_link_status), uaq_intr, 776*497492a7Sjmatthew USBD_DEFAULT_INTERVAL); 777*497492a7Sjmatthew if (err) { 778*497492a7Sjmatthew printf("%s: couldn't open interrupt pipe\n", 779*497492a7Sjmatthew sc->sc_dev.dv_xname); 780*497492a7Sjmatthew return; 781*497492a7Sjmatthew } 782*497492a7Sjmatthew 783*497492a7Sjmatthew uaq_ifmedia_upd(ifp); 784*497492a7Sjmatthew 785*497492a7Sjmatthew ifp->if_flags |= IFF_RUNNING; 786*497492a7Sjmatthew ifq_clr_oactive(&ifp->if_snd); 787*497492a7Sjmatthew 788*497492a7Sjmatthew splx(s); 789*497492a7Sjmatthew } 790*497492a7Sjmatthew 791*497492a7Sjmatthew int 792*497492a7Sjmatthew uaq_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 793*497492a7Sjmatthew { 794*497492a7Sjmatthew struct uaq_softc *sc = ifp->if_softc; 795*497492a7Sjmatthew struct ifreq *ifr = (struct ifreq *)data; 796*497492a7Sjmatthew int s, error = 0; 797*497492a7Sjmatthew 798*497492a7Sjmatthew s = splnet(); 799*497492a7Sjmatthew 800*497492a7Sjmatthew switch (cmd) { 801*497492a7Sjmatthew case SIOCSIFADDR: 802*497492a7Sjmatthew ifp->if_flags |= IFF_UP; 803*497492a7Sjmatthew if (!(ifp->if_flags & IFF_RUNNING)) 804*497492a7Sjmatthew uaq_init(sc); 805*497492a7Sjmatthew break; 806*497492a7Sjmatthew 807*497492a7Sjmatthew case SIOCSIFFLAGS: 808*497492a7Sjmatthew if (ifp->if_flags & IFF_UP) { 809*497492a7Sjmatthew if (ifp->if_flags & IFF_RUNNING) 810*497492a7Sjmatthew error = ENETRESET; 811*497492a7Sjmatthew else 812*497492a7Sjmatthew uaq_init(sc); 813*497492a7Sjmatthew } else { 814*497492a7Sjmatthew if (ifp->if_flags & IFF_RUNNING) 815*497492a7Sjmatthew uaq_stop(sc); 816*497492a7Sjmatthew } 817*497492a7Sjmatthew break; 818*497492a7Sjmatthew 819*497492a7Sjmatthew case SIOCGIFMEDIA: 820*497492a7Sjmatthew case SIOCSIFMEDIA: 821*497492a7Sjmatthew error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd); 822*497492a7Sjmatthew break; 823*497492a7Sjmatthew 824*497492a7Sjmatthew default: 825*497492a7Sjmatthew error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 826*497492a7Sjmatthew } 827*497492a7Sjmatthew 828*497492a7Sjmatthew if (error == ENETRESET) { 829*497492a7Sjmatthew if (ifp->if_flags & IFF_RUNNING) 830*497492a7Sjmatthew uaq_iff(sc); 831*497492a7Sjmatthew error = 0; 832*497492a7Sjmatthew } 833*497492a7Sjmatthew 834*497492a7Sjmatthew splx(s); 835*497492a7Sjmatthew 836*497492a7Sjmatthew return (error); 837*497492a7Sjmatthew } 838*497492a7Sjmatthew 839*497492a7Sjmatthew int 840*497492a7Sjmatthew uaq_xfer_list_init(struct uaq_softc *sc, struct uaq_chain *ch, 841*497492a7Sjmatthew uint32_t bufsize, int listlen) 842*497492a7Sjmatthew { 843*497492a7Sjmatthew struct uaq_chain *c; 844*497492a7Sjmatthew int i; 845*497492a7Sjmatthew 846*497492a7Sjmatthew for (i = 0; i < listlen; i++) { 847*497492a7Sjmatthew c = &ch[i]; 848*497492a7Sjmatthew c->uc_sc = sc; 849*497492a7Sjmatthew c->uc_idx = i; 850*497492a7Sjmatthew c->uc_buflen = 0; 851*497492a7Sjmatthew c->uc_bufmax = bufsize; 852*497492a7Sjmatthew c->uc_cnt = 0; 853*497492a7Sjmatthew if (c->uc_xfer == NULL) { 854*497492a7Sjmatthew c->uc_xfer = usbd_alloc_xfer(sc->sc_udev); 855*497492a7Sjmatthew if (c->uc_xfer == NULL) 856*497492a7Sjmatthew return (ENOBUFS); 857*497492a7Sjmatthew 858*497492a7Sjmatthew c->uc_buf = usbd_alloc_buffer(c->uc_xfer, c->uc_bufmax); 859*497492a7Sjmatthew if (c->uc_buf == NULL) { 860*497492a7Sjmatthew usbd_free_xfer(c->uc_xfer); 861*497492a7Sjmatthew c->uc_xfer = NULL; 862*497492a7Sjmatthew return (ENOBUFS); 863*497492a7Sjmatthew } 864*497492a7Sjmatthew } 865*497492a7Sjmatthew } 866*497492a7Sjmatthew 867*497492a7Sjmatthew return (0); 868*497492a7Sjmatthew } 869*497492a7Sjmatthew 870*497492a7Sjmatthew void 871*497492a7Sjmatthew uaq_xfer_list_free(struct uaq_softc *sc, struct uaq_chain *ch, int listlen) 872*497492a7Sjmatthew { 873*497492a7Sjmatthew int i; 874*497492a7Sjmatthew 875*497492a7Sjmatthew for (i = 0; i < listlen; i++) { 876*497492a7Sjmatthew if (ch[i].uc_buf != NULL) { 877*497492a7Sjmatthew ch[i].uc_buf = NULL; 878*497492a7Sjmatthew } 879*497492a7Sjmatthew ch[i].uc_cnt = 0; 880*497492a7Sjmatthew if (ch[i].uc_xfer != NULL) { 881*497492a7Sjmatthew usbd_free_xfer(ch[i].uc_xfer); 882*497492a7Sjmatthew ch[i].uc_xfer = NULL; 883*497492a7Sjmatthew } 884*497492a7Sjmatthew } 885*497492a7Sjmatthew } 886*497492a7Sjmatthew 887*497492a7Sjmatthew void 888*497492a7Sjmatthew uaq_stop(struct uaq_softc *sc) 889*497492a7Sjmatthew { 890*497492a7Sjmatthew struct uaq_cdata *cd; 891*497492a7Sjmatthew struct ifnet *ifp; 892*497492a7Sjmatthew usbd_status err; 893*497492a7Sjmatthew 894*497492a7Sjmatthew ifp = &sc->sc_ac.ac_if; 895*497492a7Sjmatthew ifp->if_timer = 0; 896*497492a7Sjmatthew ifp->if_flags &= ~IFF_RUNNING; 897*497492a7Sjmatthew ifq_clr_oactive(&ifp->if_snd); 898*497492a7Sjmatthew 899*497492a7Sjmatthew sc->sc_link_status = 0; 900*497492a7Sjmatthew sc->sc_link_speed = 0; 901*497492a7Sjmatthew 902*497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_RX] != NULL) { 903*497492a7Sjmatthew err = usbd_close_pipe(sc->sc_ep[UAQ_ENDPT_RX]); 904*497492a7Sjmatthew if (err) { 905*497492a7Sjmatthew printf("%s: close rx pipe failed: %s\n", 906*497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(err)); 907*497492a7Sjmatthew } 908*497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_RX] = NULL; 909*497492a7Sjmatthew } 910*497492a7Sjmatthew 911*497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_TX] != NULL) { 912*497492a7Sjmatthew err = usbd_close_pipe(sc->sc_ep[UAQ_ENDPT_TX]); 913*497492a7Sjmatthew if (err) { 914*497492a7Sjmatthew printf("%s: close tx pipe failed: %s\n", 915*497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(err)); 916*497492a7Sjmatthew } 917*497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_TX] = NULL; 918*497492a7Sjmatthew } 919*497492a7Sjmatthew 920*497492a7Sjmatthew if (sc->sc_ep[UAQ_ENDPT_INTR] != NULL) { 921*497492a7Sjmatthew err = usbd_close_pipe(sc->sc_ep[UAQ_ENDPT_INTR]); 922*497492a7Sjmatthew if (err) { 923*497492a7Sjmatthew printf("%s: close intr pipe failed: %s\n", 924*497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(err)); 925*497492a7Sjmatthew } 926*497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_INTR] = NULL; 927*497492a7Sjmatthew } 928*497492a7Sjmatthew 929*497492a7Sjmatthew cd = &sc->sc_cdata; 930*497492a7Sjmatthew uaq_xfer_list_free(sc, cd->uaq_rx_chain, UAQ_RX_LIST_CNT); 931*497492a7Sjmatthew uaq_xfer_list_free(sc, cd->uaq_tx_chain, UAQ_TX_LIST_CNT); 932*497492a7Sjmatthew } 933*497492a7Sjmatthew 934*497492a7Sjmatthew void 935*497492a7Sjmatthew uaq_link(struct uaq_softc *sc) 936*497492a7Sjmatthew { 937*497492a7Sjmatthew if (sc->sc_link_speed > 0) { 938*497492a7Sjmatthew uint8_t resend[3] = { 0, 0xf8, 7 }; 939*497492a7Sjmatthew uint8_t qctrl[5] = { 7, 0x00, 0x01, 0x1e, 0xff }; 940*497492a7Sjmatthew uint8_t ipg = 0; 941*497492a7Sjmatthew 942*497492a7Sjmatthew switch (sc->sc_link_speed) { 943*497492a7Sjmatthew case UAQ_STATUS_SPEED_100M: 944*497492a7Sjmatthew resend[1] = 0xfb; 945*497492a7Sjmatthew resend[2] = 0x4; 946*497492a7Sjmatthew break; 947*497492a7Sjmatthew 948*497492a7Sjmatthew case UAQ_STATUS_SPEED_5G: 949*497492a7Sjmatthew ipg = 5; 950*497492a7Sjmatthew break; 951*497492a7Sjmatthew } 952*497492a7Sjmatthew 953*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_IPG_0, 1, ipg); 954*497492a7Sjmatthew 955*497492a7Sjmatthew uaq_write_mem(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_TX_PAUSE_RESEND_T, 956*497492a7Sjmatthew 3, resend, 3); 957*497492a7Sjmatthew uaq_write_mem(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RX_BULKIN_QCTRL, 958*497492a7Sjmatthew 5, qctrl, 5); 959*497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_PAUSE_WATERLVL_LOW, 960*497492a7Sjmatthew 2, 0x0810); 961*497492a7Sjmatthew 962*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BMRX_DMA_CTRL, 1, 963*497492a7Sjmatthew 0); 964*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BMTX_DMA_CTRL, 1, 965*497492a7Sjmatthew 0); 966*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_ARC_CTRL, 1, 0); 967*497492a7Sjmatthew 968*497492a7Sjmatthew sc->sc_rxctl = UAQ_SFR_RX_CTL_IPE | UAQ_SFR_RX_CTL_AB; 969*497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RX_CTL, 2, 970*497492a7Sjmatthew sc->sc_rxctl); 971*497492a7Sjmatthew 972*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_ETH_MAC_PATH, 1, 973*497492a7Sjmatthew UAQ_SFR_RX_PATH_READY); 974*497492a7Sjmatthew 975*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BULK_OUT_CTRL, 1, 976*497492a7Sjmatthew UAQ_SFR_BULK_OUT_EFF_EN); 977*497492a7Sjmatthew 978*497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MEDIUM_STATUS_MODE, 979*497492a7Sjmatthew 2, 0); 980*497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MEDIUM_STATUS_MODE, 981*497492a7Sjmatthew 2, UAQ_SFR_MEDIUM_XGMIIMODE | UAQ_SFR_MEDIUM_FULL_DUPLEX | 982*497492a7Sjmatthew UAQ_SFR_MEDIUM_RECEIVE_EN | UAQ_SFR_MEDIUM_RXFLOW_CTRLEN | 983*497492a7Sjmatthew UAQ_SFR_MEDIUM_TXFLOW_CTRLEN); /* JUMBO_EN */ 984*497492a7Sjmatthew 985*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RXCOE_CTL, 1, 986*497492a7Sjmatthew UAQ_SFR_RXCOE_IP | UAQ_SFR_RXCOE_TCP | UAQ_SFR_RXCOE_UDP | 987*497492a7Sjmatthew UAQ_SFR_RXCOE_TCPV6 | UAQ_SFR_RXCOE_UDPV6); 988*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_TXCOE_CTL, 1, 989*497492a7Sjmatthew UAQ_SFR_TXCOE_IP | UAQ_SFR_TXCOE_TCP | UAQ_SFR_TXCOE_UDP | 990*497492a7Sjmatthew UAQ_SFR_TXCOE_TCPV6 | UAQ_SFR_TXCOE_UDPV6); 991*497492a7Sjmatthew 992*497492a7Sjmatthew sc->sc_rxctl |= UAQ_SFR_RX_CTL_START; 993*497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RX_CTL, 2, 994*497492a7Sjmatthew sc->sc_rxctl); 995*497492a7Sjmatthew } else { 996*497492a7Sjmatthew uint16_t mode; 997*497492a7Sjmatthew 998*497492a7Sjmatthew mode = uaq_read_2(sc, UAQ_CMD_ACCESS_MAC, 999*497492a7Sjmatthew UAQ_SFR_MEDIUM_STATUS_MODE, 2); 1000*497492a7Sjmatthew mode &= ~UAQ_SFR_MEDIUM_RECEIVE_EN; 1001*497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_MEDIUM_STATUS_MODE, 1002*497492a7Sjmatthew 2, mode); 1003*497492a7Sjmatthew 1004*497492a7Sjmatthew sc->sc_rxctl &= ~UAQ_SFR_RX_CTL_START; 1005*497492a7Sjmatthew uaq_write_2(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_RX_CTL, 2, 1006*497492a7Sjmatthew sc->sc_rxctl); 1007*497492a7Sjmatthew 1008*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BULK_OUT_CTRL, 1, 1009*497492a7Sjmatthew UAQ_SFR_BULK_OUT_FLUSH_EN | UAQ_SFR_BULK_OUT_EFF_EN); 1010*497492a7Sjmatthew 1011*497492a7Sjmatthew uaq_write_1(sc, UAQ_CMD_ACCESS_MAC, UAQ_SFR_BULK_OUT_CTRL, 1, 1012*497492a7Sjmatthew UAQ_SFR_BULK_OUT_EFF_EN); 1013*497492a7Sjmatthew } 1014*497492a7Sjmatthew } 1015*497492a7Sjmatthew 1016*497492a7Sjmatthew void 1017*497492a7Sjmatthew uaq_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 1018*497492a7Sjmatthew { 1019*497492a7Sjmatthew struct uaq_softc *sc = priv; 1020*497492a7Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 1021*497492a7Sjmatthew uint64_t linkstatus; 1022*497492a7Sjmatthew uint64_t baudrate; 1023*497492a7Sjmatthew int link_state; 1024*497492a7Sjmatthew 1025*497492a7Sjmatthew if (status == USBD_CANCELLED) 1026*497492a7Sjmatthew return; 1027*497492a7Sjmatthew 1028*497492a7Sjmatthew if (status != USBD_NORMAL_COMPLETION) { 1029*497492a7Sjmatthew DPRINTFN(2, ("uaq_intr: status=%d\n", status)); 1030*497492a7Sjmatthew if (status == USBD_STALLED) 1031*497492a7Sjmatthew usbd_clear_endpoint_stall_async( 1032*497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_INTR]); 1033*497492a7Sjmatthew return; 1034*497492a7Sjmatthew } 1035*497492a7Sjmatthew 1036*497492a7Sjmatthew linkstatus = letoh64(sc->sc_link_status); 1037*497492a7Sjmatthew DPRINTFN(1, ("uaq_intr: link status %llx\n", linkstatus)); 1038*497492a7Sjmatthew 1039*497492a7Sjmatthew if (linkstatus & UAQ_STATUS_LINK) { 1040*497492a7Sjmatthew link_state = LINK_STATE_FULL_DUPLEX; 1041*497492a7Sjmatthew sc->sc_link_speed = (linkstatus & UAQ_STATUS_SPEED_MASK) 1042*497492a7Sjmatthew >> UAQ_STATUS_SPEED_SHIFT; 1043*497492a7Sjmatthew switch (sc->sc_link_speed) { 1044*497492a7Sjmatthew case UAQ_STATUS_SPEED_5G: 1045*497492a7Sjmatthew baudrate = IF_Gbps(5); 1046*497492a7Sjmatthew break; 1047*497492a7Sjmatthew case UAQ_STATUS_SPEED_2_5G: 1048*497492a7Sjmatthew baudrate = IF_Mbps(2500); 1049*497492a7Sjmatthew break; 1050*497492a7Sjmatthew case UAQ_STATUS_SPEED_1G: 1051*497492a7Sjmatthew baudrate = IF_Gbps(1); 1052*497492a7Sjmatthew break; 1053*497492a7Sjmatthew case UAQ_STATUS_SPEED_100M: 1054*497492a7Sjmatthew baudrate = IF_Mbps(100); 1055*497492a7Sjmatthew break; 1056*497492a7Sjmatthew default: 1057*497492a7Sjmatthew baudrate = 0; 1058*497492a7Sjmatthew break; 1059*497492a7Sjmatthew } 1060*497492a7Sjmatthew 1061*497492a7Sjmatthew ifp->if_baudrate = baudrate; 1062*497492a7Sjmatthew } else { 1063*497492a7Sjmatthew link_state = LINK_STATE_DOWN; 1064*497492a7Sjmatthew sc->sc_link_speed = 0; 1065*497492a7Sjmatthew } 1066*497492a7Sjmatthew 1067*497492a7Sjmatthew if (link_state != ifp->if_link_state) { 1068*497492a7Sjmatthew ifp->if_link_state = link_state; 1069*497492a7Sjmatthew if_link_state_change(ifp); 1070*497492a7Sjmatthew usb_add_task(sc->sc_udev, &sc->sc_link_task); 1071*497492a7Sjmatthew } 1072*497492a7Sjmatthew } 1073*497492a7Sjmatthew 1074*497492a7Sjmatthew void 1075*497492a7Sjmatthew uaq_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 1076*497492a7Sjmatthew { 1077*497492a7Sjmatthew struct uaq_chain *c = (struct uaq_chain *)priv; 1078*497492a7Sjmatthew struct uaq_softc *sc = c->uc_sc; 1079*497492a7Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 1080*497492a7Sjmatthew uint8_t *buf; 1081*497492a7Sjmatthew uint64_t *pdesc; 1082*497492a7Sjmatthew uint64_t desc; 1083*497492a7Sjmatthew uint32_t total_len; 1084*497492a7Sjmatthew struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 1085*497492a7Sjmatthew struct mbuf *m; 1086*497492a7Sjmatthew int pktlen, s; 1087*497492a7Sjmatthew int count, offset; 1088*497492a7Sjmatthew 1089*497492a7Sjmatthew if (usbd_is_dying(sc->sc_udev)) 1090*497492a7Sjmatthew return; 1091*497492a7Sjmatthew 1092*497492a7Sjmatthew if (!(ifp->if_flags & IFF_RUNNING)) 1093*497492a7Sjmatthew return; 1094*497492a7Sjmatthew 1095*497492a7Sjmatthew if (status != USBD_NORMAL_COMPLETION) { 1096*497492a7Sjmatthew if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 1097*497492a7Sjmatthew return; 1098*497492a7Sjmatthew if (usbd_ratecheck(&sc->sc_rx_notice)) { 1099*497492a7Sjmatthew printf("%s: usb errors on rx: %s\n", 1100*497492a7Sjmatthew sc->sc_dev.dv_xname, usbd_errstr(status)); 1101*497492a7Sjmatthew } 1102*497492a7Sjmatthew if (status == USBD_STALLED) 1103*497492a7Sjmatthew usbd_clear_endpoint_stall_async( 1104*497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_RX]); 1105*497492a7Sjmatthew goto done; 1106*497492a7Sjmatthew } 1107*497492a7Sjmatthew 1108*497492a7Sjmatthew usbd_get_xfer_status(xfer, NULL, (void **)&buf, &total_len, NULL); 1109*497492a7Sjmatthew DPRINTFN(3, ("received %d bytes\n", total_len)); 1110*497492a7Sjmatthew if ((total_len & 7) != 0) { 1111*497492a7Sjmatthew printf("%s: weird rx transfer length %d\n", 1112*497492a7Sjmatthew sc->sc_dev.dv_xname, total_len); 1113*497492a7Sjmatthew goto done; 1114*497492a7Sjmatthew } 1115*497492a7Sjmatthew 1116*497492a7Sjmatthew pdesc = (uint64_t *)(buf + (total_len - sizeof(desc))); 1117*497492a7Sjmatthew desc = lemtoh64(pdesc); 1118*497492a7Sjmatthew 1119*497492a7Sjmatthew count = desc & UAQ_RX_HDR_COUNT_MASK; 1120*497492a7Sjmatthew if (count == 0) 1121*497492a7Sjmatthew goto done; 1122*497492a7Sjmatthew 1123*497492a7Sjmatthew /* get offset of packet headers */ 1124*497492a7Sjmatthew offset = total_len - ((count + 1) * sizeof(desc)); 1125*497492a7Sjmatthew if (offset != ((desc & UAQ_RX_HDR_OFFSET_MASK) >> 1126*497492a7Sjmatthew UAQ_RX_HDR_OFFSET_SHIFT)) { 1127*497492a7Sjmatthew printf("%s: offset mismatch, got %d expected %lld\n", 1128*497492a7Sjmatthew sc->sc_dev.dv_xname, offset, 1129*497492a7Sjmatthew desc >> UAQ_RX_HDR_OFFSET_SHIFT); 1130*497492a7Sjmatthew goto done; 1131*497492a7Sjmatthew } 1132*497492a7Sjmatthew if (offset < 0 || offset > total_len) { 1133*497492a7Sjmatthew printf("%s: offset %d outside buffer (%d)\n", 1134*497492a7Sjmatthew sc->sc_dev.dv_xname, offset, total_len); 1135*497492a7Sjmatthew goto done; 1136*497492a7Sjmatthew } 1137*497492a7Sjmatthew 1138*497492a7Sjmatthew pdesc = (uint64_t *)(buf + offset); 1139*497492a7Sjmatthew total_len = offset; 1140*497492a7Sjmatthew 1141*497492a7Sjmatthew while (count-- > 0) { 1142*497492a7Sjmatthew desc = lemtoh64(pdesc); 1143*497492a7Sjmatthew pdesc++; 1144*497492a7Sjmatthew 1145*497492a7Sjmatthew pktlen = (desc & UAQ_RX_PKT_LEN_MASK) >> UAQ_RX_PKT_LEN_SHIFT; 1146*497492a7Sjmatthew if (pktlen > total_len) { 1147*497492a7Sjmatthew DPRINTFN(2, ("not enough bytes for this packet\n")); 1148*497492a7Sjmatthew ifp->if_ierrors++; 1149*497492a7Sjmatthew goto done; 1150*497492a7Sjmatthew } 1151*497492a7Sjmatthew 1152*497492a7Sjmatthew m = m_devget(buf + 2, pktlen - 2, ETHER_ALIGN); 1153*497492a7Sjmatthew if (m == NULL) { 1154*497492a7Sjmatthew DPRINTFN(2, ("m_devget failed for this packet\n")); 1155*497492a7Sjmatthew ifp->if_ierrors++; 1156*497492a7Sjmatthew goto done; 1157*497492a7Sjmatthew } 1158*497492a7Sjmatthew 1159*497492a7Sjmatthew if ((desc & UAQ_RX_PKT_L3_ERR) == 0) 1160*497492a7Sjmatthew m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK; 1161*497492a7Sjmatthew 1162*497492a7Sjmatthew if ((desc & UAQ_RX_PKT_L4_ERR) == 0) 1163*497492a7Sjmatthew m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK | 1164*497492a7Sjmatthew M_UDP_CSUM_IN_OK; 1165*497492a7Sjmatthew 1166*497492a7Sjmatthew #if NVLAN > 0 1167*497492a7Sjmatthew if (desc & UAQ_RX_PKT_VLAN) { 1168*497492a7Sjmatthew m->m_pkthdr.ether_vtag = (desc >> UAQ_RX_PKT_VLAN_SHIFT) & 1169*497492a7Sjmatthew 0xfff; 1170*497492a7Sjmatthew m->m_flags |= M_VLANTAG; 1171*497492a7Sjmatthew } 1172*497492a7Sjmatthew #endif 1173*497492a7Sjmatthew ml_enqueue(&ml, m); 1174*497492a7Sjmatthew 1175*497492a7Sjmatthew total_len -= roundup(pktlen, UAQ_RX_BUF_ALIGN); 1176*497492a7Sjmatthew buf += roundup(pktlen, UAQ_RX_BUF_ALIGN); 1177*497492a7Sjmatthew } 1178*497492a7Sjmatthew 1179*497492a7Sjmatthew done: 1180*497492a7Sjmatthew s = splnet(); 1181*497492a7Sjmatthew if_input(ifp, &ml); 1182*497492a7Sjmatthew splx(s); 1183*497492a7Sjmatthew memset(c->uc_buf, 0, UAQ_RX_BUFSZ); 1184*497492a7Sjmatthew 1185*497492a7Sjmatthew usbd_setup_xfer(xfer, sc->sc_ep[UAQ_ENDPT_RX], c, c->uc_buf, 1186*497492a7Sjmatthew UAQ_RX_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, 1187*497492a7Sjmatthew USBD_NO_TIMEOUT, uaq_rxeof); 1188*497492a7Sjmatthew usbd_transfer(xfer); 1189*497492a7Sjmatthew } 1190*497492a7Sjmatthew 1191*497492a7Sjmatthew 1192*497492a7Sjmatthew void 1193*497492a7Sjmatthew uaq_watchdog(struct ifnet *ifp) 1194*497492a7Sjmatthew { 1195*497492a7Sjmatthew struct uaq_softc *sc = ifp->if_softc; 1196*497492a7Sjmatthew struct uaq_chain *c; 1197*497492a7Sjmatthew usbd_status err; 1198*497492a7Sjmatthew int i, s; 1199*497492a7Sjmatthew 1200*497492a7Sjmatthew ifp->if_timer = 0; 1201*497492a7Sjmatthew 1202*497492a7Sjmatthew if (usbd_is_dying(sc->sc_udev)) 1203*497492a7Sjmatthew return; 1204*497492a7Sjmatthew 1205*497492a7Sjmatthew if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP)) 1206*497492a7Sjmatthew return; 1207*497492a7Sjmatthew 1208*497492a7Sjmatthew sc = ifp->if_softc; 1209*497492a7Sjmatthew s = splnet(); 1210*497492a7Sjmatthew 1211*497492a7Sjmatthew ifp->if_oerrors++; 1212*497492a7Sjmatthew DPRINTF(("%s: watchdog timeout\n", sc->sc_dev.dv_xname)); 1213*497492a7Sjmatthew 1214*497492a7Sjmatthew for (i = 0; i < UAQ_TX_LIST_CNT; i++) { 1215*497492a7Sjmatthew c = &sc->sc_cdata.uaq_tx_chain[i]; 1216*497492a7Sjmatthew if (c->uc_cnt > 0) { 1217*497492a7Sjmatthew usbd_get_xfer_status(c->uc_xfer, NULL, NULL, NULL, 1218*497492a7Sjmatthew &err); 1219*497492a7Sjmatthew uaq_txeof(c->uc_xfer, c, err); 1220*497492a7Sjmatthew } 1221*497492a7Sjmatthew } 1222*497492a7Sjmatthew 1223*497492a7Sjmatthew if (ifq_is_oactive(&ifp->if_snd)) 1224*497492a7Sjmatthew ifq_restart(&ifp->if_snd); 1225*497492a7Sjmatthew splx(s); 1226*497492a7Sjmatthew } 1227*497492a7Sjmatthew 1228*497492a7Sjmatthew void 1229*497492a7Sjmatthew uaq_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 1230*497492a7Sjmatthew { 1231*497492a7Sjmatthew struct uaq_softc *sc; 1232*497492a7Sjmatthew struct uaq_chain *c; 1233*497492a7Sjmatthew struct ifnet *ifp; 1234*497492a7Sjmatthew int s; 1235*497492a7Sjmatthew 1236*497492a7Sjmatthew c = priv; 1237*497492a7Sjmatthew sc = c->uc_sc; 1238*497492a7Sjmatthew ifp = &sc->sc_ac.ac_if; 1239*497492a7Sjmatthew 1240*497492a7Sjmatthew if (usbd_is_dying(sc->sc_udev)) 1241*497492a7Sjmatthew return; 1242*497492a7Sjmatthew 1243*497492a7Sjmatthew if (status != USBD_NORMAL_COMPLETION) 1244*497492a7Sjmatthew DPRINTF(("%s: %s uc_idx=%u : %s\n", sc->sc_dev.dv_xname, 1245*497492a7Sjmatthew __func__, c->uc_idx, usbd_errstr(status))); 1246*497492a7Sjmatthew else 1247*497492a7Sjmatthew DPRINTF(("%s: txeof\n", sc->sc_dev.dv_xname)); 1248*497492a7Sjmatthew 1249*497492a7Sjmatthew s = splnet(); 1250*497492a7Sjmatthew 1251*497492a7Sjmatthew c->uc_cnt = 0; 1252*497492a7Sjmatthew c->uc_buflen = 0; 1253*497492a7Sjmatthew 1254*497492a7Sjmatthew SLIST_INSERT_HEAD(&sc->sc_cdata.uaq_tx_free, c, uc_list); 1255*497492a7Sjmatthew 1256*497492a7Sjmatthew if (status != USBD_NORMAL_COMPLETION) { 1257*497492a7Sjmatthew if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { 1258*497492a7Sjmatthew splx(s); 1259*497492a7Sjmatthew return; 1260*497492a7Sjmatthew } 1261*497492a7Sjmatthew 1262*497492a7Sjmatthew ifp->if_oerrors++; 1263*497492a7Sjmatthew printf("%s: usb error on tx: %s\n", sc->sc_dev.dv_xname, 1264*497492a7Sjmatthew usbd_errstr(status)); 1265*497492a7Sjmatthew 1266*497492a7Sjmatthew if (status == USBD_STALLED) 1267*497492a7Sjmatthew usbd_clear_endpoint_stall_async( 1268*497492a7Sjmatthew sc->sc_ep[UAQ_ENDPT_TX]); 1269*497492a7Sjmatthew splx(s); 1270*497492a7Sjmatthew return; 1271*497492a7Sjmatthew } 1272*497492a7Sjmatthew 1273*497492a7Sjmatthew ifp->if_timer = 0; 1274*497492a7Sjmatthew if (ifq_is_oactive(&ifp->if_snd)) 1275*497492a7Sjmatthew ifq_restart(&ifp->if_snd); 1276*497492a7Sjmatthew splx(s); 1277*497492a7Sjmatthew } 1278*497492a7Sjmatthew 1279*497492a7Sjmatthew void 1280*497492a7Sjmatthew uaq_start(struct ifnet *ifp) 1281*497492a7Sjmatthew { 1282*497492a7Sjmatthew struct uaq_softc *sc = ifp->if_softc; 1283*497492a7Sjmatthew struct uaq_cdata *cd = &sc->sc_cdata; 1284*497492a7Sjmatthew struct uaq_chain *c; 1285*497492a7Sjmatthew struct mbuf *m = NULL; 1286*497492a7Sjmatthew int s, mlen; 1287*497492a7Sjmatthew 1288*497492a7Sjmatthew if ((sc->sc_link_speed == 0) || 1289*497492a7Sjmatthew (ifp->if_flags & (IFF_RUNNING|IFF_UP)) != 1290*497492a7Sjmatthew (IFF_RUNNING|IFF_UP)) { 1291*497492a7Sjmatthew return; 1292*497492a7Sjmatthew } 1293*497492a7Sjmatthew 1294*497492a7Sjmatthew s = splnet(); 1295*497492a7Sjmatthew 1296*497492a7Sjmatthew c = SLIST_FIRST(&cd->uaq_tx_free); 1297*497492a7Sjmatthew while (c != NULL) { 1298*497492a7Sjmatthew m = ifq_deq_begin(&ifp->if_snd); 1299*497492a7Sjmatthew if (m == NULL) 1300*497492a7Sjmatthew break; 1301*497492a7Sjmatthew 1302*497492a7Sjmatthew mlen = m->m_pkthdr.len; 1303*497492a7Sjmatthew 1304*497492a7Sjmatthew /* Discard packet larger than buffer. */ 1305*497492a7Sjmatthew if (mlen + sizeof(uint64_t) >= c->uc_bufmax) { 1306*497492a7Sjmatthew ifq_deq_commit(&ifp->if_snd, m); 1307*497492a7Sjmatthew m_freem(m); 1308*497492a7Sjmatthew ifp->if_oerrors++; 1309*497492a7Sjmatthew continue; 1310*497492a7Sjmatthew } 1311*497492a7Sjmatthew 1312*497492a7Sjmatthew /* Append packet to current buffer. */ 1313*497492a7Sjmatthew mlen = uaq_encap_txpkt(sc, m, c->uc_buf + c->uc_buflen, 1314*497492a7Sjmatthew c->uc_bufmax - c->uc_buflen); 1315*497492a7Sjmatthew if (mlen <= 0) { 1316*497492a7Sjmatthew ifq_deq_rollback(&ifp->if_snd, m); 1317*497492a7Sjmatthew break; 1318*497492a7Sjmatthew } 1319*497492a7Sjmatthew 1320*497492a7Sjmatthew ifq_deq_commit(&ifp->if_snd, m); 1321*497492a7Sjmatthew c->uc_cnt += 1; 1322*497492a7Sjmatthew c->uc_buflen += mlen; 1323*497492a7Sjmatthew 1324*497492a7Sjmatthew #if NBPFILTER > 0 1325*497492a7Sjmatthew if (ifp->if_bpf) 1326*497492a7Sjmatthew bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 1327*497492a7Sjmatthew #endif 1328*497492a7Sjmatthew 1329*497492a7Sjmatthew m_freem(m); 1330*497492a7Sjmatthew } 1331*497492a7Sjmatthew 1332*497492a7Sjmatthew if (c != NULL) { 1333*497492a7Sjmatthew /* Send current buffer unless empty */ 1334*497492a7Sjmatthew if (c->uc_buflen > 0 && c->uc_cnt > 0) { 1335*497492a7Sjmatthew SLIST_REMOVE_HEAD(&cd->uaq_tx_free, uc_list); 1336*497492a7Sjmatthew if (uaq_encap_xfer(sc, c)) { 1337*497492a7Sjmatthew SLIST_INSERT_HEAD(&cd->uaq_tx_free, c, 1338*497492a7Sjmatthew uc_list); 1339*497492a7Sjmatthew } 1340*497492a7Sjmatthew c = SLIST_FIRST(&cd->uaq_tx_free); 1341*497492a7Sjmatthew 1342*497492a7Sjmatthew ifp->if_timer = 5; 1343*497492a7Sjmatthew if (c == NULL) 1344*497492a7Sjmatthew ifq_set_oactive(&ifp->if_snd); 1345*497492a7Sjmatthew } 1346*497492a7Sjmatthew } 1347*497492a7Sjmatthew 1348*497492a7Sjmatthew splx(s); 1349*497492a7Sjmatthew } 1350*497492a7Sjmatthew 1351*497492a7Sjmatthew int 1352*497492a7Sjmatthew uaq_encap_txpkt(struct uaq_softc *sc, struct mbuf *m, char *buf, 1353*497492a7Sjmatthew uint32_t maxlen) 1354*497492a7Sjmatthew { 1355*497492a7Sjmatthew uint64_t desc; 1356*497492a7Sjmatthew int padded; 1357*497492a7Sjmatthew 1358*497492a7Sjmatthew desc = m->m_pkthdr.len; 1359*497492a7Sjmatthew padded = roundup(m->m_pkthdr.len, UAQ_TX_BUF_ALIGN); 1360*497492a7Sjmatthew if (((padded + sizeof(desc)) % sc->sc_out_frame_size) == 0) { 1361*497492a7Sjmatthew desc |= UAQ_TX_PKT_DROP_PADD; 1362*497492a7Sjmatthew padded += 8; 1363*497492a7Sjmatthew } 1364*497492a7Sjmatthew 1365*497492a7Sjmatthew if (padded + sizeof(desc) > maxlen) 1366*497492a7Sjmatthew return (-1); 1367*497492a7Sjmatthew 1368*497492a7Sjmatthew #if NVLAN > 0 1369*497492a7Sjmatthew if (m->m_flags & M_VLANTAG) 1370*497492a7Sjmatthew desc |= (((uint64_t)m->m_pkthdr.ether_vtag) << 1371*497492a7Sjmatthew UAQ_TX_PKT_VLAN_SHIFT) | UAQ_TX_PKT_VLAN; 1372*497492a7Sjmatthew #endif 1373*497492a7Sjmatthew 1374*497492a7Sjmatthew htolem64((uint64_t *)buf, desc); 1375*497492a7Sjmatthew m_copydata(m, 0, m->m_pkthdr.len, buf + sizeof(desc)); 1376*497492a7Sjmatthew return (padded + sizeof(desc)); 1377*497492a7Sjmatthew } 1378*497492a7Sjmatthew 1379*497492a7Sjmatthew int 1380*497492a7Sjmatthew uaq_encap_xfer(struct uaq_softc *sc, struct uaq_chain *c) 1381*497492a7Sjmatthew { 1382*497492a7Sjmatthew usbd_status err; 1383*497492a7Sjmatthew 1384*497492a7Sjmatthew usbd_setup_xfer(c->uc_xfer, sc->sc_ep[UAQ_ENDPT_TX], c, c->uc_buf, 1385*497492a7Sjmatthew c->uc_buflen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 10000, 1386*497492a7Sjmatthew uaq_txeof); 1387*497492a7Sjmatthew 1388*497492a7Sjmatthew err = usbd_transfer(c->uc_xfer); 1389*497492a7Sjmatthew if (err != USBD_IN_PROGRESS) { 1390*497492a7Sjmatthew c->uc_cnt = 0; 1391*497492a7Sjmatthew c->uc_buflen = 0; 1392*497492a7Sjmatthew uaq_stop(sc); 1393*497492a7Sjmatthew return (EIO); 1394*497492a7Sjmatthew } 1395*497492a7Sjmatthew 1396*497492a7Sjmatthew return (0); 1397*497492a7Sjmatthew } 1398