From owner-svn-src-all@freebsd.org Sun Nov 6 18:11:20 2016 Return-Path: Delivered-To: svn-src-all@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 5A7FAC33F60; Sun, 6 Nov 2016 18:11:20 +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 1D6642F7; Sun, 6 Nov 2016 18:11:20 +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 uA6IBJ4G095150; Sun, 6 Nov 2016 18:11:19 GMT (envelope-from avos@FreeBSD.org) Received: (from avos@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uA6IBJO4095149; Sun, 6 Nov 2016 18:11:19 GMT (envelope-from avos@FreeBSD.org) Message-Id: <201611061811.uA6IBJO4095149@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: avos set sender to avos@FreeBSD.org using -f From: Andriy Voskoboinyk Date: Sun, 6 Nov 2016 18:11:19 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r308381 - head/sys/dev/rtwn/pci X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 06 Nov 2016 18:11:20 -0000 Author: avos Date: Sun Nov 6 18:11:19 2016 New Revision: 308381 URL: https://svnweb.freebsd.org/changeset/base/308381 Log: rtwn: fix Tx ring cleanup. Do not try to clear stale Tx descriptor entries when there are some running vaps; just free node references - rtwn_pci_tx_done() will free mbufs without creating holes in the Tx descriptor space. Also, reset only 2 first entries in the beacon ring - other will not be used anyway. Tested with RTL8188CE, STA + STA mode. Modified: head/sys/dev/rtwn/pci/rtwn_pci_attach.c Modified: head/sys/dev/rtwn/pci/rtwn_pci_attach.c ============================================================================== --- head/sys/dev/rtwn/pci/rtwn_pci_attach.c Sun Nov 6 17:24:16 2016 (r308380) +++ head/sys/dev/rtwn/pci/rtwn_pci_attach.c Sun Nov 6 18:11:19 2016 (r308381) @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include @@ -75,6 +76,8 @@ static int rtwn_pci_alloc_rx_list(struct static void rtwn_pci_reset_rx_list(struct rtwn_softc *); static void rtwn_pci_free_rx_list(struct rtwn_softc *); static int rtwn_pci_alloc_tx_list(struct rtwn_softc *, int); +static void rtwn_pci_reset_tx_ring_stopped(struct rtwn_softc *, int); +static void rtwn_pci_reset_beacon_ring(struct rtwn_softc *, int); static void rtwn_pci_reset_tx_list(struct rtwn_softc *, struct ieee80211vap *, int); static void rtwn_pci_free_tx_list(struct rtwn_softc *, int); @@ -312,48 +315,109 @@ fail: } static void -rtwn_pci_reset_tx_list(struct rtwn_softc *sc, struct ieee80211vap *vap, - int qid) +rtwn_pci_reset_tx_ring_stopped(struct rtwn_softc *sc, int qid) { - struct rtwn_vap *uvp = RTWN_VAP(vap); struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); - struct rtwn_tx_ring *tx_ring = &pc->tx_ring[qid]; - int i, id; - - id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID); + struct rtwn_tx_ring *ring = &pc->tx_ring[qid]; + int i; for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { - struct rtwn_tx_data *tx_data = &tx_ring->tx_data[i]; + struct rtwn_tx_data *data = &ring->tx_data[i]; + void *desc = (uint8_t *)ring->desc + sc->txdesc_len * i; - if (vap == NULL || (tx_data->ni == NULL && - (tx_data->id == id || id == RTWN_VAP_ID_INVALID)) || - (tx_data->ni != NULL && tx_data->ni->ni_vap == vap)) { - void *tx_desc = - (uint8_t *)tx_ring->desc + sc->txdesc_len * i; - - rtwn_pci_copy_tx_desc(pc, tx_desc, NULL); - - if (tx_data->m != NULL) { - bus_dmamap_sync(tx_ring->data_dmat, - tx_data->map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(tx_ring->data_dmat, - tx_data->map); - m_freem(tx_data->m); - tx_data->m = NULL; - } - if (tx_data->ni != NULL) { - ieee80211_free_node(tx_data->ni); - tx_data->ni = NULL; - } + rtwn_pci_copy_tx_desc(pc, desc, NULL); + + if (data->m != NULL) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + m_freem(data->m); + data->m = NULL; + } + if (data->ni != NULL) { + ieee80211_free_node(data->ni); + data->ni = NULL; } } - bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTWRITE); sc->qfullmsk &= ~(1 << qid); - tx_ring->queued = 0; - tx_ring->last = tx_ring->cur = 0; + ring->queued = 0; + ring->last = ring->cur = 0; +} + +/* + * Clear entry 0 (or 1) in the beacon queue (other are not used). + */ +static void +rtwn_pci_reset_beacon_ring(struct rtwn_softc *sc, int id) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring = &pc->tx_ring[RTWN_PCI_BEACON_QUEUE]; + struct rtwn_tx_data *data = &ring->tx_data[id]; + struct rtwn_tx_desc_common *txd = (struct rtwn_tx_desc_common *) + ((uint8_t *)ring->desc + id * sc->txdesc_len); + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD); + if (txd->flags0 & RTWN_FLAGS0_OWN) { + /* Clear OWN bit. */ + txd->flags0 &= ~RTWN_FLAGS0_OWN; + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, + BUS_DMASYNC_PREWRITE); + + /* Unload mbuf. */ + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + } +} + +/* + * Drop stale entries from Tx ring before the vap will be deleted. + * In case if vap is NULL just free everything and reset cur / last pointers. + */ +static void +rtwn_pci_reset_tx_list(struct rtwn_softc *sc, struct ieee80211vap *vap, + int qid) +{ + int i; + + if (vap == NULL) { + if (qid != RTWN_PCI_BEACON_QUEUE) { + /* + * Device was stopped; just clear all entries. + */ + rtwn_pci_reset_tx_ring_stopped(sc, qid); + } else { + for (i = 0; i < RTWN_PORT_COUNT; i++) + rtwn_pci_reset_beacon_ring(sc, i); + } + } else if (qid == RTWN_PCI_BEACON_QUEUE && + (vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_IBSS)) { + struct rtwn_vap *uvp = RTWN_VAP(vap); + + rtwn_pci_reset_beacon_ring(sc, uvp->id); + } else { + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring = &pc->tx_ring[qid]; + + for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { + struct rtwn_tx_data *data = &ring->tx_data[i]; + if (data->ni != NULL && data->ni->ni_vap == vap) { + /* + * NB: if some vap is still running + * rtwn_pci_tx_done() will free the mbuf; + * otherwise, rtwn_stop() will reset all rings + * after device shutdown. + */ + ieee80211_free_node(data->ni); + data->ni = NULL; + } + } + } } static void