1 /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> 5 * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> 6 * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/cdefs.h> 22 __FBSDID("$FreeBSD$"); 23 24 #include "opt_wlan.h" 25 26 #include <sys/param.h> 27 #include <sys/lock.h> 28 #include <sys/mutex.h> 29 #include <sys/mbuf.h> 30 #include <sys/kernel.h> 31 #include <sys/socket.h> 32 #include <sys/systm.h> 33 #include <sys/malloc.h> 34 #include <sys/queue.h> 35 #include <sys/taskqueue.h> 36 #include <sys/bus.h> 37 #include <sys/endian.h> 38 39 #include <net/if.h> 40 #include <net/if_var.h> 41 #include <net/ethernet.h> 42 #include <net/if_media.h> 43 44 #include <net80211/ieee80211_var.h> 45 #include <net80211/ieee80211_radiotap.h> 46 #include <net80211/ieee80211_ratectl.h> 47 48 #include <dev/usb/usb.h> 49 #include <dev/usb/usbdi.h> 50 51 #include <dev/rtwn/if_rtwnreg.h> 52 #include <dev/rtwn/if_rtwnvar.h> 53 54 #include <dev/rtwn/if_rtwn_beacon.h> 55 #include <dev/rtwn/if_rtwn_debug.h> 56 #include <dev/rtwn/if_rtwn_ridx.h> 57 #include <dev/rtwn/if_rtwn_task.h> 58 #include <dev/rtwn/if_rtwn_tx.h> 59 60 #include <dev/rtwn/usb/rtwn_usb_var.h> 61 62 #include <dev/rtwn/usb/rtwn_usb_reg.h> 63 #include <dev/rtwn/usb/rtwn_usb_tx.h> 64 65 static struct rtwn_data * _rtwn_usb_getbuf(struct rtwn_usb_softc *); 66 static struct rtwn_data * rtwn_usb_getbuf(struct rtwn_usb_softc *); 67 static void rtwn_usb_txeof(struct rtwn_usb_softc *, 68 struct rtwn_data *, int); 69 70 static const uint8_t wme2qid[] = 71 { RTWN_BULK_TX_BE, RTWN_BULK_TX_BK, 72 RTWN_BULK_TX_VI, RTWN_BULK_TX_VO }; 73 74 static struct rtwn_data * 75 _rtwn_usb_getbuf(struct rtwn_usb_softc *uc) 76 { 77 struct rtwn_softc *sc = &uc->uc_sc; 78 struct rtwn_data *bf; 79 80 bf = STAILQ_FIRST(&uc->uc_tx_inactive); 81 if (bf != NULL) 82 STAILQ_REMOVE_HEAD(&uc->uc_tx_inactive, next); 83 else { 84 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, 85 "%s: out of xmit buffers\n", __func__); 86 } 87 return (bf); 88 } 89 90 static struct rtwn_data * 91 rtwn_usb_getbuf(struct rtwn_usb_softc *uc) 92 { 93 struct rtwn_softc *sc = &uc->uc_sc; 94 struct rtwn_data *bf; 95 96 RTWN_ASSERT_LOCKED(sc); 97 98 bf = _rtwn_usb_getbuf(uc); 99 if (bf == NULL) { 100 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: stop queue\n", 101 __func__); 102 } 103 return (bf); 104 } 105 106 static void 107 rtwn_usb_txeof(struct rtwn_usb_softc *uc, struct rtwn_data *data, int status) 108 { 109 struct rtwn_softc *sc = &uc->uc_sc; 110 111 RTWN_ASSERT_LOCKED(sc); 112 113 if (data->ni != NULL) /* not a beacon frame */ 114 ieee80211_tx_complete(data->ni, data->m, status); 115 116 if (sc->sc_ratectl != RTWN_RATECTL_NET80211) 117 if (sc->sc_tx_n_active > 0) 118 sc->sc_tx_n_active--; 119 120 data->ni = NULL; 121 data->m = NULL; 122 123 STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, data, next); 124 sc->qfullmsk = 0; 125 #ifndef D4054 126 if (STAILQ_EMPTY(&uc->uc_tx_active) && STAILQ_EMPTY(&uc->uc_tx_pending)) 127 sc->sc_tx_timer = 0; 128 else 129 sc->sc_tx_timer = 5; 130 #endif 131 } 132 133 void 134 rtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) 135 { 136 struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer); 137 struct rtwn_softc *sc = &uc->uc_sc; 138 struct rtwn_data *data; 139 140 RTWN_ASSERT_LOCKED(sc); 141 142 switch (USB_GET_STATE(xfer)){ 143 case USB_ST_TRANSFERRED: 144 data = STAILQ_FIRST(&uc->uc_tx_active); 145 if (data == NULL) 146 goto tr_setup; 147 STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); 148 rtwn_usb_txeof(uc, data, 0); 149 /* FALLTHROUGH */ 150 case USB_ST_SETUP: 151 tr_setup: 152 data = STAILQ_FIRST(&uc->uc_tx_pending); 153 if (data == NULL) { 154 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, 155 "%s: empty pending queue\n", __func__); 156 sc->sc_tx_n_active = 0; 157 goto finish; 158 } 159 STAILQ_REMOVE_HEAD(&uc->uc_tx_pending, next); 160 STAILQ_INSERT_TAIL(&uc->uc_tx_active, data, next); 161 162 /* 163 * Note: if this is a beacon frame, ensure that it will go 164 * into appropriate queue. 165 */ 166 if (data->ni == NULL && RTWN_CHIP_HAS_BCNQ1(sc)) 167 rtwn_switch_bcnq(sc, data->id); 168 usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); 169 usbd_transfer_submit(xfer); 170 if (sc->sc_ratectl != RTWN_RATECTL_NET80211) 171 sc->sc_tx_n_active++; 172 break; 173 default: 174 data = STAILQ_FIRST(&uc->uc_tx_active); 175 if (data == NULL) 176 goto tr_setup; 177 STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); 178 rtwn_usb_txeof(uc, data, 1); 179 if (error != USB_ERR_CANCELLED) { 180 usbd_xfer_set_stall(xfer); 181 goto tr_setup; 182 } 183 break; 184 } 185 finish: 186 #ifdef IEEE80211_SUPPORT_SUPERG 187 /* 188 * If the TX active queue drops below a certain 189 * threshold, ensure we age fast-frames out so they're 190 * transmitted. 191 */ 192 if (sc->sc_ratectl != RTWN_RATECTL_NET80211 && 193 sc->sc_tx_n_active <= 1) { 194 /* XXX ew - net80211 should defer this for us! */ 195 196 /* 197 * Note: this sc_tx_n_active currently tracks 198 * the number of pending transmit submissions 199 * and not the actual depth of the TX frames 200 * pending to the hardware. That means that 201 * we're going to end up with some sub-optimal 202 * aggregation behaviour. 203 */ 204 /* 205 * XXX TODO: just make this a callout timer schedule so we can 206 * flush the FF staging queue if we're approaching idle. 207 */ 208 rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); 209 } 210 #endif 211 /* Kick-start more transmit */ 212 rtwn_start(sc); 213 } 214 215 static void 216 rtwn_usb_tx_checksum(struct rtwn_tx_desc_common *txd) 217 { 218 txd->txdw7.usb_checksum = 0; 219 txd->txdw7.usb_checksum = rtwn_usb_calc_tx_checksum(txd); 220 } 221 222 int 223 rtwn_usb_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni, 224 struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id) 225 { 226 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 227 struct rtwn_tx_desc_common *txd; 228 struct rtwn_data *data; 229 struct usb_xfer *xfer; 230 uint16_t ac; 231 232 RTWN_ASSERT_LOCKED(sc); 233 234 if (m->m_pkthdr.len + sc->txdesc_len > RTWN_USB_TXBUFSZ) 235 return (EINVAL); 236 237 data = rtwn_usb_getbuf(uc); 238 if (data == NULL) 239 return (ENOBUFS); 240 241 ac = M_WME_GETAC(m); 242 243 switch (type) { 244 case IEEE80211_FC0_TYPE_CTL: 245 case IEEE80211_FC0_TYPE_MGT: 246 xfer = uc->uc_xfer[RTWN_BULK_TX_VO]; 247 break; 248 default: 249 xfer = uc->uc_xfer[wme2qid[ac]]; 250 break; 251 } 252 253 txd = (struct rtwn_tx_desc_common *)tx_desc; 254 txd->pktlen = htole16(m->m_pkthdr.len); 255 txd->offset = sc->txdesc_len; 256 txd->flags0 |= RTWN_FLAGS0_OWN; 257 rtwn_usb_tx_checksum(txd); 258 259 /* Dump Tx descriptor. */ 260 rtwn_dump_tx_desc(sc, tx_desc); 261 262 memcpy(data->buf, tx_desc, sc->txdesc_len); 263 m_copydata(m, 0, m->m_pkthdr.len, 264 (caddr_t)(data->buf + sc->txdesc_len)); 265 266 data->buflen = m->m_pkthdr.len + sc->txdesc_len; 267 data->id = id; 268 data->ni = ni; 269 if (data->ni != NULL) { 270 data->m = m; 271 #ifndef D4054 272 sc->sc_tx_timer = 5; 273 #endif 274 } 275 276 STAILQ_INSERT_TAIL(&uc->uc_tx_pending, data, next); 277 if (STAILQ_EMPTY(&uc->uc_tx_inactive)) 278 sc->qfullmsk = 1; 279 280 usbd_transfer_start(xfer); 281 282 return (0); 283 } 284