diff options
author | Andriy Voskoboinyk <avos@FreeBSD.org> | 2016-10-17 20:38:24 +0000 |
---|---|---|
committer | Andriy Voskoboinyk <avos@FreeBSD.org> | 2016-10-17 20:38:24 +0000 |
commit | 7453645f2a9411a3f9d982b768bcc323f41cf906 (patch) | |
tree | 16c1ed3b4792028154ca7701feb649ba12da9951 /sys/dev/rtwn/usb | |
parent | a1a604ca902bbe790abd63576d5127680663f0e1 (diff) | |
download | src-7453645f2a9411a3f9d982b768bcc323f41cf906.tar.gz src-7453645f2a9411a3f9d982b768bcc323f41cf906.zip |
rtwn(4), urtwn(4): merge common code, add support for 11ac devices.
All devices:
- add support for rate adaptation via ieee80211_amrr(9);
- use short preamble for transmitted frames when needed;
- multi-bss support:
* for RTL8821AU: 2 VAPs at the same time;
* other: 1 any VAP + 1 sta VAP.
RTL8188CE:
- fix IQ calibration bug (reason of significant speed degradation);
- add h/w crypto acceleration support.
USB:
- A-MPDU Tx support;
- short GI support;
Other:
- add support for RTL8812AU / RTL8821AU chipsets
(a/b/g/n only; no ac yet);
- split merged code into subparts:
* bus glue (usb/*, pci/*, rtl*/usb/*, rtl*/pci/*)
* common (if_rtwn*)
* chip-specific (rtl*/*)
- various other bugfixes.
Due to code reorganization, module names / requirements were changed too:
urtwn urtwnfw -> rtwn rtwn_usb rtwnfw
rtwn rtwnfw -> rtwn rtwn_pci rtwnfw
Tested with RTL8188CE, RTL8188CUS, RTL8188EU and RTL8821AU.
Tested by: kevlo, garga,
Peter Garshtja <peter.garshtja@ambient-md.com>,
Kevin McAleavey <kevin.mcaleavey@knosproject.com>,
Ilias-Dimitrios Vrachnis <id@vrachnis.com>,
<otacilio.neto@bsd.com.br>
Relnotes: yes
Notes
Notes:
svn path=/head/; revision=307529
Diffstat (limited to 'sys/dev/rtwn/usb')
-rw-r--r-- | sys/dev/rtwn/usb/rtwn_usb_attach.c | 433 | ||||
-rw-r--r-- | sys/dev/rtwn/usb/rtwn_usb_attach.h | 159 | ||||
-rw-r--r-- | sys/dev/rtwn/usb/rtwn_usb_ep.c | 253 | ||||
-rw-r--r-- | sys/dev/rtwn/usb/rtwn_usb_ep.h | 25 | ||||
-rw-r--r-- | sys/dev/rtwn/usb/rtwn_usb_reg.c | 179 | ||||
-rw-r--r-- | sys/dev/rtwn/usb/rtwn_usb_reg.h | 45 | ||||
-rw-r--r-- | sys/dev/rtwn/usb/rtwn_usb_rx.c | 335 | ||||
-rw-r--r-- | sys/dev/rtwn/usb/rtwn_usb_rx.h | 24 | ||||
-rw-r--r-- | sys/dev/rtwn/usb/rtwn_usb_tx.c | 282 | ||||
-rw-r--r-- | sys/dev/rtwn/usb/rtwn_usb_tx.h | 26 | ||||
-rw-r--r-- | sys/dev/rtwn/usb/rtwn_usb_var.h | 74 |
11 files changed, 1835 insertions, 0 deletions
diff --git a/sys/dev/rtwn/usb/rtwn_usb_attach.c b/sys/dev/rtwn/usb/rtwn_usb_attach.c new file mode 100644 index 000000000000..a47797b56af7 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_attach.c @@ -0,0 +1,433 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> + * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/linker.h> +#include <sys/kdb.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/ethernet.h> +#include <net/if_media.h> + +#include <net80211/ieee80211_var.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include "usbdevs.h" + +#include <dev/rtwn/if_rtwnvar.h> +#include <dev/rtwn/if_rtwn_nop.h> + +#include <dev/rtwn/usb/rtwn_usb_var.h> + +#include <dev/rtwn/usb/rtwn_usb_attach.h> +#include <dev/rtwn/usb/rtwn_usb_ep.h> +#include <dev/rtwn/usb/rtwn_usb_reg.h> +#include <dev/rtwn/usb/rtwn_usb_tx.h> + +#include <dev/rtwn/rtl8192c/r92c_reg.h> + +static device_probe_t rtwn_usb_match; +static device_attach_t rtwn_usb_attach; +static device_detach_t rtwn_usb_detach; +static device_suspend_t rtwn_usb_suspend; +static device_resume_t rtwn_usb_resume; + +static int rtwn_usb_alloc_list(struct rtwn_softc *, + struct rtwn_data[], int, int); +static int rtwn_usb_alloc_rx_list(struct rtwn_softc *); +static int rtwn_usb_alloc_tx_list(struct rtwn_softc *); +static void rtwn_usb_free_list(struct rtwn_softc *, + struct rtwn_data data[], int); +static void rtwn_usb_free_rx_list(struct rtwn_softc *); +static void rtwn_usb_free_tx_list(struct rtwn_softc *); +static void rtwn_usb_reset_lists(struct rtwn_softc *, + struct ieee80211vap *); +static void rtwn_usb_reset_tx_list(struct rtwn_usb_softc *, + rtwn_datahead *, struct ieee80211vap *); +static void rtwn_usb_start_xfers(struct rtwn_softc *); +static void rtwn_usb_abort_xfers(struct rtwn_softc *); +static int rtwn_usb_fw_write_block(struct rtwn_softc *, + const uint8_t *, uint16_t, int); +static void rtwn_usb_attach_methods(struct rtwn_softc *); + +#define RTWN_CONFIG_INDEX 0 + + +static int +rtwn_usb_match(device_t self) +{ + struct usb_attach_arg *uaa = device_get_ivars(self); + + if (uaa->usb_mode != USB_MODE_HOST) + return (ENXIO); + if (uaa->info.bConfigIndex != RTWN_CONFIG_INDEX) + return (ENXIO); + if (uaa->info.bIfaceIndex != RTWN_IFACE_INDEX) + return (ENXIO); + + return (usbd_lookup_id_by_uaa(rtwn_devs, sizeof(rtwn_devs), uaa)); +} + +static int +rtwn_usb_alloc_list(struct rtwn_softc *sc, struct rtwn_data data[], + int ndata, int maxsz) +{ + int i, error; + + for (i = 0; i < ndata; i++) { + struct rtwn_data *dp = &data[i]; + dp->m = NULL; + dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); + if (dp->buf == NULL) { + device_printf(sc->sc_dev, + "could not allocate buffer\n"); + error = ENOMEM; + goto fail; + } + dp->ni = NULL; + } + + return (0); +fail: + rtwn_usb_free_list(sc, data, ndata); + return (error); +} + +static int +rtwn_usb_alloc_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int error, i; + + error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT, + RTWN_RXBUFSZ); + if (error != 0) + return (error); + + STAILQ_INIT(&uc->uc_rx_active); + STAILQ_INIT(&uc->uc_rx_inactive); + + for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) + STAILQ_INSERT_HEAD(&uc->uc_rx_inactive, &uc->uc_rx[i], next); + + return (0); +} + +static int +rtwn_usb_alloc_tx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int error, i; + + error = rtwn_usb_alloc_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT, + RTWN_TXBUFSZ); + if (error != 0) + return (error); + + STAILQ_INIT(&uc->uc_tx_active); + STAILQ_INIT(&uc->uc_tx_inactive); + STAILQ_INIT(&uc->uc_tx_pending); + + for (i = 0; i < RTWN_USB_TX_LIST_COUNT; i++) + STAILQ_INSERT_HEAD(&uc->uc_tx_inactive, &uc->uc_tx[i], next); + + return (0); +} + +static void +rtwn_usb_free_list(struct rtwn_softc *sc, struct rtwn_data data[], int ndata) +{ + int i; + + for (i = 0; i < ndata; i++) { + struct rtwn_data *dp = &data[i]; + + if (dp->buf != NULL) { + free(dp->buf, M_USBDEV); + dp->buf = NULL; + } + if (dp->ni != NULL) { + ieee80211_free_node(dp->ni); + dp->ni = NULL; + } + if (dp->m != NULL) { + m_freem(dp->m); + dp->m = NULL; + } + } +} + +static void +rtwn_usb_free_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + rtwn_usb_free_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT); + + STAILQ_INIT(&uc->uc_rx_active); + STAILQ_INIT(&uc->uc_rx_inactive); +} + +static void +rtwn_usb_free_tx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT); + + STAILQ_INIT(&uc->uc_tx_active); + STAILQ_INIT(&uc->uc_tx_inactive); + STAILQ_INIT(&uc->uc_tx_pending); +} + +static void +rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + RTWN_ASSERT_LOCKED(sc); + + rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap); + rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap); + if (vap == NULL) + sc->qfullmsk = 0; +} + +static void +rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc, + rtwn_datahead *head, struct ieee80211vap *vap) +{ + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct rtwn_data *dp, *tmp; + int id; + + id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID); + + STAILQ_FOREACH_SAFE(dp, head, next, tmp) { + if (vap == NULL || (dp->ni == NULL && + (dp->id == id || id == RTWN_VAP_ID_INVALID)) || + (dp->ni != NULL && dp->ni->ni_vap == vap)) { + if (dp->ni != NULL) { + ieee80211_free_node(dp->ni); + dp->ni = NULL; + } + + if (dp->m != NULL) { + m_freem(dp->m); + dp->m = NULL; + } + + STAILQ_REMOVE(head, dp, rtwn_data, next); + STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next); + } + } +} + +static void +rtwn_usb_start_xfers(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]); +} + +static void +rtwn_usb_abort_xfers(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int i; + + RTWN_ASSERT_LOCKED(sc); + + /* abort any pending transfers */ + for (i = 0; i < RTWN_N_TRANSFER; i++) + usbd_transfer_stop(uc->uc_xfer[i]); +} + +static int +rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf, + uint16_t reg, int mlen) +{ + int error; + + /* XXX fix this deconst */ + error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf), + mlen); + + return (error); +} + +static void +rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc) +{ + + rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0, + R92C_TXDMA_OFFSET_DROP_DATA_EN, 1); +} + +static void +rtwn_usb_attach_methods(struct rtwn_softc *sc) +{ + sc->sc_write_1 = rtwn_usb_write_1; + sc->sc_write_2 = rtwn_usb_write_2; + sc->sc_write_4 = rtwn_usb_write_4; + sc->sc_read_1 = rtwn_usb_read_1; + sc->sc_read_2 = rtwn_usb_read_2; + sc->sc_read_4 = rtwn_usb_read_4; + sc->sc_delay = rtwn_usb_delay; + sc->sc_tx_start = rtwn_usb_tx_start; + sc->sc_start_xfers = rtwn_usb_start_xfers; + sc->sc_reset_lists = rtwn_usb_reset_lists; + sc->sc_abort_xfers = rtwn_usb_abort_xfers; + sc->sc_fw_write_block = rtwn_usb_fw_write_block; + sc->sc_get_qmap = rtwn_usb_get_qmap; + sc->sc_set_desc_addr = rtwn_nop_softc; + sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx; +} + +static int +rtwn_usb_attach(device_t self) +{ + struct usb_attach_arg *uaa = device_get_ivars(self); + struct rtwn_usb_softc *uc = device_get_softc(self); + struct rtwn_softc *sc = &uc->uc_sc; + struct ieee80211com *ic = &sc->sc_ic; + int error; + + device_set_usb_desc(self); + uc->uc_udev = uaa->device; + sc->sc_dev = self; + ic->ic_name = device_get_nameunit(self); + + /* Need to be initialized early. */ + rtwn_sysctlattach(sc); + mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); + + rtwn_usb_attach_methods(sc); + rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa)); + + error = rtwn_usb_setup_endpoints(uc); + if (error != 0) + goto detach; + + /* Allocate Tx/Rx buffers. */ + error = rtwn_usb_alloc_rx_list(sc); + if (error != 0) + goto detach; + + error = rtwn_usb_alloc_tx_list(sc); + if (error != 0) + goto detach; + + /* Generic attach. */ + error = rtwn_attach(sc); + if (error != 0) + goto detach; + + return (0); + +detach: + rtwn_usb_detach(self); /* failure */ + return (ENXIO); +} + +static int +rtwn_usb_detach(device_t self) +{ + struct rtwn_usb_softc *uc = device_get_softc(self); + struct rtwn_softc *sc = &uc->uc_sc; + + /* Generic detach. */ + rtwn_detach(sc); + + /* Free Tx/Rx buffers. */ + rtwn_usb_free_tx_list(sc); + rtwn_usb_free_rx_list(sc); + + /* Detach all USB transfers. */ + usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER); + + rtwn_detach_private(sc); + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +static int +rtwn_usb_suspend(device_t self) +{ + struct rtwn_usb_softc *uc = device_get_softc(self); + + rtwn_suspend(&uc->uc_sc); + + return (0); +} + +static int +rtwn_usb_resume(device_t self) +{ + struct rtwn_usb_softc *uc = device_get_softc(self); + + rtwn_resume(&uc->uc_sc); + + return (0); +} + +static device_method_t rtwn_usb_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rtwn_usb_match), + DEVMETHOD(device_attach, rtwn_usb_attach), + DEVMETHOD(device_detach, rtwn_usb_detach), + DEVMETHOD(device_suspend, rtwn_usb_suspend), + DEVMETHOD(device_resume, rtwn_usb_resume), + + DEVMETHOD_END +}; + +static driver_t rtwn_usb_driver = { + "rtwn", + rtwn_usb_methods, + sizeof(struct rtwn_usb_softc) +}; + +static devclass_t rtwn_usb_devclass; + +DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, rtwn_usb_devclass, NULL, NULL); +MODULE_VERSION(rtwn_usb, 1); +MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1); +MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1); +MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2); +USB_PNP_HOST_INFO(rtwn_devs); diff --git a/sys/dev/rtwn/usb/rtwn_usb_attach.h b/sys/dev/rtwn/usb/rtwn_usb_attach.h new file mode 100644 index 000000000000..6bfed2e43a07 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_attach.h @@ -0,0 +1,159 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> + * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * 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$ + */ + +void r92cu_attach(struct rtwn_usb_softc *); +void r88eu_attach(struct rtwn_usb_softc *); +void r12au_attach(struct rtwn_usb_softc *); +void r21au_attach(struct rtwn_usb_softc *); + +enum { + RTWN_CHIP_RTL8192CU, + RTWN_CHIP_RTL8188EU, + RTWN_CHIP_RTL8812AU, + RTWN_CHIP_RTL8821AU, + RTWN_CHIP_MAX_USB +}; + +/* various supported device vendors/products */ +static const STRUCT_USB_HOST_ID rtwn_devs[] = { + /* RTL8188CE-VAU/RTL8188CUS/RTL8188RU/RTL8192CU */ +#define RTWN_RTL8192CU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8192CU) } + RTWN_RTL8192CU_DEV(ABOCOM, RTL8188CU_1), + RTWN_RTL8192CU_DEV(ABOCOM, RTL8188CU_2), + RTWN_RTL8192CU_DEV(ABOCOM, RTL8192CU), + RTWN_RTL8192CU_DEV(ASUS, RTL8192CU), + RTWN_RTL8192CU_DEV(ASUS, USBN10NANO), + RTWN_RTL8192CU_DEV(AZUREWAVE, RTL8188CE_1), + RTWN_RTL8192CU_DEV(AZUREWAVE, RTL8188CE_2), + RTWN_RTL8192CU_DEV(AZUREWAVE, RTL8188CU), + RTWN_RTL8192CU_DEV(BELKIN, F7D2102), + RTWN_RTL8192CU_DEV(BELKIN, RTL8188CU), + RTWN_RTL8192CU_DEV(BELKIN, RTL8192CU), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_1), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_2), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_3), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_4), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_5), + RTWN_RTL8192CU_DEV(COREGA, RTL8192CU), + RTWN_RTL8192CU_DEV(DLINK, RTL8188CU), + RTWN_RTL8192CU_DEV(DLINK, RTL8192CU_1), + RTWN_RTL8192CU_DEV(DLINK, RTL8192CU_2), + RTWN_RTL8192CU_DEV(DLINK, RTL8192CU_3), + RTWN_RTL8192CU_DEV(DLINK, DWA131B), + RTWN_RTL8192CU_DEV(EDIMAX, EW7811UN), + RTWN_RTL8192CU_DEV(EDIMAX, RTL8192CU), + RTWN_RTL8192CU_DEV(FEIXUN, RTL8188CU), + RTWN_RTL8192CU_DEV(FEIXUN, RTL8192CU), + RTWN_RTL8192CU_DEV(GUILLEMOT, HWNUP150), + RTWN_RTL8192CU_DEV(HAWKING, RTL8192CU), + RTWN_RTL8192CU_DEV(HP3, RTL8188CU), + RTWN_RTL8192CU_DEV(NETGEAR, WNA1000M), + RTWN_RTL8192CU_DEV(NETGEAR, RTL8192CU), + RTWN_RTL8192CU_DEV(NETGEAR4, RTL8188CU), + RTWN_RTL8192CU_DEV(NOVATECH, RTL8188CU), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_1), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_2), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_3), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_4), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CUS), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8192CU), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CE_0), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CE_1), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CTV), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_0), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_1), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_2), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_3), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_COMBO), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CUS), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188RU_1), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188RU_2), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188RU_3), + RTWN_RTL8192CU_DEV(REALTEK, RTL8191CU), + RTWN_RTL8192CU_DEV(REALTEK, RTL8192CE), + RTWN_RTL8192CU_DEV(REALTEK, RTL8192CU), + RTWN_RTL8192CU_DEV(SITECOMEU, RTL8188CU_1), + RTWN_RTL8192CU_DEV(SITECOMEU, RTL8188CU_2), + RTWN_RTL8192CU_DEV(SITECOMEU, RTL8192CU), + RTWN_RTL8192CU_DEV(TRENDNET, RTL8188CU), + RTWN_RTL8192CU_DEV(TRENDNET, RTL8192CU), + RTWN_RTL8192CU_DEV(ZYXEL, RTL8192CU), +#undef RTWN_RTL8192CU_DEV + + /* RTL8188EU */ +#define RTWN_RTL8188EU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8188EU) } + RTWN_RTL8188EU_DEV(ABOCOM, RTL8188EU), + RTWN_RTL8188EU_DEV(DLINK, DWA123D1), + RTWN_RTL8188EU_DEV(DLINK, DWA125D1), + RTWN_RTL8188EU_DEV(ELECOM, WDC150SU2M), + RTWN_RTL8188EU_DEV(REALTEK, RTL8188ETV), + RTWN_RTL8188EU_DEV(REALTEK, RTL8188EU), +#undef RTWN_RTL8188EU_DEV + + /* RTL8812AU */ +#define RTWN_RTL8812AU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8812AU) } + RTWN_RTL8812AU_DEV(ASUS, USBAC56), + RTWN_RTL8812AU_DEV(CISCOLINKSYS, WUSB6300), + RTWN_RTL8812AU_DEV(DLINK, DWA182C1), + RTWN_RTL8812AU_DEV(DLINK, DWA180A1), + RTWN_RTL8812AU_DEV(EDIMAX, EW7822UAC), + RTWN_RTL8812AU_DEV(IODATA, WNAC867U), + RTWN_RTL8812AU_DEV(MELCO, WIU3866D), + RTWN_RTL8812AU_DEV(NEC, WL900U), + RTWN_RTL8812AU_DEV(PLANEX2, GW900D), + RTWN_RTL8812AU_DEV(SENAO, EUB1200AC), + RTWN_RTL8812AU_DEV(SITECOMEU, WLA7100), + RTWN_RTL8812AU_DEV(TPLINK, T4U), + RTWN_RTL8812AU_DEV(TRENDNET, TEW805UB), + RTWN_RTL8812AU_DEV(ZYXEL, NWD6605), +#undef RTWN_RTL8812AU_DEV + + /* RTL8821AU */ +#define RTWN_RTL8821AU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8821AU) } + RTWN_RTL8821AU_DEV(DLINK, DWA171A1), + RTWN_RTL8821AU_DEV(DLINK, DWA172A1), + RTWN_RTL8821AU_DEV(EDIMAX, EW7811UTC_1), + RTWN_RTL8821AU_DEV(EDIMAX, EW7811UTC_2), + RTWN_RTL8821AU_DEV(HAWKING, HD65U), + RTWN_RTL8821AU_DEV(MELCO, WIU2433DM), + RTWN_RTL8821AU_DEV(NETGEAR, A6100) +#undef RTWN_RTL8821AU_DEV +}; + +typedef void (*chip_usb_attach)(struct rtwn_usb_softc *); + +static const chip_usb_attach rtwn_chip_usb_attach[RTWN_CHIP_MAX_USB] = { + [RTWN_CHIP_RTL8192CU] = r92cu_attach, + [RTWN_CHIP_RTL8188EU] = r88eu_attach, + [RTWN_CHIP_RTL8812AU] = r12au_attach, + [RTWN_CHIP_RTL8821AU] = r21au_attach +}; + +static __inline void +rtwn_usb_attach_private(struct rtwn_usb_softc *uc, int chip) +{ + rtwn_chip_usb_attach[chip](uc); +} diff --git a/sys/dev/rtwn/usb/rtwn_usb_ep.c b/sys/dev/rtwn/usb/rtwn_usb_ep.c new file mode 100644 index 000000000000..8694e33dd2d1 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_ep.c @@ -0,0 +1,253 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> + * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include <sys/param.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/taskqueue.h> +#include <sys/bus.h> +#include <sys/endian.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usb_device.h> + +#include <net/if.h> +#include <net/ethernet.h> +#include <net/if_media.h> + +#include <net80211/ieee80211_var.h> + +#include <dev/rtwn/if_rtwnvar.h> +#include <dev/rtwn/if_rtwn_debug.h> + +#include <dev/rtwn/usb/rtwn_usb_var.h> +#include <dev/rtwn/usb/rtwn_usb_ep.h> +#include <dev/rtwn/usb/rtwn_usb_rx.h> +#include <dev/rtwn/usb/rtwn_usb_tx.h> + +#include <dev/rtwn/rtl8192c/usb/r92cu_reg.h> + + +static struct usb_config rtwn_config[RTWN_N_TRANSFER] = { + [RTWN_BULK_RX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .bufsize = RTWN_RXBUFSZ, + .flags = { + .pipe_bof = 1, + .short_xfer_ok = 1 + }, + .callback = rtwn_bulk_rx_callback, + }, + [RTWN_BULK_TX_BE] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1, + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, + [RTWN_BULK_TX_BK] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1, + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, + [RTWN_BULK_TX_VI] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1 + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, + [RTWN_BULK_TX_VO] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1 + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, +}; + +static void +rtwn_usb_setup_queues(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + int hasnq, haslq, nqueues, nqpages, nrempages; + + /* Get Tx queues to USB endpoints mapping. */ + hasnq = haslq = 0; + switch (uc->ntx) { + case 4: + case 3: + haslq = 1; + /* FALLTHROUGH */ + case 2: + hasnq = 1; + /* FALLTHROUGH */ + default: + break; + } + nqueues = 1 + hasnq + haslq; + + /* Get the number of pages for each queue. */ + nqpages = (sc->page_count - sc->npubqpages) / nqueues; + + /* + * The remaining pages are assigned to the high priority + * queue. + */ + nrempages = (sc->page_count - sc->npubqpages) % nqueues; + + sc->nhqpages = nqpages + nrempages; + sc->nnqpages = (hasnq ? nqpages : 0); + sc->nlqpages = (haslq ? nqpages : 0); +} + +int +rtwn_usb_setup_endpoints(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + const uint8_t iface_index = RTWN_IFACE_INDEX; + struct usb_endpoint *ep, *ep_end; + uint8_t addr[RTWN_MAX_EPOUT]; + int error; + + /* Determine the number of bulk-out pipes. */ + uc->ntx = 0; + ep = uc->uc_udev->endpoints; + ep_end = uc->uc_udev->endpoints + uc->uc_udev->endpoints_max; + for (; ep != ep_end; ep++) { + uint8_t eaddr; + + if ((ep->edesc == NULL) || (ep->iface_index != iface_index)) + continue; + + eaddr = ep->edesc->bEndpointAddress; + RTWN_DPRINTF(sc, RTWN_DEBUG_USB, + "%s: endpoint: addr %u, direction %s\n", __func__, + UE_GET_ADDR(eaddr), UE_GET_DIR(eaddr) == UE_DIR_OUT ? + "output" : "input"); + + if (UE_GET_DIR(eaddr) == UE_DIR_OUT) { + if (uc->ntx == RTWN_MAX_EPOUT) + break; + + addr[uc->ntx++] = UE_GET_ADDR(eaddr); + } + } + if (uc->ntx == 0 || uc->ntx > RTWN_MAX_EPOUT) { + device_printf(sc->sc_dev, + "%s: invalid number of Tx bulk pipes (%d)\n", __func__, + uc->ntx); + return (EINVAL); + } + + /* NB: keep in sync with rtwn_dma_init(). */ + rtwn_config[RTWN_BULK_TX_VO].endpoint = addr[0]; + switch (uc->ntx) { + case 4: + case 3: + rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[2]; + rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[2]; + rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[1]; + break; + case 2: + rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[1]; + rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[1]; + rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0]; + break; + case 1: + rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[0]; + rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[0]; + rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0]; + break; + default: + KASSERT(0, ("unhandled number of endpoints %d\n", uc->ntx)); + break; + } + + error = usbd_transfer_setup(uc->uc_udev, &iface_index, + uc->uc_xfer, rtwn_config, RTWN_N_TRANSFER, uc, &sc->sc_mtx); + if (error) { + device_printf(sc->sc_dev, "could not allocate USB transfers, " + "err=%s\n", usbd_errstr(error)); + return (error); + } + + /* Assign pages for each queue (if not done). */ + if (sc->nhqpages == 0 && sc->nnqpages == 0 && sc->nlqpages == 0) + rtwn_usb_setup_queues(uc); + + return (0); +} + +uint16_t +rtwn_usb_get_qmap(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + switch (uc->ntx) { + case 1: + return (R92C_TRXDMA_CTRL_QMAP_HQ); + case 2: + return (R92C_TRXDMA_CTRL_QMAP_HQ_NQ); + default: + return (R92C_TRXDMA_CTRL_QMAP_3EP); + } +} diff --git a/sys/dev/rtwn/usb/rtwn_usb_ep.h b/sys/dev/rtwn/usb/rtwn_usb_ep.h new file mode 100644 index 000000000000..0cdd738e1794 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_ep.h @@ -0,0 +1,25 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * 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 IF_RTWN_EP_H +#define IF_RTWN_EP_H + +int rtwn_usb_setup_endpoints(struct rtwn_usb_softc *); +uint16_t rtwn_usb_get_qmap(struct rtwn_softc *); + +#endif /* IF_RTWN_EP_H */ diff --git a/sys/dev/rtwn/usb/rtwn_usb_reg.c b/sys/dev/rtwn/usb/rtwn_usb_reg.c new file mode 100644 index 000000000000..2091c6ac6444 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_reg.c @@ -0,0 +1,179 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> + * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/taskqueue.h> +#include <sys/bus.h> +#include <sys/endian.h> + +#include <net/if.h> +#include <net/ethernet.h> +#include <net/if_media.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_radiotap.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> + +#include <dev/rtwn/if_rtwnvar.h> +#include <dev/rtwn/if_rtwn_debug.h> + +#include <dev/rtwn/usb/rtwn_usb_var.h> +#include <dev/rtwn/usb/rtwn_usb_reg.h> + +static int rtwn_do_request(struct rtwn_softc *, + struct usb_device_request *, void *); +static int rtwn_usb_read_region_1(struct rtwn_softc *, + uint16_t, uint8_t *, int); + +/* USB Requests. */ +#define R92C_REQ_REGS 0x05 + + +static int +rtwn_do_request(struct rtwn_softc *sc, struct usb_device_request *req, + void *data) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + usb_error_t err; + int ntries = 10; + + RTWN_ASSERT_LOCKED(sc); + + while (ntries--) { + err = usbd_do_request_flags(uc->uc_udev, &sc->sc_mtx, + req, data, 0, NULL, 250 /* ms */); + if (err == USB_ERR_NORMAL_COMPLETION) + return (0); + + RTWN_DPRINTF(sc, RTWN_DEBUG_USB, + "%s: control request failed, %s (retries left: %d)\n", + __func__, usbd_errstr(err), ntries); + if (err == USB_ERR_NOT_CONFIGURED) + return (ENXIO); + + usb_pause_mtx(&sc->sc_mtx, hz / 100); + } + return (EIO); +} + +/* export for rtwn_fw_write_block() */ +int +rtwn_usb_write_region_1(struct rtwn_softc *sc, uint16_t addr, uint8_t *buf, + int len) +{ + usb_device_request_t req; + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = R92C_REQ_REGS; + USETW(req.wValue, addr); + USETW(req.wIndex, 0); + USETW(req.wLength, len); + return (rtwn_do_request(sc, &req, buf)); +} + +int +rtwn_usb_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val) +{ + return (rtwn_usb_write_region_1(sc, addr, &val, sizeof(val))); +} + +int +rtwn_usb_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val) +{ + val = htole16(val); + return (rtwn_usb_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); +} + +int +rtwn_usb_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val) +{ + val = htole32(val); + return (rtwn_usb_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); +} + +static int +rtwn_usb_read_region_1(struct rtwn_softc *sc, uint16_t addr, uint8_t *buf, + int len) +{ + usb_device_request_t req; + + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = R92C_REQ_REGS; + USETW(req.wValue, addr); + USETW(req.wIndex, 0); + USETW(req.wLength, len); + return (rtwn_do_request(sc, &req, buf)); +} + +uint8_t +rtwn_usb_read_1(struct rtwn_softc *sc, uint16_t addr) +{ + uint8_t val; + + if (rtwn_usb_read_region_1(sc, addr, &val, 1) != 0) + return (0xff); + return (val); +} + +uint16_t +rtwn_usb_read_2(struct rtwn_softc *sc, uint16_t addr) +{ + uint16_t val; + + if (rtwn_usb_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0) + return (0xffff); + return (le16toh(val)); +} + +uint32_t +rtwn_usb_read_4(struct rtwn_softc *sc, uint16_t addr) +{ + uint32_t val; + + if (rtwn_usb_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0) + return (0xffffffff); + return (le32toh(val)); +} + +void +rtwn_usb_delay(struct rtwn_softc *sc, int usec) +{ + + /* 1ms delay as default is too big. */ + if (usec < 1000) + DELAY(usec); + else { + usb_pause_mtx(&sc->sc_mtx, + MAX(msecs_to_ticks(usec / 1000), 1)); + } +} diff --git a/sys/dev/rtwn/usb/rtwn_usb_reg.h b/sys/dev/rtwn/usb/rtwn_usb_reg.h new file mode 100644 index 000000000000..1149248d71aa --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_reg.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * 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_USB_REG_H +#define RTWN_USB_REG_H + +static __inline uint16_t +rtwn_usb_calc_tx_checksum(void *buf) +{ + uint16_t sum = 0; + int i; + + /* NB: checksum calculation takes into account only first 32 bytes. */ + for (i = 0; i < 32 / 2; i++) + sum ^= ((uint16_t *)buf)[i]; + + return (sum); /* NB: already little endian. */ +} + +int rtwn_usb_write_region_1(struct rtwn_softc *, uint16_t, + uint8_t *, int); +int rtwn_usb_write_1(struct rtwn_softc *, uint16_t, uint8_t); +int rtwn_usb_write_2(struct rtwn_softc *, uint16_t, uint16_t); +int rtwn_usb_write_4(struct rtwn_softc *, uint16_t, uint32_t); +uint8_t rtwn_usb_read_1(struct rtwn_softc *, uint16_t); +uint16_t rtwn_usb_read_2(struct rtwn_softc *, uint16_t); +uint32_t rtwn_usb_read_4(struct rtwn_softc *, uint16_t); +void rtwn_usb_delay(struct rtwn_softc *, int); + +#endif /* RTWN_USB_REG_H */ diff --git a/sys/dev/rtwn/usb/rtwn_usb_rx.c b/sys/dev/rtwn/usb/rtwn_usb_rx.c new file mode 100644 index 000000000000..edb605e1aaf1 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_rx.c @@ -0,0 +1,335 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> + * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include <sys/param.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/taskqueue.h> +#include <sys/bus.h> +#include <sys/endian.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_radiotap.h> +#ifdef IEEE80211_SUPPORT_SUPERG +#include <net80211/ieee80211_superg.h> +#endif + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> + +#include <dev/rtwn/if_rtwnreg.h> +#include <dev/rtwn/if_rtwnvar.h> + +#include <dev/rtwn/if_rtwn_debug.h> +#include <dev/rtwn/if_rtwn_ridx.h> +#include <dev/rtwn/if_rtwn_rx.h> +#include <dev/rtwn/if_rtwn_task.h> +#include <dev/rtwn/if_rtwn_tx.h> + +#include <dev/rtwn/usb/rtwn_usb_var.h> +#include <dev/rtwn/usb/rtwn_usb_rx.h> + +#include <dev/rtwn/rtl8192c/r92c_reg.h> /* for CAM_ALGO_NONE */ +#include <dev/rtwn/rtl8192c/r92c_rx_desc.h> + + +static struct mbuf * +rtwn_rx_copy_to_mbuf(struct rtwn_softc *sc, struct r92c_rx_stat *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))) { + /* + * 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"); + goto fail; + } + + pktlen = MS(rxdw0, R92C_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 mbuf *m, *m0 = NULL; + uint32_t rxdw0; + int totlen, pktlen, infosz; + + /* Process packets. */ + while (len >= sizeof(*stat)) { + stat = (struct r92c_rx_stat *)buf; + rxdw0 = le32toh(stat->rxdw0); + + pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + if (__predict_false(pktlen == 0)) + break; + + infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; + + /* Make sure everything fits in xfer. */ + totlen = sizeof(*stat) + infosz + pktlen; + if (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))) { + 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(uc, 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, int8_t *rssi) +{ + struct r92c_rx_stat stat; + + /* Imitate PCIe layout. */ + m_copydata(m, 0, sizeof(struct r92c_rx_stat), (caddr_t)&stat); + m_adj(m, sizeof(struct r92c_rx_stat)); + + return (rtwn_rx_common(sc, m, &stat, rssi)); +} + +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; + int8_t nf, rssi; + + 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, &rssi); + + RTWN_UNLOCK(sc); + + nf = RTWN_NOISE_FLOOR; + if (ni != NULL) { + if (ni->ni_flags & IEEE80211_NODE_HT) + m->m_flags |= M_AMPDU; + (void)ieee80211_input(ni, m, rssi - nf, nf); + ieee80211_free_node(ni); + } else { + (void)ieee80211_input_all(ic, m, + rssi - nf, nf); + } + 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: + /* Finished receive; age anything left on the FF queue by a little bump */ + /* + * XXX TODO: just make this a callout timer schedule so we can + * flush the FF staging queue if we're approaching idle. + */ +#ifdef IEEE80211_SUPPORT_SUPERG + if (!(sc->sc_flags & RTWN_FW_LOADED)) + rtwn_cmd_sleepable(uc, NULL, 0, rtwn_ff_flush_all); +#endif + + /* Kick-start more transmit in case we stalled */ + rtwn_start(sc); +} diff --git a/sys/dev/rtwn/usb/rtwn_usb_rx.h b/sys/dev/rtwn/usb/rtwn_usb_rx.h new file mode 100644 index 000000000000..e370816969a7 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_rx.h @@ -0,0 +1,24 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * 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_USB_RX_H +#define RTWN_USB_RX_H + +void rtwn_bulk_rx_callback(struct usb_xfer *, usb_error_t); + +#endif /* RTWN_USB_RX_H */ diff --git a/sys/dev/rtwn/usb/rtwn_usb_tx.c b/sys/dev/rtwn/usb/rtwn_usb_tx.c new file mode 100644 index 000000000000..1580d85d0323 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_tx.c @@ -0,0 +1,282 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> + * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include <sys/param.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/taskqueue.h> +#include <sys/bus.h> +#include <sys/endian.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/ethernet.h> +#include <net/if_media.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_radiotap.h> +#include <net80211/ieee80211_ratectl.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> + +#include <dev/rtwn/if_rtwnreg.h> +#include <dev/rtwn/if_rtwnvar.h> + +#include <dev/rtwn/if_rtwn_beacon.h> +#include <dev/rtwn/if_rtwn_debug.h> +#include <dev/rtwn/if_rtwn_ridx.h> +#include <dev/rtwn/if_rtwn_task.h> +#include <dev/rtwn/if_rtwn_tx.h> + +#include <dev/rtwn/usb/rtwn_usb_var.h> + +#include <dev/rtwn/usb/rtwn_usb_reg.h> +#include <dev/rtwn/usb/rtwn_usb_tx.h> + +static struct rtwn_data * _rtwn_usb_getbuf(struct rtwn_usb_softc *); +static struct rtwn_data * rtwn_usb_getbuf(struct rtwn_usb_softc *); +static void rtwn_usb_txeof(struct rtwn_usb_softc *, + struct rtwn_data *, int); + + +static const uint8_t wme2qid[] = + { RTWN_BULK_TX_BE, RTWN_BULK_TX_BK, + RTWN_BULK_TX_VI, RTWN_BULK_TX_VO }; + + +static struct rtwn_data * +_rtwn_usb_getbuf(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + struct rtwn_data *bf; + + bf = STAILQ_FIRST(&uc->uc_tx_inactive); + if (bf != NULL) + STAILQ_REMOVE_HEAD(&uc->uc_tx_inactive, next); + else { + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: out of xmit buffers\n", __func__); + } + return (bf); +} + +static struct rtwn_data * +rtwn_usb_getbuf(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + struct rtwn_data *bf; + + RTWN_ASSERT_LOCKED(sc); + + bf = _rtwn_usb_getbuf(uc); + if (bf == NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: stop queue\n", + __func__); + } + return (bf); +} + +static void +rtwn_usb_txeof(struct rtwn_usb_softc *uc, struct rtwn_data *data, int status) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + RTWN_ASSERT_LOCKED(sc); + + if (data->ni != NULL) /* not a beacon frame */ + ieee80211_tx_complete(data->ni, data->m, status); + + if (sc->sc_ratectl != RTWN_RATECTL_NET80211) + if (sc->sc_tx_n_active > 0) + sc->sc_tx_n_active--; + + data->ni = NULL; + data->m = NULL; + + STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, data, next); + sc->qfullmsk = 0; +#ifndef D4054 + if (STAILQ_EMPTY(&uc->uc_tx_active) && STAILQ_EMPTY(&uc->uc_tx_pending)) + sc->sc_tx_timer = 0; + else + sc->sc_tx_timer = 5; +#endif +} + +void +rtwn_bulk_tx_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 rtwn_data *data; + + RTWN_ASSERT_LOCKED(sc); + + switch (USB_GET_STATE(xfer)){ + case USB_ST_TRANSFERRED: + data = STAILQ_FIRST(&uc->uc_tx_active); + if (data == NULL) + goto tr_setup; + STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); + rtwn_usb_txeof(uc, data, 0); + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + data = STAILQ_FIRST(&uc->uc_tx_pending); + if (data == NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: empty pending queue\n", __func__); + sc->sc_tx_n_active = 0; + goto finish; + } + STAILQ_REMOVE_HEAD(&uc->uc_tx_pending, next); + STAILQ_INSERT_TAIL(&uc->uc_tx_active, data, next); + + /* + * Note: if this is a beacon frame, ensure that it will go + * into appropriate queue. + */ + if (data->ni == NULL && RTWN_CHIP_HAS_BCNQ1(sc)) + rtwn_switch_bcnq(sc, data->id); + usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); + usbd_transfer_submit(xfer); + if (sc->sc_ratectl != RTWN_RATECTL_NET80211) + sc->sc_tx_n_active++; + break; + default: + data = STAILQ_FIRST(&uc->uc_tx_active); + if (data == NULL) + goto tr_setup; + STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); + rtwn_usb_txeof(uc, data, 1); + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } +finish: +#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 && + sc->sc_tx_n_active <= 1) { + /* XXX ew - net80211 should defer this for us! */ + + /* + * Note: this sc_tx_n_active currently tracks + * the number of pending transmit submissions + * and not the actual depth of the TX frames + * pending to the hardware. That means that + * we're going to end up with some sub-optimal + * aggregation behaviour. + */ + /* + * 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(uc, NULL, 0, rtwn_ff_flush_all); + } +#endif + /* Kick-start more transmit */ + rtwn_start(sc); +} + +static void +rtwn_usb_tx_checksum(struct rtwn_tx_desc_common *txd) +{ + txd->txdw7.usb_checksum = 0; + txd->txdw7.usb_checksum = rtwn_usb_calc_tx_checksum(txd); +} + +int +rtwn_usb_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + struct rtwn_tx_desc_common *txd; + struct rtwn_data *data; + struct usb_xfer *xfer; + uint16_t ac; + + RTWN_ASSERT_LOCKED(sc); + + data = rtwn_usb_getbuf(uc); + if (data == NULL) + return (ENOBUFS); + + ac = M_WME_GETAC(m); + + switch (type) { + case IEEE80211_FC0_TYPE_CTL: + case IEEE80211_FC0_TYPE_MGT: + xfer = uc->uc_xfer[RTWN_BULK_TX_VO]; + break; + default: + xfer = uc->uc_xfer[wme2qid[ac]]; + break; + } + + txd = (struct rtwn_tx_desc_common *)tx_desc; + txd->pktlen = htole16(m->m_pkthdr.len); + txd->offset = sc->txdesc_len; + txd->flags0 |= RTWN_FLAGS0_OWN; + rtwn_usb_tx_checksum(txd); + + /* Dump Tx descriptor. */ + rtwn_dump_tx_desc(sc, tx_desc); + + memcpy(data->buf, tx_desc, sc->txdesc_len); + m_copydata(m, 0, m->m_pkthdr.len, + (caddr_t)(data->buf + sc->txdesc_len)); + + data->buflen = m->m_pkthdr.len + sc->txdesc_len; + data->id = id; + data->ni = ni; + if (data->ni != NULL) { + data->m = m; +#ifndef D4054 + sc->sc_tx_timer = 5; +#endif + } + + STAILQ_INSERT_TAIL(&uc->uc_tx_pending, data, next); + if (STAILQ_EMPTY(&uc->uc_tx_inactive)) + sc->qfullmsk = 1; + + usbd_transfer_start(xfer); + + return (0); +} diff --git a/sys/dev/rtwn/usb/rtwn_usb_tx.h b/sys/dev/rtwn/usb/rtwn_usb_tx.h new file mode 100644 index 000000000000..01527080d515 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_tx.h @@ -0,0 +1,26 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * 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_USB_TX_H +#define RTWN_USB_TX_H + +void rtwn_bulk_tx_callback(struct usb_xfer *, usb_error_t); +int rtwn_usb_tx_start(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, uint8_t *, uint8_t, int); + +#endif /* RTWN_USB_TX_H */ diff --git a/sys/dev/rtwn/usb/rtwn_usb_var.h b/sys/dev/rtwn/usb/rtwn_usb_var.h new file mode 100644 index 000000000000..be7f8f198834 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_var.h @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * + * 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$ + */ + +#ifndef RTWN_USBVAR_H +#define RTWN_USBVAR_H + +#define RTWN_IFACE_INDEX 0 + +#define RTWN_USB_RX_LIST_COUNT 1 +#define RTWN_USB_TX_LIST_COUNT 16 + +struct rtwn_data { + uint8_t *buf; + /* 'id' is meaningful for beacons only */ + int id; + uint16_t buflen; + struct mbuf *m; + struct ieee80211_node *ni; + STAILQ_ENTRY(rtwn_data) next; +}; +typedef STAILQ_HEAD(, rtwn_data) rtwn_datahead; + +enum { + RTWN_BULK_RX, + RTWN_BULK_TX_BE, /* = WME_AC_BE */ + RTWN_BULK_TX_BK, /* = WME_AC_BK */ + RTWN_BULK_TX_VI, /* = WME_AC_VI */ + RTWN_BULK_TX_VO, /* = WME_AC_VO */ + RTWN_N_TRANSFER = 5, +}; + +#define RTWN_EP_QUEUES RTWN_BULK_RX + +struct rtwn_usb_softc { + struct rtwn_softc uc_sc; /* must be the first */ + struct usb_device *uc_udev; + struct usb_xfer *uc_xfer[RTWN_N_TRANSFER]; + + struct rtwn_data uc_rx[RTWN_USB_RX_LIST_COUNT]; + rtwn_datahead uc_rx_active; + rtwn_datahead uc_rx_inactive; + struct rtwn_data uc_tx[RTWN_USB_TX_LIST_COUNT]; + rtwn_datahead uc_tx_active; + rtwn_datahead uc_tx_inactive; + rtwn_datahead uc_tx_pending; + + int (*uc_align_rx)(int, int); + + int ntx; + int tx_agg_desc_num; +}; +#define RTWN_USB_SOFTC(sc) ((struct rtwn_usb_softc *)(sc)) + +#define rtwn_usb_align_rx(_uc, _totlen, _len) \ + (((_uc)->uc_align_rx)((_totlen), (_len))) + +#endif /* RTWN_USBVAR_H */ |