]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/cxgbe/t4_netmap.c
cxgbe(4): knobs to experiment with the interrupt coalescing timer for
[FreeBSD/FreeBSD.git] / sys / dev / cxgbe / t4_netmap.c
1 /*-
2  * Copyright (c) 2014 Chelsio Communications, Inc.
3  * All rights reserved.
4  * Written by: Navdeep Parhar <np@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include "opt_inet.h"
32 #include "opt_inet6.h"
33
34 #ifdef DEV_NETMAP
35 #include <sys/param.h>
36 #include <sys/eventhandler.h>
37 #include <sys/lock.h>
38 #include <sys/types.h>
39 #include <sys/mbuf.h>
40 #include <sys/selinfo.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <machine/bus.h>
44 #include <net/ethernet.h>
45 #include <net/if.h>
46 #include <net/if_media.h>
47 #include <net/if_var.h>
48 #include <net/if_clone.h>
49 #include <net/if_types.h>
50 #include <net/netmap.h>
51 #include <dev/netmap/netmap_kern.h>
52
53 #include "common/common.h"
54 #include "common/t4_regs.h"
55 #include "common/t4_regs_values.h"
56
57 extern int fl_pad;      /* XXXNM */
58 extern int spg_len;     /* XXXNM */
59 extern int fl_pktshift; /* XXXNM */
60
61 SYSCTL_NODE(_hw, OID_AUTO, cxgbe, CTLFLAG_RD, 0, "cxgbe netmap parameters");
62
63 int rx_ndesc = 256;
64 SYSCTL_INT(_hw_cxgbe, OID_AUTO, nm_rx_ndesc, CTLFLAG_RWTUN,
65     &rx_ndesc, 0, "# of rx descriptors after which the hw cidx is updated.");
66
67 int holdoff_tmr_idx = 2;
68 SYSCTL_INT(_hw_cxgbe, OID_AUTO, nm_holdoff_tmr_idx, CTLFLAG_RWTUN,
69     &holdoff_tmr_idx, 0, "Holdoff timer index for netmap rx queues.");
70
71 /* netmap ifnet routines */
72 static void cxgbe_nm_init(void *);
73 static int cxgbe_nm_ioctl(struct ifnet *, unsigned long, caddr_t);
74 static int cxgbe_nm_transmit(struct ifnet *, struct mbuf *);
75 static void cxgbe_nm_qflush(struct ifnet *);
76
77 static int cxgbe_nm_init_synchronized(struct port_info *);
78 static int cxgbe_nm_uninit_synchronized(struct port_info *);
79
80 static void
81 cxgbe_nm_init(void *arg)
82 {
83         struct port_info *pi = arg;
84         struct adapter *sc = pi->adapter;
85
86         if (begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4nminit") != 0)
87                 return;
88         cxgbe_nm_init_synchronized(pi);
89         end_synchronized_op(sc, 0);
90
91         return;
92 }
93
94 static int
95 cxgbe_nm_init_synchronized(struct port_info *pi)
96 {
97         struct adapter *sc = pi->adapter;
98         struct ifnet *ifp = pi->nm_ifp;
99         int rc = 0;
100
101         ASSERT_SYNCHRONIZED_OP(sc);
102
103         if (ifp->if_drv_flags & IFF_DRV_RUNNING)
104                 return (0);     /* already running */
105
106         if (!(sc->flags & FULL_INIT_DONE) &&
107             ((rc = adapter_full_init(sc)) != 0))
108                 return (rc);    /* error message displayed already */
109
110         if (!(pi->flags & PORT_INIT_DONE) &&
111             ((rc = port_full_init(pi)) != 0))
112                 return (rc);    /* error message displayed already */
113
114         rc = update_mac_settings(ifp, XGMAC_ALL);
115         if (rc)
116                 return (rc);    /* error message displayed already */
117
118         ifp->if_drv_flags |= IFF_DRV_RUNNING;
119
120         return (rc);
121 }
122
123 static int
124 cxgbe_nm_uninit_synchronized(struct port_info *pi)
125 {
126 #ifdef INVARIANTS
127         struct adapter *sc = pi->adapter;
128 #endif
129         struct ifnet *ifp = pi->nm_ifp;
130
131         ASSERT_SYNCHRONIZED_OP(sc);
132
133         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
134
135         return (0);
136 }
137
138 static int
139 cxgbe_nm_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
140 {
141         int rc = 0, mtu, flags;
142         struct port_info *pi = ifp->if_softc;
143         struct adapter *sc = pi->adapter;
144         struct ifreq *ifr = (struct ifreq *)data;
145         uint32_t mask;
146
147         MPASS(pi->nm_ifp == ifp);
148
149         switch (cmd) {
150         case SIOCSIFMTU:
151                 mtu = ifr->ifr_mtu;
152                 if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO))
153                         return (EINVAL);
154
155                 rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4nmtu");
156                 if (rc)
157                         return (rc);
158                 ifp->if_mtu = mtu;
159                 if (ifp->if_drv_flags & IFF_DRV_RUNNING)
160                         rc = update_mac_settings(ifp, XGMAC_MTU);
161                 end_synchronized_op(sc, 0);
162                 break;
163
164         case SIOCSIFFLAGS:
165                 rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4nflg");
166                 if (rc)
167                         return (rc);
168
169                 if (ifp->if_flags & IFF_UP) {
170                         if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
171                                 flags = pi->nmif_flags;
172                                 if ((ifp->if_flags ^ flags) &
173                                     (IFF_PROMISC | IFF_ALLMULTI)) {
174                                         rc = update_mac_settings(ifp,
175                                             XGMAC_PROMISC | XGMAC_ALLMULTI);
176                                 }
177                         } else
178                                 rc = cxgbe_nm_init_synchronized(pi);
179                         pi->nmif_flags = ifp->if_flags;
180                 } else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
181                         rc = cxgbe_nm_uninit_synchronized(pi);
182                 end_synchronized_op(sc, 0);
183                 break;
184
185         case SIOCADDMULTI:
186         case SIOCDELMULTI: /* these two are called with a mutex held :-( */
187                 rc = begin_synchronized_op(sc, pi, HOLD_LOCK, "t4nmulti");
188                 if (rc)
189                         return (rc);
190                 if (ifp->if_drv_flags & IFF_DRV_RUNNING)
191                         rc = update_mac_settings(ifp, XGMAC_MCADDRS);
192                 end_synchronized_op(sc, LOCK_HELD);
193                 break;
194
195         case SIOCSIFCAP:
196                 mask = ifr->ifr_reqcap ^ ifp->if_capenable;
197                 if (mask & IFCAP_TXCSUM) {
198                         ifp->if_capenable ^= IFCAP_TXCSUM;
199                         ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
200                 }
201                 if (mask & IFCAP_TXCSUM_IPV6) {
202                         ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
203                         ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6);
204                 }
205                 if (mask & IFCAP_RXCSUM)
206                         ifp->if_capenable ^= IFCAP_RXCSUM;
207                 if (mask & IFCAP_RXCSUM_IPV6)
208                         ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
209                 break;
210
211         case SIOCSIFMEDIA:
212         case SIOCGIFMEDIA:
213                 ifmedia_ioctl(ifp, ifr, &pi->nm_media, cmd);
214                 break;
215
216         default:
217                 rc = ether_ioctl(ifp, cmd, data);
218         }
219
220         return (rc);
221 }
222
223 static int
224 cxgbe_nm_transmit(struct ifnet *ifp, struct mbuf *m)
225 {
226
227         m_freem(m);
228         return (0);
229 }
230
231 static void
232 cxgbe_nm_qflush(struct ifnet *ifp)
233 {
234
235         return;
236 }
237
238 static int
239 alloc_nm_rxq_hwq(struct port_info *pi, struct sge_nm_rxq *nm_rxq, int cong)
240 {
241         int rc, cntxt_id, i;
242         __be32 v;
243         struct adapter *sc = pi->adapter;
244         struct netmap_adapter *na = NA(pi->nm_ifp);
245         struct fw_iq_cmd c;
246
247         MPASS(na != NULL);
248         MPASS(nm_rxq->iq_desc != NULL);
249         MPASS(nm_rxq->fl_desc != NULL);
250
251         bzero(nm_rxq->iq_desc, pi->qsize_rxq * IQ_ESIZE);
252         bzero(nm_rxq->fl_desc, na->num_rx_desc * EQ_ESIZE + spg_len);
253
254         bzero(&c, sizeof(c));
255         c.op_to_vfn = htobe32(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST |
256             F_FW_CMD_WRITE | F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(sc->pf) |
257             V_FW_IQ_CMD_VFN(0));
258         c.alloc_to_len16 = htobe32(F_FW_IQ_CMD_ALLOC | F_FW_IQ_CMD_IQSTART |
259             FW_LEN16(c));
260         if (pi->flags & INTR_NM_RXQ) {
261                 KASSERT(nm_rxq->intr_idx < sc->intr_count,
262                     ("%s: invalid direct intr_idx %d", __func__,
263                     nm_rxq->intr_idx));
264                 v = V_FW_IQ_CMD_IQANDSTINDEX(nm_rxq->intr_idx);
265         } else {
266                 CXGBE_UNIMPLEMENTED(__func__);  /* XXXNM: needs review */
267                 v = V_FW_IQ_CMD_IQANDSTINDEX(nm_rxq->intr_idx) |
268                     F_FW_IQ_CMD_IQANDST;
269         }
270         c.type_to_iqandstindex = htobe32(v |
271             V_FW_IQ_CMD_TYPE(FW_IQ_TYPE_FL_INT_CAP) |
272             V_FW_IQ_CMD_VIID(pi->nm_viid) |
273             V_FW_IQ_CMD_IQANUD(X_UPDATEDELIVERY_INTERRUPT));
274         c.iqdroprss_to_iqesize = htobe16(V_FW_IQ_CMD_IQPCIECH(pi->tx_chan) |
275             F_FW_IQ_CMD_IQGTSMODE |
276             V_FW_IQ_CMD_IQINTCNTTHRESH(0) |
277             V_FW_IQ_CMD_IQESIZE(ilog2(IQ_ESIZE) - 4));
278         c.iqsize = htobe16(pi->qsize_rxq);
279         c.iqaddr = htobe64(nm_rxq->iq_ba);
280         if (cong >= 0) {
281                 c.iqns_to_fl0congen = htobe32(F_FW_IQ_CMD_IQFLINTCONGEN |
282                     V_FW_IQ_CMD_FL0CNGCHMAP(cong) | F_FW_IQ_CMD_FL0CONGCIF |
283                     F_FW_IQ_CMD_FL0CONGEN);
284         }
285         c.iqns_to_fl0congen |=
286             htobe32(V_FW_IQ_CMD_FL0HOSTFCMODE(X_HOSTFCMODE_NONE) |
287                 F_FW_IQ_CMD_FL0FETCHRO | F_FW_IQ_CMD_FL0DATARO |
288                 (fl_pad ? F_FW_IQ_CMD_FL0PADEN : 0));
289         c.fl0dcaen_to_fl0cidxfthresh =
290             htobe16(V_FW_IQ_CMD_FL0FBMIN(X_FETCHBURSTMIN_64B) |
291                 V_FW_IQ_CMD_FL0FBMAX(X_FETCHBURSTMAX_512B));
292         c.fl0size = htobe16(na->num_rx_desc / 8 + spg_len / EQ_ESIZE);
293         c.fl0addr = htobe64(nm_rxq->fl_ba);
294
295         rc = -t4_wr_mbox(sc, sc->mbox, &c, sizeof(c), &c);
296         if (rc != 0) {
297                 device_printf(sc->dev,
298                     "failed to create netmap ingress queue: %d\n", rc);
299                 return (rc);
300         }
301
302         nm_rxq->iq_cidx = 0;
303         MPASS(nm_rxq->iq_sidx == pi->qsize_rxq - spg_len / IQ_ESIZE);
304         nm_rxq->iq_gen = F_RSPD_GEN;
305         nm_rxq->iq_cntxt_id = be16toh(c.iqid);
306         nm_rxq->iq_abs_id = be16toh(c.physiqid);
307         cntxt_id = nm_rxq->iq_cntxt_id - sc->sge.iq_start;
308         if (cntxt_id >= sc->sge.niq) {
309                 panic ("%s: nm_rxq->iq_cntxt_id (%d) more than the max (%d)",
310                     __func__, cntxt_id, sc->sge.niq - 1);
311         }
312         sc->sge.iqmap[cntxt_id] = (void *)nm_rxq;
313
314         nm_rxq->fl_cntxt_id = be16toh(c.fl0id);
315         nm_rxq->fl_pidx = nm_rxq->fl_cidx = 0;
316         MPASS(nm_rxq->fl_sidx == na->num_rx_desc);
317         cntxt_id = nm_rxq->fl_cntxt_id - sc->sge.eq_start;
318         if (cntxt_id >= sc->sge.neq) {
319                 panic("%s: nm_rxq->fl_cntxt_id (%d) more than the max (%d)",
320                     __func__, cntxt_id, sc->sge.neq - 1);
321         }
322         sc->sge.eqmap[cntxt_id] = (void *)nm_rxq;
323
324         nm_rxq->fl_db_val = F_DBPRIO | V_QID(nm_rxq->fl_cntxt_id) | V_PIDX(0);
325         if (is_t5(sc))
326                 nm_rxq->fl_db_val |= F_DBTYPE;
327
328         if (is_t5(sc) && cong >= 0) {
329                 uint32_t param, val;
330
331                 param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) |
332                     V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_CONM_CTXT) |
333                     V_FW_PARAMS_PARAM_YZ(nm_rxq->iq_cntxt_id);
334                 param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) |
335                     V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_CONM_CTXT) |
336                     V_FW_PARAMS_PARAM_YZ(nm_rxq->iq_cntxt_id);
337                 if (cong == 0)
338                         val = 1 << 19;
339                 else {
340                         val = 2 << 19;
341                         for (i = 0; i < 4; i++) {
342                                 if (cong & (1 << i))
343                                         val |= 1 << (i << 2);
344                         }
345                 }
346
347                 rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
348                 if (rc != 0) {
349                         /* report error but carry on */
350                         device_printf(sc->dev,
351                             "failed to set congestion manager context for "
352                             "ingress queue %d: %d\n", nm_rxq->iq_cntxt_id, rc);
353                 }
354         }
355
356         t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS),
357             V_INGRESSQID(nm_rxq->iq_cntxt_id) |
358             V_SEINTARM(V_QINTR_TIMER_IDX(holdoff_tmr_idx)));
359
360         return (rc);
361 }
362
363 static int
364 free_nm_rxq_hwq(struct port_info *pi, struct sge_nm_rxq *nm_rxq)
365 {
366         struct adapter *sc = pi->adapter;
367         int rc;
368
369         rc = -t4_iq_free(sc, sc->mbox, sc->pf, 0, FW_IQ_TYPE_FL_INT_CAP,
370             nm_rxq->iq_cntxt_id, nm_rxq->fl_cntxt_id, 0xffff);
371         if (rc != 0)
372                 device_printf(sc->dev, "%s: failed for iq %d, fl %d: %d\n",
373                     __func__, nm_rxq->iq_cntxt_id, nm_rxq->fl_cntxt_id, rc);
374         return (rc);
375 }
376
377 static int
378 alloc_nm_txq_hwq(struct port_info *pi, struct sge_nm_txq *nm_txq)
379 {
380         int rc, cntxt_id;
381         size_t len;
382         struct adapter *sc = pi->adapter;
383         struct netmap_adapter *na = NA(pi->nm_ifp);
384         struct fw_eq_eth_cmd c;
385
386         MPASS(na != NULL);
387         MPASS(nm_txq->desc != NULL);
388
389         len = na->num_tx_desc * EQ_ESIZE + spg_len;
390         bzero(nm_txq->desc, len);
391
392         bzero(&c, sizeof(c));
393         c.op_to_vfn = htobe32(V_FW_CMD_OP(FW_EQ_ETH_CMD) | F_FW_CMD_REQUEST |
394             F_FW_CMD_WRITE | F_FW_CMD_EXEC | V_FW_EQ_ETH_CMD_PFN(sc->pf) |
395             V_FW_EQ_ETH_CMD_VFN(0));
396         c.alloc_to_len16 = htobe32(F_FW_EQ_ETH_CMD_ALLOC |
397             F_FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c));
398         c.autoequiqe_to_viid = htobe32(F_FW_EQ_ETH_CMD_AUTOEQUEQE |
399             V_FW_EQ_ETH_CMD_VIID(pi->nm_viid));
400         c.fetchszm_to_iqid =
401             htobe32(V_FW_EQ_ETH_CMD_HOSTFCMODE(X_HOSTFCMODE_NONE) |
402                 V_FW_EQ_ETH_CMD_PCIECHN(pi->tx_chan) | F_FW_EQ_ETH_CMD_FETCHRO |
403                 V_FW_EQ_ETH_CMD_IQID(sc->sge.nm_rxq[nm_txq->iqidx].iq_cntxt_id));
404         c.dcaen_to_eqsize = htobe32(V_FW_EQ_ETH_CMD_FBMIN(X_FETCHBURSTMIN_64B) |
405                       V_FW_EQ_ETH_CMD_FBMAX(X_FETCHBURSTMAX_512B) |
406                       V_FW_EQ_ETH_CMD_EQSIZE(len / EQ_ESIZE));
407         c.eqaddr = htobe64(nm_txq->ba);
408
409         rc = -t4_wr_mbox(sc, sc->mbox, &c, sizeof(c), &c);
410         if (rc != 0) {
411                 device_printf(pi->dev,
412                     "failed to create netmap egress queue: %d\n", rc);
413                 return (rc);
414         }
415
416         nm_txq->cntxt_id = G_FW_EQ_ETH_CMD_EQID(be32toh(c.eqid_pkd));
417         cntxt_id = nm_txq->cntxt_id - sc->sge.eq_start;
418         if (cntxt_id >= sc->sge.neq)
419             panic("%s: nm_txq->cntxt_id (%d) more than the max (%d)", __func__,
420                 cntxt_id, sc->sge.neq - 1);
421         sc->sge.eqmap[cntxt_id] = (void *)nm_txq;
422
423         nm_txq->pidx = nm_txq->cidx = 0;
424         MPASS(nm_txq->sidx == na->num_tx_desc);
425         nm_txq->equiqidx = nm_txq->equeqidx = nm_txq->dbidx = 0;
426
427         nm_txq->doorbells = sc->doorbells;
428         if (isset(&nm_txq->doorbells, DOORBELL_UDB) ||
429             isset(&nm_txq->doorbells, DOORBELL_UDBWC) ||
430             isset(&nm_txq->doorbells, DOORBELL_WCWR)) {
431                 uint32_t s_qpp = sc->sge.eq_s_qpp;
432                 uint32_t mask = (1 << s_qpp) - 1;
433                 volatile uint8_t *udb;
434
435                 udb = sc->udbs_base + UDBS_DB_OFFSET;
436                 udb += (nm_txq->cntxt_id >> s_qpp) << PAGE_SHIFT;
437                 nm_txq->udb_qid = nm_txq->cntxt_id & mask;
438                 if (nm_txq->udb_qid >= PAGE_SIZE / UDBS_SEG_SIZE)
439                         clrbit(&nm_txq->doorbells, DOORBELL_WCWR);
440                 else {
441                         udb += nm_txq->udb_qid << UDBS_SEG_SHIFT;
442                         nm_txq->udb_qid = 0;
443                 }
444                 nm_txq->udb = (volatile void *)udb;
445         }
446
447         return (rc);
448 }
449
450 static int
451 free_nm_txq_hwq(struct port_info *pi, struct sge_nm_txq *nm_txq)
452 {
453         struct adapter *sc = pi->adapter;
454         int rc;
455
456         rc = -t4_eth_eq_free(sc, sc->mbox, sc->pf, 0, nm_txq->cntxt_id);
457         if (rc != 0)
458                 device_printf(sc->dev, "%s: failed for eq %d: %d\n", __func__,
459                     nm_txq->cntxt_id, rc);
460         return (rc);
461 }
462
463 static int
464 cxgbe_netmap_on(struct adapter *sc, struct port_info *pi, struct ifnet *ifp,
465     struct netmap_adapter *na)
466 {
467         struct netmap_slot *slot;
468         struct sge_nm_rxq *nm_rxq;
469         struct sge_nm_txq *nm_txq;
470         int rc, i, j, hwidx;
471         struct hw_buf_info *hwb;
472         uint16_t *rss;
473
474         ASSERT_SYNCHRONIZED_OP(sc);
475
476         if ((pi->flags & PORT_INIT_DONE) == 0 ||
477             (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
478                 return (EAGAIN);
479
480         hwb = &sc->sge.hw_buf_info[0];
481         for (i = 0; i < SGE_FLBUF_SIZES; i++, hwb++) {
482                 if (hwb->size == NETMAP_BUF_SIZE(na))
483                         break;
484         }
485         if (i >= SGE_FLBUF_SIZES) {
486                 if_printf(ifp, "no hwidx for netmap buffer size %d.\n",
487                     NETMAP_BUF_SIZE(na));
488                 return (ENXIO);
489         }
490         hwidx = i;
491
492         /* Must set caps before calling netmap_reset */
493         nm_set_native_flags(na);
494
495         for_each_nm_rxq(pi, i, nm_rxq) {
496                 alloc_nm_rxq_hwq(pi, nm_rxq, tnl_cong(pi));
497                 nm_rxq->fl_hwidx = hwidx;
498                 slot = netmap_reset(na, NR_RX, i, 0);
499                 MPASS(slot != NULL);    /* XXXNM: error check, not assert */
500
501                 /* We deal with 8 bufs at a time */
502                 MPASS((na->num_rx_desc & 7) == 0);
503                 MPASS(na->num_rx_desc == nm_rxq->fl_sidx);
504                 for (j = 0; j < nm_rxq->fl_sidx; j++) {
505                         uint64_t ba;
506
507                         PNMB(na, &slot[j], &ba);
508                         MPASS(ba != 0);
509                         nm_rxq->fl_desc[j] = htobe64(ba | hwidx);
510                 }
511                 j = nm_rxq->fl_pidx = nm_rxq->fl_sidx - 8;
512                 MPASS((j & 7) == 0);
513                 j /= 8; /* driver pidx to hardware pidx */
514                 wmb();
515                 t4_write_reg(sc, MYPF_REG(A_SGE_PF_KDOORBELL),
516                     nm_rxq->fl_db_val | V_PIDX(j));
517         }
518
519         for_each_nm_txq(pi, i, nm_txq) {
520                 alloc_nm_txq_hwq(pi, nm_txq);
521                 slot = netmap_reset(na, NR_TX, i, 0);
522                 MPASS(slot != NULL);    /* XXXNM: error check, not assert */
523         }
524
525         rss = malloc(pi->nm_rss_size * sizeof (*rss), M_CXGBE, M_ZERO |
526             M_WAITOK);
527         for (i = 0; i < pi->nm_rss_size;) {
528                 for_each_nm_rxq(pi, j, nm_rxq) {
529                         rss[i++] = nm_rxq->iq_abs_id;
530                         if (i == pi->nm_rss_size)
531                                 break;
532                 }
533         }
534         rc = -t4_config_rss_range(sc, sc->mbox, pi->nm_viid, 0, pi->nm_rss_size,
535             rss, pi->nm_rss_size);
536         if (rc != 0)
537                 if_printf(ifp, "netmap rss_config failed: %d\n", rc);
538         free(rss, M_CXGBE);
539
540         rc = -t4_enable_vi(sc, sc->mbox, pi->nm_viid, true, true);
541         if (rc != 0)
542                 if_printf(ifp, "netmap enable_vi failed: %d\n", rc);
543
544         return (rc);
545 }
546
547 static int
548 cxgbe_netmap_off(struct adapter *sc, struct port_info *pi, struct ifnet *ifp,
549     struct netmap_adapter *na)
550 {
551         int rc, i;
552         struct sge_nm_txq *nm_txq;
553         struct sge_nm_rxq *nm_rxq;
554
555         ASSERT_SYNCHRONIZED_OP(sc);
556
557         rc = -t4_enable_vi(sc, sc->mbox, pi->nm_viid, false, false);
558         if (rc != 0)
559                 if_printf(ifp, "netmap disable_vi failed: %d\n", rc);
560         nm_clear_native_flags(na);
561
562         for_each_nm_txq(pi, i, nm_txq) {
563                 struct sge_qstat *spg = (void *)&nm_txq->desc[nm_txq->sidx];
564
565                 /* Wait for hw pidx to catch up ... */
566                 while (be16toh(nm_txq->pidx) != spg->pidx)
567                         pause("nmpidx", 1);
568
569                 /* ... and then for the cidx. */
570                 while (spg->pidx != spg->cidx)
571                         pause("nmcidx", 1);
572
573                 free_nm_txq_hwq(pi, nm_txq);
574         }
575         for_each_nm_rxq(pi, i, nm_rxq) {
576                 free_nm_rxq_hwq(pi, nm_rxq);
577         }
578
579         return (rc);
580 }
581
582 static int
583 cxgbe_netmap_reg(struct netmap_adapter *na, int on)
584 {
585         struct ifnet *ifp = na->ifp;
586         struct port_info *pi = ifp->if_softc;
587         struct adapter *sc = pi->adapter;
588         int rc;
589
590         rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4nmreg");
591         if (rc != 0)
592                 return (rc);
593         if (on)
594                 rc = cxgbe_netmap_on(sc, pi, ifp, na);
595         else
596                 rc = cxgbe_netmap_off(sc, pi, ifp, na);
597         end_synchronized_op(sc, 0);
598
599         return (rc);
600 }
601
602 /* How many packets can a single type1 WR carry in n descriptors */
603 static inline int
604 ndesc_to_npkt(const int n)
605 {
606
607         MPASS(n > 0 && n <= SGE_MAX_WR_NDESC);
608
609         return (n * 2 - 1);
610 }
611 #define MAX_NPKT_IN_TYPE1_WR    (ndesc_to_npkt(SGE_MAX_WR_NDESC))
612
613 /* Space (in descriptors) needed for a type1 WR that carries n packets */
614 static inline int
615 npkt_to_ndesc(const int n)
616 {
617
618         MPASS(n > 0 && n <= MAX_NPKT_IN_TYPE1_WR);
619
620         return ((n + 2) / 2);
621 }
622
623 /* Space (in 16B units) needed for a type1 WR that carries n packets */
624 static inline int
625 npkt_to_len16(const int n)
626 {
627
628         MPASS(n > 0 && n <= MAX_NPKT_IN_TYPE1_WR);
629
630         return (n * 2 + 1);
631 }
632
633 #define NMIDXDIFF(q, idx) IDXDIFF((q)->pidx, (q)->idx, (q)->sidx)
634
635 static void
636 ring_nm_txq_db(struct adapter *sc, struct sge_nm_txq *nm_txq)
637 {
638         int n;
639         u_int db = nm_txq->doorbells;
640
641         MPASS(nm_txq->pidx != nm_txq->dbidx);
642
643         n = NMIDXDIFF(nm_txq, dbidx);
644         if (n > 1)
645                 clrbit(&db, DOORBELL_WCWR);
646         wmb();
647
648         switch (ffs(db) - 1) {
649         case DOORBELL_UDB:
650                 *nm_txq->udb = htole32(V_QID(nm_txq->udb_qid) | V_PIDX(n));
651                 break;
652
653         case DOORBELL_WCWR: {
654                 volatile uint64_t *dst, *src;
655
656                 /*
657                  * Queues whose 128B doorbell segment fits in the page do not
658                  * use relative qid (udb_qid is always 0).  Only queues with
659                  * doorbell segments can do WCWR.
660                  */
661                 KASSERT(nm_txq->udb_qid == 0 && n == 1,
662                     ("%s: inappropriate doorbell (0x%x, %d, %d) for nm_txq %p",
663                     __func__, nm_txq->doorbells, n, nm_txq->pidx, nm_txq));
664
665                 dst = (volatile void *)((uintptr_t)nm_txq->udb +
666                     UDBS_WR_OFFSET - UDBS_DB_OFFSET);
667                 src = (void *)&nm_txq->desc[nm_txq->dbidx];
668                 while (src != (void *)&nm_txq->desc[nm_txq->dbidx + 1])
669                         *dst++ = *src++;
670                 wmb();
671                 break;
672         }
673
674         case DOORBELL_UDBWC:
675                 *nm_txq->udb = htole32(V_QID(nm_txq->udb_qid) | V_PIDX(n));
676                 wmb();
677                 break;
678
679         case DOORBELL_KDB:
680                 t4_write_reg(sc, MYPF_REG(A_SGE_PF_KDOORBELL),
681                     V_QID(nm_txq->cntxt_id) | V_PIDX(n));
682                 break;
683         }
684         nm_txq->dbidx = nm_txq->pidx;
685 }
686
687 int lazy_tx_credit_flush = 1;
688
689 /*
690  * Write work requests to send 'npkt' frames and ring the doorbell to send them
691  * on their way.  No need to check for wraparound.
692  */
693 static void
694 cxgbe_nm_tx(struct adapter *sc, struct sge_nm_txq *nm_txq,
695     struct netmap_kring *kring, int npkt, int npkt_remaining, int txcsum)
696 {
697         struct netmap_ring *ring = kring->ring;
698         struct netmap_slot *slot;
699         const u_int lim = kring->nkr_num_slots - 1;
700         struct fw_eth_tx_pkts_wr *wr = (void *)&nm_txq->desc[nm_txq->pidx];
701         uint16_t len;
702         uint64_t ba;
703         struct cpl_tx_pkt_core *cpl;
704         struct ulptx_sgl *usgl;
705         int i, n;
706
707         while (npkt) {
708                 n = min(npkt, MAX_NPKT_IN_TYPE1_WR);
709                 len = 0;
710
711                 wr = (void *)&nm_txq->desc[nm_txq->pidx];
712                 wr->op_pkd = htobe32(V_FW_WR_OP(FW_ETH_TX_PKTS_WR));
713                 wr->equiq_to_len16 = htobe32(V_FW_WR_LEN16(npkt_to_len16(n)));
714                 wr->npkt = n;
715                 wr->r3 = 0;
716                 wr->type = 1;
717                 cpl = (void *)(wr + 1);
718
719                 for (i = 0; i < n; i++) {
720                         slot = &ring->slot[kring->nr_hwcur];
721                         PNMB(kring->na, slot, &ba);
722                         MPASS(ba != 0);
723
724                         cpl->ctrl0 = nm_txq->cpl_ctrl0;
725                         cpl->pack = 0;
726                         cpl->len = htobe16(slot->len);
727                         /*
728                          * netmap(4) says "netmap does not use features such as
729                          * checksum offloading, TCP segmentation offloading,
730                          * encryption, VLAN encapsulation/decapsulation, etc."
731                          *
732                          * So the ncxl interfaces have tx hardware checksumming
733                          * disabled by default.  But you can override netmap by
734                          * enabling IFCAP_TXCSUM on the interface manully.
735                          */
736                         cpl->ctrl1 = txcsum ? 0 :
737                             htobe64(F_TXPKT_IPCSUM_DIS | F_TXPKT_L4CSUM_DIS);
738
739                         usgl = (void *)(cpl + 1);
740                         usgl->cmd_nsge = htobe32(V_ULPTX_CMD(ULP_TX_SC_DSGL) |
741                             V_ULPTX_NSGE(1));
742                         usgl->len0 = htobe32(slot->len);
743                         usgl->addr0 = htobe64(ba);
744
745                         slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
746                         cpl = (void *)(usgl + 1);
747                         MPASS(slot->len + len <= UINT16_MAX);
748                         len += slot->len;
749                         kring->nr_hwcur = nm_next(kring->nr_hwcur, lim);
750                 }
751                 wr->plen = htobe16(len);
752
753                 npkt -= n;
754                 nm_txq->pidx += npkt_to_ndesc(n);
755                 MPASS(nm_txq->pidx <= nm_txq->sidx);
756                 if (__predict_false(nm_txq->pidx == nm_txq->sidx)) {
757                         /*
758                          * This routine doesn't know how to write WRs that wrap
759                          * around.  Make sure it wasn't asked to.
760                          */
761                         MPASS(npkt == 0);
762                         nm_txq->pidx = 0;
763                 }
764
765                 if (npkt == 0 && npkt_remaining == 0) {
766                         /* All done. */
767                         if (lazy_tx_credit_flush == 0) {
768                                 wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUEQ |
769                                     F_FW_WR_EQUIQ);
770                                 nm_txq->equeqidx = nm_txq->pidx;
771                                 nm_txq->equiqidx = nm_txq->pidx;
772                         }
773                         ring_nm_txq_db(sc, nm_txq);
774                         return;
775                 }
776
777                 if (NMIDXDIFF(nm_txq, equiqidx) >= nm_txq->sidx / 2) {
778                         wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUEQ |
779                             F_FW_WR_EQUIQ);
780                         nm_txq->equeqidx = nm_txq->pidx;
781                         nm_txq->equiqidx = nm_txq->pidx;
782                 } else if (NMIDXDIFF(nm_txq, equeqidx) >= 64) {
783                         wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUEQ);
784                         nm_txq->equeqidx = nm_txq->pidx;
785                 }
786                 if (NMIDXDIFF(nm_txq, dbidx) >= 2 * SGE_MAX_WR_NDESC)
787                         ring_nm_txq_db(sc, nm_txq);
788         }
789
790         /* Will get called again. */
791         MPASS(npkt_remaining);
792 }
793
794 /* How many contiguous free descriptors starting at pidx */
795 static inline int
796 contiguous_ndesc_available(struct sge_nm_txq *nm_txq)
797 {
798
799         if (nm_txq->cidx > nm_txq->pidx)
800                 return (nm_txq->cidx - nm_txq->pidx - 1);
801         else if (nm_txq->cidx > 0)
802                 return (nm_txq->sidx - nm_txq->pidx);
803         else
804                 return (nm_txq->sidx - nm_txq->pidx - 1);
805 }
806
807 static int
808 reclaim_nm_tx_desc(struct sge_nm_txq *nm_txq)
809 {
810         struct sge_qstat *spg = (void *)&nm_txq->desc[nm_txq->sidx];
811         uint16_t hw_cidx = spg->cidx;   /* snapshot */
812         struct fw_eth_tx_pkts_wr *wr;
813         int n = 0;
814
815         hw_cidx = be16toh(hw_cidx);
816
817         while (nm_txq->cidx != hw_cidx) {
818                 wr = (void *)&nm_txq->desc[nm_txq->cidx];
819
820                 MPASS(wr->op_pkd == htobe32(V_FW_WR_OP(FW_ETH_TX_PKTS_WR)));
821                 MPASS(wr->type == 1);
822                 MPASS(wr->npkt > 0 && wr->npkt <= MAX_NPKT_IN_TYPE1_WR);
823
824                 n += wr->npkt;
825                 nm_txq->cidx += npkt_to_ndesc(wr->npkt);
826
827                 /*
828                  * We never sent a WR that wrapped around so the credits coming
829                  * back, WR by WR, should never cause the cidx to wrap around
830                  * either.
831                  */
832                 MPASS(nm_txq->cidx <= nm_txq->sidx);
833                 if (__predict_false(nm_txq->cidx == nm_txq->sidx))
834                         nm_txq->cidx = 0;
835         }
836
837         return (n);
838 }
839
840 static int
841 cxgbe_netmap_txsync(struct netmap_kring *kring, int flags)
842 {
843         struct netmap_adapter *na = kring->na;
844         struct ifnet *ifp = na->ifp;
845         struct port_info *pi = ifp->if_softc;
846         struct adapter *sc = pi->adapter;
847         struct sge_nm_txq *nm_txq = &sc->sge.nm_txq[pi->first_nm_txq + kring->ring_id];
848         const u_int head = kring->rhead;
849         u_int reclaimed = 0;
850         int n, d, npkt_remaining, ndesc_remaining, txcsum;
851
852         /*
853          * Tx was at kring->nr_hwcur last time around and now we need to advance
854          * to kring->rhead.  Note that the driver's pidx moves independent of
855          * netmap's kring->nr_hwcur (pidx counts descriptors and the relation
856          * between descriptors and frames isn't 1:1).
857          */
858
859         npkt_remaining = head >= kring->nr_hwcur ? head - kring->nr_hwcur :
860             kring->nkr_num_slots - kring->nr_hwcur + head;
861         txcsum = ifp->if_capenable & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6);
862         while (npkt_remaining) {
863                 reclaimed += reclaim_nm_tx_desc(nm_txq);
864                 ndesc_remaining = contiguous_ndesc_available(nm_txq);
865                 /* Can't run out of descriptors with packets still remaining */
866                 MPASS(ndesc_remaining > 0);
867
868                 /* # of desc needed to tx all remaining packets */
869                 d = (npkt_remaining / MAX_NPKT_IN_TYPE1_WR) * SGE_MAX_WR_NDESC;
870                 if (npkt_remaining % MAX_NPKT_IN_TYPE1_WR)
871                         d += npkt_to_ndesc(npkt_remaining % MAX_NPKT_IN_TYPE1_WR);
872
873                 if (d <= ndesc_remaining)
874                         n = npkt_remaining;
875                 else {
876                         /* Can't send all, calculate how many can be sent */
877                         n = (ndesc_remaining / SGE_MAX_WR_NDESC) *
878                             MAX_NPKT_IN_TYPE1_WR;
879                         if (ndesc_remaining % SGE_MAX_WR_NDESC)
880                                 n += ndesc_to_npkt(ndesc_remaining % SGE_MAX_WR_NDESC);
881                 }
882
883                 /* Send n packets and update nm_txq->pidx and kring->nr_hwcur */
884                 npkt_remaining -= n;
885                 cxgbe_nm_tx(sc, nm_txq, kring, n, npkt_remaining, txcsum);
886         }
887         MPASS(npkt_remaining == 0);
888         MPASS(kring->nr_hwcur == head);
889         MPASS(nm_txq->dbidx == nm_txq->pidx);
890
891         /*
892          * Second part: reclaim buffers for completed transmissions.
893          */
894         if (reclaimed || flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
895                 reclaimed += reclaim_nm_tx_desc(nm_txq);
896                 kring->nr_hwtail += reclaimed;
897                 if (kring->nr_hwtail >= kring->nkr_num_slots)
898                         kring->nr_hwtail -= kring->nkr_num_slots;
899         }
900
901         nm_txsync_finalize(kring);
902
903         return (0);
904 }
905
906 static int
907 cxgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
908 {
909         struct netmap_adapter *na = kring->na;
910         struct netmap_ring *ring = kring->ring;
911         struct ifnet *ifp = na->ifp;
912         struct port_info *pi = ifp->if_softc;
913         struct adapter *sc = pi->adapter;
914         struct sge_nm_rxq *nm_rxq = &sc->sge.nm_rxq[pi->first_nm_rxq + kring->ring_id];
915         u_int const head = nm_rxsync_prologue(kring);
916         u_int n;
917         int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
918
919         if (netmap_no_pendintr || force_update) {
920                 kring->nr_hwtail = atomic_load_acq_32(&nm_rxq->fl_cidx);
921                 kring->nr_kflags &= ~NKR_PENDINTR;
922         }
923
924         /* Userspace done with buffers from kring->nr_hwcur to head */
925         n = head >= kring->nr_hwcur ? head - kring->nr_hwcur :
926             kring->nkr_num_slots - kring->nr_hwcur + head;
927         n &= ~7U;
928         if (n > 0) {
929                 u_int fl_pidx = nm_rxq->fl_pidx;
930                 struct netmap_slot *slot = &ring->slot[fl_pidx];
931                 uint64_t ba;
932                 int i, dbinc = 0, hwidx = nm_rxq->fl_hwidx;
933
934                 /*
935                  * We always deal with 8 buffers at a time.  We must have
936                  * stopped at an 8B boundary (fl_pidx) last time around and we
937                  * must have a multiple of 8B buffers to give to the freelist.
938                  */
939                 MPASS((fl_pidx & 7) == 0);
940                 MPASS((n & 7) == 0);
941
942                 IDXINCR(kring->nr_hwcur, n, kring->nkr_num_slots);
943                 IDXINCR(nm_rxq->fl_pidx, n, nm_rxq->fl_sidx);
944
945                 while (n > 0) {
946                         for (i = 0; i < 8; i++, fl_pidx++, slot++) {
947                                 PNMB(na, slot, &ba);
948                                 MPASS(ba != 0);
949                                 nm_rxq->fl_desc[fl_pidx] = htobe64(ba | hwidx);
950                                 slot->flags &= ~NS_BUF_CHANGED;
951                                 MPASS(fl_pidx <= nm_rxq->fl_sidx);
952                         }
953                         n -= 8;
954                         if (fl_pidx == nm_rxq->fl_sidx) {
955                                 fl_pidx = 0;
956                                 slot = &ring->slot[0];
957                         }
958                         if (++dbinc == 8 && n >= 32) {
959                                 wmb();
960                                 t4_write_reg(sc, MYPF_REG(A_SGE_PF_KDOORBELL),
961                                     nm_rxq->fl_db_val | V_PIDX(dbinc));
962                                 dbinc = 0;
963                         }
964                 }
965                 MPASS(nm_rxq->fl_pidx == fl_pidx);
966
967                 if (dbinc > 0) {
968                         wmb();
969                         t4_write_reg(sc, MYPF_REG(A_SGE_PF_KDOORBELL),
970                             nm_rxq->fl_db_val | V_PIDX(dbinc));
971                 }
972         }
973
974         nm_rxsync_finalize(kring);
975
976         return (0);
977 }
978
979 /*
980  * Create an ifnet solely for netmap use and register it with the kernel.
981  */
982 int
983 create_netmap_ifnet(struct port_info *pi)
984 {
985         struct adapter *sc = pi->adapter;
986         struct netmap_adapter na;
987         struct ifnet *ifp;
988         device_t dev = pi->dev;
989         uint8_t mac[ETHER_ADDR_LEN];
990         int rc;
991
992         if (pi->nnmtxq <= 0 || pi->nnmrxq <= 0)
993                 return (0);
994         MPASS(pi->nm_ifp == NULL);
995
996         /*
997          * Allocate a virtual interface exclusively for netmap use.  Give it the
998          * MAC address normally reserved for use by a TOE interface.  (The TOE
999          * driver on FreeBSD doesn't use it).
1000          */
1001         rc = t4_alloc_vi_func(sc, sc->mbox, pi->tx_chan, sc->pf, 0, 1, &mac[0],
1002             &pi->nm_rss_size, FW_VI_FUNC_OFLD, 0);
1003         if (rc < 0) {
1004                 device_printf(dev, "unable to allocate netmap virtual "
1005                     "interface for port %d: %d\n", pi->port_id, -rc);
1006                 return (-rc);
1007         }
1008         pi->nm_viid = rc;
1009         pi->nm_xact_addr_filt = -1;
1010
1011         ifp = if_alloc(IFT_ETHER);
1012         if (ifp == NULL) {
1013                 device_printf(dev, "Cannot allocate netmap ifnet\n");
1014                 return (ENOMEM);
1015         }
1016         pi->nm_ifp = ifp;
1017         ifp->if_softc = pi;
1018
1019         if_initname(ifp, is_t4(pi->adapter) ? "ncxgbe" : "ncxl",
1020             device_get_unit(dev));
1021         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1022
1023         ifp->if_init = cxgbe_nm_init;
1024         ifp->if_ioctl = cxgbe_nm_ioctl;
1025         ifp->if_transmit = cxgbe_nm_transmit;
1026         ifp->if_qflush = cxgbe_nm_qflush;
1027
1028         /*
1029          * netmap(4) says "netmap does not use features such as checksum
1030          * offloading, TCP segmentation offloading, encryption, VLAN
1031          * encapsulation/decapsulation, etc."
1032          *
1033          * By default we comply with the statement above.  But we do declare the
1034          * ifnet capable of L3/L4 checksumming so that a user can override
1035          * netmap and have the hardware do the L3/L4 checksums.
1036          */
1037         ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_JUMBO_MTU |
1038             IFCAP_HWCSUM_IPV6;
1039         ifp->if_capenable = 0;
1040         ifp->if_hwassist = 0;
1041
1042         /* nm_media has already been setup by the caller */
1043
1044         ether_ifattach(ifp, mac);
1045
1046         /*
1047          * Register with netmap in the kernel.
1048          */
1049         bzero(&na, sizeof(na));
1050
1051         na.ifp = pi->nm_ifp;
1052         na.na_flags = NAF_BDG_MAYSLEEP;
1053
1054         /* Netmap doesn't know about the space reserved for the status page. */
1055         na.num_tx_desc = pi->qsize_txq - spg_len / EQ_ESIZE;
1056
1057         /*
1058          * The freelist's cidx/pidx drives netmap's rx cidx/pidx.  So
1059          * num_rx_desc is based on the number of buffers that can be held in the
1060          * freelist, and not the number of entries in the iq.  (These two are
1061          * not exactly the same due to the space taken up by the status page).
1062          */
1063         na.num_rx_desc = (pi->qsize_rxq / 8) * 8;
1064         na.nm_txsync = cxgbe_netmap_txsync;
1065         na.nm_rxsync = cxgbe_netmap_rxsync;
1066         na.nm_register = cxgbe_netmap_reg;
1067         na.num_tx_rings = pi->nnmtxq;
1068         na.num_rx_rings = pi->nnmrxq;
1069         netmap_attach(&na);     /* This adds IFCAP_NETMAP to if_capabilities */
1070
1071         return (0);
1072 }
1073
1074 int
1075 destroy_netmap_ifnet(struct port_info *pi)
1076 {
1077         struct adapter *sc = pi->adapter;
1078
1079         if (pi->nm_ifp == NULL)
1080                 return (0);
1081
1082         netmap_detach(pi->nm_ifp);
1083         ifmedia_removeall(&pi->nm_media);
1084         ether_ifdetach(pi->nm_ifp);
1085         if_free(pi->nm_ifp);
1086         t4_free_vi(sc, sc->mbox, sc->pf, 0, pi->nm_viid);
1087
1088         return (0);
1089 }
1090
1091 static void
1092 handle_nm_fw6_msg(struct adapter *sc, struct ifnet *ifp,
1093     const struct cpl_fw6_msg *cpl)
1094 {
1095         const struct cpl_sge_egr_update *egr;
1096         uint32_t oq;
1097         struct sge_nm_txq *nm_txq;
1098
1099         if (cpl->type != FW_TYPE_RSSCPL && cpl->type != FW6_TYPE_RSSCPL)
1100                 panic("%s: FW_TYPE 0x%x on nm_rxq.", __func__, cpl->type);
1101
1102         /* data[0] is RSS header */
1103         egr = (const void *)&cpl->data[1];
1104         oq = be32toh(egr->opcode_qid);
1105         MPASS(G_CPL_OPCODE(oq) == CPL_SGE_EGR_UPDATE);
1106         nm_txq = (void *)sc->sge.eqmap[G_EGR_QID(oq) - sc->sge.eq_start];
1107
1108         netmap_tx_irq(ifp, nm_txq->nid);
1109 }
1110
1111 void
1112 t4_nm_intr(void *arg)
1113 {
1114         struct sge_nm_rxq *nm_rxq = arg;
1115         struct port_info *pi = nm_rxq->pi;
1116         struct adapter *sc = pi->adapter;
1117         struct ifnet *ifp = pi->nm_ifp;
1118         struct netmap_adapter *na = NA(ifp);
1119         struct netmap_kring *kring = &na->rx_rings[nm_rxq->nid];
1120         struct netmap_ring *ring = kring->ring;
1121         struct iq_desc *d = &nm_rxq->iq_desc[nm_rxq->iq_cidx];
1122         uint32_t lq;
1123         u_int n = 0, work = 0;
1124         uint8_t opcode;
1125         uint32_t fl_cidx = atomic_load_acq_32(&nm_rxq->fl_cidx);
1126
1127         while ((d->rsp.u.type_gen & F_RSPD_GEN) == nm_rxq->iq_gen) {
1128
1129                 rmb();
1130
1131                 lq = be32toh(d->rsp.pldbuflen_qid);
1132                 opcode = d->rss.opcode;
1133
1134                 switch (G_RSPD_TYPE(d->rsp.u.type_gen)) {
1135                 case X_RSPD_TYPE_FLBUF:
1136                         /* No buffer packing so new buf every time */
1137                         MPASS(lq & F_RSPD_NEWBUF);
1138
1139                         /* fall through */
1140
1141                 case X_RSPD_TYPE_CPL:
1142                         MPASS(opcode < NUM_CPL_CMDS);
1143
1144                         switch (opcode) {
1145                         case CPL_FW4_MSG:
1146                         case CPL_FW6_MSG:
1147                                 handle_nm_fw6_msg(sc, ifp,
1148                                     (const void *)&d->cpl[0]);
1149                                 break;
1150                         case CPL_RX_PKT:
1151                                 ring->slot[fl_cidx].len = G_RSPD_LEN(lq) - fl_pktshift;
1152                                 ring->slot[fl_cidx].flags = kring->nkr_slot_flags;
1153                                 if (__predict_false(++fl_cidx == nm_rxq->fl_sidx))
1154                                         fl_cidx = 0;
1155                                 break;
1156                         default:
1157                                 panic("%s: unexpected opcode 0x%x on nm_rxq %p",
1158                                     __func__, opcode, nm_rxq);
1159                         }
1160                         break;
1161
1162                 case X_RSPD_TYPE_INTR:
1163                         /* Not equipped to handle forwarded interrupts. */
1164                         panic("%s: netmap queue received interrupt for iq %u\n",
1165                             __func__, lq);
1166
1167                 default:
1168                         panic("%s: illegal response type %d on nm_rxq %p",
1169                             __func__, G_RSPD_TYPE(d->rsp.u.type_gen), nm_rxq);
1170                 }
1171
1172                 d++;
1173                 if (__predict_false(++nm_rxq->iq_cidx == nm_rxq->iq_sidx)) {
1174                         nm_rxq->iq_cidx = 0;
1175                         d = &nm_rxq->iq_desc[0];
1176                         nm_rxq->iq_gen ^= F_RSPD_GEN;
1177                 }
1178
1179                 if (__predict_false(++n == rx_ndesc)) {
1180                         atomic_store_rel_32(&nm_rxq->fl_cidx, fl_cidx);
1181                         netmap_rx_irq(ifp, nm_rxq->nid, &work);
1182                         MPASS(work != 0);
1183                         t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS),
1184                             V_CIDXINC(n) | V_INGRESSQID(nm_rxq->iq_cntxt_id) |
1185                             V_SEINTARM(V_QINTR_TIMER_IDX(X_TIMERREG_UPDATE_CIDX)));
1186                         n = 0;
1187                 }
1188         }
1189         if (fl_cidx != nm_rxq->fl_cidx) {
1190                 atomic_store_rel_32(&nm_rxq->fl_cidx, fl_cidx);
1191                 netmap_rx_irq(ifp, nm_rxq->nid, &work);
1192         }
1193         t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS), V_CIDXINC(n) |
1194             V_INGRESSQID((u32)nm_rxq->iq_cntxt_id) |
1195             V_SEINTARM(V_QINTR_TIMER_IDX(holdoff_tmr_idx)));
1196 }
1197 #endif