]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/netmap/netmap_pt.c
dts: Update our device tree sources file fomr Linux 4.13
[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_kctx **kctxs;
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         D("%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, int is_kthread)
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_kctx *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->kctxs[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) && is_kthread) {
341             /* Disable guest kick to avoid sending unnecessary kicks */
342             ptring_intr_enable(ptring, 0);
343             nm_os_kctx_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             if (is_kthread) {
358                 usleep_range(1,1);
359             }
360             /* Reenable notifications. */
361             ptring_kick_enable(ptring, 1);
362             /* Doublecheck. */
363             ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
364             if (shadow_ring.head != kring->rhead) {
365                 /* We won the race condition, there are more packets to
366                  * transmit. Disable notifications and do another cycle */
367                 ptring_kick_enable(ptring, 0);
368                 continue;
369             }
370             break;
371         }
372
373         if (nm_kr_txempty(kring)) {
374             /* No more available TX slots. We stop waiting for a notification
375              * from the backend (netmap_tx_irq). */
376             ND(1, "TX ring");
377             break;
378         }
379 #endif
380         if (unlikely(ptns->stopped)) {
381             D("backend netmap is being stopped");
382             break;
383         }
384     }
385
386     nm_kr_put(kring);
387
388     if (more_txspace && ptring_intr_enabled(ptring) && is_kthread) {
389         ptring_intr_enable(ptring, 0);
390         nm_os_kctx_send_irq(kth);
391         IFRATE(ptns->rate_ctx.new.htxk++);
392     }
393 }
394
395 /* Called on backend nm_notify when there is no worker thread. */
396 static void
397 ptnetmap_tx_nothread_notify(void *data)
398 {
399         struct netmap_kring *kring = data;
400         struct netmap_pt_host_adapter *pth_na =
401                 (struct netmap_pt_host_adapter *)kring->na->na_private;
402         struct ptnetmap_state *ptns = pth_na->ptns;
403
404         if (unlikely(!ptns)) {
405                 D("ERROR ptnetmap state is NULL");
406                 return;
407         }
408
409         if (unlikely(ptns->stopped)) {
410                 D("backend netmap is being stopped");
411                 return;
412         }
413
414         /* We cannot access the CSB here (to check ptring->guest_need_kick),
415          * unless we switch address space to the one of the guest. For now
416          * we unconditionally inject an interrupt. */
417         nm_os_kctx_send_irq(ptns->kctxs[kring->ring_id]);
418         IFRATE(ptns->rate_ctx.new.htxk++);
419         ND(1, "%s interrupt", kring->name);
420 }
421
422 /*
423  * We need RX kicks from the guest when (tail == head-1), where we wait
424  * for the guest to refill.
425  */
426 #ifndef BUSY_WAIT
427 static inline int
428 ptnetmap_norxslots(struct netmap_kring *kring, uint32_t g_head)
429 {
430     return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
431                             kring->nkr_num_slots - 1));
432 }
433 #endif /* !BUSY_WAIT */
434
435 /* Handle RX events: from the guest or from the backend */
436 static void
437 ptnetmap_rx_handler(void *data, int is_kthread)
438 {
439     struct netmap_kring *kring = data;
440     struct netmap_pt_host_adapter *pth_na =
441                 (struct netmap_pt_host_adapter *)kring->na->na_private;
442     struct ptnetmap_state *ptns = pth_na->ptns;
443     struct ptnet_ring __user *ptring;
444     struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
445     struct nm_kctx *kth;
446     uint32_t num_slots;
447     int dry_cycles = 0;
448     bool some_recvd = false;
449     IFRATE(uint32_t pre_tail);
450
451     if (unlikely(!ptns || !ptns->pth_na)) {
452         D("ERROR ptnetmap state %p, ptnetmap host adapter %p", ptns,
453           ptns ? ptns->pth_na : NULL);
454         return;
455     }
456
457     if (unlikely(ptns->stopped)) {
458         RD(1, "backend netmap is being stopped");
459         return;
460     }
461
462     if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
463         D("ERROR nm_kr_tryget()");
464         return;
465     }
466
467     /* This is a guess, to be fixed in the rate callback. */
468     IFRATE(ptns->rate_ctx.new.grxk++);
469
470     /* Get RX ptring pointer from the CSB. */
471     ptring = ptns->ptrings + (pth_na->up.num_tx_rings + kring->ring_id);
472     kth = ptns->kctxs[pth_na->up.num_tx_rings + kring->ring_id];
473
474     num_slots = kring->nkr_num_slots;
475     shadow_ring.head = kring->rhead;
476     shadow_ring.cur = kring->rcur;
477
478     /* Disable notifications. */
479     ptring_kick_enable(ptring, 0);
480     /* Copy the guest kring pointers from the CSB */
481     ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
482
483     for (;;) {
484         uint32_t hwtail;
485
486         /* Netmap prologue */
487         shadow_ring.tail = kring->rtail;
488         if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
489             /* Reinit ring and enable notifications. */
490             netmap_ring_reinit(kring);
491             ptring_kick_enable(ptring, 1);
492             break;
493         }
494
495         if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
496             ptnetmap_kring_dump("pre rxsync", kring);
497         }
498
499         IFRATE(pre_tail = kring->rtail);
500         if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
501             /* Reenable notifications. */
502             ptring_kick_enable(ptring, 1);
503             D("ERROR rxsync()");
504             break;
505         }
506         /*
507          * Finalize
508          * Copy host hwcur and hwtail into the CSB for the guest sync()
509          */
510         hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
511         ptnetmap_host_write_kring_csb(ptring, kring->nr_hwcur, hwtail);
512         if (kring->rtail != hwtail) {
513             kring->rtail = hwtail;
514             some_recvd = true;
515             dry_cycles = 0;
516         } else {
517             dry_cycles++;
518         }
519
520         IFRATE(rate_batch_stats_update(&ptns->rate_ctx.new.rxbs, pre_tail,
521                                        kring->rtail, num_slots));
522
523         if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
524             ptnetmap_kring_dump("post rxsync", kring);
525         }
526
527 #ifndef BUSY_WAIT
528         /* Interrupt the guest if needed. */
529         if (some_recvd && ptring_intr_enabled(ptring)) {
530             /* Disable guest kick to avoid sending unnecessary kicks */
531             ptring_intr_enable(ptring, 0);
532             nm_os_kctx_send_irq(kth);
533             IFRATE(ptns->rate_ctx.new.hrxk++);
534             some_recvd = false;
535         }
536 #endif
537         /* Read CSB to see if there is more work to do. */
538         ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
539 #ifndef BUSY_WAIT
540         if (ptnetmap_norxslots(kring, shadow_ring.head)) {
541             /*
542              * No more slots available for reception. We enable notification and
543              * go to sleep, waiting for a kick from the guest when new receive
544              * slots are available.
545              */
546             usleep_range(1,1);
547             /* Reenable notifications. */
548             ptring_kick_enable(ptring, 1);
549             /* Doublecheck. */
550             ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
551             if (!ptnetmap_norxslots(kring, shadow_ring.head)) {
552                 /* We won the race condition, more slots are available. Disable
553                  * notifications and do another cycle. */
554                 ptring_kick_enable(ptring, 0);
555                 continue;
556             }
557             break;
558         }
559
560         hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
561         if (unlikely(hwtail == kring->rhead ||
562                      dry_cycles >= PTN_RX_DRY_CYCLES_MAX)) {
563             /* No more packets to be read from the backend. We stop and
564              * wait for a notification from the backend (netmap_rx_irq). */
565             ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
566                hwtail, kring->rhead, dry_cycles);
567             break;
568         }
569 #endif
570         if (unlikely(ptns->stopped)) {
571             D("backend netmap is being stopped");
572             break;
573         }
574     }
575
576     nm_kr_put(kring);
577
578     /* Interrupt the guest if needed. */
579     if (some_recvd && ptring_intr_enabled(ptring)) {
580         ptring_intr_enable(ptring, 0);
581         nm_os_kctx_send_irq(kth);
582         IFRATE(ptns->rate_ctx.new.hrxk++);
583     }
584 }
585
586 #ifdef NETMAP_PT_DEBUG
587 static void
588 ptnetmap_print_configuration(struct ptnetmap_cfg *cfg)
589 {
590         int k;
591
592         D("ptnetmap configuration:");
593         D("  CSB ptrings @%p, num_rings=%u, cfgtype %08x", cfg->ptrings,
594           cfg->num_rings, cfg->cfgtype);
595         for (k = 0; k < cfg->num_rings; k++) {
596                 switch (cfg->cfgtype) {
597                 case PTNETMAP_CFGTYPE_QEMU: {
598                         struct ptnetmap_cfgentry_qemu *e =
599                                 (struct ptnetmap_cfgentry_qemu *)(cfg+1) + k;
600                         D("    ring #%d: ioeventfd=%lu, irqfd=%lu", k,
601                                 (unsigned long)e->ioeventfd,
602                                 (unsigned long)e->irqfd);
603                         break;
604                 }
605
606                 case PTNETMAP_CFGTYPE_BHYVE:
607                 {
608                         struct ptnetmap_cfgentry_bhyve *e =
609                                 (struct ptnetmap_cfgentry_bhyve *)(cfg+1) + k;
610                         D("    ring #%d: wchan=%lu, ioctl_fd=%lu, "
611                           "ioctl_cmd=%lu, msix_msg_data=%lu, msix_addr=%lu",
612                                 k, (unsigned long)e->wchan,
613                                 (unsigned long)e->ioctl_fd,
614                                 (unsigned long)e->ioctl_cmd,
615                                 (unsigned long)e->ioctl_data.msg_data,
616                                 (unsigned long)e->ioctl_data.addr);
617                         break;
618                 }
619                 }
620         }
621
622 }
623 #endif /* NETMAP_PT_DEBUG */
624
625 /* Copy actual state of the host ring into the CSB for the guest init */
626 static int
627 ptnetmap_kring_snapshot(struct netmap_kring *kring, struct ptnet_ring __user *ptring)
628 {
629     if (CSB_WRITE(ptring, head, kring->rhead))
630         goto err;
631     if (CSB_WRITE(ptring, cur, kring->rcur))
632         goto err;
633
634     if (CSB_WRITE(ptring, hwcur, kring->nr_hwcur))
635         goto err;
636     if (CSB_WRITE(ptring, hwtail, NM_ACCESS_ONCE(kring->nr_hwtail)))
637         goto err;
638
639     DBG(ptnetmap_kring_dump("ptnetmap_kring_snapshot", kring);)
640
641     return 0;
642 err:
643     return EFAULT;
644 }
645
646 static struct netmap_kring *
647 ptnetmap_kring(struct netmap_pt_host_adapter *pth_na, int k)
648 {
649         if (k < pth_na->up.num_tx_rings) {
650                 return pth_na->up.tx_rings + k;
651         }
652         return pth_na->up.rx_rings + k - pth_na->up.num_tx_rings;
653 }
654
655 static int
656 ptnetmap_krings_snapshot(struct netmap_pt_host_adapter *pth_na)
657 {
658         struct ptnetmap_state *ptns = pth_na->ptns;
659         struct netmap_kring *kring;
660         unsigned int num_rings;
661         int err = 0, k;
662
663         num_rings = pth_na->up.num_tx_rings +
664                     pth_na->up.num_rx_rings;
665
666         for (k = 0; k < num_rings; k++) {
667                 kring = ptnetmap_kring(pth_na, k);
668                 err |= ptnetmap_kring_snapshot(kring, ptns->ptrings + k);
669         }
670
671         return err;
672 }
673
674 /*
675  * Functions to create kernel contexts, and start/stop the workers.
676  */
677
678 static int
679 ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na,
680                       struct ptnetmap_cfg *cfg, int use_tx_kthreads)
681 {
682         struct ptnetmap_state *ptns = pth_na->ptns;
683         struct nm_kctx_cfg nmk_cfg;
684         unsigned int num_rings;
685         uint8_t *cfg_entries = (uint8_t *)(cfg + 1);
686         int k;
687
688         num_rings = pth_na->up.num_tx_rings +
689                     pth_na->up.num_rx_rings;
690
691         for (k = 0; k < num_rings; k++) {
692                 nmk_cfg.attach_user = 1; /* attach kthread to user process */
693                 nmk_cfg.worker_private = ptnetmap_kring(pth_na, k);
694                 nmk_cfg.type = k;
695                 if (k < pth_na->up.num_tx_rings) {
696                         nmk_cfg.worker_fn = ptnetmap_tx_handler;
697                         nmk_cfg.use_kthread = use_tx_kthreads;
698                         nmk_cfg.notify_fn = ptnetmap_tx_nothread_notify;
699                 } else {
700                         nmk_cfg.worker_fn = ptnetmap_rx_handler;
701                         nmk_cfg.use_kthread = 1;
702                 }
703
704                 ptns->kctxs[k] = nm_os_kctx_create(&nmk_cfg,
705                         cfg->cfgtype, cfg_entries + k * cfg->entry_size);
706                 if (ptns->kctxs[k] == NULL) {
707                         goto err;
708                 }
709         }
710
711         return 0;
712 err:
713         for (k = 0; k < num_rings; k++) {
714                 if (ptns->kctxs[k]) {
715                         nm_os_kctx_destroy(ptns->kctxs[k]);
716                         ptns->kctxs[k] = NULL;
717                 }
718         }
719         return EFAULT;
720 }
721
722 static int
723 ptnetmap_start_kctx_workers(struct netmap_pt_host_adapter *pth_na)
724 {
725         struct ptnetmap_state *ptns = pth_na->ptns;
726         int num_rings;
727         int error;
728         int k;
729
730         if (!ptns) {
731                 D("BUG ptns is NULL");
732                 return EFAULT;
733         }
734
735         ptns->stopped = false;
736
737         num_rings = ptns->pth_na->up.num_tx_rings +
738                     ptns->pth_na->up.num_rx_rings;
739         for (k = 0; k < num_rings; k++) {
740                 //nm_os_kctx_worker_setaff(ptns->kctxs[k], xxx);
741                 error = nm_os_kctx_worker_start(ptns->kctxs[k]);
742                 if (error) {
743                         return error;
744                 }
745         }
746
747         return 0;
748 }
749
750 static void
751 ptnetmap_stop_kctx_workers(struct netmap_pt_host_adapter *pth_na)
752 {
753         struct ptnetmap_state *ptns = pth_na->ptns;
754         int num_rings;
755         int k;
756
757         if (!ptns) {
758                 /* Nothing to do. */
759                 return;
760         }
761
762         ptns->stopped = true;
763
764         num_rings = ptns->pth_na->up.num_tx_rings +
765                     ptns->pth_na->up.num_rx_rings;
766         for (k = 0; k < num_rings; k++) {
767                 nm_os_kctx_worker_stop(ptns->kctxs[k]);
768         }
769 }
770
771 static struct ptnetmap_cfg *
772 ptnetmap_read_cfg(struct nmreq *nmr)
773 {
774         uintptr_t *nmr_ptncfg = (uintptr_t *)&nmr->nr_arg1;
775         struct ptnetmap_cfg *cfg;
776         struct ptnetmap_cfg tmp;
777         size_t cfglen;
778
779         if (copyin((const void *)*nmr_ptncfg, &tmp, sizeof(tmp))) {
780                 D("Partial copyin() failed");
781                 return NULL;
782         }
783
784         cfglen = sizeof(tmp) + tmp.num_rings * tmp.entry_size;
785         cfg = nm_os_malloc(cfglen);
786         if (!cfg) {
787                 return NULL;
788         }
789
790         if (copyin((const void *)*nmr_ptncfg, cfg, cfglen)) {
791                 D("Full copyin() failed");
792                 nm_os_free(cfg);
793                 return NULL;
794         }
795
796         return cfg;
797 }
798
799 static int nm_unused_notify(struct netmap_kring *, int);
800 static int nm_pt_host_notify(struct netmap_kring *, int);
801
802 /* Create ptnetmap state and switch parent adapter to ptnetmap mode. */
803 static int
804 ptnetmap_create(struct netmap_pt_host_adapter *pth_na,
805                 struct ptnetmap_cfg *cfg)
806 {
807     int use_tx_kthreads = ptnetmap_tx_workers; /* snapshot */
808     struct ptnetmap_state *ptns;
809     unsigned int num_rings;
810     int ret, i;
811
812     /* Check if ptnetmap state is already there. */
813     if (pth_na->ptns) {
814         D("ERROR adapter %p already in ptnetmap mode", pth_na->parent);
815         return EINVAL;
816     }
817
818     num_rings = pth_na->up.num_tx_rings + pth_na->up.num_rx_rings;
819
820     if (num_rings != cfg->num_rings) {
821         D("ERROR configuration mismatch, expected %u rings, found %u",
822            num_rings, cfg->num_rings);
823         return EINVAL;
824     }
825
826     if (!use_tx_kthreads && na_is_generic(pth_na->parent)) {
827         D("ERROR ptnetmap direct transmission not supported with "
828           "passed-through emulated adapters");
829         return EOPNOTSUPP;
830     }
831
832     ptns = nm_os_malloc(sizeof(*ptns) + num_rings * sizeof(*ptns->kctxs));
833     if (!ptns) {
834         return ENOMEM;
835     }
836
837     ptns->kctxs = (struct nm_kctx **)(ptns + 1);
838     ptns->stopped = true;
839
840     /* Cross-link data structures. */
841     pth_na->ptns = ptns;
842     ptns->pth_na = pth_na;
843
844     /* Store the CSB address provided by the hypervisor. */
845     ptns->ptrings = cfg->ptrings;
846
847     DBG(ptnetmap_print_configuration(cfg));
848
849     /* Create kernel contexts. */
850     if ((ret = ptnetmap_create_kctxs(pth_na, cfg, use_tx_kthreads))) {
851         D("ERROR ptnetmap_create_kctxs()");
852         goto err;
853     }
854     /* Copy krings state into the CSB for the guest initialization */
855     if ((ret = ptnetmap_krings_snapshot(pth_na))) {
856         D("ERROR ptnetmap_krings_snapshot()");
857         goto err;
858     }
859
860     /* Overwrite parent nm_notify krings callback, and
861      * clear NAF_BDG_MAYSLEEP if needed. */
862     pth_na->parent->na_private = pth_na;
863     pth_na->parent_nm_notify = pth_na->parent->nm_notify;
864     pth_na->parent->nm_notify = nm_unused_notify;
865     pth_na->parent_na_flags = pth_na->parent->na_flags;
866     if (!use_tx_kthreads) {
867         /* VALE port txsync is executed under spinlock on Linux, so
868          * we need to make sure the bridge cannot sleep. */
869         pth_na->parent->na_flags &= ~NAF_BDG_MAYSLEEP;
870     }
871
872     for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
873         pth_na->up.rx_rings[i].save_notify =
874                 pth_na->up.rx_rings[i].nm_notify;
875         pth_na->up.rx_rings[i].nm_notify = nm_pt_host_notify;
876     }
877     for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
878         pth_na->up.tx_rings[i].save_notify =
879                 pth_na->up.tx_rings[i].nm_notify;
880         pth_na->up.tx_rings[i].nm_notify = nm_pt_host_notify;
881     }
882
883 #ifdef RATE
884     memset(&ptns->rate_ctx, 0, sizeof(ptns->rate_ctx));
885     setup_timer(&ptns->rate_ctx.timer, &rate_callback,
886             (unsigned long)&ptns->rate_ctx);
887     if (mod_timer(&ptns->rate_ctx.timer, jiffies + msecs_to_jiffies(1500)))
888         D("[ptn] Error: mod_timer()\n");
889 #endif
890
891     DBG(D("[%s] ptnetmap configuration DONE", pth_na->up.name));
892
893     return 0;
894
895 err:
896     pth_na->ptns = NULL;
897     nm_os_free(ptns);
898     return ret;
899 }
900
901 /* Switch parent adapter back to normal mode and destroy
902  * ptnetmap state. */
903 static void
904 ptnetmap_delete(struct netmap_pt_host_adapter *pth_na)
905 {
906     struct ptnetmap_state *ptns = pth_na->ptns;
907     int num_rings;
908     int i;
909
910     if (!ptns) {
911         /* Nothing to do. */
912         return;
913     }
914
915     /* Restore parent adapter callbacks. */
916     pth_na->parent->nm_notify = pth_na->parent_nm_notify;
917     pth_na->parent->na_private = NULL;
918     pth_na->parent->na_flags = pth_na->parent_na_flags;
919
920     for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
921         pth_na->up.rx_rings[i].nm_notify =
922                 pth_na->up.rx_rings[i].save_notify;
923         pth_na->up.rx_rings[i].save_notify = NULL;
924     }
925     for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
926         pth_na->up.tx_rings[i].nm_notify =
927                 pth_na->up.tx_rings[i].save_notify;
928         pth_na->up.tx_rings[i].save_notify = NULL;
929     }
930
931     /* Destroy kernel contexts. */
932     num_rings = ptns->pth_na->up.num_tx_rings +
933                 ptns->pth_na->up.num_rx_rings;
934     for (i = 0; i < num_rings; i++) {
935         nm_os_kctx_destroy(ptns->kctxs[i]);
936         ptns->kctxs[i] = NULL;
937     }
938
939     IFRATE(del_timer(&ptns->rate_ctx.timer));
940
941     nm_os_free(ptns);
942
943     pth_na->ptns = NULL;
944
945     DBG(D("[%s] ptnetmap deleted", pth_na->up.name));
946 }
947
948 /*
949  * Called by netmap_ioctl().
950  * Operation is indicated in nmr->nr_cmd.
951  *
952  * Called without NMG_LOCK.
953  */
954 int
955 ptnetmap_ctl(struct nmreq *nmr, struct netmap_adapter *na)
956 {
957     struct netmap_pt_host_adapter *pth_na;
958     struct ptnetmap_cfg *cfg;
959     char *name;
960     int cmd, error = 0;
961
962     name = nmr->nr_name;
963     cmd = nmr->nr_cmd;
964
965     DBG(D("name: %s", name));
966
967     if (!nm_ptnetmap_host_on(na)) {
968         D("ERROR Netmap adapter %p is not a ptnetmap host adapter", na);
969         error = ENXIO;
970         goto done;
971     }
972     pth_na = (struct netmap_pt_host_adapter *)na;
973
974     NMG_LOCK();
975     switch (cmd) {
976     case NETMAP_PT_HOST_CREATE:
977         /* Read hypervisor configuration from userspace. */
978         cfg = ptnetmap_read_cfg(nmr);
979         if (!cfg)
980             break;
981         /* Create ptnetmap state (kctxs, ...) and switch parent
982          * adapter to ptnetmap mode. */
983         error = ptnetmap_create(pth_na, cfg);
984         nm_os_free(cfg);
985         if (error)
986             break;
987         /* Start kthreads. */
988         error = ptnetmap_start_kctx_workers(pth_na);
989         if (error)
990             ptnetmap_delete(pth_na);
991         break;
992
993     case NETMAP_PT_HOST_DELETE:
994         /* Stop kthreads. */
995         ptnetmap_stop_kctx_workers(pth_na);
996         /* Switch parent adapter back to normal mode and destroy
997          * ptnetmap state (kthreads, ...). */
998         ptnetmap_delete(pth_na);
999         break;
1000
1001     default:
1002         D("ERROR invalid cmd (nmr->nr_cmd) (0x%x)", cmd);
1003         error = EINVAL;
1004         break;
1005     }
1006     NMG_UNLOCK();
1007
1008 done:
1009     return error;
1010 }
1011
1012 /* nm_notify callbacks for ptnetmap */
1013 static int
1014 nm_pt_host_notify(struct netmap_kring *kring, int flags)
1015 {
1016         struct netmap_adapter *na = kring->na;
1017         struct netmap_pt_host_adapter *pth_na =
1018                 (struct netmap_pt_host_adapter *)na->na_private;
1019         struct ptnetmap_state *ptns;
1020         int k;
1021
1022         /* First check that the passthrough port is not being destroyed. */
1023         if (unlikely(!pth_na)) {
1024                 return NM_IRQ_COMPLETED;
1025         }
1026
1027         ptns = pth_na->ptns;
1028         if (unlikely(!ptns || ptns->stopped)) {
1029                 return NM_IRQ_COMPLETED;
1030         }
1031
1032         k = kring->ring_id;
1033
1034         /* Notify kthreads (wake up if needed) */
1035         if (kring->tx == NR_TX) {
1036                 ND(1, "TX backend irq");
1037                 IFRATE(ptns->rate_ctx.new.btxwu++);
1038         } else {
1039                 k += pth_na->up.num_tx_rings;
1040                 ND(1, "RX backend irq");
1041                 IFRATE(ptns->rate_ctx.new.brxwu++);
1042         }
1043         nm_os_kctx_worker_wakeup(ptns->kctxs[k]);
1044
1045         return NM_IRQ_COMPLETED;
1046 }
1047
1048 static int
1049 nm_unused_notify(struct netmap_kring *kring, int flags)
1050 {
1051     D("BUG this should never be called");
1052     return ENXIO;
1053 }
1054
1055 /* nm_config callback for bwrap */
1056 static int
1057 nm_pt_host_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
1058         u_int *rxr, u_int *rxd)
1059 {
1060     struct netmap_pt_host_adapter *pth_na =
1061         (struct netmap_pt_host_adapter *)na;
1062     struct netmap_adapter *parent = pth_na->parent;
1063     int error;
1064
1065     //XXX: maybe calling parent->nm_config is better
1066
1067     /* forward the request */
1068     error = netmap_update_config(parent);
1069
1070     *rxr = na->num_rx_rings = parent->num_rx_rings;
1071     *txr = na->num_tx_rings = parent->num_tx_rings;
1072     *txd = na->num_tx_desc = parent->num_tx_desc;
1073     *rxd = na->num_rx_desc = parent->num_rx_desc;
1074
1075     DBG(D("rxr: %d txr: %d txd: %d rxd: %d", *rxr, *txr, *txd, *rxd));
1076
1077     return error;
1078 }
1079
1080 /* nm_krings_create callback for ptnetmap */
1081 static int
1082 nm_pt_host_krings_create(struct netmap_adapter *na)
1083 {
1084     struct netmap_pt_host_adapter *pth_na =
1085         (struct netmap_pt_host_adapter *)na;
1086     struct netmap_adapter *parent = pth_na->parent;
1087     enum txrx t;
1088     int error;
1089
1090     DBG(D("%s", pth_na->up.name));
1091
1092     /* create the parent krings */
1093     error = parent->nm_krings_create(parent);
1094     if (error) {
1095         return error;
1096     }
1097
1098     /* A ptnetmap host adapter points the very same krings
1099      * as its parent adapter. These pointer are used in the
1100      * TX/RX worker functions. */
1101     na->tx_rings = parent->tx_rings;
1102     na->rx_rings = parent->rx_rings;
1103     na->tailroom = parent->tailroom;
1104
1105     for_rx_tx(t) {
1106         struct netmap_kring *kring;
1107
1108         /* Parent's kring_create function will initialize
1109          * its own na->si. We have to init our na->si here. */
1110         nm_os_selinfo_init(&na->si[t]);
1111
1112         /* Force the mem_rings_create() method to create the
1113          * host rings independently on what the regif asked for:
1114          * these rings are needed by the guest ptnetmap adapter
1115          * anyway. */
1116         kring = &NMR(na, t)[nma_get_nrings(na, t)];
1117         kring->nr_kflags |= NKR_NEEDRING;
1118     }
1119
1120     return 0;
1121 }
1122
1123 /* nm_krings_delete callback for ptnetmap */
1124 static void
1125 nm_pt_host_krings_delete(struct netmap_adapter *na)
1126 {
1127     struct netmap_pt_host_adapter *pth_na =
1128         (struct netmap_pt_host_adapter *)na;
1129     struct netmap_adapter *parent = pth_na->parent;
1130
1131     DBG(D("%s", pth_na->up.name));
1132
1133     parent->nm_krings_delete(parent);
1134
1135     na->tx_rings = na->rx_rings = na->tailroom = NULL;
1136 }
1137
1138 /* nm_register callback */
1139 static int
1140 nm_pt_host_register(struct netmap_adapter *na, int onoff)
1141 {
1142     struct netmap_pt_host_adapter *pth_na =
1143         (struct netmap_pt_host_adapter *)na;
1144     struct netmap_adapter *parent = pth_na->parent;
1145     int error;
1146     DBG(D("%s onoff %d", pth_na->up.name, onoff));
1147
1148     if (onoff) {
1149         /* netmap_do_regif has been called on the ptnetmap na.
1150          * We need to pass the information about the
1151          * memory allocator to the parent before
1152          * putting it in netmap mode
1153          */
1154         parent->na_lut = na->na_lut;
1155     }
1156
1157     /* forward the request to the parent */
1158     error = parent->nm_register(parent, onoff);
1159     if (error)
1160         return error;
1161
1162
1163     if (onoff) {
1164         na->na_flags |= NAF_NETMAP_ON | NAF_PTNETMAP_HOST;
1165     } else {
1166         ptnetmap_delete(pth_na);
1167         na->na_flags &= ~(NAF_NETMAP_ON | NAF_PTNETMAP_HOST);
1168     }
1169
1170     return 0;
1171 }
1172
1173 /* nm_dtor callback */
1174 static void
1175 nm_pt_host_dtor(struct netmap_adapter *na)
1176 {
1177     struct netmap_pt_host_adapter *pth_na =
1178         (struct netmap_pt_host_adapter *)na;
1179     struct netmap_adapter *parent = pth_na->parent;
1180
1181     DBG(D("%s", pth_na->up.name));
1182
1183     /* The equivalent of NETMAP_PT_HOST_DELETE if the hypervisor
1184      * didn't do it. */
1185     ptnetmap_stop_kctx_workers(pth_na);
1186     ptnetmap_delete(pth_na);
1187
1188     parent->na_flags &= ~NAF_BUSY;
1189
1190     netmap_adapter_put(pth_na->parent);
1191     pth_na->parent = NULL;
1192 }
1193
1194 /* check if nmr is a request for a ptnetmap adapter that we can satisfy */
1195 int
1196 netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
1197                 struct netmap_mem_d *nmd, int create)
1198 {
1199     struct nmreq parent_nmr;
1200     struct netmap_adapter *parent; /* target adapter */
1201     struct netmap_pt_host_adapter *pth_na;
1202     struct ifnet *ifp = NULL;
1203     int error;
1204
1205     /* Check if it is a request for a ptnetmap adapter */
1206     if ((nmr->nr_flags & (NR_PTNETMAP_HOST)) == 0) {
1207         return 0;
1208     }
1209
1210     D("Requesting a ptnetmap host adapter");
1211
1212     pth_na = nm_os_malloc(sizeof(*pth_na));
1213     if (pth_na == NULL) {
1214         D("ERROR malloc");
1215         return ENOMEM;
1216     }
1217
1218     /* first, try to find the adapter that we want to passthrough
1219      * We use the same nmr, after we have turned off the ptnetmap flag.
1220      * In this way we can potentially passthrough everything netmap understands.
1221      */
1222     memcpy(&parent_nmr, nmr, sizeof(parent_nmr));
1223     parent_nmr.nr_flags &= ~(NR_PTNETMAP_HOST);
1224     error = netmap_get_na(&parent_nmr, &parent, &ifp, nmd, create);
1225     if (error) {
1226         D("parent lookup failed: %d", error);
1227         goto put_out_noputparent;
1228     }
1229     DBG(D("found parent: %s", parent->name));
1230
1231     /* make sure the interface is not already in use */
1232     if (NETMAP_OWNED_BY_ANY(parent)) {
1233         D("NIC %s busy, cannot ptnetmap", parent->name);
1234         error = EBUSY;
1235         goto put_out;
1236     }
1237
1238     pth_na->parent = parent;
1239
1240     /* Follow netmap_attach()-like operations for the host
1241      * ptnetmap adapter. */
1242
1243     //XXX pth_na->up.na_flags = parent->na_flags;
1244     pth_na->up.num_rx_rings = parent->num_rx_rings;
1245     pth_na->up.num_tx_rings = parent->num_tx_rings;
1246     pth_na->up.num_tx_desc = parent->num_tx_desc;
1247     pth_na->up.num_rx_desc = parent->num_rx_desc;
1248
1249     pth_na->up.nm_dtor = nm_pt_host_dtor;
1250     pth_na->up.nm_register = nm_pt_host_register;
1251
1252     /* Reuse parent's adapter txsync and rxsync methods. */
1253     pth_na->up.nm_txsync = parent->nm_txsync;
1254     pth_na->up.nm_rxsync = parent->nm_rxsync;
1255
1256     pth_na->up.nm_krings_create = nm_pt_host_krings_create;
1257     pth_na->up.nm_krings_delete = nm_pt_host_krings_delete;
1258     pth_na->up.nm_config = nm_pt_host_config;
1259
1260     /* Set the notify method only or convenience, it will never
1261      * be used, since - differently from default krings_create - we
1262      * ptnetmap krings_create callback inits kring->nm_notify
1263      * directly. */
1264     pth_na->up.nm_notify = nm_unused_notify;
1265
1266     pth_na->up.nm_mem = netmap_mem_get(parent->nm_mem);
1267
1268     pth_na->up.na_flags |= NAF_HOST_RINGS;
1269
1270     error = netmap_attach_common(&pth_na->up);
1271     if (error) {
1272         D("ERROR netmap_attach_common()");
1273         goto put_out;
1274     }
1275
1276     *na = &pth_na->up;
1277     netmap_adapter_get(*na);
1278
1279     /* set parent busy, because attached for ptnetmap */
1280     parent->na_flags |= NAF_BUSY;
1281
1282     strncpy(pth_na->up.name, parent->name, sizeof(pth_na->up.name));
1283     strcat(pth_na->up.name, "-PTN");
1284
1285     DBG(D("%s ptnetmap request DONE", pth_na->up.name));
1286
1287     /* drop the reference to the ifp, if any */
1288     if (ifp)
1289         if_rele(ifp);
1290
1291     return 0;
1292
1293 put_out:
1294     netmap_adapter_put(parent);
1295     if (ifp)
1296         if_rele(ifp);
1297 put_out_noputparent:
1298     nm_os_free(pth_na);
1299     return error;
1300 }
1301 #endif /* WITH_PTNETMAP_HOST */
1302
1303 #ifdef WITH_PTNETMAP_GUEST
1304 /*
1305  * Guest ptnetmap txsync()/rxsync() routines, used in ptnet device drivers.
1306  * These routines are reused across the different operating systems supported
1307  * by netmap.
1308  */
1309
1310 /*
1311  * Reconcile host and guest views of the transmit ring.
1312  *
1313  * Guest user wants to transmit packets up to the one before ring->head,
1314  * and guest kernel knows tx_ring->hwcur is the first packet unsent
1315  * by the host kernel.
1316  *
1317  * We push out as many packets as possible, and possibly
1318  * reclaim buffers from previously completed transmission.
1319  *
1320  * Notifications from the host are enabled only if the user guest would
1321  * block (no space in the ring).
1322  */
1323 bool
1324 netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
1325                        int flags)
1326 {
1327         bool notify = false;
1328
1329         /* Disable notifications */
1330         ptring->guest_need_kick = 0;
1331
1332         /*
1333          * First part: tell the host (updating the CSB) to process the new
1334          * packets.
1335          */
1336         kring->nr_hwcur = ptring->hwcur;
1337         ptnetmap_guest_write_kring_csb(ptring, kring->rcur, kring->rhead);
1338
1339         /* Ask for a kick from a guest to the host if needed. */
1340         if (((kring->rhead != kring->nr_hwcur || nm_kr_txempty(kring))
1341                 && NM_ACCESS_ONCE(ptring->host_need_kick)) ||
1342                         (flags & NAF_FORCE_RECLAIM)) {
1343                 ptring->sync_flags = flags;
1344                 notify = true;
1345         }
1346
1347         /*
1348          * Second part: reclaim buffers for completed transmissions.
1349          */
1350         if (nm_kr_txempty(kring) || (flags & NAF_FORCE_RECLAIM)) {
1351                 ptnetmap_guest_read_kring_csb(ptring, kring);
1352         }
1353
1354         /*
1355          * No more room in the ring for new transmissions. The user thread will
1356          * go to sleep and we need to be notified by the host when more free
1357          * space is available.
1358          */
1359         if (nm_kr_txempty(kring)) {
1360                 /* Reenable notifications. */
1361                 ptring->guest_need_kick = 1;
1362                 /* Double check */
1363                 ptnetmap_guest_read_kring_csb(ptring, kring);
1364                 /* If there is new free space, disable notifications */
1365                 if (unlikely(!nm_kr_txempty(kring))) {
1366                         ptring->guest_need_kick = 0;
1367                 }
1368         }
1369
1370         ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
1371                 kring->name, ptring->head, ptring->cur, ptring->hwtail,
1372                 kring->rhead, kring->rcur, kring->nr_hwtail);
1373
1374         return notify;
1375 }
1376
1377 /*
1378  * Reconcile host and guest view of the receive ring.
1379  *
1380  * Update hwcur/hwtail from host (reading from CSB).
1381  *
1382  * If guest user has released buffers up to the one before ring->head, we
1383  * also give them to the host.
1384  *
1385  * Notifications from the host are enabled only if the user guest would
1386  * block (no more completed slots in the ring).
1387  */
1388 bool
1389 netmap_pt_guest_rxsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
1390                        int flags)
1391 {
1392         bool notify = false;
1393
1394         /* Disable notifications */
1395         ptring->guest_need_kick = 0;
1396
1397         /*
1398          * First part: import newly received packets, by updating the kring
1399          * hwtail to the hwtail known from the host (read from the CSB).
1400          * This also updates the kring hwcur.
1401          */
1402         ptnetmap_guest_read_kring_csb(ptring, kring);
1403         kring->nr_kflags &= ~NKR_PENDINTR;
1404
1405         /*
1406          * Second part: tell the host about the slots that guest user has
1407          * released, by updating cur and head in the CSB.
1408          */
1409         if (kring->rhead != kring->nr_hwcur) {
1410                 ptnetmap_guest_write_kring_csb(ptring, kring->rcur,
1411                                                kring->rhead);
1412                 /* Ask for a kick from the guest to the host if needed. */
1413                 if (NM_ACCESS_ONCE(ptring->host_need_kick)) {
1414                         ptring->sync_flags = flags;
1415                         notify = true;
1416                 }
1417         }
1418
1419         /*
1420          * No more completed RX slots. The user thread will go to sleep and
1421          * we need to be notified by the host when more RX slots have been
1422          * completed.
1423          */
1424         if (nm_kr_rxempty(kring)) {
1425                 /* Reenable notifications. */
1426                 ptring->guest_need_kick = 1;
1427                 /* Double check */
1428                 ptnetmap_guest_read_kring_csb(ptring, kring);
1429                 /* If there are new slots, disable notifications. */
1430                 if (!nm_kr_rxempty(kring)) {
1431                         ptring->guest_need_kick = 0;
1432                 }
1433         }
1434
1435         ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
1436                 kring->name, ptring->head, ptring->cur, ptring->hwtail,
1437                 kring->rhead, kring->rcur, kring->nr_hwtail);
1438
1439         return notify;
1440 }
1441
1442 /*
1443  * Callbacks for ptnet drivers: nm_krings_create, nm_krings_delete, nm_dtor.
1444  */
1445 int
1446 ptnet_nm_krings_create(struct netmap_adapter *na)
1447 {
1448         struct netmap_pt_guest_adapter *ptna =
1449                         (struct netmap_pt_guest_adapter *)na; /* Upcast. */
1450         struct netmap_adapter *na_nm = &ptna->hwup.up;
1451         struct netmap_adapter *na_dr = &ptna->dr.up;
1452         int ret;
1453
1454         if (ptna->backend_regifs) {
1455                 return 0;
1456         }
1457
1458         /* Create krings on the public netmap adapter. */
1459         ret = netmap_hw_krings_create(na_nm);
1460         if (ret) {
1461                 return ret;
1462         }
1463
1464         /* Copy krings into the netmap adapter private to the driver. */
1465         na_dr->tx_rings = na_nm->tx_rings;
1466         na_dr->rx_rings = na_nm->rx_rings;
1467
1468         return 0;
1469 }
1470
1471 void
1472 ptnet_nm_krings_delete(struct netmap_adapter *na)
1473 {
1474         struct netmap_pt_guest_adapter *ptna =
1475                         (struct netmap_pt_guest_adapter *)na; /* Upcast. */
1476         struct netmap_adapter *na_nm = &ptna->hwup.up;
1477         struct netmap_adapter *na_dr = &ptna->dr.up;
1478
1479         if (ptna->backend_regifs) {
1480                 return;
1481         }
1482
1483         na_dr->tx_rings = NULL;
1484         na_dr->rx_rings = NULL;
1485
1486         netmap_hw_krings_delete(na_nm);
1487 }
1488
1489 void
1490 ptnet_nm_dtor(struct netmap_adapter *na)
1491 {
1492         struct netmap_pt_guest_adapter *ptna =
1493                         (struct netmap_pt_guest_adapter *)na;
1494
1495         netmap_mem_put(ptna->dr.up.nm_mem); // XXX is this needed?
1496         memset(&ptna->dr, 0, sizeof(ptna->dr));
1497         netmap_mem_pt_guest_ifp_del(na->nm_mem, na->ifp);
1498 }
1499
1500 int
1501 netmap_pt_guest_attach(struct netmap_adapter *arg, void *csb,
1502                        unsigned int nifp_offset, unsigned int memid)
1503 {
1504         struct netmap_pt_guest_adapter *ptna;
1505         struct ifnet *ifp = arg ? arg->ifp : NULL;
1506         int error;
1507
1508         /* get allocator */
1509         arg->nm_mem = netmap_mem_pt_guest_new(ifp, nifp_offset, memid);
1510         if (arg->nm_mem == NULL)
1511                 return ENOMEM;
1512         arg->na_flags |= NAF_MEM_OWNER;
1513         error = netmap_attach_ext(arg, sizeof(struct netmap_pt_guest_adapter));
1514         if (error)
1515                 return error;
1516
1517         /* get the netmap_pt_guest_adapter */
1518         ptna = (struct netmap_pt_guest_adapter *) NA(ifp);
1519         ptna->csb = csb;
1520
1521         /* Initialize a separate pass-through netmap adapter that is going to
1522          * be used by the ptnet driver only, and so never exposed to netmap
1523          * applications. We only need a subset of the available fields. */
1524         memset(&ptna->dr, 0, sizeof(ptna->dr));
1525         ptna->dr.up.ifp = ifp;
1526         ptna->dr.up.nm_mem = netmap_mem_get(ptna->hwup.up.nm_mem);
1527         ptna->dr.up.nm_config = ptna->hwup.up.nm_config;
1528
1529         ptna->backend_regifs = 0;
1530
1531         return 0;
1532 }
1533
1534 #endif /* WITH_PTNETMAP_GUEST */