rtwn_pci(4): add support for event-based Tx reports.

It will be used for RTL8188EE (and, probably, others).

MFC after:	4 days
This commit is contained in:
Andriy Voskoboinyk 2019-01-02 05:21:06 +00:00
parent b5a81dd4c5
commit 17d5fbf21b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=342677
16 changed files with 150 additions and 110 deletions

View File

@ -83,12 +83,12 @@ rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *pc,
}
static void
rtwn_pci_rx_frame(struct rtwn_softc *sc, struct rtwn_rx_stat_pci *rx_desc,
int desc_idx)
rtwn_pci_rx_frame(struct rtwn_pci_softc *pc)
{
struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
struct rtwn_softc *sc = &pc->pc_sc;
struct rtwn_rx_ring *ring = &pc->rx_ring;
struct rtwn_rx_data *rx_data = &ring->rx_data[desc_idx];
struct rtwn_rx_stat_pci *rx_desc = &ring->desc[ring->cur];
struct rtwn_rx_data *rx_data = &ring->rx_data[ring->cur];
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni;
uint32_t rxdw0;
@ -148,9 +148,6 @@ rtwn_pci_rx_frame(struct rtwn_softc *sc, struct rtwn_rx_stat_pci *rx_desc,
panic("%s: could not load old RX mbuf",
device_get_name(sc->sc_dev));
/* Physical address may have changed. */
rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr,
MJUMPAGESIZE, desc_idx);
goto fail;
}
@ -165,10 +162,6 @@ rtwn_pci_rx_frame(struct rtwn_softc *sc, struct rtwn_rx_stat_pci *rx_desc,
"%s: Rx frame len %d, infosz %d, shift %d\n",
__func__, pktlen, infosz, shift);
/* Update RX descriptor. */
rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr, MJUMPAGESIZE,
desc_idx);
/* Send the frame to the 802.11 layer. */
RTWN_UNLOCK(sc);
if (ni != NULL) {
@ -186,6 +179,72 @@ rtwn_pci_rx_frame(struct rtwn_softc *sc, struct rtwn_rx_stat_pci *rx_desc,
counter_u64_add(ic->ic_ierrors, 1);
}
static int
rtwn_pci_rx_buf_copy(struct rtwn_pci_softc *pc)
{
struct rtwn_rx_ring *ring = &pc->rx_ring;
struct rtwn_rx_stat_pci *rx_desc = &ring->desc[ring->cur];
struct rtwn_rx_data *rx_data = &ring->rx_data[ring->cur];
uint32_t rxdw0;
int desc_size, pktlen;
/*
* NB: tx_report() / c2h_report() expects to see USB Rx
* descriptor - same as for PCIe, but without rxbufaddr* fields.
*/
desc_size = sizeof(struct rtwn_rx_stat_common);
KASSERT(sizeof(pc->pc_rx_buf) < desc_size,
("adjust size for PCIe Rx buffer!"));
memcpy(pc->pc_rx_buf, rx_desc, desc_size);
rxdw0 = le32toh(rx_desc->rxdw0);
pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
if (pktlen > sizeof(pc->pc_rx_buf) - desc_size)
{
/* Looks like an ordinary Rx frame. */
return (desc_size);
}
bus_dmamap_sync(ring->data_dmat, rx_data->map, BUS_DMASYNC_POSTREAD);
memcpy(pc->pc_rx_buf + desc_size, mtod(rx_data->m, void *), pktlen);
return (desc_size + pktlen);
}
static void
rtwn_pci_tx_report(struct rtwn_pci_softc *pc, int len)
{
struct rtwn_softc *sc = &pc->pc_sc;
if (sc->sc_ratectl != RTWN_RATECTL_NET80211) {
/* shouldn't happen */
device_printf(sc->sc_dev,
"%s called while ratectl = %d!\n",
__func__, sc->sc_ratectl);
return;
}
RTWN_NT_LOCK(sc);
rtwn_handle_tx_report(sc, pc->pc_rx_buf, len);
RTWN_NT_UNLOCK(sc);
#ifdef IEEE80211_SUPPORT_SUPERG
/*
* NB: this will executed only when 'report' bit is set.
*/
if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1)
rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
#endif
}
static void
rtwn_pci_c2h_report(struct rtwn_pci_softc *pc, int len)
{
rtwn_handle_c2h_report(&pc->pc_sc, pc->pc_rx_buf, len);
}
static void
rtwn_pci_tx_done(struct rtwn_softc *sc, int qid)
{
@ -263,21 +322,50 @@ rtwn_pci_rx_done(struct rtwn_softc *sc)
{
struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
struct rtwn_rx_ring *ring = &pc->rx_ring;
struct rtwn_rx_stat_pci *rx_desc;
struct rtwn_rx_data *rx_data;
int len;
bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD);
for (;;) {
struct rtwn_rx_stat_pci *rx_desc = &ring->desc[ring->cur];
rx_desc = &ring->desc[ring->cur];
rx_data = &ring->rx_data[ring->cur];
if (le32toh(rx_desc->rxdw0) & RTWN_RXDW0_OWN)
break;
rtwn_pci_rx_frame(sc, rx_desc, ring->cur);
len = rtwn_pci_rx_buf_copy(pc);
switch (rtwn_classify_intr(sc, pc->pc_rx_buf, len)) {
case RTWN_RX_DATA:
rtwn_pci_rx_frame(pc);
break;
case RTWN_RX_TX_REPORT:
rtwn_pci_tx_report(pc, len);
break;
case RTWN_RX_OTHER:
rtwn_pci_c2h_report(pc, len);
break;
default:
/* NOTREACHED */
KASSERT(0, ("unknown Rx classification code"));
break;
}
/* Update / reset RX descriptor (and set OWN bit). */
rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr,
MJUMPAGESIZE, ring->cur);
if (!(sc->sc_flags & RTWN_RUNNING))
return;
ring->cur = (ring->cur + 1) % RTWN_PCI_RX_LIST_COUNT;
/* NB: device can reuse current descriptor. */
bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
BUS_DMASYNC_POSTREAD);
if (le32toh(rx_desc->rxdw0) & RTWN_RXDW0_OWN)
ring->cur = (ring->cur + 1) % RTWN_PCI_RX_LIST_COUNT;
}
}
@ -289,13 +377,13 @@ rtwn_pci_intr(void *arg)
int i, status, tx_rings;
RTWN_LOCK(sc);
status = rtwn_classify_intr(sc, &tx_rings, 0);
status = rtwn_pci_get_intr_status(pc, &tx_rings);
RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: status %08X, tx_rings %08X\n",
__func__, status, tx_rings);
if (status == 0 && tx_rings == 0)
goto unlock;
if (status & RTWN_PCI_INTR_RX) {
if (status & (RTWN_PCI_INTR_RX | RTWN_PCI_INTR_TX_REPORT)) {
rtwn_pci_rx_done(sc);
if (!(sc->sc_flags & RTWN_RUNNING))
goto unlock;

View File

@ -26,6 +26,9 @@
#define RTWN_PCI_RX_LIST_COUNT 256
#define RTWN_PCI_TX_LIST_COUNT 256
/* sizeof(struct rtwn_rx_stat_common) + R88E_INTR_MSG_LEN */
#define RTWN_PCI_RX_TMP_BUF_SIZE 84
struct rtwn_rx_data {
bus_dmamap_t map;
struct mbuf *m;
@ -95,8 +98,8 @@ enum {
/* Shortcuts */
/* Vendor driver treats RX errors like ROK... */
#define RTWN_PCI_INTR_RX \
(RTWN_PCI_INTR_RX_OVERFLOW | RTWN_PCI_INTR_RX_DESC_UNAVAIL | \
RTWN_PCI_INTR_RX_DONE)
(RTWN_PCI_INTR_RX_ERROR | RTWN_PCI_INTR_RX_OVERFLOW | \
RTWN_PCI_INTR_RX_DESC_UNAVAIL | RTWN_PCI_INTR_RX_DONE)
struct rtwn_pci_softc {
@ -109,6 +112,7 @@ struct rtwn_pci_softc {
void *pc_ih;
bus_size_t pc_mapsize;
uint8_t pc_rx_buf[RTWN_PCI_RX_TMP_BUF_SIZE];
struct rtwn_rx_ring rx_ring;
struct rtwn_tx_ring tx_ring[RTWN_PCI_NTXQUEUES];
@ -122,6 +126,8 @@ struct rtwn_pci_softc {
void *, bus_dma_segment_t *);
void (*pc_copy_tx_desc)(void *, const void *);
void (*pc_enable_intr)(struct rtwn_pci_softc *);
int (*pc_get_intr_status)(struct rtwn_pci_softc *,
int *);
};
#define RTWN_PCI_SOFTC(sc) ((struct rtwn_pci_softc *)(sc))
@ -133,5 +139,7 @@ struct rtwn_pci_softc {
(((_pc)->pc_copy_tx_desc)((_dest), (_src)))
#define rtwn_pci_enable_intr(_pc) \
(((_pc)->pc_enable_intr)((_pc)))
#define rtwn_pci_get_intr_status(_pc, _tx_rings) \
(((_pc)->pc_get_intr_status)((_pc), (_tx_rings)))
#endif /* RTWN_PCI_VAR_H */

View File

@ -81,6 +81,7 @@ void r88e_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t);
void r88e_parse_rom(struct rtwn_softc *, uint8_t *);
/* r88e_rx.c */
int r88e_classify_intr(struct rtwn_softc *, void *, int);
void r88e_ratectl_tx_complete(struct rtwn_softc *, uint8_t *, int);
void r88e_handle_c2h_report(struct rtwn_softc *, uint8_t *, int);
int8_t r88e_get_rssi_cck(struct rtwn_softc *, void *);

View File

@ -56,6 +56,25 @@ __FBSDID("$FreeBSD$");
#include <dev/rtwn/rtl8188e/r88e_rx_desc.h>
int
r88e_classify_intr(struct rtwn_softc *sc, void *buf, int len)
{
struct r92c_rx_stat *stat = buf;
int report_sel = MS(le32toh(stat->rxdw3), R88E_RXDW3_RPT);
switch (report_sel) {
case R88E_RXDW3_RPT_RX:
return (RTWN_RX_DATA);
case R88E_RXDW3_RPT_TX1: /* per-packet Tx report */
case R88E_RXDW3_RPT_TX2: /* periodical Tx report */
return (RTWN_RX_TX_REPORT);
case R88E_RXDW3_RPT_HIS:
return (RTWN_RX_OTHER);
default: /* shut up the compiler */
return (RTWN_RX_DATA);
}
}
void
r88e_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
{

View File

@ -33,7 +33,4 @@ void r88eu_init_intr(struct rtwn_softc *);
void r88eu_init_rx_agg(struct rtwn_softc *);
void r88eu_post_init(struct rtwn_softc *);
/* r88eu_rx.c */
int r88eu_classify_intr(struct rtwn_softc *, void *, int);
#endif /* RTL8188EU_H */

View File

@ -130,7 +130,7 @@ r88eu_attach(struct rtwn_usb_softc *uc)
sc->sc_get_rx_stats = r88e_get_rx_stats;
sc->sc_get_rssi_cck = r88e_get_rssi_cck;
sc->sc_get_rssi_ofdm = r88e_get_rssi_ofdm;
sc->sc_classify_intr = r88eu_classify_intr;
sc->sc_classify_intr = r88e_classify_intr;
sc->sc_handle_tx_report = r88e_ratectl_tx_complete;
sc->sc_handle_c2h_report = r88e_handle_c2h_report;
sc->sc_check_frame = rtwn_nop_int_softc_mbuf;

View File

@ -1,74 +0,0 @@
/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */
/*-
* Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
* Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
* Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_wlan.h"
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/taskqueue.h>
#include <sys/bus.h>
#include <sys/endian.h>
#include <sys/linker.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <net/if_media.h>
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
#include <dev/rtwn/if_rtwnreg.h>
#include <dev/rtwn/if_rtwnvar.h>
#include <dev/rtwn/if_rtwn_debug.h>
#include <dev/rtwn/rtl8188e/r88e_rx_desc.h>
#include <dev/rtwn/rtl8188e/usb/r88eu.h>
int
r88eu_classify_intr(struct rtwn_softc *sc, void *buf, int len)
{
struct r92c_rx_stat *stat = buf;
int report_sel = MS(le32toh(stat->rxdw3), R88E_RXDW3_RPT);
switch (report_sel) {
case R88E_RXDW3_RPT_RX:
return (RTWN_RX_DATA);
case R88E_RXDW3_RPT_TX1: /* per-packet Tx report */
case R88E_RXDW3_RPT_TX2: /* periodical Tx report */
return (RTWN_RX_TX_REPORT);
case R88E_RXDW3_RPT_HIS:
return (RTWN_RX_OTHER);
default: /* shut up the compiler */
return (RTWN_RX_DATA);
}
}

View File

@ -60,7 +60,7 @@ void r92ce_post_init(struct rtwn_softc *);
void r92ce_set_led(struct rtwn_softc *, int, int);
/* r92ce_rx.c */
int r92ce_classify_intr(struct rtwn_softc *, void *, int);
int r92ce_get_intr_status(struct rtwn_pci_softc *, int *);
void r92ce_enable_intr(struct rtwn_pci_softc *);
void r92ce_start_xfers(struct rtwn_softc *);

View File

@ -155,6 +155,7 @@ r92ce_attach(struct rtwn_pci_softc *pc)
pc->pc_tx_postsetup = r92ce_tx_postsetup;
pc->pc_copy_tx_desc = r92ce_copy_tx_desc;
pc->pc_enable_intr = r92ce_enable_intr;
pc->pc_get_intr_status = r92ce_get_intr_status;
pc->pc_qmap = 0xf771;
pc->tcr =
@ -175,7 +176,7 @@ r92ce_attach(struct rtwn_pci_softc *pc)
sc->sc_get_rx_stats = r92c_get_rx_stats;
sc->sc_get_rssi_cck = r92c_get_rssi_cck;
sc->sc_get_rssi_ofdm = r92c_get_rssi_ofdm;
sc->sc_classify_intr = r92ce_classify_intr;
sc->sc_classify_intr = r92c_classify_intr;
sc->sc_handle_tx_report = rtwn_nop_softc_uint8_int;
sc->sc_handle_c2h_report = rtwn_nop_softc_uint8_int;
sc->sc_check_frame = rtwn_nop_int_softc_mbuf;

View File

@ -58,10 +58,10 @@ __FBSDID("$FreeBSD$");
int
r92ce_classify_intr(struct rtwn_softc *sc, void *arg, int len __unused)
r92ce_get_intr_status(struct rtwn_pci_softc *pc, int *rings)
{
struct rtwn_softc *sc = &pc->pc_sc;
uint32_t status;
int *rings = arg;
int ret;
*rings = 0;

View File

@ -102,6 +102,7 @@ void r92c_efuse_postread(struct rtwn_softc *);
void r92c_parse_rom(struct rtwn_softc *, uint8_t *);
/* r92c_rx.c */
int r92c_classify_intr(struct rtwn_softc *, void *, int);
int8_t r92c_get_rssi_cck(struct rtwn_softc *, void *);
int8_t r92c_get_rssi_ofdm(struct rtwn_softc *, void *);
uint8_t r92c_rx_radiotap_flags(const void *);

View File

@ -52,6 +52,13 @@ __FBSDID("$FreeBSD$");
#include <dev/rtwn/rtl8192c/r92c_rx_desc.h>
int
r92c_classify_intr(struct rtwn_softc *sc, void *buf, int len)
{
/* NB: reports are fetched from C2H_MSG register. */
return (RTWN_RX_DATA);
}
int8_t
r92c_get_rssi_cck(struct rtwn_softc *sc, void *physt)
{

View File

@ -47,7 +47,6 @@ void r92cu_post_init(struct rtwn_softc *);
void r92cu_set_led(struct rtwn_softc *, int, int);
/* r92cu_rx.c */
int r92cu_classify_intr(struct rtwn_softc *, void *, int);
int r92cu_align_rx(int, int);
/* r92cu_tx.c */

View File

@ -168,7 +168,7 @@ r92cu_attach(struct rtwn_usb_softc *uc)
sc->sc_get_rx_stats = r92c_get_rx_stats;
sc->sc_get_rssi_cck = r92c_get_rssi_cck;
sc->sc_get_rssi_ofdm = r92c_get_rssi_ofdm;
sc->sc_classify_intr = r92cu_classify_intr;
sc->sc_classify_intr = r92c_classify_intr;
sc->sc_handle_tx_report = rtwn_nop_softc_uint8_int;
sc->sc_handle_c2h_report = rtwn_nop_softc_uint8_int;
sc->sc_check_frame = rtwn_nop_int_softc_mbuf;

View File

@ -49,13 +49,6 @@ __FBSDID("$FreeBSD$");
#include <dev/rtwn/rtl8192c/usb/r92cu.h>
int
r92cu_classify_intr(struct rtwn_softc *sc, void *buf, int len)
{
/* NB: reports are fetched from C2H_MSG register. */
return (RTWN_RX_DATA);
}
int
r92cu_align_rx(int totlen, int len)
{

View File

@ -13,7 +13,7 @@ SRCS = rtwn_usb_attach.c rtwn_usb_ep.c rtwn_usb_reg.c rtwn_usb_rx.c \
opt_bus.h opt_rtwn.h opt_usb.h opt_wlan.h usb_if.h usbdevs.h
.PATH: ${SRCTOP}/sys/dev/rtwn/rtl8188e/usb
SRCS += r88eu_attach.c r88eu_init.c r88eu_rx.c \
SRCS += r88eu_attach.c r88eu_init.c \
r88eu.h r88eu_reg.h
.PATH: ${SRCTOP}/sys/dev/rtwn/rtl8192c/usb