From owner-svn-src-head@FreeBSD.ORG Tue Jul 3 06:59:13 2012 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 893A0106566B; Tue, 3 Jul 2012 06:59:13 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 631AF8FC12; Tue, 3 Jul 2012 06:59:13 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q636xDXd027192; Tue, 3 Jul 2012 06:59:13 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q636xDL5027184; Tue, 3 Jul 2012 06:59:13 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201207030659.q636xDL5027184@svn.freebsd.org> From: Adrian Chadd Date: Tue, 3 Jul 2012 06:59:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r238055 - head/sys/dev/ath X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 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: Tue, 03 Jul 2012 06:59:13 -0000 Author: adrian Date: Tue Jul 3 06:59:12 2012 New Revision: 238055 URL: http://svn.freebsd.org/changeset/base/238055 Log: Begin abstracting out the RX path in preparation for RX EDMA support. The RX EDMA support requires a modified approach to the RX descriptor handling. Specifically: * There's now two RX queues - high and low priority; * The RX queues are implemented as FIFOs; they're now an array of pointers to buffers; * .. and the RX buffer and descriptor are in the same "buffer", rather than being separate. So to that end, this commit abstracts out most of the RX related functions from the bulk of the driver. Notably, the RX DMA/buffer allocation isn't updated, primarily because I haven't yet fleshed out what it should look like. Whilst I'm here, create a set of matching but mostly unimplemented EDMA stubs. Tested: * AR9280, station mode TODO: * Thorough AP and other mode testing for non-EDMA chips; * Figure out how to allocate RX buffers suitable for RX EDMA, including correctly setting the mbuf length to compensate for the RX descriptor and completion status area. Added: head/sys/dev/ath/if_ath_rx_edma.c (contents, props changed) head/sys/dev/ath/if_ath_rx_edma.h (contents, props changed) Modified: head/sys/dev/ath/if_ath.c head/sys/dev/ath/if_ath_rx.c head/sys/dev/ath/if_ath_rx.h head/sys/dev/ath/if_athvar.h Modified: head/sys/dev/ath/if_ath.c ============================================================================== --- head/sys/dev/ath/if_ath.c Tue Jul 3 06:56:11 2012 (r238054) +++ head/sys/dev/ath/if_ath.c Tue Jul 3 06:59:12 2012 (r238055) @@ -108,6 +108,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -302,6 +303,17 @@ ath_attach(u_int16_t devid, struct ath_s #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 * descriptor. MAC's that don't have support will @@ -376,7 +388,7 @@ ath_attach(u_int16_t devid, struct ath_s 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_T * 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, struc /* * 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. Modified: head/sys/dev/ath/if_ath_rx.c ============================================================================== --- head/sys/dev/ath/if_ath_rx.c Tue Jul 3 06:56:11 2012 (r238054) +++ head/sys/dev/ath/if_ath_rx.c Tue Jul 3 06:59:12 2012 (r238055) @@ -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 } } -/* - * 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) \ @@ -965,10 +942,41 @@ rx_proc_next: } /* + * 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 d /* * 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; +} Modified: head/sys/dev/ath/if_ath_rx.h ============================================================================== --- head/sys/dev/ath/if_ath_rx.h Tue Jul 3 06:56:11 2012 (r238054) +++ head/sys/dev/ath/if_ath_rx.h Tue Jul 3 06:59:12 2012 (r238055) @@ -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 Added: head/sys/dev/ath/if_ath_rx_edma.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/ath/if_ath_rx_edma.c Tue Jul 3 06:59:12 2012 (r238055) @@ -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; +} Added: head/sys/dev/ath/if_ath_rx_edma.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/ath/if_ath_rx_edma.h Tue Jul 3 06:59:12 2012 (r238055) @@ -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 Modified: head/sys/dev/ath/if_athvar.h ============================================================================== --- head/sys/dev/ath/if_athvar.h Tue Jul 3 06:56:11 2012 (r238054) +++ head/sys/dev/ath/if_athvar.h Tue Jul 3 06:59:12 2012 (r238055) @@ -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;