diff options
Diffstat (limited to 'freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c')
-rw-r--r-- | freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c new file mode 100644 index 00000000..049717a4 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c @@ -0,0 +1,240 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <rtems/bsd/local/opt_wlan.h> + +#include <rtems/bsd/sys/param.h> +#include <rtems/bsd/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 <net80211/ieee80211_ratectl.h> + +#include <dev/rtwn/if_rtwnreg.h> +#include <dev/rtwn/if_rtwnvar.h> + +#include <dev/rtwn/if_rtwn_debug.h> +#include <dev/rtwn/if_rtwn_ridx.h> + +#include <dev/rtwn/rtl8812a/r12a.h> +#include <dev/rtwn/rtl8812a/r12a_var.h> +#include <dev/rtwn/rtl8812a/r12a_fw_cmd.h> +#include <dev/rtwn/rtl8812a/r12a_rx_desc.h> + + +#ifndef RTWN_WITHOUT_UCODE +void +r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) +{ +#if __FreeBSD_version >= 1200012 + struct ieee80211_ratectl_tx_status txs; +#endif + struct r12a_c2h_tx_rpt *rpt; + struct ieee80211_node *ni; + int ntries; + + /* Skip Rx descriptor / report id / sequence fields. */ + buf += sizeof(struct r92c_rx_stat) + 2; + len -= sizeof(struct r92c_rx_stat) + 2; + + rpt = (struct r12a_c2h_tx_rpt *)buf; + if (len != sizeof(*rpt)) { + device_printf(sc->sc_dev, + "%s: wrong report size (%d, must be %zu)\n", + __func__, len, sizeof(*rpt)); + return; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: ccx report dump: 0: %02X, id: %02X, 2: %02X, queue time: " + "low %02X, high %02X, final ridx: %02X, rsvd: %04X\n", + __func__, rpt->txrptb0, rpt->macid, rpt->txrptb2, + rpt->queue_time_low, rpt->queue_time_high, rpt->final_rate, + rpt->reserved); + + if (rpt->macid > sc->macid_limit) { + device_printf(sc->sc_dev, + "macid %u is too big; increase MACID_MAX limit\n", + rpt->macid); + return; + } + + ntries = MS(rpt->txrptb2, R12A_TXRPTB2_RETRY_CNT); + + ni = sc->node_list[rpt->macid]; + if (ni != NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was" + "%s sent (%d retries)\n", __func__, rpt->macid, + (rpt->txrptb0 & (R12A_TXRPTB0_RETRY_OVER | + R12A_TXRPTB0_LIFE_EXPIRE)) ? " not" : "", ntries); + +#if __FreeBSD_version >= 1200012 + txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY | + IEEE80211_RATECTL_STATUS_FINAL_RATE; + txs.long_retries = ntries; + if (rpt->final_rate > RTWN_RIDX_OFDM54) { /* MCS */ + txs.final_rate = + (rpt->final_rate - 12) | IEEE80211_RATE_MCS; + } else + txs.final_rate = ridx2rate[rpt->final_rate]; + if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) + txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; + else if (rpt->txrptb0 & R12A_TXRPTB0_LIFE_EXPIRE) + txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; + else + txs.status = IEEE80211_RATECTL_TX_SUCCESS; + ieee80211_ratectl_tx_complete(ni, &txs); +#else + struct ieee80211vap *vap = ni->ni_vap; + if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL); + } else { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL); + } +#endif + } else { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: macid %u, ni is NULL\n", __func__, rpt->macid); + } +} + +void +r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + struct r12a_softc *rs = sc->sc_priv; + + /* Skip Rx descriptor. */ + buf += sizeof(struct r92c_rx_stat); + len -= sizeof(struct r92c_rx_stat); + + if (len < 2) { + device_printf(sc->sc_dev, "C2H report too short (len %d)\n", + len); + return; + } + len -= 2; + + switch (buf[0]) { /* command id */ + case R12A_C2H_TX_REPORT: + /* NOTREACHED */ + KASSERT(0, ("use handle_tx_report() instead of %s\n", + __func__)); + break; + case R12A_C2H_IQK_FINISHED: + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "FW IQ calibration finished\n"); + rs->rs_flags &= ~R12A_IQK_RUNNING; + break; + default: + device_printf(sc->sc_dev, + "%s: C2H report %u was not handled\n", + __func__, buf[0]); + } +} +#else +void +r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + /* Should not happen. */ + device_printf(sc->sc_dev, "%s: called\n", __func__); +} + +void +r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + /* Should not happen. */ + device_printf(sc->sc_dev, "%s: called\n", __func__); +} +#endif + +int +r12a_check_frame_checksum(struct rtwn_softc *sc, struct mbuf *m) +{ + struct r12a_softc *rs = sc->sc_priv; + struct r92c_rx_stat *stat; + uint32_t rxdw1; + + stat = mtod(m, struct r92c_rx_stat *); + rxdw1 = le32toh(stat->rxdw1); + if (rxdw1 & R12A_RXDW1_CKSUM) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: %s/%s checksum is %s\n", __func__, + (rxdw1 & R12A_RXDW1_UDP) ? "UDP" : "TCP", + (rxdw1 & R12A_RXDW1_IPV6) ? "IPv6" : "IP", + (rxdw1 & R12A_RXDW1_CKSUM_ERR) ? "invalid" : "valid"); + + if (rxdw1 & R12A_RXDW1_CKSUM_ERR) + return (-1); + + if ((rxdw1 & R12A_RXDW1_IPV6) ? + (rs->rs_flags & R12A_RXCKSUM6_EN) : + (rs->rs_flags & R12A_RXCKSUM_EN)) { + m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | + CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } + } + + return (0); +} + +uint8_t +r12a_rx_radiotap_flags(const void *buf) +{ + const struct r92c_rx_stat *stat = buf; + uint8_t flags, rate; + + if (!(stat->rxdw4 & htole32(R12A_RXDW4_SPLCP))) + return (0); + rate = MS(le32toh(stat->rxdw3), R92C_RXDW3_RATE); + if (RTWN_RATE_IS_CCK(rate)) + flags = IEEE80211_RADIOTAP_F_SHORTPRE; + else + flags = IEEE80211_RADIOTAP_F_SHORTGI; + return (flags); +} |