From owner-svn-src-head@freebsd.org Sun Dec 13 21:00:22 2015 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7C53DA427C5; Sun, 13 Dec 2015 21:00:22 +0000 (UTC) (envelope-from avos@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 45741194C; Sun, 13 Dec 2015 21:00:22 +0000 (UTC) (envelope-from avos@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tBDL0LhJ078591; Sun, 13 Dec 2015 21:00:21 GMT (envelope-from avos@FreeBSD.org) Received: (from avos@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tBDL0LIi078588; Sun, 13 Dec 2015 21:00:21 GMT (envelope-from avos@FreeBSD.org) Message-Id: <201512132100.tBDL0LIi078588@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: avos set sender to avos@FreeBSD.org using -f From: Andriy Voskoboinyk Date: Sun, 13 Dec 2015 21:00:21 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r292167 - head/sys/dev/usb/wlan X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 13 Dec 2015 21:00:22 -0000 Author: avos Date: Sun Dec 13 21:00:21 2015 New Revision: 292167 URL: https://svnweb.freebsd.org/changeset/base/292167 Log: urtwn: add rate control support for RTL8188EU. Tested with: - RTL8188EU, STA and HOSTAP modes. - RTL8188CUS, STA mode. Reviewed by: kevlo Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D4402 Modified: head/sys/dev/usb/wlan/if_urtwn.c head/sys/dev/usb/wlan/if_urtwnreg.h head/sys/dev/usb/wlan/if_urtwnvar.h Modified: head/sys/dev/usb/wlan/if_urtwn.c ============================================================================== --- head/sys/dev/usb/wlan/if_urtwn.c Sun Dec 13 20:53:51 2015 (r292166) +++ head/sys/dev/usb/wlan/if_urtwn.c Sun Dec 13 21:00:21 2015 (r292167) @@ -183,8 +183,12 @@ static struct ieee80211vap *urtwn_vap_cr static void urtwn_vap_delete(struct ieee80211vap *); static struct mbuf * urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int, int *); -static struct mbuf * urtwn_rxeof(struct usb_xfer *, struct urtwn_data *, +static struct mbuf * urtwn_report_intr(struct usb_xfer *, struct urtwn_data *, int *, int8_t *); +static struct mbuf * urtwn_rxeof(struct urtwn_softc *, uint8_t *, int, + int *, int8_t *); +static void urtwn_r88e_ratectl_tx_complete(struct urtwn_softc *, + void *); static void urtwn_txeof(struct urtwn_softc *, struct urtwn_data *, int); static int urtwn_alloc_list(struct urtwn_softc *, @@ -295,6 +299,10 @@ static int urtwn_wme_update(struct ieee static void urtwn_set_promisc(struct urtwn_softc *); static void urtwn_update_promisc(struct ieee80211com *); static void urtwn_update_mcast(struct ieee80211com *); +static struct ieee80211_node *urtwn_r88e_node_alloc(struct ieee80211vap *, + const uint8_t mac[IEEE80211_ADDR_LEN]); +static void urtwn_r88e_newassoc(struct ieee80211_node *, int); +static void urtwn_r88e_node_free(struct ieee80211_node *); static void urtwn_set_chan(struct urtwn_softc *, struct ieee80211_channel *, struct ieee80211_channel *); @@ -419,6 +427,7 @@ urtwn_attach(device_t self) mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, MTX_DEF); + URTWN_NT_LOCK_INIT(sc); callout_init(&sc->sc_watchdog_ch, 0); mbufq_init(&sc->sc_snd, ifqmaxlen); @@ -504,6 +513,12 @@ urtwn_attach(device_t self) ic->ic_wme.wme_update = urtwn_wme_update; ic->ic_update_promisc = urtwn_update_promisc; ic->ic_update_mcast = urtwn_update_mcast; + if (sc->chip & URTWN_CHIP_88E) { + ic->ic_node_alloc = urtwn_r88e_node_alloc; + ic->ic_newassoc = urtwn_r88e_newassoc; + sc->sc_node_free = ic->ic_node_free; + ic->ic_node_free = urtwn_r88e_node_free; + } ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), URTWN_TX_RADIOTAP_PRESENT, @@ -560,6 +575,7 @@ urtwn_detach(device_t self) URTWN_UNLOCK(sc); ieee80211_ifdetach(ic); + URTWN_NT_LOCK_DESTROY(sc); mtx_destroy(&sc->sc_mtx); return (0); @@ -638,6 +654,8 @@ urtwn_vap_create(struct ieee80211com *ic TASK_INIT(&uvp->tsf_task_adhoc, 0, urtwn_tsf_task_adhoc, vap); } + if (URTWN_CHIP_HAS_RATECTL(sc)) + ieee80211_ratectl_init(vap); /* complete setup */ ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status, mac); @@ -649,12 +667,15 @@ static void urtwn_vap_delete(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; + struct urtwn_softc *sc = ic->ic_softc; struct urtwn_vap *uvp = URTWN_VAP(vap); if (uvp->bcn_mbuf != NULL) m_freem(uvp->bcn_mbuf); if (vap->iv_opmode == IEEE80211_M_IBSS) ieee80211_draintask(ic, &uvp->tsf_task_adhoc); + if (URTWN_CHIP_HAS_RATECTL(sc)) + ieee80211_ratectl_deinit(vap); ieee80211_vap_detach(vap); free(uvp, M_80211_VAP); } @@ -743,16 +764,14 @@ urtwn_rx_frame(struct urtwn_softc *sc, u } static struct mbuf * -urtwn_rxeof(struct usb_xfer *xfer, struct urtwn_data *data, int *rssi, +urtwn_report_intr(struct usb_xfer *xfer, struct urtwn_data *data, int *rssi, int8_t *nf) { struct urtwn_softc *sc = data->sc; struct ieee80211com *ic = &sc->sc_ic; struct r92c_rx_stat *stat; - struct mbuf *m, *m0 = NULL, *prevm = NULL; - uint32_t rxdw0; uint8_t *buf; - int len, totlen, pktlen, infosz, npkts; + int len; usbd_xfer_status(xfer, &len, NULL, NULL, NULL); @@ -762,6 +781,36 @@ urtwn_rxeof(struct usb_xfer *xfer, struc } buf = data->buf; + stat = (struct r92c_rx_stat *)buf; + + if (sc->chip & URTWN_CHIP_88E) { + int report_sel = MS(le32toh(stat->rxdw3), R88E_RXDW3_RPT); + + switch (report_sel) { + case R88E_RXDW3_RPT_RX: + return (urtwn_rxeof(sc, buf, len, rssi, nf)); + case R88E_RXDW3_RPT_TX1: + urtwn_r88e_ratectl_tx_complete(sc, &stat[1]); + break; + default: + DPRINTFN(7, "case %d was not handled\n", report_sel); + break; + } + } else + return (urtwn_rxeof(sc, buf, len, rssi, nf)); + + return (NULL); +} + +static struct mbuf * +urtwn_rxeof(struct urtwn_softc *sc, uint8_t *buf, int len, int *rssi, + int8_t *nf) +{ + struct r92c_rx_stat *stat; + struct mbuf *m, *m0 = NULL, *prevm = NULL; + uint32_t rxdw0; + int totlen, pktlen, infosz, npkts; + /* Get the number of encapsulated frames. */ stat = (struct r92c_rx_stat *)buf; npkts = MS(le32toh(stat->rxdw2), R92C_RXDW2_PKTCNT); @@ -805,6 +854,35 @@ urtwn_rxeof(struct usb_xfer *xfer, struc } 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; + + 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); + } + } else + DPRINTFN(8, "macid %d, ni is NULL\n", macid); + URTWN_NT_UNLOCK(sc); +} + +static void urtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) { struct urtwn_softc *sc = usbd_xfer_softc(xfer); @@ -824,7 +902,7 @@ urtwn_bulk_rx_callback(struct usb_xfer * if (data == NULL) goto tr_setup; STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); - m = urtwn_rxeof(xfer, data, &rssi, &nf); + m = urtwn_report_intr(xfer, data, &rssi, &nf); STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); /* FALLTHROUGH */ case USB_ST_SETUP: @@ -2008,10 +2086,7 @@ urtwn_newstate(struct ieee80211vap *vap, urtwn_write_1(sc, R92C_T2T_SIFS + 1, 10); /* Intialize rate adaptation. */ - if (sc->chip & URTWN_CHIP_88E) - ni->ni_txrate = - ni->ni_rates.rs_rates[ni->ni_rates.rs_nrates-1]; - else + if (!(sc->chip & URTWN_CHIP_88E)) urtwn_ra_init(sc); /* Turn link LED on. */ urtwn_set_led(sc, URTWN_LED_LINK, 1); @@ -2162,16 +2237,38 @@ urtwn_r88e_get_rssi(struct urtwn_softc * return (rssi); } +static __inline uint8_t +rate2ridx(uint8_t rate) +{ + switch (rate) { + 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; + case 2: return 0; + case 4: return 1; + case 11: return 2; + case 22: return 3; + default: return 0; + } +} + static int urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m, struct urtwn_data *data) { - struct ieee80211_frame *wh; - struct ieee80211_key *k = NULL; + const struct ieee80211_txparam *tp; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_key *k = NULL; + struct ieee80211_channel *chan; + struct ieee80211_frame *wh; struct r92c_tx_desc *txd; - uint8_t macid, raid, ridx, subtype, type, tid, qsel; + uint8_t macid, raid, rate, ridx, subtype, type, tid, qsel; int hasqos, ismcast; URTWN_ASSERT_LOCKED(sc); @@ -2192,6 +2289,38 @@ urtwn_tx_data(struct urtwn_softc *sc, st } else tid = 0; + 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 { + if (ic->ic_curmode != IEEE80211_MODE_11B) + rate = 108; + else + rate = 22; + } + } + + ridx = rate2ridx(rate); + if (ic->ic_curmode != IEEE80211_MODE_11B) + raid = R92C_RAID_11BG; + else + raid = R92C_RAID_11B; + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_encap(ni, m); if (k == NULL) { @@ -2214,25 +2343,21 @@ urtwn_tx_data(struct urtwn_softc *sc, st if (ismcast) txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); - raid = R92C_RAID_11B; /* by default */ - ridx = URTWN_RIDX_CCK1; if (!ismcast) { - macid = URTWN_MACID_BSS; + if (sc->chip & URTWN_CHIP_88E) { + struct urtwn_node *un = URTWN_NODE(ni); + macid = un->id; + } else + macid = URTWN_MACID_BSS; if (type == IEEE80211_FC0_TYPE_DATA) { qsel = tid % URTWN_MAX_TID; - if (!(m->m_flags & M_EAPOL)) { - if (ic->ic_curmode != IEEE80211_MODE_11B) { - raid = R92C_RAID_11BG; - ridx = URTWN_RIDX_OFDM54; - } else - ridx = URTWN_RIDX_CCK11; - } - - if (sc->chip & URTWN_CHIP_88E) - txd->txdw2 |= htole32(R88E_TXDW2_AGGBK); - else + if (sc->chip & URTWN_CHIP_88E) { + txd->txdw2 |= htole32( + R88E_TXDW2_AGGBK | + R88E_TXDW2_CCX_RPT); + } else txd->txdw1 |= htole32(R92C_TXDW1_AGGBK); if (ic->ic_flags & IEEE80211_F_USEPROT) { @@ -2272,8 +2397,8 @@ urtwn_tx_data(struct urtwn_softc *sc, st txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); /* Force this rate if needed. */ - if (ismcast || type != IEEE80211_FC0_TYPE_DATA || - (m->m_flags & M_EAPOL)) + if (URTWN_CHIP_HAS_RATECTL(sc) || ismcast || + (m->m_flags & M_EAPOL) || type != IEEE80211_FC0_TYPE_DATA) txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); if (!hasqos) { @@ -3705,6 +3830,63 @@ urtwn_update_mcast(struct ieee80211com * /* XXX do nothing? */ } +static struct ieee80211_node * +urtwn_r88e_node_alloc(struct ieee80211vap *vap, + 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 +urtwn_r88e_newassoc(struct ieee80211_node *ni, int isnew) +{ + struct urtwn_softc *sc = ni->ni_ic->ic_softc; + struct urtwn_node *un = URTWN_NODE(ni); + uint8_t id; + + 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 +urtwn_r88e_node_free(struct ieee80211_node *ni) +{ + 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); +} + static void urtwn_set_chan(struct urtwn_softc *sc, struct ieee80211_channel *c, struct ieee80211_channel *extc) @@ -4022,6 +4204,12 @@ urtwn_init(struct urtwn_softc *sc) /* Enable hardware sequence numbering. */ urtwn_write_1(sc, R92C_HWSEQ_CTRL, 0xff); + /* 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); + } + /* Perform LO and IQ calibrations. */ urtwn_iq_calib(sc); /* Perform LC calibration. */ Modified: head/sys/dev/usb/wlan/if_urtwnreg.h ============================================================================== --- head/sys/dev/usb/wlan/if_urtwnreg.h Sun Dec 13 20:53:51 2015 (r292166) +++ head/sys/dev/usb/wlan/if_urtwnreg.h Sun Dec 13 21:00:21 2015 (r292167) @@ -158,6 +158,9 @@ #define R92C_INIRTS_RATE_SEL 0x480 #define R92C_INIDATA_RATE_SEL(macid) (0x484 + (macid)) #define R92C_MAX_AGGR_NUM 0x4ca +#define R88E_TX_RPT_CTRL 0x4ec +#define R88E_TX_RPT_MACID_MAX 0x4ed +#define R88E_TX_RPT_TIME 0x4f0 /* EDCA Configuration. */ #define R92C_EDCA_VO_PARAM 0x500 #define R92C_EDCA_VI_PARAM 0x504 @@ -479,6 +482,10 @@ #define R92C_RRSR_RSC_UPSUBCHNL 0x00400000 #define R92C_RRSR_SHORT 0x00800000 +/* Bits for R88E_TX_RPT_CTRL. */ +#define R88E_TX_RPT1_ENA 0x01 +#define R88E_TX_RPT2_ENA 0x02 + /* Bits for R92C_EDCA_XX_PARAM. */ #define R92C_EDCA_PARAM_AIFS_M 0x000000ff #define R92C_EDCA_PARAM_AIFS_S 0 @@ -895,6 +902,11 @@ struct r92c_fw_cmd_macid_cfg { uint8_t macid; #define URTWN_MACID_BSS 0 #define URTWN_MACID_BC 4 /* Broadcast. */ +#define R92C_MACID_MAX 31 +#define R88E_MACID_MAX 63 +#define URTWN_MACID_MAX(sc) (((sc)->chip & URTWN_CHIP_88E) ? \ + R88E_MACID_MAX : R92C_MACID_MAX) +#define URTWN_MACID_UNDEFINED (uint8_t)-1 #define URTWN_MACID_VALID 0x80 } __packed; @@ -972,6 +984,11 @@ struct r92c_rx_stat { #define R92C_RXDW3_RATE_S 0 #define R92C_RXDW3_HT 0x00000040 #define R92C_RXDW3_HTC 0x00000400 +#define R88E_RXDW3_RPT_M 0x0000c000 +#define R88E_RXDW3_RPT_S 14 +#define R88E_RXDW3_RPT_RX 0 +#define R88E_RXDW3_RPT_TX1 1 +#define R88E_RXDW3_RPT_TX2 2 uint32_t rxdw4; uint32_t rxdw5; @@ -1059,6 +1076,7 @@ struct r92c_tx_desc { uint32_t txdw2; #define R88E_TXDW2_AGGBK 0x00010000 +#define R88E_TXDW2_CCX_RPT 0x00080000 uint16_t txdw3; uint16_t txdseq; @@ -1091,6 +1109,30 @@ struct r92c_tx_desc { uint16_t pad; } __packed __attribute__((aligned(4))); +struct r88e_tx_rpt_ccx { + uint8_t rptb0; + uint8_t rptb1; +#define R88E_RPTB1_MACID_M 0x3f +#define R88E_RPTB1_MACID_S 0 +#define R88E_RPTB1_PKT_OK 0x40 +#define R88E_RPTB1_BMC 0x80 + + uint8_t rptb2; +#define R88E_RPTB2_RETRY_CNT_M 0x3f +#define R88E_RPTB2_RETRY_CNT_S 0 +#define R88E_RPTB2_LIFE_EXPIRE 0x40 +#define R88E_RPTB2_RETRY_OVER 0x80 + + uint8_t rptb3; + uint8_t rptb4; + uint8_t rptb5; + uint8_t rptb6; +#define R88E_RPTB6_QSEL_M 0xf0 +#define R88E_RPTB6_QSEL_S 4 + + uint8_t rptb7; +} __packed; + static const uint8_t ridx2rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; Modified: head/sys/dev/usb/wlan/if_urtwnvar.h ============================================================================== --- head/sys/dev/usb/wlan/if_urtwnvar.h Sun Dec 13 20:53:51 2015 (r292166) +++ head/sys/dev/usb/wlan/if_urtwnvar.h Sun Dec 13 21:00:21 2015 (r292167) @@ -86,6 +86,12 @@ struct urtwn_fw_info { size_t size; }; +struct urtwn_node { + struct ieee80211_node ni; /* must be the first */ + uint8_t id; +}; +#define URTWN_NODE(ni) ((struct urtwn_node *)(ni)) + struct urtwn_vap { struct ieee80211vap vap; @@ -152,10 +158,16 @@ struct urtwn_softc { #define URTWN_CHIP_UMC_A_CUT 0x08 #define URTWN_CHIP_88E 0x10 +#define URTWN_CHIP_HAS_RATECTL(_sc) (!!((_sc)->chip & URTWN_CHIP_88E)) + + void (*sc_node_free)(struct ieee80211_node *); void (*sc_rf_write)(struct urtwn_softc *, int, uint8_t, uint32_t); int (*sc_power_on)(struct urtwn_softc *); + struct ieee80211_node *node_list[R88E_MACID_MAX]; + struct mtx nt_mtx; + uint8_t board_type; uint8_t regulatory; uint8_t pa_setting; @@ -213,3 +225,9 @@ struct urtwn_softc { #define URTWN_LOCK(sc) mtx_lock(&(sc)->sc_mtx) #define URTWN_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) #define URTWN_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) + +#define URTWN_NT_LOCK_INIT(sc) \ + mtx_init(&(sc)->nt_mtx, "node table lock", NULL, MTX_DEF) +#define URTWN_NT_LOCK(sc) mtx_lock(&(sc)->nt_mtx) +#define URTWN_NT_UNLOCK(sc) mtx_unlock(&(sc)->nt_mtx) +#define URTWN_NT_LOCK_DESTROY(sc) mtx_destroy(&(sc)->nt_mtx)