2013-06-08 16:02:31 +00:00
|
|
|
/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */
|
|
|
|
|
|
|
|
/*-
|
|
|
|
* Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
|
2014-04-25 08:01:22 +00:00
|
|
|
* Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
|
2015-12-13 22:08:27 +00:00
|
|
|
* Copyright (c) 2015 Andriy Voskoboinyk <avos@FreeBSD.org>
|
2013-06-08 16:02:31 +00:00
|
|
|
*
|
|
|
|
* 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$");
|
|
|
|
|
|
|
|
/*
|
2014-04-25 08:01:22 +00:00
|
|
|
* Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU.
|
2013-06-08 16:02:31 +00:00
|
|
|
*/
|
|
|
|
|
2015-09-29 05:03:24 +00:00
|
|
|
#include "opt_wlan.h"
|
2016-02-22 00:48:53 +00:00
|
|
|
#include "opt_urtwn.h"
|
2015-09-29 05:03:24 +00:00
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <sys/lock.h>
|
|
|
|
#include <sys/mutex.h>
|
2015-12-06 14:07:57 +00:00
|
|
|
#include <sys/condvar.h>
|
2013-06-08 16:02:31 +00:00
|
|
|
#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/firmware.h>
|
|
|
|
#include <sys/kdb.h>
|
|
|
|
|
|
|
|
#include <machine/bus.h>
|
|
|
|
#include <machine/resource.h>
|
|
|
|
#include <sys/rman.h>
|
|
|
|
|
|
|
|
#include <net/bpf.h>
|
|
|
|
#include <net/if.h>
|
2013-10-26 17:58:36 +00:00
|
|
|
#include <net/if_var.h>
|
2013-06-08 16:02:31 +00:00
|
|
|
#include <net/if_arp.h>
|
|
|
|
#include <net/ethernet.h>
|
|
|
|
#include <net/if_dl.h>
|
|
|
|
#include <net/if_media.h>
|
|
|
|
#include <net/if_types.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/in_var.h>
|
|
|
|
#include <netinet/if_ether.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
|
|
|
|
#include <net80211/ieee80211_var.h>
|
2015-09-22 02:48:59 +00:00
|
|
|
#include <net80211/ieee80211_input.h>
|
2013-06-08 16:02:31 +00:00
|
|
|
#include <net80211/ieee80211_regdomain.h>
|
|
|
|
#include <net80211/ieee80211_radiotap.h>
|
|
|
|
#include <net80211/ieee80211_ratectl.h>
|
2016-04-05 22:14:21 +00:00
|
|
|
#ifdef IEEE80211_SUPPORT_SUPERG
|
|
|
|
#include <net80211/ieee80211_superg.h>
|
|
|
|
#endif
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
#include <dev/usb/usb.h>
|
|
|
|
#include <dev/usb/usbdi.h>
|
2015-12-06 14:07:57 +00:00
|
|
|
#include <dev/usb/usb_device.h>
|
2013-06-08 16:02:31 +00:00
|
|
|
#include "usbdevs.h"
|
|
|
|
|
|
|
|
#include <dev/usb/usb_debug.h>
|
|
|
|
|
2016-03-20 03:54:57 +00:00
|
|
|
#include <dev/urtwn/if_urtwnreg.h>
|
|
|
|
#include <dev/urtwn/if_urtwnvar.h>
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
#ifdef USB_DEBUG
|
2016-01-20 23:27:02 +00:00
|
|
|
enum {
|
|
|
|
URTWN_DEBUG_XMIT = 0x00000001, /* basic xmit operation */
|
|
|
|
URTWN_DEBUG_RECV = 0x00000002, /* basic recv operation */
|
|
|
|
URTWN_DEBUG_STATE = 0x00000004, /* 802.11 state transitions */
|
|
|
|
URTWN_DEBUG_RA = 0x00000008, /* f/w rate adaptation setup */
|
|
|
|
URTWN_DEBUG_USB = 0x00000010, /* usb requests */
|
|
|
|
URTWN_DEBUG_FIRMWARE = 0x00000020, /* firmware(9) loading debug */
|
|
|
|
URTWN_DEBUG_BEACON = 0x00000040, /* beacon handling */
|
|
|
|
URTWN_DEBUG_INTR = 0x00000080, /* ISR */
|
|
|
|
URTWN_DEBUG_TEMP = 0x00000100, /* temperature calibration */
|
|
|
|
URTWN_DEBUG_ROM = 0x00000200, /* various ROM info */
|
|
|
|
URTWN_DEBUG_KEY = 0x00000400, /* crypto keys management */
|
|
|
|
URTWN_DEBUG_TXPWR = 0x00000800, /* dump Tx power values */
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
URTWN_DEBUG_RSSI = 0x00001000, /* dump RSSI lookups */
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DEBUG_ANY = 0xffffffff
|
|
|
|
};
|
|
|
|
|
|
|
|
#define URTWN_DPRINTF(_sc, _m, ...) do { \
|
|
|
|
if ((_sc)->sc_debug & (_m)) \
|
|
|
|
device_printf((_sc)->sc_dev, __VA_ARGS__); \
|
|
|
|
} while(0)
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
#else
|
|
|
|
#define URTWN_DPRINTF(_sc, _m, ...) do { (void) sc; } while (0)
|
2013-06-08 16:02:31 +00:00
|
|
|
#endif
|
|
|
|
|
2015-09-22 02:48:59 +00:00
|
|
|
#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh)
|
2013-06-08 16:02:31 +00:00
|
|
|
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
static int urtwn_enable_11n = 1;
|
|
|
|
TUNABLE_INT("hw.usb.urtwn.enable_11n", &urtwn_enable_11n);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* various supported device vendors/products */
|
2013-06-10 05:45:16 +00:00
|
|
|
static const STRUCT_USB_HOST_ID urtwn_devs[] = {
|
2013-06-08 16:02:31 +00:00
|
|
|
#define URTWN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
|
2014-04-25 08:01:22 +00:00
|
|
|
#define URTWN_RTL8188E_DEV(v,p) \
|
|
|
|
{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTWN_RTL8188E) }
|
|
|
|
#define URTWN_RTL8188E 1
|
2013-06-08 16:02:31 +00:00
|
|
|
URTWN_DEV(ABOCOM, RTL8188CU_1),
|
|
|
|
URTWN_DEV(ABOCOM, RTL8188CU_2),
|
|
|
|
URTWN_DEV(ABOCOM, RTL8192CU),
|
|
|
|
URTWN_DEV(ASUS, RTL8192CU),
|
2014-05-27 01:47:23 +00:00
|
|
|
URTWN_DEV(ASUS, USBN10NANO),
|
2013-06-08 16:02:31 +00:00
|
|
|
URTWN_DEV(AZUREWAVE, RTL8188CE_1),
|
|
|
|
URTWN_DEV(AZUREWAVE, RTL8188CE_2),
|
|
|
|
URTWN_DEV(AZUREWAVE, RTL8188CU),
|
|
|
|
URTWN_DEV(BELKIN, F7D2102),
|
|
|
|
URTWN_DEV(BELKIN, RTL8188CU),
|
|
|
|
URTWN_DEV(BELKIN, RTL8192CU),
|
|
|
|
URTWN_DEV(CHICONY, RTL8188CUS_1),
|
|
|
|
URTWN_DEV(CHICONY, RTL8188CUS_2),
|
|
|
|
URTWN_DEV(CHICONY, RTL8188CUS_3),
|
|
|
|
URTWN_DEV(CHICONY, RTL8188CUS_4),
|
|
|
|
URTWN_DEV(CHICONY, RTL8188CUS_5),
|
|
|
|
URTWN_DEV(COREGA, RTL8192CU),
|
|
|
|
URTWN_DEV(DLINK, RTL8188CU),
|
|
|
|
URTWN_DEV(DLINK, RTL8192CU_1),
|
|
|
|
URTWN_DEV(DLINK, RTL8192CU_2),
|
|
|
|
URTWN_DEV(DLINK, RTL8192CU_3),
|
2013-06-25 06:43:04 +00:00
|
|
|
URTWN_DEV(DLINK, DWA131B),
|
2013-06-08 16:02:31 +00:00
|
|
|
URTWN_DEV(EDIMAX, EW7811UN),
|
|
|
|
URTWN_DEV(EDIMAX, RTL8192CU),
|
|
|
|
URTWN_DEV(FEIXUN, RTL8188CU),
|
|
|
|
URTWN_DEV(FEIXUN, RTL8192CU),
|
|
|
|
URTWN_DEV(GUILLEMOT, HWNUP150),
|
|
|
|
URTWN_DEV(HAWKING, RTL8192CU),
|
|
|
|
URTWN_DEV(HP3, RTL8188CU),
|
|
|
|
URTWN_DEV(NETGEAR, WNA1000M),
|
|
|
|
URTWN_DEV(NETGEAR, RTL8192CU),
|
|
|
|
URTWN_DEV(NETGEAR4, RTL8188CU),
|
|
|
|
URTWN_DEV(NOVATECH, RTL8188CU),
|
|
|
|
URTWN_DEV(PLANEX2, RTL8188CU_1),
|
|
|
|
URTWN_DEV(PLANEX2, RTL8188CU_2),
|
|
|
|
URTWN_DEV(PLANEX2, RTL8188CU_3),
|
|
|
|
URTWN_DEV(PLANEX2, RTL8188CU_4),
|
|
|
|
URTWN_DEV(PLANEX2, RTL8188CUS),
|
|
|
|
URTWN_DEV(PLANEX2, RTL8192CU),
|
|
|
|
URTWN_DEV(REALTEK, RTL8188CE_0),
|
|
|
|
URTWN_DEV(REALTEK, RTL8188CE_1),
|
|
|
|
URTWN_DEV(REALTEK, RTL8188CTV),
|
|
|
|
URTWN_DEV(REALTEK, RTL8188CU_0),
|
|
|
|
URTWN_DEV(REALTEK, RTL8188CU_1),
|
|
|
|
URTWN_DEV(REALTEK, RTL8188CU_2),
|
2015-04-28 03:24:27 +00:00
|
|
|
URTWN_DEV(REALTEK, RTL8188CU_3),
|
2013-06-08 16:02:31 +00:00
|
|
|
URTWN_DEV(REALTEK, RTL8188CU_COMBO),
|
|
|
|
URTWN_DEV(REALTEK, RTL8188CUS),
|
|
|
|
URTWN_DEV(REALTEK, RTL8188RU_1),
|
|
|
|
URTWN_DEV(REALTEK, RTL8188RU_2),
|
2014-10-02 12:27:41 +00:00
|
|
|
URTWN_DEV(REALTEK, RTL8188RU_3),
|
2013-06-08 16:02:31 +00:00
|
|
|
URTWN_DEV(REALTEK, RTL8191CU),
|
|
|
|
URTWN_DEV(REALTEK, RTL8192CE),
|
|
|
|
URTWN_DEV(REALTEK, RTL8192CU),
|
|
|
|
URTWN_DEV(SITECOMEU, RTL8188CU_1),
|
|
|
|
URTWN_DEV(SITECOMEU, RTL8188CU_2),
|
|
|
|
URTWN_DEV(SITECOMEU, RTL8192CU),
|
|
|
|
URTWN_DEV(TRENDNET, RTL8188CU),
|
|
|
|
URTWN_DEV(TRENDNET, RTL8192CU),
|
|
|
|
URTWN_DEV(ZYXEL, RTL8192CU),
|
2014-04-25 08:01:22 +00:00
|
|
|
/* URTWN_RTL8188E */
|
2016-02-23 01:56:58 +00:00
|
|
|
URTWN_RTL8188E_DEV(ABOCOM, RTL8188EU),
|
2014-10-24 15:36:30 +00:00
|
|
|
URTWN_RTL8188E_DEV(DLINK, DWA123D1),
|
2014-08-20 01:26:27 +00:00
|
|
|
URTWN_RTL8188E_DEV(DLINK, DWA125D1),
|
2014-10-24 15:36:30 +00:00
|
|
|
URTWN_RTL8188E_DEV(ELECOM, WDC150SU2M),
|
2014-04-25 08:01:22 +00:00
|
|
|
URTWN_RTL8188E_DEV(REALTEK, RTL8188ETV),
|
|
|
|
URTWN_RTL8188E_DEV(REALTEK, RTL8188EU),
|
|
|
|
#undef URTWN_RTL8188E_DEV
|
2013-06-08 16:02:31 +00:00
|
|
|
#undef URTWN_DEV
|
|
|
|
};
|
|
|
|
|
|
|
|
static device_probe_t urtwn_match;
|
|
|
|
static device_attach_t urtwn_attach;
|
|
|
|
static device_detach_t urtwn_detach;
|
|
|
|
|
|
|
|
static usb_callback_t urtwn_bulk_tx_callback;
|
|
|
|
static usb_callback_t urtwn_bulk_rx_callback;
|
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
static void urtwn_sysctlattach(struct urtwn_softc *);
|
|
|
|
static void urtwn_drain_mbufq(struct urtwn_softc *);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
static usb_error_t urtwn_do_request(struct urtwn_softc *,
|
|
|
|
struct usb_device_request *, void *);
|
2013-06-08 16:02:31 +00:00
|
|
|
static struct ieee80211vap *urtwn_vap_create(struct ieee80211com *,
|
|
|
|
const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
|
|
|
|
const uint8_t [IEEE80211_ADDR_LEN],
|
|
|
|
const uint8_t [IEEE80211_ADDR_LEN]);
|
|
|
|
static void urtwn_vap_delete(struct ieee80211vap *);
|
2015-12-14 13:05:16 +00:00
|
|
|
static struct mbuf * urtwn_rx_copy_to_mbuf(struct urtwn_softc *,
|
|
|
|
struct r92c_rx_stat *, int);
|
|
|
|
static struct mbuf * urtwn_report_intr(struct usb_xfer *,
|
|
|
|
struct urtwn_data *);
|
|
|
|
static struct mbuf * urtwn_rxeof(struct urtwn_softc *, uint8_t *, int);
|
2015-12-13 21:00:21 +00:00
|
|
|
static void urtwn_r88e_ratectl_tx_complete(struct urtwn_softc *,
|
|
|
|
void *);
|
2015-12-14 13:05:16 +00:00
|
|
|
static struct ieee80211_node *urtwn_rx_frame(struct urtwn_softc *,
|
|
|
|
struct mbuf *, int8_t *);
|
2015-10-24 19:59:15 +00:00
|
|
|
static void urtwn_txeof(struct urtwn_softc *, struct urtwn_data *,
|
|
|
|
int);
|
2015-04-04 08:36:02 +00:00
|
|
|
static int urtwn_alloc_list(struct urtwn_softc *,
|
2013-06-08 16:02:31 +00:00
|
|
|
struct urtwn_data[], int, int);
|
|
|
|
static int urtwn_alloc_rx_list(struct urtwn_softc *);
|
|
|
|
static int urtwn_alloc_tx_list(struct urtwn_softc *);
|
|
|
|
static void urtwn_free_list(struct urtwn_softc *,
|
|
|
|
struct urtwn_data data[], int);
|
2015-10-09 14:31:32 +00:00
|
|
|
static void urtwn_free_rx_list(struct urtwn_softc *);
|
|
|
|
static void urtwn_free_tx_list(struct urtwn_softc *);
|
2013-06-08 16:02:31 +00:00
|
|
|
static struct urtwn_data * _urtwn_getbuf(struct urtwn_softc *);
|
|
|
|
static struct urtwn_data * urtwn_getbuf(struct urtwn_softc *);
|
2015-12-03 14:38:55 +00:00
|
|
|
static usb_error_t urtwn_write_region_1(struct urtwn_softc *, uint16_t,
|
2013-06-08 16:02:31 +00:00
|
|
|
uint8_t *, int);
|
2015-12-03 14:38:55 +00:00
|
|
|
static usb_error_t urtwn_write_1(struct urtwn_softc *, uint16_t, uint8_t);
|
|
|
|
static usb_error_t urtwn_write_2(struct urtwn_softc *, uint16_t, uint16_t);
|
|
|
|
static usb_error_t urtwn_write_4(struct urtwn_softc *, uint16_t, uint32_t);
|
|
|
|
static usb_error_t urtwn_read_region_1(struct urtwn_softc *, uint16_t,
|
2013-06-08 16:02:31 +00:00
|
|
|
uint8_t *, int);
|
|
|
|
static uint8_t urtwn_read_1(struct urtwn_softc *, uint16_t);
|
|
|
|
static uint16_t urtwn_read_2(struct urtwn_softc *, uint16_t);
|
|
|
|
static uint32_t urtwn_read_4(struct urtwn_softc *, uint16_t);
|
2015-04-04 08:36:02 +00:00
|
|
|
static int urtwn_fw_cmd(struct urtwn_softc *, uint8_t,
|
2013-06-08 16:02:31 +00:00
|
|
|
const void *, int);
|
2015-12-13 21:50:38 +00:00
|
|
|
static void urtwn_cmdq_cb(void *, int);
|
|
|
|
static int urtwn_cmd_sleepable(struct urtwn_softc *, const void *,
|
|
|
|
size_t, CMD_FUNC_PROTO);
|
2014-04-25 08:01:22 +00:00
|
|
|
static void urtwn_r92c_rf_write(struct urtwn_softc *, int,
|
|
|
|
uint8_t, uint32_t);
|
2015-04-04 08:36:02 +00:00
|
|
|
static void urtwn_r88e_rf_write(struct urtwn_softc *, int,
|
2014-04-25 08:01:22 +00:00
|
|
|
uint8_t, uint32_t);
|
2013-06-08 16:02:31 +00:00
|
|
|
static uint32_t urtwn_rf_read(struct urtwn_softc *, int, uint8_t);
|
2015-04-04 08:36:02 +00:00
|
|
|
static int urtwn_llt_write(struct urtwn_softc *, uint32_t,
|
2013-06-08 16:02:31 +00:00
|
|
|
uint32_t);
|
2015-11-24 19:20:45 +00:00
|
|
|
static int urtwn_efuse_read_next(struct urtwn_softc *, uint8_t *);
|
|
|
|
static int urtwn_efuse_read_data(struct urtwn_softc *, uint8_t *,
|
|
|
|
uint8_t, uint8_t);
|
2016-01-20 23:27:02 +00:00
|
|
|
#ifdef USB_DEBUG
|
2015-11-24 19:20:45 +00:00
|
|
|
static void urtwn_dump_rom_contents(struct urtwn_softc *,
|
|
|
|
uint8_t *, uint16_t);
|
|
|
|
#endif
|
|
|
|
static int urtwn_efuse_read(struct urtwn_softc *, uint8_t *,
|
|
|
|
uint16_t);
|
2015-12-03 14:38:55 +00:00
|
|
|
static int urtwn_efuse_switch_power(struct urtwn_softc *);
|
2013-06-08 16:02:31 +00:00
|
|
|
static int urtwn_read_chipid(struct urtwn_softc *);
|
2015-11-24 19:20:45 +00:00
|
|
|
static int urtwn_read_rom(struct urtwn_softc *);
|
|
|
|
static int urtwn_r88e_read_rom(struct urtwn_softc *);
|
2013-06-08 16:02:31 +00:00
|
|
|
static int urtwn_ra_init(struct urtwn_softc *);
|
2015-11-10 00:12:00 +00:00
|
|
|
static void urtwn_init_beacon(struct urtwn_softc *,
|
|
|
|
struct urtwn_vap *);
|
|
|
|
static int urtwn_setup_beacon(struct urtwn_softc *,
|
|
|
|
struct ieee80211_node *);
|
|
|
|
static void urtwn_update_beacon(struct ieee80211vap *, int);
|
|
|
|
static int urtwn_tx_beacon(struct urtwn_softc *sc,
|
|
|
|
struct urtwn_vap *);
|
2015-12-13 22:00:19 +00:00
|
|
|
static int urtwn_key_alloc(struct ieee80211vap *,
|
|
|
|
struct ieee80211_key *, ieee80211_keyix *,
|
|
|
|
ieee80211_keyix *);
|
|
|
|
static void urtwn_key_set_cb(struct urtwn_softc *,
|
|
|
|
union sec_param *);
|
|
|
|
static void urtwn_key_del_cb(struct urtwn_softc *,
|
|
|
|
union sec_param *);
|
|
|
|
static int urtwn_key_set(struct ieee80211vap *,
|
|
|
|
const struct ieee80211_key *);
|
|
|
|
static int urtwn_key_delete(struct ieee80211vap *,
|
|
|
|
const struct ieee80211_key *);
|
2015-11-10 12:52:26 +00:00
|
|
|
static void urtwn_tsf_task_adhoc(void *, int);
|
2015-11-10 00:12:00 +00:00
|
|
|
static void urtwn_tsf_sync_enable(struct urtwn_softc *,
|
|
|
|
struct ieee80211vap *);
|
2015-12-14 12:36:10 +00:00
|
|
|
static void urtwn_get_tsf(struct urtwn_softc *, uint64_t *);
|
2013-06-08 16:02:31 +00:00
|
|
|
static void urtwn_set_led(struct urtwn_softc *, int, int);
|
2015-10-23 08:26:26 +00:00
|
|
|
static void urtwn_set_mode(struct urtwn_softc *, uint8_t);
|
2015-11-10 12:52:26 +00:00
|
|
|
static void urtwn_ibss_recv_mgmt(struct ieee80211_node *,
|
|
|
|
struct mbuf *, int,
|
|
|
|
const struct ieee80211_rx_stats *, int, int);
|
2015-04-04 08:36:02 +00:00
|
|
|
static int urtwn_newstate(struct ieee80211vap *,
|
2013-06-08 16:02:31 +00:00
|
|
|
enum ieee80211_state, int);
|
2016-01-20 23:55:39 +00:00
|
|
|
static void urtwn_calib_to(void *);
|
|
|
|
static void urtwn_calib_cb(struct urtwn_softc *,
|
|
|
|
union sec_param *);
|
2013-06-08 16:02:31 +00:00
|
|
|
static void urtwn_watchdog(void *);
|
|
|
|
static void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t);
|
|
|
|
static int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *);
|
2014-04-25 08:01:22 +00:00
|
|
|
static int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *);
|
2015-11-09 23:46:13 +00:00
|
|
|
static int urtwn_tx_data(struct urtwn_softc *,
|
2013-06-08 16:02:31 +00:00
|
|
|
struct ieee80211_node *, struct mbuf *,
|
|
|
|
struct urtwn_data *);
|
2015-12-14 20:39:38 +00:00
|
|
|
static int urtwn_tx_raw(struct urtwn_softc *,
|
|
|
|
struct ieee80211_node *, struct mbuf *,
|
|
|
|
struct urtwn_data *,
|
|
|
|
const struct ieee80211_bpf_params *);
|
2015-11-09 23:46:13 +00:00
|
|
|
static void urtwn_tx_start(struct urtwn_softc *, struct mbuf *,
|
|
|
|
uint8_t, struct urtwn_data *);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
static int urtwn_transmit(struct ieee80211com *, struct mbuf *);
|
|
|
|
static void urtwn_start(struct urtwn_softc *);
|
|
|
|
static void urtwn_parent(struct ieee80211com *);
|
2014-04-25 08:01:22 +00:00
|
|
|
static int urtwn_r92c_power_on(struct urtwn_softc *);
|
|
|
|
static int urtwn_r88e_power_on(struct urtwn_softc *);
|
2016-02-22 01:15:02 +00:00
|
|
|
static void urtwn_r92c_power_off(struct urtwn_softc *);
|
|
|
|
static void urtwn_r88e_power_off(struct urtwn_softc *);
|
2013-06-08 16:02:31 +00:00
|
|
|
static int urtwn_llt_init(struct urtwn_softc *);
|
2016-02-22 00:48:53 +00:00
|
|
|
#ifndef URTWN_WITHOUT_UCODE
|
2013-06-08 16:02:31 +00:00
|
|
|
static void urtwn_fw_reset(struct urtwn_softc *);
|
2014-04-25 08:01:22 +00:00
|
|
|
static void urtwn_r88e_fw_reset(struct urtwn_softc *);
|
2015-04-04 08:36:02 +00:00
|
|
|
static int urtwn_fw_loadpage(struct urtwn_softc *, int,
|
2013-06-08 16:02:31 +00:00
|
|
|
const uint8_t *, int);
|
|
|
|
static int urtwn_load_firmware(struct urtwn_softc *);
|
2016-02-22 00:48:53 +00:00
|
|
|
#endif
|
2015-12-06 14:07:57 +00:00
|
|
|
static int urtwn_dma_init(struct urtwn_softc *);
|
2015-12-03 14:38:55 +00:00
|
|
|
static int urtwn_mac_init(struct urtwn_softc *);
|
2013-06-08 16:02:31 +00:00
|
|
|
static void urtwn_bb_init(struct urtwn_softc *);
|
|
|
|
static void urtwn_rf_init(struct urtwn_softc *);
|
|
|
|
static void urtwn_cam_init(struct urtwn_softc *);
|
2015-12-13 22:00:19 +00:00
|
|
|
static int urtwn_cam_write(struct urtwn_softc *, uint32_t,
|
|
|
|
uint32_t);
|
2013-06-08 16:02:31 +00:00
|
|
|
static void urtwn_pa_bias_init(struct urtwn_softc *);
|
|
|
|
static void urtwn_rxfilter_init(struct urtwn_softc *);
|
|
|
|
static void urtwn_edca_init(struct urtwn_softc *);
|
2015-04-04 08:36:02 +00:00
|
|
|
static void urtwn_write_txpower(struct urtwn_softc *, int,
|
2013-06-08 16:02:31 +00:00
|
|
|
uint16_t[]);
|
|
|
|
static void urtwn_get_txpower(struct urtwn_softc *, int,
|
2015-04-04 08:36:02 +00:00
|
|
|
struct ieee80211_channel *,
|
2013-06-08 16:02:31 +00:00
|
|
|
struct ieee80211_channel *, uint16_t[]);
|
2014-04-25 08:01:22 +00:00
|
|
|
static void urtwn_r88e_get_txpower(struct urtwn_softc *, int,
|
2015-04-04 08:36:02 +00:00
|
|
|
struct ieee80211_channel *,
|
2014-04-25 08:01:22 +00:00
|
|
|
struct ieee80211_channel *, uint16_t[]);
|
2013-06-08 16:02:31 +00:00
|
|
|
static void urtwn_set_txpower(struct urtwn_softc *,
|
2015-04-04 08:36:02 +00:00
|
|
|
struct ieee80211_channel *,
|
2013-06-08 16:02:31 +00:00
|
|
|
struct ieee80211_channel *);
|
2015-10-27 14:21:24 +00:00
|
|
|
static void urtwn_set_rx_bssid_all(struct urtwn_softc *, int);
|
|
|
|
static void urtwn_set_gain(struct urtwn_softc *, uint8_t);
|
2013-06-08 16:02:31 +00:00
|
|
|
static void urtwn_scan_start(struct ieee80211com *);
|
|
|
|
static void urtwn_scan_end(struct ieee80211com *);
|
|
|
|
static void urtwn_set_channel(struct ieee80211com *);
|
2015-12-09 09:29:38 +00:00
|
|
|
static int urtwn_wme_update(struct ieee80211com *);
|
2016-01-20 23:01:33 +00:00
|
|
|
static void urtwn_update_slot(struct ieee80211com *);
|
|
|
|
static void urtwn_update_slot_cb(struct urtwn_softc *,
|
|
|
|
union sec_param *);
|
|
|
|
static void urtwn_update_aifs(struct urtwn_softc *, uint8_t);
|
2015-11-08 23:21:54 +00:00
|
|
|
static void urtwn_set_promisc(struct urtwn_softc *);
|
|
|
|
static void urtwn_update_promisc(struct ieee80211com *);
|
2015-10-09 14:31:32 +00:00
|
|
|
static void urtwn_update_mcast(struct ieee80211com *);
|
2016-04-13 05:19:16 +00:00
|
|
|
static struct ieee80211_node *urtwn_node_alloc(struct ieee80211vap *,
|
2015-12-13 21:00:21 +00:00
|
|
|
const uint8_t mac[IEEE80211_ADDR_LEN]);
|
2016-04-13 05:19:16 +00:00
|
|
|
static void urtwn_newassoc(struct ieee80211_node *, int);
|
|
|
|
static void urtwn_node_free(struct ieee80211_node *);
|
2013-06-08 16:02:31 +00:00
|
|
|
static void urtwn_set_chan(struct urtwn_softc *,
|
2015-04-04 08:36:02 +00:00
|
|
|
struct ieee80211_channel *,
|
2013-06-08 16:02:31 +00:00
|
|
|
struct ieee80211_channel *);
|
|
|
|
static void urtwn_iq_calib(struct urtwn_softc *);
|
|
|
|
static void urtwn_lc_calib(struct urtwn_softc *);
|
2016-01-20 23:55:39 +00:00
|
|
|
static void urtwn_temp_calib(struct urtwn_softc *);
|
2015-12-03 14:38:55 +00:00
|
|
|
static int urtwn_init(struct urtwn_softc *);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
static void urtwn_stop(struct urtwn_softc *);
|
2013-06-08 16:02:31 +00:00
|
|
|
static void urtwn_abort_xfers(struct urtwn_softc *);
|
|
|
|
static int urtwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
|
|
|
|
const struct ieee80211_bpf_params *);
|
2014-05-20 15:53:17 +00:00
|
|
|
static void urtwn_ms_delay(struct urtwn_softc *);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Aliases. */
|
|
|
|
#define urtwn_bb_write urtwn_write_4
|
|
|
|
#define urtwn_bb_read urtwn_read_4
|
|
|
|
|
|
|
|
static const struct usb_config urtwn_config[URTWN_N_TRANSFER] = {
|
|
|
|
[URTWN_BULK_RX] = {
|
|
|
|
.type = UE_BULK,
|
|
|
|
.endpoint = UE_ADDR_ANY,
|
|
|
|
.direction = UE_DIR_IN,
|
|
|
|
.bufsize = URTWN_RXBUFSZ,
|
|
|
|
.flags = {
|
|
|
|
.pipe_bof = 1,
|
|
|
|
.short_xfer_ok = 1
|
|
|
|
},
|
|
|
|
.callback = urtwn_bulk_rx_callback,
|
|
|
|
},
|
|
|
|
[URTWN_BULK_TX_BE] = {
|
|
|
|
.type = UE_BULK,
|
|
|
|
.endpoint = 0x03,
|
|
|
|
.direction = UE_DIR_OUT,
|
|
|
|
.bufsize = URTWN_TXBUFSZ,
|
|
|
|
.flags = {
|
|
|
|
.ext_buffer = 1,
|
|
|
|
.pipe_bof = 1,
|
|
|
|
.force_short_xfer = 1
|
|
|
|
},
|
|
|
|
.callback = urtwn_bulk_tx_callback,
|
|
|
|
.timeout = URTWN_TX_TIMEOUT, /* ms */
|
|
|
|
},
|
|
|
|
[URTWN_BULK_TX_BK] = {
|
|
|
|
.type = UE_BULK,
|
|
|
|
.endpoint = 0x03,
|
|
|
|
.direction = UE_DIR_OUT,
|
|
|
|
.bufsize = URTWN_TXBUFSZ,
|
|
|
|
.flags = {
|
|
|
|
.ext_buffer = 1,
|
|
|
|
.pipe_bof = 1,
|
|
|
|
.force_short_xfer = 1,
|
|
|
|
},
|
|
|
|
.callback = urtwn_bulk_tx_callback,
|
|
|
|
.timeout = URTWN_TX_TIMEOUT, /* ms */
|
|
|
|
},
|
|
|
|
[URTWN_BULK_TX_VI] = {
|
|
|
|
.type = UE_BULK,
|
|
|
|
.endpoint = 0x02,
|
|
|
|
.direction = UE_DIR_OUT,
|
|
|
|
.bufsize = URTWN_TXBUFSZ,
|
|
|
|
.flags = {
|
|
|
|
.ext_buffer = 1,
|
|
|
|
.pipe_bof = 1,
|
|
|
|
.force_short_xfer = 1
|
|
|
|
},
|
|
|
|
.callback = urtwn_bulk_tx_callback,
|
|
|
|
.timeout = URTWN_TX_TIMEOUT, /* ms */
|
|
|
|
},
|
|
|
|
[URTWN_BULK_TX_VO] = {
|
|
|
|
.type = UE_BULK,
|
|
|
|
.endpoint = 0x02,
|
|
|
|
.direction = UE_DIR_OUT,
|
|
|
|
.bufsize = URTWN_TXBUFSZ,
|
|
|
|
.flags = {
|
|
|
|
.ext_buffer = 1,
|
|
|
|
.pipe_bof = 1,
|
|
|
|
.force_short_xfer = 1
|
|
|
|
},
|
|
|
|
.callback = urtwn_bulk_tx_callback,
|
|
|
|
.timeout = URTWN_TX_TIMEOUT, /* ms */
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2015-12-09 09:29:38 +00:00
|
|
|
static const struct wme_to_queue {
|
|
|
|
uint16_t reg;
|
|
|
|
uint8_t qid;
|
|
|
|
} wme2queue[WME_NUM_AC] = {
|
|
|
|
{ R92C_EDCA_BE_PARAM, URTWN_BULK_TX_BE},
|
|
|
|
{ R92C_EDCA_BK_PARAM, URTWN_BULK_TX_BK},
|
|
|
|
{ R92C_EDCA_VI_PARAM, URTWN_BULK_TX_VI},
|
|
|
|
{ R92C_EDCA_VO_PARAM, URTWN_BULK_TX_VO}
|
|
|
|
};
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static int
|
|
|
|
urtwn_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 != URTWN_CONFIG_INDEX)
|
|
|
|
return (ENXIO);
|
|
|
|
if (uaa->info.bIfaceIndex != URTWN_IFACE_INDEX)
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
return (usbd_lookup_id_by_uaa(urtwn_devs, sizeof(urtwn_devs), uaa));
|
|
|
|
}
|
|
|
|
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
static void
|
|
|
|
urtwn_update_chw(struct ieee80211com *ic)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* We're driving this ourselves (eventually); don't involve net80211 */
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static int
|
|
|
|
urtwn_attach(device_t self)
|
|
|
|
{
|
|
|
|
struct usb_attach_arg *uaa = device_get_ivars(self);
|
|
|
|
struct urtwn_softc *sc = device_get_softc(self);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2016-01-07 18:41:03 +00:00
|
|
|
uint8_t bands[howmany(IEEE80211_MODE_MAX, 8)];
|
2013-06-08 16:02:31 +00:00
|
|
|
int error;
|
|
|
|
|
|
|
|
device_set_usb_desc(self);
|
|
|
|
sc->sc_udev = uaa->device;
|
|
|
|
sc->sc_dev = self;
|
2014-04-25 08:01:22 +00:00
|
|
|
if (USB_GET_DRIVER_INFO(uaa) == URTWN_RTL8188E)
|
|
|
|
sc->chip |= URTWN_CHIP_88E;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
#ifdef USB_DEBUG
|
|
|
|
int debug;
|
|
|
|
if (resource_int_value(device_get_name(sc->sc_dev),
|
|
|
|
device_get_unit(sc->sc_dev), "debug", &debug) == 0)
|
|
|
|
sc->sc_debug = debug;
|
|
|
|
#endif
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
mtx_init(&sc->sc_mtx, device_get_nameunit(self),
|
|
|
|
MTX_NETWORK_LOCK, MTX_DEF);
|
2015-12-13 21:50:38 +00:00
|
|
|
URTWN_CMDQ_LOCK_INIT(sc);
|
2015-12-13 21:00:21 +00:00
|
|
|
URTWN_NT_LOCK_INIT(sc);
|
2016-01-20 23:55:39 +00:00
|
|
|
callout_init(&sc->sc_calib_to, 0);
|
2013-06-08 16:02:31 +00:00
|
|
|
callout_init(&sc->sc_watchdog_ch, 0);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
mbufq_init(&sc->sc_snd, ifqmaxlen);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-12-06 14:07:57 +00:00
|
|
|
sc->sc_iface_index = URTWN_IFACE_INDEX;
|
|
|
|
error = usbd_transfer_setup(uaa->device, &sc->sc_iface_index,
|
|
|
|
sc->sc_xfer, urtwn_config, URTWN_N_TRANSFER, sc, &sc->sc_mtx);
|
2013-06-08 16:02:31 +00:00
|
|
|
if (error) {
|
|
|
|
device_printf(self, "could not allocate USB transfers, "
|
|
|
|
"err=%s\n", usbd_errstr(error));
|
|
|
|
goto detach;
|
|
|
|
}
|
|
|
|
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
|
|
|
|
error = urtwn_read_chipid(sc);
|
|
|
|
if (error) {
|
|
|
|
device_printf(sc->sc_dev, "unsupported test chip\n");
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
goto detach;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine number of Tx/Rx chains. */
|
|
|
|
if (sc->chip & URTWN_CHIP_92C) {
|
|
|
|
sc->ntxchains = (sc->chip & URTWN_CHIP_92C_1T2R) ? 1 : 2;
|
|
|
|
sc->nrxchains = 2;
|
|
|
|
} else {
|
|
|
|
sc->ntxchains = 1;
|
|
|
|
sc->nrxchains = 1;
|
|
|
|
}
|
2014-04-25 08:01:22 +00:00
|
|
|
|
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
2015-11-24 19:20:45 +00:00
|
|
|
error = urtwn_r88e_read_rom(sc);
|
2014-04-25 08:01:22 +00:00
|
|
|
else
|
2015-11-24 19:20:45 +00:00
|
|
|
error = urtwn_read_rom(sc);
|
|
|
|
if (error != 0) {
|
|
|
|
device_printf(sc->sc_dev, "%s: cannot read rom, error %d\n",
|
|
|
|
__func__, error);
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
goto detach;
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
device_printf(sc->sc_dev, "MAC/BB RTL%s, RF 6052 %dT%dR\n",
|
|
|
|
(sc->chip & URTWN_CHIP_92C) ? "8192CU" :
|
2014-04-25 08:01:22 +00:00
|
|
|
(sc->chip & URTWN_CHIP_88E) ? "8188EU" :
|
2013-06-08 16:02:31 +00:00
|
|
|
(sc->board_type == R92C_BOARD_TYPE_HIGHPA) ? "8188RU" :
|
|
|
|
(sc->board_type == R92C_BOARD_TYPE_MINICARD) ? "8188CE-VAU" :
|
|
|
|
"8188CUS", sc->ntxchains, sc->nrxchains);
|
|
|
|
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
|
2015-05-25 18:50:26 +00:00
|
|
|
ic->ic_softc = sc;
|
2015-05-25 13:51:13 +00:00
|
|
|
ic->ic_name = device_get_nameunit(self);
|
2013-06-08 16:02:31 +00:00
|
|
|
ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
|
|
|
|
ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
|
|
|
|
|
|
|
|
/* set device capabilities */
|
|
|
|
ic->ic_caps =
|
|
|
|
IEEE80211_C_STA /* station mode */
|
|
|
|
| IEEE80211_C_MONITOR /* monitor mode */
|
2015-11-10 12:52:26 +00:00
|
|
|
| IEEE80211_C_IBSS /* adhoc mode */
|
2015-11-10 00:12:00 +00:00
|
|
|
| IEEE80211_C_HOSTAP /* hostap mode */
|
2013-06-08 16:02:31 +00:00
|
|
|
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
|
|
|
|
| IEEE80211_C_SHSLOT /* short slot time supported */
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
#if 0
|
2013-06-08 16:02:31 +00:00
|
|
|
| IEEE80211_C_BGSCAN /* capable of bg scanning */
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
#endif
|
2013-06-08 16:02:31 +00:00
|
|
|
| IEEE80211_C_WPA /* 802.11i */
|
2015-12-09 09:29:38 +00:00
|
|
|
| IEEE80211_C_WME /* 802.11e */
|
2016-04-05 22:14:21 +00:00
|
|
|
| IEEE80211_C_SWAMSDUTX /* Do software A-MSDU TX */
|
|
|
|
| IEEE80211_C_FF /* Atheros fast-frames */
|
2013-06-08 16:02:31 +00:00
|
|
|
;
|
|
|
|
|
2015-12-13 22:00:19 +00:00
|
|
|
ic->ic_cryptocaps =
|
|
|
|
IEEE80211_CRYPTO_WEP |
|
|
|
|
IEEE80211_CRYPTO_TKIP |
|
|
|
|
IEEE80211_CRYPTO_AES_CCM;
|
|
|
|
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
/* Assume they're all 11n capable for now */
|
|
|
|
if (urtwn_enable_11n) {
|
|
|
|
device_printf(self, "enabling 11n\n");
|
|
|
|
ic->ic_htcaps = IEEE80211_HTC_HT |
|
2016-04-06 00:52:30 +00:00
|
|
|
#if 0
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
IEEE80211_HTC_AMPDU |
|
2016-04-06 00:52:30 +00:00
|
|
|
#endif
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
IEEE80211_HTC_AMSDU |
|
|
|
|
IEEE80211_HTCAP_MAXAMSDU_3839 |
|
|
|
|
IEEE80211_HTCAP_SMPS_OFF;
|
|
|
|
/* no HT40 just yet */
|
|
|
|
// ic->ic_htcaps |= IEEE80211_HTCAP_CHWIDTH40;
|
|
|
|
|
|
|
|
/* XXX TODO: verify chains versus streams for urtwn */
|
|
|
|
ic->ic_txstream = sc->ntxchains;
|
|
|
|
ic->ic_rxstream = sc->nrxchains;
|
|
|
|
}
|
|
|
|
|
2016-01-07 18:41:03 +00:00
|
|
|
memset(bands, 0, sizeof(bands));
|
|
|
|
setbit(bands, IEEE80211_MODE_11B);
|
|
|
|
setbit(bands, IEEE80211_MODE_11G);
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
if (urtwn_enable_11n)
|
|
|
|
setbit(bands, IEEE80211_MODE_11NG);
|
2016-01-07 18:41:03 +00:00
|
|
|
ieee80211_init_channels(ic, NULL, bands);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
ieee80211_ifattach(ic);
|
2013-06-08 16:02:31 +00:00
|
|
|
ic->ic_raw_xmit = urtwn_raw_xmit;
|
|
|
|
ic->ic_scan_start = urtwn_scan_start;
|
|
|
|
ic->ic_scan_end = urtwn_scan_end;
|
|
|
|
ic->ic_set_channel = urtwn_set_channel;
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
ic->ic_transmit = urtwn_transmit;
|
|
|
|
ic->ic_parent = urtwn_parent;
|
2013-06-08 16:02:31 +00:00
|
|
|
ic->ic_vap_create = urtwn_vap_create;
|
|
|
|
ic->ic_vap_delete = urtwn_vap_delete;
|
2015-12-09 09:29:38 +00:00
|
|
|
ic->ic_wme.wme_update = urtwn_wme_update;
|
2016-01-20 23:01:33 +00:00
|
|
|
ic->ic_updateslot = urtwn_update_slot;
|
2015-11-08 23:21:54 +00:00
|
|
|
ic->ic_update_promisc = urtwn_update_promisc;
|
2013-06-08 16:02:31 +00:00
|
|
|
ic->ic_update_mcast = urtwn_update_mcast;
|
2015-12-13 21:00:21 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
2016-04-13 05:19:16 +00:00
|
|
|
ic->ic_node_alloc = urtwn_node_alloc;
|
|
|
|
ic->ic_newassoc = urtwn_newassoc;
|
2015-12-13 21:00:21 +00:00
|
|
|
sc->sc_node_free = ic->ic_node_free;
|
2016-04-13 05:19:16 +00:00
|
|
|
ic->ic_node_free = urtwn_node_free;
|
2015-12-13 21:00:21 +00:00
|
|
|
}
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
ic->ic_update_chw = urtwn_update_chw;
|
|
|
|
ic->ic_ampdu_enable = urtwn_ampdu_enable;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-04-04 08:36:02 +00:00
|
|
|
ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr,
|
2013-06-08 16:02:31 +00:00
|
|
|
sizeof(sc->sc_txtap), URTWN_TX_RADIOTAP_PRESENT,
|
|
|
|
&sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
|
|
|
|
URTWN_RX_RADIOTAP_PRESENT);
|
|
|
|
|
2015-12-13 21:50:38 +00:00
|
|
|
TASK_INIT(&sc->cmdq_task, 0, urtwn_cmdq_cb, sc);
|
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
urtwn_sysctlattach(sc);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
if (bootverbose)
|
|
|
|
ieee80211_announce(ic);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
detach:
|
|
|
|
urtwn_detach(self);
|
|
|
|
return (ENXIO); /* failure */
|
|
|
|
}
|
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
static void
|
|
|
|
urtwn_sysctlattach(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
#ifdef USB_DEBUG
|
|
|
|
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
|
|
|
|
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
|
|
|
|
|
|
|
|
SYSCTL_ADD_U32(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
|
|
|
|
"debug", CTLFLAG_RW, &sc->sc_debug, sc->sc_debug,
|
|
|
|
"control debugging printfs");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static int
|
|
|
|
urtwn_detach(device_t self)
|
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = device_get_softc(self);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2014-03-14 06:37:08 +00:00
|
|
|
unsigned int x;
|
2015-04-04 08:36:02 +00:00
|
|
|
|
2014-03-14 06:37:08 +00:00
|
|
|
/* Prevent further ioctls. */
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
sc->sc_flags |= URTWN_DETACHED;
|
|
|
|
URTWN_UNLOCK(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
urtwn_stop(sc);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
callout_drain(&sc->sc_watchdog_ch);
|
2016-01-20 23:55:39 +00:00
|
|
|
callout_drain(&sc->sc_calib_to);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-09-29 05:03:24 +00:00
|
|
|
/* stop all USB transfers */
|
|
|
|
usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER);
|
|
|
|
|
2014-03-14 06:37:08 +00:00
|
|
|
/* Prevent further allocations from RX/TX data lists. */
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
STAILQ_INIT(&sc->sc_tx_active);
|
|
|
|
STAILQ_INIT(&sc->sc_tx_inactive);
|
|
|
|
STAILQ_INIT(&sc->sc_tx_pending);
|
|
|
|
|
|
|
|
STAILQ_INIT(&sc->sc_rx_active);
|
|
|
|
STAILQ_INIT(&sc->sc_rx_inactive);
|
|
|
|
URTWN_UNLOCK(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2014-03-14 06:37:08 +00:00
|
|
|
/* drain USB transfers */
|
|
|
|
for (x = 0; x != URTWN_N_TRANSFER; x++)
|
|
|
|
usbd_transfer_drain(sc->sc_xfer[x]);
|
|
|
|
|
|
|
|
/* Free data buffers. */
|
|
|
|
URTWN_LOCK(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_free_tx_list(sc);
|
|
|
|
urtwn_free_rx_list(sc);
|
2014-03-14 06:37:08 +00:00
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
|
2015-12-13 21:50:38 +00:00
|
|
|
if (ic->ic_softc == sc) {
|
|
|
|
ieee80211_draintask(ic, &sc->cmdq_task);
|
|
|
|
ieee80211_ifdetach(ic);
|
|
|
|
}
|
|
|
|
|
2015-12-13 21:00:21 +00:00
|
|
|
URTWN_NT_LOCK_DESTROY(sc);
|
2015-12-13 21:50:38 +00:00
|
|
|
URTWN_CMDQ_LOCK_DESTROY(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
mtx_destroy(&sc->sc_mtx);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-10-09 14:31:32 +00:00
|
|
|
urtwn_drain_mbufq(struct urtwn_softc *sc)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
2015-10-09 14:31:32 +00:00
|
|
|
struct mbuf *m;
|
|
|
|
struct ieee80211_node *ni;
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
|
|
|
|
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
|
|
|
|
m->m_pkthdr.rcvif = NULL;
|
|
|
|
ieee80211_free_node(ni);
|
|
|
|
m_freem(m);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static usb_error_t
|
|
|
|
urtwn_do_request(struct urtwn_softc *sc, struct usb_device_request *req,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
usb_error_t err;
|
|
|
|
int ntries = 10;
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
|
|
|
while (ntries--) {
|
|
|
|
err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
|
|
|
|
req, data, 0, NULL, 250 /* ms */);
|
|
|
|
if (err == 0)
|
|
|
|
break;
|
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_USB,
|
|
|
|
"%s: control request failed, %s (retries left: %d)\n",
|
|
|
|
__func__, usbd_errstr(err), ntries);
|
2013-06-08 16:02:31 +00:00
|
|
|
usb_pause_mtx(&sc->sc_mtx, hz / 100);
|
|
|
|
}
|
|
|
|
return (err);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ieee80211vap *
|
|
|
|
urtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
|
|
|
|
enum ieee80211_opmode opmode, int flags,
|
|
|
|
const uint8_t bssid[IEEE80211_ADDR_LEN],
|
|
|
|
const uint8_t mac[IEEE80211_ADDR_LEN])
|
|
|
|
{
|
2015-11-10 00:12:00 +00:00
|
|
|
struct urtwn_softc *sc = ic->ic_softc;
|
2013-06-08 16:02:31 +00:00
|
|
|
struct urtwn_vap *uvp;
|
|
|
|
struct ieee80211vap *vap;
|
|
|
|
|
|
|
|
if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */
|
|
|
|
return (NULL);
|
|
|
|
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
uvp = malloc(sizeof(struct urtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO);
|
2013-06-08 16:02:31 +00:00
|
|
|
vap = &uvp->vap;
|
|
|
|
/* enable s/w bmiss handling for sta mode */
|
2013-11-06 12:57:01 +00:00
|
|
|
|
2015-04-04 08:36:02 +00:00
|
|
|
if (ieee80211_vap_setup(ic, vap, name, unit, opmode,
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) {
|
2013-11-06 12:57:01 +00:00
|
|
|
/* out of memory */
|
|
|
|
free(uvp, M_80211_VAP);
|
|
|
|
return (NULL);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-11-10 12:52:26 +00:00
|
|
|
if (opmode == IEEE80211_M_HOSTAP || opmode == IEEE80211_M_IBSS)
|
2015-11-10 00:12:00 +00:00
|
|
|
urtwn_init_beacon(sc, uvp);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* override state transition machine */
|
|
|
|
uvp->newstate = vap->iv_newstate;
|
|
|
|
vap->iv_newstate = urtwn_newstate;
|
2015-11-10 00:12:00 +00:00
|
|
|
vap->iv_update_beacon = urtwn_update_beacon;
|
2015-12-13 22:00:19 +00:00
|
|
|
vap->iv_key_alloc = urtwn_key_alloc;
|
|
|
|
vap->iv_key_set = urtwn_key_set;
|
|
|
|
vap->iv_key_delete = urtwn_key_delete;
|
2016-04-17 02:39:58 +00:00
|
|
|
|
|
|
|
/* 802.11n parameters */
|
|
|
|
vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_16;
|
2016-04-18 00:28:25 +00:00
|
|
|
vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K;
|
2016-04-17 02:39:58 +00:00
|
|
|
|
2015-11-10 12:52:26 +00:00
|
|
|
if (opmode == IEEE80211_M_IBSS) {
|
|
|
|
uvp->recv_mgmt = vap->iv_recv_mgmt;
|
|
|
|
vap->iv_recv_mgmt = urtwn_ibss_recv_mgmt;
|
|
|
|
TASK_INIT(&uvp->tsf_task_adhoc, 0, urtwn_tsf_task_adhoc, vap);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-12-13 21:00:21 +00:00
|
|
|
if (URTWN_CHIP_HAS_RATECTL(sc))
|
|
|
|
ieee80211_ratectl_init(vap);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* complete setup */
|
|
|
|
ieee80211_vap_attach(vap, ieee80211_media_change,
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
ieee80211_media_status, mac);
|
2013-06-08 16:02:31 +00:00
|
|
|
ic->ic_opmode = opmode;
|
|
|
|
return (vap);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_vap_delete(struct ieee80211vap *vap)
|
|
|
|
{
|
2015-11-10 12:52:26 +00:00
|
|
|
struct ieee80211com *ic = vap->iv_ic;
|
2015-12-13 21:00:21 +00:00
|
|
|
struct urtwn_softc *sc = ic->ic_softc;
|
2013-06-08 16:02:31 +00:00
|
|
|
struct urtwn_vap *uvp = URTWN_VAP(vap);
|
|
|
|
|
2015-11-10 12:52:26 +00:00
|
|
|
if (uvp->bcn_mbuf != NULL)
|
|
|
|
m_freem(uvp->bcn_mbuf);
|
|
|
|
if (vap->iv_opmode == IEEE80211_M_IBSS)
|
|
|
|
ieee80211_draintask(ic, &uvp->tsf_task_adhoc);
|
2015-12-13 21:00:21 +00:00
|
|
|
if (URTWN_CHIP_HAS_RATECTL(sc))
|
|
|
|
ieee80211_ratectl_deinit(vap);
|
2013-06-08 16:02:31 +00:00
|
|
|
ieee80211_vap_detach(vap);
|
|
|
|
free(uvp, M_80211_VAP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct mbuf *
|
2015-12-14 13:05:16 +00:00
|
|
|
urtwn_rx_copy_to_mbuf(struct urtwn_softc *sc, struct r92c_rx_stat *stat,
|
|
|
|
int totlen)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2013-06-08 16:02:31 +00:00
|
|
|
struct mbuf *m;
|
2015-12-14 13:05:16 +00:00
|
|
|
uint32_t rxdw0;
|
|
|
|
int pktlen;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* don't pass packets to the ieee80211 framework if the driver isn't
|
|
|
|
* RUNNING.
|
|
|
|
*/
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
if (!(sc->sc_flags & URTWN_RUNNING))
|
2013-06-08 16:02:31 +00:00
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
rxdw0 = le32toh(stat->rxdw0);
|
|
|
|
if (rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR)) {
|
|
|
|
/*
|
|
|
|
* This should not happen since we setup our Rx filter
|
|
|
|
* to not receive these frames.
|
|
|
|
*/
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_RECV,
|
|
|
|
"%s: RX flags error (%s)\n", __func__,
|
2015-12-14 13:05:16 +00:00
|
|
|
rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV");
|
|
|
|
goto fail;
|
2014-09-09 05:21:31 +00:00
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-12-14 13:05:16 +00:00
|
|
|
pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
|
|
|
|
if (pktlen < sizeof(struct ieee80211_frame_ack)) {
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_RECV,
|
|
|
|
"%s: frame is too short: %d\n", __func__, pktlen);
|
2015-12-14 13:05:16 +00:00
|
|
|
goto fail;
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-12-14 13:05:16 +00:00
|
|
|
if (__predict_false(totlen > MCLBYTES)) {
|
|
|
|
/* convert to m_getjcl if this happens */
|
|
|
|
device_printf(sc->sc_dev, "%s: frame too long: %d (%d)\n",
|
|
|
|
__func__, pktlen, totlen);
|
|
|
|
goto fail;
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2014-01-09 01:48:33 +00:00
|
|
|
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
|
2015-12-14 13:05:16 +00:00
|
|
|
if (__predict_false(m == NULL)) {
|
|
|
|
device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n",
|
|
|
|
__func__);
|
|
|
|
goto fail;
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Finalize mbuf. */
|
2015-12-14 13:05:16 +00:00
|
|
|
memcpy(mtod(m, uint8_t *), (uint8_t *)stat, totlen);
|
|
|
|
m->m_pkthdr.len = m->m_len = totlen;
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
return (m);
|
2015-12-14 13:05:16 +00:00
|
|
|
fail:
|
|
|
|
counter_u64_add(ic->ic_ierrors, 1);
|
|
|
|
return (NULL);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct mbuf *
|
2015-12-14 13:05:16 +00:00
|
|
|
urtwn_report_intr(struct usb_xfer *xfer, struct urtwn_data *data)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = data->sc;
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2013-06-08 16:02:31 +00:00
|
|
|
struct r92c_rx_stat *stat;
|
|
|
|
uint8_t *buf;
|
2015-12-13 21:00:21 +00:00
|
|
|
int len;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (len < sizeof(*stat)) {
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
counter_u64_add(ic->ic_ierrors, 1);
|
2013-06-08 16:02:31 +00:00
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = data->buf;
|
2015-12-13 21:00:21 +00:00
|
|
|
stat = (struct r92c_rx_stat *)buf;
|
|
|
|
|
2016-04-05 22:14:21 +00:00
|
|
|
/*
|
|
|
|
* For 88E chips we can tie the FF flushing here;
|
|
|
|
* this is where we do know exactly how deep the
|
|
|
|
* transmit queue is.
|
|
|
|
*
|
|
|
|
* But it won't work for R92 chips, so we can't
|
|
|
|
* take the easy way out.
|
|
|
|
*/
|
|
|
|
|
2015-12-13 21:00:21 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
|
|
|
int report_sel = MS(le32toh(stat->rxdw3), R88E_RXDW3_RPT);
|
|
|
|
|
|
|
|
switch (report_sel) {
|
|
|
|
case R88E_RXDW3_RPT_RX:
|
2015-12-14 13:05:16 +00:00
|
|
|
return (urtwn_rxeof(sc, buf, len));
|
2015-12-13 21:00:21 +00:00
|
|
|
case R88E_RXDW3_RPT_TX1:
|
|
|
|
urtwn_r88e_ratectl_tx_complete(sc, &stat[1]);
|
|
|
|
break;
|
|
|
|
default:
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_INTR,
|
|
|
|
"%s: case %d was not handled\n", __func__,
|
|
|
|
report_sel);
|
2015-12-13 21:00:21 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else
|
2015-12-14 13:05:16 +00:00
|
|
|
return (urtwn_rxeof(sc, buf, len));
|
2015-12-13 21:00:21 +00:00
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct mbuf *
|
2015-12-14 13:05:16 +00:00
|
|
|
urtwn_rxeof(struct urtwn_softc *sc, uint8_t *buf, int len)
|
2015-12-13 21:00:21 +00:00
|
|
|
{
|
|
|
|
struct r92c_rx_stat *stat;
|
|
|
|
struct mbuf *m, *m0 = NULL, *prevm = NULL;
|
|
|
|
uint32_t rxdw0;
|
|
|
|
int totlen, pktlen, infosz, npkts;
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Get the number of encapsulated frames. */
|
|
|
|
stat = (struct r92c_rx_stat *)buf;
|
|
|
|
npkts = MS(le32toh(stat->rxdw2), R92C_RXDW2_PKTCNT);
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_RECV,
|
|
|
|
"%s: Rx %d frames in one chunk\n", __func__, npkts);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Process all of them. */
|
|
|
|
while (npkts-- > 0) {
|
|
|
|
if (len < sizeof(*stat))
|
|
|
|
break;
|
|
|
|
stat = (struct r92c_rx_stat *)buf;
|
|
|
|
rxdw0 = le32toh(stat->rxdw0);
|
|
|
|
|
|
|
|
pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
|
|
|
|
if (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;
|
|
|
|
|
2015-12-14 13:05:16 +00:00
|
|
|
m = urtwn_rx_copy_to_mbuf(sc, stat, totlen);
|
2013-06-08 16:02:31 +00:00
|
|
|
if (m0 == NULL)
|
|
|
|
m0 = m;
|
|
|
|
if (prevm == NULL)
|
|
|
|
prevm = m;
|
|
|
|
else {
|
|
|
|
prevm->m_next = m;
|
|
|
|
prevm = m;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next chunk is 128-byte aligned. */
|
|
|
|
totlen = (totlen + 127) & ~127;
|
|
|
|
buf += totlen;
|
|
|
|
len -= totlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (m0);
|
|
|
|
}
|
|
|
|
|
2015-12-13 21:00:21 +00:00
|
|
|
static void
|
|
|
|
urtwn_r88e_ratectl_tx_complete(struct urtwn_softc *sc, void *arg)
|
|
|
|
{
|
|
|
|
struct r88e_tx_rpt_ccx *rpt = arg;
|
|
|
|
struct ieee80211vap *vap;
|
|
|
|
struct ieee80211_node *ni;
|
|
|
|
uint8_t macid;
|
|
|
|
int ntries;
|
|
|
|
|
|
|
|
macid = MS(rpt->rptb1, R88E_RPTB1_MACID);
|
|
|
|
ntries = MS(rpt->rptb2, R88E_RPTB2_RETRY_CNT);
|
|
|
|
|
|
|
|
URTWN_NT_LOCK(sc);
|
|
|
|
ni = sc->node_list[macid];
|
|
|
|
if (ni != NULL) {
|
|
|
|
vap = ni->ni_vap;
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_INTR, "%s: frame for macid %d was"
|
|
|
|
"%s sent (%d retries)\n", __func__, macid,
|
|
|
|
(rpt->rptb1 & R88E_RPTB1_PKT_OK) ? "" : " not",
|
|
|
|
ntries);
|
2015-12-13 21:00:21 +00:00
|
|
|
|
|
|
|
if (rpt->rptb1 & R88E_RPTB1_PKT_OK) {
|
|
|
|
ieee80211_ratectl_tx_complete(vap, ni,
|
|
|
|
IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL);
|
|
|
|
} else {
|
|
|
|
ieee80211_ratectl_tx_complete(vap, ni,
|
|
|
|
IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL);
|
|
|
|
}
|
2016-01-20 23:27:02 +00:00
|
|
|
} else {
|
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_INTR, "%s: macid %d, ni is NULL\n",
|
|
|
|
__func__, macid);
|
|
|
|
}
|
2015-12-13 21:00:21 +00:00
|
|
|
URTWN_NT_UNLOCK(sc);
|
|
|
|
}
|
|
|
|
|
2015-12-14 13:05:16 +00:00
|
|
|
static struct ieee80211_node *
|
|
|
|
urtwn_rx_frame(struct urtwn_softc *sc, struct mbuf *m, int8_t *rssi_p)
|
|
|
|
{
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
struct ieee80211_frame_min *wh;
|
|
|
|
struct r92c_rx_stat *stat;
|
|
|
|
uint32_t rxdw0, rxdw3;
|
|
|
|
uint8_t rate, cipher;
|
2016-04-13 05:19:16 +00:00
|
|
|
int8_t rssi = -127;
|
2015-12-14 13:05:16 +00:00
|
|
|
int infosz;
|
|
|
|
|
|
|
|
stat = mtod(m, struct r92c_rx_stat *);
|
|
|
|
rxdw0 = le32toh(stat->rxdw0);
|
|
|
|
rxdw3 = le32toh(stat->rxdw3);
|
|
|
|
|
|
|
|
rate = MS(rxdw3, R92C_RXDW3_RATE);
|
|
|
|
cipher = MS(rxdw0, R92C_RXDW0_CIPHER);
|
|
|
|
infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
|
|
|
|
|
|
|
|
/* Get RSSI from PHY status descriptor if present. */
|
|
|
|
if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) {
|
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
rssi = urtwn_r88e_get_rssi(sc, rate, &stat[1]);
|
|
|
|
else
|
|
|
|
rssi = urtwn_get_rssi(sc, rate, &stat[1]);
|
2016-04-13 05:19:16 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_RSSI, "%s: rssi=%d\n", __func__, rssi);
|
2015-12-14 13:05:16 +00:00
|
|
|
/* Update our average RSSI. */
|
|
|
|
urtwn_update_avgrssi(sc, rate, rssi);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ieee80211_radiotap_active(ic)) {
|
|
|
|
struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
|
|
|
|
|
|
|
|
tap->wr_flags = 0;
|
|
|
|
|
|
|
|
urtwn_get_tsf(sc, &tap->wr_tsft);
|
|
|
|
if (__predict_false(le32toh((uint32_t)tap->wr_tsft) <
|
|
|
|
le32toh(stat->rxdw5))) {
|
|
|
|
tap->wr_tsft = le32toh(tap->wr_tsft >> 32) - 1;
|
|
|
|
tap->wr_tsft = (uint64_t)htole32(tap->wr_tsft) << 32;
|
|
|
|
} else
|
|
|
|
tap->wr_tsft &= 0xffffffff00000000;
|
|
|
|
tap->wr_tsft += stat->rxdw5;
|
|
|
|
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
/* XXX 20/40? */
|
|
|
|
/* XXX shortgi? */
|
|
|
|
|
2015-12-14 13:05:16 +00:00
|
|
|
/* Map HW rate index to 802.11 rate. */
|
|
|
|
if (!(rxdw3 & R92C_RXDW3_HT)) {
|
|
|
|
tap->wr_rate = ridx2rate[rate];
|
|
|
|
} else if (rate >= 12) { /* MCS0~15. */
|
|
|
|
/* Bit 7 set means HT MCS instead of rate. */
|
|
|
|
tap->wr_rate = 0x80 | (rate - 12);
|
|
|
|
}
|
2016-04-13 05:19:16 +00:00
|
|
|
|
|
|
|
/* XXX TODO: this isn't right; should use the last good RSSI */
|
2015-12-14 13:05:16 +00:00
|
|
|
tap->wr_dbm_antsignal = rssi;
|
|
|
|
tap->wr_dbm_antnoise = URTWN_NOISE_FLOOR;
|
|
|
|
}
|
|
|
|
|
|
|
|
*rssi_p = rssi;
|
|
|
|
|
|
|
|
/* Drop descriptor. */
|
|
|
|
m_adj(m, sizeof(*stat) + infosz);
|
|
|
|
wh = mtod(m, struct ieee80211_frame_min *);
|
|
|
|
|
|
|
|
if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
|
|
|
|
cipher != R92C_CAM_ALGO_NONE) {
|
|
|
|
m->m_flags |= M_WEP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m->m_len >= sizeof(*wh))
|
|
|
|
return (ieee80211_find_rxnode(ic, wh));
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static void
|
|
|
|
urtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
|
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = usbd_xfer_softc(xfer);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2013-06-08 16:02:31 +00:00
|
|
|
struct ieee80211_node *ni;
|
|
|
|
struct mbuf *m = NULL, *next;
|
|
|
|
struct urtwn_data *data;
|
2015-12-14 13:05:16 +00:00
|
|
|
int8_t nf, rssi;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
|
|
|
switch (USB_GET_STATE(xfer)) {
|
|
|
|
case USB_ST_TRANSFERRED:
|
|
|
|
data = STAILQ_FIRST(&sc->sc_rx_active);
|
|
|
|
if (data == NULL)
|
|
|
|
goto tr_setup;
|
|
|
|
STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next);
|
2015-12-14 13:05:16 +00:00
|
|
|
m = urtwn_report_intr(xfer, data);
|
2013-06-08 16:02:31 +00:00
|
|
|
STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next);
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case USB_ST_SETUP:
|
|
|
|
tr_setup:
|
|
|
|
data = STAILQ_FIRST(&sc->sc_rx_inactive);
|
|
|
|
if (data == NULL) {
|
|
|
|
KASSERT(m == NULL, ("mbuf isn't NULL"));
|
2016-04-05 22:14:21 +00:00
|
|
|
goto finish;
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next);
|
|
|
|
STAILQ_INSERT_TAIL(&sc->sc_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;
|
2015-12-14 13:05:16 +00:00
|
|
|
|
|
|
|
ni = urtwn_rx_frame(sc, m, &rssi);
|
2016-04-13 05:19:16 +00:00
|
|
|
|
|
|
|
/* Store a global last-good RSSI */
|
|
|
|
if (rssi != -127)
|
|
|
|
sc->last_rssi = rssi;
|
|
|
|
|
2015-12-14 13:05:16 +00:00
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
nf = URTWN_NOISE_FLOOR;
|
|
|
|
if (ni != NULL) {
|
2016-04-13 05:19:16 +00:00
|
|
|
if (rssi != -127)
|
|
|
|
URTWN_NODE(ni)->last_rssi = rssi;
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
if (ni->ni_flags & IEEE80211_NODE_HT)
|
|
|
|
m->m_flags |= M_AMPDU;
|
2016-04-13 05:19:16 +00:00
|
|
|
(void)ieee80211_input(ni, m,
|
|
|
|
URTWN_NODE(ni)->last_rssi - nf, nf);
|
2013-06-08 16:02:31 +00:00
|
|
|
ieee80211_free_node(ni);
|
2015-10-23 07:42:56 +00:00
|
|
|
} else {
|
2016-04-13 05:19:16 +00:00
|
|
|
/* Use last good global RSSI */
|
|
|
|
(void)ieee80211_input_all(ic, m,
|
|
|
|
sc->last_rssi - nf, nf);
|
2015-10-23 07:42:56 +00:00
|
|
|
}
|
2015-12-14 13:05:16 +00:00
|
|
|
URTWN_LOCK(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
m = next;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* needs it to the inactive queue due to a error. */
|
|
|
|
data = STAILQ_FIRST(&sc->sc_rx_active);
|
|
|
|
if (data != NULL) {
|
|
|
|
STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next);
|
|
|
|
STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next);
|
|
|
|
}
|
|
|
|
if (error != USB_ERR_CANCELLED) {
|
|
|
|
usbd_xfer_set_stall(xfer);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
counter_u64_add(ic->ic_ierrors, 1);
|
2013-06-08 16:02:31 +00:00
|
|
|
goto tr_setup;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2016-04-05 22:14:21 +00:00
|
|
|
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
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
ieee80211_ff_age_all(ic, 1);
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Kick-start more transmit in case we stalled */
|
|
|
|
urtwn_start(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-10-24 19:59:15 +00:00
|
|
|
urtwn_txeof(struct urtwn_softc *sc, struct urtwn_data *data, int status)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
2015-10-24 19:59:15 +00:00
|
|
|
|
2015-11-10 00:12:00 +00:00
|
|
|
if (data->ni != NULL) /* not a beacon frame */
|
|
|
|
ieee80211_tx_complete(data->ni, data->m, status);
|
2015-10-24 19:59:15 +00:00
|
|
|
|
2016-04-05 22:14:21 +00:00
|
|
|
if (sc->sc_tx_n_active > 0)
|
|
|
|
sc->sc_tx_n_active--;
|
|
|
|
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
data->ni = NULL;
|
|
|
|
data->m = NULL;
|
2015-10-24 19:59:15 +00:00
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
sc->sc_txtimer = 0;
|
2015-10-24 19:59:15 +00:00
|
|
|
|
|
|
|
STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2015-10-09 14:31:32 +00:00
|
|
|
static int
|
|
|
|
urtwn_alloc_list(struct urtwn_softc *sc, struct urtwn_data data[],
|
|
|
|
int ndata, int maxsz)
|
|
|
|
{
|
|
|
|
int i, error;
|
|
|
|
|
|
|
|
for (i = 0; i < ndata; i++) {
|
|
|
|
struct urtwn_data *dp = &data[i];
|
|
|
|
dp->sc = sc;
|
|
|
|
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:
|
|
|
|
urtwn_free_list(sc, data, ndata);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_alloc_rx_list(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
int error, i;
|
|
|
|
|
|
|
|
error = urtwn_alloc_list(sc, sc->sc_rx, URTWN_RX_LIST_COUNT,
|
|
|
|
URTWN_RXBUFSZ);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
STAILQ_INIT(&sc->sc_rx_active);
|
|
|
|
STAILQ_INIT(&sc->sc_rx_inactive);
|
|
|
|
|
|
|
|
for (i = 0; i < URTWN_RX_LIST_COUNT; i++)
|
|
|
|
STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_alloc_tx_list(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
int error, i;
|
|
|
|
|
|
|
|
error = urtwn_alloc_list(sc, sc->sc_tx, URTWN_TX_LIST_COUNT,
|
|
|
|
URTWN_TXBUFSZ);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
STAILQ_INIT(&sc->sc_tx_active);
|
|
|
|
STAILQ_INIT(&sc->sc_tx_inactive);
|
|
|
|
STAILQ_INIT(&sc->sc_tx_pending);
|
|
|
|
|
|
|
|
for (i = 0; i < URTWN_TX_LIST_COUNT; i++)
|
|
|
|
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i], next);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_free_list(struct urtwn_softc *sc, struct urtwn_data data[], int ndata)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ndata; i++) {
|
|
|
|
struct urtwn_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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_free_rx_list(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
urtwn_free_list(sc, sc->sc_rx, URTWN_RX_LIST_COUNT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_free_tx_list(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
urtwn_free_list(sc, sc->sc_tx, URTWN_TX_LIST_COUNT);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static void
|
|
|
|
urtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error)
|
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = usbd_xfer_softc(xfer);
|
2016-04-05 22:14:21 +00:00
|
|
|
#ifdef IEEE80211_SUPPORT_SUPERG
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
#endif
|
2013-06-08 16:02:31 +00:00
|
|
|
struct urtwn_data *data;
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
|
|
|
switch (USB_GET_STATE(xfer)){
|
|
|
|
case USB_ST_TRANSFERRED:
|
|
|
|
data = STAILQ_FIRST(&sc->sc_tx_active);
|
|
|
|
if (data == NULL)
|
|
|
|
goto tr_setup;
|
|
|
|
STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next);
|
2015-10-24 19:59:15 +00:00
|
|
|
urtwn_txeof(sc, data, 0);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* FALLTHROUGH */
|
|
|
|
case USB_ST_SETUP:
|
|
|
|
tr_setup:
|
|
|
|
data = STAILQ_FIRST(&sc->sc_tx_pending);
|
|
|
|
if (data == NULL) {
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_XMIT,
|
|
|
|
"%s: empty pending queue\n", __func__);
|
2016-04-05 22:14:21 +00:00
|
|
|
sc->sc_tx_n_active = 0;
|
2015-09-29 05:03:24 +00:00
|
|
|
goto finish;
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next);
|
|
|
|
STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next);
|
|
|
|
usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen);
|
|
|
|
usbd_transfer_submit(xfer);
|
2016-04-05 22:14:21 +00:00
|
|
|
sc->sc_tx_n_active++;
|
2013-06-08 16:02:31 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
data = STAILQ_FIRST(&sc->sc_tx_active);
|
|
|
|
if (data == NULL)
|
|
|
|
goto tr_setup;
|
2015-10-24 19:59:15 +00:00
|
|
|
STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next);
|
|
|
|
urtwn_txeof(sc, data, 1);
|
2013-06-08 16:02:31 +00:00
|
|
|
if (error != USB_ERR_CANCELLED) {
|
|
|
|
usbd_xfer_set_stall(xfer);
|
|
|
|
goto tr_setup;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-09-29 05:03:24 +00:00
|
|
|
finish:
|
2016-04-05 22:14:21 +00:00
|
|
|
#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_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.
|
|
|
|
*/
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
ieee80211_ff_flush(ic, WME_AC_VO);
|
|
|
|
ieee80211_ff_flush(ic, WME_AC_VI);
|
|
|
|
ieee80211_ff_flush(ic, WME_AC_BE);
|
|
|
|
ieee80211_ff_flush(ic, WME_AC_BK);
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
}
|
|
|
|
#endif
|
2015-09-29 05:03:24 +00:00
|
|
|
/* Kick-start more transmit */
|
|
|
|
urtwn_start(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct urtwn_data *
|
|
|
|
_urtwn_getbuf(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
struct urtwn_data *bf;
|
|
|
|
|
|
|
|
bf = STAILQ_FIRST(&sc->sc_tx_inactive);
|
|
|
|
if (bf != NULL)
|
|
|
|
STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next);
|
2016-01-20 23:27:02 +00:00
|
|
|
else {
|
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_XMIT,
|
|
|
|
"%s: out of xmit buffers\n", __func__);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
return (bf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct urtwn_data *
|
|
|
|
urtwn_getbuf(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
struct urtwn_data *bf;
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
|
|
|
bf = _urtwn_getbuf(sc);
|
2016-01-20 23:27:02 +00:00
|
|
|
if (bf == NULL) {
|
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_XMIT, "%s: stop queue\n",
|
|
|
|
__func__);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
return (bf);
|
|
|
|
}
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
static usb_error_t
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_write_region_1(struct urtwn_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 (urtwn_do_request(sc, &req, buf));
|
|
|
|
}
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
static usb_error_t
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_write_1(struct urtwn_softc *sc, uint16_t addr, uint8_t val)
|
|
|
|
{
|
2015-12-03 14:38:55 +00:00
|
|
|
return (urtwn_write_region_1(sc, addr, &val, sizeof(val)));
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
static usb_error_t
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_write_2(struct urtwn_softc *sc, uint16_t addr, uint16_t val)
|
|
|
|
{
|
|
|
|
val = htole16(val);
|
2015-12-03 14:38:55 +00:00
|
|
|
return (urtwn_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val)));
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
static usb_error_t
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_write_4(struct urtwn_softc *sc, uint16_t addr, uint32_t val)
|
|
|
|
{
|
|
|
|
val = htole32(val);
|
2015-12-03 14:38:55 +00:00
|
|
|
return (urtwn_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val)));
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
static usb_error_t
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_read_region_1(struct urtwn_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 (urtwn_do_request(sc, &req, buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t
|
|
|
|
urtwn_read_1(struct urtwn_softc *sc, uint16_t addr)
|
|
|
|
{
|
|
|
|
uint8_t val;
|
|
|
|
|
|
|
|
if (urtwn_read_region_1(sc, addr, &val, 1) != 0)
|
|
|
|
return (0xff);
|
|
|
|
return (val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t
|
|
|
|
urtwn_read_2(struct urtwn_softc *sc, uint16_t addr)
|
|
|
|
{
|
|
|
|
uint16_t val;
|
|
|
|
|
|
|
|
if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0)
|
|
|
|
return (0xffff);
|
|
|
|
return (le16toh(val));
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
urtwn_read_4(struct urtwn_softc *sc, uint16_t addr)
|
|
|
|
{
|
|
|
|
uint32_t val;
|
|
|
|
|
|
|
|
if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0)
|
|
|
|
return (0xffffffff);
|
|
|
|
return (le32toh(val));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_fw_cmd(struct urtwn_softc *sc, uint8_t id, const void *buf, int len)
|
|
|
|
{
|
|
|
|
struct r92c_fw_cmd cmd;
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_error_t error;
|
2013-06-08 16:02:31 +00:00
|
|
|
int ntries;
|
|
|
|
|
2016-02-22 00:48:53 +00:00
|
|
|
if (!(sc->sc_flags & URTWN_FW_LOADED)) {
|
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_FIRMWARE, "%s: firmware "
|
|
|
|
"was not loaded; command (id %d) will be discarded\n",
|
|
|
|
__func__, id);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Wait for current FW box to be empty. */
|
|
|
|
for (ntries = 0; ntries < 100; ntries++) {
|
|
|
|
if (!(urtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur)))
|
|
|
|
break;
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
if (ntries == 100) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"could not send firmware command\n");
|
|
|
|
return (ETIMEDOUT);
|
|
|
|
}
|
|
|
|
memset(&cmd, 0, sizeof(cmd));
|
|
|
|
cmd.id = id;
|
|
|
|
if (len > 3)
|
|
|
|
cmd.id |= R92C_CMD_FLAG_EXT;
|
|
|
|
KASSERT(len <= sizeof(cmd.msg), ("urtwn_fw_cmd\n"));
|
|
|
|
memcpy(cmd.msg, buf, len);
|
|
|
|
|
|
|
|
/* Write the first word last since that will trigger the FW. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_region_1(sc, R92C_HMEBOX_EXT(sc->fwcur),
|
2013-06-08 16:02:31 +00:00
|
|
|
(uint8_t *)&cmd + 4, 2);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
|
|
|
error = urtwn_write_region_1(sc, R92C_HMEBOX(sc->fwcur),
|
2013-06-08 16:02:31 +00:00
|
|
|
(uint8_t *)&cmd + 0, 4);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2015-12-13 21:50:38 +00:00
|
|
|
static void
|
|
|
|
urtwn_cmdq_cb(void *arg, int pending)
|
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = arg;
|
|
|
|
struct urtwn_cmdq *item;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Device must be powered on (via urtwn_power_on())
|
|
|
|
* before any command may be sent.
|
|
|
|
*/
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
if (!(sc->sc_flags & URTWN_RUNNING)) {
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
URTWN_CMDQ_LOCK(sc);
|
|
|
|
while (sc->cmdq[sc->cmdq_first].func != NULL) {
|
|
|
|
item = &sc->cmdq[sc->cmdq_first];
|
|
|
|
sc->cmdq_first = (sc->cmdq_first + 1) % URTWN_CMDQ_SIZE;
|
|
|
|
URTWN_CMDQ_UNLOCK(sc);
|
|
|
|
|
|
|
|
item->func(sc, &item->data);
|
|
|
|
|
|
|
|
URTWN_CMDQ_LOCK(sc);
|
|
|
|
memset(item, 0, sizeof (*item));
|
|
|
|
}
|
|
|
|
URTWN_CMDQ_UNLOCK(sc);
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_cmd_sleepable(struct urtwn_softc *sc, const void *ptr, size_t len,
|
|
|
|
CMD_FUNC_PROTO)
|
|
|
|
{
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
|
|
|
|
KASSERT(len <= sizeof(union sec_param), ("buffer overflow"));
|
|
|
|
|
|
|
|
URTWN_CMDQ_LOCK(sc);
|
|
|
|
if (sc->cmdq[sc->cmdq_last].func != NULL) {
|
|
|
|
device_printf(sc->sc_dev, "%s: cmdq overflow\n", __func__);
|
|
|
|
URTWN_CMDQ_UNLOCK(sc);
|
|
|
|
|
|
|
|
return (EAGAIN);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr != NULL)
|
|
|
|
memcpy(&sc->cmdq[sc->cmdq_last].data, ptr, len);
|
|
|
|
sc->cmdq[sc->cmdq_last].func = func;
|
|
|
|
sc->cmdq_last = (sc->cmdq_last + 1) % URTWN_CMDQ_SIZE;
|
|
|
|
URTWN_CMDQ_UNLOCK(sc);
|
|
|
|
|
|
|
|
ieee80211_runtask(ic, &sc->cmdq_task);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
static __inline void
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, uint32_t val)
|
2014-04-25 08:01:22 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
sc->sc_rf_write(sc, chain, addr, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_r92c_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr,
|
|
|
|
uint32_t val)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
|
|
|
urtwn_bb_write(sc, R92C_LSSI_PARAM(chain),
|
|
|
|
SM(R92C_LSSI_PARAM_ADDR, addr) |
|
|
|
|
SM(R92C_LSSI_PARAM_DATA, val));
|
|
|
|
}
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
static void
|
|
|
|
urtwn_r88e_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr,
|
|
|
|
uint32_t val)
|
|
|
|
{
|
|
|
|
urtwn_bb_write(sc, R92C_LSSI_PARAM(chain),
|
|
|
|
SM(R88E_LSSI_PARAM_ADDR, addr) |
|
|
|
|
SM(R92C_LSSI_PARAM_DATA, val));
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static uint32_t
|
|
|
|
urtwn_rf_read(struct urtwn_softc *sc, int chain, uint8_t addr)
|
|
|
|
{
|
|
|
|
uint32_t reg[R92C_MAX_CHAINS], val;
|
|
|
|
|
|
|
|
reg[0] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(0));
|
|
|
|
if (chain != 0)
|
|
|
|
reg[chain] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(chain));
|
|
|
|
|
|
|
|
urtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
|
|
|
|
reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
urtwn_bb_write(sc, R92C_HSSI_PARAM2(chain),
|
|
|
|
RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) |
|
|
|
|
R92C_HSSI_PARAM2_READ_EDGE);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
urtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
|
|
|
|
reg[0] | R92C_HSSI_PARAM2_READ_EDGE);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
if (urtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI)
|
|
|
|
val = urtwn_bb_read(sc, R92C_HSPI_READBACK(chain));
|
|
|
|
else
|
|
|
|
val = urtwn_bb_read(sc, R92C_LSSI_READBACK(chain));
|
|
|
|
return (MS(val, R92C_LSSI_READBACK_DATA));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_llt_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data)
|
|
|
|
{
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_error_t error;
|
2013-06-08 16:02:31 +00:00
|
|
|
int ntries;
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_4(sc, R92C_LLT_INIT,
|
2013-06-08 16:02:31 +00:00
|
|
|
SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) |
|
|
|
|
SM(R92C_LLT_INIT_ADDR, addr) |
|
|
|
|
SM(R92C_LLT_INIT_DATA, data));
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Wait for write operation to complete. */
|
|
|
|
for (ntries = 0; ntries < 20; ntries++) {
|
|
|
|
if (MS(urtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) ==
|
|
|
|
R92C_LLT_INIT_OP_NO_ACTIVE)
|
|
|
|
return (0);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
return (ETIMEDOUT);
|
|
|
|
}
|
|
|
|
|
2015-11-24 19:20:45 +00:00
|
|
|
static int
|
|
|
|
urtwn_efuse_read_next(struct urtwn_softc *sc, uint8_t *val)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
|
|
|
uint32_t reg;
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_error_t error;
|
2013-06-08 16:02:31 +00:00
|
|
|
int ntries;
|
|
|
|
|
2015-11-24 19:20:45 +00:00
|
|
|
if (sc->last_rom_addr >= URTWN_EFUSE_MAX_LEN)
|
|
|
|
return (EFAULT);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
reg = urtwn_read_4(sc, R92C_EFUSE_CTRL);
|
2015-11-24 19:20:45 +00:00
|
|
|
reg = RW(reg, R92C_EFUSE_CTRL_ADDR, sc->last_rom_addr);
|
2013-06-08 16:02:31 +00:00
|
|
|
reg &= ~R92C_EFUSE_CTRL_VALID;
|
2015-11-24 19:20:45 +00:00
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_4(sc, R92C_EFUSE_CTRL, reg);
|
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Wait for read operation to complete. */
|
|
|
|
for (ntries = 0; ntries < 100; ntries++) {
|
|
|
|
reg = urtwn_read_4(sc, R92C_EFUSE_CTRL);
|
|
|
|
if (reg & R92C_EFUSE_CTRL_VALID)
|
2015-11-24 19:20:45 +00:00
|
|
|
break;
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
2015-11-24 19:20:45 +00:00
|
|
|
if (ntries == 100) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"could not read efuse byte at address 0x%x\n",
|
|
|
|
sc->last_rom_addr);
|
|
|
|
return (ETIMEDOUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
*val = MS(reg, R92C_EFUSE_CTRL_DATA);
|
|
|
|
sc->last_rom_addr++;
|
|
|
|
|
|
|
|
return (0);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2015-11-24 19:20:45 +00:00
|
|
|
static int
|
|
|
|
urtwn_efuse_read_data(struct urtwn_softc *sc, uint8_t *rom, uint8_t off,
|
|
|
|
uint8_t msk)
|
|
|
|
{
|
|
|
|
uint8_t reg;
|
|
|
|
int i, error;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
if (msk & (1 << i))
|
|
|
|
continue;
|
|
|
|
error = urtwn_efuse_read_next(sc, ®);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n",
|
|
|
|
off * 8 + i * 2, reg);
|
2015-11-24 19:20:45 +00:00
|
|
|
rom[off * 8 + i * 2 + 0] = reg;
|
|
|
|
|
|
|
|
error = urtwn_efuse_read_next(sc, ®);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n",
|
|
|
|
off * 8 + i * 2 + 1, reg);
|
2015-11-24 19:20:45 +00:00
|
|
|
rom[off * 8 + i * 2 + 1] = reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
#ifdef USB_DEBUG
|
2013-06-08 16:02:31 +00:00
|
|
|
static void
|
2015-11-24 19:20:45 +00:00
|
|
|
urtwn_dump_rom_contents(struct urtwn_softc *sc, uint8_t *rom, uint16_t size)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2015-11-24 19:20:45 +00:00
|
|
|
/* Dump ROM contents. */
|
|
|
|
device_printf(sc->sc_dev, "%s:", __func__);
|
|
|
|
for (i = 0; i < size; i++) {
|
|
|
|
if (i % 32 == 0)
|
|
|
|
printf("\n%03X: ", i);
|
|
|
|
else if (i % 4 == 0)
|
|
|
|
printf(" ");
|
|
|
|
|
|
|
|
printf("%02X", rom[i]);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_efuse_read(struct urtwn_softc *sc, uint8_t *rom, uint16_t size)
|
|
|
|
{
|
|
|
|
#define URTWN_CHK(res) do { \
|
|
|
|
if ((error = res) != 0) \
|
|
|
|
goto end; \
|
|
|
|
} while(0)
|
|
|
|
uint8_t msk, off, reg;
|
|
|
|
int error;
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
URTWN_CHK(urtwn_efuse_switch_power(sc));
|
2014-04-25 08:01:22 +00:00
|
|
|
|
2015-11-24 19:20:45 +00:00
|
|
|
/* Read full ROM image. */
|
|
|
|
sc->last_rom_addr = 0;
|
|
|
|
memset(rom, 0xff, size);
|
|
|
|
|
|
|
|
URTWN_CHK(urtwn_efuse_read_next(sc, ®));
|
|
|
|
while (reg != 0xff) {
|
|
|
|
/* check for extended header */
|
|
|
|
if ((sc->chip & URTWN_CHIP_88E) && (reg & 0x1f) == 0x0f) {
|
|
|
|
off = reg >> 5;
|
|
|
|
URTWN_CHK(urtwn_efuse_read_next(sc, ®));
|
|
|
|
|
|
|
|
if ((reg & 0x0f) != 0x0f)
|
|
|
|
off = ((reg & 0xf0) >> 1) | off;
|
|
|
|
else
|
2013-06-08 16:02:31 +00:00
|
|
|
continue;
|
2015-11-24 19:20:45 +00:00
|
|
|
} else
|
|
|
|
off = reg >> 4;
|
|
|
|
msk = reg & 0xf;
|
|
|
|
|
|
|
|
URTWN_CHK(urtwn_efuse_read_data(sc, rom, off, msk));
|
|
|
|
URTWN_CHK(urtwn_efuse_read_next(sc, ®));
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
2015-11-24 19:20:45 +00:00
|
|
|
|
|
|
|
end:
|
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
#ifdef USB_DEBUG
|
|
|
|
if (sc->sc_debug & URTWN_DEBUG_ROM)
|
2015-11-24 19:20:45 +00:00
|
|
|
urtwn_dump_rom_contents(sc, rom, size);
|
2013-06-08 16:02:31 +00:00
|
|
|
#endif
|
2015-11-24 19:20:45 +00:00
|
|
|
|
2015-05-08 09:01:00 +00:00
|
|
|
urtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF);
|
2015-11-24 19:20:45 +00:00
|
|
|
|
|
|
|
if (error != 0) {
|
|
|
|
device_printf(sc->sc_dev, "%s: error while reading ROM\n",
|
|
|
|
__func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
#undef URTWN_CHK
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
2015-05-08 09:01:00 +00:00
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
static int
|
2014-04-25 08:01:22 +00:00
|
|
|
urtwn_efuse_switch_power(struct urtwn_softc *sc)
|
|
|
|
{
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_error_t error;
|
2014-04-25 08:01:22 +00:00
|
|
|
uint32_t reg;
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON);
|
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2015-04-24 04:57:18 +00:00
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
reg = urtwn_read_2(sc, R92C_SYS_ISO_CTRL);
|
|
|
|
if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) {
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_SYS_ISO_CTRL,
|
2014-04-25 08:01:22 +00:00
|
|
|
reg | R92C_SYS_ISO_CTRL_PWC_EV12V);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
}
|
|
|
|
reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN);
|
|
|
|
if (!(reg & R92C_SYS_FUNC_EN_ELDR)) {
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_SYS_FUNC_EN,
|
2014-04-25 08:01:22 +00:00
|
|
|
reg | R92C_SYS_FUNC_EN_ELDR);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
}
|
|
|
|
reg = urtwn_read_2(sc, R92C_SYS_CLKR);
|
|
|
|
if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) !=
|
|
|
|
(R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) {
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_SYS_CLKR,
|
2014-04-25 08:01:22 +00:00
|
|
|
reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
}
|
2015-12-03 14:38:55 +00:00
|
|
|
|
|
|
|
return (0);
|
2014-04-25 08:01:22 +00:00
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_read_chipid(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
uint32_t reg;
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
return (0);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
reg = urtwn_read_4(sc, R92C_SYS_CFG);
|
|
|
|
if (reg & R92C_SYS_CFG_TRP_VAUX_EN)
|
|
|
|
return (EIO);
|
|
|
|
|
|
|
|
if (reg & R92C_SYS_CFG_TYPE_92C) {
|
|
|
|
sc->chip |= URTWN_CHIP_92C;
|
|
|
|
/* Check if it is a castrated 8192C. */
|
|
|
|
if (MS(urtwn_read_4(sc, R92C_HPON_FSM),
|
|
|
|
R92C_HPON_FSM_CHIP_BONDING_ID) ==
|
|
|
|
R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R)
|
|
|
|
sc->chip |= URTWN_CHIP_92C_1T2R;
|
|
|
|
}
|
|
|
|
if (reg & R92C_SYS_CFG_VENDOR_UMC) {
|
|
|
|
sc->chip |= URTWN_CHIP_UMC;
|
|
|
|
if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0)
|
|
|
|
sc->chip |= URTWN_CHIP_UMC_A_CUT;
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2015-11-24 19:20:45 +00:00
|
|
|
static int
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_read_rom(struct urtwn_softc *sc)
|
|
|
|
{
|
2015-11-24 19:20:45 +00:00
|
|
|
struct r92c_rom *rom = &sc->rom.r92c_rom;
|
|
|
|
int error;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Read full ROM image. */
|
2015-11-24 19:20:45 +00:00
|
|
|
error = urtwn_efuse_read(sc, (uint8_t *)rom, sizeof(*rom));
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* XXX Weird but this is what the vendor driver does. */
|
2015-11-24 19:20:45 +00:00
|
|
|
sc->last_rom_addr = 0x1fa;
|
|
|
|
error = urtwn_efuse_read_next(sc, &sc->pa_setting);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_ROM, "%s: PA setting=0x%x\n", __func__,
|
|
|
|
sc->pa_setting);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE);
|
|
|
|
|
|
|
|
sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY);
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_ROM, "%s: regulatory type=%d\n",
|
|
|
|
__func__, sc->regulatory);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
|
|
|
sc->sc_rf_write = urtwn_r92c_rf_write;
|
|
|
|
sc->sc_power_on = urtwn_r92c_power_on;
|
2016-02-22 01:15:02 +00:00
|
|
|
sc->sc_power_off = urtwn_r92c_power_off;
|
2015-11-24 19:20:45 +00:00
|
|
|
|
|
|
|
return (0);
|
2014-04-25 08:01:22 +00:00
|
|
|
}
|
|
|
|
|
2015-11-24 19:20:45 +00:00
|
|
|
static int
|
2014-04-25 08:01:22 +00:00
|
|
|
urtwn_r88e_read_rom(struct urtwn_softc *sc)
|
|
|
|
{
|
2016-01-17 00:52:21 +00:00
|
|
|
struct r88e_rom *rom = &sc->rom.r88e_rom;
|
|
|
|
int error;
|
2014-04-25 08:01:22 +00:00
|
|
|
|
2016-01-17 00:52:21 +00:00
|
|
|
error = urtwn_efuse_read(sc, (uint8_t *)rom, sizeof(sc->rom.r88e_rom));
|
2015-11-24 19:20:45 +00:00
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
2015-04-24 04:57:18 +00:00
|
|
|
|
2016-01-17 00:52:21 +00:00
|
|
|
sc->bw20_tx_pwr_diff = (rom->tx_pwr_diff >> 4);
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->bw20_tx_pwr_diff & 0x08)
|
|
|
|
sc->bw20_tx_pwr_diff |= 0xf0;
|
2016-01-17 00:52:21 +00:00
|
|
|
sc->ofdm_tx_pwr_diff = (rom->tx_pwr_diff & 0xf);
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->ofdm_tx_pwr_diff & 0x08)
|
|
|
|
sc->ofdm_tx_pwr_diff |= 0xf0;
|
2016-01-17 00:52:21 +00:00
|
|
|
sc->regulatory = MS(rom->rf_board_opt, R92C_ROM_RF1_REGULATORY);
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_ROM, "%s: regulatory type %d\n",
|
|
|
|
__func__,sc->regulatory);
|
2016-01-17 00:52:21 +00:00
|
|
|
IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
|
|
|
sc->sc_rf_write = urtwn_r88e_rf_write;
|
|
|
|
sc->sc_power_on = urtwn_r88e_power_on;
|
2016-02-22 01:15:02 +00:00
|
|
|
sc->sc_power_off = urtwn_r88e_power_off;
|
2015-11-24 19:20:45 +00:00
|
|
|
|
|
|
|
return (0);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize rate adaptation in firmware.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
urtwn_ra_init(struct urtwn_softc *sc)
|
|
|
|
{
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2013-06-08 16:02:31 +00:00
|
|
|
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
|
|
|
struct ieee80211_node *ni;
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
struct ieee80211_rateset *rs, *rs_ht;
|
2013-06-08 16:02:31 +00:00
|
|
|
struct r92c_fw_cmd_macid_cfg cmd;
|
|
|
|
uint32_t rates, basicrates;
|
|
|
|
uint8_t mode;
|
|
|
|
int maxrate, maxbasicrate, error, i, j;
|
|
|
|
|
|
|
|
ni = ieee80211_ref_node(vap->iv_bss);
|
|
|
|
rs = &ni->ni_rates;
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
rs_ht = (struct ieee80211_rateset *) &ni->ni_htrates;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Get normal and basic rates mask. */
|
|
|
|
rates = basicrates = 0;
|
|
|
|
maxrate = maxbasicrate = 0;
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
|
|
|
|
/* This is for 11bg */
|
2013-06-08 16:02:31 +00:00
|
|
|
for (i = 0; i < rs->rs_nrates; i++) {
|
|
|
|
/* Convert 802.11 rate to HW rate index. */
|
2015-10-22 15:42:53 +00:00
|
|
|
for (j = 0; j < nitems(ridx2rate); j++)
|
|
|
|
if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) ==
|
|
|
|
ridx2rate[j])
|
2013-06-08 16:02:31 +00:00
|
|
|
break;
|
2015-10-22 15:42:53 +00:00
|
|
|
if (j == nitems(ridx2rate)) /* Unknown rate, skip. */
|
2013-06-08 16:02:31 +00:00
|
|
|
continue;
|
|
|
|
rates |= 1 << j;
|
|
|
|
if (j > maxrate)
|
|
|
|
maxrate = j;
|
|
|
|
if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) {
|
|
|
|
basicrates |= 1 << j;
|
|
|
|
if (j > maxbasicrate)
|
|
|
|
maxbasicrate = j;
|
|
|
|
}
|
|
|
|
}
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
|
|
|
|
/* If we're doing 11n, enable 11n rates */
|
|
|
|
if (ni->ni_flags & IEEE80211_NODE_HT) {
|
|
|
|
for (i = 0; i < rs_ht->rs_nrates; i++) {
|
|
|
|
if ((rs_ht->rs_rates[i] & 0x7f) > 0xf)
|
|
|
|
continue;
|
|
|
|
/* 11n rates start at index 12 */
|
|
|
|
j = ((rs_ht->rs_rates[i]) & 0xf) + 12;
|
|
|
|
rates |= (1 << j);
|
|
|
|
|
|
|
|
/* Guard against the rate table being oddly ordered */
|
|
|
|
if (j > maxrate)
|
|
|
|
maxrate = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (ic->ic_curmode == IEEE80211_MODE_11NG)
|
|
|
|
raid = R92C_RAID_11GN;
|
|
|
|
#endif
|
|
|
|
/* NB: group addressed frames are done at 11bg rates for now */
|
2013-06-08 16:02:31 +00:00
|
|
|
if (ic->ic_curmode == IEEE80211_MODE_11B)
|
|
|
|
mode = R92C_RAID_11B;
|
|
|
|
else
|
|
|
|
mode = R92C_RAID_11BG;
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
/* XXX misleading 'mode' value here for unicast frames */
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_RA,
|
|
|
|
"%s: mode 0x%x, rates 0x%08x, basicrates 0x%08x\n", __func__,
|
2013-06-08 16:02:31 +00:00
|
|
|
mode, rates, basicrates);
|
|
|
|
|
|
|
|
/* Set rates mask for group addressed frames. */
|
|
|
|
cmd.macid = URTWN_MACID_BC | URTWN_MACID_VALID;
|
|
|
|
cmd.mask = htole32(mode << 28 | basicrates);
|
|
|
|
error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
|
|
|
|
if (error != 0) {
|
2013-06-30 05:10:33 +00:00
|
|
|
ieee80211_free_node(ni);
|
2013-06-08 16:02:31 +00:00
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"could not add broadcast station\n");
|
|
|
|
return (error);
|
|
|
|
}
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Set initial MRR rate. */
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_RA, "%s: maxbasicrate %d\n", __func__,
|
|
|
|
maxbasicrate);
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BC),
|
|
|
|
maxbasicrate);
|
|
|
|
|
|
|
|
/* Set rates mask for unicast frames. */
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
if (ni->ni_flags & IEEE80211_NODE_HT)
|
|
|
|
mode = R92C_RAID_11GN;
|
|
|
|
else if (ic->ic_curmode == IEEE80211_MODE_11B)
|
|
|
|
mode = R92C_RAID_11B;
|
|
|
|
else
|
|
|
|
mode = R92C_RAID_11BG;
|
2013-06-08 16:02:31 +00:00
|
|
|
cmd.macid = URTWN_MACID_BSS | URTWN_MACID_VALID;
|
|
|
|
cmd.mask = htole32(mode << 28 | rates);
|
|
|
|
error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
|
|
|
|
if (error != 0) {
|
2013-06-30 05:10:33 +00:00
|
|
|
ieee80211_free_node(ni);
|
2013-06-08 16:02:31 +00:00
|
|
|
device_printf(sc->sc_dev, "could not add BSS station\n");
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
/* Set initial MRR rate. */
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_RA, "%s: maxrate %d\n", __func__,
|
|
|
|
maxrate);
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BSS),
|
|
|
|
maxrate);
|
|
|
|
|
|
|
|
/* Indicate highest supported rate. */
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
if (ni->ni_flags & IEEE80211_NODE_HT)
|
|
|
|
ni->ni_txrate = rs_ht->rs_rates[rs_ht->rs_nrates - 1]
|
|
|
|
| IEEE80211_RATE_MCS;
|
|
|
|
else
|
|
|
|
ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1];
|
2013-06-30 05:10:33 +00:00
|
|
|
ieee80211_free_node(ni);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2015-11-06 11:29:24 +00:00
|
|
|
static void
|
2015-11-10 00:12:00 +00:00
|
|
|
urtwn_init_beacon(struct urtwn_softc *sc, struct urtwn_vap *uvp)
|
|
|
|
{
|
|
|
|
struct r92c_tx_desc *txd = &uvp->bcn_desc;
|
|
|
|
|
|
|
|
txd->txdw0 = htole32(
|
|
|
|
SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | R92C_TXDW0_BMCAST |
|
|
|
|
R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG);
|
|
|
|
txd->txdw1 = htole32(
|
|
|
|
SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BEACON) |
|
|
|
|
SM(R92C_TXDW1_RAID, R92C_RAID_11B));
|
|
|
|
|
2015-12-05 15:08:01 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
2015-11-10 00:12:00 +00:00
|
|
|
txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, URTWN_MACID_BC));
|
2015-12-05 15:08:01 +00:00
|
|
|
txd->txdseq |= htole16(R88E_TXDSEQ_HWSEQ_EN);
|
|
|
|
} else {
|
2015-11-10 00:12:00 +00:00
|
|
|
txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, URTWN_MACID_BC));
|
2015-12-05 15:08:01 +00:00
|
|
|
txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN);
|
|
|
|
}
|
2015-11-10 00:12:00 +00:00
|
|
|
|
|
|
|
txd->txdw4 = htole32(R92C_TXDW4_DRVRATE);
|
|
|
|
txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, URTWN_RIDX_CCK1));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_setup_beacon(struct urtwn_softc *sc, struct ieee80211_node *ni)
|
|
|
|
{
|
|
|
|
struct ieee80211vap *vap = ni->ni_vap;
|
|
|
|
struct urtwn_vap *uvp = URTWN_VAP(vap);
|
|
|
|
struct mbuf *m;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
|
|
|
if (ni->ni_chan == IEEE80211_CHAN_ANYC)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
m = ieee80211_beacon_alloc(ni);
|
|
|
|
if (m == NULL) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"%s: could not allocate beacon frame\n", __func__);
|
|
|
|
return (ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uvp->bcn_mbuf != NULL)
|
|
|
|
m_freem(uvp->bcn_mbuf);
|
|
|
|
|
|
|
|
uvp->bcn_mbuf = m;
|
|
|
|
|
|
|
|
if ((error = urtwn_tx_beacon(sc, uvp)) != 0)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
/* XXX bcnq stuck workaround */
|
|
|
|
if ((error = urtwn_tx_beacon(sc, uvp)) != 0)
|
|
|
|
return (error);
|
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_BEACON, "%s: beacon was %srecognized\n",
|
|
|
|
__func__, urtwn_read_1(sc, R92C_TDECTRL + 2) &
|
|
|
|
(R92C_TDECTRL_BCN_VALID >> 16) ? "" : "not ");
|
|
|
|
|
2015-11-10 00:12:00 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_update_beacon(struct ieee80211vap *vap, int item)
|
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = vap->iv_ic->ic_softc;
|
|
|
|
struct urtwn_vap *uvp = URTWN_VAP(vap);
|
|
|
|
struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off;
|
|
|
|
struct ieee80211_node *ni = vap->iv_bss;
|
|
|
|
int mcast = 0;
|
|
|
|
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
if (uvp->bcn_mbuf == NULL) {
|
|
|
|
uvp->bcn_mbuf = ieee80211_beacon_alloc(ni);
|
|
|
|
if (uvp->bcn_mbuf == NULL) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"%s: could not allocate beacon frame\n", __func__);
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
|
|
|
|
if (item == IEEE80211_BEACON_TIM)
|
|
|
|
mcast = 1; /* XXX */
|
|
|
|
|
|
|
|
setbit(bo->bo_flags, item);
|
|
|
|
ieee80211_beacon_update(ni, uvp->bcn_mbuf, mcast);
|
|
|
|
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
urtwn_tx_beacon(sc, uvp);
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Push a beacon frame into the chip. Beacon will
|
|
|
|
* be repeated by the chip every R92C_BCN_INTERVAL.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
urtwn_tx_beacon(struct urtwn_softc *sc, struct urtwn_vap *uvp)
|
|
|
|
{
|
|
|
|
struct r92c_tx_desc *desc = &uvp->bcn_desc;
|
|
|
|
struct urtwn_data *bf;
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
|
|
|
bf = urtwn_getbuf(sc);
|
|
|
|
if (bf == NULL)
|
|
|
|
return (ENOMEM);
|
|
|
|
|
|
|
|
memcpy(bf->buf, desc, sizeof(*desc));
|
|
|
|
urtwn_tx_start(sc, uvp->bcn_mbuf, IEEE80211_FC0_TYPE_MGT, bf);
|
|
|
|
|
|
|
|
sc->sc_txtimer = 5;
|
|
|
|
callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2015-12-13 22:00:19 +00:00
|
|
|
static int
|
|
|
|
urtwn_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
|
|
|
|
ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
|
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = vap->iv_ic->ic_softc;
|
|
|
|
uint8_t i;
|
|
|
|
|
|
|
|
if (!(&vap->iv_nw_keys[0] <= k &&
|
|
|
|
k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) {
|
|
|
|
if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) {
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
/*
|
|
|
|
* First 4 slots for group keys,
|
|
|
|
* what is left - for pairwise.
|
|
|
|
* XXX incompatible with IBSS RSN.
|
|
|
|
*/
|
|
|
|
for (i = IEEE80211_WEP_NKID;
|
|
|
|
i < R92C_CAM_ENTRY_COUNT; i++) {
|
|
|
|
if ((sc->keys_bmap & (1 << i)) == 0) {
|
|
|
|
sc->keys_bmap |= 1 << i;
|
|
|
|
*keyix = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
if (i == R92C_CAM_ENTRY_COUNT) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"%s: no free space in the key table\n",
|
|
|
|
__func__);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
*keyix = 0;
|
|
|
|
} else {
|
|
|
|
*keyix = k - vap->iv_nw_keys;
|
|
|
|
}
|
|
|
|
*rxkeyix = *keyix;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_key_set_cb(struct urtwn_softc *sc, union sec_param *data)
|
|
|
|
{
|
|
|
|
struct ieee80211_key *k = &data->key;
|
|
|
|
uint8_t algo, keyid;
|
|
|
|
int i, error;
|
|
|
|
|
|
|
|
if (k->wk_keyix < IEEE80211_WEP_NKID)
|
|
|
|
keyid = k->wk_keyix;
|
|
|
|
else
|
|
|
|
keyid = 0;
|
|
|
|
|
|
|
|
/* Map net80211 cipher to HW crypto algorithm. */
|
|
|
|
switch (k->wk_cipher->ic_cipher) {
|
|
|
|
case IEEE80211_CIPHER_WEP:
|
|
|
|
if (k->wk_keylen < 8)
|
|
|
|
algo = R92C_CAM_ALGO_WEP40;
|
|
|
|
else
|
|
|
|
algo = R92C_CAM_ALGO_WEP104;
|
|
|
|
break;
|
|
|
|
case IEEE80211_CIPHER_TKIP:
|
|
|
|
algo = R92C_CAM_ALGO_TKIP;
|
|
|
|
break;
|
|
|
|
case IEEE80211_CIPHER_AES_CCM:
|
|
|
|
algo = R92C_CAM_ALGO_AES;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
device_printf(sc->sc_dev, "%s: undefined cipher %d\n",
|
|
|
|
__func__, k->wk_cipher->ic_cipher);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_KEY,
|
|
|
|
"%s: keyix %d, keyid %d, algo %d/%d, flags %04X, len %d, "
|
|
|
|
"macaddr %s\n", __func__, k->wk_keyix, keyid,
|
|
|
|
k->wk_cipher->ic_cipher, algo, k->wk_flags, k->wk_keylen,
|
|
|
|
ether_sprintf(k->wk_macaddr));
|
2015-12-13 22:00:19 +00:00
|
|
|
|
|
|
|
/* Write key. */
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
error = urtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i),
|
|
|
|
LE_READ_4(&k->wk_key[i * 4]));
|
|
|
|
if (error != 0)
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write CTL0 last since that will validate the CAM entry. */
|
|
|
|
error = urtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix),
|
|
|
|
LE_READ_4(&k->wk_macaddr[2]));
|
|
|
|
if (error != 0)
|
|
|
|
goto fail;
|
|
|
|
error = urtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix),
|
|
|
|
SM(R92C_CAM_ALGO, algo) |
|
|
|
|
SM(R92C_CAM_KEYID, keyid) |
|
|
|
|
SM(R92C_CAM_MACLO, LE_READ_2(&k->wk_macaddr[0])) |
|
|
|
|
R92C_CAM_VALID);
|
|
|
|
if (error != 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
device_printf(sc->sc_dev, "%s fails, error %d\n", __func__, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_key_del_cb(struct urtwn_softc *sc, union sec_param *data)
|
|
|
|
{
|
|
|
|
struct ieee80211_key *k = &data->key;
|
|
|
|
int i;
|
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_KEY,
|
|
|
|
"%s: keyix %d, flags %04X, macaddr %s\n", __func__,
|
2015-12-13 22:00:19 +00:00
|
|
|
k->wk_keyix, k->wk_flags, ether_sprintf(k->wk_macaddr));
|
|
|
|
|
|
|
|
urtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), 0);
|
|
|
|
urtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), 0);
|
|
|
|
|
|
|
|
/* Clear key. */
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
urtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), 0);
|
|
|
|
sc->keys_bmap &= ~(1 << k->wk_keyix);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
|
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = vap->iv_ic->ic_softc;
|
|
|
|
|
|
|
|
if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
|
|
|
|
/* Not for us. */
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (!urtwn_cmd_sleepable(sc, k, sizeof(*k), urtwn_key_set_cb));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
|
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = vap->iv_ic->ic_softc;
|
|
|
|
|
|
|
|
if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
|
|
|
|
/* Not for us. */
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (!urtwn_cmd_sleepable(sc, k, sizeof(*k), urtwn_key_del_cb));
|
|
|
|
}
|
|
|
|
|
2015-11-10 12:52:26 +00:00
|
|
|
static void
|
|
|
|
urtwn_tsf_task_adhoc(void *arg, int pending)
|
|
|
|
{
|
|
|
|
struct ieee80211vap *vap = arg;
|
|
|
|
struct urtwn_softc *sc = vap->iv_ic->ic_softc;
|
|
|
|
struct ieee80211_node *ni;
|
|
|
|
uint32_t reg;
|
|
|
|
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
ni = ieee80211_ref_node(vap->iv_bss);
|
|
|
|
reg = urtwn_read_1(sc, R92C_BCN_CTRL);
|
|
|
|
|
|
|
|
/* Accept beacons with the same BSSID. */
|
|
|
|
urtwn_set_rx_bssid_all(sc, 0);
|
|
|
|
|
|
|
|
/* Enable synchronization. */
|
|
|
|
reg &= ~R92C_BCN_CTRL_DIS_TSF_UDT0;
|
|
|
|
urtwn_write_1(sc, R92C_BCN_CTRL, reg);
|
|
|
|
|
|
|
|
/* Synchronize. */
|
|
|
|
usb_pause_mtx(&sc->sc_mtx, hz * ni->ni_intval * 5 / 1000);
|
|
|
|
|
|
|
|
/* Disable synchronization. */
|
|
|
|
reg |= R92C_BCN_CTRL_DIS_TSF_UDT0;
|
|
|
|
urtwn_write_1(sc, R92C_BCN_CTRL, reg);
|
|
|
|
|
|
|
|
/* Remove beacon filter. */
|
|
|
|
urtwn_set_rx_bssid_all(sc, 1);
|
|
|
|
|
|
|
|
/* Enable beaconing. */
|
|
|
|
urtwn_write_1(sc, R92C_MBID_NUM,
|
|
|
|
urtwn_read_1(sc, R92C_MBID_NUM) | R92C_MBID_TXBCN_RPT0);
|
|
|
|
reg |= R92C_BCN_CTRL_EN_BCN;
|
|
|
|
|
|
|
|
urtwn_write_1(sc, R92C_BCN_CTRL, reg);
|
|
|
|
ieee80211_free_node(ni);
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
}
|
|
|
|
|
2015-11-10 00:12:00 +00:00
|
|
|
static void
|
|
|
|
urtwn_tsf_sync_enable(struct urtwn_softc *sc, struct ieee80211vap *vap)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
2015-11-10 12:52:26 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
struct urtwn_vap *uvp = URTWN_VAP(vap);
|
|
|
|
|
2015-11-10 00:12:00 +00:00
|
|
|
/* Reset TSF. */
|
|
|
|
urtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RST0);
|
|
|
|
|
|
|
|
switch (vap->iv_opmode) {
|
|
|
|
case IEEE80211_M_STA:
|
|
|
|
/* Enable TSF synchronization. */
|
|
|
|
urtwn_write_1(sc, R92C_BCN_CTRL,
|
|
|
|
urtwn_read_1(sc, R92C_BCN_CTRL) &
|
|
|
|
~R92C_BCN_CTRL_DIS_TSF_UDT0);
|
|
|
|
break;
|
2015-11-10 12:52:26 +00:00
|
|
|
case IEEE80211_M_IBSS:
|
|
|
|
ieee80211_runtask(ic, &uvp->tsf_task_adhoc);
|
|
|
|
break;
|
2015-11-10 00:12:00 +00:00
|
|
|
case IEEE80211_M_HOSTAP:
|
|
|
|
/* Enable beaconing. */
|
|
|
|
urtwn_write_1(sc, R92C_MBID_NUM,
|
|
|
|
urtwn_read_1(sc, R92C_MBID_NUM) | R92C_MBID_TXBCN_RPT0);
|
|
|
|
urtwn_write_1(sc, R92C_BCN_CTRL,
|
|
|
|
urtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
device_printf(sc->sc_dev, "undefined opmode %d\n",
|
|
|
|
vap->iv_opmode);
|
|
|
|
return;
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2015-12-14 12:36:10 +00:00
|
|
|
static void
|
|
|
|
urtwn_get_tsf(struct urtwn_softc *sc, uint64_t *buf)
|
|
|
|
{
|
|
|
|
urtwn_read_region_1(sc, R92C_TSFTR, (uint8_t *)buf, sizeof(*buf));
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static void
|
|
|
|
urtwn_set_led(struct urtwn_softc *sc, int led, int on)
|
|
|
|
{
|
|
|
|
uint8_t reg;
|
2015-04-04 08:36:02 +00:00
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
if (led == URTWN_LED_LINK) {
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
|
|
|
reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0xf0;
|
|
|
|
urtwn_write_1(sc, R92C_LEDCFG2, reg | 0x60);
|
|
|
|
if (!on) {
|
|
|
|
reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0x90;
|
|
|
|
urtwn_write_1(sc, R92C_LEDCFG2,
|
|
|
|
reg | R92C_LEDCFG0_DIS);
|
|
|
|
urtwn_write_1(sc, R92C_MAC_PINMUX_CFG,
|
|
|
|
urtwn_read_1(sc, R92C_MAC_PINMUX_CFG) &
|
|
|
|
0xfe);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
reg = urtwn_read_1(sc, R92C_LEDCFG0) & 0x70;
|
|
|
|
if (!on)
|
|
|
|
reg |= R92C_LEDCFG0_DIS;
|
|
|
|
urtwn_write_1(sc, R92C_LEDCFG0, reg);
|
|
|
|
}
|
|
|
|
sc->ledlink = on; /* Save LED state. */
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-23 08:26:26 +00:00
|
|
|
static void
|
|
|
|
urtwn_set_mode(struct urtwn_softc *sc, uint8_t mode)
|
|
|
|
{
|
|
|
|
uint8_t reg;
|
|
|
|
|
|
|
|
reg = urtwn_read_1(sc, R92C_MSR);
|
|
|
|
reg = (reg & ~R92C_MSR_MASK) | mode;
|
|
|
|
urtwn_write_1(sc, R92C_MSR, reg);
|
|
|
|
}
|
|
|
|
|
2015-11-10 12:52:26 +00:00
|
|
|
static void
|
|
|
|
urtwn_ibss_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 urtwn_softc *sc = vap->iv_ic->ic_softc;
|
|
|
|
struct urtwn_vap *uvp = URTWN_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);
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
urtwn_get_tsf(sc, &curr_tstamp);
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
curr_tstamp = le64toh(curr_tstamp);
|
|
|
|
|
|
|
|
if (ni_tstamp >= curr_tstamp)
|
|
|
|
(void) ieee80211_ibss_merge(ni);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static int
|
|
|
|
urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
|
|
|
|
{
|
|
|
|
struct urtwn_vap *uvp = URTWN_VAP(vap);
|
|
|
|
struct ieee80211com *ic = vap->iv_ic;
|
2015-08-20 03:57:41 +00:00
|
|
|
struct urtwn_softc *sc = ic->ic_softc;
|
2013-06-08 16:02:31 +00:00
|
|
|
struct ieee80211_node *ni;
|
|
|
|
enum ieee80211_state ostate;
|
2015-11-10 00:12:00 +00:00
|
|
|
uint32_t reg;
|
|
|
|
uint8_t mode;
|
|
|
|
int error = 0;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
ostate = vap->iv_state;
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_STATE, "%s -> %s\n",
|
|
|
|
ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
IEEE80211_UNLOCK(ic);
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
callout_stop(&sc->sc_watchdog_ch);
|
|
|
|
|
|
|
|
if (ostate == IEEE80211_S_RUN) {
|
2016-01-20 23:55:39 +00:00
|
|
|
/* Stop calibration. */
|
|
|
|
callout_stop(&sc->sc_calib_to);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Turn link LED off. */
|
|
|
|
urtwn_set_led(sc, URTWN_LED_LINK, 0);
|
|
|
|
|
|
|
|
/* Set media status to 'No Link'. */
|
2015-10-23 08:26:26 +00:00
|
|
|
urtwn_set_mode(sc, R92C_MSR_NOLINK);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Stop Rx of data frames. */
|
|
|
|
urtwn_write_2(sc, R92C_RXFLTMAP2, 0);
|
|
|
|
|
|
|
|
/* Disable TSF synchronization. */
|
|
|
|
urtwn_write_1(sc, R92C_BCN_CTRL,
|
2015-11-10 00:12:00 +00:00
|
|
|
(urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN) |
|
2013-06-08 16:02:31 +00:00
|
|
|
R92C_BCN_CTRL_DIS_TSF_UDT0);
|
|
|
|
|
2015-11-10 00:12:00 +00:00
|
|
|
/* Disable beaconing. */
|
|
|
|
urtwn_write_1(sc, R92C_MBID_NUM,
|
|
|
|
urtwn_read_1(sc, R92C_MBID_NUM) & ~R92C_MBID_TXBCN_RPT0);
|
|
|
|
|
|
|
|
/* Reset TSF. */
|
|
|
|
urtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RST0);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Reset EDCA parameters. */
|
|
|
|
urtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217);
|
|
|
|
urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317);
|
|
|
|
urtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320);
|
|
|
|
urtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (nstate) {
|
|
|
|
case IEEE80211_S_INIT:
|
|
|
|
/* Turn link LED off. */
|
|
|
|
urtwn_set_led(sc, URTWN_LED_LINK, 0);
|
|
|
|
break;
|
|
|
|
case IEEE80211_S_SCAN:
|
|
|
|
/* Pause AC Tx queues. */
|
|
|
|
urtwn_write_1(sc, R92C_TXPAUSE,
|
2016-01-04 21:16:49 +00:00
|
|
|
urtwn_read_1(sc, R92C_TXPAUSE) | R92C_TX_QUEUE_AC);
|
2013-06-08 16:02:31 +00:00
|
|
|
break;
|
|
|
|
case IEEE80211_S_AUTH:
|
|
|
|
urtwn_set_chan(sc, ic->ic_curchan, NULL);
|
|
|
|
break;
|
|
|
|
case IEEE80211_S_RUN:
|
|
|
|
if (vap->iv_opmode == IEEE80211_M_MONITOR) {
|
|
|
|
/* Turn link LED on. */
|
|
|
|
urtwn_set_led(sc, URTWN_LED_LINK, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ni = ieee80211_ref_node(vap->iv_bss);
|
2015-11-10 00:12:00 +00:00
|
|
|
|
|
|
|
if (ic->ic_bsschan == IEEE80211_CHAN_ANYC ||
|
|
|
|
ni->ni_chan == IEEE80211_CHAN_ANYC) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"%s: could not move to RUN state\n", __func__);
|
|
|
|
error = EINVAL;
|
|
|
|
goto end_run;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (vap->iv_opmode) {
|
|
|
|
case IEEE80211_M_STA:
|
|
|
|
mode = R92C_MSR_INFRA;
|
|
|
|
break;
|
2015-11-10 12:52:26 +00:00
|
|
|
case IEEE80211_M_IBSS:
|
|
|
|
mode = R92C_MSR_ADHOC;
|
|
|
|
break;
|
2015-11-10 00:12:00 +00:00
|
|
|
case IEEE80211_M_HOSTAP:
|
|
|
|
mode = R92C_MSR_AP;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
device_printf(sc->sc_dev, "undefined opmode %d\n",
|
|
|
|
vap->iv_opmode);
|
|
|
|
error = EINVAL;
|
|
|
|
goto end_run;
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Set media status to 'Associated'. */
|
2015-11-10 00:12:00 +00:00
|
|
|
urtwn_set_mode(sc, mode);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Set BSSID. */
|
|
|
|
urtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0]));
|
|
|
|
urtwn_write_4(sc, R92C_BSSID + 4, LE_READ_2(&ni->ni_bssid[4]));
|
|
|
|
|
|
|
|
if (ic->ic_curmode == IEEE80211_MODE_11B)
|
|
|
|
urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0);
|
|
|
|
else /* 802.11b/g */
|
|
|
|
urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3);
|
|
|
|
|
|
|
|
/* Enable Rx of data frames. */
|
|
|
|
urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
|
|
|
|
|
|
|
|
/* Flush all AC queues. */
|
|
|
|
urtwn_write_1(sc, R92C_TXPAUSE, 0);
|
|
|
|
|
|
|
|
/* Set beacon interval. */
|
|
|
|
urtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval);
|
|
|
|
|
|
|
|
/* Allow Rx from our BSSID only. */
|
2015-11-08 23:21:54 +00:00
|
|
|
if (ic->ic_promisc == 0) {
|
2015-11-10 00:12:00 +00:00
|
|
|
reg = urtwn_read_4(sc, R92C_RCR);
|
|
|
|
|
|
|
|
if (vap->iv_opmode != IEEE80211_M_HOSTAP)
|
|
|
|
reg |= R92C_RCR_CBSSID_DATA;
|
2015-11-10 12:52:26 +00:00
|
|
|
if (vap->iv_opmode != IEEE80211_M_IBSS)
|
|
|
|
reg |= R92C_RCR_CBSSID_BCN;
|
2015-11-10 00:12:00 +00:00
|
|
|
|
|
|
|
urtwn_write_4(sc, R92C_RCR, reg);
|
|
|
|
}
|
|
|
|
|
2015-11-10 12:52:26 +00:00
|
|
|
if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
|
|
|
|
vap->iv_opmode == IEEE80211_M_IBSS) {
|
2015-11-10 00:12:00 +00:00
|
|
|
error = urtwn_setup_beacon(sc, ni);
|
|
|
|
if (error != 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"unable to push beacon into the chip, "
|
|
|
|
"error %d\n", error);
|
|
|
|
goto end_run;
|
|
|
|
}
|
2015-11-08 23:21:54 +00:00
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Enable TSF synchronization. */
|
2015-11-10 00:12:00 +00:00
|
|
|
urtwn_tsf_sync_enable(sc, vap);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
urtwn_write_1(sc, R92C_SIFS_CCK + 1, 10);
|
|
|
|
urtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10);
|
|
|
|
urtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10);
|
|
|
|
urtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10);
|
|
|
|
urtwn_write_1(sc, R92C_R2T_SIFS + 1, 10);
|
|
|
|
urtwn_write_1(sc, R92C_T2T_SIFS + 1, 10);
|
|
|
|
|
|
|
|
/* Intialize rate adaptation. */
|
2015-12-13 21:00:21 +00:00
|
|
|
if (!(sc->chip & URTWN_CHIP_88E))
|
2014-04-25 08:01:22 +00:00
|
|
|
urtwn_ra_init(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Turn link LED on. */
|
|
|
|
urtwn_set_led(sc, URTWN_LED_LINK, 1);
|
|
|
|
|
|
|
|
sc->avg_pwdb = -1; /* Reset average RSSI. */
|
|
|
|
/* Reset temperature calibration state machine. */
|
2016-01-20 23:55:39 +00:00
|
|
|
sc->sc_flags &= ~URTWN_TEMP_MEASURED;
|
2013-06-08 16:02:31 +00:00
|
|
|
sc->thcal_lctemp = 0;
|
2016-01-20 23:55:39 +00:00
|
|
|
/* Start periodic calibration. */
|
|
|
|
callout_reset(&sc->sc_calib_to, 2*hz, urtwn_calib_to, sc);
|
2015-11-10 00:12:00 +00:00
|
|
|
|
|
|
|
end_run:
|
2013-06-08 16:02:31 +00:00
|
|
|
ieee80211_free_node(ni);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2015-11-10 00:12:00 +00:00
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
IEEE80211_LOCK(ic);
|
2015-11-10 00:12:00 +00:00
|
|
|
return (error != 0 ? error : uvp->newstate(vap, nstate, arg));
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2016-01-20 23:55:39 +00:00
|
|
|
static void
|
|
|
|
urtwn_calib_to(void *arg)
|
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = arg;
|
|
|
|
|
|
|
|
/* Do it in a process context. */
|
|
|
|
urtwn_cmd_sleepable(sc, NULL, 0, urtwn_calib_cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_calib_cb(struct urtwn_softc *sc, union sec_param *data)
|
|
|
|
{
|
|
|
|
/* Do temperature compensation. */
|
|
|
|
urtwn_temp_calib(sc);
|
|
|
|
|
|
|
|
if ((urtwn_read_1(sc, R92C_MSR) & R92C_MSR_MASK) != R92C_MSR_NOLINK)
|
|
|
|
callout_reset(&sc->sc_calib_to, 2*hz, urtwn_calib_to, sc);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static void
|
|
|
|
urtwn_watchdog(void *arg)
|
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = arg;
|
|
|
|
|
|
|
|
if (sc->sc_txtimer > 0) {
|
|
|
|
if (--sc->sc_txtimer == 0) {
|
|
|
|
device_printf(sc->sc_dev, "device timeout\n");
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
counter_u64_add(sc->sc_ic.ic_oerrors, 1);
|
2013-06-08 16:02:31 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_update_avgrssi(struct urtwn_softc *sc, int rate, int8_t rssi)
|
|
|
|
{
|
|
|
|
int pwdb;
|
|
|
|
|
|
|
|
/* Convert antenna signal to percentage. */
|
|
|
|
if (rssi <= -100 || rssi >= 20)
|
|
|
|
pwdb = 0;
|
|
|
|
else if (rssi >= 0)
|
|
|
|
pwdb = 100;
|
|
|
|
else
|
|
|
|
pwdb = 100 + rssi;
|
2014-04-25 08:01:22 +00:00
|
|
|
if (!(sc->chip & URTWN_CHIP_88E)) {
|
2015-10-22 15:42:53 +00:00
|
|
|
if (rate <= URTWN_RIDX_CCK11) {
|
2014-04-25 08:01:22 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
if (sc->avg_pwdb == -1) /* Init. */
|
|
|
|
sc->avg_pwdb = pwdb;
|
|
|
|
else if (sc->avg_pwdb < pwdb)
|
|
|
|
sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1;
|
|
|
|
else
|
|
|
|
sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20);
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_RSSI, "%s: PWDB %d, EMA %d\n", __func__,
|
2016-01-20 23:27:02 +00:00
|
|
|
pwdb, sc->avg_pwdb);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int8_t
|
|
|
|
urtwn_get_rssi(struct urtwn_softc *sc, int rate, void *physt)
|
|
|
|
{
|
|
|
|
static const int8_t cckoff[] = { 16, -12, -26, -46 };
|
|
|
|
struct r92c_rx_phystat *phy;
|
|
|
|
struct r92c_rx_cck *cck;
|
|
|
|
uint8_t rpt;
|
|
|
|
int8_t rssi;
|
|
|
|
|
2015-10-22 15:42:53 +00:00
|
|
|
if (rate <= URTWN_RIDX_CCK11) {
|
2013-06-08 16:02:31 +00:00
|
|
|
cck = (struct r92c_rx_cck *)physt;
|
|
|
|
if (sc->sc_flags & URTWN_FLAG_CCK_HIPWR) {
|
|
|
|
rpt = (cck->agc_rpt >> 5) & 0x3;
|
|
|
|
rssi = (cck->agc_rpt & 0x1f) << 1;
|
|
|
|
} else {
|
|
|
|
rpt = (cck->agc_rpt >> 6) & 0x3;
|
|
|
|
rssi = cck->agc_rpt & 0x3e;
|
|
|
|
}
|
|
|
|
rssi = cckoff[rpt] - rssi;
|
|
|
|
} else { /* OFDM/HT. */
|
|
|
|
phy = (struct r92c_rx_phystat *)physt;
|
|
|
|
rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110;
|
|
|
|
}
|
|
|
|
return (rssi);
|
|
|
|
}
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
static int8_t
|
|
|
|
urtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt)
|
|
|
|
{
|
|
|
|
struct r92c_rx_phystat *phy;
|
|
|
|
struct r88e_rx_cck *cck;
|
|
|
|
uint8_t cck_agc_rpt, lna_idx, vga_idx;
|
|
|
|
int8_t rssi;
|
|
|
|
|
2014-04-26 14:39:58 +00:00
|
|
|
rssi = 0;
|
2015-10-22 15:42:53 +00:00
|
|
|
if (rate <= URTWN_RIDX_CCK11) {
|
2014-04-25 08:01:22 +00:00
|
|
|
cck = (struct r88e_rx_cck *)physt;
|
|
|
|
cck_agc_rpt = cck->agc_rpt;
|
|
|
|
lna_idx = (cck_agc_rpt & 0xe0) >> 5;
|
2015-04-04 08:36:02 +00:00
|
|
|
vga_idx = cck_agc_rpt & 0x1f;
|
2014-04-25 08:01:22 +00:00
|
|
|
switch (lna_idx) {
|
|
|
|
case 7:
|
|
|
|
if (vga_idx <= 27)
|
|
|
|
rssi = -100 + 2* (27 - vga_idx);
|
|
|
|
else
|
|
|
|
rssi = -100;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
rssi = -48 + 2 * (2 - vga_idx);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
rssi = -42 + 2 * (7 - vga_idx);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
rssi = -36 + 2 * (7 - vga_idx);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
rssi = -24 + 2 * (7 - vga_idx);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
rssi = -12 + 2 * (5 - vga_idx);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
rssi = 8 - (2 * vga_idx);
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
rssi = 14 - (2 * vga_idx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rssi += 6;
|
|
|
|
} else { /* OFDM/HT. */
|
|
|
|
phy = (struct r92c_rx_phystat *)physt;
|
|
|
|
rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110;
|
|
|
|
}
|
|
|
|
return (rssi);
|
|
|
|
}
|
|
|
|
|
2015-12-13 21:00:21 +00:00
|
|
|
static __inline uint8_t
|
|
|
|
rate2ridx(uint8_t rate)
|
|
|
|
{
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
if (rate & IEEE80211_RATE_MCS) {
|
|
|
|
/* 11n rates start at idx 12 */
|
|
|
|
return ((rate & 0xf) + 12);
|
|
|
|
}
|
2015-12-13 21:00:21 +00:00
|
|
|
switch (rate) {
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
/* 11g */
|
2015-12-13 21:00:21 +00:00
|
|
|
case 12: return 4;
|
|
|
|
case 18: return 5;
|
|
|
|
case 24: return 6;
|
|
|
|
case 36: return 7;
|
|
|
|
case 48: return 8;
|
|
|
|
case 72: return 9;
|
|
|
|
case 96: return 10;
|
|
|
|
case 108: return 11;
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
/* 11b */
|
2015-12-13 21:00:21 +00:00
|
|
|
case 2: return 0;
|
|
|
|
case 4: return 1;
|
|
|
|
case 11: return 2;
|
|
|
|
case 22: return 3;
|
|
|
|
default: return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static int
|
2015-11-09 23:46:13 +00:00
|
|
|
urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni,
|
|
|
|
struct mbuf *m, struct urtwn_data *data)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
2015-12-13 21:00:21 +00:00
|
|
|
const struct ieee80211_txparam *tp;
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2013-06-08 16:02:31 +00:00
|
|
|
struct ieee80211vap *vap = ni->ni_vap;
|
2015-12-13 21:00:21 +00:00
|
|
|
struct ieee80211_key *k = NULL;
|
|
|
|
struct ieee80211_channel *chan;
|
|
|
|
struct ieee80211_frame *wh;
|
2013-06-08 16:02:31 +00:00
|
|
|
struct r92c_tx_desc *txd;
|
2015-12-13 21:00:21 +00:00
|
|
|
uint8_t macid, raid, rate, ridx, subtype, type, tid, qsel;
|
2015-12-09 09:29:38 +00:00
|
|
|
int hasqos, ismcast;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Software crypto.
|
|
|
|
*/
|
2015-11-09 23:46:13 +00:00
|
|
|
wh = mtod(m, struct ieee80211_frame *);
|
2014-04-25 08:01:22 +00:00
|
|
|
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
|
2015-11-09 23:46:13 +00:00
|
|
|
subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
|
2015-12-09 09:29:38 +00:00
|
|
|
hasqos = IEEE80211_QOS_HAS_SEQ(wh);
|
2015-11-09 23:46:13 +00:00
|
|
|
ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
2015-12-09 09:29:38 +00:00
|
|
|
/* Select TX ring for this frame. */
|
|
|
|
if (hasqos) {
|
|
|
|
tid = ((const struct ieee80211_qosframe *)wh)->i_qos[0];
|
|
|
|
tid &= IEEE80211_QOS_TID;
|
|
|
|
} else
|
|
|
|
tid = 0;
|
|
|
|
|
2015-12-13 21:00:21 +00:00
|
|
|
chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ?
|
|
|
|
ni->ni_chan : ic->ic_curchan;
|
|
|
|
tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
|
|
|
|
|
|
|
|
/* Choose a TX rate index. */
|
|
|
|
if (type == IEEE80211_FC0_TYPE_MGT)
|
|
|
|
rate = tp->mgmtrate;
|
|
|
|
else if (ismcast)
|
|
|
|
rate = tp->mcastrate;
|
|
|
|
else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
|
|
|
|
rate = tp->ucastrate;
|
|
|
|
else if (m->m_flags & M_EAPOL)
|
|
|
|
rate = tp->mgmtrate;
|
|
|
|
else {
|
|
|
|
if (URTWN_CHIP_HAS_RATECTL(sc)) {
|
|
|
|
/* XXX pass pktlen */
|
|
|
|
(void) ieee80211_ratectl_rate(ni, NULL, 0);
|
|
|
|
rate = ni->ni_txrate;
|
|
|
|
} else {
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
/* XXX TODO: drop the default rate for 11b/11g? */
|
|
|
|
if (ni->ni_flags & IEEE80211_NODE_HT)
|
|
|
|
rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */
|
|
|
|
else if (ic->ic_curmode != IEEE80211_MODE_11B)
|
2015-12-13 21:00:21 +00:00
|
|
|
rate = 108;
|
|
|
|
else
|
|
|
|
rate = 22;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
/*
|
|
|
|
* XXX TODO: this should be per-node, for 11b versus 11bg
|
|
|
|
* nodes in hostap mode
|
|
|
|
*/
|
2015-12-13 21:00:21 +00:00
|
|
|
ridx = rate2ridx(rate);
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
if (ni->ni_flags & IEEE80211_NODE_HT)
|
|
|
|
raid = R92C_RAID_11GN;
|
|
|
|
else if (ic->ic_curmode != IEEE80211_MODE_11B)
|
2015-12-13 21:00:21 +00:00
|
|
|
raid = R92C_RAID_11BG;
|
|
|
|
else
|
|
|
|
raid = R92C_RAID_11B;
|
|
|
|
|
2014-01-08 08:06:56 +00:00
|
|
|
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
|
2015-11-09 23:46:13 +00:00
|
|
|
k = ieee80211_crypto_encap(ni, m);
|
2013-06-08 16:02:31 +00:00
|
|
|
if (k == NULL) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"ieee80211_crypto_encap returns NULL.\n");
|
|
|
|
return (ENOBUFS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* in case packet header moved, reset pointer */
|
2015-11-09 23:46:13 +00:00
|
|
|
wh = mtod(m, struct ieee80211_frame *);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
2015-04-04 08:36:02 +00:00
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Fill Tx descriptor. */
|
|
|
|
txd = (struct r92c_tx_desc *)data->buf;
|
|
|
|
memset(txd, 0, sizeof(*txd));
|
|
|
|
|
|
|
|
txd->txdw0 |= htole32(
|
|
|
|
SM(R92C_TXDW0_OFFSET, sizeof(*txd)) |
|
|
|
|
R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG);
|
2015-11-09 23:46:13 +00:00
|
|
|
if (ismcast)
|
2013-06-08 16:02:31 +00:00
|
|
|
txd->txdw0 |= htole32(R92C_TXDW0_BMCAST);
|
2015-11-09 23:46:13 +00:00
|
|
|
|
|
|
|
if (!ismcast) {
|
2015-12-13 21:00:21 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
|
|
|
struct urtwn_node *un = URTWN_NODE(ni);
|
|
|
|
macid = un->id;
|
|
|
|
} else
|
|
|
|
macid = URTWN_MACID_BSS;
|
2015-11-09 23:46:13 +00:00
|
|
|
|
|
|
|
if (type == IEEE80211_FC0_TYPE_DATA) {
|
2015-12-09 09:29:38 +00:00
|
|
|
qsel = tid % URTWN_MAX_TID;
|
2015-11-09 23:46:13 +00:00
|
|
|
|
2015-12-13 21:00:21 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
|
|
|
txd->txdw2 |= htole32(
|
|
|
|
R88E_TXDW2_AGGBK |
|
|
|
|
R88E_TXDW2_CCX_RPT);
|
|
|
|
} else
|
2015-11-09 23:46:13 +00:00
|
|
|
txd->txdw1 |= htole32(R92C_TXDW1_AGGBK);
|
|
|
|
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
/* protmode, non-HT */
|
|
|
|
/* XXX TODO: noack frames? */
|
|
|
|
if ((rate & 0x80) == 0 &&
|
|
|
|
(ic->ic_flags & IEEE80211_F_USEPROT)) {
|
2015-11-09 23:46:13 +00:00
|
|
|
switch (ic->ic_protmode) {
|
|
|
|
case IEEE80211_PROT_CTSONLY:
|
|
|
|
txd->txdw4 |= htole32(
|
|
|
|
R92C_TXDW4_CTS2SELF |
|
|
|
|
R92C_TXDW4_HWRTSEN);
|
|
|
|
break;
|
|
|
|
case IEEE80211_PROT_RTSCTS:
|
|
|
|
txd->txdw4 |= htole32(
|
|
|
|
R92C_TXDW4_RTSEN |
|
|
|
|
R92C_TXDW4_HWRTSEN);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
|
|
|
|
/* protmode, HT */
|
|
|
|
/* XXX TODO: noack frames? */
|
|
|
|
if ((rate & 0x80) &&
|
|
|
|
(ic->ic_htprotmode == IEEE80211_PROT_RTSCTS)) {
|
|
|
|
txd->txdw4 |= htole32(
|
|
|
|
R92C_TXDW4_RTSEN |
|
|
|
|
R92C_TXDW4_HWRTSEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX TODO: rtsrate is configurable? 24mbit may
|
|
|
|
* be a bit high for RTS rate? */
|
2015-11-09 23:46:13 +00:00
|
|
|
txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE,
|
|
|
|
URTWN_RIDX_OFDM24));
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
|
2015-11-09 23:46:13 +00:00
|
|
|
txd->txdw5 |= htole32(0x0001ff00);
|
|
|
|
} else /* IEEE80211_FC0_TYPE_MGT */
|
|
|
|
qsel = R92C_TXDW1_QSEL_MGNT;
|
2013-06-08 16:02:31 +00:00
|
|
|
} else {
|
2015-11-09 23:46:13 +00:00
|
|
|
macid = URTWN_MACID_BC;
|
|
|
|
qsel = R92C_TXDW1_QSEL_MGNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
txd->txdw1 |= htole32(
|
|
|
|
SM(R92C_TXDW1_QSEL, qsel) |
|
|
|
|
SM(R92C_TXDW1_RAID, raid));
|
2013-06-08 16:02:31 +00:00
|
|
|
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
/* XXX TODO: 40MHZ flag? */
|
|
|
|
/* XXX TODO: AMPDU flag? (AGG_ENABLE or AGG_BREAK?) Density shift? */
|
|
|
|
/* XXX Short preamble? */
|
|
|
|
/* XXX Short-GI? */
|
|
|
|
|
2015-11-09 23:46:13 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, macid));
|
|
|
|
else
|
|
|
|
txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, macid));
|
|
|
|
|
|
|
|
txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx));
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
|
2015-12-05 15:08:01 +00:00
|
|
|
/* Force this rate if needed. */
|
2015-12-13 21:00:21 +00:00
|
|
|
if (URTWN_CHIP_HAS_RATECTL(sc) || ismcast ||
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
(tp->ucastrate != IEEE80211_FIXED_RATE_NONE) ||
|
2015-12-13 21:00:21 +00:00
|
|
|
(m->m_flags & M_EAPOL) || type != IEEE80211_FC0_TYPE_DATA)
|
2013-06-08 16:02:31 +00:00
|
|
|
txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
|
|
|
|
|
2015-12-09 09:29:38 +00:00
|
|
|
if (!hasqos) {
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Use HW sequence numbering for non-QoS frames. */
|
2015-12-05 15:08:01 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
txd->txdseq = htole16(R88E_TXDSEQ_HWSEQ_EN);
|
|
|
|
else
|
|
|
|
txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN);
|
2015-11-09 23:46:13 +00:00
|
|
|
} else {
|
|
|
|
/* Set sequence number. */
|
|
|
|
txd->txdseq = htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-12-13 22:00:19 +00:00
|
|
|
if (k != NULL && !(k->wk_flags & IEEE80211_KEY_SWCRYPT)) {
|
|
|
|
uint8_t cipher;
|
|
|
|
|
|
|
|
switch (k->wk_cipher->ic_cipher) {
|
|
|
|
case IEEE80211_CIPHER_WEP:
|
|
|
|
case IEEE80211_CIPHER_TKIP:
|
|
|
|
cipher = R92C_TXDW1_CIPHER_RC4;
|
|
|
|
break;
|
|
|
|
case IEEE80211_CIPHER_AES_CCM:
|
|
|
|
cipher = R92C_TXDW1_CIPHER_AES;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
device_printf(sc->sc_dev, "%s: unknown cipher %d\n",
|
|
|
|
__func__, k->wk_cipher->ic_cipher);
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, cipher));
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
if (ieee80211_radiotap_active_vap(vap)) {
|
|
|
|
struct urtwn_tx_radiotap_header *tap = &sc->sc_txtap;
|
|
|
|
|
|
|
|
tap->wt_flags = 0;
|
2015-11-09 23:46:13 +00:00
|
|
|
if (k != NULL)
|
|
|
|
tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
|
|
|
|
ieee80211_radiotap_tx(vap, m);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 23:46:13 +00:00
|
|
|
data->ni = ni;
|
|
|
|
|
|
|
|
urtwn_tx_start(sc, m, type, data);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2015-12-14 20:39:38 +00:00
|
|
|
static int
|
|
|
|
urtwn_tx_raw(struct urtwn_softc *sc, struct ieee80211_node *ni,
|
|
|
|
struct mbuf *m, struct urtwn_data *data,
|
|
|
|
const struct ieee80211_bpf_params *params)
|
|
|
|
{
|
|
|
|
struct ieee80211vap *vap = ni->ni_vap;
|
|
|
|
struct ieee80211_key *k = NULL;
|
|
|
|
struct ieee80211_frame *wh;
|
|
|
|
struct r92c_tx_desc *txd;
|
|
|
|
uint8_t cipher, ridx, type;
|
|
|
|
|
|
|
|
/* Encrypt the frame if need be. */
|
|
|
|
cipher = R92C_TXDW1_CIPHER_NONE;
|
|
|
|
if (params->ibp_flags & IEEE80211_BPF_CRYPTO) {
|
|
|
|
/* Retrieve key for TX. */
|
|
|
|
k = ieee80211_crypto_encap(ni, m);
|
|
|
|
if (k == NULL)
|
|
|
|
return (ENOBUFS);
|
|
|
|
|
|
|
|
if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) {
|
|
|
|
switch (k->wk_cipher->ic_cipher) {
|
|
|
|
case IEEE80211_CIPHER_WEP:
|
|
|
|
case IEEE80211_CIPHER_TKIP:
|
|
|
|
cipher = R92C_TXDW1_CIPHER_RC4;
|
|
|
|
break;
|
|
|
|
case IEEE80211_CIPHER_AES_CCM:
|
|
|
|
cipher = R92C_TXDW1_CIPHER_AES;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"%s: unknown cipher %d\n",
|
|
|
|
__func__, k->wk_cipher->ic_cipher);
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
/* XXX TODO: 11n checks, matching urtwn_tx_data() */
|
|
|
|
|
2015-12-14 20:39:38 +00:00
|
|
|
wh = mtod(m, struct ieee80211_frame *);
|
|
|
|
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
|
|
|
|
|
|
|
|
/* Fill Tx descriptor. */
|
|
|
|
txd = (struct r92c_tx_desc *)data->buf;
|
|
|
|
memset(txd, 0, sizeof(*txd));
|
|
|
|
|
|
|
|
txd->txdw0 |= htole32(
|
|
|
|
SM(R92C_TXDW0_OFFSET, sizeof(*txd)) |
|
|
|
|
R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG);
|
|
|
|
if (IEEE80211_IS_MULTICAST(wh->i_addr1))
|
|
|
|
txd->txdw0 |= htole32(R92C_TXDW0_BMCAST);
|
|
|
|
|
|
|
|
if (params->ibp_flags & IEEE80211_BPF_RTS)
|
|
|
|
txd->txdw4 |= htole32(R92C_TXDW4_RTSEN);
|
|
|
|
if (params->ibp_flags & IEEE80211_BPF_CTS)
|
|
|
|
txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF);
|
|
|
|
if (txd->txdw4 & htole32(R92C_TXDW4_RTSEN | R92C_TXDW4_CTS2SELF)) {
|
|
|
|
txd->txdw4 |= htole32(R92C_TXDW4_HWRTSEN);
|
|
|
|
txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE,
|
|
|
|
URTWN_RIDX_OFDM24));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, URTWN_MACID_BC));
|
|
|
|
else
|
|
|
|
txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, URTWN_MACID_BC));
|
|
|
|
|
[urtwn] welcome basic 11n support to urtwn.
This is a pretty good reference for teaching an almost-11n-capable
driver about 11n.
It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
for transmit. That'll come later. This means that receive throughput
should be higher, but transmit throughput won't have changed much.
* Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
so until we correctly handle it in software driven scans, disable.
* Add null 11n methods for channel width / ampdu_enable.
the firmware can apparently handle ampdu tx (and hopefully block-ack
handling and retransmission) so I'll go review the linux code and
figure it out.
* Set the number of tx/rx streams. I /hope/ that nchains == nstreams
here.
* Add 11n channels in the call to ieee80211_init_channels().
* Don't enable HT40 for now - I'll have to verify the channel set command
and tidy it up a bit first.
* Teach the RX path about M_AMPDU for 11n nodes. Kinda wonder why
we aren't just doing this in net80211 already, this is the fourth
driver I've had to do this to.
* Teach rate2ridx() about MCS rates and what hardware rates to use.
* Teach the urtwn_tx_data() routine about MCS/11ng transmission.
It doesn't know about short-gi and 40MHz modes yet; that'll come
later.
* For 8192CU firmware, teach the rate table code about MCS rates.
* Ensure that the fixed rate transmit sets the right transmit flag
so the firmware obeys the driver transmit path.
* Set the default transmit rate to MCS4 if no rate control is available.
* Add HT protection (RTS-CTS exchange) support.
* Add appropriate XXX TODO entries.
TODO:
* 40MHz, short-gi, etc - channel tuning, TX, RX;
* teach urtwn_tx_raw() about (more) 11n stuff;
* A-MPDU TX would be nice!
Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
Tested:
* RTL8188EU - STA (me)
* RTL8192CU - STA (me)
* RTL8188EU - hostap (avos)
* RTL8192CU - STA (avos)
Reviewed by: avos
2016-03-22 01:09:15 +00:00
|
|
|
/* XXX TODO: rate index/config (RAID) for 11n? */
|
2015-12-14 20:39:38 +00:00
|
|
|
txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT));
|
|
|
|
txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, cipher));
|
|
|
|
|
|
|
|
/* Choose a TX rate index. */
|
|
|
|
ridx = rate2ridx(params->ibp_rate0);
|
|
|
|
txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx));
|
|
|
|
txd->txdw5 |= htole32(0x0001ff00);
|
|
|
|
txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
|
|
|
|
|
|
|
|
if (!IEEE80211_QOS_HAS_SEQ(wh)) {
|
|
|
|
/* Use HW sequence numbering for non-QoS frames. */
|
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
txd->txdseq = htole16(R88E_TXDSEQ_HWSEQ_EN);
|
|
|
|
else
|
|
|
|
txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN);
|
|
|
|
} else {
|
|
|
|
/* Set sequence number. */
|
|
|
|
txd->txdseq = htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ieee80211_radiotap_active_vap(vap)) {
|
|
|
|
struct urtwn_tx_radiotap_header *tap = &sc->sc_txtap;
|
|
|
|
|
|
|
|
tap->wt_flags = 0;
|
|
|
|
if (k != NULL)
|
|
|
|
tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
|
|
|
|
ieee80211_radiotap_tx(vap, m);
|
|
|
|
}
|
|
|
|
|
|
|
|
data->ni = ni;
|
|
|
|
|
|
|
|
urtwn_tx_start(sc, m, type, data);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2015-11-09 23:46:13 +00:00
|
|
|
static void
|
|
|
|
urtwn_tx_start(struct urtwn_softc *sc, struct mbuf *m, uint8_t type,
|
|
|
|
struct urtwn_data *data)
|
|
|
|
{
|
|
|
|
struct usb_xfer *xfer;
|
|
|
|
struct r92c_tx_desc *txd;
|
|
|
|
uint16_t ac, sum;
|
|
|
|
int i, xferlen;
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
|
|
|
ac = M_WME_GETAC(m);
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case IEEE80211_FC0_TYPE_CTL:
|
|
|
|
case IEEE80211_FC0_TYPE_MGT:
|
|
|
|
xfer = sc->sc_xfer[URTWN_BULK_TX_VO];
|
|
|
|
break;
|
|
|
|
default:
|
2015-12-09 09:29:38 +00:00
|
|
|
xfer = sc->sc_xfer[wme2queue[ac].qid];
|
2015-11-09 23:46:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
txd = (struct r92c_tx_desc *)data->buf;
|
|
|
|
txd->txdw0 |= htole32(SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len));
|
|
|
|
|
|
|
|
/* Compute Tx descriptor checksum. */
|
|
|
|
sum = 0;
|
|
|
|
for (i = 0; i < sizeof(*txd) / 2; i++)
|
|
|
|
sum ^= ((uint16_t *)txd)[i];
|
|
|
|
txd->txdsum = sum; /* NB: already little endian. */
|
|
|
|
|
|
|
|
xferlen = sizeof(*txd) + m->m_pkthdr.len;
|
|
|
|
m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&txd[1]);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
data->buflen = xferlen;
|
2015-11-09 23:46:13 +00:00
|
|
|
data->m = m;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
|
|
|
|
usbd_transfer_start(xfer);
|
|
|
|
}
|
|
|
|
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
static int
|
|
|
|
urtwn_transmit(struct ieee80211com *ic, struct mbuf *m)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct urtwn_softc *sc = ic->ic_softc;
|
|
|
|
int error;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
URTWN_LOCK(sc);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
if ((sc->sc_flags & URTWN_RUNNING) == 0) {
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
return (ENXIO);
|
|
|
|
}
|
|
|
|
error = mbufq_enqueue(&sc->sc_snd, m);
|
|
|
|
if (error) {
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
urtwn_start(sc);
|
2014-02-14 01:47:12 +00:00
|
|
|
URTWN_UNLOCK(sc);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
|
|
|
|
return (0);
|
2014-02-14 01:47:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
urtwn_start(struct urtwn_softc *sc)
|
2014-02-14 01:47:12 +00:00
|
|
|
{
|
|
|
|
struct ieee80211_node *ni;
|
|
|
|
struct mbuf *m;
|
|
|
|
struct urtwn_data *bf;
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
|
2013-06-08 16:02:31 +00:00
|
|
|
bf = urtwn_getbuf(sc);
|
|
|
|
if (bf == NULL) {
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
mbufq_prepend(&sc->sc_snd, m);
|
2013-06-08 16:02:31 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
|
|
|
|
m->m_pkthdr.rcvif = NULL;
|
2016-04-05 22:14:21 +00:00
|
|
|
|
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_XMIT, "%s: called; m=%p\n",
|
|
|
|
__func__,
|
|
|
|
m);
|
|
|
|
|
2015-11-09 23:46:13 +00:00
|
|
|
if (urtwn_tx_data(sc, ni, m, bf) != 0) {
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
if_inc_counter(ni->ni_vap->iv_ifp,
|
|
|
|
IFCOUNTER_OERRORS, 1);
|
2013-06-08 16:02:31 +00:00
|
|
|
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
|
2015-09-29 05:03:24 +00:00
|
|
|
m_freem(m);
|
2013-06-08 16:02:31 +00:00
|
|
|
ieee80211_free_node(ni);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
sc->sc_txtimer = 5;
|
|
|
|
callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
static void
|
|
|
|
urtwn_parent(struct ieee80211com *ic)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
2015-08-20 03:57:41 +00:00
|
|
|
struct urtwn_softc *sc = ic->ic_softc;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2014-03-14 06:37:08 +00:00
|
|
|
URTWN_LOCK(sc);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
if (sc->sc_flags & URTWN_DETACHED) {
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
return;
|
|
|
|
}
|
2014-03-14 06:37:08 +00:00
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
if (ic->ic_nrunning > 0) {
|
|
|
|
if (urtwn_init(sc) != 0) {
|
|
|
|
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
|
|
|
if (vap != NULL)
|
|
|
|
ieee80211_stop(vap);
|
|
|
|
} else
|
|
|
|
ieee80211_start_all(ic);
|
|
|
|
} else
|
|
|
|
urtwn_stop(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
static __inline int
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_power_on(struct urtwn_softc *sc)
|
2014-04-25 08:01:22 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
return sc->sc_power_on(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_r92c_power_on(struct urtwn_softc *sc)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
|
|
|
uint32_t reg;
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_error_t error;
|
2013-06-08 16:02:31 +00:00
|
|
|
int ntries;
|
|
|
|
|
|
|
|
/* Wait for autoload done bit. */
|
|
|
|
for (ntries = 0; ntries < 1000; ntries++) {
|
|
|
|
if (urtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN)
|
|
|
|
break;
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
if (ntries == 1000) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"timeout waiting for chip autoload\n");
|
|
|
|
return (ETIMEDOUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Unlock ISO/CLK/Power control register. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, R92C_RSV_CTRL, 0);
|
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Move SPS into PWM mode. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b);
|
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
reg = urtwn_read_1(sc, R92C_LDOV12D_CTRL);
|
|
|
|
if (!(reg & R92C_LDOV12D_CTRL_LDV12_EN)) {
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, R92C_LDOV12D_CTRL,
|
2013-06-08 16:02:31 +00:00
|
|
|
reg | R92C_LDOV12D_CTRL_LDV12_EN);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, R92C_SYS_ISO_CTRL,
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_read_1(sc, R92C_SYS_ISO_CTRL) &
|
|
|
|
~R92C_SYS_ISO_CTRL_MD2PP);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Auto enable WLAN. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_APS_FSMCO,
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
for (ntries = 0; ntries < 1000; ntries++) {
|
2014-03-06 06:39:55 +00:00
|
|
|
if (!(urtwn_read_2(sc, R92C_APS_FSMCO) &
|
|
|
|
R92C_APS_FSMCO_APFM_ONMAC))
|
2013-06-08 16:02:31 +00:00
|
|
|
break;
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
if (ntries == 1000) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"timeout waiting for MAC auto ON\n");
|
|
|
|
return (ETIMEDOUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable radio, GPIO and LED functions. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_APS_FSMCO,
|
2013-06-08 16:02:31 +00:00
|
|
|
R92C_APS_FSMCO_AFSM_HSUS |
|
|
|
|
R92C_APS_FSMCO_PDN_EN |
|
|
|
|
R92C_APS_FSMCO_PFM_ALDN);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Release RF digital isolation. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_SYS_ISO_CTRL,
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Initialize MAC. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, R92C_APSD_CTRL,
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
for (ntries = 0; ntries < 200; ntries++) {
|
|
|
|
if (!(urtwn_read_1(sc, R92C_APSD_CTRL) &
|
|
|
|
R92C_APSD_CTRL_OFF_STATUS))
|
|
|
|
break;
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
if (ntries == 200) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"timeout waiting for MAC initialization\n");
|
|
|
|
return (ETIMEDOUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
|
|
|
|
reg = urtwn_read_2(sc, R92C_CR);
|
|
|
|
reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
|
|
|
|
R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN |
|
|
|
|
R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN |
|
|
|
|
R92C_CR_ENSEC;
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_CR, reg);
|
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, 0xfe10, 0x19);
|
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
static int
|
|
|
|
urtwn_r88e_power_on(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
uint32_t reg;
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_error_t error;
|
2014-04-25 08:01:22 +00:00
|
|
|
int ntries;
|
|
|
|
|
|
|
|
/* Wait for power ready bit. */
|
|
|
|
for (ntries = 0; ntries < 5000; ntries++) {
|
2015-04-24 04:57:18 +00:00
|
|
|
if (urtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST)
|
2014-04-25 08:01:22 +00:00
|
|
|
break;
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2014-04-25 08:01:22 +00:00
|
|
|
}
|
|
|
|
if (ntries == 5000) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"timeout waiting for chip power up\n");
|
|
|
|
return (ETIMEDOUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset BB. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, R92C_SYS_FUNC_EN,
|
2014-04-25 08:01:22 +00:00
|
|
|
urtwn_read_1(sc, R92C_SYS_FUNC_EN) & ~(R92C_SYS_FUNC_EN_BBRSTB |
|
|
|
|
R92C_SYS_FUNC_EN_BB_GLB_RST));
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 2,
|
2015-04-24 04:57:18 +00:00
|
|
|
urtwn_read_1(sc, R92C_AFE_XTAL_CTRL + 2) | 0x80);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
|
|
|
/* Disable HWPDN. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_APS_FSMCO,
|
2015-04-24 04:57:18 +00:00
|
|
|
urtwn_read_2(sc, R92C_APS_FSMCO) & ~R92C_APS_FSMCO_APDM_HPDN);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
|
|
|
/* Disable WL suspend. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_APS_FSMCO,
|
2015-04-24 04:57:18 +00:00
|
|
|
urtwn_read_2(sc, R92C_APS_FSMCO) &
|
|
|
|
~(R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE));
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_APS_FSMCO,
|
2015-04-24 04:57:18 +00:00
|
|
|
urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
for (ntries = 0; ntries < 5000; ntries++) {
|
2015-04-24 04:57:18 +00:00
|
|
|
if (!(urtwn_read_2(sc, R92C_APS_FSMCO) &
|
|
|
|
R92C_APS_FSMCO_APFM_ONMAC))
|
2014-04-25 08:01:22 +00:00
|
|
|
break;
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2014-04-25 08:01:22 +00:00
|
|
|
}
|
|
|
|
if (ntries == 5000)
|
|
|
|
return (ETIMEDOUT);
|
|
|
|
|
|
|
|
/* Enable LDO normal mode. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, R92C_LPLDO_CTRL,
|
2016-02-22 01:15:02 +00:00
|
|
|
urtwn_read_1(sc, R92C_LPLDO_CTRL) & ~R92C_LPLDO_CTRL_SLEEP);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
|
|
|
/* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_CR, 0);
|
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
reg = urtwn_read_2(sc, R92C_CR);
|
|
|
|
reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
|
|
|
|
R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN |
|
|
|
|
R92C_CR_SCHEDULE_EN | R92C_CR_ENSEC | R92C_CR_CALTMR_EN;
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_2(sc, R92C_CR, reg);
|
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2016-02-22 01:15:02 +00:00
|
|
|
static __inline void
|
|
|
|
urtwn_power_off(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
|
|
|
|
return sc->sc_power_off(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_r92c_power_off(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
uint32_t reg;
|
|
|
|
|
|
|
|
/* Block all Tx queues. */
|
|
|
|
urtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL);
|
|
|
|
|
|
|
|
/* Disable RF */
|
|
|
|
urtwn_rf_write(sc, 0, 0, 0);
|
|
|
|
|
|
|
|
urtwn_write_1(sc, R92C_APSD_CTRL, R92C_APSD_CTRL_OFF);
|
|
|
|
|
|
|
|
/* Reset BB state machine */
|
|
|
|
urtwn_write_1(sc, R92C_SYS_FUNC_EN,
|
|
|
|
R92C_SYS_FUNC_EN_USBD | R92C_SYS_FUNC_EN_USBA |
|
|
|
|
R92C_SYS_FUNC_EN_BB_GLB_RST);
|
|
|
|
urtwn_write_1(sc, R92C_SYS_FUNC_EN,
|
|
|
|
R92C_SYS_FUNC_EN_USBD | R92C_SYS_FUNC_EN_USBA);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset digital sequence
|
|
|
|
*/
|
|
|
|
#ifndef URTWN_WITHOUT_UCODE
|
|
|
|
if (urtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RDY) {
|
|
|
|
/* Reset MCU ready status */
|
|
|
|
urtwn_write_1(sc, R92C_MCUFWDL, 0);
|
|
|
|
|
|
|
|
/* If firmware in ram code, do reset */
|
|
|
|
urtwn_fw_reset(sc);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Reset MAC and Enable 8051 */
|
|
|
|
urtwn_write_1(sc, R92C_SYS_FUNC_EN + 1,
|
|
|
|
(R92C_SYS_FUNC_EN_CPUEN |
|
|
|
|
R92C_SYS_FUNC_EN_ELDR |
|
|
|
|
R92C_SYS_FUNC_EN_HWPDN) >> 8);
|
|
|
|
|
|
|
|
/* Reset MCU ready status */
|
|
|
|
urtwn_write_1(sc, R92C_MCUFWDL, 0);
|
|
|
|
|
|
|
|
/* Disable MAC clock */
|
|
|
|
urtwn_write_2(sc, R92C_SYS_CLKR,
|
|
|
|
R92C_SYS_CLKR_ANAD16V_EN |
|
|
|
|
R92C_SYS_CLKR_ANA8M |
|
|
|
|
R92C_SYS_CLKR_LOADER_EN |
|
|
|
|
R92C_SYS_CLKR_80M_SSC_DIS |
|
|
|
|
R92C_SYS_CLKR_SYS_EN |
|
|
|
|
R92C_SYS_CLKR_RING_EN |
|
|
|
|
0x4000);
|
|
|
|
|
|
|
|
/* Disable AFE PLL */
|
|
|
|
urtwn_write_1(sc, R92C_AFE_PLL_CTRL, 0x80);
|
|
|
|
|
|
|
|
/* Gated AFE DIG_CLOCK */
|
|
|
|
urtwn_write_2(sc, R92C_AFE_XTAL_CTRL, 0x880F);
|
|
|
|
|
|
|
|
/* Isolated digital to PON */
|
|
|
|
urtwn_write_1(sc, R92C_SYS_ISO_CTRL,
|
|
|
|
R92C_SYS_ISO_CTRL_MD2PP |
|
|
|
|
R92C_SYS_ISO_CTRL_PA2PCIE |
|
|
|
|
R92C_SYS_ISO_CTRL_PD2CORE |
|
|
|
|
R92C_SYS_ISO_CTRL_IP2MAC |
|
|
|
|
R92C_SYS_ISO_CTRL_DIOP |
|
|
|
|
R92C_SYS_ISO_CTRL_DIOE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pull GPIO PIN to balance level and LED control
|
|
|
|
*/
|
|
|
|
/* 1. Disable GPIO[7:0] */
|
|
|
|
urtwn_write_2(sc, R92C_GPIO_IOSEL, 0x0000);
|
|
|
|
|
|
|
|
reg = urtwn_read_4(sc, R92C_GPIO_PIN_CTRL) & ~0x0000ff00;
|
|
|
|
reg |= ((reg << 8) & 0x0000ff00) | 0x00ff0000;
|
|
|
|
urtwn_write_4(sc, R92C_GPIO_PIN_CTRL, reg);
|
|
|
|
|
|
|
|
/* Disable GPIO[10:8] */
|
|
|
|
urtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 0x00);
|
|
|
|
|
|
|
|
reg = urtwn_read_2(sc, R92C_GPIO_IO_SEL) & ~0x00f0;
|
|
|
|
reg |= (((reg & 0x000f) << 4) | 0x0780);
|
|
|
|
urtwn_write_2(sc, R92C_GPIO_IO_SEL, reg);
|
|
|
|
|
|
|
|
/* Disable LED0 & 1 */
|
|
|
|
urtwn_write_2(sc, R92C_LEDCFG0, 0x8080);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset digital sequence
|
|
|
|
*/
|
|
|
|
/* Disable ELDR clock */
|
|
|
|
urtwn_write_2(sc, R92C_SYS_CLKR,
|
|
|
|
R92C_SYS_CLKR_ANAD16V_EN |
|
|
|
|
R92C_SYS_CLKR_ANA8M |
|
|
|
|
R92C_SYS_CLKR_LOADER_EN |
|
|
|
|
R92C_SYS_CLKR_80M_SSC_DIS |
|
|
|
|
R92C_SYS_CLKR_SYS_EN |
|
|
|
|
R92C_SYS_CLKR_RING_EN |
|
|
|
|
0x4000);
|
|
|
|
|
|
|
|
/* Isolated ELDR to PON */
|
|
|
|
urtwn_write_1(sc, R92C_SYS_ISO_CTRL + 1,
|
|
|
|
(R92C_SYS_ISO_CTRL_DIOR |
|
|
|
|
R92C_SYS_ISO_CTRL_PWC_EV12V) >> 8);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Disable analog sequence
|
|
|
|
*/
|
|
|
|
/* Disable A15 power */
|
|
|
|
urtwn_write_1(sc, R92C_LDOA15_CTRL, R92C_LDOA15_CTRL_OBUF);
|
|
|
|
/* Disable digital core power */
|
|
|
|
urtwn_write_1(sc, R92C_LDOV12D_CTRL,
|
|
|
|
urtwn_read_1(sc, R92C_LDOV12D_CTRL) &
|
|
|
|
~R92C_LDOV12D_CTRL_LDV12_EN);
|
|
|
|
|
|
|
|
/* Enter PFM mode */
|
|
|
|
urtwn_write_1(sc, R92C_SPS0_CTRL, 0x23);
|
|
|
|
|
|
|
|
/* Set USB suspend */
|
|
|
|
urtwn_write_2(sc, R92C_APS_FSMCO,
|
|
|
|
R92C_APS_FSMCO_APDM_HOST |
|
|
|
|
R92C_APS_FSMCO_AFSM_HSUS |
|
|
|
|
R92C_APS_FSMCO_PFM_ALDN);
|
|
|
|
|
|
|
|
/* Lock ISO/CLK/Power control register. */
|
|
|
|
urtwn_write_1(sc, R92C_RSV_CTRL, 0x0E);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_r88e_power_off(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
uint8_t reg;
|
|
|
|
int ntries;
|
|
|
|
|
|
|
|
/* Disable any kind of TX reports. */
|
|
|
|
urtwn_write_1(sc, R88E_TX_RPT_CTRL,
|
|
|
|
urtwn_read_1(sc, R88E_TX_RPT_CTRL) &
|
|
|
|
~(R88E_TX_RPT1_ENA | R88E_TX_RPT2_ENA));
|
|
|
|
|
|
|
|
/* Stop Rx. */
|
|
|
|
urtwn_write_1(sc, R92C_CR, 0);
|
|
|
|
|
|
|
|
/* Move card to Low Power State. */
|
|
|
|
/* Block all Tx queues. */
|
|
|
|
urtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL);
|
|
|
|
|
|
|
|
for (ntries = 0; ntries < 20; ntries++) {
|
|
|
|
/* Should be zero if no packet is transmitting. */
|
|
|
|
if (urtwn_read_4(sc, R88E_SCH_TXCMD) == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
urtwn_ms_delay(sc);
|
|
|
|
}
|
|
|
|
if (ntries == 20) {
|
|
|
|
device_printf(sc->sc_dev, "%s: failed to block Tx queues\n",
|
|
|
|
__func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CCK and OFDM are disabled, and clock are gated. */
|
|
|
|
urtwn_write_1(sc, R92C_SYS_FUNC_EN,
|
|
|
|
urtwn_read_1(sc, R92C_SYS_FUNC_EN) & ~R92C_SYS_FUNC_EN_BBRSTB);
|
|
|
|
|
|
|
|
urtwn_ms_delay(sc);
|
|
|
|
|
|
|
|
/* Reset MAC TRX */
|
|
|
|
urtwn_write_1(sc, R92C_CR,
|
|
|
|
R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
|
|
|
|
R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN |
|
|
|
|
R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN);
|
|
|
|
|
|
|
|
/* check if removed later */
|
|
|
|
urtwn_write_1(sc, R92C_CR + 1,
|
|
|
|
urtwn_read_1(sc, R92C_CR + 1) & ~(R92C_CR_ENSEC >> 8));
|
|
|
|
|
|
|
|
/* Respond TxOK to scheduler */
|
|
|
|
urtwn_write_1(sc, R92C_DUAL_TSF_RST,
|
|
|
|
urtwn_read_1(sc, R92C_DUAL_TSF_RST) | 0x20);
|
|
|
|
|
|
|
|
/* If firmware in ram code, do reset. */
|
|
|
|
#ifndef URTWN_WITHOUT_UCODE
|
|
|
|
if (urtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RDY)
|
|
|
|
urtwn_r88e_fw_reset(sc);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Reset MCU ready status. */
|
|
|
|
urtwn_write_1(sc, R92C_MCUFWDL, 0x00);
|
|
|
|
|
|
|
|
/* Disable 32k. */
|
|
|
|
urtwn_write_1(sc, R88E_32K_CTRL,
|
|
|
|
urtwn_read_1(sc, R88E_32K_CTRL) & ~0x01);
|
|
|
|
|
|
|
|
/* Move card to Disabled state. */
|
|
|
|
/* Turn off RF. */
|
|
|
|
urtwn_write_1(sc, R92C_RF_CTRL, 0);
|
|
|
|
|
|
|
|
/* LDO Sleep mode. */
|
|
|
|
urtwn_write_1(sc, R92C_LPLDO_CTRL,
|
|
|
|
urtwn_read_1(sc, R92C_LPLDO_CTRL) | R92C_LPLDO_CTRL_SLEEP);
|
|
|
|
|
|
|
|
/* Turn off MAC by HW state machine */
|
|
|
|
urtwn_write_1(sc, R92C_APS_FSMCO + 1,
|
|
|
|
urtwn_read_1(sc, R92C_APS_FSMCO + 1) |
|
|
|
|
(R92C_APS_FSMCO_APFM_OFF >> 8));
|
|
|
|
|
|
|
|
for (ntries = 0; ntries < 20; ntries++) {
|
|
|
|
/* Wait until it will be disabled. */
|
|
|
|
if ((urtwn_read_1(sc, R92C_APS_FSMCO + 1) &
|
|
|
|
(R92C_APS_FSMCO_APFM_OFF >> 8)) == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
urtwn_ms_delay(sc);
|
|
|
|
}
|
|
|
|
if (ntries == 20) {
|
|
|
|
device_printf(sc->sc_dev, "%s: could not turn off MAC\n",
|
|
|
|
__func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* schmit trigger */
|
|
|
|
urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 2,
|
|
|
|
urtwn_read_1(sc, R92C_AFE_XTAL_CTRL + 2) | 0x80);
|
|
|
|
|
|
|
|
/* Enable WL suspend. */
|
|
|
|
urtwn_write_1(sc, R92C_APS_FSMCO + 1,
|
|
|
|
(urtwn_read_1(sc, R92C_APS_FSMCO + 1) & ~0x10) | 0x08);
|
|
|
|
|
|
|
|
/* Enable bandgap mbias in suspend. */
|
|
|
|
urtwn_write_1(sc, R92C_APS_FSMCO + 3, 0);
|
|
|
|
|
|
|
|
/* Clear SIC_EN register. */
|
|
|
|
urtwn_write_1(sc, R92C_GPIO_MUXCFG + 1,
|
|
|
|
urtwn_read_1(sc, R92C_GPIO_MUXCFG + 1) & ~0x10);
|
|
|
|
|
|
|
|
/* Set USB suspend enable local register */
|
|
|
|
urtwn_write_1(sc, R92C_USB_SUSPEND,
|
|
|
|
urtwn_read_1(sc, R92C_USB_SUSPEND) | 0x10);
|
|
|
|
|
|
|
|
/* Reset MCU IO Wrapper. */
|
|
|
|
reg = urtwn_read_1(sc, R92C_RSV_CTRL + 1);
|
|
|
|
urtwn_write_1(sc, R92C_RSV_CTRL + 1, reg & ~0x08);
|
|
|
|
urtwn_write_1(sc, R92C_RSV_CTRL + 1, reg | 0x08);
|
|
|
|
|
|
|
|
/* marked as 'For Power Consumption' code. */
|
|
|
|
urtwn_write_1(sc, R92C_GPIO_OUT, urtwn_read_1(sc, R92C_GPIO_IN));
|
|
|
|
urtwn_write_1(sc, R92C_GPIO_IOSEL, 0xff);
|
|
|
|
|
|
|
|
urtwn_write_1(sc, R92C_GPIO_IO_SEL,
|
|
|
|
urtwn_read_1(sc, R92C_GPIO_IO_SEL) << 4);
|
|
|
|
urtwn_write_1(sc, R92C_GPIO_MOD,
|
|
|
|
urtwn_read_1(sc, R92C_GPIO_MOD) | 0x0f);
|
|
|
|
|
|
|
|
/* Set LNA, TRSW, EX_PA Pin to output mode. */
|
|
|
|
urtwn_write_4(sc, R88E_BB_PAD_CTRL, 0x00080808);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static int
|
|
|
|
urtwn_llt_init(struct urtwn_softc *sc)
|
|
|
|
{
|
2014-04-25 08:01:22 +00:00
|
|
|
int i, error, page_count, pktbuf_count;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
page_count = (sc->chip & URTWN_CHIP_88E) ?
|
|
|
|
R88E_TX_PAGE_COUNT : R92C_TX_PAGE_COUNT;
|
|
|
|
pktbuf_count = (sc->chip & URTWN_CHIP_88E) ?
|
|
|
|
R88E_TXPKTBUF_COUNT : R92C_TXPKTBUF_COUNT;
|
|
|
|
|
|
|
|
/* Reserve pages [0; page_count]. */
|
|
|
|
for (i = 0; i < page_count; i++) {
|
2013-06-08 16:02:31 +00:00
|
|
|
if ((error = urtwn_llt_write(sc, i, i + 1)) != 0)
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
/* NB: 0xff indicates end-of-list. */
|
|
|
|
if ((error = urtwn_llt_write(sc, i, 0xff)) != 0)
|
|
|
|
return (error);
|
|
|
|
/*
|
2014-04-25 08:01:22 +00:00
|
|
|
* Use pages [page_count + 1; pktbuf_count - 1]
|
2013-06-08 16:02:31 +00:00
|
|
|
* as ring buffer.
|
|
|
|
*/
|
2014-04-25 08:01:22 +00:00
|
|
|
for (++i; i < pktbuf_count - 1; i++) {
|
2013-06-08 16:02:31 +00:00
|
|
|
if ((error = urtwn_llt_write(sc, i, i + 1)) != 0)
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
/* Make the last page point to the beginning of the ring buffer. */
|
2014-04-25 08:01:22 +00:00
|
|
|
error = urtwn_llt_write(sc, i, page_count + 1);
|
2013-06-08 16:02:31 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2016-02-22 00:48:53 +00:00
|
|
|
#ifndef URTWN_WITHOUT_UCODE
|
2013-06-08 16:02:31 +00:00
|
|
|
static void
|
|
|
|
urtwn_fw_reset(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
uint16_t reg;
|
|
|
|
int ntries;
|
|
|
|
|
|
|
|
/* Tell 8051 to reset itself. */
|
|
|
|
urtwn_write_1(sc, R92C_HMETFR + 3, 0x20);
|
|
|
|
|
|
|
|
/* Wait until 8051 resets by itself. */
|
|
|
|
for (ntries = 0; ntries < 100; ntries++) {
|
|
|
|
reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN);
|
|
|
|
if (!(reg & R92C_SYS_FUNC_EN_CPUEN))
|
|
|
|
return;
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
/* Force 8051 reset. */
|
|
|
|
urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN);
|
2014-04-25 08:01:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_r88e_fw_reset(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
uint16_t reg;
|
|
|
|
|
|
|
|
reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN);
|
|
|
|
urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN);
|
|
|
|
urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg | R92C_SYS_FUNC_EN_CPUEN);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_fw_loadpage(struct urtwn_softc *sc, int page, const uint8_t *buf, int len)
|
|
|
|
{
|
|
|
|
uint32_t reg;
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_error_t error = USB_ERR_NORMAL_COMPLETION;
|
|
|
|
int off, mlen;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
reg = urtwn_read_4(sc, R92C_MCUFWDL);
|
|
|
|
reg = RW(reg, R92C_MCUFWDL_PAGE, page);
|
|
|
|
urtwn_write_4(sc, R92C_MCUFWDL, reg);
|
|
|
|
|
|
|
|
off = R92C_FW_START_ADDR;
|
|
|
|
while (len > 0) {
|
|
|
|
if (len > 196)
|
|
|
|
mlen = 196;
|
|
|
|
else if (len > 4)
|
|
|
|
mlen = 4;
|
|
|
|
else
|
|
|
|
mlen = 1;
|
|
|
|
/* XXX fix this deconst */
|
2015-04-04 08:36:02 +00:00
|
|
|
error = urtwn_write_region_1(sc, off,
|
2013-06-08 16:02:31 +00:00
|
|
|
__DECONST(uint8_t *, buf), mlen);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
2013-06-08 16:02:31 +00:00
|
|
|
break;
|
|
|
|
off += mlen;
|
|
|
|
buf += mlen;
|
|
|
|
len -= mlen;
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_load_firmware(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
const struct firmware *fw;
|
|
|
|
const struct r92c_fw_hdr *hdr;
|
|
|
|
const char *imagename;
|
|
|
|
const u_char *ptr;
|
|
|
|
size_t len;
|
|
|
|
uint32_t reg;
|
|
|
|
int mlen, ntries, page, error;
|
|
|
|
|
2014-04-24 03:16:47 +00:00
|
|
|
URTWN_UNLOCK(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Read firmware image from the filesystem. */
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
imagename = "urtwn-rtl8188eufw";
|
|
|
|
else if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) ==
|
|
|
|
URTWN_CHIP_UMC_A_CUT)
|
2013-06-08 16:02:31 +00:00
|
|
|
imagename = "urtwn-rtl8192cfwU";
|
|
|
|
else
|
|
|
|
imagename = "urtwn-rtl8192cfwT";
|
|
|
|
|
|
|
|
fw = firmware_get(imagename);
|
2014-04-24 03:16:47 +00:00
|
|
|
URTWN_LOCK(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
if (fw == NULL) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"failed loadfirmware of file %s\n", imagename);
|
|
|
|
return (ENOENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
len = fw->datasize;
|
|
|
|
|
|
|
|
if (len < sizeof(*hdr)) {
|
|
|
|
device_printf(sc->sc_dev, "firmware too short\n");
|
|
|
|
error = EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
ptr = fw->data;
|
|
|
|
hdr = (const struct r92c_fw_hdr *)ptr;
|
|
|
|
/* Check if there is a valid FW header and skip it. */
|
|
|
|
if ((le16toh(hdr->signature) >> 4) == 0x88c ||
|
2014-04-25 08:01:22 +00:00
|
|
|
(le16toh(hdr->signature) >> 4) == 0x88e ||
|
2013-06-08 16:02:31 +00:00
|
|
|
(le16toh(hdr->signature) >> 4) == 0x92c) {
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_FIRMWARE,
|
|
|
|
"FW V%d.%d %02d-%02d %02d:%02d\n",
|
2013-06-08 16:02:31 +00:00
|
|
|
le16toh(hdr->version), le16toh(hdr->subversion),
|
|
|
|
hdr->month, hdr->date, hdr->hour, hdr->minute);
|
|
|
|
ptr += sizeof(*hdr);
|
|
|
|
len -= sizeof(*hdr);
|
|
|
|
}
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
if (urtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) {
|
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
urtwn_r88e_fw_reset(sc);
|
|
|
|
else
|
|
|
|
urtwn_fw_reset(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_write_1(sc, R92C_MCUFWDL, 0);
|
|
|
|
}
|
2014-04-25 08:01:22 +00:00
|
|
|
|
2014-07-10 09:42:34 +00:00
|
|
|
if (!(sc->chip & URTWN_CHIP_88E)) {
|
|
|
|
urtwn_write_2(sc, R92C_SYS_FUNC_EN,
|
|
|
|
urtwn_read_2(sc, R92C_SYS_FUNC_EN) |
|
|
|
|
R92C_SYS_FUNC_EN_CPUEN);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_write_1(sc, R92C_MCUFWDL,
|
|
|
|
urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN);
|
|
|
|
urtwn_write_1(sc, R92C_MCUFWDL + 2,
|
|
|
|
urtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08);
|
|
|
|
|
2014-03-14 06:38:22 +00:00
|
|
|
/* Reset the FWDL checksum. */
|
|
|
|
urtwn_write_1(sc, R92C_MCUFWDL,
|
|
|
|
urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_CHKSUM_RPT);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
for (page = 0; len > 0; page++) {
|
|
|
|
mlen = min(len, R92C_FW_PAGE_SIZE);
|
|
|
|
error = urtwn_fw_loadpage(sc, page, ptr, mlen);
|
|
|
|
if (error != 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"could not load firmware page\n");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
ptr += mlen;
|
|
|
|
len -= mlen;
|
|
|
|
}
|
|
|
|
urtwn_write_1(sc, R92C_MCUFWDL,
|
|
|
|
urtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN);
|
|
|
|
urtwn_write_1(sc, R92C_MCUFWDL + 1, 0);
|
|
|
|
|
|
|
|
/* Wait for checksum report. */
|
|
|
|
for (ntries = 0; ntries < 1000; ntries++) {
|
|
|
|
if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT)
|
|
|
|
break;
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
if (ntries == 1000) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"timeout waiting for checksum report\n");
|
|
|
|
error = ETIMEDOUT;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
reg = urtwn_read_4(sc, R92C_MCUFWDL);
|
|
|
|
reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY;
|
|
|
|
urtwn_write_4(sc, R92C_MCUFWDL, reg);
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
urtwn_r88e_fw_reset(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Wait for firmware readiness. */
|
|
|
|
for (ntries = 0; ntries < 1000; ntries++) {
|
|
|
|
if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY)
|
|
|
|
break;
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
if (ntries == 1000) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"timeout waiting for firmware readiness\n");
|
|
|
|
error = ETIMEDOUT;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
fail:
|
|
|
|
firmware_put(fw, FIRMWARE_UNLOAD);
|
|
|
|
return (error);
|
|
|
|
}
|
2016-02-22 00:48:53 +00:00
|
|
|
#endif
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-12-06 14:07:57 +00:00
|
|
|
static int
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_dma_init(struct urtwn_softc *sc)
|
2014-04-25 08:01:22 +00:00
|
|
|
{
|
2015-12-06 14:07:57 +00:00
|
|
|
struct usb_endpoint *ep, *ep_end;
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_error_t usb_err;
|
2015-12-06 14:07:57 +00:00
|
|
|
uint32_t reg;
|
|
|
|
int hashq, hasnq, haslq, nqueues, ntx;
|
|
|
|
int error, pagecount, npubqpages, nqpages, nrempages, tx_boundary;
|
2015-12-03 14:17:28 +00:00
|
|
|
|
|
|
|
/* Initialize LLT table. */
|
|
|
|
error = urtwn_llt_init(sc);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
2015-12-06 14:07:57 +00:00
|
|
|
/* Determine the number of bulk-out pipes. */
|
|
|
|
ntx = 0;
|
|
|
|
ep = sc->sc_udev->endpoints;
|
|
|
|
ep_end = sc->sc_udev->endpoints + sc->sc_udev->endpoints_max;
|
|
|
|
for (; ep != ep_end; ep++) {
|
|
|
|
if ((ep->edesc == NULL) ||
|
|
|
|
(ep->iface_index != sc->sc_iface_index))
|
|
|
|
continue;
|
|
|
|
if (UE_GET_DIR(ep->edesc->bEndpointAddress) == UE_DIR_OUT)
|
|
|
|
ntx++;
|
|
|
|
}
|
|
|
|
if (ntx == 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"%d: invalid number of Tx bulk pipes\n", ntx);
|
2015-12-03 14:38:55 +00:00
|
|
|
return (EIO);
|
2015-12-06 14:07:57 +00:00
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Get Tx queues to USB endpoints mapping. */
|
2015-12-06 14:07:57 +00:00
|
|
|
hashq = hasnq = haslq = nqueues = 0;
|
|
|
|
switch (ntx) {
|
|
|
|
case 1: hashq = 1; break;
|
|
|
|
case 2: hashq = hasnq = 1; break;
|
|
|
|
case 3: case 4: hashq = hasnq = haslq = 1; break;
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
nqueues = hashq + hasnq + haslq;
|
|
|
|
if (nqueues == 0)
|
|
|
|
return (EIO);
|
2015-12-06 14:07:57 +00:00
|
|
|
|
|
|
|
npubqpages = nqpages = nrempages = pagecount = 0;
|
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
tx_boundary = R88E_TX_PAGE_BOUNDARY;
|
|
|
|
else {
|
|
|
|
pagecount = R92C_TX_PAGE_COUNT;
|
|
|
|
npubqpages = R92C_PUBQ_NPAGES;
|
|
|
|
tx_boundary = R92C_TX_PAGE_BOUNDARY;
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Set number of pages for normal priority queue. */
|
2015-12-06 14:07:57 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
|
|
|
usb_err = urtwn_write_2(sc, R92C_RQPN_NPQ, 0xd);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
|
|
|
usb_err = urtwn_write_4(sc, R92C_RQPN, 0x808e000d);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
|
|
|
} else {
|
|
|
|
/* Get the number of pages for each queue. */
|
|
|
|
nqpages = (pagecount - npubqpages) / nqueues;
|
|
|
|
/*
|
|
|
|
* The remaining pages are assigned to the high priority
|
|
|
|
* queue.
|
|
|
|
*/
|
|
|
|
nrempages = (pagecount - npubqpages) % nqueues;
|
|
|
|
usb_err = urtwn_write_1(sc, R92C_RQPN_NPQ, hasnq ? nqpages : 0);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
|
|
|
usb_err = urtwn_write_4(sc, R92C_RQPN,
|
|
|
|
/* Set number of pages for public queue. */
|
|
|
|
SM(R92C_RQPN_PUBQ, npubqpages) |
|
|
|
|
/* Set number of pages for high priority queue. */
|
|
|
|
SM(R92C_RQPN_HPQ, hashq ? nqpages + nrempages : 0) |
|
|
|
|
/* Set number of pages for low priority queue. */
|
|
|
|
SM(R92C_RQPN_LPQ, haslq ? nqpages : 0) |
|
|
|
|
/* Load values. */
|
|
|
|
R92C_RQPN_LD);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-12-06 14:07:57 +00:00
|
|
|
usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, tx_boundary);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
2015-12-03 14:38:55 +00:00
|
|
|
return (EIO);
|
2015-12-06 14:07:57 +00:00
|
|
|
usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, tx_boundary);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
2015-12-03 14:38:55 +00:00
|
|
|
return (EIO);
|
2015-12-06 14:07:57 +00:00
|
|
|
usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, tx_boundary);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
2015-12-03 14:38:55 +00:00
|
|
|
return (EIO);
|
2015-12-06 14:07:57 +00:00
|
|
|
usb_err = urtwn_write_1(sc, R92C_TRXFF_BNDY, tx_boundary);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
2015-12-03 14:38:55 +00:00
|
|
|
return (EIO);
|
2015-12-06 14:07:57 +00:00
|
|
|
usb_err = urtwn_write_1(sc, R92C_TDECTRL + 1, tx_boundary);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
2015-12-03 14:38:55 +00:00
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Set queue to USB pipe mapping. */
|
|
|
|
reg = urtwn_read_2(sc, R92C_TRXDMA_CTRL);
|
|
|
|
reg &= ~R92C_TRXDMA_CTRL_QMAP_M;
|
|
|
|
if (nqueues == 1) {
|
|
|
|
if (hashq)
|
|
|
|
reg |= R92C_TRXDMA_CTRL_QMAP_HQ;
|
|
|
|
else if (hasnq)
|
|
|
|
reg |= R92C_TRXDMA_CTRL_QMAP_NQ;
|
|
|
|
else
|
|
|
|
reg |= R92C_TRXDMA_CTRL_QMAP_LQ;
|
|
|
|
} else if (nqueues == 2) {
|
2015-12-10 07:45:58 +00:00
|
|
|
/*
|
|
|
|
* All 2-endpoints configs have high and normal
|
|
|
|
* priority queues.
|
|
|
|
*/
|
|
|
|
reg |= R92C_TRXDMA_CTRL_QMAP_HQ_NQ;
|
2013-06-08 16:02:31 +00:00
|
|
|
} else
|
|
|
|
reg |= R92C_TRXDMA_CTRL_QMAP_3EP;
|
2015-12-06 14:07:57 +00:00
|
|
|
usb_err = urtwn_write_2(sc, R92C_TRXDMA_CTRL, reg);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
2015-12-03 14:38:55 +00:00
|
|
|
return (EIO);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Set Tx/Rx transfer page boundary. */
|
2015-12-06 14:07:57 +00:00
|
|
|
usb_err = urtwn_write_2(sc, R92C_TRXFF_BNDY + 2,
|
|
|
|
(sc->chip & URTWN_CHIP_88E) ? 0x23ff : 0x27ff);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
2015-12-03 14:38:55 +00:00
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
2015-12-06 14:07:57 +00:00
|
|
|
/* Set Tx/Rx transfer page size. */
|
|
|
|
usb_err = urtwn_write_1(sc, R92C_PBP,
|
|
|
|
SM(R92C_PBP_PSRX, R92C_PBP_128) |
|
|
|
|
SM(R92C_PBP_PSTX, R92C_PBP_128));
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
2015-12-03 14:38:55 +00:00
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
static int
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_mac_init(struct urtwn_softc *sc)
|
|
|
|
{
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_error_t error;
|
2013-06-08 16:02:31 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Write MAC initialization values. */
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
|
|
|
for (i = 0; i < nitems(rtl8188eu_mac); i++) {
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, rtl8188eu_mac[i].reg,
|
2014-04-25 08:01:22 +00:00
|
|
|
rtl8188eu_mac[i].val);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
}
|
|
|
|
urtwn_write_1(sc, R92C_MAX_AGGR_NUM, 0x07);
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < nitems(rtl8192cu_mac); i++)
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_write_1(sc, rtl8192cu_mac[i].reg,
|
2014-04-25 08:01:22 +00:00
|
|
|
rtl8192cu_mac[i].val);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
2014-04-25 08:01:22 +00:00
|
|
|
}
|
2015-12-03 14:38:55 +00:00
|
|
|
|
|
|
|
return (0);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_bb_init(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
const struct urtwn_bb_prog *prog;
|
|
|
|
uint32_t reg;
|
2014-04-25 08:01:22 +00:00
|
|
|
uint8_t crystalcap;
|
2013-06-08 16:02:31 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Enable BB and RF. */
|
|
|
|
urtwn_write_2(sc, R92C_SYS_FUNC_EN,
|
|
|
|
urtwn_read_2(sc, R92C_SYS_FUNC_EN) |
|
|
|
|
R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST |
|
|
|
|
R92C_SYS_FUNC_EN_DIO_RF);
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
if (!(sc->chip & URTWN_CHIP_88E))
|
|
|
|
urtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
urtwn_write_1(sc, R92C_RF_CTRL,
|
|
|
|
R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
|
|
|
|
urtwn_write_1(sc, R92C_SYS_FUNC_EN,
|
|
|
|
R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD |
|
|
|
|
R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB);
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
if (!(sc->chip & URTWN_CHIP_88E)) {
|
|
|
|
urtwn_write_1(sc, R92C_LDOHCI12_CTRL, 0x0f);
|
|
|
|
urtwn_write_1(sc, 0x15, 0xe9);
|
|
|
|
urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Select BB programming based on board type. */
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
prog = &rtl8188eu_bb_prog;
|
|
|
|
else if (!(sc->chip & URTWN_CHIP_92C)) {
|
2013-06-08 16:02:31 +00:00
|
|
|
if (sc->board_type == R92C_BOARD_TYPE_MINICARD)
|
|
|
|
prog = &rtl8188ce_bb_prog;
|
|
|
|
else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
|
|
|
|
prog = &rtl8188ru_bb_prog;
|
|
|
|
else
|
|
|
|
prog = &rtl8188cu_bb_prog;
|
|
|
|
} else {
|
|
|
|
if (sc->board_type == R92C_BOARD_TYPE_MINICARD)
|
|
|
|
prog = &rtl8192ce_bb_prog;
|
|
|
|
else
|
|
|
|
prog = &rtl8192cu_bb_prog;
|
|
|
|
}
|
|
|
|
/* Write BB initialization values. */
|
|
|
|
for (i = 0; i < prog->count; i++) {
|
|
|
|
urtwn_bb_write(sc, prog->regs[i], prog->vals[i]);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->chip & URTWN_CHIP_92C_1T2R) {
|
|
|
|
/* 8192C 1T only configuration. */
|
|
|
|
reg = urtwn_bb_read(sc, R92C_FPGA0_TXINFO);
|
|
|
|
reg = (reg & ~0x00000003) | 0x2;
|
|
|
|
urtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg);
|
|
|
|
|
|
|
|
reg = urtwn_bb_read(sc, R92C_FPGA1_TXINFO);
|
|
|
|
reg = (reg & ~0x00300033) | 0x00200022;
|
|
|
|
urtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg);
|
|
|
|
|
|
|
|
reg = urtwn_bb_read(sc, R92C_CCK0_AFESETTING);
|
|
|
|
reg = (reg & ~0xff000000) | 0x45 << 24;
|
|
|
|
urtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg);
|
|
|
|
|
|
|
|
reg = urtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
|
|
|
|
reg = (reg & ~0x000000ff) | 0x23;
|
|
|
|
urtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg);
|
|
|
|
|
|
|
|
reg = urtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1);
|
|
|
|
reg = (reg & ~0x00000030) | 1 << 4;
|
|
|
|
urtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg);
|
|
|
|
|
|
|
|
reg = urtwn_bb_read(sc, 0xe74);
|
|
|
|
reg = (reg & ~0x0c000000) | 2 << 26;
|
|
|
|
urtwn_bb_write(sc, 0xe74, reg);
|
|
|
|
reg = urtwn_bb_read(sc, 0xe78);
|
|
|
|
reg = (reg & ~0x0c000000) | 2 << 26;
|
|
|
|
urtwn_bb_write(sc, 0xe78, reg);
|
|
|
|
reg = urtwn_bb_read(sc, 0xe7c);
|
|
|
|
reg = (reg & ~0x0c000000) | 2 << 26;
|
|
|
|
urtwn_bb_write(sc, 0xe7c, reg);
|
|
|
|
reg = urtwn_bb_read(sc, 0xe80);
|
|
|
|
reg = (reg & ~0x0c000000) | 2 << 26;
|
|
|
|
urtwn_bb_write(sc, 0xe80, reg);
|
|
|
|
reg = urtwn_bb_read(sc, 0xe88);
|
|
|
|
reg = (reg & ~0x0c000000) | 2 << 26;
|
|
|
|
urtwn_bb_write(sc, 0xe88, reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write AGC values. */
|
|
|
|
for (i = 0; i < prog->agccount; i++) {
|
|
|
|
urtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE,
|
|
|
|
prog->agcvals[i]);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
|
|
|
urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553422);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2014-04-25 08:01:22 +00:00
|
|
|
urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553420);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2014-04-25 08:01:22 +00:00
|
|
|
|
2016-01-17 00:52:21 +00:00
|
|
|
crystalcap = sc->rom.r88e_rom.crystalcap;
|
2014-04-25 08:01:22 +00:00
|
|
|
if (crystalcap == 0xff)
|
|
|
|
crystalcap = 0x20;
|
|
|
|
crystalcap &= 0x3f;
|
|
|
|
reg = urtwn_bb_read(sc, R92C_AFE_XTAL_CTRL);
|
|
|
|
urtwn_bb_write(sc, R92C_AFE_XTAL_CTRL,
|
|
|
|
RW(reg, R92C_AFE_XTAL_CTRL_ADDR,
|
|
|
|
crystalcap | crystalcap << 6));
|
|
|
|
} else {
|
|
|
|
if (urtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) &
|
|
|
|
R92C_HSSI_PARAM2_CCK_HIPWR)
|
|
|
|
sc->sc_flags |= URTWN_FLAG_CCK_HIPWR;
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2015-10-09 14:31:32 +00:00
|
|
|
static void
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_rf_init(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
const struct urtwn_rf_prog *prog;
|
|
|
|
uint32_t reg, type;
|
|
|
|
int i, j, idx, off;
|
|
|
|
|
|
|
|
/* Select RF programming based on board type. */
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
prog = rtl8188eu_rf_prog;
|
|
|
|
else if (!(sc->chip & URTWN_CHIP_92C)) {
|
2013-06-08 16:02:31 +00:00
|
|
|
if (sc->board_type == R92C_BOARD_TYPE_MINICARD)
|
|
|
|
prog = rtl8188ce_rf_prog;
|
|
|
|
else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
|
|
|
|
prog = rtl8188ru_rf_prog;
|
|
|
|
else
|
|
|
|
prog = rtl8188cu_rf_prog;
|
|
|
|
} else
|
|
|
|
prog = rtl8192ce_rf_prog;
|
|
|
|
|
|
|
|
for (i = 0; i < sc->nrxchains; i++) {
|
|
|
|
/* Save RF_ENV control type. */
|
|
|
|
idx = i / 2;
|
|
|
|
off = (i % 2) * 16;
|
|
|
|
reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx));
|
|
|
|
type = (reg >> off) & 0x10;
|
|
|
|
|
|
|
|
/* Set RF_ENV enable. */
|
|
|
|
reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i));
|
|
|
|
reg |= 0x100000;
|
|
|
|
urtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Set RF_ENV output high. */
|
|
|
|
reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i));
|
|
|
|
reg |= 0x10;
|
|
|
|
urtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Set address and data lengths of RF registers. */
|
|
|
|
reg = urtwn_bb_read(sc, R92C_HSSI_PARAM2(i));
|
|
|
|
reg &= ~R92C_HSSI_PARAM2_ADDR_LENGTH;
|
|
|
|
urtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
reg = urtwn_bb_read(sc, R92C_HSSI_PARAM2(i));
|
|
|
|
reg &= ~R92C_HSSI_PARAM2_DATA_LENGTH;
|
|
|
|
urtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Write RF initialization values for this chain. */
|
|
|
|
for (j = 0; j < prog[i].count; j++) {
|
|
|
|
if (prog[i].regs[j] >= 0xf9 &&
|
|
|
|
prog[i].regs[j] <= 0xfe) {
|
|
|
|
/*
|
|
|
|
* These are fake RF registers offsets that
|
|
|
|
* indicate a delay is required.
|
|
|
|
*/
|
2014-05-20 15:53:17 +00:00
|
|
|
usb_pause_mtx(&sc->sc_mtx, hz / 20); /* 50ms */
|
2013-06-08 16:02:31 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
urtwn_rf_write(sc, i, prog[i].regs[j],
|
|
|
|
prog[i].vals[j]);
|
2014-05-20 15:53:17 +00:00
|
|
|
urtwn_ms_delay(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore RF_ENV control type. */
|
|
|
|
reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx));
|
|
|
|
reg &= ~(0x10 << off) | (type << off);
|
|
|
|
urtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(idx), reg);
|
|
|
|
|
|
|
|
/* Cache RF register CHNLBW. */
|
|
|
|
sc->rf_chnlbw[i] = urtwn_rf_read(sc, i, R92C_RF_CHNLBW);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) ==
|
|
|
|
URTWN_CHIP_UMC_A_CUT) {
|
|
|
|
urtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255);
|
|
|
|
urtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_cam_init(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
/* Invalidate all CAM entries. */
|
|
|
|
urtwn_write_4(sc, R92C_CAMCMD,
|
|
|
|
R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR);
|
|
|
|
}
|
|
|
|
|
2015-12-13 22:00:19 +00:00
|
|
|
static int
|
|
|
|
urtwn_cam_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data)
|
|
|
|
{
|
|
|
|
usb_error_t error;
|
|
|
|
|
|
|
|
error = urtwn_write_4(sc, R92C_CAMWRITE, data);
|
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
|
|
|
error = urtwn_write_4(sc, R92C_CAMCMD,
|
|
|
|
R92C_CAMCMD_POLLING | R92C_CAMCMD_WRITE |
|
|
|
|
SM(R92C_CAMCMD_ADDR, addr));
|
|
|
|
if (error != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
return (EIO);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static void
|
|
|
|
urtwn_pa_bias_init(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
uint8_t reg;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < sc->nrxchains; i++) {
|
|
|
|
if (sc->pa_setting & (1 << i))
|
|
|
|
continue;
|
|
|
|
urtwn_rf_write(sc, i, R92C_RF_IPA, 0x0f406);
|
|
|
|
urtwn_rf_write(sc, i, R92C_RF_IPA, 0x4f406);
|
|
|
|
urtwn_rf_write(sc, i, R92C_RF_IPA, 0x8f406);
|
|
|
|
urtwn_rf_write(sc, i, R92C_RF_IPA, 0xcf406);
|
|
|
|
}
|
|
|
|
if (!(sc->pa_setting & 0x10)) {
|
|
|
|
reg = urtwn_read_1(sc, 0x16);
|
|
|
|
reg = (reg & ~0xf0) | 0x90;
|
|
|
|
urtwn_write_1(sc, 0x16, reg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_rxfilter_init(struct urtwn_softc *sc)
|
|
|
|
{
|
2015-11-08 23:21:54 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
|
|
|
uint32_t rcr;
|
|
|
|
uint16_t filter;
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Accept all multicast frames. */
|
|
|
|
urtwn_write_4(sc, R92C_MAR + 0, 0xffffffff);
|
|
|
|
urtwn_write_4(sc, R92C_MAR + 4, 0xffffffff);
|
2015-11-08 23:21:54 +00:00
|
|
|
|
|
|
|
/* Filter for management frames. */
|
|
|
|
filter = 0x7f3f;
|
2015-11-10 00:12:00 +00:00
|
|
|
switch (vap->iv_opmode) {
|
|
|
|
case IEEE80211_M_STA:
|
2015-11-08 23:21:54 +00:00
|
|
|
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));
|
2015-11-10 00:12:00 +00:00
|
|
|
break;
|
|
|
|
case IEEE80211_M_HOSTAP:
|
|
|
|
filter &= ~(
|
|
|
|
R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) |
|
2016-02-29 00:05:37 +00:00
|
|
|
R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP));
|
2015-11-10 00:12:00 +00:00
|
|
|
break;
|
|
|
|
case IEEE80211_M_MONITOR:
|
2015-11-10 12:52:26 +00:00
|
|
|
case IEEE80211_M_IBSS:
|
2015-11-10 00:12:00 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
device_printf(sc->sc_dev, "%s: undefined opmode %d\n",
|
|
|
|
__func__, vap->iv_opmode);
|
|
|
|
break;
|
2015-11-08 23:21:54 +00:00
|
|
|
}
|
|
|
|
urtwn_write_2(sc, R92C_RXFLTMAP0, filter);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Reject all control frames. */
|
|
|
|
urtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
|
2015-11-08 23:21:54 +00:00
|
|
|
|
|
|
|
/* Reject all data frames. */
|
|
|
|
urtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (vap->iv_opmode == IEEE80211_M_MONITOR) {
|
|
|
|
/* Accept all frames. */
|
|
|
|
rcr |= R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF |
|
|
|
|
R92C_RCR_AAP;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set Rx filter. */
|
|
|
|
urtwn_write_4(sc, R92C_RCR, rcr);
|
|
|
|
|
|
|
|
if (ic->ic_promisc != 0) {
|
|
|
|
/* Update Rx filter. */
|
|
|
|
urtwn_set_promisc(sc);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_edca_init(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
urtwn_write_2(sc, R92C_SPEC_SIFS, 0x100a);
|
|
|
|
urtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x100a);
|
|
|
|
urtwn_write_2(sc, R92C_SIFS_CCK, 0x100a);
|
|
|
|
urtwn_write_2(sc, R92C_SIFS_OFDM, 0x100a);
|
|
|
|
urtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b);
|
|
|
|
urtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f);
|
|
|
|
urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005ea324);
|
|
|
|
urtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002fa226);
|
|
|
|
}
|
|
|
|
|
2015-10-09 14:31:32 +00:00
|
|
|
static void
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_write_txpower(struct urtwn_softc *sc, int chain,
|
|
|
|
uint16_t power[URTWN_RIDX_COUNT])
|
|
|
|
{
|
|
|
|
uint32_t reg;
|
|
|
|
|
|
|
|
/* Write per-CCK rate Tx power. */
|
|
|
|
if (chain == 0) {
|
|
|
|
reg = urtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32);
|
|
|
|
reg = RW(reg, R92C_TXAGC_A_CCK1, power[0]);
|
|
|
|
urtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg);
|
|
|
|
reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
|
|
|
|
reg = RW(reg, R92C_TXAGC_A_CCK2, power[1]);
|
|
|
|
reg = RW(reg, R92C_TXAGC_A_CCK55, power[2]);
|
|
|
|
reg = RW(reg, R92C_TXAGC_A_CCK11, power[3]);
|
|
|
|
urtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
|
|
|
|
} else {
|
|
|
|
reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32);
|
|
|
|
reg = RW(reg, R92C_TXAGC_B_CCK1, power[0]);
|
|
|
|
reg = RW(reg, R92C_TXAGC_B_CCK2, power[1]);
|
|
|
|
reg = RW(reg, R92C_TXAGC_B_CCK55, power[2]);
|
|
|
|
urtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg);
|
|
|
|
reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
|
|
|
|
reg = RW(reg, R92C_TXAGC_B_CCK11, power[3]);
|
|
|
|
urtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
|
|
|
|
}
|
|
|
|
/* Write per-OFDM rate Tx power. */
|
|
|
|
urtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain),
|
|
|
|
SM(R92C_TXAGC_RATE06, power[ 4]) |
|
|
|
|
SM(R92C_TXAGC_RATE09, power[ 5]) |
|
|
|
|
SM(R92C_TXAGC_RATE12, power[ 6]) |
|
|
|
|
SM(R92C_TXAGC_RATE18, power[ 7]));
|
|
|
|
urtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain),
|
|
|
|
SM(R92C_TXAGC_RATE24, power[ 8]) |
|
|
|
|
SM(R92C_TXAGC_RATE36, power[ 9]) |
|
|
|
|
SM(R92C_TXAGC_RATE48, power[10]) |
|
|
|
|
SM(R92C_TXAGC_RATE54, power[11]));
|
|
|
|
/* Write per-MCS Tx power. */
|
|
|
|
urtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain),
|
|
|
|
SM(R92C_TXAGC_MCS00, power[12]) |
|
|
|
|
SM(R92C_TXAGC_MCS01, power[13]) |
|
|
|
|
SM(R92C_TXAGC_MCS02, power[14]) |
|
|
|
|
SM(R92C_TXAGC_MCS03, power[15]));
|
|
|
|
urtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain),
|
|
|
|
SM(R92C_TXAGC_MCS04, power[16]) |
|
|
|
|
SM(R92C_TXAGC_MCS05, power[17]) |
|
|
|
|
SM(R92C_TXAGC_MCS06, power[18]) |
|
|
|
|
SM(R92C_TXAGC_MCS07, power[19]));
|
|
|
|
urtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain),
|
|
|
|
SM(R92C_TXAGC_MCS08, power[20]) |
|
2014-02-05 08:09:02 +00:00
|
|
|
SM(R92C_TXAGC_MCS09, power[21]) |
|
2013-06-08 16:02:31 +00:00
|
|
|
SM(R92C_TXAGC_MCS10, power[22]) |
|
|
|
|
SM(R92C_TXAGC_MCS11, power[23]));
|
|
|
|
urtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain),
|
|
|
|
SM(R92C_TXAGC_MCS12, power[24]) |
|
|
|
|
SM(R92C_TXAGC_MCS13, power[25]) |
|
|
|
|
SM(R92C_TXAGC_MCS14, power[26]) |
|
|
|
|
SM(R92C_TXAGC_MCS15, power[27]));
|
|
|
|
}
|
|
|
|
|
2015-10-09 14:31:32 +00:00
|
|
|
static void
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_get_txpower(struct urtwn_softc *sc, int chain,
|
|
|
|
struct ieee80211_channel *c, struct ieee80211_channel *extc,
|
|
|
|
uint16_t power[URTWN_RIDX_COUNT])
|
|
|
|
{
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2015-11-24 19:20:45 +00:00
|
|
|
struct r92c_rom *rom = &sc->rom.r92c_rom;
|
2013-06-08 16:02:31 +00:00
|
|
|
uint16_t cckpow, ofdmpow, htpow, diff, max;
|
|
|
|
const struct urtwn_txpwr *base;
|
|
|
|
int ridx, chan, group;
|
|
|
|
|
|
|
|
/* Determine channel group. */
|
|
|
|
chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */
|
|
|
|
if (chan <= 3)
|
|
|
|
group = 0;
|
|
|
|
else if (chan <= 9)
|
|
|
|
group = 1;
|
|
|
|
else
|
|
|
|
group = 2;
|
|
|
|
|
|
|
|
/* Get original Tx power based on board type and RF chain. */
|
|
|
|
if (!(sc->chip & URTWN_CHIP_92C)) {
|
|
|
|
if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
|
|
|
|
base = &rtl8188ru_txagc[chain];
|
|
|
|
else
|
|
|
|
base = &rtl8192cu_txagc[chain];
|
|
|
|
} else
|
|
|
|
base = &rtl8192cu_txagc[chain];
|
|
|
|
|
|
|
|
memset(power, 0, URTWN_RIDX_COUNT * sizeof(power[0]));
|
|
|
|
if (sc->regulatory == 0) {
|
2015-10-22 15:42:53 +00:00
|
|
|
for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++)
|
2013-06-08 16:02:31 +00:00
|
|
|
power[ridx] = base->pwr[0][ridx];
|
|
|
|
}
|
2015-10-22 15:42:53 +00:00
|
|
|
for (ridx = URTWN_RIDX_OFDM6; ridx < URTWN_RIDX_COUNT; ridx++) {
|
2013-06-08 16:02:31 +00:00
|
|
|
if (sc->regulatory == 3) {
|
|
|
|
power[ridx] = base->pwr[0][ridx];
|
|
|
|
/* Apply vendor limits. */
|
|
|
|
if (extc != NULL)
|
|
|
|
max = rom->ht40_max_pwr[group];
|
|
|
|
else
|
|
|
|
max = rom->ht20_max_pwr[group];
|
|
|
|
max = (max >> (chain * 4)) & 0xf;
|
|
|
|
if (power[ridx] > max)
|
|
|
|
power[ridx] = max;
|
|
|
|
} else if (sc->regulatory == 1) {
|
|
|
|
if (extc == NULL)
|
|
|
|
power[ridx] = base->pwr[group][ridx];
|
|
|
|
} else if (sc->regulatory != 2)
|
|
|
|
power[ridx] = base->pwr[0][ridx];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Compute per-CCK rate Tx power. */
|
|
|
|
cckpow = rom->cck_tx_pwr[chain][group];
|
2015-10-22 15:42:53 +00:00
|
|
|
for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) {
|
2013-06-08 16:02:31 +00:00
|
|
|
power[ridx] += cckpow;
|
|
|
|
if (power[ridx] > R92C_MAX_TX_PWR)
|
|
|
|
power[ridx] = R92C_MAX_TX_PWR;
|
|
|
|
}
|
|
|
|
|
|
|
|
htpow = rom->ht40_1s_tx_pwr[chain][group];
|
|
|
|
if (sc->ntxchains > 1) {
|
|
|
|
/* Apply reduction for 2 spatial streams. */
|
|
|
|
diff = rom->ht40_2s_tx_pwr_diff[group];
|
|
|
|
diff = (diff >> (chain * 4)) & 0xf;
|
|
|
|
htpow = (htpow > diff) ? htpow - diff : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Compute per-OFDM rate Tx power. */
|
|
|
|
diff = rom->ofdm_tx_pwr_diff[group];
|
|
|
|
diff = (diff >> (chain * 4)) & 0xf;
|
|
|
|
ofdmpow = htpow + diff; /* HT->OFDM correction. */
|
2015-10-22 15:42:53 +00:00
|
|
|
for (ridx = URTWN_RIDX_OFDM6; ridx <= URTWN_RIDX_OFDM54; ridx++) {
|
2013-06-08 16:02:31 +00:00
|
|
|
power[ridx] += ofdmpow;
|
|
|
|
if (power[ridx] > R92C_MAX_TX_PWR)
|
|
|
|
power[ridx] = R92C_MAX_TX_PWR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Compute per-MCS Tx power. */
|
|
|
|
if (extc == NULL) {
|
|
|
|
diff = rom->ht20_tx_pwr_diff[group];
|
|
|
|
diff = (diff >> (chain * 4)) & 0xf;
|
|
|
|
htpow += diff; /* HT40->HT20 correction. */
|
|
|
|
}
|
|
|
|
for (ridx = 12; ridx <= 27; ridx++) {
|
|
|
|
power[ridx] += htpow;
|
|
|
|
if (power[ridx] > R92C_MAX_TX_PWR)
|
|
|
|
power[ridx] = R92C_MAX_TX_PWR;
|
|
|
|
}
|
2016-01-20 23:27:02 +00:00
|
|
|
#ifdef USB_DEBUG
|
|
|
|
if (sc->sc_debug & URTWN_DEBUG_TXPWR) {
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Dump per-rate Tx power values. */
|
|
|
|
printf("Tx power for chain %d:\n", chain);
|
2015-10-22 15:42:53 +00:00
|
|
|
for (ridx = URTWN_RIDX_CCK1; ridx < URTWN_RIDX_COUNT; ridx++)
|
2013-06-08 16:02:31 +00:00
|
|
|
printf("Rate %d = %u\n", ridx, power[ridx]);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-10-09 14:31:32 +00:00
|
|
|
static void
|
2014-04-25 08:01:22 +00:00
|
|
|
urtwn_r88e_get_txpower(struct urtwn_softc *sc, int chain,
|
|
|
|
struct ieee80211_channel *c, struct ieee80211_channel *extc,
|
|
|
|
uint16_t power[URTWN_RIDX_COUNT])
|
|
|
|
{
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2016-01-17 00:52:21 +00:00
|
|
|
struct r88e_rom *rom = &sc->rom.r88e_rom;
|
2014-04-25 08:01:22 +00:00
|
|
|
uint16_t cckpow, ofdmpow, bw20pow, htpow;
|
|
|
|
const struct urtwn_r88e_txpwr *base;
|
|
|
|
int ridx, chan, group;
|
|
|
|
|
|
|
|
/* Determine channel group. */
|
|
|
|
chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */
|
|
|
|
if (chan <= 2)
|
|
|
|
group = 0;
|
|
|
|
else if (chan <= 5)
|
|
|
|
group = 1;
|
|
|
|
else if (chan <= 8)
|
|
|
|
group = 2;
|
|
|
|
else if (chan <= 11)
|
|
|
|
group = 3;
|
|
|
|
else if (chan <= 13)
|
|
|
|
group = 4;
|
|
|
|
else
|
|
|
|
group = 5;
|
|
|
|
|
|
|
|
/* Get original Tx power based on board type and RF chain. */
|
|
|
|
base = &rtl8188eu_txagc[chain];
|
|
|
|
|
|
|
|
memset(power, 0, URTWN_RIDX_COUNT * sizeof(power[0]));
|
|
|
|
if (sc->regulatory == 0) {
|
2015-10-22 15:42:53 +00:00
|
|
|
for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++)
|
2014-04-25 08:01:22 +00:00
|
|
|
power[ridx] = base->pwr[0][ridx];
|
|
|
|
}
|
2015-10-22 15:42:53 +00:00
|
|
|
for (ridx = URTWN_RIDX_OFDM6; ridx < URTWN_RIDX_COUNT; ridx++) {
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->regulatory == 3)
|
|
|
|
power[ridx] = base->pwr[0][ridx];
|
|
|
|
else if (sc->regulatory == 1) {
|
|
|
|
if (extc == NULL)
|
|
|
|
power[ridx] = base->pwr[group][ridx];
|
|
|
|
} else if (sc->regulatory != 2)
|
|
|
|
power[ridx] = base->pwr[0][ridx];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Compute per-CCK rate Tx power. */
|
2016-01-17 00:52:21 +00:00
|
|
|
cckpow = rom->cck_tx_pwr[group];
|
2015-10-22 15:42:53 +00:00
|
|
|
for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) {
|
2014-04-25 08:01:22 +00:00
|
|
|
power[ridx] += cckpow;
|
|
|
|
if (power[ridx] > R92C_MAX_TX_PWR)
|
|
|
|
power[ridx] = R92C_MAX_TX_PWR;
|
|
|
|
}
|
|
|
|
|
2016-01-17 00:52:21 +00:00
|
|
|
htpow = rom->ht40_tx_pwr[group];
|
2014-04-25 08:01:22 +00:00
|
|
|
|
|
|
|
/* Compute per-OFDM rate Tx power. */
|
|
|
|
ofdmpow = htpow + sc->ofdm_tx_pwr_diff;
|
2015-10-22 15:42:53 +00:00
|
|
|
for (ridx = URTWN_RIDX_OFDM6; ridx <= URTWN_RIDX_OFDM54; ridx++) {
|
2014-04-25 08:01:22 +00:00
|
|
|
power[ridx] += ofdmpow;
|
|
|
|
if (power[ridx] > R92C_MAX_TX_PWR)
|
|
|
|
power[ridx] = R92C_MAX_TX_PWR;
|
|
|
|
}
|
|
|
|
|
|
|
|
bw20pow = htpow + sc->bw20_tx_pwr_diff;
|
|
|
|
for (ridx = 12; ridx <= 27; ridx++) {
|
|
|
|
power[ridx] += bw20pow;
|
|
|
|
if (power[ridx] > R92C_MAX_TX_PWR)
|
|
|
|
power[ridx] = R92C_MAX_TX_PWR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-09 14:31:32 +00:00
|
|
|
static void
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_set_txpower(struct urtwn_softc *sc, struct ieee80211_channel *c,
|
|
|
|
struct ieee80211_channel *extc)
|
|
|
|
{
|
|
|
|
uint16_t power[URTWN_RIDX_COUNT];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < sc->ntxchains; i++) {
|
|
|
|
/* Compute per-rate Tx power values. */
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
urtwn_r88e_get_txpower(sc, i, c, extc, power);
|
|
|
|
else
|
|
|
|
urtwn_get_txpower(sc, i, c, extc, power);
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Write per-rate Tx power values to hardware. */
|
|
|
|
urtwn_write_txpower(sc, i, power);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-27 14:21:24 +00:00
|
|
|
static void
|
|
|
|
urtwn_set_rx_bssid_all(struct urtwn_softc *sc, int enable)
|
|
|
|
{
|
|
|
|
uint32_t reg;
|
|
|
|
|
|
|
|
reg = urtwn_read_4(sc, R92C_RCR);
|
|
|
|
if (enable)
|
|
|
|
reg &= ~R92C_RCR_CBSSID_BCN;
|
|
|
|
else
|
|
|
|
reg |= R92C_RCR_CBSSID_BCN;
|
|
|
|
urtwn_write_4(sc, R92C_RCR, reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_set_gain(struct urtwn_softc *sc, uint8_t gain)
|
|
|
|
{
|
|
|
|
uint32_t reg;
|
|
|
|
|
|
|
|
reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0));
|
|
|
|
reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, gain);
|
|
|
|
urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg);
|
|
|
|
|
|
|
|
if (!(sc->chip & URTWN_CHIP_88E)) {
|
|
|
|
reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1));
|
|
|
|
reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, gain);
|
|
|
|
urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static void
|
|
|
|
urtwn_scan_start(struct ieee80211com *ic)
|
|
|
|
{
|
2015-10-27 14:21:24 +00:00
|
|
|
struct urtwn_softc *sc = ic->ic_softc;
|
|
|
|
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
/* Receive beacons / probe responses from any BSSID. */
|
2015-11-10 12:52:26 +00:00
|
|
|
if (ic->ic_opmode != IEEE80211_M_IBSS)
|
|
|
|
urtwn_set_rx_bssid_all(sc, 1);
|
|
|
|
|
2015-10-27 14:21:24 +00:00
|
|
|
/* Set gain for scanning. */
|
|
|
|
urtwn_set_gain(sc, 0x20);
|
|
|
|
URTWN_UNLOCK(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_scan_end(struct ieee80211com *ic)
|
|
|
|
{
|
2015-10-27 14:21:24 +00:00
|
|
|
struct urtwn_softc *sc = ic->ic_softc;
|
|
|
|
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
/* Restore limitations. */
|
2015-11-10 12:52:26 +00:00
|
|
|
if (ic->ic_promisc == 0 && ic->ic_opmode != IEEE80211_M_IBSS)
|
2015-11-08 23:21:54 +00:00
|
|
|
urtwn_set_rx_bssid_all(sc, 0);
|
2015-11-10 12:52:26 +00:00
|
|
|
|
2015-10-27 14:21:24 +00:00
|
|
|
/* Set gain under link. */
|
|
|
|
urtwn_set_gain(sc, 0x32);
|
|
|
|
URTWN_UNLOCK(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_set_channel(struct ieee80211com *ic)
|
|
|
|
{
|
2015-08-20 03:57:41 +00:00
|
|
|
struct urtwn_softc *sc = ic->ic_softc;
|
2015-12-13 21:43:54 +00:00
|
|
|
struct ieee80211_channel *c = ic->ic_curchan;
|
2015-04-04 08:41:02 +00:00
|
|
|
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
URTWN_LOCK(sc);
|
2015-04-04 08:41:02 +00:00
|
|
|
if (vap->iv_state == IEEE80211_S_SCAN) {
|
|
|
|
/* Make link LED blink during scan. */
|
|
|
|
urtwn_set_led(sc, URTWN_LED_LINK, !sc->ledlink);
|
|
|
|
}
|
2015-12-13 21:43:54 +00:00
|
|
|
urtwn_set_chan(sc, c, NULL);
|
|
|
|
sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq);
|
|
|
|
sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags);
|
|
|
|
sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq);
|
|
|
|
sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags);
|
2013-06-08 16:02:31 +00:00
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
}
|
|
|
|
|
2015-12-09 09:29:38 +00:00
|
|
|
static int
|
|
|
|
urtwn_wme_update(struct ieee80211com *ic)
|
|
|
|
{
|
|
|
|
const struct wmeParams *wmep =
|
|
|
|
ic->ic_wme.wme_chanParams.cap_wmeParams;
|
|
|
|
struct urtwn_softc *sc = ic->ic_softc;
|
|
|
|
uint8_t aifs, acm, slottime;
|
|
|
|
int ac;
|
|
|
|
|
|
|
|
acm = 0;
|
2015-12-13 20:48:24 +00:00
|
|
|
slottime = IEEE80211_GET_SLOTTIME(ic);
|
2015-12-09 09:29:38 +00:00
|
|
|
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) {
|
|
|
|
/* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */
|
|
|
|
aifs = wmep[ac].wmep_aifsn * slottime + IEEE80211_DUR_SIFS;
|
|
|
|
urtwn_write_4(sc, wme2queue[ac].reg,
|
|
|
|
SM(R92C_EDCA_PARAM_TXOP, wmep[ac].wmep_txopLimit) |
|
|
|
|
SM(R92C_EDCA_PARAM_ECWMIN, wmep[ac].wmep_logcwmin) |
|
|
|
|
SM(R92C_EDCA_PARAM_ECWMAX, wmep[ac].wmep_logcwmax) |
|
|
|
|
SM(R92C_EDCA_PARAM_AIFS, aifs));
|
|
|
|
if (ac != WME_AC_BE)
|
|
|
|
acm |= wmep[ac].wmep_acm << ac;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (acm != 0)
|
|
|
|
acm |= R92C_ACMHWCTRL_EN;
|
|
|
|
urtwn_write_1(sc, R92C_ACMHWCTRL,
|
|
|
|
(urtwn_read_1(sc, R92C_ACMHWCTRL) & ~R92C_ACMHWCTRL_ACM_MASK) |
|
|
|
|
acm);
|
|
|
|
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-20 23:01:33 +00:00
|
|
|
static void
|
|
|
|
urtwn_update_slot(struct ieee80211com *ic)
|
|
|
|
{
|
|
|
|
urtwn_cmd_sleepable(ic->ic_softc, NULL, 0, urtwn_update_slot_cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_update_slot_cb(struct urtwn_softc *sc, union sec_param *data)
|
|
|
|
{
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
uint8_t slottime;
|
|
|
|
|
|
|
|
slottime = IEEE80211_GET_SLOTTIME(ic);
|
|
|
|
|
2016-01-20 23:27:02 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_ANY, "%s: setting slot time to %uus\n",
|
|
|
|
__func__, slottime);
|
2016-01-20 23:01:33 +00:00
|
|
|
|
|
|
|
urtwn_write_1(sc, R92C_SLOT, slottime);
|
|
|
|
urtwn_update_aifs(sc, slottime);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_update_aifs(struct urtwn_softc *sc, uint8_t slottime)
|
|
|
|
{
|
|
|
|
const struct wmeParams *wmep =
|
|
|
|
sc->sc_ic.ic_wme.wme_chanParams.cap_wmeParams;
|
|
|
|
uint8_t aifs, ac;
|
|
|
|
|
|
|
|
for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) {
|
|
|
|
/* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */
|
|
|
|
aifs = wmep[ac].wmep_aifsn * slottime + IEEE80211_DUR_SIFS;
|
|
|
|
urtwn_write_1(sc, wme2queue[ac].reg, aifs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-08 23:21:54 +00:00
|
|
|
static void
|
|
|
|
urtwn_set_promisc(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
|
|
|
uint32_t rcr, mask1, mask2;
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
|
|
|
if (vap->iv_opmode == IEEE80211_M_MONITOR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mask1 = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP;
|
|
|
|
mask2 = R92C_RCR_APM;
|
|
|
|
|
|
|
|
if (vap->iv_state == IEEE80211_S_RUN) {
|
|
|
|
switch (vap->iv_opmode) {
|
|
|
|
case IEEE80211_M_STA:
|
2015-11-10 00:12:00 +00:00
|
|
|
mask2 |= R92C_RCR_CBSSID_DATA;
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case IEEE80211_M_HOSTAP:
|
|
|
|
mask2 |= R92C_RCR_CBSSID_BCN;
|
2015-11-08 23:21:54 +00:00
|
|
|
break;
|
2015-11-10 12:52:26 +00:00
|
|
|
case IEEE80211_M_IBSS:
|
|
|
|
mask2 |= R92C_RCR_CBSSID_DATA;
|
|
|
|
break;
|
2015-11-08 23:21:54 +00:00
|
|
|
default:
|
|
|
|
device_printf(sc->sc_dev, "%s: undefined opmode %d\n",
|
|
|
|
__func__, vap->iv_opmode);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rcr = urtwn_read_4(sc, R92C_RCR);
|
|
|
|
if (ic->ic_promisc == 0)
|
|
|
|
rcr = (rcr & ~mask1) | mask2;
|
|
|
|
else
|
|
|
|
rcr = (rcr & ~mask2) | mask1;
|
|
|
|
urtwn_write_4(sc, R92C_RCR, rcr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_update_promisc(struct ieee80211com *ic)
|
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = ic->ic_softc;
|
|
|
|
|
|
|
|
URTWN_LOCK(sc);
|
|
|
|
if (sc->sc_flags & URTWN_RUNNING)
|
|
|
|
urtwn_set_promisc(sc);
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static void
|
2015-05-25 19:53:29 +00:00
|
|
|
urtwn_update_mcast(struct ieee80211com *ic)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
|
|
|
/* XXX do nothing? */
|
|
|
|
}
|
|
|
|
|
2015-12-13 21:00:21 +00:00
|
|
|
static struct ieee80211_node *
|
2016-04-13 05:19:16 +00:00
|
|
|
urtwn_node_alloc(struct ieee80211vap *vap,
|
2015-12-13 21:00:21 +00:00
|
|
|
const uint8_t mac[IEEE80211_ADDR_LEN])
|
|
|
|
{
|
|
|
|
struct urtwn_node *un;
|
|
|
|
|
|
|
|
un = malloc(sizeof (struct urtwn_node), M_80211_NODE,
|
|
|
|
M_NOWAIT | M_ZERO);
|
|
|
|
|
|
|
|
if (un == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
un->id = URTWN_MACID_UNDEFINED;
|
|
|
|
|
|
|
|
return &un->ni;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-04-13 05:19:16 +00:00
|
|
|
urtwn_newassoc(struct ieee80211_node *ni, int isnew)
|
2015-12-13 21:00:21 +00:00
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = ni->ni_ic->ic_softc;
|
|
|
|
struct urtwn_node *un = URTWN_NODE(ni);
|
|
|
|
uint8_t id;
|
|
|
|
|
2016-04-13 05:19:16 +00:00
|
|
|
/* Only do this bit for R88E chips */
|
|
|
|
if (! (sc->chip & URTWN_CHIP_88E))
|
|
|
|
return;
|
|
|
|
|
2015-12-13 21:00:21 +00:00
|
|
|
if (!isnew)
|
|
|
|
return;
|
|
|
|
|
|
|
|
URTWN_NT_LOCK(sc);
|
|
|
|
for (id = 0; id <= URTWN_MACID_MAX(sc); id++) {
|
|
|
|
if (id != URTWN_MACID_BC && sc->node_list[id] == NULL) {
|
|
|
|
un->id = id;
|
|
|
|
sc->node_list[id] = ni;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
URTWN_NT_UNLOCK(sc);
|
|
|
|
|
|
|
|
if (id > URTWN_MACID_MAX(sc)) {
|
|
|
|
device_printf(sc->sc_dev, "%s: node table is full\n",
|
|
|
|
__func__);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-04-13 05:19:16 +00:00
|
|
|
urtwn_node_free(struct ieee80211_node *ni)
|
2015-12-13 21:00:21 +00:00
|
|
|
{
|
|
|
|
struct urtwn_softc *sc = ni->ni_ic->ic_softc;
|
|
|
|
struct urtwn_node *un = URTWN_NODE(ni);
|
|
|
|
|
|
|
|
URTWN_NT_LOCK(sc);
|
|
|
|
if (un->id != URTWN_MACID_UNDEFINED)
|
|
|
|
sc->node_list[un->id] = NULL;
|
|
|
|
URTWN_NT_UNLOCK(sc);
|
|
|
|
|
|
|
|
sc->sc_node_free(ni);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static void
|
|
|
|
urtwn_set_chan(struct urtwn_softc *sc, struct ieee80211_channel *c,
|
|
|
|
struct ieee80211_channel *extc)
|
|
|
|
{
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2013-06-08 16:02:31 +00:00
|
|
|
uint32_t reg;
|
|
|
|
u_int chan;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */
|
|
|
|
if (chan == 0 || chan == IEEE80211_CHAN_ANY) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"%s: invalid channel %x\n", __func__, chan);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set Tx power for this new channel. */
|
|
|
|
urtwn_set_txpower(sc, c, extc);
|
|
|
|
|
|
|
|
for (i = 0; i < sc->nrxchains; i++) {
|
|
|
|
urtwn_rf_write(sc, i, R92C_RF_CHNLBW,
|
|
|
|
RW(sc->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan));
|
|
|
|
}
|
|
|
|
#ifndef IEEE80211_NO_HT
|
|
|
|
if (extc != NULL) {
|
|
|
|
/* Is secondary channel below or above primary? */
|
|
|
|
int prichlo = c->ic_freq < extc->ic_freq;
|
|
|
|
|
|
|
|
urtwn_write_1(sc, R92C_BWOPMODE,
|
|
|
|
urtwn_read_1(sc, R92C_BWOPMODE) & ~R92C_BWOPMODE_20MHZ);
|
|
|
|
|
|
|
|
reg = urtwn_read_1(sc, R92C_RRSR + 2);
|
|
|
|
reg = (reg & ~0x6f) | (prichlo ? 1 : 2) << 5;
|
|
|
|
urtwn_write_1(sc, R92C_RRSR + 2, reg);
|
|
|
|
|
|
|
|
urtwn_bb_write(sc, R92C_FPGA0_RFMOD,
|
|
|
|
urtwn_bb_read(sc, R92C_FPGA0_RFMOD) | R92C_RFMOD_40MHZ);
|
|
|
|
urtwn_bb_write(sc, R92C_FPGA1_RFMOD,
|
|
|
|
urtwn_bb_read(sc, R92C_FPGA1_RFMOD) | R92C_RFMOD_40MHZ);
|
|
|
|
|
|
|
|
/* Set CCK side band. */
|
|
|
|
reg = urtwn_bb_read(sc, R92C_CCK0_SYSTEM);
|
|
|
|
reg = (reg & ~0x00000010) | (prichlo ? 0 : 1) << 4;
|
|
|
|
urtwn_bb_write(sc, R92C_CCK0_SYSTEM, reg);
|
|
|
|
|
|
|
|
reg = urtwn_bb_read(sc, R92C_OFDM1_LSTF);
|
|
|
|
reg = (reg & ~0x00000c00) | (prichlo ? 1 : 2) << 10;
|
|
|
|
urtwn_bb_write(sc, R92C_OFDM1_LSTF, reg);
|
|
|
|
|
|
|
|
urtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2,
|
|
|
|
urtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) &
|
|
|
|
~R92C_FPGA0_ANAPARAM2_CBW20);
|
|
|
|
|
|
|
|
reg = urtwn_bb_read(sc, 0x818);
|
|
|
|
reg = (reg & ~0x0c000000) | (prichlo ? 2 : 1) << 26;
|
|
|
|
urtwn_bb_write(sc, 0x818, reg);
|
|
|
|
|
|
|
|
/* Select 40MHz bandwidth. */
|
|
|
|
urtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
|
|
|
|
(sc->rf_chnlbw[0] & ~0xfff) | chan);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
urtwn_write_1(sc, R92C_BWOPMODE,
|
|
|
|
urtwn_read_1(sc, R92C_BWOPMODE) | R92C_BWOPMODE_20MHZ);
|
|
|
|
|
|
|
|
urtwn_bb_write(sc, R92C_FPGA0_RFMOD,
|
|
|
|
urtwn_bb_read(sc, R92C_FPGA0_RFMOD) & ~R92C_RFMOD_40MHZ);
|
|
|
|
urtwn_bb_write(sc, R92C_FPGA1_RFMOD,
|
|
|
|
urtwn_bb_read(sc, R92C_FPGA1_RFMOD) & ~R92C_RFMOD_40MHZ);
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
if (!(sc->chip & URTWN_CHIP_88E)) {
|
|
|
|
urtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2,
|
|
|
|
urtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) |
|
|
|
|
R92C_FPGA0_ANAPARAM2_CBW20);
|
|
|
|
}
|
2015-04-04 08:36:02 +00:00
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Select 20MHz bandwidth. */
|
|
|
|
urtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
|
2015-04-04 08:36:02 +00:00
|
|
|
(sc->rf_chnlbw[0] & ~0xfff) | chan |
|
2014-04-25 08:01:22 +00:00
|
|
|
((sc->chip & URTWN_CHIP_88E) ? R88E_RF_CHNLBW_BW20 :
|
|
|
|
R92C_RF_CHNLBW_BW20));
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_iq_calib(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_lc_calib(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
uint32_t rf_ac[2];
|
|
|
|
uint8_t txmode;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
txmode = urtwn_read_1(sc, R92C_OFDM1_LSTF + 3);
|
|
|
|
if ((txmode & 0x70) != 0) {
|
|
|
|
/* Disable all continuous Tx. */
|
|
|
|
urtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70);
|
|
|
|
|
|
|
|
/* Set RF mode to standby mode. */
|
|
|
|
for (i = 0; i < sc->nrxchains; i++) {
|
|
|
|
rf_ac[i] = urtwn_rf_read(sc, i, R92C_RF_AC);
|
|
|
|
urtwn_rf_write(sc, i, R92C_RF_AC,
|
|
|
|
RW(rf_ac[i], R92C_RF_AC_MODE,
|
|
|
|
R92C_RF_AC_MODE_STANDBY));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Block all Tx queues. */
|
2016-01-04 21:16:49 +00:00
|
|
|
urtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
/* Start calibration. */
|
|
|
|
urtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
|
|
|
|
urtwn_rf_read(sc, 0, R92C_RF_CHNLBW) | R92C_RF_CHNLBW_LCSTART);
|
|
|
|
|
|
|
|
/* Give calibration the time to complete. */
|
2014-05-20 15:53:17 +00:00
|
|
|
usb_pause_mtx(&sc->sc_mtx, hz / 10); /* 100ms */
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Restore configuration. */
|
|
|
|
if ((txmode & 0x70) != 0) {
|
|
|
|
/* Restore Tx mode. */
|
|
|
|
urtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode);
|
|
|
|
/* Restore RF mode. */
|
|
|
|
for (i = 0; i < sc->nrxchains; i++)
|
|
|
|
urtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]);
|
|
|
|
} else {
|
|
|
|
/* Unblock all Tx queues. */
|
|
|
|
urtwn_write_1(sc, R92C_TXPAUSE, 0x00);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-20 23:55:39 +00:00
|
|
|
static void
|
|
|
|
urtwn_temp_calib(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
uint8_t temp;
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
|
|
|
if (!(sc->sc_flags & URTWN_TEMP_MEASURED)) {
|
|
|
|
/* Start measuring temperature. */
|
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP,
|
|
|
|
"%s: start measuring temperature\n", __func__);
|
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
|
|
|
urtwn_rf_write(sc, 0, R88E_RF_T_METER,
|
|
|
|
R88E_RF_T_METER_START);
|
|
|
|
} else {
|
|
|
|
urtwn_rf_write(sc, 0, R92C_RF_T_METER,
|
|
|
|
R92C_RF_T_METER_START);
|
|
|
|
}
|
|
|
|
sc->sc_flags |= URTWN_TEMP_MEASURED;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sc->sc_flags &= ~URTWN_TEMP_MEASURED;
|
|
|
|
|
|
|
|
/* Read measured temperature. */
|
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
|
|
|
temp = MS(urtwn_rf_read(sc, 0, R88E_RF_T_METER),
|
|
|
|
R88E_RF_T_METER_VAL);
|
|
|
|
} else {
|
|
|
|
temp = MS(urtwn_rf_read(sc, 0, R92C_RF_T_METER),
|
|
|
|
R92C_RF_T_METER_VAL);
|
|
|
|
}
|
|
|
|
if (temp == 0) { /* Read failed, skip. */
|
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP,
|
|
|
|
"%s: temperature read failed, skipping\n", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP,
|
|
|
|
"%s: temperature: previous %u, current %u\n",
|
|
|
|
__func__, sc->thcal_lctemp, temp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Redo LC calibration if temperature changed significantly since
|
|
|
|
* last calibration.
|
|
|
|
*/
|
|
|
|
if (sc->thcal_lctemp == 0) {
|
|
|
|
/* First LC calibration is performed in urtwn_init(). */
|
|
|
|
sc->thcal_lctemp = temp;
|
|
|
|
} else if (abs(temp - sc->thcal_lctemp) > 1) {
|
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP,
|
|
|
|
"%s: LC calib triggered by temp: %u -> %u\n",
|
|
|
|
__func__, sc->thcal_lctemp, temp);
|
|
|
|
urtwn_lc_calib(sc);
|
|
|
|
/* Record temperature of last LC calibration. */
|
|
|
|
sc->thcal_lctemp = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
static int
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
urtwn_init(struct urtwn_softc *sc)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
|
|
|
|
uint8_t macaddr[IEEE80211_ADDR_LEN];
|
2013-06-08 16:02:31 +00:00
|
|
|
uint32_t reg;
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_error_t usb_err = USB_ERR_NORMAL_COMPLETION;
|
2013-06-08 16:02:31 +00:00
|
|
|
int error;
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
URTWN_LOCK(sc);
|
|
|
|
if (sc->sc_flags & URTWN_RUNNING) {
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
return (0);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Init firmware commands ring. */
|
|
|
|
sc->fwcur = 0;
|
|
|
|
|
|
|
|
/* Allocate Tx/Rx buffers. */
|
|
|
|
error = urtwn_alloc_rx_list(sc);
|
|
|
|
if (error != 0)
|
|
|
|
goto fail;
|
2015-04-04 08:36:02 +00:00
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
error = urtwn_alloc_tx_list(sc);
|
|
|
|
if (error != 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* Power on adapter. */
|
|
|
|
error = urtwn_power_on(sc);
|
|
|
|
if (error != 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* Initialize DMA. */
|
|
|
|
error = urtwn_dma_init(sc);
|
|
|
|
if (error != 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* Set info size in Rx descriptors (in 64-bit words). */
|
|
|
|
urtwn_write_1(sc, R92C_RX_DRVINFO_SZ, 4);
|
|
|
|
|
|
|
|
/* Init interrupts. */
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_err = urtwn_write_4(sc, R88E_HISR, 0xffffffff);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
goto fail;
|
|
|
|
usb_err = urtwn_write_4(sc, R88E_HIMR, R88E_HIMR_CPWM | R88E_HIMR_CPWM2 |
|
2014-04-25 08:01:22 +00:00
|
|
|
R88E_HIMR_TBDER | R88E_HIMR_PSTIMEOUT);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
goto fail;
|
|
|
|
usb_err = urtwn_write_4(sc, R88E_HIMRE, R88E_HIMRE_RXFOVW |
|
2014-04-25 08:01:22 +00:00
|
|
|
R88E_HIMRE_TXFOVW | R88E_HIMRE_RXERR | R88E_HIMRE_TXERR);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
goto fail;
|
|
|
|
usb_err = urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION,
|
2014-04-25 08:01:22 +00:00
|
|
|
urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) |
|
|
|
|
R92C_USB_SPECIAL_OPTION_INT_BULK_SEL);
|
2015-12-03 14:38:55 +00:00
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
goto fail;
|
2014-04-25 08:01:22 +00:00
|
|
|
} else {
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_err = urtwn_write_4(sc, R92C_HISR, 0xffffffff);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
goto fail;
|
|
|
|
usb_err = urtwn_write_4(sc, R92C_HIMR, 0xffffffff);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
goto fail;
|
2014-04-25 08:01:22 +00:00
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Set MAC address. */
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
IEEE80211_ADDR_COPY(macaddr, vap ? vap->iv_myaddr : ic->ic_macaddr);
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_err = urtwn_write_region_1(sc, R92C_MACID, macaddr, IEEE80211_ADDR_LEN);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
goto fail;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Set initial network type. */
|
2015-10-23 08:26:26 +00:00
|
|
|
urtwn_set_mode(sc, R92C_MSR_INFRA);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-11-08 23:21:54 +00:00
|
|
|
/* Initialize Rx filter. */
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_rxfilter_init(sc);
|
|
|
|
|
2015-05-08 09:01:00 +00:00
|
|
|
/* Set response rate. */
|
2013-06-08 16:02:31 +00:00
|
|
|
reg = urtwn_read_4(sc, R92C_RRSR);
|
|
|
|
reg = RW(reg, R92C_RRSR_RATE_BITMAP, R92C_RRSR_RATE_CCK_ONLY_1M);
|
|
|
|
urtwn_write_4(sc, R92C_RRSR, reg);
|
|
|
|
|
|
|
|
/* Set short/long retry limits. */
|
|
|
|
urtwn_write_2(sc, R92C_RL,
|
|
|
|
SM(R92C_RL_SRL, 0x30) | SM(R92C_RL_LRL, 0x30));
|
|
|
|
|
|
|
|
/* Initialize EDCA parameters. */
|
|
|
|
urtwn_edca_init(sc);
|
|
|
|
|
|
|
|
/* Setup rate fallback. */
|
2014-04-25 08:01:22 +00:00
|
|
|
if (!(sc->chip & URTWN_CHIP_88E)) {
|
|
|
|
urtwn_write_4(sc, R92C_DARFRC + 0, 0x00000000);
|
|
|
|
urtwn_write_4(sc, R92C_DARFRC + 4, 0x10080404);
|
|
|
|
urtwn_write_4(sc, R92C_RARFRC + 0, 0x04030201);
|
|
|
|
urtwn_write_4(sc, R92C_RARFRC + 4, 0x08070605);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
urtwn_write_1(sc, R92C_FWHW_TXQ_CTRL,
|
|
|
|
urtwn_read_1(sc, R92C_FWHW_TXQ_CTRL) |
|
|
|
|
R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW);
|
|
|
|
/* Set ACK timeout. */
|
|
|
|
urtwn_write_1(sc, R92C_ACKTO, 0x40);
|
|
|
|
|
|
|
|
/* Setup USB aggregation. */
|
|
|
|
reg = urtwn_read_4(sc, R92C_TDECTRL);
|
|
|
|
reg = RW(reg, R92C_TDECTRL_BLK_DESC_NUM, 6);
|
|
|
|
urtwn_write_4(sc, R92C_TDECTRL, reg);
|
|
|
|
urtwn_write_1(sc, R92C_TRXDMA_CTRL,
|
|
|
|
urtwn_read_1(sc, R92C_TRXDMA_CTRL) |
|
|
|
|
R92C_TRXDMA_CTRL_RXDMA_AGG_EN);
|
|
|
|
urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48);
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E)
|
|
|
|
urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH + 1, 4);
|
2015-04-30 02:47:21 +00:00
|
|
|
else {
|
2014-04-25 08:01:22 +00:00
|
|
|
urtwn_write_1(sc, R92C_USB_DMA_AGG_TO, 4);
|
2015-04-30 02:47:21 +00:00
|
|
|
urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION,
|
|
|
|
urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) |
|
|
|
|
R92C_USB_SPECIAL_OPTION_AGG_EN);
|
|
|
|
urtwn_write_1(sc, R92C_USB_AGG_TH, 8);
|
|
|
|
urtwn_write_1(sc, R92C_USB_AGG_TO, 6);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Initialize beacon parameters. */
|
2014-04-25 08:01:22 +00:00
|
|
|
urtwn_write_2(sc, R92C_BCN_CTRL, 0x1010);
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404);
|
|
|
|
urtwn_write_1(sc, R92C_DRVERLYINT, 0x05);
|
|
|
|
urtwn_write_1(sc, R92C_BCNDMATIM, 0x02);
|
|
|
|
urtwn_write_2(sc, R92C_BCNTCFG, 0x660f);
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
if (!(sc->chip & URTWN_CHIP_88E)) {
|
|
|
|
/* Setup AMPDU aggregation. */
|
|
|
|
urtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */
|
|
|
|
urtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16);
|
|
|
|
urtwn_write_2(sc, R92C_MAX_AGGR_NUM, 0x0708);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
urtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2016-02-22 00:48:53 +00:00
|
|
|
#ifndef URTWN_WITHOUT_UCODE
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Load 8051 microcode. */
|
|
|
|
error = urtwn_load_firmware(sc);
|
2016-02-22 00:48:53 +00:00
|
|
|
if (error == 0)
|
|
|
|
sc->sc_flags |= URTWN_FW_LOADED;
|
|
|
|
#endif
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Initialize MAC/BB/RF blocks. */
|
2015-12-03 14:38:55 +00:00
|
|
|
error = urtwn_mac_init(sc);
|
|
|
|
if (error != 0) {
|
|
|
|
device_printf(sc->sc_dev,
|
|
|
|
"%s: error while initializing MAC block\n", __func__);
|
|
|
|
goto fail;
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
urtwn_bb_init(sc);
|
|
|
|
urtwn_rf_init(sc);
|
|
|
|
|
2015-11-08 23:21:54 +00:00
|
|
|
/* Reinitialize Rx filter (D3845 is not committed yet). */
|
|
|
|
urtwn_rxfilter_init(sc);
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
|
|
|
urtwn_write_2(sc, R92C_CR,
|
|
|
|
urtwn_read_2(sc, R92C_CR) | R92C_CR_MACTXEN |
|
|
|
|
R92C_CR_MACRXEN);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Turn CCK and OFDM blocks on. */
|
|
|
|
reg = urtwn_bb_read(sc, R92C_FPGA0_RFMOD);
|
|
|
|
reg |= R92C_RFMOD_CCK_EN;
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_err = urtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
goto fail;
|
2013-06-08 16:02:31 +00:00
|
|
|
reg = urtwn_bb_read(sc, R92C_FPGA0_RFMOD);
|
|
|
|
reg |= R92C_RFMOD_OFDM_EN;
|
2015-12-03 14:38:55 +00:00
|
|
|
usb_err = urtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg);
|
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
goto fail;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Clear per-station keys table. */
|
|
|
|
urtwn_cam_init(sc);
|
|
|
|
|
2015-12-13 22:00:19 +00:00
|
|
|
/* Enable decryption / encryption. */
|
|
|
|
urtwn_write_2(sc, R92C_SECCFG,
|
|
|
|
R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF |
|
|
|
|
R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA |
|
|
|
|
R92C_SECCFG_TXBCKEY_DEF | R92C_SECCFG_RXBCKEY_DEF);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install static keys (if any).
|
|
|
|
* Must be called after urtwn_cam_init().
|
|
|
|
*/
|
|
|
|
ieee80211_runtask(ic, &sc->cmdq_task);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Enable hardware sequence numbering. */
|
2016-01-04 21:16:49 +00:00
|
|
|
urtwn_write_1(sc, R92C_HWSEQ_CTRL, R92C_TX_QUEUE_ALL);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2015-12-13 21:00:21 +00:00
|
|
|
/* Enable per-packet TX report. */
|
|
|
|
if (sc->chip & URTWN_CHIP_88E) {
|
|
|
|
urtwn_write_1(sc, R88E_TX_RPT_CTRL,
|
|
|
|
urtwn_read_1(sc, R88E_TX_RPT_CTRL) | R88E_TX_RPT1_ENA);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* Perform LO and IQ calibrations. */
|
|
|
|
urtwn_iq_calib(sc);
|
|
|
|
/* Perform LC calibration. */
|
|
|
|
urtwn_lc_calib(sc);
|
|
|
|
|
|
|
|
/* Fix USB interference issue. */
|
2014-04-25 08:01:22 +00:00
|
|
|
if (!(sc->chip & URTWN_CHIP_88E)) {
|
|
|
|
urtwn_write_1(sc, 0xfe40, 0xe0);
|
|
|
|
urtwn_write_1(sc, 0xfe41, 0x8d);
|
|
|
|
urtwn_write_1(sc, 0xfe42, 0x80);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
urtwn_pa_bias_init(sc);
|
|
|
|
}
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
/* Initialize GPIO setting. */
|
|
|
|
urtwn_write_1(sc, R92C_GPIO_MUXCFG,
|
|
|
|
urtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT);
|
|
|
|
|
|
|
|
/* Fix for lower temperature. */
|
2014-04-25 08:01:22 +00:00
|
|
|
if (!(sc->chip & URTWN_CHIP_88E))
|
|
|
|
urtwn_write_1(sc, 0x15, 0xe9);
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
usbd_transfer_start(sc->sc_xfer[URTWN_BULK_RX]);
|
|
|
|
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
sc->sc_flags |= URTWN_RUNNING;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
|
|
|
callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc);
|
|
|
|
fail:
|
2015-12-03 14:38:55 +00:00
|
|
|
if (usb_err != USB_ERR_NORMAL_COMPLETION)
|
|
|
|
error = EIO;
|
|
|
|
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
|
|
|
|
return (error);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
urtwn_stop(struct urtwn_softc *sc)
|
2013-06-08 16:02:31 +00:00
|
|
|
{
|
|
|
|
|
2015-12-03 14:38:55 +00:00
|
|
|
URTWN_LOCK(sc);
|
|
|
|
if (!(sc->sc_flags & URTWN_RUNNING)) {
|
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-02-22 00:48:53 +00:00
|
|
|
sc->sc_flags &= ~(URTWN_RUNNING | URTWN_FW_LOADED |
|
|
|
|
URTWN_TEMP_MEASURED);
|
2016-01-20 23:55:39 +00:00
|
|
|
sc->thcal_lctemp = 0;
|
2013-06-08 16:02:31 +00:00
|
|
|
callout_stop(&sc->sc_watchdog_ch);
|
2015-09-29 05:03:24 +00:00
|
|
|
|
2016-02-22 01:15:02 +00:00
|
|
|
urtwn_abort_xfers(sc);
|
2015-09-29 05:03:24 +00:00
|
|
|
urtwn_drain_mbufq(sc);
|
2016-02-22 01:15:02 +00:00
|
|
|
urtwn_power_off(sc);
|
2015-12-03 14:38:55 +00:00
|
|
|
URTWN_UNLOCK(sc);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
urtwn_abort_xfers(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
URTWN_ASSERT_LOCKED(sc);
|
|
|
|
|
|
|
|
/* abort any pending transfers */
|
|
|
|
for (i = 0; i < URTWN_N_TRANSFER; i++)
|
|
|
|
usbd_transfer_stop(sc->sc_xfer[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
|
|
|
|
const struct ieee80211_bpf_params *params)
|
|
|
|
{
|
|
|
|
struct ieee80211com *ic = ni->ni_ic;
|
2015-08-20 03:57:41 +00:00
|
|
|
struct urtwn_softc *sc = ic->ic_softc;
|
2013-06-08 16:02:31 +00:00
|
|
|
struct urtwn_data *bf;
|
2015-11-09 23:46:13 +00:00
|
|
|
int error;
|
2013-06-08 16:02:31 +00:00
|
|
|
|
2016-04-05 22:14:21 +00:00
|
|
|
URTWN_DPRINTF(sc, URTWN_DEBUG_XMIT, "%s: called; m=%p\n",
|
|
|
|
__func__,
|
|
|
|
m);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
/* prevent management frames from being sent if we're not ready */
|
2015-11-09 23:46:13 +00:00
|
|
|
URTWN_LOCK(sc);
|
Replay r286410. Change KPI of how device drivers that provide wireless
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
2015-08-27 08:56:39 +00:00
|
|
|
if (!(sc->sc_flags & URTWN_RUNNING)) {
|
2015-11-09 23:46:13 +00:00
|
|
|
error = ENETDOWN;
|
|
|
|
goto end;
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
2015-11-09 23:46:13 +00:00
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
bf = urtwn_getbuf(sc);
|
|
|
|
if (bf == NULL) {
|
2015-11-09 23:46:13 +00:00
|
|
|
error = ENOBUFS;
|
|
|
|
goto end;
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2015-12-14 20:39:38 +00:00
|
|
|
if (params == NULL) {
|
|
|
|
/*
|
|
|
|
* Legacy path; interpret frame contents to decide
|
|
|
|
* precisely how to send the frame.
|
|
|
|
*/
|
|
|
|
error = urtwn_tx_data(sc, ni, m, bf);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Caller supplied explicit parameters to use in
|
|
|
|
* sending the frame.
|
|
|
|
*/
|
|
|
|
error = urtwn_tx_raw(sc, ni, m, bf, params);
|
|
|
|
}
|
|
|
|
if (error != 0) {
|
2013-06-08 16:02:31 +00:00
|
|
|
STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
|
2015-11-09 23:46:13 +00:00
|
|
|
goto end;
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
2015-11-09 23:46:13 +00:00
|
|
|
|
2015-09-29 05:03:24 +00:00
|
|
|
sc->sc_txtimer = 5;
|
2015-11-09 23:46:13 +00:00
|
|
|
callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc);
|
|
|
|
|
|
|
|
end:
|
|
|
|
if (error != 0)
|
|
|
|
m_freem(m);
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
URTWN_UNLOCK(sc);
|
|
|
|
|
2015-11-09 23:46:13 +00:00
|
|
|
return (error);
|
2013-06-08 16:02:31 +00:00
|
|
|
}
|
|
|
|
|
2014-05-20 15:53:17 +00:00
|
|
|
static void
|
|
|
|
urtwn_ms_delay(struct urtwn_softc *sc)
|
|
|
|
{
|
|
|
|
usb_pause_mtx(&sc->sc_mtx, hz / 1000);
|
|
|
|
}
|
|
|
|
|
2013-06-08 16:02:31 +00:00
|
|
|
static device_method_t urtwn_methods[] = {
|
|
|
|
/* Device interface */
|
|
|
|
DEVMETHOD(device_probe, urtwn_match),
|
|
|
|
DEVMETHOD(device_attach, urtwn_attach),
|
|
|
|
DEVMETHOD(device_detach, urtwn_detach),
|
|
|
|
|
2014-04-25 08:01:22 +00:00
|
|
|
DEVMETHOD_END
|
2013-06-08 16:02:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static driver_t urtwn_driver = {
|
|
|
|
"urtwn",
|
|
|
|
urtwn_methods,
|
|
|
|
sizeof(struct urtwn_softc)
|
|
|
|
};
|
|
|
|
|
|
|
|
static devclass_t urtwn_devclass;
|
|
|
|
|
|
|
|
DRIVER_MODULE(urtwn, uhub, urtwn_driver, urtwn_devclass, NULL, NULL);
|
|
|
|
MODULE_DEPEND(urtwn, usb, 1, 1, 1);
|
|
|
|
MODULE_DEPEND(urtwn, wlan, 1, 1, 1);
|
2016-02-22 00:48:53 +00:00
|
|
|
#ifndef URTWN_WITHOUT_UCODE
|
2013-06-08 16:02:31 +00:00
|
|
|
MODULE_DEPEND(urtwn, firmware, 1, 1, 1);
|
2016-02-22 00:48:53 +00:00
|
|
|
#endif
|
2013-06-08 16:02:31 +00:00
|
|
|
MODULE_VERSION(urtwn, 1);
|
2015-12-11 05:28:00 +00:00
|
|
|
USB_PNP_HOST_INFO(urtwn_devs);
|