Author: avos Date: Sun Dec 11 17:15:25 2016 New Revision: 309852 URL: https://svnweb.freebsd.org/changeset/base/309852
Log: rsu: fix and enable Rx TCP checksum offloading. Tested with Asus USB-N10, STA mode. Modified: head/sys/dev/usb/wlan/if_rsu.c head/sys/dev/usb/wlan/if_rsureg.h Modified: head/sys/dev/usb/wlan/if_rsu.c ============================================================================== --- head/sys/dev/usb/wlan/if_rsu.c Sun Dec 11 13:26:35 2016 (r309851) +++ head/sys/dev/usb/wlan/if_rsu.c Sun Dec 11 17:15:25 2016 (r309852) @@ -255,6 +255,7 @@ static int rsu_tx_start(struct rsu_softc static int rsu_transmit(struct ieee80211com *, struct mbuf *); static void rsu_start(struct rsu_softc *); static void _rsu_start(struct rsu_softc *); +static int rsu_ioctl_net(struct ieee80211com *, u_long, void *); static void rsu_parent(struct ieee80211com *); static void rsu_stop(struct rsu_softc *); static void rsu_ms_delay(struct rsu_softc *, int); @@ -444,6 +445,7 @@ rsu_attach(device_t self) device_set_usb_desc(self); sc->sc_udev = uaa->device; sc->sc_dev = self; + sc->sc_rx_checksum_enable = 1; if (rsu_enable_11n) sc->sc_ht = !! (USB_GET_DRIVER_INFO(uaa) & RSU_HT_SUPPORTED); @@ -590,6 +592,7 @@ rsu_attach(device_t self) ic->ic_vap_delete = rsu_vap_delete; ic->ic_update_promisc = rsu_update_promisc; ic->ic_update_mcast = rsu_update_mcast; + ic->ic_ioctl = rsu_ioctl_net; ic->ic_parent = rsu_parent; ic->ic_transmit = rsu_transmit; ic->ic_send_mgmt = rsu_send_mgmt; @@ -676,8 +679,10 @@ rsu_vap_create(struct ieee80211com *ic, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { + struct rsu_softc *sc = ic->ic_softc; struct rsu_vap *uvp; struct ieee80211vap *vap; + struct ifnet *ifp; if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return (NULL); @@ -692,6 +697,13 @@ rsu_vap_create(struct ieee80211com *ic, return (NULL); } + ifp = vap->iv_ifp; + ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6; + RSU_LOCK(sc); + if (sc->sc_rx_checksum_enable) + ifp->if_capenable |= IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6; + RSU_UNLOCK(sc); + /* override state transition machine */ uvp->newstate = vap->iv_newstate; if (opmode == IEEE80211_M_MONITOR) @@ -2396,9 +2408,37 @@ rsu_rx_frame(struct rsu_softc *sc, struc }; /* Hardware does Rx TCP checksum offload. */ + /* + * This flag can be set for some other + * (e.g., EAPOL) frame types, so don't rely on it. + */ if (rxdw3 & R92S_RXDW3_TCPCHKVALID) { - if (__predict_true(rxdw3 & R92S_RXDW3_TCPCHKRPT)) + RSU_DPRINTF(sc, RSU_DEBUG_RX, + "%s: TCP/IP checksums: %schecked / %schecked\n", + __func__, + (rxdw3 & R92S_RXDW3_TCPCHKRPT) ? "" : "not ", + (rxdw3 & R92S_RXDW3_IPCHKRPT) ? "" : "not "); + + /* + * 'IP header checksum valid' bit will not be set if + * the frame was not checked / has incorrect checksum / + * does not have checksum (IPv6). + * + * NB: if DF bit is not set then frame will not be checked. + */ + if (rxdw3 & R92S_RXDW3_IPCHKRPT) { + m->m_pkthdr.csum_flags = CSUM_IP_CHECKED; + m->m_pkthdr.csum_flags |= CSUM_IP_VALID; + } + + /* + * This is independent of the above check. + */ + if (rxdw3 & R92S_RXDW3_TCPCHKRPT) { m->m_pkthdr.csum_flags |= CSUM_DATA_VALID; + m->m_pkthdr.csum_flags |= CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } } /* Drop descriptor. */ @@ -2915,6 +2955,59 @@ rsu_start(struct rsu_softc *sc) taskqueue_enqueue(taskqueue_thread, &sc->tx_task); } +static int +rsu_ioctl_net(struct ieee80211com *ic, u_long cmd, void *data) +{ + struct rsu_softc *sc = ic->ic_softc; + struct ifreq *ifr = (struct ifreq *)data; + int error; + + error = 0; + switch (cmd) { + case SIOCSIFCAP: + { + struct ieee80211vap *vap; + int rxmask; + + rxmask = ifr->ifr_reqcap & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6); + + RSU_LOCK(sc); + /* Both RXCSUM bits must be set (or unset). */ + if (sc->sc_rx_checksum_enable && + rxmask != (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) { + rxmask = 0; + sc->sc_rx_checksum_enable = 0; + rsu_rxfilter_set(sc, R92S_RCR_TCP_OFFLD_EN, 0); + } else if (!sc->sc_rx_checksum_enable && rxmask != 0) { + rxmask = IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6; + sc->sc_rx_checksum_enable = 1; + rsu_rxfilter_set(sc, 0, R92S_RCR_TCP_OFFLD_EN); + } else { + /* Nothing to do. */ + RSU_UNLOCK(sc); + break; + } + RSU_UNLOCK(sc); + + IEEE80211_LOCK(ic); /* XXX */ + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + struct ifnet *ifp = vap->iv_ifp; + + ifp->if_capenable &= + ~(IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6); + ifp->if_capenable |= rxmask; + } + IEEE80211_UNLOCK(ic); + break; + } + default: + error = ENOTTY; /* for net80211 */ + break; + } + + return (error); +} + static void rsu_parent(struct ieee80211com *ic) { @@ -3434,6 +3527,8 @@ rsu_rxfilter_init(struct rsu_softc *sc) reg = rsu_read_4(sc, R92S_RCR); reg &= ~R92S_RCR_AICV; reg |= R92S_RCR_APP_PHYSTS; + if (sc->sc_rx_checksum_enable) + reg |= R92S_RCR_TCP_OFFLD_EN; rsu_write_4(sc, R92S_RCR, reg); /* Update dynamic Rx filter parts. */ @@ -3512,10 +3607,6 @@ rsu_init(struct rsu_softc *sc) if (error != 0) goto fail; - /* Enable Rx TCP checksum offload. */ - rsu_write_4(sc, R92S_RCR, - rsu_read_4(sc, R92S_RCR) | 0x04000000); - rsu_write_4(sc, R92S_CR, rsu_read_4(sc, R92S_CR) & ~0xff000000); Modified: head/sys/dev/usb/wlan/if_rsureg.h ============================================================================== --- head/sys/dev/usb/wlan/if_rsureg.h Sun Dec 11 13:26:35 2016 (r309851) +++ head/sys/dev/usb/wlan/if_rsureg.h Sun Dec 11 17:15:25 2016 (r309852) @@ -164,6 +164,7 @@ #define R92S_RCR_APWRMGT 0x00400000 #define R92S_RCR_CBSSID 0x00800000 #define R92S_RCR_APP_PHYSTS 0x02000000 +#define R92S_RCR_TCP_OFFLD_EN 0x04000000 #define R92S_RCR_ENMBID 0x08000000 /* Bits for R92S_RXFLTMAP*. */ @@ -853,6 +854,7 @@ struct rsu_softc { u_int sc_running:1, sc_vap_is_running:1, + sc_rx_checksum_enable:1, sc_calibrating:1, sc_active_scan:1, sc_extra_scan:1; _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"