Index: head/sys/dev/rtwn/if_rtwn_rx.c =================================================================== --- head/sys/dev/rtwn/if_rtwn_rx.c (revision 320724) +++ head/sys/dev/rtwn/if_rtwn_rx.c (revision 320725) @@ -1,517 +1,517 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include void rtwn_get_rates(struct rtwn_softc *sc, const struct ieee80211_rateset *rs, const struct ieee80211_htrateset *rs_ht, uint32_t *rates_p, int *maxrate_p, int basic_rates) { uint32_t rates; uint8_t ridx; int i, maxrate; /* Get rates mask. */ rates = 0; maxrate = 0; /* This is for 11bg */ for (i = 0; i < rs->rs_nrates; i++) { /* Convert 802.11 rate to HW rate index. */ ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i])); if (ridx == RTWN_RIDX_UNKNOWN) /* Unknown rate, skip. */ continue; if (((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0) || !basic_rates) { rates |= 1 << ridx; if (ridx > maxrate) maxrate = ridx; } } /* If we're doing 11n, enable 11n rates */ if (rs_ht != NULL && !basic_rates) { for (i = 0; i < rs_ht->rs_nrates; i++) { if ((rs_ht->rs_rates[i] & 0x7f) > 0xf) continue; /* 11n rates start at index 12 */ ridx = RTWN_RIDX_MCS((rs_ht->rs_rates[i]) & 0xf); rates |= (1 << ridx); /* Guard against the rate table being oddly ordered */ if (ridx > maxrate) maxrate = ridx; } } RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X, maxrate %d\n", __func__, rates, maxrate); if (rates_p != NULL) *rates_p = rates; if (maxrate_p != NULL) *maxrate_p = maxrate; } void rtwn_set_basicrates(struct rtwn_softc *sc, uint32_t rates) { RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X\n", __func__, rates); rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RATE_BITMAP_M, rates); } static void rtwn_update_avgrssi(struct rtwn_softc *sc, struct rtwn_node *un, int8_t rssi, int is_cck) { int pwdb; /* Convert antenna signal to percentage. */ if (rssi <= -100 || rssi >= 20) pwdb = 0; else if (rssi >= 0) pwdb = 100; else pwdb = 100 + rssi; if (is_cck) { /* CCK gain is smaller than OFDM/MCS gain. */ pwdb += 6; if (pwdb > 100) pwdb = 100; if (pwdb <= 14) pwdb -= 4; else if (pwdb <= 26) pwdb -= 8; else if (pwdb <= 34) pwdb -= 6; else if (pwdb <= 42) pwdb -= 2; } if (un->avg_pwdb == -1) /* Init. */ un->avg_pwdb = pwdb; else if (un->avg_pwdb < pwdb) un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20) + 1; else un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20); RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "MACID %d, PWDB %d, EMA %d\n", un->id, pwdb, un->avg_pwdb); } static int8_t rtwn_get_rssi(struct rtwn_softc *sc, void *physt, int is_cck) { int8_t rssi; if (is_cck) rssi = rtwn_get_rssi_cck(sc, physt); else /* OFDM/HT. */ rssi = rtwn_get_rssi_ofdm(sc, physt); return (rssi); } static uint32_t rtwn_get_tsf_low(struct rtwn_softc *sc, int id) { return (rtwn_read_4(sc, R92C_TSFTR(id))); } static uint32_t rtwn_get_tsf_high(struct rtwn_softc *sc, int id) { return (rtwn_read_4(sc, R92C_TSFTR(id) + 4)); } static void rtwn_get_tsf(struct rtwn_softc *sc, uint64_t *buf, int id) { /* NB: we cannot read it at once. */ *buf = rtwn_get_tsf_high(sc, id); *buf <<= 32; *buf += rtwn_get_tsf_low(sc, id); } static uint64_t -rtwn_extend_rx_tsf(struct rtwn_softc *sc, const struct r92c_rx_stat *stat) +rtwn_extend_rx_tsf(struct rtwn_softc *sc, + const struct rtwn_rx_stat_common *stat) { uint64_t tsft; uint32_t rxdw3, tsfl, tsfl_curr; int id; rxdw3 = le32toh(stat->rxdw3); tsfl = le32toh(stat->tsf_low); - id = MS(rxdw3, R92C_RXDW3_BSSID_FIT); + id = MS(rxdw3, RTWN_RXDW3_BSSID01_FIT); switch (id) { case 1: case 2: id >>= 1; tsfl_curr = rtwn_get_tsf_low(sc, id); break; default: { uint32_t tsfl0, tsfl1; tsfl0 = rtwn_get_tsf_low(sc, 0); tsfl1 = rtwn_get_tsf_low(sc, 1); if (abs(tsfl0 - tsfl) < abs(tsfl1 - tsfl)) { id = 0; tsfl_curr = tsfl0; } else { id = 1; tsfl_curr = tsfl1; } break; } } tsft = rtwn_get_tsf_high(sc, id); if (tsfl > tsfl_curr && tsfl > 0xffff0000) tsft--; tsft <<= 32; tsft += tsfl; return (tsft); } struct ieee80211_node * rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni; struct ieee80211_frame_min *wh; struct ieee80211_rx_stats rxs; struct rtwn_node *un; - struct r92c_rx_stat *stat; + struct rtwn_rx_stat_common *stat; void *physt; uint32_t rxdw0; int8_t rssi; int cipher, infosz, is_cck, pktlen, shift; stat = desc; rxdw0 = le32toh(stat->rxdw0); - cipher = MS(rxdw0, R92C_RXDW0_CIPHER); - infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; - pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); - shift = MS(rxdw0, R92C_RXDW0_SHIFT); + cipher = MS(rxdw0, RTWN_RXDW0_CIPHER); + infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8; + pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN); + shift = MS(rxdw0, RTWN_RXDW0_SHIFT); wh = (struct ieee80211_frame_min *)(mtodo(m, shift + infosz)); if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && cipher != R92C_CAM_ALGO_NONE) m->m_flags |= M_WEP; if (pktlen >= sizeof(*wh)) { ni = ieee80211_find_rxnode(ic, wh); if (ni != NULL && (ni->ni_flags & IEEE80211_NODE_HT)) m->m_flags |= M_AMPDU; } else ni = NULL; un = RTWN_NODE(ni); - if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) + if (infosz != 0 && (rxdw0 & RTWN_RXDW0_PHYST)) physt = (void *)mtodo(m, shift); else physt = (un != NULL) ? &un->last_physt : &sc->last_physt; bzero(&rxs, sizeof(rxs)); rtwn_get_rx_stats(sc, &rxs, desc, physt); if (rxs.c_pktflags & IEEE80211_RX_F_AMPDU) { /* Next MPDU will come without PHY info. */ memcpy(&sc->last_physt, physt, sizeof(sc->last_physt)); if (un != NULL) memcpy(&un->last_physt, physt, sizeof(sc->last_physt)); } /* Add some common bits. */ /* NB: should not happen. */ - if (rxdw0 & R92C_RXDW0_CRCERR) + if (rxdw0 & RTWN_RXDW0_CRCERR) rxs.c_pktflags |= IEEE80211_RX_F_FAIL_FCSCRC; rxs.r_flags |= IEEE80211_R_TSF_START; /* XXX undocumented */ rxs.r_flags |= IEEE80211_R_TSF64; rxs.c_rx_tsf = rtwn_extend_rx_tsf(sc, stat); /* Get RSSI from PHY status descriptor. */ is_cck = (rxs.c_pktflags & IEEE80211_RX_F_CCK) != 0; rssi = rtwn_get_rssi(sc, physt, is_cck); /* XXX TODO: we really need a rate-to-string method */ RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, rate %d\n", __func__, rssi, rxs.c_rate); - if (un != NULL && infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { + if (un != NULL && infosz != 0 && (rxdw0 & RTWN_RXDW0_PHYST)) { /* Update our average RSSI. */ rtwn_update_avgrssi(sc, un, rssi, is_cck); } rxs.r_flags |= IEEE80211_R_NF | IEEE80211_R_RSSI; rxs.c_nf = RTWN_NOISE_FLOOR; rxs.c_rssi = rssi - rxs.c_nf; (void) ieee80211_add_rx_params(m, &rxs); if (ieee80211_radiotap_active(ic)) { struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap; tap->wr_flags = rtwn_rx_radiotap_flags(sc, desc); tap->wr_tsft = htole64(rxs.c_rx_tsf); tap->wr_rate = rxs.c_rate; tap->wr_dbm_antsignal = rssi; tap->wr_dbm_antnoise = rxs.c_nf; } /* Drop PHY descriptor. */ m_adj(m, infosz + shift); return (ni); } void rtwn_adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf) { struct ieee80211vap *vap = ni->ni_vap; struct rtwn_softc *sc = vap->iv_ic->ic_softc; struct rtwn_vap *uvp = RTWN_VAP(vap); uint64_t ni_tstamp, curr_tstamp; uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf); if (vap->iv_state == IEEE80211_S_RUN && (subtype == IEEE80211_FC0_SUBTYPE_BEACON || subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) { ni_tstamp = le64toh(ni->ni_tstamp.tsf); RTWN_LOCK(sc); rtwn_get_tsf(sc, &curr_tstamp, uvp->id); RTWN_UNLOCK(sc); if (ni_tstamp >= curr_tstamp) (void) ieee80211_ibss_merge(ni); } } static uint8_t rtwn_get_multi_pos(const uint8_t maddr[]) { uint64_t mask = 0x00004d101df481b4; uint8_t pos = 0x27; /* initial value */ int i, j; for (i = 0; i < IEEE80211_ADDR_LEN; i++) for (j = (i == 0) ? 1 : 0; j < 8; j++) if ((maddr[i] >> j) & 1) pos ^= (mask >> (i * 8 + j - 1)); pos &= 0x3f; return (pos); } void rtwn_set_multi(struct rtwn_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; uint32_t mfilt[2]; RTWN_ASSERT_LOCKED(sc); /* general structure was copied from ath(4). */ if (ic->ic_allmulti == 0) { struct ieee80211vap *vap; struct ifnet *ifp; struct ifmultiaddr *ifma; /* * Merge multicast addresses to form the hardware filter. */ mfilt[0] = mfilt[1] = 0; TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { ifp = vap->iv_ifp; if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { caddr_t dl; uint8_t pos; dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); pos = rtwn_get_multi_pos(dl); mfilt[pos / 32] |= (1 << (pos % 32)); } if_maddr_runlock(ifp); } } else mfilt[0] = mfilt[1] = ~0; rtwn_write_4(sc, R92C_MAR + 0, mfilt[0]); rtwn_write_4(sc, R92C_MAR + 4, mfilt[1]); RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n", __func__, mfilt[0], mfilt[1]); } static void rtwn_rxfilter_update_mgt(struct rtwn_softc *sc) { uint16_t filter; filter = 0x7f7f; if (sc->bcn_vaps == 0) { /* STA and/or MONITOR mode vaps */ filter &= ~( R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) | R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) | R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ)); } if (sc->ap_vaps == sc->nvaps - sc->mon_vaps) { /* AP vaps only */ filter &= ~( R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) | R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP)); } rtwn_write_2(sc, R92C_RXFLTMAP0, filter); } void rtwn_rxfilter_update(struct rtwn_softc *sc) { RTWN_ASSERT_LOCKED(sc); /* Filter for management frames. */ rtwn_rxfilter_update_mgt(sc); /* Update Rx filter. */ rtwn_set_promisc(sc); } void rtwn_rxfilter_init(struct rtwn_softc *sc) { RTWN_ASSERT_LOCKED(sc); /* Setup multicast filter. */ rtwn_set_multi(sc); /* Reject all control frames. */ rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000); /* Reject all data frames. */ rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000); /* Append generic Rx filter bits. */ sc->rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM | R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS | R92C_RCR_APP_ICV | R92C_RCR_APP_MIC; /* Update dynamic Rx filter parts. */ rtwn_rxfilter_update(sc); } void rtwn_rxfilter_set(struct rtwn_softc *sc) { if (!(sc->sc_flags & RTWN_RCR_LOCKED)) rtwn_write_4(sc, R92C_RCR, sc->rcr); } void rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable) { if (enable) sc->rcr &= ~R92C_RCR_CBSSID_BCN; else sc->rcr |= R92C_RCR_CBSSID_BCN; rtwn_rxfilter_set(sc); } void rtwn_set_promisc(struct rtwn_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; uint32_t mask_all, mask_min; RTWN_ASSERT_LOCKED(sc); mask_all = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP; mask_min = R92C_RCR_APM; if (sc->bcn_vaps == 0) mask_min |= R92C_RCR_CBSSID_BCN; if (sc->ap_vaps == 0) mask_min |= R92C_RCR_CBSSID_DATA; if (ic->ic_promisc == 0 && sc->mon_vaps == 0) { if (sc->bcn_vaps != 0) mask_all |= R92C_RCR_CBSSID_BCN; if (sc->ap_vaps != 0) /* for Null data frames */ mask_all |= R92C_RCR_CBSSID_DATA; sc->rcr &= ~mask_all; sc->rcr |= mask_min; } else { sc->rcr &= ~mask_min; sc->rcr |= mask_all; } rtwn_rxfilter_set(sc); } Index: head/sys/dev/rtwn/if_rtwnreg.h =================================================================== --- head/sys/dev/rtwn/if_rtwnreg.h (revision 320724) +++ head/sys/dev/rtwn/if_rtwnreg.h (revision 320725) @@ -1,118 +1,167 @@ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ * $FreeBSD$ */ #define R92C_MIN_TX_PWR 0x00 #define R92C_MAX_TX_PWR 0x3f #define R92C_H2C_NBOX 4 /* Common part of Tx descriptor (named only!). */ struct rtwn_tx_desc_common { uint16_t pktlen; uint8_t offset; uint8_t flags0; #define RTWN_FLAGS0_OWN 0x80 uint32_t txdw1; /* NB: qsel is shared too; however, it looks better at the lower level */ #define RTWN_TXDW1_CIPHER_M 0x00c00000 #define RTWN_TXDW1_CIPHER_S 22 #define RTWN_TXDW1_CIPHER_NONE 0 #define RTWN_TXDW1_CIPHER_RC4 1 #define RTWN_TXDW1_CIPHER_SM4 2 #define RTWN_TXDW1_CIPHER_AES 3 uint32_t reserved[5]; union txdw7_shared { uint16_t usb_checksum; uint16_t pci_txbufsize; } txdw7; } __packed __attribute__((aligned(4))); +/* Common part of Rx descriptor. */ +struct rtwn_rx_stat_common { + uint32_t rxdw0; +#define RTWN_RXDW0_PKTLEN_M 0x00003fff +#define RTWN_RXDW0_PKTLEN_S 0 +#define RTWN_RXDW0_CRCERR 0x00004000 +#define RTWN_RXDW0_ICVERR 0x00008000 +#define RTWN_RXDW0_INFOSZ_M 0x000f0000 +#define RTWN_RXDW0_INFOSZ_S 16 +#define RTWN_RXDW0_CIPHER_M 0x00700000 +#define RTWN_RXDW0_CIPHER_S 20 +#define RTWN_RXDW0_QOS 0x00800000 +#define RTWN_RXDW0_SHIFT_M 0x03000000 +#define RTWN_RXDW0_SHIFT_S 24 +#define RTWN_RXDW0_PHYST 0x04000000 +#define RTWN_RXDW0_SWDEC 0x08000000 +#define RTWN_RXDW0_LS 0x10000000 +#define RTWN_RXDW0_FS 0x20000000 +#define RTWN_RXDW0_EOR 0x40000000 +#define RTWN_RXDW0_OWN 0x80000000 + + uint32_t rxdw1; +#define RTWN_RXDW1_AMSDU 0x00002000 +#define RTWN_RXDW1_MC 0x40000000 +#define RTWN_RXDW1_BC 0x80000000 + + uint32_t rxdw2; + uint32_t rxdw3; +#define RTWN_RXDW3_HTC 0x00000400 +#define RTWN_RXDW3_BSSID01_FIT_M 0x00003000 +#define RTWN_RXDW3_BSSID01_FIT_S 12 + + uint32_t rxdw4; + uint32_t tsf_low; +} __packed __attribute__((aligned(4))); + +/* Rx descriptor for PCIe devices. */ +struct rtwn_rx_stat_pci { + uint32_t rxdw0; + uint32_t rxdw1; + uint32_t rxdw2; + uint32_t rxdw3; + uint32_t rxdw4; + uint32_t tsf_low; + + uint32_t rxbufaddr; + uint32_t rxbufaddr64; +} __packed __attribute__((aligned(4))); + /* * Macros to access subfields in registers. */ /* Mask and Shift (getter). */ #define MS(val, field) \ (((val) & field##_M) >> field##_S) /* Shift and Mask (setter). */ #define SM(field, val) \ (((val) << field##_S) & field##_M) /* Rewrite. */ #define RW(var, field, val) \ (((var) & ~field##_M) | SM(field, val)) #define RTWN_MAX_CONDITIONS 3 /* * Structure for MAC initialization values. */ struct rtwn_mac_prog { uint16_t reg; uint8_t val; }; /* * Structure for baseband initialization values. */ struct rtwn_bb_prog { int count; const uint16_t *reg; const uint32_t *val; const uint8_t cond[RTWN_MAX_CONDITIONS]; const struct rtwn_bb_prog *next; }; struct rtwn_agc_prog { int count; const uint32_t *val; const uint8_t cond[RTWN_MAX_CONDITIONS]; const struct rtwn_agc_prog *next; }; /* * Structure for RF initialization values. */ struct rtwn_rf_prog { int count; const uint8_t *reg; const uint32_t *val; const uint8_t cond[RTWN_MAX_CONDITIONS]; const struct rtwn_rf_prog *next; }; /* XXX move to net80211. */ static __inline int rtwn_chan2centieee(const struct ieee80211_channel *c) { int chan; chan = c->ic_ieee; if (c->ic_extieee != 0) chan = (chan + c->ic_extieee) / 2; return (chan); } Index: head/sys/dev/rtwn/pci/rtwn_pci_attach.c =================================================================== --- head/sys/dev/rtwn/pci/rtwn_pci_attach.c (revision 320724) +++ head/sys/dev/rtwn/pci/rtwn_pci_attach.c (revision 320725) @@ -1,794 +1,793 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include static device_probe_t rtwn_pci_probe; static device_attach_t rtwn_pci_attach; static device_detach_t rtwn_pci_detach; static device_shutdown_t rtwn_pci_shutdown; static device_suspend_t rtwn_pci_suspend; static device_resume_t rtwn_pci_resume; static int rtwn_pci_alloc_rx_list(struct rtwn_softc *); static void rtwn_pci_reset_rx_list(struct rtwn_softc *); static void rtwn_pci_free_rx_list(struct rtwn_softc *); static int rtwn_pci_alloc_tx_list(struct rtwn_softc *, int); static void rtwn_pci_reset_tx_ring_stopped(struct rtwn_softc *, int); static void rtwn_pci_reset_beacon_ring(struct rtwn_softc *, int); static void rtwn_pci_reset_tx_list(struct rtwn_softc *, struct ieee80211vap *, int); static void rtwn_pci_free_tx_list(struct rtwn_softc *, int); static void rtwn_pci_reset_lists(struct rtwn_softc *, struct ieee80211vap *); static int rtwn_pci_fw_write_block(struct rtwn_softc *, const uint8_t *, uint16_t, int); static uint16_t rtwn_pci_get_qmap(struct rtwn_softc *); static void rtwn_pci_set_desc_addr(struct rtwn_softc *); static void rtwn_pci_beacon_update_begin(struct rtwn_softc *, struct ieee80211vap *); static void rtwn_pci_beacon_update_end(struct rtwn_softc *, struct ieee80211vap *); static void rtwn_pci_attach_methods(struct rtwn_softc *); static const struct rtwn_pci_ident * rtwn_pci_probe_sub(device_t dev) { const struct rtwn_pci_ident *ident; int vendor_id, device_id; vendor_id = pci_get_vendor(dev); device_id = pci_get_device(dev); for (ident = rtwn_pci_ident_table; ident->name != NULL; ident++) if (vendor_id == ident->vendor && device_id == ident->device) return (ident); return (NULL); } static int rtwn_pci_probe(device_t dev) { const struct rtwn_pci_ident *ident; ident = rtwn_pci_probe_sub(dev); if (ident != NULL) { device_set_desc(dev, ident->name); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int rtwn_pci_alloc_rx_list(struct rtwn_softc *sc) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); struct rtwn_rx_ring *rx_ring = &pc->rx_ring; struct rtwn_rx_data *rx_data; bus_size_t size; int i, error; /* Allocate Rx descriptors. */ - size = sizeof(struct r92ce_rx_stat) * RTWN_PCI_RX_LIST_COUNT; + size = sizeof(struct rtwn_rx_stat_pci) * RTWN_PCI_RX_LIST_COUNT; error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, 0, NULL, NULL, &rx_ring->desc_dmat); if (error != 0) { device_printf(sc->sc_dev, "could not create rx desc DMA tag\n"); goto fail; } error = bus_dmamem_alloc(rx_ring->desc_dmat, (void **)&rx_ring->desc, BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, &rx_ring->desc_map); if (error != 0) { device_printf(sc->sc_dev, "could not allocate rx desc\n"); goto fail; } error = bus_dmamap_load(rx_ring->desc_dmat, rx_ring->desc_map, rx_ring->desc, size, rtwn_pci_dma_map_addr, &rx_ring->paddr, 0); if (error != 0) { device_printf(sc->sc_dev, "could not load rx desc DMA map\n"); goto fail; } bus_dmamap_sync(rx_ring->desc_dmat, rx_ring->desc_map, BUS_DMASYNC_PREWRITE); /* Create RX buffer DMA tag. */ error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MJUMPAGESIZE, 1, MJUMPAGESIZE, 0, NULL, NULL, &rx_ring->data_dmat); if (error != 0) { device_printf(sc->sc_dev, "could not create rx buf DMA tag\n"); goto fail; } /* Allocate Rx buffers. */ for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) { rx_data = &rx_ring->rx_data[i]; error = bus_dmamap_create(rx_ring->data_dmat, 0, &rx_data->map); if (error != 0) { device_printf(sc->sc_dev, "could not create rx buf DMA map\n"); goto fail; } rx_data->m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); if (rx_data->m == NULL) { device_printf(sc->sc_dev, "could not allocate rx mbuf\n"); error = ENOMEM; goto fail; } error = bus_dmamap_load(rx_ring->data_dmat, rx_data->map, mtod(rx_data->m, void *), MJUMPAGESIZE, rtwn_pci_dma_map_addr, &rx_data->paddr, BUS_DMA_NOWAIT); if (error != 0) { device_printf(sc->sc_dev, "could not load rx buf DMA map"); goto fail; } rtwn_pci_setup_rx_desc(pc, &rx_ring->desc[i], rx_data->paddr, MJUMPAGESIZE, i); } rx_ring->cur = 0; return (0); fail: rtwn_pci_free_rx_list(sc); return (error); } static void rtwn_pci_reset_rx_list(struct rtwn_softc *sc) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); struct rtwn_rx_ring *rx_ring = &pc->rx_ring; struct rtwn_rx_data *rx_data; int i; for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) { rx_data = &rx_ring->rx_data[i]; rtwn_pci_setup_rx_desc(pc, &rx_ring->desc[i], rx_data->paddr, MJUMPAGESIZE, i); } rx_ring->cur = 0; } static void rtwn_pci_free_rx_list(struct rtwn_softc *sc) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); struct rtwn_rx_ring *rx_ring = &pc->rx_ring; struct rtwn_rx_data *rx_data; int i; if (rx_ring->desc_dmat != NULL) { if (rx_ring->desc != NULL) { bus_dmamap_sync(rx_ring->desc_dmat, rx_ring->desc_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(rx_ring->desc_dmat, rx_ring->desc_map); bus_dmamem_free(rx_ring->desc_dmat, rx_ring->desc, rx_ring->desc_map); rx_ring->desc = NULL; } bus_dma_tag_destroy(rx_ring->desc_dmat); rx_ring->desc_dmat = NULL; } for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) { rx_data = &rx_ring->rx_data[i]; if (rx_data->m != NULL) { bus_dmamap_sync(rx_ring->data_dmat, rx_data->map, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(rx_ring->data_dmat, rx_data->map); m_freem(rx_data->m); rx_data->m = NULL; } bus_dmamap_destroy(rx_ring->data_dmat, rx_data->map); rx_data->map = NULL; } if (rx_ring->data_dmat != NULL) { bus_dma_tag_destroy(rx_ring->data_dmat); rx_ring->data_dmat = NULL; } } static int rtwn_pci_alloc_tx_list(struct rtwn_softc *sc, int qid) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); struct rtwn_tx_ring *tx_ring = &pc->tx_ring[qid]; bus_size_t size; int i, error; size = sc->txdesc_len * RTWN_PCI_TX_LIST_COUNT; error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, 0, NULL, NULL, &tx_ring->desc_dmat); if (error != 0) { device_printf(sc->sc_dev, "could not create tx ring DMA tag\n"); goto fail; } error = bus_dmamem_alloc(tx_ring->desc_dmat, &tx_ring->desc, BUS_DMA_NOWAIT | BUS_DMA_ZERO, &tx_ring->desc_map); if (error != 0) { device_printf(sc->sc_dev, "can't map tx ring DMA memory\n"); goto fail; } error = bus_dmamap_load(tx_ring->desc_dmat, tx_ring->desc_map, tx_ring->desc, size, rtwn_pci_dma_map_addr, &tx_ring->paddr, BUS_DMA_NOWAIT); if (error != 0) { device_printf(sc->sc_dev, "could not load desc DMA map\n"); goto fail; } bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, BUS_DMASYNC_PREWRITE); error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MJUMPAGESIZE, 1, MJUMPAGESIZE, 0, NULL, NULL, &tx_ring->data_dmat); if (error != 0) { device_printf(sc->sc_dev, "could not create tx buf DMA tag\n"); goto fail; } for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { struct rtwn_tx_data *tx_data = &tx_ring->tx_data[i]; void *tx_desc = (uint8_t *)tx_ring->desc + sc->txdesc_len * i; uint32_t next_desc_addr = tx_ring->paddr + sc->txdesc_len * ((i + 1) % RTWN_PCI_TX_LIST_COUNT); rtwn_pci_setup_tx_desc(pc, tx_desc, next_desc_addr); error = bus_dmamap_create(tx_ring->data_dmat, 0, &tx_data->map); if (error != 0) { device_printf(sc->sc_dev, "could not create tx buf DMA map\n"); return (error); } tx_data->m = NULL; tx_data->ni = NULL; } return (0); fail: rtwn_pci_free_tx_list(sc, qid); return (error); } static void rtwn_pci_reset_tx_ring_stopped(struct rtwn_softc *sc, int qid) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); struct rtwn_tx_ring *ring = &pc->tx_ring[qid]; int i; for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { struct rtwn_tx_data *data = &ring->tx_data[i]; void *desc = (uint8_t *)ring->desc + sc->txdesc_len * i; rtwn_pci_copy_tx_desc(pc, desc, NULL); if (data->m != NULL) { bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); data->m = NULL; } if (data->ni != NULL) { ieee80211_free_node(data->ni); data->ni = NULL; } } bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTWRITE); sc->qfullmsk &= ~(1 << qid); ring->queued = 0; ring->last = ring->cur = 0; } /* * Clear entry 0 (or 1) in the beacon queue (other are not used). */ static void rtwn_pci_reset_beacon_ring(struct rtwn_softc *sc, int id) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); struct rtwn_tx_ring *ring = &pc->tx_ring[RTWN_PCI_BEACON_QUEUE]; struct rtwn_tx_data *data = &ring->tx_data[id]; struct rtwn_tx_desc_common *txd = (struct rtwn_tx_desc_common *) ((uint8_t *)ring->desc + id * sc->txdesc_len); bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD); if (txd->flags0 & RTWN_FLAGS0_OWN) { /* Clear OWN bit. */ txd->flags0 &= ~RTWN_FLAGS0_OWN; bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); /* Unload mbuf. */ bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); } } /* * Drop stale entries from Tx ring before the vap will be deleted. * In case if vap is NULL just free everything and reset cur / last pointers. */ static void rtwn_pci_reset_tx_list(struct rtwn_softc *sc, struct ieee80211vap *vap, int qid) { int i; if (vap == NULL) { if (qid != RTWN_PCI_BEACON_QUEUE) { /* * Device was stopped; just clear all entries. */ rtwn_pci_reset_tx_ring_stopped(sc, qid); } else { for (i = 0; i < RTWN_PORT_COUNT; i++) rtwn_pci_reset_beacon_ring(sc, i); } } else if (qid == RTWN_PCI_BEACON_QUEUE && (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS)) { struct rtwn_vap *uvp = RTWN_VAP(vap); rtwn_pci_reset_beacon_ring(sc, uvp->id); } else { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); struct rtwn_tx_ring *ring = &pc->tx_ring[qid]; for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { struct rtwn_tx_data *data = &ring->tx_data[i]; if (data->ni != NULL && data->ni->ni_vap == vap) { /* * NB: if some vap is still running * rtwn_pci_tx_done() will free the mbuf; * otherwise, rtwn_stop() will reset all rings * after device shutdown. */ ieee80211_free_node(data->ni); data->ni = NULL; } } } } static void rtwn_pci_free_tx_list(struct rtwn_softc *sc, int qid) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); struct rtwn_tx_ring *tx_ring = &pc->tx_ring[qid]; struct rtwn_tx_data *tx_data; int i; if (tx_ring->desc_dmat != NULL) { if (tx_ring->desc != NULL) { bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(tx_ring->desc_dmat, tx_ring->desc_map); bus_dmamem_free(tx_ring->desc_dmat, tx_ring->desc, tx_ring->desc_map); } bus_dma_tag_destroy(tx_ring->desc_dmat); } for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { tx_data = &tx_ring->tx_data[i]; if (tx_data->m != NULL) { bus_dmamap_sync(tx_ring->data_dmat, tx_data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(tx_ring->data_dmat, tx_data->map); m_freem(tx_data->m); tx_data->m = NULL; } } if (tx_ring->data_dmat != NULL) { bus_dma_tag_destroy(tx_ring->data_dmat); tx_ring->data_dmat = NULL; } sc->qfullmsk &= ~(1 << qid); tx_ring->queued = 0; tx_ring->last = tx_ring->cur = 0; } static void rtwn_pci_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap) { int i; for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) rtwn_pci_reset_tx_list(sc, vap, i); if (vap == NULL) { sc->qfullmsk = 0; rtwn_pci_reset_rx_list(sc); } } static int rtwn_pci_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf, uint16_t reg, int mlen) { int i; for (i = 0; i < mlen; i++) rtwn_pci_write_1(sc, reg++, buf[i]); /* NB: cannot fail */ return (0); } static uint16_t rtwn_pci_get_qmap(struct rtwn_softc *sc) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); KASSERT(pc->pc_qmap != 0, ("%s: qmap is not set!\n", __func__)); return (pc->pc_qmap); } static void rtwn_pci_set_desc_addr(struct rtwn_softc *sc) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, "%s: addresses:\n" "bk: %08jX, be: %08jX, vi: %08jX, vo: %08jX\n" "bcn: %08jX, mgt: %08jX, high: %08jX, rx: %08jX\n", __func__, (uintmax_t)pc->tx_ring[RTWN_PCI_BK_QUEUE].paddr, (uintmax_t)pc->tx_ring[RTWN_PCI_BE_QUEUE].paddr, (uintmax_t)pc->tx_ring[RTWN_PCI_VI_QUEUE].paddr, (uintmax_t)pc->tx_ring[RTWN_PCI_VO_QUEUE].paddr, (uintmax_t)pc->tx_ring[RTWN_PCI_BEACON_QUEUE].paddr, (uintmax_t)pc->tx_ring[RTWN_PCI_MGNT_QUEUE].paddr, (uintmax_t)pc->tx_ring[RTWN_PCI_HIGH_QUEUE].paddr, (uintmax_t)pc->rx_ring.paddr); /* Set Tx Configuration Register. */ rtwn_pci_write_4(sc, R92C_TCR, pc->tcr); /* Configure Tx DMA. */ rtwn_pci_write_4(sc, R92C_BKQ_DESA, pc->tx_ring[RTWN_PCI_BK_QUEUE].paddr); rtwn_pci_write_4(sc, R92C_BEQ_DESA, pc->tx_ring[RTWN_PCI_BE_QUEUE].paddr); rtwn_pci_write_4(sc, R92C_VIQ_DESA, pc->tx_ring[RTWN_PCI_VI_QUEUE].paddr); rtwn_pci_write_4(sc, R92C_VOQ_DESA, pc->tx_ring[RTWN_PCI_VO_QUEUE].paddr); rtwn_pci_write_4(sc, R92C_BCNQ_DESA, pc->tx_ring[RTWN_PCI_BEACON_QUEUE].paddr); rtwn_pci_write_4(sc, R92C_MGQ_DESA, pc->tx_ring[RTWN_PCI_MGNT_QUEUE].paddr); rtwn_pci_write_4(sc, R92C_HQ_DESA, pc->tx_ring[RTWN_PCI_HIGH_QUEUE].paddr); /* Configure Rx DMA. */ rtwn_pci_write_4(sc, R92C_RX_DESA, pc->rx_ring.paddr); } static void rtwn_pci_beacon_update_begin(struct rtwn_softc *sc, struct ieee80211vap *vap) { struct rtwn_vap *rvp = RTWN_VAP(vap); RTWN_ASSERT_LOCKED(sc); rtwn_beacon_enable(sc, rvp->id, 0); } static void rtwn_pci_beacon_update_end(struct rtwn_softc *sc, struct ieee80211vap *vap) { struct rtwn_vap *rvp = RTWN_VAP(vap); RTWN_ASSERT_LOCKED(sc); if (rvp->curr_mode != R92C_MSR_NOLINK) rtwn_beacon_enable(sc, rvp->id, 1); } static void rtwn_pci_attach_methods(struct rtwn_softc *sc) { sc->sc_write_1 = rtwn_pci_write_1; sc->sc_write_2 = rtwn_pci_write_2; sc->sc_write_4 = rtwn_pci_write_4; sc->sc_read_1 = rtwn_pci_read_1; sc->sc_read_2 = rtwn_pci_read_2; sc->sc_read_4 = rtwn_pci_read_4; sc->sc_delay = rtwn_pci_delay; sc->sc_tx_start = rtwn_pci_tx_start; sc->sc_reset_lists = rtwn_pci_reset_lists; sc->sc_abort_xfers = rtwn_nop_softc; sc->sc_fw_write_block = rtwn_pci_fw_write_block; sc->sc_get_qmap = rtwn_pci_get_qmap; sc->sc_set_desc_addr = rtwn_pci_set_desc_addr; sc->sc_drop_incorrect_tx = rtwn_nop_softc; sc->sc_beacon_update_begin = rtwn_pci_beacon_update_begin; sc->sc_beacon_update_end = rtwn_pci_beacon_update_end; sc->sc_beacon_unload = rtwn_pci_reset_beacon_ring; sc->bcn_check_interval = 25000; } static int rtwn_pci_attach(device_t dev) { const struct rtwn_pci_ident *ident; struct rtwn_pci_softc *pc = device_get_softc(dev); struct rtwn_softc *sc = &pc->pc_sc; struct ieee80211com *ic = &sc->sc_ic; uint32_t lcsr; int cap_off, i, error, rid; ident = rtwn_pci_probe_sub(dev); if (ident == NULL) return (ENXIO); /* * Get the offset of the PCI Express Capability Structure in PCI * Configuration Space. */ error = pci_find_cap(dev, PCIY_EXPRESS, &cap_off); if (error != 0) { device_printf(dev, "PCIe capability structure not found!\n"); return (error); } /* Enable bus-mastering. */ pci_enable_busmaster(dev); rid = PCIR_BAR(2); pc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (pc->mem == NULL) { device_printf(dev, "can't map mem space\n"); return (ENOMEM); } pc->pc_st = rman_get_bustag(pc->mem); pc->pc_sh = rman_get_bushandle(pc->mem); /* Install interrupt handler. */ rid = 1; if (pci_alloc_msi(dev, &rid) == 0) rid = 1; else rid = 0; pc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | (rid != 0 ? 0 : RF_SHAREABLE)); if (pc->irq == NULL) { device_printf(dev, "can't map interrupt\n"); goto detach; } /* Disable PCIe Active State Power Management (ASPM). */ lcsr = pci_read_config(dev, cap_off + PCIER_LINK_CTL, 4); lcsr &= ~PCIEM_LINK_CTL_ASPMC; pci_write_config(dev, cap_off + PCIER_LINK_CTL, lcsr, 4); sc->sc_dev = dev; ic->ic_name = device_get_nameunit(dev); /* Need to be initialized early. */ rtwn_sysctlattach(sc); mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); rtwn_pci_attach_methods(sc); rtwn_pci_attach_private(pc, ident->chip); /* Allocate Tx/Rx buffers. */ error = rtwn_pci_alloc_rx_list(sc); if (error != 0) { device_printf(dev, "could not allocate Rx buffers, error %d\n", error); goto detach; } for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) { error = rtwn_pci_alloc_tx_list(sc, i); if (error != 0) { device_printf(dev, "could not allocate Tx buffers, error %d\n", error); goto detach; } } /* Generic attach. */ error = rtwn_attach(sc); if (error != 0) goto detach; /* * Hook our interrupt after all initialization is complete. */ error = bus_setup_intr(dev, pc->irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, rtwn_pci_intr, sc, &pc->pc_ih); if (error != 0) { device_printf(dev, "can't establish interrupt, error %d\n", error); goto detach; } return (0); detach: rtwn_pci_detach(dev); /* failure */ return (ENXIO); } static int rtwn_pci_detach(device_t dev) { struct rtwn_pci_softc *pc = device_get_softc(dev); struct rtwn_softc *sc = &pc->pc_sc; int i; /* Generic detach. */ rtwn_detach(sc); /* Uninstall interrupt handler. */ if (pc->irq != NULL) { bus_teardown_intr(dev, pc->irq, pc->pc_ih); bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(pc->irq), pc->irq); pci_release_msi(dev); } /* Free Tx/Rx buffers. */ for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) rtwn_pci_free_tx_list(sc, i); rtwn_pci_free_rx_list(sc); if (pc->mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(pc->mem), pc->mem); rtwn_detach_private(sc); mtx_destroy(&sc->sc_mtx); return (0); } static int rtwn_pci_shutdown(device_t self) { struct rtwn_pci_softc *pc = device_get_softc(self); ieee80211_stop_all(&pc->pc_sc.sc_ic); return (0); } static int rtwn_pci_suspend(device_t self) { struct rtwn_pci_softc *pc = device_get_softc(self); rtwn_suspend(&pc->pc_sc); return (0); } static int rtwn_pci_resume(device_t self) { struct rtwn_pci_softc *pc = device_get_softc(self); rtwn_resume(&pc->pc_sc); return (0); } static device_method_t rtwn_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rtwn_pci_probe), DEVMETHOD(device_attach, rtwn_pci_attach), DEVMETHOD(device_detach, rtwn_pci_detach), DEVMETHOD(device_shutdown, rtwn_pci_shutdown), DEVMETHOD(device_suspend, rtwn_pci_suspend), DEVMETHOD(device_resume, rtwn_pci_resume), DEVMETHOD_END }; static driver_t rtwn_pci_driver = { "rtwn", rtwn_pci_methods, sizeof(struct rtwn_pci_softc) }; static devclass_t rtwn_pci_devclass; DRIVER_MODULE(rtwn_pci, pci, rtwn_pci_driver, rtwn_pci_devclass, NULL, NULL); MODULE_VERSION(rtwn_pci, 1); MODULE_DEPEND(rtwn_pci, pci, 1, 1, 1); MODULE_DEPEND(rtwn_pci, wlan, 1, 1, 1); MODULE_DEPEND(rtwn_pci, rtwn, 2, 2, 2); Index: head/sys/dev/rtwn/pci/rtwn_pci_rx.c =================================================================== --- head/sys/dev/rtwn/pci/rtwn_pci_rx.c (revision 320724) +++ head/sys/dev/rtwn/pci/rtwn_pci_rx.c (revision 320725) @@ -1,314 +1,312 @@ /* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2015 Stefan Sperling * Copyright (c) 2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include - void rtwn_pci_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { if (error != 0) return; KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); *(bus_addr_t *)arg = segs[0].ds_addr; } void -rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *pc, struct r92ce_rx_stat *desc, - bus_addr_t addr, size_t len, int idx) +rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *pc, + struct rtwn_rx_stat_pci *desc, bus_addr_t addr, size_t len, int idx) { memset(desc, 0, sizeof(*desc)); - desc->rxdw0 = htole32(SM(R92C_RXDW0_PKTLEN, len) | - ((idx == RTWN_PCI_RX_LIST_COUNT - 1) ? R92C_RXDW0_EOR : 0)); + desc->rxdw0 = htole32(SM(RTWN_RXDW0_PKTLEN, len) | + ((idx == RTWN_PCI_RX_LIST_COUNT - 1) ? RTWN_RXDW0_EOR : 0)); desc->rxbufaddr = htole32(addr); bus_space_barrier(pc->pc_st, pc->pc_sh, 0, pc->pc_mapsize, BUS_SPACE_BARRIER_WRITE); - desc->rxdw0 |= htole32(R92C_RXDW0_OWN); + desc->rxdw0 |= htole32(RTWN_RXDW0_OWN); } static void -rtwn_pci_rx_frame(struct rtwn_softc *sc, struct r92ce_rx_stat *rx_desc, +rtwn_pci_rx_frame(struct rtwn_softc *sc, struct rtwn_rx_stat_pci *rx_desc, int desc_idx) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); struct rtwn_rx_ring *ring = &pc->rx_ring; struct rtwn_rx_data *rx_data = &ring->rx_data[desc_idx]; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni; uint32_t rxdw0; struct mbuf *m, *m1; int infosz, pktlen, shift, error; /* Dump Rx descriptor. */ RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC, "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X, " "addr: %08X (64: %08X)\n", __func__, le32toh(rx_desc->rxdw0), le32toh(rx_desc->rxdw1), le32toh(rx_desc->rxdw2), le32toh(rx_desc->rxdw3), le32toh(rx_desc->rxdw4), le32toh(rx_desc->tsf_low), le32toh(rx_desc->rxbufaddr), le32toh(rx_desc->rxbufaddr64)); rxdw0 = le32toh(rx_desc->rxdw0); - if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) { + if (__predict_false(rxdw0 & (RTWN_RXDW0_CRCERR | RTWN_RXDW0_ICVERR))) { /* * This should not happen since we setup our Rx filter * to not receive these frames. */ RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, "%s: RX flags error (%s)\n", __func__, - rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV"); + rxdw0 & RTWN_RXDW0_CRCERR ? "CRC" : "ICV"); goto fail; } - pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN); if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack) || pktlen > MJUMPAGESIZE)) { RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, "%s: frame is too short/long: %d\n", __func__, pktlen); goto fail; } - infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; - shift = MS(rxdw0, R92C_RXDW0_SHIFT); + infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8; + shift = MS(rxdw0, RTWN_RXDW0_SHIFT); m1 = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); if (__predict_false(m1 == NULL)) { device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n", __func__); goto fail; } bus_dmamap_sync(ring->data_dmat, rx_data->map, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(ring->data_dmat, rx_data->map); error = bus_dmamap_load(ring->data_dmat, rx_data->map, mtod(m1, void *), MJUMPAGESIZE, rtwn_pci_dma_map_addr, &rx_data->paddr, 0); if (error != 0) { m_freem(m1); error = bus_dmamap_load(ring->data_dmat, rx_data->map, mtod(rx_data->m, void *), MJUMPAGESIZE, rtwn_pci_dma_map_addr, &rx_data->paddr, BUS_DMA_NOWAIT); if (error != 0) panic("%s: could not load old RX mbuf", device_get_name(sc->sc_dev)); /* Physical address may have changed. */ rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr, MJUMPAGESIZE, desc_idx); goto fail; } /* Finalize mbuf. */ m = rx_data->m; rx_data->m = m1; m->m_pkthdr.len = m->m_len = pktlen + infosz + shift; ni = rtwn_rx_common(sc, m, rx_desc); RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, "%s: Rx frame len %d, infosz %d, shift %d\n", __func__, pktlen, infosz, shift); /* Update RX descriptor. */ rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr, MJUMPAGESIZE, desc_idx); /* Send the frame to the 802.11 layer. */ RTWN_UNLOCK(sc); if (ni != NULL) { (void)ieee80211_input_mimo(ni, m); /* Node is no longer needed. */ ieee80211_free_node(ni); } else (void)ieee80211_input_mimo_all(ic, m); RTWN_LOCK(sc); return; fail: counter_u64_add(ic->ic_ierrors, 1); } static void rtwn_pci_tx_done(struct rtwn_softc *sc, int qid) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); struct rtwn_tx_ring *ring = &pc->tx_ring[qid]; struct rtwn_tx_desc_common *desc; struct rtwn_tx_data *data; RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: qid %d, last %d, cur %d\n", __func__, qid, ring->last, ring->cur); bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD); while(ring->last != ring->cur) { data = &ring->tx_data[ring->last]; desc = (struct rtwn_tx_desc_common *) ((uint8_t *)ring->desc + sc->txdesc_len * ring->last); KASSERT(data->m != NULL, ("no mbuf")); if (desc->flags0 & RTWN_FLAGS0_OWN) break; /* Unmap and free mbuf. */ bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); if (data->ni != NULL) { /* not a beacon frame */ ieee80211_tx_complete(data->ni, data->m, 0); data->ni = NULL; ring->queued--; KASSERT(ring->queued >= 0, ("ring->queued (qid %d) underflow!\n", qid)); } else m_freem(data->m); data->m = NULL; ring->last = (ring->last + 1) % RTWN_PCI_TX_LIST_COUNT; #ifndef D4054 if (ring->queued > 0) sc->sc_tx_timer = 5; else sc->sc_tx_timer = 0; #endif } if ((sc->qfullmsk & (1 << qid)) != 0 && ring->queued < (RTWN_PCI_TX_LIST_COUNT - 1)) { sc->qfullmsk &= ~(1 << qid); rtwn_start(sc); } #ifdef IEEE80211_SUPPORT_SUPERG /* * If the TX active queue drops below a certain * threshold, ensure we age fast-frames out so they're * transmitted. */ if (sc->sc_ratectl != RTWN_RATECTL_NET80211 && ring->queued <= 1) { /* * XXX TODO: just make this a callout timer schedule * so we can flush the FF staging queue if we're * approaching idle. */ rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); } #endif } static void rtwn_pci_rx_done(struct rtwn_softc *sc) { struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); struct rtwn_rx_ring *ring = &pc->rx_ring; bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD); for (;;) { - struct r92ce_rx_stat *rx_desc = &ring->desc[ring->cur]; + struct rtwn_rx_stat_pci *rx_desc = &ring->desc[ring->cur]; - if (le32toh(rx_desc->rxdw0) & R92C_RXDW0_OWN) + if (le32toh(rx_desc->rxdw0) & RTWN_RXDW0_OWN) break; rtwn_pci_rx_frame(sc, rx_desc, ring->cur); if (!(sc->sc_flags & RTWN_RUNNING)) return; ring->cur = (ring->cur + 1) % RTWN_PCI_RX_LIST_COUNT; } } void rtwn_pci_intr(void *arg) { struct rtwn_softc *sc = arg; struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); int i, status, tx_rings; RTWN_LOCK(sc); status = rtwn_classify_intr(sc, &tx_rings, 0); RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: status %08X, tx_rings %08X\n", __func__, status, tx_rings); if (status == 0 && tx_rings == 0) goto unlock; if (status & RTWN_PCI_INTR_RX) { rtwn_pci_rx_done(sc); if (!(sc->sc_flags & RTWN_RUNNING)) goto unlock; } if (tx_rings != 0) for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) if (tx_rings & (1 << i)) rtwn_pci_tx_done(sc, i); if (sc->sc_flags & RTWN_RUNNING) rtwn_pci_enable_intr(pc); unlock: RTWN_UNLOCK(sc); } Index: head/sys/dev/rtwn/pci/rtwn_pci_rx.h =================================================================== --- head/sys/dev/rtwn/pci/rtwn_pci_rx.h (revision 320724) +++ head/sys/dev/rtwn/pci/rtwn_pci_rx.h (revision 320725) @@ -1,27 +1,27 @@ /*- * Copyright (c) 2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #ifndef RTWN_PCI_RX_H #define RTWN_PCI_RX_H void rtwn_pci_dma_map_addr(void *, bus_dma_segment_t *, int, int); void rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *, - struct r92ce_rx_stat *, bus_addr_t, size_t, int); + struct rtwn_rx_stat_pci *, bus_addr_t, size_t, int); void rtwn_pci_intr(void *); #endif /* RTWN_PCI_RX_H */ Index: head/sys/dev/rtwn/pci/rtwn_pci_var.h =================================================================== --- head/sys/dev/rtwn/pci/rtwn_pci_var.h (revision 320724) +++ head/sys/dev/rtwn/pci/rtwn_pci_var.h (revision 320725) @@ -1,140 +1,137 @@ /* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2015 Stefan Sperling * Copyright (c) 2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #ifndef RTWN_PCI_VAR_H #define RTWN_PCI_VAR_H -#include - - #define RTWN_PCI_RX_LIST_COUNT 256 #define RTWN_PCI_TX_LIST_COUNT 256 struct rtwn_rx_data { bus_dmamap_t map; struct mbuf *m; bus_addr_t paddr; }; struct rtwn_rx_ring { - struct r92ce_rx_stat *desc; + struct rtwn_rx_stat_pci *desc; bus_addr_t paddr; bus_dma_tag_t desc_dmat; bus_dmamap_t desc_map; bus_dma_tag_t data_dmat; bus_dma_segment_t seg; struct rtwn_rx_data rx_data[RTWN_PCI_RX_LIST_COUNT]; int cur; }; struct rtwn_tx_data { bus_dmamap_t map; struct mbuf *m; struct ieee80211_node *ni; }; struct rtwn_tx_ring { bus_addr_t paddr; bus_dma_tag_t desc_dmat; bus_dmamap_t desc_map; bus_dma_tag_t data_dmat; bus_dma_segment_t seg; void *desc; struct rtwn_tx_data tx_data[RTWN_PCI_TX_LIST_COUNT]; int queued; int cur; int last; }; /* * TX queue indices. */ enum { RTWN_PCI_BK_QUEUE, RTWN_PCI_BE_QUEUE, RTWN_PCI_VI_QUEUE, RTWN_PCI_VO_QUEUE, RTWN_PCI_BEACON_QUEUE, RTWN_PCI_TXCMD_QUEUE, RTWN_PCI_MGNT_QUEUE, RTWN_PCI_HIGH_QUEUE, RTWN_PCI_HCCA_QUEUE, RTWN_PCI_NTXQUEUES }; /* * Interrupt events. */ enum { RTWN_PCI_INTR_RX_ERROR = 0x00000001, RTWN_PCI_INTR_RX_OVERFLOW = 0x00000002, RTWN_PCI_INTR_RX_DESC_UNAVAIL = 0x00000004, RTWN_PCI_INTR_RX_DONE = 0x00000008, RTWN_PCI_INTR_TX_ERROR = 0x00000010, RTWN_PCI_INTR_TX_OVERFLOW = 0x00000020, RTWN_PCI_INTR_TX_REPORT = 0x00000040, RTWN_PCI_INTR_PS_TIMEOUT = 0x00000080 }; /* Shortcuts */ /* Vendor driver treats RX errors like ROK... */ #define RTWN_PCI_INTR_RX \ (RTWN_PCI_INTR_RX_OVERFLOW | RTWN_PCI_INTR_RX_DESC_UNAVAIL | \ RTWN_PCI_INTR_RX_DONE) struct rtwn_pci_softc { struct rtwn_softc pc_sc; /* must be the first */ struct resource *irq; struct resource *mem; bus_space_tag_t pc_st; bus_space_handle_t pc_sh; void *pc_ih; bus_size_t pc_mapsize; struct rtwn_rx_ring rx_ring; struct rtwn_tx_ring tx_ring[RTWN_PCI_NTXQUEUES]; /* must be set by the driver. */ uint16_t pc_qmap; uint32_t tcr; void (*pc_setup_tx_desc)(struct rtwn_pci_softc *, void *, uint32_t); void (*pc_tx_postsetup)(struct rtwn_pci_softc *, void *, bus_dma_segment_t *); void (*pc_copy_tx_desc)(void *, const void *); void (*pc_enable_intr)(struct rtwn_pci_softc *); }; #define RTWN_PCI_SOFTC(sc) ((struct rtwn_pci_softc *)(sc)) #define rtwn_pci_setup_tx_desc(_pc, _desc, _addr) \ (((_pc)->pc_setup_tx_desc)((_pc), (_desc), (_addr))) #define rtwn_pci_tx_postsetup(_pc, _txd, _segs) \ (((_pc)->pc_tx_postsetup)((_pc), (_txd), (_segs))) #define rtwn_pci_copy_tx_desc(_pc, _dest, _src) \ (((_pc)->pc_copy_tx_desc)((_dest), (_src))) #define rtwn_pci_enable_intr(_pc) \ (((_pc)->pc_enable_intr)((_pc))) #endif /* RTWN_PCI_VAR_H */ Index: head/sys/dev/rtwn/usb/rtwn_usb_rx.c =================================================================== --- head/sys/dev/rtwn/usb/rtwn_usb_rx.c (revision 320724) +++ head/sys/dev/rtwn/usb/rtwn_usb_rx.c (revision 320725) @@ -1,324 +1,321 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef IEEE80211_SUPPORT_SUPERG #include #endif #include #include #include #include #include #include #include #include #include #include #include -#include /* for CAM_ALGO_NONE */ -#include - static struct mbuf * -rtwn_rx_copy_to_mbuf(struct rtwn_softc *sc, struct r92c_rx_stat *stat, +rtwn_rx_copy_to_mbuf(struct rtwn_softc *sc, struct rtwn_rx_stat_common *stat, int totlen) { struct ieee80211com *ic = &sc->sc_ic; struct mbuf *m; uint32_t rxdw0; int pktlen; RTWN_ASSERT_LOCKED(sc); /* Dump Rx descriptor. */ RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC, "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X\n", __func__, le32toh(stat->rxdw0), le32toh(stat->rxdw1), le32toh(stat->rxdw2), le32toh(stat->rxdw3), le32toh(stat->rxdw4), le32toh(stat->tsf_low)); /* * don't pass packets to the ieee80211 framework if the driver isn't * RUNNING. */ if (!(sc->sc_flags & RTWN_RUNNING)) return (NULL); rxdw0 = le32toh(stat->rxdw0); - if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) { + if (__predict_false(rxdw0 & (RTWN_RXDW0_CRCERR | RTWN_RXDW0_ICVERR))) { /* * This should not happen since we setup our Rx filter * to not receive these frames. */ RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, "%s: RX flags error (%s)\n", __func__, - rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV"); + rxdw0 & RTWN_RXDW0_CRCERR ? "CRC" : "ICV"); goto fail; } - pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN); if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack))) { /* * Should not happen (because of Rx filter setup). */ RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, "%s: frame is too short: %d\n", __func__, pktlen); goto fail; } m = m_get2(totlen, M_NOWAIT, MT_DATA, M_PKTHDR); if (__predict_false(m == NULL)) { device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n", __func__); goto fail; } /* Finalize mbuf. */ memcpy(mtod(m, uint8_t *), (uint8_t *)stat, totlen); m->m_pkthdr.len = m->m_len = totlen; if (rtwn_check_frame(sc, m) != 0) { m_freem(m); goto fail; } return (m); fail: counter_u64_add(ic->ic_ierrors, 1); return (NULL); } static struct mbuf * rtwn_rxeof(struct rtwn_softc *sc, uint8_t *buf, int len) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); - struct r92c_rx_stat *stat; + struct rtwn_rx_stat_common *stat; struct mbuf *m, *m0 = NULL; uint32_t rxdw0; int totlen, pktlen, infosz; /* Process packets. */ while (len >= sizeof(*stat)) { - stat = (struct r92c_rx_stat *)buf; + stat = (struct rtwn_rx_stat_common *)buf; rxdw0 = le32toh(stat->rxdw0); - pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN); if (__predict_false(pktlen == 0)) break; - infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; + infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8; /* Make sure everything fits in xfer. */ totlen = sizeof(*stat) + infosz + pktlen; if (totlen > len) { device_printf(sc->sc_dev, "%s: totlen (%d) > len (%d)!\n", __func__, totlen, len); break; } if (m0 == NULL) m0 = m = rtwn_rx_copy_to_mbuf(sc, stat, totlen); else { m->m_next = rtwn_rx_copy_to_mbuf(sc, stat, totlen); if (m->m_next != NULL) m = m->m_next; } /* Align next frame. */ totlen = rtwn_usb_align_rx(uc, totlen, len); buf += totlen; len -= totlen; } return (m0); } static struct mbuf * rtwn_report_intr(struct rtwn_usb_softc *uc, struct usb_xfer *xfer, struct rtwn_data *data) { struct rtwn_softc *sc = &uc->uc_sc; struct ieee80211com *ic = &sc->sc_ic; uint8_t *buf; int len; usbd_xfer_status(xfer, &len, NULL, NULL, NULL); - if (__predict_false(len < sizeof(struct r92c_rx_stat))) { + if (__predict_false(len < sizeof(struct rtwn_rx_stat_common))) { counter_u64_add(ic->ic_ierrors, 1); return (NULL); } buf = data->buf; switch (rtwn_classify_intr(sc, buf, len)) { case RTWN_RX_DATA: return (rtwn_rxeof(sc, buf, len)); case RTWN_RX_TX_REPORT: if (sc->sc_ratectl != RTWN_RATECTL_NET80211) { /* shouldn't happen */ device_printf(sc->sc_dev, "%s called while ratectl = %d!\n", __func__, sc->sc_ratectl); break; } RTWN_NT_LOCK(sc); rtwn_handle_tx_report(sc, buf, len); RTWN_NT_UNLOCK(sc); #ifdef IEEE80211_SUPPORT_SUPERG /* * NB: this will executed only when 'report' bit is set. */ if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1) rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); #endif break; case RTWN_RX_OTHER: rtwn_handle_c2h_report(sc, buf, len); break; default: /* NOTREACHED */ KASSERT(0, ("unknown Rx classification code")); break; } return (NULL); } static struct ieee80211_node * rtwn_rx_frame(struct rtwn_softc *sc, struct mbuf *m) { - struct r92c_rx_stat stat; + struct rtwn_rx_stat_common stat; /* Imitate PCIe layout. */ - m_copydata(m, 0, sizeof(struct r92c_rx_stat), (caddr_t)&stat); - m_adj(m, sizeof(struct r92c_rx_stat)); + m_copydata(m, 0, sizeof(stat), (caddr_t)&stat); + m_adj(m, sizeof(stat)); return (rtwn_rx_common(sc, m, &stat)); } void rtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) { struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer); struct rtwn_softc *sc = &uc->uc_sc; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni; struct mbuf *m = NULL, *next; struct rtwn_data *data; RTWN_ASSERT_LOCKED(sc); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: data = STAILQ_FIRST(&uc->uc_rx_active); if (data == NULL) goto tr_setup; STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next); m = rtwn_report_intr(uc, xfer, data); STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: data = STAILQ_FIRST(&uc->uc_rx_inactive); if (data == NULL) { KASSERT(m == NULL, ("mbuf isn't NULL")); goto finish; } STAILQ_REMOVE_HEAD(&uc->uc_rx_inactive, next); STAILQ_INSERT_TAIL(&uc->uc_rx_active, data, next); usbd_xfer_set_frame_data(xfer, 0, data->buf, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); /* * To avoid LOR we should unlock our private mutex here to call * ieee80211_input() because here is at the end of a USB * callback and safe to unlock. */ while (m != NULL) { next = m->m_next; m->m_next = NULL; ni = rtwn_rx_frame(sc, m); RTWN_UNLOCK(sc); if (ni != NULL) { (void)ieee80211_input_mimo(ni, m); ieee80211_free_node(ni); } else { (void)ieee80211_input_mimo_all(ic, m); } RTWN_LOCK(sc); m = next; } break; default: /* needs it to the inactive queue due to a error. */ data = STAILQ_FIRST(&uc->uc_rx_active); if (data != NULL) { STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next); STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next); } if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); counter_u64_add(ic->ic_ierrors, 1); goto tr_setup; } break; } finish: /* Kick-start more transmit in case we stalled */ rtwn_start(sc); }