diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 84cbd00e3ec7..c5dc03f0517e 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -108,6 +108,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -301,6 +302,17 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) sc->sc_debug = ath_debug; #endif + /* + * Setup the DMA/EDMA functions based on the current + * hardware support. + * + * This is required before the descriptors are allocated. + */ + if (ath_hal_hasedma(sc->sc_ah)) + ath_recv_setup_edma(sc); + else + ath_recv_setup_legacy(sc); + /* * Check if the MAC has multi-rate retry support. * We do this by trying to setup a fake extended @@ -376,7 +388,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", ifp->if_xname); - TASK_INIT(&sc->sc_rxtask, 0, ath_rx_tasklet, sc); + TASK_INIT(&sc->sc_rxtask, 0, sc->sc_rx.recv_tasklet, sc); TASK_INIT(&sc->sc_bmisstask, 0, ath_bmiss_proc, sc); TASK_INIT(&sc->sc_bstucktask,0, ath_bstuck_proc, sc); TASK_INIT(&sc->sc_resettask,0, ath_reset_proc, sc); @@ -2100,7 +2112,7 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) * That way frames aren't dropped which shouldn't be. */ ath_stoprecv(sc, (reset_type != ATH_RESET_NOLOSS)); - ath_rx_proc(sc, 0); + ath_rx_flush(sc); ath_settkipmic(sc); /* configure TKIP MIC handling */ /* NB: indicate channel change so we do a full reset */ @@ -4018,7 +4030,7 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) /* * First, handle completed TX/RX frames. */ - ath_rx_proc(sc, 0); + ath_rx_flush(sc); ath_draintxq(sc, ATH_RESET_NOLOSS); /* * Next, flush the non-scheduled frames. diff --git a/sys/dev/ath/if_ath_rx.c b/sys/dev/ath/if_ath_rx.c index 532f20020c2a..dd03fb91d640 100644 --- a/sys/dev/ath/if_ath_rx.c +++ b/sys/dev/ath/if_ath_rx.c @@ -214,8 +214,8 @@ ath_calcrxfilter(struct ath_softc *sc) return rfilt; } -int -ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) +static int +ath_legacy_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) { struct ath_hal *ah = sc->sc_ah; int error; @@ -463,29 +463,6 @@ ath_handle_micerror(struct ieee80211com *ic, } } -/* - * Only run the RX proc if it's not already running. - * Since this may get run as part of the reset/flush path, - * the task can't clash with an existing, running tasklet. - */ -void -ath_rx_tasklet(void *arg, int npending) -{ - struct ath_softc *sc = arg; - - CTR1(ATH_KTR_INTR, "ath_rx_proc: pending=%d", npending); - DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending); - ATH_PCU_LOCK(sc); - if (sc->sc_inreset_cnt > 0) { - device_printf(sc->sc_dev, - "%s: sc_inreset_cnt > 0; skipping\n", __func__); - ATH_PCU_UNLOCK(sc); - return; - } - ATH_PCU_UNLOCK(sc); - ath_rx_proc(sc, 1); -} - static int ath_rx_pkt(struct ath_softc *sc, struct ath_rx_status *rs, HAL_STATUS status, uint64_t tsf, int nf, struct ath_buf *bf) @@ -814,7 +791,7 @@ rx_next: return (is_good); } -void +static void ath_rx_proc(struct ath_softc *sc, int resched) { #define PA2DESC(_sc, _pa) \ @@ -964,11 +941,42 @@ rx_proc_next: ATH_PCU_UNLOCK(sc); } +/* + * Only run the RX proc if it's not already running. + * Since this may get run as part of the reset/flush path, + * the task can't clash with an existing, running tasklet. + */ +static void +ath_legacy_rx_tasklet(void *arg, int npending) +{ + struct ath_softc *sc = arg; + + CTR1(ATH_KTR_INTR, "ath_rx_proc: pending=%d", npending); + DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending); + ATH_PCU_LOCK(sc); + if (sc->sc_inreset_cnt > 0) { + device_printf(sc->sc_dev, + "%s: sc_inreset_cnt > 0; skipping\n", __func__); + ATH_PCU_UNLOCK(sc); + return; + } + ATH_PCU_UNLOCK(sc); + + ath_rx_proc(sc, 1); +} + +static void +ath_legacy_flushrecv(struct ath_softc *sc) +{ + + ath_rx_proc(sc, 0); +} + /* * Disable the receive h/w in preparation for a reset. */ -void -ath_stoprecv(struct ath_softc *sc, int dodelay) +static void +ath_legacy_stoprecv(struct ath_softc *sc, int dodelay) { #define PA2DESC(_sc, _pa) \ ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ @@ -1019,8 +1027,8 @@ ath_stoprecv(struct ath_softc *sc, int dodelay) /* * Enable the receive h/w following a reset. */ -int -ath_startrecv(struct ath_softc *sc) +static int +ath_legacy_startrecv(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; @@ -1044,3 +1052,17 @@ ath_startrecv(struct ath_softc *sc) ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */ return 0; } + + +void +ath_recv_setup_legacy(struct ath_softc *sc) +{ + + device_printf(sc->sc_dev, "DMA setup: legacy\n"); + + sc->sc_rx.recv_start = ath_legacy_startrecv; + sc->sc_rx.recv_stop = ath_legacy_stoprecv; + sc->sc_rx.recv_flush = ath_legacy_flushrecv; + sc->sc_rx.recv_tasklet = ath_legacy_rx_tasklet; + sc->sc_rx.recv_rxbuf_init = ath_legacy_rxbuf_init; +} diff --git a/sys/dev/ath/if_ath_rx.h b/sys/dev/ath/if_ath_rx.h index d3bd4306a4c2..f99425ea442f 100644 --- a/sys/dev/ath/if_ath_rx.h +++ b/sys/dev/ath/if_ath_rx.h @@ -32,12 +32,26 @@ #define __IF_ATH_RX_H__ extern u_int32_t ath_calcrxfilter(struct ath_softc *sc); -extern int ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf); extern void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, int rssi, int nf); + +#define ath_stoprecv(_sc, _dodelay) \ + (_sc)->sc_rx.recv_stop((_sc), (_dodelay)) +#define ath_startrecv(_sc) \ + (_sc)->sc_rx.recv_start((_sc)) +#define ath_rx_flush(_sc) \ + (_sc)->sc_rx.recv_flush((_sc)) +#define ath_rxbuf_init(_sc, _bf) \ + (_sc)->sc_rx.recv_rxbuf_init((_sc), (_bf)) + +#if 0 +extern int ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf); extern void ath_rx_tasklet(void *arg, int npending); extern void ath_rx_proc(struct ath_softc *sc, int resched); extern void ath_stoprecv(struct ath_softc *sc, int dodelay); extern int ath_startrecv(struct ath_softc *sc); +#endif + +extern void ath_recv_setup_legacy(struct ath_softc *sc); #endif diff --git a/sys/dev/ath/if_ath_rx_edma.c b/sys/dev/ath/if_ath_rx_edma.c new file mode 100644 index 000000000000..dc9b1a9c64f4 --- /dev/null +++ b/sys/dev/ath/if_ath_rx_edma.c @@ -0,0 +1,192 @@ +/*- + * Copyright (c) 2012 Adrian Chadd + * 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, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Driver for the Atheros Wireless LAN controller. + * + * This software is derived from work of Atsushi Onoe; his contribution + * is greatly appreciated. + */ + +#include "opt_inet.h" +#include "opt_ath.h" +/* + * This is needed for register operations which are performed + * by the driver - eg, calls to ath_hal_gettsf32(). + * + * It's also required for any AH_DEBUG checks in here, eg the + * module dependencies. + */ +#include "opt_ah.h" +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for mp_ncpus */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifdef IEEE80211_SUPPORT_SUPERG +#include +#endif +#ifdef IEEE80211_SUPPORT_TDMA +#include +#endif + +#include + +#ifdef INET +#include +#include +#endif + +#include +#include /* XXX for softled */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ATH_TX99_DIAG +#include +#endif + +#include + +static void +ath_edma_stoprecv(struct ath_softc *sc, int dodelay) +{ + struct ath_hal *ah = sc->sc_ah; + + ath_hal_stoppcurecv(ah); + ath_hal_setrxfilter(ah, 0); + ath_hal_stopdmarecv(ah); + + DELAY(3000); + + if (sc->sc_rxpending != NULL) { + m_freem(sc->sc_rxpending); + sc->sc_rxpending = NULL; + } + + sc->sc_rxlink = NULL; +} + +static int +ath_edma_startrecv(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + + sc->sc_rxlink = NULL; + sc->sc_rxpending = NULL; + + /* XXX setup HP RX queue FIFO pointer */ + /* XXX setup LP RX queue FIFO pointer */ + /* XXX ath_hal_rxena() */ + ath_mode_init(sc); + ath_hal_startpcurecv(ah); + return (0); +} + +static void +ath_edma_recv_flush(struct ath_softc *sc) +{ + + device_printf(sc->sc_dev, "%s: called\n", __func__); +} + +static void +ath_edma_recv_tasklet(void *arg, int npending) +{ + struct ath_softc *sc = (struct ath_softc *) arg; + + device_printf(sc->sc_dev, "%s: called; npending=%d\n", + __func__, + npending); + /* XXX TODO */ +} + +static int +ath_edma_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) +{ + + device_printf(sc->sc_dev, "%s: called; bf=%p\n", __func__, bf); + return (EIO); +} + +void +ath_recv_setup_edma(struct ath_softc *sc) +{ + + device_printf(sc->sc_dev, "DMA setup: EDMA\n"); + + sc->sc_rx.recv_stop = ath_edma_stoprecv; + sc->sc_rx.recv_start = ath_edma_startrecv; + sc->sc_rx.recv_flush = ath_edma_recv_flush; + sc->sc_rx.recv_tasklet = ath_edma_recv_tasklet; + sc->sc_rx.recv_rxbuf_init = ath_edma_rxbuf_init; +} diff --git a/sys/dev/ath/if_ath_rx_edma.h b/sys/dev/ath/if_ath_rx_edma.h new file mode 100644 index 000000000000..e786daa6c433 --- /dev/null +++ b/sys/dev/ath/if_ath_rx_edma.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2012 Adrian Chadd + * 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, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $FreeBSD$ + */ +#ifndef __IF_ATH_RX_EDMA_H__ +#define __IF_ATH_RX_EDMA_H__ + +extern void ath_recv_setup_edma(struct ath_softc *sc); + +#endif diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 81083dc3bf9f..d622df53d159 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -372,6 +372,15 @@ typedef enum { ATH_RESET_FULL = 2, } ATH_RESET_TYPE; +struct ath_rx_methods { + void (*recv_stop)(struct ath_softc *sc, int dodelay); + int (*recv_start)(struct ath_softc *sc); + void (*recv_flush)(struct ath_softc *sc); + void (*recv_tasklet)(void *arg, int npending); + int (*recv_rxbuf_init)(struct ath_softc *sc, + struct ath_buf *bf); +}; + struct ath_softc { struct ifnet *sc_ifp; /* interface common */ struct ath_stats sc_stats; /* interface statistics */ @@ -385,6 +394,8 @@ struct ath_softc { u_int8_t sc_nbssid0; /* # vap's using base mac */ uint32_t sc_bssidmask; /* bssid mask */ + struct ath_rx_methods sc_rx; + void (*sc_node_cleanup)(struct ieee80211_node *); void (*sc_node_free)(struct ieee80211_node *); device_t sc_dev;