source: rtems-libbsd/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.c @ 0cbb715

55-freebsd-126-freebsd-12
Last change on this file since 0cbb715 was 0cbb715, checked in by Christian Mauderer <Christian.Mauderer@…>, on 11/22/16 at 09:41:47

rtwn: Import from FreeBSD.

  • Property mode set to 100644
File size: 6.9 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*      $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $     */
4
5/*-
6 * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
7 * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
8 * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
9 *
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#include <sys/cdefs.h>
24__FBSDID("$FreeBSD$");
25
26#include <rtems/bsd/local/opt_wlan.h>
27
28#include <rtems/bsd/sys/param.h>
29#include <rtems/bsd/sys/lock.h>
30#include <sys/mutex.h>
31#include <sys/mbuf.h>
32#include <sys/kernel.h>
33#include <sys/socket.h>
34#include <sys/systm.h>
35#include <sys/malloc.h>
36#include <sys/queue.h>
37#include <sys/taskqueue.h>
38#include <sys/bus.h>
39#include <sys/endian.h>
40
41#include <machine/bus.h>
42#include <machine/resource.h>
43#include <sys/rman.h>
44
45#include <net/if.h>
46#include <net/if_var.h>
47#include <net/ethernet.h>
48#include <net/if_media.h>
49
50#include <net80211/ieee80211_var.h>
51#include <net80211/ieee80211_radiotap.h>
52
53#include <dev/rtwn/if_rtwnreg.h>
54#include <dev/rtwn/if_rtwnvar.h>
55#include <dev/rtwn/if_rtwn_debug.h>
56
57#include <dev/rtwn/pci/rtwn_pci_var.h>
58#include <dev/rtwn/pci/rtwn_pci_tx.h>
59
60#include <dev/rtwn/rtl8192c/pci/r92ce_reg.h>
61
62
63static struct mbuf *
64rtwn_mbuf_defrag(struct mbuf *m0, int how)
65{
66        struct mbuf *m = NULL;
67
68        KASSERT(m0->m_flags & M_PKTHDR,
69            ("M_PKTHDR flag is absent (m %p)!", m0));
70
71        /* NB: we need _exactly_ one mbuf (no less, no more). */
72        if (m0->m_pkthdr.len > MJUMPAGESIZE) {
73                /* XXX MJUM9BYTES? */
74                return (NULL);
75        } else if (m0->m_pkthdr.len > MCLBYTES) {
76                m = m_getjcl(how, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
77                if (m == NULL)
78                        return (NULL);
79
80                if (m_dup_pkthdr(m, m0, how) == 0) {
81                        m_freem(m);
82                        return (NULL);
83                }
84
85                m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
86                m->m_len = m->m_pkthdr.len;
87                m_freem(m0);
88
89                return (m);
90        } else
91                return (m_defrag(m0, how));
92}
93
94static int
95rtwn_pci_tx_start_frame(struct rtwn_softc *sc, struct ieee80211_node *ni,
96    struct mbuf *m, uint8_t *tx_desc, uint8_t type)
97{
98        struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
99        struct rtwn_tx_ring *ring;
100        struct rtwn_tx_data *data;
101        struct rtwn_tx_desc_common *txd;
102        bus_dma_segment_t segs[1];
103        uint8_t qid;
104        int nsegs, error;
105
106        RTWN_ASSERT_LOCKED(sc);
107
108        switch (type) {
109        case IEEE80211_FC0_TYPE_CTL:
110        case IEEE80211_FC0_TYPE_MGT:
111                qid = RTWN_PCI_MGNT_QUEUE;
112                break;
113        default:
114                qid = M_WME_GETAC(m);
115                break;
116        }
117
118        ring = &pc->tx_ring[qid];
119        data = &ring->tx_data[ring->cur];
120        if (data->m != NULL) {
121                RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT,
122                    "%s: ring #%u is full (m %p)\n", __func__, qid, data->m);
123                return (ENOBUFS);
124        }
125
126        txd = (struct rtwn_tx_desc_common *)
127            ((uint8_t *)ring->desc + sc->txdesc_len * ring->cur);
128        if (txd->flags0 & RTWN_FLAGS0_OWN) {
129                device_printf(sc->sc_dev,
130                    "%s: OWN bit is set (tx desc %d, ring %u)!\n",
131                    __func__, ring->cur, qid);
132                return (ENOBUFS);
133        }
134
135        /* Copy Tx descriptor. */
136        rtwn_pci_copy_tx_desc(pc, txd, tx_desc);
137        txd->pktlen = htole16(m->m_pkthdr.len);
138        txd->offset = sc->txdesc_len;
139
140        error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs,
141            &nsegs, BUS_DMA_NOWAIT);
142        if (error != 0 && error != EFBIG) {
143                device_printf(sc->sc_dev, "can't map mbuf (error %d)\n",
144                    error);
145                return (error);
146        }
147        if (error != 0) {
148                struct mbuf *mnew;
149
150                mnew = rtwn_mbuf_defrag(m, M_NOWAIT);
151                if (mnew == NULL) {
152                        device_printf(sc->sc_dev, "can't defragment mbuf\n");
153                        return (ENOBUFS);
154                }
155                m = mnew;
156
157                error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m,
158                    segs, &nsegs, BUS_DMA_NOWAIT);
159                if (error != 0) {
160                        device_printf(sc->sc_dev,
161                            "can't map mbuf (error %d)\n", error);
162                        if (ni != NULL) {
163                                if_inc_counter(ni->ni_vap->iv_ifp,
164                                    IFCOUNTER_OERRORS, 1);
165                                ieee80211_free_node(ni);
166                        }
167                        m_freem(m);
168                        return (0);     /* XXX */
169                }
170        }
171
172        rtwn_pci_tx_postsetup(pc, txd, segs);
173        txd->flags0 |= RTWN_FLAGS0_OWN;
174
175        /* Dump Tx descriptor. */
176        rtwn_dump_tx_desc(sc, txd);
177
178        bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
179            BUS_DMASYNC_POSTWRITE);
180        bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE);
181
182        data->m = m;
183        data->ni = ni;
184
185        ring->cur = (ring->cur + 1) % RTWN_PCI_TX_LIST_COUNT;
186
187        ring->queued++;
188        if (ring->queued >= (RTWN_PCI_TX_LIST_COUNT - 1))
189                sc->qfullmsk |= (1 << qid);
190
191#ifndef D4054
192        sc->sc_tx_timer = 5;
193#endif
194
195        /* Kick TX. */
196        rtwn_write_2(sc, R92C_PCIE_CTRL_REG, (1 << qid));
197
198        return (0);
199}
200
201static int
202rtwn_pci_tx_start_beacon(struct rtwn_softc *sc, struct mbuf *m,
203    uint8_t *tx_desc, int id)
204{
205        struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
206        struct rtwn_tx_ring *ring;
207        struct rtwn_tx_data *data;
208        struct rtwn_tx_desc_common *txd;
209        bus_dma_segment_t segs[1];
210        int nsegs, error, own;
211
212        RTWN_ASSERT_LOCKED(sc);
213
214        KASSERT(id == 0 || id == 1, ("bogus vap id %d\n", id));
215
216        ring = &pc->tx_ring[RTWN_PCI_BEACON_QUEUE];
217        data = &ring->tx_data[id];
218        txd = (struct rtwn_tx_desc_common *)
219            ((uint8_t *)ring->desc + id * sc->txdesc_len);
220
221        bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
222            BUS_DMASYNC_POSTREAD);
223        own = !!(txd->flags0 & RTWN_FLAGS0_OWN);
224        error = 0;
225        if (!own || txd->pktlen != htole16(m->m_pkthdr.len)) {
226                if (!own) {
227                        /* Copy Tx descriptor. */
228                        rtwn_pci_copy_tx_desc(pc, txd, tx_desc);
229                        txd->offset = sc->txdesc_len;
230                } else {
231                        /* Reload mbuf. */
232                        bus_dmamap_unload(ring->data_dmat, data->map);
233                }
234
235                error = bus_dmamap_load_mbuf_sg(ring->data_dmat,
236                    data->map, m, segs, &nsegs, BUS_DMA_NOWAIT);
237                if (error != 0) {
238                        device_printf(sc->sc_dev,
239                            "can't map beacon (error %d)\n", error);
240                        txd->flags0 &= ~RTWN_FLAGS0_OWN;
241                        goto end;
242                }
243
244                txd->pktlen = htole16(m->m_pkthdr.len);
245                rtwn_pci_tx_postsetup(pc, txd, segs);
246                txd->flags0 |= RTWN_FLAGS0_OWN;
247end:
248                bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
249                    BUS_DMASYNC_PREWRITE);
250        }
251
252        /* Dump Tx descriptor. */
253        rtwn_dump_tx_desc(sc, txd);
254
255        bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
256
257        return (0);
258}
259
260int
261rtwn_pci_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni,
262    struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id)
263{
264        int error = 0;
265
266        RTWN_ASSERT_LOCKED(sc);
267
268        if (ni == NULL)         /* beacon frame */
269                error = rtwn_pci_tx_start_beacon(sc, m, tx_desc, id);
270        else
271                error = rtwn_pci_tx_start_frame(sc, ni, m, tx_desc, type);
272
273        return (error);
274}
Note: See TracBrowser for help on using the repository browser.