]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/netmap/netmap_pt.c
Update tcpdump to 4.9.0.
[FreeBSD/FreeBSD.git] / sys / dev / netmap / netmap_pt.c
1 /*
2  * Copyright (C) 2015 Stefano Garzarella
3  * Copyright (C) 2016 Vincenzo Maffione
4  * All rights reserved.
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  * $FreeBSD$
28  */
29
30 /*
31  * common headers
32  */
33 #if defined(__FreeBSD__)
34 #include <sys/cdefs.h>
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/types.h>
38 #include <sys/selinfo.h>
39 #include <sys/socket.h>
40 #include <net/if.h>
41 #include <net/if_var.h>
42 #include <machine/bus.h>
43
44 //#define usleep_range(_1, _2)
45 #define usleep_range(_1, _2) \
46         pause_sbt("ptnetmap-sleep", SBT_1US * _1, SBT_1US * 1, C_ABSOLUTE)
47
48 #elif defined(linux)
49 #include <bsd_glue.h>
50 #endif
51
52 #include <net/netmap.h>
53 #include <dev/netmap/netmap_kern.h>
54 #include <net/netmap_virt.h>
55 #include <dev/netmap/netmap_mem2.h>
56
57 #ifdef WITH_PTNETMAP_HOST
58
59 /* RX cycle without receive any packets */
60 #define PTN_RX_DRY_CYCLES_MAX   10
61
62 /* Limit Batch TX to half ring.
63  * Currently disabled, since it does not manage NS_MOREFRAG, which
64  * results in random drops in the VALE txsync. */
65 //#define PTN_TX_BATCH_LIM(_n)  ((_n >> 1))
66
67 //#define BUSY_WAIT
68
69 #define NETMAP_PT_DEBUG  /* Enables communication debugging. */
70 #ifdef NETMAP_PT_DEBUG
71 #define DBG(x) x
72 #else
73 #define DBG(x)
74 #endif
75
76
77 #undef RATE
78 //#define RATE  /* Enables communication statistics. */
79 #ifdef RATE
80 #define IFRATE(x) x
81 struct rate_batch_stats {
82     unsigned long sync;
83     unsigned long sync_dry;
84     unsigned long pkt;
85 };
86
87 struct rate_stats {
88     unsigned long gtxk;     /* Guest --> Host Tx kicks. */
89     unsigned long grxk;     /* Guest --> Host Rx kicks. */
90     unsigned long htxk;     /* Host --> Guest Tx kicks. */
91     unsigned long hrxk;     /* Host --> Guest Rx Kicks. */
92     unsigned long btxwu;    /* Backend Tx wake-up. */
93     unsigned long brxwu;    /* Backend Rx wake-up. */
94     struct rate_batch_stats txbs;
95     struct rate_batch_stats rxbs;
96 };
97
98 struct rate_context {
99     struct timer_list timer;
100     struct rate_stats new;
101     struct rate_stats old;
102 };
103
104 #define RATE_PERIOD  2
105 static void
106 rate_callback(unsigned long arg)
107 {
108     struct rate_context * ctx = (struct rate_context *)arg;
109     struct rate_stats cur = ctx->new;
110     struct rate_batch_stats *txbs = &cur.txbs;
111     struct rate_batch_stats *rxbs = &cur.rxbs;
112     struct rate_batch_stats *txbs_old = &ctx->old.txbs;
113     struct rate_batch_stats *rxbs_old = &ctx->old.rxbs;
114     uint64_t tx_batch, rx_batch;
115     unsigned long txpkts, rxpkts;
116     unsigned long gtxk, grxk;
117     int r;
118
119     txpkts = txbs->pkt - txbs_old->pkt;
120     rxpkts = rxbs->pkt - rxbs_old->pkt;
121
122     tx_batch = ((txbs->sync - txbs_old->sync) > 0) ?
123                txpkts / (txbs->sync - txbs_old->sync): 0;
124     rx_batch = ((rxbs->sync - rxbs_old->sync) > 0) ?
125                rxpkts / (rxbs->sync - rxbs_old->sync): 0;
126
127     /* Fix-up gtxk and grxk estimates. */
128     gtxk = (cur.gtxk - ctx->old.gtxk) - (cur.btxwu - ctx->old.btxwu);
129     grxk = (cur.grxk - ctx->old.grxk) - (cur.brxwu - ctx->old.brxwu);
130
131     printk("txpkts  = %lu Hz\n", txpkts/RATE_PERIOD);
132     printk("gtxk    = %lu Hz\n", gtxk/RATE_PERIOD);
133     printk("htxk    = %lu Hz\n", (cur.htxk - ctx->old.htxk)/RATE_PERIOD);
134     printk("btxw    = %lu Hz\n", (cur.btxwu - ctx->old.btxwu)/RATE_PERIOD);
135     printk("rxpkts  = %lu Hz\n", rxpkts/RATE_PERIOD);
136     printk("grxk    = %lu Hz\n", grxk/RATE_PERIOD);
137     printk("hrxk    = %lu Hz\n", (cur.hrxk - ctx->old.hrxk)/RATE_PERIOD);
138     printk("brxw    = %lu Hz\n", (cur.brxwu - ctx->old.brxwu)/RATE_PERIOD);
139     printk("txbatch = %llu avg\n", tx_batch);
140     printk("rxbatch = %llu avg\n", rx_batch);
141     printk("\n");
142
143     ctx->old = cur;
144     r = mod_timer(&ctx->timer, jiffies +
145             msecs_to_jiffies(RATE_PERIOD * 1000));
146     if (unlikely(r))
147         D("[ptnetmap] Error: mod_timer()\n");
148 }
149
150 static void
151 rate_batch_stats_update(struct rate_batch_stats *bf, uint32_t pre_tail,
152                         uint32_t act_tail, uint32_t num_slots)
153 {
154     int n = (int)act_tail - pre_tail;
155
156     if (n) {
157         if (n < 0)
158             n += num_slots;
159
160         bf->sync++;
161         bf->pkt += n;
162     } else {
163         bf->sync_dry++;
164     }
165 }
166
167 #else /* !RATE */
168 #define IFRATE(x)
169 #endif /* RATE */
170
171 struct ptnetmap_state {
172     /* Kthreads. */
173     struct nm_kthread **kthreads;
174
175     /* Shared memory with the guest (TX/RX) */
176     struct ptnet_ring __user *ptrings;
177
178     bool stopped;
179
180     /* Netmap adapter wrapping the backend. */
181     struct netmap_pt_host_adapter *pth_na;
182
183     IFRATE(struct rate_context rate_ctx;)
184 };
185
186 static inline void
187 ptnetmap_kring_dump(const char *title, const struct netmap_kring *kring)
188 {
189     RD(1, "%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d \
190                     rtail: %d head: %d cur: %d tail: %d",
191             title, kring->name, kring->nr_hwcur,
192             kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail,
193             kring->ring->head, kring->ring->cur, kring->ring->tail);
194 }
195
196 /*
197  * TX functions to set/get and to handle host/guest kick.
198  */
199
200
201 /* Enable or disable guest --> host kicks. */
202 static inline void
203 ptring_kick_enable(struct ptnet_ring __user *ptring, uint32_t val)
204 {
205     CSB_WRITE(ptring, host_need_kick, val);
206 }
207
208 /* Are guest interrupt enabled or disabled? */
209 static inline uint32_t
210 ptring_intr_enabled(struct ptnet_ring __user *ptring)
211 {
212     uint32_t v;
213
214     CSB_READ(ptring, guest_need_kick, v);
215
216     return v;
217 }
218
219 /* Enable or disable guest interrupts. */
220 static inline void
221 ptring_intr_enable(struct ptnet_ring __user *ptring, uint32_t val)
222 {
223     CSB_WRITE(ptring, guest_need_kick, val);
224 }
225
226 /* Handle TX events: from the guest or from the backend */
227 static void
228 ptnetmap_tx_handler(void *data)
229 {
230     struct netmap_kring *kring = data;
231     struct netmap_pt_host_adapter *pth_na =
232                 (struct netmap_pt_host_adapter *)kring->na->na_private;
233     struct ptnetmap_state *ptns = pth_na->ptns;
234     struct ptnet_ring __user *ptring;
235     struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
236     bool more_txspace = false;
237     struct nm_kthread *kth;
238     uint32_t num_slots;
239     int batch;
240     IFRATE(uint32_t pre_tail);
241
242     if (unlikely(!ptns)) {
243         D("ERROR ptnetmap state is NULL");
244         return;
245     }
246
247     if (unlikely(ptns->stopped)) {
248         RD(1, "backend netmap is being stopped");
249         return;
250     }
251
252     if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
253         D("ERROR nm_kr_tryget()");
254         return;
255     }
256
257     /* This is a guess, to be fixed in the rate callback. */
258     IFRATE(ptns->rate_ctx.new.gtxk++);
259
260     /* Get TX ptring pointer from the CSB. */
261     ptring = ptns->ptrings + kring->ring_id;
262     kth = ptns->kthreads[kring->ring_id];
263
264     num_slots = kring->nkr_num_slots;
265     shadow_ring.head = kring->rhead;
266     shadow_ring.cur = kring->rcur;
267
268     /* Disable guest --> host notifications. */
269     ptring_kick_enable(ptring, 0);
270     /* Copy the guest kring pointers from the CSB */
271     ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
272
273     for (;;) {
274         /* If guest moves ahead too fast, let's cut the move so
275          * that we don't exceed our batch limit. */
276         batch = shadow_ring.head - kring->nr_hwcur;
277         if (batch < 0)
278             batch += num_slots;
279
280 #ifdef PTN_TX_BATCH_LIM
281         if (batch > PTN_TX_BATCH_LIM(num_slots)) {
282             uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
283
284             if (head_lim >= num_slots)
285                 head_lim -= num_slots;
286             ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
287                                                      head_lim);
288             shadow_ring.head = head_lim;
289             batch = PTN_TX_BATCH_LIM(num_slots);
290         }
291 #endif /* PTN_TX_BATCH_LIM */
292
293         if (nm_kr_txspace(kring) <= (num_slots >> 1)) {
294             shadow_ring.flags |= NAF_FORCE_RECLAIM;
295         }
296
297         /* Netmap prologue */
298         shadow_ring.tail = kring->rtail;
299         if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
300             /* Reinit ring and enable notifications. */
301             netmap_ring_reinit(kring);
302             ptring_kick_enable(ptring, 1);
303             break;
304         }
305
306         if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
307             ptnetmap_kring_dump("pre txsync", kring);
308         }
309
310         IFRATE(pre_tail = kring->rtail);
311         if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
312             /* Reenable notifications. */
313             ptring_kick_enable(ptring, 1);
314             D("ERROR txsync()");
315             break;
316         }
317
318         /*
319          * Finalize
320          * Copy host hwcur and hwtail into the CSB for the guest sync(), and
321          * do the nm_sync_finalize.
322          */
323         ptnetmap_host_write_kring_csb(ptring, kring->nr_hwcur,
324                                       kring->nr_hwtail);
325         if (kring->rtail != kring->nr_hwtail) {
326             /* Some more room available in the parent adapter. */
327             kring->rtail = kring->nr_hwtail;
328             more_txspace = true;
329         }
330
331         IFRATE(rate_batch_stats_update(&ptns->rate_ctx.new.txbs, pre_tail,
332                                        kring->rtail, num_slots));
333
334         if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
335             ptnetmap_kring_dump("post txsync", kring);
336         }
337
338 #ifndef BUSY_WAIT
339         /* Interrupt the guest if needed. */
340         if (more_txspace && ptring_intr_enabled(ptring)) {
341             /* Disable guest kick to avoid sending unnecessary kicks */
342             ptring_intr_enable(ptring, 0);
343             nm_os_kthread_send_irq(kth);
344             IFRATE(ptns->rate_ctx.new.htxk++);
345             more_txspace = false;
346         }
347 #endif
348         /* Read CSB to see if there is more work to do. */
349         ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
350 #ifndef BUSY_WAIT
351         if (shadow_ring.head == kring->rhead) {
352             /*
353              * No more packets to transmit. We enable notifications and
354              * go to sleep, waiting for a kick from the guest when new
355              * new slots are ready for transmission.
356              */
357             usleep_range(1,1);
358             /* Reenable notifications. */
359             ptring_kick_enable(ptring, 1);
360             /* Doublecheck. */
361             ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
362             if (shadow_ring.head != kring->rhead) {
363                 /* We won the race condition, there are more packets to
364                  * transmit. Disable notifications and do another cycle */
365                 ptring_kick_enable(ptring, 0);
366                 continue;
367             }
368             break;
369         }
370
371         if (nm_kr_txempty(kring)) {
372             /* No more available TX slots. We stop waiting for a notification
373              * from the backend (netmap_tx_irq). */
374             ND(1, "TX ring");
375             break;
376         }
377 #endif
378         if (unlikely(ptns->stopped)) {
379             D("backend netmap is being stopped");
380             break;
381         }
382     }
383
384     nm_kr_put(kring);
385
386     if (more_txspace && ptring_intr_enabled(ptring)) {
387         ptring_intr_enable(ptring, 0);
388         nm_os_kthread_send_irq(kth);
389         IFRATE(ptns->rate_ctx.new.htxk++);
390     }
391 }
392
393 /*
394  * We need RX kicks from the guest when (tail == head-1), where we wait
395  * for the guest to refill.
396  */
397 #ifndef BUSY_WAIT
398 static inline int
399 ptnetmap_norxslots(struct netmap_kring *kring, uint32_t g_head)
400 {
401     return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
402                             kring->nkr_num_slots - 1));
403 }
404 #endif /* !BUSY_WAIT */
405
406 /* Handle RX events: from the guest or from the backend */
407 static void
408 ptnetmap_rx_handler(void *data)
409 {
410     struct netmap_kring *kring = data;
411     struct netmap_pt_host_adapter *pth_na =
412                 (struct netmap_pt_host_adapter *)kring->na->na_private;
413     struct ptnetmap_state *ptns = pth_na->ptns;
414     struct ptnet_ring __user *ptring;
415     struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
416     struct nm_kthread *kth;
417     uint32_t num_slots;
418     int dry_cycles = 0;
419     bool some_recvd = false;
420     IFRATE(uint32_t pre_tail);
421
422     if (unlikely(!ptns || !ptns->pth_na)) {
423         D("ERROR ptnetmap state %p, ptnetmap host adapter %p", ptns,
424           ptns ? ptns->pth_na : NULL);
425         return;
426     }
427
428     if (unlikely(ptns->stopped)) {
429         RD(1, "backend netmap is being stopped");
430         return;
431     }
432
433     if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
434         D("ERROR nm_kr_tryget()");
435         return;
436     }
437
438     /* This is a guess, to be fixed in the rate callback. */
439     IFRATE(ptns->rate_ctx.new.grxk++);
440
441     /* Get RX ptring pointer from the CSB. */
442     ptring = ptns->ptrings + (pth_na->up.num_tx_rings + kring->ring_id);
443     kth = ptns->kthreads[pth_na->up.num_tx_rings + kring->ring_id];
444
445     num_slots = kring->nkr_num_slots;
446     shadow_ring.head = kring->rhead;
447     shadow_ring.cur = kring->rcur;
448
449     /* Disable notifications. */
450     ptring_kick_enable(ptring, 0);
451     /* Copy the guest kring pointers from the CSB */
452     ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
453
454     for (;;) {
455         uint32_t hwtail;
456
457         /* Netmap prologue */
458         shadow_ring.tail = kring->rtail;
459         if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
460             /* Reinit ring and enable notifications. */
461             netmap_ring_reinit(kring);
462             ptring_kick_enable(ptring, 1);
463             break;
464         }
465
466         if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
467             ptnetmap_kring_dump("pre rxsync", kring);
468         }
469
470         IFRATE(pre_tail = kring->rtail);
471         if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
472             /* Reenable notifications. */
473             ptring_kick_enable(ptring, 1);
474             D("ERROR rxsync()");
475             break;
476         }
477         /*
478          * Finalize
479          * Copy host hwcur and hwtail into the CSB for the guest sync()
480          */
481         hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
482         ptnetmap_host_write_kring_csb(ptring, kring->nr_hwcur, hwtail);
483         if (kring->rtail != hwtail) {
484             kring->rtail = hwtail;
485             some_recvd = true;
486             dry_cycles = 0;
487         } else {
488             dry_cycles++;
489         }
490
491         IFRATE(rate_batch_stats_update(&ptns->rate_ctx.new.rxbs, pre_tail,
492                                        kring->rtail, num_slots));
493
494         if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
495             ptnetmap_kring_dump("post rxsync", kring);
496         }
497
498 #ifndef BUSY_WAIT
499         /* Interrupt the guest if needed. */
500         if (some_recvd && ptring_intr_enabled(ptring)) {
501             /* Disable guest kick to avoid sending unnecessary kicks */
502             ptring_intr_enable(ptring, 0);
503             nm_os_kthread_send_irq(kth);
504             IFRATE(ptns->rate_ctx.new.hrxk++);
505             some_recvd = false;
506         }
507 #endif
508         /* Read CSB to see if there is more work to do. */
509         ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
510 #ifndef BUSY_WAIT
511         if (ptnetmap_norxslots(kring, shadow_ring.head)) {
512             /*
513              * No more slots available for reception. We enable notification and
514              * go to sleep, waiting for a kick from the guest when new receive
515              * slots are available.
516              */
517             usleep_range(1,1);
518             /* Reenable notifications. */
519             ptring_kick_enable(ptring, 1);
520             /* Doublecheck. */
521             ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
522             if (!ptnetmap_norxslots(kring, shadow_ring.head)) {
523                 /* We won the race condition, more slots are available. Disable
524                  * notifications and do another cycle. */
525                 ptring_kick_enable(ptring, 0);
526                 continue;
527             }
528             break;
529         }
530
531         hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
532         if (unlikely(hwtail == kring->rhead ||
533                      dry_cycles >= PTN_RX_DRY_CYCLES_MAX)) {
534             /* No more packets to be read from the backend. We stop and
535              * wait for a notification from the backend (netmap_rx_irq). */
536             ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
537                hwtail, kring->rhead, dry_cycles);
538             break;
539         }
540 #endif
541         if (unlikely(ptns->stopped)) {
542             D("backend netmap is being stopped");
543             break;
544         }
545     }
546
547     nm_kr_put(kring);
548
549     /* Interrupt the guest if needed. */
550     if (some_recvd && ptring_intr_enabled(ptring)) {
551         ptring_intr_enable(ptring, 0);
552         nm_os_kthread_send_irq(kth);
553         IFRATE(ptns->rate_ctx.new.hrxk++);
554     }
555 }
556
557 #ifdef NETMAP_PT_DEBUG
558 static void
559 ptnetmap_print_configuration(struct ptnetmap_cfg *cfg)
560 {
561         int k;
562
563         D("ptnetmap configuration:");
564         D("  CSB ptrings @%p, num_rings=%u, cfgtype %08x", cfg->ptrings,
565           cfg->num_rings, cfg->cfgtype);
566         for (k = 0; k < cfg->num_rings; k++) {
567                 switch (cfg->cfgtype) {
568                 case PTNETMAP_CFGTYPE_QEMU: {
569                         struct ptnetmap_cfgentry_qemu *e =
570                                 (struct ptnetmap_cfgentry_qemu *)(cfg+1) + k;
571                         D("    ring #%d: ioeventfd=%lu, irqfd=%lu", k,
572                                 (unsigned long)e->ioeventfd,
573                                 (unsigned long)e->irqfd);
574                         break;
575                 }
576
577                 case PTNETMAP_CFGTYPE_BHYVE:
578                 {
579                         struct ptnetmap_cfgentry_bhyve *e =
580                                 (struct ptnetmap_cfgentry_bhyve *)(cfg+1) + k;
581                         D("    ring #%d: wchan=%lu, ioctl_fd=%lu, "
582                           "ioctl_cmd=%lu, msix_msg_data=%lu, msix_addr=%lu",
583                                 k, (unsigned long)e->wchan,
584                                 (unsigned long)e->ioctl_fd,
585                                 (unsigned long)e->ioctl_cmd,
586                                 (unsigned long)e->ioctl_data.msg_data,
587                                 (unsigned long)e->ioctl_data.addr);
588                         break;
589                 }
590                 }
591         }
592
593 }
594 #endif /* NETMAP_PT_DEBUG */
595
596 /* Copy actual state of the host ring into the CSB for the guest init */
597 static int
598 ptnetmap_kring_snapshot(struct netmap_kring *kring, struct ptnet_ring __user *ptring)
599 {
600     if(CSB_WRITE(ptring, head, kring->rhead))
601         goto err;
602     if(CSB_WRITE(ptring, cur, kring->rcur))
603         goto err;
604
605     if(CSB_WRITE(ptring, hwcur, kring->nr_hwcur))
606         goto err;
607     if(CSB_WRITE(ptring, hwtail, NM_ACCESS_ONCE(kring->nr_hwtail)))
608         goto err;
609
610     DBG(ptnetmap_kring_dump("ptnetmap_kring_snapshot", kring);)
611
612     return 0;
613 err:
614     return EFAULT;
615 }
616
617 static struct netmap_kring *
618 ptnetmap_kring(struct netmap_pt_host_adapter *pth_na, int k)
619 {
620         if (k < pth_na->up.num_tx_rings) {
621                 return pth_na->up.tx_rings + k;
622         }
623         return pth_na->up.rx_rings + k - pth_na->up.num_tx_rings;
624 }
625
626 static int
627 ptnetmap_krings_snapshot(struct netmap_pt_host_adapter *pth_na)
628 {
629         struct ptnetmap_state *ptns = pth_na->ptns;
630         struct netmap_kring *kring;
631         unsigned int num_rings;
632         int err = 0, k;
633
634         num_rings = pth_na->up.num_tx_rings +
635                     pth_na->up.num_rx_rings;
636
637         for (k = 0; k < num_rings; k++) {
638                 kring = ptnetmap_kring(pth_na, k);
639                 err |= ptnetmap_kring_snapshot(kring, ptns->ptrings + k);
640         }
641
642         return err;
643 }
644
645 /*
646  * Functions to create, start and stop the kthreads
647  */
648
649 static int
650 ptnetmap_create_kthreads(struct netmap_pt_host_adapter *pth_na,
651                          struct ptnetmap_cfg *cfg)
652 {
653         struct ptnetmap_state *ptns = pth_na->ptns;
654         struct nm_kthread_cfg nmk_cfg;
655         unsigned int num_rings;
656         uint8_t *cfg_entries = (uint8_t *)(cfg + 1);
657         int k;
658
659         num_rings = pth_na->up.num_tx_rings +
660                     pth_na->up.num_rx_rings;
661
662         for (k = 0; k < num_rings; k++) {
663                 nmk_cfg.attach_user = 1; /* attach kthread to user process */
664                 nmk_cfg.worker_private = ptnetmap_kring(pth_na, k);
665                 nmk_cfg.type = k;
666                 if (k < pth_na->up.num_tx_rings) {
667                         nmk_cfg.worker_fn = ptnetmap_tx_handler;
668                 } else {
669                         nmk_cfg.worker_fn = ptnetmap_rx_handler;
670                 }
671
672                 ptns->kthreads[k] = nm_os_kthread_create(&nmk_cfg,
673                         cfg->cfgtype, cfg_entries + k * cfg->entry_size);
674                 if (ptns->kthreads[k] == NULL) {
675                         goto err;
676                 }
677         }
678
679         return 0;
680 err:
681         for (k = 0; k < num_rings; k++) {
682                 if (ptns->kthreads[k]) {
683                         nm_os_kthread_delete(ptns->kthreads[k]);
684                         ptns->kthreads[k] = NULL;
685                 }
686         }
687         return EFAULT;
688 }
689
690 static int
691 ptnetmap_start_kthreads(struct netmap_pt_host_adapter *pth_na)
692 {
693         struct ptnetmap_state *ptns = pth_na->ptns;
694         int num_rings;
695         int error;
696         int k;
697
698         if (!ptns) {
699                 D("BUG ptns is NULL");
700                 return EFAULT;
701         }
702
703         ptns->stopped = false;
704
705         num_rings = ptns->pth_na->up.num_tx_rings +
706                     ptns->pth_na->up.num_rx_rings;
707         for (k = 0; k < num_rings; k++) {
708                 //nm_os_kthread_set_affinity(ptns->kthreads[k], xxx);
709                 error = nm_os_kthread_start(ptns->kthreads[k]);
710                 if (error) {
711                         return error;
712                 }
713         }
714
715         return 0;
716 }
717
718 static void
719 ptnetmap_stop_kthreads(struct netmap_pt_host_adapter *pth_na)
720 {
721         struct ptnetmap_state *ptns = pth_na->ptns;
722         int num_rings;
723         int k;
724
725         if (!ptns) {
726                 /* Nothing to do. */
727                 return;
728         }
729
730         ptns->stopped = true;
731
732         num_rings = ptns->pth_na->up.num_tx_rings +
733                     ptns->pth_na->up.num_rx_rings;
734         for (k = 0; k < num_rings; k++) {
735                 nm_os_kthread_stop(ptns->kthreads[k]);
736         }
737 }
738
739 static struct ptnetmap_cfg *
740 ptnetmap_read_cfg(struct nmreq *nmr)
741 {
742         uintptr_t *nmr_ptncfg = (uintptr_t *)&nmr->nr_arg1;
743         struct ptnetmap_cfg *cfg;
744         struct ptnetmap_cfg tmp;
745         size_t cfglen;
746
747         if (copyin((const void *)*nmr_ptncfg, &tmp, sizeof(tmp))) {
748                 D("Partial copyin() failed");
749                 return NULL;
750         }
751
752         cfglen = sizeof(tmp) + tmp.num_rings * tmp.entry_size;
753         cfg = malloc(cfglen, M_DEVBUF, M_NOWAIT | M_ZERO);
754         if (!cfg) {
755                 return NULL;
756         }
757
758         if (copyin((const void *)*nmr_ptncfg, cfg, cfglen)) {
759                 D("Full copyin() failed");
760                 free(cfg, M_DEVBUF);
761                 return NULL;
762         }
763
764         return cfg;
765 }
766
767 static int nm_unused_notify(struct netmap_kring *, int);
768 static int nm_pt_host_notify(struct netmap_kring *, int);
769
770 /* Create ptnetmap state and switch parent adapter to ptnetmap mode. */
771 static int
772 ptnetmap_create(struct netmap_pt_host_adapter *pth_na,
773                 struct ptnetmap_cfg *cfg)
774 {
775     struct ptnetmap_state *ptns;
776     unsigned int num_rings;
777     int ret, i;
778
779     /* Check if ptnetmap state is already there. */
780     if (pth_na->ptns) {
781         D("ERROR adapter %p already in ptnetmap mode", pth_na->parent);
782         return EINVAL;
783     }
784
785     num_rings = pth_na->up.num_tx_rings + pth_na->up.num_rx_rings;
786
787     if (num_rings != cfg->num_rings) {
788         D("ERROR configuration mismatch, expected %u rings, found %u",
789            num_rings, cfg->num_rings);
790         return EINVAL;
791     }
792
793     ptns = malloc(sizeof(*ptns) + num_rings * sizeof(*ptns->kthreads),
794                   M_DEVBUF, M_NOWAIT | M_ZERO);
795     if (!ptns) {
796         return ENOMEM;
797     }
798
799     ptns->kthreads = (struct nm_kthread **)(ptns + 1);
800     ptns->stopped = true;
801
802     /* Cross-link data structures. */
803     pth_na->ptns = ptns;
804     ptns->pth_na = pth_na;
805
806     /* Store the CSB address provided by the hypervisor. */
807     ptns->ptrings = cfg->ptrings;
808
809     DBG(ptnetmap_print_configuration(cfg));
810
811     /* Create kthreads */
812     if ((ret = ptnetmap_create_kthreads(pth_na, cfg))) {
813         D("ERROR ptnetmap_create_kthreads()");
814         goto err;
815     }
816     /* Copy krings state into the CSB for the guest initialization */
817     if ((ret = ptnetmap_krings_snapshot(pth_na))) {
818         D("ERROR ptnetmap_krings_snapshot()");
819         goto err;
820     }
821
822     /* Overwrite parent nm_notify krings callback. */
823     pth_na->parent->na_private = pth_na;
824     pth_na->parent_nm_notify = pth_na->parent->nm_notify;
825     pth_na->parent->nm_notify = nm_unused_notify;
826
827     for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
828         pth_na->up.rx_rings[i].save_notify =
829                 pth_na->up.rx_rings[i].nm_notify;
830         pth_na->up.rx_rings[i].nm_notify = nm_pt_host_notify;
831     }
832     for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
833         pth_na->up.tx_rings[i].save_notify =
834                 pth_na->up.tx_rings[i].nm_notify;
835         pth_na->up.tx_rings[i].nm_notify = nm_pt_host_notify;
836     }
837
838 #ifdef RATE
839     memset(&ptns->rate_ctx, 0, sizeof(ptns->rate_ctx));
840     setup_timer(&ptns->rate_ctx.timer, &rate_callback,
841             (unsigned long)&ptns->rate_ctx);
842     if (mod_timer(&ptns->rate_ctx.timer, jiffies + msecs_to_jiffies(1500)))
843         D("[ptn] Error: mod_timer()\n");
844 #endif
845
846     DBG(D("[%s] ptnetmap configuration DONE", pth_na->up.name));
847
848     return 0;
849
850 err:
851     pth_na->ptns = NULL;
852     free(ptns, M_DEVBUF);
853     return ret;
854 }
855
856 /* Switch parent adapter back to normal mode and destroy
857  * ptnetmap state. */
858 static void
859 ptnetmap_delete(struct netmap_pt_host_adapter *pth_na)
860 {
861     struct ptnetmap_state *ptns = pth_na->ptns;
862     int num_rings;
863     int i;
864
865     if (!ptns) {
866         /* Nothing to do. */
867         return;
868     }
869
870     /* Restore parent adapter callbacks. */
871     pth_na->parent->nm_notify = pth_na->parent_nm_notify;
872     pth_na->parent->na_private = NULL;
873
874     for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
875         pth_na->up.rx_rings[i].nm_notify =
876                 pth_na->up.rx_rings[i].save_notify;
877         pth_na->up.rx_rings[i].save_notify = NULL;
878     }
879     for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
880         pth_na->up.tx_rings[i].nm_notify =
881                 pth_na->up.tx_rings[i].save_notify;
882         pth_na->up.tx_rings[i].save_notify = NULL;
883     }
884
885     /* Delete kthreads. */
886     num_rings = ptns->pth_na->up.num_tx_rings +
887                 ptns->pth_na->up.num_rx_rings;
888     for (i = 0; i < num_rings; i++) {
889         nm_os_kthread_delete(ptns->kthreads[i]);
890         ptns->kthreads[i] = NULL;
891     }
892
893     IFRATE(del_timer(&ptns->rate_ctx.timer));
894
895     free(ptns, M_DEVBUF);
896
897     pth_na->ptns = NULL;
898
899     DBG(D("[%s] ptnetmap deleted", pth_na->up.name));
900 }
901
902 /*
903  * Called by netmap_ioctl().
904  * Operation is indicated in nmr->nr_cmd.
905  *
906  * Called without NMG_LOCK.
907  */
908 int
909 ptnetmap_ctl(struct nmreq *nmr, struct netmap_adapter *na)
910 {
911     struct netmap_pt_host_adapter *pth_na;
912     struct ptnetmap_cfg *cfg;
913     char *name;
914     int cmd, error = 0;
915
916     name = nmr->nr_name;
917     cmd = nmr->nr_cmd;
918
919     DBG(D("name: %s", name));
920
921     if (!nm_ptnetmap_host_on(na)) {
922         D("ERROR Netmap adapter %p is not a ptnetmap host adapter", na);
923         error = ENXIO;
924         goto done;
925     }
926     pth_na = (struct netmap_pt_host_adapter *)na;
927
928     NMG_LOCK();
929     switch (cmd) {
930     case NETMAP_PT_HOST_CREATE:
931         /* Read hypervisor configuration from userspace. */
932         cfg = ptnetmap_read_cfg(nmr);
933         if (!cfg)
934             break;
935         /* Create ptnetmap state (kthreads, ...) and switch parent
936          * adapter to ptnetmap mode. */
937         error = ptnetmap_create(pth_na, cfg);
938         free(cfg, M_DEVBUF);
939         if (error)
940             break;
941         /* Start kthreads. */
942         error = ptnetmap_start_kthreads(pth_na);
943         if (error)
944             ptnetmap_delete(pth_na);
945         break;
946
947     case NETMAP_PT_HOST_DELETE:
948         /* Stop kthreads. */
949         ptnetmap_stop_kthreads(pth_na);
950         /* Switch parent adapter back to normal mode and destroy
951          * ptnetmap state (kthreads, ...). */
952         ptnetmap_delete(pth_na);
953         break;
954
955     default:
956         D("ERROR invalid cmd (nmr->nr_cmd) (0x%x)", cmd);
957         error = EINVAL;
958         break;
959     }
960     NMG_UNLOCK();
961
962 done:
963     return error;
964 }
965
966 /* nm_notify callbacks for ptnetmap */
967 static int
968 nm_pt_host_notify(struct netmap_kring *kring, int flags)
969 {
970         struct netmap_adapter *na = kring->na;
971         struct netmap_pt_host_adapter *pth_na =
972                 (struct netmap_pt_host_adapter *)na->na_private;
973         struct ptnetmap_state *ptns;
974         int k;
975
976         /* First check that the passthrough port is not being destroyed. */
977         if (unlikely(!pth_na)) {
978                 return NM_IRQ_COMPLETED;
979         }
980
981         ptns = pth_na->ptns;
982         if (unlikely(!ptns || ptns->stopped)) {
983                 return NM_IRQ_COMPLETED;
984         }
985
986         k = kring->ring_id;
987
988         /* Notify kthreads (wake up if needed) */
989         if (kring->tx == NR_TX) {
990                 ND(1, "TX backend irq");
991                 IFRATE(ptns->rate_ctx.new.btxwu++);
992         } else {
993                 k += pth_na->up.num_tx_rings;
994                 ND(1, "RX backend irq");
995                 IFRATE(ptns->rate_ctx.new.brxwu++);
996         }
997         nm_os_kthread_wakeup_worker(ptns->kthreads[k]);
998
999         return NM_IRQ_COMPLETED;
1000 }
1001
1002 static int
1003 nm_unused_notify(struct netmap_kring *kring, int flags)
1004 {
1005     D("BUG this should never be called");
1006     return ENXIO;
1007 }
1008
1009 /* nm_config callback for bwrap */
1010 static int
1011 nm_pt_host_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
1012         u_int *rxr, u_int *rxd)
1013 {
1014     struct netmap_pt_host_adapter *pth_na =
1015         (struct netmap_pt_host_adapter *)na;
1016     struct netmap_adapter *parent = pth_na->parent;
1017     int error;
1018
1019     //XXX: maybe calling parent->nm_config is better
1020
1021     /* forward the request */
1022     error = netmap_update_config(parent);
1023
1024     *rxr = na->num_rx_rings = parent->num_rx_rings;
1025     *txr = na->num_tx_rings = parent->num_tx_rings;
1026     *txd = na->num_tx_desc = parent->num_tx_desc;
1027     *rxd = na->num_rx_desc = parent->num_rx_desc;
1028
1029     DBG(D("rxr: %d txr: %d txd: %d rxd: %d", *rxr, *txr, *txd, *rxd));
1030
1031     return error;
1032 }
1033
1034 /* nm_krings_create callback for ptnetmap */
1035 static int
1036 nm_pt_host_krings_create(struct netmap_adapter *na)
1037 {
1038     struct netmap_pt_host_adapter *pth_na =
1039         (struct netmap_pt_host_adapter *)na;
1040     struct netmap_adapter *parent = pth_na->parent;
1041     enum txrx t;
1042     int error;
1043
1044     DBG(D("%s", pth_na->up.name));
1045
1046     /* create the parent krings */
1047     error = parent->nm_krings_create(parent);
1048     if (error) {
1049         return error;
1050     }
1051
1052     /* A ptnetmap host adapter points the very same krings
1053      * as its parent adapter. These pointer are used in the
1054      * TX/RX worker functions. */
1055     na->tx_rings = parent->tx_rings;
1056     na->rx_rings = parent->rx_rings;
1057     na->tailroom = parent->tailroom;
1058
1059     for_rx_tx(t) {
1060         struct netmap_kring *kring;
1061
1062         /* Parent's kring_create function will initialize
1063          * its own na->si. We have to init our na->si here. */
1064         nm_os_selinfo_init(&na->si[t]);
1065
1066         /* Force the mem_rings_create() method to create the
1067          * host rings independently on what the regif asked for:
1068          * these rings are needed by the guest ptnetmap adapter
1069          * anyway. */
1070         kring = &NMR(na, t)[nma_get_nrings(na, t)];
1071         kring->nr_kflags |= NKR_NEEDRING;
1072     }
1073
1074     return 0;
1075 }
1076
1077 /* nm_krings_delete callback for ptnetmap */
1078 static void
1079 nm_pt_host_krings_delete(struct netmap_adapter *na)
1080 {
1081     struct netmap_pt_host_adapter *pth_na =
1082         (struct netmap_pt_host_adapter *)na;
1083     struct netmap_adapter *parent = pth_na->parent;
1084
1085     DBG(D("%s", pth_na->up.name));
1086
1087     parent->nm_krings_delete(parent);
1088
1089     na->tx_rings = na->rx_rings = na->tailroom = NULL;
1090 }
1091
1092 /* nm_register callback */
1093 static int
1094 nm_pt_host_register(struct netmap_adapter *na, int onoff)
1095 {
1096     struct netmap_pt_host_adapter *pth_na =
1097         (struct netmap_pt_host_adapter *)na;
1098     struct netmap_adapter *parent = pth_na->parent;
1099     int error;
1100     DBG(D("%s onoff %d", pth_na->up.name, onoff));
1101
1102     if (onoff) {
1103         /* netmap_do_regif has been called on the ptnetmap na.
1104          * We need to pass the information about the
1105          * memory allocator to the parent before
1106          * putting it in netmap mode
1107          */
1108         parent->na_lut = na->na_lut;
1109     }
1110
1111     /* forward the request to the parent */
1112     error = parent->nm_register(parent, onoff);
1113     if (error)
1114         return error;
1115
1116
1117     if (onoff) {
1118         na->na_flags |= NAF_NETMAP_ON | NAF_PTNETMAP_HOST;
1119     } else {
1120         ptnetmap_delete(pth_na);
1121         na->na_flags &= ~(NAF_NETMAP_ON | NAF_PTNETMAP_HOST);
1122     }
1123
1124     return 0;
1125 }
1126
1127 /* nm_dtor callback */
1128 static void
1129 nm_pt_host_dtor(struct netmap_adapter *na)
1130 {
1131     struct netmap_pt_host_adapter *pth_na =
1132         (struct netmap_pt_host_adapter *)na;
1133     struct netmap_adapter *parent = pth_na->parent;
1134
1135     DBG(D("%s", pth_na->up.name));
1136
1137     /* The equivalent of NETMAP_PT_HOST_DELETE if the hypervisor
1138      * didn't do it. */
1139     ptnetmap_stop_kthreads(pth_na);
1140     ptnetmap_delete(pth_na);
1141
1142     parent->na_flags &= ~NAF_BUSY;
1143
1144     netmap_adapter_put(pth_na->parent);
1145     pth_na->parent = NULL;
1146 }
1147
1148 /* check if nmr is a request for a ptnetmap adapter that we can satisfy */
1149 int
1150 netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
1151 {
1152     struct nmreq parent_nmr;
1153     struct netmap_adapter *parent; /* target adapter */
1154     struct netmap_pt_host_adapter *pth_na;
1155     struct ifnet *ifp = NULL;
1156     int error;
1157
1158     /* Check if it is a request for a ptnetmap adapter */
1159     if ((nmr->nr_flags & (NR_PTNETMAP_HOST)) == 0) {
1160         return 0;
1161     }
1162
1163     D("Requesting a ptnetmap host adapter");
1164
1165     pth_na = malloc(sizeof(*pth_na), M_DEVBUF, M_NOWAIT | M_ZERO);
1166     if (pth_na == NULL) {
1167         D("ERROR malloc");
1168         return ENOMEM;
1169     }
1170
1171     /* first, try to find the adapter that we want to passthrough
1172      * We use the same nmr, after we have turned off the ptnetmap flag.
1173      * In this way we can potentially passthrough everything netmap understands.
1174      */
1175     memcpy(&parent_nmr, nmr, sizeof(parent_nmr));
1176     parent_nmr.nr_flags &= ~(NR_PTNETMAP_HOST);
1177     error = netmap_get_na(&parent_nmr, &parent, &ifp, create);
1178     if (error) {
1179         D("parent lookup failed: %d", error);
1180         goto put_out_noputparent;
1181     }
1182     DBG(D("found parent: %s", parent->name));
1183
1184     /* make sure the interface is not already in use */
1185     if (NETMAP_OWNED_BY_ANY(parent)) {
1186         D("NIC %s busy, cannot ptnetmap", parent->name);
1187         error = EBUSY;
1188         goto put_out;
1189     }
1190
1191     pth_na->parent = parent;
1192
1193     /* Follow netmap_attach()-like operations for the host
1194      * ptnetmap adapter. */
1195
1196     //XXX pth_na->up.na_flags = parent->na_flags;
1197     pth_na->up.num_rx_rings = parent->num_rx_rings;
1198     pth_na->up.num_tx_rings = parent->num_tx_rings;
1199     pth_na->up.num_tx_desc = parent->num_tx_desc;
1200     pth_na->up.num_rx_desc = parent->num_rx_desc;
1201
1202     pth_na->up.nm_dtor = nm_pt_host_dtor;
1203     pth_na->up.nm_register = nm_pt_host_register;
1204
1205     /* Reuse parent's adapter txsync and rxsync methods. */
1206     pth_na->up.nm_txsync = parent->nm_txsync;
1207     pth_na->up.nm_rxsync = parent->nm_rxsync;
1208
1209     pth_na->up.nm_krings_create = nm_pt_host_krings_create;
1210     pth_na->up.nm_krings_delete = nm_pt_host_krings_delete;
1211     pth_na->up.nm_config = nm_pt_host_config;
1212
1213     /* Set the notify method only or convenience, it will never
1214      * be used, since - differently from default krings_create - we
1215      * ptnetmap krings_create callback inits kring->nm_notify
1216      * directly. */
1217     pth_na->up.nm_notify = nm_unused_notify;
1218
1219     pth_na->up.nm_mem = parent->nm_mem;
1220
1221     pth_na->up.na_flags |= NAF_HOST_RINGS;
1222
1223     error = netmap_attach_common(&pth_na->up);
1224     if (error) {
1225         D("ERROR netmap_attach_common()");
1226         goto put_out;
1227     }
1228
1229     *na = &pth_na->up;
1230     netmap_adapter_get(*na);
1231
1232     /* set parent busy, because attached for ptnetmap */
1233     parent->na_flags |= NAF_BUSY;
1234
1235     strncpy(pth_na->up.name, parent->name, sizeof(pth_na->up.name));
1236     strcat(pth_na->up.name, "-PTN");
1237
1238     DBG(D("%s ptnetmap request DONE", pth_na->up.name));
1239
1240     /* drop the reference to the ifp, if any */
1241     if (ifp)
1242         if_rele(ifp);
1243
1244     return 0;
1245
1246 put_out:
1247     netmap_adapter_put(parent);
1248     if (ifp)
1249         if_rele(ifp);
1250 put_out_noputparent:
1251     free(pth_na, M_DEVBUF);
1252     return error;
1253 }
1254 #endif /* WITH_PTNETMAP_HOST */
1255
1256 #ifdef WITH_PTNETMAP_GUEST
1257 /*
1258  * Guest ptnetmap txsync()/rxsync() routines, used in ptnet device drivers.
1259  * These routines are reused across the different operating systems supported
1260  * by netmap.
1261  */
1262
1263 /*
1264  * Reconcile host and guest views of the transmit ring.
1265  *
1266  * Guest user wants to transmit packets up to the one before ring->head,
1267  * and guest kernel knows tx_ring->hwcur is the first packet unsent
1268  * by the host kernel.
1269  *
1270  * We push out as many packets as possible, and possibly
1271  * reclaim buffers from previously completed transmission.
1272  *
1273  * Notifications from the host are enabled only if the user guest would
1274  * block (no space in the ring).
1275  */
1276 bool
1277 netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
1278                        int flags)
1279 {
1280         bool notify = false;
1281
1282         /* Disable notifications */
1283         ptring->guest_need_kick = 0;
1284
1285         /*
1286          * First part: tell the host (updating the CSB) to process the new
1287          * packets.
1288          */
1289         kring->nr_hwcur = ptring->hwcur;
1290         ptnetmap_guest_write_kring_csb(ptring, kring->rcur, kring->rhead);
1291
1292         /* Ask for a kick from a guest to the host if needed. */
1293         if ((kring->rhead != kring->nr_hwcur &&
1294                 NM_ACCESS_ONCE(ptring->host_need_kick)) ||
1295                         (flags & NAF_FORCE_RECLAIM)) {
1296                 ptring->sync_flags = flags;
1297                 notify = true;
1298         }
1299
1300         /*
1301          * Second part: reclaim buffers for completed transmissions.
1302          */
1303         if (nm_kr_txempty(kring) || (flags & NAF_FORCE_RECLAIM)) {
1304                 ptnetmap_guest_read_kring_csb(ptring, kring);
1305         }
1306
1307         /*
1308          * No more room in the ring for new transmissions. The user thread will
1309          * go to sleep and we need to be notified by the host when more free
1310          * space is available.
1311          */
1312         if (nm_kr_txempty(kring)) {
1313                 /* Reenable notifications. */
1314                 ptring->guest_need_kick = 1;
1315                 /* Double check */
1316                 ptnetmap_guest_read_kring_csb(ptring, kring);
1317                 /* If there is new free space, disable notifications */
1318                 if (unlikely(!nm_kr_txempty(kring))) {
1319                         ptring->guest_need_kick = 0;
1320                 }
1321         }
1322
1323         ND(1, "TX - CSB: head:%u cur:%u hwtail:%u - KRING: head:%u cur:%u tail: %u",
1324                         ptring->head, ptring->cur, ptring->hwtail,
1325                         kring->rhead, kring->rcur, kring->nr_hwtail);
1326
1327         return notify;
1328 }
1329
1330 /*
1331  * Reconcile host and guest view of the receive ring.
1332  *
1333  * Update hwcur/hwtail from host (reading from CSB).
1334  *
1335  * If guest user has released buffers up to the one before ring->head, we
1336  * also give them to the host.
1337  *
1338  * Notifications from the host are enabled only if the user guest would
1339  * block (no more completed slots in the ring).
1340  */
1341 bool
1342 netmap_pt_guest_rxsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
1343                        int flags)
1344 {
1345         bool notify = false;
1346
1347         /* Disable notifications */
1348         ptring->guest_need_kick = 0;
1349
1350         /*
1351          * First part: import newly received packets, by updating the kring
1352          * hwtail to the hwtail known from the host (read from the CSB).
1353          * This also updates the kring hwcur.
1354          */
1355         ptnetmap_guest_read_kring_csb(ptring, kring);
1356         kring->nr_kflags &= ~NKR_PENDINTR;
1357
1358         /*
1359          * Second part: tell the host about the slots that guest user has
1360          * released, by updating cur and head in the CSB.
1361          */
1362         if (kring->rhead != kring->nr_hwcur) {
1363                 ptnetmap_guest_write_kring_csb(ptring, kring->rcur,
1364                                                kring->rhead);
1365                 /* Ask for a kick from the guest to the host if needed. */
1366                 if (NM_ACCESS_ONCE(ptring->host_need_kick)) {
1367                         ptring->sync_flags = flags;
1368                         notify = true;
1369                 }
1370         }
1371
1372         /*
1373          * No more completed RX slots. The user thread will go to sleep and
1374          * we need to be notified by the host when more RX slots have been
1375          * completed.
1376          */
1377         if (nm_kr_rxempty(kring)) {
1378                 /* Reenable notifications. */
1379                 ptring->guest_need_kick = 1;
1380                 /* Double check */
1381                 ptnetmap_guest_read_kring_csb(ptring, kring);
1382                 /* If there are new slots, disable notifications. */
1383                 if (!nm_kr_rxempty(kring)) {
1384                         ptring->guest_need_kick = 0;
1385                 }
1386         }
1387
1388         ND(1, "RX - CSB: head:%u cur:%u hwtail:%u - KRING: head:%u cur:%u",
1389                 ptring->head, ptring->cur, ptring->hwtail,
1390                 kring->rhead, kring->rcur);
1391
1392         return notify;
1393 }
1394
1395 /*
1396  * Callbacks for ptnet drivers: nm_krings_create, nm_krings_delete, nm_dtor.
1397  */
1398 int
1399 ptnet_nm_krings_create(struct netmap_adapter *na)
1400 {
1401         struct netmap_pt_guest_adapter *ptna =
1402                         (struct netmap_pt_guest_adapter *)na; /* Upcast. */
1403         struct netmap_adapter *na_nm = &ptna->hwup.up;
1404         struct netmap_adapter *na_dr = &ptna->dr.up;
1405         int ret;
1406
1407         if (ptna->backend_regifs) {
1408                 return 0;
1409         }
1410
1411         /* Create krings on the public netmap adapter. */
1412         ret = netmap_hw_krings_create(na_nm);
1413         if (ret) {
1414                 return ret;
1415         }
1416
1417         /* Copy krings into the netmap adapter private to the driver. */
1418         na_dr->tx_rings = na_nm->tx_rings;
1419         na_dr->rx_rings = na_nm->rx_rings;
1420
1421         return 0;
1422 }
1423
1424 void
1425 ptnet_nm_krings_delete(struct netmap_adapter *na)
1426 {
1427         struct netmap_pt_guest_adapter *ptna =
1428                         (struct netmap_pt_guest_adapter *)na; /* Upcast. */
1429         struct netmap_adapter *na_nm = &ptna->hwup.up;
1430         struct netmap_adapter *na_dr = &ptna->dr.up;
1431
1432         if (ptna->backend_regifs) {
1433                 return;
1434         }
1435
1436         na_dr->tx_rings = NULL;
1437         na_dr->rx_rings = NULL;
1438
1439         netmap_hw_krings_delete(na_nm);
1440 }
1441
1442 void
1443 ptnet_nm_dtor(struct netmap_adapter *na)
1444 {
1445         struct netmap_pt_guest_adapter *ptna =
1446                         (struct netmap_pt_guest_adapter *)na;
1447
1448         netmap_mem_put(ptna->dr.up.nm_mem);
1449         memset(&ptna->dr, 0, sizeof(ptna->dr));
1450         netmap_mem_pt_guest_ifp_del(na->nm_mem, na->ifp);
1451 }
1452
1453 #endif /* WITH_PTNETMAP_GUEST */