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 71 static const uint8_t wme2qid[] = 72 { RTWN_BULK_TX_BE, RTWN_BULK_TX_BK, 73 RTWN_BULK_TX_VI, RTWN_BULK_TX_VO }; 74 75 76 static struct rtwn_data * 77 _rtwn_usb_getbuf(struct rtwn_usb_softc *uc) 78 { 79 struct rtwn_softc *sc = &uc->uc_sc; 80 struct rtwn_data *bf; 81 82 bf = STAILQ_FIRST(&uc->uc_tx_inactive); 83 if (bf != NULL) 84 STAILQ_REMOVE_HEAD(&uc->uc_tx_inactive, next); 85 else { 86 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, 87 "%s: out of xmit buffers\n", __func__); 88 } 89 return (bf); 90 } 91 92 static struct rtwn_data * 93 rtwn_usb_getbuf(struct rtwn_usb_softc *uc) 94 { 95 struct rtwn_softc *sc = &uc->uc_sc; 96 struct rtwn_data *bf; 97 98 RTWN_ASSERT_LOCKED(sc); 99 100 bf = _rtwn_usb_getbuf(uc); 101 if (bf == NULL) { 102 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: stop queue\n", 103 __func__); 104 } 105 return (bf); 106 } 107 108 static void 109 rtwn_usb_txeof(struct rtwn_usb_softc *uc, struct rtwn_data *data, int status) 110 { 111 struct rtwn_softc *sc = &uc->uc_sc; 112 113 RTWN_ASSERT_LOCKED(sc); 114 115 if (data->ni != NULL) /* not a beacon frame */ 116 ieee80211_tx_complete(data->ni, data->m, status); 117 118 if (sc->sc_ratectl != RTWN_RATECTL_NET80211) 119 if (sc->sc_tx_n_active > 0) 120 sc->sc_tx_n_active--; 121 122 data->ni = NULL; 123 data->m = NULL; 124 125 STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, data, next); 126 sc->qfullmsk = 0; 127 #ifndef D4054 128 if (STAILQ_EMPTY(&uc->uc_tx_active) && STAILQ_EMPTY(&uc->uc_tx_pending)) 129 sc->sc_tx_timer = 0; 130 else 131 sc->sc_tx_timer = 5; 132 #endif 133 } 134 135 void 136 rtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) 137 { 138 struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer); 139 struct rtwn_softc *sc = &uc->uc_sc; 140 struct rtwn_data *data; 141 142 RTWN_ASSERT_LOCKED(sc); 143 144 switch (USB_GET_STATE(xfer)){ 145 case USB_ST_TRANSFERRED: 146 data = STAILQ_FIRST(&uc->uc_tx_active); 147 if (data == NULL) 148 goto tr_setup; 149 STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); 150 rtwn_usb_txeof(uc, data, 0); 151 /* FALLTHROUGH */ 152 case USB_ST_SETUP: 153 tr_setup: 154 data = STAILQ_FIRST(&uc->uc_tx_pending); 155 if (data == NULL) { 156 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, 157 "%s: empty pending queue\n", __func__); 158 sc->sc_tx_n_active = 0; 159 goto finish; 160 } 161 STAILQ_REMOVE_HEAD(&uc->uc_tx_pending, next); 162 STAILQ_INSERT_TAIL(&uc->uc_tx_active, data, next); 163 164 /* 165 * Note: if this is a beacon frame, ensure that it will go 166 * into appropriate queue. 167 */ 168 if (data->ni == NULL && RTWN_CHIP_HAS_BCNQ1(sc)) 169 rtwn_switch_bcnq(sc, data->id); 170 usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); 171 usbd_transfer_submit(xfer); 172 if (sc->sc_ratectl != RTWN_RATECTL_NET80211) 173 sc->sc_tx_n_active++; 174 break; 175 default: 176 data = STAILQ_FIRST(&uc->uc_tx_active); 177 if (data == NULL) 178 goto tr_setup; 179 STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); 180 rtwn_usb_txeof(uc, data, 1); 181 if (error != USB_ERR_CANCELLED) { 182 usbd_xfer_set_stall(xfer); 183 goto tr_setup; 184 } 185 break; 186 } 187 finish: 188 #ifdef IEEE80211_SUPPORT_SUPERG 189 /* 190 * If the TX active queue drops below a certain 191 * threshold, ensure we age fast-frames out so they're 192 * transmitted. 193 */ 194 if (sc->sc_ratectl != RTWN_RATECTL_NET80211 && 195 sc->sc_tx_n_active <= 1) { 196 /* XXX ew - net80211 should defer this for us! */ 197 198 /* 199 * Note: this sc_tx_n_active currently tracks 200 * the number of pending transmit submissions 201 * and not the actual depth of the TX frames 202 * pending to the hardware. That means that 203 * we're going to end up with some sub-optimal 204 * aggregation behaviour. 205 */ 206 /* 207 * XXX TODO: just make this a callout timer schedule so we can 208 * flush the FF staging queue if we're approaching idle. 209 */ 210 rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); 211 } 212 #endif 213 /* Kick-start more transmit */ 214 rtwn_start(sc); 215 } 216 217 static void 218 rtwn_usb_tx_checksum(struct rtwn_tx_desc_common *txd) 219 { 220 txd->txdw7.usb_checksum = 0; 221 txd->txdw7.usb_checksum = rtwn_usb_calc_tx_checksum(txd); 222 } 223 224 int 225 rtwn_usb_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni, 226 struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id) 227 { 228 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); 229 struct rtwn_tx_desc_common *txd; 230 struct rtwn_data *data; 231 struct usb_xfer *xfer; 232 uint16_t ac; 233 234 RTWN_ASSERT_LOCKED(sc); 235 236 if (m->m_pkthdr.len + sc->txdesc_len > RTWN_USB_TXBUFSZ) 237 return (EINVAL); 238 239 data = rtwn_usb_getbuf(uc); 240 if (data == NULL) 241 return (ENOBUFS); 242 243 ac = M_WME_GETAC(m); 244 245 switch (type) { 246 case IEEE80211_FC0_TYPE_CTL: 247 case IEEE80211_FC0_TYPE_MGT: 248 xfer = uc->uc_xfer[RTWN_BULK_TX_VO]; 249 break; 250 default: 251 xfer = uc->uc_xfer[wme2qid[ac]]; 252 break; 253 } 254 255 txd = (struct rtwn_tx_desc_common *)tx_desc; 256 txd->pktlen = htole16(m->m_pkthdr.len); 257 txd->offset = sc->txdesc_len; 258 txd->flags0 |= RTWN_FLAGS0_OWN; 259 rtwn_usb_tx_checksum(txd); 260 261 /* Dump Tx descriptor. */ 262 rtwn_dump_tx_desc(sc, tx_desc); 263 264 memcpy(data->buf, tx_desc, sc->txdesc_len); 265 m_copydata(m, 0, m->m_pkthdr.len, 266 (caddr_t)(data->buf + sc->txdesc_len)); 267 268 data->buflen = m->m_pkthdr.len + sc->txdesc_len; 269 data->id = id; 270 data->ni = ni; 271 if (data->ni != NULL) { 272 data->m = m; 273 #ifndef D4054 274 sc->sc_tx_timer = 5; 275 #endif 276 } 277 278 STAILQ_INSERT_TAIL(&uc->uc_tx_pending, data, next); 279 if (STAILQ_EMPTY(&uc->uc_tx_inactive)) 280 sc->qfullmsk = 1; 281 282 usbd_transfer_start(xfer); 283 284 return (0); 285 } 286