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